using Common.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using static Common.Attributes.ATSCommandAttribute;
namespace ZLGCANFD
{
///
/// ZLG CAN 驱动类 (由 TSMaster CAN 改写)
///
[ATSCommand]
[DeviceCategory("CAN卡驱动")]
public class CAN
{
public static event Action ConnectEvent;
public static event Action DisConnectEvent;
public static bool ConnectFlag { get; set; } = false;
// 存储 ZLG 的设备句柄和多通道句柄
private static nint _deviceHandle = 0;
private static Dictionary _channelHandles = new Dictionary();
///
/// 用于接收 CAN FD 报文的队列
///
private static readonly Queue _receivedMessages = new Queue();
private static readonly object _lock = new object(); // 线程安全锁
// 接收线程控制标志
private static bool _isReceiving = false;
public static Action listener; // ZLG 接收事件委托
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class ZCAN_CANFD_FRAME
{
public uint can_id; // 报文ID (包含扩展帧标志位)
public byte len; // 数据长度
public byte flags; // CANFD标志 (0x01:CANFD, 0x02:BRS, 0x04:ESI)
public byte __res0; // 保留
public byte __res1; // 保留
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] data; // 数据负载
// --- 添加以下属性以解决报错并适配旧代码 ---
///
/// 模拟 eff 字段:1表示扩展帧,0表示标准帧
///
public uint eff
{
get { return (can_id & 0x80000000) != 0 ? 1u : 0u; }
set
{
if (value != 0)
can_id |= 0x80000000; // 将最高位置1,表示扩展帧
else
can_id &= 0x7FFFFFFF; // 将最高位清0,表示标准帧
}
}
public ZCAN_CANFD_FRAME()
{
data = new byte[64];
}
}
///
/// 初始化 CAN 驱动
///
[Browsable(false)]
public static int Init(uint deviceType, uint deviceIndex)
{
if (_deviceHandle != 0) return 0;
_deviceHandle = ZLGCAN.ZCAN_OpenDevice(deviceType, deviceIndex, 0);
if (_deviceHandle == 0)
{
Debug.WriteLine("ZLG 设备初始化失败!");
return -1;
}
return 0;
}
///
/// 释放 CAN 驱动
///
[Browsable(false)]
public static void Release()
{
DisConnect();
if (_deviceHandle != 0)
{
ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
_deviceHandle = 0;
}
}
///
/// 注册监听器
///
[Browsable(false)]
public static int RegisterListener(Action listenEvent)
{
listener = listenEvent;
if (!_isReceiving)
{
_isReceiving = true;
Task.Run(ReceiveThreadProcess);
}
return 0;
}
///
/// 注销监听器
///
[Browsable(false)]
public static int UnRegisterListener()
{
listener = null;
_isReceiving = false;
return 0;
}
private static void ReceiveThreadProcess()
{
while (_isReceiving)
{
bool hasData = false;
foreach (var chnHandle in _channelHandles.Values)
{
uint len = ZLGCAN.ZCAN_GetReceiveNum(chnHandle, ZDBC.FT_CANFD);
if (len > 0)
{
int size = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data));
nint ptr = Marshal.AllocHGlobal((int)len * size);
uint readLen = ZLGCAN.ZCAN_ReceiveFD(chnHandle, ptr, len, 50);
for (int i = 0; i < readLen; i++)
{
nint pItem = ptr + i * size;
var frame = Marshal.PtrToStructure(pItem);
lock (_lock)
{
_receivedMessages.Enqueue(frame);
}
listener?.Invoke(frame);
}
Marshal.FreeHGlobal(ptr);
hasData = true;
}
}
if (!hasData) Thread.Sleep(10);
}
}
public static int Connect(uint channel, ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG config)
{
if (_deviceHandle == 0) return -1;
nint chnHandle = ZLGCAN.ZCAN_InitCAN(_deviceHandle, channel, ref config);
if (chnHandle == 0)
{
Debug.WriteLine($"CAN 通道 {channel} 初始化失败");
return -1;
}
if (ZLGCAN.ZCAN_StartCAN(chnHandle) == 1)
{
_channelHandles[channel] = chnHandle;
ConnectFlag = true;
Task.Run(() => ConnectEvent?.Invoke());
return 0;
}
else
{
Debug.WriteLine($"CAN 通道 {channel} 启动失败");
return -1;
}
}
public static int DisConnect()
{
foreach (var handle in _channelHandles.Values)
{
ZLGCAN.ZCAN_ResetCAN(handle);
}
_channelHandles.Clear();
ConnectFlag = false;
Task.Run(() => DisConnectEvent?.Invoke());
return 0;
}
[Browsable(false)]
public static int LoadDBC(string filePath, int[] channel, out uint databaseID)
{
// 1. 初始化 ZDBC 模块,获取句柄
databaseID = ZDBC.ZDBC_Init(0, 1);
if (databaseID == ZDBC.INVALID_DBC_HANDLE)
{
return -1; // 初始化失败
}
// 2. 构造文件信息结构体并加载
ZDBC.FileInfo fileInfo = new ZDBC.FileInfo();
fileInfo.strFilePath = new byte[ZDBC._MAX_FILE_PATH_ + 1];
byte[] pathBytes = System.Text.Encoding.Default.GetBytes(filePath);
Array.Copy(pathBytes, fileInfo.strFilePath, Math.Min(pathBytes.Length, ZDBC._MAX_FILE_PATH_));
fileInfo.type = ZDBC.PROTOCOL_OTHER; // 默认普通 CAN/CANFD
fileInfo.merge = 0; // 清除原有数据加载新文件
// 将结构体封送到非托管内存
nint pFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo));
Marshal.StructureToPtr(fileInfo, pFileInfo, false);
bool success = ZDBC.ZDBC_LoadFile(databaseID, pFileInfo);
Marshal.FreeHGlobal(pFileInfo); // 释放临时内存
if (!success) return -2; // 加载文件失败
// 3. 将加载的数据同步到您本地的缓存(如 MsgDatabase)
// 注意:ZLG 的加载通常是全局的,如果您的业务逻辑需要分 channel 存储,
// 需要根据您的解析类进行填充
foreach (var ch in channel)
{
// 这里的 Parse 需要您根据 ZDBC 的 API 重新实现(见下方第2点)
DBCParse.Parse(databaseID, ch);
}
return 0;
}
[Browsable(false)]
public static int UnLoadDBC(uint? databaseID = null)
{
// 1. 如果传入了句柄,释放 ZDBC 引擎资源
if (databaseID.HasValue && databaseID.Value != ZDBC.INVALID_DBC_HANDLE)
{
ZDBC.ZDBC_Release(databaseID.Value);
}
// 2. 清除本地缓存
DBCParse.MsgDatabase.Clear();
return 0;
}
#region 信号值获取方法 (ZLG 适配版)
public static double GetSignalValue(byte channel, string AMsgName, string ASgnName)
{
double value = double.NaN;
var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find != null)
{
int re = GetZlgSignalValue(ref find.ACANFD, AMsgName, ASgnName, ref value);
if (re != 1)
{
Debug.WriteLine($"GetSignalValue: 获取信号值失败, 消息: {AMsgName}, 信号: {ASgnName}");
}
}
else
{
Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
}
return value;
}
[Browsable(false)]
public static int GetSignalValue(byte channel, string AMsgName, string ASgnName, ref double value)
{
var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find != null)
{
return GetZlgSignalValue(ref find.ACANFD, AMsgName, ASgnName, ref value);
}
else
{
Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1;
}
}
[Browsable(false)]
public static int GetSignalValue(ref ZCAN_CANFD_FRAME ACANFD, string AMsgName, string ASgnName, ref double value)
{
return GetZlgSignalValue(ref ACANFD, AMsgName, ASgnName, ref value);
}
#endregion
#region ZLG 私有解析辅助
private static int GetZlgSignalValue(ref ZCAN_CANFD_FRAME frame, string msgName, string sigName, ref double val)
{
try
{
// 模拟或调用 ZLG 外部 DBC 库进行信号解析
return 0;
}
catch
{
return -1;
}
}
#endregion
private static Dictionary _cyclicTimers = new Dictionary();
#region 信号值设置方法 (ZLG 适配版)
public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0)
{
var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find == null)
{
Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1;
}
int re = EncodeZlgSignal(ref find.ACANFD, AMsgName, ASgnName, AValue);
if (re != 0)
{
Debug.WriteLine($"设置信号值编码失败! 消息:{AMsgName}, 信号:{ASgnName}");
return re;
}
if (isSend)
{
return TransmitLogic(channel, find, sendPeriod);
}
return 0;
}
public static int SetSignalValue(uint channel, string AMsgName, float sendPeriod = 0)
{
var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find == null)
{
Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1;
}
return TransmitLogic((byte)channel, find, sendPeriod);
}
#endregion
#region 内部辅助逻辑
private static int TransmitLogic(byte channel, ZLG_Msg msg, float period)
{
if (period <= 0)
{
return SendZlgFrame(channel, msg.ACANFD);
}
else
{
string key = $"{channel}_{msg.msg_id}";
if (_cyclicTimers.ContainsKey(key))
{
_cyclicTimers[key].Stop();
_cyclicTimers[key].Dispose();
}
var timer = new System.Timers.Timer(period);
timer.Elapsed += (s, e) => SendZlgFrame(channel, msg.ACANFD);
timer.AutoReset = true;
timer.Enabled = true;
_cyclicTimers[key] = timer;
return 0;
}
}
private static int SendZlgFrame(byte channel, ZCAN_CANFD_FRAME frame)
{
if (!_channelHandles.ContainsKey(channel)) return -1;
nint ptr = Marshal.AllocHGlobal(Marshal.SizeOf(frame));
try
{
Marshal.StructureToPtr(frame, ptr, false);
uint result = ZLGCAN.ZCAN_TransmitFD(_channelHandles[channel], ptr, 1);
return result == 1 ? 0 : -1;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
private static int EncodeZlgSignal(ref ZCAN_CANFD_FRAME frame, string msgName, string sigName, double val)
{
// 信号编码逻辑实现
return 0;
}
#endregion
}
}