This commit is contained in:
2026-05-14 17:21:47 +08:00
parent b67ba5bb27
commit 2b2097d1ed
2 changed files with 119 additions and 127 deletions

View File

@@ -12,6 +12,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Interop; using System.Windows.Interop;
@@ -27,7 +28,19 @@ namespace CapMachine.Wpf.CanDrive
private readonly IContainerProvider ContainerProvider; private readonly IContainerProvider ContainerProvider;
private readonly object _dbcParserLock = new object(); private readonly object _dbcParserLock = new object();
private readonly object _canSendLock = new object(); private readonly object _canSendLock = new object();
private readonly object _recvBufferLock = new object();
private const int DbcStringBufferCapacity = 256; private const int DbcStringBufferCapacity = 256;
private const int RecvBufferSize = 128;
/// <summary>
/// 预分配的接收缓冲区指针,避免每次循环分配/释放
/// </summary>
private IntPtr RecvMsgBufferPtr = IntPtr.Zero;
/// <summary>
/// 接收缓冲区对应的托管数组
/// </summary>
private readonly USB2CAN.CAN_MSG[] RecvMsgBuffer = new USB2CAN.CAN_MSG[RecvBufferSize];
/// <summary> /// <summary>
/// 实例化函数 /// 实例化函数
@@ -508,12 +521,12 @@ namespace CapMachine.Wpf.CanDrive
/// <summary> /// <summary>
/// CycleRevice 扫描Task /// CycleRevice 扫描Task
/// </summary> /// </summary>
private static Task CycleReviceTask { get; set; } private Task? CycleReviceTask { get; set; }
/// <summary> /// <summary>
/// CycleSend 扫描Task /// CycleSend 扫描Task
/// </summary> /// </summary>
private static Task CycleSendTask { get; set; } private Task? CycleSendTask { get; set; }
StringBuilder ValueSb = new StringBuilder(16); StringBuilder ValueSb = new StringBuilder(16);
@@ -551,7 +564,7 @@ namespace CapMachine.Wpf.CanDrive
/// <summary> /// <summary>
/// 循环获取CAN消息 /// 循环获取CAN消息(使用预分配缓冲区,避免每次循环内存分配/释放)
/// </summary> /// </summary>
public void StartCycleReviceCanMsg() public void StartCycleReviceCanMsg()
{ {
@@ -560,105 +573,105 @@ namespace CapMachine.Wpf.CanDrive
return; return;
} }
// 预分配接收缓冲区(仅在首次或已释放后分配)
EnsureRecvBufferAllocated();
CycleReviceTask = Task.Run(async () => CycleReviceTask = Task.Run(async () =>
{ {
var msgSize = Marshal.SizeOf(typeof(USB2CAN.CAN_MSG));
double[] valueDouble = new double[1];
while (IsCycleRevice) while (IsCycleRevice)
{ {
await Task.Delay(ReviceCycle); await Task.Delay(ReviceCycle);
try try
{ {
IntPtr msgPtRead = IntPtr.Zero; int CanNum;
try lock (_recvBufferLock)
{ {
//另外一个CAN通道读取数据 if (RecvMsgBufferPtr == IntPtr.Zero) break;
USB2CAN.CAN_MSG[] CanMsgBuffer = new USB2CAN.CAN_MSG[128]; CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, RecvMsgBufferPtr, RecvBufferSize);
//申请数据缓冲区
msgPtRead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * CanMsgBuffer.Length);
int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, CanMsgBuffer.Length);
if (CanNum > 0) if (CanNum > 0)
{ {
for (int i = 0; i < CanNum; i++) 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)); //有溢出报错 RecvMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure(
CanMsgBuffer[i] = (USB2CAN.CAN_MSG)Marshal.PtrToStructure((IntPtr)(msgPtRead + i * Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))), typeof(USB2CAN.CAN_MSG)); (IntPtr)(RecvMsgBufferPtr + i * msgSize), 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);
//Console.WriteLine("");
//报文给高速记录的服务
HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg() HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
{ {
Category = "CAN", Category = "CAN",
MsgInfo = "0x" + CanMsgBuffer[i].ID.ToString("X8"), MsgInfo = "0x" + RecvMsgBuffer[i].ID.ToString("X8"),
MsgData = BitConverter.ToString(CanMsgBuffer[i].Data), MsgData = BitConverter.ToString(RecvMsgBuffer[i].Data),
Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") 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!");
}
if (CanNum > 0)
{
lock (_dbcParserLock)
{
//将CAN消息数据填充到信号里面用DBC解析数据
CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum);
double[] valueDouble = new double[1]; if (CanNum > 0)
//循环获取消息的数据 {
foreach (var item in ListCanDbcModel) lock (_dbcParserLock)
{ {
//有配置的名称的,认为是有用的,则需要读取数据 lock (_recvBufferLock)
//if (!string.IsNullOrEmpty(item.Name)) {
//{ if (RecvMsgBufferPtr == IntPtr.Zero) break;
valueDouble[0] = 0; CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, RecvMsgBufferPtr, CanNum);
CAN_DBCParser.DBC_GetSignalValue(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), valueDouble); }
item.SignalRtValue = valueDouble[0].ToString();
//} foreach (var item in ListCanDbcModel)
} {
valueDouble[0] = 0;
CAN_DBCParser.DBC_GetSignalValue(DBCHandle, new StringBuilder(item.MsgName), new StringBuilder(item.SignalName), valueDouble);
item.SignalRtValue = valueDouble[0].ToString();
} }
} }
} }
finally
{
if (msgPtRead != IntPtr.Zero)
{
//释放数据缓冲区,必须释放,否则程序运行一段时间后会报内存不足
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) catch (Exception ex)
{ {
//LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}"); Console.WriteLine($"CAN循环接收异常: {ex.Message}");
} }
} }
}); });
} }
/// <summary>
/// 确保接收缓冲区已分配
/// </summary>
private void EnsureRecvBufferAllocated()
{
lock (_recvBufferLock)
{
if (RecvMsgBufferPtr == IntPtr.Zero)
{
RecvMsgBufferPtr = Marshal.AllocHGlobal(
Marshal.SizeOf(typeof(USB2CAN.CAN_MSG)) * RecvBufferSize);
}
}
}
/// <summary>
/// 释放接收缓冲区
/// </summary>
private void FreeRecvBuffer()
{
lock (_recvBufferLock)
{
if (RecvMsgBufferPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(RecvMsgBufferPtr);
RecvMsgBufferPtr = IntPtr.Zero;
}
}
}
#region #region
// 添加取消标记源字段用于停止任务 // 添加取消标记源字段用于停止任务
private CancellationTokenSource CycleSendCts; private CancellationTokenSource? CycleSendCts;
/// <summary> /// <summary>
/// 计算每毫秒对应的ticks数只需计算一次 /// 计算每毫秒对应的ticks数只需计算一次
@@ -673,8 +686,6 @@ namespace CapMachine.Wpf.CanDrive
private long DelayTicks; private long DelayTicks;
private int DelayMs; private int DelayMs;
private static readonly Random _random = new Random();
/// <summary> /// <summary>
/// 精确周期发送CAN数据 /// 精确周期发送CAN数据
/// </summary> /// </summary>
@@ -778,16 +789,13 @@ namespace CapMachine.Wpf.CanDrive
} }
catch (Exception ex) catch (Exception ex)
{ {
// 确保在任何情况下(正常退出、异常、取消)都会停止计时器 Console.WriteLine($"CAN精确周期发送异常: {ex.Message}");
Stopwatcher.Stop();
// 清理其他可能的资源
Console.WriteLine("CAN周期发送任务已结束资源已清理");
} }
finally finally
{ {
// 确保在任何情况下(正常退出、异常、取消)都会停止计时器 // 确保在任何情况下(正常退出、异常、取消)都会停止计时器
Stopwatcher.Stop(); Stopwatcher.Stop();
Console.WriteLine("CAN周期发送任务已结束资源已清理");
} }
}, token); }, token);
@@ -807,54 +815,6 @@ namespace CapMachine.Wpf.CanDrive
/// <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>
/// 关闭设备 /// 关闭设备
/// </summary> /// </summary>
@@ -862,22 +822,54 @@ namespace CapMachine.Wpf.CanDrive
{ {
IsCycleRevice = false; IsCycleRevice = false;
IsCycleSend = false; IsCycleSend = false;
// 停止精确发送并释放CTS
try try
{ {
StopCycleSendMsg(); StopCycleSendMsg();
} }
catch catch (Exception ex)
{ {
Console.WriteLine($"停止CAN发送异常: {ex.Message}");
} }
// 等待发送任务结束
try try
{ {
var task = CycleReviceTask; var sendTask = CycleSendTask;
if (task != null && !task.IsCompleted) if (sendTask != null && !sendTask.IsCompleted)
{ {
task.Wait(TimeSpan.FromMilliseconds(ReviceCycle + 500)); sendTask.Wait(TimeSpan.FromMilliseconds(SendCycle * 3 + 500));
} }
} }
catch (Exception ex)
{
Console.WriteLine($"等待CAN发送任务结束异常: {ex.Message}");
}
// 等待接收任务结束
try
{
var recvTask = CycleReviceTask;
if (recvTask != null && !recvTask.IsCompleted)
{
recvTask.Wait(TimeSpan.FromMilliseconds(ReviceCycle + 500));
}
}
catch (Exception ex)
{
Console.WriteLine($"等待CAN接收任务结束异常: {ex.Message}");
}
// 释放接收缓冲区
FreeRecvBuffer();
// 释放CTS资源
try
{
CycleSendCts?.Dispose();
CycleSendCts = null;
}
catch catch
{ {
} }

View File

@@ -222,7 +222,7 @@ namespace CapMachine.Wpf.Services
{ {
ToomossCanDrive.IsCycleSend = true; ToomossCanDrive.IsCycleSend = true;
ToomossCanDrive.CmdData = CmdData; ToomossCanDrive.CmdData = CmdData;
ToomossCanDrive.StartCycleSendMsg(); ToomossCanDrive.StartPrecisionCycleSendMsg();
} }
else else
{ {
@@ -231,7 +231,7 @@ namespace CapMachine.Wpf.Services
} }
else else
{ {
ToomossCanDrive.IsCycleSend = false; ToomossCanDrive.StopCycleSendMsg();
} }
} }