[Common]
优化InterlockAction的CanDo函数的互锁信息生成方法。 修正InterlockLimitRangeDouble构造函数错误抛出InvalidCastException异常的问题。 修正InterlockLimitRangeInt和InterlockLimitRangeShort未实现字串解析构造函数的问题。 修正InterlockManager的CreateInterlockLimit函数中未将新生成的InterlockLimit对象添加到_dicLimitToActionMap字典中的问题。 移除IOType对象中的ToIoType()扩展方法,因为IO的前缀为ModuleName,而不是DI_、DO_等。
This commit is contained in:
parent
f57dbff818
commit
be713cd7af
|
@ -9,29 +9,4 @@ namespace Aitex.Core.RT.IOCore
|
|||
AI = 2,
|
||||
AO = 3
|
||||
}
|
||||
|
||||
public static class IoCoreExtensions
|
||||
{
|
||||
public static IOType ToIoType(this string ioName)
|
||||
{
|
||||
IOType ioType;
|
||||
// 根据IO名称前缀确定IO类型
|
||||
if (ioName.StartsWith("DI_"))
|
||||
ioType = IOType.DI;
|
||||
else if(ioName.StartsWith("DO_"))
|
||||
ioType = IOType.DO;
|
||||
else if(ioName.StartsWith("AI_"))
|
||||
ioType = IOType.AI;
|
||||
else if(ioName.StartsWith("AO_"))
|
||||
ioType = IOType.AO;
|
||||
else
|
||||
{
|
||||
var err = $"Undefined prefix of io name '{ioName}' of interlock limit.";
|
||||
LOG.Error(err);
|
||||
throw new InvalidIoNameException(err);
|
||||
}
|
||||
|
||||
return ioType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Aitex.Core.RT.IOCore
|
||||
{
|
||||
|
@ -48,32 +49,38 @@ namespace Aitex.Core.RT.IOCore
|
|||
|
||||
// 如果DO已经输出Action定义的电平,则反向
|
||||
if (_do.SetValue(!_actionValue, out reason))
|
||||
reason = $"Force setting DO-{_do.IoTableIndex}({_do.Name}) = [{((!_actionValue) ? "ON" : "OFF")}]";
|
||||
reason = $"Interlock Force set DO-{_do.IoTableIndex}({_do.Name}) = [{((!_actionValue) ? "ON" : "OFF")}]";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanDo(out string reason)
|
||||
{
|
||||
reason = string.Empty;
|
||||
bool result = true;
|
||||
var sbReason = new StringBuilder();
|
||||
var result = true;
|
||||
foreach (var limit in _limits)
|
||||
{
|
||||
if (!limit.CanDo(out var reason2))
|
||||
if (!limit.CanDo(out var limitReason))
|
||||
{
|
||||
if (reason.Length > 0)
|
||||
{
|
||||
reason += "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
reason =
|
||||
$"Interlock triggered, DO-{_do.IoTableIndex}({_do.Name}) can not be [{(_actionValue ? "ON" : "OFF")}], {_tip} \n";
|
||||
}
|
||||
reason += reason2;
|
||||
sbReason.AppendLine(limitReason);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有互锁被触发,则打印互锁信息
|
||||
if (!result)
|
||||
{
|
||||
sbReason.Insert(0,
|
||||
$"Interlock triggered, DO-{_do.IoTableIndex}({_do.Name}) can not be [{(_actionValue ? "ON" : "OFF")}], {_tip} \r\n");
|
||||
reason = sbReason.ToString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ActionName}, Action={_actionValue}, Limit Count={_limits.Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ public class InterlockLimitRangeDouble : IAnalogInterlockLimitRange<double>
|
|||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
throw new InvalidCastException($"unable to convert {value} to double range.");
|
||||
else
|
||||
throw new InvalidCastException($"unable to convert {value} to double range.");
|
||||
}
|
||||
|
||||
public InterlockLimitRangeDouble(double min, double max)
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
using System;
|
||||
|
||||
namespace Aitex.Core.RT.IOCore;
|
||||
|
||||
public class InterlockLimitRangeInt: IAnalogInterlockLimitRange<int>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public InterlockLimitRangeInt(string value)
|
||||
{
|
||||
var strValues = value.Split(':');
|
||||
if (strValues.Length == 2
|
||||
&& int.TryParse(strValues[0], out var min)
|
||||
&& int.TryParse(strValues[1], out var max))
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
else
|
||||
throw new InvalidCastException($"unable to convert {value} to double range.");
|
||||
}
|
||||
|
||||
public InterlockLimitRangeInt(short min, short max)
|
||||
{
|
||||
Min = min;
|
||||
|
|
|
@ -1,8 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace Aitex.Core.RT.IOCore;
|
||||
|
||||
public class InterlockLimitRangeShort : IAnalogInterlockLimitRange<short>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public InterlockLimitRangeShort(string value)
|
||||
{
|
||||
var strValues = value.Split(':');
|
||||
if (strValues.Length == 2
|
||||
&& short.TryParse(strValues[0], out var min)
|
||||
&& short.TryParse(strValues[1], out var max))
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
else
|
||||
throw new InvalidCastException($"unable to convert {value} to double range.");
|
||||
}
|
||||
|
||||
public InterlockLimitRangeShort(short min, short max)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
@ -158,12 +159,15 @@ namespace Aitex.Core.RT.IOCore
|
|||
{
|
||||
// 检查InterlockLimit是否已经存在于字典中
|
||||
var limitInDic = _dicLimitToActionMap.Keys.FirstOrDefault(x => x.UniqueId == limit.UniqueId);
|
||||
Debug.Assert(limitInDic != null, "The condition should never be hit");
|
||||
|
||||
// 存在则插入InterlockAction;不存在则新建
|
||||
if (limitInDic != null)
|
||||
_dicLimitToActionMap[limitInDic].Add(newAction);
|
||||
else
|
||||
{
|
||||
_dicLimitToActionMap[limit] = new List<InterlockAction> { newAction };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -249,22 +253,25 @@ namespace Aitex.Core.RT.IOCore
|
|||
/// <param name="cultureTip">多国语言提示信息。</param>
|
||||
/// <param name="reason">创建失败并返回null的原因。</param>
|
||||
/// <returns>互锁限制条件对象的实例。</returns>
|
||||
private static IInterlockLimit CreateInterlockLimit(string ioName, string limitValue, string tip,
|
||||
private static IInterlockLimit CreateInterlockLimit(IOType ioType, string ioName, string limitValue, string tip,
|
||||
Dictionary<string, string> cultureTip , out string reason)
|
||||
{
|
||||
Debug.Assert(Enum.TryParse<IOType>(ioType.ToString(), out _),"Undefined IO Type");
|
||||
Debug.Assert(!string.IsNullOrEmpty(ioName),"IO Name can not be empty");
|
||||
Debug.Assert(!string.IsNullOrEmpty(limitValue),"LimitValue can not be empty");
|
||||
|
||||
reason = "";
|
||||
var type = ioName.ToIoType();
|
||||
|
||||
// 创建一个InterlockLimit实例。
|
||||
IIOAccessor io;
|
||||
IInterlockLimit limit;
|
||||
try
|
||||
{
|
||||
io = GetIoByIoType(ioName.ToIoType(), ioName);
|
||||
io = GetIoByIoType(ioType, ioName);
|
||||
}
|
||||
catch (IoNotFoundException)
|
||||
{
|
||||
reason = $"limit node {ioName} no such {ioName.ToIoType()} defined";
|
||||
reason = $"limit node {ioName} no such {ioType} defined";
|
||||
return null;
|
||||
}
|
||||
catch (InvalidIoTypeExeption)
|
||||
|
@ -273,7 +280,7 @@ namespace Aitex.Core.RT.IOCore
|
|||
return null;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
switch (ioType)
|
||||
{
|
||||
case IOType.DI:
|
||||
limit = new DiLimit((DIAccessor)io, limitValue, tip, cultureTip);
|
||||
|
@ -301,7 +308,10 @@ namespace Aitex.Core.RT.IOCore
|
|||
|
||||
// 如果不存在,则返回新创建的对象。
|
||||
if (limitExist == null)
|
||||
{
|
||||
_dicLimitToActionMap.Add(limit, new List<InterlockAction>());
|
||||
return limit;
|
||||
}
|
||||
|
||||
// 返回已存在的对象。
|
||||
return limitExist;
|
||||
|
@ -330,18 +340,29 @@ namespace Aitex.Core.RT.IOCore
|
|||
return null;
|
||||
}
|
||||
|
||||
// 节点不包含‘di’、‘do’、‘ai’、‘ao’、‘io’,或者不包含‘value’属性
|
||||
// 节点不包含‘di’、‘do’、‘ai’、‘ao’,或者不包含‘value’属性
|
||||
string limitIoName;
|
||||
IOType limitIoType;
|
||||
if (xmlNodeLimit.HasAttribute("di"))
|
||||
{
|
||||
limitIoName = xmlNodeLimit.GetAttribute("di");
|
||||
limitIoType = IOType.DI;
|
||||
}
|
||||
else if (xmlNodeLimit.HasAttribute("do"))
|
||||
{
|
||||
limitIoName = xmlNodeLimit.GetAttribute("do");
|
||||
limitIoType = IOType.DO;
|
||||
}
|
||||
else if (xmlNodeLimit.HasAttribute("ai"))
|
||||
{
|
||||
limitIoName = xmlNodeLimit.GetAttribute("ai");
|
||||
limitIoType = IOType.AI;
|
||||
}
|
||||
else if (xmlNodeLimit.HasAttribute("ao"))
|
||||
{
|
||||
limitIoName = xmlNodeLimit.GetAttribute("ao");
|
||||
else if (xmlNodeLimit.HasAttribute("io"))
|
||||
limitIoName = xmlNodeLimit.GetAttribute("io");
|
||||
limitIoType = IOType.AO;
|
||||
}
|
||||
else
|
||||
{
|
||||
reason = "limit node lack of di/do/ai/ao/io attribute";
|
||||
|
@ -374,7 +395,7 @@ namespace Aitex.Core.RT.IOCore
|
|||
dicLimitTips["en-US"] = xmlNodeLimit.GetAttribute("tip.en-US");
|
||||
}
|
||||
|
||||
var limit = CreateInterlockLimit(limitIoName, limitValue, tip, dicLimitTips, out reason);
|
||||
var limit = CreateInterlockLimit(limitIoType, limitIoName, limitValue, tip, dicLimitTips, out reason);
|
||||
return limit;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,13 +34,13 @@ namespace MECF.Framework.Common.SCCore
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// 注册一个回调函数,当指定的配置项发生变化时,调用此函数。
|
||||
/// 注册一个回调函数,当指定的配置项发生变化时,调用此函数。
|
||||
/// </summary>
|
||||
/// <param name="name">系统配置项名称。</param>
|
||||
/// <param name="name">系统配置项名称。</param>
|
||||
/// <param name="callback">
|
||||
/// 当配置项值变化时,调用此委托。
|
||||
/// 当配置项值变化时,调用此委托。
|
||||
/// <br/>
|
||||
/// 此委托的传入参数为系统配置值变更后的新值。
|
||||
/// 此委托的传入参数为系统配置值变更后的新值。
|
||||
/// </param>
|
||||
void RegisterValueChangedCallback(string name, Action<object> callback);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue