using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LFP_Manager.DataStructure;
using LFP_Manager.Utils;
using LFP_Manager.Controls;
using System.Web.Services.Description;
using System.Data.Entity.Core.Common.CommandTrees;
using DevExpress.XtraRichEdit.Fields.Expression;
using DevExpress.XtraRichEdit.Layout;
using DevExpress.XtraPrinting.Native.LayoutAdjustment;
using System.Windows.Forms;

namespace LFP_Manager.Function
{
    class csSerialCommFunction124050
    {
        public const byte READ_COIL_STATUS = 0x01;
        public const byte READ_HOLDING_REG = 0x03;
        public const byte READ_INPUT_REG = 0x04;                 //Byul 구문 추가 필요
        public const byte FORCE_SINGLE_COIL = 0x05;
        public const byte PRESET_SINGLE_REG = 0x06;
        public const byte PRESET_MULTI_REG = 0x10;
        public const byte WRITE_COIL_REG = 0x0F;
        public const byte ERROR_REG = 0x90;

        public const byte FW_FLASH_ERASE_CMD = 0x43;
        public const byte FW_FLASH_WRITE_CMD = 0x31;

        public const byte NO_CMD = 0xFF;

        public static byte[] GetCRC(byte[] pby, int nSize)
        {
            ushort uIndex, i;
            ushort crc;
            byte uchCRCHi = 0xff;
            byte uchCRCLo = 0xff;
            byte[] result = new byte[2];

            for (i = 0; i < nSize; i++)
            {
                uIndex = (ushort)((int)uchCRCLo ^ (int)pby[i]);
                uchCRCLo = (byte)(uchCRCHi ^ csUtils.auchCRCHi[uIndex]);
                uchCRCHi = csUtils.auchCRCLo[uIndex];
            }
            crc = (ushort)((uchCRCHi << 8) | uchCRCLo);

            result[0] = (byte)(crc >> 8);
            result[1] = (byte)(crc >> 0);

            return result;
        }

        static public byte[] MakeReadRegisterData(ushort DevID, ushort cmd, ushort ReadAddr, ushort Size)
        {
            byte[] result = new byte[8];
            byte[] crc;

            result[0] = (byte)DevID;                // Device ID
            result[1] = (byte)cmd;     // Command
            result[2] = (byte)(ReadAddr >> 8);      // Register Address MSB
            result[3] = (byte)(ReadAddr >> 0);      // Register Address LSB
            result[4] = (byte)(Size >> 8);          // Count of Register MSB
            result[5] = (byte)(Size >> 0);          // Count of Register LSB

            crc = GetCRC(result, 6);

            result[6] = crc[1];                       // CRCH
            result[7] = crc[0];                       // CRCL

            return result;
        }

        static public byte[] MakeWriteCoilData(ushort DevID, ushort WriteAddr, short WriteData)
        {
            byte[] result = new byte[7 + (1 * 1) + 2];
            byte[] crc;
            ushort i = 0;

            result[i++] = (byte)DevID;                  // Device ID
            result[i++] = (byte)WRITE_COIL_REG;       // Command
            result[i++] = (byte)(WriteAddr >> 8);       // Register Address MSB
            result[i++] = (byte)(WriteAddr >> 0);       // Register Address LSB
            result[i++] = (byte)(1 >> 8);            // Count of Register MSB
            result[i++] = (byte)(1 >> 0);            // Count of Register LSB
            result[i++] = (byte)(1 * 1);             // Byte Count - [2 * (Num of register)]

            result[i++] = (byte)(WriteData >> 0);

            crc = GetCRC(result, i);

            result[i++] = crc[1];                       // CRCH
            result[i++] = crc[0];                       // CRCL

            return result;
        }

        static public byte[] MakeWriteRegisterData(ushort DevID, ushort WriteAddr, short[] WriteData)
        {
            byte[] result = new byte[9 + (WriteData.Length * 2)];
            byte[] crc;
            ushort i = 0;

            result[i++] = (byte)DevID;                              // Device ID
            result[i++] = (byte)PRESET_MULTI_REG;                   // Command
            result[i++] = (byte)(WriteAddr >> 8);                   // Register Address MSB
            result[i++] = (byte)(WriteAddr >> 0);                   // Register Address LSB
            result[i++] = (byte)(WriteData.Length >> 8);            // Count of Register MSB
            result[i++] = (byte)(WriteData.Length >> 0);            // Count of Register LSB
            result[i++] = (byte)(WriteData.Length * 2);             // Byte Count - [2 * (Num of register)]

            for (int j = 0; j < WriteData.Length; j++)
            {
                result[i++] = (byte)(WriteData[j] >> 8);
                result[i++] = (byte)(WriteData[j] >> 0);
            }

            crc = GetCRC(result, i);

            result[i++] = crc[1];                       // CRCH
            result[i++] = crc[0];                       // CRCL

            return result;
        }

        static short GetRegister(ushort reg_addr, ref DeviceParamData aParam)
        {
            short result = 0;

            switch (reg_addr)
            {
                //case 19: result = (short)(0 >> 16); break;		// 0021 : UTC TimeStamp MSB
                //case 20: result = (short)(58 >> 0); break;		// 0022 : UTC TimeStamp LSB
                //case 21: result = (short)0x1000; break;			// 0023 : Cell Balancing Flag
                //case 22: result = (short)0x0000; break;		// 0024 : Cell Balancing Voltage
                //case 23: result = (short)15; break;     // 0024 : Cell Balancing Time

                case 0x4002: result = (short)aParam.CellUnderVoltageWarning; break;     // 0061 : Low cell voltage warning data
                                                                                        //case 33: result = (short)param.sf1.voltage.CUV_Threshold; break;		// 0062 : Low cell voltage protection data
                                                                                        //case 34: result = (short)param.sf1.voltage.CUV_Recovery; break;		// 0063 : Low cell voltage recovery data
                                                                                        //case 35: result = (short)param.sf1.voltage.SUV_Warning; break;		// 0064 : Low voltage warning data
                                                                                        //case 36: result = (short)param.sf1.voltage.SUV_Threshold; break;		// 0065 : Low voltage protection data
                                                                                        //case 37: result = (short)param.sf1.voltage.SUV_Recovery; break;		// 0066 : Low voltage recovery data
                                                                                        //case 38: result = (short)param.sf1.voltage.COV_Warning; break;		// 0067 : Over cell voltage warning data
                                                                                        //case 39: result = (short)param.sf1.voltage.COV_Threshold; break;		// 0068 : Over cell voltage protection data
                                                                                        //case 40: result = (short)param.sf1.voltage.COV_Recovery; break;		// 0069 : Over cell voltage recovery data
                                                                                        //case 41: result = (short)param.sf1.voltage.SOV_Warning; break;		// 0070 : Over voltage warning data
                                                                                        //case 42: result = (short)param.sf1.voltage.SOV_Threshold; break;		// 0071 : Over voltage protection data
                                                                                        //case 43: result = (short)param.sf1.voltage.SOV_Recovery; break;		// 0072 : Over voltage recovery data

                    //case 44: result = (short)param.sf1.temperature.OT_Chg_Warning; break;		// 0044 : Charge over temperature warning data
                    //case 45: result = (short)param.sf1.temperature.OT_Chg_Threshold; break;	// 0045 : Charge over temperature protection data
                    //case 46: result = (short)param.sf1.temperature.OT_Chg_Recovery; break;	// 0046 : Charge over temperature recovery data
                    //case 47: result = (short)param.sf1.temperature.OT_Chg_Time; break;		// 0047 : Charge over temperature time

                    //case 48: result = (short)param.sf1.temperature.OT_Dsg_Warning; break;		// 0048 : Discharge over temperature warning data
                    //case 49: result = (short)param.sf1.temperature.OT_Dsg_Threshold; break;	// 0049 : Discharge over temperature protection data
                    //case 50: result = (short)param.sf1.temperature.OT_Dsg_Recovery; break;	// 0050 : Discharge over temperature recovery data
                    //case 51: result = (short)param.sf1.temperature.OT_Dsg_Time; break;		// 0051 : Discharge over temperature time
            }

            return result;
        }

        static byte[] ModBusGetRegWordToBytes(ushort addr, ref DeviceParamData aParam)
        {
            short data;
            byte[] result = new byte[2];

            data = GetRegister(addr, ref aParam);

            result[0] = (byte)(data >> 8);
            result[1] = (byte)(data >> 0);

            return result;
        }

        static public byte[] MakeWriteRegisterData(ushort DevID, ushort WriteAddr, ushort reg_len, ref DeviceParamData aParam)
        {
            int tlen = (reg_len * 2) + 7 + 2;
            byte[] result = new byte[tlen];
            byte[] tmp;
            byte[] crc;

            result[0] = (byte)DevID;                // Device ID
            result[1] = (byte)PRESET_MULTI_REG;     // Command
            result[2] = (byte)(WriteAddr >> 8);     // Register Address MSB
            result[3] = (byte)(WriteAddr >> 0);     // Register Address LSB
            result[4] = (byte)(reg_len >> 8);       // Count of Register MSB
            result[5] = (byte)(reg_len >> 0);       // Count of Register LSB
            result[6] = (byte)(reg_len * 2); ;       // Current Value MSB

            for (int i = 0; i < reg_len; i++)
            {
                tmp = ModBusGetRegWordToBytes((ushort)(WriteAddr + i), ref aParam);
                result[7 + (i * 2) + 0] = tmp[0];
                result[7 + (i * 2) + 1] = tmp[1];
            }
            crc = GetCRC(result, 8);

            result[tlen - 2] = crc[0];                       // CRCH
            result[tlen - 1] = crc[1];                       // CRCL

            return result;
        }

        public static byte[] MakeCheckSum(byte[] sData, int offset, int len, bool flag)
        {
            byte[] result = new byte[2];
            int checksum = 0;

            for (int i = 0; i < len; i++)
            {
                checksum += sData[i + offset];
            }

            checksum = ~checksum + 1;

            result[0] = (byte)(checksum >> 8);
            result[1] = (byte)checksum;

            return result;
        }

        private static byte[] MakeTxPacket(byte[] sData, int len)
        {
            string str = "";
            byte[] result;
            char[] chrArray;
            int checksum = 0;
            string checksumStr = "";
            char[] checksumChr;

            str = "~";

            for (int i = 0; i < len; i++)
            {
                str += sData[i].ToString("X2");
            }

            str += "\r";

            chrArray = str.ToCharArray();

            for (int i = 0; i < (chrArray.Length - 6); i++)
            {
                checksum += chrArray[i + 1];
            }

            checksum = ~checksum + 1;

            checksumStr = String.Format("{0:X2}{1:X2}", (byte)(checksum >> 8), (byte)checksum);
            checksumChr = checksumStr.ToCharArray();

            for (int i = 0; i < 4; i++)
            {
                chrArray[chrArray.Length - 5 + i] = checksumChr[i];
            }

            result = new byte[chrArray.Length];

            for (int i = 0; i < chrArray.Length; i++)
            {
                result[i] = (byte)chrArray[i];
            }

            return result;
        }

        public static byte[] LengthLchk(int sLen)
        {
            byte[] result = new byte[2];
            int lchksum = 0;

            lchksum = (~(((sLen >> 8) & 0xF) +
                         ((sLen >> 4) & 0xF) +
                         ((sLen >> 0) & 0xF)) + 1) % 16;
            lchksum = ((lchksum << 12) | sLen);

            result[0] = (byte)(lchksum >> 8);
            result[1] = (byte)(lchksum >> 0);

            return result;
        }

        public static byte[] MakeTxData(byte addr, byte cmd, int sLen)
        {
            int buffCh = 0;
            byte[] sData;
            byte[] lenId;
            byte[] checksum;

            sData = new byte[((sLen > 0) ? 11 : 10)];

            sData[buffCh] = 0x7E; buffCh++;                 // SOI
            sData[buffCh] = 0x25; buffCh++;                 // VER
            sData[buffCh] = addr; buffCh++;                 // ADDR
            sData[buffCh] = 0x46; buffCh++;                 // CID1
            sData[buffCh] = cmd; buffCh++;                  // CID2 (CMD)

            lenId = LengthLchk(sLen);                       // LENID
            sData[buffCh] = lenId[0]; buffCh++;             // LENID MSB
            sData[buffCh] = lenId[1]; buffCh++;             // LENID LSB

            if (sLen > 0)
            {
                sData[buffCh] = (byte)(sLen / 2); buffCh++;  // INFO
            }

            checksum = csSerialCommFunction.MakeCheckSum(sData, 1, sData.Length - 4, false);

            sData[buffCh] = checksum[1]; buffCh++;
            sData[buffCh] = checksum[0]; buffCh++;

            sData[buffCh] = 0x0D; buffCh++;                  // EOI

            return MakeTxPacket(sData, sData.Length);
        }

        public static int TbPacketCheck(byte[] rdata, int rlen)
        {
            int result = 0;
            byte[] cdata;
            byte[] checksum;
            byte[] checksum1;

            checksum = MakeCheckSum(rdata, 1, rlen - 6, false);

            checksum1 = new byte[2];
            checksum1[0] = csUtils.StrByte2toByte(rdata[rlen - 4], rdata[rlen - 5]);
            checksum1[1] = csUtils.StrByte2toByte(rdata[rlen - 2], rdata[rlen - 3]);


            if ((checksum[0] == checksum1[0]) && (checksum[1] == checksum1[1]))
            {
                cdata = csUtils.StrToByteArray(rdata, 0, rlen);

                result = 1;
            }

            return result;
        }

        static public int ModbusPacketFromSlaveCheck(byte[] rdata, ushort rlen)
        {
            int result = 0;
            byte[] cdata, crc;
            ushort clen, bytecount;

            if (rlen > 2)
            {
                cdata = rdata;

                switch (cdata[1])
                {
                    case READ_COIL_STATUS:
                    case READ_HOLDING_REG:
                    case READ_INPUT_REG:
                        bytecount = cdata[2];
                        clen = (ushort)(bytecount + 5);	// header 3, tail 2
                        if (rlen >= clen)
                        {
                            crc = GetCRC(cdata, (ushort)(rlen - 2));
                            if ((crc[1] == cdata[rlen - 2]) && (crc[0] == cdata[rlen - 1])) result = 1;
                            else result = -1;
                        }
                        break;
                    case PRESET_MULTI_REG:
                    case FORCE_SINGLE_COIL:
                    case PRESET_SINGLE_REG:
                        clen = 8;
                        if (rlen >= clen)
                        {
                            crc = GetCRC(cdata, (ushort)(rlen - 2));
                            if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 1;
                            else result = -1;
                        }
                        break;
                    case ERROR_REG:
                        clen = 6;
                        if (rlen >= clen)
                        {
                            crc = GetCRC(cdata, (ushort)(rlen - 2));
                            if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 1;
                            else result = -1;
                        }
                        break;
                    case FW_FLASH_ERASE_CMD:
                        clen = 5;
                        if (rlen >= clen)
                        {
                            crc = GetCRC(cdata, (ushort)(rlen - 2));
                            if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 2;
                            else result = -1;
                        }
                        break;
                    case FW_FLASH_WRITE_CMD:
                        clen = 5;
                        if (rlen >= clen)
                        {
                            crc = GetCRC(cdata, (ushort)(rlen - 2));
                            if ((crc[0] == cdata[rlen - 1]) && (crc[1] == cdata[rlen - 2])) result = 2;
                            else result = -1;
                        }
                        break;

                    default:
                        result = -1;
                        break;
                }
            }
            return result;
        }

        public static short[] SerialRxProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref DeviceSystemData rSystemData)
        {
            short[] result = new short[2];

            switch (rData[1])
            {
                case READ_COIL_STATUS:
                    ReadCoilRegisterProcess(rData, rRegAddr, rLen, ref rSystemData);
                    break;
                case READ_HOLDING_REG:
                    ReadHoldRegisterProcess(rData, rRegAddr, rLen, ref rSystemData);
                    break;
                case READ_INPUT_REG:
                    //ReadInputRegisterProcess(rData, rRegAddr, rLen, ref rSystemData);
                    break;
                //case READ_INPUT_REG:
                //    ReadRegister(rData, rRegAddr, rLen, ref rSystemData);
                //    break;
                case PRESET_MULTI_REG:
                    //			read_holding_reg_process(reverse16(rsp->start_addr, true), reverse16(rsp->qty_reg, true));
                    //result[0] = 1;
                    //result[1] = 1;
                    break;
                case ERROR_REG:
                    result[0] = 2;
                    result[1] = (short)((rData[0] << 8) | rData[1]);
                    break;
            }

            return result;
        }

        private static void ReadCoilRegisterProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref DeviceSystemData rSystemData)
        {
            int i, j;
            short reg_count;
            short reg_value;
            i = 2;
            reg_count = rData[i];

            i++;
            for (j = 0; j < reg_count; j++)
            {
                reg_value = (short)(rData[i + j]);
                SetCoilRegister((short)(rRegAddr + j), reg_value, ref rSystemData);
                i++;
            }
        }

        private static void ReadHoldRegisterProcess(byte[] rData, ushort rRegAddr, ushort rLen, ref DeviceSystemData rSystemData)
        {
            int i, j;
            short reg_count;
            short reg_value;
            i = 2;
            reg_count = (short)(rData[i] / 2); i += 1;

            for (j = 0; j < reg_count; j++)
            {
                reg_value = (short)(rData[i] << 8 | rData[i + 1]);
                SetHoldRegister((short)(rRegAddr + j), reg_value, ref rSystemData);
                i += 2;
            }
        }

        private static void SetCoilRegister(short reg_addr, short reg_value, ref DeviceSystemData rSystemData)
        {
            switch (reg_addr)
            {
                case 0x3078:
                    rSystemData.StatusData.relayStatus = reg_value;
                    rSystemData.CalibrationData.FetCalib.FetStatus = reg_value;
                    break;
                case 0x502E:
                    rSystemData.CalibrationData.ChaMode.Mode = reg_value;
                    break;
            }
        }

        private static void SetHoldRegister(short reg_addr, short reg_value, ref DeviceSystemData rSystemData)
        {
            int temp = 0;
            try
            {
                switch (reg_addr)
                {
                    case 0: rSystemData.ValueData.voltageOfPack = (short)(reg_value / 10); break;               //Total Voltage
                    case 1: rSystemData.ValueData.current = (short)((reg_value) / 10); break;           //Total Current
                    case 2:         // Cell Voltage #1
                    case 3:         // Cell Voltage #2
                    case 4:         // Cell Voltage #3
                    case 5:         // Cell Voltage #4
                    case 6:         // Cell Voltage #5
                    case 7:         // Cell Voltage #6
                    case 8:         // Cell Voltage #7
                    case 9:         // Cell Voltage #8'
                    case 10:        // Cell Voltage #9
                    case 11:        // Cell Voltage #10
                    case 12:        // Cell Voltage #11
                    case 13:        // Cell Voltage #12
                    case 14:        // Cell Voltage #13
                    case 15:        // Cell Voltage #14
                    case 16:        // Cell Voltage #15
                    case 17:        // Cell Voltage #16
                        rSystemData.ValueData.CellVoltage[reg_addr - 2] = (ushort)(reg_value / 1);
                        csUtils.MakeMaxAvgMinCellVoltage(ref rSystemData, 39);
                        break;                          // 15 CellVoltage      1mV
                    case 18: rSystemData.ValueData.Ext1Temperature = (short)((reg_value) * 10); break;      // Ext1 Temperature (Temp of MOS-FET)
                    case 19: rSystemData.ValueData.Ext2Temperature = (short)((reg_value) * 10); break;      // Ext2 Amb. PCB Temperature 1C
                    case 20: break;         // Temp Max.
                    case 21: rSystemData.ValueData.remainingCapacity = (short)(reg_value / 1); break;       // Remaining Capacity
                    case 22: rSystemData.ValueData.MaxBattChargeCurr = reg_value / 1; break;
                    case 23: rSystemData.ValueData.stateOfHealth = (short)(reg_value * 10); break;
                    case 24: rSystemData.ValueData.rSOC = (short)(reg_value * 10); break;                   // SOC
                    case 25: rSystemData.StatusData.status = reg_value; break;                              // Operating Status
                    case 26: rSystemData.StatusData.warning = MakeUartWarningData(reg_value); break;        // Warning Status
                    case 27: rSystemData.StatusData.protection = MakeUartTripData(reg_value); break;        // Protection Status
                    case 28: rSystemData.StatusData.errorCode = reg_value; break;                           // Error Code
                                                                                                            // 0x0001 : Voltage error
                                                                                                            // 0x0002 : Temperature error
                                                                                                            // 0x0004 : Current Check Error
                                                                                                            // 0x0010 : Cell unbalance
                                                                                                            // 0x4000 : Gyro alarm
                                                                                                            // 0x8000 : Communication alarm
                    case 29:                                                                                // Cycle count MSB
                        temp = rSystemData.ValueData.cycleCount;
                        rSystemData.ValueData.cycleCount = (temp & (0x0000FFFF)) | (reg_value << 16);
                        break;
                    case 30:                                                                                // Cycle count LSB
                        temp = rSystemData.ValueData.cycleCount;
                        rSystemData.ValueData.cycleCount = (int)(temp & (0xFFFF0000)) | (reg_value << 0);
                        break;
                    //case 31:                                                                                // fullChargeCapacity MSB
                    //    temp = rSystemData.ValueData.fullChargeCapacity;
                    //    rSystemData.ValueData.fullChargeCapacity = (temp & (0x0000FFFF)) | (reg_value << 16);
                    //    break;
                    //case 32:                                                                                // fullChargeCapacity LSB
                    //    temp = rSystemData.ValueData.fullChargeCapacity;
                    //    rSystemData.ValueData.fullChargeCapacity = (int)(temp & (0xFFFF0000)) | (reg_value << 0);
                    //    break;
                    case 32:
                    case 33:
                    case 34:
                    case 35:
                        try
                        {
                            rSystemData.ValueData.CellTemperature[((reg_addr - 32) * 2) + 0] = (short)(((reg_value >> 8) & 0xFF) * 10);
                            rSystemData.ValueData.CellTemperature[((reg_addr - 32) * 2) + 1] = (short)(((reg_value >> 0) & 0xFF) * 10);
                            csUtils.MakeMaxAvgMinTemperature(ref rSystemData, 8);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(string.Format("{0} - ({1})({2})", ex, reg_addr, rSystemData.ValueData.CellTemperature.Length), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        break;
                    case 36: rSystemData.recv_cellQty = reg_value; break;       // Cell Qty
                    case 37: rSystemData.ValueData.designedCapacity = reg_value; break;
                    case 38: rSystemData.StatusData.cellBallanceStatus = reg_value; break;

                    //case 42:
                    //    rSystemData.ValueData.CellTemperature[6 + 0] = (short)(((reg_value >> 8) & 0xFF) * 10);
                    //    rSystemData.ValueData.CellTemperature[6 + 1] = (short)(((reg_value >> 0) & 0xFF) * 10);
                    //    MakeMaxAvgMinTemperature(ref rSystemData);
                    //    break;

                    //case 61: rSystemData.StatusData.cellBallanceStatus = reg_value; break;
                    //45 ~ 99 : Reserved
                    case 45: rSystemData.BmsDateTimeShort1 = (ushort)reg_value; break;     // DateTime
                    case 46:
                        rSystemData.BmsDateTimeShort2 = (ushort)reg_value;
                        int yy, MM, dd, HH, mm, ss;
                        rSystemData.BmsDateTimeInt = (rSystemData.BmsDateTimeShort1 << 16) | (rSystemData.BmsDateTimeShort2);
                        yy = (rSystemData.BmsDateTimeInt >> 26) & 0x003F;
                        MM = ((rSystemData.BmsDateTimeInt >> 22) & 0x000F) % 13;
                        dd = ((rSystemData.BmsDateTimeInt >> 17) & 0x001F) % 32;
                        HH = ((rSystemData.BmsDateTimeInt >> 12) & 0x001F) % 24;
                        mm = ((rSystemData.BmsDateTimeInt >> 6) & 0x003F) % 60;
                        ss = ((rSystemData.BmsDateTimeInt >> 0) & 0x003F) % 60;
                        yy += 2000;

                        rSystemData.BmsDateTime.DateTimeStr = string.Format("{0:0000}-{1:00}-{2:00} {3:00}:{4:00}:{5:00}"
                            , yy
                            , MM
                            , dd
                            , HH
                            , mm
                            , ss
                            );
                        break;     // DateTime

                    case 47: rSystemData.CalibrationData.ChaMode.Mode = reg_value; break;   // 0x2F
                    case 48: rSystemData.CalibrationData.ChaMode.Value = reg_value; break;   // 0x2F

                    case 49: rSystemData.StatusData.specialAlarm = (short)(reg_value); break; // Special Alarm

                    case 56: rSystemData.CalibrationData.BalCalib.Volt = reg_value; break;     // Cell Balance Voltage
                    case 57: rSystemData.CalibrationData.BalCalib.Diff = reg_value; break;     // Cell Balance Diff

                    case 58: rSystemData.ParamData.LowSocWarning = reg_value; break;

                    case 61: rSystemData.ParamData.CellUnderVoltageWarning = reg_value; break;
                    case 62: rSystemData.ParamData.CellUnderVoltageTrip = reg_value; break;
                    case 63: rSystemData.ParamData.CellUnderVoltageRelease = reg_value; break;
                    case 64: rSystemData.ParamData.SysUnderVoltageWarning = (short)(reg_value / 10); break;
                    case 65: rSystemData.ParamData.SysUnderVoltageTrip = (short)(reg_value / 10); break;
                    case 66: rSystemData.ParamData.SysUnderVoltageRelease = (short)(reg_value / 10); break;
                    case 67: rSystemData.ParamData.CellOverVoltageWarning = reg_value; break;
                    case 68: rSystemData.ParamData.CellOverVoltageTrip = reg_value; break;
                    case 69: rSystemData.ParamData.CellOverVoltageRelease = reg_value; break;
                    case 70: rSystemData.ParamData.SysOverVoltageWarning = (short)(reg_value / 10); break;
                    case 71: rSystemData.ParamData.SysOverVoltageTrip = (short)(reg_value / 10); break;
                    case 72: rSystemData.ParamData.SysOverVoltageRelease = (short)(reg_value / 10); break;

                    case 76: rSystemData.ParamData.ChaOverCurrentTimes = (short)(reg_value / 1); break;
                    case 77: rSystemData.ParamData.DchOverCurrentTimes = (short)(reg_value / 1); break;
                    case 78: rSystemData.ParamData.ChaOverCurrentReleaseTime = (short)(reg_value * 1); break;
                    case 79: rSystemData.ParamData.DchOverCurrentReleaseTime = (short)(reg_value * 1); break;
                    case 80: rSystemData.ParamData.ChaOverCurrentTrip1 = (short)(reg_value / 10); break;
                    case 81: rSystemData.ParamData.DchOverCurrentTrip1 = (short)(reg_value / 10); break;
                    case 82: rSystemData.ParamData.ShortCircuit = (short)(reg_value / 10); break;         // Short Circuit Current = 300A
                    case 83: rSystemData.ParamData.ChaOverCurrentTrip2 = (short)(reg_value / 10); break;
                    case 84: rSystemData.ParamData.DchOverCurrentTrip2 = (short)(reg_value / 10); break;
                    case 85: rSystemData.ParamData.ChaOverCurrentDelay1 = (short)(reg_value / 1); break;
                    case 86: rSystemData.ParamData.ChaOverCurrentDelay2 = (short)(reg_value / 1); break;
                    case 87: rSystemData.ParamData.DchOverCurrentDelay1 = (short)(reg_value / 1); break;
                    case 88: rSystemData.ParamData.DchOverCurrentDelay2 = (short)(reg_value / 1); break;

                    case 90: rSystemData.ParamData.ChaLowTempWarning = (short)(reg_value - 50); break;
                    case 91: rSystemData.ParamData.ChaLowTempTrip = (short)(reg_value - 50); break;
                    case 92: rSystemData.ParamData.ChaLowTempRelease = (short)(reg_value - 50); break;
                    case 93: rSystemData.ParamData.ChaHighTempWarning = (short)(reg_value - 50); break;
                    case 94: rSystemData.ParamData.ChaHighTempTrip = (short)(reg_value - 50); break;
                    case 95: rSystemData.ParamData.ChaHighTempRelease = (short)(reg_value - 50); break;
                    case 96: rSystemData.ParamData.DchLowTempWarning = (short)(reg_value - 50); break;
                    case 97: rSystemData.ParamData.DchLowTempTrip = (short)(reg_value - 50); break;
                    case 98: rSystemData.ParamData.DchLowTempRelease = (short)(reg_value - 50); break;
                    case 99: rSystemData.ParamData.DchHighTempWarning = (short)(reg_value - 50); break;
                    case 100: rSystemData.ParamData.DchHighTempTrip = (short)(reg_value - 50); break;
                    case 101: rSystemData.ParamData.DchHighTempRelease = (short)(reg_value - 50); break;

                    case 102: break;            // PCB High Temp Warning
                    case 103: break;            // PCB High Temp Trip
                    case 104: break;            // PCB High Temp Release
                                                //100 ~111 : Model_Product Name
                    case 105:
                    case 106:
                    case 107:
                    case 108:
                    case 109:
                    case 110:
                    case 111:
                    case 112:
                    case 113:
                    case 114:
                    case 115:
                    case 116:
                        int mReg = reg_addr - 105;
                        rSystemData.Information.Model_Byte[(mReg * 2) + 0] = (byte)(reg_value >> 8);
                        rSystemData.Information.Model_Byte[(mReg * 2) + 1] = (byte)(reg_value >> 0);
                        if (reg_addr == 116)
                        {
                            rSystemData.Information.ModelName = Encoding.Default.GetString(rSystemData.Information.Model_Byte).Trim('\0');
                        }
                        break;

                    //112 ~114 : FW Version
                    case 117:
                    case 118:
                    case 119:
                        int fReg = reg_addr - 117;
                        rSystemData.Information.FwVer_Byte[(fReg * 2) + 0] = (byte)(reg_value >> 8);
                        rSystemData.Information.FwVer_Byte[(fReg * 2) + 1] = (byte)(reg_value >> 0);
                        if (reg_addr == 119)
                        {
                            rSystemData.Information.SwProductRev = Encoding.Default.GetString(rSystemData.Information.FwVer_Byte).Trim('\0');
                        }
                        break;
                    //115 ~ 122 : BMS Serial number
                    case 120:
                    case 121:
                    case 122:
                    case 123:
                    case 124:
                    case 125:
                    case 126:
                    case 127:
                        int snReg = reg_addr - 120;
                        rSystemData.Information.BMS_SN[(snReg * 2) + 0] = (byte)(reg_value >> 8);
                        rSystemData.Information.BMS_SN[(snReg * 2) + 1] = (byte)(reg_value >> 0);
                        if (reg_addr == 127)
                        {
                            rSystemData.Information.HwSerialNumber = Encoding.Default.GetString(rSystemData.Information.BMS_SN).Trim('\0');
                        }
                        break;

                    case 130: rSystemData.ParamData.EnvLowTempWarning = (short)(reg_value - 50); break;
                    case 131: rSystemData.ParamData.EnvLowTempTrip = (short)(reg_value - 50); break;
                    case 132: rSystemData.ParamData.EnvLowTempRelease = (short)(reg_value - 50); break;
                    case 133: rSystemData.ParamData.EnvHighTempWarning = (short)(reg_value - 50); break;
                    case 134: rSystemData.ParamData.EnvHighTempTrip = (short)(reg_value - 50); break;
                    case 135: rSystemData.ParamData.EnvHighTempRelease = (short)(reg_value - 50); break;

                    case 136:       // Anti-Theft Communication
                        rSystemData.CalibrationData.AntiTheft.Comm = reg_value;
                        break;
                    case 137:       // Anti-Theft Gyro-Scope
                        rSystemData.CalibrationData.AntiTheft.GyroScope = reg_value;
                        break;

                    case 138:       // Cell Voltage #17
                    case 139:       // Cell Voltage #18 
                    case 140:       // Cell Voltage #19
                    case 141:       // Cell Voltage #20 
                    case 142:       // Cell Voltage #21 
                    case 143:       // Cell Voltage #22 
                    case 144:       // Cell Voltage #23 
                    case 145:       // Cell Voltage #24 
                    case 146:       // Cell Voltage #25 
                    case 147:       // Cell Voltage #26 
                    case 148:       // Cell Voltage #27 
                    case 149:       // Cell Voltage #28 
                    case 150:       // Cell Voltage #29 
                    case 151:       // Cell Voltage #30 
                    case 152:       // Cell Voltage #31 
                    case 153:       // Cell Voltage #32 
                    case 154:       // Cell Voltage #33 
                    case 155:       // Cell Voltage #34 
                    case 156:       // Cell Voltage #35 
                    case 157:       // Cell Voltage #36 
                    case 158:       // Cell Voltage #37 
                    case 159:       // Cell Voltage #38 
                    case 160:       // Cell Voltage #39 
                        rSystemData.ValueData.CellVoltage[reg_addr - 138 + 16] = (ushort)(reg_value / 1);
                        break;

                    case 163:       // 0xA3
                    case 164:       // 0xA4
                    case 165:       // 0xA5
                    case 166:       // 0xA6
                        int ManuDateReg = reg_addr - 163;
                        rSystemData.Information.ManuDate_Byte[(ManuDateReg * 2) + 0] = (byte)(reg_value >> 8);
                        rSystemData.Information.ManuDate_Byte[(ManuDateReg * 2) + 1] = (byte)(reg_value >> 0);
                        if (reg_addr == 166)
                        {
                            rSystemData.Information.ManufacturingDate = Encoding.Default.GetString(rSystemData.Information.ManuDate_Byte).Trim('\0');
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("{0} - ({1})", ex, reg_addr), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            csMakeDataFunction.MakeAlarm(ref rSystemData);
        }

        public static short MakeUartWarningData(short rdata)
        {
            short result = 0;
            bool[] bAlarm = csUtils.Int16ToBitArray(rdata);

            if (bAlarm[0] == true) result |= (short)(1 << 2);       // 0x0001：Pack OV
            if (bAlarm[1] == true) result |= (short)(1 << 4);       // 0x0002：Cell OV
            if (bAlarm[2] == true) result |= (short)(1 << 3);       // 0x0004：Pack UV
            if (bAlarm[3] == true) result |= (short)(1 << 5);       // 0x0008：Cell UV

            if (bAlarm[4] == true) result |= (short)(1 << 6);       // 0x0010：Charging OC
            if (bAlarm[5] == true) result |= (short)(1 << 7);       // 0x0020：Discharging OC

            if (bAlarm[8] == true) result |= (short)(1 << 0);       // 0x0080: Charging Over Tempratuer
            if (bAlarm[9] == true) result |= (short)(1 << 0);       // 0x0080: Discharging Over Tempratuer
            if (bAlarm[10] == true) result |= (short)(1 << 1);      // 0x0040: Charging Under Tempratuer
            if (bAlarm[11] == true) result |= (short)(1 << 1);      // 0x0040: Discharging Under Tempratuer
            if (bAlarm[12] == true) result |= (short)(1 << 11);       // 0x0200：SOC Low

            return result;
        }

        public static short MakeUartTripData(short rdata)
        {
            short result = 0;
            bool[] bAlarm = csUtils.Int16ToBitArray(rdata);

            if (bAlarm[0] == true) result |= (short)(1 << 2);       // 0x0001：Pack OV
            if (bAlarm[1] == true) result |= (short)(1 << 4);       // 0x0002：Cell OV
            if (bAlarm[2] == true) result |= (short)(1 << 3);       // 0x0004：Pack UV
            if (bAlarm[3] == true) result |= (short)(1 << 5);       // 0x0008：Cell UV

            if (bAlarm[4] == true) result |= (short)(1 << 6);       // 0x0010：Charging OC
            if (bAlarm[5] == true) result |= (short)(1 << 7);       // 0x0020：Discharging OC

            if (bAlarm[8] == true) result |= (short)(1 << 0);       // 0x0080: Charging Over Tempratuer
            if (bAlarm[9] == true) result |= (short)(1 << 0);       // 0x0080: Discharging Over Tempratuer
            if (bAlarm[10] == true) result |= (short)(1 << 1);      // 0x0040: Charging Under Tempratuer
            if (bAlarm[11] == true) result |= (short)(1 << 1);      // 0x0040: Discharging Under Tempratuer
            if (bAlarm[13] == true) result |= (short)(1 << 9);       // 0x0200：Short Circuit Protection

            return result;
        }

        private static short MakeUartErrorData(short rdata, short cdata)
        {
            short result = cdata;
            bool[] bAlarm = csUtils.Int16ToBitArray(rdata);

            if (bAlarm[0] == true) result |= (short)(1 << 9);       // 0x0001：Voltage error
            if (bAlarm[1] == true) result |= (short)(1 << 9);       // 0x0002：Temperature error
            if (bAlarm[2] == true) result |= (short)(1 << 9);       // 0x0004: 电流检测Error
            if (bAlarm[3] == true) result |= (short)(1 << 9);       // 0x0010：Cell unbalance

            return result;
        }
    }
}
