#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>

#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <arpa/inet.h>
#include <netinet/in.h>

#include <assert.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#include "../Log/log.h"
#include "../ShareMemory/shmMem.h"
#include "../Define/define.h"
#include "../Config.h"
#include "../SelectGun/SelectGun.h"
#include "../timeout.h"
#include "../DataBase/DataBase.h"
#include "DoComm.h"

//------------------------------------------------------------------------------
static DoCommGblData gDoCommGblData             = {0};
static MoreInfoReq gMoreInfoReq[2]              = {0};
//static ChangePageReq gPageReq[2]                = {0};
static ConnectorActReqVar gConnectorActReq[2]   = {0};
static struct SysConfigData *pSysConfig         = NULL;
static struct SysInfoData *pSysInfo             = NULL;
static struct WARNING_CODE_INFO *pSysWarning    = NULL;
static struct AlarmCodeData *pAlarmCode         = NULL;
static struct PsuData *ShmPsuData               = NULL;
static struct OCPP16Data *ShmOCPP16Data         = NULL;
static struct PrimaryMcuData *ShmPrimaryMcuData = NULL;
static SelectGunInfo *ShmSelectGunInfo          = NULL;
static DcCommonInfo *ShmDcCommonData            = NULL;

//static struct ChargingInfoData  *ChargingData[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY]
static struct ChargingInfoData *pDcChargingInfo = NULL;
static struct timeb             gRegTimeUp[2][MAX_REGISTER_NUM] = {0};
static struct WARNING_CODE_INFO gPreSysWarningInfo = {0};

// Hexdump
char old_Hexdump[10240];
static uint8_t RemoteStartNoIDState = NO;
static uint8_t ReservationState[2] = {0};
static char ReservationIdTag[2][32];
//static uint8_t DeductResultReq[2] = {0};
static int LineStatusCode[2] = {0};
static unsigned int LedIntensity = 0;
static int TimeZoneOffset = 0;
int RxLen;
char Rxdata[1024];
uint8_t _isplugin = 0;
int gunstatus[2];
//------------------------------------------------------------------------------
static void removeFaultCodeToBuf(uint8_t *Code);
static void addFaultCodeToBuf(uint8_t *Code);
static int readMiscCommand(int fd, uint8_t id);
static int writeCsuModuleVersion(int fd);
static int writeGroundFaultDetection(int fd, uint8_t status, uint8_t id);

//------------------------------------------------------------------------------
//--- Common function ---
//------------------------------------------------------------------------------
void GetClockTime(struct timespec *_now_time, void *null)
{
    clock_gettime(CLOCK_MONOTONIC, _now_time);
}

static int DiffTimeb(struct timeb ST, struct timeb ET)
{
    //return milli-second
    unsigned int StartTime, StopTime;

    StartTime = (unsigned int)ST.time;
    StopTime = (unsigned int)ET.time;

    return (StopTime - StartTime) * 1000 + ET.millitm - ST.millitm;
}

/**
 * [hexdump : check data]
 * @Author   Jerry
 * @DateTime 2018-12-21
 * @param    p          [description]
 * @param    size       [description]
 */
static void Hexdump(const void *p, size_t size)
{
    const uint8_t *c = p;
    char message[10240] = {0};
    uint32_t i = 0;
    uint32_t message_len = 0;

    assert(p);

    //printf("Dumping %u bytes from %p:\n", size, p);
    message_len += sprintf(&message[message_len], "\nDumping %u bytes from %p:\n",  (unsigned int)size, p);

    while (size > 0) {
        for (i = 0; i < 16; i++) {
            if (i < size) {
                //printf("%02x ", c[i]);
                message_len += sprintf(&message[message_len], "%02x ", c[i]);
            } else {
                //printf("   ");
                message_len += sprintf(&message[message_len], "   ");
            }
        }

        for (i = 0; i < 16; i++) {
            if (i < size) {
                //printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
                message_len += sprintf(&message[message_len], "%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
            } else {
                //printf(" ");
                message_len += sprintf(&message[message_len], " ");
            }
        }

        //printf("\n");
        message_len += sprintf(&message[message_len], "\n");
        c += 16;

        if (size <= 16) {
            break;
        }

        size -= 16;
    }

    //message_len += sprintf(&message[message_len], "\n");
    if( strcmp(old_Hexdump,message) != EQUAL ) {
        log_info("%s", message);
        strcpy(old_Hexdump,message);
    }
}

static int string2ByteArray(char *input, uint8_t *output)
{
    int loop = 0;
    int i = 0;

    while (input[loop] != '\0') {
        output[i++] = input[loop++];
    }
    output[loop] = '\0';

    return loop + 1;
}

int string2Date(char* input, uint8_t* output)
{
    int loop = 0;
    int i = 0;

    while (input[loop] != '\0') {
        loop++;
    }
    loop++;

    while (input[loop] != '\0') {
        output[i++] = input[loop++];
    }
    output[loop] = '\0';

    return loop + 1;
}
static void unixSocketSigPipeHandle(int sig)
{
    log_error("socket packet error %x", sig);
}

static void InitSocketSigPipe(void)
{
    struct sigaction action;

    action.sa_handler = unixSocketSigPipeHandle;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGPIPE, &action, NULL);
}

//------------------------------------------------------------------------------
static void setTcpStatus(uint8_t setValue)
{
    pAlarmCode->AlarmEvents.bits.DisconnectedFromDo = setValue;
}

//------------------------------------------------------------------------------
//--- TCP socket function ---
//------------------------------------------------------------------------------
static int sendTcpSocket(int fd, uint8_t *data, uint16_t dataLen)
{
    int size = -1;
    int i;
    char _info[1024];
    int len = 0;

    // ReadCmdline show network package
    if (ShmDcCommonData->showNetPackage) {
        len = 0;
        len += sprintf(&_info[len], "Net Tx[%d]:", dataLen);
        for (i = 0; i < dataLen; i++) {
            if (i == 0)
                len += sprintf(&_info[len], "[%X]\t", data[i]);
            else
                len += sprintf(&_info[len], "%X ", data[i]);
        }
        len += sprintf(&_info[len], "\n");
        printf("%s", _info);
    }

    size = send(fd, data, dataLen , 0);
    if ((size < 0) || (errno == EAGAIN)) {
        if (size < 0) {
            log_error("Send Socket Size = %d, EAGAIN error %d:%s", size, errno, strerror(errno));
        }
    }

    return size;
}

static int recvTcpSocket(int fd, uint8_t *data, uint16_t dataLen,uint8_t ishead)
{
    int size = -1;
    int i;
    uint8_t *pdata = (uint8_t *)data;

    size = recv(fd, pdata, dataLen, MSG_WAITALL);
    if ((errno == EAGAIN) || (size < 0)) {
        log_error("Receive Socket Size = %d, EAGAIN error %d:%s", size, errno, strerror(errno));
    }
    // ReadCmdline show network package
    if (ShmDcCommonData->showNetPackage) {
        if (ishead) {
            RxLen = 0;
            RxLen += sprintf(&Rxdata[RxLen], "Net Rx[%d]:", size);
        }
        for (i = 0; i < dataLen; i++) {
            if (ishead && i == 0)
                RxLen += sprintf(&Rxdata[RxLen], "[%X]\t", data[i]);
            else
                RxLen += sprintf(&Rxdata[RxLen], "%X ", data[i]);
        }
        if (!ishead) {
            RxLen += sprintf(&Rxdata[RxLen], "\n");
            printf("%s", Rxdata);
            strcpy(Rxdata,"");
        }
    }

    return size;
}

static int getSO_ERROR(int fd)
{
    int err = 1;
    socklen_t len = sizeof err;

    if (-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &len)) {
        log_error("getSO_ERROR");
    }

    if (err) {
        errno = err;        // set errno to the socket SO_ERROR
    }

    return err;
}

static void closeSocket(int fd)        // *not* the Windows closesocket()
{
    if (fd < 0) {
        return;
    }

    getSO_ERROR(fd); // first clear any errors, which can cause close to fail
    if (shutdown(fd, SHUT_RDWR) < 0) { // secondly, terminate the 'reliable' delivery
        if (errno != ENOTCONN && errno != EINVAL) { // SGI causes EINVAL
            log_info("shutdown");
        }
    }

    if (close(fd) < 0) { // finally call close()
        log_info("client socket close");
    }
}

static int doCommConnToServer(void)
{
    struct sockaddr_in dest;
    struct timeval tv;
    int flag;
    int TcpSock = 0;

    //if (TcpSock > 0) {
    //    close(TcpSock);
    //}

    if ((TcpSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        log_error("Open TCP socket NG");
        return -1;
    }

    //flag = fcntl (TcpSock, F_GETFL, 0);
    //if (flag >= 0) {
    //    flag |= O_NONBLOCK;
    //    fcntl(TcpSock, F_SETFL, flag );
    //}

    tv.tv_sec = 3;
    tv.tv_usec = 0;
    setsockopt(TcpSock, SOL_SOCKET,  SO_RCVTIMEO, &tv, sizeof(struct timeval)); //設定等待3s
    setsockopt(TcpSock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));  //設定傳送3s
    flag = 1;
    setsockopt(TcpSock, SOL_SOCKET, MSG_NOSIGNAL, &flag, sizeof(flag));

    memset(&dest, 0, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(DoTcpPort);
    inet_aton(DoIPAddress, (struct in_addr *) &dest.sin_addr.s_addr);

    if (connect(TcpSock, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
        close(TcpSock);
        return -1;
    }

    return TcpSock;
}

//------------------------------------------------------------------------------
//--- Audi select gun ---
//------------------------------------------------------------------------------
static void clearPricesInfo(uint8_t id)
{
    memset(&ShmSelectGunInfo->PricesInfo[id], 0, sizeof(PricesInfo));
    ShmSelectGunInfo->PricesInfo[id].Balance = FAIL_BALANCE_PRICES;
}

static void ClearAuthorizedFlag(void)
{
    ShmOCPP16Data->SpMsg.bits.AuthorizeConf = NO;
    pSysInfo->AuthorizeFlag = NO;
}

static void ClearDetectPluginFlag(int gunIndex)
{
    if (pSysConfig->TotalConnectorCount > 1 && gunIndex == RIGHT_GUN_NUM)
        return;
    ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit = NO;
}

static bool isDetectPlugin(int gunIndex)
{
    if (pSysConfig->TotalConnectorCount == 1 && gunIndex == RIGHT_GUN_NUM)
        return false;
    if (ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit == YES) {
        return true;
    }
    /*
    if (pSysInfo->WaitForPlugit == YES) {
        return true;
    }
    */
    return false;
}

static void destroySelectGun(uint8_t curGun)
{
    uint8_t i = 0;
    uint8_t totalGun = pSysConfig->TotalConnectorCount;

    if (curGun == DESTROY_ALL_SEL) {
        ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_RELEASE;
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_RELEASE;

        for (i = 0; i < totalGun; i++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

            pDcChargingInfo->TimeoutFlag = Timeout_None;
            clearPricesInfo(i);
        }
        pSysInfo->CurGunSelected = 0;
        strcpy((char *)pSysConfig->UserId, "");
    }

    //for charging timeout or complete
    if ((curGun == LEFT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.LeftGun != SEL_GUN_RELEASE)) {
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_RELEASE;
        if (ShmOCPP16Data->SpMsg.bits.AuthorizeConf != NO) {
            ClearAuthorizedFlag();
        }
        clearPricesInfo(curGun);
    }

    if ((curGun == RIGHT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.RightGun != SEL_GUN_RELEASE)) {
        if (ShmOCPP16Data->SpMsg.bits.AuthorizeConf != NO) {
            ClearAuthorizedFlag();
        }

        clearPricesInfo(curGun);
    }
}

static int getConfirmSelectedGun(uint8_t curSel)
{
    if (((curSel == LEFT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.LeftGun >= SEL_GUN_CONFIRM)) ||
            ((curSel == RIGHT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.RightGun >= SEL_GUN_CONFIRM))) {
        return PASS;
    }

    return FAIL;
}

static int getSelGunWaitToAuthor(uint8_t curGun)
{
    if (curGun == LEFT_GUN_NUM && ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_ATHOR) {
        return FAIL;
    }

    if (curGun == RIGHT_GUN_NUM && ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_ATHOR) {
        return FAIL;
    }

    return PASS;
}

static void setConfirmSelGun(uint8_t selGun)
{
    if (selGun == LEFT_GUN_NUM && ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_RELEASE) {
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_CONFIRM;
        //printf("confirmSelGun left");
    } else if (selGun == RIGHT_GUN_NUM && ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_RELEASE) {
        ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_CONFIRM;
        //printf("confirmSelGun right");
    }
}

//------------------------------------------------------------------------------
//--- DoComm function ---
//------------------------------------------------------------------------------
static int compareOpcode(uint8_t opCode)
{
    if (opCode != OP_WAIT_RESPONSE) {
        //log_error("response operative code fail");
        return FAIL;
    }

    return PASS;
}

static int compareResult(uint8_t result)
{
    if (result != COMMAND_RESULT_OK) {
        //log_error("response result fail");
        return FAIL;
    }

    return PASS;
}

static int compareRegister(uint8_t srcReg, uint8_t destReg)
{
    if (srcReg != destReg) {
        //log_error("response register fail");
        return FAIL;
    }

    return PASS;
}

static float transPricesUnit(int prices)
{
    //printf("prices = %.2f", prices * PRICES_UNIT);
    return (prices * PRICES_UNIT);
}

static void clearMiscCommand(void)
{
    gDoCommGblData.MiscCmd = 0;
}
int timecmp(uint8_t* time1, uint8_t* time2)
{
    for (int i = 0; i < strlen(time1); i++) {
        if (time1[i] != time2[i]) {
            return FALSE;
        }
    }
    return TRUE;
}
static int qrCodeUrlInfoHandle(uint8_t *data)
{
    //int len = 0;
    //char cmdBuf[128] = {0};
    char localTime[128] = {0};
    uint16_t timeLen = 0;
    struct timeb SeqEndTime;
    struct tm *tm;
    char _setTime[50];
    uint8_t cmdBuf[128];
    if ((char *)&data[0] == '\0') {
        log_error("QR code date error");
        return FAIL;
    }

    //get local system time
    ftime(&SeqEndTime);
    SeqEndTime.time = time(NULL);
    tm = localtime(&SeqEndTime.time);
    timeLen = sprintf(localTime, "%04d-%02d-%02d %02d:%02d",
                      tm->tm_year + 1900,
                      tm->tm_mon + 1,
                      tm->tm_mday,
                      tm->tm_hour,
                      tm->tm_min);

    //copy QR code string
    memset(ShmDcCommonData->QRCodeString, '\0', sizeof(ShmDcCommonData->QRCodeString));
    //printf("data =  %s", data);
    //len =

    string2ByteArray((char *)data, (uint8_t *)ShmDcCommonData->QRCodeString);
    string2Date((char*)data, (uint8_t*)_setTime);
    //printf("SystemId =  %s", pSysConfig->SystemId);
    if (!timecmp(localTime, _setTime)) {
        //log_info("Set Timer:%s", _setTime);
        sprintf((char*)cmdBuf, "date -u -s \"%s\" >> /dev/null &", _setTime);
        system((char*)cmdBuf);
        system("hwclock -w -u");
        system("hwclock -s");
    }


    //if ((char *)&data[len] == '\0') {
    //    log_error("power cabinet system date error");
    //    return FAIL;
    //}

    //set system date
    //if (strncmp((char *)localTime, (char *)&data[len], timeLen) != 0) {
    //    sprintf(cmdBuf, "date -s \"%s\" >> /dev/null", (char *)&data[len]);
    //    system(cmdBuf);
    //    log_info("local time = %s, data time = %s", localTime, (char *)&data[len]);
    //    ShmOCPP16Data->MsMsg.bits.ResetReq = YES;
    //    strcpy((char *)ShmOCPP16Data->Reset.Type, "Soft");
    //    sleep(3);
    //    //gDoCommGblData.DisConnCount = CHECK_NETWORK_FAIL_COUNT;
    //}

    return PASS;
}

static int updateFirmwareHandle(uint8_t *imgName)
{
    int ret = PASS;
    char cmdBuf[1024] = {0};

    sprintf(cmdBuf, "/mnt/%s", imgName);
    log_info("Program ready to check file %s", cmdBuf);
    if ( access(cmdBuf, F_OK) != -1) {
        log_info("File '%s' exist.", cmdBuf);
        pSysInfo->FirmwareUpdate = YES;
    } else {
        log_info("File '%s' doesn't exist.", cmdBuf);
        ret = FAIL;
    }

#if 0
    char cmdBuf[1024] = {0};
    int status = 0;

    system("touch ./tftpUpdate.sh"); //創建shell
    sprintf(cmdBuf, "echo tftp -gr %s -l %s/%s %s; > ./tftpUpdate.sh",
            imgName,
            IMAGE_FILE_PATH,
            imgName,
            DoIPAddress);
    system("chmod +x ./tftpUpdate.sh"); //修改權限

    status = system("sh tftpUpdate.sh"); //執行shell
    if (-1 == status) {
        printf("system error!");
    } else {
        printf("exit status value = [0x%x]", status);

        if (WIFEXITED(status)) {
            if (0 == WEXITSTATUS(status)) {
                printf("run shell script successfully.");
                pSysInfo->FirmwareUpdate = YES;
            } else {
                printf("run shell script fail, script exit code: %d", WEXITSTATUS(status));
            }
        } else {
            printf("exit status = [%d]", WEXITSTATUS(status));
        }
    }

    system("rm -rf ./tftpUpdate.sh"); //刪除shell
#endif //0

    return ret;
}

static int miscCommandHandle(uint8_t dataLen, uint8_t plugNum, uint8_t *data)
{
    int ret = PASS;
    uint8_t i = 0, j = 0;
    uint8_t cmdCount = (dataLen / 6);
    uint16_t cmd = 0;
    uint32_t value = 0;
    float prices = 0;
    MiscCommand *pMiscCmd = NULL;

    if (cmdCount < 1) {
        gDoCommGblData.MiscCmd = 0;
        //printf("cmdCount fail = %d, data len = %d", cmdCount, dataLen);
        return FAIL;
    }

    for (i = 0; i < cmdCount; i++) {
        pMiscCmd = (MiscCommand *)data + i;
        cmd = ntohs(pMiscCmd->CMD);
        value = ntohl(*((uint32_t *)&pMiscCmd->Value[0]));
        //log_info("misc command = %x, value = %d", cmd, value);

        switch (cmd) {
        //--- Execute parameter ---
        case MISC_CMD_CONNECOTOR_TIMEOUT:
            ShmSelectGunInfo->RemoteSetup.ConnectionTimeout = value;
            log_info("connection timeout = %d", ShmSelectGunInfo->RemoteSetup.ConnectionTimeout);
            clearMiscCommand();
            break;

        case MISC_CMD_OPERATIVE_STATE:
            if ((value > YES) || (value < NO)) {
                if (plugNum == 1) {
                    clearMiscCommand();
                }
                break;
            }

            log_info("change availability plugNum = %d, value = %d", plugNum, value);
            ShmOCPP16Data->CsMsg.bits[plugNum].ChangeAvailabilityReq = YES;
            if (value == YES) {
                strcpy((char *)ShmOCPP16Data->ChangeAvailability[plugNum].Type, "Operative");
            } else if (value == NO) {
                strcpy((char *)ShmOCPP16Data->ChangeAvailability[plugNum].Type, "Inoperative");
            }

            if (plugNum == 1) {
                clearMiscCommand();
            }
            break;

        case MISC_CMD_DEFAULT_PRICES:
            prices = transPricesUnit((int)value);
            log_info("default prices = %.2f", prices);
            ShmDcCommonData->ChargingRate = prices;
            pSysConfig->BillingData.isBilling = YES;
            for (j = 0; j < 24; j++) {
                pSysConfig->BillingData.Fee[j] = prices;
            }

            clearMiscCommand();
            break;

        case MISC_CMD_DEFAULT_CURRENCY:
            if (value < 0) {
                clearMiscCommand();
                return FAIL;
            }

            //log_info("default currency = %s%c", (uint8_t *)Currency[value]);
            log_info("default currency = %s", (uint8_t *)GetCurrency(value));
            pSysConfig->BillingData.Currency = value;
            clearMiscCommand();
            break;

        case MISC_CMD_ACCOUNT_BALANCE:
            if (pSysInfo->CurGunSelected != (plugNum)) {
                clearMiscCommand();
                break;
            }

#if defined DD360Audi
            if (getConfirmSelectedGun(plugNum) == FAIL) {
                log_info("Remote start not select gun");
                break;
            }
#endif //DD360Audi

            ShmSelectGunInfo->PricesInfo[plugNum].Balance = transPricesUnit((int)value);
            log_info("%d misc balance = %.2f", plugNum, ShmSelectGunInfo->PricesInfo[plugNum].Balance);
            clearMiscCommand();
            break;

        case MISC_CMD_BACKEND_STATUS :
            ShmSelectGunInfo->EthDevStatus.Backend = value;
            break;

        case MISC_CMD_ETHERNET_STATUS :
            ShmSelectGunInfo->EthDevStatus.Ethernet = value;
            break;

        case MISC_CMD_WIFI_STATUS :
            ShmSelectGunInfo->EthDevStatus.Wifi = value;
            break;

        case MISC_CMD_4G_STATUS :
            ShmSelectGunInfo->EthDevStatus.FourG = value;
            break;

        case MISC_CMD_BILLING_INFO:
            pSysConfig->BillingData.isBilling = value;
            break;

        case MISC_CMD_WEB_STOP_CHARGING:
            pSysConfig->StopChargingByButton = value;
            break;

        //--- Control Dispenser ---
        case MISC_CMD_HARDWARE_REBOOT:
            if (value != YES) {
                clearMiscCommand();
                break;
            }

            log_info("Hardware reboot");
            ShmOCPP16Data->MsMsg.bits.ResetReq = YES;
            strcpy((char *)ShmOCPP16Data->Reset.Type, "Hard");
            clearMiscCommand();
            break;

        case MISC_CMD_SOFTWARE_RESTART:
            if (value != YES) {
                clearMiscCommand();
                break;
            }

            clearMiscCommand();
            log_info("Software reboot");
            ShmOCPP16Data->MsMsg.bits.ResetReq = YES;
            strcpy((char *)ShmOCPP16Data->Reset.Type, "Soft");
            break;

        case MISC_CMD_REMOTE_START_CHARGING:
            if (value != YES) {
                if (plugNum == 1) {
                    clearMiscCommand();
                }
                break;
            }
            log_info("Remote start charging plugNum = %d", plugNum);

#if defined DD360Audi
            if (getSelGunWaitToAuthor(plugNum) == FAIL) {
                log_error("Remote start gun already charging");
                break;
            }

            if (pSysInfo->CurGunSelected != (plugNum)) {
                if (plugNum == LEFT_GUN_NUM &&
                        (ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_CONFIRM ||
                         ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_ATHOR)) {
                    ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_RELEASE;
                    strcpy((char *)pSysConfig->UserId, "");
                    pSysInfo->WaitForPlugit = NO;
                    sleep(1); //Jerry add
                    pSysInfo->SystemPage = _LCM_SELECT_GUN;
                    GetClockTime(&pSysInfo->SystemTimeoutTimer, NULL);
                    pSysInfo->SystemTimeoutFlag = Timeout_None;
                }

                if (plugNum == RIGHT_GUN_NUM &&
                        (ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_CONFIRM ||
                         ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_ATHOR)) {
                    ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_RELEASE;
                    strcpy((char *)pSysConfig->UserId, "");
                    pSysInfo->WaitForPlugit = NO;
                    sleep(1); //Jerry add
                    pSysInfo->SystemPage = _LCM_SELECT_GUN;
                    GetClockTime(&pSysInfo->SystemTimeoutTimer, NULL);
                    pSysInfo->SystemTimeoutFlag = Timeout_None;
                }

                pSysInfo->CurGunSelected = (plugNum);
                pSysInfo->CurGunSelectedByAc = NO_DEFINE;
            }
#else
            pSysInfo->CurGunSelected = (plugNum);
            pSysInfo->CurGunSelectedByAc = NO_DEFINE;
#endif //DD360Audi
            setConfirmSelGun(pSysInfo->CurGunSelected);

            ShmOCPP16Data->CsMsg.bits[plugNum].RemoteStartTransactionReq = YES;
            ShmSelectGunInfo->PricesInfo[plugNum].Balance = 0.00;
            clearMiscCommand();
            break;

        case MISC_CMD_REMOTE_STOP_CHARGING:
            if (value != YES) {
                if (plugNum == 1) {
                    clearMiscCommand();
                }
                break;
            }

            strcpy((char *)pSysConfig->UserId, "");
            //pSysInfo->WaitForPlugit = NO;
            ClearDetectPluginFlag(plugNum);
#ifdef DD360Audi
            pSysInfo->SystemPage = _LCM_SELECT_GUN;
#endif
            GetClockTime(&pSysInfo->SystemTimeoutTimer, NULL);
            pSysInfo->SystemTimeoutFlag = Timeout_None;
            destroySelectGun(plugNum);

            clearMiscCommand();
            break;

        case MISC_CMD_REMOTE_UNLOCK:
            if (value != YES) {
                if (plugNum == 1) {
                    clearMiscCommand();
                }
                break;
            }

            if (isDetectPlugin(plugNum) == YES) {
                ClearDetectPluginFlag(plugNum);
                strcpy((char *)pSysConfig->UserId, "");
#ifdef DD360Audi
                pSysInfo->SystemPage = _LCM_SELECT_GUN;
#endif
                GetClockTime(&pSysInfo->SystemTimeoutTimer, NULL);
                pSysInfo->SystemTimeoutFlag = Timeout_None;
                destroySelectGun(plugNum);
            } else {
                pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);

                pDcChargingInfo->StopChargeFlag = POWER_CABINET_STOP_CHARGING;
            }
            break;
        case MISC_CMD_AUTH_DISABLE:
            pSysConfig->AuthorisationMode = value;
            log_info("Auto Authorize Disable:%d", pSysConfig->AuthorisationMode);
            //clearMiscCommand();
        	break;
        case MISC_CMD_EVCCID_ENABLE:
            pSysConfig->isAuthrizeByEVCCID = value;
            log_info("Authorize By EVCCID:%d",pSysConfig->isAuthrizeByEVCCID);
            //clearMiscCommand();
        	break;
        case MISC_CMD_RESERVATION:
            if(value != YES)
            {
                break;
            }
            gMoreInfoReq[plugNum].bits.ReservationReq = YES;
            break;
        case MISC_CMD_CHANGE_LCM_PAGE:
            if(value == LCM_PAGE_REMOTE_START_NO_ID)
            {
                gMoreInfoReq[plugNum].bits.RemoteStartNoID = YES;
            }
            /*
            if(value == LCM_PAGE_JOIN_LINE)
            {
                if(!gPageReq[plugNum].bits.JoinLine)
                {
                    log_info("Gun %d JoinLine page is trigger", plugNum);
                }
                gPageReq[plugNum].bits.JoinLine = YES;
            }
            if(value == LCM_PAGE_PAYMENT_SWITCH)
            {
                if(!gPageReq[plugNum].bits.PaymentSwitch)
                {
                    log_info("Gun %d PaymentSwitch page is trigger", plugNum);
                }
                gPageReq[plugNum].bits.PaymentSwitch = YES;
            }*/
            break;
        case MISC_CMD_QR_CODE_REQ:
            break;
        case MISC_CMD_STATION_INFO_REQ:
            if(value != YES)
            {
                break;
            }
            gMoreInfoReq[plugNum].bits.StationInfoReq = YES;
            break;
        case MISC_CMD_FINAL_COST_REQ:
            if(value != YES)
            {
                break;
            }
            gMoreInfoReq[plugNum].bits.FinalCostReq = YES;
            break;
        case MISC_CMD_LINE_STATUS_REQ:
            LineStatusCode[plugNum] = value;
            //ShmDcCommonData->LineStatus[plugNum] = value;
            log_info("Gun %d Line Status Code: %d", plugNum, LineStatusCode[plugNum]);
            break;
        case MISC_CMD_LED_INTENSITY:
            LedIntensity = value;
            log_info("Led Intensity: %d", LedIntensity);
            break;
        case MISC_CMD_TIME_OFFSET:
            TimeZoneOffset = value;
            log_info("Time Zone Offset: %d", TimeZoneOffset);
            ShmDcCommonData->TZOffset = TimeZoneOffset;
            /*
            if (TimeZoneOffset == 480) {
                system("export TZ=CST-8");
                log_info("Set Time Zone CST 8");
            }
            */
            break;
        case MISC_CMD_DEFAULT_PRICE_REQ:
            if (value != YES)
            {
                break;
            }
            gMoreInfoReq[plugNum].bits.DefaultPriceReq = YES;
            break;
        case MISC_CMD_USER_PRICE_REQ:
            if (value != YES)
            {
                break;
            }
            gMoreInfoReq[plugNum].bits.UserPriceReq = YES;
            break;
        case MISC_CMD_RECEIPT_REQ:
            if (value != YES)
            {
                break;
            }
            gMoreInfoReq[plugNum].bits.ReceiptReq = YES;
            break;
        case MISC_CMD_RFIDCARD_ENDIAN:
            if (pSysConfig->RfidCardNumEndian != value) {
                pSysConfig->RfidCardNumEndian = value;
                log_info("Set RFID CARD %s endian", value ? "Big" : "Little");
            }
            break;
        default:
            clearMiscCommand();
            break;
        }
        usleep(128);
    }

    return ret;
}
void AddDispenserReq(uint8_t* buff, MiscCommand* req)
{
    buff[0] = (req->CMD >> 8) & 0xFF;
    buff[1] = req->CMD & 0xFF;



    buff[2] = req->Value[0];
    buff[3] = req->Value[1];
    buff[4] = req->Value[2];
    buff[5] = req->Value[3];
}

static int chargingcapabilityHandle(uint8_t *data, uint8_t plugNum)
{
    uint8_t addr = 0;
    float MaxVolt, MaxCurrent, MaxPower;
    static PricesInfo pricesInfo[2] = {0};
    CapabilityInfo *pCapabilityInfo = NULL;
    AccountInfo *pAccountInfo = NULL;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);

    //--- charging capability information --------------------------------------
    pCapabilityInfo = (CapabilityInfo *)&data[0];

    MaxVolt = (float)(ntohs(pCapabilityInfo->OutputVoltage));
    if (MaxVolt >= 0) {
        if (MaxVolt > MAX_VOLTAGE) {
            MaxVolt = MAX_VOLTAGE;
        }
        pDcChargingInfo->MaximumChargingVoltage = MaxVolt;
    }

    MaxCurrent = (float)(ntohs(pCapabilityInfo->OutputCurrent));
    if (MaxCurrent >= 0) {
        if (MaxCurrent > MAX_CURRENCY) {
            MaxCurrent = MAX_CURRENCY;
        }
        pDcChargingInfo->AvailableChargingCurrent = MaxCurrent;
    }

    MaxPower = (float)(ntohs(pCapabilityInfo->OutputPower));
    if (MaxPower >= 0) {
        if (MaxPower > MAX_POWER) {
            MaxPower = MAX_POWER;
        }
        pDcChargingInfo->AvailableChargingPower = MaxPower;
    }
    //MaxVolt = (float)(data[0] << 8 |data[1]);
    //MaxCurrent = (float)(data[2] << 8 | data[3]);
    //MaxPower = (float)(data[4] << 8 | data[5]);
    //printf("MaxVolt=%f, MaxCurrent=%f, MaxPower=%f,", MaxVolt, MaxCurrent, MaxPower);

    //--- user prices information ----------------------------------------------
    addr = (sizeof(CapabilityInfo) - 2); //2 byte reserved
    pAccountInfo = (AccountInfo *)&data[addr];

    pSysConfig->BillingData.Currency = pAccountInfo->Currency;
    ShmSelectGunInfo->PricesInfo[plugNum].UserPrices = transPricesUnit(ntohl(pAccountInfo->UserPrices));
    pDcChargingInfo->ChargingFee                     = transPricesUnit(ntohl(pAccountInfo->TotalCost));
    ShmSelectGunInfo->PricesInfo[plugNum].Balance    = transPricesUnit(ntohl(pAccountInfo->Balance));
    ShmSelectGunInfo->PricesInfo[plugNum].Discount   = transPricesUnit(ntohl(pAccountInfo->Discount));
    ShmSelectGunInfo->PricesInfo[plugNum].TransactionId = ntohl(pAccountInfo->Transaction);
    ShmSelectGunInfo->PricesInfo[plugNum].EnergyCost = transPricesUnit(ntohl(pAccountInfo->EnergyCost));
    ShmSelectGunInfo->PricesInfo[plugNum].ParkingFee = transPricesUnit(ntohl(pAccountInfo->ParkingFee));
    pAccountInfo->RemainAmount = ntohl(pAccountInfo->RemainAmount);
    memcpy((char*)&ShmSelectGunInfo->PricesInfo[plugNum].RemainAmount, (char*)&pAccountInfo->RemainAmount, sizeof(uint32_t));

    if ((pricesInfo[plugNum].UserPrices != ShmSelectGunInfo->PricesInfo[plugNum].UserPrices) ||
            (pricesInfo[plugNum].Balance != ShmSelectGunInfo->PricesInfo[plugNum].Balance) ||
			(pricesInfo[plugNum].Discount != ShmSelectGunInfo->PricesInfo[plugNum].Discount) ||
			(pricesInfo[plugNum].TransactionId != ShmSelectGunInfo->PricesInfo[plugNum].TransactionId) ||
            (pricesInfo[plugNum].EnergyCost != ShmSelectGunInfo->PricesInfo[plugNum].EnergyCost) ||
            (pricesInfo[plugNum].ParkingFee != ShmSelectGunInfo->PricesInfo[plugNum].ParkingFee) || 
            (pricesInfo[plugNum].RemainAmount != ShmSelectGunInfo->PricesInfo[plugNum].RemainAmount)) {
        pricesInfo[plugNum].UserPrices = ShmSelectGunInfo->PricesInfo[plugNum].UserPrices;
        pricesInfo[plugNum].Balance = ShmSelectGunInfo->PricesInfo[plugNum].Balance;
        pricesInfo[plugNum].Discount = ShmSelectGunInfo->PricesInfo[plugNum].Discount;
        pricesInfo[plugNum].TransactionId = ShmSelectGunInfo->PricesInfo[plugNum].TransactionId;
        pricesInfo[plugNum].ParkingFee = ShmSelectGunInfo->PricesInfo[plugNum].ParkingFee;
        pricesInfo[plugNum].EnergyCost = ShmSelectGunInfo->PricesInfo[plugNum].EnergyCost;
        pricesInfo[plugNum].RemainAmount = ShmSelectGunInfo->PricesInfo[plugNum].RemainAmount;
        if (ShmSelectGunInfo->PricesInfo[plugNum].TransactionId != 0) {

            //ShmDcCommonData->TransactionInfo[plugNum].TransactionId = ShmSelectGunInfo->PricesInfo[plugNum].TransactionId;
            //UpdateDeductInfoStatus(plugNum, &ShmDcCommonData->TransactionInfo[plugNum]);

            log_info("id = %d, transaction id = %d, user prices = %.2f, Discount = %.2f, Account balances = %.2f, currency = %s",
                plugNum,
                ShmSelectGunInfo->PricesInfo[plugNum].TransactionId,
                ShmSelectGunInfo->PricesInfo[plugNum].UserPrices,
                ShmSelectGunInfo->PricesInfo[plugNum].Discount,
                ShmSelectGunInfo->PricesInfo[plugNum].Balance,
                (uint8_t*)GetCurrency(pSysConfig->BillingData.Currency)
            );
            log_info("Total Cost:%.2f", pDcChargingInfo->ChargingFee);
            log_info("Parking Fee:%.2f", ShmSelectGunInfo->PricesInfo[plugNum].ParkingFee);
            log_info("Energy Cost:%.2f", ShmSelectGunInfo->PricesInfo[plugNum].EnergyCost);
            log_info("Remain Amount:%.2f", ShmSelectGunInfo->PricesInfo[plugNum].RemainAmount);
        }
    }

    return PASS;
}

static void addFaultCodeToBuf(uint8_t *Code)
{
    uint8_t warningCount = pSysWarning->WarningCount;

    if (warningCount < 10) {
        memcpy(&pSysWarning->WarningCode[warningCount][0],
               Code,
               strlen((char *)Code));
        pSysWarning->WarningCount++;
        log_info("Warning Code:%s",Code);
    }
}

static void removeFaultCodeToBuf(uint8_t *Code)
{
    uint8_t find = 0x01;
    uint8_t i = 0;
    char _code[7] = {0};

    sprintf(_code, "%s", Code);

    // 把相關的錯誤碼一次移除,避免重複顯示
    while (find) {
        usleep(128);
        find = 0x00;
        for (i = 0; i < pSysWarning->WarningCount; i++) {
            usleep(128);
            if (find == 0x00) {
                if (memcmp(&pSysWarning->WarningCode[i][0], _code, 7) == 0) {
                    find = 0x01;
                }
            } else {
                memcpy(&pSysWarning->WarningCode[i - 1][0],
                       &pSysWarning->WarningCode[i][0], 7);
            }
        }

        if (find) {
            pSysWarning->WarningCount--;
        }
    }
}

bool CompareArrayIsZero(uint8_t *array, unsigned int array_size)
{
    uint8_t i;

    if (array != NULL) {
        for (i = 0; i < array_size; i++) {
            if (array[i] != 0) {
                return false;
            }
        }
    }

    return true;
}
static int powerCabinetStatusProcess(uint8_t dataLen, uint8_t *data)
{
    uint8_t ret = 0;
    uint8_t i = 0;
    uint8_t count = 0;
    uint8_t EventCodeTmp[7] = {0};
    uint8_t StatusArray[MAX_REGISTER_NUM][WARNING_CODE_SIZE] = {0};
    uint8_t remaindLen = 0;
    //uint8_t statusCodeError = 0;
    if (dataLen > 0) {
        //Hexdump((uint8_t *)data, dataLen);

        remaindLen = dataLen % WARNING_CODE_SIZE;

        if (remaindLen != 0) {
            log_info("fail status code length =  %d", dataLen);
            dataLen -= remaindLen;
        }

        if (dataLen < WARNING_CODE_SIZE) {
            log_error("fail status code length = %d", dataLen);
            //Hexdump(data, dataLen);
            if (pSysWarning->WarningCount > 0) {
                for (i = 0; i < pSysWarning->WarningCount; i++) {
                    usleep(128);
                    if (pSysWarning->WarningCode[i][1] >= '3' ||  //from backend or power cabinet
                            (pSysWarning->WarningCode[i][0] >= 'B' &&
                             pSysWarning->WarningCode[i][1] >= '4')) {
                        memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                        memcpy(EventCodeTmp,
                               pSysWarning->WarningCode[i],
                               sizeof(EventCodeTmp));
                        removeFaultCodeToBuf(EventCodeTmp);
                    }
                }
            }
            return FAIL;
        }

        for (count = 0; count < dataLen; count += WARNING_CODE_SIZE) {
            usleep(128);

            if (strncmp((char *)&data[count + 1], "1", 1) != 0 &&
                    strncmp((char *)&data[count + 1], "2", 1) != 0 &&
                    strncmp((char *)&data[count + 1], "3", 1) != 0 &&
                    (strncmp((char *)&data[count], "B", 1) != 0 &&
                     strncmp((char *)&data[count + 1], "4", 1) != 0)
               ) {
                log_error("error status code = %s", (char *)&data[count]);
                continue;
            }

            // misc command status code handle
            if (strncmp((char *)&data[count], MISC_ST_MISC_CMD, WARNING_CODE_SIZE) == 0) {
                gDoCommGblData.MiscCmd = REG_MISC_CONTROL;
                memset((char *)&data[count], 0, WARNING_CODE_SIZE);
                continue;
            } else if (strncmp((char *)&data[count], MISC_ST_VERSION, WARNING_CODE_SIZE) == 0) {
                gDoCommGblData.MiscCmd = REG_REPORT_CSU_VERSION;
                memset((char *)&data[count], 0, WARNING_CODE_SIZE);
                continue;
            }

            if (CompareArrayIsZero((uint8_t *)&data[count], WARNING_CODE_SIZE) == true) {
                memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                memcpy(EventCodeTmp, (char *)&data[count], sizeof(EventCodeTmp));
                log_error("error status = %s", EventCodeTmp);
                continue;
            }

            strncpy((char *)&StatusArray[count / WARNING_CODE_SIZE], (char *)&data[count], WARNING_CODE_SIZE);

            ret = 0;
            for (i = 0; i < pSysWarning->WarningCount; i++) {
                usleep(128);
                if (memcmp(&pSysWarning->WarningCode[i][0],
                           StatusArray[count / WARNING_CODE_SIZE],
                           WARNING_CODE_SIZE) == 0) {
                    ret = 1;
                    break;
                }
            }

            if (ret == 0) {
                addFaultCodeToBuf(StatusArray[count / WARNING_CODE_SIZE]);
            }
            //Rtn=StatusCodeProcessing(StatusArray[count/6]);
        }
    } else {
        if (CompareArrayIsZero(data, WARNING_CODE_SIZE) == false) {
            log_error("power cabinet status code data length is zero, but have data");
            //Hexdump((uint8_t *)data, WARNING_CODE_SIZE);
        }
    }

    for (i = 0; i < pSysWarning->WarningCount; i++) {
        usleep(128);

        if (pSysWarning->WarningCode[i][1] >= '3' || //from backend or power cabinet 0x33
                (pSysWarning->WarningCode[i][0] >= 'B' &&
                 pSysWarning->WarningCode[i][1] >= '4')) {
            ret = 0;

            for (count = 0; count < (dataLen / WARNING_CODE_SIZE); count++) {
                usleep(128);
                if (memcmp(&pSysWarning->WarningCode[i][0],
                           StatusArray[count],
                           WARNING_CODE_SIZE) == 0) {
                    ret = 1;
                    break;
                }
            }

            if (ret == 0) {
                memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                memcpy(EventCodeTmp,
                       pSysWarning->WarningCode[i],
                       sizeof(EventCodeTmp));
                removeFaultCodeToBuf(EventCodeTmp);
            }
        }
    }

    return PASS;
}

static int responsePackeHandle(int fd, uint8_t *pResult, uint8_t plugNum, uint8_t reg)
{
    int ret = PASS;
    uint8_t rawDataLen = 0;
    CsuResultPkt *pCsuResult = (CsuResultPkt *)pResult;
    SoftwareUpdInfo *pSoftwareUpd = NULL;
    PcPsuOutput *pPcPsuOutput = NULL;

    //Hexdump((uint8_t *)pCsuResult, sizeof(CmdHead) + pCsuResult->Head.DataLen);
    if (compareOpcode(pCsuResult->Head.OP) == FAIL ||
            compareResult(pCsuResult->Data.Result) == FAIL ||
            compareRegister(pCsuResult->Data.Register, reg) == FAIL) {
        if (reg != REG_CHARGING_PERMISSION) {
            return FAIL;
        }
    }

    rawDataLen = (pCsuResult->Head.DataLen - 2); //2 byte = register and result byte

    switch (pCsuResult->Data.Register) {
    case REG_MODEL_NAME:
        break;

    case REG_CONNECTOR_ID:
        gDoCommGblData.ConnectorID[0] = pCsuResult->Data.Data[0];
        gDoCommGblData.ConnectorID[1] = pCsuResult->Data.Data[1];
        log_info("OK (Left connector ID = %d, Right connector ID = %d)",
                 pCsuResult->Data.Data[0],
                 pCsuResult->Data.Data[1]);
        ShmDcCommonData->pGunInfo[0].ConnectorID = pCsuResult->Data.Data[0];
        ShmDcCommonData->pGunInfo[1].ConnectorID = pCsuResult->Data.Data[1];
        break;

    case REG_POWER_CABINET_STATUS:
        ret = powerCabinetStatusProcess(rawDataLen, pCsuResult->Data.Data);
        break;

    case REG_DISPENSER_STATUS:
        memset(&gPreSysWarningInfo, 0, sizeof(struct WARNING_CODE_INFO));
        memcpy((uint8_t *)&gPreSysWarningInfo,
               pSysWarning,
               sizeof(struct WARNING_CODE_INFO));
        break;

    case REG_CHARGING_CAP:
        chargingcapabilityHandle(pCsuResult->Data.Data, plugNum);
        break;

    case REG_CHARGING_TARGET:
        break;

    case REG_SOFTWARE_UPDATE:
        pSoftwareUpd = (SoftwareUpdInfo *)&pCsuResult->Data.Data[0];

        if ((strcmp((char *)pSoftwareUpd->ImgName, "") == 0) ||
                (rawDataLen == 0) ||
                pSoftwareUpd->UpdateState != 1) {
            ret = FAIL;
            break;
        }

        ret = FAIL;
        ret = updateFirmwareHandle(pSoftwareUpd->ImgName);
        break;

    case REG_PLUG_IN_STATE:
        break;

    case REG_CONNECTOR_STATE:
        break;

    case REG_USER_ID:
        //log_info("USER ID:%s", pCsuResult->Data.Data[0] == 1 ? "Accept" : "Reject" );
        //if (pCsuResult->Data.Data[0] <= 0) {
        //    return FAIL;
        //}
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }

        ShmSelectGunInfo->AuthorStateFromCabinet[plugNum] = pCsuResult->Data.Data[0];

        return pCsuResult->Data.Data[0];
        break;

    case REG_CHARGING_PERMISSION:
        //log_info("id = %d, result = %s, action = %s",
        //           pCsuResult->Head.ID,
        //           pCsuResult->Data.Result == 1 ? "OK" : "NG",
        //           pCsuResult->Data.Data[0] == 1 ? "Permitted" : "NOT permitted");
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }

        ShmSelectGunInfo->WaitDoCommPermission[plugNum] = pCsuResult->Data.Data[0];
        return pCsuResult->Data.Data[0];
        break;

    case REG_MISC_CONTROL:
        miscCommandHandle(rawDataLen, plugNum, pCsuResult->Data.Data);
        break;

    case REG_REPORT_CSU_VERSION:
    case REG_REPORT_OTHER_VERSION:
        break;

    case REG_PRESENT_CHARGING_INFO:
        pPcPsuOutput = (PcPsuOutput *)&pCsuResult->Data.Data[0];

        ShmDcCommonData->PcPsuOutput[plugNum].Voltage = ntohs((uint16_t)pPcPsuOutput->Voltage);
        ShmDcCommonData->PcPsuOutput[plugNum].Current = ntohs((uint16_t)pPcPsuOutput->Current);
        //log_info("%d power cabinet PSU output vol = %f, cur = %f",
        //         plugNum,
        //         (float)ShmDcCommonData->PcPsuOutput[plugNum].Voltage,
        //         (float)ShmDcCommonData->PcPsuOutput[plugNum].Current);
        break;

    case REG_QRCODE_URL_INFO:
        ret = qrCodeUrlInfoHandle(pCsuResult->Data.Data);
        break;

    case REG_WAIT_PLUG_IT_STATE:
        break;

    case REG_Ground_Fault_Detection:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }

        //集電弓relay 不打開才能進入動作
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);
        if(pDcChargingInfo->PantographFlag == YES)
        {
            GroundFaultDetection *gfd = (GroundFaultDetection *)&pCsuResult->Data.Data[0];
            if(pDcChargingInfo->GroundFaultStatus != gfd->Status)
            {
                log_info("id = %d, GFD Result = %d",
                           pCsuResult->Head.ID,
                           gfd->Status);
            }
            pDcChargingInfo->GroundFaultStatus = gfd->Status;
        }
        break;

    case REG_RESERVATION_IDTAG:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        uint8_t reservationState = pCsuResult->Data.Data[0] == YES ? YES : NO;
        memset(&ReservationIdTag[plugNum][0], 0x00, 32);
        if(reservationState)
        {
            strcpy(&ReservationIdTag[plugNum][0], (char *)&pCsuResult->Data.Data[1]);
        }
        if(reservationState != ReservationState[plugNum] || 
            (strcmp((char*)ShmDcCommonData->pGunInfo[plugNum].ReservationID, (char*)ReservationIdTag[plugNum]) != EQUAL) )
        {
            log_info("id = %d reservation is %s", pCsuResult->Head.ID, reservationState ? "trigger" : "expired");
            if(reservationState)
            {
                log_info("id = %d reservation idTag: %s", pCsuResult->Head.ID, (char *)&ReservationIdTag[plugNum][0]);
                pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(plugNum);
                strcpy(&ShmDcCommonData->pGunInfo[plugNum].ReservationID[0], (char*)&pCsuResult->Data.Data[1]);
                
                pDcChargingInfo->SystemStatus = S_RESERVATION;
            } else {
                if (pDcChargingInfo->SystemStatus == S_RESERVATION && pSysInfo->WaitForPlugit == NO)
                    pDcChargingInfo->SystemStatus = S_IDLE;
            }
        }
        ReservationState[plugNum] = reservationState;
        ShmDcCommonData->pGunInfo[plugNum].ReservationStatus = reservationState;
        break;

    case REG_REMOTE_START_NO_ID:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        uint8_t remoteStartNoIdState = pCsuResult->Data.Data[0] == YES ? YES : NO;
        if(remoteStartNoIdState != RemoteStartNoIDState)
        {
            log_info("RemoteStartNoID is %s", remoteStartNoIdState ? "trigger" : "expired");
        }
        RemoteStartNoIDState = remoteStartNoIdState;
        break;

    case REG_STATION_INFO:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        StationVar _stationInfo;
        memset((char *)&_stationInfo, 0x00, sizeof(StationVar));

        _stationInfo.StationID = (pCsuResult->Data.Data[0] << 24) +
                                 (pCsuResult->Data.Data[1] << 16) +
                                 (pCsuResult->Data.Data[2] << 8) +
                                 pCsuResult->Data.Data[3];
        memcpy(_stationInfo.StationName, (char *)&pCsuResult->Data.Data[4], 64);
        _stationInfo.WeatherID |= (pCsuResult->Data.Data[68] << 24);
        _stationInfo.WeatherID |= (pCsuResult->Data.Data[69] << 16);
        _stationInfo.WeatherID |= (pCsuResult->Data.Data[70] << 8);
        _stationInfo.WeatherID |= pCsuResult->Data.Data[71];
        uint8_t *pFloat = (uint8_t *)&_stationInfo.Temperature;
        *(pFloat + 3) = pCsuResult->Data.Data[72];
        *(pFloat + 2) = pCsuResult->Data.Data[73];
        *(pFloat + 1) = pCsuResult->Data.Data[74];
        *(pFloat) = pCsuResult->Data.Data[75];

        ShmDcCommonData->WeatherID = _stationInfo.WeatherID;
        ShmDcCommonData->Temperature = _stationInfo.Temperature;
        ShmDcCommonData->Location = atoi(_stationInfo.StationName);

        log_info("Station Name: %s, ID: %d, Weather: %d, Temperature: %.1f",
                _stationInfo.StationName,
                _stationInfo.StationID,
                _stationInfo.WeatherID,
                _stationInfo.Temperature);
        break;

    case REG_DEDUCT_INFO:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        break;
    case REG_READ_CABINET_SYSTEMID:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        if (strcmp((char*)pSysConfig->SystemId, (char*)pCsuResult->Data.Data) != 0) {
            strcpy((char*)pSysConfig->SystemId, (char*)pCsuResult->Data.Data);
            log_info("System ID:%s", pSysConfig->SystemId);
        }
        break;
    case REG_READ_DEFAULT_PRICE:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        gMoreInfoReq[plugNum].bits.DefaultPriceReq = NO;
        if (strcmp((char*)ShmDcCommonData->DefaultPriceString, (char*)pCsuResult->Data.Data) != EQUAL) {
            strcpy((char*)ShmDcCommonData->DefaultPriceString, (char*)pCsuResult->Data.Data);
            log_info("Default Price:%s", ShmDcCommonData->DefaultPriceString);
        }
        break;
    case REG_READ_USER_PRICE:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        gMoreInfoReq[plugNum].bits.UserPriceReq = NO;
        if (strcmp((char*)ShmDcCommonData->pGunInfo[plugNum].UserPriceString, (char*)pCsuResult->Data.Data) != EQUAL) {
            strcpy((char*)ShmDcCommonData->pGunInfo[plugNum].UserPriceString, (char*)pCsuResult->Data.Data);
            log_info("User Price:%s", ShmDcCommonData->pGunInfo[plugNum].UserPriceString);
        }
        break;
    case REG_RECEIPT_INFO:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        gMoreInfoReq[plugNum].bits.ReceiptReq = NO;
        if (strcmp((char*)ShmDcCommonData->pGunInfo[plugNum].ReceiptInfo, (char*)pCsuResult->Data.Data) != EQUAL) {
            strcpy((char*)ShmDcCommonData->pGunInfo[plugNum].ReceiptInfo, (char*)pCsuResult->Data.Data);
            log_info("Gun%d Receipt:%s", plugNum, ShmDcCommonData->pGunInfo[plugNum].ReceiptInfo);
        }
        break;
    case REG_READ_CHARGING_TIMESTAMP:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        if (rawDataLen <= 2) {
            log_info("No Charging timestamp");
            break;
        }

        strcpy((char*)ShmDcCommonData->pGunInfo[plugNum].ChargeStartTime, (char*)&pCsuResult->Data.Data[0]);
        int timelen = strlen((char*)ShmDcCommonData->pGunInfo[plugNum].ChargeStartTime);
        if (timelen != 0) {
            timelen = strcpy((char*)ShmDcCommonData->pGunInfo[plugNum].ChargeStopTime, (char*)&pCsuResult->Data.Data[timelen+1]);
        }
        break;
        
    case REG_POWER_CONSUMPTION_INFO:
        if (pCsuResult->Data.Result == COMMAND_RESULT_NG) {
            return COMMAND_RESULT_NG;
        }
        
        PowConsumValue* pValue =NULL;
        pValue = (PowConsumValue*)&pCsuResult->Data.Data[0];

        pValue->Gun1_Consumption = ntohl(pValue->Gun1_Consumption);
        pValue->Gun2_Consumption = ntohl(pValue->Gun2_Consumption);
        pValue->Gun3_Consumption = ntohl(pValue->Gun3_Consumption);
        pValue->Gun4_Consumption = ntohl(pValue->Gun4_Consumption);
        memcpy((char*)&ShmDcCommonData->pConsumption.Gun1_Consumption, (char*)&pValue->Gun1_Consumption, sizeof(uint32_t));
        memcpy((char*)&ShmDcCommonData->pConsumption.Gun2_Consumption, (char*)&pValue->Gun2_Consumption, sizeof(uint32_t));
        memcpy((char*)&ShmDcCommonData->pConsumption.Gun3_Consumption, (char*)&pValue->Gun3_Consumption, sizeof(uint32_t));
        memcpy((char*)&ShmDcCommonData->pConsumption.Gun4_Consumption, (char*)&pValue->Gun4_Consumption, sizeof(uint32_t));
        /*
        log_info("Gun1_Consumption:%f", ShmDcCommonData->pConsumption.Gun1_Consumption);
        log_info("Gun2_Consumption:%f", ShmDcCommonData->pConsumption.Gun2_Consumption);
        log_info("Gun3_Consumption:%f", ShmDcCommonData->pConsumption.Gun3_Consumption);
        log_info("Gun4_Consumption:%f", ShmDcCommonData->pConsumption.Gun4_Consumption);
        */
        
        break;
        
    default:
        break;
    }

    return ret;
}

static int composeSocketData(int fd,
                             uint8_t id,
                             uint8_t opCode,
                             uint8_t reg,
                             uint8_t dataLen,
                             uint8_t *data)
{
    int ret = PASS;
    int size = 0;
    int sendPktLen = 0;
    uint8_t i = 0;
    uint8_t plugNum = 0;
    CsuCmdPkt csuCmdPkt = {0};
    CsuResultPkt csuResult = {0};

    csuCmdPkt.Head.SeqNum = gDoCommGblData.SeqNum++;
    csuCmdPkt.Head.ID = id;
    csuCmdPkt.Head.OP = opCode;
    csuCmdPkt.Head.DataLen = dataLen + 1; //+1 for register byte

    csuCmdPkt.Data.Register = reg;
    if ((data != NULL) && (dataLen > 0)) {
        memcpy(csuCmdPkt.Data.Data, data, dataLen);
    }

    sendPktLen = csuCmdPkt.Head.DataLen + sizeof(csuCmdPkt.Head);

    //Hexdump((uint8_t *)&csuCmdPkt, sendPktLen);

    //send command packet
    if ((size = sendTcpSocket(fd, (uint8_t *)&csuCmdPkt, sendPktLen)) < 0) {
        log_error("TCP socket send packet fail = %d", size);
        gDoCommGblData.DisConnCount++;
        return FAIL;
    }

    //receive result head
    if ((size = recvTcpSocket(fd, (uint8_t *)&csuResult.Head, sizeof(csuResult.Head), 1)) < 0) {
        log_error("TCP socket RX head fail = %d", size);
        gDoCommGblData.DisConnCount++;
        return FAIL;
    }

    //receive result raw data
    if ((size = recvTcpSocket(fd, (uint8_t *)&csuResult.Data, csuResult.Head.DataLen, 0)) < 0) {
        log_error("TCP socket RX data fail = %d", size);
        gDoCommGblData.DisConnCount++;
        return FAIL;
    }

    for (i = 0; i < sizeof(gDoCommGblData.ConnectorID); i++) {
        if (id == gDoCommGblData.ConnectorID[i]) {
            plugNum = i;
            break;
        }
    }

    ret = responsePackeHandle(fd, (uint8_t *)&csuResult, plugNum, csuCmdPkt.Data.Register);

    gDoCommGblData.DisConnCount = 0; //送收資料沒有問題, 清除中斷網路計數

    return ret;
}
static int writeDispenserRequest(int fd, uint8_t id, uint8_t gunIndex)
{
    int ret = PASS;
    int count = 0;
    MiscCommand dispenserReq;
    uint8_t data[6] = { 0 };
    if (gConnectorActReq[gunIndex].bits.ChargingCancel)
    {
        dispenserReq.CMD = DISPENSER_REQ_CHARGING_CANCEL;
        dispenserReq.Value[0] = 0;
        dispenserReq.Value[1] = 0;
        dispenserReq.Value[2] = 0;
        dispenserReq.Value[3] = 1;
        AddDispenserReq(data, &dispenserReq);
        count++;
        //log_info("Write Gun %d CHARGING_CANCEL", gunIndex);
    }

    if ((ret = composeSocketData(fd,
        id,
        OP_WRITE_DATA,
        REG_DISPENSER_REQUEST,
        (count * 6),
        &data[0])) == FAIL) {
        return ret;
    }
    return ret;
}
static int readReservationState(int fd, uint8_t id)
{
    int ret = PASS;

    if ((ret = composeSocketData(fd,
                                 id,
                                 OP_READ_DATA,
                                 REG_RESERVATION_IDTAG,
                                 0,
                                 NULL)) == FAIL) {
        return ret;
    }

    return ret;
}

static int readRemoteStartNoIDState(int fd)
{
    int ret = PASS;

    if ((ret = composeSocketData(fd,
                                 ID_REGISTER,
                                 OP_READ_DATA,
                                 REG_REMOTE_START_NO_ID,
                                 0,
                                 NULL)) == FAIL) {
        return ret;
    }

    return ret;
}

static int readChargerStationInfo(int fd)
{
    int ret = PASS;

    if ((ret = composeSocketData(fd,
                                 ID_REGISTER,
                                 OP_READ_DATA,
                                 REG_STATION_INFO,
                                 0,
                                 NULL)) == FAIL) {
        return ret;
    }

    return ret;
}
/*
static int writeDeductInfo(int fd, uint8_t id,uint8_t gunIndex, RecordTransactionInfo *transactionInfo)
{
    int ret = PASS;
    uint8_t dataBuf[104] = {0};
    //int i;

    memset((char *)dataBuf, 0x00, sizeof(dataBuf));
    dataBuf[0] = transactionInfo->DeductResult;
    dataBuf[1] = transactionInfo->IsDonateInvoice;
    dataBuf[2] = (transactionInfo->TransactionId >> 24) & 0xFF;
    dataBuf[3] = (transactionInfo->TransactionId >> 16) & 0xFF;
    dataBuf[4] = (transactionInfo->TransactionId >> 8) & 0xFF;
    dataBuf[5] = (transactionInfo->TransactionId & 0xFF);

    int amount = (int)(transactionInfo->Amount * 100);

    dataBuf[6] = (amount >> 24) & 0xFF;
    dataBuf[7] = (amount >> 16) & 0xFF;
    dataBuf[8] = (amount >> 8) & 0xFF;
    dataBuf[9] = (amount & 0xFF);
    memcpy((char *)&dataBuf[10], transactionInfo->pCreditCard.ApprovalNo,9);
    memcpy((char *)&dataBuf[19], transactionInfo->pCreditCard.VemData, 64);
    memcpy((char*)&dataBuf[83], transactionInfo->pCreditCard.CardNo, 20);

    log_info("Gun[%d] TransactionId:%d DeductResult:%d IsDonateInvoice:%d Amount:%f Approva Num:'%s' VemData:'%s' CardNo:'%s'",
    		transactionInfo->ConnectorID,
            transactionInfo->TransactionId,
            transactionInfo->DeductResult,
            transactionInfo->IsDonateInvoice,
            transactionInfo->Amount,
            transactionInfo->pCreditCard.ApprovalNo,
            transactionInfo->pCreditCard.VemData,
            transactionInfo->pCreditCard.CardNo);
    // copy deduct result to dataBuf here

    if ((ret = composeSocketData(fd,
                                 id,
                                 OP_WRITE_DATA,
                                 REG_DEDUCT_INFO,
                                 104,
                                 &dataBuf[0])) == FAIL) {
        return ret;
    }

    return ret;
}
*/

static int readChargingTimeStamp(int fd, uint8_t id)
{
    int ret = PASS;
    if ((ret = composeSocketData(fd,
                                 id,
                                 OP_READ_DATA,
                                 REG_READ_CHARGING_TIMESTAMP,
                                 0,
                                 NULL)) == FAIL) {
        return ret;
    }

    return ret;
}
static int writeWaitPlugItState(int fd, uint8_t id, uint8_t gunIndex)
{
    int ret = PASS;
    uint8_t data[2] = { ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit, 0 };
    if (_isplugin != ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit) {
        //log_info("Wait Gun%d for plug:%s", gunIndex, ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit == 0 ? "disable" : "enable");
        _isplugin = ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit;
    }
    //printf("WaitForPlugit = %d", pSysInfo->WaitForPlugit);

    if ((ret = composeSocketData(fd,
                                 id,
                                 OP_WRITE_DATA,
                                 REG_WAIT_PLUG_IT_STATE,
                                 1,
                                 &data[0])) == FAIL) {
        return ret;
    }

    return ret;
}

static int readQRcodeURLAndSystemDate(int fd)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_READ_DATA,
                            REG_QRCODE_URL_INFO,
                            0,
                            NULL);
    return ret;
}

static int writePresentChargingInfo(int fd, uint8_t plugNum, uint8_t id)
{
    int ret = PASS;
    uint8_t dataBuf[16] = {0};
    PreChargingInfo *pPreChargingInfo = (PreChargingInfo *)dataBuf;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);

    if(pDcChargingInfo->PantographFlag == NO)
    {
        pPreChargingInfo->PresentChargingVoltage = htons((uint16_t)(pDcChargingInfo->PresentChargingVoltage * 10));
        pPreChargingInfo->PresentChargingCurrent = htons((uint16_t)(pDcChargingInfo->PresentChargingCurrent * 10));
    }
    else
    {
        pPreChargingInfo->PresentChargingVoltage = htons((uint16_t)(ShmDcCommonData->PcPsuOutput[plugNum].Voltage));
        pPreChargingInfo->PresentChargingCurrent = htons((uint16_t)(ShmDcCommonData->PcPsuOutput[plugNum].Current));
    }
    pPreChargingInfo->RemainChargingDuration = htonl(pDcChargingInfo->RemainChargingDuration);
    pPreChargingInfo->EvBatterySoc = pDcChargingInfo->EvBatterySoc;

    ret = composeSocketData(fd,
                            id,
                            OP_WRITE_DATA,
                            REG_PRESENT_CHARGING_INFO,
                            sizeof(PreChargingInfo),
                            (uint8_t *)pPreChargingInfo);
    return ret;
}

static int writeOtherModuleVersion(int fd)
{
    int ret = PASS;
    uint8_t data[255] = {0};
    uint8_t dataLen = 0;

    //report other module version message
    memcpy(&data[dataLen], pSysInfo->FanModuleFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->RelayModuleFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->Connector1FwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->Connector2FwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->LedModuleFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_WRITE_DATA,
                            REG_REPORT_OTHER_VERSION,
                            dataLen,
                            &data[0]);

    return ret;
}

static int writeCsuModuleVersion(int fd)
{
    int ret = PASS;
    uint8_t data[255] = {0};
    uint8_t dataLen = 0;

    //report CSU platform version message
    memcpy(&data[dataLen], pSysInfo->CsuBootLoadFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->CsuKernelFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->CsuRootFsFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;
    memcpy(&data[dataLen], pSysInfo->CsuPrimFwRev, VERSION_BUF_SIZE);
    dataLen += VERSION_BUF_SIZE;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_WRITE_DATA,
                            REG_REPORT_CSU_VERSION,
                            dataLen,
                            &data[0]);

    return ret;
}

static int readMiscCommand(int fd, uint8_t id)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            id,
                            OP_READ_DATA,
                            REG_MISC_CONTROL,
                            0,
                            NULL);

    return ret;
}

static int readChargePermission(int fd, uint8_t id)
{
    return composeSocketData(fd,
                             id,
                             OP_READ_DATA,
                             REG_CHARGING_PERMISSION,
                             0,
                             NULL);
}

static int writeGroundFaultDetection(int fd, uint8_t status, uint8_t id)
{
    int ret = PASS;
    uint8_t dataBuf[1] = {status};
    ret = composeSocketData(fd,
                            id,
                            OP_WRITE_DATA,
                            REG_Ground_Fault_Detection,
                            1,
                            &dataBuf[0]);
    return ret;
}

static int writeUserID(int fd, uint8_t id, uint8_t *pUserID)
{
    if ((strlen((char *)pUserID) <= 0) || (pUserID == NULL)) {
        return FAIL;
    }
    uint8_t data[50];
    int datalen = strlen((char*)pUserID);
    memcpy((uint8_t*)data, pUserID, datalen);
    data[datalen] = '\0';
    data[datalen+1] = ShmDcCommonData->AuthroizeType;
    datalen += 2;
    return composeSocketData(fd,
                             id,
                             OP_WRITE_DATA,
                             REG_USER_ID,
                             datalen,
                             &data[0]);
}

static int writeConnectorState(int fd, uint8_t plugNum, uint8_t id)
{
    uint8_t dataBuf[16] = {'\0'};
    uint32_t _consumption;
    ConnectorState *pConnState = (ConnectorState *)dataBuf;
    static char vendorErrorCodeTmp[2][WARNING_CODE_SIZE] = {0};
    int ret = PASS;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);

    pConnState->ConnectorTemp = pDcChargingInfo->ConnectorTemp;
    pConnState->ChillerTemp = pDcChargingInfo->ChillerTemp;
    pConnState->PlugIn = pDcChargingInfo->ConnectorPlugIn;
    pConnState->ConnectMode = pDcChargingInfo->SystemStatus;

    if (pDcChargingInfo->SystemStatus <= S_AUTHORIZING) {
        pConnState->State = CONN_ST_IDLE;    //idle
        strncpy((char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode,
                "",
                sizeof(ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode));
        strncpy(&vendorErrorCodeTmp[plugNum][0], "", WARNING_CODE_SIZE);
    } else if ((pDcChargingInfo->SystemStatus <= S_PREPARING_FOR_EVSE) ||
               (pDcChargingInfo->SystemStatus == S_CCS_PRECHARGE_ST0) ||
               (pDcChargingInfo->SystemStatus == S_CCS_PRECHARGE_ST1)) {
        pConnState->State = CONN_ST_PREPARING;    //preparing
    } else if (pDcChargingInfo->SystemStatus == S_CHARGING) {
        pConnState->State = CONN_ST_CHARGING;    //charging
    } else if (pDcChargingInfo->SystemStatus == S_TERMINATING ||
            pDcChargingInfo->SystemStatus == S_COMPLETE) {
        if (pSysConfig->ModelName[3] == 'P') {
            if (!ShmDcCommonData->pGunInfo[plugNum].isMeterStop) {
                return FAIL;
            }
        } else {
            if (pDcChargingInfo->RelayK1K2Status == YES) {
                return FAIL;
            }
        }
        pConnState->State = CONN_ST_TERMINATING;    //terminating

    } else if ((pDcChargingInfo->SystemStatus == S_ALARM) ||
               (pDcChargingInfo->SystemStatus == S_FAULT)) {
        if (pSysConfig->ModelName[3] == 'P') {
            if (!ShmDcCommonData->pGunInfo[plugNum].isMeterStop && pDcChargingInfo->SystemStatus == S_ALARM) {
                return FAIL;
            }
        } else {
            if (pDcChargingInfo->RelayK1K2Status == YES && pDcChargingInfo->SystemStatus == S_ALARM) {
                return FAIL;
            }
        }
        pConnState->State = CONN_ST_ALARM;
        strncpy((char *)pConnState->WarningCode,
                (char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode,
                WARNING_CODE_SIZE);

        if (strncmp(&vendorErrorCodeTmp[plugNum][0], "", WARNING_CODE_SIZE) == 0) {
            strncpy(&vendorErrorCodeTmp[plugNum][0],
                    (char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode,
                    WARNING_CODE_SIZE);
            vendorErrorCodeTmp[plugNum][6] = '\0';
            /*
            log_info("1 ID = %d, VendorErrorCode = %s",
                     plugNum,
                     (char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode);
            */
        } else {
            if (strncmp(&vendorErrorCodeTmp[plugNum][0],
                        (char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode,
                        WARNING_CODE_SIZE) != 0
               ) {
                strncpy(&vendorErrorCodeTmp[plugNum][0],
                        (char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode,
                        WARNING_CODE_SIZE);
                vendorErrorCodeTmp[plugNum][6] = '\0';
                /*
                log_info("2 ID = %d, VendorErrorCode = %s",
                         plugNum,
                         (char *)ShmOCPP16Data->StatusNotification[plugNum].VendorErrorCode);
                         */
            }
        }
    }
    if (gunstatus[plugNum] != pConnState->State) {
        log_info("Gun%d Status[%d] to OCPP Backend",plugNum,pConnState->State);
        gunstatus[plugNum] = pConnState->State;
    }

#ifdef DD360

        memcpy((char*)&_consumption, (char*)&ShmDcCommonData->pGunInfo[plugNum].PowerConsumption, sizeof(float));
        pConnState->consumption = ntohl(_consumption);

#endif
    ret = composeSocketData(fd,
                            id,
                            OP_WRITE_DATA,
                            REG_CONNECTOR_STATE,
                            sizeof(dataBuf) - 1,
                            &dataBuf[0]);
    return ret;
}

/**
 *
 * @param data
 * @param length
 * @return
 */
uint32_t crc32(uint8_t *data, uint32_t length)
{
	uint32_t crc=0xFFFFFFFF;

	for(size_t i=0;i<length;i++)
	{
		char ch=data[i];
		for(size_t j=0;j<8;j++)
		{
			uint32_t b=(ch^crc)&1;

			crc>>=1;

			if(b) crc=crc^0xEDB88320;

			ch>>=1;
		}
	}

	return ~crc;
}

/**
 *
 * @param filename
 * @return
 */
uint32_t getFileCrc32(char *filename)
{
	uint32_t result = 0;

	int fd = open(filename, O_RDONLY);
    if(fd < 0)
    {
        log_error("Can not open file %s\n", filename);
    }
    else
    {
    	struct stat st;
		stat(filename, &st);
		uint8_t *data;
		data = malloc(st.st_size);

		if(read(fd,data,st.st_size) == st.st_size)
		{
			result = crc32(data, st.st_size);
			close(fd);
		} else {
			log_error("Read file Error %d\n", st.st_size);
		}

		free(data);
    }

	return result;
}
static int wrtieOcmpInfo(int fd, uint8_t plugNum, uint8_t id)
{
    int ret = PASS;
    uint8_t dataBuf[241];

    OcmfInfoData* pOcmf = (OcmfInfoData*)dataBuf;
    pOcmf->CRC = htonl(getFileCrc32(ShmDcCommonData->pGunInfo[plugNum].OcmfFileName));
    if (pOcmf->CRC == 0) {
        log_info("CRC is Zero! Not transmit to Cabinet");
        return FAIL;
    }
    //memcpy((char*)pOcmf->TxId,pSysInfo->DcMeterReadTransactionRecord[plugNum].head.transactionId,sizeof(pSysInfo->DcMeterReadTransactionRecord[plugNum].head.transactionId));
    sprintf((char*)pOcmf->TxId,"%d",ShmDcCommonData->ocmfTridRecord[plugNum]);

    memcpy((char*)pOcmf->OcmfPublicKey, (char*)pSysInfo->DcMeterStatusInfo[plugNum].publicKeyOcmf,sizeof(pSysInfo->DcMeterStatusInfo[plugNum].publicKeyOcmf));
    log_info("txid:[%s], crc:[%X], publicKey:[%s]",pOcmf->TxId,htonl(pOcmf->CRC),pSysInfo->DcMeterStatusInfo[plugNum].publicKeyOcmf);
    ret = composeSocketData(fd,
                        id,
                        OP_WRITE_DATA,
                        REG_OCMF_INFO,
                        sizeof(dataBuf) - 1,
                        &dataBuf[0]);
    return ret;
}
static int writePlugInStatus(int fd, uint8_t plugNum, uint8_t id)
{
    int ret = PASS;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);
    uint8_t dataBuf[2] = {pDcChargingInfo->ConnectorPlugIn, 0};

    ret = composeSocketData(fd,
                            id,
                            OP_WRITE_DATA,
                            REG_PLUG_IN_STATE,
                            1,
                            &dataBuf[0]);
    return ret;
}

static int readSoftwareUpdate(int fd, uint8_t gunID)
{
    int ret = PASS;
    uint8_t dataBuf[2] = {pSysInfo->FirmwareUpdate, 0};

    ret = composeSocketData(fd,
                            gunID,
                            OP_READ_DATA,
                            REG_SOFTWARE_UPDATE,
                            1,
                            &dataBuf[0]);

    return ret;
}

static int writeChargingTarget(int fd, uint8_t plugNum, uint8_t id)
{
    int ret = PASS;
    float ChargingVolt, ChargingAmp;
    uint8_t dataBuf[4] = {0};
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);

    if ((pDcChargingInfo->SystemStatus <= S_PREPARING_FOR_EV || pDcChargingInfo->SystemStatus >= S_TERMINATING) &&
        pDcChargingInfo->SystemStatus != S_CCS_PRECHARGE_ST0 && pDcChargingInfo->SystemStatus != S_CCS_PRECHARGE_ST1) {
        pDcChargingInfo->EvBatterytargetVoltage = 0;
        pDcChargingInfo->EvBatterytargetCurrent = 0;
    }

    ChargingVolt = pDcChargingInfo->EvBatterytargetVoltage;
    ChargingAmp = pDcChargingInfo->EvBatterytargetCurrent;
    ChargingVolt *= 10;
    ChargingAmp *= 10;

    dataBuf[0] = ((uint16_t)ChargingVolt >> 8) & 0xFF;
    dataBuf[1] = ((uint16_t)ChargingVolt) & 0xFF;
    dataBuf[2] = ((uint16_t)ChargingAmp >> 8) & 0xFF;
    dataBuf[3] = ((uint16_t)ChargingAmp) & 0xFF;

    ret = composeSocketData(fd,
                            id,
                            OP_WRITE_DATA,
                            REG_CHARGING_TARGET,
                            sizeof(dataBuf),
                            &dataBuf[0]);

    return ret;
}

static int readChargingCapability(int fd, uint8_t id)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            id,
                            OP_READ_DATA,
                            REG_CHARGING_CAP,
                            0,
                            NULL);

    return ret;
}

static int readReceiptInfo(int fd, uint8_t id)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            id,
                            OP_READ_DATA,
                            REG_RECEIPT_INFO,
                            0,
                            NULL);

    return ret;
}

static int writeDispenserStatus(int fd, uint8_t gunID)
{
    uint8_t warningCount = 0;
    uint8_t count = 0;
    uint8_t CurWarnCodeTmp[10][6] = {0};
    uint8_t PreWarnCodeTmp[10][6] = {0};
    int ret = PASS;

    if ((pSysWarning->WarningCount <= 0) &&
            (gPreSysWarningInfo.WarningCount <= 0)) {
        return FAIL;
    }

    warningCount = pSysWarning->WarningCount;
    for (count = 0; count < warningCount; count++) {
        memcpy(CurWarnCodeTmp[count], pSysWarning->WarningCode[count], WARNING_CODE_SIZE);
    }

    warningCount = gPreSysWarningInfo.WarningCount;
    for (count = 0; count < warningCount; count++) {
        memcpy(PreWarnCodeTmp[count], gPreSysWarningInfo.WarningCode[count], WARNING_CODE_SIZE);
    }

    if (strcmp((char *)&CurWarnCodeTmp[0], (char *)&PreWarnCodeTmp[0]) == 0) {
        return FAIL;
    }

    ret = composeSocketData(fd,
                            gunID,
                            OP_WRITE_DATA,
                            REG_DISPENSER_STATUS,
                            strlen((char *)CurWarnCodeTmp),
                            &CurWarnCodeTmp[0][0]);

    return ret;
}

static int readPowerCabinetStatus(int fd, uint8_t gunID)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            gunID,
                            OP_READ_DATA,
                            REG_POWER_CABINET_STATUS,
                            0,
                            NULL);

    return ret;
}

static int readConnectorID(int fd)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_READ_DATA,
                            REG_CONNECTOR_ID,
                            0,
                            NULL);

    return ret;
}
static int readSystemID(int fd)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_READ_DATA,
                            REG_READ_CABINET_SYSTEMID,
                            0,
                            NULL);

    return ret;
}
static int readDefaultPrice(int fd)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_READ_DATA,
                            REG_READ_DEFAULT_PRICE,
                            0,
                            NULL);

    return ret;
}
static int readUserPrice(int fd, uint8_t gunID)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            gunID,
                            OP_READ_DATA,
                            REG_READ_USER_PRICE,
                            0,
                            NULL);

    return ret;
}
static int readConsumptionInfo(int fd)
{
    int ret = PASS;

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_READ_DATA,
                            REG_POWER_CONSUMPTION_INFO,
                            0,
                            NULL);

    return ret;
}
static int WriteModelName(int fd)
{
    int ret = PASS;
    uint8_t Tmp = 0;
    uint8_t TmpBuf[255] = {0};

    memcpy(TmpBuf,
           pSysConfig->ModelName,
           strlen((char *)pSysConfig->ModelName));

    Tmp = (uint8_t)(ShmPrimaryMcuData->InputDet.bits.Key2 << 2 |
                    ShmPrimaryMcuData->InputDet.bits.Key1 << 1 |
                    ShmPrimaryMcuData->InputDet.bits.Key0);

    TmpBuf[strlen((char *)pSysConfig->ModelName)] = Tmp; //Dispenser switch value

    ret = composeSocketData(fd,
                            ID_REGISTER,
                            OP_WRITE_DATA,
                            REG_MODEL_NAME,
                            strlen((char *)pSysConfig->ModelName) + 1,
                            &TmpBuf[0]);

    return ret;
}

static void calDisconnectCount(uint8_t *pValue, uint8_t maxCount)
{
    sleep(3); //wait 1 second

    if ((*pValue) >= maxCount) {
        setTcpStatus(ABNORMAL);
    } else {
        (*pValue)++;
    }
}

static int CheckNetworkStatus(void)
{
    char *ipAddr = (char *)&pSysConfig->Eth0Interface.EthIpAddress;

    //printf("Check network IP Header = %s\n", ipAddr);
    if (strstr(ipAddr, CMP_ETH_IP_HEAD) != NULL) {
        return 1;
    }

    return 0;
}

static void updateFirmwareProcess(int fd, uint8_t gunID, uint8_t totalConnCount)
{
    bool canUpdateFirmware = true;
    uint8_t plugNum = 0;
    uint8_t ackCount = 5;
    struct timeb updateTime;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);

    if (pSysWarning->Level != 2) {
        for (plugNum = 0; plugNum < totalConnCount; plugNum++) {
            if (pDcChargingInfo->SystemStatus != S_IDLE &&
                    pDcChargingInfo->SystemStatus != S_RESERVATION &&
                    pDcChargingInfo->SystemStatus != S_MAINTAIN) {
                canUpdateFirmware = false;
            }
        }
    }

    if (canUpdateFirmware) {
        ftime(&updateTime);
        if (DiffTimeb(gRegTimeUp[0][REG_SOFTWARE_UPDATE], updateTime) > LOOP_RETRY_TIME * 5) {
            readSoftwareUpdate(fd, gunID);
            ftime(&gRegTimeUp[0][REG_SOFTWARE_UPDATE]);
        }

        if (pSysInfo->FirmwareUpdate == YES) {
            while (ackCount != 0) {
                ftime(&updateTime);
                if (DiffTimeb(gRegTimeUp[0][REG_SOFTWARE_UPDATE], updateTime) > LOOP_RETRY_TIME / 2) {
                    readSoftwareUpdate(fd, gunID);
                    ftime(&gRegTimeUp[0][REG_SOFTWARE_UPDATE]);
                    if (pSysInfo->FirmwareUpdate == NO) {
                        ackCount--;
                    }
                }
                usleep(128);
            }
        }
    }
}

static void checkAuthorProcess(int fd, uint8_t plugNum)
{
    int ret = 0;
    uint8_t gunID = 0;
    struct timeb AuthNowTime;

#if defined DD360Audi
    gunID = gDoCommGblData.ConnectorID[pSysInfo->CurGunSelected];
    //gunID = gDoCommGblData.ConnectorID[plugNum];
    if (pSysConfig->AuthorisationMode) {
        gunID = ID_REGISTER;
        ShmSelectGunInfo->PricesInfo[pSysInfo->CurGunSelected].Balance = 0.0;
    }
#else
    gunID = ID_REGISTER;

    ShmSelectGunInfo->PricesInfo[pSysInfo->CurGunSelected].Balance = 0.0; //非Audi 不需要等待主櫃回報餘額
#endif // DD360Audi

    if ((ShmOCPP16Data->SpMsg.bits.AuthorizeReq == YES) ||
            (pSysInfo->AuthorizeFlag == YES)) {
        ftime(&AuthNowTime);

        if (DiffTimeb(gRegTimeUp[plugNum][REG_USER_ID], AuthNowTime) > LOOP_RETRY_TIME) {
            ret = writeUserID(fd,
                              gunID,
                              pSysConfig->UserId);
            if (ret >= 0) {
                memset(ShmOCPP16Data->Authorize.ResponseIdTagInfo.Status,
                       0,
                       sizeof(ShmOCPP16Data->Authorize.ResponseIdTagInfo.Status));

                if (ret == 0) {
                    strcpy((char *)ShmOCPP16Data->Authorize.ResponseIdTagInfo.Status, "Invalid");
                } else {
                    strcpy((char *)ShmOCPP16Data->Authorize.ResponseIdTagInfo.Status, "Accepted");
                }

                //printf("%d Balance = %.2f, %.2f\n",
                //       plugNum,
                //       ShmSelectGunInfo->PricesInfo[plugNum].Balance,
                //       FAIL_BALANCE_PRICES);

                if (ShmSelectGunInfo->PricesInfo[plugNum].Balance != FAIL_BALANCE_PRICES) {
                    ShmOCPP16Data->SpMsg.bits.AuthorizeConf = YES; //isAuthorizedComplete
                    ShmOCPP16Data->SpMsg.bits.AuthorizeReq  = NO;
                    pSysInfo->AuthorizeFlag                 = NO;
                    ShmPsuData->SystemAvailablePower        = NO;
                    ShmPsuData->SystemPresentPsuQuantity    = NO;
                }
            }
            ftime(&gRegTimeUp[plugNum][REG_USER_ID]);
        }
    }
}

static int messageTrigger(int fd, uint8_t plugNum, uint8_t gunID, uint8_t curReg)
{
    int ret = DISPENSER_INIT_SUCC;
    int isContinue = 1;
    struct timeb NowTime;

    while (isContinue) {
        usleep(128);
        ftime(&NowTime);

        switch (curReg) {
        case REG_MODEL_NAME:
            if (WriteModelName(fd) == PASS) {
                gDoCommGblData.DisConnCount = 0;
                curReg = REG_CONNECTOR_ID;
            } else {
                sleep(1);
            }
            break;

        case REG_CONNECTOR_ID:
            if (readConnectorID(fd) == PASS) {
                gDoCommGblData.DisConnCount = 0;
                curReg = REG_REPORT_CSU_VERSION;
            } else {
                sleep(1);
            }
            break;

        case REG_POWER_CABINET_STATUS:
            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                readPowerCabinetStatus(fd, gunID);
                ftime(&gRegTimeUp[plugNum][curReg]);
            }
            curReg = REG_DISPENSER_STATUS;
            break;

        case REG_DISPENSER_STATUS:
            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                writeDispenserStatus(fd, gunID);
                ftime(&gRegTimeUp[plugNum][curReg]);
            }
            curReg = REG_CHARGING_CAP;
            break;

        case REG_CHARGING_CAP:
            if(gMoreInfoReq[plugNum].bits.FinalCostReq)
            {
                if (readChargingCapability(fd, gunID) == PASS && readChargingTimeStamp(fd, gunID) == PASS) {
					gMoreInfoReq[plugNum].bits.FinalCostReq = false;
					pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);
					//ShmDcCommonData->TransactionInfo[plugNum].Amount = pDcChargingInfo->ChargingFee;
					ShmDcCommonData->pGunInfo[plugNum].finalcost_flag = TRUE;
					log_info("Gun %d get final cost %f", plugNum, pDcChargingInfo->ChargingFee);
                }
            }
            curReg = REG_PLUG_IN_STATE;
            break;

        //case REG_CHARGING_TARGET:
        //    writeChargingTarget(fd, plugNum, gunID);
        //    break;

        //case REG_SOFTWARE_UPDATE:
        //    if (ChargingData[plugNum]->SystemStatus == S_IDLE) {
        //        if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > L OOP_RETRY_TIME||
        //DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0  * 1) {
        //            readSoftwareUpdate(fd);
        //            ftime(&gRegTimeUp[plugNum][curReg]);
        //        }
        //        while (pSysInfo->FirmwareUpdate == YES) {
        //            ftime(&NowTime);
        //            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowT ime) > LOOP_RETRY_TIME||
        //DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
        //                readSoftwareUpdate(fd);
        //            }
        //            usleep(128);
        //        }
        //    }
        //    isContinue = 0;
        //    break;

        case REG_PLUG_IN_STATE:
            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                writePlugInStatus(fd, plugNum, gunID);
                ftime(&gRegTimeUp[plugNum][curReg]);
            }
            curReg = REG_CONNECTOR_STATE;
            break;

        case REG_CONNECTOR_STATE:
            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                writeConnectorState(fd, plugNum, gunID);
                ftime(&gRegTimeUp[plugNum][curReg]);
            }
            curReg = REG_OCMF_INFO;
            break;
        case REG_OCMF_INFO:
            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                if (ShmDcCommonData->pGunInfo[plugNum].SendOcmfDataReq) {
                    if (wrtieOcmpInfo(fd,plugNum,gunID) == PASS) {
                        DB_Upload_ocmf(plugNum,ShmDcCommonData->ocmfTridRecord[plugNum]);
                        ShmDcCommonData->pGunInfo[plugNum].SendOcmfDataReq = FALSE;
                        char cmd[500];
                        sprintf(cmd,"rm -f %s",ShmDcCommonData->pGunInfo[plugNum].OcmfFileName);
                        system(cmd);
                        ShmDcCommonData->ocmfTridRecord[plugNum] = 0;
                    } else {
                        ShmDcCommonData->pGunInfo[plugNum].SendOcmfDataReq = FALSE;
                    }
                }
                ftime(&gRegTimeUp[plugNum][curReg]);
            }
            curReg = REG_DISPENSER_REQUEST;
            break;
        case REG_DISPENSER_REQUEST:
            /*
            gConnectorActReq[plugNum].bits.ChargingCancel = ShmDcCommonData->OperateIDLE[plugNum];
            if (gConnectorActReq[plugNum].Value != 0)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {

                    if (writeDispenserRequest(fd, gunID, plugNum) == PASS)
                    {
                        gConnectorActReq[plugNum].Value = 0;
                        log_info("Gun %d CHARGING_CANCEL OK", plugNum);
                        ShmDcCommonData->OperateIDLE[plugNum] = 0;
                    }
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            */
            curReg = REG_QRCODE_URL_INFO;
            break;
        case REG_QRCODE_URL_INFO:
            if (gunID == 1) {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > (LOOP_RETRY_TIME * 10) ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0
                    ) {
                    readQRcodeURLAndSystemDate(fd);
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
#ifdef DD360Audi
        curReg = REG_POWER_CONSUMPTION_INFO;
#else
        curReg = REG_READ_CABINET_SYSTEMID;
#endif
            break;
        //case REG_USER_ID:
        //    writeUserID(fd, gunID, uint8_t *pUserID);
        //    break;

        //case REG_CHARGING_PERMISSION:
        //    readChargePermission(fd, gunID);
        //    break;

        case REG_MISC_CONTROL:
            readMiscCommand(fd, gunID);

            if(gMoreInfoReq[plugNum].Value == 0)
            {
                isContinue = 0;
            }
            else
            {
                curReg = REG_RESERVATION_IDTAG;
            }
            break;

        case REG_REPORT_CSU_VERSION:
        case REG_REPORT_OTHER_VERSION:
            if (gDoCommGblData.MiscCmd != 0) {
                writeCsuModuleVersion(fd);
                writeOtherModuleVersion(fd);
                clearMiscCommand();
                isContinue = 0;
            } else {
                //power up write dispenser version and get power cabinet system ID
                if ((writeCsuModuleVersion(fd) == PASS) &&
                        (writeOtherModuleVersion(fd) == PASS) &&
                        (readQRcodeURLAndSystemDate(fd) == PASS)
                   ) {
                    //gDoCommGblData.DisConnCount = 0;
                    isContinue = 0;
                }
            }
            break;

        case REG_READ_CABINET_SYSTEMID:
            if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > (LOOP_RETRY_TIME * 10) ||
                DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                readSystemID(fd);
                ftime(&gRegTimeUp[plugNum][curReg]);
            }
            curReg = REG_RESERVATION_IDTAG;
            /*
            //check misc command from power cabinet
            if (gDoCommGblData.MiscCmd != 0) {
                if (gDoCommGblData.MiscCmd != REG_MISC_CONTROL) {
                    log_error("misc command failed = %x", gDoCommGblData.MiscCmd);
                }
                curReg = gDoCommGblData.MiscCmd;
            } else if (gMoreInfoReq[plugNum].Value != 0) {
                curReg = REG_RESERVATION_IDTAG;
            } else {
                isContinue = 0;
            }
            */
            break;
        case REG_RESERVATION_IDTAG:
            if (gMoreInfoReq[plugNum].bits.ReservationReq)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                    if (readReservationState(fd, gunID) == PASS)
                    {
                        gMoreInfoReq[plugNum].bits.ReservationReq = ReservationState[plugNum] == NO ? NO : YES;
                    }
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            curReg = REG_POWER_CONSUMPTION_INFO;
            break;
        case REG_POWER_CONSUMPTION_INFO:
            if (pSysConfig->ShowInformation || ShmDcCommonData->debugflag) {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                    readConsumptionInfo(fd);
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            //check misc command from power cabinet
            if (gDoCommGblData.MiscCmd != 0) {
                if (gDoCommGblData.MiscCmd != REG_MISC_CONTROL) {
                    log_error("misc command failed = %x", gDoCommGblData.MiscCmd);
                }
                curReg = gDoCommGblData.MiscCmd;
            } else if (gMoreInfoReq[plugNum].Value != 0) {
                curReg = REG_REMOTE_START_NO_ID;
            } else {
                isContinue = 0;
            }
            break;
            

        case REG_REMOTE_START_NO_ID:
            if (gMoreInfoReq[plugNum].bits.RemoteStartNoID)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                    if (readRemoteStartNoIDState(fd) == PASS)
                    {
                        gMoreInfoReq[plugNum].bits.RemoteStartNoID = RemoteStartNoIDState == NO ? NO : YES;
                    }
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            curReg = REG_STATION_INFO;
            break;
        case REG_STATION_INFO:
            if (gMoreInfoReq[plugNum].bits.StationInfoReq)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {

                    if (readChargerStationInfo(fd) == PASS)
                    {
                        gMoreInfoReq[plugNum].bits.StationInfoReq = NO;
                    }
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            //isContinue = 0;
            curReg = REG_READ_DEFAULT_PRICE;
            break;

        case REG_READ_DEFAULT_PRICE:
            if (gMoreInfoReq[plugNum].bits.DefaultPriceReq)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                    readDefaultPrice(fd);
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            curReg = REG_READ_USER_PRICE;
            break;
        case REG_READ_USER_PRICE:
            if (gMoreInfoReq[plugNum].bits.UserPriceReq)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                    readUserPrice(fd,gunID);
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            curReg = REG_RECEIPT_INFO;
            break;
        case REG_RECEIPT_INFO:
            if (gMoreInfoReq[plugNum].bits.ReceiptReq)
            {
                if (DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) > LOOP_RETRY_TIME ||
                    DiffTimeb(gRegTimeUp[plugNum][curReg], NowTime) < 0) {
                    readReceiptInfo(fd, gunID);
                    ftime(&gRegTimeUp[plugNum][curReg]);
                }
            }
            curReg = REG_REFUND_AMOUNT;
            break;
        case REG_REFUND_AMOUNT:
            curReg = REG_PREPAYMENT_INFO;
            break;

        case REG_PREPAYMENT_INFO:
            curReg = REG_PAYMENT_FAIL_REASON;
            break;

        case REG_PAYMENT_FAIL_REASON:
            curReg = REG_CONNECTOR_QR_CODE;
            break;

        case REG_CONNECTOR_QR_CODE:
            isContinue = 0;
            break;


        default:
            log_error("error curReg = %x", curReg);
            gDoCommGblData.MiscCmd = 0;
            gDoCommGblData.DisConnCount = CHECK_NETWORK_FAIL_COUNT;
            isContinue = 0;
            break;
        }

        if (gDoCommGblData.DisConnCount >= CHECK_NETWORK_FAIL_COUNT) {
            return DISPENSER_SOCKET_RECONN;
        }
    }//for

    return ret;
}

//static bool isDetectPlugin()
//{
//    if (pSysInfo->WaitForPlugit == YES) {
//        return YES;
//    }
//
//    return NO;
//}

static void systemStatusProcess(int fd, uint8_t totalGun, uint8_t plugNum, uint8_t gunID)
{
    uint8_t i = 0;
    int j;
    struct timeb AuthNowTime = {0};
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(plugNum);
\
    struct timeb SeqEndTime;
    struct tm* tm;

    switch (pDcChargingInfo->SystemStatus) {
    case S_IDLE:
    case S_RESERVATION:
    case S_MAINTAIN:
    case S_ALARM:
    case S_AUTHORIZING:
        
        if(pDcChargingInfo->SystemStatus == S_ALARM) {
            ftime(&AuthNowTime);
            if (DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) < 0
                ) {
                writePresentChargingInfo(fd, plugNum, gunID);
                ftime(&gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO]);
            }
        }

        checkAuthorProcess(fd, plugNum);

        //authorization complete, write wait plug it state
        if (ShmSelectGunInfo->PricesInfo[plugNum].Balance == FAIL_BALANCE_PRICES) {
            break;
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_WAIT_PLUG_IT_STATE], AuthNowTime) > (LOOP_RETRY_TIME / 10) ||
                DiffTimeb(gRegTimeUp[plugNum][REG_WAIT_PLUG_IT_STATE], AuthNowTime) < 0
           ) {
            writeWaitPlugItState(fd, gunID, plugNum);
            ftime(&gRegTimeUp[plugNum][REG_WAIT_PLUG_IT_STATE]);
        }
        /*
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_MISC_CONTROL], AuthNowTime) > (LOOP_RETRY_TIME / 10) ||
                DiffTimeb(gRegTimeUp[plugNum][REG_MISC_CONTROL], AuthNowTime) < 0
           ) {
            readMiscCommand(fd, gunID);
            ftime(&gRegTimeUp[plugNum][REG_MISC_CONTROL]);
        }
        */
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) < 0
           ) {
            readChargingCapability(fd, gunID);
			if (pDcChargingInfo->PantographFlag)
				writeGroundFaultDetection(fd, 0, gunID);
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_CAP]);
        }

        break;

    case S_PREPARNING: //get permission
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CONNECTOR_STATE], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CONNECTOR_STATE], AuthNowTime) < 0
           ) {
            writeConnectorState(fd, plugNum, gunID);
            ftime(&gRegTimeUp[plugNum][REG_CONNECTOR_STATE]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) < 0
           ) {
            if (readChargePermission(fd, gunID) && readChargingCapability(fd, gunID)) {
                for (i = 0; i < totalGun; i++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

                    ShmPsuData->SystemAvailablePower += pDcChargingInfo->AvailableChargingPower;
                }
                ShmPsuData->SystemPresentPsuQuantity = (ShmPsuData->SystemAvailablePower / 30);
            }
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_PERMISSION]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) < 0
           ) {
            writePresentChargingInfo(fd, plugNum, gunID);
			if (pDcChargingInfo->PantographFlag)
				writeGroundFaultDetection(fd, 0, gunID);
            ftime(&gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO]);
        }
        break;

    case S_PREPARING_FOR_EV://wait connector lock
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) < 0
           ) {
            readChargingCapability(fd, gunID);
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_CAP]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) < 0
           ) {
            if (readChargePermission(fd, gunID) == 0) {
                log_info("S_PREPARING_FOR_EV Stop charging by power cabinet's permission = %d, %d",
                         plugNum,
                         REG_CHARGING_PERMISSION);
                pDcChargingInfo->StopChargeFlag = POWER_CABINET_STOP_CHARGING;
            }
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_PERMISSION]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) < 0
           ) {
            writePresentChargingInfo(fd, plugNum, gunID);
			if (pDcChargingInfo->PantographFlag)
				writeGroundFaultDetection(fd, 0, gunID);
            ftime(&gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO]);
        }
        break;

    case S_PREPARING_FOR_EVSE: //insaulation test
    case S_CCS_PRECHARGE_ST0:
    case S_CCS_PRECHARGE_ST1:

        writeChargingTarget(fd, plugNum, gunID);

		if (pDcChargingInfo->PantographFlag)
			writeGroundFaultDetection(fd, 1, gunID);

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) < 0
           ) {
            readChargingCapability(fd, gunID);
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_CAP]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) < 0
           ) {
            if (readChargePermission(fd, gunID) == 0) {
                log_info("S_PREPARING_FOR_EVSE Stop charging by power cabinet's permission = %d, %d",
                         plugNum,
                         REG_CHARGING_PERMISSION);
                pDcChargingInfo->StopChargeFlag = POWER_CABINET_STOP_CHARGING;
            }
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_PERMISSION]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) < 0
           ) {
            writePresentChargingInfo(fd, plugNum, gunID);
            ftime(&gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO]);
        }
        break;

    case S_CHARGING: //charging
    case S_TERMINATING:
        if(pDcChargingInfo->Type == _Type_GB || pDcChargingInfo->Type == _Type_Chademo)
        {
			if (pDcChargingInfo->PantographFlag)
				writeGroundFaultDetection(fd, 0, gunID);
        }
        else
        {
			if (pDcChargingInfo->PantographFlag)
				writeGroundFaultDetection(fd, 1, gunID);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) < 0
           ) {
            readChargingCapability(fd, gunID);
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_CAP]);
        }

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_PERMISSION], AuthNowTime) < 0
           ) {
            if (readChargePermission(fd, gunID) == 0) {
                if (pDcChargingInfo->StopChargeFlag != POWER_CABINET_STOP_CHARGING) {
                    log_info("Stop charging by power cabinet's permission = %d, %d",
                        plugNum,
                        REG_CHARGING_PERMISSION);
                    pDcChargingInfo->StopChargeFlag = POWER_CABINET_STOP_CHARGING;
                }
                //printf("%d StopChargeFlag = %d\n", plugNum, pDcChargingInfo->StopChargeFlag);
            }
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_PERMISSION]);
        }
        writeChargingTarget(fd, plugNum, gunID);

        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) < 0
           ) {
            writePresentChargingInfo(fd, plugNum, gunID);
            ftime(&gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO]);
        }

        // 獲得Charging時間
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_READ_CHARGING_TIMESTAMP], AuthNowTime) > (LOOP_RETRY_TIME*5) ||
            DiffTimeb(gRegTimeUp[plugNum][REG_READ_CHARGING_TIMESTAMP], AuthNowTime) < 0
            ) {
            readChargingTimeStamp(fd, gunID);
            ftime(&gRegTimeUp[plugNum][REG_READ_CHARGING_TIMESTAMP]);
        }
        break;
    case S_COMPLETE:
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) > LOOP_RETRY_TIME ||
                DiffTimeb(gRegTimeUp[plugNum][REG_CHARGING_CAP], AuthNowTime) < 0
           ) {
            readChargingCapability(fd, gunID);
			if (pDcChargingInfo->PantographFlag)
				writeGroundFaultDetection(fd, 0, gunID);
            ftime(&gRegTimeUp[plugNum][REG_CHARGING_CAP]);
        }
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) > LOOP_RETRY_TIME ||
            DiffTimeb(gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO], AuthNowTime) < 0
            ) {
            writePresentChargingInfo(fd, plugNum, gunID);
            ftime(&gRegTimeUp[plugNum][REG_PRESENT_CHARGING_INFO]);
        }
        // 獲得Charging時間
        /*
        ftime(&AuthNowTime);
        if (DiffTimeb(gRegTimeUp[plugNum][REG_READ_CHARGING_TIMESTAMP], AuthNowTime) > (LOOP_RETRY_TIME / 10) ||
            DiffTimeb(gRegTimeUp[plugNum][REG_READ_CHARGING_TIMESTAMP], AuthNowTime) < 0
            ) {
            readChargingTimeStamp(fd, gunID);
            ftime(&gRegTimeUp[plugNum][REG_READ_CHARGING_TIMESTAMP]);
        }
        */
        break;

    default:
        break;
    }
}

static int networkCreatePorcess(void)
{
    int fd = 0;
    uint8_t discount = 0;
    while (pSysInfo->SelfTestSeq != _STEST_COMPLETE) {
        usleep(128);
    }

    setTcpStatus(ABNORMAL);

    /**************** Check Network **********/
    //log_info("Check Dispenser Network Information");
    while (pSysInfo->SelfTestSeq != _STEST_COMPLETE) {
        usleep(125);
    }

    while (!CheckNetworkStatus()) {
        calDisconnectCount(&gDoCommGblData.DisConnCount, CHECK_NETWORK_FAIL_COUNT);
        if( gDoCommGblData.DisConnCount != discount ) {
            discount =  gDoCommGblData.DisConnCount;
            log_error("disconnect count = % d", gDoCommGblData.DisConnCount);
        }
    }
    log_info("Dispenser Network Information checked: IP = % s Netmask = % s, Gateway = % s",
             pSysConfig->Eth0Interface.EthIpAddress,
             pSysConfig->Eth0Interface.EthSubmaskAddress,
             pSysConfig->Eth0Interface.EthGatewayAddress);

    gDoCommGblData.DisConnCount = 0;
    discount = 0;

    /**************** Power cabinet connection **********/
    log_info("Connect to Power Cabinet");
    while ((fd = doCommConnToServer()) <= 0) {
        calDisconnectCount(&gDoCommGblData.DisConnCount, CONNECT_SERVER_FAIL_COUNT);
        if( gDoCommGblData.DisConnCount != discount && fd == -1) {
            discount = gDoCommGblData.DisConnCount;
            log_error("disconnect count = %d, fd = %d", gDoCommGblData.DisConnCount, fd);
        }
    }
    log_info("Power cabinet connected(fd = % d): IP = % s Netmask = % s, Gateway = % s",
             fd,
             pSysConfig->Eth0Interface.EthIpAddress,
             pSysConfig->Eth0Interface.EthSubmaskAddress,
             pSysConfig->Eth0Interface.EthGatewayAddress);

    gDoCommGblData.DisConnCount = 0;
    destroySelectGun(DESTROY_ALL_SEL);

    sleep(3);

    setTcpStatus(NORMAL);

    return fd;
}

int main(int argc, char *argv[])
{
    uint8_t plugNum = 0, gunID = 0;
    uint8_t index = 0;
    uint8_t totalConnCount = 0;
    uint8_t initDone = DISPENER_INIT_FAIL;
    char tmpbuf[256] = {0};
    int fd = 0;
    int isContinue = 1;

    InitSocketSigPipe();

    /**************** Initialization **********/
    if (CreateAllCsuShareMemory() == FAIL) {
        log_error("create share memory error");
        return FAIL;
    }

    MappingGunChargingInfo("DoComm Task");

    pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
    pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
    pSysWarning = (struct WARNING_CODE_INFO *)GetShmSysWarningInfo();

    pAlarmCode = (struct AlarmCodeData *)GetShmAlarmCodeData();
    ShmPsuData = (struct PsuData *)GetShmPsuData();
    ShmPrimaryMcuData = (struct PrimaryMcuData *)GetShmPrimaryMcuData();
    ShmOCPP16Data = (struct OCPP16Data *)GetShmOCPP16Data();
    ShmSelectGunInfo = (SelectGunInfo *)GetShmSelectGunInfo();
    ShmDcCommonData = (DcCommonInfo *)GetShmDcCommonData();

    totalConnCount = pSysConfig->TotalConnectorCount;

    for (index = 0; index < totalConnCount; index++) {
        clearPricesInfo(index);
    }

    //initial trigger message timer
    for (index = 0; index < MAX_REGISTER_NUM; index++) {
        ftime(&gRegTimeUp[0][index]);
        usleep(128);
        ftime(&gRegTimeUp[1][index]);
        usleep(50000);
    }

    setTcpStatus(NORMAL);

    while (isContinue) {
        if (initDone == DISPENER_INIT_FAIL) {
            fd = networkCreatePorcess();

            initDone = messageTrigger(fd, 0, 0, REG_MODEL_NAME); //first trigger model name and connector id
        } else {
            plugNum = 0;
            gunID = 0;
            for (plugNum = 0; plugNum < totalConnCount; plugNum++) {
                //checkAuthorProcess(fd, plugNum);

                //plugNum : setup chargingData value for bottom layer
                //gunID : connector Id from power cabinet, 1 = left gun, 2 = right gun,
                gunID = gDoCommGblData.ConnectorID[plugNum];
                systemStatusProcess(fd, totalConnCount, plugNum, gunID);

                initDone = messageTrigger(fd,
                                          plugNum,
                                          gunID,
                                          REG_POWER_CABINET_STATUS);

                if (initDone == DISPENSER_SOCKET_RECONN) {
                    break;
                }
            }
        }

        if (initDone != DISPENSER_SOCKET_RECONN) {
            //update dispenser firmware
            updateFirmwareProcess(fd, gDoCommGblData.ConnectorID[0], totalConnCount);

            usleep(100000);
            continue;
        }

        //Ethernet error recovery handle
        log_info("Disconnected from power cabinet...re-connecting");
        setTcpStatus(ABNORMAL);


        if (pSysConfig->Eth0Interface.EthDhcpClient == 0) {
            system("pgrep -f \"udhcpc -i eth0\" | xargs kill");
            sprintf(tmpbuf,
                    "/sbin/udhcpc -i eth0 -x hostname:CSU3_%s -s /root/dhcp_script/eth0.script > /dev/null &",
                    pSysConfig->SystemId);
            system(tmpbuf);
        }

        gDoCommGblData.DisConnCount = 0;
        gDoCommGblData.SeqNum = 0;

        closeSocket(fd);
        fd = 0;

        initDone = DISPENER_INIT_FAIL;
    }
}