diff --git a/BDU.sln b/BDU.sln index d07fc60..719e0ed 100644 --- a/BDU.sln +++ b/BDU.sln @@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "加密狗", "加密狗\加 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDU", "BDU\BDU.csproj", "{0C2B5CA2-D873-255B-1B76-741346ECA1BB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZLGCANFD", "ZLGCANFD\ZLGCANFD.csproj", "{307FD972-9EFD-453F-BBF3-92ECA032DA73}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,6 +58,10 @@ Global {0C2B5CA2-D873-255B-1B76-741346ECA1BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {0C2B5CA2-D873-255B-1B76-741346ECA1BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {0C2B5CA2-D873-255B-1B76-741346ECA1BB}.Release|Any CPU.Build.0 = Release|Any CPU + {307FD972-9EFD-453F-BBF3-92ECA032DA73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {307FD972-9EFD-453F-BBF3-92ECA032DA73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {307FD972-9EFD-453F-BBF3-92ECA032DA73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {307FD972-9EFD-453F-BBF3-92ECA032DA73}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BDU/BDU.csproj b/BDU/BDU.csproj index 74fce97..87bac22 100644 --- a/BDU/BDU.csproj +++ b/BDU/BDU.csproj @@ -27,11 +27,10 @@ - - + diff --git a/BDU/Logic/DeviceConnect.cs b/BDU/Logic/DeviceConnect.cs index 77aae4c..6ee731a 100644 --- a/BDU/Logic/DeviceConnect.cs +++ b/BDU/Logic/DeviceConnect.cs @@ -11,7 +11,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; -using TSMasterCAN; +using ZLGCANFD; namespace BDU.Logic { @@ -102,9 +102,9 @@ namespace BDU.Logic { tmpDevice.CommunicationProtocol = device.CommunicationProtocol; CAN.DisConnect(); - var re1 = CAN.Init("ATS测试系统"); + var re1 = CAN.Init(ZLGCAN.ZCAN_USBCANFD_100U,0); var re2 = CAN.LoadDBC(SystemConfig.Instance.DBCFilePath, [0, 1, 2, 3], out _); - var re3 = CAN.Connect(); + var re3 = CAN.Connect(0,new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG()); if (re1 == 0 && re2 == 0 && re3 == 0) { tmpDevice.Connected = true; @@ -279,7 +279,7 @@ namespace BDU.Logic break; case "CAN": - var re1 = CAN.Init("ATS测试系统"); + var re1 = CAN.Init(ZLGCAN.ZCAN_USBCANFD_100U, 0); //var re2 = CAN.LoadDBC(SystemConfig.Instance.DBCFilePath, [0, 1, 2, 3], out _); //var re3 = CAN.Connect(); if (re1 == 0 && CAN.ConnectFlag) diff --git a/BDU/Views/CANCatchSingalView.xaml.cs b/BDU/Views/CANCatchSingalView.xaml.cs index 747f4d1..3bcd45e 100644 --- a/BDU/Views/CANCatchSingalView.xaml.cs +++ b/BDU/Views/CANCatchSingalView.xaml.cs @@ -15,7 +15,7 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; -using TSMasterCAN; +using ZLGCANFD; namespace BDU.Views { @@ -57,7 +57,7 @@ namespace BDU.Views SignalName = DBCParse.MsgDatabase[通道][选中报文].signal_Name[选中信号], CatchID = Guid.NewGuid(), LogInterval = TimeSpan.FromMilliseconds(采集间隔), - MessageID = DBCParse.MsgDatabase[通道][选中报文].msg_id + MessageID =(int)DBCParse.MsgDatabase[通道][选中报文].msg_id }); } else diff --git a/BDU/Views/ToolBar.xaml.cs b/BDU/Views/ToolBar.xaml.cs index ebf29c6..b39fcaa 100644 --- a/BDU/Views/ToolBar.xaml.cs +++ b/BDU/Views/ToolBar.xaml.cs @@ -22,9 +22,10 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; -using TSMasterCAN; + using static BDU.Models.ParameterModel; using Path = System.IO.Path; +using ZLGCANFD; namespace BDU.Views { @@ -375,12 +376,12 @@ namespace BDU.Views private void ChannelMapping_Click(object sender, RoutedEventArgs e) { - var re = CAN.ShowChannelMappingWindow(true); - if (re != 0) - { - var msg = CAN.GetErrorDescription(re); - Log.Error($"同星通道映射界面打开失败:{msg}"); - } + //var re = CAN.ShowChannelMappingWindow(true); + //if (re != 0) + //{ + // var msg = CAN.GetErrorDescription(re); + // Log.Error($"同星通道映射界面打开失败:{msg}"); + //} } private void TestDataInfo_Click(object sender, RoutedEventArgs e) @@ -450,7 +451,7 @@ namespace BDU.Views var re = CAN.LoadDBC(openFileDialog.FileName, [0, 1, 2, 3], out var DataBaseID); if (re != 0) { - Log.Error("CAN数据库加载失败:" + CAN.GetErrorDescription(re)); + Log.Error("CAN数据库加载失败:");// + CAN.GetErrorDescription(re) } else { @@ -479,7 +480,7 @@ namespace BDU.Views } else { - var res = CAN.Connect(); + var res = CAN.Connect(ZLGCAN.ZCAN_USBCANFD_100U,new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG()); if (res == 0) { Log.Success($"CAN卡连接成功,返回值:{res}"); @@ -609,5 +610,7 @@ namespace BDU.Views { new DeviceManageWindow().Show(); } + + } } diff --git a/TOSUNCAN/TOSUNCAN.csproj b/TOSUNCAN/TOSUNCAN.csproj index 5e27efa..3a672d4 100644 --- a/TOSUNCAN/TOSUNCAN.csproj +++ b/TOSUNCAN/TOSUNCAN.csproj @@ -8,6 +8,10 @@ True + + + + diff --git a/ZLGCAN/Class1.cs b/ZLGCAN/Class1.cs new file mode 100644 index 0000000..e2a3294 --- /dev/null +++ b/ZLGCAN/Class1.cs @@ -0,0 +1,7 @@ +namespace ZLGCAN +{ + public class Class1 + { + + } +} diff --git a/ZLGCAN/ZLGCAN.csproj b/ZLGCAN/ZLGCAN.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/ZLGCAN/ZLGCAN.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/ZLGCANFD/CAN.cs b/ZLGCANFD/CAN.cs new file mode 100644 index 0000000..d0e2351 --- /dev/null +++ b/ZLGCANFD/CAN.cs @@ -0,0 +1,419 @@ +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 + } +} \ No newline at end of file diff --git a/ZLGCANFD/DBCParse.cs b/ZLGCANFD/DBCParse.cs new file mode 100644 index 0000000..3f91b17 --- /dev/null +++ b/ZLGCANFD/DBCParse.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace ZLGCANFD +{ + public class ZLG_Msg + { + public int msg_type { get; set; } + public uint msg_id { get; set; } + public double msg_cyclic { get; set; } + public byte msg_dlc { get; set; } + public string msg_name { get; set; } + public List signals { get; set; } = new List(); + public string[] signal_Name { get; set; } + + // 适配 ZLG 的 CANFD 帧结构 (来自 2.txt) + public CAN.ZCAN_CANFD_FRAME ACANFD; + } + + public class DBCParse + { + // 存储多通道的消息数据库 + public static List> MsgDatabase { get; set; } = + Enumerable.Range(0, 12).Select(_ => new List()).ToList(); + + /// + /// ZLG 专用解析逻辑:遍历 ZDBC 内部的消息链表并填充到 MsgDatabase + /// + /// ZDBC_Init 返回的句柄 + /// 目标通道索引 + public static void Parse(uint hDBC, int channel) + { + if (hDBC == ZDBC.INVALID_DBC_HANDLE) return; + + // 1. 初始化指针空间 + int msgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage)); + nint pMsg = Marshal.AllocHGlobal(msgSize); + + try + { + // 清空当前通道旧数据 + MsgDatabase[channel].Clear(); + + // 2. 迭代获取所有消息 + bool hasMessage = ZDBC.ZDBC_GetFirstMessage(hDBC, pMsg); + while (hasMessage) + { + ZDBC.DBCMessage dbMsg = Marshal.PtrToStructure(pMsg); + + ZLG_Msg temp = new ZLG_Msg(); + temp.msg_id = dbMsg.nID; + temp.msg_name = Encoding.Default.GetString(dbMsg.strName).TrimEnd('\0'); + temp.msg_dlc = (byte)dbMsg.nSize; + temp.msg_cyclic = dbMsg.nCycleTime; + temp.msg_type = dbMsg.nExtend; // 0-标准帧, 1-扩展帧 + + // 3. 处理信号 + int sigCount = (int)dbMsg.nSignalCount; + temp.signal_Name = new string[sigCount]; + for (int i = 0; i < sigCount; i++) + { + var sig = dbMsg.vSignals[i]; + temp.signals.Add(sig); + temp.signal_Name[i] = Encoding.Default.GetString(sig.strName).TrimEnd('\0'); + } + + // 4. 初始化对应的 ZLG 发送帧结构 (预设好 ID 和 DLC) + temp.ACANFD = new CAN.ZCAN_CANFD_FRAME(); + temp.ACANFD.can_id = dbMsg.nID; + temp.ACANFD.len = (byte)dbMsg.nSize; + temp.ACANFD.eff = dbMsg.nExtend; + temp.ACANFD.data = new byte[64]; + + MsgDatabase[channel].Add(temp); + + // 获取下一条 + hasMessage = ZDBC.ZDBC_GetNextMessage(hDBC, pMsg); + } + + // 按 ID 排序 + MsgDatabase[channel].Sort((a, b) => a.msg_id.CompareTo(b.msg_id)); + } + finally + { + // 释放内存 + Marshal.FreeHGlobal(pMsg); + } + } + + /// + /// 加载 DBC 的入口函数 + /// + public static int LoadDBC(string filePath, int[] channels, out uint databaseID) + { + // 初始化 + databaseID = ZDBC.ZDBC_Init(0, 1); + if (databaseID == ZDBC.INVALID_DBC_HANDLE) return -1; + + // 准备文件信息 + ZDBC.FileInfo fileInfo = new ZDBC.FileInfo(); + fileInfo.strFilePath = new byte[ZDBC._MAX_FILE_PATH_ + 1]; + byte[] pathBytes = Encoding.Default.GetBytes(filePath); + Array.Copy(pathBytes, fileInfo.strFilePath, Math.Min(pathBytes.Length, ZDBC._MAX_FILE_PATH_)); + fileInfo.type = ZDBC.PROTOCOL_OTHER; + 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) + { + ZDBC.ZDBC_Release(databaseID); + return -2; + } + + // 解析到各通道 + foreach (var ch in channels) + { + Parse(databaseID, ch); + } + + return 0; + } + + /// + /// 卸载 DBC 并释放 ZDBC 句柄 + /// + public static int UnLoadDBC(uint? databaseID = null) + { + if (databaseID.HasValue && databaseID.Value != ZDBC.INVALID_DBC_HANDLE) + { + ZDBC.ZDBC_Release(databaseID.Value); + } + + foreach (var list in MsgDatabase) + { + list.Clear(); + } + return 0; + } + } +} \ No newline at end of file diff --git a/ZLGCANFD/ZLGAPI.cs b/ZLGCANFD/ZLGAPI.cs new file mode 100644 index 0000000..71b8495 --- /dev/null +++ b/ZLGCANFD/ZLGAPI.cs @@ -0,0 +1,1236 @@ +// update time 2025/12/11 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Runtime.InteropServices; + +namespace ZLGCANFD +{ + + public class ZLGCAN + { + + #region 设备类型 + public static uint ZCAN_PCI9810 = 2; + public static uint ZCAN_USBCAN1 = 3; + public static uint ZCAN_USBCAN2 = 4; + public static uint ZCAN_PCI9820 = 5; + public static uint ZCAN_CANETUDP = 12; + public static uint ZCAN_PCI9840 = 14; + public static uint ZCAN_PCI9820I = 16; + public static uint ZCAN_CANETTCP = 17; + public static uint ZCAN_PCI5010U = 19; + public static uint ZCAN_USBCAN_E_U = 20; + public static uint ZCAN_USBCAN_2E_U = 21; + public static uint ZCAN_PCI5020U = 22; + public static uint ZCAN_PCIE9221 = 24; + public static uint ZCAN_WIFICAN_TCP = 25; + public static uint ZCAN_WIFICAN_UDP = 26; + public static uint ZCAN_PCIe9120 = 27; + public static uint ZCAN_PCIe9110 = 28; + public static uint ZCAN_PCIe9140 = 29; + public static uint ZCAN_USBCAN_4E_U = 31; + public static uint ZCAN_CANDTU_200UR = 32; + public static uint ZCAN_USBCAN_8E_U = 34; + public static uint ZCAN_CANDTU_NET = 36; + public static uint ZCAN_CANDTU_100UR = 37; + public static uint ZCAN_PCIE_CANFD_200U = 39; + public static uint ZCAN_PCIE_CANFD_400U = 40; + public static uint ZCAN_USBCANFD_200U = 41; + public static uint ZCAN_USBCANFD_100U = 42; + public static uint ZCAN_USBCANFD_MINI = 43; + public static uint ZCAN_CANSCOPE = 45; + public static uint ZCAN_CLOUD = 46; + public static uint ZCAN_CANDTU_NET_400 = 47; + public static uint ZCAN_CANFDNET_TCP = 48; + public static uint ZCAN_CANFDNET_200U_TCP = 48; + public static uint ZCAN_CANFDNET_UDP = 49; + public static uint ZCAN_CANFDNET_200U_UDP = 49; + public static uint ZCAN_CANFDWIFI_TCP = 50; + public static uint ZCAN_CANFDWIFI_100U_TCP = 50; + public static uint ZCAN_CANFDWIFI_UDP = 51; + public static uint ZCAN_CANFDWIFI_100U_UDP = 51; + public static uint ZCAN_CANFDNET_400U_TCP = 52; + public static uint ZCAN_CANFDNET_400U_UDP = 53; + public static uint ZCAN_CANFDNET_100U_TCP = 55; + public static uint ZCAN_CANFDNET_100U_UDP = 56; + public static uint ZCAN_CANFDNET_800U_TCP = 57; + public static uint ZCAN_CANFDNET_800U_UDP = 58; + public static uint ZCAN_USBCANFD_800U = 59; + public static uint ZCAN_PCIE_CANFD_100U_EX = 60; + public static uint ZCAN_PCIE_CANFD_400U_EX = 61; + public static uint ZCAN_PCIE_CANFD_200U_MINI = 62; + public static uint ZCAN_PCIE_CANFD_200U_EX = 63; + public static uint ZCAN_PCIE_CANFD_200U_M2 = 63; + public static uint ZCAN_CANFDDTU_400_TCP = 64; + public static uint ZCAN_CANFDDTU_400_UDP = 65; + public static uint ZCAN_CANFDWIFI_200U_TCP = 66; + public static uint ZCAN_CANFDWIFI_200U_UDP = 67; + public static uint ZCAN_CANFDDTU_800ER_TCP = 68; + public static uint ZCAN_CANFDDTU_800ER_UDP = 69; + public static uint ZCAN_CANFDDTU_800EWGR_TCP = 70; + public static uint ZCAN_CANFDDTU_800EWGR_UDP = 71; + public static uint ZCAN_CANFDDTU_600EWGR_TCP = 72; + public static uint ZCAN_CANFDDTU_600EWGR_UDP = 73; + public static uint ZCAN_CANFDDTU_CASCADE_TCP = 74; + public static uint ZCAN_CANFDDTU_CASCADE_UDP = 75; + public static uint ZCAN_USBCANFD_400U = 76; + public static uint ZCAN_CANFDDTU_200U = 77; + public static uint ZCAN_ZPSCANFD_TCP = 78; + public static uint ZCAN_ZPSCANFD_USB = 79; + public static uint ZCAN_CANFDBRIDGE_PLUS = 80; + public static uint ZCAN_CANFDDTU_300U = 81; + public static uint ZCAN_PCIE_CANFD_800U = 82; + public static uint ZCAN_PCIE_CANFD_1200U = 83; + public static uint ZCAN_MINI_PCIE_CANFD = 84; + public static uint ZCAN_USBCANFD_800H = 85; + #endregion + + #region LIN事件 + public static uint ZCAN_LIN_WAKE_UP = 1; + public static uint ZCAN_LIN_ENTERED_SLEEP_MODE = 2; + public static uint ZCAN_LIN_EXITED_SLEEP_MODE = 3; + #endregion + + #region 函数 + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern nint ZCAN_OpenDevice(uint device_type, uint device_index, uint reserved); + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern nint ZCAN_OpenDeviceByName(uint device_type, string name); + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_CloseDevice(nint device_handle); + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_IsDeviceOnLine(nint device_handle); + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_GetDeviceInf(nint device_handle, nint pInfo); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern nint ZCAN_InitCAN(nint device_handle, uint can_index, nint pInitConfig); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern nint ZCAN_InitCAN(nint device_handle, uint can_index, ref ZCAN_CHANNEL_INIT_CONFIG config); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_StartCAN(nint chn_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ResetCAN(nint chn_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ClearBuffer(nint chn_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ReadChannelErrInfo(nint chn_handle, ref ZCAN_CHANNEL_ERR_INFO pErrInfo); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_GetReceiveNum(nint channel_handle, byte type); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_Transmit(nint channel_handle, nint pTransmit, uint len); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_TransmitFD(nint channel_handle, nint pTransmit, uint len); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_TransmitData(nint device_handle, nint pTransmit, uint len); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_Receive(nint channel_handle, nint pReceive, uint len, int wait_time = -1); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ReceiveFD(nint channel_handle, nint pReceive, uint len, int wait_time = -1); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ReceiveData(nint device_handle, nint pReceive, uint len, int wait_time); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_SetValue(nint device_handle, string path, string value); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_SetValue(nint device_handle, string path, nint value); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_SetValue(nint device_handle, string path, ref ZCAN_AUTO_TRANSMIT_OBJ value); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_SetValue(nint device_handle, string path, ref ZCANFD_AUTO_TRANSMIT_OBJ value); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern nint ZCAN_GetValue(nint device_handle, string path); + + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern nint ZCAN_InitLIN(nint device_handle, uint lin_index, nint pLINInitConfig); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_StartLIN(nint channel_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ResetLIN(nint channel_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_TransmitLIN(nint channel_handle, nint pSend, uint Len); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_GetLINReceiveNum(nint channel_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_ReceiveLIN(nint channel_handle, nint pReceive, uint Len, int WaitTime); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_SetLINPublish(nint channel_handle, nint pSend, uint nPublishCount); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_SetLINSubscribe(nint channel_handle, nint pSend, uint nSubscribeCount); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_WakeUpLIN(nint channel_handle); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_UDS_Request(nint device_handle, nint req, nint resp, nint dataBuf, uint dataBufSize); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_UDS_Control(nint device_handle, nint ctrl, nint resp); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_UDS_RequestEX(nint device_handle, nint requestData, nint resp, nint dataBuf, uint dataBufSize); + + + [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZCAN_UDS_ControlEX(nint device_handle, uint dataType, nint ctrl, nint resp); + #endregion + + #region 结构体 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_DEVICE_INFO + { + public ushort hw_Version; + public ushort fw_Version; + public ushort dr_Version; + public ushort in_Version; + public ushort irq_Num; + public byte can_Num; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public char[] str_Serial_Num; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] + public char[] str_hw_Type; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_CHANNEL_INIT_CONFIG + { + public uint can_type; + public _ZCAN_CHANNEL_INIT_CONFIG config; + } + + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + public struct _ZCAN_CHANNEL_INIT_CONFIG + { + [FieldOffset(0)] + public _ZCAN_CHANNEL_CAN_INIT_CONFIG can; + [FieldOffset(0)] + public _ZCAN_CHANNEL_CANFD_INIT_CONFIG canfd; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct _ZCAN_CHANNEL_CAN_INIT_CONFIG + { + public uint acc_code; + public uint acc_mask; + public uint reserved; + public byte filter; + public byte timing0; + public byte timing1; + public byte mode; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct _ZCAN_CHANNEL_CANFD_INIT_CONFIG + { + public uint acc_code; + public uint acc_mask; + public uint abit_timing; + public uint dbit_timing; + public uint brp; + public byte filter; + public byte mode; + public ushort pad; + public uint reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_CHANNEL_ERR_INFO + { + public uint error_code; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] passive_ErrData; + public byte arLost_ErrData; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_Transmit_Data + { + public can_frame frame; + public uint transmit_type; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class can_frame + { + public uint can_id; + public byte can_dlc; // frame payload length in byte (0 .. CAN_MAX_DLEN) + public byte __pad; // padding + public byte __res0; // reserved / padding + public byte __res1; // reserved / padding + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] data; // frame data + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class canfd_frame + { + public uint can_id; + public byte len; + public byte flags; + public byte __res0; + public byte __res1; /* reserved / padding */ + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] data; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class ZCAN_Receive_Data + { + public can_frame frame; + public ulong timestamp; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class ZCAN_ReceiveFD_Data + { + public canfd_frame frame; + public ulong timestamp; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_AUTO_TRANSMIT_OBJ //CANFD定时发送帧结构体 + { + public ushort enable; //0-禁用,1-使能 + public ushort index; //定时报文索引 + public uint interval; //定时周期 + public ZCAN_Transmit_Data obj; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANFD_AUTO_TRANSMIT_OBJ //CANFD定时发送帧结构体 + { + public ushort enable; //0-禁用,1-使能 + public ushort index; //定时报文索引 + public uint interval; //定时周期 + public ZCAN_TransmitFD_Data obj; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_TransmitFD_Data + { + public canfd_frame frame; // 报文数据信息,详见 canfd_frame 结构说明。 + public uint transmit_type; // 发送方式,0=正常发送,1=单次发送,2=自发自收,3=单次自发自收。 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANCANFDData + { + public ulong timeStamp; + public uint flag; // flag用于设置一些参数,内部结构可以通过以下函数实现设置和取值 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] extraData; //未使用 + public canfd_frame frame; //实际报文结构体 + + // frameType 帧类型 0-CAN 1-CANFD + public uint frameType { + get { return flag & 0x03; } + set { flag = (uint)(flag & ~0x03 | value & 0x03); } + } + + // txDelay队列发送延时,延时时间存放在 timeStamp 字段;0-不启用延时,1-启用延时,单位1ms,2-启用延时,单位100us + public uint txDelay { + get { return flag >> 2 & 0x03; } + set { flag = (uint)(flag & ~0x0C | (value & 0x03) << 2); } + } + + public uint transmitType { + get { return flag >> 4 & 0x0F; } + set { flag = (uint)(flag & ~0x0F | (value & 0x0F) << 4); } + } + + public uint txEchoRequest { + get { return flag >> 8 & 0x01; } + set { flag = flag | (value & 0x01) << 8; } + } + + public uint txEchoed { + get { return flag >> 9 & 0x01; } // bit9 + set { flag = (uint)(flag & ~0x200 | (value & 0x01) << 9); } + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct PID + { + public byte rawVal; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct RxData + { + public ulong timeStamp; + public byte datalen; + public byte dir; + public byte chkSum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] + public byte[] reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] data; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANDataObj + { + public byte dataType; // 1-CAN/CANFD数据, 4-LIN数据 + public byte chnl; // 数据通道 + public ushort flag; // 未使用 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] extraData; // 未使用 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 92)] + public byte[] data; // 报文结构体 + } + + + // LIN + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANLINData + { + public PID pid; // 受保护的ID + public RxData rxData; // 数据 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] reserved; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANLINErrData + { + public ulong timeStamp; // 时间戳,单位微秒(us) + public PID pid; // 受保护的ID + + public byte dataLen; // 数据长度 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] data; // 数据 + + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] errData; // 错误信息 + + public byte dir; // 传输方向 + public byte chkSum; // 数据校验,部分设备不支持校验数据的获取 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] reserved; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANLINEventData + { + public ulong timeStamp; // 时间戳,单位微秒(us) + public byte type; // 数据长度 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] reserved; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_LIN_MSG + { + public byte chnl; // 数据通道 + public byte dataType; // 0-LIN,1-ErrLIN + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 46)] + public byte[] data; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_LIN_INIT_CONFIG + { + public byte linMode; // 0-slave,1-master + public byte chkSumMode; // 1-经典校验,2-增强校验 3-自动(对应eZLINChkSumMode的模式) + public byte maxLength; // 最大数据长度,8~64 + public byte reserved; + public uint libBaud; // 波特率,取值1000~20000 + + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_LIN_PUBLISH_CFG + { + public byte ID; // 受保护的ID(ID取值范围为0-63) + public byte datelen; // 范围1~8 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 数据段内容 + public byte[] data; + public byte chkSumMode; // 校验方式:0-默认,启动时配置 1-经典校验 2-增强校验(对应eZLINChkSumMode的模式) + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] reserved; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_LIN_SUBSCIBE_CFG + { + public byte ID; // 受保护的ID(ID取值范围为0-63) + public byte datelen; // dataLen范围为1-8 当为255(0xff)则表示设备自动识别报文长度 + public byte chkSumMode; // 校验方式:0-默认,启动时配置 1-经典校验 2-增强校验(对应eZLINChkSumMode的模式) + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] reserved; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SESSION_PARAM + { + public uint timeout; // 响应超时时间(ms)。因PC定时器误差,建议设置不小于200ms + public uint enhanced_timeout; // 收到消极响应错误码为0x78后的超时时间(ms)。因PC定时器误差,建议设置不小于200ms + public byte threeInOne; //三合一,把下面三个变量写进这一个变量 + + // threeInOne 包含以下三个变量 + // BYTE check_any_negative_response : 1; // 接收到非本次请求服务的消极响应时是否需要判定为响应错误 + // BYTE wait_if_suppress_response : 1; // 抑制响应时是否需要等待消极响应,等待时长为响应超时时间 + // BYTE flag : 6; // 保留 + public byte check_any_negative_response + { + get { return (byte)(threeInOne & 0x0001); } + set { threeInOne = (byte)(threeInOne & ~0x0001 | value & 0x0001); } + } + public byte wait_if_suppress_response + { + get { return (byte)((threeInOne & 0x0002) >> 1); } + set { threeInOne = (byte)(threeInOne & ~0x0002 | value & 0x0002); } + } + public byte flag + { + get { return (byte)((threeInOne & 0x00FC) >> 2); } + set { threeInOne = (byte)(threeInOne & ~0x00FC | value & 0x00FC); } + } + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] reserved0; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TRANS_PARAM + { + public byte version; // 传输协议版本,VERSION_0,VERSION_1 + public byte max_data_len; // 单帧最大数据长度,can:8,canfd:64 + public byte local_st_min; // 本程序发送流控时用,连续帧之间的最小间隔,0x00-0x7F(0ms~127ms),0xF1-0xF9(100us~900us) + public byte block_size; // 流控帧的块大小 + public byte fill_byte; // 无效字节的填充数据 + public byte ext_frame; // 0:标准帧 1:扩展帧 + public byte is_modify_ecu_st_min; // 是否忽略ECU 返回流控的STmin,强制使用本程序设置的remote_st_min 参数代替 + public byte remote_st_min; // 发送多帧时用, is_modify_ecu_st_min = 1 时有效,0x00 - 0x7F(0ms~127ms), 0xF1 - 0xF9(100us~900us) + public uint fc_timeout; // 接收流控超时时间(ms),如发送首帧后需要等待回应流控帧 + public byte fill_mode; // 数据长度填充模式 0-就近填充 1-不填充 2-最大填充 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] reserved0; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TRANS_PARAM_LIN + { + public byte fill_byte; // 无效字节的填充数据 + public byte st_min; // 从节点准备接收诊断请求的下一帧或传输诊断响应的下一帧所需的最小时间 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] reserved0; + }; + + + // CAN UDS请求数据 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_UDS_REQUEST // 硬件UDS接口构体 + { + public uint req_id; // 请求事务索引ID,范围0~65535 + public byte channel; // 设备通道索引 + public byte frame_type; // 帧类型 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] reserved0; + public uint src_addr; // 请求地址 + public uint dst_addr; // 响应地址 + public byte suppress_response; // 1-抑制响应 + public byte sid; // 请求服务id + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] reserved1; + + public SESSION_PARAM session_param; + public TRANS_PARAM trans_param; + public nint data; // 数据数组(不包含SID) + public uint data_len; // 数据数组的长度 + public uint reserved2; + } + + + // LIN UDS请求数据 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZLIN_UDS_REQUEST // 硬件UDS接口构体 + { + public uint req_id; // 请求事务索引ID,范围0~65535 + public byte channel; // 设备通道索引 + public byte suppress_response; // 1:抑制响应 0:不抑制 + public byte sid; // 请求服务id + public byte Nad; // 节点地址 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] reserved1; + + + public SESSION_PARAM session_param; + public TRANS_PARAM_LIN trans_param; + public nint data; // 数据数组(不包含SID) + public uint data_len; // 数据数组的长度 + public uint reserved2; + } + + + // UDS响应数据 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_UDS_RESPONSE + { + public byte status; // 响应状态 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] reserved; + public byte type; // 响应类型 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 大小为8 + public byte[] raw; + }; + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UDS_RESPONSE_Positive + { + public byte sid; // 响应服务id + public uint data_len; // 数据长度(不包含SID), 数据存放在接口传入的dataBuf中 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UDS_RESPONSE_Negative + { + public byte neg_code; // 固定为0x7F + public byte sid; // 请求服务id + public byte error_code; // 错误码 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UDS_RESPONSE_raw + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 大小为8 + public byte[] raw; + } + + + [StructLayout(LayoutKind.Explicit)] + public struct _UDS_RESPONSE_union + { + [FieldOffset(0)] + public UDS_RESPONSE_Positive zudsPositive; + + [FieldOffset(0)] + public UDS_RESPONSE_Negative zudsNegative; + + [FieldOffset(0)] + public UDS_RESPONSE_raw raw; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANCANFDUdsData + { + public nint req; // 请求信息 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] + public byte[] reserved; // 保留位 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANLINUdsData + { + public nint req; // 请求信息 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] + public byte[] reserved; // 保留位 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCANUdsRequestDataObj + { + public uint dataType; // 数据类型 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)] + public byte[] data; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] reserved; // 保留位 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZCAN_DYNAMIC_CONFIG_DATA + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public char[] key; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public char[] value; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BusUsage + { + public ulong nTimeStampBegin; // 测量起始时间戳,单位us + public ulong nTimeStampEnd; // 测量结束时间戳,单位us + public byte nChnl; // 通道 + public byte nReserved; // 保留 + public ushort nBusUsage; // 总线利用率(%),总线利用率*100展示。取值0~10000,如8050表示80.50% + public uint nFrameCount; // 帧数量 + } + #endregion + } + + + public class ZDBC + { + #region 常量定义 + public const int _MAX_FILE_PATH_ = 260; // 最长文件路径 + public const int _DBC_NAME_LENGTH_ = 127; // 名称最长长度 + public const int _DBC_COMMENT_MAX_LENGTH_ = 127; // 注释最长长度 + public const int _DBC_UNIT_MAX_LENGTH_ = 23; // 单位最长长度 + public const int _DBC_SIGNAL_MAX_COUNT_ = 256; // 一个消息含有的信号的最大数目 + + public const int MUTIPLEXER_NONE = 0; // 不使用复用器 + public const int MUTIPLEXER_M_VALUE = 1; // 复用信号,当复用器开关的值为multiplexer_value时,该信号有效 + public const int MUTIPLEXER_M_SWITCH = 2; // 复用器开关,一个DBC消息只能有一个信号为开关 + + public const int FT_CAN = 0; // CAN + public const int FT_CANFD = 1; // CANFD + + public const int PROTOCOL_J1939 = 0; + public const int PROTOCOL_OTHER = 1; + public const uint INVALID_DBC_HANDLE = 0xffffffff; // 无效的DBC句柄 + #endregion + + #region 函数部分 + + // ZDBC.dll + public delegate bool OnSend(nint ctx, nint pObj); + public delegate void OnMultiTransDone(nint ctx, nint pMsg, nint data, ushort nLen, byte nDirection); + public static OnSend onSend; + public static OnMultiTransDone onMultiTransDone; + + /// + /// 此函数用于初始化解析模块,只需要初始化一次。 + /// + /// 是否关闭多帧发送,为 1 时不支持多帧的消息发送。 + /// 是否开启异步解析;0-不启动,ZDBC_AsyncAnalyse 接口无效;1-启动, 独立线程解析出消息。 + /// 为 INVALID_DBC_HANDLE 表示初始化失败,其他表示初始化成功,保存该返回值,之后的函数调用都要用到该句柄。 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZDBC_Init(byte disableMultiSend = 0, byte enableAsyncAnalyse = 1); + + /// + /// 释放资源, 与DBC_Init配对使用 + /// + /// hDBC-句柄, ZDBC_Init的返回值 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZDBC_Release(uint DBCHandle); + + /// + /// 此函数用以加载 DBC 格式文件。 + /// + /// 句柄;ZDBC_Init的返回值 + /// 结构体 FileInfo的指针 + /// 为 true 表示加载成功,false 表示失败。 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_LoadFile(uint DBCHandle, nint pFileInfo); + + /// + /// 从字符串加载DBC + /// + /// hDBC-句柄, DBC_Load的返回值 + /// pFileContent-文件内容字符串 + /// merge-是否合并到当前数据库; 1:不清除现有的数据, 即支持加载多个文件;0:清除原来的数据 + /// + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_LoadContent(uint DBCHandle, nint pFileContent, uint merge); + + /// + /// 获取文件的第一条消息。 + /// + /// hDBC-句柄, DBC_Load的返回值 + /// pMsg 存储消息的信息 + /// true表示成功 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_GetFirstMessage(uint DBCHandle, nint pMsg); + + /// + /// 获取下一条消息。 + /// + /// hDBC-句柄, DBC_Load的返回值 + /// pMsg 存储消息的信息 + /// true表示成功 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_GetNextMessage(uint DBCHandle, nint pMsg); + + /// + /// 此函数用以根据 ID 获取消息数据。 + /// + /// 句柄; + /// 帧 ID; + /// 消息信息结构体 + /// + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_GetMessageById(uint DBCHandle, uint nID, nint pMsg); + + /// + /// 此函数用以获取 DBC 文件中含有的消息数目。 + /// + /// DBC句柄 + /// DBC 文件中含有的消息数目 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZDBC_GetMessageCount(uint DBCHandle); + + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_Analyse(uint DBCHandle, nint pObj, nint pMsg); + + + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_AsyncAnalyse(uint DBCHandle, nint pObj, uint frame_type, ulong extraData); + + + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZDBC_OnReceive(uint DBCHandle, nint pObj, uint frame_type); + + + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZDBC_SetSender(uint hDBC, OnSend sender, nint ctx); + + + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZDBC_SetOnMultiTransDoneFunc(uint hDBC, OnMultiTransDone func, nint ctx); + + + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern byte ZDBC_Send(uint hDBC, nint pMsg); + + /// + /// 根据原始数据解码为 DBCMessage。 + /// + /// DBC句柄 + /// 输出参数,解析结果。 + /// 帧数据数组, ControlCAN 传入 VCI_CAN_OBJ, zlgcan 传入 can_frame。 + /// 原始帧数据个数, 即数组大小。 + /// frame_type 帧类型, 参考FT_CAN=0、FT_CANFD=1,ControlCAN不支持CANFD。 + /// 是否成功。 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_Decode(uint DBCHandle, nint P2DBCMessage, nint P2Obj, uint nCount, byte frame_type); + + /// + /// 根据 DBCMessage 编码为原始数据。 + /// + /// DBC句柄; + /// 编码的原始数据缓冲区数组, ControlCAN 传入 VCI_CAN_OBJ, zlgcan 传入 can_frame。 + /// 输出参数,pObj 缓冲区大小, 返回时为实际原始数据个数。 + /// 输入参数,DBC 消息。 + /// frame_type 帧类型, FT_CAN=0、FT_CANFD=1,ControlCAN不支持CANFD。 + /// 是否成功。 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_Encode(uint DBCHandle, nint P2Obj, nint P2nCount, nint pMsg, byte frame_type); + + /// + /// 信号原始值转换为实际值 + /// + /// sgl 信号 + /// rawVal 原始值, 如果该值超出信号长度可表示范围,会被截断。 + /// 实际值 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern double ZDBC_CalcActualValue(nint sgl, nint rawVal); //原始值通过计算转为实际值,实际值会传入rawVal的地址 + + /// + /// 信号实际值转换为原始值 + /// + /// sgl 信号 + /// actualVal 实际值, 超出可表示范围时会被修正 + /// 原始值 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern ulong ZDBC_CalcRawValue(nint sgl, nint actualVal); + + /// + /// 获取网络节点数量 + /// + /// ZDBC_Init的返回值 + /// 网络节点总数量 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZDBC_GetNetworkNodeCount(uint DBCHandle); + + /// + /// + /// + /// ZDBC_Init的返回值 + /// index 位置索引 + /// DBCNetworkNode * node 网络节点信息 + /// + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool ZDBC_GetNetworkNodeAt(uint DBCHandle, uint index, nint node); + + + /// + /// 获取具体信号的值与含义对个数 + /// + /// ZDBC_Init的返回值 + /// message的ID + /// signal的名字 + /// + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZDBC_GetValDescPairCount(uint DBCHandle, uint mag_id, string signal_name); + + + /// + /// 获取具体信号的值与含义对 + /// + /// ZDBC_Init的返回值 + /// message的ID + /// signal的名字 + /// ValDescPair结构体类型 + [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZDBC_GetValDescPair(uint DBCHandle, uint mag_id, string signal_name, nint pair); + + + #endregion + + #region DBC 结构体部分 + + public struct FileInfo + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _MAX_FILE_PATH_ + 1)] + public byte[] strFilePath; // dbc文件路径 + public byte type; // dbc的协议类型, j1939选择PROTOCOL_J1939, 其他协议选择PROTOCOL_OTHER + public byte merge; // 1:不清除现有的数据, 即支持加载多个文件 0:清除原来的数据 + }; + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct DBCSignal + { + + public uint nStartBit; // 起始位 + public uint nLen; // 位长度 + public double nFactor; // 转换因子 + public double nOffset; // 转换偏移实际值=原始值*nFactor+nOffset + public double nMin; // 最小值 + public double nMax; // 最大值 + public ulong nRawvalue; // 原始值 + public byte is_signed; // 1:有符号数据, 0:无符号 + public byte is_motorola; // 是否摩托罗拉格式 + public byte multiplexer_type; // 复用器类型 + public byte val_type; // 0:integer, 1:float, 2:double + public uint multiplexer_value; // 复用器开关值为此值时信号有效 + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_UNIT_MAX_LENGTH_ + 1)] + public byte[] unit; //单位 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)] + public byte[] strName; //名称 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_COMMENT_MAX_LENGTH_ + 1)] + public byte[] strComment; //注释 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)] + public byte[] strValDesc; //值描述 + + public double initialValue; // 初始化值(原始值) + public uint initialValueValid; // 初始值是否有效 + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct DBCMessage + { + public uint nSignalCount; // 信号数量 + public uint nID; // ID + public uint nSize; // 消息占的字节数目 + public double nCycleTime; // 发送周期 + public byte nExtend; // 1:扩展帧, 0:标准帧 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_SIGNAL_MAX_COUNT_)] + public DBCSignal[] vSignals; // 信号集合 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)] + public byte[] strName; // 名称 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_COMMENT_MAX_LENGTH_ + 1)] + public byte[] strComment; // 注释 + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct ValDescPair + { + public double value; // 信号值 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)] + public byte[] strName; // 对应的值描述 + } + #endregion + } + + + public class ZUDS + { + #region 参数定义 + + public static uint udsRTR = 0x40000000; // Remote Transmission Request + public static uint udsEFF = 0x80000000; // Extend Frame Flag + public static uint udsERR = 0x20000000; // Err flag + + #endregion + + #region 函数部分 + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + public delegate uint OnUDSTransmitDelegate(nint ctx, nint frame, uint count); + + + /// + /// 该函数用于初始化 UDS 函数库,返回操作句柄,用于后续的操作,与 ZUDS_Release + /// 配对使用。 + /// typedef uint32 TP_TYPE; // transport protocol + /// #define DoCAN 0 + /// + /// + /// 操作句柄,= ZUDS_INVALID_HANDLE 为无效句柄,其他值为有效句柄。 + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern uint ZUDS_Init(uint type); + + + /// + /// 该函数用于释放资源,与 ZUDS_Init 配对使用。 + /// + /// + /// + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_Release(uint type); + + + /// + /// 该函数用于设置函数库的参数。 + /// + /// + /// 参数类型,= PARAM_TYPE_SESSION 0 用 于 设 置 会 话 层 参 数 , = + ///PARAM_TYPE_ISO15765 1 用于设置 ISO15765 的通信参数; + /// 参数值,type =PARAM_TYPE_SESSION 0 时为 ZUDS_SESSION_PARAM, + ///type= PARAM_TYPE_ISO15765 1 时为 ZUDS_ISO15765_PARAM。 + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_SetParam(uint ZUDS_HANDLE, byte type, nint param); + + + /// + /// 该函数用于设置发送回调函数。函数库自身并不发送帧数据,把打包的帧数据通过回调 + ///函数传出给用户发送,用户可通过 zlgcan 函数库进行帧数据发送。 + /// + /// + /// ctx 上下文参数, 在回调函数中传出, 库内部不会处理该参数; + /// :回调函数原型;typedef uint32 (*OnUDSTransmit)(void* ctx, const ZUDS_FRAME* frame, uint32 count); + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_SetTransmitHandler(uint ZUDS_HANDLE, nint ctx, OnUDSTransmitDelegate onUDSTransmit); + + + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_OnReceive(uint ZUDS_HANDLE, nint ZUDS_FRAME); + + + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_Request(uint ZUDS_HANDLE, nint ZUDS_REQUEST, nint ZUDS_RESPONSE); + + + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_Stop(uint ZUDS_HANDLE); + + + [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)] + public static extern void ZUDS_SetTesterPresent(uint ZUDS_HANDLE, byte enable, nint param); + + #endregion + + #region 结构体部分 + /// + /// 会话层面参数;即一应一答传输时的通讯参数。 + /// + public struct ZUDS_SESSION_PARAM + { + public ushort timeout;// ms, timeout to wait the response of the server + public ushort enhanced_timeout; // ms,timeout to wait after negative response: error code 0x78 + public uint reserved0; // 保留 + public uint reserved1; // 保留 + } + + + /// + /// 传输数据部分的参数,例如传输时侯每帧报文的字节数。 + /// + public struct ZUDS_ISO15765_PARAM + { + public byte version; // VERSION_0, VERSION_1格式版本,为 VERSION_0 时符合 ISO15765-2 的 2004 版本格式要求;为 + //hVERSION_1 是符合 ISO15765-2 的 2016 版本新增的格式要求,如下图所示 + public byte max_data_len; // max data length, can:8, canfd:64 + public byte local_st_min; // ms, min time between two consecutive frames + public byte block_size; + public byte fill_byte; // fill to invalid byte + public byte frame_type; // 0:std 1:ext + public byte is_modify_ecu_st_min; //是否忽略 ECU 返回流控的 STmin,强制使用本程序设置的 + //remote_st_min 参数代替 + + public byte remote_st_min; //发 送 多 帧 时 用, is_ignore_ecu_st_min = 1 时 有 效 , + //0x00-0x7F(0ms ~127ms), 0xF1-0xF9(100us ~900us) + public ushort fc_timeout; //接收流控超时时间(ms), 如发送首帧后需要等待回应流控帧。 + public byte fill_mode;//字节填充模式。FILL_MODE_NONE-不填充0;FILL_MODE_SHORT- 小于 8 字节填充至 8 字节,大于 8 字节时按 DLC 就近填充1;FILL_MODE_MAX- 始终填充至最大数据长度 (不建议)2。 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] reserved; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZUDS_TESTER_PRESENT_PARAM + { + public uint addr;//会话保持的请求地址; + public ushort cycle;//发送周期,单位毫秒; + public byte suppress_response; // 1:suppress是否抑制响应,建议设置为 1; + public uint reserved;//:保留,忽略即可。 + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZUDS_REQUEST + { + public uint src_addr; // 请求地址 + public uint dst_addr; // 响应地址 + public byte suppress_response; // 1:抑制响应 + public byte sid; //service id of request + public ushort reserve0; + public nint param; //array,params of the service + public uint param_len; //参数数组的长度 + public uint reserved; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class ZUDS_RESPONSE + { + public byte status; + public byte type; // RT_POSITIVE, RT_NEGATIVE + public _ZUDS_Union union; + public uint reserved; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ZUDS_positive + { + public byte sid; // service id of response + public nint param; // array, params of the service, don't free + public uint param_len; + + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct _ZUDS_negative + { + public byte neg_code; // 0x7F + public byte sid; //service id of response + public byte error_code;//消极响应的错误码 + + } + + + [StructLayout(LayoutKind.Explicit)] + public struct _ZUDS_Union + { + [FieldOffset(0)] + public ZUDS_positive zudsPositive; + + [FieldOffset(0)] + public _ZUDS_negative zudsNegative; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class ZUDS_FRAME + { + public uint id; + public byte extend; + public byte remote; + public byte data_len; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] data; + public uint reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class ZUDS_CTX + { + public nint can_type; // 0-CAN 1-CANFD 2-CANFD加速 + public nint chn_handle; // 通道句柄 + } + #endregion + } +} diff --git a/ZLGCANFD/ZLGCANFD.csproj b/ZLGCANFD/ZLGCANFD.csproj new file mode 100644 index 0000000..98d3004 --- /dev/null +++ b/ZLGCANFD/ZLGCANFD.csproj @@ -0,0 +1,19 @@ + + + + Library + net8.0-windows + enable + enable + true + + + + + + + + Always + + +