using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; 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 Venus_Core; namespace Venus_RT.Devices { static class EdwardsPumpErrorInformation { public static Dictionary EdwardsPumpParameters = new Dictionary() { { 1,"System Node status"}, { 3,"Pump Current"}, { 4,"Pump Power"}, { 7,"Booster Current"}, { 8,"Booster Power"}, { 11,"Dry Pump Control"}, { 12,"Booster Control"}, { 14,"Pump Run hours"}, { 16,"Pcocess hours"}, { 21,"Time to Stop"}, { 34,"N2 flow state"}, { 35,"N2 flow rate"}, { 39,"Exhaust pressure"}, { 46,"Gas ballast"}, { 47,"Inlet/cleaning purge (valve 2)"}, { 48,"Zero Sensors Countdown"}, { 50,"System Run Hours"}, { 52,"Analogue water flow rate"}, { 53,"Active gauge voltage input"}, { 54,"MB Stator temperature"}, { 55,"TCS Reference Temperature"}, { 56,"Exhaust temperature"}, { 57,"DP end cover temperature"}, { 60,"Discrete water flow OK switch"}, { 62,"MB end cover temperature"}, { 68,"On/Off Process"}, { 70,"DP stator temperature 2"}, { 72,"Pump speed demand"}, { 84,"Exhaust pipe temperature"}, { 85,"Accessories Module Cold Junction Temperature"}, { 89,"Purge Gas Heater control"}, { 116,"Pump Power (iXL120 only)"}, { 152,"Gate Valve ls Closed"}, { 153,"Gate Valve ls Open"}, { 161,"Gate Valve Control"}, { 170,"Booster inverter powered elapsed days"}, { 173,"Booster inverter heatsink temperature"}, { 174,"Booster Actual Speed"}, { 175,"Booster Actual Speed Percent"}, { 177,"Booster Speed Reference"}, { 178,"Booster Off Process Speed Reference"}, { 180,"Pump Inverter powered elapsed days"}, { 183,"Pump inverter heatsink temperature"}, { 184,"Pump Actual Speed Hz"}, { 185,"Pump Actual Speed Percent"}, { 187,"Pump Speed Reference"}, { 188,"Pump Off Process Speed Reference"}, { 211,"Gas -Inlet 1"}, { 212,"Gas - 3rd 8 4th"}, { 213,"Gas -4th or 5th"}, { 214,"Gas -LV"}, { 215,"Gas -Bypass"}, { 216,"Gas -Exhaust 1"}, { 217,"Gas - Exhaust 2"}, { 219,"Gas - Seals"}, { 222,"Both Pumps Start"}, { 224,"Dry Pump Start"}, { 226,"Run Til Crash"}, { 227,"Auto/Fast Shutdown"}, { 228,"Open Gate Valve"}, { 230,"Process ON/AUC"}, { 231,"Remote/Local Control (Relay)"}, { 233,"Booster Running (Relay)"}, { 234,"Pump Running (Relay)"}, { 235,"Final Valve Signal (Relay)'Qualification inhibit'"}, { 236,"General Warning (Relay)"}, { 237,"Gas Flow Warning (Relay)"}, { 239,"Exhaust Pressure Warning (Relay)"}, { 240,"Water Flow Warning (Relay)"}, { 241,"Alarm (Relay)"}, { 242,"MicroTim in control LED"}, { 245,"Pump inverter Controller Temperature"}, { 246,"Booster inverter Controller Temperature"}, }; public static Dictionary EdwardsPumpPriorityLevel = new Dictionary { { 0,"Indication only; no warning or alarm."}, { 1,"Warning condition exists."}, { 2,"Alarm condition exists: shut down the pump unless run til crash is set."}, { 3,"Alarm condition exists: shut down the pump."} }; public static Dictionary EdwardsPumpAlarmType = new Dictionary { { 0,"No alarm"}, { 1,"Digital alarm"}, { 9,"Low warning"}, { 10,"Low alarm"}, { 11,"High warning"}, { 12,"High alarm"}, { 13,"Device error"}, { 14,"Device not present"} }; public static Dictionary EdwardsPumpBitFieldStatus = new Dictionary() { { 0,"Module missing"}, { 1,"Sensor present at switch-on, but now disconnected"}, { 2,"Wrong gas module fitted"}, { 3,"Voltage above valid maximum voltage"}, { 4,"Voltage below valid minimum voltage"}, { 5,"ADC(analogue to digital convertor) not operating"}, { 6,"Electrical supply has been interrupted"}, { 7,"Watchdog reset has occurred"}, { 8,"Sensor missing at switch on"}, { 9,"Module switching on"}, { 10,"No current consumption at pump switch-on"}, { 11,"Wrong phase input to pump"}, { 12,"EMS (emergency stop) has been activated"}, { 13,"Flow sensor zero out of range"}, { 14,"cannot zero sensors"}, { 15,"Configuration set read error"}, }; } 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------------------------ // private Stopwatch _pumpOnTimeWatch = new Stopwatch(); public EdwardsPumpState StatusDry { get; set; } private string oldAlarm; public string LastPMTime { get { return _statPumpOnTime != null ? _statPumpOnTime.LastPMTime.ToString() : ""; } } public float DaysFromLastPM { get { return _statPumpOnTime == null ? 0 : _statPumpOnTime.fromLastPM; } set { if (_statPumpOnTime != null) _statPumpOnTime.fromLastPM = value; } } public float 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; } } private List searchList = new List() { EdwardsPumpMessage.QUERY_Pump_Status, EdwardsPumpMessage.QUERY_Information }; private int i = 0; // --------------------------Constructor----------------------- // public EdwardsPump(ModuleName mod) : base(mod.ToString(), VenusDevice.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 EdwardsPump(ModuleName mod, string name) : base(mod.ToString(), VenusDevice.MainPump.ToString(), "Edwards Pump", "") { _PortNum = SC.GetStringValue($"{mod.ToString()}.{name}.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; LOG.Write(eEvent.ERR_DRY_PUMP, 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_LONG_REPLY); SendCmd(EdwardsPumpMessage.COMMAND_Take_Control); _timerQueryStatus.Start(CHK_ST_INTERVAL); _timerControlStatus.Start(CHK_CONTROL_INTERVAL); _timerReceiveStatus.Start(CHK_REC_INTERVAL); DATA.Subscribe($"{Module}.PumpOnTime", () => StatsDataManager.Instance.GetRFPumpTotalTime($"{Module}.PumpOnTime")); return true; } private void OnErrorOccurred(string obj) { //StatusDry = EdwardsPumpState.ERROR; LOG.Write(eEvent.WARN_DEVICE_INFO, Module, $"[{Module}] edwards pump error: [{obj}]"); } private void OnPortDataChanged(string obj) { if (string.IsNullOrEmpty(obj)) LOG.Write(eEvent.WARN_DEVICE_INFO, 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: LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Take Control Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.COMMAND_Release_Control: LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Release Control Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.COMMAND_Switch_on_Pump: LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Switch on Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.COMMAND_Switch_off_Pump_Fast_shut_down: LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Switch off Edwards Pump {QueryCmdReply(cmd)}"); break; case EdwardsPumpMessage.QUERY_Pump_Status: string[] cmds = cmd.Split(','); if (cmds[0] == "0") { StatusDry = EdwardsPumpState.OFF; if (_trigPumpOn.Q && _timerPumpOn.IsTimeout()) { _trigPumpOn.RST = true; LOG.Write(eEvent.WARN_DEVICE_INFO, Module, "Edwards Pump 无法打开"); } if (_trigPumpOff.Q) { LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Edwards Pump关闭"); } _trigPumpOff.RST = true; } else if (cmds[0] == "4") { StatusDry = EdwardsPumpState.ON; if (_trigPumpOff.Q && _timerPumpOff.IsTimeout()) { _trigPumpOff.RST = true; LOG.Write(eEvent.WARN_DEVICE_INFO, Module, "Edwards Pump 无法关闭"); } if (_trigPumpOn.Q) { LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Edwards Pump打开"); } _trigPumpOn.RST = true; } break; case EdwardsPumpMessage.QUERY_Information: if (oldAlarm == cmd) { break; } oldAlarm = cmd; string[] infos = cmd.Split(';'); int number = int.Parse(infos[0]); if (number > 0 && infos.Length > 1) { for (int i = 1; i < infos.Length; i++) { string detail = infos[i]; string[] details = detail.Split(','); if (details.Length == 4) { int parameterCode = int.Parse(details[0]); int priorityCode = int.Parse(details[1]); int alarmTypeCode = int.Parse(details[2]); int bitStatusCode = int.Parse(details[3]); string parameterDesc = EdwardsPumpErrorInformation.EdwardsPumpParameters.ContainsKey(parameterCode) ? EdwardsPumpErrorInformation.EdwardsPumpParameters[parameterCode] : "UnKnowParameter"; string priorityDesc = EdwardsPumpErrorInformation.EdwardsPumpPriorityLevel.ContainsKey(priorityCode) ? EdwardsPumpErrorInformation.EdwardsPumpPriorityLevel[priorityCode] : "UnknowPriority"; string alarmTypeDesc = EdwardsPumpErrorInformation.EdwardsPumpAlarmType.ContainsKey(alarmTypeCode) ? EdwardsPumpErrorInformation.EdwardsPumpAlarmType[alarmTypeCode] : "UnknowAlarmType"; var bitStatus = ConvertIntToBitArray(bitStatusCode); string bitbitStatusDesc = ""; for (int j = 0; j < 16; j++) { if (bitStatus[j] == true) { bitbitStatusDesc += EdwardsPumpErrorInformation.EdwardsPumpBitFieldStatus.ContainsKey(j) ? EdwardsPumpErrorInformation.EdwardsPumpBitFieldStatus[j] : "UnKnowStatus"; bitbitStatusDesc += " "; } } if (priorityCode == 0 ||priorityCode == 1) { LOG.Write(eEvent.WARN_DEFAULT_WARN, Module, $"Code:{detail},Parameter:{parameterDesc},Priority:{priorityDesc},Alarm Type:{alarmTypeDesc},Status:{bitbitStatusDesc}]"); } else { LOG.Write(eEvent.ERR_DRY_PUMP, Module, $"Code:{detail},Parameter:{parameterDesc},Priority:{priorityDesc},Alarm Type:{alarmTypeDesc},Status:{bitbitStatusDesc}]"); } } } } break; default: LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Edwards Pump {SendData} {QueryCmdReply(cmd)}"); break; } } catch (Exception ex) { LOG.WriteExeption($"[{Module}] edwards pump error: ", ex); } } 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()) { string cmd = searchList[i]; this.SendCmd(cmd); _timerQueryStatus.Start(CHK_ST_INTERVAL); i = (i + 1) % searchList.Count; } //if (_timerReceiveStatus.IsTimeout()) //{ // _trigReceiveStatus.CLK = true; // if (_trigReceiveStatus.Q) // { // //EV.PostMessage(Module, EventEnum.DefaultWarning, "Edwards Pump 没有回复"); // //EV.PostAlarmLog(Module, "Edwards Pump 没有回复",) // } //} _trigOnOff.CLK = IsRunning; //第一次检测到打开了,开始计时 if (_trigOnOff.R) { _total = TotalDays; _fromLast = DaysFromLastPM; _timerTotal.Start(0); _timerFromLast.Start(0); _pumpOnTimeWatch.Start(); } //第一次检测到从打开到关闭状态 if (_trigOnOff.T) { } //如果开着,就更新SC if (_trigOnOff.M && _pumpOnTimeWatch.ElapsedMilliseconds > 1000) { TotalDays = (float)1 / 60 / 60; DaysFromLastPM = (float)1 / 60 / 60; _pumpOnTimeWatch.Restart(); //_timerTotal.Restart(0); //_timerFromLast.Restart(0); if (ModuleHelper.IsPm(Module)) { StatsDataManager.Instance.Increase($"{Module}.PumpOnTime", $"{Module} PumpOnTime", DaysFromLastPM, TotalDays); } } if (PMIntervalDays > 0) { _trigPMNeeded.CLK = IsPMNeeded; if (_trigPMNeeded.Q) { if (EnableAlarm) { EV.PostAlarmLog(Module, "pump on time value larger than setting interval days"); } } } //if (ModuleHelper.IsPm(Module)) // 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.Write(eEvent.EV_DEVICE_INFO, Module, $"[{Module}] Switch on Edwards Pump"); } else if (SendData == "!P2") { _trigPumpOff.CLK = true; _timerPumpOff.Start(CHK_PUMP_REC_INTERVAL); LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"[{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 ResetPumpStats() { _statPumpOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.PumpOnTime"); } public override void SetPumpOnOff(bool on) { SendCmd(on ? EdwardsPumpMessage.COMMAND_Switch_on_Pump : EdwardsPumpMessage.COMMAND_Switch_off_Pump_Fast_shut_down); } public override bool ReConnect() { return _serial.ReConnect(); } private bool[] ConvertIntToBitArray(int number) { bool[] bits = new bool[sizeof(int) * 8]; for (int i = 0; i < bits.Length; i++) { bits[i] = (number & (1 << i)) != 0; } return bits; } } }