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 } }