257 lines
8.3 KiB
C#
257 lines
8.3 KiB
C#
|
|
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<IoSensor, bool> 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<bool>($"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<bool>($"{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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|