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 { //interface IPumpControl //{ // bool IsRunning { get; } // void TurnON(); // void TurnOFF(); //} public enum SkyPumpState { ON = 0, OFF, Connected, Disconnected, Unknown, ERROR } static class SkyPumpMessage { public const string EOF = "\r\n"; public const string SET_ON = "@00CON_FDP_ON"; public const string SET_OFF = "@00CON_FDP_OFF"; public const string GET_ON = "@00FDP_ONOK"; // \0\r\n public const string GET_OFF = "@00FDP_OFFOK"; // \0\r\n public const string READ_DATA = "@00READ_RUN_PARA"; public const string GET_DATA = "@00RUN_PARA"; } class SkyPump : PumpBase { // ----------------------------Fields-------------------------- // private const ushort CHK_ST_INTERVAL = 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 string _fdp_Current = null; private string _roots_Current = null; private string _fdp_Temp = null; private string _roots_Temp = null; private string _n2Flow = null; private string _pressure = null; private string _runTime = null; private readonly AsyncSerialPort _serial; private readonly DeviceTimer _timerQueryStatus = 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 SkyPumpState StatusDry { get; set; } public SkyPumpState StatusRoose { get; set; } public string FDP_Current { get { return _fdp_Current; } } public string ROOTS_Current { get { return _roots_Current; } } public string FDP_Temp { get { return _fdp_Temp; } } public string ROOTS_Temp { get { return _roots_Temp; } } public string N2Flow { get { return _n2Flow; } } public string Pressure { get { return _pressure; } } public string RunTime { get { return _runTime; } } 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 == SkyPumpState.ON; } } [Subscription(AITPumpProperty.IsError)] public override bool IsError { get { return StatusDry == SkyPumpState.ERROR || StatusDry == SkyPumpState.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 SkyPump(ModuleName mod) : base(mod.ToString(), VirgoDevice.MainPump.ToString(), "SKY pump", "") { _PortNum = SC.GetStringValue($"{mod}.DryPump.Port"); StatusDry = SkyPumpState.Unknown; _serial = new AsyncSerialPort(_PortNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "\r\n", false); } public override bool Initialize() { base.Initialize(); if (!_serial.Open()) { StatusDry = SkyPumpState.Disconnected; EV.PostAlarmLog(this.Module, "Sky Pump串口无法打开"); return false; } _statPumpOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.PumpOnTime"); StatusDry = SkyPumpState.Connected; _trigPumpOn.RST = true; _trigPumpOff.RST = true; _trigReceiveStatus.RST = true; _serial.OnDataChanged += OnPortDataChanged; _serial.OnBinaryDataChanged += OnPortBinaryDataChanged; _serial.OnErrorHappened += OnErrorOccurred; _timerQueryStatus.Start(CHK_ST_INTERVAL); _timerReceiveStatus.Start(CHK_REC_INTERVAL); return true; } private void OnPortBinaryDataChanged(byte[] obj) { try { _timerReceiveStatus.Stop(); _timerReceiveStatus.Start(CHK_REC_INTERVAL); _trigReceiveStatus.RST = true; var strData = System.Text.Encoding.ASCII.GetString(obj); if (strData.Contains(SkyPumpMessage.EOF)) { string cmd = ""; if (obj.Length == 14 || obj.Length >= 40) cmd = Encoding.ASCII.GetString(obj, 0, 11); else if (obj.Length == 15) cmd = Encoding.ASCII.GetString(obj, 0, 12); if (cmd == SkyPumpMessage.GET_ON) { _trigPumpOn.CLK = true; _timerPumpOn.Start(CHK_PUMP_REC_INTERVAL); LOG.Info($"[{Module}] {SkyPumpMessage.GET_ON}"); return; } if (cmd == SkyPumpMessage.GET_OFF) { _trigPumpOff.CLK = true; _timerPumpOff.Start(CHK_PUMP_REC_INTERVAL); LOG.Info($"[{Module}] {SkyPumpMessage.GET_OFF}"); return; } if (cmd == SkyPumpMessage.GET_DATA) { _fdp_Current = Encoding.ASCII.GetString(obj, 11, 2); _roots_Current = Encoding.ASCII.GetString(obj, 13, 2); _fdp_Temp = Encoding.ASCII.GetString(obj, 15, 3); _roots_Temp = Encoding.ASCII.GetString(obj, 18, 3); _n2Flow = Encoding.ASCII.GetString(obj, 21, 2); _pressure = Encoding.ASCII.GetString(obj, 23, 4); _runTime = Encoding.ASCII.GetString(obj, 27, 5); ParaErrSta1(new BitArray(new byte[] { obj[32] })); ParaErrSta2(new BitArray(new byte[] { obj[33] })); ParaRunSta(new BitArray(new byte[] { obj[34] })); //ParaRunSta(new BitArray(new byte[] { obj[35] })); ParaErrSta3(new BitArray(new byte[] { obj[36] })); } } else { if (!SC.GetValue("System.IsSimulatorMode")) { LOG.Info($"[{Module}] Sky Pump 数据无效:[{strData}]"); } } } catch (Exception ex) { if (!SC.GetValue("System.IsSimulatorMode")) { LOG.Error($"[{Module}] sky pump data para error: [{ex.Message}]"); } } } private void OnErrorOccurred(string obj) { StatusDry = SkyPumpState.ERROR; LOG.Error($"[{Module}] sky pump error: [{obj}]"); } private void OnPortDataChanged(string obj) { if (string.IsNullOrEmpty(obj)) LOG.Error($"[{Module}] sky pump message IsNullOrEmpty"); try { string cmd = obj.ToString().Split('\n')[0].Split('\r')[0]; if (cmd == SkyPumpMessage.GET_ON) { LOG.Info($"[{Module}] {SkyPumpMessage.GET_ON}"); return; } if (cmd == SkyPumpMessage.GET_OFF) { LOG.Info($"[{Module}] {SkyPumpMessage.GET_OFF}"); return; } if (cmd.Substring(0, 11) == SkyPumpMessage.GET_DATA) { _fdp_Current = cmd.Substring(11, 2); _roots_Current = cmd.Substring(13, 2); _fdp_Temp = cmd.Substring(15, 3); _roots_Temp = cmd.Substring(18, 3); _n2Flow = cmd.Substring(21, 2); _pressure = cmd.Substring(23, 4); _runTime = cmd.Substring(27, 5); ParaErrSta1(new BitArray(new byte[] { Convert.ToByte(cmd[32]) })); ParaErrSta2(new BitArray(new byte[] { Convert.ToByte(cmd[33]) })); ParaRunSta(new BitArray(new byte[] { Convert.ToByte(cmd[34]) })); //ParaRunSta(new BitArray(new byte[] { Convert.ToByte(cmd[35]) })); ParaErrSta3(new BitArray(new byte[] { Convert.ToByte(cmd[36]) })); } } catch(Exception ex) { LOG.Error($"[{Module}] sky pump error: [{ex.Message}]"); } } public void ParaErrSta1(BitArray bits) { for (int i = 0; i < bits.Count; i++) { if (bits[i]) ErrSta1(i); } } public void ParaErrSta2(BitArray bits) { for (int i = 0; i < bits.Count; i++) { if (bits[i]) ErrSta2(i); } } public void ParaErrSta3(BitArray bits) { for (int i = 0; i < bits.Count; i++) { if (bits[i]) ErrSta3(i); } } public void ParaRunSta(BitArray bits) { string sRes = "sky pump status: "; for (int i = 0; i < bits.Count; i++) { if (bits[i]) sRes += RunStaTure(i); else sRes += RunStaFalse(i); } _counter++; if (_counter == _counterMax) { _counter = 0; //LOG.Info($"[{Module}] {sRes}"); } } public string RunStaTure(int code) { switch (code) { case 7: return "远程。"; case 6: StatusDry = SkyPumpState.ON; if (_trigPumpOn.Q) { EV.PostInfoLog(this.Module, $"Dry Pump打开"); } if (_trigPumpOff.Q && _timerPumpOff.IsTimeout()) { _trigPumpOff.RST = true; EV.PostMessage(Module, EventEnum.DefaultWarning, "Dry Pump 无法关闭"); } _trigPumpOn.RST = true; return "干泵开, "; case 5: StatusRoose = SkyPumpState.ON; return "罗茨泵开, "; case 4: return "泵冷阀开, "; case 3: return "清洗阀开, "; case 2: return "有警示, "; case 1: return "有故障, "; case 0: return "无水, "; default: return ""; } } public string RunStaFalse(int code) { switch (code) { case 7: return "本地。"; case 6: StatusDry = SkyPumpState.OFF; if (_trigPumpOn.Q && _timerPumpOn.IsTimeout()) { _trigPumpOn.RST = true; EV.PostMessage(Module, EventEnum.DefaultWarning, "Dry Pump 无法打开"); } if (_trigPumpOff.Q) { EV.PostInfoLog(this.Module, $"Dry Pump关闭"); } _trigPumpOff.RST = true; return "干泵关, "; case 5: StatusRoose = SkyPumpState.OFF; return "罗茨泵关, "; case 4: return "泵冷阀关, "; case 3: return "清洗阀关, "; case 2: return "无警示, "; case 1: return "无故障, "; case 0: return "有水, "; default: return ""; } } public void ErrSta1(int error) { switch (error) { case 7: LOG.Error($"[{Module}]上泵变频器除通讯外故障"); break; case 6: LOG.Error($"[{Module}]下泵变频器除通讯外故障"); break; case 5: LOG.Error($"[{Module}]上泵接触器"); break; case 4: LOG.Error($"[{Module}]下泵接触器"); break; case 3: LOG.Error($"[{Module}]上泵电机过热"); break; case 2: LOG.Error($"[{Module}]下泵电机过热"); break; case 1: LOG.Error($"[{Module}]急停"); break; case 0: LOG.Error($"[{Module}]水冷"); break; default: break; } } public void ErrSta2(int error) { switch (error) { case 7: LOG.Error($"[{Module}]下泵变频器通讯故障"); break; case 6: LOG.Error($"[{Module}]上泵变频器通讯故障"); break; case 5: LOG.Error($"[{Module}]排气压力"); break; case 4: LOG.Error($"[{Module}]氮气流量"); break; case 3: LOG.Error($"[{Module}]下泵电流"); break; case 2: LOG.Error($"[{Module}]上泵电流"); break; case 1: LOG.Error($"[{Module}]下泵温度"); break; case 0: LOG.Error($"[{Module}]上泵温度"); break; default: break; } } public void ErrSta3(int error) { switch (error) { case 7: case 6: case 5: case 4: case 3: case 2: break; case 1: LOG.Error($"[{Module}]下泵温度传感器未连接"); break; case 0: LOG.Error($"[{Module}]上泵温度传感器未连接"); break; default: break; } } public override void Monitor() { try { // 状态查询 if (_timerQueryStatus.IsTimeout() && this.StatusDry != SkyPumpState.ERROR) { this.SendCmd(SkyPumpMessage.READ_DATA); _timerQueryStatus.Start(CHK_ST_INTERVAL); } if (_timerReceiveStatus.IsTimeout() && this.StatusDry != SkyPumpState.ERROR) { _trigReceiveStatus.CLK = true; if(_trigReceiveStatus.Q) { EV.PostMessage(Module, EventEnum.DefaultWarning, "Dry 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) { return _serial.Write(str + "\r"); } public override void Reset() { _trigPumpOn.RST = true; _trigPumpOff.RST = true; _trigReceiveStatus.RST = true; _trigPMNeeded.RST = true; //SetPumpOnOff(false); } public override void Terminate() { //if (StatusDry == SkyPumpState.ON) // SetPumpOnOff(false); _serial?.Close(); } public override void SetPumpOnOff(bool on) { SendCmd(on ? SkyPumpMessage.SET_ON : SkyPumpMessage.SET_OFF); } } }