607 lines
23 KiB
C#
607 lines
23 KiB
C#
using Common.Attributes;
|
||
//using DeviceCommand.Interface;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.IO;
|
||
using System.IO.Ports;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Net.Sockets;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using static Common.Attributes.ATSCommandAttribute;
|
||
|
||
namespace DeviceCommand.Base
|
||
{
|
||
[ATSCommand]
|
||
[DeviceCategory("全部驱动")] // 添加分类属性
|
||
public class Serial_Port
|
||
{
|
||
public string PortName { get; set; } = "COM1";
|
||
public int BaudRate { get; set; } = 9600;
|
||
public int DataBits { get; set; } = 8;
|
||
public StopBits StopBits { get; set; } = StopBits.One;
|
||
public Parity Parity { get; set; } = Parity.None;
|
||
public int ReadTimeout { get; set; } = 3000;
|
||
public int WriteTimeout { get; set; } = 3000;
|
||
public SerialPort _SerialPort { get; set; } = new SerialPort();
|
||
|
||
/// <summary>
|
||
/// 创建并配置串口实例
|
||
/// </summary>
|
||
/// <param name="portName">串口名称(如"COM1")</param>
|
||
/// <param name="baudRate">波特率</param>
|
||
/// <param name="dataBits">数据位,配置默认值:8</param>
|
||
/// <param name="stopBits">停止位,配置默认值:StopBits.One</param>
|
||
/// <param name="parity">校验位(根据设备需求设置),配置默认值:Parity.None</param>
|
||
/// <param name="readTimeout">读取超时</param>
|
||
/// <param name="writeTimeout">写入超时</param>
|
||
public Serial_Port CreateDevice(string portName, int baudRate
|
||
, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None
|
||
, int readTimeout = 3000, int writeTimeout = 3000)
|
||
{
|
||
PortName = portName;
|
||
BaudRate = baudRate;
|
||
DataBits = dataBits;
|
||
StopBits = stopBits;
|
||
Parity = parity;
|
||
ReadTimeout = readTimeout;
|
||
WriteTimeout = writeTimeout;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 修改串口实例参数
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="PortName">串口名称(如"COM1")</param>
|
||
/// <param name="BaudRate">波特率</param>
|
||
/// <param name="dataBits">数据位</param>
|
||
/// <param name="stopBits">停止位</param>
|
||
/// <param name="parity">校验位(根据设备需求设置)</param>
|
||
/// <param name="ReadTimeout">读取超时</param>
|
||
/// <param name="WriteTimeout">写入超时</param>
|
||
public static void ChangeDeviceConfig(Serial_Port serialPort, string PortName, int BaudRate
|
||
, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None
|
||
, int ReadTimeout = 3000, int WriteTimeout = 3000)
|
||
{
|
||
// 更新配置串口实例参数
|
||
serialPort.PortName = PortName; // 串口名称(如"COM1")
|
||
serialPort.BaudRate = BaudRate; // 波特率
|
||
//serialPort.ReadTimeout = ReadTimeout;
|
||
//serialPort.WriteTimeout = WriteTimeout;
|
||
serialPort.Parity = parity; // 校验位(根据设备需求设置)
|
||
serialPort.DataBits = dataBits; // 数据位
|
||
serialPort.StopBits = stopBits; // 停止位
|
||
|
||
if (ReadTimeout > 0)
|
||
serialPort.ReadTimeout = ReadTimeout; // 读取超时
|
||
if (WriteTimeout > 0)
|
||
serialPort.WriteTimeout = WriteTimeout;// 写入超时
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口连接
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="ct">支持中途取消发送指令</param>
|
||
public static async Task<bool> ConnectAsync(Serial_Port serialPort, CancellationToken ct = default)
|
||
{
|
||
if (serialPort._SerialPort.PortName != serialPort.PortName
|
||
|| serialPort._SerialPort.BaudRate != serialPort.BaudRate
|
||
|| serialPort._SerialPort.Parity != serialPort.Parity
|
||
|| serialPort._SerialPort.DataBits != serialPort.DataBits
|
||
|| serialPort._SerialPort.StopBits != serialPort.StopBits
|
||
|| serialPort._SerialPort.ReadTimeout != serialPort.ReadTimeout
|
||
|| serialPort._SerialPort.WriteTimeout != serialPort.WriteTimeout)
|
||
{
|
||
|
||
// 关闭现有连接并重新配置
|
||
serialPort._SerialPort.Close();
|
||
|
||
//更新串口配置
|
||
serialPort._SerialPort.PortName = serialPort.PortName;
|
||
serialPort._SerialPort.BaudRate = serialPort.BaudRate;
|
||
serialPort._SerialPort.Parity = serialPort.Parity;
|
||
serialPort._SerialPort.DataBits = serialPort.DataBits;
|
||
serialPort._SerialPort.StopBits = serialPort.StopBits;
|
||
serialPort._SerialPort.ReadTimeout = serialPort.ReadTimeout;
|
||
serialPort._SerialPort.WriteTimeout = serialPort.WriteTimeout;
|
||
|
||
// 重新打开串口
|
||
serialPort._SerialPort.Open();
|
||
|
||
}
|
||
else
|
||
{
|
||
// 检查串口是否已打开
|
||
if (!serialPort._SerialPort.IsOpen)
|
||
{
|
||
// 打开串口
|
||
serialPort._SerialPort.Open();
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口关闭
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
public static void Close(Serial_Port serialPort)
|
||
{
|
||
if (serialPort._SerialPort.IsOpen)
|
||
{
|
||
// 关闭串口连接
|
||
serialPort._SerialPort.Close();
|
||
//Console.WriteLine("串口已关闭");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口发送byte类型数据信息
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="bytes">发送的数据信息为byte类型</param>
|
||
/// <param name="ct">支持中途取消发送指令</param>
|
||
public static async Task SendAsync(Serial_Port serialPort, byte[] bytes, CancellationToken ct = default)
|
||
{
|
||
if (!serialPort._SerialPort.IsOpen) return;
|
||
|
||
// 获取写入超时时间
|
||
var timeoutMs = serialPort.WriteTimeout;
|
||
if (timeoutMs <= 0)
|
||
{
|
||
serialPort._SerialPort.Write(bytes, 0, bytes.Length); // 向串口写入字节数据
|
||
return;
|
||
}
|
||
|
||
var sendTask = Task.Run(() =>
|
||
{
|
||
// 向串口写入字节数据
|
||
serialPort._SerialPort.Write(bytes, 0, bytes.Length);
|
||
}, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
throw new TimeoutException($"串口通讯异常:写入操作在 {timeoutMs} ms内未完成");
|
||
}
|
||
|
||
await sendTask;
|
||
|
||
//if (serialPort._SerialPort.IsOpen)
|
||
//{
|
||
//try
|
||
//{
|
||
// // 异步发送数据到串口
|
||
// await Task.Run(() =>
|
||
// {
|
||
// serialPort._SerialPort.Write(bytes, 0, bytes.Length); // 向串口写入字节数据
|
||
// }, ct);
|
||
//}
|
||
//catch (Exception ex)
|
||
//{
|
||
// // 异常处理
|
||
// //Console.WriteLine($"发送数据失败: {ex.Message}");
|
||
// MessageBox.Show($"串口发送数据失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
//}
|
||
//}
|
||
//else
|
||
//{
|
||
// //Console.WriteLine("串口未打开");
|
||
// MessageBox.Show($"串口未打开", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
//}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口发送字符串类型数据信息
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="str">发送的数据信息为字符串类型</param>
|
||
/// <param name="ct">支持中途取消发送指令</param>
|
||
public static async Task SendAsync(Serial_Port serialPort, string str, CancellationToken ct = default)
|
||
{
|
||
if (!serialPort._SerialPort.IsOpen) return;
|
||
|
||
// 将字符串转换为字节数组
|
||
byte[] bytes = Encoding.UTF8.GetBytes(str);
|
||
|
||
// 获取写入超时时间
|
||
var timeoutMs = serialPort.WriteTimeout;
|
||
if (timeoutMs <= 0)
|
||
{
|
||
serialPort._SerialPort.Write(bytes, 0, bytes.Length);
|
||
return;
|
||
}
|
||
|
||
var sendTask = Task.Run(() =>
|
||
{
|
||
// 向串口写入字节数据
|
||
serialPort._SerialPort.Write(bytes, 0, bytes.Length);
|
||
}, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
throw new TimeoutException($"串口通讯异常:写入操作在 {timeoutMs} ms内未完成");
|
||
}
|
||
|
||
await sendTask;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口读取byte类型数据信息
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="buffer">读取的数据信息为byte数组类型</param>
|
||
/// <param name="ct">支持中途取消发送指令</param>
|
||
public static async Task<byte[]> ReadAsync(Serial_Port serialPort, byte[] buffer, CancellationToken ct = default)
|
||
{
|
||
if (!serialPort._SerialPort.IsOpen) return null;
|
||
|
||
int bytesRead = 0;
|
||
|
||
// 获取写入超时时间
|
||
var timeoutMs = serialPort.ReadTimeout;
|
||
if (timeoutMs <= 0)
|
||
{
|
||
return await ReadByte(serialPort, buffer, ct);
|
||
//while (bytesRead < buffer.Length)
|
||
//{
|
||
// if (serialPort._SerialPort.BytesToRead > 0)
|
||
// {
|
||
// bytesRead += serialPort._SerialPort.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
||
// }
|
||
//}
|
||
//return buffer;
|
||
}
|
||
|
||
//var readTask = Task.Run(() =>
|
||
//{
|
||
// while (bytesRead < buffer.Length)
|
||
// {
|
||
// if (serialPort._SerialPort.BytesToRead > 0)
|
||
// {
|
||
// bytesRead += serialPort._SerialPort.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
||
// }
|
||
// }
|
||
//}, ct);
|
||
var readTask = ReadByte(serialPort, buffer, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
|
||
}
|
||
|
||
return buffer;
|
||
|
||
|
||
//try
|
||
//{
|
||
// // 异步读取串口数据
|
||
// await Task.Run(() =>
|
||
// {
|
||
// while (bytesRead < buffer.Length)
|
||
// {
|
||
// if (serialPort._SerialPort.BytesToRead > 0)
|
||
// {
|
||
// bytesRead += serialPort._SerialPort.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
||
// }
|
||
// }
|
||
// }, ct);
|
||
//}
|
||
//catch (Exception ex)
|
||
//{
|
||
// //Console.WriteLine($"读取数据失败: {ex.Message}");
|
||
// MessageBox.Show($"读取串口数据失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
// return null;
|
||
//}
|
||
//return buffer;
|
||
}
|
||
|
||
public static async Task<byte[]> ReadByte(Serial_Port serialPort, byte[] buffer, CancellationToken ct)
|
||
{
|
||
int bytesRead = 0;
|
||
while (bytesRead < buffer.Length)
|
||
{
|
||
if (serialPort._SerialPort.BytesToRead > 0)
|
||
{
|
||
bytesRead += serialPort._SerialPort.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
||
}
|
||
}
|
||
return buffer;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口读取字符串类型数据信息
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="delimiter">读取的数据信息为字符串类型,string delimiter = "\n"</param>
|
||
/// <param name="ct">支持中途取消发送指令</param>
|
||
public static async Task<string> ReadAsync(Serial_Port serialPort, string delimiter = "\n", CancellationToken ct = default)
|
||
{
|
||
if (!serialPort._SerialPort.IsOpen) return null;
|
||
|
||
// 获取写入超时时间
|
||
var timeoutMs = serialPort.ReadTimeout;
|
||
if (timeoutMs <= 0)
|
||
{
|
||
return await ReadDefaultString(serialPort, delimiter, ct);
|
||
}
|
||
|
||
var readTask = ReadDefaultString(serialPort, delimiter, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
|
||
}
|
||
|
||
return await readTask;
|
||
|
||
//try
|
||
//{
|
||
// // 异步读取串口数据
|
||
// await Task.Run(() =>
|
||
// {
|
||
// while (true)
|
||
// {
|
||
// if (ct.IsCancellationRequested)
|
||
// return;
|
||
|
||
// if (serialPort._SerialPort.BytesToRead > 0)
|
||
// {
|
||
// bytesRead = serialPort._SerialPort.Read(buffer, 0, buffer.Length);
|
||
// memoryStream.Write(buffer, 0, bytesRead);
|
||
|
||
// data = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||
// int lineEndIndex = data.IndexOf(delimiter);
|
||
|
||
// // 找到分隔符,则返回数据
|
||
// if (lineEndIndex >= 0)
|
||
// {
|
||
// data = data.Substring(0, lineEndIndex).Trim();
|
||
// return;
|
||
// }
|
||
// }
|
||
// }
|
||
// }, ct);
|
||
//}
|
||
//catch (Exception ex)
|
||
//{
|
||
// //Console.WriteLine($"读取串口数据失败: {ex.Message}");
|
||
// MessageBox.Show($"读取串口数据失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
// return null;
|
||
//}
|
||
//return data;
|
||
}
|
||
|
||
private static async Task<string> ReadDefaultString(Serial_Port serialPort, string delimiter, CancellationToken ct)
|
||
{
|
||
delimiter ??= "\n";
|
||
MemoryStream memoryStream = new();
|
||
byte[] buffer = new byte[2048];
|
||
int bytesRead = 0;
|
||
string data = string.Empty;
|
||
|
||
// 异步读取串口数据
|
||
await Task.Run(() =>
|
||
{
|
||
while (true)
|
||
{
|
||
if (ct.IsCancellationRequested)
|
||
return;
|
||
|
||
if (serialPort._SerialPort.BytesToRead > 0)
|
||
{
|
||
bytesRead = serialPort._SerialPort.Read(buffer, 0, buffer.Length);
|
||
memoryStream.Write(buffer, 0, bytesRead);
|
||
|
||
data = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||
int lineEndIndex = data.IndexOf(delimiter);
|
||
|
||
// 找到分隔符,则返回数据
|
||
if (lineEndIndex >= 0)
|
||
{
|
||
data = data.Substring(0, lineEndIndex).Trim();
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}, ct);
|
||
return data;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口读取字符串类型数据信息
|
||
/// </summary>
|
||
/// <param name="serialPort">串口实例</param>
|
||
/// <param name="delimiter">读取的数据信息为字符串类型,string delimiter</param>
|
||
/// <param name="ct">支持中途取消发送指令</param>
|
||
public static async Task<string> ReadStrAsync(Serial_Port serialPort, string delimiter, CancellationToken ct = default)
|
||
{
|
||
if (!serialPort._SerialPort.IsOpen)
|
||
{
|
||
return null; // 串口未打开,返回 null
|
||
}
|
||
|
||
// 获取写入超时时间
|
||
var timeoutMs = serialPort.ReadTimeout;
|
||
if (timeoutMs <= 0)
|
||
{
|
||
return await ReadString(serialPort, delimiter, ct);
|
||
}
|
||
|
||
var readTask = ReadString(serialPort, delimiter, ct);
|
||
var timeoutTask = Task.Delay(timeoutMs, ct);
|
||
|
||
var completedTask = await Task.WhenAny(readTask, timeoutTask);
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
|
||
}
|
||
|
||
return await readTask;
|
||
|
||
////delimiter ??= "\n"; // 默认分隔符为换行符
|
||
//MemoryStream memoryStream = new();
|
||
//byte[] buffer = new byte[2048];
|
||
//int bytesRead;
|
||
//string data = string.Empty;
|
||
|
||
//// 异步读取串口数据
|
||
//await Task.Run(() =>
|
||
//{
|
||
// while (true)
|
||
// {
|
||
// if (ct.IsCancellationRequested)
|
||
// return;
|
||
|
||
// if (serialPort._SerialPort.BytesToRead > 0)
|
||
// {
|
||
// // 从串口读取数据
|
||
// bytesRead = serialPort._SerialPort.Read(buffer, 0, buffer.Length);
|
||
// memoryStream.Write(buffer, 0, bytesRead);
|
||
|
||
// // 获取当前已读取的数据
|
||
// data = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||
|
||
// // 查找分隔符
|
||
// int delimiterIndex = data.IndexOf(delimiter);
|
||
// if (delimiterIndex >= 0)
|
||
// {
|
||
// // 如果找到分隔符,则返回读取到的字符串
|
||
// data = data.Substring(0, delimiterIndex).Trim();
|
||
// return;
|
||
// }
|
||
// }
|
||
// }
|
||
//}, ct);
|
||
|
||
//try
|
||
//{
|
||
// // 异步读取串口数据
|
||
// await Task.Run(() =>
|
||
// {
|
||
// while (true)
|
||
// {
|
||
// if (ct.IsCancellationRequested)
|
||
// return;
|
||
|
||
// if (serialPort._SerialPort.BytesToRead > 0)
|
||
// {
|
||
// // 从串口读取数据
|
||
// bytesRead = serialPort._SerialPort.Read(buffer, 0, buffer.Length);
|
||
// memoryStream.Write(buffer, 0, bytesRead);
|
||
|
||
// // 获取当前已读取的数据
|
||
// data = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||
|
||
// // 查找分隔符
|
||
// int delimiterIndex = data.IndexOf(delimiter);
|
||
// if (delimiterIndex >= 0)
|
||
// {
|
||
// // 如果找到分隔符,则返回读取到的字符串
|
||
// data = data.Substring(0, delimiterIndex).Trim();
|
||
// return;
|
||
// }
|
||
// }
|
||
// }
|
||
// }, ct);
|
||
//}
|
||
//catch (Exception ex)
|
||
//{
|
||
// //Console.WriteLine($"读取串口数据时发生错误: {ex.Message}");
|
||
// MessageBox.Show($"读取串口数据时发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
// return null;
|
||
//}
|
||
|
||
//return data; // 如果没有数据返回,返回 null
|
||
}
|
||
|
||
private static async Task<string> ReadString(Serial_Port serialPort, string delimiter, CancellationToken ct)
|
||
{
|
||
//delimiter ??= "\n";
|
||
MemoryStream memoryStream = new();
|
||
byte[] buffer = new byte[2048];
|
||
int bytesRead = 0;
|
||
string data = string.Empty;
|
||
|
||
// 异步读取串口数据
|
||
await Task.Run(() =>
|
||
{
|
||
while (true)
|
||
{
|
||
if (ct.IsCancellationRequested)
|
||
return;
|
||
|
||
if (serialPort._SerialPort.BytesToRead > 0)
|
||
{
|
||
bytesRead = serialPort._SerialPort.Read(buffer, 0, buffer.Length);
|
||
memoryStream.Write(buffer, 0, bytesRead);
|
||
|
||
data = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||
int lineEndIndex = data.IndexOf(delimiter);
|
||
|
||
// 找到分隔符,则返回数据
|
||
if (lineEndIndex >= 0)
|
||
{
|
||
data = data.Substring(0, lineEndIndex).Trim();
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}, ct);
|
||
return data;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 串口连接
|
||
/// </summary>
|
||
/// <param name="ct">取消令牌</param>
|
||
/// <returns>连接结果</returns>
|
||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||
{
|
||
return await ConnectAsync(this, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 断开串口连接
|
||
/// </summary>
|
||
public void Disconnect()
|
||
{
|
||
Close(this);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发送字符串到串口
|
||
/// </summary>
|
||
/// <param name="str">要发送的字符串</param>
|
||
/// <param name="ct">取消令牌</param>
|
||
public async Task SendStringAsync(string str, CancellationToken ct = default)
|
||
{
|
||
await SendAsync(this, str, ct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 接收字符串直到遇到指定分隔符
|
||
/// </summary>
|
||
/// <param name="delimiter">分隔符</param>
|
||
/// <param name="ct">取消令牌</param>
|
||
/// <returns>接收到的字符串</returns>
|
||
public async Task<string> ReceiveStringToAsync(string delimiter, CancellationToken ct = default)
|
||
{
|
||
return await ReadAsync(this, delimiter, ct);
|
||
}
|
||
|
||
}
|
||
} |