BOB/DeviceCommand/Base/Serial_Port.cs
2025-11-13 17:03:20 +08:00

161 lines
7.2 KiB
C#

using System.Text;
using System.IO.Ports;
namespace DeviceCommand.Base
{
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();
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;
}
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;
serialPort.BaudRate = BaudRate;
serialPort.DataBits = dataBits;
serialPort.StopBits = stopBits;
serialPort.Parity = parity;
if (ReadTimeout > 0) serialPort.ReadTimeout = ReadTimeout;
if (WriteTimeout > 0) serialPort.WriteTimeout = WriteTimeout;
}
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;
}
public static void Close(Serial_Port serialPort)
{
if (serialPort._SerialPort.IsOpen) serialPort._SerialPort.Close();
}
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;
}
public static async Task SendAsync(Serial_Port serialPort, string str, CancellationToken ct = default)
{
if (!serialPort._SerialPort.IsOpen) return;
byte[] bytes = Encoding.UTF8.GetBytes(str);
await SendAsync(serialPort, bytes, ct);
}
public static async Task<byte[]> ReadAsync(Serial_Port serialPort, byte[] buffer, CancellationToken ct = default)
{
if (!serialPort._SerialPort.IsOpen) return null;
var timeoutMs = serialPort.ReadTimeout;
var readTask = ReadByte(serialPort, buffer, ct);
if (timeoutMs <= 0) return await readTask;
var timeoutTask = Task.Delay(timeoutMs, ct);
var completedTask = await Task.WhenAny(readTask, timeoutTask);
if (completedTask == timeoutTask) throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
return await readTask;
}
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;
}
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;
var readTask = ReadDefaultString(serialPort, delimiter, ct);
if (timeoutMs <= 0) return await readTask;
var timeoutTask = Task.Delay(timeoutMs, ct);
var completedTask = await Task.WhenAny(readTask, timeoutTask);
if (completedTask == timeoutTask) throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
return await readTask;
}
private static async Task<string> ReadDefaultString(Serial_Port serialPort, string delimiter, CancellationToken ct)
{
delimiter ??= "\n";
MemoryStream memoryStream = new();
byte[] buffer = new byte[2048];
string data = string.Empty;
await Task.Run(() =>
{
while (true)
{
if (ct.IsCancellationRequested) return;
if (serialPort._SerialPort.BytesToRead > 0)
{
int 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;
}
}
}