LIN 值更新和LIN接受优化数据

This commit is contained in:
2025-10-15 11:13:37 +08:00
parent ad1d3e081f
commit fb4bc6d9d7
6 changed files with 227 additions and 45 deletions

View File

@@ -1,4 +1,4 @@
using CapMachine.Wpf.Dtos; using CapMachine.Wpf.Dtos;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -27,11 +27,29 @@ namespace CapMachine.Wpf.LinDrive
/// </summary> /// </summary>
public string? SignalName { get; set; } public string? SignalName { get; set; }
/// <summary>
/// 指令数据改变Handler
/// 改变发送消息名称/帧名称
/// </summary>
public event EventHandler<string>? LinCmdDataChangedHandler;
private double _SignalCmdValue;
/// <summary> /// <summary>
/// 指令值 /// 指令值
/// 没有的话,则给默认值 /// 没有的话,则给默认值
/// </summary> /// </summary>
public double SignalCmdValue { get; set; } public double SignalCmdValue
{
get { return _SignalCmdValue; }
set
{
if (_SignalCmdValue != value)
{
_SignalCmdValue = value;
LinCmdDataChangedHandler?.Invoke(this, MsgName!);
}
}
}
///// <summary> ///// <summary>
///// 逻辑规则Id ///// 逻辑规则Id

View File

@@ -1,4 +1,4 @@
using Prism.Mvvm; using Prism.Mvvm;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -62,7 +62,7 @@ namespace CapMachine.Wpf.LinDrive
} }
} }
private StringBuilder _SignalRtValueSb = new StringBuilder(10); private StringBuilder _SignalRtValueSb = new StringBuilder(16);
/// <summary> /// <summary>
/// 信号实时值 StringBuilder /// 信号实时值 StringBuilder
/// </summary> /// </summary>
@@ -71,12 +71,24 @@ namespace CapMachine.Wpf.LinDrive
get { return _SignalRtValueSb; } get { return _SignalRtValueSb; }
set set
{ {
//if (_SignalRtValueSb != value) if (value == null)
//{ {
SignalRtValue = value.ToString(); if (_SignalRtValue != string.Empty)
_SignalRtValueSb = value; {
//} _SignalRtValueSb.Clear();
SignalRtValue = string.Empty;
}
return;
}
// 复制内容到内部可变缓冲区,避免多个模型共享同一个 StringBuilder 实例
var str = value.ToString();
if (!string.Equals(_SignalRtValue, str, StringComparison.Ordinal))
{
_SignalRtValueSb.Clear();
_SignalRtValueSb.Append(str);
SignalRtValue = str;
}
} }
} }

View File

@@ -77,12 +77,33 @@ namespace CapMachine.Wpf.LinDrive
/// </summary> /// </summary>
public HighSpeedDataService HighSpeedDataService { get; set; } public HighSpeedDataService HighSpeedDataService { get; set; }
/// <summary>
/// 接收优化上下文:缓存帧与信号的 StringBuilder避免循环中重复分配
/// </summary>
private class SignalReadCtx
{
public string SignalName { get; set; }
public StringBuilder SignalNameSB { get; set; }
public LinLdfModel ModelRef { get; set; }
}
private class FrameReadCtx
{
public string MsgName { get; set; }
public StringBuilder MsgNameSB { get; set; }
public bool IsMasterFrame { get; set; }
public List<SignalReadCtx> Signals { get; set; } = new List<SignalReadCtx>();
}
private List<FrameReadCtx> RecvFrameCtxs = new List<FrameReadCtx>();
/// <summary> /// <summary>
/// 开始LDF文件写入 /// 开始LDF文件写入
/// </summary> /// </summary>
public ObservableCollection<LinLdfModel> StartLdf(string LdfPath) public ObservableCollection<LinLdfModel> StartLdf(string LdfPath)
{ {
LDF_Parser(LdfPath); LDF_Parser(LdfPath);
BuildRecvFrameCtxs();
return ListLinLdfModel; return ListLinLdfModel;
} }
@@ -186,6 +207,30 @@ namespace CapMachine.Wpf.LinDrive
/// </summary> /// </summary>
public List<LinCmdData> CmdData { get; set; } = new List<LinCmdData>(); public List<LinCmdData> CmdData { get; set; } = new List<LinCmdData>();
/// <summary>
/// 加载要发送的数据(订阅数据变化事件)
/// 一般是激活后才注册事件
/// </summary>
/// <param name="cmdData"></param>
public void LoadCmdDataToDrive(List<LinCmdData> cmdData)
{
// 取消订阅旧数据源事件
if (CmdData != null && CmdData.Count > 0)
{
foreach (var cmd in CmdData)
{
cmd.LinCmdDataChangedHandler -= CmdData_LinCmdDataChangedHandler;
}
}
// 设置新数据源并订阅事件
CmdData = cmdData ?? new List<LinCmdData>();
foreach (var cmd in CmdData)
{
cmd.LinCmdDataChangedHandler += CmdData_LinCmdDataChangedHandler;
}
}
/// <summary> /// <summary>
/// 当前激活调度表下,启用的帧/报文名称集合(来自 ListLINScheduleConfig 的 IsMsgActived /// 当前激活调度表下,启用的帧/报文名称集合(来自 ListLINScheduleConfig 的 IsMsgActived
/// 为空(null) 表示不过滤,使用所有 CmdData 中的帧;非空则仅对包含在集合内的帧做信号更新与下发。 /// 为空(null) 表示不过滤,使用所有 CmdData 中的帧;非空则仅对包含在集合内的帧做信号更新与下发。
@@ -337,10 +382,49 @@ namespace CapMachine.Wpf.LinDrive
} }
} }
// 构建接收优化上下文,避免每次循环 GroupBy 与临时对象分配
BuildRecvFrameCtxs();
//解析成功 //解析成功
LdfParserState = true; LdfParserState = true;
} }
/// <summary>
/// 构建接收优化上下文
/// </summary>
private void BuildRecvFrameCtxs()
{
if (ListLinLdfModel == null || ListLinLdfModel.Count == 0)
{
RecvFrameCtxs = new List<FrameReadCtx>();
return;
}
var grouped = ListLinLdfModel.GroupBy(x => x.MsgName);
var list = new List<FrameReadCtx>();
foreach (var g in grouped)
{
var first = g.First();
var frame = new FrameReadCtx
{
MsgName = g.Key,
MsgNameSB = new StringBuilder(g.Key),
IsMasterFrame = (first.IsMasterFrame != null && first.IsMasterFrame.Contains("是"))
};
foreach (var model in g)
{
frame.Signals.Add(new SignalReadCtx
{
SignalName = model.SignalName,
SignalNameSB = new StringBuilder(model.SignalName),
ModelRef = model
});
}
list.Add(frame);
}
RecvFrameCtxs = list;
}
/// <summary> /// <summary>
/// 发送LIN数据 /// 发送LIN数据
@@ -388,32 +472,26 @@ namespace CapMachine.Wpf.LinDrive
await Task.Delay(ReviceCycle); await Task.Delay(ReviceCycle);
try try
{ {
var GroupMsg = ListLinLdfModel.GroupBy(x => x.MsgName); var frames = RecvFrameCtxs;
foreach (var itemMsg in GroupMsg) if (frames == null || frames.Count == 0)
{ {
var data = itemMsg.FirstOrDefault(); IsReviceOk = true;
//非主机发送的指令帧就可以读取数据,因为函数 LDF_ExeFrameToBus【执行帧到总线若该帧的发布者是主机那么就是主机写数据否则就是主机读数据】 continue;
//那么主机发送和读取都是同一个函数。会导致跟Master主机也会在这里执行写入导致冲突出现错误。所以做一个排出 }
if (data != null && !data.IsMasterFrame!.Contains("是"))
{
//主机读操作,读取从机返回的数据值
LDFParser.LDF_ExeFrameToBus(LDFHandle, new StringBuilder(itemMsg.Key), 1);
foreach (var itemSignal in itemMsg)
{
//LDFParser.LDF_ExeFrameToBus(LDFHandle, new StringBuilder(itemMsg.Key), 1);
LDFParser.LDF_GetSignalValueStr(LDFHandle, new StringBuilder(itemMsg.Key), new StringBuilder(itemSignal.SignalName), ReadValueStr);
itemSignal.SignalRtValueSb = ReadValueStr;
}
//报文给高速记录的服务
//HighSpeedDataService.AppendOrUpdateMsg(new Models.HighSpeed.CommMsg()
//{
// Category = "LIN",
// MsgInfo = "0x" + CanMsgBuffer[i].ID.ToString("X8"),
// MsgData = BitConverter.ToString(CanMsgBuffer[i].Data),
// Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
//});
}
foreach (var frame in frames)
{
// 仅对从机发布的帧执行读取
if (frame.IsMasterFrame)
continue;
// 主机读操作,读取从机返回的数据值
LDFParser.LDF_ExeFrameToBus(LDFHandle, frame.MsgNameSB, 1);
foreach (var sig in frame.Signals)
{
LDFParser.LDF_GetSignalValueStr(LDFHandle, frame.MsgNameSB, sig.SignalNameSB, ReadValueStr);
sig.ModelRef.SignalRtValueSb = ReadValueStr;
}
} }
IsReviceOk = true; IsReviceOk = true;
@@ -697,6 +775,11 @@ namespace CapMachine.Wpf.LinDrive
#region #region
/// <summary>
/// 指令数据变化时,更新调度表的线程锁
/// </summary>
private readonly object SchUpdateLock = new object();
private bool _SchEnable; private bool _SchEnable;
/// <summary> /// <summary>
/// 调度表使能 /// 调度表使能
@@ -881,12 +964,10 @@ namespace CapMachine.Wpf.LinDrive
LoggerService?.Info($"调度表[{ActiveSchName}]已启动(自动执行)"); LoggerService?.Info($"调度表[{ActiveSchName}]已启动(自动执行)");
} }
// 4) 置位调度更新开关,启动参数更新任务 // 4) 置位调度更新开关(事件驱动刷新,不再自动启动周期刷新任务
//SchEnable = true; //SchEnable = true;
if (CycleUpdateCmdTask == null || CycleUpdateCmdTask.IsCompleted) // 不再自动启动周期更新任务,改为数据变化事件驱动刷新
{ // if (CycleUpdateCmdTask == null || CycleUpdateCmdTask.IsCompleted) { StartCycleUpdateCmd(); }
StartCycleUpdateCmd();
}
} }
@@ -963,6 +1044,67 @@ namespace CapMachine.Wpf.LinDrive
}); });
} }
/// <summary>
/// 指令数据发生变化事件回调
/// </summary>
/// <param name="sender"></param>
/// <param name="e">消息/帧名称</param>
private void CmdData_LinCmdDataChangedHandler(object? sender, string e)
{
UpdateSchDataByCmdDataChanged(e);
}
/// <summary>
/// 指令数据变化时,按消息名增量刷新调度表数据
/// </summary>
/// <param name="changedMsgName">发生变化的帧名称</param>
private void UpdateSchDataByCmdDataChanged(string changedMsgName)
{
try
{
// 与CAN保持一致仅在循环发送开启且调度表使能时才更新
if (!IsCycleSend) return;
if (!SchEnable) return;
// 基础防御
if (LDFHandle == 0) return;
if (string.IsNullOrEmpty(ActiveSchName)) return;
if (string.IsNullOrEmpty(changedMsgName)) return;
// 若配置了激活帧过滤,则不在集合内的帧不更新
if (ActiveMsgNames != null && ActiveMsgNames.Count > 0 && !ActiveMsgNames.Contains(changedMsgName))
return;
lock (SchUpdateLock)
{
// 仅更新对应消息/帧的信号值
var relatedCmds = CmdData.Where(x => string.Equals(x.MsgName, changedMsgName, StringComparison.Ordinal));
foreach (var cmd in relatedCmds)
{
LDFParser.LDF_SetSignalValue(LDFHandle, new StringBuilder(changedMsgName), new StringBuilder(cmd.SignalName), cmd.SignalCmdValue);
}
// 将更新后的信号值推送到适配器当前运行的调度表(离线表刷新)
var retPush = LDFParser.LDF_SetSchToTable(LDFHandle, new StringBuilder(ActiveSchName), 0);
if (retPush < 0)
{
IsSendOk = false;
LoggerService?.Info($"刷新调度表[{ActiveSchName}]失败, 返回:{retPush}");
}
else
{
IsSendOk = true;
//Console.WriteLine($"Update LIN Schedule Success -- Sch:[{ActiveSchName}] Msg:[{changedMsgName}]");
}
}
}
catch (Exception ex)
{
IsSendOk = false;
LoggerService?.Info($"时间:{DateTime.Now.ToString()}-【LIN_SCH】-{ex.Message}");
}
}
/// <summary> /// <summary>
/// 停止调度表自动执行 /// 停止调度表自动执行
/// </summary> /// </summary>
@@ -971,6 +1113,7 @@ namespace CapMachine.Wpf.LinDrive
try try
{ {
IsCycleSend = false; IsCycleSend = false;
SchEnable = false;
ActiveMsgNames = null; // 清空激活帧过滤集合 ActiveMsgNames = null; // 清空激活帧过滤集合
if (LDFHandle != 0) if (LDFHandle != 0)
{ {

View File

@@ -1,4 +1,4 @@
using CapMachine.Model.CANLIN; using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos; using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.LinDrive; using CapMachine.Wpf.LinDrive;
using ImTools; using ImTools;
@@ -363,8 +363,12 @@ namespace CapMachine.Wpf.Services
{ {
if (CmdData.Count > 0) if (CmdData.Count > 0)
{ {
//ToomossLinDrive.IsCycleSend = true; ////订阅 CmdData 的数据变化事件,确保基于数据变化刷新调度表
//ToomossLinDrive.LoadCmdDataToDrive(CmdData);
ToomossLinDrive.CmdData = CmdData; ToomossLinDrive.CmdData = CmdData;
//ToomossLinDrive.IsCycleSend = true;
//ToomossLinDrive.StartPrecisionCycleSendMsg(); //ToomossLinDrive.StartPrecisionCycleSendMsg();
//ToomossLinDrive.StartCycleSendMsg(); //ToomossLinDrive.StartCycleSendMsg();

View File

@@ -1,4 +1,4 @@
using AutoMapper; using AutoMapper;
using CapMachine.Core; using CapMachine.Core;
using CapMachine.Model.CANLIN; using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive; using CapMachine.Wpf.CanDrive;
@@ -486,6 +486,8 @@ namespace CapMachine.Wpf.ViewModels
LinDriveService.InitLinConfig(SelectCanLinConfigPro); LinDriveService.InitLinConfig(SelectCanLinConfigPro);
InitLoadLinConfigPro(); InitLoadLinConfigPro();
// 订阅 CmdData 的数据变化事件,用于基于数据变化刷新调度表
LinDriveService.ToomossLinDrive.LoadCmdDataToDrive(LinDriveService.CmdData);
} }
else else
{ {

View File

@@ -167,13 +167,16 @@
<!-- 子节点模板:文本显示 --> <!-- 子节点模板:文本显示 -->
<HierarchicalDataTemplate.ItemTemplate> <HierarchicalDataTemplate.ItemTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"> <StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<CheckBox <CheckBox
Margin="0,0,6,0" Margin="0,0,6,0"
VerticalAlignment="Center"
IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding CanEdit}" IsEnabled="{Binding CanEdit}" />
VerticalAlignment="Center" /> <TextBlock
<TextBlock FontSize="16" Foreground="DimGray" VerticalAlignment="Center"> VerticalAlignment="Center"
FontSize="16"
Foreground="DimGray">
<Run Text="{Binding MsgName}" /> <Run Text="{Binding MsgName}" />
<Run Text=" (Index: " /> <Run Text=" (Index: " />
<Run Text="{Binding MsgNameIndex}" /> <Run Text="{Binding MsgNameIndex}" />