From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点
---
CanSimulator/CanNode.cs | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 311 insertions(+), 0 deletions(-)
diff --git a/CanSimulator/CanNode.cs b/CanSimulator/CanNode.cs
new file mode 100644
index 0000000..361583b
--- /dev/null
+++ b/CanSimulator/CanNode.cs
@@ -0,0 +1,311 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using log4net;
+
+namespace CanSimulator
+{
+ /// <summary>
+ /// 鎺ユ敹婊ゆ尝鍣ㄩ厤缃�
+ /// </summary>
+ public sealed class AcceptanceFilter
+ {
+ /// <summary>
+ /// 婊ゆ尝鍣� ID锛堝尮閰嶅�硷級
+ /// </summary>
+ public uint FilterId { get; set; }
+
+ /// <summary>
+ /// 鎺╃爜锛堜负 1 鐨勪綅鍙備笌姣旇緝锛�
+ /// </summary>
+ public uint Mask { get; set; } = 0x7FF; // 榛樿鏍囧噯甯у叏鍖归厤
+
+ /// <summary>
+ /// 鏄惁涓烘墿灞曞抚婊ゆ尝鍣�
+ /// </summary>
+ public bool IsExtended { get; set; }
+
+ /// <summary>
+ /// 妫�鏌ョ粰瀹氬抚 ID 鏄惁閫氳繃姝ゆ护娉㈠櫒
+ /// </summary>
+ public bool Accepts(uint frameId, bool isExtended)
+ {
+ if (IsExtended != isExtended) return false;
+ return (frameId & Mask) == (FilterId & Mask);
+ }
+ }
+
+ /// <summary>
+ /// 铏氭嫙 CAN 鑺傜偣
+ /// 妯℃嫙涓�涓� CAN 閫氳鍗$殑绔偣锛屽叿鏈夊彂閫佸拰鎺ユ敹鍔熻兘
+ /// </summary>
+ public sealed class CanNode
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(CanNode));
+
+ /// <summary>
+ /// 鑺傜偣鍞竴鏍囪瘑
+ /// </summary>
+ public string NodeId { get; }
+
+ /// <summary>
+ /// 鑺傜偣鍚嶇О锛堝彲閫夋弿杩帮級
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// 鑺傜偣鏄惁宸叉縺娲伙紙杩炴帴鍒版�荤嚎锛�
+ /// </summary>
+ public bool IsActive { get; private set; }
+
+ /// <summary>
+ /// 鎺ユ敹婊ゆ尝鍣ㄥ垪琛�
+ /// </summary>
+ private readonly List<AcceptanceFilter> _filters = new();
+
+ /// <summary>
+ /// 鎺ユ敹閭锛團IFO 闃熷垪锛�
+ /// </summary>
+ private readonly ConcurrentQueue<CanFrame> _receiveMailbox = new();
+
+ /// <summary>
+ /// 鍙戦�佸巻鍙茶褰�
+ /// </summary>
+ private readonly ConcurrentQueue<CanFrame> _sendHistory = new();
+
+ /// <summary>
+ /// 鏈�澶ч偖绠卞閲�
+ /// </summary>
+ public int MaxMailboxSize { get; set; } = 1000;
+
+ /// <summary>
+ /// 鏈�澶у巻鍙茶褰曞閲�
+ /// </summary>
+ public int MaxHistorySize { get; set; } = 500;
+
+ /// <summary>
+ /// 鎺ユ敹甯ц鏁板櫒
+ /// </summary>
+ public long RxCount { get; private set; }
+
+ /// <summary>
+ /// 鍙戦�佸抚璁℃暟鍣�
+ /// </summary>
+ public long TxCount { get; private set; }
+
+ /// <summary>
+ /// 閿欒璁℃暟鍣�
+ /// </summary>
+ public long ErrorCount { get; private set; }
+
+ /// <summary>
+ /// 鏄惁鍚敤鑷姩鍝嶅簲妯″紡锛堟敹鍒板抚鍚庡師灏佷笉鍔ㄥ洖澶嶏級
+ /// </summary>
+ public bool AutoResponseEnabled { get; set; }
+
+ /// <summary>
+ /// 鑷姩鍝嶅簲寤惰繜锛堟绉掞級- 妯℃嫙鐪熷疄璁惧鍝嶅簲鏃堕棿
+ /// </summary>
+ public int AutoResponseDelayMs { get; set; } = 0;
+
+ /// <summary>
+ /// 鑷姩鍝嶅簲浜嬩欢锛堢敤浜庢棩蹇�/鐩戞帶锛�
+ /// </summary>
+ public event EventHandler<CanFrame>? AutoResponseSent;
+
+ /// <summary>
+ /// 甯ф帴鏀朵簨浠�
+ /// </summary>
+ public event EventHandler<CanFrame>? FrameReceived;
+
+ /// <summary>
+ /// 甯у彂閫佷簨浠�
+ /// </summary>
+ public event EventHandler<CanFrame>? FrameSent;
+
+ public CanNode(string nodeId, string? name = null)
+ {
+ NodeId = nodeId ?? throw new ArgumentNullException(nameof(nodeId));
+ Name = name ?? nodeId;
+ }
+
+ /// <summary>
+ /// 婵�娲昏妭鐐癸紙杩炴帴鍒版�荤嚎锛�
+ /// </summary>
+ public void Activate()
+ {
+ IsActive = true;
+ Log.Info($"[CanNode] 鑺傜偣 {NodeId} ({Name}) 宸叉縺娲�");
+ }
+
+ /// <summary>
+ /// 鍋滅敤鑺傜偣锛堜粠鎬荤嚎鏂紑锛�
+ /// </summary>
+ public void Deactivate()
+ {
+ IsActive = false;
+ Log.Info($"[CanNode] 鑺傜偣 {NodeId} ({Name}) 宸插仠鐢�");
+ }
+
+ /// <summary>
+ /// 娣诲姞鎺ユ敹婊ゆ尝鍣�
+ /// </summary>
+ public void AddFilter(AcceptanceFilter filter)
+ {
+ lock (_filters)
+ {
+ _filters.Add(filter);
+ }
+ Log.Debug($"[CanNode] 鑺傜偣 {NodeId} 娣诲姞婊ゆ尝鍣�: ID=0x{filter.FilterId:X3}, Mask=0x{filter.Mask:X3}");
+ }
+
+ /// <summary>
+ /// 娓呴櫎鎵�鏈夋护娉㈠櫒
+ /// </summary>
+ public void ClearFilters()
+ {
+ lock (_filters)
+ {
+ _filters.Clear();
+ }
+ Log.Debug($"[CanNode] 鑺傜偣 {NodeId} 娓呴櫎鎵�鏈夋护娉㈠櫒");
+ }
+
+ /// <summary>
+ /// 璁剧疆閫氶厤绗︽护娉㈠櫒锛堟帴鏀舵墍鏈夊抚锛�
+ /// </summary>
+ public void SetPromiscuousMode()
+ {
+ lock (_filters)
+ {
+ _filters.Clear();
+ _filters.Add(new AcceptanceFilter { FilterId = 0, Mask = 0, IsExtended = false });
+ _filters.Add(new AcceptanceFilter { FilterId = 0, Mask = 0, IsExtended = true });
+ }
+ Log.Debug($"[CanNode] 鑺傜偣 {NodeId} 璁剧疆涓烘贩鏉傛ā寮忥紙鎺ユ敹鎵�鏈夊抚锛�");
+ }
+
+ /// <summary>
+ /// 妫�鏌ュ抚鏄惁閫氳繃婊ゆ尝鍣�
+ /// </summary>
+ internal bool AcceptsFrame(CanFrame frame)
+ {
+ lock (_filters)
+ {
+ // 濡傛灉娌℃湁璁剧疆婊ゆ尝鍣紝榛樿鎷掔粷
+ if (_filters.Count == 0) return false;
+
+ // 浠讳竴婊ゆ尝鍣ㄥ尮閰嶅嵆鎺ュ彈
+ return _filters.Any(f => f.Accepts(frame.FrameId, frame.Format == CanFrameFormat.Extended));
+ }
+ }
+
+ /// <summary>
+ /// 鎺ユ敹甯э紙鐢辨�荤嚎璋冪敤锛�
+ /// </summary>
+ internal void ReceiveFrame(CanFrame frame)
+ {
+ if (!IsActive) return;
+ if (!AcceptsFrame(frame)) return;
+
+ // 鍏ラ槦鎺ユ敹閭
+ while (_receiveMailbox.Count >= MaxMailboxSize)
+ {
+ _receiveMailbox.TryDequeue(out _); // 涓㈠純鏈�鏃х殑甯�
+ }
+ _receiveMailbox.Enqueue(frame);
+ RxCount++;
+
+ // 瑙﹀彂浜嬩欢
+ FrameReceived?.Invoke(this, frame);
+ Log.Debug($"[CanNode] 鑺傜偣 {NodeId} 鎺ユ敹甯�: {frame}");
+ }
+
+ /// <summary>
+ /// 鍙戦�佸抚
+ /// </summary>
+ public void SendFrame(CanFrame frame)
+ {
+ if (!IsActive)
+ {
+ ErrorCount++;
+ throw new InvalidOperationException($"鑺傜偣 {NodeId} 鏈縺娲伙紝鏃犳硶鍙戦�佸抚");
+ }
+
+ frame.SourceNodeId = NodeId;
+ frame.Timestamp = DateTime.Now;
+
+ // 璁板綍鍙戦�佸巻鍙�
+ while (_sendHistory.Count >= MaxHistorySize)
+ {
+ _sendHistory.TryDequeue(out _);
+ }
+ _sendHistory.Enqueue(frame);
+ TxCount++;
+
+ // 瑙﹀彂浜嬩欢锛堢敱鎬荤嚎澶勭悊璺敱锛�
+ FrameSent?.Invoke(this, frame);
+ Log.Debug($"[CanNode] 鑺傜偣 {NodeId} 鍙戦�佸抚: {frame}");
+ }
+
+ /// <summary>
+ /// 浠庢帴鏀堕偖绠变腑鍙栧嚭涓�甯�
+ /// </summary>
+ public bool TryDequeueReceived(out CanFrame? frame)
+ {
+ return _receiveMailbox.TryDequeue(out frame);
+ }
+
+ /// <summary>
+ /// 鏌ョ湅鎺ユ敹閭涓殑鎵�鏈夊抚锛堜笉绉婚櫎锛�
+ /// </summary>
+ public List<CanFrame> PeekReceiveMailbox()
+ {
+ return _receiveMailbox.ToList();
+ }
+
+ /// <summary>
+ /// 娓呯┖鎺ユ敹閭
+ /// </summary>
+ public void ClearReceiveMailbox()
+ {
+ while (_receiveMailbox.TryDequeue(out _)) { }
+ Log.Debug($"[CanNode] 鑺傜偣 {NodeId} 娓呯┖鎺ユ敹閭");
+ }
+
+ /// <summary>
+ /// 鑾峰彇鍙戦�佸巻鍙�
+ /// </summary>
+ public List<CanFrame> GetSendHistory()
+ {
+ return _sendHistory.ToList();
+ }
+
+ /// <summary>
+ /// 娓呯┖鍙戦�佸巻鍙�
+ /// </summary>
+ public void ClearSendHistory()
+ {
+ while (_sendHistory.TryDequeue(out _)) { }
+ }
+
+ /// <summary>
+ /// 閲嶇疆鑺傜偣缁熻
+ /// </summary>
+ public void ResetCounters()
+ {
+ RxCount = 0;
+ TxCount = 0;
+ ErrorCount = 0;
+ }
+
+ /// <summary>
+ /// 鑾峰彇鑺傜偣鐘舵�佹憳瑕�
+ /// </summary>
+ public string GetStatusSummary()
+ {
+ return $"Node={NodeId}, Active={IsActive}, Rx={RxCount}, Tx={TxCount}, Err={ErrorCount}, Mailbox={_receiveMailbox.Count}";
+ }
+ }
+}
--
Gitblit v1.9.1