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();
}
}
}