周立功开发过程1
This commit is contained in:
36
.windsurf/rules/zlgcan.md
Normal file
36
.windsurf/rules/zlgcan.md
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
())trigger: manual
|
||||
---
|
||||
### 目标:根据周立功的CAN卡提供的官方资料,进行封装成C#类库供使用,主要是CAN,CAN FD,LIN三个通信,其中CAN和CAN FD使用DBC配置,LIN使用LDF配置,
|
||||
|
||||
### 周立功CAN卡型号:USBCANFD 200U
|
||||
|
||||
### 官网网络资源地址
|
||||
|
||||
函数库简介:https://manual.zlg.cn/web/#/152/5333
|
||||
开发流程:https://manual.zlg.cn/web/#/152/5334
|
||||
数据结构定义:https://manual.zlg.cn/web/#/152/5335
|
||||
函数说明:https://manual.zlg.cn/web/#/152/5336
|
||||
设备类型号:https://manual.zlg.cn/web/#/152/6361
|
||||
|
||||
### 官方ZLGAPI
|
||||
|
||||
CapMachine.Wpf\CanDrive\ZlgCan\ZLGAPI.cs
|
||||
|
||||
### 官方接口函数使用方法:
|
||||
|
||||
CapMachine.Wpf\CanDrive\ZlgCan\接口函数使用手册.pdf
|
||||
|
||||
### 要求:
|
||||
|
||||
相关的封装内容放到CapMachine.Wpf\CanDrive\ZlgCan下,封装要体现工程化能力,需要考虑性能,后期长时间运行
|
||||
|
||||
功能要全面,我之前用的图莫斯的CAN卡,是另外一套函数,在CapMachine.Wpf\CanDrive 和CapMachine.Wpf\LinDrive 中封装实现,你可以查看
|
||||
|
||||
官方的样例在\CapMachine\Sample\C#_USBCANFD_251215,可借鉴使用
|
||||
|
||||
可以联网查询信息
|
||||
|
||||
需要详细的注释分析过程
|
||||
|
||||
当前提供的CAN和LIN的基础能力,我最终需要的是使用DBC(CAN/CAN FD)和LDF(LIN)配置文件进行读取数据和控制发送
|
||||
@@ -131,6 +131,8 @@ namespace CapMachine.Wpf
|
||||
containerRegistry.RegisterSingleton<CanDriveService>();
|
||||
containerRegistry.RegisterSingleton<CanFdDriveService>();
|
||||
containerRegistry.RegisterSingleton<LinDriveService>();
|
||||
containerRegistry.RegisterSingleton<ZlgCanDriveService>();
|
||||
containerRegistry.RegisterSingleton<ZlgLinDriveService>();
|
||||
containerRegistry.RegisterSingleton<MachineRtDataService>();
|
||||
containerRegistry.RegisterSingleton<DataRecordService>();
|
||||
containerRegistry.RegisterSingleton<HighSpeedDataService>();
|
||||
@@ -181,6 +183,8 @@ namespace CapMachine.Wpf
|
||||
containerRegistry.RegisterForNavigation<CANConfigView, CANConfigViewModel>();
|
||||
containerRegistry.RegisterForNavigation<CANFDConfigView, CANFDConfigViewModel>();
|
||||
containerRegistry.RegisterForNavigation<LINConfigView, LinConfigViewModel>();
|
||||
containerRegistry.RegisterForNavigation<ZlgCanDriveConfigView, ZlgCanDriveConfigViewModel>();
|
||||
containerRegistry.RegisterForNavigation<ZlgLinDriveConfigView, ZlgLinDriveConfigViewModel>();
|
||||
|
||||
|
||||
//注册Dialog视图时绑定VM
|
||||
|
||||
@@ -792,7 +792,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
}
|
||||
|
||||
// 同步值到CAN消息
|
||||
DBCParserByFD.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(msgName), msgPtSend);
|
||||
DBCParserByFD.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(msgName), msgPtSend);
|
||||
var canMsg = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
|
||||
|
||||
// 直接发送此消息,无需通过队列
|
||||
@@ -947,7 +947,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
itemSignal.SignalCmdValue = random.Next(0, 100);
|
||||
DBCParserByFD.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
|
||||
}
|
||||
DBCParserByFD.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
DBCParserByFD.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
SchCanMsg[Index] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CANFD.CANFD_MSG));
|
||||
Index++;
|
||||
}
|
||||
@@ -1003,7 +1003,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
{
|
||||
DBCParserByFD.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
|
||||
}
|
||||
DBCParserByFD.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
DBCParserByFD.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
//每个分组就是一个帧指令/消息数据
|
||||
SchCanMsg[Index] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CANFD.CANFD_MSG));
|
||||
//分配当前消息帧在集合中的位置信息到ListCANScheduleConfig中,方便实时更新时定位帧的位置
|
||||
@@ -1120,99 +1120,6 @@ namespace CapMachine.Wpf.CanDrive
|
||||
/// </summary>
|
||||
private int CycleUpdateIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 循环更新调度表的指令数据
|
||||
/// 定时更新数据到调度表中
|
||||
/// </summary>
|
||||
public void StartCycleUpdateCmd()
|
||||
{
|
||||
CycleUpdateCmdTask = Task.Run(async () =>
|
||||
{
|
||||
while (IsCycleSend)
|
||||
{
|
||||
await Task.Delay(UpdateCycle);
|
||||
try
|
||||
{
|
||||
|
||||
//通过DBC进行对消息赋值
|
||||
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CANFD.CANFD_MSG)));
|
||||
CycleUpdateIndex = 0;
|
||||
//循环给MSG赋值数据,顺序是固定的,跟初始时设置是一样的
|
||||
foreach (var itemMsg in GroupMsg)
|
||||
{
|
||||
foreach (var itemSignal in itemMsg)
|
||||
{
|
||||
//itemSignal.SignalCmdValue = random.Next(0, 100); //仿真测试数据使用
|
||||
DBCParserByFD.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
|
||||
}
|
||||
DBCParserByFD.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
SchCanMsg[CycleUpdateIndex] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CANFD.CANFD_MSG));
|
||||
CycleUpdateIndex++;
|
||||
}
|
||||
|
||||
//通过DBC写入数据后生成CanMsg
|
||||
//将信号值填入CAN消息里面
|
||||
|
||||
//释放申请的临时缓冲区
|
||||
Marshal.FreeHGlobal(msgPtSend);
|
||||
|
||||
//CAN_UpdateSchedule 官网解释
|
||||
// ---MsgTabIndex CAN调度表索引号
|
||||
// ---MsgIndex 开始更新帧起始索引,若起始索引大于调度表帧数,则将帧添加到调度表后面
|
||||
// ---pCanMsg 需要更新的CAN帧指针
|
||||
// ---MsgNum pCanMsgTab里面包含的有效帧数
|
||||
|
||||
//CAN_UpdateSchedule中的MsgIndex表示当前的调度器中的帧Index序号
|
||||
//因为调度表中的帧集合和控制帧的集合和要更新的帧集合都是同一个集合SchCanMsg
|
||||
//默认1号调度表,一个更新所有的帧数据
|
||||
var ret = USB2CANFD.CANFD_UpdateSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)(0), SchCanMsg, (byte)SchCanMsg.Count());//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
|
||||
if (ret == USB2CANFD.CANFD_SUCCESS)
|
||||
{
|
||||
IsSendOk = true;
|
||||
Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex:{(byte)0} -- MsgIndex:{(byte)(0)} ");
|
||||
}
|
||||
else
|
||||
{
|
||||
IsSendOk = false;
|
||||
Console.WriteLine($"Update CAN Schedule Error ret = {ret} -- SchTabIndex:{(byte)0} -- MsgIndex:{(byte)(0)}");
|
||||
//return;
|
||||
}
|
||||
|
||||
//一个报文帧一个报文帧进行更新数据
|
||||
////配置信息 默认启用1号调度器,MsgTabIndex=0;
|
||||
//foreach (var itemMsgSchConfig in ListCANScheduleConfig)
|
||||
//{
|
||||
// //USB2CANFD.CAN_MSG[] SchCanMsg1=new CAN_MSG[1];
|
||||
// //SchCanMsg1[0] = SchCanMsg[itemMsgSchConfig.MsgIndex];
|
||||
|
||||
// // MsgTabIndex CAN调度表索引号 ;MsgIndex 开始更新帧起始索引,若起始索引大于调度表帧数,则将帧添加到调度表后面, ;
|
||||
// // pCanMsg 需要更新的CAN帧指针,消息数据 ; MsgNum pCanMsgTab里面包含的有效帧数,一个调度表对应一个帧/消息,即为:1 (byte)(itemMsgSchConfig.MsgIndex+0)
|
||||
// var ret = USB2CANFD.CAN_UpdateSchedule(DevHandle, WriteCANIndex, (byte)0, (byte)(itemMsgSchConfig.MsgIndex), SchCanMsg, 1);//配置调度表,该函数耗时可能会比较长,但是只需要执行一次即可
|
||||
// if (ret == USB2CANFD.CAN_SUCCESS)
|
||||
// {
|
||||
// Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex:{(byte)itemMsgSchConfig.SchTabIndex} -- MsgIndex:{(byte)(itemMsgSchConfig.MsgIndex)} ");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Console.WriteLine($"Update CAN Schedule Error ret = {ret} -- SchTabIndex:{(byte)itemMsgSchConfig.SchTabIndex} -- MsgIndex:{(byte)(itemMsgSchConfig.MsgIndex)}");
|
||||
// //return;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsSendOk = false;
|
||||
LoggerService.Info($"时间:{DateTime.Now.ToString()}-【MSG】-{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
IsSendOk = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载要发送的数据
|
||||
/// 一般是激活后才注册事件
|
||||
@@ -1257,7 +1164,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void UpdateSchDataByCmdDataChanged()
|
||||
public void UpdateSchDataByCmdDataChanged()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1284,7 +1191,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
var SetSignalValue = DBCParserByFD.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
|
||||
//monitorValueLog.UpdateValue1(SetSignalValue);
|
||||
}
|
||||
var SyncValueToCanMsg = DBCParserByFD.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
var SyncValueToCanMsg = DBCParserByFD.DBC_SyncValueToCANFDMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
|
||||
//monitorValueLog.UpdateValue2(SyncValueToCanMsg);
|
||||
SchCanMsg[CycleUpdateIndex] = (USB2CANFD.CANFD_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CANFD.CANFD_MSG));
|
||||
CycleUpdateIndex++;
|
||||
@@ -1309,7 +1216,7 @@ namespace CapMachine.Wpf.CanDrive
|
||||
if (ret == USB2CANFD.CANFD_SUCCESS)
|
||||
{
|
||||
IsSendOk = true;
|
||||
//Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex:{(byte)0} -- MsgIndex:{(byte)(0)} ");
|
||||
Console.WriteLine($"Update CAN Schedule Success -- SchTabIndex:{(byte)0} -- MsgIndex:{(byte)(0)}-- SchCanMsg.Count():{(SchCanMsg.Count())} ");
|
||||
//monitorValueLog.UpdateValue3(ret);
|
||||
}
|
||||
else
|
||||
@@ -1469,14 +1376,14 @@ namespace CapMachine.Wpf.CanDrive
|
||||
else if (CanNum == 0)
|
||||
{
|
||||
IsReviceOk = false;
|
||||
Console.WriteLine("No CAN data!");
|
||||
//Console.WriteLine("No CAN data!");
|
||||
}
|
||||
else
|
||||
{
|
||||
IsReviceOk = false;
|
||||
Console.WriteLine("Get CAN data error!");
|
||||
}
|
||||
Console.WriteLine("");
|
||||
//Console.WriteLine("");
|
||||
|
||||
//将CAN消息数据填充到信号里面
|
||||
DBCParserByFD.DBC_SyncCANFDMsgToValue(DBCHandle, msgPtRead, CanNum);
|
||||
|
||||
1232
CapMachine.Wpf/CanDrive/ZlgCan/ZLGAPI.cs
Normal file
1232
CapMachine.Wpf/CanDrive/ZlgCan/ZLGAPI.cs
Normal file
File diff suppressed because it is too large
Load Diff
82
CapMachine.Wpf/CanDrive/ZlgCan/ZlgCanChannelOptions.cs
Normal file
82
CapMachine.Wpf/CanDrive/ZlgCan/ZlgCanChannelOptions.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
|
||||
namespace CapMachine.Wpf.CanDrive.ZlgCan
|
||||
{
|
||||
/// <summary>
|
||||
/// ZLG CANFD 通道初始化参数。
|
||||
/// </summary>
|
||||
public sealed class ZlgCanFdChannelOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 仲裁域波特率(单位:bps)。例如 500000。
|
||||
/// </summary>
|
||||
public uint ArbitrationBaudRate { get; set; } = 500000;
|
||||
|
||||
/// <summary>
|
||||
/// 数据域波特率(单位:bps)。例如 2000000。
|
||||
/// </summary>
|
||||
public uint DataBaudRate { get; set; } = 2000000;
|
||||
|
||||
/// <summary>
|
||||
/// 终端电阻。
|
||||
/// </summary>
|
||||
public bool EnableInternalResistance { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 仅监听模式。
|
||||
/// </summary>
|
||||
public bool ListenOnly { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用总线利用率上报。
|
||||
/// </summary>
|
||||
public bool EnableBusUsage { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 总线利用率上报周期(单位:ms)。
|
||||
/// </summary>
|
||||
public int BusUsagePeriodMs { get; set; } = 500;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用设备层“合并接收”(ZCAN_ReceiveData)。
|
||||
/// </summary>
|
||||
public bool EnableMergeReceive { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 合并接收缓冲区最大帧数量。
|
||||
/// </summary>
|
||||
public int MergeReceiveBufferFrames { get; set; } = 100;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ZLG LIN 通道初始化参数。
|
||||
/// </summary>
|
||||
public sealed class ZlgLinChannelOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// LIN 模式:true=主节点,false=从节点。
|
||||
/// </summary>
|
||||
public bool IsMaster { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 校验模式。
|
||||
/// 1-经典校验,2-增强校验,3-自动。
|
||||
/// </summary>
|
||||
public byte ChecksumMode { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据长度(8~64)。
|
||||
/// </summary>
|
||||
public byte MaxLength { get; set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 波特率(1000~20000)。
|
||||
/// </summary>
|
||||
public uint BaudRate { get; set; } = 19200;
|
||||
|
||||
/// <summary>
|
||||
/// LIN 接收轮询等待时间(ms)。
|
||||
/// </summary>
|
||||
public int ReceiveWaitMs { get; set; } = 10;
|
||||
}
|
||||
}
|
||||
1428
CapMachine.Wpf/CanDrive/ZlgCan/ZlgCanFd200uDriver.cs
Normal file
1428
CapMachine.Wpf/CanDrive/ZlgCan/ZlgCanFd200uDriver.cs
Normal file
File diff suppressed because it is too large
Load Diff
62
CapMachine.Wpf/CanDrive/ZlgCan/ZlgCanIdHelper.cs
Normal file
62
CapMachine.Wpf/CanDrive/ZlgCan/ZlgCanIdHelper.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
|
||||
namespace CapMachine.Wpf.CanDrive.ZlgCan
|
||||
{
|
||||
/// <summary>
|
||||
/// ZLG CAN ID 帮助类。
|
||||
/// </summary>
|
||||
public static class ZlgCanIdHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成 ZLG/SocketCAN 风格的 can_id(包含扩展帧/远程帧/错误帧标志位)。
|
||||
/// </summary>
|
||||
/// <param name="id">CAN 标识符(标准帧 11bit:0~0x7FF;扩展帧 29bit:0~0x1FFFFFFF)。</param>
|
||||
/// <param name="isExtended">是否为扩展帧。</param>
|
||||
/// <param name="isRemote">是否为远程帧(RTR)。</param>
|
||||
/// <param name="isError">是否为错误帧。</param>
|
||||
/// <returns>包含标志位的 can_id。</returns>
|
||||
public static uint MakeCanId(uint id, bool isExtended, bool isRemote, bool isError)
|
||||
{
|
||||
// 兼容官方样例写法:bit31 扩展帧,bit30 RTR,bit29 ERR
|
||||
// 注意:该函数不做强约束校验(例如扩展帧 29bit),上层可按需要增加校验。
|
||||
uint canId = id & 0x1FFFFFFF;
|
||||
|
||||
if (isExtended)
|
||||
{
|
||||
canId |= 1u << 31;
|
||||
}
|
||||
|
||||
if (isRemote)
|
||||
{
|
||||
canId |= 1u << 30;
|
||||
}
|
||||
|
||||
if (isError)
|
||||
{
|
||||
canId |= 1u << 29;
|
||||
}
|
||||
|
||||
return canId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 can_id 中提取 29bit 标识符。
|
||||
/// </summary>
|
||||
/// <param name="canId">包含标志位的 can_id。</param>
|
||||
/// <returns>29bit 标识符。</returns>
|
||||
public static uint GetArbitrationId(uint canId)
|
||||
{
|
||||
return canId & 0x1FFFFFFF;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断 can_id 是否为扩展帧。
|
||||
/// </summary>
|
||||
/// <param name="canId">包含标志位的 can_id。</param>
|
||||
/// <returns>是否扩展帧。</returns>
|
||||
public static bool IsExtended(uint canId)
|
||||
{
|
||||
return (canId & (1u << 31)) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
570
CapMachine.Wpf/CanDrive/ZlgCan/ZlgDbcDatabase.cs
Normal file
570
CapMachine.Wpf/CanDrive/ZlgCan/ZlgDbcDatabase.cs
Normal file
@@ -0,0 +1,570 @@
|
||||
using CapMachine.Wpf.CanDrive;
|
||||
using CapMachine.Wpf.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace CapMachine.Wpf.CanDrive.ZlgCan
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于周立功 ZDBC(zdbc.dll)的 DBC 数据库封装。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 设计要点:
|
||||
/// - zdbc.dll 为原生依赖,必须放置在程序输出目录(AppContext.BaseDirectory)。
|
||||
/// - 本类封装 DBC 文件加载、消息/信号枚举、以及基于 DBCMessage 的编码/解码能力。
|
||||
/// - 运行稳定性:实现 IDisposable,确保 ZDBC_Release 与相关非托管内存释放。
|
||||
/// </remarks>
|
||||
public sealed class ZlgDbcDatabase : IDisposable
|
||||
{
|
||||
private readonly ILogService _log;
|
||||
private readonly object _sync = new object();
|
||||
|
||||
private uint _dbcHandle;
|
||||
private bool _disposed;
|
||||
|
||||
// 复用非托管缓冲,避免高频 Allocate/Free
|
||||
private IntPtr _msgPtr = IntPtr.Zero;
|
||||
private IntPtr _countPtr = IntPtr.Zero;
|
||||
private IntPtr _canFramePtr = IntPtr.Zero;
|
||||
private IntPtr _canFdFramePtr = IntPtr.Zero;
|
||||
|
||||
private readonly Dictionary<string, ZDBC.DBCMessage> _messageByName = new Dictionary<string, ZDBC.DBCMessage>(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, uint> _messageIdByName = new Dictionary<string, uint>(StringComparer.Ordinal);
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数。
|
||||
/// </summary>
|
||||
/// <param name="logService">日志服务。</param>
|
||||
public ZlgDbcDatabase(ILogService logService)
|
||||
{
|
||||
_log = logService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已加载。
|
||||
/// </summary>
|
||||
public bool IsLoaded
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dbcHandle != 0 && _dbcHandle != ZDBC.INVALID_DBC_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载 DBC 文件。
|
||||
/// </summary>
|
||||
/// <param name="dbcPath">DBC 文件路径。</param>
|
||||
/// <param name="enableAsyncAnalyse">是否启用异步解析(库内部线程)。</param>
|
||||
/// <param name="merge">是否合并到当前数据库(支持加载多个文件)。</param>
|
||||
/// <param name="protocolType">协议类型:J1939=0,其他=1。</param>
|
||||
public void Load(string dbcPath, bool enableAsyncAnalyse = true, bool merge = false, byte protocolType = ZDBC.PROTOCOL_OTHER)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(dbcPath))
|
||||
{
|
||||
throw new ArgumentException("dbcPath 不能为空。", nameof(dbcPath));
|
||||
}
|
||||
|
||||
EnsureNativeDllExists("zdbc.dll");
|
||||
|
||||
if (!File.Exists(dbcPath))
|
||||
{
|
||||
throw new FileNotFoundException("DBC 文件不存在。", dbcPath);
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (_dbcHandle == 0 || _dbcHandle == ZDBC.INVALID_DBC_HANDLE)
|
||||
{
|
||||
_dbcHandle = ZDBC.ZDBC_Init(0, enableAsyncAnalyse ? (byte)1 : (byte)0);
|
||||
if (_dbcHandle == ZDBC.INVALID_DBC_HANDLE)
|
||||
{
|
||||
_dbcHandle = 0;
|
||||
throw new InvalidOperationException("ZDBC_Init 初始化失败。");
|
||||
}
|
||||
}
|
||||
|
||||
var fileInfo = new ZDBC.FileInfo
|
||||
{
|
||||
strFilePath = BuildFixedPathBytes(dbcPath, ZDBC._MAX_FILE_PATH_ + 1),
|
||||
type = protocolType,
|
||||
merge = (byte)(merge ? 1 : 0)
|
||||
};
|
||||
|
||||
IntPtr pFile = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.FileInfo)));
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr(fileInfo, pFile, false);
|
||||
var ok = ZDBC.ZDBC_LoadFile(_dbcHandle, pFile);
|
||||
if (!ok)
|
||||
{
|
||||
throw new InvalidOperationException("ZDBC_LoadFile 失败,请检查 DBC 文件格式。");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pFile);
|
||||
}
|
||||
|
||||
RefreshMessageCache_NoLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 枚举 DBC 内全部 Message/Signal 元信息,并转换为 UI 使用的 CanDbcModel 集合。
|
||||
/// </summary>
|
||||
/// <returns>信号集合。</returns>
|
||||
public ObservableCollection<CanDbcModel> BuildCanDbcModels()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (!IsLoaded)
|
||||
{
|
||||
return new ObservableCollection<CanDbcModel>();
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
var list = new List<CanDbcModel>();
|
||||
|
||||
foreach (var kv in _messageByName)
|
||||
{
|
||||
var msg = kv.Value;
|
||||
var msgName = ByteArrayToAsciiString(msg.strName);
|
||||
var msgIdStr = "0x" + msg.nID.ToString("X8");
|
||||
|
||||
var signals = msg.vSignals;
|
||||
if (signals == null || signals.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var signalCount = (int)Math.Min(msg.nSignalCount, (uint)signals.Length);
|
||||
for (int i = 0; i < signalCount; i++)
|
||||
{
|
||||
var s = signals[i];
|
||||
var sigName = ByteArrayToAsciiString(s.strName);
|
||||
if (string.IsNullOrWhiteSpace(sigName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list.Add(new CanDbcModel
|
||||
{
|
||||
MsgName = msgName,
|
||||
MsgId = msgIdStr,
|
||||
SignalName = sigName,
|
||||
SignalDesc = ByteArrayToAsciiString(s.strComment),
|
||||
SignalUnit = ByteArrayToAsciiString(s.unit),
|
||||
SignalRtValue = "--",
|
||||
Publisher = string.Empty
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return new ObservableCollection<CanDbcModel>(list);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 MsgName 获取 Message ID。
|
||||
/// </summary>
|
||||
/// <param name="msgName">消息名称。</param>
|
||||
/// <returns>Message ID。</returns>
|
||||
public uint GetMessageIdByName(string msgName)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (string.IsNullOrWhiteSpace(msgName)) return 0;
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
return _messageIdByName.TryGetValue(msgName, out var id) ? id : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 MsgName + 信号值集合编码为 CAN/CANFD 原始帧。
|
||||
/// </summary>
|
||||
/// <param name="msgName">消息名称。</param>
|
||||
/// <param name="signals">信号值(SignalName -> 实际值)。</param>
|
||||
/// <param name="frameType">帧类型:FT_CAN=0,FT_CANFD=1。</param>
|
||||
/// <returns>编码后的 can_id 与数据。</returns>
|
||||
public (uint CanId, byte[] Data, int DataLen) EncodeToRawFrame(string msgName, IDictionary<string, double> signals, byte frameType)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (!IsLoaded)
|
||||
{
|
||||
throw new InvalidOperationException("DBC 未加载。");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msgName))
|
||||
{
|
||||
throw new ArgumentException("msgName 不能为空。", nameof(msgName));
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_messageByName.TryGetValue(msgName, out var msg))
|
||||
{
|
||||
throw new InvalidOperationException($"DBC 中未找到消息:{msgName}");
|
||||
}
|
||||
|
||||
// 在副本上修改信号,避免污染缓存
|
||||
var workingMsg = msg;
|
||||
if (workingMsg.vSignals == null)
|
||||
{
|
||||
workingMsg.vSignals = new ZDBC.DBCSignal[ZDBC._DBC_SIGNAL_MAX_COUNT_];
|
||||
}
|
||||
|
||||
if (signals != null)
|
||||
{
|
||||
foreach (var kv in signals)
|
||||
{
|
||||
SetSignalActualValue(ref workingMsg, kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
EnsureMarshalBuffers_NoLock();
|
||||
|
||||
// 写入 msg 到非托管
|
||||
Marshal.StructureToPtr(workingMsg, _msgPtr, false);
|
||||
|
||||
// nCount 输入输出参数,准备 1 帧
|
||||
Marshal.WriteInt32(_countPtr, 1);
|
||||
|
||||
if (frameType == ZDBC.FT_CAN)
|
||||
{
|
||||
var ok = ZDBC.ZDBC_Encode(_dbcHandle, _canFramePtr, _countPtr, _msgPtr, frameType);
|
||||
if (!ok)
|
||||
{
|
||||
throw new InvalidOperationException("ZDBC_Encode(CAN) 失败。");
|
||||
}
|
||||
|
||||
var frame = (ZlgNativeCanFrame)Marshal.PtrToStructure(_canFramePtr, typeof(ZlgNativeCanFrame));
|
||||
var len = Math.Min(8, (int)frame.can_dlc);
|
||||
var data = new byte[len];
|
||||
if (len > 0 && frame.data != null)
|
||||
{
|
||||
Array.Copy(frame.data, data, len);
|
||||
}
|
||||
|
||||
return (frame.can_id, data, len);
|
||||
}
|
||||
|
||||
if (frameType == ZDBC.FT_CANFD)
|
||||
{
|
||||
var ok = ZDBC.ZDBC_Encode(_dbcHandle, _canFdFramePtr, _countPtr, _msgPtr, frameType);
|
||||
if (!ok)
|
||||
{
|
||||
throw new InvalidOperationException("ZDBC_Encode(CANFD) 失败。");
|
||||
}
|
||||
|
||||
var frame = (ZlgNativeCanFdFrame)Marshal.PtrToStructure(_canFdFramePtr, typeof(ZlgNativeCanFdFrame));
|
||||
var len = Math.Min(64, (int)frame.len);
|
||||
var data = new byte[len];
|
||||
if (len > 0 && frame.data != null)
|
||||
{
|
||||
Array.Copy(frame.data, data, len);
|
||||
}
|
||||
|
||||
return (frame.can_id, data, len);
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(frameType), "frameType 仅支持 FT_CAN=0 或 FT_CANFD=1。");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将原始 CAN/CANFD 帧解码为 DBCMessage,并返回消息名称与信号实际值。
|
||||
/// </summary>
|
||||
/// <param name="canId">can_id。</param>
|
||||
/// <param name="data">payload。</param>
|
||||
/// <param name="frameType">帧类型:FT_CAN=0,FT_CANFD=1。</param>
|
||||
/// <returns>解码结果。</returns>
|
||||
public (string MsgName, Dictionary<string, double> Signals) DecodeRawFrame(uint canId, byte[] data, byte frameType)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (!IsLoaded)
|
||||
{
|
||||
throw new InvalidOperationException("DBC 未加载。");
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
EnsureMarshalBuffers_NoLock();
|
||||
|
||||
if (frameType == ZDBC.FT_CAN)
|
||||
{
|
||||
var frame = ZlgNativeCanFrame.Create(canId, data ?? Array.Empty<byte>(), requestTxEcho: false);
|
||||
Marshal.StructureToPtr(frame, _canFramePtr, false);
|
||||
|
||||
var ok = ZDBC.ZDBC_Decode(_dbcHandle, _msgPtr, _canFramePtr, 1, frameType);
|
||||
if (!ok)
|
||||
{
|
||||
return (string.Empty, new Dictionary<string, double>());
|
||||
}
|
||||
|
||||
var msg = Marshal.PtrToStructure<ZDBC.DBCMessage>(_msgPtr);
|
||||
return ExtractActualSignals(msg);
|
||||
}
|
||||
|
||||
if (frameType == ZDBC.FT_CANFD)
|
||||
{
|
||||
var frame = ZlgNativeCanFdFrame.Create(canId, data ?? Array.Empty<byte>(), requestTxEcho: false);
|
||||
Marshal.StructureToPtr(frame, _canFdFramePtr, false);
|
||||
|
||||
var ok = ZDBC.ZDBC_Decode(_dbcHandle, _msgPtr, _canFdFramePtr, 1, frameType);
|
||||
if (!ok)
|
||||
{
|
||||
return (string.Empty, new Dictionary<string, double>());
|
||||
}
|
||||
|
||||
var msg = Marshal.PtrToStructure<ZDBC.DBCMessage>(_msgPtr);
|
||||
return ExtractActualSignals(msg);
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(frameType), "frameType 仅支持 FT_CAN=0 或 FT_CANFD=1。");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_dbcHandle != 0 && _dbcHandle != ZDBC.INVALID_DBC_HANDLE)
|
||||
{
|
||||
ZDBC.ZDBC_Release(_dbcHandle);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn($"ZDBC_Release 异常:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dbcHandle = 0;
|
||||
}
|
||||
|
||||
FreeMarshalBuffers_NoLock();
|
||||
_messageByName.Clear();
|
||||
_messageIdByName.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshMessageCache_NoLock()
|
||||
{
|
||||
_messageByName.Clear();
|
||||
_messageIdByName.Clear();
|
||||
|
||||
if (!IsLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureMarshalBuffers_NoLock();
|
||||
|
||||
// 遍历消息
|
||||
var msg = new ZDBC.DBCMessage
|
||||
{
|
||||
vSignals = new ZDBC.DBCSignal[ZDBC._DBC_SIGNAL_MAX_COUNT_],
|
||||
strName = new byte[ZDBC._DBC_NAME_LENGTH_ + 1],
|
||||
strComment = new byte[ZDBC._DBC_COMMENT_MAX_LENGTH_ + 1]
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(msg, _msgPtr, false);
|
||||
var ok = ZDBC.ZDBC_GetFirstMessage(_dbcHandle, _msgPtr);
|
||||
while (ok)
|
||||
{
|
||||
var m = Marshal.PtrToStructure<ZDBC.DBCMessage>(_msgPtr);
|
||||
var name = ByteArrayToAsciiString(m.strName);
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
_messageByName[name] = m;
|
||||
_messageIdByName[name] = m.nID;
|
||||
}
|
||||
|
||||
Marshal.StructureToPtr(msg, _msgPtr, false);
|
||||
ok = ZDBC.ZDBC_GetNextMessage(_dbcHandle, _msgPtr);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureMarshalBuffers_NoLock()
|
||||
{
|
||||
if (_msgPtr == IntPtr.Zero)
|
||||
{
|
||||
_msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage)));
|
||||
}
|
||||
|
||||
if (_countPtr == IntPtr.Zero)
|
||||
{
|
||||
_countPtr = Marshal.AllocHGlobal(sizeof(int));
|
||||
}
|
||||
|
||||
if (_canFramePtr == IntPtr.Zero)
|
||||
{
|
||||
_canFramePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZlgNativeCanFrame)));
|
||||
}
|
||||
|
||||
if (_canFdFramePtr == IntPtr.Zero)
|
||||
{
|
||||
_canFdFramePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZlgNativeCanFdFrame)));
|
||||
}
|
||||
}
|
||||
|
||||
private void FreeMarshalBuffers_NoLock()
|
||||
{
|
||||
if (_canFdFramePtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(_canFdFramePtr);
|
||||
_canFdFramePtr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (_canFramePtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(_canFramePtr);
|
||||
_canFramePtr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (_countPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(_countPtr);
|
||||
_countPtr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (_msgPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(_msgPtr);
|
||||
_msgPtr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureNativeDllExists(string dllName)
|
||||
{
|
||||
var baseDir = AppContext.BaseDirectory;
|
||||
var full = Path.Combine(baseDir, dllName);
|
||||
if (!File.Exists(full))
|
||||
{
|
||||
throw new FileNotFoundException($"未找到 {dllName},请将其复制到程序输出目录:{baseDir}", full);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSignalActualValue(ref ZDBC.DBCMessage msg, string signalName, double actualValue)
|
||||
{
|
||||
if (msg.vSignals == null || msg.vSignals.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var count = (int)Math.Min(msg.nSignalCount, (uint)msg.vSignals.Length);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var s = msg.vSignals[i];
|
||||
var name = ByteArrayToAsciiString(s.strName);
|
||||
if (!string.Equals(name, signalName, StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 使用 ZDBC_CalcRawValue 做实际值->原始值转换
|
||||
IntPtr pSgl = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal)));
|
||||
IntPtr pVal = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double)));
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr(s, pSgl, false);
|
||||
Marshal.StructureToPtr(actualValue, pVal, false);
|
||||
var raw = ZDBC.ZDBC_CalcRawValue(pSgl, pVal);
|
||||
msg.vSignals[i].nRawvalue = raw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pVal);
|
||||
Marshal.FreeHGlobal(pSgl);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private (string MsgName, Dictionary<string, double> Signals) ExtractActualSignals(ZDBC.DBCMessage msg)
|
||||
{
|
||||
var msgName = ByteArrayToAsciiString(msg.strName);
|
||||
var dict = new Dictionary<string, double>(StringComparer.Ordinal);
|
||||
|
||||
if (msg.vSignals == null)
|
||||
{
|
||||
return (msgName, dict);
|
||||
}
|
||||
|
||||
var count = (int)Math.Min(msg.nSignalCount, (uint)msg.vSignals.Length);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var s = msg.vSignals[i];
|
||||
var name = ByteArrayToAsciiString(s.strName);
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 使用 ZDBC_CalcActualValue 做原始值->实际值转换
|
||||
IntPtr pSgl = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal)));
|
||||
IntPtr pRaw = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ulong)));
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr(s, pSgl, false);
|
||||
Marshal.StructureToPtr(s.nRawvalue, pRaw, false);
|
||||
var actual = ZDBC.ZDBC_CalcActualValue(pSgl, pRaw);
|
||||
dict[name] = actual;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pRaw);
|
||||
Marshal.FreeHGlobal(pSgl);
|
||||
}
|
||||
}
|
||||
|
||||
return (msgName, dict);
|
||||
}
|
||||
|
||||
private static byte[] BuildFixedPathBytes(string path, int fixedLen)
|
||||
{
|
||||
var bytes = Encoding.ASCII.GetBytes(path);
|
||||
var dst = new byte[fixedLen];
|
||||
Array.Clear(dst, 0, dst.Length);
|
||||
Array.Copy(bytes, 0, dst, 0, Math.Min(bytes.Length, fixedLen - 1));
|
||||
return dst;
|
||||
}
|
||||
|
||||
private static string ByteArrayToAsciiString(byte[]? bytes)
|
||||
{
|
||||
if (bytes == null || bytes.Length == 0) return string.Empty;
|
||||
|
||||
int len = Array.IndexOf(bytes, (byte)0);
|
||||
if (len < 0) len = bytes.Length;
|
||||
|
||||
return Encoding.ASCII.GetString(bytes, 0, len).Trim();
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZlgDbcDatabase));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
103
CapMachine.Wpf/CanDrive/ZlgCan/ZlgNativeFrames.cs
Normal file
103
CapMachine.Wpf/CanDrive/ZlgCan/ZlgNativeFrames.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CapMachine.Wpf.CanDrive.ZlgCan
|
||||
{
|
||||
/// <summary>
|
||||
/// 供 DBC 编解码/Marshal 使用的原生 CAN 帧结构(与 zlgcan can_frame 二进制布局兼容)。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ZlgNativeCanFrame
|
||||
{
|
||||
public uint can_id;
|
||||
public byte can_dlc;
|
||||
public byte __pad;
|
||||
public byte __res0;
|
||||
public byte __res1;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] data;
|
||||
|
||||
/// <summary>
|
||||
/// 创建 CAN 帧。
|
||||
/// </summary>
|
||||
/// <param name="canId">can_id(包含扩展帧等标志位)。</param>
|
||||
/// <param name="payload">数据(0~8)。</param>
|
||||
/// <param name="requestTxEcho">是否请求发送回显。</param>
|
||||
/// <returns>原生 CAN 帧。</returns>
|
||||
public static ZlgNativeCanFrame Create(uint canId, byte[] payload, bool requestTxEcho)
|
||||
{
|
||||
var len = Math.Min(8, payload?.Length ?? 0);
|
||||
var frame = new ZlgNativeCanFrame
|
||||
{
|
||||
can_id = canId,
|
||||
can_dlc = (byte)len,
|
||||
__pad = 0,
|
||||
__res0 = 0,
|
||||
__res1 = 0,
|
||||
data = new byte[8]
|
||||
};
|
||||
|
||||
if (len > 0 && payload != null)
|
||||
{
|
||||
Array.Copy(payload, frame.data, len);
|
||||
}
|
||||
|
||||
if (requestTxEcho)
|
||||
{
|
||||
frame.__pad |= 0x20;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 供 DBC 编解码/Marshal 使用的原生 CANFD 帧结构(与 zlgcan canfd_frame 二进制布局兼容)。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ZlgNativeCanFdFrame
|
||||
{
|
||||
public uint can_id;
|
||||
public byte len;
|
||||
public byte flags;
|
||||
public byte __res0;
|
||||
public byte __res1;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
|
||||
public byte[] data;
|
||||
|
||||
/// <summary>
|
||||
/// 创建 CANFD 帧。
|
||||
/// </summary>
|
||||
/// <param name="canId">can_id(包含扩展帧等标志位)。</param>
|
||||
/// <param name="payload">数据(0~64)。</param>
|
||||
/// <param name="requestTxEcho">是否请求发送回显。</param>
|
||||
/// <returns>原生 CANFD 帧。</returns>
|
||||
public static ZlgNativeCanFdFrame Create(uint canId, byte[] payload, bool requestTxEcho)
|
||||
{
|
||||
var len = Math.Min(64, payload?.Length ?? 0);
|
||||
var frame = new ZlgNativeCanFdFrame
|
||||
{
|
||||
can_id = canId,
|
||||
len = (byte)len,
|
||||
flags = 0,
|
||||
__res0 = 0,
|
||||
__res1 = 0,
|
||||
data = new byte[64]
|
||||
};
|
||||
|
||||
if (len > 0 && payload != null)
|
||||
{
|
||||
Array.Copy(payload, frame.data, len);
|
||||
}
|
||||
|
||||
if (requestTxEcho)
|
||||
{
|
||||
frame.flags |= 0x20;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
CapMachine.Wpf/CanDrive/ZlgCan/接口函数使用手册.pdf
Normal file
BIN
CapMachine.Wpf/CanDrive/ZlgCan/接口函数使用手册.pdf
Normal file
Binary file not shown.
@@ -79,6 +79,8 @@ namespace CapMachine.Wpf.Services
|
||||
MenuItems.Add(new NavigationItem("", "CAN配置", "CANConfigView"));
|
||||
MenuItems.Add(new NavigationItem("", "CANFD配置", "CANFDConfigView"));
|
||||
MenuItems.Add(new NavigationItem("", "LIN配置", "LINConfigView"));
|
||||
MenuItems.Add(new NavigationItem("", "ZLG CAN配置", "ZlgCanDriveConfigView"));
|
||||
MenuItems.Add(new NavigationItem("", "ZLG LIN配置", "ZlgLinDriveConfigView"));
|
||||
MenuItems.Add(new NavigationItem("", "工艺参数", "ProConfigView"));
|
||||
MenuItems.Add(new NavigationItem("", "工艺曲线", "RealTimeChartView"));
|
||||
MenuItems.Add(new NavigationItem("", "动作日志", "ActionLogView"));
|
||||
|
||||
320
CapMachine.Wpf/Services/ZlgCanDriveService.cs
Normal file
320
CapMachine.Wpf/Services/ZlgCanDriveService.cs
Normal file
@@ -0,0 +1,320 @@
|
||||
using CapMachine.Model.CANLIN;
|
||||
using CapMachine.Wpf.CanDrive;
|
||||
using CapMachine.Wpf.CanDrive.ZlgCan;
|
||||
using ImTools;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace CapMachine.Wpf.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// ZLG CAN/CANFD 驱动服务(共享设备句柄)。
|
||||
/// </summary>
|
||||
public sealed class ZlgCanDriveService : BindableBase
|
||||
{
|
||||
private readonly ILogService _log;
|
||||
|
||||
/// <summary>
|
||||
/// 共享的 ZLG 驱动实例(CAN/CANFD/LIN)。
|
||||
/// </summary>
|
||||
public ZlgCanFd200uDriver Driver { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的配置程序(沿用原有 FreeSql 模型)。
|
||||
/// </summary>
|
||||
public CanLinConfigPro? SelectedCanLinConfigPro { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dbc 消息集合(用于 UI 绑定)。
|
||||
/// </summary>
|
||||
public ObservableCollection<CanDbcModel> ListCanDbcModel { get; private set; } = new ObservableCollection<CanDbcModel>();
|
||||
|
||||
private bool _dbcParserState;
|
||||
/// <summary>
|
||||
/// DBC 解析状态。
|
||||
/// </summary>
|
||||
public bool DbcParserState
|
||||
{
|
||||
get { return _dbcParserState; }
|
||||
private set { _dbcParserState = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private bool _openState;
|
||||
/// <summary>
|
||||
/// 设备打开状态。
|
||||
/// </summary>
|
||||
public bool OpenState
|
||||
{
|
||||
get { return _openState; }
|
||||
private set { _openState = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private ZlgCanMode _mode;
|
||||
/// <summary>
|
||||
/// CAN 模式(单选:CAN 或 CANFD)。
|
||||
/// </summary>
|
||||
public ZlgCanMode Mode
|
||||
{
|
||||
get { return _mode; }
|
||||
set { _mode = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送使能(与 UI 的调度表使能语义对齐)。
|
||||
/// </summary>
|
||||
public bool SchEnable
|
||||
{
|
||||
get { return Driver.SchEnable; }
|
||||
set { Driver.SchEnable = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用事件驱动发送。
|
||||
/// </summary>
|
||||
public bool IsCycleSend
|
||||
{
|
||||
get { return Driver.IsCycleSend; }
|
||||
set { Driver.IsCycleSend = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否正在循环接收(对齐 Toomoss:IsCycleRevice)。
|
||||
/// </summary>
|
||||
public bool IsCycleRevice
|
||||
{
|
||||
get { return Driver.IsReceiving; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最近是否发送成功(用于 UI 指示)。
|
||||
/// </summary>
|
||||
public bool IsSendOk
|
||||
{
|
||||
get { return Driver.IsSendOk; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最近是否接收成功(用于 UI 指示)。
|
||||
/// </summary>
|
||||
public bool IsReviceOk
|
||||
{
|
||||
get { return Driver.IsReviceOk; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 要发送的 CAN 指令数据。
|
||||
/// </summary>
|
||||
public List<CanCmdData> CmdData { get; } = new List<CanCmdData>();
|
||||
|
||||
private CanCmdData? SpeedCanCmdData { get; set; }
|
||||
|
||||
private uint _deviceIndex = 0;
|
||||
private ZlgCanFdChannelOptions _channel0 = new ZlgCanFdChannelOptions();
|
||||
|
||||
/// <summary>
|
||||
/// 构造。
|
||||
/// </summary>
|
||||
/// <param name="logService">日志服务。</param>
|
||||
public ZlgCanDriveService(ILogService logService)
|
||||
{
|
||||
_log = logService;
|
||||
Driver = new ZlgCanFd200uDriver(logService);
|
||||
|
||||
Driver.PropertyChanged += (_, __) =>
|
||||
{
|
||||
OpenState = Driver.OpenState;
|
||||
RaisePropertyChanged(nameof(IsCycleRevice));
|
||||
RaisePropertyChanged(nameof(IsSendOk));
|
||||
RaisePropertyChanged(nameof(IsReviceOk));
|
||||
};
|
||||
|
||||
OpenState = Driver.OpenState;
|
||||
Mode = ZlgCanMode.Can;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 CAN 配置信息,并将配置中的名称映射到 DBC 信号集合(用于 UI 显示)。
|
||||
/// </summary>
|
||||
/// <param name="selectedCanLinConfigPro">选中的配置。</param>
|
||||
public void InitCanConfig(CanLinConfigPro selectedCanLinConfigPro)
|
||||
{
|
||||
SelectedCanLinConfigPro = selectedCanLinConfigPro;
|
||||
if (SelectedCanLinConfigPro?.CanLinConfigContents == null) return;
|
||||
|
||||
foreach (var item in SelectedCanLinConfigPro.CanLinConfigContents)
|
||||
{
|
||||
var find = ListCanDbcModel.FindFirst(a => a.SignalName == item.SignalName);
|
||||
if (find != null)
|
||||
{
|
||||
find.Name = item.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新配置(从 DTO/DB 同步到驱动)。
|
||||
/// </summary>
|
||||
/// <param name="deviceIndex">设备索引。</param>
|
||||
/// <param name="arbBaudRate">仲裁波特率(bps)。</param>
|
||||
/// <param name="dataBaudRate">数据波特率(bps)。</param>
|
||||
/// <param name="resEnable">终端电阻使能。</param>
|
||||
/// <param name="mergeReceive">是否合并接收。</param>
|
||||
/// <param name="mergeReceiveBufferFrames">合并接收缓冲帧数。</param>
|
||||
public void UpdateConfig(uint deviceIndex, uint arbBaudRate, uint dataBaudRate, bool resEnable, bool mergeReceive = false, int mergeReceiveBufferFrames = 100)
|
||||
{
|
||||
_deviceIndex = deviceIndex;
|
||||
_channel0.ArbitrationBaudRate = arbBaudRate;
|
||||
_channel0.DataBaudRate = dataBaudRate;
|
||||
_channel0.EnableInternalResistance = resEnable;
|
||||
_channel0.EnableMergeReceive = mergeReceive;
|
||||
_channel0.MergeReceiveBufferFrames = mergeReceiveBufferFrames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 CAN/CANFD(按 Mode)。
|
||||
/// </summary>
|
||||
public void StartCanDrive()
|
||||
{
|
||||
if (OpenState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Driver.OpenAndInitCan(_deviceIndex, _channel0);
|
||||
Driver.StartReceiveLoop(_channel0.EnableMergeReceive, _channel0.MergeReceiveBufferFrames);
|
||||
OpenState = Driver.OpenState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使能/停止循环接收。
|
||||
/// </summary>
|
||||
/// <param name="enable">true=启动接收线程,false=停止接收线程。</param>
|
||||
public void SetReceiveEnabled(bool enable)
|
||||
{
|
||||
if (!OpenState)
|
||||
{
|
||||
throw new InvalidOperationException("设备未连接,无法切换循环接收。");
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (!Driver.IsReceiving)
|
||||
{
|
||||
Driver.StartReceiveLoop(_channel0.EnableMergeReceive, _channel0.MergeReceiveBufferFrames);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Driver.IsReceiving)
|
||||
{
|
||||
Driver.StopReceiveLoop();
|
||||
}
|
||||
}
|
||||
|
||||
RaisePropertyChanged(nameof(IsCycleRevice));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭设备(会同时关闭共享的 LIN 通道)。
|
||||
/// </summary>
|
||||
public void CloseDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
Driver.Close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
OpenState = Driver.OpenState;
|
||||
DbcParserState = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载 DBC。
|
||||
/// </summary>
|
||||
/// <param name="path">DBC 路径。</param>
|
||||
public ObservableCollection<CanDbcModel> StartDbc(string path)
|
||||
{
|
||||
if (!OpenState)
|
||||
{
|
||||
throw new InvalidOperationException("请先打开设备后再加载 DBC。");
|
||||
}
|
||||
|
||||
ListCanDbcModel = Driver.StartDbc(path);
|
||||
DbcParserState = ListCanDbcModel != null && ListCanDbcModel.Count > 0;
|
||||
return ListCanDbcModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载要发送的数据(订阅数据变化事件)。
|
||||
/// </summary>
|
||||
/// <param name="cmdData">指令数据集合。</param>
|
||||
public void LoadCmdDataToDrive(List<CanCmdData> cmdData)
|
||||
{
|
||||
var list = cmdData ?? new List<CanCmdData>();
|
||||
|
||||
CmdData.Clear();
|
||||
CmdData.AddRange(list);
|
||||
|
||||
foreach (var item in CmdData)
|
||||
{
|
||||
if (string.Equals(item.ConfigName, "转速", StringComparison.Ordinal))
|
||||
{
|
||||
SpeedCanCmdData = item;
|
||||
}
|
||||
}
|
||||
|
||||
Driver.LoadCmdDataToDrive(CmdData, channelIndex: 0, frameType: Mode == ZlgCanMode.Can ? (byte)ZDBC.FT_CAN : (byte)ZDBC.FT_CANFD);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动发送(目前对齐原服务:仅发送转速)。
|
||||
/// </summary>
|
||||
/// <param name="speedData">转速。</param>
|
||||
public void SendMsgToCanDrive(double speedData)
|
||||
{
|
||||
if (!OpenState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SpeedCanCmdData != null)
|
||||
{
|
||||
SpeedCanCmdData.SignalCmdValue = speedData;
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Warn("未配置转速指令项(ConfigName=转速),忽略手动发送。");
|
||||
}
|
||||
|
||||
// 若未启用事件驱动发送,则这里主动发送一次(与旧行为兼容)
|
||||
if (!IsCycleSend || !SchEnable)
|
||||
{
|
||||
var firstMsg = CmdData.FirstOrDefault()?.MsgName;
|
||||
if (!string.IsNullOrWhiteSpace(firstMsg))
|
||||
{
|
||||
Driver.SendOneMsgByCmdData(firstMsg, 0, Mode == ZlgCanMode.Can ? (byte)ZDBC.FT_CAN : (byte)ZDBC.FT_CANFD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ZLG CAN 工作模式。
|
||||
/// </summary>
|
||||
public enum ZlgCanMode
|
||||
{
|
||||
/// <summary>
|
||||
/// CAN 经典帧。
|
||||
/// </summary>
|
||||
Can = 0,
|
||||
/// <summary>
|
||||
/// CAN FD。
|
||||
/// </summary>
|
||||
CanFd = 1
|
||||
}
|
||||
}
|
||||
157
CapMachine.Wpf/Services/ZlgLinDriveService.cs
Normal file
157
CapMachine.Wpf/Services/ZlgLinDriveService.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
using CapMachine.Model.CANLIN;
|
||||
using CapMachine.Wpf.LinDrive;
|
||||
using Prism.Mvvm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace CapMachine.Wpf.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// ZLG LIN 驱动服务(共享设备句柄)。
|
||||
/// </summary>
|
||||
public sealed class ZlgLinDriveService : BindableBase
|
||||
{
|
||||
private readonly ILogService _log;
|
||||
private readonly ZlgCanDriveService _zlgCanDriveService;
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的配置程序(沿用原有 FreeSql 模型)。
|
||||
/// </summary>
|
||||
public CanLinConfigPro? SelectedCanLinConfigPro { get; set; }
|
||||
|
||||
private bool _openState;
|
||||
/// <summary>
|
||||
/// LIN 打开状态。
|
||||
/// </summary>
|
||||
public bool OpenState
|
||||
{
|
||||
get { return _openState; }
|
||||
private set { _openState = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private bool _ldfParserState;
|
||||
/// <summary>
|
||||
/// LDF 解析状态(ZLG LIN 暂未接入 LDF,固定为 false)。
|
||||
/// </summary>
|
||||
public bool LdfParserState
|
||||
{
|
||||
get { return _ldfParserState; }
|
||||
private set { _ldfParserState = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LDF 消息集合(UI 绑定),ZLG LIN 暂未接入 LDF,默认空。
|
||||
/// </summary>
|
||||
public ObservableCollection<LinLdfModel> ListLinLdfModel { get; private set; } = new ObservableCollection<LinLdfModel>();
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用调度发送(与 UI 的调度表使能语义对齐)。
|
||||
/// </summary>
|
||||
public bool SchEnable
|
||||
{
|
||||
get { return _zlgCanDriveService.Driver.SchEnable; }
|
||||
set { _zlgCanDriveService.Driver.SchEnable = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用事件驱动发送。
|
||||
/// </summary>
|
||||
public bool IsCycleSend
|
||||
{
|
||||
get { return _zlgCanDriveService.Driver.IsCycleSend; }
|
||||
set { _zlgCanDriveService.Driver.IsCycleSend = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造。
|
||||
/// </summary>
|
||||
/// <param name="zlgCanDriveService">共享 CAN 服务。</param>
|
||||
/// <param name="logService">日志服务。</param>
|
||||
public ZlgLinDriveService(ZlgCanDriveService zlgCanDriveService, ILogService logService)
|
||||
{
|
||||
_zlgCanDriveService = zlgCanDriveService;
|
||||
_log = logService;
|
||||
|
||||
_zlgCanDriveService.Driver.LinFrameReceived += frame =>
|
||||
{
|
||||
// 未来接入 LDF 后在这里做 Sync/Decode;当前仅保留事件链路,不做假解析。
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 LIN 配置信息(目前仅缓存)。
|
||||
/// </summary>
|
||||
/// <param name="selectedLinConfigPro">选中的配置。</param>
|
||||
public void InitLinConfig(CanLinConfigPro selectedLinConfigPro)
|
||||
{
|
||||
SelectedCanLinConfigPro = selectedLinConfigPro;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 LIN(共享设备句柄)。
|
||||
/// </summary>
|
||||
/// <param name="deviceIndex">设备索引。</param>
|
||||
/// <param name="baudRate">波特率。</param>
|
||||
/// <param name="isMaster">是否主节点。</param>
|
||||
public void StartLinDrive(uint deviceIndex, uint baudRate, bool isMaster)
|
||||
{
|
||||
if (OpenState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 先确保设备打开(不影响 CAN 后续 Init)
|
||||
_zlgCanDriveService.Driver.OpenDevice(deviceIndex);
|
||||
|
||||
// 初始化 LIN 通道
|
||||
_zlgCanDriveService.Driver.OpenAndInitLin(0, new CanDrive.ZlgCan.ZlgLinChannelOptions
|
||||
{
|
||||
BaudRate = baudRate,
|
||||
IsMaster = isMaster,
|
||||
MaxLength = 8,
|
||||
ChecksumMode = 3
|
||||
});
|
||||
|
||||
// 统一由 CAN 服务侧启动接收线程(设备级 merge 接收可以同时收 CAN/LIN)
|
||||
if (!_zlgCanDriveService.Driver.IsReceiving)
|
||||
{
|
||||
_zlgCanDriveService.Driver.StartReceiveLoop(mergeReceive: true, bufferFrames: 200);
|
||||
}
|
||||
|
||||
OpenState = true;
|
||||
LdfParserState = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error($"ZLG LIN 打开失败:{ex.Message}");
|
||||
OpenState = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 LIN(共享设备句柄下,当前实现以 CloseDevice 为准:关闭将同时关闭 CAN/LIN)。
|
||||
/// </summary>
|
||||
public void CloseDevice()
|
||||
{
|
||||
// ZLG 的通道句柄都在 Driver 内部;当前 Close 会关闭所有通道,保持与旧系统“同一时刻只有一种驱动工作”的原则一致。
|
||||
_zlgCanDriveService.CloseDevice();
|
||||
OpenState = false;
|
||||
LdfParserState = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载 LDF(ZLG LIN 暂未接入 LDF 解析 DLL,因此此处明确失败,不返回模拟数据)。
|
||||
/// </summary>
|
||||
/// <param name="path">LDF 路径。</param>
|
||||
public ObservableCollection<LinLdfModel> StartLdf(string path)
|
||||
{
|
||||
_log.Warn("ZLG LIN 当前版本未接入 LDF 解析(项目内仅存在 USB2XXX.dll 的 LDFParser)。");
|
||||
throw new NotSupportedException("ZLG LIN 暂未支持 LDF 解析,请后续提供/确认 ZLG 的 LDF DLL 接口(如 zldf.dll)后再接入。");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -938,18 +938,12 @@ namespace CapMachine.Wpf.ViewModels
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void SchEnableCmdCall(object par)
|
||||
{
|
||||
var dd = SelectedCANConfigExdDto.SchEnable;
|
||||
var Result = (bool)par;
|
||||
if (Result)
|
||||
if (SelectedCANConfigExdDto == null)
|
||||
{
|
||||
CanDriveService.ToomossCanDrive.SchEnable = true;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
CanDriveService.ToomossCanDrive.SchEnable = false;
|
||||
|
||||
}
|
||||
CanDriveService.ToomossCanDrive.SchEnable = SelectedCANConfigExdDto.SchEnable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace CapMachine.Wpf.ViewModels
|
||||
//MachineDataService = machineDataService;
|
||||
DialogService = dialogService;
|
||||
|
||||
EventAggregator.GetEvent<LogicRuleChangeEvent>().Subscribe(LogicRuleChangeEventCall);
|
||||
|
||||
//仲裁波特率
|
||||
ArbBaudRateCbxItems = new ObservableCollection<CbxItems>()
|
||||
{
|
||||
@@ -713,6 +715,33 @@ namespace CapMachine.Wpf.ViewModels
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private DelegateCommand _btnTestPLC;
|
||||
/// <summary>
|
||||
/// 临时测试的方法
|
||||
/// </summary>
|
||||
public DelegateCommand btnTestPLC
|
||||
{
|
||||
set
|
||||
{
|
||||
_btnTestPLC = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
if (_btnTestPLC == null)
|
||||
{
|
||||
_btnTestPLC = new DelegateCommand(() => btnTestPLCCall());
|
||||
}
|
||||
return _btnTestPLC;
|
||||
}
|
||||
}
|
||||
//临时测试的方法
|
||||
private void btnTestPLCCall()
|
||||
{
|
||||
CanFdDriveService.ToomossCanFDDrive.UpdateSchDataByCmdDataChanged();
|
||||
}
|
||||
|
||||
|
||||
#region Dbc操作
|
||||
|
||||
private ObservableCollection<CanDbcModel> _ListCanDbcModel;
|
||||
@@ -973,18 +1002,12 @@ namespace CapMachine.Wpf.ViewModels
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void SchEnableCmdCall(object par)
|
||||
{
|
||||
var dd = SelectedCANConfigExdDto.SchEnable;
|
||||
var Result = (bool)par;
|
||||
if (Result)
|
||||
if (SelectedCANConfigExdDto == null)
|
||||
{
|
||||
CanFdDriveService.ToomossCanFDDrive.SchEnable = true;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
CanFdDriveService.ToomossCanFDDrive.SchEnable = false;
|
||||
|
||||
}
|
||||
CanFdDriveService.ToomossCanFDDrive.SchEnable = SelectedCANConfigExdDto.SchEnable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
722
CapMachine.Wpf/ViewModels/ZlgCanDriveConfigViewModel.cs
Normal file
722
CapMachine.Wpf/ViewModels/ZlgCanDriveConfigViewModel.cs
Normal file
@@ -0,0 +1,722 @@
|
||||
using AutoMapper;
|
||||
using CapMachine.Core;
|
||||
using CapMachine.Model.CANLIN;
|
||||
using CapMachine.Wpf.CanDrive;
|
||||
using CapMachine.Wpf.Dtos;
|
||||
using CapMachine.Wpf.Services;
|
||||
using ImTools;
|
||||
using Microsoft.Win32;
|
||||
using Prism.Commands;
|
||||
using Prism.Events;
|
||||
using Prism.Regions;
|
||||
using Prism.Services.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using static CapMachine.Wpf.Models.ComEnum;
|
||||
|
||||
namespace CapMachine.Wpf.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// ZLG CAN/CANFD 合并配置 ViewModel(模式切换:单选)。
|
||||
/// </summary>
|
||||
public class ZlgCanDriveConfigViewModel : NavigationViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数。
|
||||
/// </summary>
|
||||
public ZlgCanDriveConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
|
||||
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
|
||||
ComActionService comActionService, ILogService logService, LogicRuleService logicRuleService,
|
||||
ConfigService configService, ZlgCanDriveService zlgCanDriveService, ZlgLinDriveService zlgLinDriveService,
|
||||
IMapper mapper)
|
||||
{
|
||||
DialogService = dialogService;
|
||||
FreeSql = freeSql;
|
||||
EventAggregator = eventAggregator;
|
||||
RegionManager = regionManager;
|
||||
SysRunService = sysRunService;
|
||||
ComActionService = comActionService;
|
||||
LogService = logService;
|
||||
LogicRuleService = logicRuleService;
|
||||
ConfigService = configService;
|
||||
ZlgCanDriveService = zlgCanDriveService;
|
||||
ZlgLinDriveService = zlgLinDriveService;
|
||||
Mapper = mapper;
|
||||
|
||||
SelectedMode = ZlgCanMode.Can;
|
||||
InitLoadCanConfigPro();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dialog 服务。
|
||||
/// </summary>
|
||||
public IDialogService DialogService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// FreeSql。
|
||||
/// </summary>
|
||||
public IFreeSql FreeSql { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件聚合。
|
||||
/// </summary>
|
||||
public IEventAggregator EventAggregator { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 区域导航。
|
||||
/// </summary>
|
||||
public IRegionManager RegionManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 系统运行服务。
|
||||
/// </summary>
|
||||
public SysRunService SysRunService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 通信互斥控制。
|
||||
/// </summary>
|
||||
public ComActionService ComActionService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志。
|
||||
/// </summary>
|
||||
public ILogService LogService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 逻辑规则服务。
|
||||
/// </summary>
|
||||
public LogicRuleService LogicRuleService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 配置服务。
|
||||
/// </summary>
|
||||
public ConfigService ConfigService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ZLG CAN 服务。
|
||||
/// </summary>
|
||||
public ZlgCanDriveService ZlgCanDriveService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ZLG LIN 服务(用于互斥判断)。
|
||||
/// </summary>
|
||||
public ZlgLinDriveService ZlgLinDriveService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Mapper。
|
||||
/// </summary>
|
||||
public IMapper Mapper { get; }
|
||||
|
||||
private List<CanLinConfigPro> _canLinConfigPros = new List<CanLinConfigPro>();
|
||||
|
||||
private string? _opTip;
|
||||
/// <summary>
|
||||
/// 操作提示(用于 UI 状态展示)。
|
||||
/// </summary>
|
||||
public string? OpTip
|
||||
{
|
||||
get { return _opTip; }
|
||||
set { _opTip = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private string? _lastError;
|
||||
/// <summary>
|
||||
/// 最近一次错误信息(用于 UI 状态展示)。
|
||||
/// </summary>
|
||||
public string? LastError
|
||||
{
|
||||
get { return _lastError; }
|
||||
set { _lastError = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private ZlgCanMode _selectedMode;
|
||||
/// <summary>
|
||||
/// 模式选择:CAN/CANFD(单选)。
|
||||
/// </summary>
|
||||
public ZlgCanMode SelectedMode
|
||||
{
|
||||
get { return _selectedMode; }
|
||||
set
|
||||
{
|
||||
_selectedMode = value;
|
||||
RaisePropertyChanged();
|
||||
RaisePropertyChanged(nameof(DbcPathTitle));
|
||||
RaisePropertyChanged(nameof(SelectedModeKey));
|
||||
RaisePropertyChanged(nameof(CurrentDbcPath));
|
||||
RaisePropertyChanged(nameof(CurrentCycle));
|
||||
RaisePropertyChanged(nameof(CurrentSchEnable));
|
||||
RaisePropertyChanged(nameof(CanBaudRate));
|
||||
RaisePropertyChanged(nameof(CanFdArbBaudRate));
|
||||
RaisePropertyChanged(nameof(CanFdDataBaudRate));
|
||||
RaisePropertyChanged(nameof(ConnectButtonText));
|
||||
ZlgCanDriveService.Mode = value;
|
||||
InitLoadCanConfigPro();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接按钮文字(对齐 Toomoss 风格)。
|
||||
/// </summary>
|
||||
public string ConnectButtonText
|
||||
{
|
||||
get { return SelectedMode == ZlgCanMode.Can ? "连接CAN" : "连接CANFD"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定用:模式 Key(Can/CanFd)。
|
||||
/// </summary>
|
||||
public string SelectedModeKey
|
||||
{
|
||||
get { return SelectedMode == ZlgCanMode.Can ? "Can" : "CanFd"; }
|
||||
set
|
||||
{
|
||||
if (string.Equals(value, "Can", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SelectedMode = ZlgCanMode.Can;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(value, "CanFd", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "CanFD", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SelectedMode = ZlgCanMode.CanFd;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DBC 路径标题。
|
||||
/// </summary>
|
||||
public string DbcPathTitle
|
||||
{
|
||||
get { return SelectedMode == ZlgCanMode.Can ? "CAN DBC 文件路径:" : "CANFD DBC 文件路径:"; }
|
||||
}
|
||||
|
||||
private ObservableCollection<CanLinConfigPro>? _listCanLinConfigPro;
|
||||
/// <summary>
|
||||
/// 配置程序集合。
|
||||
/// </summary>
|
||||
public ObservableCollection<CanLinConfigPro>? ListCanLinConfigPro
|
||||
{
|
||||
get { return _listCanLinConfigPro; }
|
||||
set { _listCanLinConfigPro = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中的配置程序。
|
||||
/// </summary>
|
||||
public CanLinConfigPro? SelectCanLinConfigPro { get; set; }
|
||||
|
||||
private ObservableCollection<CanDbcModel>? _listCanDbcModel;
|
||||
/// <summary>
|
||||
/// DBC 信号集合。
|
||||
/// </summary>
|
||||
public ObservableCollection<CanDbcModel>? ListCanDbcModel
|
||||
{
|
||||
get { return _listCanDbcModel; }
|
||||
set { _listCanDbcModel = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的 DBC 信号。
|
||||
/// </summary>
|
||||
public CanDbcModel? SelectedCanDbcModel { get; set; }
|
||||
|
||||
private CANConfigExdDto? _selectedCANConfigExdDto;
|
||||
/// <summary>
|
||||
/// CAN 配置 DTO。
|
||||
/// </summary>
|
||||
public CANConfigExdDto? SelectedCANConfigExdDto
|
||||
{
|
||||
get { return _selectedCANConfigExdDto; }
|
||||
set { _selectedCANConfigExdDto = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private CANFdConfigExdDto? _selectedCANFdConfigExdDto;
|
||||
/// <summary>
|
||||
/// CANFD 配置 DTO。
|
||||
/// </summary>
|
||||
public CANFdConfigExdDto? SelectedCANFdConfigExdDto
|
||||
{
|
||||
get { return _selectedCANFdConfigExdDto; }
|
||||
set { _selectedCANFdConfigExdDto = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private void InitLoadCanConfigPro()
|
||||
{
|
||||
var info = SelectedMode == ZlgCanMode.Can ? CANLIN.CAN : CANLIN.CANFD;
|
||||
|
||||
_canLinConfigPros = FreeSql.Select<CanLinConfigPro>()
|
||||
.Where(a => a.CANLINInfo == info)
|
||||
.Include(a => a.CANConfigExd)
|
||||
.Include(a => a.CANFdConfigExd)
|
||||
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))
|
||||
.ToList();
|
||||
|
||||
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(_canLinConfigPros);
|
||||
}
|
||||
|
||||
private void SyncSelectedConfig()
|
||||
{
|
||||
if (SelectCanLinConfigPro == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedMode == ZlgCanMode.Can)
|
||||
{
|
||||
SelectedCANConfigExdDto = Mapper.Map<CANConfigExdDto>(SelectCanLinConfigPro.CANConfigExd);
|
||||
SelectedCANFdConfigExdDto = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedCANFdConfigExdDto = Mapper.Map<CANFdConfigExdDto>(SelectCanLinConfigPro.CANFdConfigExd);
|
||||
SelectedCANConfigExdDto = null;
|
||||
}
|
||||
|
||||
RaisePropertyChanged(nameof(CurrentDbcPath));
|
||||
RaisePropertyChanged(nameof(CurrentCycle));
|
||||
RaisePropertyChanged(nameof(CurrentSchEnable));
|
||||
RaisePropertyChanged(nameof(CanBaudRate));
|
||||
RaisePropertyChanged(nameof(CanFdArbBaudRate));
|
||||
RaisePropertyChanged(nameof(CanFdDataBaudRate));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前 DBC 路径(随模式切换映射到对应 DTO)。
|
||||
/// </summary>
|
||||
public string? CurrentDbcPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return SelectedMode == ZlgCanMode.Can
|
||||
? SelectedCANConfigExdDto?.DbcPath
|
||||
: SelectedCANFdConfigExdDto?.DbcPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SelectedMode == ZlgCanMode.Can)
|
||||
{
|
||||
if (SelectedCANConfigExdDto == null) return;
|
||||
SelectedCANConfigExdDto.DbcPath = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null) return;
|
||||
SelectedCANFdConfigExdDto.DbcPath = value;
|
||||
}
|
||||
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前周期(随模式切换映射到对应 DTO)。
|
||||
/// </summary>
|
||||
public int CurrentCycle
|
||||
{
|
||||
get
|
||||
{
|
||||
return SelectedMode == ZlgCanMode.Can
|
||||
? (SelectedCANConfigExdDto?.Cycle ?? 0)
|
||||
: (SelectedCANFdConfigExdDto?.Cycle ?? 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SelectedMode == ZlgCanMode.Can)
|
||||
{
|
||||
if (SelectedCANConfigExdDto == null) return;
|
||||
SelectedCANConfigExdDto.Cycle = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null) return;
|
||||
SelectedCANFdConfigExdDto.Cycle = value;
|
||||
}
|
||||
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前调度使能(随模式切换映射到对应 DTO)。
|
||||
/// </summary>
|
||||
public bool CurrentSchEnable
|
||||
{
|
||||
get
|
||||
{
|
||||
return SelectedMode == ZlgCanMode.Can
|
||||
? (SelectedCANConfigExdDto?.SchEnable ?? false)
|
||||
: (SelectedCANFdConfigExdDto?.SchEnable ?? false);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SelectedMode == ZlgCanMode.Can)
|
||||
{
|
||||
if (SelectedCANConfigExdDto == null) return;
|
||||
SelectedCANConfigExdDto.SchEnable = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null) return;
|
||||
SelectedCANFdConfigExdDto.SchEnable = value;
|
||||
}
|
||||
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CAN 波特率。
|
||||
/// </summary>
|
||||
public int CanBaudRate
|
||||
{
|
||||
get { return SelectedCANConfigExdDto?.BaudRate ?? 0; }
|
||||
set
|
||||
{
|
||||
if (SelectedCANConfigExdDto == null) return;
|
||||
SelectedCANConfigExdDto.BaudRate = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CANFD 仲裁波特率。
|
||||
/// </summary>
|
||||
public int CanFdArbBaudRate
|
||||
{
|
||||
get { return SelectedCANFdConfigExdDto?.ArbBaudRate ?? 0; }
|
||||
set
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null) return;
|
||||
SelectedCANFdConfigExdDto.ArbBaudRate = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CANFD 数据波特率。
|
||||
/// </summary>
|
||||
public int CanFdDataBaudRate
|
||||
{
|
||||
get { return SelectedCANFdConfigExdDto?.DataBaudRate ?? 0; }
|
||||
set
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null) return;
|
||||
SelectedCANFdConfigExdDto.DataBaudRate = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void MatchSeletedAndCanDbcModel()
|
||||
{
|
||||
if (ListCanDbcModel == null || ListCanDbcModel.Count == 0) return;
|
||||
if (SelectCanLinConfigPro?.CanLinConfigContents == null || SelectCanLinConfigPro.CanLinConfigContents.Count == 0) return;
|
||||
|
||||
foreach (var itemCanDbcModel in ListCanDbcModel)
|
||||
{
|
||||
var findData = SelectCanLinConfigPro.CanLinConfigContents.FindFirst(a => a.SignalName == itemCanDbcModel.SignalName);
|
||||
if (findData != null)
|
||||
{
|
||||
switch (findData.RWInfo)
|
||||
{
|
||||
case RW.Write:
|
||||
itemCanDbcModel.IsSeletedInfo = 1;
|
||||
break;
|
||||
case RW.Read:
|
||||
itemCanDbcModel.IsSeletedInfo = 2;
|
||||
break;
|
||||
default:
|
||||
itemCanDbcModel.IsSeletedInfo = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
itemCanDbcModel.IsSeletedInfo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand<object>? _canConfigProGridSelectionChangedCmd;
|
||||
/// <summary>
|
||||
/// 配置程序选中变化。
|
||||
/// </summary>
|
||||
public DelegateCommand<object> CanConfigProGridSelectionChangedCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_canConfigProGridSelectionChangedCmd == null)
|
||||
{
|
||||
_canConfigProGridSelectionChangedCmd = new DelegateCommand<object>(CanConfigProGridSelectionChangedCmdMethod);
|
||||
}
|
||||
return _canConfigProGridSelectionChangedCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void CanConfigProGridSelectionChangedCmdMethod(object par)
|
||||
{
|
||||
if (par == null) return;
|
||||
if (par is SelectionChangedEventArgs) return;
|
||||
|
||||
if (par is CanLinConfigPro)
|
||||
{
|
||||
SelectCanLinConfigPro = par as CanLinConfigPro;
|
||||
SyncSelectedConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
var args = par as SelectionChangedEventArgs;
|
||||
if (args == null || args.AddedItems == null || args.AddedItems.Count == 0) return;
|
||||
|
||||
var selected = args.AddedItems[0] as CanLinConfigPro;
|
||||
if (selected == null) return;
|
||||
|
||||
SelectCanLinConfigPro = selected;
|
||||
SyncSelectedConfig();
|
||||
}
|
||||
|
||||
private DelegateCommand? _loadDbcCmd;
|
||||
/// <summary>
|
||||
/// 选择 DBC 文件。
|
||||
/// </summary>
|
||||
public DelegateCommand LoadDbcCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_loadDbcCmd == null)
|
||||
{
|
||||
_loadDbcCmd = new DelegateCommand(LoadDbcCmdMethod);
|
||||
}
|
||||
return _loadDbcCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadDbcCmdMethod()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SelectCanLinConfigPro == null)
|
||||
{
|
||||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
OpenFileDialog openFileDialogInfo = new OpenFileDialog();
|
||||
openFileDialogInfo.Filter = "(*.dbc;*.dbc)|*.dbc;*.dbc|all|*.*";
|
||||
openFileDialogInfo.CheckFileExists = true;
|
||||
openFileDialogInfo.CheckPathExists = true;
|
||||
openFileDialogInfo.ShowDialog();
|
||||
string fileName = openFileDialogInfo.FileName;
|
||||
|
||||
CurrentDbcPath = fileName;
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("可能未选择信息", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand<object>? _schEnableCmd;
|
||||
/// <summary>
|
||||
/// 调度使能写入驱动。
|
||||
/// </summary>
|
||||
public DelegateCommand<object> SchEnableCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_schEnableCmd == null)
|
||||
{
|
||||
_schEnableCmd = new DelegateCommand<object>(SchEnableCmdCall);
|
||||
}
|
||||
return _schEnableCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void SchEnableCmdCall(object par)
|
||||
{
|
||||
// 与旧 Toomoss 行为对齐:UI 勾选后立即下发到驱动
|
||||
ZlgCanDriveService.SchEnable = CurrentSchEnable;
|
||||
}
|
||||
|
||||
private DelegateCommand<string>? _canOpCmd;
|
||||
/// <summary>
|
||||
/// CAN 操作命令。
|
||||
/// </summary>
|
||||
public DelegateCommand<string> CanOpCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_canOpCmd == null)
|
||||
{
|
||||
_canOpCmd = new DelegateCommand<string>(CanOpCmdMethod);
|
||||
}
|
||||
return _canOpCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void CanOpCmdMethod(string par)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(par))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (par)
|
||||
{
|
||||
case "Open":
|
||||
if (ComActionService.IsCanToDoWork() == false)
|
||||
{
|
||||
MessageBox.Show("请关闭LIN连接后才能开启CAN,同一个时刻只能有一个通信驱动压缩机", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZlgLinDriveService.OpenState)
|
||||
{
|
||||
MessageBox.Show("请先关闭 ZLG LIN 连接后再开启 ZLG CAN", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectCanLinConfigPro == null)
|
||||
{
|
||||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedMode == ZlgCanMode.Can)
|
||||
{
|
||||
if (SelectedCANConfigExdDto == null)
|
||||
{
|
||||
MessageBox.Show("CAN配置为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
// ZLG 底层实际为 CANFD 通道,CAN 经典帧使用 arbitration 波特率(data 亦沿用,保持一致即可)
|
||||
ZlgCanDriveService.UpdateConfig(0, (uint)SelectedCANConfigExdDto.BaudRate, (uint)SelectedCANConfigExdDto.BaudRate, resEnable: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null)
|
||||
{
|
||||
MessageBox.Show("CANFD配置为空", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
ZlgCanDriveService.UpdateConfig(0, (uint)SelectedCANFdConfigExdDto.ArbBaudRate, (uint)SelectedCANFdConfigExdDto.DataBaudRate, SelectedCANFdConfigExdDto.ResEnable);
|
||||
}
|
||||
|
||||
ZlgCanDriveService.StartCanDrive();
|
||||
|
||||
if (ZlgCanDriveService.OpenState)
|
||||
{
|
||||
LastError = null;
|
||||
OpTip = "CAN 已连接";
|
||||
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = SelectedMode == ZlgCanMode.Can ? CanLinEnum.Can : CanLinEnum.CANFD;
|
||||
}
|
||||
else
|
||||
{
|
||||
OpTip = "CAN 连接失败";
|
||||
MessageBox.Show("CAN 连接失败(OpenState=false),请检查设备/驱动/参数。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
// 自动解析 DBC
|
||||
if (!string.IsNullOrWhiteSpace(CurrentDbcPath))
|
||||
{
|
||||
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
|
||||
MatchSeletedAndCanDbcModel();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "Close":
|
||||
ZlgCanDriveService.CloseDevice();
|
||||
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.No;
|
||||
LastError = null;
|
||||
OpTip = "CAN 已关闭";
|
||||
break;
|
||||
|
||||
case "Parse":
|
||||
if (!ZlgCanDriveService.OpenState)
|
||||
{
|
||||
MessageBox.Show("请先打开CAN后再解析", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(CurrentDbcPath))
|
||||
{
|
||||
MessageBox.Show("请选择DBC文件后再操作", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
ListCanDbcModel = ZlgCanDriveService.StartDbc(CurrentDbcPath);
|
||||
MatchSeletedAndCanDbcModel();
|
||||
LastError = null;
|
||||
OpTip = "DBC 已解析";
|
||||
break;
|
||||
|
||||
case "CycleSend":
|
||||
ZlgCanDriveService.IsCycleSend = !ZlgCanDriveService.IsCycleSend;
|
||||
OpTip = ZlgCanDriveService.IsCycleSend ? "循环发送:已开启" : "循环发送:已关闭";
|
||||
break;
|
||||
|
||||
case "CycleRecive":
|
||||
ZlgCanDriveService.SetReceiveEnabled(!ZlgCanDriveService.IsCycleRevice);
|
||||
OpTip = ZlgCanDriveService.IsCycleRevice ? "循环接收:已开启" : "循环接收:已关闭";
|
||||
break;
|
||||
|
||||
case "Save":
|
||||
if (SelectCanLinConfigPro == null)
|
||||
{
|
||||
MessageBox.Show("选中CAN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedMode == ZlgCanMode.Can)
|
||||
{
|
||||
if (SelectedCANConfigExdDto == null) return;
|
||||
FreeSql.Update<CANConfigExd>()
|
||||
.Set(a => a.DbcPath, SelectedCANConfigExdDto.DbcPath)
|
||||
.Set(a => a.Cycle, SelectedCANConfigExdDto.Cycle)
|
||||
.Set(a => a.BaudRate, SelectedCANConfigExdDto.BaudRate)
|
||||
.Set(a => a.SchEnable, SelectedCANConfigExdDto.SchEnable)
|
||||
.Where(a => a.Id == SelectedCANConfigExdDto.Id)
|
||||
.ExecuteUpdated();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedCANFdConfigExdDto == null) return;
|
||||
FreeSql.Update<CANFdConfigExd>()
|
||||
.Set(a => a.DbcPath, SelectedCANFdConfigExdDto.DbcPath)
|
||||
.Set(a => a.Cycle, SelectedCANFdConfigExdDto.Cycle)
|
||||
.Set(a => a.DataBaudRate, SelectedCANFdConfigExdDto.DataBaudRate)
|
||||
.Set(a => a.ArbBaudRate, SelectedCANFdConfigExdDto.ArbBaudRate)
|
||||
.Set(a => a.ISOEnable, SelectedCANFdConfigExdDto.ISOEnable)
|
||||
.Set(a => a.ResEnable, SelectedCANFdConfigExdDto.ResEnable)
|
||||
.Set(a => a.SchEnable, SelectedCANFdConfigExdDto.SchEnable)
|
||||
.Where(a => a.Id == SelectedCANFdConfigExdDto.Id)
|
||||
.ExecuteUpdated();
|
||||
}
|
||||
|
||||
InitLoadCanConfigPro();
|
||||
LastError = null;
|
||||
OpTip = "配置已保存";
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastError = ex.Message;
|
||||
OpTip = "操作失败";
|
||||
LogService.Error($"ZLG CAN 操作失败:{par},{ex}");
|
||||
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
339
CapMachine.Wpf/ViewModels/ZlgLinDriveConfigViewModel.cs
Normal file
339
CapMachine.Wpf/ViewModels/ZlgLinDriveConfigViewModel.cs
Normal file
@@ -0,0 +1,339 @@
|
||||
using AutoMapper;
|
||||
using CapMachine.Core;
|
||||
using CapMachine.Model.CANLIN;
|
||||
using CapMachine.Wpf.Dtos;
|
||||
using CapMachine.Wpf.LinDrive;
|
||||
using CapMachine.Wpf.Services;
|
||||
using ImTools;
|
||||
using Microsoft.Win32;
|
||||
using Prism.Commands;
|
||||
using Prism.Events;
|
||||
using Prism.Regions;
|
||||
using Prism.Services.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using static CapMachine.Wpf.Models.ComEnum;
|
||||
|
||||
namespace CapMachine.Wpf.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// ZLG LIN 配置 ViewModel。
|
||||
/// </summary>
|
||||
public class ZlgLinDriveConfigViewModel : NavigationViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数。
|
||||
/// </summary>
|
||||
public ZlgLinDriveConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
|
||||
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
|
||||
ConfigService configService, ZlgLinDriveService zlgLinDriveService, ZlgCanDriveService zlgCanDriveService,
|
||||
ComActionService comActionService, LogicRuleService logicRuleService,
|
||||
IMapper mapper)
|
||||
{
|
||||
DialogService = dialogService;
|
||||
FreeSql = freeSql;
|
||||
EventAggregator = eventAggregator;
|
||||
RegionManager = regionManager;
|
||||
SysRunService = sysRunService;
|
||||
ConfigService = configService;
|
||||
ZlgLinDriveService = zlgLinDriveService;
|
||||
ZlgCanDriveService = zlgCanDriveService;
|
||||
ComActionService = comActionService;
|
||||
LogicRuleService = logicRuleService;
|
||||
Mapper = mapper;
|
||||
|
||||
InitLoadLinConfigPro();
|
||||
}
|
||||
|
||||
public IDialogService DialogService { get; }
|
||||
public IFreeSql FreeSql { get; }
|
||||
public IEventAggregator EventAggregator { get; }
|
||||
public IRegionManager RegionManager { get; }
|
||||
public SysRunService SysRunService { get; }
|
||||
public ConfigService ConfigService { get; }
|
||||
public ZlgLinDriveService ZlgLinDriveService { get; }
|
||||
public ZlgCanDriveService ZlgCanDriveService { get; }
|
||||
public ComActionService ComActionService { get; }
|
||||
public LogicRuleService LogicRuleService { get; }
|
||||
public IMapper Mapper { get; }
|
||||
|
||||
private List<CanLinConfigPro> linConfigPros = new List<CanLinConfigPro>();
|
||||
|
||||
private ObservableCollection<CanLinConfigPro>? _ListCanLinConfigPro;
|
||||
/// <summary>
|
||||
/// LIN 配置程序集合。
|
||||
/// </summary>
|
||||
public ObservableCollection<CanLinConfigPro>? ListCanLinConfigPro
|
||||
{
|
||||
get { return _ListCanLinConfigPro; }
|
||||
set { _ListCanLinConfigPro = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中的配置程序。
|
||||
/// </summary>
|
||||
public CanLinConfigPro? SelectCanLinConfigPro { get; set; }
|
||||
|
||||
private LINConfigExdDto? _SelectedLINConfigExdDto;
|
||||
/// <summary>
|
||||
/// 选中的 LIN 配置 DTO。
|
||||
/// </summary>
|
||||
public LINConfigExdDto? SelectedLINConfigExdDto
|
||||
{
|
||||
get { return _SelectedLINConfigExdDto; }
|
||||
set { _SelectedLINConfigExdDto = value; RaisePropertyChanged(); RaisePropertyChanged(nameof(CurrentLdfPath)); RaisePropertyChanged(nameof(CurrentSchEnable)); RaisePropertyChanged(nameof(LinBaudRate)); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前 LDF 路径。
|
||||
/// </summary>
|
||||
public string? CurrentLdfPath
|
||||
{
|
||||
get { return SelectedLINConfigExdDto?.LdfPath; }
|
||||
set
|
||||
{
|
||||
if (SelectedLINConfigExdDto == null) return;
|
||||
SelectedLINConfigExdDto.LdfPath = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LIN 波特率。
|
||||
/// </summary>
|
||||
public int LinBaudRate
|
||||
{
|
||||
get { return SelectedLINConfigExdDto?.BaudRate ?? 0; }
|
||||
set
|
||||
{
|
||||
if (SelectedLINConfigExdDto == null) return;
|
||||
SelectedLINConfigExdDto.BaudRate = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调度表使能。
|
||||
/// </summary>
|
||||
public bool CurrentSchEnable
|
||||
{
|
||||
get { return SelectedLINConfigExdDto?.SchEnable ?? false; }
|
||||
set
|
||||
{
|
||||
if (SelectedLINConfigExdDto == null) return;
|
||||
SelectedLINConfigExdDto.SchEnable = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitLoadLinConfigPro()
|
||||
{
|
||||
linConfigPros = FreeSql.Select<CanLinConfigPro>()
|
||||
.Where(a => a.CANLINInfo == CANLIN.LIN)
|
||||
.Include(a => a.LINConfigExd)
|
||||
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))
|
||||
.IncludeMany(a => a.LinScheduleConfigs)
|
||||
.ToList();
|
||||
|
||||
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(linConfigPros);
|
||||
}
|
||||
|
||||
private void SyncSelectedConfig()
|
||||
{
|
||||
if (SelectCanLinConfigPro == null) return;
|
||||
SelectedLINConfigExdDto = Mapper.Map<LINConfigExdDto>(SelectCanLinConfigPro.LINConfigExd);
|
||||
}
|
||||
|
||||
private DelegateCommand<object>? _LinConfigProGridSelectionChangedCmd;
|
||||
/// <summary>
|
||||
/// LIN 配置程序选中变化。
|
||||
/// </summary>
|
||||
public DelegateCommand<object> LinConfigProGridSelectionChangedCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_LinConfigProGridSelectionChangedCmd == null)
|
||||
{
|
||||
_LinConfigProGridSelectionChangedCmd = new DelegateCommand<object>(LinConfigProGridSelectionChangedCmdMethod);
|
||||
}
|
||||
return _LinConfigProGridSelectionChangedCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void LinConfigProGridSelectionChangedCmdMethod(object par)
|
||||
{
|
||||
if (par == null) return;
|
||||
if (par is SelectionChangedEventArgs) return;
|
||||
|
||||
if (par is CanLinConfigPro)
|
||||
{
|
||||
SelectCanLinConfigPro = par as CanLinConfigPro;
|
||||
SyncSelectedConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
var args = par as SelectionChangedEventArgs;
|
||||
if (args == null || args.AddedItems == null || args.AddedItems.Count == 0) return;
|
||||
var selected = args.AddedItems[0] as CanLinConfigPro;
|
||||
if (selected == null) return;
|
||||
|
||||
SelectCanLinConfigPro = selected;
|
||||
SyncSelectedConfig();
|
||||
}
|
||||
|
||||
private DelegateCommand? _LoadLdfCmd;
|
||||
/// <summary>
|
||||
/// 选择 LDF 文件。
|
||||
/// </summary>
|
||||
public DelegateCommand LoadLdfCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_LoadLdfCmd == null)
|
||||
{
|
||||
_LoadLdfCmd = new DelegateCommand(LoadLdfCmdMethod);
|
||||
}
|
||||
return _LoadLdfCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadLdfCmdMethod()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SelectCanLinConfigPro == null || SelectedLINConfigExdDto == null)
|
||||
{
|
||||
MessageBox.Show("选中LIN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
OpenFileDialog openFileDialogInfo = new OpenFileDialog();
|
||||
openFileDialogInfo.Filter = "(*.ldf;*.ldf)|*.ldf;*.ldf|all|*.*";
|
||||
openFileDialogInfo.CheckFileExists = true;
|
||||
openFileDialogInfo.CheckPathExists = true;
|
||||
openFileDialogInfo.ShowDialog();
|
||||
|
||||
CurrentLdfPath = openFileDialogInfo.FileName;
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("可能未选择信息", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand<string>? _LinOpCmd;
|
||||
/// <summary>
|
||||
/// LIN 操作命令。
|
||||
/// </summary>
|
||||
public DelegateCommand<string> LinOpCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_LinOpCmd == null)
|
||||
{
|
||||
_LinOpCmd = new DelegateCommand<string>(LinOpCmdMethod);
|
||||
}
|
||||
return _LinOpCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void LinOpCmdMethod(string par)
|
||||
{
|
||||
switch (par)
|
||||
{
|
||||
case "Open":
|
||||
if (ComActionService.IsLINToDoWork() == false)
|
||||
{
|
||||
MessageBox.Show("请关闭CAN连接后才能开启LIN,同一个时刻只能有一个通信驱动压缩机", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZlgCanDriveService.OpenState)
|
||||
{
|
||||
MessageBox.Show("请先关闭 ZLG CAN 连接后再开启 ZLG LIN", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectCanLinConfigPro == null || SelectedLINConfigExdDto == null)
|
||||
{
|
||||
MessageBox.Show("选中LIN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
// 打开 LIN(不依赖 LDF)
|
||||
ZlgLinDriveService.StartLinDrive(0, (uint)SelectedLINConfigExdDto.BaudRate, isMaster: true);
|
||||
if (ZlgLinDriveService.OpenState)
|
||||
{
|
||||
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.Lin;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Close":
|
||||
ZlgLinDriveService.CloseDevice();
|
||||
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.No;
|
||||
break;
|
||||
|
||||
case "Save":
|
||||
if (SelectCanLinConfigPro == null || SelectedLINConfigExdDto == null)
|
||||
{
|
||||
MessageBox.Show("选中LIN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
FreeSql.Update<LINConfigExd>()
|
||||
.Set(a => a.LdfPath, SelectedLINConfigExdDto.LdfPath)
|
||||
.Set(a => a.Cycle, SelectedLINConfigExdDto.Cycle)
|
||||
.Set(a => a.BaudRate, SelectedLINConfigExdDto.BaudRate)
|
||||
.Set(a => a.SchEnable, SelectedLINConfigExdDto.SchEnable)
|
||||
.Where(a => a.Id == SelectedLINConfigExdDto.Id)
|
||||
.ExecuteUpdated();
|
||||
|
||||
InitLoadLinConfigPro();
|
||||
break;
|
||||
|
||||
case "Parse":
|
||||
// 明确提示:当前 ZLG LIN 暂不支持 LDF
|
||||
if (SelectCanLinConfigPro == null || SelectedLINConfigExdDto == null)
|
||||
{
|
||||
MessageBox.Show("选中LIN配置名称后再操作", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ZlgLinDriveService.StartLdf(SelectedLINConfigExdDto.LdfPath ?? string.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand<object>? _SchEnableCmd;
|
||||
/// <summary>
|
||||
/// 调度表使能写入驱动。
|
||||
/// </summary>
|
||||
public DelegateCommand<object> SchEnableCmd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_SchEnableCmd == null)
|
||||
{
|
||||
_SchEnableCmd = new DelegateCommand<object>(SchEnableCmdCall);
|
||||
}
|
||||
return _SchEnableCmd;
|
||||
}
|
||||
}
|
||||
|
||||
private void SchEnableCmdCall(object par)
|
||||
{
|
||||
ZlgLinDriveService.SchEnable = CurrentSchEnable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,7 +655,6 @@
|
||||
Width="40"
|
||||
Margin="5,2"
|
||||
Command="{Binding SchEnableCmd}"
|
||||
CommandParameter="{Binding SelectedCANConfigExdDto.SchEnable}"
|
||||
IsChecked="{Binding SelectedCANConfigExdDto.SchEnable}"
|
||||
Style="{StaticResource MaterialDesignSwitchToggleButton}"
|
||||
ToolTip="启用调度表" />
|
||||
|
||||
@@ -710,13 +710,15 @@
|
||||
Width="40"
|
||||
Margin="2,2"
|
||||
Command="{Binding SchEnableCmd}"
|
||||
CommandParameter="{Binding SelectedCANConfigExdDto.SchEnable}"
|
||||
IsChecked="{Binding SelectedCANConfigExdDto.SchEnable}"
|
||||
Style="{StaticResource MaterialDesignSwitchToggleButton}"
|
||||
ToolTip="启用调度表" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!--<StackPanel Grid.Row="1" Grid.Column="2">
|
||||
<Button Command="{Binding btnTestPLC}" />
|
||||
</StackPanel>-->
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
Width="1920"
|
||||
Height="1080"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Closed="Window_Closed"
|
||||
Closing="Window_Closing"
|
||||
Icon="/Assets/Images/favicon.ico"
|
||||
StateChanged="Window_StateChanged"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
WindowState="Maximized"
|
||||
WindowStyle="SingleBorderWindow"
|
||||
mc:Ignorable="d" Closing="Window_Closing" Closed="Window_Closed">
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<localEx:BindingProxy x:Key="Proxy" Data="{Binding}" />
|
||||
</Window.Resources>
|
||||
|
||||
375
CapMachine.Wpf/Views/ZlgCanDriveConfigView.xaml
Normal file
375
CapMachine.Wpf/Views/ZlgCanDriveConfigView.xaml
Normal file
@@ -0,0 +1,375 @@
|
||||
<UserControl
|
||||
x:Class="CapMachine.Wpf.Views.ZlgCanDriveConfigView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:local="clr-namespace:CapMachine.Wpf.Views"
|
||||
xmlns:localEx="clr-namespace:CapMachine.Wpf"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
d:DesignHeight="980"
|
||||
d:DesignWidth="1920"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<localEx:BindingProxy x:Key="Proxy" Data="{Binding}" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="60" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<materialDesign:Card
|
||||
Margin="3"
|
||||
Background="{DynamicResource MaterialDesignLightBackground}"
|
||||
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
|
||||
UniformCornerRadius="5">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0,10,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="30"
|
||||
Text="" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="30"
|
||||
FontWeight="Bold"
|
||||
Text="{Binding DbcPathTitle}" />
|
||||
|
||||
<Border
|
||||
Width="700"
|
||||
Margin="5,8"
|
||||
Padding="15,5"
|
||||
Background="LightGray"
|
||||
CornerRadius="5">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="22"
|
||||
Text="{Binding CurrentDbcPath}" />
|
||||
</Border>
|
||||
|
||||
<Button Command="{Binding LoadDbcCmd}" Foreground="White">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="2,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="18"
|
||||
Text=" " />
|
||||
<TextBlock VerticalAlignment="Center" FontSize="14" Text="选择Dbc文件" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Margin="5,0"
|
||||
Command="{Binding CanOpCmd}"
|
||||
CommandParameter="CycleRecive">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource MaterialDesignFlatDarkBgButton}" TargetType="Button">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.IsCycleRevice}" Value="true">
|
||||
<Setter Property="Background" Value="LimeGreen" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.IsCycleRevice}" Value="false">
|
||||
<Setter Property="Background" Value="Gray" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="2,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="18"
|
||||
Text="" />
|
||||
<TextBlock VerticalAlignment="Center" FontSize="14" Text="循环接收" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<TextBlock Margin="10,0,5,0" VerticalAlignment="Center" FontSize="14" Text="报文状态:" />
|
||||
|
||||
<Border Margin="0,10,5,10" Padding="5" CornerRadius="3">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="Gray" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.IsSendOk}" Value="true">
|
||||
<Setter Property="Background" Value="LimeGreen" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="发送" />
|
||||
</Border>
|
||||
|
||||
<Border Margin="0,10,5,10" Padding="5" CornerRadius="3">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="Gray" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.IsReviceOk}" Value="true">
|
||||
<Setter Property="Background" Value="LimeGreen" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="接收" />
|
||||
</Border>
|
||||
|
||||
<TextBlock Margin="25,0,5,0" VerticalAlignment="Center" FontSize="18" Text="模式:" />
|
||||
<ComboBox
|
||||
Width="120"
|
||||
Margin="0,0,15,0"
|
||||
VerticalAlignment="Center"
|
||||
SelectedValue="{Binding SelectedModeKey}"
|
||||
SelectedValuePath="Tag">
|
||||
<ComboBoxItem Content="CAN" Tag="Can" />
|
||||
<ComboBoxItem Content="CANFD" Tag="CanFd" />
|
||||
</ComboBox>
|
||||
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding CanOpCmd}"
|
||||
CommandParameter="Open"
|
||||
Foreground="White">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="2,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="18"
|
||||
Text="" />
|
||||
<TextBlock VerticalAlignment="Center" FontSize="14" Text="{Binding ConnectButtonText}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding CanOpCmd}"
|
||||
CommandParameter="Close"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="关闭" />
|
||||
</Button>
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding CanOpCmd}"
|
||||
CommandParameter="Parse"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="解析" />
|
||||
</Button>
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding CanOpCmd}"
|
||||
CommandParameter="Save"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="保存" />
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="15,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="18"
|
||||
Text="" />
|
||||
|
||||
<TextBlock Margin="0,0,5,0" VerticalAlignment="Center" FontSize="14" Text="连接" />
|
||||
<Border
|
||||
Width="50"
|
||||
Margin="0,10,5,10"
|
||||
Padding="5"
|
||||
CornerRadius="3">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.OpenState}" Value="True">
|
||||
<Setter Property="Background" Value="LimeGreen" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.OpenState}" Value="False">
|
||||
<Setter Property="Background" Value="Gray" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="连接" />
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Width="60"
|
||||
Margin="0,10,5,10"
|
||||
Padding="5"
|
||||
CornerRadius="3">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.DbcParserState}" Value="True">
|
||||
<Setter Property="Background" Value="LimeGreen" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.DbcParserState}" Value="False">
|
||||
<Setter Property="Background" Value="Gray" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="Dbc解析" />
|
||||
</Border>
|
||||
|
||||
<Button
|
||||
Margin="10,0,5,0"
|
||||
Command="{Binding CanOpCmd}"
|
||||
CommandParameter="CycleSend">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource MaterialDesignFlatDarkBgButton}" TargetType="Button">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.IsCycleSend}" Value="true">
|
||||
<Setter Property="Background" Value="LimeGreen" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ZlgCanDriveService.IsCycleSend}" Value="false">
|
||||
<Setter Property="Background" Value="Gray" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="2,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="18"
|
||||
Text="" />
|
||||
<TextBlock VerticalAlignment="Center" FontSize="14" Text="循环发送" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Text="{Binding OpTip}" />
|
||||
<TextBlock
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="Red"
|
||||
Text="{Binding LastError}" />
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="400" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<materialDesign:Card
|
||||
Grid.Column="0"
|
||||
Margin="3"
|
||||
Background="{DynamicResource MaterialDesignLightBackground}"
|
||||
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
|
||||
UniformCornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Text="配置程序" />
|
||||
|
||||
<DataGrid
|
||||
x:Name="CanConfigDatagrid"
|
||||
Grid.Row="1"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
HeadersVisibility="Column"
|
||||
ItemsSource="{Binding ListCanLinConfigPro}"
|
||||
SelectedItem="{Binding SelectCanLinConfigPro, Mode=TwoWay}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<prism:InvokeCommandAction
|
||||
Command="{Binding CanConfigProGridSelectionChangedCmd}"
|
||||
CommandParameter="{Binding ElementName=CanConfigDatagrid, Path=SelectedItem}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Binding="{Binding ConfigName}" Header="名称" Width="*" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<materialDesign:Card
|
||||
Grid.Column="1"
|
||||
Margin="3"
|
||||
Background="{DynamicResource MaterialDesignLightBackground}"
|
||||
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
|
||||
UniformCornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="80" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Text="参数/信号" />
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" FontSize="16" Text="周期:" />
|
||||
<TextBox
|
||||
Width="100"
|
||||
Margin="5,0,20,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Text="{Binding CurrentCycle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<CheckBox
|
||||
VerticalAlignment="Center"
|
||||
Content="调度使能"
|
||||
IsChecked="{Binding CurrentSchEnable, Mode=TwoWay}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Click">
|
||||
<prism:InvokeCommandAction
|
||||
Command="{Binding SchEnableCmd}"
|
||||
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid
|
||||
Grid.Row="2"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
HeadersVisibility="Column"
|
||||
ItemsSource="{Binding ListCanDbcModel}"
|
||||
SelectedItem="{Binding SelectedCanDbcModel, Mode=TwoWay}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Binding="{Binding MsgName}" Header="Msg" Width="200" />
|
||||
<DataGridTextColumn Binding="{Binding SignalName}" Header="Signal" Width="*" />
|
||||
<DataGridTextColumn Binding="{Binding SignalRtValue}" Header="Value" Width="150" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
28
CapMachine.Wpf/Views/ZlgCanDriveConfigView.xaml.cs
Normal file
28
CapMachine.Wpf/Views/ZlgCanDriveConfigView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace CapMachine.Wpf.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// ZlgCanDriveConfigView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ZlgCanDriveConfigView : UserControl
|
||||
{
|
||||
public ZlgCanDriveConfigView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
201
CapMachine.Wpf/Views/ZlgLinDriveConfigView.xaml
Normal file
201
CapMachine.Wpf/Views/ZlgLinDriveConfigView.xaml
Normal file
@@ -0,0 +1,201 @@
|
||||
<UserControl
|
||||
x:Class="CapMachine.Wpf.Views.ZlgLinDriveConfigView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:local="clr-namespace:CapMachine.Wpf.Views"
|
||||
xmlns:localEx="clr-namespace:CapMachine.Wpf"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
d:DesignHeight="980"
|
||||
d:DesignWidth="1920"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<localEx:BindingProxy x:Key="Proxy" Data="{Binding}" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="60" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<materialDesign:Card
|
||||
Margin="3"
|
||||
Background="{DynamicResource MaterialDesignLightBackground}"
|
||||
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
|
||||
UniformCornerRadius="5">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0,10,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="30"
|
||||
Text="" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="30"
|
||||
FontWeight="Bold"
|
||||
Text="LIN LDF 文件路径:" />
|
||||
|
||||
<Border
|
||||
Width="800"
|
||||
Margin="5,8"
|
||||
Padding="15,5"
|
||||
Background="LightGray"
|
||||
CornerRadius="5">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="22"
|
||||
Text="{Binding CurrentLdfPath}" />
|
||||
</Border>
|
||||
|
||||
<Button Command="{Binding LoadLdfCmd}" Foreground="White">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="2,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="/Assets/Fonts/#iconfont"
|
||||
FontSize="18"
|
||||
Text=" " />
|
||||
<TextBlock VerticalAlignment="Center" FontSize="14" Text="选择Ldf文件" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Margin="15,0,2,0"
|
||||
Command="{Binding LinOpCmd}"
|
||||
CommandParameter="Open"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="打开" />
|
||||
</Button>
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding LinOpCmd}"
|
||||
CommandParameter="Close"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="关闭" />
|
||||
</Button>
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding LinOpCmd}"
|
||||
CommandParameter="Parse"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="解析" />
|
||||
</Button>
|
||||
<Button
|
||||
Margin="2,0"
|
||||
Command="{Binding LinOpCmd}"
|
||||
CommandParameter="Save"
|
||||
Foreground="White">
|
||||
<TextBlock FontSize="14" Text="保存" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="400" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<materialDesign:Card
|
||||
Grid.Column="0"
|
||||
Margin="3"
|
||||
Background="{DynamicResource MaterialDesignLightBackground}"
|
||||
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
|
||||
UniformCornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Text="配置程序" />
|
||||
|
||||
<DataGrid
|
||||
x:Name="LinConfigDatagrid"
|
||||
Grid.Row="1"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
HeadersVisibility="Column"
|
||||
ItemsSource="{Binding ListCanLinConfigPro}"
|
||||
SelectedItem="{Binding SelectCanLinConfigPro, Mode=TwoWay}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="SelectionChanged">
|
||||
<prism:InvokeCommandAction
|
||||
Command="{Binding LinConfigProGridSelectionChangedCmd}"
|
||||
CommandParameter="{Binding ElementName=LinConfigDatagrid, Path=SelectedItem}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Binding="{Binding ConfigName}" Header="名称" Width="*" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<materialDesign:Card
|
||||
Grid.Column="1"
|
||||
Margin="3"
|
||||
Background="{DynamicResource MaterialDesignLightBackground}"
|
||||
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
|
||||
UniformCornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="80" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Text="参数" />
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" FontSize="16" Text="波特率:" />
|
||||
<TextBox
|
||||
Width="120"
|
||||
Margin="5,0,20,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Text="{Binding LinBaudRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<CheckBox
|
||||
VerticalAlignment="Center"
|
||||
Content="调度使能"
|
||||
IsChecked="{Binding CurrentSchEnable, Mode=TwoWay}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Click">
|
||||
<prism:InvokeCommandAction
|
||||
Command="{Binding SchEnableCmd}"
|
||||
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="10"
|
||||
FontSize="16"
|
||||
TextWrapping="Wrap"
|
||||
Text="提示:当前 ZLG LIN 仅提供硬件 LIN 收发能力;LDF 解析需要后续接入 ZLG 的 LDF DLL(不会返回模拟数据)。" />
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
28
CapMachine.Wpf/Views/ZlgLinDriveConfigView.xaml.cs
Normal file
28
CapMachine.Wpf/Views/ZlgLinDriveConfigView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace CapMachine.Wpf.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// ZlgLinDriveConfigView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ZlgLinDriveConfigView : UserControl
|
||||
{
|
||||
public ZlgLinDriveConfigView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Sample/C#_USBCANFD_251215/USBCANFD.sln
Normal file
28
Sample/C#_USBCANFD_251215/USBCANFD.sln
Normal 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
|
||||
6
Sample/C#_USBCANFD_251215/USBCANFD/App.config
Normal file
6
Sample/C#_USBCANFD_251215/USBCANFD/App.config
Normal 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>
|
||||
930
Sample/C#_USBCANFD_251215/USBCANFD/Program.cs
Normal file
930
Sample/C#_USBCANFD_251215/USBCANFD/Program.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")]
|
||||
99
Sample/C#_USBCANFD_251215/USBCANFD/USBCANFD.csproj
Normal file
99
Sample/C#_USBCANFD_251215/USBCANFD/USBCANFD.csproj
Normal 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>
|
||||
1236
Sample/C#_USBCANFD_251215/USBCANFD/ZLGAPI.cs
Normal file
1236
Sample/C#_USBCANFD_251215/USBCANFD/ZLGAPI.cs
Normal file
File diff suppressed because it is too large
Load Diff
28
Sample/zdbc_c#_251106/DBC.sln
Normal file
28
Sample/zdbc_c#_251106/DBC.sln
Normal 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
|
||||
6
Sample/zdbc_c#_251106/DBC/App.config
Normal file
6
Sample/zdbc_c#_251106/DBC/App.config
Normal 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>
|
||||
99
Sample/zdbc_c#_251106/DBC/DBC.csproj
Normal file
99
Sample/zdbc_c#_251106/DBC/DBC.csproj
Normal 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>
|
||||
411
Sample/zdbc_c#_251106/DBC/Program.cs
Normal file
411
Sample/zdbc_c#_251106/DBC/Program.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Sample/zdbc_c#_251106/DBC/Properties/AssemblyInfo.cs
Normal file
36
Sample/zdbc_c#_251106/DBC/Properties/AssemblyInfo.cs
Normal 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")]
|
||||
1169
Sample/zdbc_c#_251106/DBC/ZLGAPI.cs
Normal file
1169
Sample/zdbc_c#_251106/DBC/ZLGAPI.cs
Normal file
File diff suppressed because it is too large
Load Diff
28
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC.sln
Normal file
28
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC.sln
Normal 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
|
||||
6
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/App.config
Normal file
6
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/App.config
Normal 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>
|
||||
99
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/DBC.csproj
Normal file
99
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/DBC.csproj
Normal 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>
|
||||
411
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/Program.cs
Normal file
411
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/Program.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")]
|
||||
1169
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/ZLGAPI.cs
Normal file
1169
Sample/zdbc_c#_251106/zdbc_c#_251106/DBC/ZLGAPI.cs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user