using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using log4net; namespace CanSimulator { /// /// CAN 总线状态 /// public enum CanBusState { /// 停止状态 Stopped, /// 运行中 Running, /// 暂停 Paused, /// 错误 Error } /// /// CAN 总线模拟器事件参数 /// public sealed class CanBusFrameEventArgs : EventArgs { public CanFrame Frame { get; } public string SourceNodeId { get; } public CanBusFrameEventArgs(CanFrame frame, string sourceNodeId) { Frame = frame; SourceNodeId = sourceNodeId; } } /// /// CAN 总线模拟器 /// 模拟一条虚拟 CAN 总线,多个虚拟节点可以挂载到总线上进行通讯 /// public sealed class CanBusSimulator : IDisposable { private static readonly ILog Log = LogManager.GetLogger(typeof(CanBusSimulator)); /// /// 总线名称 /// public string BusName { get; } /// /// 总线状态 /// public CanBusState State { get; private set; } = CanBusState.Stopped; /// /// 波特率(仅用于模拟显示,不影响实际逻辑) /// public int BaudRate { get; set; } = 500000; // 默认 500kbps /// /// 模拟延迟(毫秒)- 模拟真实总线传输延迟 /// public int SimulatedLatencyMs { get; set; } = 0; /// /// 已注册的节点 /// private readonly ConcurrentDictionary _nodes = new(); /// /// 总线日志(最近 N 条帧) /// private readonly ConcurrentQueue _busLog = new(); private int _maxLogSize = 5000; /// /// 总线统计 /// public long TotalFramesTransmitted { get; private set; } public long TotalFramesReceived { get; private set; } public DateTime? LastActivityTime { get; private set; } /// /// 帧在总线上传输事件(可用于监控/日志) /// public event EventHandler? FrameTransmitted; /// /// 总线状态变化事件 /// public event EventHandler? StateChanged; public CanBusSimulator(string busName = "CAN_BUS_1") { BusName = busName ?? throw new ArgumentNullException(nameof(busName)); } /// /// 启动总线 /// public void Start() { if (State == CanBusState.Running) { Log.Warn($"[CanBus] 总线 {BusName} 已在运行中"); return; } State = CanBusState.Running; Log.Info($"[CanBus] 总线 {BusName} 已启动 (波特率: {BaudRate}bps)"); StateChanged?.Invoke(this, State); } /// /// 停止总线 /// public void Stop() { if (State == CanBusState.Stopped) return; State = CanBusState.Stopped; Log.Info($"[CanBus] 总线 {BusName} 已停止"); StateChanged?.Invoke(this, State); } /// /// 暂停总线(帧仍在保留但不路由) /// public void Pause() { if (State != CanBusState.Running) return; State = CanBusState.Paused; Log.Info($"[CanBus] 总线 {BusName} 已暂停"); StateChanged?.Invoke(this, State); } /// /// 恢复总线 /// public void Resume() { if (State != CanBusState.Paused) return; State = CanBusState.Running; Log.Info($"[CanBus] 总线 {BusName} 已恢复"); StateChanged?.Invoke(this, State); } /// /// 注册节点到总线 /// public CanNode RegisterNode(string nodeId, string? name = null) { if (string.IsNullOrWhiteSpace(nodeId)) throw new ArgumentException("节点 ID 不能为空", nameof(nodeId)); var node = new CanNode(nodeId, name); node.FrameSent += OnNodeFrameSent; if (!_nodes.TryAdd(nodeId, node)) { Log.Warn($"[CanBus] 节点 {nodeId} 已存在,将被替换"); _nodes.TryRemove(nodeId, out var oldNode); oldNode?.Deactivate(); _nodes.TryAdd(nodeId, node); } // 如果总线已运行,自动激活节点 if (State == CanBusState.Running) { node.Activate(); } Log.Info($"[CanBus] 节点 {nodeId} ({name ?? nodeId}) 已注册到总线 {BusName}"); return node; } /// /// 注销节点 /// public bool UnregisterNode(string nodeId) { if (_nodes.TryRemove(nodeId, out var node)) { node.FrameSent -= OnNodeFrameSent; node.Deactivate(); Log.Info($"[CanBus] 节点 {nodeId} 已从总线 {BusName} 注销"); return true; } return false; } /// /// 获取节点 /// public CanNode? GetNode(string nodeId) { _nodes.TryGetValue(nodeId, out var node); return node; } /// /// 获取所有已注册节点 /// public IReadOnlyList GetAllNodes() { return _nodes.Values.ToList(); } /// /// 向总线发送帧(由节点发送,总线负责路由) /// private void OnNodeFrameSent(object? sender, CanFrame frame) { if (State != CanBusState.Running) return; // 模拟延迟 if (SimulatedLatencyMs > 0) { Thread.Sleep(SimulatedLatencyMs); } // 记录到总线日志 while (_busLog.Count >= _maxLogSize) { _busLog.TryDequeue(out _); } _busLog.Enqueue(frame); TotalFramesTransmitted++; LastActivityTime = DateTime.Now; // 路由到所有其他节点 int routed = 0; foreach (var kvp in _nodes) { if (kvp.Key == frame.SourceNodeId) continue; // 不路由回源节点 try { kvp.Value.ReceiveFrame(frame); routed++; TotalFramesReceived++; } catch (Exception ex) { Log.Error($"[CanBus] 路由帧到节点 {kvp.Key} 失败: {ex.Message}"); } } // 检查源节点是否启用自动响应模式 if (_nodes.TryGetValue(frame.SourceNodeId, out var sourceNode) && sourceNode.AutoResponseEnabled) { try { // 模拟响应延迟 if (sourceNode.AutoResponseDelayMs > 0) { Thread.Sleep(sourceNode.AutoResponseDelayMs); } // 创建响应帧(复制原始帧数据,来源为源节点) var responseFrame = new CanFrame { FrameId = frame.FrameId, Format = frame.Format, Type = frame.Type, Data = (byte[])frame.Data.Clone(), SourceNodeId = sourceNode.NodeId, Timestamp = DateTime.Now }; // 将响应帧路由到所有其他节点(不包括响应源自身) foreach (var kvp in _nodes) { if (kvp.Key == sourceNode.NodeId) continue; try { kvp.Value.ReceiveFrame(responseFrame); TotalFramesReceived++; } catch (Exception ex) { Log.Error($"[CanBus] 路由响应帧到节点 {kvp.Key} 失败: {ex.Message}"); } } // 将响应帧送入源节点的接收邮箱(让源节点能看到自己的响应) sourceNode.ReceiveFrame(responseFrame); TotalFramesReceived++; // 记录响应帧到总线日志 _busLog.Enqueue(responseFrame); TotalFramesTransmitted++; Log.Debug($"[CanBus] 节点 {sourceNode.NodeId} 自动响应帧 {responseFrame.FrameIdHex}"); } catch (Exception ex) { Log.Error($"[CanBus] 源节点自动响应失败: {ex.Message}"); } } Log.Debug($"[CanBus] 帧 {frame.FrameIdHex} 从 {frame.SourceNodeId} 路由到 {routed} 个节点"); FrameTransmitted?.Invoke(this, new CanBusFrameEventArgs(frame, frame.SourceNodeId)); } /// /// 直接注入帧到总线(用于模拟外部设备发送) /// public void InjectFrame(CanFrame frame) { if (State != CanBusState.Running) { Log.Warn($"[CanBus] 总线未运行,无法注入帧"); return; } frame.Timestamp = DateTime.Now; // 记录到日志 while (_busLog.Count >= _maxLogSize) { _busLog.TryDequeue(out _); } _busLog.Enqueue(frame); TotalFramesTransmitted++; LastActivityTime = DateTime.Now; // 路由到所有节点 foreach (var kvp in _nodes) { try { kvp.Value.ReceiveFrame(frame); TotalFramesReceived++; } catch (Exception ex) { Log.Error($"[CanBus] 注入帧路由到节点 {kvp.Key} 失败: {ex.Message}"); } } FrameTransmitted?.Invoke(this, new CanBusFrameEventArgs(frame, frame.SourceNodeId)); Log.Debug($"[CanBus] 注入帧 {frame.FrameIdHex} 到总线"); } /// /// 获取总线日志 /// public List GetBusLog(int maxCount = 100) { var all = _busLog.ToList(); if (all.Count <= maxCount) return all; return all.Skip(all.Count - maxCount).ToList(); } /// /// 清空总线日志 /// public void ClearBusLog() { while (_busLog.TryDequeue(out _)) { } } /// /// 重置所有统计 /// public void ResetStatistics() { TotalFramesTransmitted = 0; TotalFramesReceived = 0; LastActivityTime = null; foreach (var node in _nodes.Values) { node.ResetCounters(); } } /// /// 获取总线状态摘要 /// public string GetStatusSummary() { return $"Bus={BusName}, State={State}, BaudRate={BaudRate}, Nodes={_nodes.Count}, " + $"Tx={TotalFramesTransmitted}, Rx={TotalFramesReceived}, " + $"LastActivity={LastActivityTime?.ToString("HH:mm:ss") ?? "N/A"}"; } public void Dispose() { Stop(); foreach (var node in _nodes.Values) { node.Deactivate(); } _nodes.Clear(); } } }