1187 lines
41 KiB
C#
1187 lines
41 KiB
C#
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;
|
|
}
|
|
|
|
|
|
}
|
|
} |