412 lines
17 KiB
C#
412 lines
17 KiB
C#
/*
|
||
* 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;
|
||
}
|
||
}
|
||
}
|