diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/IOType.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/IOType.cs index 27202ad..dbe7039 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/IOType.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/IOType.cs @@ -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; - } - } } diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockAction.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockAction.cs index c48d089..db167ad 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockAction.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockAction.cs @@ -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}"; + } } } diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeDouble.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeDouble.cs index d861c70..dafc0c2 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeDouble.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeDouble.cs @@ -16,8 +16,8 @@ public class InterlockLimitRangeDouble : IAnalogInterlockLimitRange 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) diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeInt.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeInt.cs index 3cdd457..bc1aad6 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeInt.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeInt.cs @@ -1,9 +1,25 @@ +using System; + namespace Aitex.Core.RT.IOCore; public class InterlockLimitRangeInt: IAnalogInterlockLimitRange { #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; diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeShort.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeShort.cs index 1f1631f..b109aaf 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeShort.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockLimitRangeShort.cs @@ -1,8 +1,24 @@ +using System; + namespace Aitex.Core.RT.IOCore; public class InterlockLimitRangeShort : IAnalogInterlockLimitRange { #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) { diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManager.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManager.cs index 1c5b474..f22f19e 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManager.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManager.cs @@ -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 { newAction }; + } } } } @@ -249,22 +253,25 @@ namespace Aitex.Core.RT.IOCore /// 多国语言提示信息。 /// 创建失败并返回null的原因。 /// 互锁限制条件对象的实例。 - private static IInterlockLimit CreateInterlockLimit(string ioName, string limitValue, string tip, + private static IInterlockLimit CreateInterlockLimit(IOType ioType, string ioName, string limitValue, string tip, Dictionary cultureTip , out string reason) { + Debug.Assert(Enum.TryParse(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()); 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; } diff --git a/MECF.Framework.Common/MECF/Framework/Common/SCCore/ISCManager.cs b/MECF.Framework.Common/MECF/Framework/Common/SCCore/ISCManager.cs index f20a088..6705cdc 100644 --- a/MECF.Framework.Common/MECF/Framework/Common/SCCore/ISCManager.cs +++ b/MECF.Framework.Common/MECF/Framework/Common/SCCore/ISCManager.cs @@ -34,13 +34,13 @@ namespace MECF.Framework.Common.SCCore /// - /// עһصָ仯ʱô˺ + /// 注册一个回调函数,当指定的配置项发生变化时,调用此函数。 /// - /// ϵͳơ + /// 系统配置项名称。 /// - /// ֵ仯ʱôίС + /// 当配置项值变化时,调用此委托。 ///
- /// ίеĴΪϵͳֵֵ + /// 此委托的传入参数为系统配置值变更后的新值。 /// void RegisterValueChangedCallback(string name, Action callback); }