using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.Device; 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.Equipment; using MECF.Framework.Common.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using static Mono.Security.X509.X520; using Venus_Core; using System.Diagnostics; namespace Venus_RT.Devices { /// /// 描述:该类用于对单Chiller Controller下多设备共享 的驱动 只单一的用于串口的连接 /// 需要存储的变量及说明 /// Statusflag:与chiller的开关有关 /// Alarmflag: 报警 /// chillerIsOn:正在进行 /// ControlTcFeedback:返回值 /// public enum ChillerMsgType { Get, Set } public class SMCChillerDrive { public SMCChillerState StatusSMC { get; set; } private readonly string _PortNum = "COM92"; private readonly AsyncSerialPort _serial; BlockingCollection blockingCollection = new BlockingCollection(); public string PortName => _PortNum; private Dictionary _address2Module;//不正确 应该以字典的形式 以头去打印 private Dictionary _addressQuery; private Dictionary> _addressCmdQueue; private ModuleName Module;//不正确 应该以字典的形式 以头去打印 // --------------------------Constructor----------------------- // public SMCChillerDrive(string Port) { _PortNum = Port; StatusSMC = SMCChillerState.Unknown; _serial = new AsyncSerialPort(_PortNum, 9600, 7, System.IO.Ports.Parity.Even, System.IO.Ports.StopBits.One, "\r\n", true); if (!_serial.Open()) { StatusSMC = SMCChillerState.Disconnected; LOG.Write(eEvent.ERR_DEVICE_CHILLER, ModuleName.System, $"SMC Chiller串口:{_PortNum}无法打开"); } StatusSMC = SMCChillerState.Connected; _serial.OnDataChanged += OnPortDataChanged; _serial.OnErrorHappened += OnErrorOccurred; _address2Module = new Dictionary(); _addressQuery = new Dictionary(); _addressCmdQueue = new Dictionary>(); Task.Run(() => { foreach (var data in blockingCollection.GetConsumingEnumerable()) { _serial?.Write(data); System.Threading.Thread.Sleep(500); } }); } private void OnPortDataChanged(string obj) { try { if (SC.GetValue("System.IsSimulatorMode")) { //Statusflag[0] = true; //if (_controlTcSetPoint <= SetPointLimitMax / 2 && _controlTcSetPoint >= SetPointLimitMin) // _controlTcFeedback = _controlTcSetPoint; return; } if (string.IsNullOrEmpty(obj)) { LOG.Write(eEvent.ERR_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}] smc chiller message IsNullOrEmpty"); return; } string cmd = obj.Split(new char[] { '\r', '\n' })[0]; //若为system或null 说明dic中无value或value无效 //Debug.Assert(chillerData != null && module != ModuleName.System); if (ModbusUtility.CalculateLrc(ModbusUtility.HexToBytes(cmd.Substring(1, cmd.Length - 3))).ToString("X2") != cmd.Substring(cmd.Length - 2)) //LRC check { LOG.Write(eEvent.ERR_DEVICE_CHILLER, Module, $"[{_PortNum}] smc chiller message LRC check error"); return; } //注意 数据开头有":" //地址位 决定了是哪个chamber的哪个type ModuleName module = ModuleName.System; //LOG.Write(eEvent.INFO_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}] smc chiller receive message {cmd}"); string header = cmd.Substring(1, 2); if (_address2Module.ContainsKey(header) && _addressQuery.ContainsKey(header)) { module = ModuleHelper.Converter(_address2Module[header].Split('.')[0]); //LOG.Write(eEvent.INFO_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}] smc chiller know module:{_address2Module[cmd.Substring(1, 2)]},{cmd.Substring(1, 2)}"); } else { LOG.Write(eEvent.ERR_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}]:address => {header} not in Dictionary"); return; } switch (cmd.Substring(3, 2)) //function code { case "03": //返回的寄存器内容 if (cmd.Substring(5, 2) == "16") //返回了全部11个寄存器、22个Byte数据 { ChillerData chillerdata = new ChillerData(); for (int iRegisterNo = 0; iRegisterNo < 11; iRegisterNo++) { string sBuf = cmd.Substring(4 * iRegisterNo + 7, 4); int iBuf = 0; for (int i = 3; i > -1; i--) { iBuf += Convert.ToInt32(sBuf.Substring(i, 1), 16) * (int)Math.Pow(16, 3 - i); } switch (iRegisterNo) { case 0: //Circulating fluid discharge temperature if (iBuf > 32767) // 16位数的最大正值 { iBuf -= 65536; // 转换为负值 } chillerdata.ControlTcFeedback = (float)iBuf / 10; break; case 4: //Status flag 1 for (int i = 0; i < 16; i++) { chillerdata.Statusflag[i] = Convert.ToBoolean((int)Math.Pow(2, i) & iBuf); } break; case 5: //Alarm flag 1 for (int i = 0; i < 16; i++) { chillerdata.Alarmflag[i] = Convert.ToBoolean((int)Math.Pow(2, i) & iBuf); } break; case 6: //Alarm flag 2 for (int i = 0; i < 16; i++) { chillerdata.Alarmflag[i + 16] = Convert.ToBoolean((int)Math.Pow(2, i) & iBuf); } break; case 7: //Alarm flag 3 for (int i = 0; i < 16; i++) { chillerdata.Alarmflag[i + 32] = Convert.ToBoolean((int)Math.Pow(2, i) & iBuf); } break; case 9: //Status flag 2 for (int i = 0; i < 16; i++) { chillerdata.Statusflag[i + 16] = Convert.ToBoolean((int)Math.Pow(2, i) & iBuf); } break; } } _addressCmdQueue[header].Dequeue(); _addressQuery[header] = chillerdata; } break; case "06": //寄存器的写成功消息 break; } } catch (Exception ex) { LOG.Write(eEvent.ERR_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}] smc chiller error: [{ex.Message}]"); } } private void OnErrorOccurred(string obj) { StatusSMC = SMCChillerState.ERROR; LOG.Write(eEvent.ERR_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}] smc chiller error: [{obj}]"); } public void SendCmd(ChillerMsgType type,string str) { //消息通用格式:开头 + 内容 + LRC + 结尾 //_serial?.Write(":" + str + ModbusUtility.CalculateLrc(ModbusUtility.HexToBytes(str)).ToString("X2") + "\r\n"); //如果是设置的直接发出无需等待 if (type == ChillerMsgType.Set) { blockingCollection.Add(":" + str + ModbusUtility.CalculateLrc(ModbusUtility.HexToBytes(str)).ToString("X2") + "\r\n"); } //如果是获取的可以慢一些 在数据回复后继续 if (type == ChillerMsgType.Get) { //每interval获取温度 超过一秒时效性失去意义 500 * 2积累太多数据 同时注意其是与monitor紧密联系的 实际上是每interval就会进来可能导致数组变大 //因此每次进来要控制规模 > 2 时 实时性已经失去此时应该等待回复并把头前的清除掉 而且要注意 chiller本身升温很慢 界面上ramp不明显 _addressCmdQueue[str.Substring(0, 2)].Enqueue(str); if (_addressCmdQueue[str.Substring(0, 2)].Count > 1) _addressCmdQueue[str.Substring(0, 2)].Dequeue(); else blockingCollection.Add(":" + _addressCmdQueue[str.Substring(0, 2)].Peek() + ModbusUtility.CalculateLrc(ModbusUtility.HexToBytes(str)).ToString("X2") + "\r\n"); } } public void AddAddress(string address, string chillertype) { //address => "02" chillertype => PMA.OutChiller _address2Module.Add(address,chillertype); _addressQuery.Add(address, new ChillerData()); _addressCmdQueue.Add(address, new Queue()); } public ChillerData QueryData(string address) { if (_addressQuery.ContainsKey(address)) { return _addressQuery[address]; } else { LOG.Write(eEvent.ERR_DEVICE_CHILLER, ModuleName.System, $"[{_PortNum}] => address:{address} not exist"); return null; } } public void Terminate() { _serial?.Close(); } } public class ChillerData { public bool[] Statusflag {get; set;} public bool[] Alarmflag { get; set; } public float ControlTcFeedback { get; set; } public ChillerData() { Statusflag = new bool[32]; Alarmflag = new bool[48]; ControlTcFeedback = 0.0f; } } }