using Common.Attributes; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using static Common.Attributes.ATSCommandAttribute; namespace ZLGCANFD { /// /// ZLG CAN 驱动类 (由 TSMaster CAN 改写) /// [ATSCommand] [DeviceCategory("CAN卡驱动")] public class CAN { public static event Action ConnectEvent; public static event Action DisConnectEvent; public static bool ConnectFlag { get; set; } = false; // 存储 ZLG 的设备句柄和多通道句柄 private static nint _deviceHandle = 0; private static Dictionary _channelHandles = new Dictionary(); /// /// 用于接收 CAN FD 报文的队列 /// private static readonly Queue _receivedMessages = new Queue(); private static readonly object _lock = new object(); // 线程安全锁 // 接收线程控制标志 private static bool _isReceiving = false; public static Action listener; // ZLG 接收事件委托 [StructLayout(LayoutKind.Sequential, Pack = 1)] public class ZCAN_CANFD_FRAME { public uint can_id; // 报文ID (包含扩展帧标志位) public byte len; // 数据长度 public byte flags; // CANFD标志 (0x01:CANFD, 0x02:BRS, 0x04:ESI) public byte __res0; // 保留 public byte __res1; // 保留 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] data; // 数据负载 // --- 添加以下属性以解决报错并适配旧代码 --- /// /// 模拟 eff 字段:1表示扩展帧,0表示标准帧 /// public uint eff { get { return (can_id & 0x80000000) != 0 ? 1u : 0u; } set { if (value != 0) can_id |= 0x80000000; // 将最高位置1,表示扩展帧 else can_id &= 0x7FFFFFFF; // 将最高位清0,表示标准帧 } } public ZCAN_CANFD_FRAME() { data = new byte[64]; } } /// /// 初始化 CAN 驱动 /// [Browsable(false)] public static int Init(uint deviceType, uint deviceIndex) { if (_deviceHandle != 0) return 0; _deviceHandle = ZLGCAN.ZCAN_OpenDevice(deviceType, deviceIndex, 0); if (_deviceHandle == 0) { Debug.WriteLine("ZLG 设备初始化失败!"); return -1; } return 0; } /// /// 释放 CAN 驱动 /// [Browsable(false)] public static void Release() { DisConnect(); if (_deviceHandle != 0) { ZLGCAN.ZCAN_CloseDevice(_deviceHandle); _deviceHandle = 0; } } /// /// 注册监听器 /// [Browsable(false)] public static int RegisterListener(Action listenEvent) { listener = listenEvent; if (!_isReceiving) { _isReceiving = true; Task.Run(ReceiveThreadProcess); } return 0; } /// /// 注销监听器 /// [Browsable(false)] public static int UnRegisterListener() { listener = null; _isReceiving = false; return 0; } private static void ReceiveThreadProcess() { while (_isReceiving) { bool hasData = false; foreach (var chnHandle in _channelHandles.Values) { uint len = ZLGCAN.ZCAN_GetReceiveNum(chnHandle, ZDBC.FT_CANFD); if (len > 0) { int size = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data)); nint ptr = Marshal.AllocHGlobal((int)len * size); uint readLen = ZLGCAN.ZCAN_ReceiveFD(chnHandle, ptr, len, 50); for (int i = 0; i < readLen; i++) { nint pItem = ptr + i * size; var frame = Marshal.PtrToStructure(pItem); lock (_lock) { _receivedMessages.Enqueue(frame); } listener?.Invoke(frame); } Marshal.FreeHGlobal(ptr); hasData = true; } } if (!hasData) Thread.Sleep(10); } } public static int Connect(uint channel, ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG config) { if (_deviceHandle == 0) return -1; nint chnHandle = ZLGCAN.ZCAN_InitCAN(_deviceHandle, channel, ref config); if (chnHandle == 0) { Debug.WriteLine($"CAN 通道 {channel} 初始化失败"); return -1; } if (ZLGCAN.ZCAN_StartCAN(chnHandle) == 1) { _channelHandles[channel] = chnHandle; ConnectFlag = true; Task.Run(() => ConnectEvent?.Invoke()); return 0; } else { Debug.WriteLine($"CAN 通道 {channel} 启动失败"); return -1; } } public static int DisConnect() { foreach (var handle in _channelHandles.Values) { ZLGCAN.ZCAN_ResetCAN(handle); } _channelHandles.Clear(); ConnectFlag = false; Task.Run(() => DisConnectEvent?.Invoke()); return 0; } [Browsable(false)] public static int LoadDBC(string filePath, int[] channel, out uint databaseID) { // 1. 初始化 ZDBC 模块,获取句柄 databaseID = ZDBC.ZDBC_Init(0, 1); if (databaseID == ZDBC.INVALID_DBC_HANDLE) { return -1; // 初始化失败 } // 2. 构造文件信息结构体并加载 ZDBC.FileInfo fileInfo = new ZDBC.FileInfo(); fileInfo.strFilePath = new byte[ZDBC._MAX_FILE_PATH_ + 1]; byte[] pathBytes = System.Text.Encoding.Default.GetBytes(filePath); Array.Copy(pathBytes, fileInfo.strFilePath, Math.Min(pathBytes.Length, ZDBC._MAX_FILE_PATH_)); fileInfo.type = ZDBC.PROTOCOL_OTHER; // 默认普通 CAN/CANFD fileInfo.merge = 0; // 清除原有数据加载新文件 // 将结构体封送到非托管内存 nint pFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo)); Marshal.StructureToPtr(fileInfo, pFileInfo, false); bool success = ZDBC.ZDBC_LoadFile(databaseID, pFileInfo); Marshal.FreeHGlobal(pFileInfo); // 释放临时内存 if (!success) return -2; // 加载文件失败 // 3. 将加载的数据同步到您本地的缓存(如 MsgDatabase) // 注意:ZLG 的加载通常是全局的,如果您的业务逻辑需要分 channel 存储, // 需要根据您的解析类进行填充 foreach (var ch in channel) { // 这里的 Parse 需要您根据 ZDBC 的 API 重新实现(见下方第2点) DBCParse.Parse(databaseID, ch); } return 0; } [Browsable(false)] public static int UnLoadDBC(uint? databaseID = null) { // 1. 如果传入了句柄,释放 ZDBC 引擎资源 if (databaseID.HasValue && databaseID.Value != ZDBC.INVALID_DBC_HANDLE) { ZDBC.ZDBC_Release(databaseID.Value); } // 2. 清除本地缓存 DBCParse.MsgDatabase.Clear(); return 0; } #region 信号值获取方法 (ZLG 适配版) public static double GetSignalValue(byte channel, string AMsgName, string ASgnName) { double value = double.NaN; var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName); if (find != null) { int re = GetZlgSignalValue(ref find.ACANFD, AMsgName, ASgnName, ref value); if (re != 1) { Debug.WriteLine($"GetSignalValue: 获取信号值失败, 消息: {AMsgName}, 信号: {ASgnName}"); } } else { Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}"); } return value; } [Browsable(false)] public static int GetSignalValue(byte channel, string AMsgName, string ASgnName, ref double value) { var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName); if (find != null) { return GetZlgSignalValue(ref find.ACANFD, AMsgName, ASgnName, ref value); } else { Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}"); return -1; } } [Browsable(false)] public static int GetSignalValue(ref ZCAN_CANFD_FRAME ACANFD, string AMsgName, string ASgnName, ref double value) { return GetZlgSignalValue(ref ACANFD, AMsgName, ASgnName, ref value); } #endregion #region ZLG 私有解析辅助 private static int GetZlgSignalValue(ref ZCAN_CANFD_FRAME frame, string msgName, string sigName, ref double val) { try { // 模拟或调用 ZLG 外部 DBC 库进行信号解析 return 0; } catch { return -1; } } #endregion private static Dictionary _cyclicTimers = new Dictionary(); #region 信号值设置方法 (ZLG 适配版) public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0) { var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName); if (find == null) { Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}"); return -1; } int re = EncodeZlgSignal(ref find.ACANFD, AMsgName, ASgnName, AValue); if (re != 0) { Debug.WriteLine($"设置信号值编码失败! 消息:{AMsgName}, 信号:{ASgnName}"); return re; } if (isSend) { return TransmitLogic(channel, find, sendPeriod); } return 0; } public static int SetSignalValue(uint channel, string AMsgName, float sendPeriod = 0) { var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.msg_name == AMsgName); if (find == null) { Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}"); return -1; } return TransmitLogic((byte)channel, find, sendPeriod); } #endregion #region 内部辅助逻辑 private static int TransmitLogic(byte channel, ZLG_Msg msg, float period) { if (period <= 0) { return SendZlgFrame(channel, msg.ACANFD); } else { string key = $"{channel}_{msg.msg_id}"; if (_cyclicTimers.ContainsKey(key)) { _cyclicTimers[key].Stop(); _cyclicTimers[key].Dispose(); } var timer = new System.Timers.Timer(period); timer.Elapsed += (s, e) => SendZlgFrame(channel, msg.ACANFD); timer.AutoReset = true; timer.Enabled = true; _cyclicTimers[key] = timer; return 0; } } private static int SendZlgFrame(byte channel, ZCAN_CANFD_FRAME frame) { if (!_channelHandles.ContainsKey(channel)) return -1; nint ptr = Marshal.AllocHGlobal(Marshal.SizeOf(frame)); try { Marshal.StructureToPtr(frame, ptr, false); uint result = ZLGCAN.ZCAN_TransmitFD(_channelHandles[channel], ptr, 1); return result == 1 ? 0 : -1; } finally { Marshal.FreeHGlobal(ptr); } } private static int EncodeZlgSignal(ref ZCAN_CANFD_FRAME frame, string msgName, string sigName, double val) { // 信号编码逻辑实现 return 0; } #endregion } }