using Aitex.Common.Util; using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.Util; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Xml; namespace MECF.Framework.Common.Device.Bases { /// /// 信号塔对象。 /// public class SignalTowerBase : BaseDevice, IDevice { #region Variables /// /// 是否关闭蜂鸣器输出。 /// True:蜂鸣器被手动关闭,满足事件条件也不要打开蜂鸣器。 /// False:根据当前系统状态和配置事件自动输出蜂鸣器状态。 /// private bool _switchBuzzerOff; /// /// 信号塔事件字典,从配置文件中读取。 /// private Dictionary> _signalTowerEvent; /// /// 信号塔中组件字典。 /// private readonly Dictionary _dicStParts; /// /// 信号塔组件动作字典。 /// private Dictionary _dicMergedActions; #endregion #region Constructors /// /// 构建信号塔对象的实例。 /// /// 当前模组名称。 /// 设备配置文件。 /// 所属Module的名称。 public SignalTowerBase(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule) { _dicStParts = new Dictionary(); var doRedLight = ParseDoNode("doRed", node, ioModule); var doYellowLight = ParseDoNode("doYellow", node, ioModule); var doGreenLight = ParseDoNode("doGreen", node, ioModule); var doBlueLight = ParseDoNode("doBlue", node, ioModule); var doWhiteLight = ParseDoNode("doWhite", node, ioModule); var doBuzzer = ParseDoNode("doBuzzer", node, ioModule); var doBuzzer1 = ParseDoNode("doBuzzer1", node, ioModule); var doBuzzer2 = ParseDoNode("doBuzzer2", node, ioModule); var doBuzzer3 = ParseDoNode("doBuzzer3", node, ioModule); var doBuzzer4 = ParseDoNode("doBuzzer4", node, ioModule); var doBuzzer5 = ParseDoNode("doBuzzer5", node, ioModule); var aoBuzzerBlinkFreq = ParseAoNode("aoBuzzerBlinkFreq", node, ioModule); var eventFile = node.GetAttribute("eventFile"); // 红、黄、绿、蜂鸣器是必须定义的元件。 Debug.Assert(doRedLight != null, "DO RedLight is not valid"); Debug.Assert(doYellowLight != null, "DO RedLight is not valid"); Debug.Assert(doGreenLight != null, "DO RedLight is not valid"); Debug.Assert(doBuzzer != null, "DO RedLight is not valid"); // 创建三色灯控制元件。 CreateSignalPart(LightType.Red, doRedLight); CreateSignalPart(LightType.Yellow, doYellowLight); CreateSignalPart(LightType.Green, doGreenLight); CreateSignalPart(LightType.Blue, doBlueLight); CreateSignalPart(LightType.White, doWhiteLight); CreateSignalPart(LightType.Buzzer, doBuzzer, aoBuzzerBlinkFreq); CreateSignalPart(LightType.Buzzer1, doBuzzer1); CreateSignalPart(LightType.Buzzer2, doBuzzer2); CreateSignalPart(LightType.Buzzer3, doBuzzer3); CreateSignalPart(LightType.Buzzer4, doBuzzer4); CreateSignalPart(LightType.Buzzer5, doBuzzer5); //解析三色灯Event ParseSignalTowerEvent(eventFile); } #endregion #region Properties /// /// 返回信号塔当前状态数据集。 /// 该属性用于RT到UI间的数据传递。 /// public AITSignalTowerData DeviceData => new AITSignalTowerData { DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, IsGreenLightOn = GetSignalTowerPartValue(LightType.Green), IsRedLightOn = GetSignalTowerPartValue(LightType.Red), IsYellowLightOn = GetSignalTowerPartValue(LightType.Yellow), IsBlueLightOn = GetSignalTowerPartValue(LightType.Blue), IsWhiteLightOn = GetSignalTowerPartValue(LightType.White), IsBuzzerOn = GetSignalTowerPartValue(LightType.Buzzer), IsBuzzer1On = GetSignalTowerPartValue(LightType.Buzzer1), IsBuzzer2On = GetSignalTowerPartValue(LightType.Buzzer2), IsBuzzer3On = GetSignalTowerPartValue(LightType.Buzzer3), IsBuzzer4On = GetSignalTowerPartValue(LightType.Buzzer4), IsBuzzer5On = GetSignalTowerPartValue(LightType.Buzzer5), }; #endregion #region Methods /// /// 创建一个信号塔元件,并添加到字典中。 /// /// 信号塔元件类型,请参考。 /// 控制元件开关的DO。 /// 控制Blink频率的AO。 private void CreateSignalPart(LightType light, DOAccessor doSw, AOAccessor aoBlinkFreq = null) { if (doSw != null) _dicStParts.Add(light, new SignalTowerPartBase(light, doSw, aoBlinkFreq)); } /// /// 从指定的配置文件中解析信号塔事件。 /// /// /// private bool ParseSignalTowerEvent(string fileName) { try { var cFileName = PathManager.GetCfgDir() + fileName; if (!File.Exists(cFileName)) { LOG.Error($"Unable to find signal tower events config file {cFileName}."); return false; } var stEvents = CustomXmlSerializer.Deserialize(new FileInfo(cFileName)); stEvents.ParseEvents(out var events); if (events == null) LOG.Error("Unable to parse the signal tower events from config file."); _signalTowerEvent = events; return _signalTowerEvent != null; } catch (Exception ex) { LOG.Error(ex.ToString()); return false; } } /// /// 初始化信号塔对象实例。 /// /// /// 注册SwitchOffBuzzer操作和DeviceData数据。 /// /// public bool Initialize() { OP.Subscribe($"{Module}.{Name}.{AITSignalTowerOperation.SwitchOffBuzzer}", SwitchOffBuzzer); DATA.Subscribe(Module + "." + Name + ".DeviceData", () => DeviceData); return true; } /// /// 复位信号塔状态及其各个组件。 /// public void Reset() { _switchBuzzerOff = false; foreach (var light in _dicStParts.Values) light.Reset(); } /// /// 终止信号塔对象实例。 /// public void Terminate() { foreach (var light in _dicStParts.Values) light.Terminate(); } /// /// 周期性扫描信号塔以执行后台任务。 /// public void Monitor() { _dicMergedActions = _dicStParts.ToDictionary( x => x.Key, v => v.Value.GetAction()); // 遍历所有注册的事件,决定信号塔各元件的输出状态。 foreach (var signalEvent in _signalTowerEvent) { var obj = DATA.Poll(signalEvent.Key); if(obj is not true) continue; foreach (var newAction in signalEvent.Value) { if (!_dicStParts.TryGetValue(newAction.Light, out var stPart)) continue; // 根据当前设备状态,判断下一步信号组件的输出动作是什么 var mergedAction = MergeAction(_dicMergedActions[stPart.Light], newAction); _dicMergedActions[stPart.Light] = mergedAction; } } // 设置信号塔每个组件的输出。 foreach (var action in _dicMergedActions) { // 创建一个动作副本,解决蜂鸣器被手动关闭后无法启用的问题 var clonedAction = (STEventAction)action.Value?.Clone(); if(clonedAction == null) continue; // 如果蜂鸣器被强制关闭 if (clonedAction.Light == LightType.Buzzer && _switchBuzzerOff) clonedAction.Status = TowerLightStatus.Off; _dicStParts[action.Key].SetAction(clonedAction); } // 扫描信号塔组件状态 foreach (var light in _dicStParts.Values) light?.Monitor(); } /// /// 以指定的模式闪烁指定的信号塔元件。 /// /// 指定的信号塔元件。 /// 闪烁模式。 /// True:启动闪烁成功;False:启动闪烁失败。 public bool Blink(LightType light, STBlinkPattern pattern) { if (pattern == null) { LOG.Error($"{light} Blink Pattern can not be null"); return false; } if (_dicStParts.TryGetValue(light, out var lightInstance)) { // 强制使能蜂鸣器 _switchBuzzerOff = false; lightInstance.SetAction(new STEventAction(lightInstance.Light, TowerLightStatus.Customized, pattern)); return true; } LOG.Error($"{light} Unable to find this part of signal tower, check configuration"); return false; } /// /// 打开或关闭蜂鸣器。 /// /// /// public bool SwitchOffBuzzer(bool isOff) { _switchBuzzerOff = isOff; return true; } /// /// 关闭蜂鸣器。 /// /// /// /// private bool SwitchOffBuzzer(string arg1, object[] arg2) { _switchBuzzerOff = true; return true; } /// /// 合并信号事件。 /// /// 根据的优先级决定执行的动作。 ///
/// 此属性的数值越小,表示优先级越高。 ///
///
/// 当前输出状态。 /// 期望的输出状态。 /// 合并后的信号灯输出状态。 private STEventAction MergeAction(STEventAction currentAction, STEventAction nextAction) { if (currentAction == null) return nextAction; if (nextAction == null) return currentAction; // 获取当前动作的优先级 var curPrior = currentAction.Status == TowerLightStatus.Customized ? currentAction.BlinkPattern.Priority : (int)currentAction.Status; // 获取下一个动作的优先级 var nextPrior = nextAction.Status == TowerLightStatus.Customized ? nextAction.BlinkPattern.Priority : (int)nextAction.Status; return curPrior < nextPrior ? currentAction : nextAction; } /// /// 获取指定信号塔元件的输出状态。 /// /// /// private bool GetSignalTowerPartValue(LightType light) { if (_dicStParts.TryGetValue(light, out var part)) return part.GetValue(); return false; } #endregion } }