using System; using System.IO.Ports; using System.Text; using Aurora.Api; using Aurora.Api.Devices; using Hermes; using PropertyTools.DataAnnotations; namespace AuroraChiller { //우선 Aurora의 SmcChiller를 가져와서 LASA에 필요한 부분을 넣어주자 public enum ChillerErrorCode : int { NoError = -1, MemoryError = 0, OutOfSetRange = 1, SettingNotAllowd = 2, AbnormalCode = 3, FormatError = 4, BccError = 5, OverrunError = 6, FlemingError = 7, ParityError = 8, Unknown = 9 } public interface IMonitoringItems { } public enum eTemperatureStatus { ERROR_LOW, WARNING_LOW, OK, WARNING_HIGH, ERROR_HIGH } public enum eAlarmStatus1_Bit { LOW_LEVEL_TANK = 0, //0 Low level in tank OVER_TEMP1, //1 High circulating fluid discharge temp. OVER_TEMP2, //2 Circulating fluid discharge temp. rise OVER_TEMP3, //3 Circulating fluid discharge temp. OVER_TEMP4, //4 High circulating fluid return temp. ERR_PRESSURE1, //5 High circulating fluid discharge pressure ERR_PUMP, //6 Abnormal pump operation ERR_PRESSURE2, //7 Circulating fluid discharge pressure rise ERR_PRESSURE3, //8 Circulating fluid discharge pressure drop ERR_COMPRESSOR1, //9 High compressor intake temp. ERR_COMPRESSOR2, //10 Low compressor intake temp. OVER_TEMP5, //11 Low super heat temperature ERR_COMPRESSOR3, //12 High compressor discharge pressure ERR_UNUSED1, //13 Unused ERR_PRESSURE4, //14 Refrigerant circuit pressure (high pressure side) drop ERR_PRESSURE5, //15 Refrigerant circuit pressure (low CNT } public enum eAlarmStatus2_Bit { ERR_PRESSURE = 0, //0 Refrigerant circuit pressure (low pressure side) drop OVERLOAD, //1 Compressor overload ERR_COMM, //2 Communication error ERR_MEM, //3 Memory error ERR_DC, //4 DC line fuse cut ERR_SENSOR_TEMP1, //5 Circulating fluid discharge temp. sensor failure ERR_SENSOR_TEMP2, //6 Circulating fluid return temp. sensor failure ERR_SENSOR_COMPRESS1, //7 Compressor intake temp. sensor failure ERR_SENSOR_PRESSURE1, //8 Circulating fluid discharge pressure sensor failure ERR_SENSOR_PRESSURE2, //9 Compressor discharge pressure sensor failure ERR_SENSOR_COMPRESS2, //10 Compressor intake pressure sensor failure MAINTENANCE_PUMP, //11 Maintenance of pump MAINTENANCE_MOTOR, //12 Maintenance of fan motor MAINTENANCE_COMPRESS, //13 Maintenance of compressor ERR_SIGNAL1, //14 Contact input 1 signal detection alarm ERR_SIGNAL2, //15 Contact input 2 signal detection alarm CNT } public enum eAlarmStatus3_Bit { WATER_LEAKAGE = 0, // 0 Water leakage ERR_ELECTRIC1, //1 Electric resistivity/conductivity level rise ERR_ELECTRIC2, //2 Electric resistivity/conductivity level drop ERR_ELECTRIC3, //3 Electric resistivity/conductivity sensor error UNSUED1, //4 Unused UNSUED2, //5 Unused UNSUED3, //6 Unused UNSUED4, //7 Unused UNSUED5, //8 Unused UNSUED6, //9 Unused UNSUED7, //10 Unused UNSUED8, //11 Unused UNSUED9, //12 Unused UNSUED10, //13 Unused UNSUED11, //14 Unused UNSUED12, //15 Unused CNT } public class SmcChillerMonitoringItems : IMonitoringItems, ICloneable { //public double TargetTempCH1 { get; set; } //public double CurrentTempCH1 { get; set; } //public double TargetTempCH2 { get; set; } //public double CurrentTempCH2 { get; set; } public double TargetTemp { get; set; } public double CurrentTemp { get; set; } public double WarningRange { get; set; } public double ErrorRange { get; set; } public eTemperatureStatus TempStatus { get; set; } /* public bool[] arrAlamSt1 = new bool[(int)eAlarmStatus1_Bit.CNT]; public bool[] arrAlamSt2 = new bool[(int)eAlarmStatus2_Bit.CNT]; public bool[] arrAlamSt3 = new bool[(int)eAlarmStatus3_Bit.CNT]; */ public int AlamSt1 { get; set; } public int AlamSt2 { get; set; } public int AlamSt3 { get; set; } public int AlamSt4 { get; set; } public int Status { get; set; } public object Clone() { return new SmcChillerMonitoringItems() { //TargetTempCH1 = TargetTempCH1, //CurrentTempCH1 = CurrentTempCH1, TargetTemp = TargetTemp, CurrentTemp = CurrentTemp, WarningRange = WarningRange, ErrorRange = ErrorRange, TempStatus = TempStatus, AlamSt1 = AlamSt1, AlamSt2 = AlamSt2, AlamSt3 = AlamSt3, AlamSt4 = AlamSt4, Status = Status }; } } public class SmcChiller : SerialPortDevice { private readonly bool _IsSimulBySetting; public const byte BYTE_STX = 0x02; // 02 public const byte BYTE_ETX = 0x03; // 03 public const byte BYTE_ACK = 0x06; // 06 public const byte BYTE_NAK = 0x15; // 21 public const byte BYTE_0 = 0x30; // 48 public const byte BYTE_1 = 0x31; // 49 public const byte BYTE_5 = 0x35; // 53 public const byte BYTE_CR = 0x0D; public const byte BYTE_LF = 0x0A; public const string CMD_PV1 = "PV1"; public const string CMD_SV1 = "SV1"; public const string CMD_LOC = "LOC"; public const string CMD_STR = "STR"; public const byte BYTE_REQ_READ = 0x52; // 82 public const byte BYTE_REQ_WRITE = 0x57; // 87 public const byte LENGTH_READ_REQUEST_MSG = 8; public const byte LENGTH_WRITE_REQUEST_MSG = 13; public const byte LENGTH_SAVE_REQUEST_MSG = 8; public const byte LENGTH_RESPONSE_MSG = 14; public const byte LENGTH_SLAVE_ADDRESS = 2; public const byte LENGTH_WRITE_ADDRESS = 4; public const byte LENGTH_CMD = 3; public const byte LENGTH_DATA_INTEGER = 4; public const byte LENGTH_DATA_DECIMAL_FRACTION = 1; public const byte LENGTH_DATA = 4; public const byte LENGTH_READ_REGISTER_MSG = 17; public const byte LENGTH_RESPONSE_REGISTER_MSG = 255; private Config _Config; private SmcChillerMonitoringItems MonitoringItems; private bool bIsSimpleCommMode = false; #region Simulation private double SimulTargetTemp; #endregion public int DeviceNo = 0; public SmcChiller(string deviceId, int deviceNo, bool isSimul = false) : base(deviceId, isSimul) { _IsSimulBySetting = isSimul; MonitoringItems = new SmcChillerMonitoringItems(); DeviceNo = deviceNo; } protected override int DoActivate(IDeviceConfig config) { _Config = config as Config; IsSimul = _Config.IsSimul || _IsSimulBySetting; //임시 if (IsSimul) { return E1.OK; } var result = Open(_Config.ConnConfig as SerialConnConfig); if (result != E1.OK) { return result; } return Init(); } private int Init() { // Set init vaues from config if (!IsValidSlaveAddress(_Config.SlaveAddress)) { return E1.GENERIC; } if (IsSimul) { SimulTargetTemp = 10; } else { // TargetTemperature 설정은 장치에서 직접 설정한다. // SetTargetTemp(_Config.TargetTemperature); } return E1.OK; } public bool GetConnected() { if (!IsPortOpen()) { Log.E("SMC Chiller Serial Port is NOT Open!"); return false; } return true; } public int GetTemperatureStatus(int Channel) { double TargetTemperature = 0; double CurrentTemperature = 0; int nRetTarget = GetTargetTemp(Channel, out TargetTemperature); int nRetCurrent = GetCurrentTemp(Channel, out CurrentTemperature); if (nRetTarget == 0 && nRetCurrent == 0) { eTemperatureStatus eTemperatureStatus = ValidateTemp( TargetTemperature, CurrentTemperature, MonitoringItems.WarningRange, MonitoringItems.ErrorRange); return (int)eTemperatureStatus; } else return -1; } public bool GetChillerRunningFlag() { bool bReturn = ((MonitoringItems.Status & (1 << 1)) > 0) ? true : false; return bReturn; } private bool IsValidSlaveAddress(int slaveAddress) { return (1 <= slaveAddress && slaveAddress <= 99); } protected override int DoDeactivate() { if (IsSimul) { return E1.OK; } else { return Close(); } } public int GetTargetTemp(int Channel, out double temperature) { if (IsSimul) { temperature = SimulTargetTemp; return E1.OK; } if (bIsSimpleCommMode == false) { //if (Channel == 1) { // temperature = MonitoringItems.TargetTempCH1; //} else { // temperature = MonitoringItems.TargetTemp; //} temperature = MonitoringItems.TargetTemp; return E1.OK; } return ReadDoubleData(CMD_SV1, out temperature); } public int GetCurrentTemp(int Channel, out double temperature) { if (IsSimul) { // ex) scale = 5, [0.0, 1.0] => [-0.5, 0.5] => [-1, 1] => [-5, 5] double scale = 5; double randomValue = ((new Random().NextDouble() - 0.5) * 2) * scale; temperature = SimulTargetTemp + randomValue; return E1.OK; } if (bIsSimpleCommMode == false) { //if (Channel == 1) { // temperature = MonitoringItems.CurrentTempCH1; //} else { // temperature = MonitoringItems.CurrentTemp; //} temperature = MonitoringItems.CurrentTemp; return E1.OK; } return ReadDoubleData(CMD_PV1, out temperature); } public int ReadKeyLockSetting(out int settingValue) { if (IsSimul) { settingValue = 0; return E1.OK; } return ReadIntData(CMD_LOC, out settingValue); } private int ReadDoubleData(string cmd, out double readData) { readData = 0; if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { byte[] requestMsg = CreateReadRequestMsg(cmd); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (ReadMessage(responseMsg, BYTE_STX, BYTE_ETX) <= 0) { Log.E("ReadError"); return E1.GENERIC; } var errorCode = ValidateReadResponse(responseMsg, cmd); if (errorCode != ChillerErrorCode.NoError) { Log.E("ExceptionCode : {0}", errorCode.ToString()); return E1.GENERIC; } readData = ExtractDoubleData(responseMsg); } } return E1.OK; } private int ReadIntData(string cmd, out int readData) { readData = 0; if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { byte[] requestMsg = CreateReadRequestMsg(cmd); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (ReadMessage(responseMsg, BYTE_STX, BYTE_ETX) <= 0) { Log.E("ReadError"); return E1.GENERIC; } var errorCode = ValidateReadResponse(responseMsg, cmd); if (errorCode != ChillerErrorCode.NoError) { Log.E("ExceptionCode : {0}", errorCode.ToString()); return E1.GENERIC; } readData = ExtractIntData(responseMsg); } } return E1.OK; } private byte[] CreateReadRequestMsg(string cmd) { byte[] requestMsg = new byte[LENGTH_READ_REQUEST_MSG]; byte[] cmdByte = Encoding.Default.GetBytes(cmd); byte[] slaveAddress = GetSlaveAddress(); requestMsg[0] = BYTE_STX; Array.Copy(slaveAddress, 0, requestMsg, 1, LENGTH_SLAVE_ADDRESS); requestMsg[3] = BYTE_REQ_READ; Array.Copy(cmdByte, 0, requestMsg, 4, LENGTH_CMD); requestMsg[requestMsg.Length - 1] = BYTE_ETX; requestMsg = AppendBcc(requestMsg); return requestMsg; } //public int SetTargetTemp(double temperature) //{ // if (IsSimul) // { // SimulTargetTemp = temperature; // return E1.OK; // } // // TargetTemperature 설정은 장치에서 직접 설정하기 때문에 에러처리 한다. // return SetData(CMD_SV1, ConvertDataDoubleToString(temperature)); // //return E1.GENERIC; //} public int SetKeyLockSetting(int settingValue) { return SetData(CMD_LOC, ConvertDataIntToString(settingValue)); } private int SetData(string cmd, string writeDataStr) { if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { byte[] requestMsg = CreateWriteRequestMsg(cmd, writeDataStr); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (ReadMessage(responseMsg, BYTE_STX, BYTE_ETX) <= 0) { Log.E("ReadError"); return E1.GENERIC; } var errorCode = ValidateWriteResponse(responseMsg, cmd); if (errorCode != ChillerErrorCode.NoError) { Log.E("ExceptionCode : {0}", errorCode.ToString()); return E1.GENERIC; } } } return E1.OK; } private byte[] CreateWriteRequestMsg(string cmd, string writeData) { byte[] requestMsg = new byte[LENGTH_WRITE_REQUEST_MSG]; byte[] cmdByte = Encoding.Default.GetBytes(cmd); byte[] slaveAddress = GetSlaveAddress(); byte[] writeDataByte = Encoding.Default.GetBytes(writeData); requestMsg[0] = BYTE_STX; Array.Copy(slaveAddress, 0, requestMsg, 1, LENGTH_SLAVE_ADDRESS); requestMsg[3] = BYTE_REQ_WRITE; Array.Copy(cmdByte, 0, requestMsg, 4, LENGTH_CMD); Array.Copy(writeDataByte, 0, requestMsg, 7, LENGTH_DATA); requestMsg[requestMsg.Length - 1] = BYTE_ETX; requestMsg = AppendBcc(requestMsg); return requestMsg; } public int SaveData() { if (IsSimul) return E1.OK; if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { string cmd = CMD_STR; byte[] requestMsg = CreateSaveRequestMsg(cmd); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (ReadMessage(responseMsg, BYTE_STX, BYTE_ETX) <= 0) { Log.E("ReadError"); return E1.GENERIC; } var errorCode = ValidateWriteResponse(responseMsg, cmd); if (errorCode != ChillerErrorCode.NoError) { Log.E("ExceptionCode : {0}", errorCode.ToString()); return E1.GENERIC; } } } return E1.OK; } private byte[] CreateSaveRequestMsg(string cmd) { byte[] requestMsg = new byte[LENGTH_SAVE_REQUEST_MSG]; byte[] cmdByte = Encoding.Default.GetBytes(cmd); byte[] slaveAddress = GetSlaveAddress(); requestMsg[0] = BYTE_STX; Array.Copy(slaveAddress, 0, requestMsg, 1, LENGTH_SLAVE_ADDRESS); requestMsg[3] = BYTE_REQ_WRITE; Array.Copy(cmdByte, 0, requestMsg, 4, LENGTH_CMD); requestMsg[requestMsg.Length - 1] = BYTE_ETX; requestMsg = AppendBcc(requestMsg); return requestMsg; } private byte[] GetSlaveAddress() { return Encoding.Default.GetBytes( ConvertSlaveAddressIntToString(_Config.SlaveAddress)); } private byte[] AppendBcc(byte[] msg) { if (!_Config.BccEnable) { return msg; } byte[] bccMsg = new byte[msg.Length + 1]; Array.Copy(msg, bccMsg, msg.Length); bccMsg[bccMsg.Length - 1] = CalculateBcc(msg); return bccMsg; } private static byte CalculateBcc(byte[] msg) { if (msg.Length == 0) { return 0; } if (msg.Length == 1) { return msg[0]; } byte bcc = (byte)(msg[0] ^ msg[1]); for (int i = 2; i < msg.Length; i++) { bcc ^= msg[i]; } return bcc; } private ChillerErrorCode ValidateReadResponse(byte[] msg, string cmd) { return Validate(msg, cmd, enableCmdCheck: true); } private ChillerErrorCode ValidateWriteResponse(byte[] msg, string cmd) { return Validate(msg, cmd, enableCmdCheck: false); } private ChillerErrorCode Validate(byte[] msg, string cmd, bool enableCmdCheck) { if (msg.Length <= 0 || (enableCmdCheck && ExtractCmd(msg) != cmd)) { return ChillerErrorCode.Unknown; } if (!ValidateBcc(msg)) { return ChillerErrorCode.BccError; } if (ExtractAck(msg) == BYTE_ACK) { return ChillerErrorCode.NoError; } else { return ExtractErrorCode(msg); } } private bool ValidateBcc(byte[] msg) { if (!_Config.BccEnable) { return true; } byte[] subMsg = new byte[msg.Length - 1]; Array.Copy(msg, 0, subMsg, 0, subMsg.Length); if (subMsg[0] != BYTE_STX || subMsg[subMsg.Length - 1] != BYTE_ETX) { return false; } return CalculateBcc(subMsg) == ExtractBcc(msg); } private byte ExtractAck(byte[] msg) { return msg[3]; } private ChillerErrorCode ExtractErrorCode(byte[] msg) { return (ChillerErrorCode)(msg[4] - BYTE_0); } private string ExtractCmd(byte[] msg) { string strMsg = Encoding.Default.GetString(msg); return strMsg.Substring(4, LENGTH_CMD); } private double ExtractDoubleData(byte[] msg) { string msgStr = Encoding.Default.GetString(msg); string dataStr = msgStr.Substring(7, LENGTH_DATA); return ConvertDataStringToDouble(dataStr); } private int ExtractIntData(byte[] msg) { string msgStr = Encoding.Default.GetString(msg); string dataStr = msgStr.Substring(7, LENGTH_DATA); return ConvertDataStringToInt(dataStr); } private byte ExtractBcc(byte[] msg) { return msg[msg.Length - 1]; } private static int ConvertSlaveAddressStringToInt(string addressStr) { return Convert.ToInt32(addressStr); } private static string ConvertSlaveAddressIntToString(int address) { return string.Format("{0:00}", address); } private static double ConvertDataStringToDouble(string valueStr) { string intStr = valueStr.Substring(0, LENGTH_DATA_INTEGER); string dfStr = valueStr.Substring(0 + LENGTH_DATA_INTEGER, LENGTH_DATA_DECIMAL_FRACTION); return Convert.ToDouble(intStr) + (Convert.ToDouble(dfStr) * 0.1); } private static string ConvertDataDoubleToString(double value) { return string.Format("{0:0000}", value * 10); } private static int ConvertDataStringToInt(string valueStr) { return Convert.ToInt32(valueStr); } private static string ConvertDataIntToString(int value) { return string.Format("{0:0000}", value); } public int UpdateMonitoringItems() { lock (LockThis) { if (bIsSimpleCommMode) { if (E1.OK == GetCurrentTemp(1, out double currentTemp)) { //MonitoringItems.CurrentTempCH1 = currentTemp; } //if (IsSimul) { // MonitoringItems.TargetTempCH1 = SimulTargetTemp; //} else { // if (E1.OK == GetTargetTemp(2, out double targetTemp)) { // MonitoringItems.TargetTempCH1 = targetTemp; // } //} // //MonitoringItems.WarningRange = _Config.WarningRange; //MonitoringItems.ErrorRange = _Config.ErrorRange; // //MonitoringItems.TempStatus = ValidateTemp( // MonitoringItems.TargetTempCH1, // MonitoringItems.CurrentTempCH1, // MonitoringItems.WarningRange, // MonitoringItems.ErrorRange); // // return E1.OK; //} else { // if (IsSimul) { // return E1.OK; // } // ReadRegister(); // //MonitoringItems.TargetTemp = _Config.TargetTemp; // MonitoringItems.WarningRange = _Config.WarningRange; // MonitoringItems.ErrorRange = _Config.ErrorRange; // // MonitoringItems.TempStatus = ValidateTemp( // MonitoringItems.TargetTempCH1, // MonitoringItems.CurrentTempCH1, // MonitoringItems.WarningRange, // MonitoringItems.ErrorRange); // return E1.OK; //} MonitoringItems.WarningRange = _Config.WarningRange; MonitoringItems.ErrorRange = _Config.ErrorRange; MonitoringItems.TempStatus = ValidateTemp( MonitoringItems.TargetTemp, MonitoringItems.CurrentTemp, MonitoringItems.WarningRange, MonitoringItems.ErrorRange); return E1.OK; } ReadRegister(); return 1; } } private static eTemperatureStatus ValidateTemp(double targetTemp, double currentTemp, double warningRange, double errorRange) { var tempDiff = currentTemp - targetTemp; if (Math.Abs(tempDiff) <= warningRange) { return eTemperatureStatus.OK; } else if (Math.Abs(tempDiff) <= errorRange) { return (tempDiff < 0) ? eTemperatureStatus.WARNING_LOW : eTemperatureStatus.WARNING_HIGH; } else { return (tempDiff < 0) ? eTemperatureStatus.ERROR_LOW : eTemperatureStatus.ERROR_HIGH; } } public IMonitoringItems GetMonitoringItems() { lock (LockThis) { return MonitoringItems.Clone() as IMonitoringItems; } } public class Config : IDeviceConfig { [DisplayName("Simulation Mode (this device)")] public bool IsSimul { get; set; } = false; public IConnConfig ConnConfig { get; set; } //AuroraMachine에 있는 항목임.. 나중에 필요없으면 빼도 됨 [Category("Alarm")] public double TargetTemp { get; set; } = 20; public double WarningRange { get; set; } = 5; public double ErrorRange { get; set; } = 10; [Category("Communication")] public int SlaveAddress { get; set; } = 1; public bool BccEnable { get; set; } = true; //IConnConfig IDeviceConfig.ConnConfig { get; set; } public Config() { ConnConfig = new SerialConnConfig() { BaudRate = 9600, Parity = Parity.Even, // None StopBits = StopBits.One, // Two DataBits = 7 // 8 }; } public static Config CreateDefault() { return new Config(); } } private byte[] CreateReadRegisterMsg() { byte[] requestMsg = new byte[LENGTH_READ_REGISTER_MSG]; string strReadMessage = ConvertSlaveAddressIntToString(_Config.SlaveAddress) + "03" + "0000" + "000B";//250527 byte[] bccMessage = HexStringToByteArray(strReadMessage); byte[] byteReadMessage = Encoding.Default.GetBytes(strReadMessage); byte[] bcc = CalculateLRC(bccMessage); requestMsg[0] = (byte)(':'); Array.Copy(byteReadMessage, 0, requestMsg, 1, byteReadMessage.Length); Array.Copy(bcc, 0, requestMsg, 13, bcc.Length); requestMsg[15] = BYTE_CR; requestMsg[16] = BYTE_LF; //string check = Encoding.Default.GetString(requestMsg); return requestMsg; } private byte[] CreateReadRegisterMsg2() { byte[] requestMsg = new byte[LENGTH_READ_REGISTER_MSG]; byte[] slaveAddress = GetSlaveAddress(); requestMsg[0] = (byte)(':'); Array.Copy(slaveAddress, 0, requestMsg, 1, LENGTH_SLAVE_ADDRESS); requestMsg[3] = (byte)('0'); requestMsg[4] = (byte)('3'); requestMsg[5] = (byte)('0'); requestMsg[6] = (byte)('0'); requestMsg[7] = (byte)('0'); requestMsg[8] = (byte)('B'); requestMsg[9] = (byte)('0'); requestMsg[10] = (byte)('0'); requestMsg[11] = (byte)('0'); requestMsg[12] = (byte)('0'); requestMsg[13] = (byte)('F'); requestMsg[14] = (byte)('1'); requestMsg[15] = BYTE_CR; requestMsg[16] = BYTE_LF; return requestMsg; } private bool ParsingRegisterData(byte[] responseMsg) { if (responseMsg[3] != (byte)'0' || responseMsg[4] != (byte)'3') // 읽기는 03 return false; if (responseMsg[5] != (byte)'1' || responseMsg[6] != (byte)'6') return false; string msgStr = Encoding.Default.GetString(responseMsg); //Information of 0000h (circulating fluid discharge temperature) //responseMsg[7,8,9,10] string dataStr = msgStr.Substring(7, 4); int currenttemp = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.CurrentTemp = (double)currenttemp / 10; //Information of 0001h (circulating fluid discharge temperature ch2) //responseMsg[11,12,13,14] dataStr = msgStr.Substring(11, 4); //Information of 0002h (Electric resistivity / conductivity of the circulating fluid) //responseMsg[15,16,17,18] dataStr = msgStr.Substring(15, 4); // 순환액 토출 압력 int Electric = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); //Information of 0003h (Electric resistivity / conductivity of the circulating fluid ch2) //responseMsg[19,20,21,22] dataStr = msgStr.Substring(19, 4); //Information of 0004h (circulating fluid discharge pressure) //responseMsg[23,24,25,26] dataStr = msgStr.Substring(23, 4); int Status = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.Status = Status; //Information of 0005h (circulating fluid discharge pressure ch2) //responseMsg[27,28,29,30] dataStr = msgStr.Substring(27, 4); int Alarm1 = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.AlamSt1 = Alarm1; //Information of 0006h (circulating fluid flow rate) //responseMsg[31,32,33,34] dataStr = msgStr.Substring(31, 4); int Alarm2 = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.AlamSt2 = Alarm2; //Information of 0007h (circulating fluid flow rate ch2) //responseMsg[35,36,37,38] dataStr = msgStr.Substring(35, 4); int Alarm3 = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.AlamSt3 = Alarm3; //Information of 0008h (Data1) //responseMsg[39,40,41,42] dataStr = msgStr.Substring(39, 4); int Alarm4 = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.AlamSt4 = Alarm4; //Information of 0009h (Data2) //responseMsg[43,44,45,46] dataStr = msgStr.Substring(43, 4); //Information of 000Ah (Data3) //responseMsg[47,48,49,50] dataStr = msgStr.Substring(47, 4); //Information of 000Bh (Data4) //responseMsg[51,52,53,54] dataStr = msgStr.Substring(51, 4); int targetTemp = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); MonitoringItems.TargetTemp = (double)targetTemp / 10; return true; } private bool ParsingAllRequestData(byte[] responseMsg, int RequestAddress) { if (responseMsg[3] != (byte)'0' || responseMsg[4] != (byte)'3') return false; string msgStr = Encoding.Default.GetString(responseMsg); string dataStr = msgStr.Substring(7, 4); int RequestAddressData = Int32.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); bool bResult = ((RequestAddressData & (1 << RequestAddress)) > 0) ? true : false; return bResult; } private int ReadRegister() { if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } if(IsSimul) return E1.OK; lock (LockThis) { byte[] requestMsg = CreateReadRegisterMsg(); var request = Encoding.ASCII.GetString(requestMsg); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_REGISTER_MSG]; if (ReadMessage(responseMsg, (byte)(':'), BYTE_LF) <= 0) { Log.E("ReadError"); return E1.GENERIC; } var recv = Encoding.ASCII.GetString(responseMsg); if (ParsingRegisterData(responseMsg) == false) return E1.GENERIC; } } return E1.OK; } private bool ReadAllRequestStatus(string strReg, string strValue, string strFunc) { if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return false; } lock (LockThis) { byte[] requestMsg = CreateWriteRegisterMsg(strReg, strValue, strFunc); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_REGISTER_MSG]; if (ReadMessage(responseMsg, (byte)(':'), BYTE_LF) <= 0) { Log.E("ReadError"); return false; } return ParsingAllRequestData(responseMsg, Convert.ToInt32(strValue)); } } return false; } public int SetAllRequest(int iValue) { if (IsSimul) { return E1.OK; } string strReg = "06"; string strValue = iValue.ToString("X4"); // 입력받은 int변수(iValue)를 4자리 16진수로 만듦 string strFunc = "000C"; // 운전 개시 지시 return WriteRegister(strReg, strValue, strFunc); } public bool GetAllRequestStatus(string bitValue) { if (IsSimul) { return false; } string strReg = "04"; string strValue = bitValue; string strFunc = "000C"; // 운전 개시 지시, 원래 0042였음 return ReadAllRequestStatus(strReg, strValue, strFunc); } public int SetRunStart(bool bStart) { if (IsSimul) { return E1.OK; } if (bStart) { SetAllRequest(1); return E1.OK; } else { SetAllRequest(0); return E1.OK; } } public int RequestTest() { if (IsSimul) { return E1.OK; } SetAllRequest(2); return E1.OK; } public int SetTargetTemp(double value) { if (IsSimul) { SimulTargetTemp = value; return E1.OK; } int iValue = (int)(value * 10); string strReg = "06"; // 레지스터 쓰기 string strValue = iValue.ToString("X4"); string strFunc = "000B"; // 순환액 설정 온도 Log.I($"칠러 온도 설정 >> {iValue}"); return WriteRegister(strReg, strValue, strFunc); } public int SetTargetTemp(string Channel, double value) { if (IsSimul) { SimulTargetTemp = value; return E1.OK; } string strFunc = ""; int iValue = (int)(value * 10); string strReg = "06"; string strValue = iValue.ToString("X4");//ConvertDataDoubleToString(value); if (Channel == "CH1") { strFunc = "0040"; //64.ToString("X4");//ConvertDataIntToString(40); } if (Channel == "CH2") { strFunc = "0041"; //64.ToString("X4");//ConvertDataIntToString(40); } return WriteRegister(strReg, strValue, strFunc); } private int WriteRegister(string Reg, string value, string Func) { if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { byte[] requestMsg = CreateWriteRegisterMsg(Reg, value, Func); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_REGISTER_MSG]; if (ReadMessage(responseMsg, (byte)(':'), BYTE_LF) <= 0) { Log.E("ReadError"); return E1.GENERIC; } } } return E1.OK; } private int WriteRegisterTest(string Reg, string value, string Func) { if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { string requestMsg = CreateWriteRegisterMsgTest(Reg, value, Func); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_REGISTER_MSG]; if (ReadMessage(responseMsg, (byte)(':'), BYTE_LF) <= 0) { Log.E("ReadError"); return E1.GENERIC; } } } return E1.OK; } private int WriteRequestRegister(string Reg, string value, string Func) { if (!IsPortOpen()) { Log.E("Serial Port is NOT Open!"); return E1.NETWORK; } lock (LockThis) { byte[] requestMsg = CreateWriteRegisterMsg(Reg, value, Func); if (Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_REGISTER_MSG]; if (ReadMessage(responseMsg, (byte)(':'), BYTE_LF) <= 0) { Log.E("ReadError"); return E1.GENERIC; } if (ParsingRegisterData(responseMsg) == false) return E1.GENERIC; } } return E1.OK; } private byte[] CreateWriteRegisterMsg(string Reg, string value, string Func) { string strWriteMessage = ConvertSlaveAddressIntToString(_Config.SlaveAddress) + "06" + Func + value; // slave address + 쓰기 레지스터 + 레지스터 지시 + 입력받은 int값을 16진수로 변환한 값 byte[] requestMsg = new byte[LENGTH_READ_REGISTER_MSG]; // 17자리 배열 byte[] bccMessage = HexStringToByteArray(strWriteMessage); // 16진수 문자열을 바이트 배열로 변환 byte[] byteWriteMessage = Encoding.Default.GetBytes(strWriteMessage); // 문자열의 바이트를 입력? 근데 왜 배열로 받지? byte[] bcc = CalculateLRC(bccMessage); // 문자열의 LRC requestMsg[0] = (byte)(':'); // start Array.Copy(byteWriteMessage, 0, requestMsg, 1, byteWriteMessage.Length); Array.Copy(bcc, 0, requestMsg, 13, bcc.Length); requestMsg[15] = BYTE_CR; // end requestMsg[16] = BYTE_LF; // end string check = Encoding.Default.GetString(requestMsg); return requestMsg; } private string CreateWriteRegisterMsgTest(string Reg, string value, string Func) { string strWriteMessage = ConvertSlaveAddressIntToString(_Config.SlaveAddress) + "06" + Func + value; byte[] requestMsg = new byte[LENGTH_READ_REGISTER_MSG]; byte[] bccMessage = HexStringToByteArray(strWriteMessage); byte[] byteWriteMessage = Encoding.Default.GetBytes(strWriteMessage); byte[] bcc = CalculateLRC(bccMessage); requestMsg[0] = (byte)(':'); Array.Copy(byteWriteMessage, 0, requestMsg, 1, byteWriteMessage.Length); Array.Copy(bcc, 0, requestMsg, 13, bcc.Length); requestMsg[15] = BYTE_CR; requestMsg[16] = BYTE_LF; string check = Encoding.Default.GetString(requestMsg); return check; } private byte[] CalculateLRC(byte[] bytes) { int sum = 0; foreach (byte b in bytes) { sum += b; } byte truncatedSum = (byte)(sum & 0xFF); byte lrc = (byte)((~truncatedSum + 1) & 0xFF); string lrcHex = lrc.ToString("X2"); return new byte[] { (byte)lrcHex[0], (byte)lrcHex[1] }; } private byte[] HexStringToByteArray(string hex) // 16진수 문자열을 바이트 배열로 변환 { int length = hex.Length; byte[] bytes = new byte[length / 2]; for (int i = 0; i < length; i += 2) { bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); } return bytes; } } }