2023-04-28 10:15:33 +08:00
|
|
|
|
using Aitex.Common.Util;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
using Aitex.Core.Common.DeviceData;
|
|
|
|
|
using Aitex.Core.RT.DataCenter;
|
|
|
|
|
using Aitex.Core.RT.Device;
|
2023-04-28 10:15:33 +08:00
|
|
|
|
using Aitex.Core.RT.IOCore;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
using Aitex.Core.RT.Log;
|
|
|
|
|
using Aitex.Core.RT.OperationCenter;
|
|
|
|
|
using Aitex.Core.Util;
|
2023-04-28 10:15:33 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Xml;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
namespace MECF.Framework.Common.Device.Bases
|
|
|
|
|
{
|
2023-04-28 10:15:33 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 信号塔对象。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class SignalTowerBase : BaseDevice, IDevice
|
|
|
|
|
{
|
|
|
|
|
#region Variables
|
|
|
|
|
|
|
|
|
|
private bool _switchBuzzerOff;
|
|
|
|
|
|
|
|
|
|
private Dictionary<string, List<SignalTowerPartAction>> _signalTowerEvent;
|
|
|
|
|
|
|
|
|
|
private readonly Dictionary<LightType, SignalTowerPartBase> _dicSignalParts;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 构建信号塔对象的实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="module">当前模组名称。</param>
|
|
|
|
|
/// <param name="node">设备配置文件。</param>
|
|
|
|
|
/// <param name="ioModule">所属Module的名称。</param>
|
|
|
|
|
public SignalTowerBase(string module, XmlElement node, string ioModule = "")
|
|
|
|
|
: base(module, node, ioModule)
|
|
|
|
|
{
|
|
|
|
|
_dicSignalParts = new Dictionary<LightType, SignalTowerPartBase>();
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
// 红、黄、绿、蜂鸣器是必须定义的元件。
|
|
|
|
|
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);
|
|
|
|
|
CreateSignalPart(LightType.Buzzer1, doBuzzer1);
|
|
|
|
|
CreateSignalPart(LightType.Buzzer2, doBuzzer2);
|
|
|
|
|
CreateSignalPart(LightType.Buzzer3, doBuzzer3);
|
|
|
|
|
CreateSignalPart(LightType.Buzzer4, doBuzzer4);
|
|
|
|
|
CreateSignalPart(LightType.Buzzer5, doBuzzer5);
|
|
|
|
|
|
|
|
|
|
//解析三色灯Event
|
|
|
|
|
ParseSignalTowerEvent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected SignalTowerBase()
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 返回信号塔当前状态数据集。
|
|
|
|
|
/// <remarks>该属性用于RT到UI间的数据传递。</remarks>
|
|
|
|
|
/// </summary>
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建一个信号塔元件,并添加到字典中。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="type"></param>
|
|
|
|
|
/// <param name="do"></param>
|
|
|
|
|
private void CreateSignalPart(LightType type, DOAccessor @do)
|
|
|
|
|
{
|
|
|
|
|
if (@do != null)
|
|
|
|
|
_dicSignalParts.Add(type, new SignalTowerPartBase(type, @do));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool ParseSignalTowerEvent()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var fileName = PathManager.GetCfgDir() + "_SignalTower.xml";
|
|
|
|
|
if (!File.Exists(fileName))
|
|
|
|
|
{
|
|
|
|
|
fileName = PathManager.GetCfgDir() + "SignalTower.xml";
|
|
|
|
|
|
|
|
|
|
if (!File.Exists(fileName))
|
|
|
|
|
{
|
|
|
|
|
LOG.Error("Unable to find signal tower events definition file.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var stEvents = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(fileName));
|
|
|
|
|
_signalTowerEvent = new Dictionary<string, List<SignalTowerPartAction>>();
|
|
|
|
|
|
|
|
|
|
foreach (var _event in stEvents.Events)
|
|
|
|
|
{
|
|
|
|
|
if (!_signalTowerEvent.ContainsKey(_event.Name))
|
|
|
|
|
{
|
|
|
|
|
_signalTowerEvent[_event.Name] = new List<SignalTowerPartAction>();
|
|
|
|
|
|
|
|
|
|
foreach (LightType type in Enum.GetValues(typeof(LightType)))
|
|
|
|
|
{
|
|
|
|
|
if (!_dicSignalParts.ContainsKey(type))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var obj = _event.GetType().GetProperty(type.ToString())?.GetValue(_event);
|
|
|
|
|
if (obj != null)
|
|
|
|
|
{
|
|
|
|
|
TowerLightStatus status;
|
|
|
|
|
var str = obj.ToString().ToLower();
|
|
|
|
|
if (str.Contains("on"))
|
|
|
|
|
{
|
|
|
|
|
status = TowerLightStatus.On;
|
|
|
|
|
}
|
|
|
|
|
else if (str.Contains("off"))
|
|
|
|
|
{
|
|
|
|
|
status = TowerLightStatus.Off;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
status = TowerLightStatus.Blinking;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_signalTowerEvent[_event.Name].Add(new SignalTowerPartAction(type, status));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
LOG.Error(ex.ToString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 _dicSignalParts.Values)
|
|
|
|
|
light.Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Terminate()
|
|
|
|
|
{
|
|
|
|
|
foreach (var light in _dicSignalParts.Values)
|
|
|
|
|
light.Terminate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Monitor()
|
|
|
|
|
{
|
|
|
|
|
var tempStatus = _dicSignalParts.Keys.ToDictionary(x => x, type => TowerLightStatus.Off);
|
|
|
|
|
|
|
|
|
|
// 遍历所有注册的事件,决定信号塔各元件的输出状态。
|
|
|
|
|
foreach (var signalEvent in _signalTowerEvent)
|
|
|
|
|
{
|
|
|
|
|
var obj = DATA.Poll(signalEvent.Key);
|
|
|
|
|
if (obj == null || !(obj is bool flag) || !flag)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
foreach (var action in signalEvent.Value)
|
|
|
|
|
{
|
|
|
|
|
var mergedAction = MergeAction(tempStatus[action.Light], action.Status);
|
|
|
|
|
|
|
|
|
|
if (_switchBuzzerOff && action.Light == LightType.Buzzer)
|
|
|
|
|
{
|
|
|
|
|
mergedAction = TowerLightStatus.Off;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tempStatus[action.Light] = mergedAction;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var status in tempStatus)
|
|
|
|
|
{
|
|
|
|
|
_dicSignalParts[status.Key].SetValue(status.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var light in _dicSignalParts.Values)
|
|
|
|
|
light?.Monitor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 以指定的模式闪烁指定的信号塔元件。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="light">指定的信号塔元件。</param>
|
|
|
|
|
/// <param name="pattern">闪烁模式。</param>
|
|
|
|
|
/// <returns>True:启动闪烁成功;False:启动闪烁失败。</returns>
|
|
|
|
|
public bool Blink(LightType light, STBlinkPattern pattern)
|
|
|
|
|
{
|
|
|
|
|
if (pattern == null)
|
|
|
|
|
{
|
|
|
|
|
LOG.Error($"{light} Blink Pattern can not be null");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_dicSignalParts.TryGetValue(light, out var lightInstance))
|
|
|
|
|
{
|
|
|
|
|
lightInstance.SetValue(TowerLightStatus.Blinking, pattern);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG.Error($"{light} Unable to find this part of signal tower, check configuration");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 打开或关闭蜂鸣器。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="isOff"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool SwitchOffBuzzer(bool isOff)
|
|
|
|
|
{
|
|
|
|
|
_switchBuzzerOff = isOff;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 关闭蜂鸣器。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="arg1"></param>
|
|
|
|
|
/// <param name="arg2"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private bool SwitchOffBuzzer(string arg1, object[] arg2)
|
|
|
|
|
{
|
|
|
|
|
_switchBuzzerOff = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 合并信号灯的输出状态。
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// 如果信号灯期望的输出状态和当前输出状态中任一状态为On,则输出On;
|
|
|
|
|
/// <br/>
|
|
|
|
|
/// 如果信号灯期望的输出状态和当前输出状态中任一状态为Blink,则输出Blink;
|
|
|
|
|
/// <br/>
|
|
|
|
|
/// 如果信号灯期望的输出状态和当前输出状态*均为*为Off,则输出Off;
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="currentStatus">当前输出状态。</param>
|
|
|
|
|
/// <param name="desiredStatus">期望的输出状态。</param>
|
|
|
|
|
/// <returns>合并后的信号灯输出状态。</returns>
|
|
|
|
|
private TowerLightStatus MergeAction(TowerLightStatus currentStatus, TowerLightStatus desiredStatus)
|
|
|
|
|
{
|
|
|
|
|
if (currentStatus == TowerLightStatus.On || desiredStatus == TowerLightStatus.On)
|
|
|
|
|
{
|
|
|
|
|
return TowerLightStatus.On;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentStatus == TowerLightStatus.Blinking || desiredStatus == TowerLightStatus.Blinking)
|
|
|
|
|
{
|
|
|
|
|
return TowerLightStatus.Blinking;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TowerLightStatus.Off;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取指定信号塔元件的输出状态。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="light"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private bool GetSignalTowerPartValue(LightType light)
|
|
|
|
|
{
|
|
|
|
|
if (_dicSignalParts.TryGetValue(light, out var part))
|
|
|
|
|
return part.GetValue();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|