using System; using System.Collections.Generic; using System.Linq; using CanSimulator; namespace CanSimulatorServer { /// /// 服务端命令串执行器:对挂载节点执行 SEND/QUERY 命令,语义与原 CanDriverAdapter /// 保持一致(命令串直传协议的核心)。返回值约定: /// OK 前缀 = 成功响应;ERR 前缀 = 业务失败;其余 = 裸数据(由会话层补 OK: 前缀)。 /// public sealed class CanCommandExecutor { private readonly CanNode _node; private readonly CanBusSimulator _bus; public CanCommandExecutor(CanNode node, CanBusSimulator bus) { _node = node ?? throw new ArgumentNullException(nameof(node)); _bus = bus ?? throw new ArgumentNullException(nameof(bus)); } /// 执行一行命令(SEND:… 或 QUERY:…),异常转为 ERR 响应,不抛出。 public string Execute(string line) { try { if (line.StartsWith("SEND:", StringComparison.OrdinalIgnoreCase)) return HandleSend(line); if (line.StartsWith("QUERY:", StringComparison.OrdinalIgnoreCase)) { string query = line.Substring("QUERY:".Length); return HandleQuery(query); } return $"ERR:UNKNOWN_CMD:{line}"; } catch (ArgumentException ex) { return $"ERR:BAD_FRAME:{ex.Message}"; } catch (Exception ex) { return $"ERR:EXEC:{ex.Message}"; } } private string HandleSend(string line) { // SEND:frameId:data(data 内可含空格,不参与分段) var parts = line.Split(':'); if (parts.Length < 3) throw new ArgumentException("SEND 格式应为 SEND:frameId:data"); uint frameId = CanFrame.ParseFrameId(parts[1]); byte[] data = CanFrame.ParseData(string.Join(":", parts.Skip(2))); if (data.Length > 8) throw new ArgumentException($"数据长度超限: {data.Length} 字节(最大 8)"); var frame = new CanFrame { FrameId = frameId, Format = frameId > 0x7FF ? CanFrameFormat.Extended : CanFrameFormat.Standard, Type = CanFrameType.Data, Data = data }; _node.SendFrame(frame); // 触发总线路由(其它节点收帧 → 各自推送)与自动响应 return $"OK:TX:{frame.FrameIdHex}:{frame.Dlc}"; } private string HandleQuery(string query) { var parts = query.Split(':'); string op = parts[0].ToUpperInvariant(); switch (op) { case "RECV": { if (_node.TryDequeueReceived(out var f) && f != null) return $"OK:RECV:{f.FrameIdHex}:{f.DataHex}:{f.Timestamp:HH:mm:ss.fff}"; return "OK:RECV:EMPTY"; } case "RECV_ALL": { var mailbox = _node.PeekReceiveMailbox(); _node.ClearReceiveMailbox(); if (mailbox.Count == 0) return "OK:RECV_ALL:0"; var items = mailbox.Select(f => $"{f.FrameIdHex}:{f.DataHex}:{f.Timestamp:HH:mm:ss.fff}"); return $"OK:RECV_ALL:{mailbox.Count}:{string.Join("|", items)}"; } case "STATUS": return "OK:STATUS:" + DescribeStatus(); case "FILTER": { if (parts.Length < 3) throw new ArgumentException("FILTER 格式应为 FILTER:id:mask"); uint fid = CanFrame.ParseFrameId(parts[1]); uint mask = CanFrame.ParseFrameId(parts[2]); _node.AddFilter(new AcceptanceFilter { FilterId = fid, Mask = mask, IsExtended = fid > 0x7FF }); return $"OK:滤波器已添加 ID=0x{fid:X3}, Mask=0x{mask:X3}"; } case "FILTER_CLEAR": _node.ClearFilters(); return "OK:滤波器已清除"; case "PROMISCUOUS": _node.SetPromiscuousMode(); return "OK:混杂模式已启用"; case "BUS_ECHO": { if (parts.Length < 2) return $"OK:BUS_ECHO:{(_bus.EchoResponderToSender ? "ON" : "OFF")}"; string mode = parts[1].Trim().ToUpperInvariant(); switch (mode) { case "ON": case "1": case "TRUE": case "ENABLE": _bus.EchoResponderToSender = true; return "OK:总线应答器已开启(回显给发送者)"; case "OFF": case "0": case "FALSE": case "DISABLE": _bus.EchoResponderToSender = false; return "OK:总线应答器已关闭"; default: throw new ArgumentException($"BUS_ECHO 参数错误: {mode}"); } } case "AUTO_RESPONSE": { if (parts.Length < 2) return $"OK:AUTO_RESPONSE:{(_node.AutoResponseEnabled ? "ON" : "OFF")}"; string mode = parts[1].Trim().ToUpperInvariant(); switch (mode) { case "ON": case "1": case "TRUE": case "ENABLE": _node.AutoResponseEnabled = true; return "OK:自动响应模式已启用"; case "OFF": case "0": case "FALSE": case "DISABLE": _node.AutoResponseEnabled = false; return "OK:自动响应模式已禁用"; default: throw new ArgumentException($"AUTO_RESPONSE 参数错误: {mode}"); } } case "RESPONSE_DELAY": { if (parts.Length < 2) return $"OK:RESPONSE_DELAY:{_node.AutoResponseDelayMs}ms"; if (!int.TryParse(parts[1].Trim(), out int d) || d < 0) throw new ArgumentException($"RESPONSE_DELAY 参数错误: {parts[1]}"); _node.AutoResponseDelayMs = d; return $"OK:响应延迟已设置为 {d}ms"; } case "LOG": { var log = _bus.GetBusLog(50); if (log.Count == 0) return "OK:LOG:EMPTY"; var entries = log.Select(f => $"[{f.Timestamp:HH:mm:ss.fff}]{f.SourceNodeId}>{f.FrameIdHex}:{f.DataHex}"); return $"OK:LOG:{log.Count}:{string.Join("|", entries)}"; } case "BUS_STATUS": return "OK:" + _bus.GetStatusSummary(); default: return $"ERR:UNKNOWN_CMD:{query}"; } } private string DescribeStatus() { string nodeStatus = _node.GetStatusSummary(); // Node={nodeId}, Active=…, Rx=… string busStatus = _bus.GetStatusSummary(); // Bus=…, State=…, Nodes=… return $"{nodeStatus}|{busStatus}"; } /// 把接收帧格式化为 EV:RECV 推送行(时间戳与数据不含冒号)。 public static string FormatPush(CanFrame frame) { string src = string.IsNullOrEmpty(frame.SourceNodeId) ? "0" : frame.SourceNodeId; return $"EV:RECV:{frame.FrameIdHex}:{frame.DataHex}:{frame.Timestamp:HH.mm.ss.fff}:{src}"; } } }