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 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 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 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 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 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; } } }