Sic.Framework/MECF.Framework.Common/MECF/Framework/Common/Device/Bases/STBlinkPattern.cs

258 lines
7.8 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
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>;
namespace MECF.Framework.Common.Device.Bases;
/// <summary>
/// 信号灯塔元件闪烁模式。
/// </summary>
[Serializable]
[DataContract]
public class STBlinkPattern : IComparable, ICloneable
{
#region Variables
/// <summary>
/// 以-或.配置闪烁模式的字串正则表达式。
/// </summary>
public const string REG_PATT_BLINK_PATTERN = @"^([-\.])+$";
/// <summary>
/// 模式字符串中每个字符对应的延时时长,单位毫秒。
/// </summary>
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>
/// 构造信号灯元件闪烁模式。
/// <para>如果未指定闪烁模式,则默认开一秒,关一秒,无限循环。</para>
/// </summary>
public STBlinkPattern()
{
TotalCycles = 0;
Pattern = PATTERN_SLOW;
}
/// <summary>
/// 创建信号灯塔元件闪烁模式对象的实例。
/// </summary>
/// /// <param name="pattern">
/// 闪烁模式。
/// 请参考属性<see cref="Pattern"/>以或许模式的设置方法。
/// </param>
/// <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控制模式下的闪烁频率。
/// </param>
/// <param name="fallbackPattern">
/// 如果PLC不支持设置闪烁频率则回落到此模式。
/// </param>
public STBlinkPattern(float frequencyHz, int priority, int cycle = int.MaxValue, string fallbackPattern = PATTERN_SLOW)
{
TotalCycles = cycle;
Pattern = fallbackPattern;
FrequencyHz = frequencyHz;
Priority = priority;
IsPlcMode = true;
}
#endregion
#region Properties
/// <summary>
/// 返回是否为PLC控制模式。
/// <br/>
/// <remarks>PLC模式指闪烁效果有PLC控制以提供更精确的控制效果。</remarks>
/// </summary>
public bool IsPlcMode { get; }
/// <summary>
/// 设置或返回总循环次数。
/// </summary>
[DataMember]
public int TotalCycles { get; set; }
/// <summary>
/// 设置或返回闪烁模式。
/// <remarks>
/// 闪烁模式以字符串形式表达,表达式中仅允许包含字符’-‘(英文减号)和’.‘(英文句号)。
/// 其中<value>-</value>表示开100ms<value>.</value>表示关100ms。
/// <br/>
/// 通过'-'和‘.‘的组合,可描述不同的闪烁模式。
/// </remarks>
/// </summary>
[DataMember]
public string Pattern { get; set; }
/// <summary>
/// 闪烁频率。
/// </summary>
public float FrequencyHz { get; set; }
/// <summary>
/// 当前工作模式的优先级。
/// </summary>
public int Priority { get; set; }
#endregion
#region Static Methods
/// <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 static bool GetBlinkData(STBlinkPattern pattern, out List<BlinkDataType> blinkData, out string reason)
{
// var regex = new Regex(@"(([-\.])(\2*))");
reason = "";
blinkData = new List<BlinkDataType>();
// 校验Pattern字串的正则Pattern仅允许有字符-‘和’.’组成。
var regPatternFormat = new Regex(REG_PATT_BLINK_PATTERN);
// Pattern分组正则
var regGroup = new Regex(@"([\-\.])\1*");
if (!regPatternFormat.IsMatch(pattern.Pattern))
{
// 如果存在除-和.以外的字符则为非法Pattern字串。
reason = "pattern contains illegal characters";
LOG.Error(reason);
return false;
}
var matches = regGroup.Matches(pattern.Pattern);
foreach (Match match in matches)
{
if (match.Success && match.Groups.Count == 2)
{
var leadChar = match.Groups[1].Value; // 编组字符
var length = (uint)match.Length;
// 根据每组的字符判断动作。
TowerLightStatus action;
switch (leadChar)
{
case "-":
action = TowerLightStatus.On;
break;
case ".":
action = TowerLightStatus.Off;
break;
default:
LOG.Error($"Undefined character {leadChar} in pattern");
continue;
}
blinkData.Add(new(action, DELAY_MS_PER_CHAR * length));
}
}
return true;
}
/// <summary>
/// <inheritdoc cref="Object.ToString()"/>
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"IsPlcMode={IsPlcMode}, Freq={FrequencyHz}Hz, Pattern={Pattern}";
}
/// <inheritdoc />
public object Clone()
{
return MemberwiseClone();
}
/// <summary>
/// 对比当前STBlinkPattern是否和指定的STBlinkPattern相同。
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public int CompareTo(object obj)
{
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
&& target.Priority == Priority)
? 0
: -1;
}
/// <summary>
/// 获取预设的快速闪烁模式。
/// </summary>
/// <remarks>
/// 开200ms关200ms无限循环。
/// </remarks>
/// <returns></returns>
public static STBlinkPattern GetDefaultPattern()
{
return new STBlinkPattern(PATTERN_SLOW, (int)TowerLightStatus.Customized);
}
/// <summary>
/// 获取预设的工艺完成闪烁模式。
/// </summary>
/// <remarks>
/// 以开200ms、关200ms方式连续闪烁3次然后关1s循环5次。
/// </remarks>
/// <returns></returns>
public static STBlinkPattern GetJobDonePattern()
{
return new STBlinkPattern(PATTERN_JOB_DONE, priority:-1);
}
#endregion
}