using System;

using LFP_Manager.DataStructure;
using LFP_Manager.Utils;

namespace LFP_Manager.Function
{
    // 1. Define the data type
    public struct PACKET_HEADER
    {
        public byte Index;      // 3
        public byte R;          // 1
        public byte DP;         // 1
        public byte PF;         // 8
        public byte PS;         // 8
        public byte SA;         // 8
    }

    class csCanCommFunction
    {
        public static void CanRxProcess(ref CommConfig aConfig, int sId, UInt32 ExID, byte[] data, ref DeviceSystemData rSystemData, DateTime rTime)
        {
            PACKET_HEADER PacketHeader = CovertPtoH(ExID);

            if (PacketHeader.SA == (200 + sId))
            {
                if (data.Length > 0)
                {
                    int REF = 0;

                    rSystemData.CommFail = false;
                    rSystemData.ShelfCommFail = false;
                    rSystemData.LastRxTime = rTime;

                    switch (PacketHeader.PF)
                    {
                        case 201:            // Device heartbeat
                            rSystemData.heatbeat = (UInt32)((data[0] << 24)
                                                  | (data[1] << 16)
                                                  | (data[2] << 8)
                                                  | (data[3] << 0));
                            rSystemData.OneBuffTime = (data[4] << 8) | data[5];
                            rSystemData.AllBuffTime = (data[6] << 8) | data[7];
                            break;
                        case 1:             // Send data 0x01
                            break;
                        case 11:            // Module Voltage, Current
                            rSystemData.ValueData.voltageOfPack = (short)((data[0] * 256) + data[1]);
                            //rSystemData.ValueData.rSOC = (short)(data[2]);
                            rSystemData.CalibriationData.ForcedBalancing.AutoB = (data[3] == 0x01) ? true : false;
                            rSystemData.StatusData.warning = (short)((data[4] << 8) | data[5]);
                            rSystemData.StatusData.protect = (short)((data[6] << 8) | data[7]);
                            break;
                        case 12:            // Status code 2, Software version
                            rSystemData.StatusData.batteryStatusA = (short)((data[0] << 8) | data[1]);
                            rSystemData.StatusData.status = (short)(data[2]);                                           // Op Status

                            rSystemData.ValueData.fw_ver[0] = (byte)((((data[6] * 256) + data[7]) >> 12) & 0xf);
                            rSystemData.ValueData.fw_ver[1] = (byte)((((data[6] * 256) + data[7]) >> 8) & 0xf);
                            rSystemData.ValueData.fw_ver[2] = (byte)((((data[6] * 256) + data[7]) >> 4) & 0xf);
                            rSystemData.ValueData.fw_ver[3] = (byte)((((data[6] * 256) + data[7]) >> 0) & 0xf);
                            break;
                        case 13:            // Status code 3
                            rSystemData.StatusData.batteryStatusB = (short)((data[0] << 8) | data[1]);              // Battery Status 1
                            rSystemData.StatusData.protect1 = (short)((data[2] << 8) | data[3]);              // Protection 1
                            break;

                        case 15:            // Balancing Status - Active Balancing
                            rSystemData.StatusData.BalanceEnable = (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0));
                            rSystemData.StatusData.BalanceMode = (uint)((data[4] << 24) | (data[5] << 16) | (data[6] << 8) | (data[7] << 0));
                            break;

                        case 31:            // Cell Temperature #1 ~ #4
                        case 32:            // Cell Temperature #5 ~ #8
                        case 33:            // Cell Temperature #9 ~ #12
                        case 34:            // Cell Temperature #13 ~ #16
                            REF = PacketHeader.PF - 31;
                            for (int i = 0; i < 4; i++)
                            {
                                if (((REF * 4) + i) < rSystemData.tempQty)
                                    rSystemData.ValueData.CellTemperature[(REF * 4) + i] = (short)(((data[(i * 2)] * 256) + data[(i * 2) + 1]) - 800);
                            }
                            MakeMaxAvgMinTemperature(ref rSystemData);
                            break;
                        case 41:
                            rSystemData.ValueData.rSOC = (short)((data[0] << 8) | data[1]);
                            break;
                        case 191:           // Cell Voltage 1 ~ 4
                        case 192:           // Cell Voltage 5 ~ 8
                        case 193:           // Cell Voltage 9 ~ 12
                        case 194:           // Cell Voltage 13 ~ 16
                        case 195:           // Cell Voltage 17 ~ 20
                        case 196:           // Cell Voltage 21 ~ 24
                        case 197:           // Cell Voltage 25 ~ 28
                        case 198:           // Cell Voltage 29 ~ 32
                        case 199:           // Cell Voltage 33 ~ 36
                            REF = PacketHeader.PF - 191;
                            for (int i = 0; i < 4; i++)
                            {
                                if (((REF * 4) + i) < rSystemData.cellQty)
                                    rSystemData.ValueData.CellVoltage[(REF * 4) + i] = (ushort)((data[(i * 2)] * 256) + data[(i * 2) + 1]);
                            }
                            rSystemData = MakeMaxAvgMinCellVoltage(rSystemData);
                            break;
                        case 111:            // Cell Balancing Status
                            switch (aConfig.TargetModelIndex)
                            {
                                case 0:     // PR-57150
                                    rSystemData.StatusData.cellBalanceValue = (ushort)((data[0] << 8) + data[1]);
                                    rSystemData.StatusData.cellBalanceEndGap = (short)(data[2]);
                                    rSystemData.StatusData.cellBalanceFlag = (short)(data[3]);
                                    rSystemData.StatusData.cellBallanceStatusLv = (uint)((data[4] << 0) | (data[5] << 8) | (data[6] << 16));
                                    rSystemData.StatusData.cellBalanceInterval = (short)(data[7]);
                                    break;
                                case 3:     // PR-102150
                                    rSystemData.StatusData.cellBalanceValue = (ushort)((data[0] << 8) + data[1]);
                                    rSystemData.StatusData.cellBalanceEndGap = (short)(data[2] & 0x7F);
                                    rSystemData.StatusData.cellBalanceFlag = (short)((data[2] >> 7) & 0x01);
                                    rSystemData.StatusData.cellBalanceInterval = (short)(data[3]);
                                    rSystemData.StatusData.cellBallanceStatusLv = (uint)((data[4] << 0) | (data[5] << 8)
                                                                                       | (data[6] << 16) | (data[7] << 24));
                                    break;
                                case 4:     // PR-115300
                                    rSystemData.StatusData.cellBalanceValue = (ushort)((data[0] << 8) + data[1]);
                                    rSystemData.StatusData.cellBalanceEndGap = (short)(data[2] & 0x7F);
                                    rSystemData.StatusData.cellBalanceFlag = (short)((data[2] >> 7) & 0x01);
                                    rSystemData.StatusData.cellBalanceInterval = (short)(data[3]);
                                    rSystemData.StatusData.cellBallanceStatusLv = (uint)((data[4] << 0) | (data[5] << 8)
                                                                                       | (data[6] << 16) | (data[7] << 24));
                                    break;
                                case 5:     // PR-67150
                                    rSystemData.StatusData.cellBalanceValue = (ushort)((data[0] << 8) + data[1]);
                                    rSystemData.StatusData.cellBalanceEndGap = (short)(data[2] * 10);
                                    rSystemData.StatusData.cellBalanceFlag = (short)((data[3] >> 7) & 0x01);
                                    rSystemData.StatusData.cellBallanceStatusLv = (uint)((data[4] << 0) | (data[5] << 8) | (data[6] << 16));
                                    rSystemData.StatusData.cellBalanceInterval = (short)(data[7]);
                                    break;
                                default:
                                    rSystemData.StatusData.cellBalanceValue = (ushort)((data[0] << 8) + data[1]);
                                    rSystemData.StatusData.cellBalanceFlag = (short)((data[2] >> 7) & 0x01);
                                    rSystemData.StatusData.cellBalanceEndGap = (short)((data[2] & 0x7F) * 10);
                                    rSystemData.StatusData.cellBalanceInterval = (short)(data[3]);
                                    rSystemData.StatusData.cellBallanceStatusLv = (uint)((data[4] << 0) | (data[5] << 8) | (data[6] << 16) | (data[7] << 24));
                                    break;
                            }
                            break;
                        case 112:            // Cell Balancing Status
                            rSystemData.StatusData.cellBallanceStatusHv = (uint)((data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
                            break;
                        case 51:             // Cell Voltage Parameter
                            rSystemData.ParamData.CellUnderVoltageWarning = (short)((data[0] * 256) + data[1]);
                            rSystemData.ParamData.CellUnderVoltageTrip = (short)((data[2] * 256) + data[3]);
                            rSystemData.ParamData.CellOverVoltageWarning = (short)((data[4] * 256) + data[5]);
                            rSystemData.ParamData.CellOverVoltageTrip = (short)((data[6] * 256) + data[7]);
                            break;
                        case 71:             // System Voltage Parameter
                            rSystemData.ParamData.SysUnderVoltageWarning = (short)((data[0] * 256) + data[1]);
                            rSystemData.ParamData.SysUnderVoltageTrip = (short)((data[2] * 256) + data[3]);
                            rSystemData.ParamData.SysOverVoltageWarning = (short)((data[4] * 256) + data[5]);
                            rSystemData.ParamData.SysOverVoltageTrip = (short)((data[6] * 256) + data[7]);
                            break;
                        case 61:             // Temperature Parameter
                            rSystemData.ParamData.ChaLowTempWarning = (short)(data[0] - 80);
                            rSystemData.ParamData.ChaLowTempTrip = (short)(data[1] - 80);
                            rSystemData.ParamData.ChaHighTempWarning = (short)(data[2] - 80);
                            rSystemData.ParamData.ChaHighTempTrip = (short)(data[3] - 80);
                            rSystemData.ParamData.DchLowTempWarning = (short)(data[4] - 80);
                            rSystemData.ParamData.DchLowTempTrip = (short)(data[5] - 80);
                            rSystemData.ParamData.DchHighTempWarning = (short)(data[6] - 80);
                            rSystemData.ParamData.DchHighTempTrip = (short)(data[7] - 80);
                            break;
                        case 141:             // Soc Parameter, System Voltage Calibration K, B
                            rSystemData.ParamData.LowSocWarning = (short)(data[0]);
                            rSystemData.ParamData.LowSocRelease = (short)(data[1]);
                            rSystemData.CalibriationData.SystemVoltage.Calibration_K = (short)((data[4] * 256) + data[5]);
                            rSystemData.CalibriationData.SystemVoltage.Calibration_B = (short)((data[6] * 256) + data[7]);
                            break;
                        case 151:            // Battery Option Parameter - Cell Voltage Offset
                            rSystemData.CalibriationData.CellVoltge.CvOffsetLow = (short)((data[0] << 8) | data[1]);
                            rSystemData.CalibriationData.CellVoltge.CvOffsetHigh = (short)((data[2] << 8) | data[3]);
                            break;
                        case 221:             // Over Current Parameter
                            rSystemData.ParamData.ChaOverCurrentWarning = (short)((data[0] * 256) + data[1] - 30000);
                            rSystemData.ParamData.ChaOverCurrentTrip = (short)((data[2] * 256) + data[3] - 30000);
                            rSystemData.ParamData.DchOverCurrentWarning = (short)((data[4] * 256) + data[5] - 30000);
                            rSystemData.ParamData.DchOverCurrentTrip = (short)((data[6] * 256) + data[7] - 30000);
                            break;
                        case 231:             // Voltage release Parameter
                            rSystemData.ParamData.CellUnderVoltageRelease = (short)((data[0] * 256) + data[1]);
                            rSystemData.ParamData.CellOverVoltageRelease = (short)((data[2] * 256) + data[3]);
                            rSystemData.ParamData.SysUnderVoltageRelease = (short)((data[4] * 256) + data[5]);
                            rSystemData.ParamData.SysOverVoltageRelease = (short)((data[6] * 256) + data[7]);
                            break;
                        case 241:             // Temperature, Current release Parameter
                            rSystemData.ParamData.ChaLowTempRelease = (short)(data[0] - 80);
                            rSystemData.ParamData.ChaHighTempRelease = (short)(data[1] - 80);
                            rSystemData.ParamData.DchLowTempRelease = (short)(data[2] - 80);
                            rSystemData.ParamData.DchHighTempRelease = (short)(data[3] - 80);

                            rSystemData.ParamData.ChaOverCurrentRelease = (short)((data[4] * 256) + data[5] - 30000);
                            rSystemData.ParamData.DchOverCurrentRelease = (short)((data[6] * 256) + data[7] - 30000);
                            break;

                        case 81:                // Battery Parameter
                            rSystemData.CalibriationData.Battery.CellQty = (short)(data[0]);
                            rSystemData.CalibriationData.Battery.TempQty = (short)(data[1]);
                            rSystemData.CalibriationData.Battery.Capacity = (UInt32)((data[2] * 256) + data[3]);
                            break;
                        case 91:                // Device Address Setting
                            rSystemData.CalibriationData.SystemInfo.devAddr = (ushort)((data[0] * 256) + data[1]);
                            break;
                        case 171:               // Cell Balancing Paramwter
                            rSystemData.CalibriationData.CbParam.Threadhold = (short)((data[0] * 256) + data[1]);
                            rSystemData.CalibriationData.CbParam.Window = (short)((data[2] * 256) + data[3]);
                            rSystemData.CalibriationData.CbParam.Min = (short)(data[4]);
                            rSystemData.CalibriationData.CbParam.Interval = (short)(data[5]);
                            break;
                        case 211:
                            DateTime dev = new DateTime(data[0] + 1970
                                                        , data[1]
                                                        , data[2]
                                                        , data[3]
                                                        , data[4]
                                                        , data[5]
                                                        );
                            rSystemData.CalibriationData.SystemInfo.devTime = dev;
                            break;
                        case 2:             // Cell Voltage Difference Parameter
                            rSystemData.ParamData.CellVoltageDifferenceTrip = (short)((data[0] * 256) + data[1]);
                            rSystemData.ParamData.CellVoltageDifferenceWarning = (short)((data[2] * 256) + data[3]);
                            rSystemData.ParamData.CellVoltageDifferenceRelease = (short)((data[4] * 256) + data[5]);
                            rSystemData.ParamData.CellVoltageDifferenceTime = (short)((data[6] * 256) + data[7]);
                            break;
                    }
                }
                if (rSystemData.StatusData.protect != 0)
                    rSystemData.StatusData.alarm = 2;
                else if (rSystemData.StatusData.warning != 0)
                    rSystemData.StatusData.alarm = 1;
                else
                    rSystemData.StatusData.alarm = 0;
            }
        }
        public static void CanInvRxProcess(int sId, UInt32 exID, byte[] rData, ref DeviceSystemData aSystemData, DateTime rTime)
        {
            PACKET_HEADER PacketHeader = CovertPtoH(exID);

            if (PacketHeader.SA == (200 + sId))
            {
                if (rData.Length > 0)
                {
                    aSystemData.CommFail = false;
                    aSystemData.ShelfCommFail = false;
                    aSystemData.LastRxTime = rTime;

                    switch (PacketHeader.PF)
                    {
                        case 11:            // Device ManufactureDate
                            aSystemData.Information.ManufactureDate = (UInt32)((rData[0] << 24)
                                                                             | (rData[1] << 16)
                                                                             | (rData[2] << 8)
                                                                             | (rData[3] << 0));
                            break;
                        case 21:            // Device Serial Number MSB
                            for (int i = 0; i < 8; i++)
                            {
                                aSystemData.Information.pcb_sn[i] = rData[i];
                            }
                            break;
                        case 31:            // Device Serial Number LSB
                            for (int i = 0; i < 8; i++)
                            {
                                aSystemData.Information.pcb_sn[i + 8] = rData[i];
                            }
                            break;
                    }
                }
            }
        }

        public static PACKET_HEADER CovertPtoH(UInt32 id)
        {
            PACKET_HEADER hdr = new PACKET_HEADER();

            hdr.Index = (byte)((id >> 26) & 0x07);
            hdr.R = (byte)((id >> 25) & 0x01);
            hdr.DP = (byte)((id >> 24) & 0x01);
            hdr.PF = (byte)((id >> 16) & 0xFF);
            hdr.PS = (byte)((id >> 8) & 0xFF);
            hdr.SA = (byte)((id >> 0) & 0xFF);

            return hdr;
        }

        public static UInt32 CovertHtoP(PACKET_HEADER hdr)
        {
            UInt32 Packet = 0;

            Packet = (((UInt32)hdr.Index << 26)
                | ((UInt32)hdr.R << 25)
                | ((UInt32)hdr.DP << 24)
                | ((UInt32)hdr.PF << 16)
                | ((UInt32)hdr.PS << 8)
                | ((UInt32)hdr.SA << 0)
                );
            return Packet;
        }

        public static byte[] MakeSocRecoveryCanData(byte nSoc)
        {
            byte[] result = new byte[8];

            for (int i = 0; i < 8; i++)
                result[i] = 0xFF;

            result[0] = 0;
            result[1] = nSoc;

            return result;
        }

        public static byte[] MakeCanData(int mode, int flag, int dcp, ref DeviceParamData aParam, ref DeviceCalibration aCalib)
        {
            byte[] result = new byte[8];
            short temp = 0;

            for (int i = 0; i < 8; i++)
                { result[i] = 0xFF; }

            switch (mode)
            {
                case 1:                 // Status Req
                    result[6] = (byte)dcp;
                    break;
                //case 10:            // Cell Balancing set
                //    aCalib.CellBalancingVoltage = 3600;
                //    aCalib.CellBalancingVoltageEndGap = 100;
                //    aCalib.CellBalancingVoltageInterval = 5;
                //    result[0] = (byte)(aCalib.CellBalancingVoltage >> 8);
                //    result[1] = (byte)(aCalib.CellBalancingVoltage >> 0);
                //    result[2] = (byte)(aCalib.CellBalancingVoltageEndGap / 10);
                //    result[3] = (byte)(aCalib.CellBalancingVoltageInterval << 1);

                //    int ss = Convert.ToInt32(String.Format("{0:ss}", DateTime.Now));
                //    if (ss == 0)
                //    {
                //        result[3] |= 1;
                //        UInt32 nTime = (UInt32)csUtils.UnixTimeNow();
                //        result[4] = (byte)(nTime >> 24);
                //        result[5] = (byte)(nTime >> 16);
                //        result[6] = (byte)(nTime >> 8);
                //        result[7] = (byte)(nTime >> 0);
                //    }
                //    break;
                //case 17:
                //    if (aCalib.Current.SelectSubItem != 2)
                //        result[7] = (byte)aCalib.Current.ChaAndDchSelect;
                //    break;
            }

            // Parameter Set
            if (flag == 1)
            {
                switch (mode)
                {
                    case 25:
                        result[0] = (byte)1;
                        break;
                    case 10:            // Cell Balancing set
                        result[0] = (byte)(aCalib.CellBalancingVoltage >> 8);
                        result[1] = (byte)(aCalib.CellBalancingVoltage >> 0);
                        result[2] = (byte)(aCalib.CellBalancingVoltageEndGap / 10);
                        result[3] = (byte)(aCalib.CellBalancingVoltageInterval << 1);

                        int ss = Convert.ToInt32(String.Format("{0:ss}", DateTime.Now));
                        if (ss == 0)
                        {
                            result[3] |= 1;
                            UInt32 nTime = (UInt32)csUtils.UnixTimeNow();
                            result[4] = (byte)(nTime >> 24);
                            result[5] = (byte)(nTime >> 16);
                            result[6] = (byte)(nTime >> 8);
                            result[7] = (byte)(nTime >> 0);
                        }
                        break;
                    case 5:             // Cell Voltage Warning and Fault Parameter
                        result[0] = (byte)(aParam.CellUnderVoltageWarning >> 8);
                        result[1] = (byte)(aParam.CellUnderVoltageWarning >> 0);

                        result[2] = (byte)(aParam.CellUnderVoltageTrip >> 8);
                        result[3] = (byte)(aParam.CellUnderVoltageTrip >> 0);

                        result[4] = (byte)(aParam.CellOverVoltageWarning >> 8);
                        result[5] = (byte)(aParam.CellOverVoltageWarning >> 0);

                        result[6] = (byte)(aParam.CellOverVoltageTrip >> 8);
                        result[7] = (byte)(aParam.CellOverVoltageTrip >> 0);
                        break;
                    case 6:             // Temperature Warning and Fault Parameter
                        result[0] = (byte)(aParam.ChaLowTempWarning + 80);
                        result[1] = (byte)(aParam.ChaLowTempTrip + 80);

                        result[2] = (byte)(aParam.ChaHighTempWarning + 80);
                        result[3] = (byte)(aParam.ChaHighTempTrip + 80);

                        result[4] = (byte)(aParam.DchLowTempWarning + 80);
                        result[5] = (byte)(aParam.DchLowTempTrip + 80);

                        result[6] = (byte)(aParam.DchHighTempWarning + 80);
                        result[7] = (byte)(aParam.DchHighTempTrip + 80);
                        break;
                    case 7:             // System Voltage Warning and Fault Parameter
                        result[0] = (byte)(aParam.SysUnderVoltageWarning >> 8);
                        result[1] = (byte)(aParam.SysUnderVoltageWarning >> 0);

                        result[2] = (byte)(aParam.SysUnderVoltageTrip >> 8);
                        result[3] = (byte)(aParam.SysUnderVoltageTrip >> 0);

                        result[4] = (byte)(aParam.SysOverVoltageWarning >> 8);
                        result[5] = (byte)(aParam.SysOverVoltageWarning >> 0);

                        result[6] = (byte)(aParam.SysOverVoltageTrip >> 8);
                        result[7] = (byte)(aParam.SysOverVoltageTrip >> 0);
                        break;
                    case 14:             // SOC Warning and System Voltage Calibration K, B Parameter
                        result[0] = (byte)(aParam.LowSocWarning);
                        result[1] = (byte)(aParam.LowSocRelease);
                        result[2] = 0;
                        result[3] = 0;
                        result[4] = (byte)(aCalib.SystemVoltage.Calibration_K >> 8);
                        result[5] = (byte)(aCalib.SystemVoltage.Calibration_K >> 0);
                        result[6] = (byte)(aCalib.SystemVoltage.Calibration_B >> 8);
                        result[7] = (byte)(aCalib.SystemVoltage.Calibration_B >> 0);
                        break;
                    case 22:             // Current Warning and Fault Parameter
                        temp = (short)(aParam.ChaOverCurrentWarning + 30000);
                        result[0] = (byte)(temp >> 8);
                        result[1] = (byte)(temp >> 0);

                        temp = (short)(aParam.ChaOverCurrentTrip + 30000);
                        result[2] = (byte)(temp >> 8);
                        result[3] = (byte)(temp >> 0);

                        temp = (short)(aParam.DchOverCurrentWarning + 30000);
                        result[4] = (byte)(temp >> 8);
                        result[5] = (byte)(temp >> 0);

                        temp = (short)(aParam.DchOverCurrentTrip + 30000);
                        result[6] = (byte)(temp >> 8);
                        result[7] = (byte)(temp >> 0);
                        break;
                    case 23:             // Cell and System Voltage Release Parameter
                        result[0] = (byte)(aParam.CellUnderVoltageRelease >> 8);
                        result[1] = (byte)(aParam.CellUnderVoltageRelease >> 0);

                        result[2] = (byte)(aParam.CellOverVoltageRelease >> 8);
                        result[3] = (byte)(aParam.CellOverVoltageRelease >> 0);

                        result[4] = (byte)(aParam.SysUnderVoltageRelease >> 8);
                        result[5] = (byte)(aParam.SysUnderVoltageRelease >> 0);

                        result[6] = (byte)(aParam.SysOverVoltageRelease >> 8);
                        result[7] = (byte)(aParam.SysOverVoltageRelease >> 0);
                        break;
                    case 24:             // Cell and System Voltage Release Parameter
                        result[0] = (byte)(aParam.ChaLowTempRelease + 80);
                        result[1] = (byte)(aParam.ChaHighTempRelease + 80);

                        result[2] = (byte)(aParam.DchLowTempRelease + 80);
                        result[3] = (byte)(aParam.DchHighTempRelease + 80);

                        temp = (short)(aParam.ChaOverCurrentRelease + 30000);
                        result[4] = (byte)(temp >> 8);
                        result[5] = (byte)(temp >> 0);

                        temp = (short)(aParam.DchOverCurrentRelease + 30000);
                        result[6] = (byte)(temp >> 8);
                        result[7] = (byte)(temp >> 0);
                        break;
                    case 9:
                        result[0] = (byte)(aCalib.SystemInfo.devAddr >> 8);
                        result[1] = (byte)(aCalib.SystemInfo.devAddr >> 0);
                        break;
                    case 1:         // Auto Cell Balancing Set Data (0: Off. 1: On)
                        //result[6] = (byte)((aCalib.ForcedBalancing.DCP) ? 0x01 : 0x00);
                        result[7] = (byte)((aCalib.ForcedBalancing.AutoB) ? 0x01 : 0x00);
                        break;
                    case 12:        // Forced Cell Balancing
                        result[0] = (byte)(aCalib.ForcedBalancing2.Control);
                        result[1] = (byte)(aCalib.ForcedBalancing2.CellNo);
                        result[2] = (byte)(aCalib.ForcedBalancing2.Mode);
                        result[3] = (byte)(aCalib.ForcedBalancing2.Enable);
                        break;
                    case 8:         // Battery Paramter
                        result[0] = (byte)(aCalib.Battery.CellQty);
                        result[1] = (byte)(aCalib.Battery.TempQty);
                        result[2] = (byte)(aCalib.Battery.Capacity >> 8);
                        result[3] = (byte)(aCalib.Battery.Capacity >> 0);
                        break;
                    case 17:        // Cell Balancing Parameter
                        result[0] = (byte)(aCalib.CbParam.Threadhold >> 8);
                        result[1] = (byte)(aCalib.CbParam.Threadhold >> 0);
                        result[2] = (byte)(aCalib.CbParam.Window >> 8);
                        result[3] = (byte)(aCalib.CbParam.Window >> 0);
                        result[4] = (byte)(aCalib.CbParam.Min >> 0);
                        result[5] = (byte)(aCalib.CbParam.Interval >> 0);
                        break;
                    case 21:         // System Information (Device Address)
                        result[0] = (byte)(aCalib.SystemInfo.devAddr >> 8);
                        result[1] = (byte)(aCalib.SystemInfo.devAddr >> 0);
                        break;
                    case 13:         // Soc Calibration
                        result[0] = (byte)(aCalib.SocCalib.CellNo);
                        result[1] = (byte)(aCalib.SocCalib.SocValue);
                        break;
                    case 15:         // Parameter Option
                        result[0] = (byte)(aCalib.CellVoltge.CvOffsetLow >> 8);
                        result[1] = (byte)(aCalib.CellVoltge.CvOffsetLow >> 0);
                        result[2] = (byte)(aCalib.CellVoltge.CvOffsetHigh >> 8);
                        result[3] = (byte)(aCalib.CellVoltge.CvOffsetHigh >> 0);

                        result[7] = (byte)(0x01);
                        break;
                    case 16:         // Default Parameter
                        result[0] = (byte)(aParam.DefalutParamOption);
                        break;
                    case 2:         // Default Parameter
                        result[0] = (byte)(aParam.CellVoltageDifferenceTrip >> 8);
                        result[1] = (byte)(aParam.CellVoltageDifferenceTrip >> 0);
                        result[2] = (byte)(aParam.CellVoltageDifferenceWarning >> 8);
                        result[3] = (byte)(aParam.CellVoltageDifferenceWarning >> 0);
                        result[4] = (byte)(aParam.CellVoltageDifferenceRelease >> 8);
                        result[5] = (byte)(aParam.CellVoltageDifferenceRelease >> 0);
                        result[6] = (byte)(aParam.CellVoltageDifferenceTime >> 8);
                        result[7] = (byte)(aParam.CellVoltageDifferenceTime >> 0);
                        break;
                    case 900:
                        result[0] = (byte)(aCalib.InvData.ManufactureDate >> 24);
                        result[1] = (byte)(aCalib.InvData.ManufactureDate >> 16);
                        result[2] = (byte)(aCalib.InvData.ManufactureDate >>  8);
                        result[3] = (byte)(aCalib.InvData.ManufactureDate >>  0);

                        result[7] = (byte)(1);
                        break;
                    case 901:
                        for (int i = 0; i < 8; i++)
                        {
                            result[i] = (byte)(aCalib.InvData.pcb_sn[i]);
                        }
                        break;
                    case 902:
                        for (int i = 0; i < 8; i++)
                        {
                            result[i] = (byte)(aCalib.InvData.pcb_sn[i + 8]);
                        }
                        break;
                }
            }
            return result;
        }

        private static DeviceSystemData MakeMaxAvgMinCellVoltage(DeviceSystemData rSystemData)
        {
            DeviceSystemData result = rSystemData;
            int Max, Avg, Min, Sum;
            int MaxNo, MinNo;

            Max = Avg = Min = Sum = 0;
            MaxNo = MinNo = 0;
            for (int i = 0; i < rSystemData.cellQty; i++)
            {
                if (i == 0)
                {
                    Max = Min = rSystemData.ValueData.CellVoltage[i];
                }
                Sum += rSystemData.ValueData.CellVoltage[i];

                if (Max < rSystemData.ValueData.CellVoltage[i])
                {
                    Max = rSystemData.ValueData.CellVoltage[i];
                    MaxNo = i;
                }
                if (Min > rSystemData.ValueData.CellVoltage[i])
                {
                    Min = rSystemData.ValueData.CellVoltage[i];
                    MinNo = i;
                }
            }
            if (rSystemData.cellQty > 0)
                Avg = Sum / rSystemData.cellQty;

            result.AvgData.avgCellVoltage = (ushort)Avg;
            result.AvgData.maxCellVoltage = (ushort)Max;
            result.AvgData.maxCellNum = (short)(MaxNo + 1);
            result.AvgData.minCellVoltage = (ushort)Min;
            result.AvgData.minCellNum = (short)(MinNo + 1);
            result.AvgData.diffCellVoltage = (ushort)(Max - Min);

            return result;
        }

        private static void MakeMaxAvgMinTemperature(ref DeviceSystemData rSystemData)
        {
            int Max, Avg, Min, Sum;
            int MaxNo, MinNo;

            Max = Avg = Min = Sum = 0;
            MaxNo = MinNo = 0;
            for (int i = 0; i < rSystemData.tempQty; i++)
            {
                if (i == 0) 
                {
                    Max = Min = rSystemData.ValueData.CellTemperature[i];
                }
                Sum += rSystemData.ValueData.CellTemperature[i];

                if (Max < rSystemData.ValueData.CellTemperature[i]) 
                {
                    Max = rSystemData.ValueData.CellTemperature[i];
                    MaxNo = i;
                }
                if (Min > rSystemData.ValueData.CellTemperature[i]) 
                {
                    Min = rSystemData.ValueData.CellTemperature[i];
                    MinNo = i;
                }
            }
            if (rSystemData.tempQty > 0)
                Avg = Sum / rSystemData.tempQty;

            rSystemData.AvgData.avgTemp = (short)Avg;
            rSystemData.AvgData.maxTemp = (short)Max;
            rSystemData.AvgData.maxTempNum = (short)(MaxNo + 1);
            rSystemData.AvgData.minTemp = (short)Min;
            rSystemData.AvgData.minTempNum = (short)(MinNo + 1);
            rSystemData.AvgData.diffTemp = (short)(Max - Min);
        }

        private static DeviceSystemData MakeAlarmTripData(int id, short ndata, DeviceSystemData rSystemData)
        {
            bool[] aData = csUtils.Int16ToBitArray(ndata);
            short bFault = rSystemData.StatusData.protect;
            short bWarning = rSystemData.StatusData.warning;
            int i = 0;

            switch (id)
            {
                case 0:         // Status Code 1
                    if (aData[i++]) bWarning |=  (1 << 4);      // 00  Cell Over Voltage Warning
                    else            bWarning &= ~(1 << 4);
                    if (aData[i++]) bWarning |=  (1 << 5);      // 01  Cell Under Voltage Warning
                    else            bWarning &= ~(1 << 5);
                    if (aData[i++]) bWarning |=  (1 << 0);      // 02  High Temperature Warning
                    else            bWarning &= ~(1 << 0);
                    if (aData[i++]) bWarning |=  (1 << 1);      // 03  Low Temperature Warning
                    else            bWarning &= ~(1 << 1);
                    if (aData[i++]) bWarning |=  (1 << 2);      // 04  Module Over Voltage Warning
                    else            bWarning &= ~(1 << 2);
                    if (aData[i++]) bWarning |=  (1 << 3);      // 05  Module Under Voltage Warning
                    else            bWarning &= ~(1 << 3);
                    if (aData[i++]) bWarning |=  (1 << 9);      // 06  Cell Voltage Difference Warning
                    else            bWarning &= ~(1 << 9);
                    i++;                                        // 07  Reserved

                    if (aData[i++]) bFault |=  (1 << 4);        // 08  Cell Over Voltage Fault
                    else            bFault &= ~(1 << 4);
                    if (aData[i++]) bFault |=  (1 << 5);        // 09  Cell Under Voltage Fault
                    else            bFault &= ~(1 << 5);
                    if (aData[i++]) bFault |=  (1 << 0);        // 10  High Temperature Warning
                    else            bFault &= ~(1 << 0);
                    if (aData[i++]) bFault |=  (1 << 1);        // 11  Low Temperature Warning
                    else            bFault &= ~(1 << 1);
                    if (aData[i++]) bFault |=  (1 << 2);        // 12  Module Over Voltage Warning
                    else            bFault &= ~(1 << 2);
                    if (aData[i++]) bFault |=  (1 << 3);        // 13  Module Under Voltage Warning
                    else            bFault &= ~(1 << 3);
                    if (aData[i++]) bFault |=  (1 << 9);        // 14  Cell Voltage Difference Fault
                    else            bFault &= ~(1 << 9);
                    
                    break;
                case 1:         // Status Code 2
                    i++;                                        // 00 High SOC Warning
                    i++;                                        // 01 High SOC Fault
                    if (aData[i++]) bWarning |=  (1 << 11);     // 02 Low SOC Warning
                    else            bWarning &= ~(1 << 11);
                    i++;                                        // 03 Low SOC Fault
                    i++;                                        // 04 Reserved
                    i++;                                        // 05 Reserved
                    i++;                                        // 06 Reserved
                    i++;                                        // 07 Reserved
                    if (aData[i++]) bWarning |=  (1 << 6);      // 08 Charge Over Current Warning
                    else            bWarning &= ~(1 << 6);
                    if (aData[i++]) bFault   |=  (1 << 6);      // 09 Charge Over Current Fault
                    else            bFault   &= ~(1 << 6);
                    if (aData[i++]) bWarning |=  (1 << 7);      // 10 Discharge Over Current Warning
                    else            bWarning &= ~(1 << 7);
                    if (aData[i++]) bFault   |=  (1 << 7);      // 11 Discharge Over Current Fault
                    else            bFault   &= ~(1 << 7);
                    break;
            }

            rSystemData.StatusData.protect = bFault;
            rSystemData.StatusData.warning = bWarning;

            return rSystemData;
        }

        private static DeviceSystemData MakeWarningAlarmData(int id, short ndata, DeviceSystemData rSystemData)
        {
            bool[] aData = csUtils.Int16ToBitArray(ndata);
            short bFault = rSystemData.StatusData.protect;
            short bWarning = rSystemData.StatusData.warning;
            int i = 0;

            switch (id)
            {
                case 0:         // Status Code 1
                    if (aData[i++]) bWarning |= (1 << 4);      // 00  Cell Over Voltage Warning
                    else bWarning &= ~(1 << 4);
                    if (aData[i++]) bWarning |= (1 << 5);      // 01  Cell Under Voltage Warning
                    else bWarning &= ~(1 << 5);
                    if (aData[i++]) bWarning |= (1 << 0);      // 02  High Temperature Warning
                    else bWarning &= ~(1 << 0);
                    if (aData[i++]) bWarning |= (1 << 1);      // 03  Low Temperature Warning
                    else bWarning &= ~(1 << 1);
                    if (aData[i++]) bWarning |= (1 << 2);      // 04  Module Over Voltage Warning
                    else bWarning &= ~(1 << 2);
                    if (aData[i++]) bWarning |= (1 << 3);      // 05  Module Under Voltage Warning
                    else bWarning &= ~(1 << 3);
                    if (aData[i++]) bWarning |= (1 << 9);      // 06  Cell Voltage Difference Warning
                    else bWarning &= ~(1 << 9);
                    i++;                                        // 07  Reserved

                    if (aData[i++]) bFault |= (1 << 4);        // 08  Cell Over Voltage Fault
                    else bFault &= ~(1 << 4);
                    if (aData[i++]) bFault |= (1 << 5);        // 09  Cell Under Voltage Fault
                    else bFault &= ~(1 << 5);
                    if (aData[i++]) bFault |= (1 << 0);        // 10  High Temperature Warning
                    else bFault &= ~(1 << 0);
                    if (aData[i++]) bFault |= (1 << 1);        // 11  Low Temperature Warning
                    else bFault &= ~(1 << 1);
                    if (aData[i++]) bFault |= (1 << 2);        // 12  Module Over Voltage Warning
                    else bFault &= ~(1 << 2);
                    if (aData[i++]) bFault |= (1 << 3);        // 13  Module Under Voltage Warning
                    else bFault &= ~(1 << 3);
                    if (aData[i++]) bFault |= (1 << 9);        // 14  Cell Voltage Difference Fault
                    else bFault &= ~(1 << 9);

                    break;
                case 1:         // Status Code 2
                    i++;                                        // 00 High SOC Warning
                    i++;                                        // 01 High SOC Fault
                    if (aData[i++]) bWarning |= (1 << 11);     // 02 Low SOC Warning
                    else bWarning &= ~(1 << 11);
                    i++;                                        // 03 Low SOC Fault
                    i++;                                        // 04 Reserved
                    i++;                                        // 05 Reserved
                    i++;                                        // 06 Reserved
                    i++;                                        // 07 Reserved
                    if (aData[i++]) bWarning |= (1 << 6);      // 08 Charge Over Current Warning
                    else bWarning &= ~(1 << 6);
                    if (aData[i++]) bFault |= (1 << 6);      // 09 Charge Over Current Fault
                    else bFault &= ~(1 << 6);
                    if (aData[i++]) bWarning |= (1 << 7);      // 10 Discharge Over Current Warning
                    else bWarning &= ~(1 << 7);
                    if (aData[i++]) bFault |= (1 << 7);      // 11 Discharge Over Current Fault
                    else bFault &= ~(1 << 7);
                    break;
            }

            rSystemData.StatusData.protect = bFault;
            rSystemData.StatusData.warning = bWarning;

            return rSystemData;
        }

        public static string PacketToMsg(UInt32 exID, byte[] rData, int flag)
        {
            string result = "";
            PACKET_HEADER PacketHeader = CovertPtoH(exID);

            if (flag == 0) result = "RD: ";
            else result = "TD: ";
            result += String.Format(" ID:0x{0:X4}", exID);
            result += String.Format("[PF({3:000}) PS({4:000}) SA({5:000})]"
                , PacketHeader.Index
                , PacketHeader.R
                , PacketHeader.DP
                , PacketHeader.PF
                , PacketHeader.PS
                , PacketHeader.SA
                );

            result += String.Format("Data({0}): ", rData.Length);

            for (int i = 0; i < rData.Length; i++)
            {
                result += String.Format("{0:X2} ", rData[i]);
            }

            return result;
        }

        unsafe public static string PacketToMsg(VCI_CAN_OBJ obj, int flag)
        {
            PACKET_HEADER PacketHeader = CovertPtoH(obj.ID);
            string str;

            if (flag == 0) str = "RD: ";
            else str = "TD: ";
            str += String.Format(" ID:0x{0}", obj.ID.ToString("X4"));
            //str += String.Format("[I({0}) R({1}) DP({2}) PF({3}) PS({4}) SA({5})]"
            //    , PacketHeader.Index
            //    , PacketHeader.R
            //    , PacketHeader.DP
            //    , PacketHeader.PF
            //    , PacketHeader.PS
            //    , PacketHeader.SA
            //    );
            str += String.Format("[PF({3:000}) PS({4:000}) SA({5:000})]"
                , PacketHeader.Index
                , PacketHeader.R
                , PacketHeader.DP
                , PacketHeader.PF
                , PacketHeader.PS
                , PacketHeader.SA
                );

            str += " Frame:";
            if (obj.RemoteFlag == 0)
                str += "D-Frame ";
            else
                str += "R-Frame ";
            //if (obj.ExternFlag == 0)
            //    str += "Std-Frame ";
            //else
            //    str += "Ext-Frame ";

            //////////////////////////////////////////
            if (obj.RemoteFlag == 0)
            {
                byte len = (byte)(obj.DataLen % 9);

                str += String.Format("Data({0}): ", len);

                for (int i = 0; i < len; i++)
                {
                    str += String.Format("{0} ", obj.Data[i].ToString("X2"));
                }
            }

            return str;
        }

        unsafe public static string PacketToMsg1(VCI_CAN_OBJ obj)
        {
            string str;

            str = "Received data: ";
            str += "  Frame ID:0x" + System.Convert.ToString((Int32)obj.ID, 16);
            str += "  Frame format:";
            if (obj.RemoteFlag == 0)
                str += "Data Frame ";
            else
                str += "Remote frame ";
            if (obj.ExternFlag == 0)
                str += "Standard frame ";
            else
                str += "Extended frame ";

            //////////////////////////////////////////
            if (obj.RemoteFlag == 0)
            {
                str += "Data: ";
                byte len = (byte)(obj.DataLen % 9);
                byte j = 0;
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[0], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[1], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[2], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[3], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[4], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[5], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[6], 16);
                if (j++ < len)
                    str += " " + System.Convert.ToString(obj.Data[7], 16);

            }

            return str;
        }
    }
}
