using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using System; using System.Xml; namespace Aitex.Core.RT.Device.Devices { public class IoSensor : BaseDevice, IDevice { private DIAccessor _di = null; private DOAccessor _do = null; public DIAccessor SensorDI => _di; public DOAccessor SensorDO => _do; private R_TRIG _trigTextOut = new R_TRIG(); private bool _textOutTrigValue; public bool AlarmTrigValue { get { return _textOutTrigValue && !string.IsNullOrEmpty(_alarmText); } } private string _warningText; private string _alarmText; private string _infoText; private bool _disabledInServiceMode = false; private bool _disabledFromSc = false; private readonly R_TRIG _rTrigDisabledInSc = new(); public Action WarningAction { get; set; } public event Action OnSignalChanged; public bool Value { get { if (_di != null) return _di.Value; if (_do != null) return _do.Value; return false; } } private AITSensorData DeviceData { get { AITSensorData data = new AITSensorData() { DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, Value = Value, }; return data; } } private bool _previous; public IoSensor(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule) { _di = ParseDiNode("di", node, ioModule);// IO.DI[node.GetAttribute("di")]; _do = ParseDoNode("do", node, ioModule); _infoText = node.GetAttribute("infoText"); _warningText = node.GetAttribute("warningText"); _alarmText = node.GetAttribute("alarmText"); _disabledInServiceMode = (node.GetAttribute("DisInServiceMode") ?? "") == "true"; if(_disabledInServiceMode) LOG.Warning($"{UniqueName} will be disabled in service mode"); if (Name == "SensorMFC07Offline" || Name == "SensorMFC08Offline") { if (!SC.GetValue($"PM.{Module}.TMAEnable")) { _alarmText = ""; } } _textOutTrigValue = Convert.ToBoolean(string.IsNullOrEmpty(node.GetAttribute("textOutTrigValue")) ? "false" : node.GetAttribute("textOutTrigValue")); if (!string.IsNullOrEmpty(node.GetAttribute("scBasePath"))) //配置ScBasePath时,使用配置信息 { GetTextValue(); SC.RegisterValueChangedCallback($"{ScBasePath}.{Name}.AlarmType", (obj) => GetTextValue()); SC.RegisterValueChangedCallback($"{ScBasePath}.{Name}.Text", (obj) => GetTextValue()); SC.RegisterValueChangedCallback($"{ScBasePath}.{Name}.TrigValue", (obj) => GetTextValue()); SC.RegisterValueChangedCallback($"{ScBasePath}.{Name}.IsEnable", (obj) => GetTextValue()); // e.g. TM.IoSensor.{Name}.Disable var scPath = $"{ScBasePath}.{Name}.Disable"; _disabledFromSc = SC.SafeGetValue(scPath, false); SC.RegisterValueChangedCallback(scPath, (obj) => { if (obj is bool isDisable) _disabledFromSc = isDisable; else _disabledFromSc = false; }); } } private string GetTrigValue(XmlElement node, string xmlNodeName, string scName) { var xmlNodeValue = node.GetAttribute(xmlNodeName); return string.IsNullOrEmpty(xmlNodeValue) ? SC.GetStringValue($"{ScBasePath}.{Name}.{scName}") : xmlNodeValue; } private void GetTextValue() { var typ = SC.GetStringValue($"{ScBasePath}.{Name}.AlarmType"); var text = SC.GetStringValue($"{ScBasePath}.{Name}.Text"); _textOutTrigValue = SC.GetValue($"{ScBasePath}.{Name}.TrigValue"); if (!SC.SafeGetValue($"{ScBasePath}.{Name}.IsEnable", false)) text = ""; _ = typ switch { "Info" => _infoText = text, "Warning" => _warningText = text, "Alarm" => _alarmText = text, _ => "" }; } public bool Initialize() { DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); DATA.Subscribe($"{Module}.{Name}.Value", () => Value); return true; } public void Terminate() { } protected override void HandleMonitor() { try { #region 系统配置中禁用了该Sensor if (_disabledFromSc) { _rTrigDisabledInSc.CLK = true; if (_rTrigDisabledInSc.Q) LOG.Warning($"{UniqueName} is disabled in system config, please check '{ScBasePath}.{Name}.Disabled'"); return; // 当前IoSenser设置为不侦测报警 } else { _rTrigDisabledInSc.CLK = false; } #endregion #region Service模式Bypass报警 if (_disabledInServiceMode) { // 检查{Module}.IsService数据是否不存在,如果不存在,跳过下面步骤 var dataPath = $"{Module}.IsService"; var isServiceMode = false; lock (LockNonExistedServiceData) { if (!NonExistedServiceData.Contains(dataPath)) { // 检查所属Module是否为Service模式,如果是,不报警 var objIsService = DATA.Poll(dataPath); if (objIsService is not bool bValue) { NonExistedServiceData.Add(dataPath); LOG.Warning( $"{UniqueName} Unable to poll data '{Module}.IsService', service mode detection will be discontinued in future monitoring"); } else { isServiceMode = bValue; } } } // 如果是Service模式,不报警 if (isServiceMode) { return; } } #endregion _trigTextOut.CLK = (Value == _textOutTrigValue); if (_trigTextOut.Q) { if (WarningAction != null) { WarningAction(); } else if (!string.IsNullOrEmpty(_warningText.Trim())) { EV.PostWarningLog(Module, _warningText); } else if (!string.IsNullOrEmpty(_alarmText.Trim())) { EV.PostAlarmLog(Module, _alarmText); } else if (!string.IsNullOrEmpty(_infoText.Trim())) { EV.PostInfoLog(Module, _infoText); } } if (_previous != Value) { if (OnSignalChanged != null) OnSignalChanged(this, Value); _previous = Value; } } catch (Exception ex) { LOG.Write(ex); } } public void Reset() { _trigTextOut.RST = true; } } }