重构了SignalTower相关的对象,支持在配置文件中配置工作模式模板。
This commit is contained in:
DESKTOP-1N1NK8A\auvkk 2023-05-06 16:57:09 +08:00
parent 0a357a6369
commit 0ea1607d64
14 changed files with 348 additions and 218 deletions

View File

@ -678,7 +678,7 @@
<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\SignalTowerPartAction.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\STEventAction.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\LidBase.cs" />
@ -694,6 +694,7 @@
<Compile Include="MECF\Framework\Common\Device\Bases\STBlinkPattern.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\STEvent.cs" />
<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\VCEBase.cs" />

View File

@ -25,10 +25,15 @@ public class STBlinkPattern : IComparable, ICloneable
/// <summary>
/// 模式字符串中每个字符对应的延时时长,单位毫秒。
/// </summary>
private const uint DELAY_MS_PER_CHAR = 100;
private const uint DELAY_MS_PER_CHAR = 100;
private const string PATTERN_FAST = "-----..";
private const string PATTERN_SLOW = "-----.......";
private const string PATTERN_JOB_DONE = "-----.......";
#endregion
#region Constructors
/// <summary>
@ -38,29 +43,32 @@ public class STBlinkPattern : IComparable, ICloneable
public STBlinkPattern()
{
TotalCycles = 0;
Pattern = "----------..........";
Pattern = PATTERN_SLOW;
}
/// <summary>
/// 创建信号灯塔元件闪烁模式对象的实例。
/// </summary>
/// <param name="cycle">总循环次数0或负值表示无限循环。</param>
/// <param name="pattern">
/// /// <param name="pattern">
/// 闪烁模式。
/// 请参考属性<see cref="Pattern"/>以或许模式的设置方法。
/// </param>
public STBlinkPattern(string pattern, uint cycle = uint.MaxValue)
/// <param name="priority">当前工作模式优先级。</param>
/// <param name="cycle">总循环次数0或负值表示无限循环。</param>
public STBlinkPattern(string pattern, int priority, int cycle = int.MaxValue)
{
Debug.Assert(!string.IsNullOrEmpty(pattern), "pattern can not be null");
TotalCycles = cycle;
Pattern = pattern;
Priority = priority;
IsPlcMode = false;
}
/// <summary>
/// 创建信号灯塔元件闪烁模式对象的实例。
/// </summary>
/// <param name="priority">当前工作模式优先级。</param>
/// <param name="cycle">总循环次数0或负值表示无限循环。</param>
/// <param name="frequencyHz">
/// PLC控制模式下的闪烁频率。
@ -68,11 +76,12 @@ public class STBlinkPattern : IComparable, ICloneable
/// <param name="fallbackPattern">
/// 如果PLC不支持设置闪烁频率则回落到此模式。
/// </param>
public STBlinkPattern(float frequencyHz, uint cycle = uint.MaxValue, string fallbackPattern = "-----.....")
public STBlinkPattern(float frequencyHz, int priority, int cycle = int.MaxValue, string fallbackPattern = PATTERN_SLOW)
{
TotalCycles = cycle;
Pattern = fallbackPattern;
FrequencyHz = frequencyHz;
Priority = priority;
IsPlcMode = true;
}
@ -93,7 +102,7 @@ public class STBlinkPattern : IComparable, ICloneable
/// 设置或返回总循环次数。
/// </summary>
[DataMember]
public uint TotalCycles { get; set; }
public int TotalCycles { get; set; }
/// <summary>
/// 设置或返回闪烁模式。
@ -111,6 +120,11 @@ public class STBlinkPattern : IComparable, ICloneable
/// 闪烁频率。
/// </summary>
public float FrequencyHz { get; set; }
/// <summary>
/// 当前工作模式的优先级。
/// </summary>
public int Priority { get; set; }
#endregion
@ -119,13 +133,14 @@ public class STBlinkPattern : IComparable, ICloneable
/// <summary>
/// 解析闪烁模式字串生成闪烁数据供M<see cref="SignalTowerPartBase"/>产生闪烁效果。
/// </summary>
/// <param name="pattern"></param>
/// <param name="blinkData">闪烁效果数据。</param>
/// <param name="reason">解析失败原因。</param>
/// <returns>
/// <value>True: 解析成功</value>
/// <value>False: 解析失败</value>
/// </returns>
public bool Parse(out List<BlinkDataType> blinkData, out string reason)
public static bool GetBlinkData(STBlinkPattern pattern, out List<BlinkDataType> blinkData, out string reason)
{
// var regex = new Regex(@"(([-\.])(\2*))");
@ -138,7 +153,7 @@ public class STBlinkPattern : IComparable, ICloneable
// Pattern分组正则
var regGroup = new Regex(@"([\-\.])\1*");
if (!regPatternFormat.IsMatch(Pattern))
if (!regPatternFormat.IsMatch(pattern.Pattern))
{
// 如果存在除-和.以外的字符则为非法Pattern字串。
reason = "pattern contains illegal characters";
@ -146,7 +161,7 @@ public class STBlinkPattern : IComparable, ICloneable
return false;
}
var matches = regGroup.Matches(Pattern);
var matches = regGroup.Matches(pattern.Pattern);
foreach (Match match in matches)
{
@ -205,8 +220,11 @@ public class STBlinkPattern : IComparable, ICloneable
if (obj is not STBlinkPattern target)
return -1;
return (target.IsPlcMode == IsPlcMode && target.TotalCycles == TotalCycles &&
Math.Abs(target.FrequencyHz - FrequencyHz) < 0.01 && target.Pattern == Pattern)
return (target.IsPlcMode == IsPlcMode
&& target.TotalCycles == TotalCycles
&& Math.Abs(target.FrequencyHz - FrequencyHz) < 0.01
&& target.Pattern == Pattern
&& target.Priority == Priority)
? 0
: -1;
}
@ -218,22 +236,11 @@ public class STBlinkPattern : IComparable, ICloneable
/// 开200ms关200ms无限循环。
/// </remarks>
/// <returns></returns>
public static STBlinkPattern GetFastBlinkPattern()
public static STBlinkPattern GetDefaultPattern()
{
return new STBlinkPattern("-----..");
return new STBlinkPattern(PATTERN_SLOW, (int)TowerLightStatus.Customized);
}
/// <summary>
/// 获取预设的慢速闪烁模式。
/// </summary>
/// <remarks>
/// 开1s关1s无限循环。
/// </remarks>
/// <returns></returns>
public static STBlinkPattern GetSlowBlinkPattern()
{
return new STBlinkPattern("-----.......");
}
/// <summary>
/// 获取预设的工艺完成闪烁模式。
@ -242,23 +249,10 @@ public class STBlinkPattern : IComparable, ICloneable
/// 以开200ms、关200ms方式连续闪烁3次然后关1s循环5次。
/// </remarks>
/// <returns></returns>
public static STBlinkPattern GetProcessDoneBlinkPattern()
public static STBlinkPattern GetJobDonePattern()
{
return new STBlinkPattern("--..........");
return new STBlinkPattern(PATTERN_JOB_DONE, -1);
}
public static STBlinkPattern ParseSTEvent(string pattern, uint cycle = int.MaxValue)
{
// 如果指定了闪烁模式字串则以软件方式生成Blink
if (Regex.IsMatch(pattern, REG_PATT_BLINK_PATTERN))
return new STBlinkPattern(pattern, cycle);
// 如果指定了闪烁频率数值则以PLC方式生成Blink
if(float.TryParse(pattern, out var freq))
return new STBlinkPattern(freq, cycle);
return GetFastBlinkPattern();
}
#endregion
}

View File

@ -39,5 +39,10 @@ namespace MECF.Framework.Common.Device.Bases
[XmlAttribute]
public string Buzzer5 { get; set; }
}
public override string ToString()
{
return Name;
}
}
}

View File

@ -5,7 +5,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 预设的信号灯塔元件动作。
/// </summary>
public class SignalTowerPartAction : IComparable, ICloneable
public class STEventAction : IComparable, ICloneable
{
/// <summary>
/// 信号灯塔元件动作构造函数。
@ -13,16 +13,13 @@ namespace MECF.Framework.Common.Device.Bases
/// <param name="light">信号灯类型。</param>
/// <param name="status">信号灯输出状态。</param>
/// <param name="blinkPattern">闪烁模式。如果传入空值,则自动调用
/// <see cref="STBlinkPattern.GetFastBlinkPattern()"/>以创建默认闪烁模式。</param>
public SignalTowerPartAction(LightType light, TowerLightStatus status, STBlinkPattern blinkPattern = null)
/// <see cref="STBlinkPattern.GetDefaultPattern"/>以创建默认闪烁模式。</param>
public STEventAction(LightType light, TowerLightStatus status, STBlinkPattern blinkPattern = null)
{
Light = light;
Status = status;
if(blinkPattern != null)
BlinkPattern = blinkPattern;
else
BlinkPattern = STBlinkPattern.GetFastBlinkPattern();
BlinkPattern = blinkPattern ?? STBlinkPattern.GetDefaultPattern();
}
/// <summary>
@ -43,29 +40,32 @@ namespace MECF.Framework.Common.Device.Bases
#region Methods
public bool DoAction(out string reason)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public int CompareTo(object obj)
{
if (obj is not SignalTowerPartAction target)
if (obj is not STEventAction target)
return -1;
return (BlinkPattern.CompareTo(target.BlinkPattern) == 0 && Status == target.Status && Light == target.Light) ? 0 : -1;
return (BlinkPattern.CompareTo(target.BlinkPattern) == 0
&& Status == target.Status
&& Light == target.Light)
? 0
: -1;
}
/// <inheritdoc />
public object Clone()
{
return new SignalTowerPartAction(Light, Status, (STBlinkPattern)BlinkPattern.Clone());
return new STEventAction(Light, Status, (STBlinkPattern)BlinkPattern.Clone());
}
/// <inheritdoc/>
public override string ToString()
{
return $"{Light}, {Status}";
}
#endregion
}
}

View File

@ -1,11 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
namespace MECF.Framework.Common.Device.Bases
{
public class STEvents
{
[XmlElement(ElementName = "STEvent")]
public List<STEvent> Events;
#region Properties
/// <summary>
/// 返回工作模式模板。
/// </summary>
[XmlArray("STPatterns")]
[XmlArrayItem("STPattern")]
public List<STPatternSetting> PatternsSettings { get; set; }
/// <summary>
/// 返回预定义的事件。
/// </summary>
[XmlArray("STEvents")]
public List<STEvent> Events { get; set; }
#endregion
#region Methods
/// <summary>
/// 解析配置文件中定义的事件。
/// </summary>
/// <param name="events">
/// 返回事件字典。
/// <remarks>
/// 事件字典的Key为事件名称名称为RT中注册的Bool型数据通过DATA.Poll访问。
/// <br/>
/// 事件动作为<see cref="STEventAction"/>动作列表表示当上述事件为True时指定的信号塔组件执行的动作。
/// </remarks>
/// </param>
public void ParseEvents(out Dictionary<string, List<STEventAction>> events)
{
events = new Dictionary<string, List<STEventAction>>();
foreach (var stEvent in Events)
{
// 如果相同的事件已经添加,则不再重复添加
if (events.ContainsKey(stEvent.Name))
continue;
// 字典中创建一个事件项目
events[stEvent.Name] = new List<STEventAction>();
// 解析当前事件执行的动作
foreach (LightType light in Enum.GetValues(typeof(LightType)))
{
var obj = stEvent.GetType().GetProperty(light.ToString())?.GetValue(stEvent);
if (obj != null)
{
var status = TowerLightStatus.Unknown;
STBlinkPattern blinkPattern = null;
var str = obj.ToString().ToLower();
if (str.Contains(TowerLightStatus.On.ToString().ToLower()))
{
status = TowerLightStatus.On;
}
else if (str.Contains(TowerLightStatus.Off.ToString().ToLower()))
{
status = TowerLightStatus.Off;
}
else
{
// 使用工作模式配置中的项目
var pattern = PatternsSettings.FirstOrDefault(x =>
string.Compare(x.Name, str, StringComparison.OrdinalIgnoreCase) == 0);
blinkPattern = pattern != null
? new STBlinkPattern(pattern.Pattern, pattern.Priority, pattern.Cycles)
: STBlinkPattern.GetDefaultPattern();
status = TowerLightStatus.Customized;
}
events[stEvent.Name].Add(new STEventAction(light, status, blinkPattern));
}
}
}
}
#endregion
}
}

View File

@ -0,0 +1,48 @@
using System.Xml.Serialization;
namespace MECF.Framework.Common.Device.Bases;
public class STPatternSetting
{
#region Properties
/// <summary>
/// 返回当前工作模式名称。
/// </summary>
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
/// <summary>
/// 返回当前工作模式配置模板。
/// </summary>
[XmlAttribute(AttributeName = "pattern")]
public string Pattern { get; set; }
/// <summary>
/// 返回当前工作模式的最大循环次数。
/// </summary>
[XmlAttribute(AttributeName = "cycles")]
public int Cycles { get; set; }
/// <summary>
/// 返回当前工作模式的优先级。
/// <remarks>
/// 数字越小优先级越高。当信号塔动作合并时,优先级高的动作会覆盖优先级底的动作。
/// </remarks>
/// </summary>
[XmlAttribute(AttributeName = "priority")]
public int Priority { get; set; }
#endregion
#region Methods
/// <inheritdoc />
public override string ToString()
{
return $"{Name}, {Pattern}";
}
#endregion
}

View File

@ -11,7 +11,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
namespace MECF.Framework.Common.Device.Bases
@ -33,7 +32,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 信号塔事件字典,从配置文件中读取。
/// </summary>
private Dictionary<string, List<SignalTowerPartAction>> _signalTowerEvent;
private Dictionary<string, List<STEventAction>> _signalTowerEvent;
/// <summary>
/// 信号塔中组件字典。
@ -43,7 +42,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 信号塔组件动作字典。
/// </summary>
private Dictionary<LightType, SignalTowerPartAction> _dicMergedActions;
private Dictionary<LightType, STEventAction> _dicMergedActions;
#endregion
@ -139,6 +138,11 @@ namespace MECF.Framework.Common.Device.Bases
_dicStParts.Add(light, new SignalTowerPartBase(light, doSw, aoBlinkFreq));
}
/// <summary>
/// 从指定的配置文件中解析信号塔事件。
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private bool ParseSignalTowerEvent(string fileName)
{
try
@ -151,79 +155,12 @@ namespace MECF.Framework.Common.Device.Bases
}
var stEvents = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(cFileName));
_signalTowerEvent = new Dictionary<string, List<SignalTowerPartAction>>();
stEvents.ParseEvents(out var events);
if (events == null)
LOG.Error("Unable to parse the signal tower events from config file.");
// Blinking配置字符串规则
// 1、Blinking
// 2、Blinking,---..
// 3、Blinking,0.5
// 在线校验https://regex101.com/r/CescBw/1
var regxBlinkPatternString =
new Regex(
@"^(([bB]linking){1}(,{1})(?(2)([-\.]+)$))|(([bB]linking){1}(,{1})(?(6)(\d+\.?\d*)$))|([bB]linking){1}$");
foreach (var stEvent in stEvents.Events)
{
if (!_signalTowerEvent.ContainsKey(stEvent.Name))
{
_signalTowerEvent[stEvent.Name] = new List<SignalTowerPartAction>();
foreach (LightType type in Enum.GetValues(typeof(LightType)))
{
if (!_dicStParts.ContainsKey(type))
continue;
var obj = stEvent.GetType().GetProperty(type.ToString())?.GetValue(stEvent);
if (obj != null)
{
TowerLightStatus status = TowerLightStatus.Unknown;
STBlinkPattern blinkPattern = null;
var str = obj.ToString().ToLower();
if (str.Contains("on"))
{
status = TowerLightStatus.On;
}
else if (str.Contains("off"))
{
status = TowerLightStatus.Off;
}
else if (str.Contains("warning"))
{
status = TowerLightStatus.Warning;
blinkPattern = STBlinkPattern.GetSlowBlinkPattern();
}
else if (str.Contains("alarm"))
{
status = TowerLightStatus.Alarm;
blinkPattern = STBlinkPattern.GetFastBlinkPattern();
}
else if(str.StartsWith(TowerLightStatus.Blinking.ToString().ToLower()))
{
// 如果配置为闪烁方式检查配置中是否包含BlinkPattern字串
var matches = regxBlinkPatternString.Match(str);
if (matches.Success)
{
if (matches.Groups[9].Success) // Blinking
blinkPattern = STBlinkPattern.GetSlowBlinkPattern();
else if (matches.Groups[6].Success) // Blinking,00.0
blinkPattern = STBlinkPattern.ParseSTEvent(matches.Groups[8].Value);
else if (matches.Groups[2].Success) // Blinking,--.-
blinkPattern = STBlinkPattern.ParseSTEvent(matches.Groups[4].Value);
else
blinkPattern = STBlinkPattern.GetFastBlinkPattern();
}
status = TowerLightStatus.Blinking;
}
_signalTowerEvent[stEvent.Name].Add(new SignalTowerPartAction(type, status, blinkPattern));
}
}
}
}
return true;
_signalTowerEvent = events;
return _signalTowerEvent != null;
}
catch (Exception ex)
{
@ -231,7 +168,7 @@ namespace MECF.Framework.Common.Device.Bases
return false;
}
}
/// <summary>
/// 初始化信号塔对象实例。
/// </summary>
@ -299,7 +236,7 @@ namespace MECF.Framework.Common.Device.Bases
foreach (var action in _dicMergedActions)
{
// 创建一个动作副本,解决蜂鸣器被手动关闭后无法启用的问题
var clonedAction = (SignalTowerPartAction)action.Value?.Clone();
var clonedAction = (STEventAction)action.Value?.Clone();
if(clonedAction == null)
continue;
@ -334,7 +271,7 @@ namespace MECF.Framework.Common.Device.Bases
{
// 强制使能蜂鸣器
_switchBuzzerOff = false;
lightInstance.SetAction(new SignalTowerPartAction(lightInstance.Light, TowerLightStatus.Blinking,
lightInstance.SetAction(new STEventAction(lightInstance.Light, TowerLightStatus.Customized,
pattern));
return true;
}
@ -369,7 +306,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <summary>
/// 合并信号事件。
/// <remarks>
/// 根据<see cref="SignalTowerPartAction.Status"/>的优先级决定执行的动作。
/// 根据<see cref="STEventAction.Status"/>的优先级决定执行的动作。
/// <br/>
/// 此属性的数值越小,表示优先级越高。
/// </remarks>
@ -377,13 +314,25 @@ namespace MECF.Framework.Common.Device.Bases
/// <param name="currentAction">当前输出状态。</param>
/// <param name="nextAction">期望的输出状态。</param>
/// <returns>合并后的信号灯输出状态。</returns>
private SignalTowerPartAction MergeAction(SignalTowerPartAction currentAction, SignalTowerPartAction nextAction)
private STEventAction MergeAction(STEventAction currentAction, STEventAction nextAction)
{
if (currentAction == null)
return nextAction;
if (nextAction == null)
return currentAction;
return (int)currentAction.Status < (int)nextAction.Status ? currentAction : nextAction;
// 获取当前动作的优先级
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;
}
/// <summary>
@ -402,4 +351,7 @@ namespace MECF.Framework.Common.Device.Bases
#endregion
}
}

View File

@ -36,13 +36,13 @@ namespace MECF.Framework.Common.Device.Bases
private DOAccessor _doLight;
private AOAccessor _aoBlinkFreqHz;
private readonly LightType _lightType;
private SignalTowerPartAction _action;
private STEventAction _action;
/// <summary>
/// 闪烁次数计数器。
/// <remarks>当该计数器归零时,结束闪烁。</remarks>
/// </summary>
private uint _blinkCycleDownCounter;
private int _blinkCycleDownCounter;
private STBlinkPattern _blinkPattern;
private List<BlinkDataType> _blinkData;
@ -115,9 +115,8 @@ namespace MECF.Framework.Common.Device.Bases
Reset();
}
if (_blinkCycleDownCounter > 0
&& (_action.Status == TowerLightStatus.Blinking || _action.Status == TowerLightStatus.Alarm ||
_action.Status == TowerLightStatus.Warning))
// 如果动作状态指定使用自定义模式并且循环次数未用完则根据Pattern进行闪烁
if (_action.Status == TowerLightStatus.Customized && _blinkCycleDownCounter > 0)
{
switch (_blinkStage)
{
@ -230,7 +229,7 @@ namespace MECF.Framework.Common.Device.Bases
/// 获取信号塔元件当前正在执行的动作。
/// </summary>
/// <returns></returns>
public SignalTowerPartAction GetAction()
public STEventAction GetAction()
{
return _action;
}
@ -249,7 +248,7 @@ namespace MECF.Framework.Common.Device.Bases
/// <para>请参考<see cref="TowerLightStatus"/>枚举获取支持的动作类型。</para>
/// </summary>
/// <param name="action">信号灯的动作。</param>
public void SetAction(SignalTowerPartAction action)
public void SetAction(STEventAction action)
{
if (action == null)
{
@ -286,9 +285,7 @@ namespace MECF.Framework.Common.Device.Bases
Reset(); // 复位状态机
break;
case TowerLightStatus.Alarm:
case TowerLightStatus.Warning:
case TowerLightStatus.Blinking:
case TowerLightStatus.Customized:
// 当工作在闪烁状态时,如果没有指定闪烁模式,则创建一个默认模式。
_blinkPattern = _action.BlinkPattern;
_blinkPattern ??= new STBlinkPattern();
@ -297,23 +294,25 @@ namespace MECF.Framework.Common.Device.Bases
if (_blinkPattern.IsPlcMode && _aoBlinkFreqHz != null)
{
_aoBlinkFreqHz.FloatValue = _blinkPattern.FrequencyHz;
break;
}
// 当循环次数小于等于0时无限循环。
_blinkCycleDownCounter = _blinkPattern.TotalCycles <= 0 ? int.MaxValue : _blinkPattern.TotalCycles;
// 解析闪烁模式数据。
if (!_blinkPattern.Parse(out _blinkData, out var reason))
else
{
// 如果闪烁模式解析错误,则常亮
LOG.Error($"Unable to set {Light} to {action}, {reason}");
_blinkData = new List<BlinkDataType>(new[] { new BlinkDataType(TowerLightStatus.On, 100) });
}
// 当循环次数小于等于0时无限循环。
_blinkCycleDownCounter = _blinkPattern.TotalCycles <= 0 ? int.MaxValue : _blinkPattern.TotalCycles;
// 使能状态机
//! 注意:此步需放在最后,因为状态机异步使能,相关数据可能还未准备好
_blinkStage = FsmStateBlink.Init;
// 解析闪烁模式数据。
if (!STBlinkPattern.GetBlinkData(_blinkPattern, out _blinkData, out var reason))
{
// 如果解析闪烁数据,如果解析错误,使用默认的闪烁模式。
LOG.Error($"Unable to set {Light} to {action}, {reason}");
STBlinkPattern.GetBlinkData(STBlinkPattern.GetDefaultPattern(), out _blinkData, out _);
Debug.Assert(_blinkData != null);
}
// 使能状态机
//! 注意:此步需放在最后,因为状态机异步使能,相关数据可能还未准备好
_blinkStage = FsmStateBlink.Init;
}
break;

View File

@ -3,49 +3,33 @@ using System.Runtime.Serialization;
namespace MECF.Framework.Common.Device.Bases
{
/// <summary>
/// 信号灯塔的控制状态枚举。
/// <br/>
/// 该枚举同时决定信号塔状态合并时的优先级,值越小优先级越高。
/// </summary>
[Serializable]
[DataContract]
public enum TowerLightStatus
{
/// <summary>
/// 预置的报警闪烁状态。
/// </summary>
[EnumMember]
Alarm,
/// <summary>
/// 预置的警告闪烁状态。
/// </summary>
[EnumMember]
Warning,
/// <summary>
/// 人工配置的闪烁状态
/// </summary>
[EnumMember]
Blinking,
/// <summary>
/// 打开,灯亮或蜂鸣器响
/// </summary>
[EnumMember]
On,
/// <summary>
/// 关闭
/// </summary>
[EnumMember]
Off,
/// <summary>
/// 未知状态
/// </summary>
[EnumMember]
Unknown
}
/// <summary>
/// 信号灯塔的控制状态枚举。
/// <br/>
/// 该枚举同时决定信号塔状态合并时的优先级,值越小优先级越高。
/// </summary>
[Serializable]
[DataContract]
public enum TowerLightStatus
{
/// <summary>
/// 使用STEvents配置文件中配置的工作模式模板
/// </summary>
[EnumMember] Customized = int.MaxValue - 3,
/// <summary>
/// 打开,灯亮或蜂鸣器响
/// </summary>
[EnumMember] On = int.MaxValue - 2,
/// <summary>
/// 关闭
/// </summary>
[EnumMember] Off = int.MaxValue - 1,
/// <summary>
/// 未知状态
/// </summary>
[EnumMember] Unknown = int.MaxValue,
}
}

View File

@ -8,7 +8,7 @@ namespace MECF.Framework.Common.Device.Bases.Tests
public void ParseTest1()
{
var pattern = new STBlinkPattern("-----.....", 5);
var ret = pattern.Parse(out var blinkData, out var reason);
var ret = STBlinkPattern.GetBlinkData(pattern, out var blinkData, out var reason);
Assert.True(ret);
Assert.True(blinkData.Count == 2);
Assert.True(blinkData[0].Key == TowerLightStatus.On);
@ -21,7 +21,7 @@ namespace MECF.Framework.Common.Device.Bases.Tests
public void ParseTest2()
{
var pattern = new STBlinkPattern("..---...----", 5);
var ret = pattern.Parse(out var blinkData, out var reason);
var ret = STBlinkPattern.GetBlinkData(pattern, out var blinkData, out var reason);
Assert.True(ret);
Assert.True(blinkData.Count == 4);
Assert.True(blinkData[0].Key == TowerLightStatus.Off);
@ -38,7 +38,7 @@ namespace MECF.Framework.Common.Device.Bases.Tests
public void ParseIllegalCharTest()
{
var pattern = new STBlinkPattern("..---...1----", 5);
var ret = pattern.Parse(out var blinkData, out var reason);
var ret = STBlinkPattern.GetBlinkData(pattern, out var blinkData, out var reason);
Assert.False(ret);
Assert.True(reason == "pattern contains illegal characters");

View File

@ -784,7 +784,7 @@ namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes
{
if (type == LightType.Buzzer)
{
type = state == TowerLightStatus.Blinking ? LightType.Buzzer2 : LightType.Buzzer1;
type = state == TowerLightStatus.Customized ? LightType.Buzzer2 : LightType.Buzzer1;
state = state == TowerLightStatus.Off ? TowerLightStatus.Off : TowerLightStatus.On;
}
@ -803,7 +803,7 @@ namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes
{
{TowerLightStatus.On, "ON"},
{TowerLightStatus.Off, "OFF"},
{TowerLightStatus.Blinking, "BLINK"},
{TowerLightStatus.Customized, "BLINK"},
};
string par1 = "STOWER";

View File

@ -69,6 +69,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Aitex\Core\RT\IOCore\Interlock\InterlockManagerTests.cs" />
<Compile Include="MECF\Framework\Common\Device\Bases\STEventsTests.cs" />
<Compile Include="MECF\Framework\Common\SicMath\TimeDomainArithmeticMeanFilterTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
@ -92,6 +93,9 @@
<Content Include="SupportFiles\IoProviderConfig.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="SupportFiles\SignalTowerSettings.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="SupportFiles\_ioDefinePM1.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View File

@ -0,0 +1,29 @@
using Aitex.Core.Util;
using MECF.Framework.Common.Device.Bases;
using System.IO;
using Xunit;
namespace MECF.Framework.Common.Device.Bases.Tests
{
public class STEventsTests
{
private const string FN_STSETTINGS = "SupportFiles\\SignalTowerSettings.xml";
[Fact]
public void LoadXmlFileTest()
{
var stEvents = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(FN_STSETTINGS));
Assert.NotNull(stEvents);
Assert.True(stEvents.Events.Count > 0);
Assert.True(stEvents.PatternsSettings.Count > 0);
}
[Fact()]
public void ParseEventsTest()
{
var stEvents = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(FN_STSETTINGS));
stEvents.ParseEvents(out var events);
Assert.NotNull(events);
}
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<STEvents>
<STPatterns>
<!--注意:"JobDone"为系统保留模式,请仅更改"pattern",其余属性请勿修改 -->
<STPattern name="JobDone" pattern="--.........." cycles="-1" priority="-1" />
<STPattern name="Alarm" pattern="-----.." cycles="-1" priority="0"/>
<STPattern name="Warning" pattern="-----......." cycles="-1" priority="5"/>
<STPattern name="Blink" pattern="----------.........." cycles="-1" priority="10"/>
</STPatterns>
<STEvents>
<STEvent name ="PM1.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="TM.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="LoadLock.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="UnLoad.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="Aligner.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="WaferRobot.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="TrayRobot.IsAlarm" Red="On" Yellow="Off" Green="Off" Buzzer="Alarm"/>
<STEvent name ="PM1.IsWarning" Red="Off" Yellow="On" Green="Off" Buzzer="Warning"/>
<STEvent name ="TM.IsWarning" Red="Off" Yellow="On" Green="Off" Buzzer="Warning"/>
<STEvent name ="PM1.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="TM.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="LoadLock.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="UnLoad.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="Aligner.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="WaferRobot.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="TrayRobot.IsBusy" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
<STEvent name ="System.IsAutoRunning" Red="Off" Yellow="Off" Green="On" Buzzer="Off"/>
</STEvents>
</STEvents>