#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <linux/wireless.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>      /*標準輸入輸出定義*/
#include <stdlib.h>     /*標準函數庫定義*/
#include <unistd.h>     /*Unix 標準函數定義*/
#include <fcntl.h>      /*檔控制定義*/
#include <termios.h>    /*PPSIX 終端控制定義*/
#include <errno.h>      /*錯誤號定義*/
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <ctype.h>
#include <ifaddrs.h>
#include <math.h>
#include <stdbool.h>
#include <dirent.h>
#include <signal.h>

#include "../Config.h"
#include "main.h"
#include "../common.h"
#include "../timeout.h"

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


//------------------------------------------------------------------------------
static struct SysInfoData *pSysInfo = NULL;
static struct SysConfigData *pSysConfig = NULL;
static struct WARNING_CODE_INFO *pSysWarning = NULL;

static struct AlarmCodeData *pAlarmCode = NULL;
static struct FaultCodeData *pFaultCode = NULL;
static struct InfoCodeData  *pInfoCode = NULL;

static struct PsuData *ShmPsuData = NULL;
static struct CHAdeMOData *ShmCHAdeMOData = NULL;
static struct GBTData *ShmGBTData = NULL;
static struct CcsData *ShmCcsData = NULL;
static struct PrimaryMcuData *ShmPrimaryMcuData = NULL;
static struct FanModuleData *ShmFanModuleData = NULL;
static struct RelayModuleData *ShmRelayModuleData = NULL;
static struct LedModuleData *ShmLedModuleData = NULL;
static struct OCPP16Data *ShmOCPP16Data = NULL;
static struct OCPP20Data* ShmOCPP20Data = NULL;
static DcCommonInfo *ShmDcCommonData = NULL;

static struct ChargingInfoData *pDcChargingInfo = NULL;
static struct ChargingInfoData *pAcChargingInfo = NULL;

static struct timeb startChargingTime[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];
static struct timeb endChargingTime[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];

static SelectGunInfo *ShmSelectGunInfo = NULL;
static EvBoardErrMsg gEvBoardErr = {0};
static ChillerTempErr gChillerTempErr = {0};

struct SysConfigAndInfo         *ShmSysConfigAndInfo;
struct StatusCodeData           *ShmStatusCodeData;

#define DERATING_TARGET_LEVEL 5

// for initial index to check EV board type is correct
uint8_t bd0_1_status = 0;
uint8_t bd0_2_status = 0;
uint8_t bd1_1_status = 0;
uint8_t bd1_2_status = 0;

char *fwVersion = "V2.00.00.0000.00";
char* DebugVersion = "V2.00.12";
//sqlite3 *localDb;
bool isDb_ready;

//------------------------------------------------------------------------------
void ClearDetectPluginFlag(int gunIndex);

long long DiffTimebWithNow(struct timeb ST);
uint8_t DetectBitValue(uint8_t _byte, uint8_t _bit);
void SetBitValue(uint8_t *_byte, uint8_t _bit, uint8_t value);
unsigned long GetTimeoutValue(struct timeval _sour_time);
void gpio_set_value(unsigned int gpio, unsigned int value);
void InformOcppErrOccur(uint8_t codeType);

void RecordAlarmCode(uint8_t gunIndex, char *code);
void ReleaseAlarmCode(uint8_t gunIndex);
void ResetChargerAlarmCode(uint8_t gunIndex, char *code);
void AdjustChargerCurrent(void);
void UpdateErrorCodeToOcpp(uint8_t index);

//------------------------------------------------------------------------------
//Primary.c
extern void PrimaryLedIndicatorCtrlFork(void);
extern void ChkPrimaryStatus(void);

//RFID.c
extern void CreateRfidFork(void);
extern void ScannerCardProcess(void);
extern bool GetIsCardScan(void);
extern void SetIsCardScan(bool value);

//SelfTest.c
extern void SelfTestRun(void);

//UpgradeFW.c
/*extern void CheckFwUpdateFunction(void);*/

//Ethernet.c
extern void InitEthernet(void);
extern void GetMacAddress(void);

//WatchDog.c
extern void CreateWatchdog(void);
extern void TryCloseWatchdog(void);
extern void TryFeedWatchdog(void);

//ZipFile.c
extern void zipLogFiles(void);

//------------------------------------------------------------------------------
//--- share memory value ---
//------------------------------------------------------------------------------
static void changeLcmPage(uint8_t index)
{
    pSysInfo->SystemPage = index;
}

static uint8_t getCurLcmPage(void)
{
    return pSysInfo->SystemPage;
}

static void systemPageRestoreInit(void)
{
    if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
        pSysInfo->SystemPage = _LCM_NONE;

        return;
    }

    pSysInfo->SystemPage = _LCM_NONE;
}

static void connectorPageRestoreIdle(void)
{
    if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
        pSysInfo->ConnectorPage = _LCM_NONE;
        return;
    }

    pSysInfo->ConnectorPage = _LCM_IDLE;
}

//------------------------------------------------------------------------------
void destroySelGun(uint8_t curGun)
{
    uint8_t i = 0;
    uint8_t totalGun = pSysConfig->TotalConnectorCount;

    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        return;
    }

    //for status timeout
    if (curGun == DESTROY_ALL_SEL) {
        ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_RELEASE;
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_RELEASE;
        log_info("destroy all gun = %d, %d",
                 ShmSelectGunInfo->SelGunInfo.LeftGun,
                 ShmSelectGunInfo->SelGunInfo.RightGun);
        for (i = 0; i < totalGun; i++) {
            StopGunInfoTimeoutDet(i);
            memset(&ShmSelectGunInfo->PricesInfo[i], 0, sizeof(PricesInfo));
        }
        pSysInfo->CurGunSelected = 0;
        strcpy((char *)pSysConfig->UserId, "");
        //changeLcmPage(_LCM_SELECT_GUN);
        return;
    }

    //for charging timeout or complete
    if ((curGun == LEFT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.LeftGun != SEL_GUN_RELEASE)) {
        if (ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_CONFIRM ||
                ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_ATHOR) {
#ifdef DD360Audi
            changeLcmPage(_LCM_SELECT_GUN);
#endif
        }
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_RELEASE;
        StopGunInfoTimeoutDet(LEFT_GUN_NUM);
        if (ShmOCPP16Data->SpMsg.bits.AuthorizeConf != NO) {
            ClearAuthorizedFlag();
        }

        log_info("destroy left gun, cur page = %d", getCurLcmPage());
        if (getCurLcmPage() == pSysInfo->SystemPage) {
            log_info("clear left balance");
            memset(&ShmSelectGunInfo->PricesInfo[curGun], 0, sizeof(PricesInfo));
            ShmSelectGunInfo->PricesInfo[curGun].Balance = FAIL_BALANCE_PRICES;
        }
    }

    if ((curGun == RIGHT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.RightGun != SEL_GUN_RELEASE)) {
        if (ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_CONFIRM ||
                ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_ATHOR) {
#ifdef DD360Audi
            changeLcmPage(_LCM_SELECT_GUN);
#endif
        }
        ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_RELEASE;
        StopGunInfoTimeoutDet(RIGHT_GUN_NUM);
        if (ShmOCPP16Data->SpMsg.bits.AuthorizeConf != NO) {
            ClearAuthorizedFlag();
        }

        log_info("destroy right gun, cur page = %d", getCurLcmPage());
        if (getCurLcmPage() == pSysInfo->SystemPage) {
            log_info("clear right balance");
            memset(&ShmSelectGunInfo->PricesInfo[curGun], 0, sizeof(PricesInfo));
            ShmSelectGunInfo->PricesInfo[curGun].Balance = FAIL_BALANCE_PRICES;
        }
    }

}

static int waitRightGunPlugIt(uint8_t curGun)
{
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        return PASS;
    }

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

    return FAIL;
}

static int waitLeftGunPlugIt(uint8_t curGun)
{
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        return PASS;
    }
    if ((curGun == LEFT_GUN_NUM) && (ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_ATHOR)) {
        return PASS;
    }

    return FAIL;
}

void setSelGunWaitToAuthor(uint8_t curSel)
{
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        return;
    }
    if (curSel == LEFT_GUN_NUM && ShmSelectGunInfo->SelGunInfo.LeftGun == SEL_GUN_CONFIRM) {
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_ATHOR;
        //printf("setSelGunWaitToAuthor left");
        StopGunInfoTimeoutDet(curSel);
    } else if (curSel == RIGHT_GUN_NUM && ShmSelectGunInfo->SelGunInfo.RightGun == SEL_GUN_CONFIRM) {
        ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_ATHOR;
        //printf("setSelGunWaitToAuthor right");
        StopGunInfoTimeoutDet(curSel);
    }
}

int getConfirmSelectedGun(uint8_t curSel)
{
    if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
        return PASS;
    }

    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;
}

void confirmSelGun(uint8_t selGun)
{
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        return;
    }

    if (selGun == LEFT_GUN_NUM) {
        ShmSelectGunInfo->SelGunInfo.LeftGun = SEL_GUN_CONFIRM;
        StopGunInfoTimeoutDet(selGun);
        //printf("confirmSelGun left");
    } else if (selGun == RIGHT_GUN_NUM) {
        ShmSelectGunInfo->SelGunInfo.RightGun = SEL_GUN_CONFIRM;
        StopGunInfoTimeoutDet(selGun);
        //printf("confirmSelGun right");
    }
    // AUDI_LCM_CHANGE
    changeLcmPage(_LCM_IDLE);

    StartGunInfoTimeoutDet(selGun, Timeout_SelectGun);
}

static void GetFirmwareVersion(void)
{
    // Get CSU root file system version
    sprintf((char *)pSysInfo->CsuRootFsFwRev, fwVersion);
    sprintf((char *)ShmDcCommonData->DebugVersion, DebugVersion);

    uint8_t count = 0, chademo = 0, ccs = 0, gb = 0;
    for (uint8_t idx = 0; idx < 3; idx++) {
        if (pSysConfig->ModelName[7 + idx] == 'J' ||
            pSysConfig->ModelName[7 + idx] == 'K' ||
            pSysConfig->ModelName[7 + idx] == 'O' ||
            pSysConfig->ModelName[7 + idx] == 'S' ||
            pSysConfig->ModelName[7 + idx] == 'L') {
            chademo++;
            count++;
        } else if (pSysConfig->ModelName[7 + idx] == 'G' ||
                   pSysConfig->ModelName[7 + idx] == 'B' ||
                   pSysConfig->ModelName[7 + idx] == 'A' ||
                   pSysConfig->ModelName[7 + idx] == 'H') {
            gb++;
            count++;
        } else if (pSysConfig->ModelName[7 + idx] == 'U' ||
                   pSysConfig->ModelName[7 + idx] == 'V' ||
                   pSysConfig->ModelName[7 + idx] == 'F' ||
                   pSysConfig->ModelName[7 + idx] == 'E' ||
                   pSysConfig->ModelName[7 + idx] == 'T' ||
                   pSysConfig->ModelName[7 + idx] == 'D' ||
                   pSysConfig->ModelName[7 + idx] == 'Y' ||
                   pSysConfig->ModelName[7 + idx] == 'Z' ||
                   pSysConfig->ModelName[7 + idx] == 'I' ||
                   pSysConfig->ModelName[7 + idx] == 'Q') {
            ccs++;
            count++;
        }
    }

    if (count == 1) {
        if (chademo > 0) {
            pSysInfo->CsuRootFsFwRev[7] = '1';
        } else if (ccs > 0) {
            pSysInfo->CsuRootFsFwRev[7] = '2';
        } else if (gb > 0) {
            pSysInfo->CsuRootFsFwRev[7] = '3';
        }
    } else {
        if (chademo > 0 && ccs > 0) {
            pSysInfo->CsuRootFsFwRev[7] = '4';
        } else if (chademo > 0 && gb > 0) {
            pSysInfo->CsuRootFsFwRev[7] = '5';
        } else if (ccs > 0 && gb > 0) {
            pSysInfo->CsuRootFsFwRev[7] = '6';
        }
    }

    // Get network option from model name
    switch (pSysConfig->ModelName[10]) {
    case 'B':
    case 'U':
        //Blue tooth
        pSysInfo->CsuRootFsFwRev[9] = '3';
        break;
    case 'W':
        // WIFI
        pSysInfo->CsuRootFsFwRev[9] = '1';
        break;
    case 'T':
        // 3G/4G
        pSysInfo->CsuRootFsFwRev[9] = '2';
        break;
    case 'D': //DS60-120 add
        pSysInfo->CsuRootFsFwRev[9] = '5';
        break;
    default:
        // LAN
        pSysInfo->CsuRootFsFwRev[9] = '0';
        break;
    }
    // Get rating power from model name
    memcpy(&pSysInfo->CsuRootFsFwRev[10], &pSysConfig->ModelName[4], 0x03);

    // Get IEC or UL
    char _buf[3] = {0};
    memcpy(_buf, &pSysConfig->ModelName[2], 2);

    if (strcmp(_buf, "YE") == EQUAL || strcmp(_buf, "YC") == EQUAL) {
        pSysInfo->ChargerType = _CHARGER_TYPE_IEC;
        log_info("IEC model");
    } else if (strcmp(_buf, "WU") == EQUAL) {
        pSysInfo->ChargerType = _CHARGER_TYPE_UL;
        log_info("UL model");
    }
}
bool isCharging(uint8_t status)
{
    if ((status >= S_REASSIGN_CHECK && status <= S_CHARGING) ||
        status == S_CCS_PRECHARGE_ST0 || status == S_CCS_PRECHARGE_ST1 ) {
            return TRUE;
    }
    return FALSE;
}
static void checkGunOTPState(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    //log_info("OTP:%d OTPR%d",pSysInfo->OTPTemp,pSysInfo->OTPTempR);
    //水冷機溫度檢測
    if (((ShmDcCommonData->ChillerValve.MultiChillerGun & 0x80) >> 7) == YES) {
        if ((ShmDcCommonData->ChillerValve.MultiChillerGun & 0x7F) == 1) {
            // 單水冷機
            // Chiller OTP
            if (pDcChargingInfo->ChillerTemp == UNDEFINED_TEMP) {
                // 溫度為255時判斷Sensor fail
                ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = NO;
                ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = YES;
            } else {
                //判斷OTP
                if ((ShmDcCommonData->SystemTemp[0] >= pSysInfo->OTPTemp && ShmDcCommonData->SystemTemp[0] != UNDEFINED_TEMP) ||
                    (ShmDcCommonData->SystemTemp[1] >= pSysInfo->OTPTemp && ShmDcCommonData->SystemTemp[1] != UNDEFINED_TEMP)) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = YES;
                    RecordAlarmCode(gunIndex, "012323");
                } else if (ShmDcCommonData->SystemTemp[0] != 0 && ShmDcCommonData->SystemTemp[0] < pSysInfo->OTPTempR &&
                    ShmDcCommonData->SystemTemp[1] != 0 && ShmDcCommonData->SystemTemp[1] < pSysInfo->OTPTempR) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = NO;
                }
                //判斷Tube OTP
                if ((ShmDcCommonData->SystemTemp[2] >= pSysInfo->OTPTemp && ShmDcCommonData->SystemTemp[2] != UNDEFINED_TEMP)||
                     (ShmDcCommonData->SystemTemp[3] >= pSysInfo->OTPTemp && ShmDcCommonData->SystemTemp[3] != UNDEFINED_TEMP)) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTubeOTP = YES;
                    RecordAlarmCode(gunIndex, "012332");
                } else if (ShmDcCommonData->SystemTemp[2] != 0 && ShmDcCommonData->SystemTemp[2] < pSysInfo->OTPTempR &&
                    ShmDcCommonData->SystemTemp[3] != 0 && ShmDcCommonData->SystemTemp[3] < pSysInfo->OTPTempR) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTubeOTP = NO;
                }
                ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = NO;
            }

        } else {
            // 雙水冷機
            if (pDcChargingInfo->ChillerTemp == UNDEFINED_TEMP) {
                // 溫度為255時判斷Sensor fail
                ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = NO;
                ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = YES;
            } else {
                //判斷OTP
                if (ShmDcCommonData->SystemTemp[gunIndex*2] >= pSysInfo->OTPTemp && ShmDcCommonData->SystemTemp[gunIndex*2] != UNDEFINED_TEMP) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = YES;
                    RecordAlarmCode(gunIndex, "012323");
                } else if (ShmDcCommonData->SystemTemp[gunIndex*2] != 0 && ShmDcCommonData->SystemTemp[gunIndex*2] < pSysInfo->OTPTempR) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = NO;
                }
                if (ShmDcCommonData->SystemTemp[gunIndex*2+1] >= pSysInfo->OTPTemp && ShmDcCommonData->SystemTemp[gunIndex*2+1] != UNDEFINED_TEMP) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTubeOTP = YES;
                    RecordAlarmCode(gunIndex, "012332");
                } else if (ShmDcCommonData->SystemTemp[gunIndex*2+1] != 0 && ShmDcCommonData->SystemTemp[gunIndex*2+1] < pSysInfo->OTPTempR) {
                    ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTubeOTP = NO;
                }
                ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = NO;
            }
        }

        if (pFaultCode->FaultEvents.bits.CcsLiquidChillerWaterLevelFault == YES) {
            RecordAlarmCode(gunIndex, "011037");
        }
    }

    switch (pDcChargingInfo->Type) {
    case _Type_Chademo:
        if (pDcChargingInfo->ConnectorTemp != UNDEFINED_TEMP) {
            if (pDcChargingInfo->ConnectorTemp >= pSysInfo->OTPTemp) {
                RecordAlarmCode(gunIndex, "012229");
                ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = YES;
            } else if (pDcChargingInfo->ConnectorTemp != 0 &&
                       pDcChargingInfo->ConnectorTemp < pSysInfo->OTPTempR) {
                //ResetChargerAlarmCode(gunIndex, "012229");
                ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = NO;
            }
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail = NO;
        } else {
            // 沒接上 Sensor or 異常
            //RecordAlarmCode(gunIndex, "011018");
            //ResetChargerAlarmCode(gunIndex, "012229");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail = YES;
            if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail == NO) {
                if  (((gunIndex == 0) &&
                    (strncmp((char *)&pSysConfig->ModelName[7], "J", 1) != 0)) ||
                    ((gunIndex == 1) &&
                    ((strncmp((char *)&pSysConfig->ModelName[9], "J", 1) != 0) ))) {
                        log_info("Gun%d TempSensor Fail",gunIndex);
                    }
            }
            if  ((gunIndex == 0) &&
                    (strncmp((char *)&pSysConfig->ModelName[7], "J", 1) == 0)) {
            	ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = NO;
            	ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail = NO;
            } else if ((gunIndex == 1) &&
                    ((strncmp((char *)&pSysConfig->ModelName[9], "J", 1) == 0) )) {
            	ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = NO;
            	ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail = NO;
            }
        }
        break;

    case _Type_CCS_2:
        // CCS 不管甚麼輸出都會有槍溫偵測!!~
        if (pDcChargingInfo->ConnectorTemp != UNDEFINED_TEMP) {
            //ResetChargerAlarmCode(gunIndex, "011019");

            if (pDcChargingInfo->ConnectorTemp >= pSysInfo->OTPTemp) {
                RecordAlarmCode(gunIndex, "012230");
                ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOTP = YES;
            } else if (pDcChargingInfo->ConnectorTemp != 0 &&
                       pDcChargingInfo->ConnectorTemp < pSysInfo->OTPTempR) {
                //ResetChargerAlarmCode(gunIndex, "012230");
                ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOTP = NO;
            }
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail = NO;
            //ResetChargerAlarmCode(gunIndex, "011019");
        } else {
            // 沒接上 Sensor or 異常
            //RecordAlarmCode(gunIndex, "011019");
            //ResetChargerAlarmCode(gunIndex, "012230");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOTP = NO;
            if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail == NO) {
                log_info("Gun%d TempSensor Fail",gunIndex);
            }
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail = YES;
        }
        break;

    case _Type_GB:
        if (pDcChargingInfo->ConnectorTemp != UNDEFINED_TEMP) {
            if (pDcChargingInfo->ConnectorTemp >= pSysInfo->OTPTemp) {
                RecordAlarmCode(gunIndex, "012231");
                ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOTP = YES;
            } else if (pDcChargingInfo->ConnectorTemp != 0 &&
                       pDcChargingInfo->ConnectorTemp < pSysInfo->OTPTempR) {
                //ResetChargerAlarmCode(gunIndex, "012231");
                ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOTP = NO;
            }
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail = NO;
        } else {
            // 沒接上 Sensor or 異常
            //RecordAlarmCode(gunIndex, "011020");
            //ResetChargerAlarmCode(gunIndex, "012231");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOTP = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail = YES;
            if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail == NO) {
                log_info("Gun%d TempSensor Fail",gunIndex);
            }
        }
        break;
    }
}

static void collectError(uint8_t gunIndex)
{
    gEvBoardErr.GunErrMessage |= ShmDcCommonData->ConnectErrList[gunIndex].GunErrMessage;
    gChillerTempErr.TempErrMsg |= ShmDcCommonData->ChillerTempErr[gunIndex].TempErrMsg;
}

static void checkGBTAlarmState(uint8_t gunType)
{
    // GFD Trip
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 0)) {
        pAlarmCode->AlarmEvents.bits.GbGfdTrip = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.GbGfdTrip = NO;
    }

    // UVP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 1)) {
        pAlarmCode->AlarmEvents.bits.GbtOutputUVPFail = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.GbtOutputUVPFail = NO;
    }

    // OTP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 2)) {
        pAlarmCode->AlarmEvents.bits.GbConnectorOTP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.GbConnectorOTP = NO;
    }

    // OVP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 3)) {
        pAlarmCode->AlarmEvents.bits.SystemGbOutputOVP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.SystemGbOutputOVP = NO;
    }

    // GFD Warning
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 4)) {
        pAlarmCode->AlarmEvents.bits.GbGroundfaultWarning = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.GbGroundfaultWarning = NO;
    }

    // Relay Welding
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 5)) {
        pFaultCode->FaultEvents.bits.GbOutputRelayWelding = YES;
    } else {
        pFaultCode->FaultEvents.bits.GbOutputRelayWelding = NO;
    }

    // Relay Driving
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 6)) {
        pFaultCode->FaultEvents.bits.GbOutputRelayDrivingFault = YES;
    } else {
        pFaultCode->FaultEvents.bits.GbOutputRelayDrivingFault = NO;
    }

    // Connect temp Sensor broken
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 7)) {
        pFaultCode->FaultEvents.bits.GbConnectorTempSensorBroken = YES;
    } else {
        pFaultCode->FaultEvents.bits.GbConnectorTempSensorBroken = NO;
    }
}

static void checkCCSAlarmState(uint8_t gunType)
{
    // GFD Trip
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 0)) {
        pAlarmCode->AlarmEvents.bits.CcsGfdTrip = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.CcsGfdTrip = NO;
    }

    // UVP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 1)) {
        pAlarmCode->AlarmEvents.bits.CcsOutputUVPFail = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.CcsOutputUVPFail = NO;
    }

    // OTP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 2)) {
        pAlarmCode->AlarmEvents.bits.CcsConnectorOTP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.CcsConnectorOTP = NO;
    }

    // OVP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 3)) {
        pAlarmCode->AlarmEvents.bits.SystemCcsOutputOVP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.SystemCcsOutputOVP = NO;
    }

    // GFD Warning
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 4)) {
        pAlarmCode->AlarmEvents.bits.CcsGroundfaultWarning = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.CcsGroundfaultWarning = NO;
    }

    // Relay Welding
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 5)) {
        pFaultCode->FaultEvents.bits.CcsOutputRelayWelding = YES;
    } else {
        pFaultCode->FaultEvents.bits.CcsOutputRelayWelding = NO;
    }

    // Relay Driving
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 6)) {
        pFaultCode->FaultEvents.bits.CcsOutputRelayDrivingFault = YES;
    } else {
        pFaultCode->FaultEvents.bits.CcsOutputRelayDrivingFault = NO;
    }

    // Connect temp Sensor broken
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 7)) {
        pFaultCode->FaultEvents.bits.CcsConnectorTempSensorBroken = YES;
    } else {
        pFaultCode->FaultEvents.bits.CcsConnectorTempSensorBroken = NO;
    }
}

static void checkChaDeMoAlarmState(uint8_t gunType)
{
    // GFD Trip
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 0)) {
        pAlarmCode->AlarmEvents.bits.ChademoGfdTrip = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.ChademoGfdTrip = NO;
    }

    // UVP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 1)) {
        pAlarmCode->AlarmEvents.bits.ChademoOutputUVPFail = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.ChademoOutputUVPFail = NO;
    }

    // OTP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 2)) {
        pAlarmCode->AlarmEvents.bits.ChademoConnectorOTP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.ChademoConnectorOTP = NO;
    }

    // OVP
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 3)) {
        pAlarmCode->AlarmEvents.bits.SystemChademoOutputOVP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.SystemChademoOutputOVP = NO;
    }

    // GFD Warning
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 4)) {
        pAlarmCode->AlarmEvents.bits.ChademoGroundWarning = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.ChademoGroundWarning = NO;
    }

    // Relay Welding
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 5)) {
        pFaultCode->FaultEvents.bits.ChademoOutputRelayWelding = YES;
    } else {
        pFaultCode->FaultEvents.bits.ChademoOutputRelayWelding = NO;
    }

    // Relay Driving
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 6)) {
        pFaultCode->FaultEvents.bits.ChademoOutputRelayDrivingFault = YES;
    } else {
        pFaultCode->FaultEvents.bits.ChademoOutputRelayDrivingFault = NO;
    }

    // Connect temp Sensor broken
    if (DetectBitValue(gEvBoardErr.GunErrMessage >> (8 * gunType), 7)) {
        pFaultCode->FaultEvents.bits.ChademoConnectorTempSensorBroken = YES;
    } else {
        pFaultCode->FaultEvents.bits.ChademoConnectorTempSensorBroken = NO;
    }
}

static void checkChillerAlarmState(void)
{
    if (DetectBitValue(gChillerTempErr.TempErrMsg, 0)) {
        pAlarmCode->AlarmEvents.bits.SystemChillerOTP = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.SystemChillerOTP = NO;
    }

    if (DetectBitValue(gChillerTempErr.TempErrMsg, 1)) {
        pFaultCode->FaultEvents.bits.ChillerTempSensorBroken = YES;
    } else {
        pFaultCode->FaultEvents.bits.ChillerTempSensorBroken = NO;
    }
#if 0
    //uint8_t gunIndex = 0;

    //for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP == YES) {
        pAlarmCode->AlarmEvents.bits.SystemChillerOTP = YES;
        //log_info("SystemChillerOTP = %d", pAlarmCode->AlarmEvents.bits.SystemChillerOTP);
        return ABNORMAL;
    } else {
        pAlarmCode->AlarmEvents.bits.SystemChillerOTP = NO;
    }

    if (ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail == YES) {
        pFaultCode->FaultEvents.bits.ChillerTempSensorBroken = YES;
        return ABNORMAL;
    } else {
        pFaultCode->FaultEvents.bits.ChillerTempSensorBroken = NO;
    }
    //}
    //
    return NORMAL;
#endif //0
}

static void checkEvBoardAlarmState(uint8_t gunType)
{
    switch (gunType) {
    case _Type_Chademo:
        checkChaDeMoAlarmState(gunType);
        break;

    case _Type_CCS_2:
        checkCCSAlarmState(gunType);
        break;

    case _Type_GB:
        checkGBTAlarmState(gunType);
        break;
    }
}

unsigned long GetTimeoutValue(struct timeval _sour_time)
{
    struct timeval _end_time;
    gettimeofday(&_end_time, NULL);

    return 1000000 * (_end_time.tv_sec - _sour_time.tv_sec) + _end_time.tv_usec - _sour_time.tv_usec;
}

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;
    return (StopTime - StartTime);
}

bool CheckTimeOut(struct timeb ST)
{
    struct timeb ET;
    unsigned int StartTime, StopTime;

    ftime(&ET);
    StartTime = (unsigned int) ST.time;
    StopTime = (unsigned int) ET.time;
    return (StopTime > StartTime) ? YES : NO;
}

void setChargerMode(uint8_t gunIndex, uint8_t mode)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    pDcChargingInfo->SystemStatus = mode;
    if (mode == S_FAULT) {
        UpdateErrorCodeToOcpp(gunIndex);
    }
}

long long DiffTimebWithNow(struct timeb ST)
{
    //return milli-second
    struct timeb ET;
    long long StartTime, StopTime;

    ftime(&ET);
    StartTime = (long long)ST.time;
    StopTime = (long long)ET.time;

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

//==========================================
// Log
//==========================================
void CheckFwSlotStatusLog(void)
{
    if (bd0_1_status == 0 && bd0_2_status == 1) {
        log_info("Connector 1 : Chademo");
    } else if (bd0_1_status == 1 && bd0_2_status == 0) {
        log_info("Connector 1 : CCS");
    } else if (bd0_1_status == 1 && bd0_2_status == 1) {
        log_info("Connector 1 : GB");
    }

    if (bd1_1_status == 0 && bd1_2_status == 1) {
        log_info("Connector 2 : Chademo");
    } else if (bd1_1_status == 1 && bd1_2_status == 0) {
        log_info("Connector 2 : CCS");
    } else if (bd1_1_status == 1 && bd1_2_status == 1) {
        log_info("Connector 2 : GB");
    }
}

void CheckHwSlotStatusLog(uint8_t index)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);

    if (pDcChargingInfo->Type == _Type_Chademo) {
        log_info("Hw check : Connector %d, Type : Chademo, Evboard_id = %d ",
                 index, pDcChargingInfo->Evboard_id);
    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
        log_info("Hw check : Connector %d, Type : CCS, Evboard_id = %d ",
                 index, pDcChargingInfo->Evboard_id);
    } else if (pDcChargingInfo->Type == _Type_GB) {
        log_info("Hw check : Connector %d, Type : GB, Evboard_id = %d ",
                 index, pDcChargingInfo->Evboard_id);
    }
}

//=================================
// LCM Page
//=================================
void ChangeLcmByIndex(uint8_t page_index)
{
    if (pSysWarning->Level != WARN_LV_ER ||
            page_index == _LCM_COMPLETE ||
            page_index == _LCM_FIX
       ) {
        pSysInfo->PageIndex = page_index;
    }
}

//======================================================
// Peripheral initial
//======================================================
void InitGPIO()
{
    /*****************0~3, 4 bank, bank x 32+ num*********************/
    /***************************************************************/
    /*************** GPIO 0 ***************************************/
    /***************************************************************/
    /* GPMC_AD8         =>  GPIO0_22 *//*ID BD1_1*/
    system("echo 22 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio22/direction");
    /* GPMC_AD9         =>  GPIO0_23 *//*ID BD1_2*/
    system("echo 23 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio23/direction");
    /* GPMC_AD10        =>  GPIO0_26 *//*IO BD1_1*/
    system("echo 26 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio26/direction");
    system("echo 1 > /sys/class/gpio/gpio26/value");
    /* GPMC_AD11        =>  GPIO0_27 *//*IO BD1_2*/
    system("echo 27 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio27/direction");
    /* RMII1_REF_CLK        =>  GPIO0_29 *//*USB 0 OCP detection*/
    system("echo 29 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio29/direction");
    /*XDMA_EVENT_INTR0  =>  GPIO0_19 *//*AM_RFID_RST*/
    system("echo 19 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio19/direction");
    system("echo 1 > /sys/class/gpio/gpio19/value");
    /*XDMA_EVENT_INTR1  =>  GPIO0_20 *//*AM_RFID_ICC*/
    system("echo 20 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio20/direction");
    /***************************************************************/
    /*************** GPIO 1 ***************************************/
    /***************************************************************/
    /* GPMC_AD12    =>  GPIO1_12 *//*ID BD2_1*/
    system("echo 44 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio44/direction");
    /* GPMC_AD13    =>  GPIO1_13 *//*ID BD2_2*/
    system("echo 45 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio45/direction");
    /* GPMC_AD14    =>  GPIO1_14 *//*IO BD2_1*/
    system("echo 46 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio46/direction");
    system("echo 0 > /sys/class/gpio/gpio46/value");
    /* GPMC_AD15    =>  GPIO1_15 *//*IO BD2_2*/
    system("echo 47 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio47/direction");
    /***************************************************************/
    /*************** GPIO 2 ***************************************/
    /***************************************************************/
    /*LCD_AC_BIAS_EN    =>  GPIO2_25*//*RS-485 for module DE control*/
    system("echo 89 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio89/direction");
    system("echo 1 > /sys/class/gpio/gpio89/value");
    /*LCD_HSYNC     =>  GPIO2_23*//*RS-485 for module RE control*/
    system("echo 87 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio87/direction");
    system("echo 0 > /sys/class/gpio/gpio87/value");
    /*LCD_PCLK      =>  GPIO2_24*//*CCS communication board 1 proximity*/
    system("echo 88 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio88/direction");
    /*LCD_VSYNC     =>  GPIO2_22*//*CCS communication board 2 proximity*/
    system("echo 86 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio86/direction");
    /***************************************************************/
    /*************** GPIO 3 ***************************************/
    /***************************************************************/
    /*MCASP0_FSX        =>  GPIO3_15*//*Emergency Stop button detect*/
    system("echo 111 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio111/direction");
    /*MCASP0_ACLKR  =>  GPIO3_18*//*USB1 OCP detect*/
    system("echo 114 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio114/direction");
    /*MCASP0_AHCLKR =>  GPIO3_17*//*Emergency IO for AM3352 and STM32F407*/
    system("echo 113 > /sys/class/gpio/export");
    system("echo \"in\" > /sys/class/gpio/gpio113/direction");
    /*MCASP0_ACLKX  =>  GPIO3_14*//*Ethernet PHY reset*/
    system("echo 110 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio110/direction");
    system("echo 0 > /sys/class/gpio/gpio110/value");
    /* MCASP0_FSR       =>  GPIO3_19 *//*SMR Enable control_1 for Pskill_1*/
    system("echo 115 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio115/direction");
    system("echo 0 > /sys/class/gpio/gpio115/value");
    /* MCASP0_AXR0  =>  GPIO3_16 *//*CSU board function OK indicator.*/
    system("echo 112 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio112/direction");
    system("echo 1 > /sys/class/gpio/gpio112/value");
    /* MCASP0_AXR1  =>  GPIO3_20 *//*SMR Enable control_2 for Pskill_2*/
    system("echo 116 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio116/direction");
    system("echo 0 > /sys/class/gpio/gpio116/value");
    /* (C14) EMU0.gpio3[7] */  /*CP open/short feature enable/disable, pull low for default enable*/
    system("echo 103 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio103/direction");
    system("echo 0 > /sys/class/gpio/gpio103/value");
    /* (B14) EMU1.gpio3[8] */  /*4G module reset, pull high to reset when entry kernel, after Application start, it should be pull low.*/
    system("echo 104 > /sys/class/gpio/export");
    system("echo \"out\" > /sys/class/gpio/gpio104/direction");
    system("echo 0 > /sys/class/gpio/gpio104/value");

    log_info("Initial GPIO OK");
}

int LoadSysConfigAndInfo()
{
    int fd, wrd;
    unsigned char *buf;
    unsigned int ChkSum, ChkSumOrg;

    if ((buf = malloc(MtdBlockSize)) == NULL) {

        log_error("malloc buffer NG,rebooting..");

        if (pAlarmCode != NULL) {
            pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
        }
        sleep(5);
        system("reboot -f");
        sleep(5);
        system("reboot -f");
    }
    memset(buf, 0, MtdBlockSize);

    //================================================
    // Load configuration from mtdblock10
    //================================================
    system("nanddump /dev/mtd10 -f /mnt/EvseConfig.bin");
    fd = open("/mnt/EvseConfig.bin", O_RDWR);
    if (fd < 0) {
        free(buf);

        log_error("open mtdblock10 NG,rebooting..");

        if (pAlarmCode != NULL) {
            pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
        }
        sleep(5);
        system("reboot -f");
        sleep(5);
        system("reboot -f");
    }
    wrd = read(fd, buf, MtdBlockSize);
    close(fd);
    if (wrd < MtdBlockSize) {
        free(buf);

        log_error("read SysConfigData data NG,rebooting..");

        if (pAlarmCode != NULL) {
            pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
        }
        sleep(5);
        system("reboot -f");
        sleep(5);
        system("reboot -f");
    }

    ChkSum = 0;
    for (wrd = ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev); wrd < MtdBlockSize - 4; wrd++) {
        ChkSum += buf[wrd];
    }
    memcpy(&ChkSumOrg, buf + (MtdBlockSize - 4), sizeof(ChkSumOrg));
    memcpy(&pSysConfig->ModelName, buf + (ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev)), ARRAY_SIZE(pSysConfig->ModelName));
    memcpy(&pSysConfig->SerialNumber, buf + (ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev) + ARRAY_SIZE(pSysConfig->ModelName) + ARRAY_SIZE(pSysConfig->AcModelName)), ARRAY_SIZE(pSysConfig->SerialNumber));

    //================================================
    // Load configuration from mtdblock11
    //================================================
    if (ChkSum != ChkSumOrg) {
        log_error("Primary SysConfigData checksum NG, read backup");
        system("nanddump /dev/mtd11 -f /mnt/EvseConfig.bin");
        fd = open("/mnt/EvseConfig.bin", O_RDWR);
        if (fd < 0) {
            free(buf);

            log_error("open mtdblock11 (backup) NG,rebooting..");

            if (pAlarmCode != NULL) {
                pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
            }
            sleep(5);
            system("reboot -f");
            sleep(5);
            system("reboot -f");
        }
        memset(buf, 0, MtdBlockSize);
        wrd = read(fd, buf, MtdBlockSize);
        close(fd);
        if (wrd < MtdBlockSize) {
            free(buf);

            log_error("read backup SysConfigData data NG,rebooting..");

            if (pAlarmCode != NULL) {
                pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
            }
            sleep(5);
            system("reboot -f");
            sleep(5);
            system("reboot -f");
        }

        ChkSum = 0;
        for (wrd = ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev); wrd < MtdBlockSize - 4; wrd++) {
            ChkSum += buf[wrd];
        }
        memcpy(&ChkSumOrg, buf + (MtdBlockSize - 4), sizeof(ChkSumOrg));

        //================================================
        // Load configuration from mtdblock12 (Factory default)
        //================================================
        if (ChkSum != ChkSumOrg) {
            log_warn("backup SysConfigData checksum NG, read Factory default");
            system("nanddump /dev/mtd12 -f /mnt/EvseConfig.bin");
            fd = open("/mnt/EvseConfig.bin", O_RDWR);
            if (fd < 0) {
                log_error("open mtdblock12 (Factory default) NG,rebooting..");

                free(buf);
                if (pAlarmCode != NULL) {
                    pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
                }
                sleep(5);
                system("reboot -f");
                sleep(5);
                system("reboot -f");
            }
            memset(buf, 0, MtdBlockSize);
            wrd = read(fd, buf, MtdBlockSize);
            close(fd);
            if (wrd < MtdBlockSize) {
                log_error("read factory default  SysConfigData data NG,rebooting..");

                free(buf);
                if (pAlarmCode != NULL) {
                    pAlarmCode->AlarmEvents.bits.CsuInitFailed = 1;
                }
                sleep(5);
                system("reboot -f");
                sleep(5);
                system("reboot -f");
            }

            ChkSum = 0;
            for (wrd = ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev); wrd < MtdBlockSize - 4; wrd++) {
                ChkSum += buf[wrd];
            }
            memcpy(&ChkSumOrg, buf + (MtdBlockSize - 4), sizeof(ChkSumOrg));
            memcpy(buf + (ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev)), &pSysConfig->ModelName, ARRAY_SIZE(pSysConfig->ModelName));
            memcpy(buf + (ARRAY_SIZE(pSysConfig->CsuBootLoadFwRev) + ARRAY_SIZE(pSysConfig->ModelName) + ARRAY_SIZE(pSysConfig->AcModelName)), &pSysConfig->SerialNumber, ARRAY_SIZE(pSysConfig->SerialNumber));

            if (ChkSum != ChkSumOrg) {
                log_warn("factory default  SysConfigData checksum NG, restore factory default");
                free(buf);
                system("cd /root;./FactoryConfig -m");
                system("rm -f /Storage/OCPP/OCPPConfiguration");
                system("sync");
                sleep(5);
                system("reboot -f");
                sleep(5);
                system("reboot -f");

                return FAIL;
            }
        }
    }

    //load OK
    memcpy(pSysConfig, buf, sizeof(struct SysConfigData));
    free(buf);

    system("rm -f /mnt/EvseConfig.bin");

    // SysConfig in flash is empty (0xffffffff)
    if ((strlen((char *)pSysConfig->ModelName) > ARRAY_SIZE(pSysConfig->ModelName)) ||
            (strlen((char *)pSysConfig->SerialNumber) > ARRAY_SIZE(pSysConfig->SerialNumber)) ||
            (strlen((char *)pSysConfig->SystemId) > ARRAY_SIZE(pSysConfig->SystemId)) ||
            (pSysConfig->Eth0Interface.EthDhcpClient == 0xff)) {
        if (strlen((char *)pSysConfig->ModelName) > ARRAY_SIZE(pSysConfig->ModelName)) {
            memset(pSysConfig->ModelName, 0x00, ARRAY_SIZE(pSysConfig->ModelName));
        }

        if (strlen((char *)pSysConfig->SerialNumber) > ARRAY_SIZE(pSysConfig->SerialNumber)) {
            memset(pSysConfig->SerialNumber, 0x00, ARRAY_SIZE(pSysConfig->SerialNumber));
        }

        if (strlen((char *)pSysConfig->SystemId) > ARRAY_SIZE(pSysConfig->SystemId)) {
            memset(pSysConfig->SystemId, 0x00, ARRAY_SIZE(pSysConfig->SystemId));
        }

        if (pSysConfig->Eth0Interface.EthDhcpClient == 0xff) {
            log_info("Ethernet dhcp config is null.");
        }

        if (strlen((char *)pSysConfig->ModelName) == 0x00) {
            log_info("Model name over length.");
        }

        if (strlen((char *)pSysConfig->SerialNumber) == 0x00) {
            log_info("Model serial number over length.");
        }

        if (strlen((char *)pSysConfig->SystemId) == 0x00) {
            log_info("SystemId over length.");
        }

        system("cd /root;./FactoryConfig -m");
        sleep(3);
        system("/usr/bin/run_evse_restart.sh");
    }
    //log_info("Load SysConfigData OK");


    return PASS;
}

int Initialization(void)
{
    uint8_t count = 0;
    uint8_t pinOut[2] = {116, 115};

    // 初始化卡號驗證的 Flag
    ClearAuthorizedFlag();



    for (count = 0; count < pSysConfig->TotalConnectorCount; count++) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(count);
        // 初始化插槍驗證的 Flag
        ClearDetectPluginFlag(count);

        pDcChargingInfo->RemoteStartFlag = NO;

        if (pDcChargingInfo->Type == _Type_Chademo) {
            gpio_set_value(pinOut[count], 0x00);
            ShmCHAdeMOData->evse[pDcChargingInfo->type_index].SelfTest_Comp = NO;
        } else if (pDcChargingInfo->Type == _Type_GB) {
            gpio_set_value(pinOut[count], 0x00);
            ShmGBTData->evse[pDcChargingInfo->type_index].SelfTest_Comp = NO;
        } else if (pDcChargingInfo->Type == _Type_CCS_2) {
            //if (ShmCcsData->CommProtocol == _CCS_COMM_V2GMessage_DIN70121) { //DS60-120 remove
            if (pSysConfig->TotalConnectorCount == 1) {
                gpio_set_value(pinOut[1], 0x01);
            } else {
                gpio_set_value(pinOut[count], 0x01);
            }
            ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].SelfTest_Comp = NO;
            //}
        }

        strcpy((char *)ShmOCPP16Data->StatusNotification[count].ErrorCode, "NoError");
    }

    for (count = 0; count < pSysConfig->AcConnectorCount; count++) {
        pAcChargingInfo = (struct ChargingInfoData *)GetAcChargingInfoData(count);

        pAcChargingInfo->RemoteStartFlag = NO;

        if (pAcChargingInfo->Type == _Type_AC) {
            pAcChargingInfo->SelfTest_Comp = NO;
            strcpy((char *)ShmOCPP16Data->StatusNotification[count + pSysConfig->TotalConnectorCount].ErrorCode, "NoError");
        }
    }

    return PASS;
}

bool InitialSystemDefaultConfig()
{
    bool result = true;

    LoadSysConfigAndInfo();
    InitGPIO();
    InitEthernet();
    GetMacAddress();

//  system("echo 1 > /sys/class/gpio/gpio110/value"); //reset PHY
//  sleep(3);
//  system("/sbin/ifconfig eth0 192.168.1.10 netmask 255.255.255.0 down");
//  sleep(1);
//  system("/sbin/ifconfig eth1 192.168.0.10 netmask 255.255.255.0 up");

    return result;
}

//顯示自檢錯誤原因,觸發對應的flag
bool DisplaySelfTestFailReason()
{
    bool result = false;
    uint8_t index = 0;

    // RB、FB、407、EV 小板中有些板子無回應
    if (ShmRelayModuleData->SelfTest_Comp == NO) {
        pAlarmCode->AlarmEvents.bits.RelayboardStestFail = true;
    }

    if (ShmFanModuleData->SelfTest_Comp == NO) {
        pAlarmCode->AlarmEvents.bits.FanboardStestFail = true;
    }

    if (ShmPrimaryMcuData->SelfTest_Comp == NO) {
        pAlarmCode->AlarmEvents.bits.PrimaryStestFail = true;
    }

    if (ShmLedModuleData->SelfTest_Comp == NO) {
        pAlarmCode->AlarmEvents.bits.LedboardStestFail = true;
    }

    for (index = 0; index < pSysConfig->TotalConnectorCount; index++) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);

        if (pDcChargingInfo->Type == _Type_Chademo) {
            if (ShmCHAdeMOData->evse[pDcChargingInfo->type_index].SelfTest_Comp == NO) {
                pAlarmCode->AlarmEvents.bits.ChademoboardStestFail = true;
            }
        } else if (pDcChargingInfo->Type == _Type_GB) {
            if (ShmGBTData->evse[pDcChargingInfo->type_index].SelfTest_Comp == NO) {
                pAlarmCode->AlarmEvents.bits.GbtboardStestFail = true;
            }
        } else if (pDcChargingInfo->Type == _Type_CCS_2) {
            if (ShmCcsData->CommProtocol == _CCS_COMM_V2GMessage_DIN70121) {
                if (ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].SelfTest_Comp == NO) {
                    pAlarmCode->AlarmEvents.bits.CCSboardStestFail = true;
                }
            }
        }
    }

    for (index = 0; index < pSysConfig->AcConnectorCount; index++) {
        pAcChargingInfo = (struct ChargingInfoData *)GetAcChargingInfoData(index);

        // 先借 GBT 顯示
        if (pAcChargingInfo->SelfTest_Comp == NO) {
            pAlarmCode->AlarmEvents.bits.AcConnectorStestFail = true;
        }
    }

    if (pSysInfo->AcContactorStatus == NO) {
#if !defined DD360 && !defined DD360Audi && !defined DD360ComBox
        // AC Contact 未搭上
        pAlarmCode->AlarmEvents.bits.AcContactStestFail = true;
        result = true;
#endif // !defined DD360 && !defined DD360Audi && !defined DD360ComBox
    } else if (ShmPsuData->SystemAvailablePower <= 0 &&
             ShmPsuData->SystemAvailableCurrent <= 0) {
        // PSU 通訊問題
        pAlarmCode->AlarmEvents.bits.PsuModuleStestFail = true;
        result = true;
    }

    return result;
}

#if 0 //not use
int StoreUsrConfigData(struct SysConfigData *UsrData)
{
    int result = PASS;
    int fd, wrd;
    unsigned int i, Chk;
    uint8_t *ptr, *BufTmp;

    Chk = 0;
    ptr = (uint8_t *)UsrData;
    if ((BufTmp = malloc(MtdBlockSize)) != NULL) {
        memset(BufTmp, 0, MtdBlockSize);
        memcpy(BufTmp, ptr, sizeof(struct SysConfigData));
        for (i = 0; i < MtdBlockSize - 4; i++) {
            Chk += *(ptr + i);
        }

        memcpy(BufTmp + MtdBlockSize - 4, &Chk, 4);
        fd = open("/dev/mtdblock10", O_RDWR);
        if (fd > 0) {
            wrd = write(fd, BufTmp, MtdBlockSize);
            close(fd);
            if (wrd >= MtdBlockSize) {
                fd = open("/dev/mtdblock11", O_RDWR);
                if (fd > 0) {
                    wrd = write(fd, BufTmp, MtdBlockSize);
                    close(fd);
                    if (wrd < MtdBlockSize) {
                        log_error("write /dev/mtdblock11(backup) NG");
                        result = FAIL;
                    }
                } else {
                    log_error("open /dev/mtdblock11(backup) NG");
                    result = FAIL;
                }
            } else {
                log_error("write /dev/mtdblock10 NG");
                result = FAIL;
            }

        } else {
            log_error("open /dev/mtdblock10 NG");
            result = FAIL;
        }
    } else {
        log_error("alloc BlockSize NG");
        result = FAIL;
    }

    if (BufTmp != NULL) {
        free(BufTmp);
    }

    return result;
}
#endif //0

//===============================================
// Common Detect Chk - Stop Charging ?
//===============================================
int isEvBoardStopChargeFlag(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    //printf("StopChargeFlag = %d", chargingInfo[gunIndex]->StopChargeFlag);
    return pDcChargingInfo->StopChargeFlag;
}

bool isEvBoardNormalStopChargeFlag(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return pDcChargingInfo->NormalStopChargeFlag;
}

//===============================================
// 掃描插槍狀況
//===============================================
void ClearDetectPluginFlag(int gunIndex)
{
    if (pSysConfig->TotalConnectorCount == 1 && gunIndex == RIGHT_GUN_NUM)
        return;

    ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit = NO;
    //DS60-120 add

    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pDcChargingInfo->RemoteStartFlag == YES) {
        pDcChargingInfo->RemoteStartFlag = NO;
    }


    if (pSysInfo->OrderCharging != NO_DEFINE) {
        pSysInfo->OrderCharging = NO_DEFINE;
    }
}

void DetectPluginStart(int gunIndex)
{
    //pSysInfo->WaitForPlugit = YES;
    if (pSysConfig->TotalConnectorCount == 1 && gunIndex == RIGHT_GUN_NUM)
        return;
    ShmDcCommonData->pGunInfo[gunIndex].WaitForPlugit = YES;
    log_info("Gun%d start detect plug in",gunIndex);
}

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;
}

//===============================================
// Common Detect Chk - Chademo
//===============================================
bool isEvGunLocked_chademo(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return (DetectBitValue(pDcChargingInfo->GunLocked , 0) == 0) ? NO : YES;
}

bool isEvContactorWelding_chademo(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return DetectBitValue(ShmCHAdeMOData->ev[pDcChargingInfo->type_index].EvDetection, 3);
}

bool isEvStopReq_chademo(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return DetectBitValue(ShmCHAdeMOData->ev[pDcChargingInfo->type_index].EvDetection, 4);
}

bool isEvStopCharging_chademo(uint8_t gunIndex)
{
    if (isEvGunLocked_chademo(gunIndex) == NO) {
        // 無鎖槍 = 停止
        //log_info("gun locked none (%d) ", gunIndex);
        return YES;
    }

    return NO;
}

uint8_t isPrechargeStatus_chademo(uint8_t gunIndex)
{
    uint8_t result = 0x00;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    result = ShmCHAdeMOData->ev[pDcChargingInfo->type_index].PresentMsgFlowStatus;

    return result;
}

//===============================================
// Common Detect Chk - GB
//===============================================
bool isEvGunLocked_gb(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return (DetectBitValue(pDcChargingInfo->GunLocked , 0) == 0) ? NO : YES;
}

bool isEvStopCharging_gb(uint8_t gunIndex)
{
    if (isEvGunLocked_gb(gunIndex) == NO) {
        // 無鎖槍 = 停止
        //log_info("gun locked none. ");
        return YES;
    }

    return NO;
}

uint8_t isPrechargeStatus_gb(uint8_t gunIndex)
{
    uint8_t result = 0x00;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    result = ShmGBTData->ev[pDcChargingInfo->type_index].PresentMsgFlowStatus;

    return result;
}

//===============================================
// Common Detect Chk - CCS
//===============================================
bool isEvGunLocked_ccs(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return (DetectBitValue(pDcChargingInfo->GunLocked , 0) == 0) ? NO : YES;
}

uint8_t isPrechargeStatus_ccs(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    return ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].PresentMsgFlowStatus;;
}

bool isEvStopCharging_ccs(uint8_t gunIndex)
{
    if (isEvGunLocked_ccs(gunIndex) == NO) {
        // 無鎖槍 = 停止
        //log_info("gun locked none. ");
        return YES;
    }

    return NO;
}

//===============================================
// Callback
//===============================================
void DisplayChargingInfo()
{
    uint8_t i = 0;

    log_info("*********** DisplayChargingInfo *********** ");
    for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
        pDcChargingInfo =  (struct ChargingInfoData *)GetDcChargingInfoData(i);

        if (pDcChargingInfo->SystemStatus != S_IDLE &&
                pDcChargingInfo->SystemStatus != S_RESERVATION) {
            ChangeGunSelectByIndex(i);
            if (CheckDispenserGeneration() < _DISPENSER_GENERATION_3_5) {
                systemPageRestoreInit();
            }
            return;
        }
    }

    if (pSysConfig->AcConnectorCount > 0 &&
            pSysInfo->CurGunSelectedByAc == NO_DEFINE)
    {
        pAcChargingInfo = (struct ChargingInfoData*)GetAcChargingInfoData(0);

        if (pAcChargingInfo->SystemStatus >= S_PREPARNING &&
            pAcChargingInfo->SystemStatus <= S_COMPLETE)
        {
            pSysInfo->CurGunSelectedByAc = DEFAULT_AC_INDEX;
        }
    }

    usleep(50000);

    systemPageRestoreInit();
}

void _AutoReturnTimeout(int gunIndex)
{
    log_info("*********** _AutoReturnTimeout(%d) *********** ", pSysInfo->SystemPage);
    pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(gunIndex);
    if (pSysInfo->SystemPage == _LCM_WAIT_FOR_PLUG) {
        if (pDcChargingInfo->RemoteStartFlag) {
            ClearDetectPluginFlag(gunIndex);
        } else {
            ClearDetectPluginFlag(0);
            ClearDetectPluginFlag(1);
        }
    } else if (pSysInfo->SystemPage == _LCM_AUTHORIZ_COMP) {
        if (pDcChargingInfo->RemoteStartFlag) {
            DetectPluginStart(gunIndex);
        } else {
            if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
                pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(pSysInfo->CurGunSelected);
                if (pDcChargingInfo->SystemStatus == S_IDLE || pDcChargingInfo->SystemStatus == S_RESERVATION)
                    DetectPluginStart(gunIndex);
            } else {
                    pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(LEFT_GUN_NUM);
                    if (pDcChargingInfo->SystemStatus == S_IDLE || pDcChargingInfo->SystemStatus == S_RESERVATION)
                        DetectPluginStart(LEFT_GUN_NUM);
                    if (pSysConfig->TotalConnectorCount > 1) {
                        pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(RIGHT_GUN_NUM);
                        if (pDcChargingInfo->SystemStatus == S_IDLE || pDcChargingInfo->SystemStatus == S_RESERVATION)
                            DetectPluginStart(RIGHT_GUN_NUM);
                    }
                    pSysInfo->SystemPage = _LCM_WAIT_FOR_PLUG;
            }
        }
    } else if (pSysInfo->SystemPage == _LCM_AUTHORIZ_FAIL) {
        if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
            ClearDetectPluginFlag(gunIndex);
        } else {
            ClearDetectPluginFlag(LEFT_GUN_NUM);
            ClearDetectPluginFlag(RIGHT_GUN_NUM);
        }
        systemPageRestoreInit();
        ClearAuthorizedFlag();
    }

    usleep(50000);
    if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
        systemPageRestoreInit();
    }
}

void _SelfTestTimeout(void)
{
    if (pSysInfo->BootingStatus != BOOT_COMPLETE) {
        for (uint8_t gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            setChargerMode(gunIndex, MODE_MAINTAIN);
        }
    }
    ShmPsuData->Work_Step = _NO_WORKING;
    pSysInfo->SelfTestSeq = _STEST_FAIL;
    log_info("Self test timeout. ");
    //sleep(3);
    //system("/usr/bin/run_evse_restart.sh");
}

void _AuthorizedTimeout(void)
{
    if (IsAuthorizingMode()) {
        log_info("*********** _AuthorizedTimeout *********** ");
        //isCardScan = false;
        SetIsCardScan(false);

        pSysInfo->SystemPage = _LCM_AUTHORIZ_FAIL;
        //ChangeLcmByIndex(_LCM_AUTHORIZ_FAIL);
        strcpy((char *)pSysConfig->UserId, "");
        ClearAuthorizedFlag();
    }
}

void _DetectPlugInTimeout(int gunIndex)
{
    if (gunIndex == pSysInfo->CurGunSelected) {
        ShmDcCommonData->LcmPage = _PAGE_PLUGIN_TIMEOUT;
    }
    strcpy((char *)pSysConfig->UserId, "");
    
    uint8_t is_remote = NO;
    int i;
    for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
        pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(i);
        if (pDcChargingInfo->RemoteStartFlag) {
            //此停止為remote start停止
            is_remote = YES;
            break;
        }
    }

    if (is_remote) {
        // Remote start進入充電
        log_info("Clear Gun%d Remote start detect plugin flag",gunIndex);
        StopGunInfoTimeoutDet(gunIndex);
        ClearDetectPluginFlag(gunIndex);
    } else {
        // 刷卡進入充電
        if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
            log_info("Clear Gun%d RFID detect plugin flag", gunIndex);
            ClearDetectPluginFlag(gunIndex);
            StopGunInfoTimeoutDet(gunIndex);
        } else {
            log_info("Clear All Gun RFID detect plugin flag");
            for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
                pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(i);
                if (!pDcChargingInfo->RemoteStartFlag) {
                    ClearDetectPluginFlag(i);
                    StopGunInfoTimeoutDet(i);
                }
            }
        }
    }
    sleep(1); //等待DoComm回報插槍訊號給主櫃
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        if (pSysInfo->SystemPage == _LCM_WAIT_FOR_PLUG) 
            changeLcmPage(_LCM_IDLE);
    } else {
        systemPageRestoreInit();
    }
#if defined DD360Audi
	//pSysInfo->SystemPage = _LCM_COMPLETE;
	setChargerMode(gunIndex, S_TERMINATING);
#elif DD360 || DD360Combox
 	setChargerMode(gunIndex, S_IDLE);
#endif


}

void _DetectEvChargingEnableTimeout(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pDcChargingInfo->Type == _Type_Chademo) {
        if (!isEvGunLocked_chademo(gunIndex)) {
            log_info("*********** _DetectEvChargingEnableTimeout (chademo) ***********");
        }
    } else if (pDcChargingInfo->Type == _Type_GB) {
        if (!isEvGunLocked_ccs(gunIndex)) {
            log_info("*********** _DetectEvChargingEnableTimeout (gb) ***********");
        }
    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
        if (!isEvGunLocked_ccs(gunIndex)) {
            log_info("*********** _DetectEvChargingEnableTimeout (ccs) ***********");
        }
    }
    ChargingTerminalProcess(gunIndex);
    _AutoReturnTimeout(gunIndex);
}

void _DetectEvseChargingEnableTimeout(uint8_t gunIndex)
{
    log_info("*********** _DetectEvseChargingEnableTimeout (GFD timeout) ***********");
    //if (chargingInfo[gunIndex]->GroundFaultStatus != GFD_PASS)
    {
#if defined DD360Audi
	    //pSysInfo->SystemPage = _LCM_COMPLETE;
		setChargerMode(pSysInfo->CurGunSelected, S_TERMINATING);
#elif DD360 || DD360Combox
	setChargerMode(pSysInfo->CurGunSelected, S_COMPLETE);
#endif
    _AutoReturnTimeout(gunIndex);
    }
}

void _PrepareTimeout(uint8_t gunIndex)
{
    log_info("*********** _PrepareTimeout ***********");
#if defined DD360Audi
	    //pSysInfo->SystemPage = _LCM_COMPLETE;
		setChargerMode(pSysInfo->CurGunSelected, S_TERMINATING);
#elif DD360 || DD360Combox
	setChargerMode(pSysInfo->CurGunSelected, S_COMPLETE);
#endif
    pAlarmCode->AlarmEvents.bits.PsuNoResource = YES;
    _AutoReturnTimeout(gunIndex);
}

void _CcsPrechargeTimeout(uint8_t gunIndex)
{
    log_info("*********** _CcsPrechargeTimeout ***********");
#if defined DD360Audi
	    //pSysInfo->SystemPage = _LCM_COMPLETE;
		setChargerMode(pSysInfo->CurGunSelected, S_TERMINATING);
#elif DD360 || DD360Combox
	setChargerMode(pSysInfo->CurGunSelected, S_COMPLETE);
	pSysInfo->SystemPage = _LCM_COMPLETE;
	return;
#endif
}


//===============================================
// 取得卡號與卡號驗證
//===============================================
void AuthorizingStart(void)
{
    ShmOCPP16Data->SpMsg.bits.AuthorizeReq = YES;
    pSysInfo->AuthorizeFlag = YES;
}

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

bool isAuthorizedComplete(void)
{
    if (pSysInfo->AuthorizeFlag == YES) {
        return false;
    }
    return true;
}

bool IsAuthorizingMode()
{
    if (pSysInfo->AuthorizeFlag == NO) {
        return false;
    }

    return true;
}

//===============================================
// 紀錄 Alarm Code
//===============================================
void ResetChargerAlarmCode(uint8_t gunIndex, char *code)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (strcmp(code, "012234") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip = NO;
    } else if (strcmp(code, "012235") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = NO;
    } else if (strcmp(code, "012236") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip = NO;
    } else if (strcmp(code, "012288") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSUvpFail = NO;
    } else if (strcmp(code, "012289") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaUvpFail = NO;
    } else if (strcmp(code, "012290") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTUvpFail = NO;
    } else if (strcmp(code, "012229") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = NO;
    } else if (strcmp(code, "012230") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOTP = NO;
    } else if (strcmp(code, "012231") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOTP = NO;
    } else if (strcmp(code, "011011") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayWeldingFault = NO;
    } else if (strcmp(code, "011013") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayWeldingFault = NO;
    } else if (strcmp(code, "011015") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayWeldingFault = NO;
    } else if (strcmp(code, "011012") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayDrivingFault = NO;
    } else if (strcmp(code, "011014") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayDrivingFault = NO;
    } else if (strcmp(code, "011016") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayDrivingFault = NO;
    } else if (strcmp(code, "011018") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail = NO;
    } else if (strcmp(code, "011019") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail = NO;
    } else if (strcmp(code, "011020") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail = NO;
    } else if (strcmp(code, "012323") == EQUAL) {
        ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = NO;
    } else if (strcmp(code, "011038") == EQUAL) {
        ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = NO;
    }

    //if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) != EQUAL) {
    //    if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSUvpFail == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaUvpFail == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTUvpFail == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOTP == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOTP == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayWeldingFault == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayWeldingFault == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayWeldingFault == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayDrivingFault == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayDrivingFault == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayDrivingFault == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail == NO &&
    //            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail == NO &&
    //            ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP == NO &&
    //            ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail == NO
    //       ) {
    //        strncpy((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6);
    //    }
    //}
    if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012229", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012230", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012231", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011011", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011013", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011015", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011012", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011014", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011016", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011018", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011019", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011020", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012323", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011038", 6) == EQUAL) {
        strncpy((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6);
    }
}

void RecordAlarmCode(uint8_t gunIndex, char *code)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if((pDcChargingInfo->SystemStatus > S_IDLE && pDcChargingInfo->SystemStatus < S_TERMINATING) ||
        (pDcChargingInfo->SystemStatus >= S_CCS_PRECHARGE_ST0 && pDcChargingInfo->SystemStatus <= S_CCS_PRECHARGE_ST1))
    {
        if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) == EQUAL) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, code, 6);
        }

        if (pDcChargingInfo->StopChargeFlag == NO)
        {
            pDcChargingInfo->StopChargeFlag = YES;
        }
    }

#if 0
    if (strcmp(code, "012234") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip = YES;
    } else if (strcmp(code, "012235") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = YES;
    } else if (strcmp(code, "012236") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip = YES;
    } else if (strcmp(code, "012288") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSUvpFail = YES;
    } else if (strcmp(code, "012289") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaUvpFail = YES;
    } else if (strcmp(code, "012290") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTUvpFail = YES;
    } else if (strcmp(code, "012229") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOTP = YES;
    } else if (strcmp(code, "012230") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOTP = YES;
    } else if (strcmp(code, "012231") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOTP = YES;
    } else if (strcmp(code, "012296") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdWarning = YES;
    } else if (strcmp(code, "012297") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdWarning = YES;
    } else if (strcmp(code, "012298") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdWarning = YES;
    } else if (strcmp(code, "011011") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayWeldingFault = YES;
    } else if (strcmp(code, "011013") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayWeldingFault = YES;
    } else if (strcmp(code, "011015") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayWeldingFault = YES;
    } else if (strcmp(code, "011012") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayDrivingFault = YES;
    } else if (strcmp(code, "011014") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayDrivingFault = YES;
    } else if (strcmp(code, "011016") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayDrivingFault = YES;
    } else if (strcmp(code, "011018") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail = YES;
    } else if (strcmp(code, "011019") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail = YES;
    } else if (strcmp(code, "011020") == EQUAL) {
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail = YES;
    } else if (strcmp(code, "012323") == EQUAL) {
        if ((gunIndex == 0) &&
                ((strncmp((char *)&pSysConfig->ModelName[7], "V", 1) == 0) ||
                 (strncmp((char *)&pSysConfig->ModelName[7], "F", 1) == 0))
           ) {
            ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = YES;
        } else if ((gunIndex == 1) &&
                   ((strncmp((char *)&pSysConfig->ModelName[9], "V", 1) == 0) ||
                    (strncmp((char *)&pSysConfig->ModelName[9], "F", 1) == 0))
                  ) {
            ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerOTP = YES;
        }
    } else if (strcmp(code, "011038") == EQUAL) {
        if ((gunIndex == 0) &&
                ((strncmp((char *)&pSysConfig->ModelName[7], "V", 1) == 0) ||
                 (strncmp((char *)&pSysConfig->ModelName[7], "F", 1) == 0))
           ) {
            ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = YES;
        } else if ((gunIndex == 1) &&
                   ((strncmp((char *)&pSysConfig->ModelName[9], "V", 1) == 0) ||
                    (strncmp((char *)&pSysConfig->ModelName[9], "F", 1) == 0))
                  ) {
            ShmDcCommonData->ChillerTempErr[gunIndex].StatusBit.ChillerTempSensorFail = YES;
        }
    }
#endif
}

void ReleaseAlarmCode(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    //if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) == EQUAL) {
    //    return;
    //}
#if 0
    // 回 idle 後主要清除  GFD Trip、UVP、OVP、GFD Warning
    if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012251", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012252", 6) == EQUAL) {
        memcpy(pDcChargingInfo->ConnectorAlarmCode, "", 6);
    }
#endif
    switch (pDcChargingInfo->Type) {
    case _Type_Chademo:
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaUvpFail = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOVP = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdWarning = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayWeldingFault = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayDrivingFault = NO;
#if 0
        if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012234", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012289", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012217", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012296", 6) == EQUAL) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "", 6);
        }
#endif
        break;

    case _Type_CCS_2:
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSUvpFail = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOVP = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdWarning = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayWeldingFault = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayDrivingFault = NO;
#if 0
        if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012235", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012288", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012219", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012297", 6) == EQUAL) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "", 6);
        }
#endif
        break;

    case _Type_GB:
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTUvpFail = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOVP = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdWarning = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayWeldingFault = NO;
        ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayDrivingFault = NO;
#if 0
        if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012236", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012290", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012221", 6) == EQUAL ||
                strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012298", 6) == EQUAL) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "", 6);
        }
#endif
        break;
    }
#if 0
    //system alarm
    if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012251", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012252", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012238", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012304", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "012323", 6) == EQUAL ||
            strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "011038", 6) == EQUAL
       ) {
        memset(pDcChargingInfo->ConnectorAlarmCode, 0, sizeof(pDcChargingInfo->ConnectorAlarmCode));
    }
#endif
    memcpy(pDcChargingInfo->ConnectorAlarmCode, "", 6);
}

//===============================================
// EmergencyStop and Charging Stop
//===============================================
void ChargingTerminalProcess(uint8_t gunIndex)
{
    setChargerMode(gunIndex, MODE_TERMINATING);
}

void ChargingAlarmProcess(uint8_t gunIndex)
{
    UpdateErrorCodeToOcpp(gunIndex);
    setChargerMode(gunIndex, MODE_ALARM);
}

void AcChargingTerminalProcess(void)
{
    pAcChargingInfo =  (struct ChargingInfoData *)GetAcChargingInfoData(0);

    pAcChargingInfo->SystemStatus = MODE_TERMINATING;
}

void StopChargingProcessByString(uint8_t level)
{
    if (level > pSysWarning->Level) {
        pSysWarning->Level = level;
    }
}

void ReleaseChargingProcessByString(uint8_t level)
{
    if (level >= pSysWarning->Level) {
        pSysWarning->Level = WARN_LV_NL;
    }
}

// 一般錯誤停止充電處理函式
void BoardErrOccurByString(uint8_t index, char *code)
{
    uint8_t level = 1;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);

    if ((pDcChargingInfo->SystemStatus > S_IDLE &&
            pDcChargingInfo->SystemStatus < S_TERMINATING) ||
            (pDcChargingInfo->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
             pDcChargingInfo->SystemStatus <= S_CCS_PRECHARGE_ST1)) {
        if (strncmp(code, "023730", 6) == EQUAL &&
                pInfoCode->InfoEvents.bits.ChademoChargerGetEmergencyStop == NO
           ) {
            pInfoCode->InfoEvents.bits.ChademoChargerGetEmergencyStop = YES;
        }
        ChargingTerminalProcess(index);
    }

    StopChargingProcessByString(level);
}

void ReleaseBoardErrOccurByString(uint8_t index, char *code)
{
    bool isTrigger = false;
    uint8_t level = 1;

    if (strncmp(code, "023730", 6) == 0 &&
            pInfoCode->InfoEvents.bits.ChademoChargerGetEmergencyStop == YES) {
        isTrigger = true;
        pInfoCode->InfoEvents.bits.ChademoChargerGetEmergencyStop = NO;
    }

    if (isTrigger) {
        ReleaseChargingProcessByString(level);
    }
}

// 急停狀況的停止充電處理函式
void EmcOccureByString(char *code)
{
    uint8_t level = 2;
    // 嚴重的急停有以下幾種 : EMC 按鈕、Mainbreak、Dooropen
    // 其錯誤等級為 2
    //DS60-120 remove
    if (strncmp(code, "012251", 6) == EQUAL ||
            strncmp(code, "012252", 6) == EQUAL ||
            strncmp(code, "012304", 6) == EQUAL ||
            strncmp(code, "012238", 6) == EQUAL/* ||
            strncmp(code, "042251", 6) == EQUAL ||
            strncmp(code, "042252", 6) == EQUAL ||
            strncmp(code, "042200", 6) == EQUAL ||
            strncmp(code, "042201", 6) == EQUAL ||
            strncmp(code, "042202", 6) == EQUAL ||
            strncmp(code, "042267", 6) == EQUAL*/)
    {
        for (uint8_t gun = 0; gun < pSysConfig->TotalConnectorCount; gun++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gun);

            //strncpy((char *)ShmOCPP16Data->StatusNotification[gun].VendorErrorCode, code, 6);

            if ((pDcChargingInfo->SystemStatus > S_IDLE &&
                    pDcChargingInfo->SystemStatus < S_TERMINATING) ||
                    (pDcChargingInfo->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                     pDcChargingInfo->SystemStatus <= S_CCS_PRECHARGE_ST1)) {
                //ChargingTerminalProcess(gun);
                if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) == EQUAL) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, code, 6);
                }
                pDcChargingInfo->StopChargeFlag = DISPENSER_STOP_CHARGING;
                ChargingAlarmProcess(gun);
            } else if (pDcChargingInfo->SystemStatus == S_IDLE) {
                if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) == EQUAL) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, code, 6);
                }
            }
        }

        StopChargingProcessByString(level);
        InformOcppErrOccur(4);

    }
}

void ReleaseEmsOccureByString(uint8_t index, char *code)
{
    bool isTrigger = false;
    uint8_t level = 2;

    if (strncmp(code, "042251", 6) == 0 ) {
        isTrigger = true;
    } else if (strncmp(code, "012251", 6) == 0 &&
               pAlarmCode->AlarmEvents.bits.EmergencyStopTrip == YES) {
        isTrigger = true;
        pAlarmCode->AlarmEvents.bits.EmergencyStopTrip = NO;
    } else if (strncmp(code, "012252", 6) == 0 &&
               pAlarmCode->AlarmEvents.bits.DoorOpen == YES) {
        isTrigger = true;
        pAlarmCode->AlarmEvents.bits.DoorOpen = NO;
    } else if (strncmp(code, "012237", 6) == 0 &&
               pAlarmCode->AlarmEvents.bits.SpdTrip == YES) {
        isTrigger = true;
        pAlarmCode->AlarmEvents.bits.SpdTrip = NO;
    } else if (strncmp(code, "012238", 6) == 0 &&
               pAlarmCode->AlarmEvents.bits.MainPowerBreakerTrip == YES) {
        isTrigger = true;
        pAlarmCode->AlarmEvents.bits.MainPowerBreakerTrip = NO;
    } else if (strncmp(code, "012348", 6) == 0 &&
               pAlarmCode->AlarmEvents.bits.ChillerAlarmFail == YES) {
        isTrigger = true;
        pAlarmCode->AlarmEvents.bits.ChillerAlarmFail = NO;
    }

    if (isTrigger) {
        ReleaseChargingProcessByString(level);
        InformOcppErrOccur(6);
    }
}

static void checkOvpState(uint8_t gunIndex, uint8_t gunType)
{
    switch(gunType)
    {
        case _Type_Chademo:
            if(ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectOVP == YES)
            {
                RecordAlarmCode(gunIndex, "012217");
            }
            break;
        case _Type_CCS_2:
            if(ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectOVP == YES)
            {
                RecordAlarmCode(gunIndex, "012219");
            }
            break;
        case _Type_GB:
            if(ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectOVP == YES)
            {
                RecordAlarmCode(gunIndex, "012221");
            }
            break;
    }
}

//===============================================
// 確認各小板偵測的錯誤狀況
//===============================================
void CheckErrorOccurStatus(uint8_t index)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);
    // RB
    if (pSysConfig->PhaseLossPolicy == YES) {
        if (pAlarmCode->AlarmEvents.bits.SystemL1InputUVP == YES ||
                pAlarmCode->AlarmEvents.bits.SystemL2InputUVP == YES ||
                pAlarmCode->AlarmEvents.bits.SystemL3InputUVP == YES) {
            if (pSysWarning->ExtraErrProcess == _EXTRA_ERR_PROCESS_NONE) {
                pSysWarning->ExtraErrProcess = _EXTRA_ERR_PROCESS_INUVP;
                StopChargingProcessByString(2);
                InformOcppErrOccur(13);
            }

            //DS60-120 add -----
            if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) == EQUAL) {
                if (pAlarmCode->AlarmEvents.bits.SystemL1InputUVP == YES) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, "012203", 6);
                } else if (pAlarmCode->AlarmEvents.bits.SystemL2InputUVP == YES) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, "012204", 6);
                } else if (pAlarmCode->AlarmEvents.bits.SystemL3InputUVP == YES) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, "012205", 6);
                }
            }
            //log_info("1 CheckErrorOccurStatus");
            pDcChargingInfo->StopChargeFlag = YES;
            //------------------------------------------------------------------
        } else {
            if (pSysWarning->ExtraErrProcess == _EXTRA_ERR_PROCESS_INUVP) {
                pSysWarning->ExtraErrProcess = _EXTRA_ERR_PROCESS_NONE;
                ReleaseChargingProcessByString(2);
                InformOcppErrOccur(6);
            }
        }
    } else {
        if (pSysWarning->ExtraErrProcess == _EXTRA_ERR_PROCESS_INUVP) {
            pSysWarning->ExtraErrProcess = _EXTRA_ERR_PROCESS_NONE;
            ReleaseChargingProcessByString(2);
            InformOcppErrOccur(6);
        }
    }

    if (pAlarmCode->AlarmEvents.bits.SystemL1InputOVP == YES ||
            pAlarmCode->AlarmEvents.bits.SystemL2InputOVP == YES ||
            pAlarmCode->AlarmEvents.bits.SystemL3InputOVP == YES) {
        if (pSysWarning->ExtraErrProcess == _EXTRA_ERR_PROCESS_NONE) {
            pSysWarning->ExtraErrProcess = _EXTRA_ERR_PROCESS_INOVP;
            StopChargingProcessByString(2);
            InformOcppErrOccur(14);
        }

        //DS60-120 -----
        if (strncmp((char *)pDcChargingInfo->ConnectorAlarmCode, "", 6) == EQUAL) {
            if (pAlarmCode->AlarmEvents.bits.SystemL1InputOVP == YES) {
                memcpy(pDcChargingInfo->ConnectorAlarmCode, "012200", 6);
            } else if (pAlarmCode->AlarmEvents.bits.SystemL2InputOVP == YES) {
                memcpy(pDcChargingInfo->ConnectorAlarmCode, "012201", 6);
            } else if (pAlarmCode->AlarmEvents.bits.SystemL3InputOVP == YES) {
                memcpy(pDcChargingInfo->ConnectorAlarmCode, "012202", 6);
            }
        }
        //log_info("2 CheckErrorOccurStatus");
        pDcChargingInfo->StopChargeFlag = YES;
        //----------------------------------------------------------------------
    } else {
        if (pSysWarning->ExtraErrProcess == _EXTRA_ERR_PROCESS_INOVP) {
            pSysWarning->ExtraErrProcess = _EXTRA_ERR_PROCESS_NONE;
            ReleaseChargingProcessByString(2);
            InformOcppErrOccur(6);
        }
    }

    checkOvpState(index, pDcChargingInfo->Type);

    //--------------------------------------------------------------------------
    if (strlen((char *)pDcChargingInfo->ConnectorAlarmCode) == 0) {
        //Primary
        if (pAlarmCode->AlarmEvents.bits.EmergencyStopTrip == YES) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "012251", 6);
        } else if (pAlarmCode->AlarmEvents.bits.DoorOpen == YES) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "012252", 6);
        } else if (pAlarmCode->AlarmEvents.bits.MainPowerBreakerTrip == YES) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "012238", 6);
        } else if (pAlarmCode->AlarmEvents.bits.DisconnectedFromDo == YES) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "012304", 6);
        }/* else if (ShmDcCommonData->ConnectErrList[index].GunBits.ChaConnectTempSensorFail) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "011018", 6);
            UpdateErrorCodeToOcpp(index);
        } else if (ShmDcCommonData->ConnectErrList[index].GunBits.CCSConnectTempSensorFail) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "011019", 6);
            UpdateErrorCodeToOcpp(index);
        } else if (ShmDcCommonData->ConnectErrList[index].GunBits.GBTConnectTempSensorFail) {
            memcpy(pDcChargingInfo->ConnectorAlarmCode, "011020", 6);
            UpdateErrorCodeToOcpp(index);
        }*/
        //Chiller temperature
        //else if (pAlarmCode->AlarmEvents.bits.SystemChillerOTP == YES) {
        //    memcpy(pDcChargingInfo->ConnectorAlarmCode, "012323", 6);
        //} else if (pFaultCode->FaultEvents.bits.ChillerTempSensorBroken == YES) {
        //    memcpy(pDcChargingInfo->ConnectorAlarmCode, "011038", 6);
        //}
    }
}

//===============================================
// 確認 GPIO 狀態
//===============================================
void gpio_set_value(unsigned int gpio, unsigned int value)
{
    int fd;
    char buf[MAX_BUF];

    snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
    fd = open(buf, O_WRONLY);
    if (fd < 0) {
        perror("gpio/set-value");
        return;
    }

    if (value) {
        write(fd, "1", 2);
    } else {
        write(fd, "0", 2);
    }

    close(fd);
}

int gpio_get_value(unsigned int gpio, unsigned int *value)
{
    int fd;
    char buf[MAX_BUF];
    char ch;

    snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);

    fd = open(buf, O_RDONLY);
    if (fd < 0) {
        perror("gpio/get-value");
        return fd;
    }

    read(fd, &ch, 1);

    if (ch != '0') {
        *value = 1;
    } else {
        *value = 0;
    }

    close(fd);
    return 0;
}

void CheckGunTypeFromHw()
{
    uint8_t i = 0;
    int pinIn[4] = {22, 23, 44, 45};
    unsigned int gpioValue = 0;
    uint8_t tmp[2] = {0};

    log_info("ModelName = %s", pSysConfig->ModelName);
    for (i = 0; i < ARRAY_SIZE(pinIn); i++) {
        gpio_get_value(pinIn[i], &gpioValue);
        switch (pinIn[i]) {
        //right slot
        case 22:
            bd1_1_status = gpioValue;
            break;
        case 23:
            bd1_2_status = gpioValue;
            break;

        //left slot
        case 44:
            bd0_1_status = gpioValue;
            break;
        case 45:
            bd0_2_status = gpioValue;
            break;
        }
    }

    //BD1(Left-CCS-CND1-SMR2-左槍), BD2(Right-CHADEMO-CND2-SMR1-右槍), CCS: 10 , CHAdeMO: 01 , GBT: 11
    //CcsChargingData [0至1] 分別為 Right至Left
    //model name 槍順序左至右分別為Right至Left
    tmp[1] = (bd0_1_status << 4 | bd0_2_status);
    tmp[0] = (bd1_1_status << 4 | bd1_2_status);
    for (i = 0; i < 2; i++) {
        switch (tmp[i]) {
        case 0x01:
            log_info("BD%d(%s) = %s ", i + 1, i == 0 ? "Left" : "Right", "CHAdeMO");
            break;

        case 0x10:
            log_info("BD%d(%s) = %s ", i + 1, i == 0 ? "Left" : "Right", "CCS");
            break;

        case 0x11:
            log_info("BD%d(%s) = %s ", i + 1, i == 0 ? "Left" : "Right", "GBT");
            break;

        case 0x00:
            log_info("BD%d(%s) = %s ", i + 1, i == 0 ? "Left" : "Right", "None");
            break;
        }
    }
}

void CheckGpioInStatus()
{
    int i = 0;
    int pinIn[2] = { 27, 47 };//{IO BD1_2, IO BD2_2}
    unsigned int gpioValue = 0;

    for (i = 0; i < ARRAY_SIZE(pinIn); i++) {
        gpio_get_value(pinIn[i], &gpioValue);
        if (gpioValue == 0x01) {
            switch (pinIn[i]) {
            // 小板緊急停止
            case 47:
                for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

                    if (pDcChargingInfo->slotsIndex == 1) {
                        //if (pDcChargingInfo->Type == _Type_Chademo) {
                        //    BoardErrOccurByString(i, "023730");
                        //} else if (pDcChargingInfo->Type == _Type_CCS_2) {
                        //    BoardErrOccurByString(i, "013627");
                        //}
                        break;
                    }
                }
                break;

            case 27:
                for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

                    if (pDcChargingInfo->slotsIndex == 3) {
                    //    if (pDcChargingInfo->Type == _Type_Chademo) {
                    //        BoardErrOccurByString(i, "023730");
                    //    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
                    //        BoardErrOccurByString(i, "013627");
                    //    }
                        break;
                    }
                }
                break;
            }
        } else {
            switch (pinIn[i]) {
            // 小板解除緊急停止
            case 47:
                for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

                    if (pDcChargingInfo->slotsIndex == 1) {
                        if (pDcChargingInfo->Type == _Type_Chademo) {
                            ReleaseBoardErrOccurByString(i, "023730");
                       // } else if (pDcChargingInfo->Type == _Type_CCS_2) {
                       //     ReleaseBoardErrOccurByString(i, "013627");
                        }
                        break;
                    }
                }
                break;

            case 27:
                for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

                    if (pDcChargingInfo->slotsIndex == 3) {
                        if (pDcChargingInfo->Type == _Type_Chademo) {
                            ReleaseBoardErrOccurByString(i, "023730");
                        //} else if (pDcChargingInfo->Type == _Type_CCS_2) {
                        //    ReleaseBoardErrOccurByString(i, "013627");
                        }
                        break;
                    }
                }
                break;
            }
        }
    }
}

//===============================================
// Main process
//===============================================
// 檢查 uint8_t 中某個 Bit 的值
// _byte : 欲改變的 byte
// _bit : 該 byte 的第幾個 bit
uint8_t DetectBitValue(uint8_t _byte, uint8_t _bit)
{
    uint8_t mask_table[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

    return ( _byte & mask_table[_bit] ) != 0x00;
}

// 設定 Byte 中某個 Bit的值
// _byte : 欲改變的 byte
// _bit : 該 byte 的第幾個 bit
// value : 修改的值為 0 or 1
void SetBitValue(uint8_t *_byte, uint8_t _bit, uint8_t value)
{
    if (value == 1) {
        *_byte |= (1 << _bit);
    } else if (value == 0) {
        *_byte ^= (1 << _bit);
    }
}

uint8_t isModeChange(uint8_t gunIndex)
{
    uint8_t result = NO;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pDcChargingInfo->SystemStatus == pDcChargingInfo->PreviousSystemStatus) {
        return result;
    }

    pDcChargingInfo->PreviousSystemStatus = pDcChargingInfo->SystemStatus;
    ShmDcCommonData->SystemModeChange[gunIndex] = YES; //for Module_EvRxComm print temperature message

    return YES;
}

static int checkSlotGpioMappingGunType(uint8_t gunIndex, uint8_t gunType)
{
    uint8_t slot1 = 0, slot2 = 0;

    if (gunIndex == 0) {
        slot1 = bd0_1_status;
        slot2 = bd0_2_status;
    } else if (gunIndex == 1) {
        slot1 = bd1_1_status;
        slot2 = bd1_2_status;
    }

    log_info("slot %d gpio1 = %d, gpio2 = %d, type = %d",
             gunIndex,
             slot1,
             slot2,
             gunType);

    switch (gunType) {
    case _Type_Chademo:
        if (slot1 != NO && slot2 != YES) {
            return FAIL;
        }
        break;

    case _Type_CCS_2:
        if (slot1 != YES && slot2 != NO) {
            return FAIL;
        }
        break;

    case _Type_GB:
        if (slot1 != YES && slot2 != YES) {
            return FAIL;
        }
        break;
    }

    return PASS;
}

bool CheckConnectorTypeStatus(void)
{
    bool result = true;

    uint8_t gunIndex = 0;
    struct SysConfigData *pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
    struct ChargingInfoData *pDcChargingInfo = NULL;

    if (!MappingGunChargingInfo("CSU Task")) {
        log_error("CheckConnectorTypeStatus MappingGunChargingInfo failed");
        return false;
    }

    // 偵測槍屬於哪個 slot : 可知道插在板上的Slot 0 或 1 是 Chademo 還是 CCS
    for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

        if (checkSlotGpioMappingGunType(gunIndex, pDcChargingInfo->Type) == FAIL) {
            return false;
        }

		pDcChargingInfo->SystemStatus = S_BOOTING;
        switch (gunIndex) {
        case 0:
            if (pSysConfig->TotalConnectorCount == 1) {
                if ((bd0_1_status == YES || bd0_2_status == YES) &&
                        (bd1_1_status == NO && bd1_2_status == NO)) {
                    pDcChargingInfo->Evboard_id = 0x01;
                }

                if ((bd0_1_status == NO && bd0_2_status == NO) &&
                        (bd1_1_status == YES || bd1_2_status == YES)
                   ) {
                    pDcChargingInfo->Evboard_id = 0x02;
                }
                break;
            }

            pDcChargingInfo->Evboard_id = 0x01;
            break;

        case 1:
            pDcChargingInfo->Evboard_id = 0x02;
            break;
        }

        CheckHwSlotStatusLog(gunIndex);

        if (pDcChargingInfo->Evboard_id == 0x00) {
            return false;
        }
    }

    //AdjustChargerCurrent();

    return result;
}

int SpawnTask(void)
{
    if(SIMULATION)
        system("/root/simulation &");
    sleep(2);
    system("/root/Module_EventLogging &");
    system("/root/Module_PrimaryComm &");
    system("/root/Module_EvComm &");
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        system("/root/Module_LcmControl &");
    } else {
        system("/root/Module_LcmWistronControl &");
    }
    system("/root/Module_InternalComm &");
    system("/root/Module_ProduceUtils &");
    system("/root/Module_UpdateFW &");
    if (pSysConfig->ModelName[3] == 'P')
        system("/root/Module_DcMeter &");
    system("/root/Module_DoComm &");

    return PASS;
}

void KillTask(void)
{
    ChangeLcmByIndex(_LCM_FIX);

    system("killall Module_EventLogging");
    system("killall Module_PrimaryComm");
    system("killall Module_EvComm");
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        system("killall Module_LcmControl");
    } else {
        system("killall Module_LcmWistronControl");
    }
    system("killall Module_InternalComm");
    system("killall Module_UpdateFW");
    system("killall Module_ChkSysTask");
    if (pSysConfig->ModelName[3] == 'P')
        system("killall Module_DcMeter");
    //system("killall Module_DoComm");
    return ;

}

void KillTaskExceptPrimary(void)
{
    ChangeLcmByIndex(_LCM_FIX);

    system("killall Module_EvComm");
    system("killall Module_InternalComm");
    if (pSysConfig->ModelName[3] == 'P')
        system("killall Module_DcMeter");
#if defined DD360 || defined DD360Audi || defined DD360ComBox
    return;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

    system("killall Module_PsuComm");
    system("killall Module_4g &");
    system("killall Module_Wifi &");
}

void KillAllTask(void)
{
    ChangeLcmByIndex(_LCM_FIX);

    system("killall Module_EventLogging");
    system("killall Module_PrimaryComm");
    system("killall Module_EvComm");
    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
        system("killall Module_LcmControl");
    } else {
        system("killall Module_LcmWistronControl");
    }
    system("killall Module_InternalComm");
    system("killall Module_UpdateFW");
    system("killall Module_ChkSysTask");
    if (pSysConfig->ModelName[3] == 'P')
        system("killall Module_DcMeter");
#if defined DD360 || defined DD360Audi || defined DD360ComBox
    system("killall Module_DoComm");
    return ;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

    system("killall Module_PsuComm");
    system("killall OcppBackend &");
    system("killall Module_4g &");
    system("killall Module_Wifi &");
}

void StartSystemTimeoutDet(uint8_t flag)
{
    if (pSysInfo->SystemTimeoutFlag != flag) {
        GetClockTime(&pSysInfo->SystemTimeoutTimer);
       //log_info("Start System Timeout: %d",flag);
    }
    pSysInfo->SystemTimeoutFlag = flag;
}

void StopSystemTimeoutDet(void)
{
    GetClockTime(&pSysInfo->SystemTimeoutTimer);
    pSysInfo->SystemTimeoutFlag = Timeout_None;
}

void StartGunInfoTimeoutDet(uint8_t gunIndex, uint8_t flag)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (gunIndex < pSysConfig->TotalConnectorCount) {
        if (pDcChargingInfo->TimeoutFlag != flag) {
            GetClockTime(&pDcChargingInfo->ConnectorTimeout);
            //log_info("Start Gun%d Info timeout: %d",gunIndex,flag);
        }
        pDcChargingInfo->TimeoutFlag = flag;
    }
}
void checkLanguagePageTimeout(void)
{
    int is_idle = TRUE;
    for (int i = 0; i < pSysConfig->TotalConnectorCount; i++) {
        pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(i);
        if (pDcChargingInfo->SystemStatus != S_IDLE)
            is_idle = FALSE;
    }
    if (is_idle)
        pSysInfo->SystemPage = _PAGE_SELECTGUN;
    else
        pSysInfo->SystemPage = _PAGE_SELECT_PAY;
}
void StopGunInfoTimeoutDet(uint8_t gunIndex)
{

    if (gunIndex < pSysConfig->TotalConnectorCount) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
        pDcChargingInfo->TimeoutFlag = Timeout_None;
    }
}

void CheckConnectionTimeout(void)
{
#if defined DD360 || defined DD360Audi || defined DD360ComBox
    if (ShmSelectGunInfo->RemoteSetup.ConnectionTimeout != 0) { //Jerry add
        _connectionTimeout = ShmSelectGunInfo->RemoteSetup.ConnectionTimeout;
    } else {
        _connectionTimeout = CONN_PLUG_TIME_OUT;
    }

    return;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

    if (system("pidof -s OcppBackend > /dev/null") != 0) {
        _connectionTimeout = CONN_PLUG_TIME_OUT;
    } else {
        if (strcmp((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[ConnectionTimeOut].ItemData, "") != 0) {
            _connectionTimeout = atoi((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[ConnectionTimeOut].ItemData);
            if (_connectionTimeout <= 0) {
                _connectionTimeout = CONN_PLUG_TIME_OUT;
            }
        } else {
            _connectionTimeout = CONN_PLUG_TIME_OUT;
        }
    }
}
void _evccidlinktimeout(uint8_t gunIndex)
{
    log_info("Getting EVCCID Timeout");
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
    pDcChargingInfo->isEVCCIDVerify = true;
    StopGunInfoTimeoutDet(gunIndex);
    destroySelGun(pSysInfo->CurGunSelected);
    connectorPageRestoreIdle();
}
void CreateTimeoutFork(void)
{
    pid_t timeoutPid;

    timeoutPid = fork();
    if (timeoutPid == 0) {
        GetClockTime(&_cmdSubPriority_time);
        CheckConnectionTimeout();

        log_info("Timeout Fork Child's PID is %d", getpid());

        while (1) {
            if ((GetClockTimeoutValue(_cmdSubPriority_time) / 1000) > 5000) {
                CheckConnectionTimeout();
                GetClockTime(&_cmdSubPriority_time);
            }
            if ((GetClockTimeoutValue(ShmDcCommonData->_touch_time) / 1000) > 200) {
                ShmDcCommonData->isTouch = FALSE;
            }
            //log_info("Timeout ***********SystemTimeoutFlag = %d(%d) ********",pSysInfo->SystemTimeoutFlag,
            //        GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL);
            // 系統
            switch (pSysInfo->SystemTimeoutFlag) {
            case Timeout_SelftestChk:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= SELFTEST_TIMEOUT) {
                    _SelfTestTimeout();
                    StopSystemTimeoutDet();
                    destroySelGun(DESTROY_ALL_SEL); //jerry add
                }
                break;
            case Timeout_ShowStopPage:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= SHOW_STOP_TIMEOUT) {
                    log_error("Timeout_ShowStopPage");
                    StopSystemTimeoutDet();
                    pSysInfo->SystemPage = _PAGE_SELECTGUN;
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(pSysInfo->CurGunSelected);
                    if (pDcChargingInfo->SystemStatus == S_AUTHORIZING || pDcChargingInfo->SystemStatus == S_COMPLETE ||
                        pDcChargingInfo->SystemStatus == S_ALARM) {
                        setChargerMode(pSysInfo->CurGunSelected, MODE_IDLE);
                    }
                }
            	break;
            case Timeout_helpPage:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= HELP_PAGE_TIMEOUT) {
                    StopSystemTimeoutDet();
                    pSysInfo->SystemPage = ShmDcCommonData->previousPage;
                }
                break;
            case Timeout_SettingPage:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= SETTING_PAGE_TIMEOUT) {
                    StopSystemTimeoutDet();
                    //checkLanguagePageTimeout();
                    ShmDcCommonData->LcmPage = ShmDcCommonData->previousPage;
                }
                break;
            case Timeout_Authorizing:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= AUTHORIZE_TIMEOUT) {
                    log_error("Authorizing Timeout");
                    _AuthorizedTimeout();
                    StopSystemTimeoutDet();
                    destroySelGun(pSysInfo->CurGunSelected);
                    if (ShmSelectGunInfo->AuthorStateFromCabinet[pSysInfo->CurGunSelected] == YES) { //DoComm no ask cabinet balance
                        ShmSelectGunInfo->AuthorStateFromCabinet[pSysInfo->CurGunSelected] = NO;
                        pAlarmCode->AlarmEvents.bits.DisconnectedFromDo = ABNORMAL;
                        log_error("Author timeout restart DoComm");
                        system("killall Module_DoComm");
                        //sleep(1);
                        //system("/root/Module_DoComm &");
                    }
                }
                break;
            case Timeout_WaitBalance:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= BALANCE_TIMEOUT) {
                    log_error("Wait Balance timeout");
                    _AuthorizedTimeout();
                    StopSystemTimeoutDet();
                    destroySelGun(pSysInfo->CurGunSelected);
                    if (ShmSelectGunInfo->AuthorStateFromCabinet[pSysInfo->CurGunSelected] == YES) { //DoComm no ask cabinet balance
                        ShmSelectGunInfo->AuthorStateFromCabinet[pSysInfo->CurGunSelected] = NO;
                        pAlarmCode->AlarmEvents.bits.DisconnectedFromDo = ABNORMAL;
                        log_error("Author timeout restart DoComm");
                        system("killall Module_DoComm");
                    }
                }
                break;
            case Timeout_VerifyFail:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= AUTHORIZE_FAIL_TIMEOUT) {
                    _AutoReturnTimeout(pSysInfo->CurGunSelected);
                    StopSystemTimeoutDet();
                    destroySelGun(pSysInfo->CurGunSelected);
                    if (ShmSelectGunInfo->AuthorStateFromCabinet[pSysInfo->CurGunSelected] == YES) { //DoComm no ask cabinet balance
                        ShmSelectGunInfo->AuthorStateFromCabinet[pSysInfo->CurGunSelected] = NO;
                        pAlarmCode->AlarmEvents.bits.DisconnectedFromDo = ABNORMAL;
                        log_error("Author timeout restart DoComm");
                        system("killall Module_DoComm");
                        //sleep(1);
                        //system("/root/Module_DoComm &");
                    }
                }
                break;

            case Timeout_VerifyComp:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= AUTHORIZE_COMP_TIMEOUT) {
                    _AutoReturnTimeout(pSysInfo->CurGunSelected);
                    StopSystemTimeoutDet();
                }
                break;

            case Timeout_ReturnToChargingGunDet:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= RETURN_TO_CHARGING_PAGE) {
#if defined DD360Audi
                    if (getCurLcmPage() != _LCM_PRE_CHARGE &&
                            getCurLcmPage() != _LCM_CHARGING &&
                            getCurLcmPage() != _LCM_COMPLETE) {
                        destroySelGun(pSysInfo->CurGunSelected); //jerry add

                    }
#endif //defined DD360Audi
                    DisplayChargingInfo();
                    StopSystemTimeoutDet();
                }
                break;

            case Timeout_AuthorizingForStop:
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= AUTHORIZE_STOP_TIMEOUT) {
                    strcpy((char *)pSysConfig->UserId, "");
                    ClearAuthorizedFlag();
                    StopSystemTimeoutDet();
                }
                break;

            case Timeout_SelectGun: //Jerry add
                if (GetClockTimeoutValue(pSysInfo->SystemTimeoutTimer) / uSEC_VAL >= SEL_GUN_TIMEOUT) {
                    log_info("Timeout_SelectGun");
                    ShmDcCommonData->LcmPage = _PAGE_SELECTGUN;
                    StopSystemTimeoutDet();
                }
                break;
            }
            // 各槍
            for (uint8_t gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
                pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
                
                //log_info("Timeout ***********Gun %d TimeoutFlag = %d(%d) ********",gunIndex,pDcChargingInfo->TimeoutFlag,
                //    GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL);

                switch (pDcChargingInfo->TimeoutFlag) {
                case Timeout_EVCCID_Link:
                if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= EVCCID_LINK_TIMEOUT) {
                    _evccidlinktimeout(gunIndex);

                }
                break;

                case Timeout_WaitPlug:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= _connectionTimeout) {
                        log_info("*********** Gun%d _DetectPlugInTimeout *********** ", gunIndex);
                        _DetectPlugInTimeout(gunIndex);
                        StopGunInfoTimeoutDet(gunIndex);

                    }
                    break;
                case Timeout_Preparing:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= GUN_PREPARE_TIMEOUT) {
                        _PrepareTimeout(gunIndex);
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);
                    }
                    break;

                case Timeout_EvChargingDet:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= GUN_EV_WAIT_TIMEOUT) {
                        _DetectEvChargingEnableTimeout(gunIndex);
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);
                    }
                    break;

                case Timeout_EvseChargingDet:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= GUN_EVSE_WAIT_TIMEOUT) {
                        _DetectEvseChargingEnableTimeout(gunIndex);
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);
                    }
                    break;

                case Timeout_EvseCompleteDet:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= GUN_COMP_WAIT_TIMEOUT) {
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);
                    }
                    break;

                case Timeout_ForCcsPrechargeDet:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= GUN_PRECHARGING_TIMEOUT) {
                        _CcsPrechargeTimeout(gunIndex);
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);
                    }
                    break;
                case Timeout_ShowPlugFail:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= SHOW_PLUG_FAIL_TIMEOUT) {
                        log_info("Timeout_ShowPlugFail");
                        if (gunIndex == pSysInfo->CurGunSelected)
                            ShmDcCommonData->LcmPage = _PAGE_SELECTGUN;
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);
                    }
                    break;
                case Timeout_ExitComplete:
                    if (GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) / uSEC_VAL >= EXIT_COMPLETE_TIMEOUT) {
                        log_info("Timeout_ExitComplete");
                        if (ShmDcCommonData->pGunInfo[gunIndex].ReservationStatus) {
                            setChargerMode(gunIndex, MODE_RESERVATION);
                        } else {
                            setChargerMode(gunIndex, MODE_IDLE);
                        }
                        StopGunInfoTimeoutDet(gunIndex);
                        destroySelGun(gunIndex);

#if defined DD360 || defined DD3660ComBox
                        if (gunIndex == pSysInfo->CurGunSelected)
                            connectorPageRestoreIdle();
#endif
                    }
                    break;
                }
            }
            sleep(1);
        }
    }
}

void CheckFactoryConfigFunction(void)
{
    char Buf[256] = {0};

    if (pSysInfo->FactoryConfiguration) {
        sprintf(Buf, "cd /root;./FactoryConfig -m %s %s",
                pSysConfig->ModelName,
                pSysConfig->SerialNumber);
        system(Buf);

        system("rm -f /Storage/OCPP/OCPPConfiguration");
        system("sync");
        sleep(5);
        system("reboot -f");
        sleep(5);
        system("reboot -f");
    }
}

//===============================================
// Check reservation date is expired
//===============================================
int isReservationExpired(uint8_t gunIndex)
{
    int result = NO;
    struct tm expiredDate;
    struct timeb expiredTime;

    if (sscanf((char *) ShmOCPP16Data->ReserveNow[gunIndex].ExpiryDate,
               "%4d-%2d-%2dT%2d:%2d:%2d", &expiredDate.tm_year,
               &expiredDate.tm_mon, &expiredDate.tm_mday, &expiredDate.tm_hour,
               &expiredDate.tm_min, &expiredDate.tm_sec) == 6) {
        expiredDate.tm_year -= 1900;
        expiredDate.tm_mon -= 1;

        expiredTime.time = mktime(&expiredDate);
        if (!CheckTimeOut(expiredTime)) {
            result = YES;
        }
    }

    return result;
}

//===============================================
// OCPP
//===============================================
void CheckOcppStatus(void)
{
    bool canReset = true;
    //bool canHardReset = true; //DS60-120 add

    if (ShmOCPP16Data->SpMsg.bits.BootNotificationConf == YES) {
        ShmOCPP16Data->SpMsg.bits.BootNotificationConf = NO;
    }

    if (ShmOCPP16Data->MsMsg.bits.ResetReq == YES) {
        if (pSysWarning->Level != WARN_LV_ER) {
            for (uint8_t _index = 0; _index < pSysConfig->TotalConnectorCount; _index++) {
                pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(_index);

                if (pDcChargingInfo->SystemStatus != S_IDLE &&
                        pDcChargingInfo->SystemStatus != S_RESERVATION &&
                        pDcChargingInfo->SystemStatus != S_MAINTAIN) {
                    canReset = false;
                    if (pDcChargingInfo->SystemStatus >= S_REASSIGN &&
                            pDcChargingInfo->SystemStatus < S_TERMINATING) {
                        //canHardReset = false;
                        ChargingTerminalProcess(_index);
                        //restartFlag = 1;
                    }
                }
            }
        }

        if (canReset) {
            ShmOCPP16Data->MsMsg.bits.ResetReq = NO;
            sprintf((char *)ShmOCPP16Data->Reset.ResponseStatus, "Accepted");
            if (strcmp((char *)ShmOCPP16Data->Reset.Type, "Hard") == EQUAL) {
                log_error("****** Hard Reboot ****** ");
                ShmOCPP16Data->MsMsg.bits.ResetConf = YES;
                sleep(3);
                system("reboot -f");
            } else if (strcmp((char *)ShmOCPP16Data->Reset.Type, "Soft") == EQUAL) {
                log_error("****** Soft Reboot ****** ");
                ShmOCPP16Data->MsMsg.bits.ResetConf = YES;
                sleep(3);
                system("killall OcppBackend &");
                KillAllTask();
                TryCloseWatchdog();
                system("/usr/bin/run_evse_restart.sh");
            }
        }
    }
}

void OcppStartTransation(uint8_t gunIndex)
{
#if defined DD360 || defined DD360Audi || defined DD360ComBox
    return;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

    uint8_t _OcppGunIndex = gunIndex;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    // 如果有 AC 槍,而現在是 DC 第二把槍進入充電
    if (pSysConfig->AcConnectorCount == 1 && gunIndex == 1) {
        _OcppGunIndex = 2;
    }

    if (strcmp((char *)pDcChargingInfo->StartUserId, "") == EQUAL) {
        strcpy((char *)ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag,
               (char *)ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag);
    } else {
        strcpy((char *)ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag,
               (char *)pDcChargingInfo->StartUserId);
    }

    log_info("IdTag = %s ", ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag);

    ShmOCPP16Data->CpMsg.bits[_OcppGunIndex].StartTransactionReq = YES;
}

void OcppStopTransation(uint8_t gunIndex)
{
    uint8_t _OcppGunIndex = gunIndex;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    // 如果有 AC 槍,而現在是 DC 第二把槍進入充電
    if (pSysConfig->AcConnectorCount == 1 && gunIndex == 1) {
        _OcppGunIndex = 2;
    }

    if (strcmp((char *)pDcChargingInfo->StartUserId, "") == EQUAL) {
        strcpy((char *)ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag, (char *)ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag);
    } else {
        strcpy((char *)ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag, (char *)pDcChargingInfo->StartUserId);
    }

    log_info("IdTag = %s ", ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag);
    ShmOCPP16Data->CpMsg.bits[_OcppGunIndex].StopTransactionReq = YES;
}

bool OcppRemoteStop(uint8_t gunIndex)
{
    uint8_t acDirIndex = pSysConfig->AcConnectorCount;

    // 有 AC 槍的話
    if (acDirIndex > 0 && gunIndex > 0) {
        gunIndex += acDirIndex;
    }

    bool result = ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStopTransactionReq;

    if (ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStopTransactionReq == YES) {
        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "Remote");
        ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStopTransactionReq = NO;
    }

    return result;
}

bool WifiScheduleStop(uint8_t gunIndex)
{
    bool result = false;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    result = pDcChargingInfo->schedule.isTriggerStop;
    pDcChargingInfo->schedule.isTriggerStop = NO;

    return result;
}

void OcppRemoteStartChk()
{
    if (pSysConfig->OfflinePolicy == _OFFLINE_POLICY_NO_CHARGING) {

    } else{
        // 如果有 AC 槍,則固定是第 2 把槍,所以索引固定為 1
        uint8_t acDirIndex = pSysConfig->AcConnectorCount;

        for (uint8_t ac_index = 0; ac_index < pSysConfig->AcConnectorCount; ac_index++) {
            pAcChargingInfo = (struct ChargingInfoData *)GetAcChargingInfoData(ac_index);
            if (!isDetectPlugin(acDirIndex)) {
                if (ShmOCPP16Data->CsMsg.bits[acDirIndex].RemoteStartTransactionReq == YES) {
                    if (pAcChargingInfo->SystemStatus == S_IDLE ||
                        pAcChargingInfo->SystemStatus == S_RESERVATION) {
                        ShmOCPP16Data->CsMsg.bits[acDirIndex].RemoteStartTransactionReq = NO;
                        pAcChargingInfo->RemoteStartFlag = YES;
                        pSysInfo->OrderCharging = YES;
                        //pSysInfo->OrderCharging = DEFAULT_AC_INDEX;
                        ShmOCPP16Data->CsMsg.bits[pSysConfig->TotalConnectorCount + ac_index].RemoteStartTransactionReq = NO;
                        DetectPluginStart(acDirIndex);
                        return;
                    }
                    ShmOCPP16Data->CsMsg.bits[acDirIndex].RemoteStartTransactionReq = NO;
                }
            }
        }

        for (uint8_t _index = 0; _index < pSysConfig->TotalConnectorCount; _index++) {
            pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(_index);

            if (ShmOCPP16Data->CsMsg.bits[_index].RemoteStartTransactionReq == YES) {
                if (pDcChargingInfo->SystemStatus == S_IDLE ||
                    pDcChargingInfo->SystemStatus == S_RESERVATION) {
                    pDcChargingInfo->RemoteStartFlag = YES;
                    pSysInfo->OrderCharging = YES;
                    //pSysInfo->OrderCharging = gunIndex;
                    ShmOCPP16Data->CsMsg.bits[_index].RemoteStartTransactionReq = NO;
                    DetectPluginStart(_index);
                    if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
                        setSelGunWaitToAuthor(_index);
                    }
                }
                ShmOCPP16Data->CsMsg.bits[_index].RemoteStartTransactionReq = NO;
            }
        }
    }
}

void ChkOcppStatus(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pDcChargingInfo->SystemStatus == S_IDLE &&
            ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowReq == YES) {
        ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowReq = NO;
        if (isReservationExpired(gunIndex)) {
            log_info("***************ChkOcppStatus : OcppReservedStatus******************** ");
            //log_error("***************ChkOcppStatus : OcppReservedStatus******************** ");
            pDcChargingInfo->ReservationId = ShmOCPP16Data->ReserveNow[gunIndex].ReservationId;
            pDcChargingInfo->SystemStatus = S_RESERVATION;
        }
        ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowConf = YES;
    }

    if (pDcChargingInfo->SystemStatus == S_RESERVATION &&
            ShmOCPP16Data->CsMsg.bits[gunIndex].CancelReservationReq == YES) {
        ShmOCPP16Data->CsMsg.bits[gunIndex].CancelReservationReq = NO;
        if (isReservationExpired(gunIndex)) {
            log_info("***************ChkOcppStatus : Cancel OcppReservedStatus******************** ");
            //log_error("***************ChkOcppStatus : Cancel OcppReservedStatus******************** ");
            pDcChargingInfo->ReservationId = 0;
            pDcChargingInfo->SystemStatus = S_IDLE;
        }
        ShmOCPP16Data->CsMsg.bits[gunIndex].CancelReservationConf = YES;
    }

    if (ShmOCPP16Data->CsMsg.bits[gunIndex].ChangeAvailabilityReq == YES) {
        log_info("***************ChkOcppStatus : OcppChangeAvailability******************** ");
        //log_error("***************ChkOcppStatus : OcppChangeAvailability******************** ");
        ShmOCPP16Data->CsMsg.bits[gunIndex].ChangeAvailabilityReq = NO;
        if (strcmp((char *)ShmOCPP16Data->ChangeAvailability[gunIndex].Type, "Operative") == EQUAL) {
            if (isDb_ready) {
                DB_Update_Operactive(gunIndex, true);
            }

            pDcChargingInfo->IsAvailable = YES;
            if (pDcChargingInfo->SystemStatus == S_IDLE ||
                    pDcChargingInfo->SystemStatus == S_RESERVATION ||
                    pDcChargingInfo->SystemStatus == S_MAINTAIN) {
                setChargerMode(gunIndex, MODE_IDLE);
            }
        } else if (strcmp((char *)ShmOCPP16Data->ChangeAvailability[gunIndex].Type, "Inoperative") == EQUAL) {
            if (isDb_ready) {
                DB_Update_Operactive(gunIndex, false);
            }

            pDcChargingInfo->IsAvailable = NO;
            if (pDcChargingInfo->SystemStatus == S_IDLE ||
                    pDcChargingInfo->SystemStatus == S_RESERVATION ||
                    pDcChargingInfo->SystemStatus == S_MAINTAIN) {
                setChargerMode(gunIndex, MODE_MAINTAIN);
            }
        }
    }

    if (ShmOCPP16Data->CsMsg.bits[gunIndex].UnlockConnectorReq == YES) {
        ShmOCPP16Data->CsMsg.bits[gunIndex].UnlockConnectorReq = NO;
        if (pDcChargingInfo->SystemStatus >= S_REASSIGN_CHECK && // DS60-120 add ||
                pDcChargingInfo->SystemStatus <= S_CHARGING) {
            // 充電中,需停止充電
            strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "UnlockCommand");
            ChargingTerminalProcess(gunIndex);
        }
        strcpy((char *)ShmOCPP16Data->UnlockConnector[gunIndex].ResponseStatus, "Unlocked");
        ShmOCPP16Data->CsMsg.bits[gunIndex].UnlockConnectorConf = YES;
    }
}

bool CheckBackendChargingTimeout(uint8_t gunIndex)
{
    bool result = false;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pSysConfig->AuthorisationMode == AUTH_MODE_ENABLE) {
        if (pSysConfig->MaxChargingDuration > 0) {
            if (pDcChargingInfo->PresentChargedDuration > (pSysConfig->MaxChargingDuration * 60)) {
                result = true;
            }
        }
    } /*else if (pSysConfig->AuthorisationMode == AUTH_MODE_DISABLE) {
        // 隨插即充電的要看 offline
        if (pSysConfig->OfflineMaxChargeDuration > 0) {
            if (pDcChargingInfo->PresentChargedDuration > (pSysConfig->OfflineMaxChargeDuration * 60)) {
                result = true;
            }
        }
    }*/

    return result;
}

bool CheckBackendChargingEnergy(uint8_t gunIndex)
{
    bool result = false;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pSysConfig->AuthorisationMode == AUTH_MODE_ENABLE) {
        if (pSysConfig->MaxChargingEnergy > 0) {
            if (pDcChargingInfo->PresentChargedEnergy > pSysConfig->MaxChargingEnergy) {
                result = true;
            }
        }
    }/* else if (pSysConfig->AuthorisationMode == AUTH_MODE_DISABLE) {
        // 隨插即充電的要看 offline
        if (pSysConfig->OfflineMaxChargeEnergy > 0) {
            if (pDcChargingInfo->PresentChargedEnergy > (pSysConfig->OfflineMaxChargeEnergy)) {
                result = true;
            }
        }
    }*/

    return result;
}

void InformOcppErrOccur(uint8_t codeType)
{
    char _error[25];

    switch (codeType) {
    case 4:
        strcpy(_error, "InternalError");
        break;

    case 6:
        strcpy(_error, "NoError");
        break;

    case 7:
        strcpy(_error, "OtherError");
        break;

    case 13:
        strcpy(_error, "UnderVoltage");
        break;

    case 14:
        strcpy(_error, "OverVoltage");
        break;
    }

    for (uint8_t gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
        strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].ErrorCode, _error);
    }
}

//===============================================
// Config process
//===============================================
void AddPlugInTimes(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if (pDcChargingInfo->Type == _Type_Chademo) {
        pSysConfig->ChademoPlugInTimes += 1;
    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
        pSysConfig->Ccs2PlugInTimes += 1;
    } else if (pDcChargingInfo->Type == _Type_GB) {
        pSysConfig->GbPlugInTimes += 1;
    }
}

void ChangeStartOrStopDateTime(uint8_t isStart, uint8_t gunIndex)
{
    char cmdBuf[32];
    struct timeb csuTime;
    struct tm *tmCSU;
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    ftime(&csuTime);
    tmCSU = localtime(&csuTime.time);

    sprintf(cmdBuf, "%04d-%02d-%02d %02d:%02d:%02d", tmCSU->tm_year + 1900,
            tmCSU->tm_mon + 1, tmCSU->tm_mday, tmCSU->tm_hour, tmCSU->tm_min,
            tmCSU->tm_sec);
    if (isStart) {
        strcpy((char *)pDcChargingInfo->StartDateTime, cmdBuf);
    } else {
        strcpy((char *)pDcChargingInfo->StopDateTime, cmdBuf);
    }
}

void ChangeGunSelectByIndex(uint8_t sel)
{
    pSysInfo->CurGunSelected = sel;
    pSysInfo->CurGunSelectedByAc = NO_DEFINE;
}

void CheckIsAlternatvieByModelName()
{
    // 黑白機 ?
    /*if (strcmp((char *)pSysConfig->ModelName, "DWWU301J0UT1PH") == EQUAL ||
            strcmp((char *)pSysConfig->ModelName, "DWYE301J0ET1PH") == EQUAL ||
            strcmp((char *)pSysConfig->ModelName, "DSYE301J3EW2PH") == EQUAL ||
            strcmp((char *)pSysConfig->ModelName, "DWYC301J0UW1PH") == EQUAL) {
      */
    if (pSysConfig->ModelName[1] == 'W') { //DS60-120
        // 壁掛
        pSysInfo->IsAlternatvieConf = YES;
    } else {
        pSysInfo->IsAlternatvieConf = NO;
    }
}

void StopProcessingLoop()
{
    for (;;) {
        CheckFactoryConfigFunction();
        //CheckFwUpdateFunction();
        if (pSysWarning->Level == WARN_LV_ER) {
            ChkPrimaryStatus();
            if (pSysWarning->Level == WARN_LV_NL) {
                log_info("Soft reboot for retry self-tets (Primary). ");
                KillAllTask();
                sleep(3);
                TryCloseWatchdog();
                system("/usr/bin/run_evse_restart.sh");
                return;
            }
        }
        sleep(1);
        TryFeedWatchdog();
    }
}

bool IsConnectorWholeIdle()
{
    bool result = true;

    for (uint8_t count = 0; count < pSysConfig->TotalConnectorCount; count++) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(count);

        if (pDcChargingInfo->SystemStatus != S_IDLE &&
                pDcChargingInfo->SystemStatus != S_RESERVATION) {
            result = false;
            break;
        }
    }

    for (uint8_t count = 0; count < pSysConfig->AcConnectorCount; count++) {
        pAcChargingInfo = (struct ChargingInfoData *)GetAcChargingInfoData(count);

        if (pAcChargingInfo->SystemStatus != S_IDLE &&
                pAcChargingInfo->IsErrorOccur == NO) {
            result = false;
            break;
        }
    }

    return result;
}

void ClearAlarmCodeWhenAcOff()
{
    if (!pSysInfo->AcContactorStatus) {
        pAlarmCode->AlarmEvents.bits.PsuNoResource = NO;
    }
}

//==========================================
// Check task processing
//==========================================
void CheckTask()
{
    /*+++ 20200908, vern, disable it for DD360 +++*/
#if 0
    if (pSysConfig->ModelName[10] == 'T') {
        if (system("pidof -s Module_4g > /dev/null") != 0) {
            log_error("Module_4g not running, restart it.");
            system("/root/Module_4g &");
        }
    } else if (pSysConfig->ModelName[10] == 'W') {
        if (system("pidof -s Module_Wifi > /dev/null") != 0) {
            log_error("Module_Wifi not running, restart it.");
            system("/root/Module_Wifi &");
        }
    }

    if (strcmp((char *)pSysConfig->OcppServerURL, "") != EQUAL &&
            strcmp((char *)pSysConfig->ChargeBoxId, "") != EQUAL) {
        if (system("pidof -s OcppBackend > /dev/null") != 0) {
            log_error("OcppBackend not running, restart it.");
            system("/root/OcppBackend &");
        }
    }
#endif //0

    /*--- 20200908, vern, disable it for DD360 ---*/
    /*
    if (system("pidof -s Module_ProduceUtils > /dev/null") != 0) {
        log_error("Module_ProduceUtils not running, restart it.");
        system ("/root/Module_ProduceUtils &");
    }*/
}

//==========================================
// Check Smart Charging Profile
//==========================================
int GetStartScheduleTime(uint8_t *time)
{
    int result = -1;
    struct tm tmScheduleStart;
    struct timeb tbScheduleStart;

    if ((sscanf((char *)time, "%4d-%2d-%2dT%2d:%2d:%2d", &tmScheduleStart.tm_year, &tmScheduleStart.tm_mon, &tmScheduleStart.tm_mday, &tmScheduleStart.tm_hour, &tmScheduleStart.tm_min, &tmScheduleStart.tm_sec) == 6)) {
        tmScheduleStart.tm_year -= 1900;
        tmScheduleStart.tm_mon -= 1;
        tbScheduleStart.time = mktime(&tmScheduleStart);
        tbScheduleStart.millitm = 0;

        result = DiffTimebWithNow(tbScheduleStart) / 1000;
    }

    return result;
}

void CheckSmartChargeProfile(uint8_t _index)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(_index);

    if (ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf == YES) {
        // Get Charging Profile
        ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf = NO;
        if (strcmp((char *)ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileKind, "Absolute") == EQUAL &&
                ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileId == YES //DS60-120 add
           ) {
            int _time = GetStartScheduleTime(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.StartSchedule);
            uint8_t _startCount = NO_DEFINE;
            uint8_t _maxCount = ARRAY_SIZE(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod);

            for (uint8_t _count = 0; _count < _maxCount; _count++) {
                // 預設最小輸出電流 (MIN_OUTPUT_CUR) A
                if (_time >= ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].StartPeriod) {
                    if ((_count == 0 && ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit >= MIN_OUTPUT_CUR) ||
                            ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit > MIN_OUTPUT_CUR) {
                        _startCount = _count;
                    }
                }
            }

            log_info("_startCount = %d ", _startCount);
            if (_startCount < _maxCount) {
                //DS60-120 add
                log_info("Profile Limit = %f ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit);
                pDcChargingInfo->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * AC_OUTPUT_VOL;
                if (pDcChargingInfo->EvBatterytargetVoltage > 0 && pDcChargingInfo->PresentChargingVoltage > 0) {
                    pDcChargingInfo->ChargingProfileCurrent = (pDcChargingInfo->ChargingProfilePower / pDcChargingInfo->PresentChargingVoltage) * 10;
                } else {
                    pDcChargingInfo->ChargingProfileCurrent = 0;
                }

                //DS60-120 remove
                //log_info("*********Limit = %f ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit);
                //pDcChargingInfo->ChargingProfileCurrent = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * 10;
                //pDcChargingInfo->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * pDcChargingInfo->EvBatterytargetVoltage / 100;

                //pDcChargingInfo->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * AC_OUTPUT_VOL;
//              if ((pDcChargingInfo->EvBatterytargetVoltage * 10) > 0)
//              {
//                  pDcChargingInfo->ChargingProfileCurrent = pDcChargingInfo->ChargingProfilePower / (pDcChargingInfo->EvBatterytargetVoltage * 10);
//              }
            } else {
                pDcChargingInfo->ChargingProfilePower = -1;
                pDcChargingInfo->ChargingProfileCurrent = -1;
            }
        } else {
            pDcChargingInfo->ChargingProfilePower = -1;
            pDcChargingInfo->ChargingProfileCurrent = -1;
        }

        log_info("ChargingProfilePower = %f ", pDcChargingInfo->ChargingProfilePower);
        log_info("ChargingProfileCurrent = %f ", pDcChargingInfo->ChargingProfileCurrent);
    }
//
//      printf("-------------Schedule------------");
//      printf("index = %d ", _index);
//      printf("StartSchedule = %s ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.StartSchedule);
//      printf("ChargingRateUnit = %s ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingRateUnit);
//      printf("----------SchedulePeriod---------");
//      for (int v = 0; v < 10; v++)
//      {
//          printf("StartPeriod = %d ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[v].StartPeriod);
//          printf("Limit = %f ", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[v].Limit);
//      }
//      printf("---------------------------------");
}

void ChargingProfileFlat(uint8_t _index)
{
    if (ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf == NO) {
        if (ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileReq == NO) {
            ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileReq = YES;
        }
    }
}

void CheckReturnToChargingConn()
{
    if ((pSysConfig->TotalConnectorCount + pSysConfig->AcConnectorCount) > 1 &&
            pSysInfo->SystemPage != _LCM_AUTHORIZING &&
            pSysInfo->SystemPage != _LCM_AUTHORIZ_FAIL &&
            pSysInfo->SystemPage != _LCM_AUTHORIZ_COMP &&
            pSysInfo->SystemPage != _LCM_WAIT_FOR_PLUG) {
        bool isReturnTimeout = false;

        for (uint8_t count = 0; count < pSysConfig->TotalConnectorCount; count++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(count);

            // 如果選的 DC 槍在充電~ 則 DC 槍不改變
            if (count == pSysInfo->CurGunSelected) {
                if ((pDcChargingInfo->SystemStatus >= S_REASSIGN_CHECK &&
                        pDcChargingInfo->SystemStatus <= S_COMPLETE) ||
                        (pDcChargingInfo->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                         pDcChargingInfo->SystemStatus <= S_CCS_PRECHARGE_ST1)
                   ) {
                    isReturnTimeout = false;
                    break;
                }
            } else if (count != pSysInfo->CurGunSelected) {
                if ((pDcChargingInfo->SystemStatus >= S_REASSIGN_CHECK &&
                        pDcChargingInfo->SystemStatus <= S_COMPLETE) ||
                        (pDcChargingInfo->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                         pDcChargingInfo->SystemStatus <= S_CCS_PRECHARGE_ST1)
                   ) {
                    isReturnTimeout = true;
                    StartSystemTimeoutDet(Timeout_ReturnToChargingGunDet);
                }
            }
        }
        if (CheckDispenserGeneration() >= _DISPENSER_GENERATION_3_5) {
            if (!isReturnTimeout && 
                (ShmDcCommonData->LcmPage != _PAGE_SELECT_PAY && ShmDcCommonData->LcmPage != _PAGE_LANGUAGE &&
                ShmDcCommonData->LcmPage != _PAGE_SETTING && ShmDcCommonData->LcmPage != _PAGE_BACKLIGHT)) {
                StopSystemTimeoutDet();
            }
        } else {
            if (!isReturnTimeout) {
                StopSystemTimeoutDet();
            }
        }
    }
}

bool GetStartChargingByAlterMode(uint8_t _gun)
{
    bool result = true;

    if (pSysConfig->TotalConnectorCount == 2 &&
            pSysInfo->IsAlternatvieConf == YES) {
        for (uint8_t _select = 0; _select < pSysConfig->TotalConnectorCount; _select++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(_select);

            if (_select != _gun) {
                if (pDcChargingInfo->SystemStatus != S_IDLE &&
                        pDcChargingInfo->SystemStatus != S_RESERVATION) {
                    result = false;
                    break;
                }
            }
        }
    }

    return result;
}

void TheEndCharging(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    ftime(&endChargingTime[gunIndex]);

    if (pDcChargingInfo->PresentChargedDuration != 0) {
        pDcChargingInfo->PresentChargedDuration = DiffTimeb(startChargingTime[gunIndex], endChargingTime[gunIndex]);
    }

    pDcChargingInfo->isRemoteStart = NO;

    StopGunInfoTimeoutDet(gunIndex);
    StartGunInfoTimeoutDet(gunIndex, Timeout_EvseCompleteDet);
    ChangeStartOrStopDateTime(NO, gunIndex);
    DB_Insert_Record(gunIndex);
}

void UpdateErrorCodeToOcpp(uint8_t index)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);

    //log_info("%d = ConnectorAlarmCode = %s", index, pDcChargingInfo->ConnectorAlarmCode);
    //log_info("%d = EvConnAlarmCode = %s", index, pDcChargingInfo->EvConnAlarmCode);
    if (strcmp((char *)pDcChargingInfo->ConnectorAlarmCode, "") != EQUAL) {
        //if (strlen((char *)pDcChargingInfo->ConnectorAlarmCode) == EQUAL) {
        strcpy((char *)ShmOCPP16Data->StatusNotification[index].ErrorCode, "InternalError");
        strcpy((char *)ShmOCPP16Data->StatusNotification[index].VendorErrorCode, (char *)pDcChargingInfo->ConnectorAlarmCode);
    } else if (strcmp((char *)pDcChargingInfo->EvConnAlarmCode, "") != EQUAL) {
        //} else if (strlen((char *)pDcChargingInfo->EvConnAlarmCode) == EQUAL) {
        strcpy((char *)ShmOCPP16Data->StatusNotification[index].ErrorCode, "OtherError");
        strcpy((char *)ShmOCPP16Data->StatusNotification[index].VendorErrorCode, (char *)pDcChargingInfo->EvConnAlarmCode);
    }

    //log_info("Gun %d = VendorErrorCode = %s", index, (char *)ShmOCPP16Data->StatusNotification[index].VendorErrorCode);
}

void AdjustChargerCurrent()
{
    pSysConfig->RatingCurrent = ShmPsuData->SystemAvailableCurrent / 10;

    // 設定的電流~ 如超過可輸出的電流,則 bypass
    if (pSysConfig->RatingCurrent < pSysConfig->MaxChargingCurrent ||
            pSysConfig->RatingCurrent == 0) {
        pSysConfig->MaxChargingCurrent = 0;
    }

    log_info("PSU : MaxChargingPower = %d, MaxChargingCurrent = %d",
             ShmPsuData->SystemAvailablePower / 10,
             ShmPsuData->SystemAvailableCurrent / 10
            );

    log_info("Config : ChargingPower = %d, ChargingCurrent = %d",
             pSysConfig->MaxChargingPower,
             pSysConfig->MaxChargingCurrent
            );
}

void ResetDetAlarmStatus(uint8_t gun)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gun);

    if (pDcChargingInfo->Type == _Type_Chademo) {
        if (pAlarmCode->AlarmEvents.bits.SystemChademoOutputOVP == YES) {
            pAlarmCode->AlarmEvents.bits.SystemChademoOutputOVP = NO;
        }
    } else if (pDcChargingInfo->Type == _Type_GB) {
        if (pAlarmCode->AlarmEvents.bits.SystemGbOutputOVP == YES) {
            pAlarmCode->AlarmEvents.bits.SystemGbOutputOVP = NO;
        }
    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
        if (pAlarmCode->AlarmEvents.bits.SystemCcsOutputOVP == YES) {
            pAlarmCode->AlarmEvents.bits.SystemCcsOutputOVP = NO;
        }
    }
}
char OldUseId[32] = {0};
static void autoStartCharging(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    if ( (pSysInfo->SystemPage >= _LCM_AUTHORIZING && pSysInfo->SystemPage <= _LCM_AUTHORIZ_FAIL) ||
        pDcChargingInfo->isEVCCIDVerify || (strcmp( (char *)pSysConfig->UserId , "" ) != EQUAL)) {
            return;
    }

    if ((pDcChargingInfo->ConnectorPlugIn == YES) &&
            (pDcChargingInfo->SystemStatus == S_IDLE ) 
       ) {
        if(!pSysConfig->AuthorisationMode) {
            if (pSysConfig->isAuthrizeByEVCCID && !pDcChargingInfo->isEVCCIDVerify &&
                    pDcChargingInfo->Type == _Type_CCS_2)  {
#ifdef DD360Audi                
                // LCM show linking pic. & timeout 2 min
                if( pSysInfo->CurGunSelected == gunIndex ) {
                    systemPageRestoreInit();
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
                StartGunInfoTimeoutDet(gunIndex,Timeout_EVCCID_Link);
#endif                
                // Getting EVCCID
                if( strcmp( (char *)pDcChargingInfo->EVCCID, "" ) != EQUAL ) {
                    log_info("Authorizing EVCCID");
                    StopSystemTimeoutDet();
                    ShmDcCommonData->LcmPage = _PAGE_SELECT_PAY;
                    strcpy((char *)pSysConfig->UserId, (char *)pDcChargingInfo->EVCCID);
                    pSysInfo->CurGunSelected = gunIndex;
                    ChangeGunSelectByIndex(gunIndex);
                    confirmSelGun(gunIndex);
                    pDcChargingInfo->isEVCCIDVerify = true;
                    ShmDcCommonData->AuthroizeType = IdTokenType_MacAddress;
                    //pSysInfo->SystemPage = _LCM_AUTHORIZING;
                    pDcChargingInfo->StartMethod = _CHARGING_START_EVCCID;
                }
            } else
                return;
        } else {
            ShmDcCommonData->LcmPage = _PAGE_SELECT_PAY;
            strcpy((char *)&pSysConfig->UserId, "AutoStartCharging");
            pSysInfo->CurGunSelected = gunIndex;
            ChangeGunSelectByIndex(gunIndex);
            confirmSelGun(gunIndex);
            //pSysInfo->SystemPage = _LCM_AUTHORIZING;
            ShmDcCommonData->AuthroizeType = IdTokenType_NoAuthorization;
            pDcChargingInfo->StartMethod = _CHARGING_START_AUTOSTART;
        }
        if (strcmp( (char *)pSysConfig->UserId , OldUseId ) != EQUAL) {
            strcpy((char *)OldUseId, (char *)pSysConfig->UserId);
            log_info("Get User(%d) ID:%s",gunIndex,pSysConfig->UserId);
        }
    }else if (pDcChargingInfo->ConnectorPlugIn == NO && pDcChargingInfo->Type == _Type_CCS_2) {
        strcpy((char *)OldUseId, "");
    }
}

static bool PrecheckIsPass(uint8_t gunIndex)
{
    bool result = true;

    // relay welding or driving 是反向
    result = !ShmDcCommonData->GunRelayWeldingOccur[gunIndex];

    return result;
}

static void ReviewCriticalAlarm(void)
{
    if (//ShmDcCommonData->GunRelayDrivingOccur[0] == YES ||
            //ShmDcCommonData->GunRelayDrivingOccur[1] == YES ||
            //ShmDcCommonData->GunRelayWeldingOccur[0] == YES ||
            //ShmDcCommonData->GunRelayWeldingOccur[1] == YES ||
            pAlarmCode->AlarmEvents.bits.EmergencyStopTrip == YES ||
            pAlarmCode->AlarmEvents.bits.MainPowerBreakerTrip == YES ||
            pAlarmCode->AlarmEvents.bits.DoorOpen == YES ||
            pSysWarning->ExtraErrProcess != _EXTRA_ERR_PROCESS_NONE ||
            pAlarmCode->AlarmEvents.bits.PsuFailureAlarm == YES ||
            pAlarmCode->AlarmEvents.bits.DisconnectedFromDo == YES ||
            //Power cabinet alarm status
            ShmDcCommonData->PowerAlarmState.StatusBit.EmergencyStop == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.DoorOpen == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.DcInputOVP == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.DcInputUVP == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.SystemL1InputOVP == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.SystemL2InputOVP == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.SystemL3InputOVP == YES ||
            ShmDcCommonData->PowerAlarmState.StatusBit.PsuFailure == YES
       ) {
        pSysWarning->Level = WARN_LV_ER;
    } else {
        pSysWarning->Level = WARN_LV_NL;
    }
}

static void CheckRelayWeldingOrDrivingFault(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

    // relay welding fault then stop the charging process.
    uint8_t faultCode = RELAY_STATUS_ERROR_NONE;
    //static uint8_t drivingCount = 0;

    if (gunIndex == 0) {
        if (ShmDcCommonData->CheckRelayStatus[RELAY_SMR1_P_STATUS] == RELAY_STATUS_ERROR_WELDING ||
                ShmDcCommonData->CheckRelayStatus[RELAY_SMR1_N_STATUS] == RELAY_STATUS_ERROR_WELDING) {
            faultCode = RELAY_STATUS_ERROR_WELDING;
        } else if (ShmDcCommonData->CheckRelayStatus[RELAY_SMR1_P_STATUS] == RELAY_STATUS_ERROR_DRIVING ||
                   ShmDcCommonData->CheckRelayStatus[RELAY_SMR1_N_STATUS] == RELAY_STATUS_ERROR_DRIVING) {
            faultCode = RELAY_STATUS_ERROR_DRIVING;
        }
    } else if (gunIndex == 1) {
        if (ShmDcCommonData->CheckRelayStatus[RELAY_SMR2_P_STATUS] == RELAY_STATUS_ERROR_WELDING ||
                ShmDcCommonData->CheckRelayStatus[RELAY_SMR2_N_STATUS] == RELAY_STATUS_ERROR_WELDING) {
            faultCode = RELAY_STATUS_ERROR_WELDING;
        } else if (ShmDcCommonData->CheckRelayStatus[RELAY_SMR2_P_STATUS] == RELAY_STATUS_ERROR_DRIVING ||
                   ShmDcCommonData->CheckRelayStatus[RELAY_SMR2_N_STATUS] == RELAY_STATUS_ERROR_DRIVING) {
            faultCode = RELAY_STATUS_ERROR_DRIVING;
        }
    }

    if (faultCode == RELAY_STATUS_ERROR_WELDING) {
        // welding
        if (pDcChargingInfo->Type == _Type_Chademo) {
            RecordAlarmCode(gunIndex, "011011");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayWeldingFault = YES;
        } else if (pDcChargingInfo->Type == _Type_GB) {
            RecordAlarmCode(gunIndex, "011015");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayWeldingFault = YES;
        } else if (pDcChargingInfo->Type == _Type_CCS_2) {
            RecordAlarmCode(gunIndex, "011013");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayWeldingFault = YES;
        }
        if (ShmDcCommonData->GunRelayWeldingOccur[gunIndex] != YES) {
            log_error("Gun%d Relay welding....",gunIndex);
        }
        ShmDcCommonData->GunRelayWeldingOccur[gunIndex] = YES;

    } else if (faultCode == RELAY_STATUS_ERROR_DRIVING) {
        // driving
        if (pDcChargingInfo->Type == _Type_Chademo) {
            RecordAlarmCode(gunIndex, "011012");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayDrivingFault = YES;
        } else if (pDcChargingInfo->Type == _Type_GB) {
            RecordAlarmCode(gunIndex, "011016");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayDrivingFault = YES;
        } else if (pDcChargingInfo->Type == _Type_CCS_2) {
            RecordAlarmCode(gunIndex, "011014");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayDrivingFault = YES;
        }
        if (ShmDcCommonData->GunRelayDrivingOccur[gunIndex] != YES) {
            log_error("Gun%d Relay driving fault....",gunIndex);
        }
        ShmDcCommonData->GunRelayDrivingOccur[gunIndex] = YES;


    } else {
        ShmDcCommonData->GunRelayWeldingOccur[gunIndex] = NO;
        ShmDcCommonData->GunRelayDrivingOccur[gunIndex] = NO;
        /*
        if (pDcChargingInfo->Type == _Type_Chademo) {
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayDrivingFault = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaRelayWeldingFault = NO;
        } else if (pDcChargingInfo->Type == _Type_GB) {
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayDrivingFault = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTRelayWeldingFault = NO;
        } else if (pDcChargingInfo->Type == _Type_CCS_2) {
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayDrivingFault = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSRelayWeldingFault = NO;
        }
        */
        //drivingCount = 0;
    }

}

static void isChargingAverageState(void)
{
    if (pSysInfo->MainChargingMode != _MAIN_CHARGING_MODE_AVER) {
        pSysInfo->ReAssignedFlag = _REASSIGNED_NONE;
        return;
    }

#if !defined DD360 && !defined DD360Audi && !defined DD360ComBox
    if (pSysInfo->AcContactorStatus != YES) {
        pSysInfo->MainChargingMode = _MAIN_CHARGING_MODE_MAX;
        pSysInfo->ReAssignedFlag = _REASSIGNED_NONE;
    }
#endif //!defined DD360 && !defined DD360Audi

    // 均充 -> 最大充
    if (pSysInfo->BridgeRelayStatus == NO) {
        if (pSysInfo->ReAssignedFlag == _REASSIGNED_NONE) {
            log_info("=============Smart Charging============= Step 11 ");
            pSysInfo->ReAssignedFlag = _REASSIGNED_PREPARE_A_TO_M;
        }
    } else if (pSysInfo->ReAssignedFlag != _REASSIGNED_COMP &&
               pSysInfo->ReAssignedFlag != _REASSIGNED_WAITING) {
        log_info("=============Smart Charging============= Step 14 ");
        pSysInfo->ReAssignedFlag = _REASSIGNED_WAITING;
    } else if (pSysInfo->ReAssignedFlag == _REASSIGNED_COMP) {
        pSysInfo->MainChargingMode = _MAIN_CHARGING_MODE_MAX;
        pSysInfo->ReAssignedFlag = _REASSIGNED_NONE;
    }
}

bool Taskconutstring(char *src, char *taskname)
{
    bool result = false;

    if (src == NULL || strlen(src) == 0)
        return result;

    if (strstr(src, taskname) != NULL &&
        strstr(src, "grep") == NULL &&
        strstr(src, "[") == NULL)
    {
        result = true;
    }

    return result;
}

int GetProcessCount(char *procName)
{
	int result = 0;
	FILE *fp;
	char cmd[256];
	char buf[256];

	sprintf(cmd, "ps -ef |grep %s", procName);
	fp = popen(cmd, "r");
	if(fp != NULL)
	{
		while(fgets(buf, sizeof(buf), fp) != NULL)
		{
			if (Taskconutstring(buf, procName))
				result++;
		}
	}

	pclose(fp);

	return result;
}
void CheckTaskAlive()
{
    pid_t Pid = fork();
    if ( Pid == 0 ) {
        while(1) {
            sleep(3);
            unsigned char count = GetProcessCount("Module_ChkSysTask");
            if( count != 1 ) {
                system("pkill Module_ChkSysTask");
                sleep(10);
                system("/root/Module_ChkSysTask &");
            }
        }
        return;
    }
    log_info("Create Check Systam fork:%d",Pid);
    return;
}
/**
 * [checkPileEndGfdResult 確認充電樁GFD狀態]
 * @Author   Jerry
 * @DateTime 2021-07-01
 * @param    gunIndex   [當前的槍]
 * @param    gunType    [槍的類型]
 * @param    sysStatus  [槍的系統狀態]
 */
static void checkPileEndGfdResult(uint8_t gunIndex, uint8_t gunType, uint8_t sysStatus)
{
    switch (gunType) {
    case _Type_Chademo:
        // 檢查樁端的 GFD 結果
        if (sysStatus == S_PREPARING_FOR_EVSE &&
                isPrechargeStatus_chademo(gunIndex) >= 6) {
            // 當前操作的槍號,進入 Charging
            setChargerMode(gunIndex, MODE_CHARGING);
        }

        // 非車端的停止 : 需等待小板送出停止指令,讓車端解除槍
        //if ((sysStatus == S_ALARM ||
        //        sysStatus == S_TERMINATING) &&
        //        isEvStopCharging_chademo(gunIndex) == YES) {
        //    /*+++ 20200908, vern, disable it for DD360 +++*/
        //    if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
        //        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "Local");
        //        /*--- 20200908, vern, disable it for DD360 ---*/
        //    }
        //}

        if (pDcChargingInfo->GroundFaultStatus == GFD_FAIL) {
            // GFD 錯誤停止
            RecordAlarmCode(gunIndex, "012234");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip = YES;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdWarning = NO;
        } else if (pDcChargingInfo->GroundFaultStatus == GFD_WARNING) {
            // GFD 警告
            //RecordAlarmCode(gunIndex, "012296");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdWarning = YES;
        }
        else
        {
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdTrip = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaGfdWarning = NO;
        }
        //else if (sysStatus == S_CHARGING &&
        //           ((pDcChargingInfo->EvBatterytargetVoltage * 10) > 0 &&
        //            pDcChargingInfo->EvBatterytargetVoltage < SYSTEM_MIN_VOL) ||
        //           (pDcChargingInfo->PresentChargedDuration >= 10 &&
        //            pDcChargingInfo->PresentChargingVoltage < SYSTEM_MIN_VOL)
        //          ) {
        //    // UVP
        //    RecordAlarmCode(gunIndex, "012289");
        //    ChargingTerminalProcess(gunIndex);
        //}
        break;

    case _Type_GB:
        // 檢查樁端的 GFD 結果
        //if (isPrechargeStatus_gb(gunIndex) > 5 && isPrechargeStatus_gb(gunIndex) < 9) {
        if (sysStatus == S_PREPARING_FOR_EVSE && isPrechargeStatus_gb(gunIndex) >= 6) {
            setChargerMode(gunIndex, MODE_CHARGING);
        }

        // 非車端的停止 : 需等待小板送出停止指令,讓車端解除槍
        //if (isEvStopCharging_chademo(gunIndex) == YES) {
        //    /*+++ 20200908, vern, disable it for DD360 +++*/
        //    if ((sysStatus == S_ALARM ||
        //            sysStatus == S_TERMINATING) &&
        //            strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL
        //       ) {
        //        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "Local");
        //    }
        //    /*--- 20200908, vern, disable it for DD360 ---*/
        //}

        if (pDcChargingInfo->GroundFaultStatus == GFD_FAIL) {
            // GFD 錯誤停止
            RecordAlarmCode(gunIndex, "012236");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip = YES;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdWarning = NO;
        } else if (pDcChargingInfo->GroundFaultStatus == GFD_WARNING) {
            // GFD 警告
            //RecordAlarmCode(gunIndex, "012298");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdWarning = YES;
        }
        else
        {
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdTrip = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTGfdWarning = NO;
        }
        //else if (sysStatus == S_CHARGING &&
        //           isPrechargeStatus_gb(gunIndex) == 10 &&
        //           (((pDcChargingInfo->EvBatterytargetVoltage * 10) > 0 &&
        //             pDcChargingInfo->EvBatterytargetVoltage < SYSTEM_MIN_VOL) ||
        //            (pDcChargingInfo->PresentChargedDuration >= 10 &&
        //             pDcChargingInfo->PresentChargingVoltage < SYSTEM_MIN_VOL))
        //          ) {
        //    // UVP
        //    RecordAlarmCode(gunIndex, "012290");
        //    ChargingTerminalProcess(gunIndex);
        //}
        break;

    case _Type_CCS_2:
        // 檢查樁端的 GFD 結果
        if (sysStatus == S_PREPARING_FOR_EVSE &&
                (pDcChargingInfo->GroundFaultStatus == GFD_PASS ||
                 pDcChargingInfo->GroundFaultStatus == GFD_WARNING)
           ) {
            setChargerMode(gunIndex, MODE_CCS_PRECHARGE_STEP0);
        }

        // 非車端的停止 : 需等待小板送出停止指令,讓車端解除槍
        //if (isEvStopCharging_chademo(gunIndex) == YES) {
        //    /*+++ 20200908, vern, disable it for DD360 +++*/
        //    if ((sysStatus == S_ALARM ||
        //            sysStatus == S_TERMINATING) &&
        //            (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL)
        //       ) {
        //        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "Local");
        //    }
        //    /*--- 20200908, vern, disable it for DD360 ---*/
        //}

        if (pDcChargingInfo->GroundFaultStatus == GFD_FAIL) {
            // GFD 錯誤停止
            RecordAlarmCode(gunIndex, "012235");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = YES;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdWarning = NO;
        } else if (pDcChargingInfo->GroundFaultStatus == GFD_WARNING) {
            // GFD 警告
            //RecordAlarmCode(gunIndex, "012297");
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdWarning = YES;
        }
        else
        {
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = NO;
            ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdWarning = NO;
        }
        //else if (sysStatus == S_CHARGING &&
        //           ((pDcChargingInfo->EvBatterytargetVoltage * 10) > 0 &&
        //            pDcChargingInfo->EvBatterytargetVoltage < SYSTEM_MIN_VOL) ||
        //           (pDcChargingInfo->PresentChargedDuration >= 10 &&
        //            pDcChargingInfo->PresentChargingVoltage < SYSTEM_MIN_VOL)
        //          ) {
        //    // UVP
        //    RecordAlarmCode(gunIndex, "012288");
        //    ChargingTerminalProcess(gunIndex);
        //}
        break;
    }
}

static void checkEvBoardReqStop(uint8_t sysStatus, uint8_t gunIndex)
{
    uint8_t evBoardStopState = 0;

    if ((evBoardStopState = isEvBoardStopChargeFlag(gunIndex)) > 0) {
        log_info("evBoardStopState :%d ",evBoardStopState);
        // 板端要求停止 (錯誤)
        if (sysStatus != S_CCS_PRECHARGE_ST0 &&
                sysStatus != S_CCS_PRECHARGE_ST1) {
            if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
                strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "EVDisconnected");
            }
        }

        if (evBoardStopState == EV_BOARD_STOP_CHARGING) {
            ChargingAlarmProcess(gunIndex);
        } else if (evBoardStopState == POWER_CABINET_STOP_CHARGING) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
            log_info("Cabinet Stop Gun%d Charging permittion, Status Code [%s]",gunIndex,pDcChargingInfo->ConnectorAlarmCode);
            if (strncmp((char*)pDcChargingInfo->ConnectorAlarmCode,"000000",6) != EQUAL &&
                strncmp((char*)pDcChargingInfo->ConnectorAlarmCode,"",6) != EQUAL) {
                ChargingAlarmProcess(gunIndex);
                //log_info("Cabinet Stop Gun%d Charging permittion, Status Code [%s]",gunIndex,pDcChargingInfo->ConnectorAlarmCode);
            } else {
                ChargingTerminalProcess(gunIndex);
            }
        }
    } else if (isEvBoardNormalStopChargeFlag(gunIndex) == YES) {
        // 板端要求停止 (正常)
        if (sysStatus != S_CCS_PRECHARGE_ST0 &&
                sysStatus != S_CCS_PRECHARGE_ST1) {
            if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
                strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "EVDisconnected");
            }
        }

        ChargingTerminalProcess(gunIndex);
    } else if (OcppRemoteStop(gunIndex) == YES ||
               WifiScheduleStop(gunIndex)) {
        // 後臺要求停止
        ChargingTerminalProcess(gunIndex);
    }
}
void showversion()
{
    uint8_t index = 0;
    log_info("\t========= Charger info ========= ");
    log_info("\tSW Version = %s", pSysInfo->CsuRootFsFwRev);
    log_info("\tDebug Version = %s",ShmDcCommonData->DebugVersion);
    log_info("\tModelName = %s", pSysConfig->ModelName);
    log_info("\tRelay Board FW Rev = %s", pSysInfo->RelayModuleFwRev);
    log_info("\tFan Board FW Rev = %s", pSysInfo->FanModuleFwRev);
    log_info("\tPrimary FW Rev = %s", pSysInfo->CsuPrimFwRev);
    for (index = 0; index < pSysConfig->TotalConnectorCount; index++) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);
        if (pDcChargingInfo->Type == _Type_Chademo) {
            log_info("\tCHAdeMO[%d] FW Rev = %s",
                                     pDcChargingInfo->type_index,
                                     ShmCHAdeMOData->evse[pDcChargingInfo->type_index].version);
        } else if (pDcChargingInfo->Type == _Type_GB) {
            log_info("\tGBT[%d] FW Rev = %s",
                                     pDcChargingInfo->type_index,
                                     ShmGBTData->evse[pDcChargingInfo->type_index].version);
        } else if (pDcChargingInfo->Type == _Type_CCS_2) {
            log_info("\tCCS[%d] FW Rev = %s",
                                         pDcChargingInfo->type_index,
                                         ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].version);
        }
    }
    log_info("\t================================ ");
}


void SetNatural300AGunOTPValue(struct DERATING_BY_OTP* deratingByConnOtp)
{
    deratingByConnOtp->isNeedDerating = YES;
    deratingByConnOtp->deratingTargetCurrent[0] = 5000;
    deratingByConnOtp->deratingTargetCurrent[1] = 3000;
    deratingByConnOtp->deratingTargetCurrent[2] = 1000;
    deratingByConnOtp->deratingTargetCurrent[3] = 0;
    deratingByConnOtp->deratingTargetCurrent[4] = 0;
}
void SetLiquidCoolGunOTPValue(struct DERATING_BY_OTP* deratingByConnOtp)
{
    deratingByConnOtp->isNeedDerating = YES;
    deratingByConnOtp->deratingTargetCurrent[0] = 5000;
    deratingByConnOtp->deratingTargetCurrent[1] = 4000;
    deratingByConnOtp->deratingTargetCurrent[2] = 3000;
    deratingByConnOtp->deratingTargetCurrent[3] = 0;
    deratingByConnOtp->deratingTargetCurrent[4] = 0;
}

void SetCHAdeMoTypeKOTPValue(struct DERATING_BY_OTP* deratingByConnOtp)
{
    deratingByConnOtp->isNeedDerating = YES;
    deratingByConnOtp->deratingTargetRate[0] = 1;
    deratingByConnOtp->deratingTargetRate[1] = 0.8;
    deratingByConnOtp->deratingTargetRate[2] = 0.8;
    deratingByConnOtp->deratingTargetRate[3] = 0;
    deratingByConnOtp->deratingTargetRate[4] = 0;

    memset(&deratingByConnOtp->deratingTargetCurrent[0], 0, sizeof(deratingByConnOtp->deratingTargetCurrent));
}

void SetCHAdeMoTypeSJOTPValue(struct DERATING_BY_OTP* deratingByConnOtp)
{
    deratingByConnOtp->isNeedDerating = YES;
    deratingByConnOtp->deratingTargetCurrent[0] = 2000;
    deratingByConnOtp->deratingTargetCurrent[1] = 1250;
    deratingByConnOtp->deratingTargetCurrent[2] = 1250;
    deratingByConnOtp->deratingTargetCurrent[3] = 0;
    deratingByConnOtp->deratingTargetCurrent[4] = 0;
}

void SetCHAdeMoTypeOOTPValue(struct DERATING_BY_OTP* deratingByConnOtp)
{
    deratingByConnOtp->isNeedDerating = YES;
    deratingByConnOtp->deratingTargetCurrent[0] = 3500;
    deratingByConnOtp->deratingTargetCurrent[1] = 2000;
    deratingByConnOtp->deratingTargetCurrent[2] = 2000;
    deratingByConnOtp->deratingTargetCurrent[3] = 0;
    deratingByConnOtp->deratingTargetCurrent[4] = 0;
}

static void SetGunTypeOTPValue(void)
{
    //struct ChargingInfoData* chargingData_2 = NULL;
    uint8_t Gun1Type = 0;
    uint8_t Gun2Type = 0;
    int i,cnt;
    if (pSysConfig->TotalConnectorCount == 1) {
        pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(0);
        Gun1Type = pSysConfig->ModelName[7];
        Gun2Type = pSysConfig->ModelName[7];

        switch (Gun1Type) {
        case 'K':
            SetCHAdeMoTypeKOTPValue(&pDcChargingInfo->deratingByConnOtp);
            break;
        case 'S':
            SetCHAdeMoTypeSJOTPValue(&pDcChargingInfo->deratingByConnOtp);
            break;
        case 'I':
        case 'Q':
            SetNatural300AGunOTPValue(&pDcChargingInfo->deratingByConnOtp);
            break;
        case 'O':
            SetCHAdeMoTypeOOTPValue(&pDcChargingInfo->deratingByConnOtp);
            break;
            // 水冷
        case 'V':
        case 'F':
            SetLiquidCoolGunOTPValue(&pDcChargingInfo->deratingByConnOtp);
            break;
        default:
            pDcChargingInfo->deratingByConnOtp.isNeedDerating = NO;
        }
        if (pDcChargingInfo->deratingByConnOtp.isNeedDerating) {
            log_info("------------ Gun0 - Type:%c Derating info (OTP)-----------", Gun1Type);
            if (pDcChargingInfo->deratingByConnOtp.deratingTargetRate[0] != 0) {
                for (cnt = 0; cnt < DERATING_TARGET_LEVEL; cnt++) {
                    if (pDcChargingInfo->deratingByConnOtp.deratingTargetRate[cnt] != 0) {
                        log_info(" (Pwr) count = %d, valut = %.1f ", cnt, pDcChargingInfo->deratingByConnOtp.deratingTargetRate[cnt]);
                    }
                }
            } else if (pDcChargingInfo->deratingByConnOtp.deratingTargetCurrent[0] != 0) {
                for (cnt = 0; cnt < DERATING_TARGET_LEVEL; cnt++) {
                    if (pDcChargingInfo->deratingByConnOtp.deratingTargetCurrent[cnt] != 0) {
                        log_info(" (Cur) count = %d, valut = %.1f ", cnt, pDcChargingInfo->deratingByConnOtp.deratingTargetCurrent[cnt]);
                    }
                }
            }
        }

    } else if (pSysConfig->TotalConnectorCount == 2) {
        Gun1Type = pSysConfig->ModelName[7];
        Gun2Type = pSysConfig->ModelName[9];
        for (i = 0; i < pSysConfig->TotalConnectorCount; i++) {
            pDcChargingInfo = (struct ChargingInfoData*)GetDcChargingInfoData(i);

            switch (i == 0 ? Gun1Type : Gun2Type) {
            case 'K':
                SetCHAdeMoTypeKOTPValue(&pDcChargingInfo->deratingByConnOtp);
                break;
            case 'S':
                SetCHAdeMoTypeSJOTPValue(&pDcChargingInfo->deratingByConnOtp);
                break;
                // 風冷300A
            case 'I':
            case 'Q':
                SetNatural300AGunOTPValue(&pDcChargingInfo->deratingByConnOtp);
                break;
            case 'O':
                SetCHAdeMoTypeOOTPValue(&pDcChargingInfo->deratingByConnOtp);
                break;
                // 水冷
            case 'V':
            case 'F':
                SetLiquidCoolGunOTPValue(&pDcChargingInfo->deratingByConnOtp);
                break;
            default:
                pDcChargingInfo->deratingByConnOtp.isNeedDerating = NO;
            }
            if (pDcChargingInfo->deratingByConnOtp.isNeedDerating) {
                log_info("------------ Gun%d - Type:%c Derating info (OTP)-----------",i, i == 0 ? Gun1Type : Gun2Type);
                if (pDcChargingInfo->deratingByConnOtp.deratingTargetRate[0] != 0) {
                    for (cnt = 0; cnt < DERATING_TARGET_LEVEL; cnt++) {
                        if (pDcChargingInfo->deratingByConnOtp.deratingTargetRate[cnt] != 0) {
                            log_info(" (Pwr) count = %d, valut = %.1f ", cnt, pDcChargingInfo->deratingByConnOtp.deratingTargetRate[cnt]);
                        }
                    }
                } else if (pDcChargingInfo->deratingByConnOtp.deratingTargetCurrent[0] != 0) {
                    for (cnt = 0; cnt < DERATING_TARGET_LEVEL; cnt++) {
                        if (pDcChargingInfo->deratingByConnOtp.deratingTargetCurrent[cnt] != 0) {
                            log_info(" (Cur) count = %d, valut = %.1f ", cnt, pDcChargingInfo->deratingByConnOtp.deratingTargetCurrent[cnt]);
                        }
                    }
                }
            }
        }
    }
}
bool checkGunTempFail(uint8_t gunIndex)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
    switch (pDcChargingInfo->Type) {
        case _Type_Chademo:
            if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.ChaConnectTempSensorFail) {
                RecordAlarmCode(gunIndex,"011018");
                if (IntoChargeProcess(pDcChargingInfo->SystemStatus)) {
                    setChargerMode(gunIndex,S_ALARM);
                }

                if (pDcChargingInfo->SystemStatus == S_IDLE ||
                   pDcChargingInfo->SystemStatus == S_RESERVATION ) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, "011018", 6);
                    setChargerMode(gunIndex,S_FAULT);
                }
                return TRUE;
            }
            break;
        case _Type_CCS_2:
            if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSConnectTempSensorFail) {
                RecordAlarmCode(gunIndex,"011019");
                if (IntoChargeProcess(pDcChargingInfo->SystemStatus)) {
                    setChargerMode(gunIndex,S_ALARM);
                }

                if (pDcChargingInfo->SystemStatus == S_IDLE ||
                   pDcChargingInfo->SystemStatus == S_RESERVATION ) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, "011019", 6);
                    setChargerMode(gunIndex,S_FAULT);
                }
                
                return TRUE;
            }
            break;
        case _Type_GB:
            if (ShmDcCommonData->ConnectErrList[gunIndex].GunBits.GBTConnectTempSensorFail) {
                RecordAlarmCode(gunIndex,"011020");
                if (IntoChargeProcess(pDcChargingInfo->SystemStatus)) {
                    setChargerMode(gunIndex,S_ALARM);
                }

                if (pDcChargingInfo->SystemStatus == S_IDLE ||
                   pDcChargingInfo->SystemStatus == S_RESERVATION ) {
                    memcpy(pDcChargingInfo->ConnectorAlarmCode, "011020", 6);
                    setChargerMode(gunIndex,S_FAULT);
                }
                return TRUE;
            }
            break;
    }
    return FALSE;
}

//==========================================
// Ocmf
//==========================================

void ConfigOcmfInfo(uint8_t gun_index)
{
    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gun_index);
	strncpy((char *)pSysInfo->DcMeterTransactionAction[gun_index].head.evseId,
			(char *)pSysConfig->SerialNumber, ARRAY_SIZE(pSysConfig->SerialNumber));

	char trId[32];
	sprintf(trId, "%d", ShmSelectGunInfo->PricesInfo[gun_index].TransactionId);
	memcpy((char *)pSysInfo->DcMeterTransactionAction[gun_index].head.transactionId, trId,
			sizeof(trId));

	char clientId[32] = "DC_Charger";
	memcpy((char *)pSysInfo->DcMeterTransactionAction[gun_index].head.clientId, clientId,
			sizeof(clientId));

	pSysInfo->DcMeterTransactionAction[gun_index].head.tariffId = 0;
	pSysInfo->DcMeterTransactionAction[gun_index].head.cableId = 0;

	memcpy((char *)pSysInfo->DcMeterTransactionAction[gun_index].head.userData,
			(char *)pDcChargingInfo->StartUserId,
			sizeof(pDcChargingInfo->StartUserId));
}

void ConfigOcmfInfo_Record(int _trID, uint8_t gun_index)
{
	strncpy((char *)pSysInfo->DcMeterReadTransactionRecord[gun_index].head.evseId,
			(char *)pSysConfig->SerialNumber, ARRAY_SIZE(pSysConfig->SerialNumber));

	char trId[32];
	sprintf(trId, "%d", _trID);
	strcpy((char *)pSysInfo->DcMeterReadTransactionRecord[gun_index].head.transactionId, trId);
	strcpy((char *)pSysInfo->DcMeterReadTransactionRecord[gun_index].head.clientId, "DC_Charger");

	pSysInfo->DcMeterReadTransactionRecord[gun_index].head.tariffId = 0;
	pSysInfo->DcMeterReadTransactionRecord[gun_index].head.cableId = 0;

	strcpy((char *)pSysInfo->DcMeterReadTransactionRecord[gun_index].head.userData, "Record");
}
void StoreOcmfFile(uint8_t gun_index,int trid,int isRecord)
{
    if (ShmDcCommonData->pGunInfo[gun_index].ConnectorID <= 0 || ShmDcCommonData->pGunInfo[gun_index].ConnectorID > 4) {
        log_info("Gun%d ConnectorID:%d",gun_index,ShmDcCommonData->pGunInfo[gun_index].ConnectorID);
        return;
    }

    FILE *pfile;
    char cmd[500];
    sprintf((char*)ShmDcCommonData->pGunInfo[gun_index].OcmfFileName,"/mnt/Gun_%d_%d_OCMF",
        ShmDcCommonData->pGunInfo[gun_index].ConnectorID,trid);
    log_info("OCMF File:%s",ShmDcCommonData->pGunInfo[gun_index].OcmfFileName);

    pfile = fopen(ShmDcCommonData->pGunInfo[gun_index].OcmfFileName,"w+");
    if (isRecord)
        fprintf(pfile,"%s",pSysInfo->DcMeterReadTransactionRecord[gun_index].transactionOCMF);
    else
        fprintf(pfile,"%s",pSysInfo->DcMeterTransactionAction[gun_index].transactionOCMF);
    fclose(pfile);
    sprintf(cmd,"ftpput -u root -p y42j/4cj84 192.168.100.1 %s",ShmDcCommonData->pGunInfo[gun_index].OcmfFileName);
    if (system(cmd) != 0 ) {
        log_info("Put OCMF File to Cabinet Fail");
        sprintf(cmd,"rm -f %s",ShmDcCommonData->pGunInfo[gun_index].OcmfFileName);
        system(cmd);
    } else {
        log_info("Put OCMF File to Cabinet OK");
        ShmDcCommonData->pGunInfo[gun_index].SendOcmfDataReq = TRUE;
    }

}
void ChkOcmfRecord(uint8_t gun_index)
{
    if (pAlarmCode->AlarmEvents.bits.Meter1CommTimeout) {
        return;
    }

	int trid = DB_Get_OcmfTrid(gun_index);

	if (trid != 0 &&
			trid != ShmDcCommonData->ocmfTridRecord[gun_index] &&
			trid != ShmSelectGunInfo->PricesInfo[gun_index].TransactionId)
	{
		ShmDcCommonData->ocmfTridRecord[gun_index] = trid;
		ConfigOcmfInfo_Record(ShmDcCommonData->ocmfTridRecord[gun_index], gun_index);
		pSysInfo->DcMeterReadTransactionRecord[gun_index].ActionCmd = _DC_METER_TRANSACTION_ACTION_START;
	}

	if (pSysInfo->DcMeterReadTransactionRecord[gun_index].OcmfInfoReady == _OCMF_INFO_READY_YES &&
        ShmDcCommonData->pGunInfo[gun_index].SendOcmfDataReq == FALSE)
	{
		log_info("OCMF Record - Reture Pass \n");
		pSysInfo->DcMeterReadTransactionRecord[gun_index].OcmfInfoReady = _OCMF_INFO_READY_NO;
		//ocpp_ocmf_information(gun_index);
		DB_Update_ocmf_Record(gun_index, ShmDcCommonData->ocmfTridRecord[gun_index], true);
        StoreOcmfFile(gun_index,trid,TRUE);
		//ShmDcCommonData->ocmfTridRecord[gun_index] = 0;
	}
	else if (pSysInfo->DcMeterReadTransactionRecord[gun_index].OcmfInfoReady == _OCMF_INFO_READY_FAIL)
	{
		log_info("OCMF Record - Reture Fail \n");
		pSysInfo->DcMeterReadTransactionRecord[gun_index].OcmfInfoReady = _OCMF_INFO_READY_NO;
		DB_Update_ocmf_Record(gun_index, ShmDcCommonData->ocmfTridRecord[gun_index], false);
		//ShmDcCommonData->ocmfTridRecord[gun_index] = 0;
	}
}
int main(void)
{
    bool isModelNameMatch = true;
    uint8_t evBoardStopState = 0;
    uint8_t _ocppProfileChkFlag;
    uint8_t gunIndex = 0;
    uint8_t _isStop[2] = {0};
    float powerconsumption;
    uint8_t ConnectID[2];
    uint8_t SendOcmfDataReq[2];
    if (CreateAllCsuShareMemory() == FAIL) {
        log_error("create share memory error");
        return FAIL;
    }
    ClearAllShmMemParameter();

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

    pAlarmCode = (struct AlarmCodeData *)GetShmAlarmCodeData();
    pFaultCode = (struct FaultCodeData *)GetShmFaultCodeData();
    pInfoCode = (struct InfoCodeData *)GetShmInfoCodeData();

    ShmPsuData = (struct PsuData *)GetShmPsuData();

    ShmCHAdeMOData = (struct CHAdeMOData *)GetShmCHAdeMOData();
    ShmGBTData = (struct GBTData *)GetShmGBTData();
    ShmCcsData = (struct CcsData *)GetShmCcsData();

    ShmPrimaryMcuData = (struct PrimaryMcuData *)GetShmPrimaryMcuData();
    ShmFanModuleData = (struct FanModuleData *)GetShmFanModuleData();
    ShmRelayModuleData = (struct RelayModuleData *)GetShmRelayModuleData();
    ShmLedModuleData = (struct LedModuleData *)GetShmLedModuleData();
    ShmOCPP16Data = (struct OCPP16Data *)GetShmOCPP16Data();
    ShmOCPP20Data = (struct OCPP20Data*)GetShmOCPP20Data();
    ShmDcCommonData = (DcCommonInfo *)GetShmDcCommonData();
    ShmSelectGunInfo = (SelectGunInfo *)GetShmSelectGunInfo();
	
    ShmSysConfigAndInfo = (struct SysConfigAndInfo *)GetShmSysConfigAndInfo();
    ShmStatusCodeData = (struct StatusCodeData *)GetShmStatusCodeData();	
    log_info(" ********************************************************");
    log_info(" ******************  FileSystem Boot up *****************");
    log_info(" ********************************************************");
#if defined DD360
    log_info(" ******************  Project:DD360  *********************");
#elif defined DD360Audi
    log_info(" ******************  Project:DD360Audi  *****************");
#elif defined DD360ComBox
    log_info(" ******************  Project:DD360ComBox  ***************");
#endif
    log_info(" ********************************************************");
    if (!InitialSystemDefaultConfig()) {
        log_error("InitialSystemDefaultConfig NG ");
        //StopProcessingLoop();
        sleep(5);
        system("reboot -f");
    }
    CheckGunTypeFromHw();
    CheckIsAlternatvieByModelName();
    InitialShareMemoryInfo();
    GetFirmwareVersion();

    ChangeLcmByIndex(_LCM_INIT);
    if (!CheckConnectorTypeStatus()) {
        isModelNameMatch = false;
    }

    Initialization();
    SpawnTask();
    log_info("Spawned all Task");
    if (!isModelNameMatch) {
        pAlarmCode->AlarmEvents.bits.ModelNameNoneMatchStestFail = YES;
        ChangeLcmByIndex(_LCM_FIX);
        // Module Name 與硬體對應不正確
        log_error("Module Name & HW info none match. ");
        sleep(3);
        KillAllTask();
        StopProcessingLoop();
    }
    CreateTimeoutFork();

    PrimaryLedIndicatorCtrlFork();
    ChangeLcmByIndex(_LCM_FIX);
    SelfTestRun();
    StopSystemTimeoutDet();
    log_info("Self test finished : SelfTestSeq = %d, Work_Step = %d ",
             pSysInfo->SelfTestSeq,
             ShmPsuData->Work_Step);

    if (pSysInfo->SelfTestSeq == _STEST_FAIL ||
            ShmPsuData->Work_Step == _NO_WORKING ||
            pInfoCode->InfoEvents.bits.CcsSeccTimeoutQCA7000Comm == YES //DS60-120 add
       ) {
        /*
        if (pSysWarning->Level != WARN_LV_ER) {
            if (!DisplaySelfTestFailReason()) { //DS60-120 add
                log_info("Soft reboot for retry self-tets. ");

                sleep(3);
                system("killall OcppBackend &");
                KillAllTask();
                system("/usr/bin/run_evse_restart.sh");
            }
        }

        for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            setChargerMode(gunIndex, MODE_ALARM);
        }
        //ChangeLcmByIndex(_LCM_FIX);
        sleep(3);
        if (pSysWarning->Level == WARN_LV_ER) { //DS60-120 add
            KillTaskExceptPrimary();
        } else {
            KillTask();
        }
        StopProcessingLoop();
        */
        for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            setChargerMode(gunIndex, MODE_MAINTAIN);
        }
        ChangeLcmByIndex(_LCM_FIX);
    } else {
        for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            setChargerMode(gunIndex, MODE_IDLE);
        }
    }

    // Local DB
    if (DB_Open() != PASS) {
        log_info("DB_Open fail. ");
        isDb_ready = false;
    } else {
        isDb_ready = true;
        for (int _index = 0; _index < pSysConfig->TotalConnectorCount; _index++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(_index);

            pDcChargingInfo->IsAvailable = DB_Get_Operactive(_index);
            if (!DB_Get_PowerConsumption(_index)) {
                DB_Insert_PowerConsumption(_index, 0);
            }
        }
        DB_Reboot_Record();
    }
    log_info("===== Create DB End ===== ");

#if defined DD360Audi
    ChangeLcmByIndex(_LCM_SELECT_GUN);
#else
    ChangeLcmByIndex(_LCM_IDLE);
#endif //defined DD360Audi

    sleep(1);
    //***** 須新增的偵測 *****//
    // 1. Thernal - 控制風扇轉速
    // 2. ouput fuse - 控制風扇轉速
    CreateRfidFork();
    // Main loop
    showversion();
    CheckFwSlotStatusLog();
    //AdjustChargerCurrent();
    GetClockTime(&_cmdMainPriority_time);

    GunIndexInfo *pGunIndexInfo = (GunIndexInfo *)GetGunIndexInfo();

    CheckTaskAlive();

    CreateWatchdog();

    pSysInfo->OTPTemp = GUN_OTP_VALUE;
    pSysInfo->OTPTempR = GUN_OTP_RECOVERY;

    SetGunTypeOTPValue();
    struct ChargingInfoData *pDcInfo = NULL;
    for (;;) {

        if (ShmDcCommonData->demo_flag) {
            TryFeedWatchdog();
            usleep(WHILE_LOOP_TIME);
            continue;
        }

        CheckOcppStatus();

        ChkPrimaryStatus();

        if ((IsConnectorWholeIdle() ||
                (pSysInfo->PageIndex == _LCM_FIX)) &&
                (pSysInfo->SystemTimeoutFlag != Timeout_ReturnToChargingGunDet)
           ) {
            CheckFactoryConfigFunction();

            //CheckFwUpdateFunction();
        }

        // OCPP 邏輯
        OcppRemoteStartChk();

        // 讀卡邏輯
        ScannerCardProcess();

        // 當 AC 沒有搭上時,清除一些錯誤碼
        ClearAlarmCodeWhenAcOff();

        // 確認是否要回到充電中的槍畫面邏輯判斷
        CheckReturnToChargingConn();

        //確認Power cabinet PSU Status
        //powerCabinetPsuAlarmStatus();

        if ((GetClockTimeoutValue(_cmdMainPriority_time) / 1000) > 5000) {
            //CheckTask();

            for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
                pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

                if ((pDcChargingInfo->SystemStatus >= S_PREPARING_FOR_EVSE &&
                        pDcChargingInfo->SystemStatus <= S_CHARGING) ||
                        (pDcChargingInfo->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                         pDcChargingInfo->SystemStatus <= S_CCS_PRECHARGE_ST1)) {
                    if (pDcChargingInfo->SystemStatus == S_CHARGING &&
                            _ocppProfileChkFlag == 12) {
                        ChargingProfileFlat(gunIndex);
                        _ocppProfileChkFlag = 0;
                    } else if (pDcChargingInfo->SystemStatus != S_CHARGING) {
                        ChargingProfileFlat(gunIndex);
                        _ocppProfileChkFlag = 0;
                    } else {
                        _ocppProfileChkFlag++;
                    }
                }
                checkGunOTPState(gunIndex); //check gun OTP
                
                // OCMF
                ChkOcmfRecord(gunIndex);
            }
            GetClockTime(&_cmdMainPriority_time);
        }

        // 確認當前錯誤 Level = 2 ?
        ReviewCriticalAlarm();

        gEvBoardErr.GunErrMessage = 0; //清除系統執行中的錯誤訊息
        gChillerTempErr.TempErrMsg = 0;//清除系統執行中的錯誤訊息
        for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            // 重新收集各槍的錯誤狀態
            collectError(gunIndex);
        }
        for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
            // convert common status code to alarm event
            checkEvBoardAlarmState(pDcChargingInfo->Type);
        }
        checkChillerAlarmState();

        //log_info("MeterCommTimeout:%d",pAlarmCode->AlarmEvents.bits.MeterCommTimeout);

        for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
            pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

            autoStartCharging(gunIndex);

            CheckGpioInStatus();

            CheckErrorOccurStatus(gunIndex);

            // 確認 Relay Welding or Driving Fault
            CheckRelayWeldingOrDrivingFault(gunIndex);

            ChkOcppStatus(gunIndex);

            if (IntoChargeProcess(pDcChargingInfo->SystemStatus)) {
                CheckSmartChargeProfile(gunIndex);
            }

            //checkGunTempFail(gunIndex);

            if (pSysInfo->SelfTestSeq == _STEST_FAIL ) {
                setChargerMode(gunIndex, MODE_MAINTAIN);
                ChangeLcmByIndex(_LCM_FIX);
            }

            switch (pDcChargingInfo->SystemStatus) {
            case S_IDLE:
            case S_RESERVATION:
                if (isModeChange(gunIndex)) {
                    if (pDcChargingInfo->SystemStatus == S_IDLE)
                        log_info("============================= S_IDLE(%x) ============================= ", gunIndex);
                    else if (pDcChargingInfo->SystemStatus == S_RESERVATION) {
                        log_info("============================= S_RESERVATION(%x) ============================= ", gunIndex);
                        ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowConf = YES;
                    }
                    pDcChargingInfo->PresentChargedDuration = 0;
                    pDcChargingInfo->RemainChargingDuration = 0;
                    pDcChargingInfo->StartMethod = 0;
                    pDcChargingInfo->PresentChargingVoltage = 0;//DS60-120 add
                    pDcChargingInfo->PresentChargingCurrent = 0;//DS60-120 add
                    strcpy((char *)pDcChargingInfo->StartDateTime, "");
                    strcpy((char *)pDcChargingInfo->StopDateTime, "");
                    strcpy((char *)pDcChargingInfo->StartUserId, "");
                    strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "");
                    if (pDcChargingInfo->deratingByConnOtp.deratingIndex != 0) {
                        pDcChargingInfo->deratingByConnOtp.deratingIndex = 0;
                    }
                    ShmDcCommonData->ocmfTridRecord[gunIndex] = 0 ;
                    _isStop[gunIndex] = 0;
                    //Jerry add
                    memset(&ShmSelectGunInfo->PricesInfo[gunIndex], 0, sizeof(PricesInfo));

                    powerconsumption = ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption;
                    ConnectID[gunIndex] = ShmDcCommonData->pGunInfo[gunIndex].ConnectorID;
                    SendOcmfDataReq[gunIndex] = ShmDcCommonData->pGunInfo[gunIndex].SendOcmfDataReq;
                    memset(&ShmDcCommonData->pGunInfo[gunIndex], 0, sizeof(GunInfo));
                    ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption = powerconsumption;
                    ShmDcCommonData->pGunInfo[gunIndex].ConnectorID = ConnectID[gunIndex];
                    ShmDcCommonData->pGunInfo[gunIndex].SendOcmfDataReq = SendOcmfDataReq[gunIndex];

                    ShmSelectGunInfo->PricesInfo[gunIndex].Balance = FAIL_BALANCE_PRICES;
                    destroySelGun(gunIndex);
                    ResetDetAlarmStatus(gunIndex); //recovery OVP status code
                    if (ShmSelectGunInfo->AuthorStateFromCabinet[gunIndex] == YES) {
                        ShmSelectGunInfo->AuthorStateFromCabinet[gunIndex] = NO;
                    }
                    //strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].VendorErrorCode, "");
                    ReleaseAlarmCode(gunIndex);
                    sleep(1);
                }

                if (pDcChargingInfo->IsAvailable == NO) {
                    setChargerMode(gunIndex, MODE_MAINTAIN);
                }
            case S_FAULT:
                if (isModeChange(gunIndex)) {
                    if(pDcChargingInfo->SystemStatus == S_FAULT)
                    {
                        log_info("============================= S_FAULT(%x) ============================= ", gunIndex);
                    }
                }
                if (pSysWarning->Level == WARN_LV_ER) {
                    struct ChargingInfoData *pSelectedDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(pSysInfo->CurGunSelected);
                    if (gunIndex == pSysInfo->CurGunSelected) {
                        pSysInfo->SystemPage = _LCM_FIX;
                    } else if (pSelectedDcChargingInfo->SystemStatus != S_IDLE &&
                            pSelectedDcChargingInfo->SystemStatus != S_RESERVATION &&
                            pSelectedDcChargingInfo->SystemStatus != S_MAINTAIN &&
                            pSelectedDcChargingInfo->SystemStatus != S_FAULT) {
                        if (pSelectedDcChargingInfo->SystemStatus == S_CHARGING) {
                            pSysInfo->SystemPage = _LCM_COMPLETE;
                        } else {
                            systemPageRestoreInit();
                        }
                    }
                    ClearDetectPluginFlag(gunIndex);

                    if (pDcChargingInfo->SystemStatus != S_FAULT)
                    {
                        ChkPrimaryStatus();
                        UpdateErrorCodeToOcpp(gunIndex);
                        setChargerMode(gunIndex, MODE_FAULT);
                    }
                    continue;
                }
                if (checkGunTempFail(gunIndex)) {
                    break;
                }
                if (pDcChargingInfo->SystemStatus == S_FAULT) {
                    systemPageRestoreInit();
                    setChargerMode(gunIndex, MODE_IDLE);
                }

                isChargingAverageState();

                if (PrecheckIsPass(gunIndex) == false) {
                    //log_error("Relay welding");
                    setChargerMode(gunIndex, MODE_FAULT);
                    if (gunIndex == pSysInfo->CurGunSelected) {
                        pSysInfo->SystemPage = _LCM_FIX;
                    }
                    break;
                }

                if (pDcChargingInfo->SystemStatus == S_FAULT) {
                    pSysInfo->SystemPage = _LCM_NONE;
                    setChargerMode(gunIndex, MODE_IDLE);
                }
                
                if (pSysConfig->OfflinePolicy == _OFFLINE_POLICY_NO_CHARGING) {
                    if (pSysInfo->CurGunSelected == gunIndex) {
                        connectorPageRestoreIdle();
                    }
                    continue;
                }

                // Idle 正常程序起點
                // 判斷是否有啟用檢查插槍
                if (isDetectPlugin(gunIndex)) {
                    StartGunInfoTimeoutDet(gunIndex, Timeout_WaitPlug);
                    // 卡號驗證成功後,等待充電槍插入充電車
                    if (pDcChargingInfo->RemoteStartFlag == YES) {
                        if (pDcChargingInfo->ConnectorPlugIn == YES &&
                                pDcChargingInfo->IsAvailable) {
                            log_info("-----------------1----------------- %d ", gunIndex);
                            pDcChargingInfo->RemoteStartFlag = NO;
                            pDcChargingInfo->isRemoteStart = YES; //DS60-120
                            ChangeGunSelectByIndex(gunIndex);
                            AddPlugInTimes(gunIndex);
                            setChargerMode(gunIndex, MODE_REASSIGN_CHECK);
                            strcpy((char *)pDcChargingInfo->StartUserId, "");
                            ClearDetectPluginFlag(gunIndex);
                            StopGunInfoTimeoutDet(gunIndex);
                            pDcChargingInfo->StartMethod = _CHARGING_START_REMOTESTART;
                            continue;
                        }
                    } else if (pSysInfo->OrderCharging == NO_DEFINE) {
                        if (pDcChargingInfo->ConnectorPlugIn == YES &&
                                pDcChargingInfo->IsAvailable &&
                                (pDcChargingInfo->SystemStatus == S_IDLE ||
                                    pDcChargingInfo->SystemStatus == S_RESERVATION) &&
                                //waitSelectGunPlugIt(gunIndex)
                                (waitRightGunPlugIt(gunIndex) == PASS ||
                                 waitLeftGunPlugIt(gunIndex) == PASS) ) {
                            if (pDcChargingInfo->SystemStatus == S_RESERVATION) {
                                if (strcmp((char*)pSysConfig->UserId, (char*)ShmDcCommonData->pGunInfo[gunIndex].ReservationID) != EQUAL) {
                                    //log_info("Not Resercation ID");
                                    continue;
                                }
                            }
                            log_info("-----------------2----------------- ");
                            ChangeGunSelectByIndex(gunIndex);
                            AddPlugInTimes(gunIndex);
                            strcpy((char *)pDcChargingInfo->StartUserId, (char *)pSysConfig->UserId);
                            if (CheckDispenserGeneration() >= _DISPENSER_GENERATION_3_5) {
                                log_info("index = %d, CardNumber = %s ",
                                        gunIndex,
                                        ShmDcCommonData->pGunInfo[gunIndex].StartUserId);
                            } else {
                                log_info("index = %d, CardNumber = %s ",
                                        gunIndex,
                                        pSysConfig->UserId);
                            }

                            strcpy((char *)pSysConfig->UserId, "");
                            ShmDcCommonData->AuthroizeType = IdTokenType_Central;
                            if (pDcChargingInfo->StartMethod != _CHARGING_START_AUTOSTART &&
                                pDcChargingInfo->StartMethod != _CHARGING_START_EVCCID)
                                pDcChargingInfo->StartMethod = _CHARGING_START_RFID;
                            // 當前操作的槍號,進入 Preparing
                            setChargerMode(gunIndex, MODE_REASSIGN_CHECK);
                            systemPageRestoreInit();
                            if (pSysInfo->CurGunSelected == gunIndex) {
                                pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                            }
                            if (CheckDispenserGeneration() == _DISPENSER_GENERATION_3_5) {
                                ClearDetectPluginFlag(gunIndex);
                                StopGunInfoTimeoutDet(gunIndex);
                            } else {
                                ClearDetectPluginFlag(LEFT_GUN_NUM);
                                ClearDetectPluginFlag(RIGHT_GUN_NUM);
                                StopGunInfoTimeoutDet(LEFT_GUN_NUM);
                                StopGunInfoTimeoutDet(RIGHT_GUN_NUM);
                            }
                            continue;
                        }
                    }

                    if (isDetectPlugin(gunIndex) && pSysInfo->CurGunSelected == gunIndex) {
                        // LCM => Waiting for plugging
                        // AUDI_LCM_CHANGE
                        pSysInfo->SystemPage = _LCM_WAIT_FOR_PLUG;
                    }
                } else if (pSysConfig->isAuthrizeByEVCCID && pDcChargingInfo->ConnectorPlugIn && 
                        pSysInfo->CurGunSelected == gunIndex && !pDcChargingInfo->isEVCCIDVerify) {
                    systemPageRestoreInit();
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                    continue;
                } else {
                    if (pSysInfo->CurGunSelected == gunIndex) {
                        connectorPageRestoreIdle();
                    }
                }
                break;

            case S_REASSIGN_CHECK: {
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_REASSIGN_CHECK(%x) ============================= ", gunIndex);
                    log_info("Start Method:%d",pDcChargingInfo->StartMethod);
                    systemPageRestoreInit();

                    if (pSysInfo->OrderCharging != NO_DEFINE) {
                        pSysInfo->OrderCharging = NO_DEFINE;
                    }
                    StopSystemTimeoutDet();
                    //GetClockTime(&pDcChargingInfo->PreChargeTimer);
                }
				pDcChargingInfo->Replug_flag = true;
                setChargerMode(gunIndex, S_PREPARNING);

                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
            }
            break;

            case S_PREPARNING:
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_PREPARNING(%x) ============================= ", gunIndex);
                    StopGunInfoTimeoutDet(gunIndex);
                    StartGunInfoTimeoutDet(gunIndex, Timeout_Preparing);
                }

                if (ShmPsuData->SystemPresentPsuQuantity > 0 &&
                        ShmPsuData->SystemAvailablePower > 10 &&
                        GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) >= 3000000) {
                    setChargerMode(gunIndex, MODE_PREPARE_FOR_EV);
                }

                checkEvBoardReqStop(pDcChargingInfo->SystemStatus, gunIndex);

                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
                break;

            case S_PREPARING_FOR_EV: // 等待車端的通訊 (EV 小板),待車端回報後,開始樁端的測試
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_PREPARING_FOR_EV(%x) ============================= ", gunIndex);
                    //strcpy((char *)pSysConfig->UserId, "");
                    StopGunInfoTimeoutDet(gunIndex);
                    StartGunInfoTimeoutDet(gunIndex, Timeout_EvChargingDet);
                }

                if (pDcChargingInfo->Type == _Type_Chademo) {
                    // 檢查車端的槍鎖是否為鎖上
                    if (isEvGunLocked_chademo(gunIndex) == YES) {
                        if (pSysConfig->ModelName[3] == 'P')
                        {
                            ConfigOcmfInfo(gunIndex);
                            DB_Insert_ocmf(gunIndex);
                            pSysInfo->DcMeterTransactionAction[gunIndex].ActionCmd = _DC_METER_TRANSACTION_ACTION_START;
                        }
                        setChargerMode(gunIndex, MODE_PREPARE_FOR_EVSE);
                    }
                } else if (pDcChargingInfo->Type == _Type_GB) {
                    // 檢查車端的 charging enable 是否為 1
                    if (isEvGunLocked_gb(gunIndex) == YES) {
                        if (pSysConfig->ModelName[3] == 'P')
                        {
                            ConfigOcmfInfo(gunIndex);
                            DB_Insert_ocmf(gunIndex);
                            pSysInfo->DcMeterTransactionAction[gunIndex].ActionCmd = _DC_METER_TRANSACTION_ACTION_START;
                        }
                        setChargerMode(gunIndex, MODE_PREPARE_FOR_EVSE);
                    }
                } else if (pDcChargingInfo->Type == _Type_CCS_2) {
                    // 檢查車端的 charging enable 是否為 1
                    if (isEvGunLocked_ccs(gunIndex) == YES) {
                        if (pSysConfig->ModelName[3] == 'P')
                        {
                            ConfigOcmfInfo(gunIndex);
                            DB_Insert_ocmf(gunIndex);
                            pSysInfo->DcMeterTransactionAction[gunIndex].ActionCmd = _DC_METER_TRANSACTION_ACTION_START;
                        }
                        setChargerMode(gunIndex, MODE_PREPARE_FOR_EVSE);
                    }
                }

                checkEvBoardReqStop(pDcChargingInfo->SystemStatus, gunIndex);

                // LCM => Pre-charging
                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
                break;

            case S_PREPARING_FOR_EVSE:  // Ground fault test, 等待 Relay Board 通訊及測試,並將狀態回報, CSU 確認 Pass 後,開始進入充電
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_PREPARING_FOR_EVSE(%x) ============================= ", gunIndex);
                    StopGunInfoTimeoutDet(gunIndex);
                    StartGunInfoTimeoutDet(gunIndex, Timeout_EvseChargingDet);
                    if (pSysConfig->ModelName[3] == 'P') {
                        ShmDcCommonData->pGunInfo[gunIndex].isMeterStart = TRUE;
                        ShmDcCommonData->ocmfTridRecord[gunIndex] = ShmSelectGunInfo->PricesInfo[gunIndex].TransactionId;
                    }
                }

                checkPileEndGfdResult(gunIndex, pDcChargingInfo->Type, pDcChargingInfo->SystemStatus);

                checkEvBoardReqStop(pDcChargingInfo->SystemStatus, gunIndex);

                // LCM => Pre-charging
                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
                break;

            case S_CHARGING:  // 剛進入充電狀態,等待 EV 小板要求的輸出電流後開始輸出
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_CHARGING(%x) ============================= ", gunIndex);
                    StopGunInfoTimeoutDet(gunIndex);
                    ftime(&startChargingTime[gunIndex]);
                    strcpy((char *)ShmOCPP16Data->StartTransaction[gunIndex].ResponseIdTagInfo.Status, ""); //DS60-120 add
                    ChangeStartOrStopDateTime(YES, gunIndex);

                    OcppStartTransation(gunIndex);
                }
				pDcChargingInfo->Replug_flag = false;

                if (ShmOCPP16Data->CpMsg.bits[gunIndex].StartTransactionConf) {
                    ShmOCPP16Data->CpMsg.bits[gunIndex].StartTransactionConf = NO;
                }
                ftime(&endChargingTime[gunIndex]);
                pDcChargingInfo->PresentChargedDuration = DiffTimeb(startChargingTime[gunIndex], endChargingTime[gunIndex]);

                checkPileEndGfdResult(gunIndex, pDcChargingInfo->Type, pDcChargingInfo->SystemStatus);

                if ((time((time_t*)NULL) - ShmDcCommonData->pGunInfo[gunIndex].RecordEnergyTime) >= 5) {
                    ShmDcCommonData->pGunInfo[gunIndex].RecordEnergyTime = time((time_t*)NULL);
                    if (ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption != 0)
                        DB_Update_PowerConsumption(gunIndex, ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption);
                }

                if ((evBoardStopState = isEvBoardStopChargeFlag(gunIndex)) > 0) {
                    // 板端要求停止 (錯誤)
                    if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
                        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "EVDisconnected");
                    }

                    //printf("%d evBoardStopState = %d", gunIndex, evBoardStopState);
                    if (evBoardStopState == EV_BOARD_STOP_CHARGING) {
                        ChargingAlarmProcess(gunIndex);
                    } else if (evBoardStopState == POWER_CABINET_STOP_CHARGING) {
                        log_info("Cabinet Stop Gun%d Charging permittion, Status Code [%s]",gunIndex,pDcChargingInfo->ConnectorAlarmCode);
                        if (strncmp((char*)pDcChargingInfo->ConnectorAlarmCode,"000000",6) != EQUAL &&
                            strncmp((char*)pDcChargingInfo->ConnectorAlarmCode,"",6) != EQUAL) {
                            ChargingAlarmProcess(gunIndex);
                            //log_info("Cabinet Stop Gun%d Charging permittion, Status Code [%s]",gunIndex,pDcChargingInfo->ConnectorAlarmCode);
                        } else {
                            ChargingTerminalProcess(gunIndex);
                        }
                    }
                } else if (isEvBoardNormalStopChargeFlag(gunIndex) == YES) {
                    // 板端要求停止 (正常)
                    if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
                        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "EVDisconnected");
                    }

                    ChargingTerminalProcess(gunIndex);
                } else if (OcppRemoteStop(gunIndex) == YES ||
                           WifiScheduleStop(gunIndex) ||
                           CheckBackendChargingTimeout(gunIndex) ||
                           CheckBackendChargingEnergy(gunIndex) ||
                           strcmp((char *)ShmOCPP16Data->StartTransaction[gunIndex].ResponseIdTagInfo.Status, "Invalid") == EQUAL) {

                    // 後臺要求停止
                    ChargingTerminalProcess(gunIndex);
                }

                // LCM => Charging
                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_CHARGING;
                }

                break;

            case S_ALARM:
            case S_TERMINATING:
                if (isModeChange(gunIndex)) {
                    if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
                        strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "Local");
                    }

                    if (pDcChargingInfo->SystemStatus == S_ALARM) {
                        log_info("============================= S_ALARM(%x)  ============================= ", gunIndex);
                        UpdateErrorCodeToOcpp(gunIndex);

                        if (strcmp((char *)pDcChargingInfo->StartDateTime, "") != EQUAL) {
                            OcppStopTransation(gunIndex);
                        }

                        TheEndCharging(gunIndex);
                    } else {
                        log_info("============================= S_TERMINATING(%x) ============================= ", gunIndex);
                    }

                    //log_info ("terminating......................... %x ", gunIndex);
                    StopGunInfoTimeoutDet(gunIndex);
                    ShmDcCommonData->pGunInfo[gunIndex].RecordEnergyTime = time((time_t*)NULL);
                    if (ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption != 0)
                        DB_Update_PowerConsumption(gunIndex, ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption);

                }

                //checkPileEndGfdResult(gunIndex, pDcChargingInfo->Type, pDcChargingInfo->SystemStatus);
                if (ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P' && ShmDcCommonData->pGunInfo[gunIndex].isMeterStart &&
                    pDcChargingInfo->RelayK1K2Status == NO && !_isStop[gunIndex]) {
                        pSysInfo->DcMeterTransactionAction[gunIndex].ActionCmd = _DC_METER_TRANSACTION_ACTION_STOP;
                        log_info("Gun%d Stop Dc Meter Transcation",gunIndex);
                        _isStop[gunIndex] = TRUE;
                }
                if (pDcChargingInfo->SystemStatus == S_ALARM) {
                    if (pDcChargingInfo->ConnectorPlugIn == NO ) {
                        StartGunInfoTimeoutDet(gunIndex,Timeout_ExitComplete);
                    }
                    /*
                    if (pDcChargingInfo->ConnectorPlugIn == NO &&
                            GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) >= 10000000) {
                        if (ShmDcCommonData->pGunInfo[gunIndex].ReservationStatus) {
                            setChargerMode(gunIndex, MODE_RESERVATION);
                        } else {
                            setChargerMode(gunIndex, MODE_IDLE);
                        }
                    }
                    */
                } else {
                    if (pDcChargingInfo->Type == _Type_Chademo) {
                        if (isEvStopCharging_chademo(gunIndex) == YES ||
                                isPrechargeStatus_chademo(gunIndex) <= 0) {
                            setChargerMode(gunIndex, MODE_COMPLETE);
                        }
                    } else if (pDcChargingInfo->Type == _Type_GB) {
                        if (isEvStopCharging_gb(gunIndex) == YES ||
                                isPrechargeStatus_gb(gunIndex) <= 0) {
                            setChargerMode(gunIndex, MODE_COMPLETE);
                        }
                    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
                        if (isEvStopCharging_ccs(gunIndex) == YES &&
                                (isPrechargeStatus_ccs(gunIndex) >= 53 ||
                                 isPrechargeStatus_ccs(gunIndex) == 0  ||
                                 isPrechargeStatus_ccs(gunIndex) == 13 ||
                                 isPrechargeStatus_ccs(gunIndex) == 14)
                           ) {
                            setChargerMode(gunIndex, MODE_COMPLETE);
                        }
                    }
                }

                if (ShmSysConfigAndInfo->SysConfig.ModelName[3] == 'P') {
                    if (pDcChargingInfo->SystemStatus == S_ALARM && ShmDcCommonData->pGunInfo[gunIndex].isMeterStop &&
                            pSysInfo->DcMeterTransactionAction[gunIndex].OcmfInfoReady)
                    {
                        pSysInfo->DcMeterTransactionAction[gunIndex].OcmfInfoReady = NO;
                        DB_Update_ocmf(gunIndex);
                        StoreOcmfFile(gunIndex,ShmSelectGunInfo->PricesInfo[gunIndex].TransactionId,FALSE);
                        DB_Update_PowerConsumption(gunIndex, ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption);
                    }
                }

                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_COMPLETE;
                }
                break;

            case S_COMPLETE:
                if (isModeChange(gunIndex)) {
                    log_info ("============================= S_COMPLETE(%x) ============================= ", gunIndex);
                    if (strcmp((char *)pDcChargingInfo->StartDateTime, "") != EQUAL) {
                        OcppStopTransation(gunIndex);
                    }
                    TheEndCharging(gunIndex);
                }
                
                if (pSysInfo->DcMeterTransactionAction[gunIndex].OcmfInfoReady && ShmDcCommonData->pGunInfo[gunIndex].isMeterStop) {
                    pSysInfo->DcMeterTransactionAction[gunIndex].OcmfInfoReady = NO;
                    DB_Update_ocmf(gunIndex);
                    StoreOcmfFile(gunIndex,ShmSelectGunInfo->PricesInfo[gunIndex].TransactionId,FALSE);
                    DB_Update_PowerConsumption(gunIndex, ShmDcCommonData->pGunInfo[gunIndex].PowerConsumption);
                }
                if (pDcChargingInfo->ConnectorPlugIn == NO ) {
                        StartGunInfoTimeoutDet(gunIndex,Timeout_ExitComplete);
                }
                /*
                if (pDcChargingInfo->ConnectorPlugIn == NO &&
                        GetClockTimeoutValue(pDcChargingInfo->ConnectorTimeout) >= 10000000) {
                    if (ShmDcCommonData->pGunInfo[gunIndex].ReservationStatus) {
                        setChargerMode(gunIndex, MODE_RESERVATION);
                    } else {
                        setChargerMode(gunIndex, MODE_IDLE);
                    }
                    destroySelGun(gunIndex); //Jerry add
#if defined DD360 || defined DD3660ComBox
                    connectorPageRestoreIdle();
#endif
                }
*/
                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_COMPLETE;
                }
                break;

            case S_CCS_PRECHARGE_ST0:
                if (isModeChange(gunIndex)) {
                    log_info("============================= CCS Precharge Processing 1(%x) ============================= ", gunIndex);
                    StopGunInfoTimeoutDet(gunIndex);
                    StartGunInfoTimeoutDet(gunIndex, Timeout_ForCcsPrechargeDet);
                }

                if (pDcChargingInfo->GroundFaultStatus == GFD_FAIL) {
                    // GFD 錯誤停止
                    RecordAlarmCode(gunIndex, "012235");
                    ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = YES;
                }

                checkEvBoardReqStop(pDcChargingInfo->SystemStatus, gunIndex);

                // 等待 EV 小板 (CCS) 通知可以開始 Precharge
                // 切換 D+ Relay to Precharge Relay
                if (isPrechargeStatus_ccs(gunIndex) == 39 ||
                        isPrechargeStatus_ccs(gunIndex) == 40) {
                    if ((pDcChargingInfo->RelayKPK2Status == YES || pDcChargingInfo->PantographFlag == YES) &&
                            pDcChargingInfo->PrechargeStatus != PRECHARGE_READY)
                        //if (pDcChargingInfo->PrechargeStatus != PRECHARGE_PRERELAY_PASS)
                    {
                        //log_info("Send precharge ready 1..........%x, status = %d ",
                        //         gunIndex,
                        //         isPrechargeStatus_ccs(gunIndex));
                        if (isPrechargeStatus_ccs(gunIndex) == 39) {
                            log_info("Conn %x, Precharge ready, CCS status = PreChargeResponse (%d) ",
                                     gunIndex,
                                     isPrechargeStatus_ccs(gunIndex));
                        } else if (isPrechargeStatus_ccs(gunIndex) == 40) {
                            log_info("Conn %x, Precharge ready, CCS status = PowerDeliveryRequest start (%d) ",
                                     gunIndex,
                                     isPrechargeStatus_ccs(gunIndex));
                        }

                        pDcChargingInfo->PrechargeStatus = PRECHARGE_READY;
                    }
                } else if (isPrechargeStatus_ccs(gunIndex) == 45 ||
                           isPrechargeStatus_ccs(gunIndex) == 46
                          ) {
                    setChargerMode(gunIndex, MODE_CCS_PRECHARGE_STEP1);
                }

                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
                break;

            case S_CCS_PRECHARGE_ST1:
                if (isModeChange(gunIndex)) {
                    log_info("============================= CCS Precharge Processing 2(%x) ============================= ", gunIndex);
                }

                if (pDcChargingInfo->GroundFaultStatus == GFD_FAIL) {
                    // GFD 錯誤停止
                    RecordAlarmCode(gunIndex, "012235");
                    ShmDcCommonData->ConnectErrList[gunIndex].GunBits.CCSGfdTrip = YES;
                }

                checkEvBoardReqStop(pDcChargingInfo->SystemStatus, gunIndex);

                // 等待小板通知進入充電
                // 切換 D+ Relay to Precharge Relay
                if (pDcChargingInfo->RelayK1K2Status == YES || pDcChargingInfo->PantographFlag == YES) {
                    pDcChargingInfo->PrechargeStatus = PRECHARGE_READY;
                    setChargerMode(gunIndex, MODE_CHARGING);
                }

                if (pSysInfo->CurGunSelected == gunIndex) {
                    pSysInfo->ConnectorPage = _LCM_PRE_CHARGE;
                }
                break;
           case S_MAINTAIN:
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_MAINTAIN(%x) ============================= ", gunIndex);
                    //pSysInfo->SystemPage = _PAGE_MAINTAIN;
                    StopSystemTimeoutDet();
                    if (pSysInfo->FirmwareUpdate == YES) {
                        if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
                            pSysInfo->SystemPage = _LCM_FIX;
                        }
                        continue;
                    }
                    if (pDcChargingInfo->IsAvailable == NO) {
                        log_info("Gun%d is not availbale");
                        break;
                    }
                    /*
                    if (pSysWarning->Level != WARN_LV_ER) {
                        if (!DisplaySelfTestFailReason()) { //DS60-120 add
                            log_info("Soft reboot for retry self-tets. ");
                            sleep(3);
                            KillAllTask();
                            system("/usr/bin/run_evse_restart.sh");
                        }
                    }
                    */
                    if (pSysWarning->Level == WARN_LV_ER) { //DS60-120 add
                        KillTaskExceptPrimary();
                    } else {
                        KillTask();
                    }
                    /*
                    if (pSysInfo->SelfTestSeq == _STEST_FAIL)
                        StopProcessingLoop();
                        */
                }

                if (pSysInfo->SelfTestSeq == _STEST_FAIL) {
                    SelfTestRun();
                    StopSystemTimeoutDet();
                    sleep(3);
                    break;
                }
                if (pDcChargingInfo->IsAvailable && pSysInfo->SelfTestSeq == _STEST_COMPLETE) {
                    if (pSysWarning->Level == WARN_LV_ER)
                        setChargerMode(gunIndex, MODE_FAULT);
                    else
                        setChargerMode(gunIndex, MODE_IDLE);
                }
#ifndef DD360Audi
                if (pSysInfo->CurGunSelected == gunIndex) {
                    if (CheckDispenserGeneration() != _DISPENSER_GENERATION_3_5) {
                        pSysInfo->SystemPage = _LCM_FIX;
                    }
                }
#endif
                break;
           case S_UPDATE:
                if (isModeChange(gunIndex)) {
                    log_info("============================= S_UPDATE(%x) ============================= ", gunIndex);
                }
                if (!pSysInfo->FirmwareUpdate) {
                    setChargerMode(gunIndex, MODE_IDLE);
                }
                break;
            default:
                if (isModeChange(gunIndex)) {
                    log_info("============================= UNKONWN (%x) ============================= ", gunIndex);
                }
                if (pSysConfig->TotalConnectorCount >= 2) {
                    pDcInfo = (struct ChargingInfoData *)GetDcChargingInfoData((gunIndex ? LEFT_GUN_NUM : RIGHT_GUN_NUM));
                } else {
                    pDcInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
                }
                if (pSysInfo->SelfTestSeq != _STEST_FAIL && !IntoOperateProcess(pDcInfo->SystemStatus)) {
                    log_info("Gun%d into UNKOWN status, Dispenser will soft reset",gunIndex);
                    TryCloseWatchdog();
                    system("/usr/bin/run_evse_restart.sh");
                }
            }//switch
            TryFeedWatchdog();
        }//for

#if defined DD360Audi
        if (pSysInfo->SystemPage != _LCM_SELECT_GUN) {
#else
        if (pSysInfo->SystemPage != _LCM_NONE) {
#endif //defined DD360Audi
            ChangeLcmByIndex(pSysInfo->SystemPage);
        } else {
            bool dcPageRun = false;
            if (pGunIndexInfo->AcGunIndex > 0 && pSysInfo->CurGunSelectedByAc != NO_DEFINE) {
                pAcChargingInfo = (struct ChargingInfoData *)GetAcChargingInfoData(0);

                if (pAcChargingInfo->SystemStatus == S_IDLE) {
                    ChangeLcmByIndex(_LCM_IDLE);
                } else if (pAcChargingInfo->SystemStatus == S_PREPARNING) {
                    ChangeLcmByIndex(_LCM_PRE_CHARGE);
                } else if (pAcChargingInfo->SystemStatus == S_CHARGING) {
                    ChangeLcmByIndex(_LCM_CHARGING);
                } else if (pAcChargingInfo->SystemStatus == S_TERMINATING ||
                           pAcChargingInfo->SystemStatus == S_COMPLETE) {
                    ChangeLcmByIndex(_LCM_COMPLETE);
                } else {
                    dcPageRun = true;
                }
            } else {
                dcPageRun = true;
            }

            if (dcPageRun) {
                ChangeLcmByIndex(pSysInfo->ConnectorPage);
            }
        }

        //for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
        //    pDcChargingInfo =  (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);
        //    checkEvBoardAlarmState(pDcChargingInfo->Type);
        //    checkChillerAlarmState();
        //    //if (checkChillerAlarmState(gunIndex) == ABNORMAL) {
        //    //    break;
        //    //}
        //}
        TryFeedWatchdog();
        usleep(WHILE_LOOP_TIME);
    }

    return FAIL;
}