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