From b217acd7e9c83ef7aa6546f90fafe7d53341c650 Mon Sep 17 00:00:00 2001 From: Tyrone CT Date: Thu, 14 May 2026 22:04:31 +0800 Subject: [PATCH] =?UTF-8?q?ClaudeCode=20=E6=9B=B4=E6=94=B92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CapMachine.Wpf/CanDrive/ToomossCan.cs | 81 ++++++++++------------ CapMachine.Wpf/CapMachine.Wpf.csproj | 1 - CapMachine.Wpf/Services/CanDriveService.cs | 59 +++++----------- 3 files changed, 52 insertions(+), 89 deletions(-) diff --git a/CapMachine.Wpf/CanDrive/ToomossCan.cs b/CapMachine.Wpf/CanDrive/ToomossCan.cs index 3d06943..b52b752 100644 --- a/CapMachine.Wpf/CanDrive/ToomossCan.cs +++ b/CapMachine.Wpf/CanDrive/ToomossCan.cs @@ -711,8 +711,11 @@ namespace CapMachine.Wpf.CanDrive CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, ReadCANIndex, msgPtRead, RecvMsgBufferCapacity); //int CanNum = USB2CAN.CAN_GetMsgWithSize(DevHandle, 1, msgPtRead, RecvMsgBufferCapacity);//测试用,CAN卡 CAN1和CAN2 短接时测试用 //monitorValueLog.UpdateValue4(CanNum); + int SyncCANMsgToValue = CAN_DBCParser.DBC_PARSER_OK; if (CanNum > 0) { + //仅当确实收到了报文,才把缓冲区交给 DBC 解析器,避免负数 / 0 传给原生函数造成越界读后堆腐败 + SyncCANMsgToValue = CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum); IsReviceOk = true; if (EnableConsoleDebugLog) Console.WriteLine("Read CanMsgNum = {0}", CanNum); for (int i = 0; i < CanNum; i++) @@ -752,9 +755,10 @@ namespace CapMachine.Wpf.CanDrive IsReviceOk = false; if (EnableConsoleDebugLog) Console.WriteLine("Get CAN data error!"); } - // 将CAN消息数据填充到信号里面,用DBC解析数据(仍在锁内,避免指针被并发释放) - var SyncCANMsgToValue = CAN_DBCParser.DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum); - //monitorValueLog.UpdateValue5(SyncCANMsgToValue); + //【已修复】原来此处无条件调用 DBC_SyncCANMsgToValue(DBCHandle, msgPtRead, CanNum) + //当 CanNum == 0(无报文)或 CanNum < 0(读失败)时把无效 MsgLen 传给原生 DBC 解析器, + //会越界读 msgPtRead 缓冲后的内存导致 GC 堆腐败,运行一段时间后随机位置 AV(0xC0000005)。 + //现已挪到 CanNum > 0 分支内(参考 HASCO_Simple25001 的 StartCycleReviceCanMsg1 写法)。 } //循环获取消息的数据 @@ -962,30 +966,10 @@ namespace CapMachine.Wpf.CanDrive // 执行发送CAN逻辑 { - //再次校验前置条件,运行中若设备/DBC被关闭则直接跳过本轮(避免传 0 句柄给原生导致 AV) - if (!OpenState || DBCHandle == 0 || CmdData == null || CmdData.Count == 0) - { - await Task.Delay(10, token); - continue; - } - //本轮要发送的指令快照(避免遍历时 UI 线程并发修改) - List roundSnapshot; - lock (_canSendLock) - { - roundSnapshot = CmdData - .Where(x => !string.IsNullOrWhiteSpace(x.MsgName) && !string.IsNullOrWhiteSpace(x.SignalName)) - .ToList(); - } - if (roundSnapshot.Count == 0) - { - await Task.Delay(10, token); - continue; - } - - var GroupMsg = roundSnapshot.GroupBy(x => x.MsgName).ToList(); - USB2CAN.CAN_MSG[] CanMsg = new USB2CAN.CAN_MSG[GroupMsg.Count]; - for (int i = 0; i < GroupMsg.Count; i++) + 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]; @@ -993,33 +977,38 @@ namespace CapMachine.Wpf.CanDrive // 发送构帧临时缓冲:每轮申请/释放,避免与其他线程共享同一指针导致并发问题 IntPtr msgPtSend = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(USB2CAN.CAN_MSG))); - try + int Index = 0; + //循环给MSG赋值数据 + foreach (var itemMsg in GroupMsg) { - int Index = 0; - //循环给MSG赋值数据;DBC 解析器在 .Net 侧不是线程安全的,必须串行化 - lock (_dbcParserLock) + foreach (var itemSignal in itemMsg) { - 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++; - } + 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++; } - finally - { - // 释放非托管缓冲区(务必释放,否则长时间运行会造成内存泄漏) - Marshal.FreeHGlobal(msgPtSend); - } + + //通过DBC写入数据后生成CanMsg + //将信号值填入CAN消息里面 + + // 释放非托管缓冲区(务必释放,否则长时间运行会造成内存泄漏) + Marshal.FreeHGlobal(msgPtSend); //发送CAN数据 int SendedNum = USB2CAN.CAN_SendMsg(DevHandle, WriteCANIndex, CanMsg, (uint)CanMsg.Length); - IsSendOk = SendedNum >= 0; + if (SendedNum >= 0) + { + //Console.WriteLine("Success send frames:{0}", SendedNum); + IsSendOk = true; + } + else + { + //Console.WriteLine("Send CAN data failed! {0}", SendedNum); + IsSendOk = false; + } + } diff --git a/CapMachine.Wpf/CapMachine.Wpf.csproj b/CapMachine.Wpf/CapMachine.Wpf.csproj index 0e7ca38..87c66e3 100644 --- a/CapMachine.Wpf/CapMachine.Wpf.csproj +++ b/CapMachine.Wpf/CapMachine.Wpf.csproj @@ -7,7 +7,6 @@ enable true AnyCPU - true diff --git a/CapMachine.Wpf/Services/CanDriveService.cs b/CapMachine.Wpf/Services/CanDriveService.cs index 9160f2b..7e02948 100644 --- a/CapMachine.Wpf/Services/CanDriveService.cs +++ b/CapMachine.Wpf/Services/CanDriveService.cs @@ -214,52 +214,27 @@ namespace CapMachine.Wpf.Services /// public void CycleSendMsg() { - if (!ToomossCanDrive.OpenState) + if (ToomossCanDrive.OpenState) { - System.Windows.MessageBox.Show("CAN未打开,请先连接CAN", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand); - return; - } - - //停止已在运行的循环 - if (ToomossCanDrive.IsCycleSend == true) - { - ToomossCanDrive.StopCycleSendMsg(); - return; - } - - //必要的前置校验:DBC 必须已解析成功,否则原生互操作直接 AccessViolation 闪退 - if (!ToomossCanDrive.DbcParserState || ToomossCanDrive.DBCHandle == 0) - { - System.Windows.MessageBox.Show("DBC尚未解析成功,无法循环发送", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand); - return; - } - - //过滤掉 MsgName / SignalName 为空的行(空名传给原生 DBC 解析器是 AV 常见诱因) - List cmdDataSnapshot; - lock (_cmdDataLock) - { - cmdDataSnapshot = CmdData - .Where(x => !string.IsNullOrWhiteSpace(x.MsgName) && !string.IsNullOrWhiteSpace(x.SignalName)) - .Select(x => new CanCmdData + if (ToomossCanDrive.IsCycleSend == false) + { + if (CmdData.Count > 0) { - ConfigName = x.ConfigName, - MsgName = x.MsgName, - SignalName = x.SignalName, - SignalCmdValue = x.SignalCmdValue - }) - .ToList(); - } + ToomossCanDrive.IsCycleSend = true; + ToomossCanDrive.CmdData = CmdData; + ToomossCanDrive.StartPrecisionCycleSendMsg(); + } + else + { + System.Windows.MessageBox.Show("未发现配置的数据内容", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand); + } + } + else + { + ToomossCanDrive.StopCycleSendMsg(); + } - if (cmdDataSnapshot.Count == 0) - { - System.Windows.MessageBox.Show("未发现可发送的数据(请检查写入配置的【消息名称】/【信号名称】是否为空)", "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Hand); - return; } - - ToomossCanDrive.IsCycleSend = true; - //传入的是已经过滤的快照副本,避免与 UI 线程共享同一引用 - ToomossCanDrive.CmdData = cmdDataSnapshot; - ToomossCanDrive.StartPrecisionCycleSendMsg(); }