using System; namespace StandardScene.Fass2Simulator { public sealed class Fass2SimCommandHandler { private readonly Fass2SimVehicle _vehicle; private readonly Fass2SimMotionEngine _motion; private readonly Fass2SimActionEngine _actions; private readonly bool _logRawFrames; private long _stateResponseCount; public Fass2SimCommandHandler( Fass2SimVehicle vehicle, Fass2SimMotionEngine motion, Fass2SimActionEngine actions, bool logRawFrames) { _vehicle = vehicle; _motion = motion; _actions = actions; _logRawFrames = logRawFrames; } public void Handle(byte[] packet, string remote) { if (!Fass2SimProtocol.TryGetCommand(packet, out var command, out var expectedLength)) { Fass2SimLog.WriteLine($"[{Now()}] RX 非法报文 from {remote}, len={packet?.Length ?? 0}"); return; } if (packet.Length != expectedLength) { Fass2SimLog.WriteLine( $"[{Now()}] RX 长度不匹配 from {remote}: cmd={Fass2SimProtocol.CommandName(command)} actual={packet.Length} expected={expectedLength}"); return; } if (packet[expectedLength - 1] != Fass2SimProtocol.End) { Fass2SimLog.WriteLine($"[{Now()}] RX 帧尾错误 from {remote}: cmd={Fass2SimProtocol.CommandName(command)}"); return; } _vehicle.RecordCommandReceived(); _vehicle.LastCommand = command; if (command == Fass2SimProtocol.CmdStateResponse) { _vehicle.RecordAckReceived(); LogStateResponseAck(remote); return; } if (_logRawFrames) { Fass2SimLog.WriteLine($"[{Now()}] RX {Fass2SimProtocol.CommandName(command)} from {remote}: {Fass2SimProtocol.ToHex(packet)}"); } else { Fass2SimLog.WriteLine($"[{Now()}] RX {Fass2SimProtocol.CommandName(command)} from {remote}"); } switch (command) { case Fass2SimProtocol.CmdStart: _vehicle.State = 1; _motion.OnStartCommand(); Fass2SimLog.WriteLine($"[{Now()}] -> State={Fass2SimProtocol.StateText(_vehicle.State)}"); break; case Fass2SimProtocol.CmdStop: _vehicle.State = 2; _motion.OnStopCommand(); Fass2SimLog.WriteLine($"[{Now()}] -> State={Fass2SimProtocol.StateText(_vehicle.State)}"); break; case Fass2SimProtocol.CmdEmergencyStop: _vehicle.State = 3; _motion.OnStopCommand(); Fass2SimLog.WriteLine($"[{Now()}] -> State={Fass2SimProtocol.StateText(_vehicle.State)}"); break; case Fass2SimProtocol.CmdQuery: Fass2SimLog.WriteLine($"[{Now()}] -> TCP 查询(UDP 模式通常不发 0x00)"); break; case Fass2SimProtocol.CmdNodes: if (Fass2SimProtocol.TryParseNodes(packet, out var taskId, out var nodes)) { _motion.OnNodesCommand(taskId, nodes); } else { Fass2SimLog.WriteLine($"[{Now()}] -> 0xB1 解析失败"); } break; case Fass2SimProtocol.CmdAction: if (Fass2SimProtocol.TryParseAction(packet, out var actionId, out var patch)) { _actions.OnActionCommand(actionId, patch); } else { Fass2SimLog.WriteLine($"[{Now()}] -> 0xA1 解析失败"); } break; default: Fass2SimLog.WriteLine($"[{Now()}] -> 暂未处理"); break; } } private void LogStateResponseAck(string remote) { _stateResponseCount++; if (_stateResponseCount == 1) { Fass2SimLog.WriteLine($"[{Now()}] RX StateResponse(0x10) from {remote},调度在线(后续 0x10 仅写文件日志)"); return; } if (_stateResponseCount % 200 == 0) { Fass2SimLog.WriteFileOnly($"[{Now()}] 0x10 累计应答 {_stateResponseCount} 次"); } } private static string Now() { return DateTime.Now.ToString("HH:mm:ss.fff"); } } }