diff --git a/CapMachine.Wpf/LinDrive/LinCmdData.cs b/CapMachine.Wpf/LinDrive/LinCmdData.cs
index 9b89c56..cd67e86 100644
--- a/CapMachine.Wpf/LinDrive/LinCmdData.cs
+++ b/CapMachine.Wpf/LinDrive/LinCmdData.cs
@@ -1,4 +1,4 @@
-using CapMachine.Wpf.Dtos;
+using CapMachine.Wpf.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -27,11 +27,29 @@ namespace CapMachine.Wpf.LinDrive
///
public string? SignalName { get; set; }
+ ///
+ /// 指令数据改变Handler
+ /// 改变发送消息名称/帧名称
+ ///
+ public event EventHandler? LinCmdDataChangedHandler;
+
+ private double _SignalCmdValue;
///
/// 指令值
/// 没有的话,则给默认值
///
- public double SignalCmdValue { get; set; }
+ public double SignalCmdValue
+ {
+ get { return _SignalCmdValue; }
+ set
+ {
+ if (_SignalCmdValue != value)
+ {
+ _SignalCmdValue = value;
+ LinCmdDataChangedHandler?.Invoke(this, MsgName!);
+ }
+ }
+ }
/////
///// 逻辑规则Id
diff --git a/CapMachine.Wpf/LinDrive/LinLdfModel.cs b/CapMachine.Wpf/LinDrive/LinLdfModel.cs
index 9ec3e57..7b10672 100644
--- a/CapMachine.Wpf/LinDrive/LinLdfModel.cs
+++ b/CapMachine.Wpf/LinDrive/LinLdfModel.cs
@@ -1,4 +1,4 @@
-using Prism.Mvvm;
+using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -62,7 +62,7 @@ namespace CapMachine.Wpf.LinDrive
}
}
- private StringBuilder _SignalRtValueSb = new StringBuilder(10);
+ private StringBuilder _SignalRtValueSb = new StringBuilder(16);
///
/// 信号实时值 StringBuilder
///
@@ -71,12 +71,24 @@ namespace CapMachine.Wpf.LinDrive
get { return _SignalRtValueSb; }
set
{
- //if (_SignalRtValueSb != value)
- //{
- SignalRtValue = value.ToString();
- _SignalRtValueSb = value;
- //}
+ if (value == null)
+ {
+ if (_SignalRtValue != string.Empty)
+ {
+ _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;
+ }
}
}
diff --git a/CapMachine.Wpf/LinDrive/ToomossLin.cs b/CapMachine.Wpf/LinDrive/ToomossLin.cs
index 6c8841c..0308339 100644
--- a/CapMachine.Wpf/LinDrive/ToomossLin.cs
+++ b/CapMachine.Wpf/LinDrive/ToomossLin.cs
@@ -77,12 +77,33 @@ namespace CapMachine.Wpf.LinDrive
///
public HighSpeedDataService HighSpeedDataService { get; set; }
+ ///
+ /// 接收优化上下文:缓存帧与信号的 StringBuilder,避免循环中重复分配
+ ///
+ 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 Signals { get; set; } = new List();
+ }
+
+ private List RecvFrameCtxs = new List();
+
///
/// 开始LDF文件写入
///
public ObservableCollection StartLdf(string LdfPath)
{
LDF_Parser(LdfPath);
+ BuildRecvFrameCtxs();
return ListLinLdfModel;
}
@@ -186,6 +207,30 @@ namespace CapMachine.Wpf.LinDrive
///
public List CmdData { get; set; } = new List();
+ ///
+ /// 加载要发送的数据(订阅数据变化事件)
+ /// 一般是激活后才注册事件
+ ///
+ ///
+ public void LoadCmdDataToDrive(List cmdData)
+ {
+ // 取消订阅旧数据源事件
+ if (CmdData != null && CmdData.Count > 0)
+ {
+ foreach (var cmd in CmdData)
+ {
+ cmd.LinCmdDataChangedHandler -= CmdData_LinCmdDataChangedHandler;
+ }
+ }
+
+ // 设置新数据源并订阅事件
+ CmdData = cmdData ?? new List();
+ foreach (var cmd in CmdData)
+ {
+ cmd.LinCmdDataChangedHandler += CmdData_LinCmdDataChangedHandler;
+ }
+ }
+
///
/// 当前激活调度表下,启用的帧/报文名称集合(来自 ListLINScheduleConfig 的 IsMsgActived)。
/// 为空(null) 表示不过滤,使用所有 CmdData 中的帧;非空则仅对包含在集合内的帧做信号更新与下发。
@@ -337,10 +382,49 @@ namespace CapMachine.Wpf.LinDrive
}
}
+ // 构建接收优化上下文,避免每次循环 GroupBy 与临时对象分配
+ BuildRecvFrameCtxs();
+
//解析成功
LdfParserState = true;
}
+ ///
+ /// 构建接收优化上下文
+ ///
+ private void BuildRecvFrameCtxs()
+ {
+ if (ListLinLdfModel == null || ListLinLdfModel.Count == 0)
+ {
+ RecvFrameCtxs = new List();
+ return;
+ }
+
+ var grouped = ListLinLdfModel.GroupBy(x => x.MsgName);
+ var list = new List();
+ 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;
+ }
+
///
/// 发送LIN数据
@@ -388,32 +472,26 @@ namespace CapMachine.Wpf.LinDrive
await Task.Delay(ReviceCycle);
try
{
- var GroupMsg = ListLinLdfModel.GroupBy(x => x.MsgName);
- foreach (var itemMsg in GroupMsg)
+ var frames = RecvFrameCtxs;
+ if (frames == null || frames.Count == 0)
{
- var data = itemMsg.FirstOrDefault();
- //非主机发送的指令帧就可以读取数据,因为函数 LDF_ExeFrameToBus【执行帧到总线,若该帧的发布者是主机,那么就是主机写数据,否则就是主机读数据】
- //那么主机发送和读取都是同一个函数。会导致跟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")
- //});
- }
+ IsReviceOk = true;
+ continue;
+ }
+ 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;
@@ -697,6 +775,11 @@ namespace CapMachine.Wpf.LinDrive
#region 调度器发送报文
+ ///
+ /// 指令数据变化时,更新调度表的线程锁
+ ///
+ private readonly object SchUpdateLock = new object();
+
private bool _SchEnable;
///
/// 调度表使能
@@ -881,12 +964,10 @@ namespace CapMachine.Wpf.LinDrive
LoggerService?.Info($"调度表[{ActiveSchName}]已启动(自动执行)");
}
- // 4) 置位调度更新开关,启动参数更新任务
+ // 4) 置位调度更新开关(事件驱动刷新,不再自动启动周期刷新任务)
//SchEnable = true;
- if (CycleUpdateCmdTask == null || CycleUpdateCmdTask.IsCompleted)
- {
- StartCycleUpdateCmd();
- }
+ // 不再自动启动周期更新任务,改为数据变化事件驱动刷新
+ // if (CycleUpdateCmdTask == null || CycleUpdateCmdTask.IsCompleted) { StartCycleUpdateCmd(); }
}
@@ -963,6 +1044,67 @@ namespace CapMachine.Wpf.LinDrive
});
}
+ ///
+ /// 指令数据发生变化事件回调
+ ///
+ ///
+ /// 消息/帧名称
+ private void CmdData_LinCmdDataChangedHandler(object? sender, string e)
+ {
+ UpdateSchDataByCmdDataChanged(e);
+ }
+
+ ///
+ /// 指令数据变化时,按消息名增量刷新调度表数据
+ ///
+ /// 发生变化的帧名称
+ 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}");
+ }
+ }
+
///
/// 停止调度表自动执行
///
@@ -971,6 +1113,7 @@ namespace CapMachine.Wpf.LinDrive
try
{
IsCycleSend = false;
+ SchEnable = false;
ActiveMsgNames = null; // 清空激活帧过滤集合
if (LDFHandle != 0)
{
diff --git a/CapMachine.Wpf/Services/LinDriveService.cs b/CapMachine.Wpf/Services/LinDriveService.cs
index b61cfab..98ecb76 100644
--- a/CapMachine.Wpf/Services/LinDriveService.cs
+++ b/CapMachine.Wpf/Services/LinDriveService.cs
@@ -1,4 +1,4 @@
-using CapMachine.Model.CANLIN;
+using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.LinDrive;
using ImTools;
@@ -363,8 +363,12 @@ namespace CapMachine.Wpf.Services
{
if (CmdData.Count > 0)
{
- //ToomossLinDrive.IsCycleSend = true;
+ ////订阅 CmdData 的数据变化事件,确保基于数据变化刷新调度表
+ //ToomossLinDrive.LoadCmdDataToDrive(CmdData);
+
ToomossLinDrive.CmdData = CmdData;
+
+ //ToomossLinDrive.IsCycleSend = true;
//ToomossLinDrive.StartPrecisionCycleSendMsg();
//ToomossLinDrive.StartCycleSendMsg();
diff --git a/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs b/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs
index e01d0dd..1f4bb60 100644
--- a/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs
+++ b/CapMachine.Wpf/ViewModels/LinConfigViewModel.cs
@@ -1,4 +1,4 @@
-using AutoMapper;
+using AutoMapper;
using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
@@ -486,6 +486,8 @@ namespace CapMachine.Wpf.ViewModels
LinDriveService.InitLinConfig(SelectCanLinConfigPro);
InitLoadLinConfigPro();
+ // 订阅 CmdData 的数据变化事件,用于基于数据变化刷新调度表
+ LinDriveService.ToomossLinDrive.LoadCmdDataToDrive(LinDriveService.CmdData);
}
else
{
diff --git a/CapMachine.Wpf/Views/DialogLINSchConfigView.xaml b/CapMachine.Wpf/Views/DialogLINSchConfigView.xaml
index 5cade3f..fe4efd7 100644
--- a/CapMachine.Wpf/Views/DialogLINSchConfigView.xaml
+++ b/CapMachine.Wpf/Views/DialogLINSchConfigView.xaml
@@ -167,13 +167,16 @@
-
+
-
+ IsEnabled="{Binding CanEdit}" />
+