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;