using Model.Models;
using Prism.Events;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UIShare.PubEvent;
using UIShare.UIViewModel;
namespace UIShare.GlobalVariable
{
///
/// CAN 信号广播器(全局单例):
/// 不再订阅 CAN 实体实例的事件,改为从所有已注册的
/// 的 RealTimeSignals 字典中轮询读取信号值,并通过 广播。
///
public class CANSignalBroadcaster
{
private readonly IEventAggregator _eventAggregator;
private readonly SystemConfig _systemConfig;
/// 全局已注册的 CANMonitoringService 实例列表(静态,跨作用域共享)
private static readonly ConcurrentDictionary _registeredServices = new();
private CancellationTokenSource? _cts;
private Task? _broadcastTask;
/// 广播轮询间隔(毫秒)
public int PollingIntervalMs { get; set; } = 100;
public CANSignalBroadcaster(SystemConfig systemConfig, IEventAggregator eventAggregator)
{
_systemConfig = systemConfig;
_eventAggregator = eventAggregator;
}
#region 服务注册(供 CANMonitoringService 调用)
/// 注册一个 CANMonitoringService,使其信号纳入广播
public static void RegisterService(CANMonitoringService service)
{
_registeredServices.TryAdd(service, 0);
}
/// 注销一个 CANMonitoringService
public static void UnregisterService(CANMonitoringService service)
{
_registeredServices.TryRemove(service, out _);
}
#endregion
#region 启动 / 停止
/// 启动广播(幂等:多次调用只启动一次)
public void Start()
{
if (_broadcastTask != null && !_broadcastTask.IsCompleted) return;
_cts = new CancellationTokenSource();
_broadcastTask = Task.Run(() => BroadcastLoop(_cts.Token));
}
/// 停止广播
public void Stop()
{
_cts?.Cancel();
_broadcastTask = null;
}
/// 兼容旧接口:Discover 已无需执行任何操作
public void Discover() { }
#endregion
#region 广播核心逻辑
///
/// 轮询所有已注册的 CANMonitoringService 的 RealTimeSignals,
/// 结合 ConfigurationList 映射出 MessageID/Channel,广播 HardwareDataReportedEvent。
///
private async Task BroadcastLoop(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
// 预构建信号名 → 配置 的映射(避免内层循环重复查找)
var configMap = BuildConfigMap();
string scope = _systemConfig.Title;
foreach (var service in _registeredServices.Keys)
{
if (service.IsStopped) continue;
foreach (var kvp in service.RealTimeSignals)
{
if (ct.IsCancellationRequested) return;
// 信号 Key 格式: "{channel}/{MessageName}/{SignalName}"
if (!TryParseSignalKey(kvp.Key, out int channel, out string? messageName, out string? signalName))
continue;
// 从配置映射中查找对应的 MessageID
if (!configMap.TryGetValue($"{channel}/{messageName}/{signalName}", out var cfg))
continue;
string canFingerprint = $"CAN:{channel}";
string fingerprint = BuildFingerprint(canFingerprint, (uint)channel);
string methodName = BuildMethodName((uint)cfg.MessageID, signalName);
// 广播信号值
_eventAggregator.GetEvent().Publish(new HardwareReportArgs
{
Scope = scope,
HardwareFingerprint = fingerprint,
MethodName = methodName,
Value = kvp.Value,
Time = DateTime.Now
});
// 报警检查
string alarmStatus = ValueLimitAlarmHelper.CheckAlarm(fingerprint, methodName, kvp.Value, _systemConfig);
if (!string.IsNullOrEmpty(alarmStatus) && alarmStatus != "未报警")
{
_eventAggregator.GetEvent().Publish((scope, canFingerprint, alarmStatus));
}
}
}
await Task.Delay(PollingIntervalMs, ct);
}
catch (OperationCanceledException) { break; }
catch (Exception ex)
{
Logger.LoggerHelper.Error($"CANSignalBroadcaster 广播异常: {ex.Message}");
await Task.Delay(1000, ct); // 异常后等待一段时间再重试
}
}
}
///
/// 从 SystemConfig.ConfigurationList 构建 "channel/MessageName/SignalName" → CANSignalConfig 的映射
///
private Dictionary BuildConfigMap()
{
var map = new Dictionary(StringComparer.OrdinalIgnoreCase);
if (_systemConfig?.ConfigurationList == null) return map;
foreach (var cfg in _systemConfig.ConfigurationList)
{
if (string.IsNullOrEmpty(cfg.SignalName) || string.IsNullOrEmpty(cfg.MessageName)) continue;
string key = $"{cfg.Channel}/{cfg.MessageName}/{cfg.SignalName}";
map.TryAdd(key, cfg); // 第一个匹配的优先
}
return map;
}
/// 解析信号 Key: "{channel}/{MessageName}/{SignalName}"
private static bool TryParseSignalKey(string key, out int channel, out string? messageName, out string? signalName)
{
channel = 0;
messageName = null;
signalName = null;
var parts = key.Split('/');
if (parts.Length < 3) return false;
if (!int.TryParse(parts[0], out channel)) return false;
messageName = parts[1];
signalName = parts[2];
return !string.IsNullOrEmpty(messageName) && !string.IsNullOrEmpty(signalName);
}
#endregion
#region 静态工具方法(保持向后兼容)
/// 生成 CAN 信号的 DisplayName 格式:"{MessageName}.{SignalName}"
public static string BuildDisplayName(string messageName, string signalName)
{
return $"{messageName}.{signalName}";
}
/// 生成 CAN 信号的 MethodName 格式:"{MessageId:X}.{SignalName}"
public static string BuildMethodName(uint messageId, string signalName)
{
return $"{messageId:X}.{signalName}";
}
///
/// 生成 CAN 信号的 Fingerprint 格式:"{canDeviceFingerprint}:{channel}"
/// canDeviceFingerprint 来自 DeviceManager.ExtractHardwareFingerprint,如 "CAN:0"
///
public static string BuildFingerprint(string canDeviceFingerprint, uint channel)
{
return $"{canDeviceFingerprint}:{channel}";
}
#endregion
}
}