LIN 值更新和LIN接受优化数据
This commit is contained in:
@@ -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
|
||||
/// </summary>
|
||||
public string? SignalName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指令数据改变Handler
|
||||
/// 改变发送消息名称/帧名称
|
||||
/// </summary>
|
||||
public event EventHandler<string>? LinCmdDataChangedHandler;
|
||||
|
||||
private double _SignalCmdValue;
|
||||
/// <summary>
|
||||
/// 指令值
|
||||
/// 没有的话,则给默认值
|
||||
/// </summary>
|
||||
public double SignalCmdValue { get; set; }
|
||||
public double SignalCmdValue
|
||||
{
|
||||
get { return _SignalCmdValue; }
|
||||
set
|
||||
{
|
||||
if (_SignalCmdValue != value)
|
||||
{
|
||||
_SignalCmdValue = value;
|
||||
LinCmdDataChangedHandler?.Invoke(this, MsgName!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 逻辑规则Id
|
||||
|
||||
@@ -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);
|
||||
/// <summary>
|
||||
/// 信号实时值 StringBuilder
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,12 +77,33 @@ namespace CapMachine.Wpf.LinDrive
|
||||
/// </summary>
|
||||
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>
|
||||
/// 开始LDF文件写入
|
||||
/// </summary>
|
||||
public ObservableCollection<LinLdfModel> StartLdf(string LdfPath)
|
||||
{
|
||||
LDF_Parser(LdfPath);
|
||||
BuildRecvFrameCtxs();
|
||||
return ListLinLdfModel;
|
||||
}
|
||||
|
||||
@@ -186,6 +207,30 @@ namespace CapMachine.Wpf.LinDrive
|
||||
/// </summary>
|
||||
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>
|
||||
/// 当前激活调度表下,启用的帧/报文名称集合(来自 ListLINScheduleConfig 的 IsMsgActived)。
|
||||
/// 为空(null) 表示不过滤,使用所有 CmdData 中的帧;非空则仅对包含在集合内的帧做信号更新与下发。
|
||||
@@ -337,10 +382,49 @@ namespace CapMachine.Wpf.LinDrive
|
||||
}
|
||||
}
|
||||
|
||||
// 构建接收优化上下文,避免每次循环 GroupBy 与临时对象分配
|
||||
BuildRecvFrameCtxs();
|
||||
|
||||
//解析成功
|
||||
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>
|
||||
/// 发送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 调度器发送报文
|
||||
|
||||
/// <summary>
|
||||
/// 指令数据变化时,更新调度表的线程锁
|
||||
/// </summary>
|
||||
private readonly object SchUpdateLock = new object();
|
||||
|
||||
private bool _SchEnable;
|
||||
/// <summary>
|
||||
/// 调度表使能
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@@ -971,6 +1113,7 @@ namespace CapMachine.Wpf.LinDrive
|
||||
try
|
||||
{
|
||||
IsCycleSend = false;
|
||||
SchEnable = false;
|
||||
ActiveMsgNames = null; // 清空激活帧过滤集合
|
||||
if (LDFHandle != 0)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -167,13 +167,16 @@
|
||||
<!-- 子节点模板:文本显示 -->
|
||||
<HierarchicalDataTemplate.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<CheckBox
|
||||
Margin="0,0,6,0"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanEdit}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock FontSize="16" Foreground="DimGray" VerticalAlignment="Center">
|
||||
IsEnabled="{Binding CanEdit}" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Foreground="DimGray">
|
||||
<Run Text="{Binding MsgName}" />
|
||||
<Run Text=" (Index: " />
|
||||
<Run Text="{Binding MsgNameIndex}" />
|
||||
|
||||
Reference in New Issue
Block a user