using System; using System.IO.Ports; using System.Text; using System.Threading; using System.Threading.Tasks; namespace DeviceCommand.Base { public class Serial_Port : ISerialPort { 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(); protected readonly SemaphoreSlim commLock = new(1, 1); public void ConfigureDevice(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; } public virtual async Task ConnectAsync(CancellationToken ct = default) { await commLock.WaitAsync(ct); try { if (SerialPort.IsOpen) SerialPort.Close(); SerialPort.PortName = PortName; SerialPort.BaudRate = BaudRate; SerialPort.DataBits = DataBits; SerialPort.StopBits = StopBits; SerialPort.Parity = Parity; SerialPort.ReadTimeout = ReadTimeout; SerialPort.WriteTimeout = WriteTimeout; SerialPort.Open(); return true; } finally { commLock.Release(); } } public virtual void Close() { if (SerialPort.IsOpen) SerialPort.Close(); } public virtual async Task SendAsync(string data, CancellationToken ct = default) { await commLock.WaitAsync(ct); try { if (!SerialPort.IsOpen) { throw new InvalidOperationException("串口未打开,无法进行操作。"); } byte[] bytes = Encoding.UTF8.GetBytes(data); var timeoutTask = Task.Delay(WriteTimeout > 0 ? WriteTimeout : Timeout.Infinite, ct); var sendTask = Task.Run(() => SerialPort.Write(bytes, 0, bytes.Length), ct); var completedTask = await Task.WhenAny(sendTask, timeoutTask); if (completedTask == timeoutTask) throw new TimeoutException($"写入操作在 {WriteTimeout} ms内未完成"); await sendTask; } finally { commLock.Release(); } } public async Task ReadAsync(CancellationToken ct = default) { return await myReadAsync(ct: ct).WaitAsync(TimeSpan.FromMilliseconds(ReadTimeout), ct); } public async Task myReadAsync(string delimiter = "\n", CancellationToken ct = default) { await commLock.WaitAsync(ct); try { if (!SerialPort.IsOpen) { throw new InvalidOperationException("串口未打开,无法进行操作。"); } delimiter ??= "\n"; var sb = new StringBuilder(); byte[] buffer = new byte[1024]; while (!ct.IsCancellationRequested) { if (SerialPort.BytesToRead > 0) { int bytesRead = SerialPort.Read(buffer, 0, buffer.Length); sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)); int index = sb.ToString().IndexOf(delimiter, StringComparison.Ordinal); if (index >= 0) { return sb.ToString(0, index).Trim(); } } else { await Task.Delay(10, ct); // 避免 CPU 空转 } } throw new OperationCanceledException("读取被取消"); } finally { commLock.Release(); } } } }