diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interfaces/IInterlockLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interfaces/IInterlockLimit.cs index 1bcafa9..37f40b0 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interfaces/IInterlockLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interfaces/IInterlockLimit.cs @@ -41,6 +41,11 @@ public interface IInterlockLimit /// string Tip { get; } + /// + /// 返回该Limit是否对Action进行反转 + /// + bool IgnoreReverse { get; } + /*/// /// 判断两个互锁限制条件是否相等。 /// @@ -66,7 +71,6 @@ public interface IInterlockLimit /// bool CanDo(out string reason); - /// /// 获取指定互锁限制条件中限制条件的内容。 /// diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManagerBase.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManagerBase.cs index 39b61a7..fdcfa88 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManagerBase.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/InterlockManagerBase.cs @@ -163,11 +163,11 @@ public abstract class InterlockManagerBase if (actionNode.HasAttribute("tip.en-US")) dicTips["en-US"] = actionNode.GetAttribute("tip.en-US"); - var ignoreReverse = false; + var ignoreReverse_All = false;//单个Action的全局ignore,为True时所有Limit条件不反向控制 if (actionNode.HasAttribute("ignoreReverse")) { var strIgnoreReverse = actionNode.GetAttribute("ignoreReverse"); - if (!bool.TryParse(strIgnoreReverse, out ignoreReverse)) + if (!bool.TryParse(strIgnoreReverse, out ignoreReverse_All)) LOG.Error($"Unable to convert attribute 'ignoreReverse' of action '{doName}' to bool."); } @@ -213,17 +213,21 @@ public abstract class InterlockManagerBase _lstActions.Add(action); // 如果当前Action设置了忽略翻转,则不要注册Limit到当前Action的映射,避免Limit触发导致Action翻转。 - if (!ignoreReverse) + if (!ignoreReverse_All) { foreach (var limit in action.Limits) { - // 创建以Limit分组的Action字典 - if (!_dicLimitToActionMap.ContainsKey(limit)) - _dicLimitToActionMap[limit] = new List(); + if (!limit.IgnoreReverse)//如果单个limit也忽略反转,不要注册Limit到当前Action的映射,避免Limit触发导致Action翻转。 + { + // 创建以Limit分组的Action字典 + if (!_dicLimitToActionMap.ContainsKey(limit)) + _dicLimitToActionMap[limit] = new List(); - _dicLimitToActionMap[limit].Add(action); + _dicLimitToActionMap[limit].Add(action); + } } } + } Debug.Assert(!_dicActionsPerModule.ContainsKey(ModuleName.UnDefined), @@ -302,6 +306,14 @@ public abstract class InterlockManagerBase tip = dicLimitTips["en-US"]; } + var ignoreReverse = false; + if (limitNode.HasAttribute("ignoreReverse")) + { + var strIgnoreReverse = limitNode.GetAttribute("ignoreReverse"); + if (!bool.TryParse(strIgnoreReverse, out ignoreReverse)) + LOG.Error($"Unable to convert attribute 'ignoreReverse' of Limit to bool."); + } + // 节点不包含‘di’、‘do’、‘ai’、‘ao’,或者不包含‘value’属性 IInterlockLimit limit; if (limitNode.HasAttribute("di")) @@ -309,40 +321,40 @@ public abstract class InterlockManagerBase var limitName = limitNode.GetAttribute("di"); var io = GetIoByIoType(IOType.DI, limitName); var provider = new DiValueProvider((DIAccessor)io); - limit = new DiLimit(provider, limitValue, tip, dicLimitTips); + limit = new DiLimit(provider, limitValue, tip, dicLimitTips, ignoreReverse); } else if (limitNode.HasAttribute("do")) { var limitName = limitNode.GetAttribute("do"); var io = GetIoByIoType(IOType.DO, limitName); var provider = new DoValueProvider((DOAccessor)io); - limit = new DoLimit(provider, limitValue, tip, dicLimitTips); + limit = new DoLimit(provider, limitValue, tip, dicLimitTips, ignoreReverse); } else if (limitNode.HasAttribute("ai")) { var limitName = limitNode.GetAttribute("ai"); var io = GetIoByIoType(IOType.AI, limitName); var provider = new AiValueProvider((AIAccessor)io); - limit = new AiLimit(provider, limitValue, tip, dicLimitTips); + limit = new AiLimit(provider, limitValue, tip, dicLimitTips, ignoreReverse); } else if (limitNode.HasAttribute("ao")) { var limitName = limitNode.GetAttribute("ao"); var io = GetIoByIoType(IOType.AO, limitName); var provider = new AoValueProvider((AOAccessor)io); - limit = new AoLimit(provider, limitValue, tip, dicLimitTips); + limit = new AoLimit(provider, limitValue, tip, dicLimitTips, ignoreReverse); } else if (limitNode.HasAttribute("polldouble")) { var limitName = limitNode.GetAttribute("polldouble"); var provider = new DoubleDataPollProvider(limitName); - limit = new DoubleDataPollLimit(provider, limitValue, tip, dicLimitTips); + limit = new DoubleDataPollLimit(provider, limitValue, tip, dicLimitTips, ignoreReverse); } else if (limitNode.HasAttribute("pollbool")) { var limitName = limitNode.GetAttribute("pollbool"); var provider = new BoolDataPollProvider(limitName); - limit = new BoolDataPollLimit(provider, limitValue, tip, dicLimitTips); + limit = new BoolDataPollLimit(provider, limitValue, tip, dicLimitTips, ignoreReverse); } else { diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AiLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AiLimit.cs index 455f783..1edcedc 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AiLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AiLimit.cs @@ -12,8 +12,8 @@ internal class AiLimit : InterlockLimitBase #region Constructors public AiLimit(AiValueProvider dataProvider, string value, string tip, - Dictionary cultureTip) - : base(dataProvider, value, tip, cultureTip) + Dictionary cultureTip,bool ignoreReverse) + : base(dataProvider, value, tip, cultureTip, ignoreReverse) { LimitRange = new InterlockLimitRangeDouble(value); } diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AoLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AoLimit.cs index 356a71e..becf658 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AoLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/AoLimit.cs @@ -11,8 +11,8 @@ internal class AoLimit : InterlockLimitBase { #region Constructors - public AoLimit(AoValueProvider dataProvider, string value, string tip, Dictionary cultureTip) - : base(dataProvider, value, tip, cultureTip) + public AoLimit(AoValueProvider dataProvider, string value, string tip, Dictionary cultureTip, bool ignoreReverse) + : base(dataProvider, value, tip, cultureTip, ignoreReverse) { LimitRange = new InterlockLimitRangeDouble(value); } diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/BoolDataPollLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/BoolDataPollLimit.cs index 92920bb..e97251a 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/BoolDataPollLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/BoolDataPollLimit.cs @@ -10,7 +10,7 @@ public class BoolDataPollLimit : InterlockLimitBase #region Constructors public BoolDataPollLimit(IInterlockLimitDataProvider dataProvider, string value, string tip, - Dictionary cultureTip) : base(dataProvider, value, tip, cultureTip) + Dictionary cultureTip,bool ignoreReverse) : base(dataProvider, value, tip, cultureTip, ignoreReverse) { if (bool.TryParse(value, out var limitValue)) LimitValue = limitValue; diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DiLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DiLimit.cs index 7e4dc09..7ee5774 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DiLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DiLimit.cs @@ -17,8 +17,8 @@ internal class DiLimit : InterlockLimitBase public override string DaemonReason => $"{DataProvider.Name} = [{(LimitValue ? "ON" : "OFF")}]{(string.IsNullOrEmpty(Tip) ? "" : $",{Tip}")}"; - public DiLimit(DiValueProvider dataProvider, string value, string tip, Dictionary cultureTip) - : base(dataProvider, value, tip, cultureTip) + public DiLimit(DiValueProvider dataProvider, string value, string tip, Dictionary cultureTip,bool ignoreReverse) + : base(dataProvider, value, tip, cultureTip,ignoreReverse) { if (bool.TryParse(value, out var limitValue)) LimitValue = limitValue; diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoLimit.cs index 6c1eb57..7f95480 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoLimit.cs @@ -17,8 +17,8 @@ internal class DoLimit : InterlockLimitBase public override string DaemonReason => $"{DataProvider.Name} = [{(LimitValue ? "ON" : "OFF")}]{(string.IsNullOrEmpty(Tip) ? "" : $",{Tip}")}"; - public DoLimit(DoValueProvider dataProvider, string value, string tip, Dictionary cultureTip) - : base(dataProvider, value, tip, cultureTip) + public DoLimit(DoValueProvider dataProvider, string value, string tip, Dictionary cultureTip, bool ignoreReverse) + : base(dataProvider, value, tip, cultureTip, ignoreReverse) { if (bool.TryParse(value, out var limitValue)) LimitValue = limitValue; diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoubleDataPollLimit.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoubleDataPollLimit.cs index 111aa73..88646db 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoubleDataPollLimit.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/DoubleDataPollLimit.cs @@ -9,7 +9,7 @@ public class DoubleDataPollLimit : InterlockLimitBase cultureTip) : base(dataProvider, value, tip, cultureTip) + Dictionary cultureTip,bool ignoreReverse) : base(dataProvider, value, tip, cultureTip, ignoreReverse) { LimitRange = new InterlockLimitRangeDouble(value); } diff --git a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/InterlockLimitBase.cs b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/InterlockLimitBase.cs index 23c75bb..f569c35 100644 --- a/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/InterlockLimitBase.cs +++ b/MECF.Framework.Common/Aitex/Core/RT/IOCore/Interlock/Limits/InterlockLimitBase.cs @@ -16,20 +16,21 @@ public abstract class InterlockLimitBase : IInterlockLimit private Dictionary _cultureTip; private readonly R_TRIG _trigger; - #endregion + #endregion - #region Constructor + #region Constructor - /// - /// 互锁限制条件的构造函数。 - /// - /// 数据供应器对象实例 - /// 当前限制条件中的IO状态。 - /// 默认语言提示信息。 - /// 多国语言提示信息。 - /// IO名称错误,前缀不是“DI_”、”DO_“、”AI_“或"AO_". - protected InterlockLimitBase(IInterlockLimitDataProvider dataProvider, string value, string tip, - Dictionary cultureTip) + /// + /// 互锁限制条件的构造函数。 + /// + /// 数据供应器对象实例 + /// 当前限制条件中的IO状态。 + /// 默认语言提示信息。 + /// 多国语言提示信息。 + /// 是否触发Action反转 + /// IO名称错误,前缀不是“DI_”、”DO_“、”AI_“或"AO_". + protected InterlockLimitBase(IInterlockLimitDataProvider dataProvider, string value, string tip, + Dictionary cultureTip,bool ignoreReverse = false) { Debug.Assert(dataProvider != null, "The data provider can not be null."); _trigger = new R_TRIG(); @@ -37,6 +38,7 @@ public abstract class InterlockLimitBase : IInterlockLimit Tip = tip; _cultureTip = cultureTip; UniqueId = $"{dataProvider.Name}.{value}"; + IgnoreReverse = ignoreReverse; } #endregion @@ -93,11 +95,16 @@ public abstract class InterlockLimitBase : IInterlockLimit /// public string Tip { get; } - #endregion + /// + /// 返回该Limit是否对Action进行反转 + /// + public bool IgnoreReverse { get; } - #region Methods + #endregion - /* + #region Methods + + /* /// /// 判断两个互锁限制条件是否相等。 /// @@ -112,14 +119,14 @@ public abstract class InterlockLimitBase : IInterlockLimit return Name == li.Name && li.LimitValue == LimitValue; }*/ - /// - /// 返回互锁限制监测的信号当前值和期望值不相等的条件是否触发。 - /// - /// 捕获当前值和期望值不相等信号的上升沿,当上升沿到达时触发输出Q。 - /// - /// - /// - public bool IsTriggered() + /// + /// 返回互锁限制监测的信号当前值和期望值不相等的条件是否触发。 + /// + /// 捕获当前值和期望值不相等信号的上升沿,当上升沿到达时触发输出Q。 + /// + /// + /// + public bool IsTriggered() { _trigger.CLK = !CheckInRange(); return _trigger.Q;