周立功开发过程1

This commit is contained in:
2026-02-02 21:22:01 +08:00
parent 4d16b474c6
commit 2e8ad1cffa
42 changed files with 11571 additions and 122 deletions

View File

@@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "USBCANFD", "USBCANFD\USBCANFD.csproj", "{B878ECF2-86D7-4907-A7FD-66899F10ECF2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Debug|x64.ActiveCfg = Debug|x64
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Debug|x64.Build.0 = Debug|x64
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Debug|x86.ActiveCfg = Debug|x86
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Debug|x86.Build.0 = Debug|x86
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Release|x64.ActiveCfg = Release|x64
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Release|x64.Build.0 = Release|x64
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Release|x86.ActiveCfg = Release|x86
{B878ECF2-86D7-4907-A7FD-66899F10ECF2}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@@ -0,0 +1,930 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using ZLGAPI;
namespace USBCANFD
{
internal class Program
{
public static IntPtr devHandle = IntPtr.Zero; // 设备句柄
public static IntPtr[] chnHandle = new IntPtr[10]; // 通道句柄
public static int chn_max = 2; // 最大通道数量
public static volatile bool isRunning = true; // 线程标志
public static uint isMerge = 0; // 合并接收标志
public static uint isBusload = 0; // 通道利用率使能
// 线程传递参数
class ThreadParams
{
public IntPtr dev { get; set; } // 设备句柄
public IntPtr chn { get; set; } // 通道句柄
public int chnNum { get; set; } // 通道号
}
class ThreadBusload
{
public IntPtr dev { get; set; } // 设备句柄
public int chnNum { get; set; } // 通道号
}
static void Main(string[] args)
{
uint ret; // 返回值
// 打开设备 方式一:通过索引顺序打开设备
Program.devHandle = ZLGCAN.ZCAN_OpenDevice(ZLGCAN.ZCAN_USBCANFD_200U, 0, 0);
if (Program.devHandle == IntPtr.Zero)
{
Console.WriteLine("打开设备失败");
Console.ReadKey();
return;
}
else
Console.WriteLine("打开设备成功");
// 打开设备 方式二通过自定义序列号打开设备需要首先执行SN_test函数设置自定义序列号
//Program.devHandle = ZLGCAN.ZCAN_OpenDeviceByName(ZLGCAN.ZCAN_USBCANFD_200U, "C#01");
//if (Program.devHandle == IntPtr.Zero)
//{
// Console.WriteLine("打开设备失败");
// Console.ReadKey();
// return;
//}
//else
// Console.WriteLine("打开设备成功");
//// 获取设备信息
//ZLGCAN.ZCAN_DEVICE_INFO info = new ZLGCAN.ZCAN_DEVICE_INFO();
//IntPtr P2Info = Marshal.AllocHGlobal(Marshal.SizeOf(info));
//if (1 == ZLGCAN.ZCAN_GetDeviceInf(Program.devHandle, P2Info))
//{
// info = (ZLGCAN.ZCAN_DEVICE_INFO)Marshal.PtrToStructure(P2Info, typeof(ZLGCAN.ZCAN_DEVICE_INFO));
// Console.WriteLine("设备型号 {0},设备固件版本 {1:X}", new string(info.str_hw_Type).TrimEnd('\0'), info.fw_Version);
//}
//// 自定义序列号
//SN_test(Program.devHandle);
// 该函数用于检测设备是否在线
//uint status = ZLGCAN.ZCAN_IsDeviceOnLine(Program.devHandle);
//Console.WriteLine("设备状态{0}",
// status == 0 ? "ERR" :
// status == 1 ? "OK" :
// status == 2 ? "ONLINE" :
// status == 3 ? "OFFLINE" :
// status == 4 ? "UNSUPPORTED" :
// status == 5 ? "BUFFER_TOO_SMALL" : "UNKNOW");
// 初始化并打开通道
for (int i = 0; i < Program.chn_max; i++)
{
Program.chnHandle[i] = Init_chn_USBCANFD(Program.devHandle, i); // 必须初始化完一个通道,再走另外一个通道!!!
if (Program.chnHandle[i] == IntPtr.Zero)
return;
}
// 接收线程处理
if (Program.isMerge == 1) // 合并接收
{
// 设置合并接收
ret = ZLGCAN.ZCAN_SetValue(Program.devHandle, "0/set_device_recv_merge", "1");
if (ret != 1)
{
Console.WriteLine("设置合并接收失败");
Console.ReadKey();
}
ThreadParams parameters = new ThreadParams
{
dev = Program.devHandle,
chnNum = 0
};
Thread workerThread = new Thread(ReceiveThread_Merge);
workerThread.IsBackground = true; // 设置为后台线程不需要join
workerThread.Start(parameters); // 启动线程
}
else // 普通接收
{
// 关闭合并接收
ret = ZLGCAN.ZCAN_SetValue(Program.devHandle, "0/set_device_recv_merge", "0");
if (ret != 1)
{
Console.WriteLine("关闭合并接收失败");
Console.ReadKey();
}
for (int i = 0; i < Program.chn_max; i++)
{
ThreadParams parameters = new ThreadParams
{
chn = Program.chnHandle[i],
chnNum = i
};
Thread workerThread = new Thread(ReceiveThread); // 每通道独立线程接收
workerThread.IsBackground = true; // 设置为后台线程不需要join
workerThread.Start(parameters); // 启动线程
}
}
if (Program.isBusload == 1) // 通道利用率
{
ThreadBusload Busload = new ThreadBusload
{
dev = Program.devHandle,
chnNum = 0
};
Thread ThreadBusload = new Thread(Thread_Busload);
ThreadBusload.IsBackground = true; // 设置为后台线程不需要join
ThreadBusload.Start(Busload); // 启动线程
}
// 发送示例
Send_test(Program.chnHandle[0]);
//Send_test_Merge(Program.devHandle);
//// 定时发送
//AutoSend_test(Program.devHandle, 0);
//// 队列发送
//QueueSend_test(Program.devHandle, Program.chnHandle[0]);
// 阻塞等待
Console.ReadKey();
Program.isRunning = false;
// 关闭通道
for (int i = 0; i < Program.chn_max; i++)
{
ret = ZLGCAN.ZCAN_ResetCAN(Program.chnHandle[i]);
if (ret != 1)
Console.WriteLine("关闭通道{0}失败", i);
}
// 关闭设备
ret = ZLGCAN.ZCAN_CloseDevice(Program.devHandle);
if (ret != 1)
{
Console.WriteLine("关闭设备失败");
Console.ReadKey();
return;
}
}
// 初始化CAN通道
static IntPtr Init_chn_USBCANFD(IntPtr dev, int chn_idx)
{
IntPtr temp = IntPtr.Zero;
uint ret; // 返回值
// 仲裁域波特率
string path = String.Format("{0}/canfd_abit_baud_rate", chn_idx);
ret = ZLGCAN.ZCAN_SetValue(dev, path, "500000"); // 500k
if (ret != 1)
{
Console.WriteLine("设置仲裁域波特率失败");
Console.ReadKey();
return IntPtr.Zero;
}
// 数据域波特率
path = String.Format("{0}/canfd_dbit_baud_rate", chn_idx);
ret = ZLGCAN.ZCAN_SetValue(dev, path, "2000000"); // 2M
if (ret != 1)
{
Console.WriteLine("设置数据域波特率失败");
Console.ReadKey();
return IntPtr.Zero;
}
// 终端电阻
path = String.Format("{0}/initenal_resistance", chn_idx);
string resistance = "1";//1-使能 0-禁能
ret = ZLGCAN.ZCAN_SetValue(dev, path, resistance);
if (ret != 1)
{
Console.WriteLine("设置终端电阻失败");
Console.ReadKey();
return IntPtr.Zero;
}
// 初始化通道
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); // 转成指针
temp = ZLGCAN.ZCAN_InitCAN(dev, (uint)chn_idx, P2InitConfig);
Marshal.FreeHGlobal(P2InitConfig); // 释放内存
if (temp == IntPtr.Zero)
{
Console.WriteLine("初始化通道失败");
Console.ReadKey();
return IntPtr.Zero;
}
Console.WriteLine("初始化通道成功");
//// 设置滤波
//value = "0"; // 0-标准帧 1-扩展帧
// path = String.Format("{0}/filter_mode", chn_idx);
// ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, value);
// value = "0x731"; // 起始 ID
// path = String.Format("{0}/filter_start", chn_idx);
// ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, value);
// value = "0x7DF"; // 结束 ID
// path = String.Format("{0}/filter_end", chn_idx);
// ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, value);
// value = "0"; // 使能滤波
// path = String.Format("{0}/filter_ack", chn_idx);
// ret = ZLGCAN.ZCAN_SetValue(deviceHandle, path, value);
// if (ret != 1)
// {
// Console.WriteLine("使能滤波失败");
// Console.ReadKey();
// return IntPtr.Zero;
// }
if (Program.isBusload == 1) // 通道利用率
{
// 通道利用率上报
path = String.Format("{0}/set_bus_usage_enable", chn_idx);
ret = ZLGCAN.ZCAN_SetValue(dev, path, "1");
// 总线利用率上报周期
path = String.Format("{0}/set_bus_usage_period", chn_idx);
ret = ZLGCAN.ZCAN_SetValue(dev, path, "500");
}
//打开通道
uint Ret = ZLGCAN.ZCAN_StartCAN(temp);
if (Ret != 1)
{
Console.WriteLine("打开通道失败");
Console.ReadKey();
return IntPtr.Zero;
}
Console.WriteLine("打开通道成功");
return temp;
}
// 总线利用率
static void Thread_Busload(object obj)
{
ThreadBusload parameters = (ThreadBusload)obj;
while (Program.isRunning)
{
IntPtr pUse = ZLGCAN.ZCAN_GetValue(Program.devHandle, parameters.chnNum +"/get_bus_usage/1" );
if (pUse != IntPtr.Zero)
{
ZLGCAN.BusUsage busUsage = (ZLGCAN.BusUsage)Marshal.PtrToStructure(pUse, typeof(ZLGCAN.BusUsage));
Console.WriteLine("总线利用率: {0}%{1}帧/秒", busUsage.nBusUsage / 100, busUsage.nFrameCount);
}
Thread.Sleep(500);
}
}
// 接收线程
static void ReceiveThread(object obj)
{
ThreadParams parameters = obj as ThreadParams;
if (parameters == null) return;
// 配置缓冲区大小
const int BUFFER_SIZE = 100;
// 预计算结构体大小
int canStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data));
int canfdStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data));
// 分配非托管内存(循环外一次分配,复用避免频繁申请释放)
IntPtr pCanBuffer = Marshal.AllocHGlobal(canStructSize * BUFFER_SIZE); // CAN接收缓冲区
IntPtr pCanfdBuffer = Marshal.AllocHGlobal(canfdStructSize * BUFFER_SIZE); // CANFD接收缓冲区
try
{
while (Program.isRunning)
{
uint recNum = ZLGCAN.ZCAN_GetReceiveNum(parameters.chn, 0); // 0-CAN
if (recNum > 0)
{
// 限制接收数量不超过缓冲区大小(双重保险)
uint actualReceive = ZLGCAN.ZCAN_Receive(
parameters.chn,
pCanBuffer, // 传入非托管缓冲区指针C风格
BUFFER_SIZE,
10
);
if (actualReceive > 0)
{
for (int i = 0; i < actualReceive; i++)
{
// 计算当前CAN数据的指针
IntPtr pCurrentCan = (IntPtr)(pCanBuffer.ToInt64() + i * canStructSize);
// 非托管内存转换为C#结构体
ZLGCAN.ZCAN_Receive_Data recData = (ZLGCAN.ZCAN_Receive_Data)Marshal.PtrToStructure(
pCurrentCan,
typeof(ZLGCAN.ZCAN_Receive_Data)
);
// 可选ID过滤
// uint canId = recData.frame.can_id & 0x1FFFFFFF;
// if (canId != 0x731 && canId != 0x7B1)
// continue;
// 通道号和时间戳
Console.Write(String.Format("CHN:{0} [{1}] CAN ", parameters.chnNum, recData.timestamp));
// 帧类型(标准/扩展)
Console.Write((recData.frame.can_id & (1 << 31)) != 0 ? "扩展帧 " : "标准帧 ");
// 方向Tx/Rx
Console.Write((recData.frame.__pad & 0x20) == 0x20 ? "Tx " : "Rx ");
// 数据长度校验
int dataLen = Math.Min(recData.frame.can_dlc, recData.frame.data != null ? recData.frame.data.Length : 0);
// ID和数据保留原格式
Console.WriteLine(String.Format("ID:{0:X} {1}",
recData.frame.can_id & 0x1FFFFFFF,
Program.b_array2string(recData.frame.data, dataLen)
));
}
}
}
recNum = ZLGCAN.ZCAN_GetReceiveNum(parameters.chn, 1); // 1-CANFD
if (recNum > 0)
{
uint actualReceive = ZLGCAN.ZCAN_ReceiveFD(
parameters.chn,
pCanfdBuffer, // CANFD非托管缓冲区指针
BUFFER_SIZE,
10
);
if (actualReceive > 0)
{
for (int i = 0; i < actualReceive; i++)
{
// 计算当前CANFD数据的指针
IntPtr pCurrentCanfd = (IntPtr)(pCanfdBuffer.ToInt64() + i * canfdStructSize);
// 非托管内存转换为C#结构体
ZLGCAN.ZCAN_ReceiveFD_Data recFDData = (ZLGCAN.ZCAN_ReceiveFD_Data)Marshal.PtrToStructure(
pCurrentCanfd,
typeof(ZLGCAN.ZCAN_ReceiveFD_Data)
);
// 通道号和时间戳
Console.Write(String.Format("CHN:{0} [{1}] CANFD", parameters.chnNum, recFDData.timestamp));
// CANFD加速标志
if ((recFDData.frame.flags & 0x01) == 0x01)
Console.Write("加速");
// 帧类型(标准/扩展)
Console.Write((recFDData.frame.can_id & (1 << 31)) != 0 ? " 扩展帧" : " 标准帧");
// 方向Tx/Rx
Console.Write((recFDData.frame.flags & 0x20) == 0x20 ? " Tx " : " Rx ");
// 数据长度校验
int dataLen = Math.Min(recFDData.frame.len, recFDData.frame.data != null ? recFDData.frame.data.Length : 0);
// ID和数据
Console.WriteLine(String.Format("ID:{0:X} {1}",
recFDData.frame.can_id & 0x1FFFFFFF,
Program.b_array2string(recFDData.frame.data, dataLen)
));
}
}
}
ZLGAPI.ZLGCAN.ZCAN_CHANNEL_ERR_INFO errData = new ZLGAPI.ZLGCAN.ZCAN_CHANNEL_ERR_INFO{
error_code = 0,
passive_ErrData = new byte[3],
arLost_ErrData = 0
};
uint ret = ZLGAPI.ZLGCAN.ZCAN_ReadChannelErrInfo(parameters.chn, ref errData);
Analyze_err_frame(errData);
Thread.Sleep(10);
}
}
finally
{
// 确保非托管内存必释放
Marshal.FreeHGlobal(pCanfdBuffer);
Marshal.FreeHGlobal(pCanBuffer);
}
}
// 接收线程(合并接收)
static void ReceiveThread_Merge(object obj)
{
ThreadParams parameters = (ThreadParams)obj;
// 预计算结构体大小
int dataObjSize = Marshal.SizeOf(typeof(ZLGCAN.ZCANDataObj));
int canfdSize = Marshal.SizeOf(typeof(ZLGCAN.ZCANCANFDData));
int linSize = Marshal.SizeOf(typeof(ZLGCAN.ZCANLINData));
// 分配非托管内存(循环外分配,复用避免频繁申请释放)
IntPtr pDataObjs = Marshal.AllocHGlobal(dataObjSize * 100); // 写死100个最大可以面对绝大部分情况如果是动态长度容易崩溃
IntPtr pCanfdBuffer = Marshal.AllocHGlobal(canfdSize);
IntPtr pLinBuffer = Marshal.AllocHGlobal(linSize);
try
{
while (Program.isRunning)
{
// 获取待接收数据量,无数据则休眠后继续
uint recvNum = ZLGCAN.ZCAN_GetReceiveNum(parameters.dev, 2);
if (recvNum == 0)
{
Thread.Sleep(10);
continue;
}
// 接收数据
uint actualRecv = ZLGCAN.ZCAN_ReceiveData(parameters.dev, pDataObjs, 100, 10);
if (actualRecv == 0)
{
continue;
}
// 遍历处理每个接收的数据
for (int i = 0; i < actualRecv; i++)
{
// 计算当前数据对象指针
IntPtr pCurrentData = (IntPtr)(pDataObjs.ToInt64() + i * dataObjSize);
ZLGCAN.ZCANDataObj dataObj = (ZLGCAN.ZCANDataObj)Marshal.PtrToStructure(pCurrentData, typeof(ZLGCAN.ZCANDataObj));
// 根据数据类型处理
switch (dataObj.dataType)
{
case 1: // CAN/CANFD
// 复制data到非托管缓冲区
Marshal.Copy(dataObj.data, 0, pCanfdBuffer, canfdSize);
ZLGCAN.ZCANCANFDData canfdData = (ZLGCAN.ZCANCANFDData)Marshal.PtrToStructure(pCanfdBuffer, typeof(ZLGCAN.ZCANCANFDData));
//// 可选ID过滤调试用
//uint canId = canfdData.frame.can_id & 0x1FFFFFFF;
//if (canId != 0x731 && canId != 0x7B1)
// continue;
// 通道和时间戳
Console.Write(String.Format("CHN:{0} [{1}] ", dataObj.chnl, canfdData.timeStamp));
// CAN/CANFD类型 + 加速标志
if ((canfdData.flag & 1) == 0)
Console.Write("CAN");
else
{
Console.Write("CANFD");
if ((canfdData.frame.flags & 1) == 1)
Console.Write("加速");
}
// 帧类型(标准/扩展)
Console.Write((canfdData.frame.can_id & (1 << 31)) != 0 ? " 扩展帧 " : " 标准帧 ");
// 方向TX/RX
Console.Write((canfdData.flag & (1 << 9)) != 0 ? "TX " : "RX ");
// ID
Console.Write(String.Format("ID:{0:X} ", canfdData.frame.can_id & 0x1FFFFFFF));
// 打印数据
int canDataLen = Math.Min(canfdData.frame.len, canfdData.frame.data != null ? canfdData.frame.data.Length : 0);
for (int j = 0; j < canDataLen; j++)
Console.Write(String.Format("{0:X2} ", canfdData.frame.data[j]));
Console.WriteLine();
break;
case 4: // LIN
// 校验数据长度足够,避免越界复制
if (dataObj.data.Length < linSize)
break;
// 直接复制data到非托管缓冲区
Marshal.Copy(dataObj.data, 0, pLinBuffer, linSize);
ZLGCAN.ZCANLINData linData = (ZLGCAN.ZCANLINData)Marshal.PtrToStructure(pLinBuffer, typeof(ZLGCAN.ZCANLINData));
// 拼接打印信息
Console.Write(String.Format("CHN:{0} [{1}] PID:{2:X} ",
dataObj.chnl, linData.rxData.timeStamp, linData.pid.rawVal & 0x3F));
// 方向TX/RX
Console.Write(linData.rxData.dir == 1 ? "TX Data: " : "RX Data: ");
// 打印数据
int linDataLen = Math.Min(linData.rxData.datalen, linData.rxData.data != null ? linData.rxData.data.Length : 0);
for (int j = 0; j < linDataLen; j++)
Console.Write(String.Format("{0:X2} ", linData.rxData.data[j]));
Console.WriteLine();
break;
case 6: // LIN错误
Console.WriteLine("LIN 错误");
break;
}
}
}
}
finally
{
// 确保非托管内存必释放(避免泄漏)
Marshal.FreeHGlobal(pLinBuffer);
Marshal.FreeHGlobal(pCanfdBuffer);
Marshal.FreeHGlobal(pDataObjs);
}
}
// 发送示例
static void Send_test(IntPtr chnHandle)
{
// CAN
ZLGCAN.ZCAN_Transmit_Data[] can_data = new ZLGCAN.ZCAN_Transmit_Data[10];
IntPtr p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)) * 10);
byte[] sourceData = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 ,0x77,0x88};
for (int i = 0; i < 10; i++)
{
can_data[i].frame = new ZLGCAN.can_frame();
can_data[i].transmit_type = 0; // 0-正常发送
can_data[i].frame.can_id = MakeCanId((uint)0x10, 0, 0, 0); // ID
can_data[i].frame.can_dlc = 8; // 数据长度
can_data[i].frame.__pad |= 0x20; // 发送回显
can_data[i].frame.data = new byte[8]; // 此成员必须new8个字节否则无法运行数据长度修改frame.can_dlc成员即可
Array.Copy(sourceData, can_data[i].frame.data, Math.Min(8, sourceData.Length));
Marshal.StructureToPtr(can_data[i], (IntPtr)(p2CanData + i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data))), true);
}
uint ret = ZLGCAN.ZCAN_Transmit(chnHandle, p2CanData, 10);
Console.WriteLine("发送 {0} 帧CAN报文", ret);
// CANFD
ZLGCAN.ZCAN_TransmitFD_Data[] canfd_data = new ZLGCAN.ZCAN_TransmitFD_Data[10];
IntPtr p2CanFDData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_TransmitFD_Data)) * 10);
for (int i = 0; i < 10; i++)
{
canfd_data[i].frame = new ZLGCAN.canfd_frame();
canfd_data[i].transmit_type = 0; // 0-正常发送
canfd_data[i].frame.can_id = MakeCanId((uint)0x10, 0, 0, 0); // ID
canfd_data[i].frame.len = 64; // 数据长度
canfd_data[i].frame.flags |= 0x20; // 发送回显
canfd_data[i].frame.data = new byte[64]; // 此成员必须new64个字节否则无法运行数据长度修改frame.len成员即可
for (int j = 0; j < canfd_data[i].frame.len; j++)
canfd_data[i].frame.data[j] = (byte)j;
Marshal.StructureToPtr(canfd_data[i], (IntPtr)(p2CanFDData + i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_TransmitFD_Data))), true);
}
uint retfd = ZLGCAN.ZCAN_TransmitFD(chnHandle, p2CanFDData, 10);
Console.WriteLine("发送 {0} 帧CANFD报文", retfd);
Marshal.FreeHGlobal(p2CanData);
Marshal.FreeHGlobal(p2CanFDData);
}
// 合并发送
static void Send_test_Merge(IntPtr dev)
{
const int FRAME_COUNT = 10; // 发送帧数量
ZLGCAN.ZCANDataObj[] dataObjs = new ZLGCAN.ZCANDataObj[FRAME_COUNT];
IntPtr pDataObjs = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCANDataObj)) * FRAME_COUNT);
// canfd_frame
var baseFrame = new ZLGCAN.canfd_frame
{
can_id = MakeCanId(0x10, 0, 0, 0), // ID
len = 64, // 长度
flags = 0x01, // 1-CANFD加速
data = new byte[64]
};
for (int i = 0; i < baseFrame.data.Length; i++)
{
baseFrame.data[i] = (byte)(i % 0xFF); // 数据
}
for (int i = 0; i < FRAME_COUNT; i++)
{
// ZCANCANFDData
var canfdData = new ZLGCAN.ZCANCANFDData
{
timeStamp = 0, // 普通发送时 timeStamp 字段无意义
flag = 0,
extraData = new byte[4],
frame = baseFrame,
frameType = 1, // 0-CAN 1-CANFD
txEchoRequest = 1 // 1-发送回显
};
// ZCANDataObj
dataObjs[i] = new ZLGCAN.ZCANDataObj
{
dataType = 1, // 1-CAN/CANFD
chnl = 0, // 通道
flag = 0, // 未使用
data = new byte[92]
};
// 结构体转字节数组
IntPtr pCanFd = Marshal.AllocHGlobal(Marshal.SizeOf(canfdData));
try
{
Marshal.StructureToPtr(canfdData, pCanFd, false);
Marshal.Copy(pCanFd, dataObjs[i].data, 0, Marshal.SizeOf(canfdData));
}
finally
{
Marshal.FreeHGlobal(pCanFd);
}
// 拷贝到非托管内存
Marshal.StructureToPtr(dataObjs[i], IntPtr.Add(pDataObjs, i * Marshal.SizeOf(typeof(ZLGCAN.ZCANDataObj))), true);
}
// 发送
uint sentCount = ZLGCAN.ZCAN_TransmitData(dev, pDataObjs, (uint)FRAME_COUNT);
Console.WriteLine("合并发送 {0} 帧报文", sentCount);
Marshal.FreeHGlobal(pDataObjs);
}
// 定时发送
static void AutoSend_test(IntPtr dev, int chn_idx)
{
// 第一条定时任务CAN
ZLGCAN.ZCAN_Transmit_Data can_data = new ZLGCAN.ZCAN_Transmit_Data();
can_data.frame = new ZLGCAN.can_frame();
can_data.transmit_type = 0; // 0-正常发送
can_data.frame.can_id = MakeCanId((uint)0x10, 0, 0, 0); // ID
can_data.frame.can_dlc = 8; // 数据长度
can_data.frame.__pad |= 0x20; // 发送回显
can_data.frame.data = new byte[8];
for (int j = 0; j < can_data.frame.can_dlc; j++)
can_data.frame.data[j] = (byte)j;
ZLGCAN.ZCAN_AUTO_TRANSMIT_OBJ auto_can = new ZLGCAN.ZCAN_AUTO_TRANSMIT_OBJ
{
index = 0,
enable = 1,
interval = 500,
obj = new ZLGCAN.ZCAN_Transmit_Data()
};
auto_can.obj = can_data;
string path = String.Format("{0}/auto_send", chn_idx);
uint ret = ZLGCAN.ZCAN_SetValue(dev, path, ref auto_can); // 设置
if (ret != 1)
{
Console.WriteLine("设置定时发送失败");
}
//// 第二条定时任务CANFD
//ZLGCAN.ZCAN_TransmitFD_Data canfd_data = new ZLGCAN.ZCAN_TransmitFD_Data();
//canfd_data.frame = new ZLGCAN.canfd_frame();
//canfd_data.transmit_type = 0; // 0-正常发送
//canfd_data.frame.can_id = MakeCanId((uint)0x20, 0, 0, 0); // ID
//canfd_data.frame.len = 64; // 数据长度
//canfd_data.frame.flags |= 0x20; // 发送回显
//canfd_data.frame.data = new byte[64];
//for (int j = 0; j < canfd_data.frame.len; j++)
// canfd_data.frame.data[j] = (byte)j;
//ZLGCAN.ZCANFD_AUTO_TRANSMIT_OBJ auto_canfd = new ZLGCAN.ZCANFD_AUTO_TRANSMIT_OBJ
//{
// index = 1,
// enable = 1,
// interval = 500,
// obj = new ZLGCAN.ZCAN_TransmitFD_Data()
//};
//auto_canfd.obj = canfd_data;
//path = String.Format("{0}/auto_send_canfd", chn_idx);
//ret = ZLGCAN.ZCAN_SetValue(dev, path, ref auto_canfd); // 设置
//if (ret != 1)
//{
// Console.WriteLine("设置定时发送失败");
//}
// 启动通道定时任务
path = String.Format("{0}/apply_auto_send", chn_idx);
ret = ZLGCAN.ZCAN_SetValue(dev, path, "0");
if (ret != 1)
{
Console.WriteLine("启动定时发送失败");
}
// 覆盖第一条定时任务
Thread.Sleep(2000);
can_data.frame.can_id = MakeCanId((uint)0x222, 0, 0, 0); // 新ID
auto_can.obj = can_data;
path = String.Format("{0}/auto_send", chn_idx);
ret = ZLGCAN.ZCAN_SetValue(dev, path, ref auto_can);
if (ret != 1)
{
Console.WriteLine("第二次设置定时发送失败");
}
else
{
Console.WriteLine("覆盖定时发送成功");
}
Thread.Sleep(5000);
// 清空定时发送
path = String.Format("{0}/clear_auto_send", 0);
ret = ZLGCAN.ZCAN_SetValue(dev, path, "0");
if (ret != 1)
{
Console.WriteLine("清空定时发送失败");
}
}
// 设置队列发送and队列发送示例
static void QueueSend_test(IntPtr dev, IntPtr chnHandle)
{
//// 使能队列发送
//uint ret = ZLGCAN.ZCAN_SetValue(Program.dev, "0/set_send_mode", "1"); // USBCANFD V1.01版本的才需要配置
//if (ret != 1)
//{
// Console.WriteLine("设置队列发送失败");
// Console.ReadKey();
//}
uint ret = 0;
const int FRAME_COUNT = 100; // 发送帧数量
// CAN
ZLGCAN.ZCAN_Transmit_Data[] can_data = new ZLGCAN.ZCAN_Transmit_Data[100];
IntPtr p2CanData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data)) * FRAME_COUNT);
for (int i = 0; i < FRAME_COUNT; i++)
{
can_data[i].frame = new ZLGCAN.can_frame();
can_data[i].transmit_type = 0; // 0-正常发送
can_data[i].frame.can_id = MakeCanId((uint)0x10, 0, 0, 0); // ID
can_data[i].frame.can_dlc = 8; // 数据长度
can_data[i].frame.__pad |= 0x20; // 发送回显
can_data[i].frame.__pad |= 0x80; // 设置队列发送 0x80单位ms,0xC0单位100us
can_data[i].frame.__res0 = 0xA; // res1 和 res0两个字节存储时间间隔
can_data[i].frame.__res1 = 0x0;
can_data[i].frame.data = new byte[8];
for (int j = 0; j < can_data[i].frame.can_dlc; j++)
can_data[i].frame.data[j] = (byte)j;
Marshal.StructureToPtr(can_data[i], (IntPtr)(p2CanData + i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Transmit_Data))), true);
}
// 获取队列发送缓存
IntPtr free_count_p = ZLGCAN.ZCAN_GetValue(dev, "0/get_device_available_tx_count/1");
int free_count = Marshal.ReadInt32(free_count_p);
Console.WriteLine("队列缓存剩余:{0} 帧", free_count);
if (free_count > FRAME_COUNT)
{
ret = ZLGCAN.ZCAN_Transmit(chnHandle, p2CanData, 100); // 下发给设备
Console.WriteLine("发送 {0} 帧CAN报文", ret);
}
// CANFD
ZLGCAN.ZCAN_TransmitFD_Data[] canfd_data = new ZLGCAN.ZCAN_TransmitFD_Data[FRAME_COUNT];
IntPtr p2CanFDData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.ZCAN_TransmitFD_Data)) * FRAME_COUNT);
for (int i = 0; i < FRAME_COUNT; i++)
{
canfd_data[i].frame = new ZLGCAN.canfd_frame();
canfd_data[i].transmit_type = 0; // 0-正常发送
canfd_data[i].frame.can_id = MakeCanId((uint)0x11, 0, 0, 0); // ID
canfd_data[i].frame.len = 64; // 数据长度
canfd_data[i].frame.flags |= 0x20; // 发送回显
canfd_data[i].frame.flags |= 0x80; // 设置队列发送 0x80单位ms,0xC0单位100us
canfd_data[i].frame.__res0 = 0x14;
canfd_data[i].frame.__res1 = 0x0;
canfd_data[i].frame.data = new byte[64];
for (int j = 0; j < canfd_data[i].frame.len; j++)
canfd_data[i].frame.data[j] = (byte)j;
Marshal.StructureToPtr(canfd_data[i], (IntPtr)(p2CanFDData + i * Marshal.SizeOf(typeof(ZLGCAN.ZCAN_TransmitFD_Data))), true);
}
// 获取队列发送缓存
free_count_p = ZLGCAN.ZCAN_GetValue(dev, "0/get_device_available_tx_count/1");
free_count = Marshal.ReadInt32(free_count_p);
Console.WriteLine("队列缓存剩余:{0} 帧", free_count);
if (free_count > FRAME_COUNT)
{
uint retfd = ZLGCAN.ZCAN_TransmitFD(chnHandle, p2CanFDData, 10);
Console.WriteLine("发送 {0} 帧CANFD报文", retfd);
}
Thread.Sleep(2000); // 发送2秒后清空
ret = ZLGCAN.ZCAN_SetValue(dev, "0/clear_delay_send_queue", "0"); // 清空队列缓存
if (ret != 1)
{
Console.WriteLine("清空队列缓存失败");
}
Marshal.FreeHGlobal(p2CanData);
Marshal.FreeHGlobal(p2CanFDData);
}
// 错误帧解析
static void Analyze_err_frame(ZLGAPI.ZLGCAN.ZCAN_CHANNEL_ERR_INFO errData)
{
// 错误码非0时先输出错误码替换$为string.Format
if (errData.error_code != 0x0)
{
Console.Write(string.Format("错误码:{0}", errData.error_code));
}
// 匹配错误码逻辑与C++ switch完全一致
switch (errData.error_code)
{
case 0x1:
Console.WriteLine("CAN 控制器内部FIFO溢出");
break;
case 0x2:
Console.WriteLine("CAN 控制器错误报警");
break;
case 0x4:
Console.Write("CAN 控制器消极错误,");
// 替换$为string.Format多个参数按顺序占位
Console.WriteLine(string.Format("Rx ErrNUM: {0}Tx ErrNUM: {1}",
errData.passive_ErrData[1], errData.passive_ErrData[2]));
break;
case 0x8:
Console.WriteLine("CAN 控制器仲裁丢失");
break;
case 0x10:
Console.WriteLine("CAN 控制器总线错误");
break;
case 0x20:
Console.WriteLine("CAN 控制器总线关闭");
break;
case 0x40:
Console.WriteLine("CAN 缓存溢出");
break;
default:
break;
}
}
// 自定义序列号
static void SN_test(IntPtr dev)
{
// 设置自定义sn号
if (0 == ZLGCAN.ZCAN_SetValue(dev, "0/set_cn", "C#01"))
{
Console.WriteLine("设置自定义序列号失败");
Console.ReadKey();
}
// 获取自定义sn号
IntPtr P2CN = ZLGCAN.ZCAN_GetValue(dev, "0/get_cn/1");
string CN = Marshal.PtrToStringAnsi(P2CN);
Console.WriteLine("设备的自定义序列号:{0}", CN);
}
// 构造CANID
static uint MakeCanId(uint id, int eff, int rtr, int err)
{
uint ueff = (uint)(!!(Convert.ToBoolean(eff)) ? 1 : 0); // 0 标准帧1 扩展帧
uint urtr = (uint)(!!(Convert.ToBoolean(rtr)) ? 1 : 0); // 0 数据帧1 远程帧
uint uerr = (uint)(!!(Convert.ToBoolean(err)) ? 1 : 0); // 0 CAN帧1 错误帧(目前只能设置为 0
return id | ueff << 31 | urtr << 30 | uerr << 29;
}
// byte[] -> string
public static string b_array2string(byte[] ByteIn, int LEN)
{
// 空值校验(避免空引用/越界异常)
if (ByteIn == null || ByteIn.Length == 0 || LEN == 0)
return "";
// 限制实际处理长度
int actualLen = Math.Min(LEN, ByteIn.Length);
// 用StringBuilder优化拼接
System.Text.StringBuilder sb = new System.Text.StringBuilder(actualLen * 3); // 预分配容量每个字节占3字符XX + 空格)
for (int i = 0; i < actualLen; i++)
{
sb.Append(ByteIn[i].ToString("X2")); // 大写十六进制
if (i < actualLen - 1) // 最后一个字节后不添加空格
sb.Append(" ");
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("USBCANFD")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("USBCANFD")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("d1f5bf24-cf99-4141-9934-ef199c00e9c4")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B878ECF2-86D7-4907-A7FD-66899F10ECF2}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>USBCANFD</RootNamespace>
<AssemblyName>USBCANFD</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ZLGAPI.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DBC", "DBC\DBC.csproj", "{DEFCD218-D268-4833-950E-6F697BC93F8C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x64.ActiveCfg = Debug|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x64.Build.0 = Debug|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x86.ActiveCfg = Debug|x86
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x86.Build.0 = Debug|x86
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x64.ActiveCfg = Release|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x64.Build.0 = Release|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x86.ActiveCfg = Release|x86
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DEFCD218-D268-4833-950E-6F697BC93F8C}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DBC</RootNamespace>
<AssemblyName>DBC</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ZLGAPI.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,411 @@
/*
* 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;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("DBC")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DBC")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("adbdb093-47ba-4e8c-bb2e-b08ad7638493")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DBC", "DBC\DBC.csproj", "{DEFCD218-D268-4833-950E-6F697BC93F8C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x64.ActiveCfg = Debug|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x64.Build.0 = Debug|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x86.ActiveCfg = Debug|x86
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Debug|x86.Build.0 = Debug|x86
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x64.ActiveCfg = Release|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x64.Build.0 = Release|x64
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x86.ActiveCfg = Release|x86
{DEFCD218-D268-4833-950E-6F697BC93F8C}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DEFCD218-D268-4833-950E-6F697BC93F8C}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DBC</RootNamespace>
<AssemblyName>DBC</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ZLGAPI.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,411 @@
/*
* 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;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("DBC")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DBC")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("adbdb093-47ba-4e8c-bb2e-b08ad7638493")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

File diff suppressed because it is too large Load Diff