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 } }