using System; using System.Collections; using System.Text; 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.RT.SCCore; using Aitex.Core.RT.Tolerance; using Aitex.Core.Util; using MECF.Framework.Common.Communications; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Equipment; using VirgoCommon; namespace VirgoRT.Devices { public enum EdwardsPumpState { ON = 0, OFF, Connected, Disconnected, Unknown, ERROR } static class EdwardsPumpControlSystemParameters { public const int System_Node = 1; public const int Dry_Pump_Current = 3; public const int Dry_Pump_Power = 4; public const int Booster_Current = 7; public const int Booster_Power = 8; public const int Dry_Pump_Control = 11; public const int Dry_Pump_Run_hours = 14; public const int Number_of_pump_starts = 20; } static class EdwardsPumpMessage { public const string EOF = "\r\n"; public const string RESET = "/"; public const string QUERY_Alarm_Status = "?A"; public const string QUERY_Bitfield_Status = "?B"; public const string QUERY_Control_Status = "?C"; public const string QUERY_Gas_ballast_Status = "?D"; public const string QUERY_Gate_valve_Status = "?G"; public const string QUERY_Nitrogen_supply_Status = "?N"; public const string QUERY_On_process_Status = "?O"; public const string QUERY_Pump_Status = "?P"; public const string QUERY_Run_til_crash_Status = "?R"; public const string QUERY_Inlet_purge_Status = "?U"; public const string QUERY_Pump_node_type = "?T"; public const string QUERY_Value = "?V"; public const string QUERY_Serial_Number = "?S"; public const string QUERY_Information = "?I"; public const string QUERY_Format_mode = "?F"; public const string COMMAND_Release_Control = "!C0"; public const string COMMAND_Take_Control = "!C1"; public const string COMMAND_Gas_ballast = "!D"; public const string COMMAND_Equipment = "!E"; public const string COMMAND_Format_mode = "!F"; public const string COMMAND_Gate_valve = "!G"; public const string COMMAND_Reserved = "!L"; public const string COMMAND_Simulation_mode = "!M"; public const string COMMAND_Nitrogen_supply = "!N"; public const string COMMAND_On_process = "!O"; public const string COMMAND_Switch_on_Pump = "!P1"; public const string COMMAND_Switch_off_Pump_Auto_shut_down = "!P0"; public const string COMMAND_Switch_off_Pump_Fast_shut_down = "!P2"; public const string COMMAND_Run_til_crash = "!R"; public const string COMMAND_Reserved_do_not_use = "!T"; public const string COMMAND_Inlet_purge = "!U"; public const string COMMAND_Terminate_protocol = "!XO"; public const string SET_SHORT_REPLY = "!F0"; public const string SET_LONG_REPLY = "!F1"; } class EdwardsPump : PumpBase { // ----------------------------Fields-------------------------- // private const ushort CHK_ST_INTERVAL = 1000; private const ushort CHK_CONTROL_INTERVAL = 3 * 1000; private const ushort CHK_REC_INTERVAL = 20 * 1000; private const ushort CHK_PUMP_REC_INTERVAL = 10 * 1000; private double _total; private double _fromLast; private const string EOF = "\r"; private const char MSG_DELIMITER = ' '; private readonly string _PortNum = "COM91"; private const int _counterMax = 30; //private int _counter = 0; private static string SendData; private readonly AsyncSerialPort _serial; private readonly DeviceTimer _timerQueryStatus = new DeviceTimer(); private readonly DeviceTimer _timerControlStatus = new DeviceTimer(); private readonly DeviceTimer _timerReceiveStatus = new DeviceTimer(); private readonly DeviceTimer _timerPumpOn = new DeviceTimer(); private readonly DeviceTimer _timerPumpOff = new DeviceTimer(); private readonly DeviceTimer _timerTotal = new DeviceTimer(); private readonly DeviceTimer _timerFromLast = new DeviceTimer(); private readonly R_TRIG _trigPumpOn = new R_TRIG(); private readonly R_TRIG _trigPumpOff = new R_TRIG(); private readonly R_TRIG _trigReceiveStatus = new R_TRIG(); private readonly RD_TRIG _trigOnOff = new RD_TRIG(); private readonly R_TRIG _trigPMNeeded = new R_TRIG(); private StatsDataItemRFAndPump _statPumpOnTime; // --------------------------Properties------------------------ // public EdwardsPumpState StatusDry { get; set; } public string LastPMTime { get { return _statPumpOnTime != null ? _statPumpOnTime.LastPMTime.ToString() : ""; } } public double DaysFromLastPM { get { return _statPumpOnTime == null ? 0 : _statPumpOnTime.fromLastPM; } set { if (_statPumpOnTime != null) _statPumpOnTime.fromLastPM = value; } } public double TotalDays { get { return _statPumpOnTime != null ? _statPumpOnTime.Total : 0; } set { if (_statPumpOnTime != null) _statPumpOnTime.Total = value; } } public double PMIntervalDays { get { return _statPumpOnTime != null ? _statPumpOnTime.PMInterval : 0; } } public bool IsPMNeeded { get { return DaysFromLastPM > PMIntervalDays; } } public bool EnableAlarm { get { return _statPumpOnTime == null || _statPumpOnTime.AlarmEnable; } } [Subscription(AITPumpProperty.IsRunning)] public override bool IsRunning { get { return StatusDry == EdwardsPumpState.ON; } } [Subscription(AITPumpProperty.IsError)] public override bool IsError { get { return StatusDry == EdwardsPumpState.ERROR || StatusDry == EdwardsPumpState.Disconnected; } } public override AITPumpData DeviceData { get { AITPumpData deviceData = new AITPumpData { DeviceName = Name, DeviceModule = Module, DeviceSchematicId = DeviceID, DisplayName = Display, IsError = false, IsWarning = false, IsOn = IsRunning, //WaterFlow = WaterFlowValue, IsDryPumpEnable = true, IsN2PressureEnable = false, IsWaterFlowEnable = false, //WaterFlowWarning = WaterFlowWarning, //WaterFlowAlarm = WaterFlowAlarm, //N2PressureAlarm = N2PressureAlarm, //N2PressureWarning = N2PressureWarning, }; return deviceData; } } // --------------------------Constructor----------------------- // public EdwardsPump(ModuleName mod) : base(mod.ToString(), VirgoDevice.MainPump.ToString(), "Edwards Pump", "") { _PortNum = SC.GetStringValue($"{mod}.DryPump.Port"); StatusDry = EdwardsPumpState.Unknown; _serial = new AsyncSerialPort(_PortNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "\r\n", true); } public override bool Initialize() { base.Initialize(); if (!_serial.Open()) { StatusDry = EdwardsPumpState.Disconnected; EV.PostAlarmLog(Module, "Edwards Pump串口无法打开"); return false; } _statPumpOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.PumpOnTime"); StatusDry = EdwardsPumpState.Connected; _trigPumpOn.RST = true; _trigPumpOff.RST = true; _trigReceiveStatus.RST = true; _serial.OnDataChanged += OnPortDataChanged; _serial.OnErrorHappened += OnErrorOccurred; SendCmd(EdwardsPumpMessage.RESET); SendCmd(EdwardsPumpMessage.SET_SHORT_REPLY); SendCmd(EdwardsPumpMessage.COMMAND_Take_Control); _timerQueryStatus.Start(CHK_ST_INTERVAL); _timerControlStatus.Start(CHK_CONTROL_INTERVAL); _timerReceiveStatus.Start(CHK_REC_INTERVAL); return true; } private void OnErrorOccurred(string obj) { StatusDry = EdwardsPumpState.ERROR; LOG.Error($"[{Module}] edwards pump error: [{obj}]"); } private void OnPortDataChanged(string obj) { if (string.IsNullOrEmpty(obj)) LOG.Error($"[{Module}] edwards pump message IsNullOrEmpty"); try { _timerReceiveStatus.Stop(); _timerReceiveStatus.Start(CHK_REC_INTERVAL); string cmd = obj.ToString().Split('\n')[0].Split('\r')[0]; switch (SendData) { case EdwardsPumpMessage.RESET: break; case EdwardsPumpMessage.COMMAND_Take_Control: EV.PostInfoLog(Module, $"Take Control Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.COMMAND_Release_Control: EV.PostInfoLog(Module, $"Release Control Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.COMMAND_Switch_on_Pump: EV.PostInfoLog(Module, $"Switch on Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.COMMAND_Switch_off_Pump_Fast_shut_down: EV.PostInfoLog(Module, $"Switch off Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.QUERY_Pump_Status: if (cmd == "0") { StatusDry = EdwardsPumpState.OFF; if (_trigPumpOn.Q && _timerPumpOn.IsTimeout()) { _trigPumpOn.RST = true; EV.PostMessage(Module, EventEnum.DefaultWarning, "Edwards Pump 无法打开"); } if (_trigPumpOff.Q) { EV.PostInfoLog(Module, $"Edwards Pump关闭"); } _trigPumpOff.RST = true; } else if (cmd == "4") { StatusDry = EdwardsPumpState.ON; if (_trigPumpOff.Q && _timerPumpOff.IsTimeout()) { _trigPumpOff.RST = true; EV.PostMessage(Module, EventEnum.DefaultWarning, "Edwards Pump 无法关闭"); } if (_trigPumpOn.Q) { EV.PostInfoLog(Module, $"Edwards Pump打开"); } _trigPumpOn.RST = true; } break; default: //EV.PostInfoLog(this.Module, $"Edwards Pump {SendData} {QueryCmdReply(cmd)}"); break; } } catch (Exception ex) { LOG.Error($"[{Module}] edwards pump error: [{ex.Message}]"); } } public string QueryCmdReply(string cmd) { if (cmd == "ERR 0") { return "No error"; } else if (cmd == "ERR 1") { return "Invalid message"; } else if (cmd == "ERR 2") { return "Number not found"; } else if (cmd == "ERR 3") { return "Number Invalid"; } else if (cmd == "ERR 4") { return "Parameter’s value not received"; } else if (cmd == "ERR 5") { return "Command not possible"; } else { return cmd; } } public override void Monitor() { try { // 状态查询 if (_timerQueryStatus.IsTimeout() && this.StatusDry != EdwardsPumpState.ERROR) { this.SendCmd(EdwardsPumpMessage.QUERY_Pump_Status); _timerQueryStatus.Start(CHK_ST_INTERVAL); } if (_timerReceiveStatus.IsTimeout() && this.StatusDry != EdwardsPumpState.ERROR) { _trigReceiveStatus.CLK = true; if (_trigReceiveStatus.Q) { EV.PostMessage(Module, EventEnum.DefaultWarning, "Edwards Pump 没有回复"); } } _trigOnOff.CLK = IsRunning; //第一次检测到打开了,开始计时 if (_trigOnOff.R) { _total = TotalDays; _fromLast = DaysFromLastPM; _timerTotal.Start(0); _timerFromLast.Start(0); } //第一次检测到从打开到关闭状态 if (_trigOnOff.T) { } //如果开着,就更新SC if (_trigOnOff.M) { TotalDays = _total + _timerTotal.GetElapseTime() / 1000 / 60 / 60; DaysFromLastPM = _fromLast + _timerFromLast.GetElapseTime() / 1000 / 60 / 60; } if (PMIntervalDays > 0) { _trigPMNeeded.CLK = IsPMNeeded; if (_trigPMNeeded.Q) { if (EnableAlarm) { EV.PostAlarmLog(Module, "pump on time value larger than setting interval days"); } } } StatsDataManager.Instance.Increase($"{Module}.PumpOnTime", $"{Module} PumpOnTime", DaysFromLastPM, TotalDays); } catch (Exception ex) { throw ex; } } private bool SendCmd(string str) { SendData = str; if (SendData == "!P1") { _trigPumpOn.CLK = true; _timerPumpOn.Start(CHK_PUMP_REC_INTERVAL); LOG.Info($"[{Module}] Switch on Edwards Pump"); } else if (SendData == "!P2") { _trigPumpOff.CLK = true; _timerPumpOff.Start(CHK_PUMP_REC_INTERVAL); LOG.Info($"[{Module}] Switch off Edwards Pump"); } return _serial.Write(str + "\r"); } public override void Reset() { _trigPumpOn.RST = true; _trigPumpOff.RST = true; _trigReceiveStatus.RST = true; _trigPMNeeded.RST = true; SendCmd(EdwardsPumpMessage.RESET); } public override void Terminate() { //if (StatusDry == EdwardsPumpState.ON) // SetPumpOnOff(false); _serial?.Close(); } public override void SetPumpOnOff(bool on) { SendCmd(on ? EdwardsPumpMessage.COMMAND_Switch_on_Pump : EdwardsPumpMessage.COMMAND_Switch_off_Pump_Fast_shut_down); } } }