/* Pseudocode (详细计划): - 定义类 SerialPortProtocol,实现 ICommunicationProtocol。 - 字段: - _client: SerialPortClient 实例,用于串口通信。 - _waitClient: 等待客户端,用于发送后等待响应。 - _config: 只读配置对象 SerialPortConfig。 - 属性: - IsConnected: 检查 _client 是否在线。 - Terminator: 终止符设置(默认 None)。 - Encoding: 编码(默认 ASCII)。 - 事件: - ConnectionChanged: 连接状态变化时触发。 - DataReceived: 接收数据时触发(字符串形式)。 - DataSent: 发送数据时触发(字符串形式)。 - 构造函数: - 接收 SerialPortConfig 并保存到 _config。 - ConnectAsync: - 创建 SerialPortClient。 - 构建 TouchSocketConfig,设置串口选项(端口名、波特率、数据位、校验、停止位)。 - 设置数据处理适配器 PeriodPackageAdapter(CacheTimeout 100ms)。 - 调用 _client.Setup(config) 并 TryConnectAsync。 - 若成功,创建等待客户端并触发 ConnectionChanged(true),返回 true;否则触发 ConnectionChanged(false),返回 false。 - 捕获异常时也触发 ConnectionChanged(false) 并返回 false。 - DisconnectAsync: - 触发 ConnectionChanged(false),关闭 _client。 - Send/SendAsync(字节/字符串): - 检查 _client 是否存在,否则抛出 InvalidOperationException。 - 触发 DataSent(字符串形式)。 - 使用 _client.Send 或 _client.SendAsync 发送数据。 - SendAndReceive/SendAndReceiveAsync(字节/字符串): - 检查 _waitClient,否则抛出 InvalidOperationException。 - 触发 DataSent。 - 使用 _waitClient.SendThenReturn(Sync/Async) 等待响应。 - 触发 DataReceived 并返回响应(字节或字符串)。 - Dispose: -释放 _client 并置空 _waitClient。 - 为所有公开成员添加 XML 文档注释,描述参数、返回值与异常。 */ using System; using System.Text; using System.Threading.Tasks; using TeamAAS_VP.Enums; using TeamAAS_VP.Models; using TouchSocket.Core; using TouchSocket.SerialPorts; using TouchSocket.Sockets; namespace TeamAAS_VP.Core.Lights { /// /// 使用 TouchSocket 的串口通信协议封装。 /// 提供同步/异步的发送与收发方法,并通过事件报告连接与数据状态。 /// public class SerialPortProtocol : ICommunicationProtocol { /// /// 内部串口客户端实例。 /// private SerialPortClient _client; /// /// 用于发送后等待响应的等待客户端。 /// private IWaitingClient _waitClient; /// /// 串口配置,只读。 /// private readonly SerialPortConfig _config; /// /// 获取是否已连接(客户端在线)。 /// public bool IsConnected => _client?.Online == true; /// /// 数据终止符,默认为 。 /// public Terminator Terminator { get; set; } = Terminator.None; /// /// 文本编码,默认使用 ASCII 编码。 /// public Encoding Encoding { get; set; } = Encoding.ASCII; /// /// 当连接状态改变时触发。参数为触发对象和连接状态(true=已连接)。 /// public event Action ConnectionChanged; /// /// 当接收到数据时触发,携带接收到的数据(字符串形式)。 /// public event Action DataReceived; /// /// 当发送数据时触发,携带发送的数据(字符串形式)。 /// public event Action DataSent; /// /// 使用指定的串口配置构建一个新的 实例。 /// /// 串口配置,不能为 null。 /// 为 null 时抛出。 public SerialPortProtocol(SerialPortConfig config) { _config = config ?? throw new ArgumentNullException(nameof(config)); } /// /// 异步连接到串口并初始化等待客户端。 /// /// 连接成功返回 true,否则返回 false。 public async Task ConnectAsync() { try { _client = new SerialPortClient(); var config = new TouchSocketConfig() .SetSerialPortOption(new SerialPortOption() { PortName = _config.PortName, BaudRate = _config.BaudRate, DataBits = _config.DataBits, Parity = _config.Parity, StopBits = _config.StopBits }) .SetSerialDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromMilliseconds(100) }); _client.Received = async (c, e) => { string Data = e.ByteBlock.Span.ToString(Encoding); //接收到数据 DataReceived?.Invoke(this, Data.Trim()); }; _client.Setup(config); var result = await _client.TryConnectAsync(); if (result.IsSuccess) { _waitClient = _client.CreateWaitingClient(new WaitingOptions()); ConnectionChanged?.Invoke(this, true); return true; } ConnectionChanged?.Invoke(this, false); return false; } catch { ConnectionChanged?.Invoke(this, false); return false; } } /// /// 异步断开连接并关闭串口。 /// /// 完成任务。 public Task DisconnectAsync() { ConnectionChanged?.Invoke(this, false); _client?.Close(); return Task.CompletedTask; } /// /// 异步发送字节数据并等待接收响应。 /// /// 要发送的字节数组。 /// 等待超时时间(毫秒),默认 5000ms。 /// 收到的字节数组。 /// 当尚未连接或等待客户端为 null 时抛出。 public async Task SendAndReceiveAsync(byte[] data, int timeout = 5000) { if (_waitClient == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, Encoding.GetString(data)); var response = await _waitClient.SendThenReturnAsync(data, timeout); DataReceived?.Invoke(this, Encoding.GetString(response)); return response; } /// /// 异步发送字节数据(不等待响应)。 /// /// 要发送的字节数组。 /// 完成任务。 /// 当客户端未初始化时抛出。 public Task SendAsync(byte[] data) { if (_client == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, Encoding.GetString(data)); _client.Send(data); return Task.CompletedTask; } /// /// 异步发送文本并等待响应(字符串形式)。 /// /// 要发送的文本。 /// 等待超时时间(毫秒),默认 5000ms。 /// 收到的文本响应。 /// 当尚未连接或等待客户端为 null 时抛出。 public async Task SendAndReceiveAsync(string data, int timeout = 5000) { if (_waitClient == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, data); var response = await SendAndReceiveAsync(Encoding.GetBytes(data), timeout); DataReceived?.Invoke(this, Encoding.GetString(response)); return Encoding.GetString(response); } /// /// 同步发送文本并等待响应(字符串形式)。 /// /// 要发送的文本。 /// 等待超时时间(毫秒),默认 5000ms。 /// 收到的文本响应。 /// 当尚未连接或等待客户端为 null 时抛出。 public string SendAndReceive(string data, int timeout = 5000) { if (_waitClient == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, data); var response = _waitClient.SendThenReturn(Encoding.GetBytes(data), timeout); DataReceived?.Invoke(this, Encoding.GetString(response)); return Encoding.GetString(response); } /// /// 同步发送字节数据并等待响应。 /// /// 要发送的字节数组。 /// 等待超时时间(毫秒),默认 5000ms。 /// 收到的字节数组。 /// 当尚未连接或等待客户端为 null 时抛出。 public byte[] SendAndReceive(byte[] data, int timeout = 5000) { if (_waitClient == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, Encoding.GetString(data)); var response = _waitClient.SendThenReturn(data, timeout); DataReceived?.Invoke(this, Encoding.GetString(response)); return response; } /// /// 同步发送文本(不等待响应)。 /// /// 要发送的文本。 /// 当客户端未初始化时抛出。 public void Send(string data) { if (_client == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, data); _client.Send(Encoding.GetBytes(data)); } /// /// 异步发送文本(不等待响应)。 /// /// 要发送的文本。 /// 完成任务。 /// 当客户端未初始化时抛出。 public async Task SendAsync(string data) { if (_client == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, data); await _client.SendAsync(Encoding.GetBytes(data)); } /// /// 同步发送字节数据(不等待响应)。 /// /// 要发送的字节数组。 /// 当客户端未初始化时抛出。 public void Send(byte[] data) { if (_client == null) throw new InvalidOperationException("Not connected"); DataSent?.Invoke(this, Encoding.GetString(data)); _client.Send(data); } /// /// 释放底层资源。调用后实例不应再被使用。 /// public void Dispose() { _client?.Dispose(); _waitClient = null; } } }