using System; using System.Xml; 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; namespace Aitex.Core.RT.Device.Unit { public enum SlitValveStateEnum { Unknown, Up, Down, Error, } public class IoSlitValve : BaseDevice, IDevice { public SlitValveStateEnum State { get { if (_diOpen.Value && _diClose.Value) return SlitValveStateEnum.Error; if (_diOpen.Value && !_diClose.Value) return SlitValveStateEnum.Up; if (!_diOpen.Value && _diClose.Value) return SlitValveStateEnum.Down; return SlitValveStateEnum.Unknown; } } enum DeviceState { Idle, Opening, Closing, Error, } private DIAccessor _diOpen; private DIAccessor _diClose; private DIAccessor _diOpenEnable; private DIAccessor _diCloseEnable; private DOAccessor _doOpen; private DOAccessor _doClose; private DeviceState _state = DeviceState.Idle; private DeviceTimer _timer = new DeviceTimer(); private SCConfigItem _scTimeout; public bool IsOpen { get { return !_diClose.Value && _diOpen.Value; } } public bool IsClose { get { return _diClose.Value && !_diOpen.Value; } } public bool EnableOpenInterlock { get { return _diOpenEnable.Value; } } public bool EnableCloseInterlock { get { return _diCloseEnable.Value; } } //在开&关完成之后,是否保持输出,默认不保持 private bool _keepSignalOut = false; private DeviceTimer _mutexSignalTimer = new DeviceTimer(); private R_TRIG _mutexSignalTrigger = new R_TRIG(); public IoSlitValve(string module, XmlElement node, string ioModule = "") { base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module"); base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _keepSignalOut = string.IsNullOrEmpty(node.GetAttribute("keepSignalOut")) ? false : Convert.ToBoolean(node.GetAttribute("keepSignalOut")); _diOpen = ParseDiNode("diOpen", node, ioModule); _diClose = ParseDiNode("diClose", node, ioModule); _diOpenEnable = ParseDiNode("diOpenEnable", node, ioModule); _diCloseEnable = ParseDiNode("diCloseEnable", node, ioModule); _doOpen = ParseDoNode("doOpen", node, ioModule); _doClose = ParseDoNode("doClose", node, ioModule); _scTimeout = ParseScNode("scTimeout", node, ioModule); } public bool Initialize() { _state = DeviceState.Idle; DATA.Subscribe($"{Module}.{Name}.OpenFeedback", () => _diOpen.Value); DATA.Subscribe($"{Module}.{Name}.OpenEnable", () => _diOpenEnable != null ? _diOpenEnable.Value : false); DATA.Subscribe($"{Module}.{Name}.OpenSetpoint", () => _doOpen.Value); DATA.Subscribe($"{Module}.{Name}.CloseEnable", () => _diCloseEnable != null ? _diCloseEnable.Value : false); DATA.Subscribe($"{Module}.{Name}.CloseFeedback", () => _diClose.Value); DATA.Subscribe($"{Module}.{Name}.CloseSetpoint", () => _doClose.Value); DEVICE.Register($"{Module}.{Name}.Open", (out string reason, int time, object[] param) => { reason = ""; return Open(out reason); }); DEVICE.Register($"{Module}.{Name}.Close", (out string reason, int time, object[] param) => { reason = ""; return Close(out reason); }); return true; } public void Monitor() { if (_diOpen != null && _diClose != null) { if (State != SlitValveStateEnum.Error) { _mutexSignalTimer.Start(2000); } _mutexSignalTrigger.CLK = _mutexSignalTimer.IsTimeout(); if (_mutexSignalTrigger.Q) { EV.PostWarningLog(Module, $"Valve {Name} was abnormal,Reason:diOpen's value is {_diOpen.Value} and diClose's value is {_diClose.Value} too."); } } switch (_state) { case DeviceState.Opening: if (IsOpen) { if (!_keepSignalOut) { if (!_doOpen.SetValue(false, out string reason)) { LOG.Error($"{Module} reset DO failed, {reason}"); } } _state = DeviceState.Idle; } else if (_timer.IsTimeout()) { if (!_doOpen.SetValue(false, out string reason)) { LOG.Error($"{Module} reset DO failed, {reason}"); } if (_keepSignalOut) { _doClose.SetValue(true, out _); } EV.PostAlarmLog(Module, $"{Module} {Name} Can not open in {_scTimeout.IntValue} seconds"); _state = DeviceState.Error; } break; case DeviceState.Closing: if (IsClose) { if (!_keepSignalOut) { if (!_doClose.SetValue(false, out string reason)) { LOG.Error($"{Module} reset DO failed, {reason}"); } } _state = DeviceState.Idle; } else if (_timer.IsTimeout()) { if (!_doClose.SetValue(false, out string reason)) { LOG.Error($"{Module} reset DO failed, {reason}"); } if (_keepSignalOut) { _doOpen.SetValue(true, out _); } EV.PostAlarmLog(Module, $"{Module} {Name} Can not close in {_scTimeout.IntValue} seconds"); _state = DeviceState.Error; } break; default: break; } } public void Terminate() { if (!_keepSignalOut) { _doOpen.SetValue(false, out _); _doClose.SetValue(false, out _); } } public bool CheckInterlockEnable(bool open) { return open ? (_diOpenEnable == null || _diOpenEnable.Value) : (_diCloseEnable == null || _diCloseEnable.Value); } public bool SetSlitValve(bool open, out string reason) { if (open) return Open(out reason); return Close(out reason); } public bool Open(out string reason) { if (_diOpenEnable != null && !_diOpenEnable.Value) { reason = "interlock blocked open"; return false; } if (!_doClose.SetValue(false, out reason) || !_doOpen.SetValue(true, out reason)) { _doOpen.SetValue(false, out _); if (_keepSignalOut) { _doClose.SetValue(true, out _); } else { _doClose.SetValue(false, out _); } return false; } _timer.Start(_scTimeout.IntValue * 1000); _state = DeviceState.Opening; return true; } public bool Close(out string reason) { if (_diCloseEnable != null && !_diCloseEnable.Value) { reason = "interlock blocked close"; return false; } if (!_doClose.SetValue(true, out reason) || !_doOpen.SetValue(false, out reason)) { _doClose.SetValue(false, out _); if (_keepSignalOut) { _doOpen.SetValue(true, out _); } else { _doOpen.SetValue(false, out _); } return false; } _timer.Start(_scTimeout.IntValue * 1000); _state = DeviceState.Closing; return true; } public void Reset() { } } }