using System; using System.Xml; 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.RT.OperationCenter; using Aitex.Core.Util; namespace Aitex.Core.RT.Device.Unit { public class IoLid : BaseDevice, IDevice { private DIAccessor _diOFF; private DOAccessor _doON; private DOAccessor _doOFF; private CylinderState _operation; private DeviceTimer _timer = new DeviceTimer(); private R_TRIG _trigReset = new R_TRIG(); private R_TRIG _trigError = new R_TRIG(); public int SetPoint { get { return (int)CylinderState.Unknown; /* if (_doON.Value && _doOFF.Value) return (int)CylinderState.Error; if (_doON.Value && !_doOFF.Value) return (int)CylinderState.Open; if (!_doON.Value && _doOFF.Value) return (int)CylinderState.Close; if (!_doON.Value && !_doOFF.Value) return (int)CylinderState.Unknown; */ } } public CylinderState State { get { return _diOFF.Value ? CylinderState.Close : CylinderState.Open; } } public bool OFFFeedback { get { return _diOFF.Value; } } public bool ONSetPoint { get { return _doON.Value; } set { if (_doON != null && _doON.Check(value, out _)) _doON.Value = value; } } public bool OFFSetPoint { get { return _doOFF.Value; } set { if (_doOFF != null && _doOFF.Check(value, out _)) _doOFF.Value = value; } } private AITCylinderData DeviceData { get { AITCylinderData deviceData = new AITCylinderData { Module = Module, DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, CloseFeedback = OFFFeedback, //OpenSetPoint = ONSetPoint, //CloseSetPoint = OFFSetPoint }; return deviceData; } } public IoLid(string module, XmlElement node, string ioModule = "") { base.Module = module; base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _diOFF = ParseDiNode("diOFF", node, ioModule); _doON = ParseDoNode("doON", node, ioModule); _doOFF = ParseDoNode("doOFF", node, ioModule); } public bool Initialize() { DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.Open}", InvokeOpenCylinder); OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.Close}", InvokeCloseCylinder); DEVICE.Register($"{Module}.{Name}.{AITCylinderOperation.Open}", (out string reason, int time, object[] param) => { bool ret = SetCylinder(true, out reason); if (ret) { reason = $"Open Cylinder {Name}"; return true; } return false; }); DEVICE.Register($"{Module}.{Name}.{AITCylinderOperation.Close}", (out string reason, int time, object[] param) => { bool ret = SetCylinder(false, out reason); if (ret) { reason = $"Close Cylinder {Name}"; return true; } return false; }); return true; } private bool InvokeOpenCylinder(string arg1, object[] arg2) { if (!SetCylinder(true, out var reason)) { EV.PostWarningLog(Module, $"Can not open cylinder {Module}.{Name}, {reason}"); return false; } EV.PostInfoLog(Module, $"Open cylinder {Module}.{Name}"); return true; } private bool InvokeCloseCylinder(string arg1, object[] arg2) { if (!SetCylinder(false, out var reason)) { EV.PostWarningLog(Module, $"Can not close cylinder {Module}.{Name}, {reason}"); return false; } EV.PostInfoLog(Module, $"Close cylinder {Module}.{Name}"); return true; } public void Terminate() { OFFSetPoint = false; ONSetPoint = false; } public bool SetCylinder(bool isOpen, out string reason) { reason = ""; ONSetPoint = isOpen; OFFSetPoint = !isOpen; _operation = isOpen ? CylinderState.Open : CylinderState.Close; _timer.Start(1000 * 60 * 3); return true; } public void Monitor() { try { if (_timer.IsTimeout()) { _timer.Stop(); if (State != _operation) { if (_operation == CylinderState.Open) { if (!_doON.Check(true, out var reason)) EV.PostAlarmLog(Module, "Open Cylinder Failed for interlock, " + reason); else EV.PostAlarmLog(Module, "Cylinder hold close status"); } else { if (!_doON.Check(false, out var reason)) EV.PostAlarmLog(Module, "Close Cylinder Failed for interlock, " + reason); else EV.PostAlarmLog(Module, "Cylinder hold open status"); } } _operation = (CylinderState)SetPoint; } else if (_timer.IsIdle()) { return; /* _trigReset.CLK = SetPoint != (int)_operation; // fire event only check at first, SetPoint set by interlock if (_trigReset.Q) { if (_operation == CylinderState.Open) { string reason; if (!_doON.Check(true, out reason)) EV.PostMessage(Module, EventEnum.SwInterlock, Module, $"Cylinder {Display} was {"Close"},Reason:{reason}"); else EV.PostMessage(Module, EventEnum.SwInterlock, Module, $"Cylinder {Display} was {"Close"},Reason {"PLC kept"}"); } else { string reason; if (!_doON.Check(false, out reason)) EV.PostMessage(Module, EventEnum.SwInterlock, Module, $"Cylinder {Display} was {"Open"},Reason:{reason}"); else EV.PostMessage(Module, EventEnum.SwInterlock, Module, $"Cylinder {Display} was {"Open"},Reason {"PLC Kept"}"); } _operation = (CylinderState)SetPoint; } */ } _trigError.CLK = State == CylinderState.Error; if (_trigError.Q) { EV.PostAlarmLog(Module, "Cylinder in error status"); } if ((SetPoint == (int)State) && (SetPoint == (int)CylinderState.Open || SetPoint == (int)CylinderState.Close)) { OFFSetPoint = false; ONSetPoint = false; } } catch (Exception ex) { LOG.Write(ex); } } public void Reset() { _trigReset.RST = true; _trigError.RST = true; } } }