157 lines
5.8 KiB
C#
157 lines
5.8 KiB
C#
using Model.Models;
|
||
using Prism.Events;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using TSMasterCAN;
|
||
using UIShare.PubEvent;
|
||
|
||
namespace UIShare.GlobalVariable
|
||
{
|
||
/// <summary>
|
||
/// CAN 信号广播器(全局单例):
|
||
/// 统一订阅 GlobalInfo.CanPool 中所有已实例化的 ZLGCANFD 设备,
|
||
/// 将 DBC 解码后的信号值广播给所有引用该 CAN 设备的作用域,
|
||
/// 并同步检查各作用域 ValueLimitList 的超限报警。
|
||
/// </summary>
|
||
public class CANSignalBroadcaster : IDisposable
|
||
{
|
||
private readonly IEventAggregator _eventAggregator;
|
||
private readonly GlobalInfo _globalInfo;
|
||
private bool _disposed;
|
||
|
||
/// <summary>已订阅解码事件的 CANFD 实例 → 委托 映射</summary>
|
||
private readonly Dictionary<CAN, Action<uint, DBCMessage>> _handlers = new();
|
||
public CANSignalBroadcaster(GlobalInfo globalInfo, IEventAggregator eventAggregator)
|
||
{
|
||
_globalInfo = globalInfo;
|
||
_eventAggregator = eventAggregator;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扫描 GlobalInfo.CanPool 中已创建的 CANFD 实例并订阅解码事件。
|
||
/// 幂等:已订阅的实例不会重复订阅。
|
||
/// </summary>
|
||
public void Discover()
|
||
{
|
||
if (_disposed) return;
|
||
|
||
foreach (var kvp in _globalInfo.CanPool)
|
||
{
|
||
string fingerprint = kvp.Key;
|
||
var lazy = kvp.Value;
|
||
if (!lazy.IsValueCreated || lazy.Value == null) continue;
|
||
|
||
var canfd = lazy.Value;
|
||
if (_handlers.ContainsKey(canfd)) continue;
|
||
|
||
// 使用闭包捕获指纹,回调时即可区分不同 CAN 卡
|
||
Action<uint, DBCMessage> handler = (channel, msg) => OnDbcMessageDecoded(fingerprint, channel, msg);
|
||
canfd.OnDbcMessageDecoded += handler;
|
||
_handlers[canfd] = handler;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动广播器(目前 Discover 已完成订阅,此处保留以兼容 HardwareDataBroadcaster 的使用模式)。
|
||
/// </summary>
|
||
public void Start()
|
||
{
|
||
Discover();
|
||
}
|
||
|
||
/// <summary>
|
||
/// DBC 解码回调:提取所有信号,向引用该 CAN 设备的作用域广播,并检查报警。
|
||
/// </summary>
|
||
private void OnDbcMessageDecoded(string canFingerprint, uint channel, DBCMessage msg)
|
||
{
|
||
if (_disposed) return;
|
||
|
||
string signalFingerprint = BuildFingerprint(canFingerprint, channel);
|
||
var now = DateTime.Now;
|
||
|
||
// 获取引用该 CAN 设备的所有作用域
|
||
var scopes = GetScopesForFingerprint(canFingerprint);
|
||
if (scopes.Count == 0) return;
|
||
|
||
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;
|
||
|
||
double physicalValue = signal.nRawvalue * signal.nFactor + signal.nOffset;
|
||
string methodName = BuildMethodName(msg.nID, signalName);
|
||
|
||
foreach (var scope in scopes)
|
||
{
|
||
_eventAggregator.GetEvent<HardwareDataReportedEvent>().Publish(new HardwareReportArgs
|
||
{
|
||
Scope = scope,
|
||
HardwareFingerprint = signalFingerprint,
|
||
MethodName = methodName,
|
||
Value = physicalValue,
|
||
Time = now
|
||
});
|
||
|
||
string MonitorStatus = ValueLimitAlarmHelper.CheckAlarm(scope, signalFingerprint, methodName, physicalValue, _globalInfo);
|
||
if (MonitorStatus != "" && MonitorStatus != "未报警")
|
||
{
|
||
_eventAggregator.GetEvent<AlarmEvent>().Publish((scope,canFingerprint, MonitorStatus));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>获取指定硬件指纹当前被哪些作用域引用</summary>
|
||
private List<string> GetScopesForFingerprint(string fingerprint)
|
||
{
|
||
if (_globalInfo.DeviceAndScopeDic.TryGetValue(fingerprint, out var lazy))
|
||
{
|
||
var scopeList = lazy.Value;
|
||
lock (scopeList) return scopeList.ToList();
|
||
}
|
||
return new List<string>();
|
||
}
|
||
|
||
/// <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 格式:"{canDeviceFingerprint}:{channel}"
|
||
/// canDeviceFingerprint 来自 DeviceManager.ExtractHardwareFingerprint,如 "CAN:0"
|
||
/// </summary>
|
||
public static string BuildFingerprint(string canDeviceFingerprint, uint channel)
|
||
{
|
||
return $"{canDeviceFingerprint}:{channel}";
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
if (_disposed) return;
|
||
_disposed = true;
|
||
|
||
foreach (var kvp in _handlers)
|
||
{
|
||
if (kvp.Key != null)
|
||
kvp.Key.OnDbcMessageDecoded -= kvp.Value;
|
||
}
|
||
_handlers.Clear();
|
||
}
|
||
}
|
||
}
|