using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.RT.Tolerance; using Aitex.Core.Util; using MECF.Framework.Common.Communications; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Equipment; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace JetVirgoPM.Devices { class AIRSYSChiller : ChillerBase { private float _controlTcSetPoint; private float _controlTcFeedback; private readonly double _scSetPointLimitMax; private readonly double _scSetPointLimitMin; private readonly string _PortNum = "COM48"; private readonly AsyncSerialPort _serial; private readonly DeviceTimer _timerQueryStatus = new DeviceTimer(); private const ushort CHK_ST_INTERVAL = 300; public enum Operation { ReadTemperature, ReadStatus, ReadFlowRate, ReadResistivity, UnitStart, UnitStop, SelectThermoProbe, SetTemperature, SetResistivity, } private readonly Dictionary _noneParaCommandOp = new Dictionary { {Operation.ReadTemperature, "AA10\r" }, {Operation.ReadStatus, "AA42\r" }, {Operation.ReadFlowRate, "AAB1\r" }, {Operation.ReadResistivity, "AAB2\r" }, {Operation.UnitStart, "AA90\r" }, {Operation.UnitStop, "AA91\r" }, {Operation.SelectThermoProbe, "AAA1\r" }, }; private readonly Dictionary _oneParaCommandOp = new Dictionary { {Operation.SetTemperature, "AAB0{0:X4}\r" }, {Operation.SetResistivity, "AAB3{0:X4}\r" }, }; public double SetPointLimitMax { get { return _scSetPointLimitMax; ; } } public double SetPointLimitMin { get { return _scSetPointLimitMin; ; } } [Subscription(AITChillerProperty.ControlTcSetPoint)] public float ControlTcSetPoint { get { return _controlTcSetPoint; } } [Subscription(AITChillerProperty.ControlTcFeedback)] public float ControlTcFeedback { get { return _controlTcFeedback; } } [Subscription(AITChillerProperty.CoolantInletTempFeedback)] public float CoolantInletTcFeedback { get { if (Name == "Chiller2") { return GetAiValue($"{Module}.AI_2_CoolantInletTemp"); } return GetAiValue($"{Module}.AI_1_CoolantInletTemp"); } } [Subscription(AITChillerProperty.CoolantOutletTempFeedback)] public float CoolantOutletTcFeedback { get { if (Name == "Chiller2") { return GetAiValue($"{Module}.AI_2_CoolantOutletTemp"); } return GetAiValue($"{Module}.AI_1_CoolantOutletTemp"); } } public override AITChillerData DeviceData { get { AITChillerData deviceData = new AITChillerData { Module = Module, DeviceName = Name, DeviceModule = Module, DeviceSchematicId = DeviceID, DisplayName = Display, IsError = false, IsWarning = false, IsPowerOn = IsRunning, ScaleMax = SetPointLimitMax, ScaleMin = SetPointLimitMin, SetPoint = ControlTcSetPoint, FeedBack = CoolantOutletTcFeedback, CoolantInletFeedBack = CoolantInletTcFeedback, CoolantOutletFeedBack = CoolantOutletTcFeedback, Unit = "℃", }; return deviceData; } } private SCConfigItem _scAlarmRange; private SCConfigItem _scEnableAlarm; private SCConfigItem _scAlarmTime; private ToleranceChecker _toleranceChecker = new ToleranceChecker(); private string _lastAlarmString; private int _operation_flag = 0; public AIRSYSChiller(ModuleName mod, string name) : base(mod.ToString(), name, name, "") { if (Module == "PMB" && SC.GetValue($"PMB.Chiller.ChillerSameWithPMA") && SC.GetValue($"PMB.Chiller.EnableChiller")) return; _PortNum = SC.GetStringValue($"{mod}.{Name}.Port"); _scSetPointLimitMax = SC.GetValue($"{Module}.{Name}.SetPointLimitMax"); _scSetPointLimitMin = SC.GetValue($"{Module}.{Name}.SetPointLimitMin"); _scEnableAlarm = SC.GetConfigItem($"{Module}.{Name}.EnableToleranceAlarm"); _scAlarmRange = SC.GetConfigItem($"{Module}.{Name}.ToleranceAlarmRange"); _scAlarmTime = SC.GetConfigItem($"{Module}.{Name}.ToleranceAlarmTime"); _serial = new AsyncSerialPort(_PortNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.Two, "\r", true); } public override bool Initialize() { base.Initialize(); if (!_serial.Open()) { LOG.Error($"{Module}AIRSYS Chiller串口无法打开"); EV.PostAlarmLog(this.Module, "AIRSYS Chiller串口无法打开"); return false; } _serial.OnDataChanged += OnPortDataChanged; _serial.OnErrorHappened += OnErrorOccurred; _timerQueryStatus.Start(CHK_ST_INTERVAL); return true; } public override void Monitor() { if (_timerQueryStatus.IsTimeout()) { Operation queryOp = _operation_flag++ % 2 == 0 ? Operation.ReadStatus : Operation.ReadTemperature; _sendCommand(queryOp); _timerQueryStatus.Start(CHK_ST_INTERVAL); } if (IsRunning && _scEnableAlarm != null && _scEnableAlarm.BoolValue) { var range = _scAlarmRange.IntValue; var time = _scAlarmTime.IntValue; _toleranceChecker.Monitor(_controlTcFeedback, _controlTcSetPoint - Math.Abs(range), _controlTcSetPoint + Math.Abs(range), time); if (_toleranceChecker.Trig) { LOG.Error($"{Module} {Display} temperature out of tolerance in {time:0} seconds"); EV.PostAlarmLog(Module, Display + $" temperature out of tolerance in {time:0} seconds"); } } else { _toleranceChecker.RST = true; } } private void OnPortDataChanged(string obj) { if (obj.StartsWith("AA")) { string op = obj.Substring(2, 2); switch (op) { case "42": ushort significate_status = ushort.Parse(obj.Substring(4, 2), System.Globalization.NumberStyles.HexNumber); ushort low_significatate_status = ushort.Parse(obj.Substring(6, 2), System.Globalization.NumberStyles.HexNumber); _process_signicate_chiller_status(significate_status); _process_low_signicate_chiller_status(low_significatate_status); break; case "10": _controlTcFeedback = (float)Int32.Parse(obj.Substring(4, 4), System.Globalization.NumberStyles.HexNumber) / (float)10.0; break; } } else { _noRepeatAlarm($"AIRSYS chiller receive wrong message:{obj}"); } } private void OnErrorOccurred(string obj) { LOG.Error($"[{Module}] AIRSYS chiller error: [{obj}]"); } public override void SetChillerTemp(float value, float offset) { int isettemp = Convert.ToInt16((value - offset) * 10); _sendCommand(Operation.SetTemperature, isettemp); _controlTcSetPoint = value; } public override void SetChillerOnOff(bool on) { IsRunning = on; _sendCommand(on ? Operation.UnitStart : Operation.UnitStop); } private bool _sendCommand(Operation op) { if (_noneParaCommandOp.ContainsKey(op)) { return _sendCmd(_noneParaCommandOp[op]); } _noRepeatAlarm($"Adixen Turbo Pump: The {op} command need parameters"); return false; } private bool _sendCommand(Operation op, int data) { if (_oneParaCommandOp.ContainsKey(op)) { var cmd = string.Format(_oneParaCommandOp[op], data); return _sendCmd(cmd); } _noRepeatAlarm($"Adixen Turbo Pump: The command {op} does not need one parameter"); return false; } private bool _sendCmd(string cmd) { return _serial.Write(cmd); } private void _noRepeatAlarm(string alarm) { if (_lastAlarmString != alarm) { _lastAlarmString = alarm; LOG.Error($"[{Module}] {alarm}"); } } private void _process_signicate_chiller_status(ushort status) { StringBuilder errorInfo = new StringBuilder(); if ((status & 0x80) != 0) { errorInfo.Append("Memory Data Error Fault; "); } if ((status & 0x40) != 0) { errorInfo.Append("Controller Error Fault; "); } if ((status & 0x20) != 0) { errorInfo.Append("Pump Breaker Trip Fault; "); } if ((status & 0x10) != 0) { errorInfo.Append("Heater Breaker Trip Fault; "); } if ((status & 0x08) != 0) { errorInfo.Append("Water Leak Fault; "); } if ((status & 0x04) != 0) { errorInfo.Append("Return Low Flow Fault; "); } if ((status & 0x02) != 0) { errorInfo.Append("Reservoir High Temperature Fault; "); } if ((status & 0x01) != 0) { errorInfo.Append("Reservoir Low Level Fault; "); } if (errorInfo.Length > 10) { IsError = true; _noRepeatAlarm($"AIRSYS chiller status error:{errorInfo}"); } else { IsError = true; } } private void _process_low_signicate_chiller_status(ushort status) { StringBuilder errorInfo = new StringBuilder(); if ((status & 0x80) != 0) { errorInfo.Append("Temperature Fuse Fault; "); } if ((status & 0x40) != 0) { errorInfo.Append("DC Power Fuse Fault; "); } if ((status & 0x02) != 0) { errorInfo.Append("Reservoir High Temperature Warning; "); } if ((status & 0x01) != 0) { errorInfo.Append("Reservoir Low Level Warning; "); } if (errorInfo.Length > 10) { _noRepeatAlarm($"AIRSYS chiller status error:{errorInfo}"); } } } }