using System; using System.Collections.Generic; 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 IoCylinder : BaseDevice, IDevice { private readonly DIAccessor _diON; private readonly DIAccessor _diOFF; private readonly DOAccessor _doON; private readonly DOAccessor _doOFF; private CylinderState _operation; private readonly DeviceTimer _timer = new DeviceTimer(); private readonly R_TRIG _trigReset = new R_TRIG(); private readonly R_TRIG _trigError = new R_TRIG(); private readonly R_TRIG _trigCylinderStateError = new R_TRIG(); private readonly R_TRIG _trigCylinderStateOpen = new R_TRIG(); private readonly R_TRIG _trigCylinderStateClose = new R_TRIG(); private readonly R_TRIG _trigCylinderStateUnknown = new R_TRIG(); public bool EnableOpen { get; set; } public bool EnableClose { get; set; } private string _error = null; public int SetPoint { get { 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; return (int)CylinderState.Unknown; } } private void SetOtherCylinderStateRst(R_TRIG curTrig) { List list = new List() { _trigCylinderStateError, _trigCylinderStateOpen, _trigCylinderStateClose, _trigCylinderStateUnknown }; list.Remove(curTrig); list.ForEach(p => p.RST = true); } public CylinderState State { get { if (_diON != null && _diOFF != null) { if (ONFeedback && _diOFF.Value) { _trigCylinderStateError.CLK = ONFeedback && _diOFF.Value; if (_trigCylinderStateError.Q) LOG.Info($"{Module} {Name} cylinder state error"); SetOtherCylinderStateRst(_trigCylinderStateError); return CylinderState.Error; } if (ONFeedback && !_diOFF.Value) { _trigCylinderStateOpen.CLK = ONFeedback && !_diOFF.Value; if (_trigCylinderStateOpen.Q) LOG.Info($"{Module} {Name} cylinder state open"); SetOtherCylinderStateRst(_trigCylinderStateOpen); return CylinderState.Open; } if (!ONFeedback && _diOFF.Value) { _trigCylinderStateClose.CLK = !ONFeedback && _diOFF.Value; if (_trigCylinderStateClose.Q) LOG.Info($"{Module} {Name} cylinder state close"); SetOtherCylinderStateRst(_trigCylinderStateClose); return CylinderState.Close; } if (!ONFeedback && !_diOFF.Value) { _trigCylinderStateUnknown.CLK = !ONFeedback && !_diOFF.Value; if (_trigCylinderStateUnknown.Q) LOG.Info($"{Module} {Name} cylinder state unknown"); SetOtherCylinderStateRst(_trigCylinderStateUnknown); return CylinderState.Unknown; } } return CylinderState.Unknown; } } public bool ONFeedback { get { return _diON != null && _diON.Value; } } public bool OFFFeedback { get { return _diOFF != null && _diOFF.Value; } } public bool ONSetPoint { get { return _doON != null && _doON.Value; } private set { if (_doON != null && _doON.Check(value, out _error)) { LOG.Write(_error); _doON.Value = value; } } } public bool OFFSetPoint { get { return _doOFF != null && _doOFF.Value; } private set { if (_doOFF != null && _doOFF.Check(value, out _error)) { LOG.Write(_error); _doOFF.Value = value; } } } private AITCylinderData DeviceData { get { return new AITCylinderData { Module = Module, DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = Display, OpenFeedback = ONFeedback, CloseFeedback = OFFFeedback, OpenSetPoint = ONSetPoint, CloseSetPoint = OFFSetPoint }; } } private object _locker = new object(); public IoCylinder(string module, XmlElement node, string ioModule = "") { base.Module = module; base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _operation = CylinderState.Unknown; _diON = ParseDiNode("diON", node, ioModule); _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}", (s, objects) => SetCylinder(true, out _)); OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.Close}", (s, objects) => SetCylinder(false, out _)); OP.Subscribe($"{Module}.{Name}.{AITCylinderOperation.SetState}", (out string reason, int time, object[] param) => { bool isUp = (string)param[0] == "Up" ? true : false; SetCylinder(isUp, out reason); return true; }); DEVICE.Register($"{Module}.{Name}.{AITCylinderOperation.Open}", (out string reason, int time, object[] param) => SetCylinder(true, out reason)); DEVICE.Register($"{Module}.{Name}.{AITCylinderOperation.Close}", (out string reason, int time, object[] param) => SetCylinder(false, out reason)); return true; } public void Terminate() { OFFSetPoint = false; ONSetPoint = false; } public bool SetCylinder(bool isOpen, out string reason) { reason = ""; if (isOpen && State == CylinderState.Open) { LOG.Write($"检查到气缸 {Name} 已经开,该状态是当前信号下发之前的状态。"); //EV.PostInfoLog(Module, $"检查到气缸 {Name} 已经开"); //return true; } if (!isOpen && State == CylinderState.Close) { LOG.Write($"检查到气缸 {Name} 已经关,该状态是当前信号下发之前的状态。"); //EV.PostInfoLog(Module, $"检查到气缸 {Name} 已经关"); //return true; } lock (_locker) { _timer.Start(5 * 1000); ONSetPoint = isOpen; reason += _error; reason += " "; OFFSetPoint = !isOpen; reason += _error; _operation = isOpen ? CylinderState.Open : CylinderState.Close; } EV.PostInfoLog(Module, $"{(isOpen ? "打开" : "关闭")} 气缸 {Name}"); if(Name== "LiftPin1") { } if (Name == "SlitDoor1") { } return true; } public void Monitor() { try { lock (_locker) { if (_timer.IsTimeout()) { _timer.Stop(); if (State != _operation) { if (_operation == CylinderState.Open) { if (!_doON.Check(true, out var reason)) EV.PostAlarmLog(Module, $"{Name} 气缸信号无法打开, interlock, " + reason); else EV.PostAlarmLog(Module, $"{Name} 气缸信号仍然关闭"); } else { if (!_doON.Check(false, out var reason)) EV.PostAlarmLog(Module, $"{Name} 气缸信号无法关闭, interlock, " + reason); else EV.PostAlarmLog(Module, $"{Name} 气缸信号仍然打开"); } } _operation = (CylinderState)SetPoint; } else if (_timer.IsIdle()) { _trigReset.CLK = SetPoint != (int)_operation; // fire event only check at first, SetPoint set by interlock if (_trigReset.Q) { if (_operation == CylinderState.Open) { EV.PostAlarmLog(Module, !_doON.Check(true, out var reason) ? $"气缸信号 {Display} was Close,Reason:{reason}" : $"气缸信号 {Display} was Close,Reason PLC kept"); } else { EV.PostAlarmLog(Module, !_doON.Check(false, out var reason) ? $"气缸信号 {Display} was Open,Reason:{reason}" : $"气缸信号 {Display} was Open,Reason PLC Kept"); } _operation = (CylinderState)SetPoint; } } } _trigError.CLK = State == CylinderState.Error; if (_trigError.Q) { EV.PostAlarmLog(Module, $"{Name} 气缸状态错误"); } //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; _trigCylinderStateError.RST = true; _trigCylinderStateOpen.RST = true; _trigCylinderStateClose.RST = true; _trigCylinderStateUnknown.RST = true; } } }