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