Compare commits

..

2 Commits
master ... main

Author SHA1 Message Date
a61fe92fc3 添加了ZLGUSBCANFD通讯类 2026-03-17 16:06:21 +08:00
0ec430fe02 Merge pull request 'master' (#2) from master into main
Reviewed-on: #2
2026-03-16 14:50:05 +08:00
12 changed files with 1867 additions and 17 deletions

View File

@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "加密狗", "加密狗\加
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDU", "BDU\BDU.csproj", "{0C2B5CA2-D873-255B-1B76-741346ECA1BB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDU", "BDU\BDU.csproj", "{0C2B5CA2-D873-255B-1B76-741346ECA1BB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZLGCANFD", "ZLGCANFD\ZLGCANFD.csproj", "{307FD972-9EFD-453F-BBF3-92ECA032DA73}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{0C2B5CA2-D873-255B-1B76-741346ECA1BB}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -27,11 +27,10 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ATS_DBContext\ATS_DBContext.csproj" /> <ProjectReference Include="..\ATS_DBContext\ATS_DBContext.csproj" />
<ProjectReference Include="..\TOSUNCAN\TOSUNCAN.csproj" />
<ProjectReference Include="..\Command\Command.csproj" /> <ProjectReference Include="..\Command\Command.csproj" />
<ProjectReference Include="..\Common\Common.csproj" /> <ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" /> <ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" />
<ProjectReference Include="..\TOSUNCAN\TOSUNCAN.csproj" /> <ProjectReference Include="..\ZLGCANFD\ZLGCANFD.csproj" />
<ProjectReference Include="..\加密狗\加密狗.csproj" /> <ProjectReference Include="..\加密狗\加密狗.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -11,7 +11,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using TSMasterCAN; using ZLGCANFD;
namespace BDU.Logic namespace BDU.Logic
{ {
@ -102,9 +102,9 @@ namespace BDU.Logic
{ {
tmpDevice.CommunicationProtocol = device.CommunicationProtocol; tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
CAN.DisConnect(); 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 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) if (re1 == 0 && re2 == 0 && re3 == 0)
{ {
tmpDevice.Connected = true; tmpDevice.Connected = true;
@ -279,7 +279,7 @@ namespace BDU.Logic
break; break;
case "CAN": 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 re2 = CAN.LoadDBC(SystemConfig.Instance.DBCFilePath, [0, 1, 2, 3], out _);
//var re3 = CAN.Connect(); //var re3 = CAN.Connect();
if (re1 == 0 && CAN.ConnectFlag) if (re1 == 0 && CAN.ConnectFlag)

View File

@ -15,7 +15,7 @@ using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
using TSMasterCAN; using ZLGCANFD;
namespace BDU.Views namespace BDU.Views
{ {
@ -57,7 +57,7 @@ namespace BDU.Views
SignalName = DBCParse.MsgDatabase[][].signal_Name[], SignalName = DBCParse.MsgDatabase[][].signal_Name[],
CatchID = Guid.NewGuid(), CatchID = Guid.NewGuid(),
LogInterval = TimeSpan.FromMilliseconds(), LogInterval = TimeSpan.FromMilliseconds(),
MessageID = DBCParse.MsgDatabase[][].msg_id MessageID =(int)DBCParse.MsgDatabase[][].msg_id
}); });
} }
else else

View File

@ -22,9 +22,10 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using TSMasterCAN;
using static BDU.Models.ParameterModel; using static BDU.Models.ParameterModel;
using Path = System.IO.Path; using Path = System.IO.Path;
using ZLGCANFD;
namespace BDU.Views namespace BDU.Views
{ {
@ -375,12 +376,12 @@ namespace BDU.Views
private void ChannelMapping_Click(object sender, RoutedEventArgs e) private void ChannelMapping_Click(object sender, RoutedEventArgs e)
{ {
var re = CAN.ShowChannelMappingWindow(true); //var re = CAN.ShowChannelMappingWindow(true);
if (re != 0) //if (re != 0)
{ //{
var msg = CAN.GetErrorDescription(re); // var msg = CAN.GetErrorDescription(re);
Log.Error($"同星通道映射界面打开失败:{msg}"); // Log.Error($"同星通道映射界面打开失败:{msg}");
} //}
} }
private void TestDataInfo_Click(object sender, RoutedEventArgs e) 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); var re = CAN.LoadDBC(openFileDialog.FileName, [0, 1, 2, 3], out var DataBaseID);
if (re != 0) if (re != 0)
{ {
Log.Error("CAN数据库加载失败" + CAN.GetErrorDescription(re)); Log.Error("CAN数据库加载失败");// + CAN.GetErrorDescription(re)
} }
else else
{ {
@ -479,7 +480,7 @@ namespace BDU.Views
} }
else else
{ {
var res = CAN.Connect(); var res = CAN.Connect(ZLGCAN.ZCAN_USBCANFD_100U,new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG());
if (res == 0) if (res == 0)
{ {
Log.Success($"CAN卡连接成功,返回值:{res}"); Log.Success($"CAN卡连接成功,返回值:{res}");
@ -609,5 +610,7 @@ namespace BDU.Views
{ {
new DeviceManageWindow().Show(); new DeviceManageWindow().Show();
} }
} }
} }

View File

@ -8,6 +8,10 @@
<GenerateDocumentationFile>True</GenerateDocumentationFile> <GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="CanKit.Adapter.ZLG" Version="0.5.4" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" /> <ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup> </ItemGroup>

7
ZLGCAN/Class1.cs Normal file
View File

@ -0,0 +1,7 @@
namespace ZLGCAN
{
public class Class1
{
}
}

9
ZLGCAN/ZLGCAN.csproj Normal file
View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

419
ZLGCANFD/CAN.cs Normal file
View File

@ -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
{
/// <summary>
/// ZLG CAN 驱动类 (由 TSMaster CAN 改写)
/// </summary>
[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<uint, nint> _channelHandles = new Dictionary<uint, nint>();
/// <summary>
/// 用于接收 CAN FD 报文的队列
/// </summary>
private static readonly Queue<ZLGCAN.ZCAN_ReceiveFD_Data> _receivedMessages = new Queue<ZLGCAN.ZCAN_ReceiveFD_Data>();
private static readonly object _lock = new object(); // 线程安全锁
// 接收线程控制标志
private static bool _isReceiving = false;
public static Action<ZLGCAN.ZCAN_ReceiveFD_Data> 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; // 数据负载
// --- 添加以下属性以解决报错并适配旧代码 ---
/// <summary>
/// 模拟 eff 字段1表示扩展帧0表示标准帧
/// </summary>
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];
}
}
/// <summary>
/// 初始化 CAN 驱动
/// </summary>
[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;
}
/// <summary>
/// 释放 CAN 驱动
/// </summary>
[Browsable(false)]
public static void Release()
{
DisConnect();
if (_deviceHandle != 0)
{
ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
_deviceHandle = 0;
}
}
/// <summary>
/// 注册监听器
/// </summary>
[Browsable(false)]
public static int RegisterListener(Action<ZLGCAN.ZCAN_ReceiveFD_Data> listenEvent)
{
listener = listenEvent;
if (!_isReceiving)
{
_isReceiving = true;
Task.Run(ReceiveThreadProcess);
}
return 0;
}
/// <summary>
/// 注销监听器
/// </summary>
[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<ZLGCAN.ZCAN_ReceiveFD_Data>(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<string, System.Timers.Timer> _cyclicTimers = new Dictionary<string, System.Timers.Timer>();
#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
}
}

148
ZLGCANFD/DBCParse.cs Normal file
View File

@ -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<ZDBC.DBCSignal> signals { get; set; } = new List<ZDBC.DBCSignal>();
public string[] signal_Name { get; set; }
// 适配 ZLG 的 CANFD 帧结构 (来自 2.txt)
public CAN.ZCAN_CANFD_FRAME ACANFD;
}
public class DBCParse
{
// 存储多通道的消息数据库
public static List<List<ZLG_Msg>> MsgDatabase { get; set; } =
Enumerable.Range(0, 12).Select(_ => new List<ZLG_Msg>()).ToList();
/// <summary>
/// ZLG 专用解析逻辑:遍历 ZDBC 内部的消息链表并填充到 MsgDatabase
/// </summary>
/// <param name="hDBC">ZDBC_Init 返回的句柄</param>
/// <param name="channel">目标通道索引</param>
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<ZDBC.DBCMessage>(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);
}
}
/// <summary>
/// 加载 DBC 的入口函数
/// </summary>
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;
}
/// <summary>
/// 卸载 DBC 并释放 ZDBC 句柄
/// </summary>
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;
}
}
}

1236
ZLGCANFD/ZLGAPI.cs Normal file

File diff suppressed because it is too large Load Diff

19
ZLGCANFD/ZLGCANFD.csproj Normal file
View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="ZLGCANFD.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>