Files
CapMachine/CapMachine.Wpf/CanDrive/ToomossCan.cs
2025-07-08 10:37:52 +08:00

911 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.Services;
using HslCommunication;
using NPOI.OpenXmlFormats.Wordprocessing;
using Prism.Ioc;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Interop;
using static CapMachine.Wpf.CanDrive.USB2CAN;
namespace CapMachine.Wpf.CanDrive
{
/// <summary>
/// Toomoss CAN
/// </summary>
public class ToomossCan : BindableBase
{
private readonly IContainerProvider ContainerProvider;
/// <summary>
/// 实例化函数
/// </summary>
public ToomossCan(IContainerProvider containerProvider)
{
ContainerProvider = containerProvider;
HighSpeedDataService = ContainerProvider.Resolve<HighSpeedDataService>();
//Stopwatch.Frequency表示高精度计时器每秒的计数次数ticks/秒每毫秒的ticks数 = 每秒的ticks数 ÷ 1000
TicksPerMs = Stopwatch.Frequency / 1000.0;
}
/// <summary>
/// 开始CAN的驱动
/// </summary>
public void StartCanDrive()
{
IsExistsDllFile();
ScanDevice();
OpenDevice();
GetDeviceInfo();
GetCANConfig();
InitCAN();
}
/// <summary>
/// HighSpeedDataService 实例
/// </summary>
public HighSpeedDataService HighSpeedDataService { get; set; }
/// <summary>
/// 开始Dbc文件写入
/// </summary>
public ObservableCollection<CanDbcModel> StartDbc(string DbcPath)
{
DBC_Parser(DbcPath);
return ListCanDbcModel;
}
///// <summary>
///// 获取Can DBC数据集合
///// </summary>
//public void LoadCanDbcData(ObservableCollection<CanDbcModel> canDbcModels)
//{
// ListCanDbcModel = canDbcModels;
//}
/// <summary>
/// Dbc消息集合
/// 包括读取的实时值和数据
/// </summary>
public ObservableCollection<CanDbcModel> ListCanDbcModel { get; set; } = new ObservableCollection<CanDbcModel>();
#region
/// <summary>
/// 设备固件信息
/// </summary>
public USB_DEVICE.DEVICE_INFO DevInfo = new USB_DEVICE.DEVICE_INFO();
/// <summary>
/// CAN Config
/// </summary>
USB2CAN.CAN_INIT_CONFIG CANConfig = new USB2CAN.CAN_INIT_CONFIG();
/// <summary>
/// DBC加载后获取的Handle
/// DBC Handle
/// </summary>
public UInt64 DBCHandle { get; set; }
/// <summary>
/// 扫描设备Handle集合
/// </summary>
public Int32[] DevHandles { get; set; } = new Int32[20];
/// <summary>
/// 扫描设备Handle
/// </summary>
public Int32 DevHandle { get; set; } = 0;
/// <summary>
/// Write CAN Index
/// 通道的含义
/// 描述:
/// 读取接收到的CAN消息推荐使用该函数。
///原型:
///int WINAPI CAN_GetMsgWithSize(int DevHandle, unsigned char CANIndex, CAN_MSG* pCanGetMsg, int BufferSize);
///参数:
///DevHandle 设备句柄本质为设备序号的低4字节可以通过调用USB_ScanDevice函数获得。
///CANIndex CAN通道索引号0-对应CAN1,1-对应CAN2。
///pCanGetMsg 存储CAN消息缓冲区首地址。
///BufferSize 存储CAN消息缓冲区大小。
///返回值:
//大于等于0表示从CAN适配器内部成功读取到的CAN消息帧数若返回值小于0则说明调用该函数失败。
/// 目前是WriteCANIndex和ReadCANIndex需要相同
/// </summary>
public Byte WriteCANIndex { get; set; } = 0;
/// <summary>
/// Read CAN Index
/// 通道的含义
/// 描述:
///读取接收到的CAN消息推荐使用该函数。
///原型:
///int WINAPI CAN_GetMsgWithSize(int DevHandle, unsigned char CANIndex, CAN_MSG* pCanGetMsg, int BufferSize);
///参数:
///DevHandle 设备句柄本质为设备序号的低4字节可以通过调用USB_ScanDevice函数获得。
///CANIndex CAN通道索引号0-对应CAN1,1-对应CAN2。
///pCanGetMsg 存储CAN消息缓冲区首地址。
///BufferSize 存储CAN消息缓冲区大小。
///返回值:
///大于等于0表示从CAN适配器内部成功读取到的CAN消息帧数若返回值小于0则说明调用该函数失败。
/// </summary>
public Byte ReadCANIndex { get; set; } = 0;
private bool _OpenState;
/// <summary>
/// 打开设备的状态
/// </summary>
public bool OpenState
{
get { return _OpenState; }
set { _OpenState = value; RaisePropertyChanged(); }
}
private bool _DbcParserState;
/// <summary>
/// DBC解析的状态
/// </summary>
public bool DbcParserState
{
get { return _DbcParserState; }
set { _DbcParserState = value; RaisePropertyChanged(); }
}
/// <summary>
/// 扫描到设备个数
/// </summary>
public Int32 DevNum { get; set; }
public Int32 ret { get; set; }
public string dllFilePath { get; set; } = "USB2XXX.dll";
/// <summary>
/// 消息值Pt
/// </summary>
public IntPtr msgPt { get; set; }
#endregion
/// <summary>
/// ******************【1】*********************
/// 是否存在Dll文件
/// </summary>
/// <returns></returns>
public bool IsExistsDllFile()
{
if (!File.Exists(dllFilePath))
{
Console.WriteLine("请先将USB2XXX.dll和libusb-1.0.dll文件复制到exe程序文件输出目录下!");
Console.WriteLine("dll文件在usb2can_lin_pwm_example/sdk/libs/windows目录下");
Console.WriteLine("程序是32位的就复制x86目录下文件程序是64位的就复制x86_64目录下文件");
return false;
}
return true;
}
/// <summary>
/// ******************【2】*********************
/// 扫描查找设备,并将每个设备的唯一设备号存放到数组中,后面的函数需要用到
/// </summary>
/// <returns></returns>
public bool ScanDevice()
{
DevNum = USB_DEVICE.USB_ScanDevice(DevHandles);
if (DevNum <= 0)
{
Console.WriteLine("No device connected!");
return false;
}
else
{
Console.WriteLine("Have {0} device connected!", DevNum);
DevHandle = DevHandles[0];//获取第一个设备的设备号
return true;
}
}
/// <summary>
/// ******************【3】*********************
/// 打开设备
/// </summary>
/// <returns></returns>
public bool OpenDevice()
{
//打开设备
OpenState = USB_DEVICE.USB_OpenDevice(DevHandle);
if (!OpenState)
{
Console.WriteLine("Open device error!");
return false;
}
else
{
Console.WriteLine("Open device success!");
return true;
}
}
/// <summary>
/// ******************【4】*********************
/// 获取设备的固件信息
/// </summary>
/// <returns></returns>
public bool GetDeviceInfo()
{
//获取固件信息
StringBuilder FuncStr = new StringBuilder(256);
OpenState = USB_DEVICE.DEV_GetDeviceInfo(DevHandle, ref DevInfo, FuncStr);
if (!OpenState)
{
Console.WriteLine("Get device infomation error!");
return false;
}
else
{
Console.WriteLine("Firmware Info:");
Console.WriteLine(" Name:" + Encoding.Default.GetString(DevInfo.FirmwareName));
Console.WriteLine(" Build Date:" + Encoding.Default.GetString(DevInfo.BuildDate));
Console.WriteLine(" Firmware Version:v{0}.{1}.{2}", (DevInfo.FirmwareVersion >> 24) & 0xFF, (DevInfo.FirmwareVersion >> 16) & 0xFF, DevInfo.FirmwareVersion & 0xFFFF);
Console.WriteLine(" Hardware Version:v{0}.{1}.{2}", (DevInfo.HardwareVersion >> 24) & 0xFF, (DevInfo.HardwareVersion >> 16) & 0xFF, DevInfo.HardwareVersion & 0xFFFF);
Console.WriteLine(" Functions:" + DevInfo.Functions.ToString("X8"));
Console.WriteLine(" Functions String:" + FuncStr);
StringBuilder DLLBuildDate = new StringBuilder(256);
USB_DEVICE.DEV_GetDllBuildTime(DLLBuildDate);
Console.WriteLine(" DLL Build Date:" + DLLBuildDate);
return true;
}
}
/// <summary>
/// ******************【5】*********************
/// 获取设备Config配置
/// </summary>
public void GetCANConfig()
{
CANConfig.CAN_Mode = 0x80;//正常模式并接入终端电阻
//获取CAN波特率参数
ret = USB2CAN.CAN_GetCANSpeedArg(DevHandle, ref CANConfig, 500000);
if (ret != USB2CAN.CAN_SUCCESS)
{
Console.WriteLine("Get CAN Speed failed!");
return;
}
else
{
Console.WriteLine("Get CAN Speed Success!");
}
}
/// <summary>
/// ******************【6】*********************
/// 初始化CAN
/// </summary>
public void InitCAN()
{
//初始化CAN
ret = USB2CAN.CAN_Init(DevHandle, WriteCANIndex, ref CANConfig);
if (ret != USB2CAN.CAN_SUCCESS)
{
Console.WriteLine("Config CAN failed!");
return;
}
else
{
Console.WriteLine("WriteCANIndex Config CAN Success!");
}
ret = USB2CAN.CAN_Init(DevHandle, ReadCANIndex, ref CANConfig);
if (ret != USB2CAN.CAN_SUCCESS)
{
Console.WriteLine("Config CAN failed!");
return;
}
else
{
Console.WriteLine("ReadCANIndex Config CAN Success!");
}
Console.WriteLine("");
}
/// <summary>
/// ******************【7】*********************
/// DBC解析
/// </summary>
public void DBC_Parser(string Path)
{
//解析DBC文件
DBCHandle = CAN_DBCParser.DBC_ParserFile(DevHandle, new StringBuilder(Path));
if (DBCHandle == 0)
{
Console.WriteLine("Parser DBC File error!");
DbcParserState = false;
return;
}
else
{
Console.WriteLine("Parser DBC File success!");
}
ListCanDbcModel.Clear();
//打印DBC里面报文和信号相关信息
int DBCMsgNum = CAN_DBCParser.DBC_GetMsgQuantity(DBCHandle);
for (int i = 0; i < DBCMsgNum; i++)
{
StringBuilder MsgName = new StringBuilder(32);
CAN_DBCParser.DBC_GetMsgName(DBCHandle, i, MsgName);
Console.WriteLine("Msg.Name = {0}", MsgName);
int DBCSigNum = CAN_DBCParser.DBC_GetMsgSignalQuantity(DBCHandle, MsgName);
StringBuilder Publisher = new StringBuilder(32);
CAN_DBCParser.DBC_GetMsgPublisher(DBCHandle, MsgName, Publisher);
long MsgId;
MsgId = CAN_DBCParser.DBC_GetMsgIDByName(DBCHandle, MsgName);
Console.Write("Signals:");
for (int j = 0; j < DBCSigNum; j++)
{
StringBuilder SigName = new StringBuilder(32);
CAN_DBCParser.DBC_GetMsgSignalName(DBCHandle, MsgName, j, SigName);
Console.Write("{0} ", SigName);
//增加信息数据
ListCanDbcModel.Add(new CanDbcModel()
{
MsgName = MsgName.ToString(),
MsgId = "0x" + MsgId.ToString("X8"),
SignalName = SigName.ToString(),
SignalDesc = "",
SignalUnit = "",
SignalRtValue = "",
Publisher = Publisher.ToString()
});
}
Console.WriteLine("");
}
//Dbc解析成功
DbcParserState = true;
}
/// <summary>
/// 发送CAN数据
/// 发送一次
/// </summary>
public void SendCanMsg(List<CanCmdData> CmdData)
{
var GroupMsg = CmdData.GroupBy(x => x.MsgName);
USB2CAN.CAN_MSG[] CanMsg = new USB2CAN.CAN_MSG[GroupMsg.Count()];
for (int i = 0; i < GroupMsg.Count(); i++)
{
CanMsg[i] = new USB2CAN.CAN_MSG();
CanMsg[i].Data = new Byte[64];
}
IntPtr msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int Index = 0;
//循环给MSG赋值数据
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
}
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPt);
CanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPt, typeof(USB2CAN.CAN_MSG));
Index++;
}
//设置信号值
//DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), 2412);
//DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), 980);
//DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), 120);
//通过DBC写入数据后生成CanMsg
//将信号值填入CAN消息里面
//释放申请的临时缓冲区
Marshal.FreeHGlobal(msgPt);
Console.WriteLine("");
//发送CAN数据
int SendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, CanMsg, (uint)CanMsg.Length);
if (SendedNum >= 0)
{
Console.WriteLine("Success send frames:{0}", SendedNum);
}
else
{
Console.WriteLine("Send CAN data failed! {0}", SendedNum);
}
}
private bool _IsCycleRevice;
/// <summary>
/// 是否循环接收数据
/// </summary>
public bool IsCycleRevice
{
get { return _IsCycleRevice; }
set { _IsCycleRevice = value; RaisePropertyChanged(); }
}
private bool _IsCycleSend;
/// <summary>
/// 是否循环发送数据
/// </summary>
public bool IsCycleSend
{
get { return _IsCycleSend; }
set { _IsCycleSend = value; RaisePropertyChanged(); }
}
/// <summary>
/// 循环发送数据
/// </summary>
public ushort SendCycle { get; set; } = 100;
/// <summary>
/// 循环接受数据
/// </summary>
public ushort ReviceCycle { get; set; } = 500;
/// <summary>
/// CycleRevice 扫描Task
/// </summary>
private static Task CycleReviceTask { get; set; }
/// <summary>
/// CycleSend 扫描Task
/// </summary>
private static Task CycleSendTask { get; set; }
StringBuilder ValueSb = new StringBuilder(16);
double[] ValueDouble=new double[5];
private bool _IsSendOk;
/// <summary>
/// 发送报文是否OK
/// </summary>
public bool IsSendOk
{
get { return _IsSendOk; }
set
{
if (_IsSendOk != value)
{
RaisePropertyChanged();
_IsSendOk = value;
}
}
}
/// <summary>
/// 要发送的数据
/// </summary>
public List<CanCmdData> CmdData { get; set; } = new List<CanCmdData>();
/// <summary>
/// 循环发送数据
/// </summary>
public void StartCycleSendMsg()
{
CycleSendTask = Task.Run(async () =>
{
while (IsCycleSend)
{
await Task.Delay(SendCycle);
try
{
var GroupMsg = CmdData.GroupBy(x => x.MsgName);
USB2CAN.CAN_MSG[] CanMsg = new USB2CAN.CAN_MSG[GroupMsg.Count()];
for (int i = 0; i < GroupMsg.Count(); i++)
{
CanMsg[i] = new USB2CAN.CAN_MSG();
CanMsg[i].Data = new Byte[64];
}
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int Index = 0;
//循环给MSG赋值数据
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
}
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
CanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
Index++;
}
//通过DBC写入数据后生成CanMsg
//将信号值填入CAN消息里面
//释放申请的临时缓冲区
Marshal.FreeHGlobal(msgPtSend);
Console.WriteLine("");
//发送CAN数据
int SendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, CanMsg, (uint)CanMsg.Length);
if (SendedNum >= 0)
{
Console.WriteLine("Success send frames:{0}", SendedNum);
}
else
{
Console.WriteLine("Send CAN data failed! {0}", SendedNum);
}
}
catch (Exception ex)
{
//LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
}
}
});
}
#region
// 添加取消标记源字段用于停止任务
private CancellationTokenSource CycleSendCts;
/// <summary>
/// 计算每毫秒对应的ticks数只需计算一次
/// </summary>
private double TicksPerMs;
// 类成员变量定义 精确记时用
private readonly Stopwatch Stopwatcher = new Stopwatch();
private long NextExecutionTime;
// 计算需要等待的时间
private long CurrentTime;
private long DelayTicks;
private int DelayMs;
private static readonly Random _random = new Random();
/// <summary>
/// 精确周期发送CAN数据
/// </summary>
public void StartPrecisionCycleSendMsg()
{
// 创建取消标记源 用于控制任务的取消 允许在需要时通过取消令牌来优雅停止任务
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
// 保存取消标记,以便在停止时使用
CycleSendCts = cancellationTokenSource;//将取消标记源保存到类的成员变量CycleSendCts这样在外部调用停止方法时可以访问它
NextExecutionTime = 0;//初始化NextExecutionTime为0这个变量用于记录下一次执行的目标时间点
CycleSendTask = Task.Factory.StartNew(async () =>
{
try
{
// 设置当前线程为高优先级
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
// 初始化完成后开始计时
Stopwatcher.Restart();
// 预先计算固定值
long CycleInTicks = (long)(SendCycle * TicksPerMs);
//临时测试用
//long lastTicks = Stopwatcher.ElapsedTicks;
//IsCycleSend
while (IsCycleSend && !token.IsCancellationRequested)
{
try
{
// 计算下一次执行时间点 将当前设置的发送周期SendCycle(毫秒)转换为Stopwatch的计时单位(tick)累加到NextExecutionTime上
NextExecutionTime += CycleInTicks; // 转换为Stopwatch计时单位
// 获取当前时间点以Stopwatch的tick为单位
CurrentTime = Stopwatcher.ElapsedTicks;
//计算需要等待的时间,即目标时间点(NextExecutionTime)与当前时间点(CurrentTime)的差值
DelayTicks = NextExecutionTime - CurrentTime;
// 如果还有等待时间,则等待,只有在目标时间点还未到达时才执行等待
if (DelayTicks > 0)
{
////此时是需要等待的,那么需要等待多久呢, 将需等待的tick数转换回毫秒
DelayMs = (int)(DelayTicks / TicksPerMs);
//20这个数据是预估和测试的可能跟Windows抖动误差就是20ms左右当然可以不用这个IF()判断直接SpinWait.SpinUntil(() => Stopwatcher.ElapsedTicks >= NextExecutionTime);但是会导致当前独占一个CPU核心线程
//所以设置一个20的阈值20ms以下的延迟使用SpinWait.SpinUntil进行自旋等待20ms以上的延迟使用Task.Delay进行异步等待让CPU不至于一直的独占
if (DelayMs <= 20)
{
SpinWait.SpinUntil(() => Stopwatcher.ElapsedTicks >= NextExecutionTime);
}
else
{
////使用Task.Delay进行异步等待大部分等待时间通过这种方式完成避免线程阻塞
await Task.Delay(DelayMs - 20, token);
//// 使用SpinWait.SpinUntil进行精确的微调等待。自旋等待会占用CPU资源但能提供更高的定时精度确保在精确的时间点执行
////上面的Task.Delay可能会因为系统调度等原因导致实际执行时间稍晚于预期因此在这里使用SpinWait.SpinUntil来确保在精确的时间点执行
SpinWait.SpinUntil(() => Stopwatcher.ElapsedTicks >= NextExecutionTime);
}
}
// 如果已经超过了计划时间,立即执行并重新校准
if (Stopwatcher.ElapsedTicks >= NextExecutionTime + CycleInTicks)
{
//检测是否发生了严重延迟(超过一个周期)。如果当前时间已经超过了下一次计划时间,则说明系统负载过高或其他原因导致无法按时执行,
//此时重置NextExecutionTime为当前时间避免连续的延迟累积
// 严重延迟,重新校准
NextExecutionTime = Stopwatcher.ElapsedTicks;
Console.WriteLine("定时发送延迟过大,重新校准时间");
}
// 使用Stopwatch记录实际的执行间隔而不是DateTime
//Console.WriteLine($"--实际间隔(ms): {(Stopwatcher.ElapsedTicks - lastTicks) / TicksPerMs:F3}, 目标: {SendCycle}");
//lastTicks = Stopwatcher.ElapsedTicks;
//Console.WriteLine($"--当前时间(毫秒): {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
// 执行发送CAN逻辑
{
var GroupMsg = CmdData.GroupBy(x => x.MsgName);
USB2CAN.CAN_MSG[] CanMsg = new USB2CAN.CAN_MSG[GroupMsg.Count()];
for (int i = 0; i < GroupMsg.Count(); i++)
{
CanMsg[i] = new USB2CAN.CAN_MSG();
CanMsg[i].Data = new Byte[64];
}
IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)));
int Index = 0;
//循环给MSG赋值数据
foreach (var itemMsg in GroupMsg)
{
foreach (var itemSignal in itemMsg)
{
CAN_DBCParser.DBC_SetSignalValue(DBCHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), itemSignal.SignalCmdValue);
}
CAN_DBCParser.DBC_SyncValueToCANMsg(DBCHandle, new StringBuilder(itemMsg.Key), msgPtSend);
CanMsg[Index] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(msgPtSend, typeof(USB2CAN.CAN_MSG));
Index++;
}
//通过DBC写入数据后生成CanMsg
//将信号值填入CAN消息里面
//释放申请的临时缓冲区
Marshal.FreeHGlobal(msgPtSend);
//发送CAN数据
int SendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, CanMsg, (uint)CanMsg.Length);
if (SendedNum >= 0)
{
//Console.WriteLine("Success send frames:{0}", SendedNum);
IsSendOk = true;
}
else
{
//Console.WriteLine("Send CAN data failed! {0}", SendedNum);
IsSendOk = false;
}
}
}
catch (TaskCanceledException)
{
// 任务被取消,正常退出
break;
}
catch (Exception ex)
{
Console.WriteLine($"CAN周期发送异常: {ex.Message}");
// 短暂暂停避免异常情况下CPU占用过高
await Task.Delay(10, token);
}
}
}
catch (Exception ex)
{
// 确保在任何情况下(正常退出、异常、取消)都会停止计时器
Stopwatcher.Stop();
// 清理其他可能的资源
Console.WriteLine("CAN周期发送任务已结束资源已清理");
}
finally
{
// 确保在任何情况下(正常退出、异常、取消)都会停止计时器
Stopwatcher.Stop();
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
/// <summary>
/// 修改停止发送的方法
/// </summary>
public void StopCycleSendMsg()
{
IsCycleSend = false;
CycleSendCts?.Cancel();
}
#endregion
/// <summary>
/// 循环获取CAN消息
/// </summary>
public void StartCycleReviceCanMsg()
{
CycleReviceTask = Task.Run(async () =>
{
while (IsCycleRevice)
{
await Task.Delay(ReviceCycle);
try
{
//另外一个CAN通道读取数据
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[128];
//申请数据缓冲区
IntPtr msgPtRead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);
int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
if (CanNum > 0)
{
Console.WriteLine("Read CanMsgNum = {0}", CanNum);
for (int i = 0; i < CanNum; i++)
{
//CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG)); //有溢出报错
CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)(msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG));
Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
Console.WriteLine("CanMsg[{0}].TimeStamp = {1}", i, CanMsgBuffer[i].TimeStamp);
Console.Write("CanMsg[{0}].Data = ", i);
for (int j = 0; j < CanMsgBuffer[i].DataLen; j++)
{
Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
}
Console.WriteLine("");
//报文给高速记录的服务
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
{
Category = "CAN",
MsgInfo = "0x" + CanMsgBuffer[i].ID.ToString("X8"),
MsgData = BitConverter.ToString(CanMsgBuffer[i].Data),
Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
});
}
}
else if (CanNum == 0)
{
Console.WriteLine("No CAN data!");
}
else
{
Console.WriteLine("Get CAN data error!");
}
Console.WriteLine("");
//将CAN消息数据填充到信号里面用DBC解析数据
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
//循环获取消息的数据
foreach (var item in ListCanDbcModel)
{
//有配置的名称的,认为是有用的,则需要读取数据
//if (!string.IsNullOrEmpty(item.Name))
//{
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), ValueSb);
//double[] ValueDouble;
CAN_DBCParser.DBC_GetSignalValue(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), ValueDouble);
//item.SignalRtValueSb = ValueSb;
item.SignalRtValue = ValueDouble[0].ToString();
//Console.Write(ValueSb.ToString());
//}
}
//释放数据缓冲区,必须释放,否则程序运行一段时间后会报内存不足
Marshal.FreeHGlobal(msgPtRead);
Thread.Sleep(10);
////获取信号值并打印出来
//StringBuilder ValueStr = new StringBuilder(32);
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), ValueStr);
//Console.WriteLine("moto_speed = {0}", ValueStr);
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), ValueStr);
//Console.WriteLine("oil_pressure = {0}", ValueStr);
//CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), ValueStr);
//Console.WriteLine("speed_can = {0}", ValueStr);
}
catch (Exception ex)
{
//LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
}
}
});
}
/// <summary>
/// 接受CAN消息
/// </summary>
public void ReciveCanMsg()
{
//另外一个CAN通道读取数据
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[10];
msgPt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);
int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPt, CanMsgBuffer.Length);
if (CanNum > 0)
{
Console.WriteLine("Read CanMsgNum = {0}", CanNum);
for (int i = 0; i < CanNum; i++)
{
CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)msgPt + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG));
Console.WriteLine("CanMsg[{0}].ID = 0x{1}", i, CanMsgBuffer[i].ID.ToString("X8"));
//Console.WriteLine("CanMsg[{0}].TimeStamp = {1}",i,CanMsgBuffer[i].TimeStamp);
Console.Write("CanMsg[{0}].Data = ", i);
for (int j = 0; j < CanMsgBuffer[i].DataLen; j++)
{
Console.Write("{0} ", CanMsgBuffer[i].Data[j].ToString("X2"));
}
Console.WriteLine("");
}
}
else if (CanNum == 0)
{
Console.WriteLine("No CAN data!");
}
else
{
Console.WriteLine("Get CAN data error!");
}
Console.WriteLine("");
//将CAN消息数据填充到信号里面
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPt, CanNum);
//获取信号值并打印出来
StringBuilder ValueStr = new StringBuilder(32);
CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_moto_speed"), new StringBuilder("moto_speed"), ValueStr);
Console.WriteLine("moto_speed = {0}", ValueStr);
CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_oil_pressure"), new StringBuilder("oil_pressure"), ValueStr);
Console.WriteLine("oil_pressure = {0}", ValueStr);
CAN_DBCParser.DBC_GetSignalValueStr(DBCHandle, new StringBuilder("msg_speed_can"), new StringBuilder("speed_can"), ValueStr);
Console.WriteLine("speed_can = {0}", ValueStr);
}
/// <summary>
/// 关闭设备
/// </summary>
public void CloseDevice()
{
//关闭设备
USB_DEVICE.USB_CloseDevice(DevHandle);
OpenState = false;
DbcParserState = false;
IsCycleRevice = false;
IsCycleSend = false;
}
}
}