From 2b2097d1ed9dacca32d42c7796748e39813c3af1 Mon Sep 17 00:00:00 2001 From: Tyrone CT Date: Thu, 14 May 2026 17:21:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=8A=A88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CapMachine.Wpf/CanDrive/ToomossCan.cs | 242 ++++++++++----------- CapMachine.Wpf/Services/CanDriveService.cs | 4 +- 2 files changed, 119 insertions(+), 127 deletions(-) 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(); } }