can信号监控曲线添加
This commit is contained in:
@@ -22,6 +22,7 @@ using UIShare.GlobalVariable;
|
|||||||
using UIShare.PubEvent;
|
using UIShare.PubEvent;
|
||||||
using UIShare.UIViewModel;
|
using UIShare.UIViewModel;
|
||||||
using UIShare.ViewModelBase;
|
using UIShare.ViewModelBase;
|
||||||
|
using ZLGUSBCANFD;
|
||||||
|
|
||||||
|
|
||||||
namespace MonitorModule.ViewModels
|
namespace MonitorModule.ViewModels
|
||||||
@@ -119,6 +120,8 @@ namespace MonitorModule.ViewModels
|
|||||||
|
|
||||||
/// <summary>事件订阅令牌,用于 Dispose 时取消订阅</summary>
|
/// <summary>事件订阅令牌,用于 Dispose 时取消订阅</summary>
|
||||||
private SubscriptionToken? _subscriptionToken;
|
private SubscriptionToken? _subscriptionToken;
|
||||||
|
private SubscriptionToken? _dbcLoadedToken;
|
||||||
|
private SubscriptionToken? _dbcUnloadedToken;
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// 批量入库核心结构
|
// 批量入库核心结构
|
||||||
@@ -166,6 +169,10 @@ namespace MonitorModule.ViewModels
|
|||||||
// 取消 EventAggregator 订阅
|
// 取消 EventAggregator 订阅
|
||||||
if (_subscriptionToken != null)
|
if (_subscriptionToken != null)
|
||||||
_eventAggregator.GetEvent<HardwareDataReportedEvent>().Unsubscribe(_subscriptionToken);
|
_eventAggregator.GetEvent<HardwareDataReportedEvent>().Unsubscribe(_subscriptionToken);
|
||||||
|
if (_dbcLoadedToken != null)
|
||||||
|
_eventAggregator.GetEvent<DBCLoadedEvent>().Unsubscribe(_dbcLoadedToken);
|
||||||
|
if (_dbcUnloadedToken != null)
|
||||||
|
_eventAggregator.GetEvent<DBCUnloadedEvent>().Unsubscribe(_dbcUnloadedToken);
|
||||||
|
|
||||||
if (_dbFlushTask != null)
|
if (_dbFlushTask != null)
|
||||||
{
|
{
|
||||||
@@ -332,6 +339,15 @@ namespace MonitorModule.ViewModels
|
|||||||
_subscriptionToken = _eventAggregator.GetEvent<HardwareDataReportedEvent>()
|
_subscriptionToken = _eventAggregator.GetEvent<HardwareDataReportedEvent>()
|
||||||
.Subscribe(OnHardwareDataReceived, ThreadOption.UIThread);
|
.Subscribe(OnHardwareDataReceived, ThreadOption.UIThread);
|
||||||
|
|
||||||
|
// 5b. 订阅 DBC 加载/卸载事件,动态发现或清除 CAN 信号
|
||||||
|
_dbcLoadedToken = _eventAggregator.GetEvent<DBCLoadedEvent>()
|
||||||
|
.Subscribe(OnDbcLoaded, ThreadOption.UIThread);
|
||||||
|
_dbcUnloadedToken = _eventAggregator.GetEvent<DBCUnloadedEvent>()
|
||||||
|
.Subscribe(OnDbcUnloaded, ThreadOption.UIThread);
|
||||||
|
|
||||||
|
// 5c. 根据 SystemConfig.ConfigurationList 刷新已加载 DBC 中的 CAN 信号
|
||||||
|
RefreshConfiguredCanSignals();
|
||||||
|
|
||||||
// 6. 启动 OxyPlot 视觉刷新定时器
|
// 6. 启动 OxyPlot 视觉刷新定时器
|
||||||
_stopwatch.Start();
|
_stopwatch.Start();
|
||||||
_plotRefreshTimer.Start();
|
_plotRefreshTimer.Start();
|
||||||
@@ -449,7 +465,6 @@ namespace MonitorModule.ViewModels
|
|||||||
private void RestoreChannelsFromConfig()
|
private void RestoreChannelsFromConfig()
|
||||||
{
|
{
|
||||||
if (_systemConfig?.MonitorChannels == null || _systemConfig.MonitorChannels.Count == 0) return;
|
if (_systemConfig?.MonitorChannels == null || _systemConfig.MonitorChannels.Count == 0) return;
|
||||||
if (AvailableMethods.Count == 0) return;
|
|
||||||
|
|
||||||
int restored = 0;
|
int restored = 0;
|
||||||
foreach (var config in _systemConfig.MonitorChannels)
|
foreach (var config in _systemConfig.MonitorChannels)
|
||||||
@@ -508,6 +523,188 @@ namespace MonitorModule.ViewModels
|
|||||||
StatusMessage = $"已从配置自动恢复 {restored} 个监测通道";
|
StatusMessage = $"已从配置自动恢复 {restored} 个监测通道";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据 SystemConfig.ConfigurationList 刷新所有已加载 DBC 中的 CAN 信号。
|
||||||
|
/// 只添加 ConfigurationList 中配置且实际存在于 DBC 的信号;不存在则清理。
|
||||||
|
/// </summary>
|
||||||
|
private void RefreshConfiguredCanSignals()
|
||||||
|
{
|
||||||
|
if (_systemConfig?.ConfigurationList == null || _systemConfig.ConfigurationList.Count == 0) return;
|
||||||
|
if (_deviceManager?.CANFD?.DBCParser?.MsgDatabase == null) return;
|
||||||
|
|
||||||
|
var msgDb = _deviceManager.CANFD.DBCParser.MsgDatabase;
|
||||||
|
foreach (var channel in _systemConfig.ConfigurationList.Select(c => c.Channel).Distinct())
|
||||||
|
{
|
||||||
|
if (channel < 0 || channel >= msgDb.Count) continue;
|
||||||
|
RefreshCanSignalsForChannel((uint)channel, msgDb[channel]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新单个通道的 CAN 信号:以 ConfigurationList 为白名单,对照 DBC 实际存在性。
|
||||||
|
/// - DBC 中存在 → 加入 AvailableMethods;若 MonitorChannels 中也有,则恢复 Channel。
|
||||||
|
/// - DBC 中不存在 → 从 AvailableMethods 移除;若已在 Channels 中,则删除。
|
||||||
|
/// </summary>
|
||||||
|
private void RefreshCanSignalsForChannel(uint channel, List<_Msg_> messages)
|
||||||
|
{
|
||||||
|
if (_systemConfig?.ConfigurationList == null) return;
|
||||||
|
|
||||||
|
string fingerprint = CANSignalBroadcaster.BuildFingerprint(channel);
|
||||||
|
var configs = _systemConfig.ConfigurationList.Where(c => c.Channel == (int)channel).ToList();
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
foreach (var cfg in configs)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(cfg.SignalName)) continue;
|
||||||
|
|
||||||
|
string methodName = CANSignalBroadcaster.BuildMethodName((uint)cfg.MessageID, cfg.SignalName);
|
||||||
|
bool existsInDbc = messages.Any(m =>
|
||||||
|
m.msg_id == cfg.MessageID &&
|
||||||
|
m.signal_Name != null &&
|
||||||
|
m.signal_Name.Contains(cfg.SignalName));
|
||||||
|
|
||||||
|
if (existsInDbc)
|
||||||
|
{
|
||||||
|
// 加入 AvailableMethods(去重)
|
||||||
|
if (!AvailableMethods.Any(m => m.Fingerprint == fingerprint && m.MethodName == methodName))
|
||||||
|
{
|
||||||
|
string displayName = CANSignalBroadcaster.BuildDisplayName(cfg.MessageName, cfg.SignalName);
|
||||||
|
AvailableMethods.Add(new AvailableMethodItem
|
||||||
|
{
|
||||||
|
DeviceName = $"CAN{channel}",
|
||||||
|
Fingerprint = fingerprint,
|
||||||
|
MethodName = methodName,
|
||||||
|
DisplayName = displayName,
|
||||||
|
MethodInfo = null!,
|
||||||
|
Device = null!
|
||||||
|
});
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 MonitorChannels 中有持久化记录,自动恢复 Channel
|
||||||
|
var monitorConfig = _systemConfig.MonitorChannels?.FirstOrDefault(m =>
|
||||||
|
m.Fingerprint == fingerprint && m.MethodName == methodName);
|
||||||
|
if (monitorConfig != null && !Channels.Any(c =>
|
||||||
|
c.Fingerprint == fingerprint && c.MethodName == methodName))
|
||||||
|
{
|
||||||
|
AddCanChannel(cfg, fingerprint, methodName, monitorConfig.IsDisplayed);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// DBC 中不存在:从 AvailableMethods 移除
|
||||||
|
var methodToRemove = AvailableMethods.FirstOrDefault(m =>
|
||||||
|
m.Fingerprint == fingerprint && m.MethodName == methodName);
|
||||||
|
if (methodToRemove != null)
|
||||||
|
{
|
||||||
|
AvailableMethods.Remove(methodToRemove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果该信号已经在 Channels(或 MonitorChannels)中,删除
|
||||||
|
var channelToRemove = Channels.FirstOrDefault(c =>
|
||||||
|
c.Fingerprint == fingerprint && c.MethodName == methodName);
|
||||||
|
if (channelToRemove != null)
|
||||||
|
{
|
||||||
|
if (channelToRemove.Series != null) Plot.Series.Remove(channelToRemove.Series);
|
||||||
|
Channels.Remove(channelToRemove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
Plot.InvalidatePlot(true);
|
||||||
|
StatusMessage = $"CAN{channel} 已刷新配置信号";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DBCLoadedEvent 回调:DBC 加载后刷新该通道的配置信号。
|
||||||
|
/// </summary>
|
||||||
|
private void OnDbcLoaded(DBCLoadedArgs args)
|
||||||
|
{
|
||||||
|
if (args.Scope != TestStatus) return;
|
||||||
|
if (_deviceManager?.CANFD?.DBCParser?.MsgDatabase == null) return;
|
||||||
|
|
||||||
|
int channel = (int)args.Channel;
|
||||||
|
var msgDb = _deviceManager.CANFD.DBCParser.MsgDatabase;
|
||||||
|
if (channel < 0 || channel >= msgDb.Count) return;
|
||||||
|
|
||||||
|
RefreshCanSignalsForChannel(args.Channel, msgDb[channel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DBCUnloadedEvent 回调:移除对应通道的 CAN 信号(AvailableMethods + Channels)。
|
||||||
|
/// </summary>
|
||||||
|
private void OnDbcUnloaded(DBCUnloadedArgs args)
|
||||||
|
{
|
||||||
|
if (args.Scope != TestStatus) return;
|
||||||
|
|
||||||
|
string fingerprint = CANSignalBroadcaster.BuildFingerprint(args.Channel);
|
||||||
|
|
||||||
|
// 从 AvailableMethods 中移除
|
||||||
|
var toRemoveMethods = AvailableMethods.Where(m => m.Fingerprint == fingerprint).ToList();
|
||||||
|
foreach (var m in toRemoveMethods)
|
||||||
|
AvailableMethods.Remove(m);
|
||||||
|
|
||||||
|
// 从 Channels 中移除(并清理 Plot)
|
||||||
|
var toRemoveChannels = Channels.Where(c => c.Fingerprint == fingerprint).ToList();
|
||||||
|
foreach (var c in toRemoveChannels)
|
||||||
|
{
|
||||||
|
if (c.Series != null) Plot.Series.Remove(c.Series);
|
||||||
|
Channels.Remove(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toRemoveMethods.Count > 0 || toRemoveChannels.Count > 0)
|
||||||
|
{
|
||||||
|
Plot.InvalidatePlot(true);
|
||||||
|
StatusMessage = $"CAN{args.Channel} DBC 已卸载,移除 {toRemoveMethods.Count} 个信号";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将单个 CAN 信号添加为监测通道。
|
||||||
|
/// </summary>
|
||||||
|
private void AddCanChannel(CANSignalConfig cfg, string fingerprint, string methodName, bool isDisplayed)
|
||||||
|
{
|
||||||
|
var color = _palette[_colorIndex % _palette.Length];
|
||||||
|
_colorIndex++;
|
||||||
|
|
||||||
|
string displayName = CANSignalBroadcaster.BuildDisplayName(cfg.MessageName, cfg.SignalName);
|
||||||
|
var channel = new MonitorChannelVM
|
||||||
|
{
|
||||||
|
DeviceName = $"CAN{cfg.Channel}",
|
||||||
|
Fingerprint = fingerprint,
|
||||||
|
MethodName = methodName,
|
||||||
|
DisplayName = displayName,
|
||||||
|
Color = color,
|
||||||
|
IsMonitored = true,
|
||||||
|
IsDisplayed = isDisplayed
|
||||||
|
};
|
||||||
|
|
||||||
|
if (channel.IsDisplayed)
|
||||||
|
{
|
||||||
|
channel.Series = new LineSeries
|
||||||
|
{
|
||||||
|
Title = channel.DisplayName,
|
||||||
|
Color = color,
|
||||||
|
StrokeThickness = 1.5
|
||||||
|
};
|
||||||
|
Plot.Series.Add(channel.Series);
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.PropertyChanged += (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(MonitorChannelVM.IsDisplayed))
|
||||||
|
OnChannelDisplayChanged(channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
Channels.Add(channel);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 命令处理
|
#region 命令处理
|
||||||
|
|||||||
114
UIShare/GlobalVariable/CANSignalBroadcaster.cs
Normal file
114
UIShare/GlobalVariable/CANSignalBroadcaster.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
using Model.Models;
|
||||||
|
using Prism.Events;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using UIShare.PubEvent;
|
||||||
|
using ZLGUSBCANFD;
|
||||||
|
|
||||||
|
namespace UIShare.GlobalVariable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CAN 信号广播器:订阅 ZLGCANFD.OnDbcMessageDecoded 事件,
|
||||||
|
/// 将解码后的 DBC 信号值通过 HardwareDataReportedEvent 广播给监控系统。
|
||||||
|
/// 由 DeviceManager 创建和管理,生命周期与 CAN 设备绑定。
|
||||||
|
/// </summary>
|
||||||
|
public class CANSignalBroadcaster : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly string _scopeName;
|
||||||
|
private ZLGCANFD? _canfd;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public CANSignalBroadcaster(IEventAggregator eventAggregator, string scopeName)
|
||||||
|
{
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
_scopeName = scopeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绑定 CANFD 实例并订阅解码事件。
|
||||||
|
/// </summary>
|
||||||
|
public void Bind(ZLGCANFD canfd)
|
||||||
|
{
|
||||||
|
Unbind();
|
||||||
|
_canfd = canfd;
|
||||||
|
_canfd.OnDbcMessageDecoded += OnDbcMessageDecoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 取消订阅。
|
||||||
|
/// </summary>
|
||||||
|
public void Unbind()
|
||||||
|
{
|
||||||
|
if (_canfd != null)
|
||||||
|
{
|
||||||
|
_canfd.OnDbcMessageDecoded -= OnDbcMessageDecoded;
|
||||||
|
_canfd = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DBC 解码回调:提取所有信号并广播。
|
||||||
|
/// </summary>
|
||||||
|
private void OnDbcMessageDecoded(uint channel, ZDBC.DBCMessage msg)
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
|
||||||
|
string fingerprint = $"CAN:{channel}";
|
||||||
|
var now = DateTime.Now;
|
||||||
|
|
||||||
|
for (int i = 0; i < msg.nSignalCount; i++)
|
||||||
|
{
|
||||||
|
var signal = msg.vSignals[i];
|
||||||
|
string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
|
||||||
|
if (string.IsNullOrEmpty(signalName)) continue;
|
||||||
|
|
||||||
|
// 计算物理值:physical = raw * factor + offset
|
||||||
|
double physicalValue = signal.nRawvalue * signal.nFactor + signal.nOffset;
|
||||||
|
|
||||||
|
// MethodName 格式:"{MessageId:X}.{SignalName}"
|
||||||
|
string methodName = $"{msg.nID:X}.{signalName}";
|
||||||
|
|
||||||
|
_eventAggregator.GetEvent<HardwareDataReportedEvent>().Publish(new HardwareReportArgs
|
||||||
|
{
|
||||||
|
Scope = _scopeName,
|
||||||
|
HardwareFingerprint = fingerprint,
|
||||||
|
MethodName = methodName,
|
||||||
|
Value = physicalValue,
|
||||||
|
Time = now
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成 CAN 信号的 DisplayName 格式:"{MessageName}.{SignalName}"
|
||||||
|
/// </summary>
|
||||||
|
public static string BuildDisplayName(string messageName, string signalName)
|
||||||
|
{
|
||||||
|
return $"{messageName}.{signalName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成 CAN 信号的 MethodName 格式:"{MessageId:X}.{SignalName}"
|
||||||
|
/// </summary>
|
||||||
|
public static string BuildMethodName(uint messageId, string signalName)
|
||||||
|
{
|
||||||
|
return $"{messageId:X}.{signalName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成 CAN 信号的 Fingerprint 格式:"CAN:{Channel}"
|
||||||
|
/// </summary>
|
||||||
|
public static string BuildFingerprint(uint channel)
|
||||||
|
{
|
||||||
|
return $"CAN:{channel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
Unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,9 @@ namespace UIShare.GlobalVariable
|
|||||||
private readonly string _scopeName;
|
private readonly string _scopeName;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
|
||||||
|
/// <summary>CAN 信号广播器:将 DBC 解码后的信号值广播给监控系统</summary>
|
||||||
|
private CANSignalBroadcaster? _canSignalBroadcaster;
|
||||||
|
|
||||||
/// <summary>按 DeviceName 索引的设备字典,便于业务层按名取实例。</summary>
|
/// <summary>按 DeviceName 索引的设备字典,便于业务层按名取实例。</summary>
|
||||||
public IDictionary<string, IBaseInterface> DeviceMap { get; private set; }
|
public IDictionary<string, IBaseInterface> DeviceMap { get; private set; }
|
||||||
= new Dictionary<string, IBaseInterface>(StringComparer.OrdinalIgnoreCase);
|
= new Dictionary<string, IBaseInterface>(StringComparer.OrdinalIgnoreCase);
|
||||||
@@ -412,7 +415,7 @@ namespace UIShare.GlobalVariable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 打开 CAN 卡:打开设备 + 初始化并启动所有通道 + 自动加载 DBC
|
/// 打开 CAN 卡:打开设备 + 初始化并启动所有通道 + 自动加载 DBC + 启动信号广播
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<bool> ConnectCanAsync(DeviceInfoVM info)
|
private async Task<bool> ConnectCanAsync(DeviceInfoVM info)
|
||||||
{
|
{
|
||||||
@@ -436,51 +439,49 @@ namespace UIShare.GlobalVariable
|
|||||||
bool ok = await Task.Run(() =>
|
bool ok = await Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (!CANFD.打开设备()) return false;
|
if (!CANFD.打开设备()) return false;
|
||||||
|
// 启动 CAN 信号广播器
|
||||||
// 初始化并启动所有通道
|
_canSignalBroadcaster = new CANSignalBroadcaster(_eventAggregator, _scopeName);
|
||||||
int maxCh = CANFD.DBCParser.MaxChannels;
|
_canSignalBroadcaster.Bind(CANFD);
|
||||||
for (uint i = 0; i < maxCh; i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
CANFD.初始化并启动通道(i);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LoggerHelper.Warn($"CAN 通道 {i} 初始化失败:{ex.Message}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自动加载 DBC 文件
|
// 自动加载 DBC 文件
|
||||||
if (_systemConfig?.DBCAutoLoadList != null)
|
if (_systemConfig?.DBCAutoLoadList != null)
|
||||||
{
|
{
|
||||||
foreach (var item in _systemConfig.DBCAutoLoadList)
|
foreach (var item in _systemConfig.DBCAutoLoadList)
|
||||||
{
|
{
|
||||||
if (item.DBCChannel < 0 || item.DBCChannel >= maxCh) continue;
|
if (item.DBCChannel < 0 || item.DBCChannel >= 4) continue;
|
||||||
if (string.IsNullOrWhiteSpace(item.DBCFilePath)) continue;
|
if (string.IsNullOrWhiteSpace(item.DBCFilePath)) continue;
|
||||||
|
|
||||||
if (!File.Exists(item.DBCFilePath))
|
if (!File.Exists(item.DBCFilePath))
|
||||||
{
|
{
|
||||||
// 文件不存在,发布事件广播
|
// 发布 DBC 卸载事件,通知监控系统清除对应信号
|
||||||
_eventAggregator.GetEvent<DBCFileNotFoundEvent>().Publish(new DBCFileNotFoundArgs
|
_eventAggregator.GetEvent<DBCUnloadedEvent>().Publish(new DBCUnloadedArgs
|
||||||
{
|
{
|
||||||
Channel = item.DBCChannel,
|
Channel = (uint)item.DBCChannel,
|
||||||
FilePath = item.DBCFilePath,
|
|
||||||
Scope = _scopeName
|
Scope = _scopeName
|
||||||
});
|
});
|
||||||
LoggerHelper.Warn($"CAN 通道 {item.DBCChannel} 自动加载 DBC 失败:文件不存在 [{item.DBCFilePath}]");
|
LoggerHelper.Warn($"CAN 通道 {item.DBCChannel} 自动加载 DBC 失败:文件不存在 [{item.DBCFilePath}]");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
CANFD.初始化并启动通道((uint)item.DBCChannel);
|
||||||
bool loadOk = CANFD.加载通道DBC文件((uint)item.DBCChannel, item.DBCFilePath);
|
bool loadOk = CANFD.加载通道DBC文件((uint)item.DBCChannel, item.DBCFilePath);
|
||||||
if (loadOk)
|
if (loadOk)
|
||||||
{
|
{
|
||||||
LoggerHelper.Info($"CAN 通道 {item.DBCChannel} 已自动加载 DBC:{item.DBCFilePath}");
|
LoggerHelper.Info($"CAN 通道 {item.DBCChannel} 已自动加载 DBC:{item.DBCFilePath}");
|
||||||
|
// 发布 DBC 加载完成事件,通知监控系统刷新信号列表
|
||||||
|
_eventAggregator.GetEvent<DBCLoadedEvent>().Publish(new DBCLoadedArgs
|
||||||
|
{
|
||||||
|
Channel = (uint)item.DBCChannel,
|
||||||
|
Scope = _scopeName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoggerHelper.Warn($"CAN 通道 {item.DBCChannel} 自动加载 DBC 失败:{item.DBCFilePath}");
|
LoggerHelper.Warn($"CAN 通道 {item.DBCChannel} 自动加载 DBC 失败:{item.DBCFilePath}");
|
||||||
|
_eventAggregator.GetEvent<DBCUnloadedEvent>().Publish(new DBCUnloadedArgs
|
||||||
|
{
|
||||||
|
Channel = (uint)item.DBCChannel,
|
||||||
|
Scope = _scopeName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,6 +528,10 @@ namespace UIShare.GlobalVariable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 先释放 CAN 信号广播器,取消事件订阅,防止关闭过程中仍触发回调
|
||||||
|
_canSignalBroadcaster?.Dispose();
|
||||||
|
_canSignalBroadcaster = null;
|
||||||
|
|
||||||
await Task.Run(() => CANFD.关闭CAN卡设备());
|
await Task.Run(() => CANFD.关闭CAN卡设备());
|
||||||
LoggerHelper.Info($"CAN 设备 [{name}] 已成功关闭连接。");
|
LoggerHelper.Info($"CAN 设备 [{name}] 已成功关闭连接。");
|
||||||
}
|
}
|
||||||
@@ -586,6 +591,10 @@ namespace UIShare.GlobalVariable
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
// 释放 CAN 信号广播器
|
||||||
|
_canSignalBroadcaster?.Dispose();
|
||||||
|
_canSignalBroadcaster = null;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_scopeName)) return;
|
if (string.IsNullOrEmpty(_scopeName)) return;
|
||||||
|
|
||||||
// 遍历当前作用域用到的所有指纹,逐一移除本作用域的引用
|
// 遍历当前作用域用到的所有指纹,逐一移除本作用域的引用
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace UIShare.PubEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// DBC 自动加载时找不到文件事件。
|
|
||||||
/// 参数:(通道号, 文件路径)
|
|
||||||
/// </summary>
|
|
||||||
public class DBCFileNotFoundEvent : PubSubEvent<DBCFileNotFoundArgs>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DBCFileNotFoundArgs
|
|
||||||
{
|
|
||||||
public int Channel { get; set; }
|
|
||||||
public string FilePath { get; set; } = string.Empty;
|
|
||||||
public string Scope { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
17
UIShare/PubEvent/DBCLoadedEvent.cs
Normal file
17
UIShare/PubEvent/DBCLoadedEvent.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace UIShare.PubEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DBC 加载完成事件:通知订阅者某个通道的 DBC 已加载,可以刷新信号列表。
|
||||||
|
/// </summary>
|
||||||
|
public class DBCLoadedEvent : PubSubEvent<DBCLoadedArgs>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DBCLoadedArgs
|
||||||
|
{
|
||||||
|
public uint Channel { get; set; }
|
||||||
|
public string Scope { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
18
UIShare/PubEvent/DBCUnloadedEvent.cs
Normal file
18
UIShare/PubEvent/DBCUnloadedEvent.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace UIShare.PubEvent
|
||||||
|
{
|
||||||
|
public class DBCUnloadedEvent : PubSubEvent<DBCUnloadedArgs>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DBCUnloadedArgs
|
||||||
|
{
|
||||||
|
public uint Channel { get; set; }
|
||||||
|
public string Scope { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace UIShare.UIViewModel
|
namespace UIShare.UIViewModel
|
||||||
{
|
{
|
||||||
public class DeviceInfoVM : BindableBase
|
public class DeviceInfoVM : BindableBase
|
||||||
@@ -32,7 +34,8 @@ namespace UIShare.UIViewModel
|
|||||||
set => SetProperty(ref _isEnabled, value);
|
set => SetProperty(ref _isEnabled, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _isConnected;
|
private bool _isConnected=false;
|
||||||
|
[JsonIgnore]
|
||||||
public bool IsConnected
|
public bool IsConnected
|
||||||
{
|
{
|
||||||
get => _isConnected;
|
get => _isConnected;
|
||||||
|
|||||||
Reference in New Issue
Block a user