using Common.Attributes; using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using USBCANFD; namespace DeviceCommand.Device { [ADPCommand] public class ZLGCANFD : IDisposable { // 硬件设备与通道句柄 private IntPtr _deviceHandle = IntPtr.Zero; private readonly IntPtr[] _channelHandles; // 【核心修改】每个通道分配独立的 DBC 引擎句柄与锁,彻底解决台架间DBC冲突与锁竞争 private readonly uint[] _dbcHandles; private readonly bool[] _isDbcLoadedArray; private readonly object[] _channelLocks; // 通道级细粒度锁 // 异步高性能接收线程控制 private volatile bool _isRunning = false; private readonly List _receiveThreads = new List(); // 动态硬件参数 private readonly uint _deviceType; // 43: USBCANFD-400U private readonly uint _deviceIndex; // 设备索引 private readonly int _maxChannels; // 动态通道数 /// /// 事件:当接收到 CAN/CANFD 报文并且通过 DBC 成功解析后触发 /// 参数:uint 通道号 (0,1,2,3), ZDBC.DBCMessage 解析后的DBC消息结构体 /// public event Action? OnDbcMessageDecoded; public ZLGCANFD(uint deviceType = 43, uint deviceIndex = 0, int maxChannels = 4) { _deviceType = deviceType; _deviceIndex = deviceIndex; _maxChannels = maxChannels; // 初始化通道相关状态数组 _channelHandles = new IntPtr[_maxChannels]; _dbcHandles = new uint[_maxChannels]; _isDbcLoadedArray = new bool[_maxChannels]; _channelLocks = new object[_maxChannels]; for (int i = 0; i < _maxChannels; i++) { _channelHandles[i] = IntPtr.Zero; _dbcHandles[i] = 0; _isDbcLoadedArray[i] = false; _channelLocks[i] = new object(); } } #region 1. 硬件连接与通道初始化 /// /// 仅仅打开设备,不做具体的通道波特率配置(留给具体的台架去分别配置) /// public virtual bool 打开设备() { if (_deviceHandle != IntPtr.Zero) return true; _deviceHandle = ZLGCAN.ZCAN_OpenDevice(_deviceType, _deviceIndex, 0); return _deviceHandle != IntPtr.Zero; } /// /// 【核心修改】针对特定通道进行参数初始化并启动 /// public virtual bool 初始化并启动通道(uint 通道号, string abitBaud = "500000", string dbitBaud = "2000000", bool 开启终端电阻 = true) { if (_deviceHandle == IntPtr.Zero) throw new InvalidOperationException("请先调用 '打开设备()' 才能初始化通道。"); if (通道号 >= _maxChannels) return false; lock (_channelLocks[通道号]) { // 如果已经启动过,先复位 if (_channelHandles[通道号] != IntPtr.Zero) { ZLGCAN.ZCAN_ResetCAN(_channelHandles[通道号]); } // 1. 设置该通道专属的仲裁域与数据域波特率 if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/canfd_abit_baud_rate", abitBaud) != 1) return false; if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/canfd_dbit_baud_rate", dbitBaud) != 1) return false; // 2. 设置该通道专属内部终端电阻状态 string resistanceStr = 开启终端电阻 ? "1" : "0"; if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/initenal_resistance", resistanceStr) != 1) return false; // 3. 规范配置通道结构体 ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG config = new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG(); config.can_type = 1; // 1 代表 CANFD 模式 config.config.canfd.mode = 0; // 0 代表正常工作模式 IntPtr pConfig = Marshal.AllocHGlobal(Marshal.SizeOf(config)); Marshal.StructureToPtr(config, pConfig, true); _channelHandles[通道号] = ZLGCAN.ZCAN_InitCAN(_deviceHandle, 通道号, pConfig); Marshal.FreeHGlobal(pConfig); if (_channelHandles[通道号] == IntPtr.Zero) return false; // 4. 启动 CAN 通道 if (ZLGCAN.ZCAN_StartCAN(_channelHandles[通道号]) != 1) return false; // 5. 为该通道启动专属的独立后台高性能轮询接收线程(如果尚未启动轮询) if (!_isRunning) _isRunning = true; int chnIdx = (int)通道号; Thread rxThread = new Thread(() => 接收轮询核心(_channelHandles[chnIdx], (uint)chnIdx)) { IsBackground = true, Name = $"ZLGCANFD_Dev{_deviceIndex}_CH{chnIdx}_RxThread" }; _receiveThreads.Add(rxThread); rxThread.Start(); return true; } } public virtual void 关闭CAN卡设备() { _isRunning = false; Thread.Sleep(50); // 确保轮询线程安全退出 _receiveThreads.Clear(); // 动态复位所有通道并释放DBC for (uint i = 0; i < _maxChannels; i++) { lock (_channelLocks[i]) { if (_channelHandles[i] != IntPtr.Zero) { ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]); _channelHandles[i] = IntPtr.Zero; } 释放通道DBC(i); } } // 关闭设备主句柄 if (_deviceHandle != IntPtr.Zero) { ZLGCAN.ZCAN_CloseDevice(_deviceHandle); _deviceHandle = IntPtr.Zero; } } #endregion #region 2. DBC 矩阵文件操作 /// /// 【核心修改】指定通道加载特定的 DBC 文件(支持不同通道加载不同的DBC矩阵) /// public virtual bool 加载通道DBC文件(uint 通道号, string dbcFilePath) { if (通道号 >= _maxChannels) return false; lock (_channelLocks[通道号]) { try { if (_isDbcLoadedArray[通道号]) return true; uint chDbcHandle = ZDBC.ZDBC_Init(); if (chDbcHandle == 0) return false; IntPtr ptrPath = Marshal.StringToHGlobalAnsi(dbcFilePath); bool success = ZDBC.ZDBC_LoadFile(chDbcHandle, ptrPath); Marshal.FreeHGlobal(ptrPath); if (success) { _dbcHandles[通道号] = chDbcHandle; _isDbcLoadedArray[通道号] = true; } else { ZDBC.ZDBC_Release(chDbcHandle); } return success; } catch { return false; } } } public virtual void 释放通道DBC(uint 通道号) { if (通道号 >= _maxChannels) return; lock (_channelLocks[通道号]) { if (_isDbcLoadedArray[通道号] && _dbcHandles[通道号] != 0) { ZDBC.ZDBC_Release(_dbcHandles[通道号]); _dbcHandles[通道号] = 0; _isDbcLoadedArray[通道号] = false; } } } #endregion #region 3. 轮询接收与实时自动化 DBC 解码 private void 接收轮询核心(IntPtr channelHandle, uint channelIndex) { const int bufferSize = 100; int canStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data)); int canfdStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data)); int dbcMsgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage)); IntPtr ptrCanBuffer = Marshal.AllocHGlobal(canStructSize * bufferSize); IntPtr ptrCanFDBuffer = Marshal.AllocHGlobal(canfdStructSize * bufferSize); IntPtr ptrDbcMsg = Marshal.AllocHGlobal(dbcMsgSize); try { while (_isRunning) { bool currentTurnHasData = false; // 1. 自动提取并解析经典 CAN 帧 uint canNum = ZLGCAN.ZCAN_GetReceiveNum(channelHandle, 0); if (canNum > 0) { uint actualRecv = ZLGCAN.ZCAN_Receive(channelHandle, ptrCanBuffer, bufferSize, 5); for (int i = 0; i < actualRecv; i++) { IntPtr framePtr = IntPtr.Add(ptrCanBuffer, i * canStructSize); // 【通道级业务隔离隔离】只锁定当前通道的DBC句柄进行解码,高并发完全不卡顿 lock (_channelLocks[channelIndex]) { if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 0)) { var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage)); OnDbcMessageDecoded?.Invoke(channelIndex, msg); } } } currentTurnHasData = true; } // 2. 自动提取并解析高速 CANFD 帧 uint canfdNum = ZLGCAN.ZCAN_GetReceiveNum(channelHandle, 1); if (canfdNum > 0) { uint actualRecvFd = ZLGCAN.ZCAN_ReceiveFD(channelHandle, ptrCanFDBuffer, bufferSize, 5); for (int i = 0; i < actualRecvFd; i++) { IntPtr framePtr = IntPtr.Add(ptrCanFDBuffer, i * canfdStructSize); lock (_channelLocks[channelIndex]) { if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 1)) { var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage)); OnDbcMessageDecoded?.Invoke(channelIndex, msg); } } } currentTurnHasData = true; } if (!currentTurnHasData) { Thread.Sleep(2); } } } finally { Marshal.FreeHGlobal(ptrCanBuffer); Marshal.FreeHGlobal(ptrCanFDBuffer); Marshal.FreeHGlobal(ptrDbcMsg); } } #endregion #region 4. DBC 自动打包与智能报文发送 public virtual bool 发送DBC定义报文(uint 通道号, uint 帧ID, Action 配置信号动作, int 是否使用CANFD = 1) { if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false; if (!_isDbcLoadedArray[通道号]) throw new InvalidOperationException($"通道 {通道号} 的 DBC 协议未加载,无法执行打包发送指令。"); IntPtr ptrDbcMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage))); IntPtr ptrCount = Marshal.AllocHGlobal(sizeof(uint)); Marshal.WriteInt32(ptrCount, 1); try { // 使用通道级锁保护当前通道发送 lock (_channelLocks[通道号]) { uint chDbcHandle = _dbcHandles[通道号]; if (!ZDBC.ZDBC_GetMessageById(chDbcHandle, 帧ID, ptrDbcMsg)) return false; var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage)); 配置信号动作(msg); Marshal.StructureToPtr(msg, ptrDbcMsg, true); if (是否使用CANFD == 0) { IntPtr ptrCanFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.can_frame))); if (!ZDBC.ZDBC_Encode(chDbcHandle, ptrCanFrame, ptrCount, ptrDbcMsg, 0)) return false; ZLGCAN.can_frame canFrame = (ZLGCAN.can_frame)Marshal.PtrToStructure(ptrCanFrame, typeof(ZLGCAN.can_frame)); canFrame.__pad |= 0x20; ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = canFrame, transmit_type = 0 }; IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData)); Marshal.StructureToPtr(txData, pTx, true); uint sendResult = ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1); Marshal.FreeHGlobal(ptrCanFrame); Marshal.FreeHGlobal(pTx); return sendResult == 1; } else { IntPtr ptrCanFDFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.canfd_frame))); if (!ZDBC.ZDBC_Encode(chDbcHandle, ptrCanFDFrame, ptrCount, ptrDbcMsg, 1)) return false; ZLGCAN.canfd_frame canfdFrame = (ZLGCAN.canfd_frame)Marshal.PtrToStructure(ptrCanFDFrame, typeof(ZLGCAN.canfd_frame)); canfdFrame.flags |= 0x20; ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = canfdFrame, transmit_type = 0 }; IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData)); Marshal.StructureToPtr(txFdData, pTxFd, true); uint sendResult = ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1); Marshal.FreeHGlobal(ptrCanFDFrame); Marshal.FreeHGlobal(pTxFd); return sendResult == 1; } } } finally { Marshal.FreeHGlobal(ptrDbcMsg); Marshal.FreeHGlobal(ptrCount); } } #endregion #region 5. 辅助工具子系统 /// /// 【核心修改】计算物理值也需要传入对应通道,使用通道专属的DBC句柄进行计算 /// public ulong 物理值转原始寄存器值(uint 通道号, ZDBC.DBCSignal 信号定义, double 实际物理值) { if (通道号 >= _maxChannels) return 0; IntPtr pSignal = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal))); IntPtr pValue = Marshal.AllocHGlobal(sizeof(double)); try { Marshal.StructureToPtr(信号定义, pSignal, true); Marshal.StructureToPtr(实际物理值, pValue, true); lock (_channelLocks[通道号]) { return ZDBC.ZDBC_CalcRawValue(pSignal, pValue); } } finally { Marshal.FreeHGlobal(pSignal); Marshal.FreeHGlobal(pValue); } } #endregion [Browsable(false)] public void Dispose() { 关闭CAN卡设备(); } } }