using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.Util; using System; using System.Collections.Generic; using System.Linq; using System.Xml; namespace SicPM.Devices { public class IoSensor : BaseDevice, IDevice { #region Variables public event Action OnSignalChanged; private readonly DIAccessor _di = null; private readonly DOAccessor _do = null; private readonly string _warningText; private readonly string _alarmText; private readonly string _infoText; private readonly bool _textOutTrigValue; private readonly int _respDelayInSec = 0; private readonly R_TRIG _trigTextOut; private bool _previousValue; private Dictionary _dictValues; #endregion #region Constructors public IoSensor(string module, XmlElement node, string ioModule = "") { var attrModule = node.GetAttribute("module"); base.Module = string.IsNullOrEmpty(attrModule) ? module : attrModule; base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _di = ParseDiNode("di", node, ioModule); _do = ParseDoNode("do", node, ioModule); if (!int.TryParse(node.GetAttribute("respDelayInSec"), out _respDelayInSec)) _respDelayInSec = 0; _infoText = node.GetAttribute("infoText"); _warningText = node.GetAttribute("warningText"); _alarmText = node.GetAttribute("alarmText"); if(!bool.TryParse(node.GetAttribute("textOutTrigValue"), out _textOutTrigValue)) _textOutTrigValue = false; _trigTextOut = new R_TRIG(); _dictValues = new Dictionary(); } #endregion #region Properites public DIAccessor SensorDI => _di; public DOAccessor SensorDO => _do; public bool AlarmTrigValue => _textOutTrigValue && !string.IsNullOrEmpty(_alarmText); public Action WarningAction { get; set; } public bool Value { get { if (_di != null) return _di.Value; if (_do != null) return _do.Value; return false; } } private AITSensorData DeviceData { get { var data = new AITSensorData() { DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, Value = Value, }; return data; } } #endregion #region Methods /// /// /// /// /// private bool Hysteresis(bool realtimeValue) { if (_respDelayInSec <= 0) return realtimeValue; _dictValues.Add(DateTime.Now, realtimeValue); var beginMom = DateTime.Now.AddSeconds(-1 * _respDelayInSec); // 剔除记录时间超过设定的迟滞时长的数据点 foreach (var s in _dictValues.Where(kv => kv.Key < beginMom).ToList()) _dictValues.Remove(s.Key); // 检查数据缓冲中是否同时存在true和false var values = _dictValues.Select(kv => kv.Value).Distinct().ToList(); if(values.Count == 1) return values[0]; // 如果信号波动,返回无效电平,表示没有收到有效信号。 return !_textOutTrigValue; } public bool Initialize() { DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); DATA.Subscribe($"{Module}.{Name}.Value", () => Value); return true; } public void Terminate() { } public void Monitor() { try { _trigTextOut.CLK = (Hysteresis(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 (_previousValue != Value) { if (OnSignalChanged != null) OnSignalChanged(this, Value); _previousValue = Value; } } catch (Exception ex) { LOG.Write(ex); } } public void Reset() { _trigTextOut.RST = true; } #endregion } }