LIN报文和高速数据服务功能
This commit is contained in:
@@ -97,6 +97,15 @@ namespace CapMachine.Wpf.LinDrive
|
|||||||
|
|
||||||
private List<FrameReadCtx> RecvFrameCtxs = new List<FrameReadCtx>();
|
private List<FrameReadCtx> RecvFrameCtxs = new List<FrameReadCtx>();
|
||||||
|
|
||||||
|
// 接收缓冲池(重用,避免每轮分配)
|
||||||
|
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();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始LDF文件写入
|
/// 开始LDF文件写入
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -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;
|
IsReviceOk = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -1155,6 +1206,16 @@ namespace CapMachine.Wpf.LinDrive
|
|||||||
try { LDFParser.LDF_Release(LDFHandle); } catch { }
|
try { LDFParser.LDF_Release(LDFHandle); } catch { }
|
||||||
LDFHandle = 0;
|
LDFHandle = 0;
|
||||||
}
|
}
|
||||||
|
// 释放接收缓冲区
|
||||||
|
lock (RecvBufferSync)
|
||||||
|
{
|
||||||
|
if (RecvMsgBufferPtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
try { Marshal.FreeHGlobal(RecvMsgBufferPtr); }
|
||||||
|
catch { }
|
||||||
|
finally { RecvMsgBufferPtr = IntPtr.Zero; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
USB_DEVICE.USB_CloseDevice(DevHandle);
|
USB_DEVICE.USB_CloseDevice(DevHandle);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using CapMachine.Wpf.ChannelModel;
|
using CapMachine.Wpf.ChannelModel;
|
||||||
using CapMachine.Wpf.Models;
|
using CapMachine.Wpf.Models;
|
||||||
using CapMachine.Wpf.Models.HighSpeed;
|
using CapMachine.Wpf.Models.HighSpeed;
|
||||||
using CapMachine.Wpf.PrismEvent;
|
using CapMachine.Wpf.PrismEvent;
|
||||||
@@ -37,8 +37,8 @@ namespace CapMachine.Wpf.Services
|
|||||||
ContainerProvider = containerProvider;
|
ContainerProvider = containerProvider;
|
||||||
CacheHighFragMsg = new List<CommMsg>();
|
CacheHighFragMsg = new List<CommMsg>();
|
||||||
|
|
||||||
//100ms 触发一次
|
//500ms 触发一次
|
||||||
CycleTimer = new System.Timers.Timer(100);
|
CycleTimer = new System.Timers.Timer(500);
|
||||||
CycleTimer.Elapsed += CycleAction;
|
CycleTimer.Elapsed += CycleAction;
|
||||||
CycleTimer.AutoReset = true;
|
CycleTimer.AutoReset = true;
|
||||||
CycleTimer.Enabled = true;
|
CycleTimer.Enabled = true;
|
||||||
@@ -59,12 +59,26 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
// 保护 CurListMsg 的并发锁
|
||||||
|
private readonly object _curListMsgLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 触发刷盘的记录条数阈值(可根据业务容量调整,默认1万条)
|
||||||
|
/// </summary>
|
||||||
|
public int FlushRecordThreshold { get; set; } = 10000;
|
||||||
|
|
||||||
private void CycleAction(object? sender, ElapsedEventArgs e)
|
private void CycleAction(object? sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
if (IsEnable)
|
if (IsEnable)
|
||||||
{
|
{
|
||||||
//本体数据记录
|
// 将当前快照写入通道,避免共享同一 List 引用导致的并发访问问题
|
||||||
CycleChannelInfo.Writer.WriteAsync(CurListMsg);
|
List<CommMsg> snapshot;
|
||||||
|
lock (_curListMsgLock)
|
||||||
|
{
|
||||||
|
snapshot = new List<CommMsg>(CurListMsg);
|
||||||
|
}
|
||||||
|
// 非阻塞写入通道;若通道满则丢弃最老数据(由通道配置控制)
|
||||||
|
CycleChannelInfo.Writer.TryWrite(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +87,11 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void AppendOrUpdateMsg(CommMsg commMsg)
|
public void AppendOrUpdateMsg(CommMsg commMsg)
|
||||||
{
|
{
|
||||||
if (!CurListMsg.Exists(a => a.MsgInfo == commMsg.MsgInfo))
|
lock (_curListMsgLock)
|
||||||
|
{
|
||||||
|
// 以 Category+MsgInfo 作为唯一键,避免不同总线类别之间发生键冲突
|
||||||
|
int idx = CurListMsg.FindIndex(a => a.MsgInfo == commMsg.MsgInfo && a.Category == commMsg.Category);
|
||||||
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
//不存在则新增
|
//不存在则新增
|
||||||
CurListMsg.Add(commMsg);
|
CurListMsg.Add(commMsg);
|
||||||
@@ -81,11 +99,10 @@ namespace CapMachine.Wpf.Services
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//存在则更新数据
|
//存在则更新数据
|
||||||
var Data = CurListMsg.Find(a => a.MsgInfo == commMsg.MsgInfo);
|
var Data = CurListMsg[idx];
|
||||||
//Data!.MsgInfo = commMsg.MsgInfo;
|
Data.MsgData = commMsg.MsgData;
|
||||||
//Data!.Category = commMsg.Category;
|
Data.Time = commMsg.Time;
|
||||||
Data!.MsgData = commMsg.MsgData;
|
}
|
||||||
Data!.Time = commMsg.Time;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,11 +197,11 @@ namespace CapMachine.Wpf.Services
|
|||||||
////第一次计时
|
////第一次计时
|
||||||
//stopwatch.Start(); //启动Stopwatch
|
//stopwatch.Start(); //启动Stopwatch
|
||||||
|
|
||||||
//新增数据
|
// 新增数据,按条数累积以控制刷盘频率
|
||||||
CacheHighFragMsg.AddRange(CycleChannelData);
|
CacheHighFragMsg.AddRange(CycleChannelData);
|
||||||
MaxCacheCellCount++;
|
MaxCacheCellCount += CycleChannelData.Count;
|
||||||
|
|
||||||
if (MaxCacheCellCount >= 600)
|
if (MaxCacheCellCount >= FlushRecordThreshold)
|
||||||
{
|
{
|
||||||
//CSV文件保存
|
//CSV文件保存
|
||||||
SaveToCsv(CacheHighFragMsg);
|
SaveToCsv(CacheHighFragMsg);
|
||||||
|
|||||||
Reference in New Issue
Block a user