/* * 241217 程序默认用USBCANFD-200U通讯,两通道对侧 * Main 有加载DBC文件,打印DBC文件信息 * 打开设备并演示Encode Decode函数 */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Threading; using System.IO; using ZLGAPI; namespace DBC { internal class Program { private static IntPtr deviceHandle = IntPtr.Zero; // 设备句柄 private static IntPtr[] channelHandles = new IntPtr[]{ IntPtr.Zero, IntPtr.Zero }; private static int max_chn = 2; // 通道数量 private static uint DBCHandle = 0; // DBC句柄 private static volatile bool isRunning = true; // 线程标志 static void Main(string[] args) { Program.LoadDBCFile(); // 加载DBC文件 Program.ReadDBCFileMessages(); // 打印DBC文件信息 //Program.ReadSignalDescPair(); // 获取具体信号的值与含义 //Program.InitDevice(); // 打开设备,并演示接收解析和发送 Console.ReadKey(); Program.CloseDBCFile(); } // 加载DBC文件 static void LoadDBCFile() { // DBC文件路径 string DBCFilePath = "C:\\Users\\admin\\Desktop\\DBC\\12.dbc"; //string currentDirectory = AppDomain.CurrentDomain.BaseDirectory; // 获取当前执行文件exe同级目录 //string fileName = "12.DBC"; // 替换为你的文件名 //string filePath = Path.Combine(currentDirectory, fileName); //DBCFilePath = filePath.Replace("\\", "\\\\"); // 将路径中的分隔符替换为双反斜杠 Console.WriteLine("{0} ", DBCFilePath); // 加载DBC文件 Program.DBCHandle = ZDBC.ZDBC_Init(); IntPtr P2DBCFileAddress = Marshal.StringToHGlobalAnsi(DBCFilePath); bool Result = ZDBC.ZDBC_LoadFile(DBCHandle, P2DBCFileAddress); Marshal.FreeHGlobal(P2DBCFileAddress); } // 关闭DBC文件 static void CloseDBCFile() { ZDBC.ZDBC_Release(Program.DBCHandle); } // 读取DBC文件内容 static void ReadDBCFileMessages() { uint count = ZDBC.ZDBC_GetMessageCount(Program.DBCHandle); //信号数量 Console.WriteLine(" DBC文件中消息的数量:{0}\n", count); ZDBC.DBCMessage msg = new ZDBC.DBCMessage(); IntPtr ptrMsg = Marshal.AllocHGlobal(Marshal.SizeOf(msg)); if (ZDBC.ZDBC_GetFirstMessage(DBCHandle, ptrMsg)) { Program.PrintfDBCMessage(ptrMsg); } while (ZDBC.ZDBC_GetNextMessage(DBCHandle, ptrMsg)) { Program.PrintfDBCMessage(ptrMsg); } Marshal.FreeHGlobal(ptrMsg); } // 打印值描述 static void ReadSignalDescPair() { ZDBC.DBCMessage msg = new ZDBC.DBCMessage(); IntPtr ptrMsg = Marshal.AllocHGlobal(Marshal.SizeOf(msg)); uint ID = 0x36F; string SignalName = "BMS_AbnormRlyOffSt"; // 获取这个id的消息情况 if (ZDBC.ZDBC_GetMessageById(Program.DBCHandle, ID, ptrMsg)) { Program.PrintfDBCMessage(ptrMsg); } else { Console.WriteLine("没有找到这个0x{0:x}的定义", ID); } // 获取具体信号的值与含义对个数 uint ret = ZDBC.ZDBC_GetValDescPairCount(Program.DBCHandle, ID, SignalName); Console.WriteLine("{0} 的值与含义对个数: {1}\n", SignalName, ret); // 循环获取值与含义对 IntPtr ptr_pair = Marshal.AllocHGlobal((int)ret * Marshal.SizeOf(typeof(ZDBC.ValDescPair))); ZDBC.ZDBC_GetValDescPair(Program.DBCHandle, ID, SignalName, ptr_pair); ZDBC.ValDescPair[] pair = new ZDBC.ValDescPair[ret]; for (int i = 0; i < ret; i++) { pair[i] = (ZDBC.ValDescPair)Marshal.PtrToStructure((IntPtr)((Int64)ptr_pair + i * Marshal.SizeOf(typeof(ZDBC.ValDescPair))), typeof(ZDBC.ValDescPair)); string pair_name = new string(Encoding.ASCII.GetChars(pair[i].strName)); string result = pair_name.Substring(0, pair_name.IndexOf('\0')); Console.WriteLine("[{0}] {1} {2}", i + 1, result, pair[i].value); } Console.ReadKey(); } // 打印消息 static void PrintfDBCMessage(IntPtr ptrMsg) { // 消息 ZDBC.DBCMessage msg = new ZDBC.DBCMessage(); msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrMsg, typeof(ZDBC.DBCMessage)); string str_name = new string(Encoding.ASCII.GetChars(msg.strName)); string result = str_name.Substring(0, str_name.IndexOf('\0')); Console.WriteLine("0x{0:X} {1}", msg.nID, result); // 信号 Console.WriteLine("\t{0,-27} {1,-4} {2,-5} {3,-5}", "信号名", "起始位", "长度", "原始值"); for (int i = 0; i < msg.nSignalCount; i++) { ZDBC.DBCSignal curSig = msg.vSignals[i]; str_name = new string(Encoding.ASCII.GetChars(curSig.strName)); result = str_name.Substring(0, str_name.IndexOf('\0')); Console.WriteLine("\t{0,-30} {1,-7} {2,-5} {3,-8:X}", result, msg.vSignals[i].nStartBit, msg.vSignals[i].nLen, msg.vSignals[i].nRawvalue); } Console.WriteLine(""); } // 初始化设备 static void InitDevice() { //int chn_idx = 0; // 通道号 uint ret; // 返回值 //打开设备 Program.deviceHandle = ZLGCAN.ZCAN_OpenDevice(41, 0, 0); // USBCANFD-200U 41 if (Program.deviceHandle == IntPtr.Zero) { Console.WriteLine("打开设备失败"); Console.ReadKey(); return; } else Console.WriteLine("打开设备成功"); // 初始化通道 for (int i = 0; i < Program.max_chn; i++) { // 仲裁域波特率 string path = String.Format("{0}/canfd_abit_baud_rate", i); ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, "500000"); // 500k if (ret != 1) { Console.WriteLine("设置仲裁域波特率失败"); Console.ReadKey(); return; } // 数据域波特率 path = String.Format("{0}/canfd_dbit_baud_rate", i); ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, "2000000"); // 2M if (ret != 1) { Console.WriteLine("设置数据域波特率失败"); Console.ReadKey(); return; } // 终端电阻 path = String.Format("{0}/initenal_resistance", i); string resistance = "1";//1-使能 0-禁能 ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, resistance); if (ret != 1) { Console.WriteLine("设置终端电阻失败"); Console.ReadKey(); return; } // 初始化通道 ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG InitConfig = new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG(); // 结构体 InitConfig.can_type = 1; // 1 - CANFD (USBCANFD 只能选择CANFD模式) InitConfig.config.canfd.mode = 0; // 0 - 正常模式,1 - 只听模式 IntPtr P2InitConfig = Marshal.AllocHGlobal(Marshal.SizeOf(InitConfig)); Marshal.StructureToPtr(InitConfig, P2InitConfig, true); // 转成指针 Program.channelHandles[i] = ZLGCAN.ZCAN_InitCAN(deviceHandle, (uint)i, P2InitConfig); Marshal.FreeHGlobal(P2InitConfig); // 释放内存 if (Program.channelHandles[i] == IntPtr.Zero) { Console.WriteLine("初始化通道失败"); Console.ReadKey(); return; } Console.WriteLine("初始化通道成功"); //打开通道 ret = ZLGCAN.ZCAN_StartCAN(Program.channelHandles[i]); if (ret != 1) { Console.WriteLine("打开通道失败"); Console.ReadKey(); return; } Console.WriteLine("打开通道成功"); // 创建一个接收线程 Thread workerThread = new Thread(ReceiveThread); workerThread.IsBackground = true; // 设置为后台线程 workerThread.Start(Program.channelHandles[i]); // 启动线程 } Thread.Sleep(1000); // DBC发送 //Program.SendDBCMessageById(0x15D); // 阻塞等待 Console.ReadKey(); Program.isRunning = false; for (int i = 0; i < max_chn; i++) { // 关闭通道 ret = ZLGCAN.ZCAN_ResetCAN(Program.channelHandles[i]); if (ret != 1) { Console.WriteLine("关闭通道失败"); Console.ReadKey(); return; } Console.WriteLine("关闭通道成功"); } // 关闭设备 ret = ZLGCAN.ZCAN_CloseDevice(Program.deviceHandle); if (ret != 1) { Console.WriteLine("关闭设备失败"); Console.ReadKey(); return; } Console.WriteLine("关闭设备成功"); } // 接收线程 (有DBC解析) static void ReceiveThread(object state) { IntPtr cur_chn = (IntPtr)state; const int arraySize = 100; IntPtr ptrCanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data)) * arraySize); IntPtr ptrCanFDData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data)) * arraySize); IntPtr ptrMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage))); byte[] zero = new byte[Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data)) * arraySize]; while (Program.isRunning) { uint RecNum = ZLGCAN.ZCAN_GetReceiveNum(cur_chn, 0); //CAN if (RecNum != 0) { // Marshal.Copy(zero, 0, ptrCanData, zero.Length); // 赋0 uint ReceiveNum = ZLGCAN.ZCAN_Receive(cur_chn, ptrCanData, arraySize, 10); // 接收报文 for (int i = 0; i < ReceiveNum; i++) { IntPtr curPtr = IntPtr.Add(ptrCanData, i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data))); ZLGCAN.ZCAN_Receive_Data data = (ZLGCAN.ZCAN_Receive_Data)Marshal.PtrToStructure(curPtr, typeof(ZLGCAN.ZCAN_Receive_Data)); // DBC解析 if (true == ZDBC.ZDBC_Decode(Program.DBCHandle, ptrMsg, curPtr, 1, 0)) Program.PrintfDBCMessage(ptrMsg); // 打印解析 } } RecNum = ZLGCAN.ZCAN_GetReceiveNum(cur_chn, 1); // CANFD if (RecNum != 0) { // Marshal.Copy(zero, 0, ptrCanData, zero.Length); // 赋0 uint ReceiveNum = ZLGCAN.ZCAN_ReceiveFD(cur_chn, ptrCanFDData, arraySize, 10); // 接收报文 for (int i = 0; i < ReceiveNum; i++) { IntPtr curPtr = IntPtr.Add(ptrCanFDData, i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data))); ZLGCAN.ZCAN_ReceiveFD_Data data = (ZLGCAN.ZCAN_ReceiveFD_Data)Marshal.PtrToStructure(curPtr, typeof(ZLGCAN.ZCAN_ReceiveFD_Data)); // DBC解析 if (true == ZDBC.ZDBC_Decode(Program.DBCHandle, ptrMsg, curPtr, 1, 1)) { Program.PrintfDBCMessage(ptrMsg); // 打印解析 } } } } Marshal.FreeHGlobal(ptrMsg); Marshal.FreeHGlobal(ptrCanData); } // DBC发送 static void SendDBCMessageById(uint id) { // 从DBC文件获取对应ID的 DBC结构体 IntPtr ptrMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage))); if (ZDBC.ZDBC_GetMessageById(Program.DBCHandle, id, ptrMsg) == false) // 找不到对应id退出 { Marshal.FreeHGlobal(ptrMsg); return; } ZDBC.DBCMessage msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrMsg, typeof(ZDBC.DBCMessage)); //通过 ZDBC_CalcRawValue 设置信号值(这里是根据实际的DBC信号设置的值,作为示例,设置该消息的第5个信号) /* double actualVal = 12; // 物理值 IntPtr signalPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal))); IntPtr actualValPtr = Marshal.AllocHGlobal(sizeof(double)); Marshal.StructureToPtr(msg.vSignals[5], signalPtr, true); Marshal.StructureToPtr(actualVal, actualValPtr, true); //计算原始值 ulong rawValue = ZDBC.ZDBC_CalcRawValue(signalPtr, actualValPtr); // 超出可信号值范围时会被修正 msg.vSignals[5].nRawvalue = rawValue; Marshal.StructureToPtr(msg, ptrMsg, true); */ uint count = 1; // 初始化一个值 IntPtr ptrCount = Marshal.AllocHGlobal(sizeof(uint)); // 分配内存 Marshal.WriteInt32(ptrCount, (int)count); // 写入值 //CAN 根据消息类型选择can还是canfd //Encode DBC_frame -> can_frame IntPtr ptrCanFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.can_frame))); if (ZDBC.ZDBC_Encode(Program.DBCHandle, ptrCanFrame, ptrCount, ptrMsg, (int)0) == false) // Encode { Marshal.FreeHGlobal(ptrMsg); Marshal.FreeHGlobal(ptrCount); Marshal.FreeHGlobal(ptrCanFrame); return; } // 构造发送结构体 ZLGCAN.can_frame can_f = (ZLGCAN.can_frame)Marshal.PtrToStructure(ptrCanFrame, typeof(ZLGCAN.can_frame)); ZLGCAN.ZCAN_Transmit_Data tran_data = new ZLGCAN.ZCAN_Transmit_Data(); tran_data.frame = can_f; // 转换成 ZCAN_Transmit_Data,并发送 IntPtr ptrTransmit = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data))); Marshal.StructureToPtr(tran_data, ptrTransmit, true); if (count != ZLGCAN.ZCAN_Transmit(Program.channelHandles[0], ptrTransmit, count)) { Console.WriteLine("发送CAN失败"); } // CANFD // Encode DBC_frame -> canfd_frame IntPtr ptrCanFDFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.canfd_frame))); if (ZDBC.ZDBC_Encode(Program.DBCHandle, ptrCanFDFrame, ptrCount, ptrMsg, (int)1) == false) // Encode { Marshal.FreeHGlobal(ptrMsg); Marshal.FreeHGlobal(ptrCount); Marshal.FreeHGlobal(ptrCanFDFrame); return; } // 构造发送结构体 ZLGCAN.canfd_frame canfd_f = (ZLGCAN.canfd_frame)Marshal.PtrToStructure(ptrCanFDFrame, typeof(ZLGCAN.canfd_frame)); ZLGCAN.ZCAN_TransmitFD_Data tranfd_data = new ZLGCAN.ZCAN_TransmitFD_Data(); tranfd_data.frame = canfd_f; // 转换成 ZCAN_Transmit_Data,并发送 IntPtr ptrTransmitFD = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_TransmitFD_Data))); Marshal.StructureToPtr(tranfd_data, ptrTransmitFD, true); if (count != ZLGCAN.ZCAN_TransmitFD(Program.channelHandles[0], ptrTransmitFD, count)) { Console.WriteLine("发送CANFD失败"); } Marshal.FreeHGlobal(ptrMsg); Marshal.FreeHGlobal(ptrCount); Marshal.FreeHGlobal(ptrCanFrame); Marshal.FreeHGlobal(ptrCanFDFrame); Marshal.FreeHGlobal(ptrTransmit); //Marshal.FreeHGlobal(actualValPtr); //Marshal.FreeHGlobal(signalPtr); return; } } }