Sic03/Modules/SicPM/Devices/IoSensor.cs

207 lines
5.6 KiB
C#

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<IoSensor, bool> 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<DateTime, bool> _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<DateTime, bool>();
}
#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
/// <summary>
///
/// </summary>
/// <param name="realtimeValue"></param>
/// <returns></returns>
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
}
}