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