LIN 值更新和LIN接受优化数据
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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}" />
|
||||||
|
|||||||
Reference in New Issue
Block a user