From 46d086e74a0a4e88b2bb006901252ae8804a64bb Mon Sep 17 00:00:00 2001 From: Tyrone CT Date: Tue, 28 Oct 2025 23:09:10 +0800 Subject: [PATCH] =?UTF-8?q?LIN=E6=8A=A5=E6=96=87=E5=92=8C=E9=AB=98?= =?UTF-8?q?=E9=80=9F=E6=95=B0=E6=8D=AE=E6=9C=8D=E5=8A=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CapMachine.Wpf/LinDrive/ToomossLin.cs | 61 +++++++++++++++++++ .../Services/HighSpeedDataService.cs | 57 +++++++++++------ 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/CapMachine.Wpf/LinDrive/ToomossLin.cs b/CapMachine.Wpf/LinDrive/ToomossLin.cs index bb43f30..2877677 100644 --- a/CapMachine.Wpf/LinDrive/ToomossLin.cs +++ b/CapMachine.Wpf/LinDrive/ToomossLin.cs @@ -97,6 +97,15 @@ namespace CapMachine.Wpf.LinDrive private List RecvFrameCtxs = new List(); + // 接收缓冲池(重用,避免每轮分配) + private IntPtr RecvMsgBufferPtr = IntPtr.Zero; + private int RecvMsgBufferCapacity = 1024; + private readonly int LinMsgSize = Marshal.SizeOf(typeof(USB2LIN_EX.LIN_EX_MSG)); + // 控制台调试输出开关(默认关闭,防止日志风暴) + public bool EnableConsoleDebugLog { get; set; } = false; + // 保护接收缓冲的并发锁(接收读与关闭释放之间的互斥) + private readonly object RecvBufferSync = new object(); + /// /// 开始LDF文件写入 /// @@ -494,6 +503,48 @@ namespace CapMachine.Wpf.LinDrive } } + // 从适配器读取原始LIN报文,并写入高速记录服务 + lock (RecvBufferSync) + { + if (RecvMsgBufferPtr == IntPtr.Zero) + { + RecvMsgBufferPtr = Marshal.AllocHGlobal(LinMsgSize * RecvMsgBufferCapacity); + if (EnableConsoleDebugLog) LoggerService?.Info("申请 LIN RecvMsgBufferPtr"); + } + var msgPtRead = RecvMsgBufferPtr; + int linNum = LDFParser.LDF_GetRawMsg(LDFHandle, msgPtRead, RecvMsgBufferCapacity); + if (linNum > 0) + { + for (int i = 0; i < linNum; i++) + { + var msgPtr = (IntPtr)(msgPtRead + i * LinMsgSize); + var linMsg = (USB2LIN_EX.LIN_EX_MSG)Marshal.PtrToStructure(msgPtr, typeof(USB2LIN_EX.LIN_EX_MSG)); + // 仅使用有效数据长度 + int dataLen = linMsg.DataLen <= 0 ? 0 : Math.Min(linMsg.Data?.Length ?? 0, linMsg.DataLen); + string dataHex = dataLen > 0 ? BitConverter.ToString(linMsg.Data, 0, dataLen) : string.Empty; + if (EnableConsoleDebugLog) + { + Console.WriteLine($"LINMsg[{i}] PID=0x{linMsg.PID:X2} Type={linMsg.MsgType} CheckType={linMsg.CheckType} DataLen={linMsg.DataLen} Data={dataHex}"); + } + + // 推送到高速数据记录服务 + HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg() + { + Category = "LIN", + MsgInfo = "0x" + linMsg.PID.ToString("X2"), + MsgData = dataHex, + Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + }); + + } + } + else if (linNum < 0 && EnableConsoleDebugLog) + { + Console.WriteLine("Get LIN raw data error!"); + } + } + + IsReviceOk = true; } catch (Exception ex) @@ -1155,6 +1206,16 @@ namespace CapMachine.Wpf.LinDrive try { LDFParser.LDF_Release(LDFHandle); } catch { } LDFHandle = 0; } + // 释放接收缓冲区 + lock (RecvBufferSync) + { + if (RecvMsgBufferPtr != IntPtr.Zero) + { + try { Marshal.FreeHGlobal(RecvMsgBufferPtr); } + catch { } + finally { RecvMsgBufferPtr = IntPtr.Zero; } + } + } } catch { } USB_DEVICE.USB_CloseDevice(DevHandle); diff --git a/CapMachine.Wpf/Services/HighSpeedDataService.cs b/CapMachine.Wpf/Services/HighSpeedDataService.cs index bc82552..35bb6ac 100644 --- a/CapMachine.Wpf/Services/HighSpeedDataService.cs +++ b/CapMachine.Wpf/Services/HighSpeedDataService.cs @@ -1,4 +1,4 @@ -using CapMachine.Wpf.ChannelModel; +using CapMachine.Wpf.ChannelModel; using CapMachine.Wpf.Models; using CapMachine.Wpf.Models.HighSpeed; using CapMachine.Wpf.PrismEvent; @@ -37,8 +37,8 @@ namespace CapMachine.Wpf.Services ContainerProvider = containerProvider; CacheHighFragMsg = new List(); - //100ms 触发一次 - CycleTimer = new System.Timers.Timer(100); + //500ms 触发一次 + CycleTimer = new System.Timers.Timer(500); CycleTimer.Elapsed += CycleAction; CycleTimer.AutoReset = true; CycleTimer.Enabled = true; @@ -59,12 +59,26 @@ namespace CapMachine.Wpf.Services /// /// /// + // 保护 CurListMsg 的并发锁 + private readonly object _curListMsgLock = new object(); + + /// + /// 触发刷盘的记录条数阈值(可根据业务容量调整,默认1万条) + /// + public int FlushRecordThreshold { get; set; } = 10000; + private void CycleAction(object? sender, ElapsedEventArgs e) { if (IsEnable) { - //本体数据记录 - CycleChannelInfo.Writer.WriteAsync(CurListMsg); + // 将当前快照写入通道,避免共享同一 List 引用导致的并发访问问题 + List snapshot; + lock (_curListMsgLock) + { + snapshot = new List(CurListMsg); + } + // 非阻塞写入通道;若通道满则丢弃最老数据(由通道配置控制) + CycleChannelInfo.Writer.TryWrite(snapshot); } } @@ -73,19 +87,22 @@ namespace CapMachine.Wpf.Services /// public void AppendOrUpdateMsg(CommMsg commMsg) { - if (!CurListMsg.Exists(a => a.MsgInfo == commMsg.MsgInfo)) + lock (_curListMsgLock) { - //不存在则新增 - CurListMsg.Add(commMsg); - } - else - { - //存在则更新数据 - var Data = CurListMsg.Find(a => a.MsgInfo == commMsg.MsgInfo); - //Data!.MsgInfo = commMsg.MsgInfo; - //Data!.Category = commMsg.Category; - Data!.MsgData = commMsg.MsgData; - Data!.Time = commMsg.Time; + // 以 Category+MsgInfo 作为唯一键,避免不同总线类别之间发生键冲突 + int idx = CurListMsg.FindIndex(a => a.MsgInfo == commMsg.MsgInfo && a.Category == commMsg.Category); + if (idx < 0) + { + //不存在则新增 + CurListMsg.Add(commMsg); + } + else + { + //存在则更新数据 + var Data = CurListMsg[idx]; + Data.MsgData = commMsg.MsgData; + Data.Time = commMsg.Time; + } } } @@ -180,11 +197,11 @@ namespace CapMachine.Wpf.Services ////第一次计时 //stopwatch.Start(); //启动Stopwatch - //新增数据 + // 新增数据,按条数累积以控制刷盘频率 CacheHighFragMsg.AddRange(CycleChannelData); - MaxCacheCellCount++; + MaxCacheCellCount += CycleChannelData.Count; - if (MaxCacheCellCount >= 600) + if (MaxCacheCellCount >= FlushRecordThreshold) { //CSV文件保存 SaveToCsv(CacheHighFragMsg);