修正JobDone蜂鸣器鸣响循环结束后,仍然继续鸣响的问题。

优化三色灯代码。
This commit is contained in:
SL 2023-12-27 10:42:19 +08:00
parent 163d2ecad0
commit 0cfe77d1aa
16 changed files with 290 additions and 253 deletions

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using Aitex.Core.Account;
using Aitex.Core.RT.DataCenter;
@ -227,7 +228,9 @@ namespace Aitex.Core.RT.Event
OP.Subscribe("System.Diagnosis.GenPjDoneEvent", (s, args) =>
{
WriteEvent(ModuleName.System.ToString(), "PJ_DONE", "LoadLock", "0");
//WriteEvent(ModuleName.System.ToString(), "PJ_DONE", "LoadLock", "0");
EV.PostMessage(ModuleName.System.ToString(), EventEnum.PJ_DONE, "LoadLock", "0");
OP.DoOperation("System.AlertJobDone");
return true;
});

View File

@ -704,9 +704,9 @@
<Compile Include="MECF\Framework\Common\Device\Bases\ChillerBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\GasSplitterBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\HeaterBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\STEventAction.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\STAction.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\SignalTowerBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\SignalTowerPartBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\SignalTowerLightBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\LidBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\LightType.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\MfcBase.cs" />
@ -722,7 +722,7 @@
<Compile Include="MECF\Framework\Common\Device\Bases\STEvents.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\STPatternSetting.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\ThrottleValveBase.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\TowerLightStatus.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\SignalTowerActions.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\VCEBase.cs" />
<Compile Include="MECF\Framework\Common\Equipment\ModuleHelper.cs" />
<Compile Include="MECF\Framework\Common\Equipment\ModuleName.cs" />

View File

@ -1,6 +1,6 @@
namespace MECF.Framework.Common.Device.Bases
{
public enum LightType
public enum STLightTypes
{
Red = 0,
Yellow = 1,

View File

@ -5,24 +5,25 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 预设的信号灯塔元件动作。
/// </summary>
public class STEventAction : IComparable, ICloneable
public class STAction : IComparable, ICloneable
{
#region Constructors
/// <summary>
/// 信号灯塔元件动作构造函数。
/// </summary>
/// <param name="name">动作名称。</param>
/// <param name="eventName">动作名称。</param>
/// <param name="light">信号塔组件对象的实例。</param>
/// <param name="status">信号塔组件输出状态。</param>
/// <param name="action">信号塔组件输出状态。</param>
/// <param name="blinkPattern">信号塔组件工作模式。如果传入空值,则自动调用
/// <see cref="STBlinkPattern.GetDefaultPattern"/>以创建默认工作模式。</param>
public STEventAction(string name, SignalTowerPartBase light, TowerLightStatus status, STBlinkPattern blinkPattern = null)
public STAction(string eventName, SignalTowerLightBase light, SignalTowerActions action, STBlinkPattern blinkPattern = null)
{
Name = name;
StPart = light;
Status = status;
EventName = eventName;
Light = light;
Output = action;
BlinkPattern = blinkPattern ?? STBlinkPattern.GetDefaultPattern();
IsCycleDone = false;
}
@ -31,26 +32,36 @@ namespace MECF.Framework.Common.Device.Bases
#region Properties
/// <summary>
/// 动作名称。
/// 动作对应的事件名称。
/// </summary>
public string Name { get; }
public string EventName { get; }
/// <summary>
/// 返回执行当前动作的信号灯。
/// </summary>
public STLightTypes LightType => Light.Type;
/// <summary>
/// 返回信号灯实例。
/// </summary>
public SignalTowerPartBase StPart { get; }
public SignalTowerLightBase Light { get; }
/// <summary>
/// 设置或返回信号灯的输出状态。
/// 支持的状态请参考<see cref="TowerLightStatus"/>枚举。
/// 支持的状态请参考<see cref="SignalTowerActions"/>枚举。
/// </summary>
public TowerLightStatus Status { get; set; }
public SignalTowerActions Output { get; set; }
/// <summary>
/// 设置或返回信号灯闪烁模式。
/// </summary>
public STBlinkPattern BlinkPattern { get; set; }
/// <summary>
/// 设置或返回是否循环结束。
/// </summary>
public bool IsCycleDone { get; set; }
#endregion
#region Methods
@ -58,12 +69,12 @@ namespace MECF.Framework.Common.Device.Bases
/// <inheritdoc />
public int CompareTo(object obj)
{
if (obj is not STEventAction target)
if (obj is not STAction target)
return -1;
return (BlinkPattern.CompareTo(target.BlinkPattern) == 0
&& Status == target.Status
&& StPart == target.StPart)
&& Output == target.Output
&& Light == target.Light)
? 0
: -1;
}
@ -71,13 +82,13 @@ namespace MECF.Framework.Common.Device.Bases
/// <inheritdoc />
public object Clone()
{
return new STEventAction(Name, StPart, Status, (STBlinkPattern)BlinkPattern.Clone());
return new STAction(EventName, Light, Output, (STBlinkPattern)BlinkPattern.Clone());
}
/// <inheritdoc/>
public override string ToString()
{
return $"{StPart}, {Status}";
return $"{Light}, {Output}";
}
#endregion

View File

@ -4,7 +4,7 @@ using System.Diagnostics;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Aitex.Core.RT.Log;
using BlinkDataType = System.Collections.Generic.KeyValuePair<MECF.Framework.Common.Device.Bases.TowerLightStatus, uint>;
using BlinkDataType = System.Collections.Generic.KeyValuePair<MECF.Framework.Common.Device.Bases.SignalTowerActions, uint>;
namespace MECF.Framework.Common.Device.Bases;
@ -131,7 +131,7 @@ public class STBlinkPattern : IComparable, ICloneable
#region Static Methods
/// <summary>
/// 解析闪烁模式字串生成闪烁数据供M<see cref="SignalTowerPartBase"/>产生闪烁效果。
/// 解析闪烁模式字串生成闪烁数据供M<see cref="SignalTowerLightBase"/>产生闪烁效果。
/// </summary>
/// <param name="pattern"></param>
/// <param name="blinkData">闪烁效果数据。</param>
@ -171,14 +171,14 @@ public class STBlinkPattern : IComparable, ICloneable
var length = (uint)match.Length;
// 根据每组的字符判断动作。
TowerLightStatus action;
SignalTowerActions action;
switch (leadChar)
{
case "-":
action = TowerLightStatus.On;
action = SignalTowerActions.On;
break;
case ".":
action = TowerLightStatus.Off;
action = SignalTowerActions.Off;
break;
default:
@ -238,7 +238,7 @@ public class STBlinkPattern : IComparable, ICloneable
/// <returns></returns>
public static STBlinkPattern GetDefaultPattern()
{
return new STBlinkPattern(PATTERN_SLOW, (int)TowerLightStatus.Customized);
return new STBlinkPattern(PATTERN_SLOW, (int)SignalTowerActions.Customized);
}
@ -246,12 +246,12 @@ public class STBlinkPattern : IComparable, ICloneable
/// 获取预设的工艺完成闪烁模式。
/// </summary>
/// <remarks>
/// 以开200ms、关200ms方式连续闪烁3次然后关1s循环5次。
/// 以开200ms、关200ms方式连续闪烁3次然后关1s循环3次。
/// </remarks>
/// <returns></returns>
public static STBlinkPattern GetJobDonePattern()
{
return new STBlinkPattern(PATTERN_JOB_DONE, priority:-1);
return new STBlinkPattern(PATTERN_JOB_DONE, priority:-1, cycle:3);
}
#endregion

View File

@ -32,9 +32,9 @@ namespace MECF.Framework.Common.Device.Bases
/// 解析配置文件中定义的事件。
/// </summary>
/// <param name="dicLights">
/// 包含<see cref="SignalTowerPartBase"/>对象的字典。
/// 包含<see cref="SignalTowerLightBase"/>对象的字典。
/// <remarks>
/// <see cref="STEventAction"/>需要映射到相应的<see cref="SignalTowerPartBase"/>对象,因此需要传入相应的字典;
/// <see cref="STAction"/>需要映射到相应的<see cref="SignalTowerLightBase"/>对象,因此需要传入相应的字典;
/// 该字典在<see cref="SignalTowerBase"/>构造函数中创建。
/// </remarks>
/// </param>
@ -43,12 +43,12 @@ namespace MECF.Framework.Common.Device.Bases
/// <remarks>
/// 事件字典的Key为事件名称名称为RT中注册的Bool型数据通过DATA.Poll访问。
/// <br/>
/// 事件动作为<see cref="STEventAction"/>动作列表表示当上述事件为True时指定的信号塔组件执行的动作。
/// 事件动作为<see cref="STAction"/>动作列表表示当上述事件为True时指定的信号塔组件执行的动作。
/// </remarks>
/// </param>
public void ParseEvents(Dictionary<LightType, SignalTowerPartBase> dicLights, out Dictionary<string, List<STEventAction>> events)
public void ParseEvents(Dictionary<STLightTypes, SignalTowerLightBase> dicLights, out Dictionary<string, List<STAction>> events)
{
events = new Dictionary<string, List<STEventAction>>();
events = new Dictionary<string, List<STAction>>();
foreach (var stEvent in Events)
{
@ -57,24 +57,24 @@ namespace MECF.Framework.Common.Device.Bases
continue;
// 字典中创建一个事件项目
events[stEvent.Name] = new List<STEventAction>();
events[stEvent.Name] = new List<STAction>();
// 解析当前事件执行的动作
foreach (LightType light in Enum.GetValues(typeof(LightType)))
foreach (STLightTypes light in Enum.GetValues(typeof(STLightTypes)))
{
var strStatus = stEvent.GetType().GetProperty(light.ToString())?.GetValue(stEvent)?.ToString().ToLower();
if (!string.IsNullOrEmpty(strStatus))
{
var status = TowerLightStatus.Unknown;
var status = SignalTowerActions.Unknown;
STBlinkPattern blinkPattern = null;
if (strStatus.Contains(TowerLightStatus.On.ToString().ToLower()))
if (strStatus.Contains(SignalTowerActions.On.ToString().ToLower()))
{
status = TowerLightStatus.On;
status = SignalTowerActions.On;
}
else if (strStatus.Contains(TowerLightStatus.Off.ToString().ToLower()))
else if (strStatus.Contains(SignalTowerActions.Off.ToString().ToLower()))
{
status = TowerLightStatus.Off;
status = SignalTowerActions.Off;
}
else
{
@ -91,11 +91,11 @@ namespace MECF.Framework.Common.Device.Bases
}
status = TowerLightStatus.Customized;
status = SignalTowerActions.Customized;
}
if(dicLights.TryGetValue(light, out var part))
events[stEvent.Name].Add(new STEventAction(stEvent.Name, part, status, blinkPattern));
events[stEvent.Name].Add(new STAction(stEvent.Name, part, status, blinkPattern));
else
LOG.Error($"Unable to find signal tower part {light} from STEvent config file.");
}

View File

@ -10,7 +10,7 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
[Serializable]
[DataContract]
public enum TowerLightStatus
public enum SignalTowerActions
{
/// <summary>
/// 使用STEvents配置文件中配置的工作模式模板

View File

@ -13,8 +13,8 @@ using System.IO;
using System.Linq;
using System.Xml;
using DicEventActions = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<MECF.Framework.Common.Device.Bases.STEventAction>>;
using DicLightActions = System.Collections.Generic.Dictionary<MECF.Framework.Common.Device.Bases.LightType,MECF.Framework.Common.Device.Bases.STEventAction>;
using DictEvent = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<MECF.Framework.Common.Device.Bases.STAction>>;
using DictActionsPerLight = System.Collections.Generic.Dictionary<MECF.Framework.Common.Device.Bases.STLightTypes, MECF.Framework.Common.Device.Bases.STAction>;
namespace MECF.Framework.Common.Device.Bases
{
@ -30,6 +30,11 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
protected const string KEY_PATTERN_JOB_DONE = "JobDone";
/// <summary>
/// 信号灯字典。
/// </summary>
private readonly Dictionary<STLightTypes, SignalTowerLightBase> _dictStLights;
/// <summary>
/// 是否关闭蜂鸣器输出。
/// <value>True蜂鸣器被手动关闭满足事件条件也不要打开蜂鸣器。</value>
@ -48,7 +53,7 @@ namespace MECF.Framework.Common.Device.Bases
/// 内容改动后会重新创建该字典此时有可能Monitor()方法正在使用此字典。
/// </remarks>
/// </summary>
private DicEventActions _dicPreDefinedStEvents;
private DictEvent _dictPreDefinedEvents;
/// <summary>
/// 信号塔扩展事件字典。
@ -56,28 +61,23 @@ namespace MECF.Framework.Common.Device.Bases
/// 除STEvents配置中预设的事件外还有一类事件通常由RT触发这类事件也需要参与三色灯输出状态判断。
/// </remarks>
/// </summary>
private readonly DicEventActions _dicRtGeneratedStEvents;
/// <summary>
/// 信号塔中组件字典。
/// </summary>
private readonly Dictionary<LightType, SignalTowerPartBase> _dicStParts;
private readonly DictEvent _dictDynamicSTLightActions;
/// <summary>
/// 信号塔组件动作字典。
/// </summary>
private Dictionary<LightType, STEventAction> _dicMergedActions;
private DictActionsPerLight _dictSTLightActions;
/// <summary>
/// 上一次Monitor周期触发的事件列表。
/// 用于下一次Monitor周期判断是否有新的事件产生已解决蜂鸣器被手动关闭后如果未按下Reset则下次新事件产生时无法响蜂鸣器的问题。
/// </summary>
private readonly List<string> _lastEventsWithBuzzer = new List<string>();
private readonly List<string> _lastEventsWithBuzzer = [];
/// <summary>
/// STEvents配置文件解析对象。
/// </summary>
private STEvents _originStEvents;
private STEvents _eventsFileLoader;
#endregion
@ -88,12 +88,14 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
/// <param name="module">当前模组名称。</param>
/// <param name="node">设备配置文件。</param>
/// <param name="dictStLightActions"></param>
/// <param name="ioModule">所属Module的名称。</param>
public SignalTowerBase(string module, XmlElement node, string ioModule = "")
: base(module, node, ioModule)
{
_dicStParts = new Dictionary<LightType, SignalTowerPartBase>();
_dicRtGeneratedStEvents = new ();
_dictSTLightActions = new();
_dictStLights = new Dictionary<STLightTypes, SignalTowerLightBase>();
_dictDynamicSTLightActions = new ();
var doRedLight = ParseDoNode("doRed", node, ioModule);
var doYellowLight = ParseDoNode("doYellow", node, ioModule);
@ -116,27 +118,27 @@ namespace MECF.Framework.Common.Device.Bases
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);
CreateSTLight(STLightTypes.Red, doRedLight);
CreateSTLight(STLightTypes.Yellow, doYellowLight);
CreateSTLight(STLightTypes.Green, doGreenLight);
CreateSTLight(STLightTypes.Blue, doBlueLight);
CreateSTLight(STLightTypes.White, doWhiteLight);
CreateSTLight(STLightTypes.Buzzer, doBuzzer, aoBuzzerBlinkFreq);
CreateSTLight(STLightTypes.Buzzer1, doBuzzer1);
CreateSTLight(STLightTypes.Buzzer2, doBuzzer2);
CreateSTLight(STLightTypes.Buzzer3, doBuzzer3);
CreateSTLight(STLightTypes.Buzzer4, doBuzzer4);
CreateSTLight(STLightTypes.Buzzer5, doBuzzer5);
// 添加文件到监视器,当文件内容发生变化时重新加载配置。
var fullFn = PathManager.GetCfgDir() + eventFile;
FileSystemWatcherManager.Instance.Register(fullFn, fn =>
{
ParseSignalTowerEvent(fn);
ParseSTEvent(fn);
});
//解析三色灯Event
ParseSignalTowerEvent(fullFn);
ParseSTEvent(fullFn);
}
#endregion
@ -152,17 +154,17 @@ namespace MECF.Framework.Common.Device.Bases
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),
IsGreenLightOn = GetSignalTowerPartValue(STLightTypes.Green),
IsRedLightOn = GetSignalTowerPartValue(STLightTypes.Red),
IsYellowLightOn = GetSignalTowerPartValue(STLightTypes.Yellow),
IsBlueLightOn = GetSignalTowerPartValue(STLightTypes.Blue),
IsWhiteLightOn = GetSignalTowerPartValue(STLightTypes.White),
IsBuzzerOn = GetSignalTowerPartValue(STLightTypes.Buzzer),
IsBuzzer1On = GetSignalTowerPartValue(STLightTypes.Buzzer1),
IsBuzzer2On = GetSignalTowerPartValue(STLightTypes.Buzzer2),
IsBuzzer3On = GetSignalTowerPartValue(STLightTypes.Buzzer3),
IsBuzzer4On = GetSignalTowerPartValue(STLightTypes.Buzzer4),
IsBuzzer5On = GetSignalTowerPartValue(STLightTypes.Buzzer5),
};
#endregion
@ -172,13 +174,13 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 创建一个信号塔元件,并添加到字典中。
/// </summary>
/// <param name="light">信号塔元件类型,请参考<see cref="LightType"/>。</param>
/// <param name="light">信号塔元件类型,请参考<see cref="STLightTypes"/>。</param>
/// <param name="doSw">控制元件开关的DO。</param>
/// <param name="aoBlinkFreq">控制Blink频率的AO。</param>
private void CreateSignalPart(LightType light, DOAccessor doSw, AOAccessor aoBlinkFreq = null)
private void CreateSTLight(STLightTypes light, DOAccessor doSw, AOAccessor aoBlinkFreq = null)
{
if (doSw != null)
_dicStParts.Add(light, new SignalTowerPartBase(light, doSw, aoBlinkFreq));
_dictStLights.Add(light, new SignalTowerLightBase(light, doSw, aoBlinkFreq));
}
/// <summary>
@ -186,7 +188,7 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
/// <param name="fileName">包含完整路径的配置文件文件名。</param>
/// <returns></returns>
private bool ParseSignalTowerEvent(string fileName)
private bool ParseSTEvent(string fileName)
{
try
{
@ -196,15 +198,15 @@ namespace MECF.Framework.Common.Device.Bases
return false;
}
_originStEvents = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(fileName));
_originStEvents.ParseEvents(_dicStParts, out var events);
_eventsFileLoader = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(fileName));
_eventsFileLoader.ParseEvents(_dictStLights, out var events);
if (events == null)
LOG.Error("Unable to parse the signal tower events from config file.");
lock (SyncRoot)
{
_dicPreDefinedStEvents = events;
return _dicPreDefinedStEvents != null;
_dictPreDefinedEvents = events;
return _dictPreDefinedEvents != null;
}
}
catch (Exception ex)
@ -235,9 +237,9 @@ namespace MECF.Framework.Common.Device.Bases
public void Reset()
{
_switchBuzzerOff = false;
_dicRtGeneratedStEvents?.Clear();
_dictDynamicSTLightActions?.Clear();
foreach (var light in _dicStParts.Values)
foreach (var light in _dictStLights.Values)
light.Reset();
}
@ -246,7 +248,7 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
public void Terminate()
{
foreach (var light in _dicStParts.Values)
foreach (var light in _dictStLights.Values)
light.Terminate();
}
@ -256,51 +258,57 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
protected override void HandleMonitor()
{
// 创建上次发生的事件列表副本
// 遍历所有预设的事件,决定信号塔各元件的输出状态。
MonitorEvents(out var buzzerOnEvents);
List<string> events1;
lock (SyncRoot)
{
// 遍历所有预设的事件,决定信号塔各元件的输出状态。
_dicMergedActions = ConvertEventsToActions(_dicPreDefinedStEvents, out events1);
}
// 遍历所有扩展的事件,决定信号塔各元件的输出状态。
_dicMergedActions = ConvertEventsToActions(_dicRtGeneratedStEvents, out var events2, _dicMergedActions, false);
// 判断是否有新事件产生如果有需要复位_switchBuzzerOff状态以重新使能蜂鸣器解决蜂鸣器被手动关闭后如果不按Reset则无法重启启用的问题。
var eventCombined = new List<string>(events1.Concat(events2));
var newEvents = _lastEventsWithBuzzer.Except(eventCombined);
if (newEvents.Any())
// 判断是否有新的Buzzer相关事件产生如果有需要复位_switchBuzzerOff状态以重新使能蜂鸣器解决蜂鸣器被手动关闭后如果不按Reset则无法重启启用的问题。
var buzzerOnEventArray = buzzerOnEvents as string[] ?? buzzerOnEvents.ToArray();
var newBuzzerOnEvents = _lastEventsWithBuzzer.Except(buzzerOnEventArray);
if (newBuzzerOnEvents.Any())
{
_lastEventsWithBuzzer.Clear();
_lastEventsWithBuzzer.AddRange(eventCombined);
_lastEventsWithBuzzer.AddRange(buzzerOnEventArray);
_switchBuzzerOff = false;
}
// 设置信号塔每个组件的输出
foreach (var kvp in _dicMergedActions)
// 分配每个信号灯的动作。
foreach (var kvp in _dictSTLightActions)
{
var action = kvp.Value;
if (action == null)
continue;
if (action.StPart == null)
if (action?.Light == null)
continue;
// 创建动作副本因为后续可能根据_switchBuzzerOff调整输出状态避免覆盖原配置。
var cloned = (STEventAction)action.Clone();
var cloned = (STAction)action.Clone();
// 如果蜂鸣器被强制关闭则将待执行动作中的状态修改为Off
if (action.StPart.IsBuzzer && _switchBuzzerOff)
cloned.Status = TowerLightStatus.Off;
if (action.Light.IsBuzzer && _switchBuzzerOff)
cloned.Output = SignalTowerActions.Off;
action.StPart.SetAction(cloned);
action.Light.SetAction(cloned);
}
// 扫描信号塔组件状态
foreach (var light in _dicStParts.Values)
light?.Monitor();
foreach (var light in _dictStLights.Values)
{
if(light == null)
continue;
light.Monitor();
// remove the cycle done action from dynamic STEvent dictionary
var currAction = light.GetAction();
if (currAction is { IsCycleDone: true }
&& _dictDynamicSTLightActions.TryGetValue(currAction.EventName, out var actions))
{
for (var i = actions.Count - 1; i >= 0; i--)
{
if (actions[i].LightType == light.Type)
actions.RemoveAt(i);
}
}
}
}
/// <summary>
@ -309,7 +317,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <param name="light">指定的信号塔元件。</param>
/// <param name="pattern">闪烁模式。</param>
/// <returns>True启动闪烁成功False启动闪烁失败。</returns>
public bool Blink(LightType light, STBlinkPattern pattern)
public bool Blink(STLightTypes light, STBlinkPattern pattern)
{
if (pattern == null)
{
@ -317,7 +325,11 @@ namespace MECF.Framework.Common.Device.Bases
return false;
}
CreateRtEvent(new STEventAction("Rt Triggered Blink", _dicStParts[light], TowerLightStatus.Customized, pattern));
var evName = $"Manual_Blink_{light}_{Guid.NewGuid()}";
var blinkAction = new STAction(evName, _dictStLights[light], SignalTowerActions.Customized,
pattern);
CreateDynamicEvent(evName, [blinkAction]);
return true;
}
@ -325,27 +337,25 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 当Wafer回到Cassette后打开蜂鸣器以指示ProcessJob结束。
/// </summary>
/// <param name="reason">如果打开蜂鸣器失败,提示失败原因。</param>
/// <returns></returns>
public bool SwitchOnBuzzerForJobDone(out string reason)
public bool AlertJobDone()
{
reason = "";
SignalTowerPartBase targetBuzzer = null;
SignalTowerLightBase targetBuzzer = null;
STBlinkPattern blinkPattern = null;
// 读取STEvents配置文件中的JobDone模式的配置。
var settings = _originStEvents.PatternsSettings.FirstOrDefault(x => x.Name == KEY_PATTERN_JOB_DONE);
var alertPattern = _eventsFileLoader.PatternsSettings.FirstOrDefault(x => x.Name == KEY_PATTERN_JOB_DONE);
if (settings != null)
if (alertPattern != null)
{
// 解析配置中的Buzzer如果未指定Buzzer或指定为除Buzzer以外的信号灯则默认使用Buzzer。
var targetPart = settings.Part;
if (Enum.TryParse(targetPart, out LightType lightType)
&& _dicStParts.TryGetValue(lightType, out var buzzer)
var targetLight = alertPattern.Part;
if (Enum.TryParse(targetLight, out STLightTypes lightType)
&& _dictStLights.TryGetValue(lightType, out var buzzer)
&& buzzer.IsBuzzer)
targetBuzzer = buzzer;
blinkPattern = new STBlinkPattern(settings.Pattern, priority: settings.Priority, cycle: settings.Cycles);
blinkPattern = new STBlinkPattern(alertPattern.Pattern, priority: alertPattern.Priority, cycle: alertPattern.Cycles);
}
else
{
@ -354,7 +364,9 @@ namespace MECF.Framework.Common.Device.Bases
LOG.Warning($"Unable to find pre-defined pattern for {KEY_PATTERN_JOB_DONE}");
}
CreateRtEvent(new STEventAction(KEY_PATTERN_JOB_DONE, targetBuzzer, TowerLightStatus.Customized, blinkPattern));
var buzzerAction = new STAction(KEY_PATTERN_JOB_DONE, targetBuzzer, SignalTowerActions.Customized,
blinkPattern);
CreateDynamicEvent(KEY_PATTERN_JOB_DONE, [buzzerAction]);
return true;
}
@ -382,9 +394,9 @@ namespace MECF.Framework.Common.Device.Bases
}
/// <summary>
/// 合并信号事件
/// 获取优先级更高的STAction
/// <remarks>
/// 根据<see cref="STEventAction.Status"/>的优先级决定执行的动作。
/// 根据<see cref="STAction.Output"/>的优先级决定执行的动作。
/// <br/>
/// 此属性的数值越小,表示优先级越高。
/// </remarks>
@ -392,7 +404,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <param name="currentAction">当前输出状态。</param>
/// <param name="nextAction">期望的输出状态。</param>
/// <returns>合并后的信号灯输出状态。</returns>
private STEventAction MergeAction(STEventAction currentAction, STEventAction nextAction)
private STAction PickPriorAction(STAction currentAction, STAction nextAction)
{
if (currentAction == null)
return nextAction;
@ -400,14 +412,14 @@ namespace MECF.Framework.Common.Device.Bases
return currentAction;
// 获取当前动作的优先级
var curPrior = currentAction.Status == TowerLightStatus.Customized
var curPrior = currentAction.Output == SignalTowerActions.Customized
? currentAction.BlinkPattern.Priority
: (int)currentAction.Status;
: (int)currentAction.Output;
// 获取下一个动作的优先级
var nextPrior = nextAction.Status == TowerLightStatus.Customized
var nextPrior = nextAction.Output == SignalTowerActions.Customized
? nextAction.BlinkPattern.Priority
: (int)nextAction.Status;
: (int)nextAction.Output;
return curPrior < nextPrior ? currentAction : nextAction;
@ -418,102 +430,113 @@ namespace MECF.Framework.Common.Device.Bases
/// </summary>
/// <param name="light"></param>
/// <returns></returns>
private bool GetSignalTowerPartValue(LightType light)
private bool GetSignalTowerPartValue(STLightTypes light)
{
if (_dicStParts.TryGetValue(light, out var part))
if (_dictStLights.TryGetValue(light, out var part))
return part.GetValue();
return false;
}
/// <summary>
/// 获取RT中已触发的事件列表。
/// 从RT拉取已发生的STEvent列表。
/// </summary>
/// <returns></returns>
private static DicEventActions PollRtAlarms(DicEventActions dicEvents)
private static DictEvent PollRaisedEvents(DictEvent dicEvents)
{
if (dicEvents == null)
return new DicEventActions();
return new();
var data = dicEvents.Keys.ToList();
var polled = DATA.PollData(data);
var events = dicEvents.Keys.ToList();
var data = DATA.PollData(events);
var raisedEvents = data.Where(x => x.Value is true).Select(x => x.Key).ToList();
var eventTriggered = polled.Where(x => x.Value is true).Select(x => x.Key).ToList();
return dicEvents.Where(x => eventTriggered.Contains(x.Key)).ToDictionary(x => x.Key, v => v.Value);
return dicEvents.Where(x => raisedEvents.Contains(x.Key)).ToDictionary(x => x.Key, v => v.Value);
}
/// <summary>
/// 更具RT当前状态合并所有事件的动作决定信号塔组件的输出状态
/// 监视STEvent.xml中定义的事件
/// </summary>
/// <param name="dicEvents">事件字典。</param>
/// <param name="eventsWithBuzzerOn">返回需要触发Buzzer的事件的名称列表。</param>
/// <param name="initActions">信号塔组件初始动作字典。</param>
/// <param name="isPollDataNeeded">
/// 是否从RT拉去事件对应的属性值。
/// <remarks>
/// 对于<see cref="_dicRtGeneratedStEvents"/>事件列表不需要从RT拉去数据直接合并动作即可。
/// </remarks>
/// </param>
/// <returns></returns>
private DicLightActions ConvertEventsToActions(DicEventActions dicEvents, out List<string> eventsWithBuzzerOn, DicLightActions initActions = null, bool isPollDataNeeded = true)
/// <param name="eventsWithBuzzerOn"></param>
private void MonitorEvents(out IEnumerable<string> eventsWithBuzzerOn)
{
// 创建初始动作字典
initActions ??= _dicStParts.ToDictionary(
x => x.Key,
v => new STEventAction("", v.Value, TowerLightStatus.Off));
// 对于STEvent配置文件中的事件我们只需要关注那些条件为True的事件。
// 创建一个临时字典筛选条件为True的事件或直接使用_dicRtGeneratedEvents事件字典。
var dicEventsTmp = dicEvents;
// 需要从RT拉取事件状态
if (isPollDataNeeded)
dicEventsTmp = PollRtAlarms(dicEvents);
// 保存触发的事件名称列表。
var eventsBuzzerNotOff = dicEventsTmp
.Where(x => x.Value
.Any(v => v.StPart.IsBuzzer && v.Status != TowerLightStatus.Off))
.Select(x => x.Key);
eventsWithBuzzerOn = new List<string>(eventsBuzzerNotOff);
// 遍历所有预设的事件,决定信号塔各元件的输出状态。
foreach (var stEvent in dicEventsTmp)
lock (SyncRoot)
{
foreach (var newAction in stEvent.Value)
// Clear previous actions
_dictSTLightActions.Clear();
// Poll raised events of RT
var raisedEvents = PollRaisedEvents(_dictPreDefinedEvents);
// Create dictionary '_dictSTLightActions'
AssignSTActions(raisedEvents);
AssignSTActions(_dictDynamicSTLightActions);
// Get a list of events related to turning on a buzzer
var buzzerOnEv1 = GetBuzzerOnEvents(raisedEvents).ToArray();
var buzzerOnEv2 = GetBuzzerOnEvents(_dictDynamicSTLightActions).ToArray();
eventsWithBuzzerOn = buzzerOnEv1.Concat(buzzerOnEv2.Except(buzzerOnEv1));
}
}
/// <summary>
/// 根据已发生的STEvent分配各个信号灯的动作。
/// </summary>
/// <param name="raisedEvents"></param>
private void AssignSTActions(DictEvent raisedEvents)
{
foreach (var stEvent in raisedEvents)
{
foreach (var action in stEvent.Value)
{
if (!_dicStParts.TryGetValue(newAction.StPart.Light, out var stPart))
// Maybe the target light of the action is not defined
if (!_dictStLights.ContainsKey(action.LightType))
continue;
// 根据当前设备状态,判断下一步信号组件的输出动作是什么
var mergedAction = MergeAction(initActions[stPart.Light], newAction);
// Make it easier to access dictionaries using the key
var light = action.LightType;
initActions[stPart.Light] = mergedAction;
// Determine the action of light according to the event raised
if (!_dictSTLightActions.TryGetValue(light, out var oldAction))
_dictSTLightActions.Add(light, action);
else
_dictSTLightActions[light] = PickPriorAction(oldAction, action);
}
}
return initActions;
}
/// <summary>
/// 创建一个自定义的RT事件以驱动指定的信号塔组件。
/// 获取需要打开Buzzer的事件的名称。
/// </summary>
/// <param name="events"></param>
/// <returns></returns>
private IEnumerable<string> GetBuzzerOnEvents(DictEvent events)
{
// create a list for the events operating the buzzer
var buzzerOnEvents = events
.Where(x => x.Value
.Any(v => v.Light.IsBuzzer && v.Output != SignalTowerActions.Off))
.Select(x => x.Key);
return buzzerOnEvents;
}
/// <summary>
/// 创建一个动态RT事件以驱动指定的信号塔组件。
/// <remarks>
/// 自动创建Guid作为事件的Key以和STEvent配置字典的格式保持一致以为Monitor方法中需要同时对这两个字典处理格式的统一有助于统一处理任务的逻辑。
/// </remarks>
/// </summary>
/// <param name="eventName"></param>
/// <param name="actions">该事件执行的动作列表。
/// <remarks>
/// 列表的每一个元素对应一个信号塔组件需执行的动作。
/// </remarks>
/// </param>
private void CreateRtEvent(params STEventAction[] actions)
private void CreateDynamicEvent(string eventName, List<STAction> actions)
{
_dicRtGeneratedStEvents.Add(Guid.NewGuid().ToString(), actions.ToList());
SwitchOffBuzzer(false);
_dictDynamicSTLightActions[eventName] = actions;
}
#endregion

View File

@ -5,19 +5,18 @@ using Aitex.Core.RT.Device;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using SciChart.Charting2D.Interop;
using BlinkDataType = System.Collections.Generic.KeyValuePair<MECF.Framework.Common.Device.Bases.TowerLightStatus, uint>;
using BlinkDataType = System.Collections.Generic.KeyValuePair<MECF.Framework.Common.Device.Bases.SignalTowerActions, uint>;
namespace MECF.Framework.Common.Device.Bases
{
/// <summary>
/// 信号塔元件对象,包含灯和蜂鸣器。
/// 受支持的元件请参考<see cref="LightType"/>。
/// 受支持的元件请参考<see cref="STLightTypes"/>。
/// <remarks>
/// 信号塔元件的Blink模式基于一个简单的Switch-Case状态机实现。
/// </remarks>
/// </summary>
public class SignalTowerPartBase : BaseDevice, IDevice
public class SignalTowerLightBase : BaseDevice, IDevice
{
#region Variables
@ -36,8 +35,8 @@ namespace MECF.Framework.Common.Device.Bases
private DOAccessor _doLight;
private AOAccessor _aoBlinkFreqHz;
private readonly LightType _lightType;
private STEventAction _action;
private readonly STLightTypes _lightType;
private STAction _action;
/// <summary>
/// 闪烁次数计数器。
@ -62,10 +61,10 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 构建信号塔元件对象的实例。
/// </summary>
/// <param name="light">信号塔元件类型,请参考<see cref="LightType"/>。</param>
/// <param name="light">信号塔元件类型,请参考<see cref="STLightTypes"/>。</param>
/// <param name="doSwitch">控制元件开关的DO。</param>
/// <param name="aoBlinkFreq">控制Blink频率的AO。</param>
public SignalTowerPartBase(LightType light, DOAccessor doSwitch, AOAccessor aoBlinkFreq)
public SignalTowerLightBase(STLightTypes light, DOAccessor doSwitch, AOAccessor aoBlinkFreq)
{
_lightType = light;
_doLight = doSwitch;
@ -82,7 +81,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 返回信号塔元件类型。
/// </summary>
public LightType Light => _lightType;
public STLightTypes Type => _lightType;
/// <summary>
@ -117,13 +116,13 @@ namespace MECF.Framework.Common.Device.Bases
return;
// 如果信号塔元件的状态已经转为Off但状态机没有进入Idle说明可能人为取消了信号需要复位状态机。
if (_action.Status == TowerLightStatus.Off && _blinkStage != FsmStateBlink.Idle)
if (_action.Output == SignalTowerActions.Off && _blinkStage != FsmStateBlink.Idle)
{
Reset();
}
// 如果动作状态指定使用自定义模式并且循环次数未用完则根据Pattern进行闪烁
if (_action.Status == TowerLightStatus.Customized && _blinkCycleDownCounter > 0)
if (_action.Output == SignalTowerActions.Customized && _blinkCycleDownCounter > 0)
{
switch (_blinkStage)
{
@ -155,9 +154,9 @@ namespace MECF.Framework.Common.Device.Bases
_nextBlinkData = _qBlinkData.Dequeue();
if (_nextBlinkData.Key == TowerLightStatus.On)
if (_nextBlinkData.Key == SignalTowerActions.On)
_blinkStage = FsmStateBlink.PrepareOn;
else if (_nextBlinkData.Key == TowerLightStatus.Off)
else if (_nextBlinkData.Key == SignalTowerActions.Off)
_blinkStage = FsmStateBlink.PrepareOff;
else
{
@ -213,8 +212,9 @@ namespace MECF.Framework.Common.Device.Bases
{
// Blink循环结束关闭输出
_doLight.Value = false;
_action.Status = TowerLightStatus.Off;
_action.Output = SignalTowerActions.Off;
_blinkStage = FsmStateBlink.Cleanup;
_action.IsCycleDone = true;
}
else
{
@ -245,7 +245,7 @@ namespace MECF.Framework.Common.Device.Bases
/// 获取信号塔元件当前正在执行的动作。
/// </summary>
/// <returns></returns>
public STEventAction GetAction()
public STAction GetAction()
{
return _action;
}
@ -261,10 +261,10 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 设置信号塔元件动作。
/// <para>请参考<see cref="TowerLightStatus"/>枚举获取支持的动作类型。</para>
/// <para>请参考<see cref="SignalTowerActions"/>枚举获取支持的动作类型。</para>
/// </summary>
/// <param name="action">信号灯的动作。</param>
public void SetAction(STEventAction action)
public void SetAction(STAction action)
{
if (action == null)
{
@ -288,20 +288,20 @@ namespace MECF.Framework.Common.Device.Bases
}
// 执行动作
switch (_action.Status)
switch (_action.Output)
{
case TowerLightStatus.On:
case SignalTowerActions.On:
_blinkCycleDownCounter = 0;
_doLight.Value = true;
break;
case TowerLightStatus.Off:
case SignalTowerActions.Off:
_blinkCycleDownCounter = 0;
_doLight.Value = false;
Reset(); // 复位状态机
break;
case TowerLightStatus.Customized:
case SignalTowerActions.Customized:
// 当工作在闪烁状态时,如果没有指定闪烁模式,则创建一个默认模式。
_blinkPattern = _action.BlinkPattern;
_blinkPattern ??= new STBlinkPattern();
@ -320,7 +320,7 @@ namespace MECF.Framework.Common.Device.Bases
if (!STBlinkPattern.GetBlinkData(_blinkPattern, out _blinkData, out var reason))
{
// 如果解析闪烁数据,如果解析错误,使用默认的闪烁模式。
LOG.Error($"Unable to set {Light} to {action}, {reason}");
LOG.Error($"Unable to set {Type} to {action}, {reason}");
STBlinkPattern.GetBlinkData(STBlinkPattern.GetDefaultPattern(), out _blinkData, out _);
Debug.Assert(_blinkData != null);
}
@ -332,8 +332,8 @@ namespace MECF.Framework.Common.Device.Bases
break;
case TowerLightStatus.Unknown:
LOG.Error($"{Light} Undefined output status");
case SignalTowerActions.Unknown:
LOG.Error($"{Type} Undefined output status");
break;
default:
@ -350,7 +350,7 @@ namespace MECF.Framework.Common.Device.Bases
_blinkStage = FsmStateBlink.Idle;
if (_action != null)
_action.Status = TowerLightStatus.Off;
_action.Output = SignalTowerActions.Off;
_blinkCycleDownCounter = 0;
_doLight.Value = false;

View File

@ -18,7 +18,7 @@ namespace MECF.Framework.Common.OperationCenter
[ServiceKnownType(typeof(WaferStatus))]
[ServiceKnownType(typeof(TransferInfo[]))]
[ServiceKnownType(typeof(TransferInfo))]
[ServiceKnownType(typeof(TowerLightStatus))]
[ServiceKnownType(typeof(SignalTowerActions))]
[ServiceKnownType(typeof(short[]))]
[ServiceKnownType(typeof(bool[]))]
[ServiceKnownType(typeof(string[]))]

View File

@ -5,20 +5,20 @@ namespace MECF.Framework.RT.EquipmentLibrary.Devices
{
/// <summary>
/// 信号塔元件对象,包含灯和蜂鸣器。
/// 受支持的元件请参考<see cref="LightType"/>。
/// 受支持的元件请参考<see cref="STLightTypes"/>。
/// <remarks>
/// 信号塔元件的Blink模式基于一个简单的Switch-Case状态机实现。
/// </remarks>
/// </summary>
public class IoSignalTowerPart : SignalTowerPartBase
public class IoSignalTowerLight : SignalTowerLightBase
{
/// <summary>
/// 构造IoSignalTowerPart对象。
/// </summary>
/// <param name="light">信号塔元件类型,请参考<see cref="LightType"/>。</param>
/// <param name="light">信号塔元件类型,请参考<see cref="STLightTypes"/>。</param>
/// <param name="doSw">控制元件开关的DO。</param>
/// <param name="aoBlinkFreq">控制Blink频率的AO。</param>
public IoSignalTowerPart(LightType light, DOAccessor doSw, AOAccessor aoBlinkFreq)
public IoSignalTowerLight(STLightTypes light, DOAccessor doSw, AOAccessor aoBlinkFreq)
: base(light, doSw, aoBlinkFreq)
{

View File

@ -77,7 +77,7 @@ namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems
bool MoveToReadyPut(ModuleName chamber, int slot, Hand hand, out string reason);
//signal tower
bool SetSignalLight(LightType type, TowerLightStatus state, out string reason);
bool SetSignalLight(STLightTypes type, SignalTowerActions state, out string reason);
[Obsolete]
bool SetLoadPortLight(ModuleName chamber, Indicator light, IndicatorState state);

View File

@ -421,7 +421,7 @@ namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes
return _connection.Execute(new RorzeEfemHandlerGoto(this, chamber, slot, hand, false), out reason);
}
public bool SetSignalLight(LightType type, TowerLightStatus state, out string reason)
public bool SetSignalLight(STLightTypes type, SignalTowerActions state, out string reason)
{
if (_connection == null || !_connection.IsConnected || !IsCommunicationReady)
{

View File

@ -752,7 +752,7 @@ namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes
MutexId = -1;
}
public RorzeEfemHandlerSigout(RorzeEfem device, ModuleName module, LightType type, TowerLightStatus state)
public RorzeEfemHandlerSigout(RorzeEfem device, ModuleName module, STLightTypes type, SignalTowerActions state)
: base(device, module, RorzeEfemMessageType.SET, RorzeEfemBasicMessage.SIGOUT, BuildParameter(module, type, state), false)
{
Name = $"Set Signal Tower";
@ -780,30 +780,30 @@ namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes
return $"{par1}/{par2}/{par3}";
}
public static string BuildParameter(ModuleName target, LightType type, TowerLightStatus state)
public static string BuildParameter(ModuleName target, STLightTypes type, SignalTowerActions state)
{
if (type == LightType.Buzzer)
if (type == STLightTypes.Buzzer)
{
type = state == TowerLightStatus.Customized ? LightType.Buzzer2 : LightType.Buzzer1;
state = state == TowerLightStatus.Off ? TowerLightStatus.Off : TowerLightStatus.On;
type = state == SignalTowerActions.Customized ? STLightTypes.Buzzer2 : STLightTypes.Buzzer1;
state = state == SignalTowerActions.Off ? SignalTowerActions.Off : SignalTowerActions.On;
}
Dictionary<LightType, string> mapLightType = new Dictionary<LightType, string>()
Dictionary<STLightTypes, string> mapLightType = new Dictionary<STLightTypes, string>()
{
{LightType.Red, "RED"},
{LightType.Yellow, "YELLOW"},
{LightType.Green, "GREEN"},
{LightType.Blue, "BLUE"},
{LightType.White, "WHITE"},
{LightType.Buzzer1, "BUZZER1"},
{LightType.Buzzer2, "BUZZER2"},
{STLightTypes.Red, "RED"},
{STLightTypes.Yellow, "YELLOW"},
{STLightTypes.Green, "GREEN"},
{STLightTypes.Blue, "BLUE"},
{STLightTypes.White, "WHITE"},
{STLightTypes.Buzzer1, "BUZZER1"},
{STLightTypes.Buzzer2, "BUZZER2"},
};
Dictionary<TowerLightStatus, string> mapLightState = new Dictionary<TowerLightStatus, string>()
Dictionary<SignalTowerActions, string> mapLightState = new Dictionary<SignalTowerActions, string>()
{
{TowerLightStatus.On, "ON"},
{TowerLightStatus.Off, "OFF"},
{TowerLightStatus.Customized, "BLINK"},
{SignalTowerActions.On, "ON"},
{SignalTowerActions.Off, "OFF"},
{SignalTowerActions.Customized, "BLINK"},
};
string par1 = "STOWER";

View File

@ -97,7 +97,7 @@
<Compile Include="Devices\IoSCR.cs" />
<Compile Include="Devices\IoCassette.cs" />
<Compile Include="Devices\IoSensor.cs" />
<Compile Include="Devices\IoSignalTowerPart.cs" />
<Compile Include="Devices\IoSignalTowerLight.cs" />
<Compile Include="Devices\IoSignalTower.cs" />
<Compile Include="Devices\IoTC.cs" />
<Compile Include="Devices\IoTempMeter.cs" />

View File

@ -23,7 +23,7 @@ namespace MECF.Framework.Common.Device.Bases.Tests
[Fact()]
public void ParseEventsTest()
{
var mockDictStParts = new Mock<Dictionary<LightType, SignalTowerPartBase>>();
var mockDictStParts = new Mock<Dictionary<STLightTypes, SignalTowerLightBase>>();
var stEvents = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(FN_STSETTINGS));
stEvents.ParseEvents(null, out var events);
Assert.NotNull(events);