using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore.Interlock.Actions;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Equipment;
namespace Aitex.Core.RT.IOCore.Interlock
{
///
/// 互锁管理器。
///
/// 互锁管理器作为独立工作的设备,被系统的后台循环调度。
///
/// 当监测到某个InterlockLimit被触发时,和该Limit相关的所有Action中定义的DO均被
/// 置为Action节点Value属性中定义电平的反向电平。
///
///
public class InterlockManager : InterlockManagerBase
{
#region Variables
///
/// 以Module为单位,当设置该Module所属的DO并触发互锁时,是否输出Info而不是Warning。
///
private Dictionary _dicModulePostInfo;
#endregion
#region Constructors
///
/// 互锁管理器的构造函数。
///
public InterlockManager()
{
RootNodeName = "Interlock";
_dicModulePostInfo = new();
}
#endregion
#region Methods
///
/// 初始化互锁管理器。
///
/// 互锁配置文件。
/// DO点表。
/// DI点表。
/// AO点表。
/// AI点表。
/// 初始化失败原因。
///
public override bool Initialize(string configFie,
Dictionary doMap,
Dictionary diMap,
Dictionary aiMap,
Dictionary aoMap,
out string reason)
{
reason = "";
var succeeded = base.Initialize(configFie, doMap, diMap, aiMap, aoMap, out reason);
if (!succeeded)
return false;
_dicModulePostInfo = _dicLimitsPerModule.Keys.ToDictionary(x => x, x => false);
return true;
}
///
/// 背景扫描线程执行的任务。
///
public override void Monitor()
{
// 按Module扫描Interlock Limit
foreach (var moduleName in _dicLimitsPerModule.Keys.ToList())
{
Debug.Assert(moduleName != ModuleName.UnDefined,
$"Interlock Manager CanSetDo() undesired module name {ModuleName.UnDefined}");
// 检查当前Module是否旁路Interlock
var isBypassInterlock = GetScBypassInterlockValue(moduleName);
if (isBypassInterlock)
continue;
foreach (var limit in _dicLimitsPerModule[moduleName].ToList())
{
// 如果互锁没被触发
if (!limit.IsTriggered())
continue;
var reverseInfo = new StringBuilder();
var module = "System";
if (!_dicLimitToActionMap.ContainsKey(limit))//新增判断集合中是否包含,防止异常报错
continue;
var actions = _dicLimitToActionMap[limit].ToList();
foreach (var action in actions)
{
// 尝试根据Action定义复位该互锁限制条件对应的所有DO的电平
if (((InterlockAction)action).TryReverse(out var reason))
{
var ss = action.ActionName.Split('.');
if (ss.Length > 1 && ModuleHelper.IsPm(ss[0]))
module = ss[0];
reverseInfo.AppendLine(reason);
}
}
// 如果PM腔有被恢复的DO,则打印信息并报警。
if (reverseInfo.Length > 0)
{
reverseInfo.Insert(0,
$"Due to the {limit.Tip}, {limit.Description} is not [{limit.GetLimitValue()}]\r\n");
// Post事件的类型, Info还是Warning
_dicModulePostInfo.TryGetValue(moduleName, out var isPostInfo);
if (isPostInfo)
EV.PostInfoLog(module, reverseInfo.ToString().TrimEnd('\r', '\n'));
else
EV.PostWarningLog(module, reverseInfo.ToString().TrimEnd('\r', '\n'));
}
}
}
}
///
/// 设置指定Module的Interlock打印信息等级。
///
/// 模组名称
/// 是否以Info等级打印信息
public void SetEventLevel(string module, bool isPostInfo)
{
var moduleName = ModuleHelper.Converter(module);
if (_dicModulePostInfo.ContainsKey(moduleName))
_dicModulePostInfo[moduleName] = isPostInfo;
}
///
/// 对指定的DO的操作是否满足互锁条件。
///
/// 待操作的DO名称。
///
/// 指定的输出。
/// True:输出有效电平
///
/// False:清除有效电平输出
///
///
/// 如果触发互锁限制,输出互锁限制的原因。
///
///
public bool CanSetDo(string doName, bool onOff, out string reason)
{
reason = string.Empty;
var moduleName = GetModuleFromIo(doName);
Debug.Assert(moduleName != ModuleName.UnDefined,
$"Interlock Manager CanSetDo() undesired module name {ModuleName.UnDefined}");
var isBypassInterlock = GetScBypassInterlockValue(moduleName);
if (isBypassInterlock)
return true;
foreach (var action in _lstActions.Where(action => action.IsSame(doName, onOff)))
{
return action.CanDo(out reason);
}
return true;
}
///
/// 获取系统配置中指定Module的ByPassInterlock参数设置值。
///
///
/// 模组名称,
///
///
public static bool GetScBypassInterlockValue(ModuleName module)
{
return GetScBypassInterlockValue(module.ToString());
}
///
/// 获取系统配置中指定Module的ByPassInterlock参数设置值。
///
/// 模组名称
///
public static bool GetScBypassInterlockValue(string module)
{
if (ModuleHelper.IsPm(module))
return SC.SafeGetValue($"PM.{module}.BypassInterlock", false);
else
return SC.SafeGetValue($"{module}.BypassInterlock", false);
}
#endregion
}
}