/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "adc.h"
#include "crc.h"
#include "flash_if.h"
#include "gpio.h"
#include "iwdg.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "cp_detection.h"
#include "W25QXX.h"
#include "usbd_cdc_if.h"
#include "time.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

uint32_t alarm_record_code[32] =
{
    0x00012200,         // Input OVP
    0x00012203,         // Input UVP
    0x00012216,         // Output OCP
    0x00012223,         // Over temperature
    0x00012255,         // Ground fault
    0x00023703,         // Pilot error
    0x00012233,         // AC CCID
    0x00012233,         // DC CCID

    0x00012256,         // MCU self test
    0x00012258,         // Hand shaking timeout
    0x00012251,         // Emergency stop
    0x00011009,         // Relay welding
    0x00011032,         // Leak module test fail
    0x00011034,         // shutter fault
    0x00012212,         // L1 Power drop
    0x00012262,         // Circuit short

    0x00011033,         // Maximum Output Current setup error
    0x00011010,         // AC output relay  driving fault
    0x00011035,         // Ble module broken
    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000,

    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000,
    0x00000000
};

uint32_t binCRCTarget, binCRCCal;
__IO uint32_t flashdestination;
__IO uint32_t newdestination;

volatile unsigned long  ulHighFrequencyTimerTicks;

sCPModuleResult_t CpDetectionResult;

#ifndef FUNC_CP_ADC_MODIFY
sCPVoltageBoundary_t CpBoundary = {
                        CP_P12V_HIGH,
                        CP_P12V_LOW,
                        CP_P9V_HIGH,
                        CP_P9V_LOW,
                        CP_P6V_HIGH,
                        CP_P6V_LOW,
                        CP_P3V_HIGH,
                        CP_P3V_LOW,
                        CP_0V_HIGH,
                        CP_0V_LOW,
                        CP_N12V_HIGH,
                        CP_N12V_LOW,
                    };

sCPVoltageBoundary_t SpecDefBoundary = {
                        CP_SPEC_P12V_HIGH,
                        CP_SPEC_P12V_LOW,
                        CP_SPEC_P9V_HIGH,
                        CP_SPEC_P9V_LOW,
                        CP_SPEC_P6V_HIGH,
                        CP_SPEC_P6V_LOW,
                        CP_SPEC_P3V_HIGH,
                        CP_SPEC_P3V_LOW,
                        CP_SPEC_0V_HIGH,
                        CP_SPEC_0V_LOW,
                        CP_SPEC_N12V_HIGH,
                        CP_SPEC_N12V_LOW,
                    };

sCPVoltageHysteresis_t CpHysteresis = {
                        HYSTERESIS_P12V_HIGH,
                        HYSTERESIS_P12V_LOW,
                        HYSTERESIS_P9V_HIGH,
                        HYSTERESIS_P9V_LOW,
                        HYSTERESIS_P6V_HIGH,
                        HYSTERESIS_P6V_LOW,
                        HYSTERESIS_P3V_HIGH,
                        HYSTERESIS_P3V_LOW,
                        HYSTERESIS_0V_HIGH,
                        HYSTERESIS_0V_LOW,
                    };
#endif //FUNC_CP_ADC_MODIFY

struct EVSE Charger;
const unsigned char CharacterArray[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
uint32_t test_logA = 0 ;
uint32_t test_logB = 0 ;

extern I2C_HandleTypeDef hi2c2;
/* USER CODE END Variables */
#ifndef DISABLE_OS_ETH_TASK
osThreadId ethTaskHandle;
#endif

osThreadId uartTaskHandle;
osThreadId adcTaskHandle;
osThreadId timeoutTaskHandle;
osThreadId rfidTaskHandle;
osThreadId led_speakerTaskHandle;
osThreadId cpTaskHandle;
osThreadId alarmTaskHandle;
osThreadId bleTaskHandle;
osThreadId memoryTaskHandle;
osThreadId wifiTaskHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

#ifdef FUNC_RS485_SLAVE
uint8_t isValidCheckSum_IAP(uint8_t *RxBuf);
#else
uint8_t isValidCheckSum_IAP(void);
#endif

uint8_t isValidCheckSum_BLE(void);
uint8_t isValidCheckSum_WIFI(void);
void setChargerMode(uint8_t mode);
uint8_t isModeChange(void);
uint8_t isMode(uint8_t mode);
uint8_t rfidCheckSumCal(uint8_t *data, uint8_t length);
uint8_t Test_LeakModule(void);
uint8_t Valid_RFID_SN(void);
void recordAlarmHis(void);
uint8_t recordChargingHis(uint8_t isColdLoadPickUp, uint32_t statusCode);
void setLedMotion(uint8_t action);
void SetADCWDGBoundary( void);
void getlastRecord(void);
void getRotarySwitchSetting(void);
void CLC_Corr_Gain_Par(uint16_t SpecData_H ,uint16_t SpecData_L ,uint16_t MCUData_H , uint16_t MCUData_L , float *GainA , float *GainB ) ;
void CLC_Corr_Gain_Par2(uint16_t SpecData_H ,uint16_t SpecData_L ,uint16_t MCUData_H , uint16_t MCUData_L , float *GainA , float *GainB , uint8_t *PosorNeg ) ;
uint8_t Array_data_Check ( uint8_t *s1, uint8_t *s2 ) ;
void Relay_Control_Function (void) ;
uint8_t WatchDogLeakRawDataCheck_Event(void) ;
uint16_t getBrightnessDuty(uint16_t max_duty);
void parseVersionInfoFromModelname(void);

void HTK_GetBufferString(const u8* buf, const u8 len, char* szOutBuf);
void HTK_PrintBufferString(const u8* buf, const u8 len);

#ifdef ENABLE_PRINT_IMCP_MSG
int CheckPrintImcpMsg(uint8_t MsgID);
#endif

#ifdef MODIFY_IMCP
void UpdateCheckSum(uint8_t *Buf, uint16_t Len);
#endif

#ifdef MODIFY_COLD_LOAD_PICKUP_DELAY
void ColdLoadPickup_Delay(const char* Description);
#endif
#ifdef FUNC_FORCE_RUN_CSU_MODE_WITH_DC_MODELNAME
void Update_McuCtrlMode(void);
#endif
#ifdef MODIFY_DC_RS485_UPGRADE_ISSUE
void RS485_TX_Enable(void);
void RS485_TX_Disable(void);
void Prefix_UartTX(uint8_t* TxBuf, uint8_t* RxBuf);
void Postfix_UartTX(uint8_t* TxBuf, uint8_t* RxBuf);
#endif

/* USER CODE END FunctionPrototypes */

#ifndef DISABLE_OS_ETH_TASK
void StartEthTask(void const * argument);
#endif

void StartUartTask(void const * argument);
void StartAdcTask(void const * argument);
void StartTimeoutTask(void const * argument);
void StartRfidTask(void const * argument);
void StartLedSpeakerTask(void const * argument);
void StartCpTask(void const * argument);
void StartAlarmTask(void const * argument);
void StartBleTask(void const * argument);
void StartMemoryTask(void const * argument);
void StartWifiTask(void const * argument);

extern void MX_USB_DEVICE_Init(void);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* Hook prototypes */
void configureTimerForRunTimeStats(void);
unsigned long getRunTimeCounterValue(void);

/* USER CODE BEGIN 1 */
/* Functions needed when configGENERATE_RUN_TIME_STATS is on */
__weak void configureTimerForRunTimeStats(void)
{
  ulHighFrequencyTimerTicks = 0ul;
}

__weak unsigned long getRunTimeCounterValue(void)
{
  return ulHighFrequencyTimerTicks;
}
/* USER CODE END 1 */

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */

void UpdateFirmwareVersion(void)
{
#ifdef FUNC_FW_VER_TRACE

#if (FW_VER_TYPE == FW_VER_TYPE_DEVELOP)
    sprintf(Charger.Ver_FW, "D%4.2f.X0.0007.P0", FW_VER_NUM * 0.01);
#elif (FW_VER_TYPE == FW_VER_TYPE_FORMAL)

#ifdef FORCE_VER_WITH_T_PREFIX

    //---------------
#ifdef FORCE_VER_WITH_F_PREFIX
    sprintf(Charger.Ver_FW, "F%4.2f.X0.0011.P0", FW_VER_NUM * 0.00001);
#else
    sprintf(Charger.Ver_FW, "T%4.2f.X0.0011.P0", FW_VER_NUM * 0.00001);
#endif
    //---------------

    //sprintf(Charger.Ver_FW, "T%4.2f.X0.0011.P0", FW_VER_NUM * 0.00001);

#else //FORCE_VER_WITH_T_PREFIX
    sprintf(Charger.Ver_FW, "V%4.2f.X0.0007.P0", FW_VER_NUM * 0.00001);
#endif //FORCE_VER_WITH_T_PREFIX

#elif (FW_VER_TYPE == FW_VER_TYPE_TEST)
    sprintf(Charger.Ver_FW, "T%4.2f.X0.0007.P0", FW_VER_NUM * 0.00001);
#endif

#else //FUNC_FW_VER_TRACE

  //sprintf(Charger.Ver_FW, "V0.05.X0.0007.P0");
  //sprintf(Charger.Ver_FW, "V0.06.X0.0007.P0"); //20210611

#endif //FUNC_FW_VER_TRACE

#ifdef FUNC_VERSION_USE_NEW_SPEC_20240926
    //Indicate firmware belong which module board
    //L: LED board
    //R: Relay board
    //C: CHAdeMO board
    //G: GBT board
    //F: Fan board
    //D: DCM 407
    //A: AC main board
    //S: CCS board
    //M: CSU board
    Charger.Ver_FW[6] = 'A';

    //0: For formal release specification
    //1: For lab certificate specification
#ifdef FUNC_VERSION_FOR_LAB_CERTIFICATE_SPEC
    Charger.Ver_FW[7] = '1';
#else
    Charger.Ver_FW[7] = '0';
#endif
#endif //FUNC_VERSION_USE_NEW_SPEC_20240926
}

//---------------
#ifdef FUNC_STM32_FLASH_INFO

enum { STM32_UID_LEN = 12 }; //96 bits (12 bytes)

typedef struct _STM32_Flash_Info
{
    union
    {
        u8 m_UID[STM32_UID_LEN];
        u32 m_UIDw[3];
    };
    u32 m_DeviceID;
    u32 m_FlashSizeKB;
}
STM32_Flash_Info, *PSTM32_Flash_Info;

void STM32_Flash_Info_Init(PSTM32_Flash_Info p)
{
    memset(p, 0, sizeof(STM32_Flash_Info));
}

void STM32_Flash_Info_Read(PSTM32_Flash_Info p)
{
    //UID
    memcpy(p->m_UID, (u8*)UID_BASE, STM32_UID_LEN);

    //Device ID
    p->m_DeviceID = (uint32_t)(READ_BIT(DBGMCU->IDCODE, DBGMCU_IDCODE_DEV_ID));

    //Flash size
    p->m_FlashSizeKB = (uint32_t)(READ_REG(*((uint32_t *)FLASHSIZE_BASE)) & 0xFFFF);
}

void STM32_Flash_Info_Disp(PSTM32_Flash_Info p)
{
    XP("[FlashInfo]------------------------\r\n");
    //UID
    HTK_ByteArray2HexStr_XP("UID", p->m_UID, 0, STM32_UID_LEN);

    //Device ID
    XP("DeviceID: 0x%03X\r\n", p->m_DeviceID);
    {
        char *s = "DeviceFamily: ";
        if (p->m_DeviceID == 0x413)
        {
            XP("%sSTM32F40xxx/F41xxx\r\n", s);
        }
        else if (p->m_DeviceID == 0x419)
        {
            XP("%sSTM32F42xxx/F43xxx\r\n", s);
        }
        else
        {
            XP("%sUnknow\r\n", s);
        }
    }
    //Flash size
    XP("DeviceFlashSize: %d Kbytes\r\n", p->m_FlashSizeKB);

}

void STM32_Flash_Info_Proc(void)
{
    PSTM32_Flash_Info p = HTK_Malloc(sizeof(STM32_Flash_Info));
    if (p != NULL)
    {
        STM32_Flash_Info_Init(p);
        STM32_Flash_Info_Read(p);
        STM32_Flash_Info_Disp(p);
    }
    else
    {
        XP("PSTM32_Flash_Info malloc NG\r\n");
    }
}

#endif //FUNC_STM32_FLASH_INFO

#ifdef FUNC_STM32_FLASH_OPTION_BYTES

typedef struct _STM32_Flash_OB
{

    FLASH_OBProgramInitTypeDef m_SetOB;
    FLASH_OBProgramInitTypeDef m_CurOB;

    u8 m_nRST_STDBY:  1;    //0: Reset generated when entering the Standby mode
                            //1: No reset generated

    u8 m_nRST_STOP:   1;    //0: Reset generated when entering the Stop mode
                            //1: No reset generated

    u8 m_WDG_SW:      1;    //0: Hardware independent watchdog
                            //1: Software independent watchdog

}
STM32_Flash_OB, *PSTM32_Flash_OB;

void STM32_Flash_OB_Init(PSTM32_Flash_OB p)
{
    memset(p, 0, sizeof(STM32_Flash_OB));

    //Set default
    p->m_SetOB.OptionType   = OPTIONBYTE_WRP /*| OPTIONBYTE_RDP*/ | OPTIONBYTE_USER | OPTIONBYTE_BOR;
    p->m_SetOB.WRPState     = OB_WRPSTATE_ENABLE;
    p->m_SetOB.Banks        = 0;
    p->m_SetOB.BORLevel     = OB_BOR_LEVEL3;
    p->m_SetOB.USERConfig   = OB_IWDG_SW | OB_STOP_NO_RST | OB_STDBY_NO_RST;

//#ifdef FUNC_USE_STM32_SBSFU
//    //Sector_0~4: Write Protection; Sector_5~11: No Write Protection
//    p->m_SetOB.WRPSector    = OB_WRP_SECTOR_0 | OB_WRP_SECTOR_1 | OB_WRP_SECTOR_2 | OB_WRP_SECTOR_3 | OB_WRP_SECTOR_4;
//    p->m_SetOB.RDPLevel     = OB_RDP_LEVEL_1;
//#else
    //Sector_0~11: No Write Protection
    p->m_SetOB.WRPSector    = ~OB_WRP_SECTOR_All;
    p->m_SetOB.RDPLevel     = OB_RDP_LEVEL_0;
//#endif

}

void STM32_Flash_OB_Read(PSTM32_Flash_OB p)
{
    __HAL_FLASH_PREFETCH_BUFFER_DISABLE();
    HAL_FLASHEx_OBGetConfig(&p->m_CurOB);
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();

    p->m_nRST_STDBY = BIT_GET(p->m_CurOB.USERConfig, 7);
    p->m_nRST_STOP = BIT_GET(p->m_CurOB.USERConfig, 6);
    p->m_WDG_SW = BIT_GET(p->m_CurOB.USERConfig, 5);
}

void STM32_Flash_OB_WriteDefault(PSTM32_Flash_OB p)
{
    XP("<Write default OB>\r\n");
    __HAL_FLASH_PREFETCH_BUFFER_DISABLE();
    HAL_FLASH_Unlock();
    HAL_FLASH_OB_Unlock();
    {
        {
            XP("<Set OB Default>\r\n");
            HAL_FLASHEx_OBProgram(&p->m_SetOB);
            HAL_FLASH_OB_Launch();
        }

        {
            FLASH_OBProgramInitTypeDef ob;
            memcpy(&ob, &p->m_SetOB, sizeof(p->m_SetOB));
            ob.OptionType = OPTIONBYTE_WRP;
            ob.WRPState = OB_WRPSTATE_DISABLE;

            ob.WRPSector = (~p->m_SetOB.WRPSector) & OB_WRP_SECTOR_All;

            XP("<Set OB.WRPSector => Disable>\r\n");
            HAL_FLASHEx_OBProgram(&ob);
            HAL_FLASH_OB_Launch();
        }

        if (p->m_CurOB.RDPLevel == OB_RDP_LEVEL_0 && p->m_SetOB.RDPLevel == OB_RDP_LEVEL_1)
        {
            FLASH_OBProgramInitTypeDef ob;
            memcpy(&ob, &p->m_SetOB, sizeof(p->m_SetOB));
            ob.OptionType = OPTIONBYTE_RDP;

            XP("<Set OB.RDPLevel => Level 1> Please power off and then power on to restart !\r\n");
            HAL_FLASHEx_OBProgram(&ob);
            HAL_FLASH_OB_Launch();

            /* Set the OPTSTRT bit in OPTCR register */
//            XP("*(__IO uint8_t *)OPTCR_BYTE0_ADDRESS |= FLASH_OPTCR_OPTSTRT [BEG]\r\n");
//            *(__IO uint8_t *)OPTCR_BYTE0_ADDRESS |= FLASH_OPTCR_OPTSTRT;
//            XP("*(__IO uint8_t *)OPTCR_BYTE0_ADDRESS |= FLASH_OPTCR_OPTSTRT [BEG]\r\n");
            //HAL_Delay(1000);
            //NVIC_SystemReset();
        }
    }
    HAL_FLASH_OB_Lock();
    HAL_FLASH_Lock();
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
}

void STM32_Flash_OB_Disp(PSTM32_Flash_OB p)
{
    XP("[OB]-------------------------------\r\n");
    XP("OptionType: 0x%08X\r\n", p->m_CurOB.OptionType);
    XP("WRPState  : 0x%08X\r\n", p->m_CurOB.WRPState);

    XP("WRPSector : 0x%08X\r\n", p->m_CurOB.WRPSector);
    {
        for (int i = 0; i < 12; i++)
        {
            XP("\tSector_%d: %s Protection\r\n", i, BIT_GET(p->m_CurOB.WRPSector, i) == 1 ? "No" : "Write");
        }
    }

    XP("Banks     : 0x%08X\r\n", p->m_CurOB.Banks);
    XP("RDPLevel  : 0x%08X (0: 0xAA, 1: 0x55, 2: 0xCC)\r\n", p->m_CurOB.RDPLevel);
    XP("BORLevel  : 0x%08X (3: 0x00, 2: 0x04, 1: 0x08, OFF: 0x0C)\r\n", p->m_CurOB.BORLevel);

    XP("USERConfig: 0x%02X\r\n", p->m_CurOB.USERConfig);
    {
        XP("\tnRST_STDBY = %d (%s)\r\n", p->m_nRST_STDBY, (p->m_nRST_STDBY == 0 ? "STDBY_RST(0)" : "STDBY_NO_RST(0x80)"));
        XP("\tnRST_STOP = %d (%s)\r\n", p->m_nRST_STOP, (p->m_nRST_STOP == 0 ? "STOP_RST(0)" : "STOP_NO_RST(0x40)"));
        XP("\tWDG_SW = %d (%s)\r\n", p->m_WDG_SW, (p->m_WDG_SW == 0 ? "IWDG_HW(0)" : "IWDG_SW(0x20)"));
    }
}

HTK_BOOL STM32_Flash_OB_IsDefault(PSTM32_Flash_OB p)
{
    XP("m_CurOB.BORLevel   = 0x%08X,   m_SetOB.BORLevel   = 0x%08X\r\n", p->m_CurOB.BORLevel, p->m_SetOB.BORLevel);
    XP("m_CurOB.RDPLevel   = 0x%08X,   m_SetOB.RDPLevel   = 0x%08X\r\n", p->m_CurOB.RDPLevel, p->m_SetOB.RDPLevel);
    XP("m_CurOB.USERConfig = 0x%08X,   m_SetOB.USERConfig = 0x%08X\r\n", p->m_CurOB.USERConfig, p->m_SetOB.USERConfig);
    XP("m_CurOB.WRPSector  = 0x%08X,   m_SetOB.WRPSector  = 0x%08X\r\n", p->m_CurOB.WRPSector, p->m_SetOB.WRPSector);
    XP("(~p->m_SetOB.WRPSector) & OB_WRP_SECTOR_All           = 0x%08X\r\n", (~p->m_SetOB.WRPSector) & OB_WRP_SECTOR_All);

    if  (
            (p->m_CurOB.BORLevel == p->m_SetOB.BORLevel) &&
            (p->m_CurOB.RDPLevel == p->m_SetOB.RDPLevel) &&
            (p->m_CurOB.USERConfig == p->m_SetOB.USERConfig) &&
            (p->m_CurOB.WRPSector == ((~p->m_SetOB.WRPSector) & OB_WRP_SECTOR_All))
        )
    {
        XP("<OB is Default>\r\n");
        return HTK_TRUE;
    }
    else
    {
        XP("<OB is NOT Default>\r\n");
        return HTK_FALSE;
    }
}

void STM32_Flash_OB_ProcDefault(void)
{
    PSTM32_Flash_OB p = HTK_Malloc(sizeof(STM32_Flash_OB));
    if (p != NULL)
    {
        STM32_Flash_OB_Init(p);
        STM32_Flash_OB_Read(p);
        STM32_Flash_OB_Disp(p);

        if (!STM32_Flash_OB_IsDefault(p))
        {
            STM32_Flash_OB_WriteDefault(p);
            STM32_Flash_OB_Read(p);
            STM32_Flash_OB_Disp(p);
            if (STM32_Flash_OB_IsDefault(p))
            {
                XP("<Write default OB success>\r\n");
            }
            else
            {
                XP("<Write default OB fail>\r\n");
            }
        }
    }
    else
    {
        XP("STM32_Flash_OB malloc NG\r\n");
    }
}
#endif //FUNC_STM32_FLASH_OPTION_BYTES

void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

#ifdef FUNC_BOOT_TICK
    Charger.m_BootTick = HAL_GetTick();
#endif

#ifdef FUNC_STM32_FLASH_INFO
    STM32_Flash_Info_Proc();
#endif //FUNC_STM32_FLASH_INFO

#ifdef FUNC_STM32_FLASH_OPTION_BYTES
    STM32_Flash_OB_ProcDefault();
#endif

  UpdateFirmwareVersion();

  sprintf(Charger.Ver_HW, "RA2");

  HAL_GPIO_WritePin(OUT_PHY_Reset_GPIO_Port, OUT_PHY_Reset_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port, OUT_Leak_Test_Pin, GPIO_PIN_SET);
  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of ethTask */

#ifndef DISABLE_OS_ETH_TASK
  osThreadDef(ethTask, StartEthTask, osPriorityIdle, 0, 1024);
  ethTaskHandle = osThreadCreate(osThread(ethTask), NULL);
#endif

  /* definition and creation of uartTask */
  osThreadDef(uartTask, StartUartTask, osPriorityNormal, 0, 1024);
  uartTaskHandle = osThreadCreate(osThread(uartTask), NULL);

  /* definition and creation of adcTask */
  osThreadDef(adcTask, StartAdcTask, osPriorityRealtime, 0, 256);
  adcTaskHandle = osThreadCreate(osThread(adcTask), NULL);

  /* definition and creation of timeoutTask */
  osThreadDef(timeoutTask, StartTimeoutTask, osPriorityAboveNormal, 0, 128);
  timeoutTaskHandle = osThreadCreate(osThread(timeoutTask), NULL);

  /* definition and creation of rfidTask */
  osThreadDef(rfidTask, StartRfidTask, osPriorityIdle, 0, 256);
  rfidTaskHandle = osThreadCreate(osThread(rfidTask), NULL);

  /* definition and creation of led_speakerTask */
  osThreadDef(led_speakerTask, StartLedSpeakerTask, osPriorityAboveNormal, 0, 128);
  led_speakerTaskHandle = osThreadCreate(osThread(led_speakerTask), NULL);

  /* definition and creation of cpTask */
  osThreadDef(cpTask, StartCpTask, osPriorityHigh, 0, 256);
  cpTaskHandle = osThreadCreate(osThread(cpTask), NULL);

  /* definition and creation of alarmTask */
  osThreadDef(alarmTask, StartAlarmTask, osPriorityHigh, 0, 256);
  alarmTaskHandle = osThreadCreate(osThread(alarmTask), NULL);

  /* definition and creation of bleTask */
#ifdef LOCAL_LINK_BLE
  osThreadDef(bleTask, StartBleTask, osPriorityHigh, 0, 1024);
  bleTaskHandle = osThreadCreate(osThread(bleTask), NULL);
#endif
  /* definition and creation of memoryTask */
  osThreadDef(memoryTask, StartMemoryTask, osPriorityIdle, 0, 256);
  memoryTaskHandle = osThreadCreate(osThread(memoryTask), NULL);

  /* definition and creation of wifiTask */
#ifdef LOCAL_LINK_WIFI
  osThreadDef(wifiTask, StartWifiTask, osPriorityIdle, 0, 1024);
  wifiTaskHandle = osThreadCreate(osThread(wifiTask), NULL);
#endif

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

#ifndef DISABLE_OS_ETH_TASK
/* USER CODE BEGIN Header_StartEthTask */
/**
* @brief Function implementing the ethTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartEthTask */
void StartEthTask(void const * argument)
{
  /* init code for USB_DEVICE */
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN StartEthTask */
    /* Infinite loop */
    for(;;)
    {
        osDelay(1);
    }
  /* USER CODE END StartEthTask */
}
#endif //DISABLE_OS_ETH_TASK

/* USER CODE BEGIN Header_StartUartTask */
/**
  * @brief  Function implementing the uartTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartUartTask */
void StartUartTask(void const * argument)
{
  /* USER CODE BEGIN StartUartTask */
  //uuart

#ifndef DISABLE_PRINT_RTOS_MSG
  uint8_t       pcWriteBuffer[1024];
#endif

  uint8_t       endFlag[4]={0x55,0xaa,0x55,0xaa};
  __IO uint32_t flash;
  uint32_t      checksum;
  uint8_t       dbgIdx;

  #if defined(DEBUG) || defined(RTOS_STAT)
  DEBUG_INFO("========== AP initial OK ==========\n\r");
  DEBUG_INFO(" Version: %s\n\r", Charger.Ver_FW);
  DEBUG_INFO("===================================\n\r");
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)  != RESET) DEBUG_INFO("Reset flag: Pin reset \r\n");
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)  != RESET) DEBUG_INFO("Reset flag: POR reset \r\n");
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)  != RESET) DEBUG_INFO("Reset flag: SW reset \r\n");
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) DEBUG_INFO("Reset flag: IWDG reset \r\n");
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET) DEBUG_INFO("Reset flag: WWDG reset \r\n");
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST) != RESET) DEBUG_INFO("Reset flag: LP reset \r\n");
  DEBUG_INFO("\r\n");
  __HAL_RCC_CLEAR_RESET_FLAGS();
  #endif
  Charger.CSUisReady = OFF ;

#ifdef FUNC_RS485_SLAVE
  HAL_GPIO_WritePin(OUT_Meter_485_DE_GPIO_Port, OUT_Meter_485_DE_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(OUT_Meter_485_RE_GPIO_Port, OUT_Meter_485_RE_Pin, GPIO_PIN_RESET);
#endif

#ifdef FUNC_RELAY_OFF_WHEN_GET_TWICE_OFF_CMD
    u8 CsuSetRelayOffCount = 0;
#endif

#ifdef FUNC_REQUEST_OFF_WHEN_GET_TWICE_OFF_CMD
    u8 CsuSetRequestOffCount = 0;
#endif

  /* Infinite loop */
  for(;;)
  {

    timerEnable(TIMER_IDX_RTOS_STAT, 500);
    if(timer[TIMER_IDX_RTOS_STAT].isAlarm)
    {

      switch(dbgIdx)
      {
          case 0:
            #ifdef RTOS_STAT
#ifndef DISABLE_PRINT_RTOS_MSG
              printf("=================================================\r\n");
              printf("Task_Name \tState \tPrior \tStack \tTask_Id\r\n");
              vTaskList((char *)&pcWriteBuffer);
              printf("%s\r\n", pcWriteBuffer);
              printf("-------------------------------------------------\r\n");
              printf("Task_Name \tRun_Time(10us) \tUsage_Percent\r\n");
              vTaskGetRunTimeStats((char *)&pcWriteBuffer);
              printf("%s\r\n", pcWriteBuffer);
#endif //DISABLE_PRINT_RTOS_MSG
            #endif
            dbgIdx++;
            break;
          case 1:
#ifdef FUNC_EMPX10_CUSTOMIZE
              DEBUG_INFO("Firmware version: %s (AWeMP/ID:%d)\r\n", Charger.Ver_FW, Charger.m_EMPX10_RS485_ClientAddr);
#else
              DEBUG_INFO("Firmware version: %s\r\n", Charger.Ver_FW);
#endif

#ifdef FUNC_BUILD_DATE_TIME
              DEBUG_INFO("Build: %s %s\r\n", __DATE__, __TIME__); //ex: Build: Mar 10 2022 14:53:25
#endif
              //DEBUG_INFO("MCU_Control_Mode: %x\r\n",Charger.memory.EVSE_Config.data.item.MCU_Control_Mode);
              DEBUG_INFO("MCU_Control_Mode: %x (%s)\r\n",Charger.memory.EVSE_Config.data.item.MCU_Control_Mode,
                         Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_CSU ? "CSU" : "No CSU");
              DEBUG_INFO("ModelName: %s\r\n",Charger.memory.EVSE_Config.data.item.ModelName);
              DEBUG_INFO("SerialNumber: %s\r\n",Charger.memory.EVSE_Config.data.item.SerialNumber);
#ifdef FUNC_BOOT_TICK
              DEBUG_INFO("UpTime(s): %d\r\n", (HAL_GetTick() - Charger.m_BootTick) / 1000);
#endif
            dbgIdx++;
            break;
          case 2:
              if (Charger.CCID_Module_Type == CCID_MODULE_CORMEX)
              {
                DEBUG_INFO("Charger.CCID_Module_Type is CCID_MODULE_CORMEX\n\r");
              }
              else if (Charger.CCID_Module_Type == CCID_MODULE_VAC)
              {
                DEBUG_INFO("Charger.CCID_Module_Type is CCID_MODULE_VAC\n\r");
              }
              DEBUG_INFO("System mode: %d\r\n", Charger.Mode);
              DEBUG_INFO("Alarm code: 0x%08X\r\n", Charger.Alarm_Code);
#ifdef FUNC_SHOW_RELAY_INFO
            DEBUG_INFO("Relay action: Main(%d)\r\n", Charger.Relay_Action);
#endif

            dbgIdx++;
            break;
          case 3:
              DEBUG_INFO("Original Voltage[0]: %f\r\n", adc_value.ADC3_IN9_Voltage_L1.value/100.0);
              DEBUG_INFO("Original Current[0]: %f\r\n", adc_value.ADC3_IN7_Current_L1.value/100.0);
            dbgIdx++;
            break;
          case 4:
              DEBUG_INFO("Correction Voltage[0]: %f\r\n", Charger.Voltage[0]/100.0);
              DEBUG_INFO("Correction Current[0]: %f\r\n", Charger.Current[0]/100.0);
            dbgIdx++;
            break;
          case 5:
              DEBUG_INFO("PE(ADC): %d\r\n", adc_value.ADC3_IN4_GMI_VL1.value );
              DEBUG_INFO("PE(V): %f\r\n", adc_value.ADC3_IN4_GMI_VL1.value*3.3/4095 );
              DEBUG_INFO("adc_value.ADC2_IN5_Welding.value : %d(unit:0.01v)\r\n", adc_value.ADC2_IN5_Welding.value  );
              DEBUG_INFO("Charger.temperature.SystemAmbientTemp : %d(unit:C)\r\n", Charger.temperature.SystemAmbientTemp);
            dbgIdx++;
            break;
          case 6:
              if (Charger.CCID_Module_Type == CCID_MODULE_CORMEX)
              {
                DEBUG_INFO("Original GF[0]: %fmA\r\n", adc_value.ADC2_IN6_GF.value/100.0);
                DEBUG_INFO("Charger.Leak_Current: %fmA\r\n", Charger.Leak_Current/100.0);
              }
              else
              {
                DEBUG_INFO("Temperature ADC raw data : %d\r\n",  adc_value.ADC3_IN15_Temp.value);
                DEBUG_INFO("Temperature : %d\r\n", Charger.temperature.SystemAmbientTemp);
                DEBUG_INFO("ADC3_Buffer[1] (ADC): %d(unit:ADC)\r\n", ADC3_Buffer[1]  );
                DEBUG_INFO("Charger.Led_Mode: %d\r\n", Charger.Led_Mode  );
              }
            dbgIdx++;
            break;
          case 7:
              DEBUG_INFO("CP+(ADC): %d(unit:ADC)\r\n",CpDetectionResult.PositiveValue  );
              DEBUG_INFO("CP-(ADC): %d(unit:ADC)\r\n",CpDetectionResult.NegativeValue  );
              if(CpDetectionResult.PositiveValue>0)
              {
#ifdef FUNC_CP_ADC_MODIFY
                DEBUG_INFO("CP +voltage: %f\r\n", CP_GET_OPA_VIN_USE_ADC(CpDetectionResult.PositiveValue));
#else
                DEBUG_INFO("CP +voltage: %f\r\n", (float)((1.59131-((3.3*CpDetectionResult.PositiveValue)/4095))*(475/53.6)));
#endif
              }
              else
              {
                DEBUG_INFO("CP +voltage: 0\r\n");
              }
              if(CpDetectionResult.NegativeValue>0)
              {
#ifdef FUNC_CP_ADC_MODIFY
                DEBUG_INFO("CP -voltage: %f\r\n", CP_GET_OPA_VIN_USE_ADC(CpDetectionResult.NegativeValue));
#else
                DEBUG_INFO("CP -voltage: %f\r\n", (float)((1.59131-((3.3*CpDetectionResult.NegativeValue)/4095))*(475/53.6)));
#endif
              }else
              {
                DEBUG_INFO("CP -voltage: 0\r\n");
              }
              DEBUG_INFO("CP state: %d\r\n", Charger.CP_State);
            dbgIdx++;
            break;
          case 8:
              DEBUG_INFO("Power_Consumption_Cumulative: %d (0.0001KWH)\r\n", Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative);
              DEBUG_INFO("Current rating value: %d A\r\n", Charger.maxRatingCurrent);
              if (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent>=20)
              {
                 DEBUG_INFO("OCP tigger UL: %d\r\n", (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent*110)-100 );
                 DEBUG_INFO("OCP tigger IEC: %d\r\n", (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent*125)-100 );
              }
              else
              {
                DEBUG_INFO("OCP tigger UL: %d\r\n", (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent+1)*100 );
                DEBUG_INFO("OCP tigger IEC: %d\r\n", (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent*125)-100 );
              }
              DEBUG_INFO("Charger.am3352.isRequestOn: %d\r\n", Charger.am3352.isRequestOn);

#ifdef FUNC_OCP_WITH_PP
#ifdef MODIFY_OCP_PROC_WITH_MODELNAME_IDX_3_EURO_SPEC
            DEBUG_INFO("#OCPInfo(%d, %d, %d, %d) [%s]\r\n",
                Charger.m_OCP_CurMaxCurr, Charger.OCP_Magnification,
                Charger.m_OCP_BegThreshold, Charger.m_OCP_EndThreshold,
                Charger.m_bModelNameWithEuroSpecOCP ? "EuroSpec" : "NotEuroSpec");
#else
            DEBUG_INFO("#OCPInfo(%d, %d, %d, %d)\r\n",
                Charger.m_OCP_CurMaxCurr, Charger.OCP_Magnification,
                Charger.m_OCP_BegThreshold, Charger.m_OCP_EndThreshold);
#endif //MODIFY_OCP_PROC_WITH_MODELNAME_IDX_3_EURO_SPEC
#endif //FUNC_OCP_WITH_PP

#ifdef FUNC_GET_TRIP_TIME
                if (Charger.m_TripBeg != 0 && Charger.m_TripBeg < Charger.m_TripEnd)
                {
                    DEBUG_INFO("Trip period: %d\r\n", Charger.m_TripEnd - Charger.m_TripBeg);
                }
#endif
            dbgIdx++;
            break;
          case 9:
              if (Charger.Alarm_Code & ALARM_OVER_VOLTAGE)
                DEBUG_INFO("ALARM_OVER_VOLTAGE \n\r");
              if (Charger.Alarm_Code & ALARM_UNDER_VOLTAGE)
                DEBUG_INFO("ALARM_UNDER_VOLTAGE \n\r");
              if (Charger.Alarm_Code & ALARM_OVER_CURRENT)
                DEBUG_INFO("ALARM_OVER_CURRENT \n\r");
              if (Charger.Alarm_Code & ALARM_OVER_TEMPERATURE)
                DEBUG_INFO("ALARM_OVER_TEMPERATURE \n\r");
              if (Charger.Alarm_Code & ALARM_GROUND_FAIL)
                DEBUG_INFO("ALARM_GROUND_FAIL \n\r");
              if (Charger.Alarm_Code & ALARM_CP_ERROR)
                DEBUG_INFO("ALARM_CP_ERROR \n\r");
              if (Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)
                DEBUG_INFO("ALARM_CURRENT_LEAK_AC \n\r");
              if (Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC)
                DEBUG_INFO("ALARM_CURRENT_LEAK_DC \n\r");
              if (Charger.Alarm_Code & ALARM_MCU_TESTFAIL)
                DEBUG_INFO("ALARM_MCU_TESTFAIL \n\r");
            dbgIdx++;
            break;
          case 10:
              if (Charger.Alarm_Code & ALARM_HANDSHAKE_TIMEOUT)
                DEBUG_INFO("ALARM_HANDSHAKE_TIMEOUT \n\r");
              if (Charger.Alarm_Code & ALARM_EMERGENCY_STOP)
                DEBUG_INFO("ALARM_EMERGENCY_STOP \n\r");
              if (Charger.Alarm_Code & ALARM_RELAY_STATUS)
                DEBUG_INFO("ALARM_RELAY_STATUS \n\r");
              if (Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL)
                DEBUG_INFO("ALARM_LEAK_MODULE_FAIL \n\r");
              if (Charger.Alarm_Code & ALARM_SHUTTER_FAULT)
                DEBUG_INFO("ALARM_SHUTTER_FAULT \n\r");
              if (Charger.Alarm_Code & ALARM_LOCKER_FAULT)
                DEBUG_INFO("ALARM_LOCKER_FAULT \n\r");
              if (Charger.Alarm_Code & ALARM_POWER_DROP)
                DEBUG_INFO("ALARM_POWER_DROP \n\r");
              if (Charger.Alarm_Code & ALARM_CIRCUIT_SHORT)
                DEBUG_INFO("ALARM_CIRCUIT_SHORT \n\r");
              if (Charger.Alarm_Code & ALARM_ROTATORY_SWITCH_FAULT)
                DEBUG_INFO("ALARM_ROTATORY_SWITCH_FAULT \n\r");
              if (Charger.Alarm_Code & ALARM_RELAY_DRIVE_FUALT)
                DEBUG_INFO("ALARM_RELAY_DRIVE_FUALT \n\r");
            dbgIdx++;
            break;
          default:
              getlastRecord();
            dbgIdx = 0;
            break;
      }
      timerRefresh(TIMER_IDX_RTOS_STAT);
    }

    HAL_IWDG_Refresh(&hiwdg);

#ifdef FUNC_RS485_SLAVE
    if(UART_IAP_recv_end_flag == 1 || UART_RS485_recv_end_flag == 1)
#else
    if(UART_IAP_recv_end_flag == 1)
#endif
    {
#ifdef FUNC_UART_IAP_TX_BUF_INIT_ZERO
      uint8_t tx[UART_BUFFER_SIZE] = { 0 };
#else
      uint8_t tx[UART_BUFFER_SIZE];
#endif

#ifdef MODIFY_UART_TX_LEN_FROM_U8_TO_U16
      uint16_t tx_len;
#else
      uint8_t tx_len;
#endif

      uint8_t chksum = 0;
      uint8_t tmpBuf = 0 ;

      // Protocol process
#ifdef FUNC_RS485_SLAVE

        uint8_t *CurRxBuf = NULL;
        uint16_t *pCurRxBuf_RxLen = NULL;
        uint8_t *pCurRecvEndFlag = NULL;
        UART_HandleTypeDef *pUartHandle = NULL;

        if (UART_IAP_recv_end_flag == 1 && isValidCheckSum_IAP(UART_IAP_rx_buffer) == ON)
        {
            CurRxBuf = UART_IAP_rx_buffer;
            pCurRxBuf_RxLen = &UART_IAP_rx_len;
            pCurRecvEndFlag = &UART_IAP_recv_end_flag;
            pUartHandle = &IAP_USART;
#ifdef FUNC_RELAY_OFF_WHEN_CSU_CMD_TIMEOUT
            Charger.m_CSU_RxTick = HAL_GetTick();
#endif
        }
        else if (UART_RS485_recv_end_flag == 1 && isValidCheckSum_IAP(UART_RS485_rx_buffer) == ON)
        {
            CurRxBuf = UART_RS485_rx_buffer;
            pCurRxBuf_RxLen = &UART_RS485_rx_len;
            pCurRecvEndFlag = &UART_RS485_recv_end_flag;
            pUartHandle = &RS485_USART;
#ifdef FUNC_RELAY_OFF_WHEN_CSU_CMD_TIMEOUT  //DC Model
            Charger.m_CSU_RxTick = HAL_GetTick();
#endif
        }
        if (CurRxBuf != NULL)
#else
      uint8_t *CurRxBuf = UART_IAP_rx_buffer;
      if(isValidCheckSum_IAP() == ON)
#endif
      {
        Charger.CSUisReady = ON ;

#ifdef DEBUG_EMPX10_COMM
        if (CurRxBuf == UART_RS485_rx_buffer)
        {
            XP("-------------------------------------------\r\n");
            HTK_ByteArray2HexStr_XP(NULL, CurRxBuf, 0, IMCP_FM_HEAD_LEN + HTK_U16(CurRxBuf[IMCP_FM_DATALEN_LSB_IDX]) + IMCP_FM_TAIL_LEN);
        }
#endif //DEBUG_EMPX10_COMM

#ifdef ENABLE_PRINT_IMCP_MSG

#ifdef FUNC_RS485_SLAVE
#ifdef PRINT_IMCP_MSG_ONLY_ON_UPDATEPORT
        if (CurRxBuf == UART_IAP_rx_buffer && CheckPrintImcpMsg(CurRxBuf[IMCP_FM_MSGID_IDX]))
        {
            XP("-------------------------------------------\r\n");
            HTK_ByteArray2HexStr_XP(NULL, CurRxBuf, 0, IMCP_FM_HEAD_LEN + HTK_U16(CurRxBuf[IMCP_FM_DATALEN_LSB_IDX]) + IMCP_FM_TAIL_LEN);
        }
#else
        if (CheckPrintImcpMsg(CurRxBuf[IMCP_FM_MSGID_IDX]))
        {
            XP("-------------------------------------------\r\n");
            HTK_ByteArray2HexStr_XP(NULL, CurRxBuf, 0, IMCP_FM_HEAD_LEN + HTK_U16(CurRxBuf[IMCP_FM_DATALEN_LSB_IDX]) + IMCP_FM_TAIL_LEN);
        }
#endif //PRINT_IMCP_MSG_ONLY_ON_UPDATEPORT

#else //FUNC_RS485_SLAVE
        if (CheckPrintImcpMsg(UART_IAP_rx_buffer[IMCP_FM_MSGID_IDX]))
        {
            XP("-------------------------------------------\r\n");
            HTK_ByteArray2HexStr_XP(NULL, UART_IAP_rx_buffer, 0, IMCP_FM_HEAD_LEN + HTK_U16(UART_IAP_rx_buffer[IMCP_FM_DATALEN_LSB_IDX]) + IMCP_FM_TAIL_LEN);
        }
#endif //FUNC_RS485_SLAVE

#endif //ENABLE_PRINT_IMCP_MSG

#ifdef FUNC_RS485_SLAVE
        switch (CurRxBuf[3])
#else
        switch (UART_IAP_rx_buffer[3])
#endif
        {
          /*
            Query message
          */
          case PROTOCOL_MESSAGE_QUERY_FW_VER:
            tx_len = 7 + (strlen(Charger.Ver_FW));
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_FW_VER;
            tx[4] = strlen(Charger.Ver_FW)&0xff;
            tx[5] = (strlen(Charger.Ver_FW)>>0x08) & 0xff;
            for(uint8_t idx=0;idx<strlen(Charger.Ver_FW);idx++)
            {
                tx[6+idx] = Charger.Ver_FW[idx];
            }

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[6+(tx[4] | (tx[5]<<8))] = chksum;

            break;

          case PROTOCOL_MESSAGE_QUERY_HW_VER:
            tx_len = 7 + strlen(Charger.Ver_HW);
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_HW_VER;
            tx[4] = strlen(Charger.Ver_HW) & 0xff;
            tx[5] = (strlen(Charger.Ver_HW)>>0x08) & 0xff;
            for(uint8_t idx=0;idx<strlen(Charger.Ver_HW);idx++)
            {
                tx[6+idx] = Charger.Ver_HW[idx];
            }

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[6+(tx[4] | (tx[5]<<8))] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_PRESENT_INPUT_VOLTAGE:
            tx_len = 14;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_PRESENT_INPUT_VOLTAGE;
            tx[4] = 0x07;
            tx[5] = 0x00;
            tx[6] = 0x00;
            tx[7] = (((Charger.Voltage[0]/10)>>0) & 0xff);
            tx[8] = (((Charger.Voltage[0]/10)>>8) & 0xff);
            tx[9] = (((Charger.Voltage[1]/10)>>0) & 0xff);
            tx[10] = (((Charger.Voltage[1]/10)>>8) & 0xff);
            tx[11] = (((Charger.Voltage[2]/10)>>0) & 0xff);
            tx[12] = (((Charger.Voltage[2]/10)>>8) & 0xff);

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[13] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_PRESENT_OUTPUT_VOLTAGE:
            tx_len = 15;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_PRESENT_OUTPUT_VOLTAGE;
            tx[4] = 0x08;
            tx[5] = 0x00;
            tx[6] = 0x00;
            tx[7] = 0x00;
            tx[8] = 0x00;
            tx[9] = 0x00;
            tx[10] = 0x00;
            tx[11] = 0x00;
            tx[12] = 0x00;
            tx[13] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[14] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_FAN_SPEED:
            tx_len = 15;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_FAN_SPEED;
            tx[4] = 0x08;
            tx[5] = 0x00;
            tx[6] = 0x00;
            tx[7] = 0x00;
            tx[8] = 0x00;
            tx[9] = 0x00;
            tx[10] = 0x00;
            tx[11] = 0x00;
            tx[12] = 0x00;
            tx[13] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[14] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_TEMPERATURE:
            tx_len = 15;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_TEMPERATURE;
            tx[4] = 0x08;
            tx[5] = 0x00;
            tx[6] = (((Charger.temperature.SystemAmbientTemp+60)>>0) & 0xff);
            tx[7] = (((Charger.temperature.CcsConnectorTemp+60)>>0) & 0xff);
            tx[8] = 0x00;
            tx[9] = 0x00;
            tx[10] = 0x00;
            tx[11] = 0x00;
            tx[12] = 0x00;
            tx[13] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[14] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_AUX_POWER_VOLTAGE:
            tx_len = 15;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_AUX_POWER_VOLTAGE;
            tx[4] = 0x08;
            tx[5] = 0x00;
            tx[6] = 0x00;
            tx[7] = 0x00;
            tx[8] = 0x00;
            tx[9] = 0x00;
            tx[10] = 0x00;
            tx[11] = 0x00;
            tx[12] = 0x00;
            tx[13] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[14] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_RELAY_OUTPUT_STATUS:
            tx_len = 9;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_RELAY_OUTPUT_STATUS;
            tx[4] = 0x02;
            tx[5] = 0x00;
            tx[6] = ((Relay1_Action_Get()==GPIO_RELAY1_ACTION_OFF)?0:1);
            tx[7] = ((Relay2_Action_Get()==GPIO_RELAY2_ACTION_OFF)?0:1);

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
                chksum ^= tx[6 + idx];
            }
            tx[8] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_GFD_ADC_VALUE:
            tx_len = 15;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_GFD_ADC_VALUE;
            tx[4] = 0x08;
            tx[5] = 0x00;
            tx[6] = ((adc_value.ADC2_IN6_GF.value>>0) & 0xff);
            tx[7] = ((adc_value.ADC2_IN6_GF.value>>8) & 0xff);
            tx[8] = 0x00;
            tx[9] = 0x00;
            tx[10] = 0x00;
            tx[11] = 0x00;
            tx[12] = 0x00;
            tx[13] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[14] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_INPUT_GPIO_STATUS:
            tx_len = 9;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_INPUT_GPIO_STATUS;
            tx[4] = 0x02;
            tx[5] = 0x00;
            tx[6] = 0x00;
            tx[7] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[8] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_ALARM_LOG:
            tx_len = 17;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_ALARM_LOG;
            tx[4] = 0x0a;
            tx[5] = 0x00;
            tx[6] = CurRxBuf[7] ;
            tx[7] = CurRxBuf[8] ;

            tx[8] = CharacterArray[(Charger.memory.hisAlarm.data.item[CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0xF0000000)>>28];
            tx[9] = CharacterArray[(Charger.memory.hisAlarm.data.item[CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x0F000000)>>24];
            tx[10] = CharacterArray[(Charger.memory.hisAlarm.data.item[CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x00F00000)>>20];
            tx[11] = CharacterArray[(Charger.memory.hisAlarm.data.item[CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x000F0000)>>16];
            tx[12] = CharacterArray[(Charger.memory.hisAlarm.data.item[CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x0000F000)>>12];
            tx[13] = CharacterArray[(Charger.memory.hisAlarm.data.item[CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x00000F00)>>8];
            tx[14] = CharacterArray[(Charger.memory.hisAlarm.data.item [CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x000000F0)>>4];
            tx[15] = CharacterArray[ Charger.memory.hisAlarm.data.item [CurRxBuf[7] | (CurRxBuf[8]>>8)].alarmCode & 0x0000000F ];

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }


            tx[16] = chksum;

            /*
            tx[8] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.year>>0) & 0xff);
            tx[9] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.year>>8) & 0xff);
            tx[10] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.month>>0) & 0xff);;
            tx[11] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.day>>0) & 0xff);
            tx[12] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.hour>>0) & 0xff);
            tx[13] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.min>>0) & 0xff);
            tx[14] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].DateTime.sec>>0) & 0xff);
            tx[15] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].alarmCode>>0) & 0xff);
            tx[16] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].alarmCode>>8) & 0xff);
            tx[17] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].alarmCode>>16) & 0xff);
            tx[18] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].alarmCode>>24) & 0xff);
            tx[19] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].mode>>0) & 0xff);
            tx[20] = ((Charger.memory.hisAlarm.data.item[UART_IAP_rx_buffer[7] | (UART_IAP_rx_buffer[8]<<8)].isRecover>0) & 0xff);

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[21] = chksum;
            */
            break;
          case PROTOCOL_MESSAGE_QUERY_SN:
            // head +checksum = 7 ,  SystemDateTimeyear month day = 8 , SerialNumber
            tx_len = 15 + strlen(Charger.memory.EVSE_Config.data.item.SerialNumber);
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_SN;
            tx[4] = (strlen(Charger.memory.EVSE_Config.data.item.SerialNumber)+8)&0xff;
            tx[5] = ((strlen(Charger.memory.EVSE_Config.data.item.SerialNumber)+8)>>0x08) & 0xff;

            tx[6] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.year/1000)+'0';
            tx[7] = ((Charger.memory.EVSE_Config.data.item.SystemDateTime.year%1000)/100)+'0';
            tx[8] = ((Charger.memory.EVSE_Config.data.item.SystemDateTime.year%100)/10)+'0';
            tx[9] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.year%10) +'0';
            tx[10] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.month/10) +'0';
            tx[11] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.month%10) +'0';
            tx[12] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.day/10) +'0';
            tx[13] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.day%10) +'0';

            for(uint8_t idx=0;idx<strlen(Charger.memory.EVSE_Config.data.item.SerialNumber);idx++)
            {
                tx[14+idx] = Charger.memory.EVSE_Config.data.item.SerialNumber[idx];
            }

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[6+(tx[4] | (tx[5]<<8))] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_MODEL_NAME:
            tx_len = 7 + strlen(Charger.memory.EVSE_Config.data.item.ModelName);;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_MODEL_NAME;
            tx[4] = strlen(Charger.memory.EVSE_Config.data.item.ModelName)&0xff;
            tx[5] = (strlen(Charger.memory.EVSE_Config.data.item.ModelName)>>0x08) & 0xff;
            for(uint8_t idx=0;idx<strlen(Charger.memory.EVSE_Config.data.item.ModelName);idx++)
            {
                tx[6+idx] = Charger.memory.EVSE_Config.data.item.ModelName[idx];
            }
            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[6+(tx[4] | (tx[5]<<8))] = chksum;
            break;
          case PROTOCOL_MESSAGE_QUERY_PARAMETER:
            tx_len = 11;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_PARAMETER;
            tx[4] = 0x04;
            tx[5] = 0x00;
            tx[6] = CurRxBuf[6];
            tx[7] = CurRxBuf[7];

            switch(CurRxBuf[6])
            {
                case INPUT_L1_AC_VOLTAGE:
                    tx[8] = Charger.memory.EVSE_Config.data.item.Correction_VL1[CurRxBuf[7]][1] & 0xff;
                    tx[9] = (Charger.memory.EVSE_Config.data.item.Correction_VL1[CurRxBuf[7]][1]>>8) & 0xff;
                  break;
                case INPUT_L2_AC_VOLTAGE:
                    tx[8] = Charger.memory.EVSE_Config.data.item.Correction_VL2[CurRxBuf[7]][1] & 0xff;
                    tx[9] = (Charger.memory.EVSE_Config.data.item.Correction_VL2[CurRxBuf[7]][1]>>8) & 0xff;
                  break;
                case INPUT_L3_AC_VOLTAGE:
                    tx[8] = Charger.memory.EVSE_Config.data.item.Correction_VL3[CurRxBuf[7]][1] & 0xff;
                    tx[9] = (Charger.memory.EVSE_Config.data.item.Correction_VL3[CurRxBuf[7]][1]>>8) & 0xff;
                  break;
                case OUTPUT_L1_CURRENT:
                    tx[8] = Charger.memory.EVSE_Config.data.item.Correction_CL1[CurRxBuf[7]][1] & 0xff;
                    tx[9] = (Charger.memory.EVSE_Config.data.item.Correction_CL1[CurRxBuf[7]][1]>>8) & 0xff;
                  break;
                case OUTPUT_L2_CURRENT:
                    tx[8] = Charger.memory.EVSE_Config.data.item.Correction_CL2[CurRxBuf[7]][1] & 0xff;
                    tx[9] = (Charger.memory.EVSE_Config.data.item.Correction_CL2[CurRxBuf[7]][1]>>8) & 0xff;
                  break;
                case OUTPUT_L3_CURRENT:
                    tx[8] = Charger.memory.EVSE_Config.data.item.Correction_CL3[CurRxBuf[7]][1] & 0xff;
                    tx[9] = (Charger.memory.EVSE_Config.data.item.Correction_CL3[CurRxBuf[7]][1]>>8) & 0xff;
                  break;
                case LEAK_CURRENT:
                      tx[8] = (Charger.memory.EVSE_Config.data.item.Correction_Leak[CurRxBuf[7]][1]/100) & 0xff;
                      tx[9] = ((Charger.memory.EVSE_Config.data.item.Correction_Leak[CurRxBuf[7]][1]/100)>>8) & 0xff;
                  break;
            }

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[10] = chksum;

            break;
          case PROTOCOL_MESSAGE_QUERY_RTC:
            tx_len = 21;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_RTC;
            tx[4] = 0x0e;
            tx[5] = 0x00;
            tx[6] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.year/1000)+'0';
            tx[7] = ((Charger.memory.EVSE_Config.data.item.SystemDateTime.year%1000)/100)+'0';
            tx[8] = ((Charger.memory.EVSE_Config.data.item.SystemDateTime.year%100)/10)+'0';
            tx[9] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.year%10) +'0';
            tx[10] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.month/10) +'0';
            tx[11] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.month%10) +'0';
            tx[12] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.day/10) +'0';
            tx[13] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.day%10) +'0';
            tx[14] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.hour/10) +'0';
            tx[15] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.hour%10) +'0';
            tx[16] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.min/10) +'0';
            tx[17] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.min%10) +'0';
            tx[18] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.sec/10) +'0';
            tx[19] = (Charger.memory.EVSE_Config.data.item.SystemDateTime.sec%10) +'0';

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[20] = chksum;
            break;


          case PROTOCOL_MESSAGE_QUERY_PRESENT_OUTPUT_CURRENT:
            tx_len = 19;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_PRESENT_OUTPUT_CURRENT;
            tx[4] = 0x0c;
            tx[5] = 0x00;
#ifdef FUNC_ZERO_CURRENT_WHEN_OUTP_OFF
            if (Charger.Relay_Action == GPIO_RELAY_ACTION_ON)
            {
                tx[6] = (((Charger.Current[0]/10)>>0) & 0xff);
                tx[7] = (((Charger.Current[0]/10)>>8) & 0xff);
                tx[8] = (((Charger.Current[1]/10)>>0) & 0xff);
                tx[9] = (((Charger.Current[1]/10)>>8) & 0xff);
                tx[10] = (((Charger.Current[2]/10)>>0) & 0xff);
                tx[11] = (((Charger.Current[2]/10)>>8) & 0xff);
            }
            else
            {
                tx[6] = 0;
                tx[7] = 0;
                tx[8] = 0;
                tx[9] = 0;
                tx[10] = 0;
                tx[11] = 0;
            }
#else
            tx[6] = (((Charger.Current[0]/10)>>0) & 0xff);
            tx[7] = (((Charger.Current[0]/10)>>8) & 0xff);
            tx[8] = (((Charger.Current[1]/10)>>0) & 0xff);
            tx[9] = (((Charger.Current[1]/10)>>8) & 0xff);
            tx[10] = (((Charger.Current[2]/10)>>0) & 0xff);
            tx[11] = (((Charger.Current[2]/10)>>8) & 0xff);
#endif
            tx[12] = 0x00;
            tx[13] = 0x00;
            tx[14] = 0x00;
            tx[15] = 0x00;
            tx[16] = 0x00;
            tx[17] = 0x00;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[18] = chksum;

            break;
          //edward 2019/08/27
          case PROTOCOL_MESSAGE_QUERY_EVSE_STATE:
            tx_len = 21;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_EVSE_STATE;
            tx[4] = 14;
            tx[5] = 0x00;
            tx[6] = Charger.CP_State;

#ifdef MODIFY_AC_EVSE_STATUS_MAX_CHARGING_CURRENT_VARIABLE
            tx[7] = (Charger.AC_MaxChargingCurrentOrDuty&0xff);
            tx[8] = Charger.AC_MaxChargingCurrentOrDuty>>8;
#else
            tx[7] = (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent&0xff);
            tx[8] = Charger.memory.EVSE_Config.data.item.MaxChargingCurrent>>8;
#endif
            uint16_t transfer_float;

            {
#ifdef FUNC_CP_ADC_MODIFY
                transfer_float = (uint16_t)(CpDetectionResult.PositiveValue == 0 ? 0 : HTK_GetPosFromZero(CP_GET_OPA_VIN_USE_ADC(CpDetectionResult.PositiveValue)) * 100);
#else
                //transfer_float = (uint16_t)((float)(((1.59131-((3.3*CpDetectionResult.PositiveValue)/4095))*(475/53.6)))*100);
#endif
            }

            tx[9] = (transfer_float&0xff);
            tx[10] = (transfer_float&0xff00)>>8;

            {
#ifdef FUNC_CP_ADC_MODIFY
                transfer_float = (uint16_t)(CpDetectionResult.NegativeValue == 0 ? 0 : HTK_GetNegFromZero(CP_GET_OPA_VIN_USE_ADC(CpDetectionResult.NegativeValue)) * 100);
#else
                //transfer_float = (uint16_t)((float)(((((3.3*CpDetectionResult.NegativeValue)/4095)-1.59131)*(475/53.6)))*100);
#endif
            }
            tx[11] = (transfer_float&0xff);
            tx[12] = (transfer_float&0xff00)>>8;

            tx[13] = 0x00;
            if(Charger.Relay_Action == GPIO_RELAY_ACTION_ON)
            {
              tx[14] = 0x01;
            }
            else
            {
              tx[14] = 0x00;
            }
            tx[15] = 0x00;
            tx[16] = 0x00;
            tx[17] = 0x00;
            tx[18] = Charger.maxRatingCurrent;

            tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set1_GPIO_Port, IN_AC_Current_Set1_Pin)?0:1)<<0;
            tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set2_GPIO_Port, IN_AC_Current_Set2_Pin)?0:1)<<1;
            tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set3_GPIO_Port, IN_AC_Current_Set3_Pin)?0:1)<<2;
            tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set4_GPIO_Port, IN_AC_Current_Set4_Pin)?0:1)<<3;
            tmpBuf += (HAL_GPIO_ReadPin(IN_GridType_Select_GPIO_Port, IN_GridType_Select_Pin)?0:1)<<4;
            tmpBuf += (HAL_GPIO_ReadPin(IN_Grid_Groundding_GPIO_Port, IN_Grid_Groundding_Pin)?0:1)<<5;

            tx[19] = tmpBuf;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[20] = chksum;
            break;

          case PROTOCOL_MESSAGE_QUERY_EVSE_ALARM:
            tx_len = 11;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_EVSE_ALARM;
            tx[4] = 4;
            tx[5] = 0x00;
            tx[6] = (Charger.Alarm_Code&0xff);
            tx[7] = (Charger.Alarm_Code&0xff00)>>8;
            tx[8] = (Charger.Alarm_Code&0xff0000)>>16;
            tx[9] = (Charger.Alarm_Code&0xff000000)>>24;
            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[10] = chksum;
            break;
          case PROTOCOL_MESSAGE_QUERY_BLE_STATE:
            tx_len = 10;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_BLE_STATE;
            tx[4] = 3;
            tx[5] = 0x00;

            tx[6] = 0x00 ;
            tx[7] = 0x00 ;
            tx[8] = 0x00 ;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[9] = chksum;
            break;
          case PROTOCOL_MESSAGE_QUERY_BLE_LOGIC_CENTRAL_ID:
            tx_len = 39;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_BLE_LOGIC_CENTRAL_ID;
            tx[4] = 32;
            tx[5] = 0x00;
            tx[6] = 'P';
            tx[7] = 'H';
            tx[8] = 'I';
            tx[9] = 'H';
            tx[10] = 'O';
            tx[11] = 'N';
            tx[12] = 'G';
            tx[13] = ' ';
            tx[14] = 'A';
            tx[15] = 'C';

            tx[16] = '-';
            tx[17] = 'S';
            tx[18] = 'i';
            tx[19] = 'm';
            tx[20] = 'p';
            tx[21] = 'l';
            tx[22] = 'e';
            tx[23] = ' ';
            tx[24] = '1';
            tx[25] = '2';

            tx[26] = '3';
            tx[27] = '4';
            tx[28] = '5';
            tx[29] = '6';
            tx[30] = '7';
            tx[31] = '8';
            tx[32] = '9';
            tx[33] = 'A';
            tx[34] = 'B';
            tx[35] = 'C';

            tx[36] = 'D';
            tx[37] = 'E';

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[38] = chksum;
            break;
          case PROTOCOL_MESSAGE_QUERY_POWER_CONSUME:
            tx_len = 11;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_POWER_CONSUME;
            tx[4] = 4;
            tx[5] = 0x00;
            tx[6] = ((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/100)&0xff);
            tx[7] = ((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/100)&0xff00)>>8;
            tx[8] = ((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/100)&0xff0000)>>16;
            tx[9] = ((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/100)&0xff000000)>>24;
            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[10] = chksum;
            break;


          case PROTOCOL_MESSAGE_QUERY_GUN_PLUGIN_TIMES:
            tx_len = 11;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_GUN_PLUGIN_TIMES;
            tx[4] = 4;
            tx[5] = 0x00;
            tx[6] = (Charger.memory.EVSE_Config.data.item.AcPlugInTimes&0xff);
            tx[7] = (Charger.memory.EVSE_Config.data.item.AcPlugInTimes&0xff00)>>8;
            tx[8] = (Charger.memory.EVSE_Config.data.item.AcPlugInTimes&0xff0000)>>16;
            tx[9] = (Charger.memory.EVSE_Config.data.item.AcPlugInTimes&0xff000000)>>24;
            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[10] = chksum;
            break;

          case PROTOCOL_MESSAGE_QUERY_EVSE_AUTH_MODE:
            tx_len = 9;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_EVSE_AUTH_MODE;
            tx[4] = 2;
            tx[5] = 0x00;
            tx[6] = Charger.memory.EVSE_Config.data.item.AuthMode;
            tx[7] = Charger.memory.EVSE_Config.data.item.OfflinePolicy;
            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[8] = chksum;
            break;

          case PROTOCOL_MESSAGE_QUERY_PRESENT_LEAK_CURRENT:
            tx_len = 9;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_QUERY_PRESENT_LEAK_CURRENT;
            tx[4] = 2;
            tx[5] = 0x00;
            tx[6] = Charger.Leak_Current/100;
            tx[7] = 0;
            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[8] = chksum;
            break;

          /*
            Config message
          */
          case PROTOCOL_MESSAGE_CONFIG_FAN_SPEED:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_FAN_SPEED;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;

            break;
          case PROTOCOL_MESSAGE_CONFIG_SN:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_SN;
            tx[4] = 0x01;
            tx[5] = 0x00;

#ifdef MODIFY_CONFIG_SN
            {
                uint16_t len = HTK_U16(CurRxBuf[4]);
                if (len < sizeof(Charger.memory.EVSE_Config.data.item.ModelName) && HTK_IS_DISP_CHAR(CurRxBuf[14]))
                {
                    //OK
                    tx[6] = 0x01;
                    tx[7] = 0x01;
                    memset(Charger.memory.EVSE_Config.data.item.SerialNumber, 0, ARRAY_SIZE(Charger.memory.EVSE_Config.data.item.SerialNumber));
                    memset(Charger.memory.EVSE_Config.data.item.System_ID, 0, ARRAY_SIZE(Charger.memory.EVSE_Config.data.item.System_ID));
                    for(uint16_t idx=0;idx<(len-8);idx++)
                    {
                        Charger.memory.EVSE_Config.data.item.SerialNumber[idx] = CurRxBuf[14+idx];
                    }
                    Charger.memory.EVSE_Config.data.item.SerialNumber[len-8] = '\0';
                    memcpy(Charger.memory.EVSE_Config.data.item.System_ID, Charger.memory.EVSE_Config.data.item.ModelName, strlen(Charger.memory.EVSE_Config.data.item.ModelName));
                    memcpy(&Charger.memory.EVSE_Config.data.item.System_ID[strlen(Charger.memory.EVSE_Config.data.item.ModelName)], Charger.memory.EVSE_Config.data.item.SerialNumber, len);

                    XP("#CONFIG_SN: %s\r\n", Charger.memory.EVSE_Config.data.item.SerialNumber);
                    //parseVersionInfoFromModelname() ;
                    Charger.memory.EVSE_Config.op_bits.update = ON;
                    break;
                }
                else
                {
                    //NG
                    tx[6] = 0x00;
                    tx[7] = 0x00;
                    break;
                }
            }
#else //MODIFY_CONFIG_SN
//            tx[6] = 0x01;
//            tx[7] = 0x01;
//
//            memset(Charger.memory.EVSE_Config.data.item.SerialNumber, 0x00, sizeof(Charger.memory.EVSE_Config.data.item.SerialNumber)/sizeof(Charger.memory.EVSE_Config.data.item.SerialNumber[0]));
//            memset(Charger.memory.EVSE_Config.data.item.System_ID, 0x00, sizeof(Charger.memory.EVSE_Config.data.item.System_ID)/sizeof(Charger.memory.EVSE_Config.data.item.System_ID[0]));
//            for(uint16_t idx=0;idx<((CurRxBuf[4] | (CurRxBuf[5]<<8))-8);idx++)
//            {
//                Charger.memory.EVSE_Config.data.item.SerialNumber[idx] = CurRxBuf[14+idx];
//            }
//            Charger.memory.EVSE_Config.data.item.SerialNumber[(CurRxBuf[4] | (CurRxBuf[5]<<8))-8] = '\0';
//            memcpy(Charger.memory.EVSE_Config.data.item.System_ID, Charger.memory.EVSE_Config.data.item.ModelName, strlen(Charger.memory.EVSE_Config.data.item.ModelName));
//            memcpy(&Charger.memory.EVSE_Config.data.item.System_ID[strlen(Charger.memory.EVSE_Config.data.item.ModelName)], Charger.memory.EVSE_Config.data.item.SerialNumber, (CurRxBuf[4] | (CurRxBuf[5]<<8)));
//
//            parseVersionInfoFromModelname() ;
//            Charger.memory.EVSE_Config.op_bits.update = ON;
//            break;
#endif //MODIFY_CONFIG_SN
          case PROTOCOL_MESSAGE_CONFIG_MODEL_NAME:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_MODEL_NAME;
            tx[4] = 0x01;
            tx[5] = 0x00;
#ifdef MODIFY_CONFIG_MODEL_NAME

            {
                uint16_t len = HTK_U16(CurRxBuf[4]);
                if (len < sizeof(Charger.memory.EVSE_Config.data.item.ModelName) && HTK_IS_DISP_CHAR(CurRxBuf[6]))
                {
                    //OK
                    tx[6] = 0x01;
                    tx[7] = 0x01;
                    memset(Charger.memory.EVSE_Config.data.item.ModelName, 0, ARRAY_SIZE(Charger.memory.EVSE_Config.data.item.ModelName));
                    memset(Charger.memory.EVSE_Config.data.item.System_ID, 0, ARRAY_SIZE(Charger.memory.EVSE_Config.data.item.System_ID));
                    for(uint16_t idx=0;idx<len;idx++)
                    {
                        Charger.memory.EVSE_Config.data.item.ModelName[idx] = CurRxBuf[6+idx];
                    }
                    Charger.memory.EVSE_Config.data.item.ModelName[len] = '\0';
                    memcpy(Charger.memory.EVSE_Config.data.item.System_ID, Charger.memory.EVSE_Config.data.item.ModelName, strlen(Charger.memory.EVSE_Config.data.item.ModelName));
                    memcpy(&Charger.memory.EVSE_Config.data.item.System_ID[strlen(Charger.memory.EVSE_Config.data.item.ModelName)], Charger.memory.EVSE_Config.data.item.SerialNumber, len);
                    XP("#CONFIG_MODEL_NAME: %s\r\n", Charger.memory.EVSE_Config.data.item.ModelName);
#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
                    Charger.m_bCCID_MustModify = HTK_TRUE;
#endif
                    parseVersionInfoFromModelname() ;
                    Charger.memory.EVSE_Config.op_bits.update = ON;
                    break;

                }
                else
                {
                    //NG
                    tx[6] = 0x00;
                    tx[7] = 0x00;
                    break;
                }
            }

#else //MODIFY_CONFIG_MODEL_NAME
//            tx[6] = 0x01;
//            tx[7] = 0x01;
//
//            memset(Charger.memory.EVSE_Config.data.item.ModelName, 0x00, sizeof(Charger.memory.EVSE_Config.data.item.ModelName)/sizeof(Charger.memory.EVSE_Config.data.item.ModelName[0]));
//            memset(Charger.memory.EVSE_Config.data.item.System_ID, 0x00, sizeof(Charger.memory.EVSE_Config.data.item.System_ID)/sizeof(Charger.memory.EVSE_Config.data.item.System_ID[0]));
//            for(uint16_t idx=0;idx<(CurRxBuf[4] | (CurRxBuf[5]<<8));idx++)
//            {
//                Charger.memory.EVSE_Config.data.item.ModelName[idx] = CurRxBuf[6+idx];
//            }
//            Charger.memory.EVSE_Config.data.item.ModelName[(CurRxBuf[4] | (CurRxBuf[5]<<8))] = '\0';
//            memcpy(Charger.memory.EVSE_Config.data.item.System_ID, Charger.memory.EVSE_Config.data.item.ModelName, strlen(Charger.memory.EVSE_Config.data.item.ModelName));
//            memcpy(&Charger.memory.EVSE_Config.data.item.System_ID[strlen(Charger.memory.EVSE_Config.data.item.ModelName)], Charger.memory.EVSE_Config.data.item.SerialNumber, (CurRxBuf[4] | (CurRxBuf[5]<<8)));
//
//            parseVersionInfoFromModelname() ;
//            Charger.memory.EVSE_Config.op_bits.update = ON;
//            break;
#endif //MODIFY_CONFIG_MODEL_NAME

          case PROTOCOL_MESSAGE_CONFIG_PARAMETER:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_PARAMETER;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[7] = chksum;                       //checksum

            switch(CurRxBuf[6])
            {
                case INPUT_L1_AC_VOLTAGE:
                  Charger.memory.EVSE_Config.data.item.Correction_VL1[CurRxBuf[7]][0] = adc_value.ADC3_IN9_Voltage_L1.value/10;
                  Charger.memory.EVSE_Config.data.item.Correction_VL1[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;
                case INPUT_L2_AC_VOLTAGE:
                  Charger.memory.EVSE_Config.data.item.Correction_VL2[CurRxBuf[7]][0] = Charger.Voltage[1];
                  Charger.memory.EVSE_Config.data.item.Correction_VL2[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;
                case INPUT_L3_AC_VOLTAGE:
                  Charger.memory.EVSE_Config.data.item.Correction_VL3[CurRxBuf[7]][0] = Charger.Voltage[2];
                  Charger.memory.EVSE_Config.data.item.Correction_VL3[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;
                case OUTPUT_L1_CURRENT:
                  Charger.memory.EVSE_Config.data.item.Correction_CL1[CurRxBuf[7]][0] = adc_value.ADC3_IN7_Current_L1.value/10;
                  Charger.memory.EVSE_Config.data.item.Correction_CL1[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;
                case OUTPUT_L2_CURRENT:
                  Charger.memory.EVSE_Config.data.item.Correction_CL2[CurRxBuf[7]][0] = Charger.Current[0];
                  Charger.memory.EVSE_Config.data.item.Correction_CL2[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;
                case OUTPUT_L3_CURRENT:
                  Charger.memory.EVSE_Config.data.item.Correction_CL3[CurRxBuf[7]][0] = Charger.Current[0];
                  Charger.memory.EVSE_Config.data.item.Correction_CL3[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;
                case LEAK_CURRENT:
                  Charger.memory.EVSE_Config.data.item.Correction_Leak[CurRxBuf[7]][0] = adc_value.ADC2_IN6_GF.value;   // 2500->25mA
                  Charger.memory.EVSE_Config.data.item.Correction_Leak[CurRxBuf[7]][1] = ((CurRxBuf[8] | (CurRxBuf[9]<<8))*100); // mA
                  DEBUG_INFO("Charger.memory.EVSE_Config.data.item.Correction_Leak[[0] = %d\r\n",Charger.memory.EVSE_Config.data.item.Correction_Leak[CurRxBuf[7]][0]);
                  DEBUG_INFO("Charger.memory.EVSE_Config.data.item.Correction_Leak[[1] = %d\r\n",Charger.memory.EVSE_Config.data.item.Correction_Leak[CurRxBuf[7]][1]);
                  break;
                case GROUND_FAULT_VOLTAGE: //max 3.3V
                  Charger.memory.EVSE_Config.data.item.Correction_GMI[CurRxBuf[7]][0] = (uint16_t)(adc_value.ADC3_IN4_GMI_VL1.value*10*3.3/4095) ;
                  Charger.memory.EVSE_Config.data.item.Correction_GMI[CurRxBuf[7]][1] = CurRxBuf[8] | (CurRxBuf[9]<<8);
                  break;

#ifdef FUNC_SIMU_CHARGE_CURRENT_OUTPUT
                case SIMU_CHARGE_CURRENT_CMD:
                    Charger.m_bEnableSimuChargeCurrent =
                        (
                            (
                                CurRxBuf[7] == SIMU_CHARGE_CURRENT_ON &&
                                HTK_U16(CurRxBuf[8]) == SIMU_CHARGE_CURRENT_ON_PWD
                            ) ? 1 : 0
                        );
                    XP("#CSU_ParameterSimuCurr: %s\r\n", Charger.m_bEnableSimuChargeCurrent ? "ON" : "OFF");
                  break;
#endif //FUNC_SIMU_CHARGE_CURRENT_OUTPUT

#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
                case SIMU_SWITCH_RELAY_WELDING_CMD:
                    Charger.m_bDisableRelayWelding =
                        (
                            (
                                CurRxBuf[7] == SIMU_SWITCH_RELAY_WELDING_DISABLE &&
                                HTK_U16(CurRxBuf[8]) == SIMU_SWITCH_RELAY_WELDING_PWD
                            ) ? 1 : 0
                        );
                    XP("#CSU_ParameterDisableRelayWelding: %s\r\n", Charger.m_bDisableRelayWelding ? "ON" : "OFF");

                    Charger.m_bDisableCCID = Charger.m_bDisableRelayWelding;
                    XP("#CSU_ParameterDisableCCID: %s\r\n", Charger.m_bDisableCCID ? "ON" : "OFF");

                    Charger.m_bSetOCP_32A = Charger.m_bDisableRelayWelding;
                    XP("#CSU_ParameterSetOCP_32A: %s\r\n", Charger.m_bSetOCP_32A ? "ON" : "OFF");
                  break;
#endif //FUNC_SWITCH_RELAY_WELDING_PROTECT


            }

#ifdef FUNC_SIMU_CHARGE_CURRENT_OUTPUT
#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
            if (CurRxBuf[6] != SIMU_CHARGE_CURRENT_CMD && CurRxBuf[6] != SIMU_SWITCH_RELAY_WELDING_CMD)
            {
                Charger.memory.EVSE_Config.op_bits.update = ON;
            }
#else //FUNC_SWITCH_RELAY_WELDING_PROTECT
            if (CurRxBuf[6] != SIMU_CHARGE_CURRENT_CMD)
            {
                Charger.memory.EVSE_Config.op_bits.update = ON;
            }
#endif //FUNC_SWITCH_RELAY_WELDING_PROTECT
#else //FUNC_SIMU_CHARGE_CURRENT_OUTPUT
            Charger.memory.EVSE_Config.op_bits.update = ON;
#endif //FUNC_SIMU_CHARGE_CURRENT_OUTPUT
            break;

          case PROTOCOL_MESSAGE_CONFIG_RELAY_OUTPUT:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_RELAY_OUTPUT;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[7] = chksum;



#ifndef USE_OLD_ONE_STEP_CHARGE_FOR_AW_NOODOE
            if (
#ifdef MODIFY_PROTOCOL_MESSAGE_CONFIG_RELAY_OUTPUT_CHECK_LEGACY_REQUEST
                    Charger.am3352.isRequestOn &&
#endif

#ifdef MODIFY_PROTOCOL_MESSAGE_CONFIG_RELAY_OUTPUT_CHECK_ALARM_CODE
                    Charger.Alarm_Code == 0 &&
#endif

#ifdef MODIFY_PROTOCOL_MESSAGE_CONFIG_RELAY_OUTPUT_CHECK_CP_PWM
                    Charger.m_CP_CurPWM != PWM_DUTY_FULL &&
#endif
                    Charger.CP_State == SYSTEM_STATE_C &&
                    CurRxBuf[9] == 0x07 //Main relay (0111b)
                )
            {
                Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
#ifdef FUNC_RELAY_OFF_WHEN_GET_TWICE_OFF_CMD
                CsuSetRelayOffCount = 0;
#endif
            }
            else
            {
#ifdef FUNC_RELAY_OFF_WHEN_GET_TWICE_OFF_CMD
                if (++CsuSetRelayOffCount >= 2)
                {
                    CsuSetRelayOffCount = 0;
					Charger.Relay_Action = GPIO_RELAY_ACTION_OFF ;
				}
#else //FUNC_RELAY_OFF_WHEN_GET_TWICE_OFF_CMD
                Charger.Relay_Action = GPIO_RELAY_ACTION_OFF ;
#endif //FUNC_RELAY_OFF_WHEN_GET_TWICE_OFF_CMD
            }
#endif //USE_OLD_ONE_STEP_CHARGE_FOR_AW_NOODOE

#ifdef FUNC_CSU_CMD_DEBUG
            XP("#CSU_Relay: %d\r\n", CurRxBuf[9]);
#endif
            DEBUG_INFO("Set Relay Action By CSU: %d => %d\r\n", CurRxBuf[9], Charger.Relay_Action);
            break;

          case PROTOCOL_MESSAGE_CONFIG_GPIO_OUTPUT:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_GPIO_OUTPUT;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = CurRxBuf[6];
            tx[7] = 0x00 ^ CurRxBuf[6];

            break;

          case PROTOCOL_MESSAGE_CONFIG_RTC:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_RTC;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;

            setTime.Hours = (CurRxBuf[14]-'0')*10 + (CurRxBuf[15]-'0');
            setTime.Minutes = (CurRxBuf[16]-'0')*10 + (CurRxBuf[17]-'0');
            setTime.Seconds = (CurRxBuf[18]-'0')*10 + (CurRxBuf[19]-'0');
            setTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
            setTime.StoreOperation = RTC_STOREOPERATION_RESET;
            if (HAL_RTC_SetTime(&hrtc, &setTime, RTC_FORMAT_BIN) != HAL_OK)
            {
                Error_Handler();
            }

            setDate.Year = (CurRxBuf[6]-'0')*1000 + (CurRxBuf[7]-'0')*100 + (CurRxBuf[8]-'0')*10 + (CurRxBuf[9]-'0') - 2000;
            setDate.Month = (CurRxBuf[10]-'0')*10+ (CurRxBuf[11]-'0');
            setDate.Date = (CurRxBuf[12]-'0')*10 + (CurRxBuf[13]-'0');
            if (HAL_RTC_SetDate(&hrtc, &setDate, RTC_FORMAT_BIN) != HAL_OK)
            {
                Error_Handler();
            }

            break;

            case PROTOCOL_MESSAGE_CONFIG_LED_ACTION_ALARM:
#ifdef FUNC_DISABLE_LED_CMD_CHECK
                //do nothing
#else
                if((Charger.am3352.LedActionState != CurRxBuf[6])||(Charger.am3352.LedAlarmState != (CurRxBuf[7]|(CurRxBuf[8]<<8)|(CurRxBuf[9]<<16)|(CurRxBuf[10]<<24))))
#endif
                {
                  Charger.am3352.LedActionState = CurRxBuf[6];
                  Charger.am3352.LedAlarmState = (CurRxBuf[7]|(CurRxBuf[8]<<8)|(CurRxBuf[9]<<16)|(CurRxBuf[10]<<24));
#ifdef FUNC_SHOW_CSU_CONFIG_LED_ACTION_INFO
                  XP("#CSU_SetLed (%d, %d)\r\n", Charger.am3352.LedActionState, Charger.am3352.LedAlarmState);
#endif

                  switch(Charger.am3352.LedActionState)
                  {
                    case LED_ACTION_INIT:
                      setLedMotion(LED_ACTION_INIT);
                      break;
                    case LED_ACTION_IDLE:
                      setLedMotion(LED_ACTION_IDLE);
                      break;
                    case LED_ACTION_AUTHED:
                      setLedMotion(LED_ACTION_AUTHED);
                      break;
                    case LED_ACTION_CONNECTED:
                      setLedMotion(LED_ACTION_CONNECTED);
                      break;
                    case LED_ACTION_CHARGING:
                      setLedMotion(LED_ACTION_CHARGING);
                      break;
                    case LED_ACTION_STOP:
                      setLedMotion(LED_ACTION_STOP);
                      break;
                    case LED_ACTION_ALARM:
                      setLedMotion(LED_ACTION_ALARM);
                      break;
                    case LED_ACTION_MAINTAIN:
                      setLedMotion(LED_ACTION_MAINTAIN);
                      break;
                    case LED_ACTION_RFID_PASS:
                      setLedMotion(LED_ACTION_RFID_PASS);
                      timerEnable(TIMER_IDX_LED_TEMP, 3000);
                      break;
                    case LED_ACTION_RFID_FAIL:
                      setLedMotion(LED_ACTION_RFID_FAIL);
                      timerEnable(TIMER_IDX_LED_TEMP, 3000);
                      break;
                    case LED_ACTION_BLE_CONNECT:
                      setLedMotion(LED_ACTION_BLE_CONNECT);
                      timerEnable(TIMER_IDX_LED_TEMP, 3000);
                      break;
                    case LED_ACTION_BLE_DISABLE:
                      setLedMotion(LED_ACTION_BLE_DISABLE);
                      break;
                    case LED_ACTION_ALL_OFF:
                      setLedMotion(LED_ACTION_ALL_OFF);
                      break;
                    case LED_ACTION_INTERNET_DISCONNECT:
                      setLedMotion(LED_ACTION_INTERNET_DISCONNECT);
                      break;
                    case LED_ACTION_HANDSHAKE_FAIL:
                      setLedMotion(LED_ACTION_HANDSHAKE_FAIL);
                      timerEnable(TIMER_IDX_LED_TEMP, 3000);
                      break;
                    case LED_ACTION_RESTORE_SETTING:
                      setLedMotion(LED_ACTION_RESTORE_SETTING);
                      timerEnable(TIMER_IDX_LED_TEMP, 3000);
                      break;
                    default:
                      break;
                  }
                }
                tx_len = 8;
                tx[0] = 0xaa;
                tx[1] = PROTOCOL_ADDR;
                tx[2] =  CurRxBuf[1];
                tx[3] = PROTOCOL_MESSAGE_CONFIG_LED_ACTION_ALARM;
                tx[4] = 0x01;
                tx[5] = 0x00;
                tx[6] = 0x01;
                tx[7] = 0x01;
            break;
        case PROTOCOL_MESSAGE_CONFIG_MAX_CURRENT_PWM_DUTY:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_MAX_CURRENT_PWM_DUTY;
            tx[4] = 0x01;
            tx[5] = 0x00;

#ifdef FUNC_CSU_CMD_DEBUG
            XP("#CSU_SetCpPwmDuty: %d %s\r\n", CurRxBuf[6],
               (Charger.m_bBlockCsuCpPwmDuty || Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF) ? "(Block)" : "");
#endif

            if (
#ifdef FUNC_BLOCK_CSU_CONFIG_CP_PWM_DUTY
                    !Charger.m_bBlockCsuCpPwmDuty &&
#endif

#ifdef FUNC_BLOCK_CSU_CMD_SET_DUTY_WHEN_ALARM_CP_F_STATE
                    !Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF &&
#endif
                    (
                    (CurRxBuf[6] <= 32 && CurRxBuf[6] >= 6) ||
                    (CurRxBuf[6] == PWM_DUTY_OFF) ||
                    (CurRxBuf[6] == 1) ||
                    (CurRxBuf[6] == 5) ||
                    (CurRxBuf[6] == 100)
                    )
                )
            {

#ifdef MODIFY_AC_EVSE_STATUS_MAX_CHARGING_CURRENT_VARIABLE
                Charger.AC_MaxChargingCurrentOrDuty = CurRxBuf[6];
#endif

                tx[6] = 0x00;

                if(CurRxBuf[6] <= 32 && CurRxBuf[6] >= 6)
                {

                    Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = CurRxBuf[6];

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                    user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(Charger.memory.EVSE_Config.data.item.MaxChargingCurrent));
#else
                    //user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_651(Charger.memory.EVSE_Config.data.item.MaxChargingCurrent));
#endif

                    tx[6] = 0x01;
                }
                else if (CurRxBuf[6] == PWM_DUTY_OFF)
                {
                    user_pwm_setvalue(PWM_CH_CP, 0);         // State F
                    tx[6] = 0x01;
                }
                else if (CurRxBuf[6] == 5)
                {
                    user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_5);
                    tx[6] = 0x01;
                }
                else if (CurRxBuf[6] == 100)
                {
                    user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                    tx[6] = 0x01;
                }

                //control pilot E
                if (CurRxBuf[6] == 1)
                {
                    HAL_GPIO_WritePin(OUT_StateE_GPIO_Port, OUT_StateE_Pin, GPIO_PIN_SET); // ON  // State E
                    user_pwm_setvalue(PWM_CH_CP, 0);        //Temporarily, wait for EE to change the hardware and delete
                    tx[6] = 0x01;
                }
                else
                {
                    HAL_GPIO_WritePin(OUT_StateE_GPIO_Port, OUT_StateE_Pin, GPIO_PIN_RESET);   //OFF
                }
                XP("#CSU_SetCpPwmDuty_Final: %d\r\n", CurRxBuf[6]);
            }
            else
            {
                tx[6] = 0x00;
                DEBUG_INFO("CSU_SetCpPwmDuty [NG] (%d) !!!!! \r\n", CurRxBuf[6]);
            }

            for(uint16_t idx=0;idx<(tx[4] | (tx[5]<<8));idx++)
            {
              chksum ^= tx[6 + idx];
            }
            tx[7] = chksum;                       //checksum
            break;
        case PROTOCOL_MESSAGE_CONFIG_LEGACY_REQUEST:

#ifdef FUNC_CSU_CMD_DEBUG
            XP("#CSU_SetRequest: %d\r\n", CurRxBuf[6]);
#endif

            if((CurRxBuf[6]&SETTING_LEGACY_REQUEST)>0)
			{
#ifdef FUNC_REQUEST_OFF_WHEN_GET_TWICE_OFF_CMD
                CsuSetRequestOffCount = 0;
#endif
              	Charger.am3352.isRequestOff = OFF;
				Charger.rfid.op_bits.reqStart = ON;
              	if(!Charger.am3352.isRequestOn)
				{
                    DEBUG_INFO("#Request Pin On.\r\n");
                    Charger.am3352.isRequestOn = ON;
            	}
            }
			else
			{

#ifdef FUNC_REQUEST_OFF_WHEN_GET_TWICE_OFF_CMD
                if (++CsuSetRequestOffCount >= 2)
                {
                    CsuSetRequestOffCount = 0;
                    Charger.am3352.isRequestOn = OFF;
                    Charger.am3352.RequestPinDebounceCnt = 0;
                    Charger.rfid.op_bits.reqStart = OFF;
                    if(!Charger.am3352.isRequestOff)
                    {
                        DEBUG_INFO("#Request Pin Off.\r\n");
                        Charger.am3352.isRequestOff = ON;
                    }
				}
#else //FUNC_REQUEST_OFF_WHEN_GET_TWICE_OFF_CMD
              	Charger.am3352.isRequestOn = OFF;
              	Charger.am3352.RequestPinDebounceCnt = 0;
              	Charger.rfid.op_bits.reqStart = OFF;
              	if(!Charger.am3352.isRequestOff)
			  	{
              		DEBUG_INFO("#Request Pin Off.\r\n");
                    Charger.am3352.isRequestOff = ON;
              	}
#endif //FUNC_REQUEST_OFF_WHEN_GET_TWICE_OFF_CMD

            }

            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_LEGACY_REQUEST;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            break;
        case PROTOCOL_MESSAGE_CONFIG_MCU_RESET:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_MCU_RESET;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            if((CurRxBuf[6]&0x01)>0){
              DEBUG_INFO("MCU reset request.\r\n");

#ifdef MODIFY_DC_RS485_UPGRADE_ISSUE
            Prefix_UartTX(tx, CurRxBuf);
            HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len , 0x0ffff);
            Postfix_UartTX(tx, CurRxBuf);
#else
            HAL_UART_Transmit(&IAP_USART, (uint8_t *)tx, tx_len , 0x0ffff);
#endif

              osDelay(1000);
              NVIC_SystemReset();
            }
            else
            {
              tx[6] = 0x00;
              tx[7] = 0x00;
            }
            break;
        case PROTOCOL_MESSAGE_CONFIG_BREATHE_LED_TIMING:
            Charger.am3352.BreatheLedConnectFadeIn = (((uint16_t)CurRxBuf[7]<<8)+(uint16_t)CurRxBuf[6]);
            Charger.am3352.BreatheLedConnectFadeOut = (((uint16_t)CurRxBuf[9]<<8)+(uint16_t)CurRxBuf[8]);
            DEBUG_INFO("Connect Breathe Led Fade In time: %d ms.\r\n",Charger.am3352.BreatheLedConnectFadeIn);
            DEBUG_INFO("Connect Breathe Led Fade Out time: %d ms.\r\n",Charger.am3352.BreatheLedConnectFadeOut);
            Charger.am3352.BreatheLedAuthdFadeIn = (((uint16_t)CurRxBuf[11]<<8)+(uint16_t)CurRxBuf[10]);
            Charger.am3352.BreatheLedAuthdFadeOut = (((uint16_t)CurRxBuf[13]<<8)+(uint16_t)CurRxBuf[12]);
            DEBUG_INFO("Authd Breathe Led Fade In time: %d ms.\r\n",Charger.am3352.BreatheLedAuthdFadeIn);
            DEBUG_INFO("Authd Breathe Led Fade Out time: %d ms.\r\n",Charger.am3352.BreatheLedAuthdFadeOut);
            Charger.am3352.BreatheLedChargeFadeIn = (((uint16_t)CurRxBuf[15]<<8)+(uint16_t)CurRxBuf[14]);
            Charger.am3352.BreatheLedChargeFadeOut = (((uint16_t)CurRxBuf[17]<<8)+(uint16_t)CurRxBuf[16]);
            DEBUG_INFO("Charge Breathe Led Fade In time: %d ms.\r\n",Charger.am3352.BreatheLedChargeFadeIn);
            DEBUG_INFO("Charge Breathe Led Fade Out time: %d ms.\r\n",Charger.am3352.BreatheLedChargeFadeOut);
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_BREATHE_LED_TIMING;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            break;
        case PROTOCOL_MESSAGE_CONFIG_LED_BRIGHTNESS:
            memcpy(Charger.Led_Brightness, &CurRxBuf[6], 12);
//#ifdef FUNC_SHOW_CSU_CONFIG_LED_BRIGHTNESS
//            XP("#CSU_SetLedBrightness(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)\r\n",
//               Charger.Led_Brightness[0],
//               Charger.Led_Brightness[1],
//               Charger.Led_Brightness[2],
//               Charger.Led_Brightness[3],
//               Charger.Led_Brightness[4],
//               Charger.Led_Brightness[5],
//               Charger.Led_Brightness[6],
//               Charger.Led_Brightness[7],
//               Charger.Led_Brightness[8],
//               Charger.Led_Brightness[9],
//               Charger.Led_Brightness[10],
//               Charger.Led_Brightness[11]);
//#endif
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_LED_BRIGHTNESS;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            break;
        case PROTOCOL_MESSAGE_CONFIG_EVSE_AUTH_MODE:
            switch(CurRxBuf[6])
            {
                case AUTH_MODE_OCPP:
                      Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_OCPP ;
                  break;

                case AUTH_MODE_FREE:
                      Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_FREE ;
                  break;

                default:
                      Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_FREE ;
                      Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_FREE ;
                  break ;
            }

            switch(CurRxBuf[7])
            {
                case RFID_USER_AUTH_LOCAL_LIST:
                      Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_LOCAL_LIST ;
                  break;
                case RFID_USER_AUTH_PH:
                      Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_PH ;
                  break;
                case RFID_USER_AUTH_FREE:
                      Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_FREE ;
                  break;
                case RFID_USER_AUTH_NO_CHARGING:
                      Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_NO_CHARGING ;
                  break;
                default:
                      Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_FREE ;
                      Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_FREE ;
                  break ;
            }

            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_EVSE_AUTH_MODE;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;

            Charger.memory.EVSE_Config.op_bits.update = ON;
            break;
        case PROTOCOL_MESSAGE_CONFIG_ERASE_MEMORY:
            switch(CurRxBuf[6])
            {
                case 0:
                  Charger.memory.EVSE_Config.op_bits.clear = ON;
                  Charger.memory.whiteList.op_bits.clear = ON;
                  Charger.memory.hisCharging.op_bits.clear = ON;

                  Charger.memory.hisAlarm.op_bits.clear = ON;
                  Charger.memory.coldLoadPickUp.op_bits.clear = ON;
                  break;
                case 1:
                  Charger.memory.EVSE_Config.op_bits.clear = ON;
                  break;
                case 2:
                  Charger.memory.whiteList.op_bits.clear = ON;
                  break;
                case 3:
                  Charger.memory.hisCharging.op_bits.clear = ON;
                  break;
                case 4:
                  Charger.memory.hisAlarm.op_bits.clear = ON;
                  break;
                case 5:
                  Charger.memory.coldLoadPickUp.op_bits.clear = ON;
                  break;
                default:
                  break;
            }

            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_ERASE_MEMORY;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            break;
#ifdef FUNC_RESET_CONNECTOR_PLUGIN_TIMES
        case PROTOCOL_MESSAGE_CONFIG_RESET_CONNECTOR_PLUGIN_TIMES:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_CONFIG_RESET_CONNECTOR_PLUGIN_TIMES;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            if(CurRxBuf[6] == 0x01)
            {
                DEBUG_INFO("CSU reset connector plugin times.\r\n");
                Charger.memory.EVSE_Config.data.item.AcPlugInTimes = 0;
                Charger.memory.EVSE_Config.op_bits.update = ON;
            }
            else
            {
              tx[6] = 0x00;
              tx[7] = 0x00;
            }
            break;
#endif //FUNC_RESET_CONNECTOR_PLUGIN_TIMES

          /*
            Firmware update message
          */
          case PROTOCOL_MESSAGE_UPGRADE_START:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_UPGRADE_START;
            tx[4] = 0x01;
            tx[5] = 0x00;

            binCRCTarget = (CurRxBuf[6] << 24) | (CurRxBuf[6] << 16) | (CurRxBuf[6] << 8) | (CurRxBuf[6] << 0);
            flashdestination = NEW_CODE_ADDRESS;
            if(FLASH_If_Erase(NEW_CODE_ADDRESS, 3)== FLASHIF_OK)
            {
              #if defined(DEBUG) || defined(RTOS_STAT)
              DEBUG_INFO("Firmware transfer start, earase flash success....\n\r");
              #endif
              tx[6] = 0x01;
              tx[7] = 0x01;

              if (Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
              {
                  setChargerMode(MODE_MAINTAIN);
                  timerEnable(TIMER_IDX_UPDATE, 10000);
              }
            }
            else
            {
              #if defined(DEBUG) || defined(RTOS_STAT)
              DEBUG_INFO("Firmware transfer start, earase flash fail....\n\r");
              #endif
              tx[6] = 0x00;
              tx[7] = 0x00;
            }

            break;

          case PROTOCOL_MESSAGE_UPGRADE_TRANS:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_UPGRADE_TRANS;
            tx[4] = 0x01;
            tx[5] = 0x00;

            flashdestination = NEW_CODE_ADDRESS + ((CurRxBuf[6]<<0) | (CurRxBuf[7]<<8) | (CurRxBuf[8]<<16) |(CurRxBuf[9]<<24));
            if (FLASH_If_Write(flashdestination, (uint32_t*) &CurRxBuf[10],  ((((CurRxBuf[4]) | (CurRxBuf[5])<<8)-4)>>2)) == FLASHIF_OK)
            {
              #if defined(DEBUG) || defined(RTOS_STAT)
              //DEBUG_INFO("Firmware transfer start address: 0x%x, length: %d...Pass\n\r", flashdestination, (((CurRxBuf[4]) | (CurRxBuf[5])<<8)-4));
              #endif
              tx[6] = 0x01;
              tx[7] = 0x01;

              if (Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
              {
                setLedMotion(LED_ACTION_MAINTAIN);
                timerRefresh(TIMER_IDX_UPDATE);
              }
            }
            else
            {
              #if defined(DEBUG) || defined(RTOS_STAT)
              DEBUG_INFO("Firmware transfer start address: 0x%x, length: %d...Fail\n\r", flashdestination, (((CurRxBuf[4]) | (CurRxBuf[5])<<8)-4));
              #endif
              tx[6] = 0x00;
              tx[7] = 0x00;
            }

            break;

          case PROTOCOL_MESSAGE_UPGRADE_STOP:
            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_UPGRADE_STOP;
            tx[4] = 0x01;
            tx[5] = 0x00;

            flash = NEW_CODE_ADDRESS;
            checksum = HAL_CRC_Calculate(&hcrc, (uint32_t *)flash, ((FLASH_AP_LENGTH-4)>>2));
            flash = ((uint32_t)(NEW_CODE_ADDRESS+FLASH_AP_LENGTH-4));
            #if defined(DEBUG) || defined(RTOS_STAT)
            DEBUG_INFO("Firmware transfer end, AP CRC checksum, flash: 0x%x, 0x%x\r\n", checksum, *((uint32_t *)flash) );
            #endif
            if(checksum == *((uint32_t *)flash))
            {
              if (FLASH_If_Write(UPGRADE_REQ_ADDRESS,  (uint32_t *)&endFlag[0], 1) == FLASHIF_OK)
              {
                #if defined(DEBUG) || defined(RTOS_STAT)
                DEBUG_INFO("Firmware Confirm Tag write ok..\n\r");
                #endif
                tx[6] = 0x01;
                tx[7] = 0x01;
                if(isUSB_CDC_IAP)
                {
                    CDC_Transmit_FS((uint8_t *)tx, tx_len);

                }
                else
                {
#ifdef MODIFY_DC_RS485_UPGRADE_ISSUE
                    Prefix_UartTX(tx, CurRxBuf);
                    HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len , 0x0ffff);
                    Postfix_UartTX(tx, CurRxBuf);
#else
                    HAL_UART_Transmit(&IAP_USART, (uint8_t *)tx, tx_len , 0x0ffff);
#endif
                }
                osDelay(1000);
                NVIC_SystemReset();
              }
              else
              {
                #if defined(DEBUG) || defined(RTOS_STAT)
                DEBUG_INFO("Firmware Confirm Tag write fail...\n\r");
                #endif
                tx[6] = 0x00;
                tx[7] = 0x00;
              }
            }
            else
            {
              #if defined(DEBUG) || defined(RTOS_STAT)
              DEBUG_INFO("Firmware checksum compare fail...\n\r");
              #endif
              tx[6] = 0x00;
              tx[7] = 0x00;
            }

            if (Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
            {
              timerDisable(TIMER_IDX_UPDATE);
            }
            break;

          case PROTOCOL_MESSAGE_UPGRADE_ABOARD:
            #if defined(DEBUG) || defined(RTOS_STAT)
            DEBUG_INFO("Firmware update transfer aboard...\n\r");
            #endif

            tx_len = 8;
            tx[0] = 0xaa;
            tx[1] = PROTOCOL_ADDR;
            tx[2] =  CurRxBuf[1];
            tx[3] = PROTOCOL_MESSAGE_UPGRADE_ABOARD;
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x01;
            tx[7] = 0x01;
            break;

          default:
            /* Todo: bin file receive aboard */
            #if defined(DEBUG) || defined(RTOS_STAT)

#ifdef FUNC_RS485_SLAVE
            DEBUG_INFO("Protocol message unknow (0x%02X)\n\r", CurRxBuf[3]);
#else
            DEBUG_INFO("Protocol message unknow...\n\r");
#endif

            #endif
            tx_len = 8;
#ifdef FIX_RS485_UNKNOW_MSG
            tx[0] = 0x55;
#else
            tx[0] = 0xaa;
#endif
            tx[1] = PROTOCOL_ADDR;
            tx[2] = CurRxBuf[1];
            tx[3] = CurRxBuf[3];
            tx[4] = 0x01;
            tx[5] = 0x00;
            tx[6] = 0x00;
            tx[7] = 0x00;

            break;
        }
      }
      else
      {
#ifndef FUNC_RS485_SLAVE
        #if defined(DEBUG) || defined(RTOS_STAT)
        DEBUG_INFO("Protocol check sum is wrong...\n\r");
        #endif
        tx_len = 8;
#ifdef FIX_RS485_UNKNOW_MSG
        tx[0] = 0x55;
#else
        tx[0] = 0xaa;
#endif
        tx[1] = PROTOCOL_ADDR;
        tx[2] = CurRxBuf[1];
        tx[3] = CurRxBuf[3];
        tx[4] = 0x01;
        tx[5] = 0x00;
        tx[6] = 0x00;
        tx[7] = 0x00;
#endif //FUNC_RS485_SLAVE
      }

      if(isUSB_CDC_IAP)
      {
        CDC_Transmit_FS((uint8_t *)tx, tx_len);
      }
      else
      {

#ifdef FUNC_RS485_SLAVE

#ifdef MODIFY_DC_RS485_UPGRADE_ISSUE
        if (CurRxBuf != NULL)
        {
#ifdef FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
            if (CurRxBuf == UART_IAP_rx_buffer)
            {
                Prefix_UartTX(tx, CurRxBuf);
                HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len , 0x0ffff);
                Postfix_UartTX(tx, CurRxBuf);
            }
            else if (CurRxBuf == UART_RS485_rx_buffer)
            {
#ifdef FIX_RS485_UNKNOW_MSG
                if (CurRxBuf[IMCP_FM_DSTADDR_IDX] == Charger.m_EMPX10_RS485_ClientAddr && tx[0] != 0x55)
#else
                if (CurRxBuf[IMCP_FM_DSTADDR_IDX] == Charger.m_EMPX10_RS485_ClientAddr)
#endif
                {
                    Prefix_UartTX(tx, CurRxBuf);
                    HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len , 0x0ffff);
                    Postfix_UartTX(tx, CurRxBuf);
                }
//                else if (CurRxBuf[IMCP_FM_DSTADDR_IDX] == EMPX10_RS485_ADDR_BROADCAST)
//                {
//                    Prefix_UartTX(tx, CurRxBuf);
//                    HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len , 0x0ffff);
//                    Postfix_UartTX(tx, CurRxBuf);
//                }
            }
#else //FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
            Prefix_UartTX(tx, CurRxBuf);
            HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len , 0x0ffff);
            Postfix_UartTX(tx, CurRxBuf);
#endif //FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
        }
#else //MODIFY_DC_RS485_UPGRADE_ISSUE
        if (CurRxBuf != NULL)
        {
            tx[1] = Charger.m_RS485SlaveAddr; //Update Slave Address
            HAL_UART_Transmit(pUartHandle, (uint8_t *)tx, tx_len, 0xffff);
        }
#endif //MODIFY_DC_RS485_UPGRADE_ISSUE

#else //FUNC_RS485_SLAVE
        HAL_UART_Transmit(&IAP_USART, (uint8_t *)tx, tx_len, 0xffff);
#endif //FUNC_RS485_SLAVE

      }

#ifdef DEBUG_EMPX10_COMM
        if (CurRxBuf == UART_RS485_rx_buffer)
        {
            HTK_ByteArray2HexStr_XP(NULL, tx, 0, tx_len);
        }
#endif //DEBUG_EMPX10_COMM

#ifdef ENABLE_PRINT_IMCP_MSG

#ifdef FUNC_RS485_SLAVE
#ifdef PRINT_IMCP_MSG_ONLY_ON_UPDATEPORT
    if (CurRxBuf == UART_IAP_rx_buffer && CheckPrintImcpMsg(CurRxBuf[3]))
    {
        HTK_ByteArray2HexStr_XP(NULL, tx, 0, tx_len);
    }
#else
    if (CheckPrintImcpMsg(CurRxBuf[3]))
    {
        HTK_ByteArray2HexStr_XP(NULL, tx, 0, tx_len);
    }
#endif //PRINT_IMCP_MSG_ONLY_ON_UPDATEPORT
#else //FUNC_RS485_SLAVE
    if (CheckPrintImcpMsg(UART_IAP_rx_buffer[3]))
    {
        HTK_ByteArray2HexStr_XP(NULL, tx, 0, tx_len);
    }
#endif //FUNC_RS485_SLAVE

#endif //ENABLE_PRINT_IMCP_MSG

#ifdef FUNC_RS485_SLAVE
      // Clear rx_buffer and related varaible
      for(uint16_t i = 0; i < *pCurRxBuf_RxLen ; i++)
        CurRxBuf[i]=0;

      *pCurRxBuf_RxLen = 0;
      *pCurRecvEndFlag = 0;

      isUSB_CDC_IAP = OFF;
#else
      // Clear rx_buffer and related varaible
      for(uint16_t i = 0; i < UART_IAP_rx_len ; i++)
        UART_IAP_rx_buffer[i]=0;

      UART_IAP_rx_len=0;
      UART_IAP_recv_end_flag=0;
      isUSB_CDC_IAP = OFF;
#endif //FUNC_RS485_SLAVE
    }

    if(timer[TIMER_IDX_UPDATE].isAlarm == ON && Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
    {
      setChargerMode(MODE_IDLE);
      setLedMotion(LED_ACTION_IDLE);
      timerDisable(TIMER_IDX_UPDATE);
    }

#ifdef FUNC_RS485_SLAVE
    HAL_UART_Receive_DMA(&IAP_USART,(uint8_t*)UART_IAP_rx_buffer, UART_BUFFER_SIZE);
    HAL_UART_Receive_DMA(&RS485_USART,(uint8_t*)UART_RS485_rx_buffer, UART_BUFFER_SIZE);
#else
    HAL_UART_Receive_DMA(&IAP_USART,(uint8_t*)UART_IAP_rx_buffer, UART_BUFFER_SIZE);
#endif //FUNC_RS485_SLAVE

    osDelay(1);
  }
  /* USER CODE END StartUartTask */
}

/* USER CODE BEGIN Header_StartAdcTask */
/**
* @brief Function implementing the adcTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartAdcTask */

#ifdef FUNC_DEBUG_MSG_CP_STATE
const char *CP_STATE_TAG[7] = {"0:UNKNOW", "1:A(12V)", "2:B(9V)", "3:C(6V)", "4:D(3V)", "5:E(0V)", "6:F(-12V)"};
#endif

void StartAdcTask(void const * argument)
{
  /* USER CODE BEGIN StartAdcTask */
  //aadc
  uint8_t previous_cp_state = SYSTEM_STATE_A;

#ifdef MODIFY_POWER_CONSUME_ACCU_TIMER
  uint16_t updateMemReq = 0;
#else
  uint8_t updateMemReq = 0;
#endif

  struct TimeTick
  {
    uint32_t timeTick_Start;
    uint32_t timeTick_End;
    uint32_t timeTick_Delta;
  }timeTick;

  timeTick.timeTick_Start = HAL_GetTick();

#ifdef FUNC_CP_ADC_MODIFY
#ifdef NEW_CP_SPEC
    while (!Charger.m_bCpDetectModuleInitOK)
    {
        osDelay(10);
    }
#endif //NEW_CP_SPEC
#endif //FUNC_CP_ADC_MODIFY

#ifdef MODIFY_POWER_CONSUME_ACCU_TIMER
    timerEnable(TIMER_IDX_POWER, POWER_CONSUME_ACCU_TIMEOUT_SPEC);
#else
    timerEnable(TIMER_IDX_POWER, 1000);
#endif

  /* Infinite loop */
  for(;;)
  {

    Relay_Control_Function( ) ;

    // ADC chanel 1
    if(isDMAEnd_ADC1)
    {
        isDMAEnd_ADC1 = OFF;
        CpCalculate(ADC1_Buffer, ADC1_CHANEL_COUNT*ADC1_SAMPLE_COUNT, &CpDetectionResult);

#ifdef FUNC_EMPX10_CUSTOMIZE_CP_STATE_OPERATION
        if (Charger.am3352.isRequestOn == ON)
        {
            if (Charger.Alarm_Code == 0)
            {

                if (Charger.m_CP_CurPWM == PWM_DUTY_FULL)
                {
                    Charger.CP_State = SYSTEM_STATE_B;
                }
                else
                {
                    Charger.CP_State = SYSTEM_STATE_C;
                }
            }
            else
            {
                Charger.CP_State = SYSTEM_STATE_B;
            }
        }
        else
        {
            Charger.CP_State = SYSTEM_STATE_A;
        }
#else
        Charger.CP_State = CpDetectionResult.State;
#endif

#ifdef FUNC_RELAY_OFF_WHEN_CP_NOT_STATE_C
        if (Charger.CP_State != SYSTEM_STATE_C)
        {
            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
        }
#endif


#ifdef FUNC_DEBUG_MSG_CP_STATE
        if (previous_cp_state != Charger.CP_State)
        {
            XP("#CP: [%s] >>> [%s] (%+f, %+f)\r\n",
                CP_STATE_TAG[previous_cp_state],
                CP_STATE_TAG[Charger.CP_State],
                (CpDetectionResult.PositiveValue == 0 ? 0 : CP_GET_OPA_VIN_USE_ADC(CpDetectionResult.PositiveValue)),
                (CpDetectionResult.NegativeValue == 0 ? 0 : CP_GET_OPA_VIN_USE_ADC(CpDetectionResult.NegativeValue))
               );
        }
#endif

        if (Charger.Mode!= MODE_DEBUG)
        {
#ifdef MODIFY_ADCTASK_CP_STATE_CHANGE
          if((previous_cp_state != Charger.CP_State))
#else
          if((previous_cp_state != Charger.CP_State) && (Charger.CP_State !=SYSTEM_STATE_UNKNOWN ))
#endif
          {
              previous_cp_state = Charger.CP_State;
              if(Charger.CP_State == SYSTEM_STATE_A)
              {
                  user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL); // CP PWM duty set 100%
                  Charger.Relay_Action=GPIO_RELAY_ACTION_OFF;
                  Charger.memory.EVSE_Config.data.item.AcPlugInTimes++;
                  Charger.memory.EVSE_Config.op_bits.update = ON;
                  DEBUG_INFO("EVSE connector plug counts: %d\r\n", Charger.memory.EVSE_Config.data.item.AcPlugInTimes);
              }
          }
        }
        //DEBUG_INFO("HAL_GetTick() = %d\r\n",HAL_GetTick());

        if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC1_Buffer, ADC1_CHANEL_COUNT*ADC1_SAMPLE_COUNT)!=HAL_OK)Error_Handler();
    }

    // ADC chanel 2
    if(isDMAEnd_ADC2)
    {
        isDMAEnd_ADC2 = OFF;
        for(uint16_t idx=0;idx<ADC2_SAMPLE_COUNT;idx++)
        {
            ADC2_Buffer_Each[0][idx] = ADC2_Buffer[(idx*ADC2_CHANEL_COUNT) + 0];
            ADC2_Buffer_Each[1][idx] = ADC2_Buffer[(idx*ADC2_CHANEL_COUNT) + 1];
        }

        if (WatchDogLeakRawDataCheck_Event())  //clear leak WatchDogcount
        {
          Charger.counter.WatchDogLeak = 0 ;
        }

        //RlyVmax_cal
        //filter_move_avg(&adc_value.ADC2_IN5_Welding, RlyVmax_cal(ADC2_Buffer_Each[0], ADC2_SAMPLE_COUNT));
        if (Charger.GroundingSystem == GROUNGING_SYSTEM_LL)
        {
           filter_move_avg(&adc_value.ADC2_IN5_Welding, avg_v_cal(ADC2_Buffer_Each[0], ADC2_SAMPLE_COUNT));  //unit: 0.01V
        }
        else
        {
          filter_move_avg(&adc_value.ADC2_IN5_Welding, RlyVmax_cal(ADC2_Buffer_Each[0], ADC2_SAMPLE_COUNT)); //unit: 0.01V
        }

        //Leak
        filter_move_avg(&adc_value.ADC2_IN6_GF, GFRms_cal(ADC2_Buffer_Each[1], ADC2_SAMPLE_COUNT));
        if ((((adc_value.ADC2_IN6_GF.value)*Charger.coefficient.gain_leak[0])+Charger.coefficient.offset_leak[0]) <=0)
        Charger.Leak_Current = adc_value.ADC2_IN6_GF.value;
        else
        Charger.Leak_Current = (uint16_t) (((adc_value.ADC2_IN6_GF.value)*Charger.coefficient.gain_leak[0])+Charger.coefficient.offset_leak[0]) ;

        if(HAL_ADC_Start_DMA(&hadc2, (uint32_t*)&ADC2_Buffer, ADC2_CHANEL_COUNT*ADC2_SAMPLE_COUNT)!=HAL_OK)Error_Handler();
    }

   // ADC chanel 3
    if(isDMAEnd_ADC3)
    {
        isDMAEnd_ADC3 = OFF;
        for(uint16_t idx=0;idx<ADC3_SAMPLE_COUNT;idx++)
        {
            ADC3_Buffer_Each[0][idx] = ADC3_Buffer[(idx*ADC3_CHANEL_COUNT) + 0];
            ADC3_Buffer_Each[1][idx] = ADC3_Buffer[(idx*ADC3_CHANEL_COUNT) + 1];
            ADC3_Buffer_Each[2][idx] = ADC3_Buffer[(idx*ADC3_CHANEL_COUNT) + 2];
            ADC3_Buffer_Each[3][idx] = ADC3_Buffer[(idx*ADC3_CHANEL_COUNT) + 3];
            ADC3_Buffer_Each[4][idx] = ADC3_Buffer[(idx*ADC3_CHANEL_COUNT) + 4];
        }

        //VT
        filter_move_avg(&adc_value.ADC3_IN9_Voltage_L1, vRms_cal2(ADC3_Buffer_Each[0], ADC3_SAMPLE_COUNT));
        //SetADCWDGBoundary();
        //MCU VDD
        filter_move_avg(&adc_value.ADC3_IN14_UL_1998, avg_cal(ADC3_Buffer_Each[1], ADC3_SAMPLE_COUNT));
        //TEMP
        filter_move_avg(&adc_value.ADC3_IN15_Temp, avg_cal(ADC3_Buffer_Each[2], ADC3_SAMPLE_COUNT));
        Charger.temperature.SystemAmbientTemp = getTemperature(adc_value.ADC3_IN15_Temp.value);
        //PE
        filter_move_avg(&adc_value.ADC3_IN4_GMI_VL1, avg_cal(ADC3_Buffer_Each[3], ADC3_SAMPLE_COUNT));
        //CT
        Current_filter_move_avg(&adc_value.ADC3_IN7_Current_L1, cRms_cal(ADC3_Buffer_Each[4], ADC3_SAMPLE_COUNT));

        //Correction
        //VT
        Charger.Voltage[0] = (uint16_t) (((adc_value.ADC3_IN9_Voltage_L1.value)*Charger.coefficient.gain_v[0])+Charger.coefficient.offset_v[0]) ;
        //CT
#ifdef FUNC_SIMU_CHARGE_CURRENT_OUTPUT
        if (Charger.m_bEnableSimuChargeCurrent)
        {
            if (Charger.Relay_Action == GPIO_RELAY_ACTION_ON)
            {
                Charger.Current[0] = Charger.memory.EVSE_Config.data.item.MaxChargingCurrent * 100 - (rand() % 30);
            }
            else
            {
                Charger.Current[0] = 0;
            }
        }
        else
        {
            Charger.Current[0] = (uint16_t)((adc_value.ADC3_IN7_Current_L1.value*Charger.coefficient.gain_c[0])+Charger.coefficient.offset_c[0]);
        }
#else //FUNC_SIMU_CHARGE_CURRENT_OUTPUT
        Charger.Current[0] = (uint16_t)((adc_value.ADC3_IN7_Current_L1.value*Charger.coefficient.gain_c[0])+Charger.coefficient.offset_c[0]);
#endif //FUNC_SIMU_CHARGE_CURRENT_OUTPUT
        //GMI
        Charger.Gmi_Voltage = (uint16_t) (((adc_value.ADC3_IN4_GMI_VL1.value)*Charger.coefficient.gain_gmi[0])+Charger.coefficient.offset_gmi[0]) ;


#ifdef COLD_LOAD_PICKUP
        if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
          // check Power drop is not alarm
          // Power drop detection
          if((vRms_cal2(ADC3_Buffer_Each[0], ADC3_SAMPLE_COUNT) <= ALARM_SPEC_POWER_DROP) && (!Charger.AC_DripisTure) && (Charger.Mode != MODE_INITIAL))
          {
              if(Charger.counter.AC_Drip.fail > 1000)
              {
                //Charger.memory.EVSE_Config.data.item.isDispDebug  = OFF;
                if((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))
                {
                    Charger.memory.coldLoadPickUp.data.item.isEnable = ON;
                    Charger.memory.coldLoadPickUp.data.item.DateTime.year = Charger.cycle_info.startDateTime.year;
                    Charger.memory.coldLoadPickUp.data.item.DateTime.month = Charger.cycle_info.startDateTime.month;
                    Charger.memory.coldLoadPickUp.data.item.DateTime.day = Charger.cycle_info.startDateTime.day;
                    Charger.memory.coldLoadPickUp.data.item.DateTime.hour = Charger.cycle_info.startDateTime.hour;
                    Charger.memory.coldLoadPickUp.data.item.DateTime.min = Charger.cycle_info.startDateTime.min;
                    Charger.memory.coldLoadPickUp.data.item.DateTime.sec = Charger.cycle_info.startDateTime.sec;
                    Charger.memory.coldLoadPickUp.data.item.Duration = Charger.cycle_info.Duration;
                    sprintf(Charger.memory.coldLoadPickUp.data.item.PlugType, EVSE_CONNECTOR_TYPE);
                    Charger.memory.coldLoadPickUp.data.item.powerSum = Charger.cycle_info.Power_Consumption;
                    Charger.memory.coldLoadPickUp.data.item.startType = Charger.cycle_info.StartType;
                    //memcpy(Charger.memory.coldLoadPickUp.data.item.user, Charger.rfid.currentCard, 16);

                    Charger.memory.coldLoadPickUp.op_bits.update = ON;
                }
                Charger.AC_DripisTure = ON ;
              }
              else
                Charger.counter.AC_Drip.fail ++ ;
          }
          else if((vRms_cal2(ADC3_Buffer_Each[0], ADC3_SAMPLE_COUNT) > (ALARM_SPEC_UV+ALARM_SPEC_OUV_HYSTERESIS)))
          {
               Charger.counter.AC_Drip.fail = 0 ;
               if(Charger.AC_DripisTure)
               {
                    Charger.AC_DripisTure = OFF ;
                    DEBUG_INFO("Alarm AC Drip recover.\r\n");
               }
          }
        }
#endif  //COLD_LOAD_PICKUP

        // Power accumulate calculation
        if(timer[TIMER_IDX_POWER].isAlarm)
        {
            timeTick.timeTick_End = HAL_GetTick();
            timeTick.timeTick_Delta = timeTick.timeTick_End - timeTick.timeTick_Start;
            timeTick.timeTick_Start = timeTick.timeTick_End;

            if(Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative >= 0xFFFFFFFF)
            {
                Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative = 0;
            }
            else
            {
#ifdef MODIFY_POWER_CONSUME_ACCU_TIMER
                {
                    static double Energy = 0;
#ifdef FUNC_ZERO_CURRENT_WHEN_OUTP_OFF
                    u16 Curr = (Charger.Relay_Action == GPIO_RELAY_ACTION_ON) ? Charger.Current[0] : 0;
                    Energy += (((double)Charger.Voltage[0]/100.0)*((double)Curr/100.0)*((double)timeTick.timeTick_Delta/3600000.0)*10.0);
#else
                    Energy += (((double)Charger.Voltage[0]/100.0)*((double)Charger.Current[0]/100.0)*((double)timeTick.timeTick_Delta/3600000.0)*10.0);
#endif
                    if (Energy >= 1)
                    {
                        uint32_t EnergyIntPart = (uint32_t)Energy;
                        Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative += EnergyIntPart;
                        Energy -= EnergyIntPart;
                    }

                }
#else //MODIFY_POWER_CONSUME_ACCU_TIMER

                //unit : 0.0001kW , 0.1W *10 = W
                Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative += (uint32_t)((Charger.Voltage[0]/100.0)*(Charger.Current[0]/100.0)*(timeTick.timeTick_Delta/3600000.0)*10.0);
#endif //MODIFY_POWER_CONSUME_ACCU_TIMER
            }

#ifdef MODIFY_POWER_CONSUME_ACCU_TIMER
            if((++updateMemReq) > (180 * (1000 / (double)POWER_CONSUME_ACCU_TIMEOUT_SPEC))) //Interval = POWER_CONSUME_ACCU_TIMEOUT_SPEC ms
#else
            if(++updateMemReq>180) //Interval = 1000ms
#endif
            {
                Charger.memory.EVSE_Config.op_bits.update = ON;
                updateMemReq = 0;
            }
            timerRefresh(TIMER_IDX_POWER);
        }


        if(HAL_ADC_Start_DMA(&hadc3, (uint32_t*)&ADC3_Buffer, ADC3_CHANEL_COUNT*ADC3_SAMPLE_COUNT)!=HAL_OK)Error_Handler();
    }

    osDelay(1);
  }
  /* USER CODE END StartAdcTask */
}

/* USER CODE BEGIN Header_StartTimeoutTask */
/**
* @brief Function implementing the timeoutTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTimeoutTask */
void StartTimeoutTask(void const * argument)
{
  /* USER CODE BEGIN StartTimeoutTask */
  breathe.isUp = ON;
  for(int idx=0;idx<BLINKER_COUNT;idx++)
    blinker[idx].blinkCount = 0;

  flickerTimeSet(FLICKER_IDX_BREATHE, 500, 500);
  blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
  breatheTimeSet(1000, 1000, 1000, 1000, 1000, 0 );

  Charger.am3352.BreatheLedChargeFadeIn = 2500;
  Charger.am3352.BreatheLedChargeFadeOut = 2500;
  Charger.am3352.BreatheLedConnectFadeIn = 1000;
  Charger.am3352.BreatheLedConnectFadeOut = 1000;
  Charger.am3352.BreatheLedAuthdFadeIn = 1000;
  Charger.am3352.BreatheLedAuthdFadeOut = 1000;

  /* Infinite loop */
  for(;;)
  {
    if(Charger.Mode != MODE_INITIAL)
    {
        HAL_RTC_GetTime(&hrtc, &currentTime, RTC_FORMAT_BIN);
        HAL_RTC_GetDate(&hrtc, &currentDate, RTC_FORMAT_BIN);
        Charger.memory.EVSE_Config.data.item.SystemDateTime.year = currentDate.Year + 2000;
        Charger.memory.EVSE_Config.data.item.SystemDateTime.month  = currentDate.Month;
        Charger.memory.EVSE_Config.data.item.SystemDateTime.day = currentDate.Date;
        Charger.memory.EVSE_Config.data.item.SystemDateTime.hour = currentTime.Hours;
        Charger.memory.EVSE_Config.data.item.SystemDateTime.min  = currentTime.Minutes;
        Charger.memory.EVSE_Config.data.item.SystemDateTime.sec  = currentTime.Seconds;
    }
    /*
        Timer check process
    */
    for(int idx=0;idx<TIMER_COUNT;idx++)
    {
        if(timer[idx].isEnable)
        {
            if((HAL_GetTick() - timer[idx].startTime) > timer[idx].timeoutSpec)
            {
                timer[idx].isAlarm = ON;
            }
            else
            {
                timer[idx].isAlarm = OFF;
            }
        }
        else
        {
            timer[idx].startTime = HAL_GetTick();
            timer[idx].isAlarm = OFF;
        }
    }

    /*
        Blink timer process
    */
    for(int idx=0;idx<BLINKER_COUNT;idx++)
    {
        if((HAL_GetTick() - blinker[idx].blinkStartTime) > (blinker[idx].isOn ? blinker[idx].blinkOnSpec : blinker[idx].blinkOffSpec))
        {
            if(blinker[idx].blinkCount >= blinker[idx].blinkCountSpec)
            {
                if((HAL_GetTick() - blinker[idx].resetStartTime) > blinker[idx].blinkRestSpec)
                {
                    if(!blinker[idx].blinkRestSpec) //no rest case
                      blinker[idx].blinkisFinish = ON ;
                    blinker[idx].blinkCount = 0;
                }
                else
                {
                    blinker[idx].isOn= OFF;
                    blinker[idx].blinkisFinish = ON ;
                }
            }
            else
            {
                if(blinker[idx].isOn)
                    blinker[idx].blinkCount++;
                blinker[idx].blinkStartTime = HAL_GetTick();
                blinker[idx].resetStartTime = HAL_GetTick();
                blinker[idx].isOn ^= ON;
                if(blinker[idx].blinkRestSpec > 0) //had rest case
                  blinker[idx].blinkisFinish = OFF ;
            }
        }
    }

    /*
        Flick timer process
    */
    for(int idx=0;idx<FLICKER_COUNT;idx++)
    {
        if((HAL_GetTick() - flicker[idx].StartTime) > (flicker[idx].isOn ? flicker[idx].OnSpec : flicker[idx].OffSpec))
        {
          flicker[idx].StartTime = HAL_GetTick();
          flicker[idx].isOn ^= ON;
        }
    }


    /*
        Breathe timer process
    */
    if(breathe.isUp)
    {
        breathe.countPause = 0;
        breathe.countDown = breathe.timeDown;
        if(++breathe.countUp >= breathe.timeUp)
          breathe.isUp = OFF;

        breathe.duty[0] = breathe.RGB[0]*breathe.countUp/breathe.timeUp;
        breathe.duty[1] = breathe.RGB[1]*breathe.countUp/breathe.timeUp;
        breathe.duty[2] = breathe.RGB[2]*breathe.countUp/breathe.timeUp;
        breathe.duty[3] = breathe.RGB[3]*breathe.countUp/breathe.timeUp;
    }
    else
    {
        breathe.countUp = 1000*BREATHE_LED_LOW_BOUNDARY/breathe.timeDown;
        if(breathe.countDown <= 1000*BREATHE_LED_LOW_BOUNDARY/breathe.timeDown)
        {
            //if(++breathe.countPause>250)   //breathe ON->oFF need delay nedd Uncomment annotations
                breathe.isUp = ON;
        }
        else
        {
          if(breathe.countDown > 1000*BREATHE_LED_LOW_BOUNDARY/breathe.timeDown)
            breathe.countDown -=1;
        }

        breathe.duty[0] = breathe.RGB[0]*breathe.countDown/breathe.timeDown;
        breathe.duty[1] = breathe.RGB[1]*breathe.countDown/breathe.timeDown;
        breathe.duty[2] = breathe.RGB[2]*breathe.countDown/breathe.timeDown;
        breathe.duty[3] = breathe.RGB[3]*breathe.countDown/breathe.timeDown;
    }

    osDelay(1);
  }
  /* USER CODE END StartTimeoutTask */
}

/* USER CODE BEGIN Header_StartRfidTask */
/**
* @brief Function implementing the rfidTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartRfidTask */
void StartRfidTask(void const * argument)
{
  /* USER CODE BEGIN StartRfidTask */
  //rrfid
  uint8_t cardType = 0;
  uint8_t tmpBuf[32];
  uint8_t tx[UART_BUFFER_SIZE>>4];
  uint8_t tx_len;

  HAL_GPIO_WritePin(OUT_RFID_Reset_GPIO_Port, OUT_RFID_Reset_Pin, GPIO_PIN_SET);
  /* Infinite loop */
  for(;;)
  {
    // Read card SN
    if(!Charger.rfid.op_bits.reqHalt && !Charger.rfid.op_bits.reqBlockRead)
    {
      switch(cardType)
      {
        case 0x00:
            tx_len = 4;
            tx[0] = tx_len - 0x01;
            tx[1] = RFID_CMD_REQUEST_SN_14443A;
            tx[2] = 0x01;
            tx[3] = rfidCheckSumCal(tx, tx_len-1);
            cardType++;
            break;
        case 0x01:
            tx_len = 5;
            tx[0] = tx_len - 0x01;
            tx[1] = RFID_CMD_REQUEST_SN_14443B;
            tx[2] = 0x00;
            tx[3] = 0x00;
            tx[4] = rfidCheckSumCal(tx, tx_len-1);
            cardType++;
            break;
        case 0x02:
            tx_len = 9;
            tx[0] = tx_len - 0x01;
            tx[1] = RFID_CMD_REQUEST_SN_FELICA;
            tx[2] = 0x06;
            tx[3] = 0x00;
            tx[4] = 0xff;
            tx[5] = 0xff;
            tx[6] = 0x01;
            tx[7] = 0x00;
            tx[8] = rfidCheckSumCal(tx, tx_len-1);
            cardType++;
            break;
        default:
            cardType = 0;
            break;
      }

      HAL_UART_Transmit(&RFID_USART, (uint8_t *)tx, tx_len, 0xffff);
      osDelay(100);
    }

    if(Charger.rfid.op_bits.reqHalt)
    {
      tx_len = 3;
      tx[0] = tx_len - 0x01;
      tx[1] = RFID_CMD_HALT_14443A;
      tx[2] = rfidCheckSumCal(tx, tx_len-1);
      HAL_UART_Transmit(&RFID_USART, (uint8_t *)tx, tx_len, 0xffff);
      osDelay(100);
    }

    if(Charger.rfid.op_bits.reqBlockRead)
    {
        tx_len = 0x0b;
        tx[0] = tx_len - 0x01;
        tx[1] = RFID_CMD_BLOCK_READ;
        tx[2] = Charger.rfid.keyType;
        tx[3] = Charger.rfid.targetBlock;
        tx[4] = Charger.rfid.key[0];
        tx[5] = Charger.rfid.key[1];
        tx[6] = Charger.rfid.key[2];
        tx[7] = Charger.rfid.key[3];
        tx[8] = Charger.rfid.key[4];
        tx[9] = Charger.rfid.key[5];
        tx[10] = rfidCheckSumCal(tx, tx_len-1);
        HAL_UART_Transmit(&RFID_USART, (uint8_t *)tx, tx_len, 0xffff);
        osDelay(100);
    }

    // RFID module feedback process
    if(UART_RFID_recv_end_flag == ON)
    {
        if((rfidCheckSumCal(UART_RFID_rx_buffer, UART_RFID_rx_buffer[0]) == UART_RFID_rx_buffer[UART_RFID_rx_buffer[0]]) && (Charger.Mode != MODE_INITIAL) && (Charger.Mode != MODE_ALARM))
        {
            switch(UART_RFID_rx_buffer[1])
            {
                case RFID_CMD_LED:
                  break;
                case RFID_CMD_REQUEST_SN_14443A:
                  if(UART_RFID_rx_buffer[0] == 9)
                  {
                      Charger.rfid.snType = RFID_SN_TYPE_4BYTE;
                      memset(&Charger.rfid.data_Sn[0], 0x00, ARRAY_SIZE(Charger.rfid.data_Sn));
                      for(uint8_t idx=0;idx<16;idx++)
                      {
                         if(idx<4)
                         {
                             Charger.rfid.data_Sn[idx] = UART_RFID_rx_buffer[idx+2];
                         }
                         else
                         {
                             Charger.rfid.data_Sn[idx] = 0x00;
                         }
                      }

                      if(isMode(MODE_IDLE))
                      {
                          memset(&Charger.rfid.currentCard[0], 0x00, ARRAY_SIZE(Charger.rfid.currentCard));
                      }
                      if(Charger.memory.EVSE_Config.data.item.RFID_SN_Endian)
                      {
                          DEBUG_INFO("RFID SN: %02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                          sprintf((char *)tmpBuf, "%02X%02X%02X%02X", Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                          memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                      }
                      else
                      {
                          DEBUG_INFO("RFID SN: %02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3]);
                          sprintf((char *)tmpBuf, "%02X%02X%02X%02X", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3]);
                          memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                      }
                  }
                  else if(UART_RFID_rx_buffer[0] == 0x0c)
                  {
                      Charger.rfid.snType = RFID_SN_TYPE_7BYTE;
                      memset(&Charger.rfid.data_Sn[0], 0x00, ARRAY_SIZE(Charger.rfid.data_Sn));
                      for(uint8_t idx=0;idx<16;idx++)
                      {
                         if(idx<7)
                         {
                             Charger.rfid.data_Sn[idx] = UART_RFID_rx_buffer[idx+2];
                         }
                         else
                         {
                             Charger.rfid.data_Sn[idx] = 0x00;
                         }
                      }

                      if(isMode(MODE_IDLE))
                      {
                          memset(&Charger.rfid.currentCard[0], 0x00, ARRAY_SIZE(Charger.rfid.currentCard));
                      }
                      if(Charger.memory.EVSE_Config.data.item.RFID_SN_Endian)
                      {
                          DEBUG_INFO("RFID SN: %02X%02X%02X%02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[6], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                          sprintf((char *)tmpBuf, "%02X%02X%02X%02X%02X%02X%02X", Charger.rfid.data_Sn[6], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                          memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                      }
                      else
                      {
                          DEBUG_INFO("RFID SN: %02X%02X%02X%02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[6]);
                          sprintf((char *)tmpBuf, "%02X%02X%02X%02X%02X%02X%02X", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[6]);
                          memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                      }
                  }

                  //PH
                  if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_PH )
                  {
                    if(UART_RFID_rx_buffer[0] >= 9)
                    {
                        if(isMode(MODE_IDLE))
                        {
                            if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
                            {
                                Charger.rfid.targetBlock = 0x02;
                                Charger.rfid.keyType = 0x00;
                                memset(&Charger.rfid.key[0], 0xff, 6);
                                Charger.rfid.op_bits.reqBlockRead = ON;
                                //control in RFID_CMD_BLOCK_READ to Valid_RFID_SN
                            }
                        }
                        else if(isMode(MODE_CHARGING) || isMode(MODE_STOP))
                        {
                            if ((Array_data_Check(Charger.rfid.currentCard,Charger.rfid.nowCard))&&(Charger.cycle_info.StartType != START_METHOD_BLE))
                            {
                                if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
                                {
                                    Charger.rfid.op_bits.reqStop = ON;
                                    setLedMotion(LED_ACTION_RFID_PASS);
                                    Charger.speaker.motion = SPEAKER_SHORT;
                                    timerEnable(TIMER_IDX_LED_TEMP, 3000);
                                }
                                DEBUG_WARN("reqStop = ON.\r\n");
                            }
                            else
                            {
                                if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
                                {
                                  setLedMotion(LED_ACTION_RFID_FAIL);
                                  Charger.speaker.motion = SPEAKER_BLINK;
                                  blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                                  timerEnable(TIMER_IDX_LED_TEMP, 3000);
                                }
                                DEBUG_WARN("reqStop = Fail\r\n");
                            }
                            Charger.rfid.op_bits.reqHalt = ON;
                            Charger.rfid.op_bits.reqBlockRead = OFF;
                        }
                    }
                  }
                  //White List
                  else if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_LOCAL_LIST)
                  {
                      DEBUG_WARN("OfflinePolicy is White List\r\n");
                  }
                  //Free
                  else if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_FREE)
                  {
                        Charger.rfid.op_bits.reqHalt = ON;
                        Charger.rfid.op_bits.reqBlockRead = OFF;
                        if(isMode(MODE_IDLE))
                        {
                            for(uint8_t idx=0;idx<16;idx++)
                            {
                                  Charger.rfid.currentCard[idx] = Charger.rfid.data_Sn[idx];
                            }

                            Charger.rfid.op_bits.reqStart = ON;
                            memcpy(&Charger.rfid.currentCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                            if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                              setLedMotion(LED_ACTION_RFID_PASS);
                              Charger.speaker.motion = SPEAKER_SHORT;
                              timerEnable(TIMER_IDX_LED_TEMP, 3000);
                            }
                            DEBUG_WARN("RFID authorize pass.\r\n");
                        }
                        else if(isMode(MODE_CHARGING) || isMode(MODE_STOP))
                        {
                            DEBUG_WARN("RFID authorize pass.\r\n");
                            if (Array_data_Check(Charger.rfid.currentCard,Charger.rfid.nowCard))
                            {
                              Charger.rfid.op_bits.reqStop = ON;
                              if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                setLedMotion(LED_ACTION_RFID_PASS);
                                Charger.speaker.motion = SPEAKER_SHORT;
                                timerEnable(TIMER_IDX_LED_TEMP, 3000);
                              }
                              DEBUG_WARN("reqStop = ON.\r\n");
                            }
                            else
                            {
                              if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                setLedMotion(LED_ACTION_RFID_FAIL);
                                Charger.speaker.motion = SPEAKER_BLINK;
                                blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                                timerEnable(TIMER_IDX_LED_TEMP, 3000);
                              }
                              DEBUG_WARN("reqStop = Fail\r\n");
                            }
                        }
                  }
                  //NO charger
                  else // Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_NO_CHARGING
                  {
                        setLedMotion(LED_ACTION_RFID_FAIL);
                        Charger.speaker.motion = SPEAKER_BLINK;
                        blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                        timerEnable(TIMER_IDX_LED_TEMP, 3000);

                        Charger.rfid.op_bits.reqHalt = ON;
                        Charger.rfid.op_bits.reqBlockRead = OFF;
                        DEBUG_WARN("It is RFID NO charger mode \r\n");
                  }

                  break;
                case RFID_CMD_REQUEST_SN_14443B:
                    if(UART_RFID_rx_buffer[1] == RFID_CMD_REQUEST_SN_14443B)
                    {
                        Charger.rfid.snType = RFID_SN_TYPE_14443B;
                        memset(&Charger.rfid.data_Sn[0], 0x00, ARRAY_SIZE(Charger.rfid.data_Sn));
                        for(uint8_t idx=0;idx<16;idx++)
                        {
                            if(idx<13)
                            {
                                Charger.rfid.data_Sn[idx] = UART_RFID_rx_buffer[idx+2];
                            }
                        }

                        if(isMode(MODE_IDLE))
                            memset(&Charger.rfid.nowCard[0], 0x00, ARRAY_SIZE(Charger.rfid.nowCard));
                        if(Charger.memory.EVSE_Config.data.item.RFID_SN_Endian)
                        {
                            DEBUG_INFO("RFID SN: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[12], Charger.rfid.data_Sn[11], Charger.rfid.data_Sn[10], Charger.rfid.data_Sn[9], Charger.rfid.data_Sn[8], Charger.rfid.data_Sn[7], Charger.rfid.data_Sn[6], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                            sprintf((char *)tmpBuf, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", Charger.rfid.data_Sn[12], Charger.rfid.data_Sn[11], Charger.rfid.data_Sn[10], Charger.rfid.data_Sn[9], Charger.rfid.data_Sn[8], Charger.rfid.data_Sn[7], Charger.rfid.data_Sn[6], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                            memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.nowCard));
                        }
                        else
                        {
                            DEBUG_INFO("RFID SN: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[6], Charger.rfid.data_Sn[7], Charger.rfid.data_Sn[8], Charger.rfid.data_Sn[9], Charger.rfid.data_Sn[10], Charger.rfid.data_Sn[11], Charger.rfid.data_Sn[12]);
                            sprintf((char *)tmpBuf, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[6], Charger.rfid.data_Sn[7], Charger.rfid.data_Sn[8], Charger.rfid.data_Sn[9], Charger.rfid.data_Sn[10], Charger.rfid.data_Sn[11], Charger.rfid.data_Sn[12]);
                            memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.nowCard));
                        }
                    }

                    //White List
                    if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_LOCAL_LIST)
                    {
                          DEBUG_WARN("OfflinePolicy is White List\r\n");
                    }
                    //Free
                    else if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_FREE)
                    {
                          Charger.rfid.op_bits.reqHalt = ON;
                          Charger.rfid.op_bits.reqBlockRead = OFF;
                          if(isMode(MODE_IDLE))
                          {
                              for(uint8_t idx=0;idx<16;idx++)
                              {
                                    Charger.rfid.currentCard[idx] = Charger.rfid.data_Sn[idx];
                              }

                              Charger.rfid.op_bits.reqStart = ON;
                              memcpy(&Charger.rfid.currentCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                              if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                setLedMotion(LED_ACTION_RFID_PASS);
                                Charger.speaker.motion = SPEAKER_SHORT;
                                timerEnable(TIMER_IDX_LED_TEMP, 3000);
                              }
                              DEBUG_WARN("RFID authorize pass.\r\n");
                          }
                          else if(isMode(MODE_CHARGING) || isMode(MODE_STOP))
                          {
                              DEBUG_WARN("RFID authorize pass.\r\n");
                              if (Array_data_Check(Charger.rfid.currentCard,Charger.rfid.nowCard))
                              {
                                Charger.rfid.op_bits.reqStop = ON;
                                if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                  setLedMotion(LED_ACTION_RFID_PASS);
                                  Charger.speaker.motion = SPEAKER_SHORT;
                                  timerEnable(TIMER_IDX_LED_TEMP, 3000);
                                }
                                DEBUG_WARN("reqStop = ON.\r\n");
                              }
                              else
                              {
                                if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                  setLedMotion(LED_ACTION_RFID_FAIL);
                                  Charger.speaker.motion = SPEAKER_BLINK;
                                  blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                                  timerEnable(TIMER_IDX_LED_TEMP, 3000);
                                }
                                DEBUG_WARN("reqStop = Fail\r\n");
                              }
                          }
                    }
                    //NO charger
                    else // Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_NO_CHARGING
                    {
                          setLedMotion(LED_ACTION_RFID_FAIL);
                          Charger.speaker.motion = SPEAKER_BLINK;
                          blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                          timerEnable(TIMER_IDX_LED_TEMP, 3000);

                          Charger.rfid.op_bits.reqHalt = ON;
                          Charger.rfid.op_bits.reqBlockRead = OFF;
                          DEBUG_WARN("It is RFID NO charger mode \r\n");
                    }
                    break;
                case RFID_CMD_REQUEST_SN_FELICA:
                    if(UART_RFID_rx_buffer[1] == RFID_CMD_REQUEST_SN_FELICA)
                    {
                        Charger.rfid.snType = RFID_SN_TYPE_FELICA;
                        memset(&Charger.rfid.data_Sn[0], 0x00, ARRAY_SIZE(Charger.rfid.data_Sn));
                        for(uint8_t idx=0;idx<16;idx++)
                        {
                            if(idx<6)
                            {
                                Charger.rfid.data_Sn[idx] = UART_RFID_rx_buffer[idx+6];
                            }
                        }

                        if(isMode(MODE_IDLE))
                            memset(&Charger.rfid.nowCard[0], 0x00, ARRAY_SIZE(Charger.rfid.nowCard));
                        if(Charger.memory.EVSE_Config.data.item.RFID_SN_Endian)
                        {
                            DEBUG_INFO("RFID SN: %02X%02X%02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                            sprintf((char *)tmpBuf, "%02X%02X%02X%02X%02X%02X", Charger.rfid.data_Sn[5], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[0]);
                            memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.nowCard));
                        }
                        else
                        {
                            DEBUG_INFO("RFID SN: %02X%02X%02X%02X%02X%02X\r\n", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[5]);
                            sprintf((char *)tmpBuf, "%02X%02X%02X%02X%02X%02X", Charger.rfid.data_Sn[0], Charger.rfid.data_Sn[1], Charger.rfid.data_Sn[2], Charger.rfid.data_Sn[3], Charger.rfid.data_Sn[4], Charger.rfid.data_Sn[5]);
                            memcpy(&Charger.rfid.nowCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.nowCard));
                        }
                    }

                    //White List
                    if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_LOCAL_LIST)
                    {
                          DEBUG_WARN("OfflinePolicy is White List\r\n");
                    }
                    //Free
                    else if (Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_FREE)
                    {
                          Charger.rfid.op_bits.reqHalt = ON;
                          Charger.rfid.op_bits.reqBlockRead = OFF;
                          if(isMode(MODE_IDLE))
                          {
                              for(uint8_t idx=0;idx<16;idx++)
                              {
                                    Charger.rfid.currentCard[idx] = Charger.rfid.data_Sn[idx];
                              }

                              Charger.rfid.op_bits.reqStart = ON;
                              memcpy(&Charger.rfid.currentCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));
                              if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                setLedMotion(LED_ACTION_RFID_PASS);
                                Charger.speaker.motion = SPEAKER_SHORT;
                                timerEnable(TIMER_IDX_LED_TEMP, 3000);
                              }
                              DEBUG_WARN("RFID authorize pass.\r\n");
                          }
                          else if(isMode(MODE_CHARGING) || isMode(MODE_STOP))
                          {
                              DEBUG_WARN("RFID authorize pass.\r\n");
                              if (Array_data_Check(Charger.rfid.currentCard,Charger.rfid.nowCard))
                              {
                                Charger.rfid.op_bits.reqStop = ON;
                                if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                  setLedMotion(LED_ACTION_RFID_PASS);
                                  Charger.speaker.motion = SPEAKER_SHORT;
                                  timerEnable(TIMER_IDX_LED_TEMP, 3000);
                                }
                                DEBUG_WARN("reqStop = ON.\r\n");
                              }
                              else
                              {
                                if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                  setLedMotion(LED_ACTION_RFID_FAIL);
                                  Charger.speaker.motion = SPEAKER_BLINK;
                                  blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                                  timerEnable(TIMER_IDX_LED_TEMP, 3000);
                                }
                                DEBUG_WARN("reqStop = Fail\r\n");
                              }
                          }
                    }
                    //NO charger
                    else // Charger.memory.EVSE_Config.data.item.OfflinePolicy == RFID_USER_AUTH_NO_CHARGING
                    {
                          setLedMotion(LED_ACTION_RFID_FAIL);
                          Charger.speaker.motion = SPEAKER_BLINK;
                          blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                          timerEnable(TIMER_IDX_LED_TEMP, 3000);

                          Charger.rfid.op_bits.reqHalt = ON;
                          Charger.rfid.op_bits.reqBlockRead = OFF;
                          DEBUG_WARN("It is RFID NO charger mode \r\n");
                    }
                    osDelay(1000);
                    break;

                case RFID_CMD_BLOCK_READ:
                  if(UART_RFID_rx_buffer[1] == RFID_CMD_BLOCK_READ)
                  {
                    memcpy(Charger.rfid.data_Block, &UART_RFID_rx_buffer[2], 0x10);
                    Charger.rfid.op_bits.reqHalt = ON;
                    Charger.rfid.op_bits.reqBlockRead = OFF;

                    //RFID_PH
                    if(Valid_RFID_SN())
                    {
                        if(isMode(MODE_IDLE))
                        {
                            Charger.rfid.op_bits.reqStart = ON;
                            setLedMotion(LED_ACTION_RFID_PASS);
                            Charger.speaker.motion = SPEAKER_SHORT;
                            timerEnable(TIMER_IDX_LED_TEMP, 3000);
                            memcpy(&Charger.rfid.currentCard[0], &tmpBuf[0], ARRAY_SIZE(Charger.rfid.currentCard));                        }
                        else if(isMode(MODE_CHARGING) || isMode(MODE_STOP))
                        {
                            Charger.rfid.op_bits.reqStop = ON;
                        }
                        DEBUG_WARN("RFID authorize pass.\r\n");
                    }
                    else
                    {
                        setLedMotion(LED_ACTION_RFID_FAIL);
                        Charger.speaker.motion = SPEAKER_BLINK;
                        blinkerTimeSet(BLINKER_IDX_SPEAKER, 100, 100, SPEAK_RESET_RFID_TIME, 3) ; // SPEAK_RESET_RFID_TIME -> Avoid repeating
                        timerEnable(TIMER_IDX_LED_TEMP, 3000);
                        DEBUG_WARN("RFID authorize fault.\r\n");
                    }
                  }
                  break;
                case RFID_CMD_BLOCK_WRITE:
                  break;
                case RFID_CMD_HALT_14443A:
                  if(UART_RFID_rx_buffer[1] == RFID_CMD_HALT_14443A)
                  {
                      Charger.rfid.op_bits.reqHalt = OFF;
                      DEBUG_INFO("RFID card(14443A) halt succcess.\r\n");
                  }
                  break;
                case RFID_CMD_HALT_14443B:
                  if(UART_RFID_rx_buffer[1] == RFID_CMD_HALT_14443B)
                  {
                      Charger.rfid.op_bits.reqHalt = OFF;
                      DEBUG_INFO("RFID card(14443B) halt succcess.\r\n");
                  }
                  break;
                case (RFID_CMD_BLOCK_READ ^ 0xff):
                    Charger.rfid.op_bits.reqBlockRead = OFF;
                    DEBUG_WARN("RFID cread block fail.\r\n");
                    break;
                default:
                  break;
            }
        }

        // Clear rx_buffer and related varaible
        for(uint16_t i = 0; i < UART_RFID_rx_len ; i++)
            UART_RFID_rx_buffer[i]=0;

        UART_RFID_rx_len = 0;
        UART_RFID_recv_end_flag = OFF;
    }
    HAL_UART_Receive_DMA(&RFID_USART,(uint8_t*)UART_RFID_rx_buffer, (UART_BUFFER_SIZE>>4));

    osDelay(300);
  }
  /* USER CODE END StartRfidTask */
}

/* USER CODE BEGIN Header_StartLedSpeakerTask */
/**
* @brief Function implementing the led_speakerTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartLedSpeakerTask */
void StartLedSpeakerTask(void const * argument)
{
  /* USER CODE BEGIN StartLedSpeakerTask */
  uint16_t    led_pwm_duty_now[4];
  uint16_t    breathe_duty_now[4];

  //standard default
  for(uint8_t idx=0;idx<12;idx++)
    Charger.Led_Brightness[idx] = 0x33;

  /*
  //Night mode starndard default brightness
  Charger.Led_Brightness[0] = 0x11;     //00:00~ 01:59
  Charger.Led_Brightness[1] = 0x11;     //02:00~ 03:59
  Charger.Led_Brightness[2] = 0x11;     //04:00~ 05:59
  Charger.Led_Brightness[3] = 0x33;     //06:00~ 07:59
  Charger.Led_Brightness[4] = 0x33;     //08:00~ 09:59
  Charger.Led_Brightness[5] = 0x33;     //10:00~ 11:59
  Charger.Led_Brightness[6] = 0x33;     //12:00~ 13:59
  Charger.Led_Brightness[7] = 0x33;     //14:00~ 15:59
  Charger.Led_Brightness[8] = 0x33;     //16:00~ 17:59
  Charger.Led_Brightness[9] = 0x11;     //18:00~ 19:59
  Charger.Led_Brightness[10] = 0x11;    //20:00~ 21:59
  Charger.Led_Brightness[11] = 0x11;    //22:00~ 23:59
  */

  /* Infinite loop */
  for(;;)
  {
    led_pwm_duty_now[0] = getBrightnessDuty(Charger.led_pwm_duty[0]);
    led_pwm_duty_now[1] = getBrightnessDuty(Charger.led_pwm_duty[1]);
    led_pwm_duty_now[2] = getBrightnessDuty(Charger.led_pwm_duty[2]);
    led_pwm_duty_now[3] = getBrightnessDuty(Charger.led_pwm_duty[3]);

    breathe_duty_now[0] = getBrightnessDuty(breathe.duty[0]);
    breathe_duty_now[1] = getBrightnessDuty(breathe.duty[1]);
    breathe_duty_now[2] = getBrightnessDuty(breathe.duty[2]);
    breathe_duty_now[3] = getBrightnessDuty(breathe.duty[3]);

    if(timer[TIMER_IDX_LED_TEMP].isAlarm)
    {
        timerDisable(TIMER_IDX_LED_TEMP);
        setLedMotion(Charger.Led_Mode);
    }

    /*
     LED red process
    */
    switch(Charger.led_R.motion)
    {
        case LED_MOTION_ON:
          user_pwm_setvalue(PWM_CH_LED_R, led_pwm_duty_now[0]);
          break;
        case LED_MOTION_BLINK:
          if(blinker[BLINKER_IDX_LED].isOn)
            user_pwm_setvalue(PWM_CH_LED_R, led_pwm_duty_now[0]);
          else
            user_pwm_setvalue(PWM_CH_LED_R, PWM_DUTY_OFF);
          break;
        case LED_MOTION_BREATHE:
          user_pwm_setvalue(PWM_CH_LED_R, breathe_duty_now[0]);
            break;
        case LED_MOTION_OFF:
        default:
          user_pwm_setvalue(PWM_CH_LED_R, PWM_DUTY_OFF);
          break;
    }

    /*
     LED green process
    */
    switch(Charger.led_G.motion)
    {
        case LED_MOTION_ON:
          user_pwm_setvalue(PWM_CH_LED_G, led_pwm_duty_now[1]);
          break;
        case LED_MOTION_BLINK:
          if(blinker[BLINKER_IDX_LED].isOn)
            user_pwm_setvalue(PWM_CH_LED_G, led_pwm_duty_now[1]);
          else
            user_pwm_setvalue(PWM_CH_LED_G, PWM_DUTY_OFF);
          break;
        case LED_MOTION_BREATHE:
          user_pwm_setvalue(PWM_CH_LED_G, breathe_duty_now[1]);
            break;
        case LED_MOTION_OFF:
        default:
          user_pwm_setvalue(PWM_CH_LED_G, PWM_DUTY_OFF);
          break;
    }

    /*
     LED blue process
    */
    switch(Charger.led_B.motion)
    {
        case LED_MOTION_ON:
          user_pwm_setvalue(PWM_CH_LED_B, led_pwm_duty_now[2]);
          break;
        case LED_MOTION_BLINK:
          if(blinker[BLINKER_IDX_LED].isOn)
            user_pwm_setvalue(PWM_CH_LED_B, led_pwm_duty_now[2]);
          else
            user_pwm_setvalue(PWM_CH_LED_B, PWM_DUTY_OFF);
          break;
        case LED_MOTION_BREATHE:
            user_pwm_setvalue(PWM_CH_LED_B, breathe_duty_now[2]);
            break;
        case LED_MOTION_OFF:
        default:
          user_pwm_setvalue(PWM_CH_LED_B, PWM_DUTY_OFF);
          break;
    }

    /*
     LED white process
    */
    switch(Charger.led_W.motion)
    {
        case LED_MOTION_ON:
          user_pwm_setvalue(PWM_CH_LED_W, led_pwm_duty_now[3]);
          break;
        case LED_MOTION_BLINK:
          if(blinker[BLINKER_IDX_LED].isOn)
            user_pwm_setvalue(PWM_CH_LED_W, led_pwm_duty_now[3]);
          else
            user_pwm_setvalue(PWM_CH_LED_W, PWM_DUTY_OFF);
          break;
        case LED_MOTION_BREATHE:
            user_pwm_setvalue(PWM_CH_LED_W, breathe_duty_now[3]);
            break;
        case LED_MOTION_OFF:
        default:
          user_pwm_setvalue(PWM_CH_LED_W, PWM_DUTY_OFF);
          break;
    }

    /*
     LED breathe process
    */
    if(flicker[FLICKER_IDX_BREATHE].isOn)
        HAL_GPIO_WritePin(OUT_LED_Breathe_GPIO_Port, OUT_LED_Breathe_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(OUT_LED_Breathe_GPIO_Port, OUT_LED_Breathe_Pin, GPIO_PIN_RESET);

    /*
     Spearker process
    */
    switch(Charger.speaker.motion)
    {
        case SPEAKER_LONG:
          timerEnable(TIMER_IDX_SPEAKER, 600);
          HAL_GPIO_WritePin(OUT_Speaker_GPIO_Port, OUT_Speaker_Pin, GPIO_PIN_SET);

          if(timer[TIMER_IDX_SPEAKER].isAlarm)
          {
            timerDisable(TIMER_IDX_SPEAKER);
            Charger.speaker.motion = SPEAKER_NONE;
          }

          break;
        case SPEAKER_SHORT:
          timerEnable(TIMER_IDX_SPEAKER, 200);
          HAL_GPIO_WritePin(OUT_Speaker_GPIO_Port, OUT_Speaker_Pin, GPIO_PIN_SET);

          if(timer[TIMER_IDX_SPEAKER].isAlarm)
          {
            timerDisable(TIMER_IDX_SPEAKER);
            Charger.speaker.motion = SPEAKER_NONE;
          }

          break;
        case SPEAKER_BLINK:
          if(blinker[BLINKER_IDX_SPEAKER].isOn)
            HAL_GPIO_WritePin(OUT_Speaker_GPIO_Port, OUT_Speaker_Pin, GPIO_PIN_SET);
          else
            HAL_GPIO_WritePin(OUT_Speaker_GPIO_Port, OUT_Speaker_Pin, GPIO_PIN_RESET);

          if(blinker[BLINKER_IDX_SPEAKER].blinkisFinish)
          {
            disblinkerTime(BLINKER_IDX_SPEAKER);
          }
          break;
        case SPEAKER_NONE:
        default:
            HAL_GPIO_WritePin(OUT_Speaker_GPIO_Port, OUT_Speaker_Pin, GPIO_PIN_RESET);
            break;
    }

    osDelay(1);
  }
  /* USER CODE END StartLedSpeakerTask */
}

/* USER CODE BEGIN Header_StartCpTask */

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
void CpTask_CtrlCpPwm_P0(void)
{
//#ifdef FUNC_CCS //======================================================================
    uint16_t MaxCurr = Charger.memory.EVSE_Config.data.item.MaxChargingCurrent;

//    if (Charger.m_bRunCCS) //CCS Charge
//    {
//        user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_5);
//        Charger.MaxChargingCurrent_Previous = MaxCurr;
//    }
//    else //Normal Charge
    {
#ifdef FUNC_MODIFY_CP_PWM_CTRL_20231225
        if (Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU || Charger.m_bModelNameDC)
        {
            if ((MaxCurr >= 6) && (MaxCurr <= Charger.maxRatingCurrent))
            {
                user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(MaxCurr));
                Charger.MaxChargingCurrent_Previous = MaxCurr;
            }
            else
            {
                user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(Charger.maxRatingCurrent));
                Charger.MaxChargingCurrent_Previous = Charger.maxRatingCurrent;
            }
        }
        else
        {
            if ((Charger.AC_MaxChargingCurrentOrDuty >= 6) && (Charger.AC_MaxChargingCurrentOrDuty <= Charger.maxRatingCurrent))
            {
                user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(Charger.AC_MaxChargingCurrentOrDuty));
            }
            else
            {
                if (Charger.AC_MaxChargingCurrentOrDuty == 0)
                {
                    user_pwm_setvalue(PWM_CH_CP, 0);
                }
                else if (Charger.AC_MaxChargingCurrentOrDuty == 1)
                {
                    user_pwm_setvalue(PWM_CH_CP, 0);
                }
                else if (Charger.AC_MaxChargingCurrentOrDuty == 5)
                {
                    user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_5);
                }
                else if (Charger.AC_MaxChargingCurrentOrDuty == 100)
                {
                    user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                }
                else
                {
                    user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                }
            }
            Charger.MaxChargingCurrent_Previous = Charger.AC_MaxChargingCurrentOrDuty;
        }
#else //FUNC_MODIFY_CP_PWM_CTRL_20231225
        if ((MaxCurr >= 6) && (MaxCurr <= Charger.maxRatingCurrent))
        {
            user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(MaxCurr));
            Charger.MaxChargingCurrent_Previous = MaxCurr;
        }
        else
        {
            user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(Charger.maxRatingCurrent));
            Charger.MaxChargingCurrent_Previous = Charger.maxRatingCurrent;
        }
#endif //FUNC_MODIFY_CP_PWM_CTRL_20231225
    }
//#else //FUNC_CCS //======================================================================
//    uint16_t MaxCurr = Charger.memory.EVSE_Config.data.item.MaxChargingCurrent;
//    if (MaxCurr < 6)
//    {
//#ifdef MODIFY_CP_TASK_CTRL_CP_PWM_BELOW_SIX
//        if (MaxCurr == 0)
//        {
//            user_pwm_setvalue(PWM_CH_CP, 0);
//            Charger.MaxChargingCurrent_Previous = MaxCurr;
//        }
//        else
//        {
//            user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(6));
//            Charger.MaxChargingCurrent_Previous = MaxCurr;
//        }
//#else //MODIFY_CP_TASK_CTRL_CP_PWM_BELOW_SIX
//        user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(6));
//        Charger.MaxChargingCurrent_Previous = MaxCurr;
//#endif //MODIFY_CP_TASK_CTRL_CP_PWM_BELOW_SIX
//    }
//    else if ((MaxCurr >= 6) && (MaxCurr <= Charger.maxRatingCurrent))
//    {
//        user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(MaxCurr));
//        Charger.MaxChargingCurrent_Previous = MaxCurr;
//    }
//    else
//    {
//        user_pwm_setvalue(PWM_CH_CP, GetCpPwmDuty(Charger.maxRatingCurrent));
//        Charger.MaxChargingCurrent_Previous = Charger.maxRatingCurrent;
//    }
//#endif //FUNC_CCS //======================================================================
}

void CpTask_CtrlCpPwm_P1(void)
{
    if (
            (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent != Charger.MaxChargingCurrent_Previous) &&
            (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent <= Charger.maxRatingCurrent)
        )
    {
        CpTask_CtrlCpPwm_P0();
    }
}
#endif //MODIFY_CP_TASK_CTRL_CP_PWM

#ifdef TRIM_CCID_SELFTEST
void Proc_CCID_SelfTest(void)
{
    // check Leak Module do CCID selftset.
    if (Charger.CCID_Module_Type == CCID_MODULE_CORMEX)
    {
        Charger.Test_LeakModuleisPass = Test_LeakModule();
    }
    else if (Charger.CCID_Module_Type == CCID_MODULE_VAC)
    {
        Charger.Test_LeakModuleisPass  = PASS;
    }
    else
    {
        DEBUG_INFO("Did not judge Leak module can't self test  before charging.\r\n");
    }

    XP("Proc CCID Self-Test(%d): %s\r\n", Charger.CCID_Module_Type, Charger.Test_LeakModuleisPass == PASS ? "OK" : "NG");

}
#endif

#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
uint8_t AutoModifyCCID(void)
{
    uint8_t old = Charger.CCID_Module_Type;
    if (Test_LeakModule() == PASS)
    {
        Charger.m_bCCID_MustModify = HTK_FALSE;
        Charger.m_CCID_ModuleTestOK = Charger.CCID_Module_Type;
        return PASS;
    }
    else
    {
        Charger.CCID_Module_Type = (Charger.CCID_Module_Type == CCID_MODULE_CORMEX ? CCID_MODULE_VAC : CCID_MODULE_CORMEX);
        XP("#AutoModifyCCID: %s\r\n", CCID_MODULE_TYPE_STR);
        if (Test_LeakModule() == PASS)
        {
            Charger.m_bCCID_MustModify = HTK_TRUE;
            Charger.m_CCID_ModuleTestOK = Charger.CCID_Module_Type;
            return PASS;
        }
        else
        {
            Charger.m_bCCID_MustModify = HTK_FALSE;
            Charger.m_CCID_ModuleTestOK = CCID_MODULE_UNKNOW;
            Charger.CCID_Module_Type = old;
            return FAIL;
        }
    }
}
#endif

/**
* @brief Function implementing the cpTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartCpTask */
void StartCpTask(void const * argument)
{
  /* USER CODE BEGIN StartCpTask */
    //ccp
    uint32_t duration_delta;
    Charger.Mode = MODE_INITIAL;
    Charger.Relay_Action=GPIO_RELAY_ACTION_OFF;

    setLedMotion(LED_ACTION_INIT);

    //Check MCU control mode depend on GPIO state
#ifdef FUNC_FORCE_RUN_CSU_MODE_WITH_DC_MODELNAME
    Update_McuCtrlMode();
#else
    if(HAL_GPIO_ReadPin(IN_ACT_REQ_GPIO_Port, IN_ACT_REQ_Pin) == GPIO_PIN_RESET)
    {
        Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_CSU;
        DEBUG_INFO(" Check MCU_Control_Mode is CSU in CP task\r\n");
    }
    else
    {
        Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_NO_CSU;
        DEBUG_INFO(" MCU_Control_Mode is NO NO NO CSU in CP task\r\n");
    }
#endif
    //Charger.ModelReadisOK = FAIL ;

    /* Infinite loop */
    for(;;)
    {
        if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU)
        {
#ifdef MODIFY_CPTASK_HEAD
            Proc_CpTaskHead(HTK_FALSE);
#endif
            // Cancel EV ready restart cp logic
            if (Charger.Mode != MODE_HANDSHAKE)
            {
              timerDisable(TIMER_IDX_SIMU_DISCONNECT);
            }

            switch(Charger.Mode)
            {
                  case MODE_INITIAL:
                        setLedMotion(LED_ACTION_INIT);
                        user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                        HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port, OUT_Leak_Test_Pin, GPIO_PIN_SET); // for VAC LeakModule use

                        if (Charger.ModelReadisOK ==PASS)
                        {
                          getRotarySwitchSetting( );
                          getGridTypeSwitchSetting( );
                          Charger.isTestLeakModule = ON ;

#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
                          if (AutoModifyCCID() == PASS)
#else
                          if(Test_LeakModule() == PASS)
#endif
                          {
                              DEBUG_INFO("Leak module self test pass when initial.\r\n");
                              osDelay(1000);

                              if(Charger.isDebugEnable)
                                  setChargerMode(MODE_DEBUG);
                              else
                              {
                                  if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                    // Cold load pick up check
                                    if((Charger.CP_State == SYSTEM_STATE_A) && Charger.memory.coldLoadPickUp.data.item.isEnable)
                                    {
                                        recordChargingHis(OFF, END_STATUS_CODE_DROP);
                                        Charger.memory.coldLoadPickUp.data.item.isEnable = OFF;
                                        Charger.memory.coldLoadPickUp.op_bits.update = ON;
                                    }
                                  }
                                  osDelay(5000) ;                //wait hardware PE feedback data so delay some time
/*
TEST CALI VAL
Charger.memory.EVSE_Config.data.item.Correction_VL1[1][0] = 0x0A59;
Charger.memory.EVSE_Config.data.item.Correction_VL1[1][1] = 0x0A91;
Charger.memory.EVSE_Config.data.item.Correction_VL1[2][0] = 0x0684;
Charger.memory.EVSE_Config.data.item.Correction_VL1[2][1] = 0x06A7;

Charger.memory.EVSE_Config.data.item.Correction_CL1[1][0] = 0x0139;
Charger.memory.EVSE_Config.data.item.Correction_CL1[1][1] = 0x0140;
Charger.memory.EVSE_Config.data.item.Correction_CL1[2][0] = 0x0062;
Charger.memory.EVSE_Config.data.item.Correction_CL1[2][1] = 0x0064;

Charger.memory.EVSE_Config.data.item.Correction_Leak[1][0] = 0x0632;
Charger.memory.EVSE_Config.data.item.Correction_Leak[1][1] = 0x05DC;
Charger.memory.EVSE_Config.data.item.Correction_Leak[2][0] = 0x0488;
Charger.memory.EVSE_Config.data.item.Correction_Leak[2][1] = 0x03E8;

Charger.memory.EVSE_Config.op_bits.update = ON;
*/
                                  setChargerMode(MODE_IDLE);
                              }
                          }
                          else
                          {
                              Charger.Alarm_Code |= ALARM_LEAK_MODULE_FAIL;
                              DEBUG_INFO("Leak module self test fail when initial.\r\n");
                              Charger.counter.LEAK_MODULE.isLatch = ON ;
                          }
                          Charger.isTestLeakModule = OFF ;
                        }

                    break;

                  case MODE_IDLE:
                    if(isModeChange())
                    {
                        setLedMotion(LED_ACTION_IDLE);
                        Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                        Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;

#ifdef MODIFY_AC_EVSE_STATUS_MAX_CHARGING_CURRENT_VARIABLE
                        Charger.AC_MaxChargingCurrentOrDuty = Charger.maxRatingCurrent;
#endif

                        user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                        Charger.isSetStartTime = ON  ;
                    }

                    if (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_OCPP)
                    {
                        if( Charger.memory.coldLoadPickUp.data.item.isEnable || Charger.rfid.op_bits.reqStart)
                        {
                            osDelay(LED_RFID_TIME);       // for Buzzer and RFID /Fail LED use
                            setLedMotion(LED_ACTION_AUTHED);
                            // Check start method type
                            memset(&Charger.cycle_info.userId[0], 0x00, ARRAY_SIZE(Charger.cycle_info.userId));

                            if(Charger.rfid.op_bits.reqStart)
                            {
                                Charger.cycle_info.StartType = START_METHOD_RFID;
                                memcpy(&Charger.cycle_info.userId[0], &Charger.rfid.currentCard[0], ARRAY_SIZE(Charger.rfid.currentCard));
                                Charger.istoHandShakeMode = ON ;
                            }
                            Charger.rfid.op_bits.reqStart = OFF;

                            if(Charger.memory.coldLoadPickUp.data.item.isEnable)
                            {
                                Charger.memory.coldLoadPickUp.data.item.isEnable = OFF;
                                Charger.memory.coldLoadPickUp.op_bits.update = ON;
                                DEBUG_INFO("coldLoadPickUp ON to rand wait sec.\r\n");
#ifdef MODIFY_COLD_LOAD_PICKUP_DELAY
                                ColdLoadPickup_Delay("coldLoadPickUp ON to rand wait sec.");
#else
                                osDelay((rand()%175000)+5000);
                                //osDelay((rand()%5000)+5000);
#endif
                                Charger.istoHandShakeMode = ON ;
                            }
                        }


                        if (Charger.istoHandShakeMode == ON) //charger can to HandShakeMode
                        {
                            if ((Charger.CP_State == SYSTEM_STATE_B)||(Charger.CP_State == SYSTEM_STATE_C))
                            {
                              timerDisable(TIMER_IDX_CP);
                              Charger.istoHandShakeMode = OFF ;
                              setChargerMode(MODE_HANDSHAKE);
                              if (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'E')
                                timerEnable(TIMER_IDX_SIMU_DISCONNECT, 30000);
                            }
                            else
                            {
                              timerEnable(TIMER_IDX_CP, 180000);
                            }
                        }
                    }
                    else if (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_FREE)
                    {
                        if((Charger.CP_State == SYSTEM_STATE_B) ||
                           (Charger.CP_State == SYSTEM_STATE_C) ||
                            Charger.memory.coldLoadPickUp.data.item.isEnable )
                        {
                            setLedMotion(LED_ACTION_AUTHED);
                            // Check start method type
                            memset(&Charger.cycle_info.userId[0], 0x00, ARRAY_SIZE(Charger.cycle_info.userId));
                            if(Charger.rfid.op_bits.reqStart)
                            {
                                Charger.cycle_info.StartType = START_METHOD_RFID;
                                memcpy(&Charger.cycle_info.userId[0], &Charger.rfid.currentCard[0], ARRAY_SIZE(Charger.rfid.currentCard));
                            }
                            else
                              Charger.cycle_info.StartType = START_METHOD_CP;

                            Charger.ble.isRequestOn = OFF;
                            Charger.rfid.op_bits.reqStart = OFF;
                            if(Charger.memory.coldLoadPickUp.data.item.isEnable)
                            {
                                Charger.memory.coldLoadPickUp.data.item.isEnable = OFF;
                                Charger.memory.coldLoadPickUp.op_bits.update = ON;
                                DEBUG_INFO("coldLoadPickUp ON to rand wait sec.\r\n");
#ifdef MODIFY_COLD_LOAD_PICKUP_DELAY
                                ColdLoadPickup_Delay("coldLoadPickUp ON to rand wait sec.");
#else
                                osDelay((rand()%175000)+5000);
#endif
                            }
                            setChargerMode(MODE_HANDSHAKE);
                            if (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'E')
                              timerEnable(TIMER_IDX_SIMU_DISCONNECT, 30000);
                        }
                    }
                    break;

                case MODE_HANDSHAKE:
                    if(isModeChange())
                    {
                        Charger.isCP_in_B = OFF ;
                        Charger.isTestLeakModule = ON ;
#ifdef TRIM_CCID_SELFTEST
                        Proc_CCID_SelfTest();
#endif
                        //check Leak test pass
                        if (Charger.Test_LeakModuleisPass)
                        {
#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P0();
#endif
                            DEBUG_INFO("Leak module self test pass before charging.\r\n");
                        }
                        else
                        {
                            Charger.Alarm_Code |= ALARM_LEAK_MODULE_FAIL;
                            DEBUG_INFO("Leak module self test fail before charging.\r\n");
                            Charger.counter.LEAK_MODULE.retry ++ ;
                            if (Charger.counter.LEAK_MODULE.retry >=2)
                            {
                              Charger.counter.LEAK_MODULE.isLatch = ON ;
                            }
                        }

                        osDelay(300);

                        Charger.isTestLeakModule = OFF ;

                    }

                    // to chaging moder
                    if(Charger.CP_State == SYSTEM_STATE_C)
                    {
                        setChargerMode(MODE_CHARGING);

                        if (Charger.isSetStartTime == ON)
                        {
                          Charger.cycle_info.startTimeTick = HAL_GetTick();
                          Charger.cycle_info.startDateTime.year = Charger.memory.EVSE_Config.data.item.SystemDateTime.year;
                          Charger.cycle_info.startDateTime.month = Charger.memory.EVSE_Config.data.item.SystemDateTime.month;
                          Charger.cycle_info.startDateTime.day = Charger.memory.EVSE_Config.data.item.SystemDateTime.day;
                          Charger.cycle_info.startDateTime.hour = Charger.memory.EVSE_Config.data.item.SystemDateTime.hour;
                          Charger.cycle_info.startDateTime.min = Charger.memory.EVSE_Config.data.item.SystemDateTime.min;
                          Charger.cycle_info.startDateTime.sec = Charger.memory.EVSE_Config.data.item.SystemDateTime.sec;
                          Charger.cycle_info.meterStart = Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative;
                        }
                    }

                    if(Charger.CP_State == SYSTEM_STATE_B)
                    {
                        Charger.isCP_in_B = ON ;
                        setLedMotion(LED_ACTION_CONNECTED);
                    }

                    //RFID remove gun
                    if ((Charger.cycle_info.StartType == START_METHOD_RFID) && (Charger.CP_State == SYSTEM_STATE_A) && (Charger.isCP_in_B == ON))
                    {
                        Charger.isCP_in_B = OFF ;
                        setChargerMode(MODE_IDLE);
                    }

                    //FREE remove gun
                    if ((Charger.cycle_info.StartType == START_METHOD_CP) && Charger.CP_State == SYSTEM_STATE_A)
                    {
                        setChargerMode(MODE_IDLE);
                    }

                    // EV ready restart cp logic
                    if (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'E')
                    {
                        if(timer[TIMER_IDX_SIMU_DISCONNECT].isAlarm == ON)
                        {
                            user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_ZERO);
                            osDelay(4000);
                            user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                            osDelay(600);

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P0();
#endif
                            timerDisable(TIMER_IDX_SIMU_DISCONNECT);
                        }
                    }

                    break;

                case MODE_CHARGING:
                    if(isModeChange())
                    {
#ifdef MODIFY_CPTASK_CSU_0_1_CHARGE_MODE
                        CpTask_CtrlCpPwm_P0();
#endif
                        setLedMotion(LED_ACTION_CHARGING);
                    }

                    if (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_OCPP)
                    {
#ifdef MODIFY_AW_CP_TASK_CSU_0_1_CHARGING_MODE_STOP_WITHOUT_STATE_C
                        if(Charger.CP_State!=SYSTEM_STATE_C || Charger.rfid.op_bits.reqStop )
#else
                        if(((Charger.CP_State!=SYSTEM_STATE_C)&&(Charger.CP_State!=SYSTEM_STATE_UNKNOWN)) || Charger.rfid.op_bits.reqStop )
#endif
                        {
                            setChargerMode(MODE_STOP);
                        }
                        else
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
                            duration_delta = (HAL_GetTick() - Charger.cycle_info.startTimeTick);
                            Charger.cycle_info.Duration = duration_delta;
                            Charger.cycle_info.Power_Consumption = Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative - Charger.cycle_info.meterStart;

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P1();
#endif
                        }
                    }
                    else if (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_FREE)
                    {
#ifdef MODIFY_AW_CP_TASK_CSU_0_1_CHARGING_MODE_STOP_WITHOUT_STATE_C
                        if(Charger.CP_State!=SYSTEM_STATE_C)
#else
                        if((Charger.CP_State != SYSTEM_STATE_C) && (Charger.CP_State != SYSTEM_STATE_UNKNOWN))
#endif
                        {
                            setChargerMode(MODE_STOP);
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                        }
                        else
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_ON;

                            duration_delta = (HAL_GetTick() - Charger.cycle_info.startTimeTick);
                            Charger.cycle_info.Duration = duration_delta;
                            Charger.cycle_info.Power_Consumption = Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative - Charger.cycle_info.meterStart;

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P1();
#endif
                        }
                    }
                    break;

                case MODE_STOP:
                    if(isModeChange())
                    {
                      if ((Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_OCPP) && Charger.rfid.op_bits.reqStop)
                      {
                        osDelay(LED_RFID_TIME);       // for Buzzer and RFID /Fail LED use
                      }

                      setLedMotion(LED_ACTION_STOP);
                      Charger.isCP_in_B = OFF ;
                      Charger.is_RFIDKeepCharger = ON ;
                      Charger.isSetStartTime = OFF ;
                    }

                    if (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_OCPP)
                    {
                      //GB
                      if(Charger.CP_State == SYSTEM_STATE_A)
                      {
                          Charger.cycle_info.endTimeTick = HAL_GetTick();
                          recordChargingHis(OFF, END_STATUS_CODE_NORMAL);
                          Charger.rfid.op_bits.reqStop = OFF;
                          setChargerMode(MODE_IDLE);
                          Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                          timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                          Charger.isCP_in_B = OFF ;
                          Charger.is_RFIDKeepCharger = OFF ;
                          Charger.cycle_info.StartType = START_METHOD_NONE;
                      }
                      else
                      {
                          //rfid close PWM and relay
                          if ((Charger.rfid.op_bits.reqStop == ON)&&Charger.cycle_info.StartType == START_METHOD_RFID)
                          {
                              Charger.rfid.op_bits.reqStop = OFF;
                              user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);  // close pwm
                              timerEnable( TIMER_IDX_RFID_RELAY_OFF, 3000); //is set wait 3 sec
                              Charger.is_RFIDKeepCharger = OFF ;
                          }

                          if (timer[TIMER_IDX_RFID_RELAY_OFF].isAlarm == ON) //is wait 3 sec
                          {
                            timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;

                            setChargerMode(MODE_IDLE);

                            Charger.cycle_info.StartType = START_METHOD_NONE;
                          }

                          //cp close or open PWM
                          if((Charger.CP_State == SYSTEM_STATE_B))
                          {
                              timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                              Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                              Charger.isCP_in_B = ON ;
                          }
                          else if (Charger.CP_State == SYSTEM_STATE_C )
                          {
                              if ( Charger.isCP_in_B == ON && Charger.is_RFIDKeepCharger == ON)
                              {
                                Charger.is_RFIDKeepCharger = OFF ;
                                Charger.isCP_in_B = OFF ;
                                Charger.isTestLeakModule = ON ;
#ifdef TRIM_CCID_SELFTEST
                                Proc_CCID_SelfTest();
#endif
                                //check Leak test pass
                                if (Charger.Test_LeakModuleisPass)
                                {
                                    timerEnable(TIMER_IDX_CP, 180000);
#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                                    CpTask_CtrlCpPwm_P0();
#endif
                                    setChargerMode(MODE_CHARGING);
                                    DEBUG_INFO("Leak module self test pass before charging.\r\n");
                                }
                                else
                                {
                                    Charger.Alarm_Code |= ALARM_LEAK_MODULE_FAIL;
                                    DEBUG_INFO("Leak module self test fail before charging.\r\n");

                                    Charger.counter.LEAK_MODULE.retry ++ ;
                                    if (Charger.counter.LEAK_MODULE.retry >=2)
                                    {
                                      Charger.counter.LEAK_MODULE.isLatch = ON ;
                                    }
                                }
                                osDelay(300);
                                Charger.isTestLeakModule = OFF ;

                              }
                          }
                       }
                    }
                    else if (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_FREE)
                    {
                      if (Charger.CP_State == SYSTEM_STATE_A)
                      {
                          Charger.cycle_info.endTimeTick = HAL_GetTick();
                          recordChargingHis(OFF, END_STATUS_CODE_NORMAL);

                          Charger.ble.isRequestOff = OFF;
                          Charger.rfid.op_bits.reqStop = OFF;
                          setChargerMode(MODE_IDLE);
                      }
                      else
                      {
                          if (Charger.CP_State == SYSTEM_STATE_B)
                          {
                              Charger.isCP_in_B = ON ;
                          }
                          if((Charger.CP_State == SYSTEM_STATE_C))
                          {
                              setChargerMode(MODE_CHARGING);
                          }
                      }
                    }
                    break;

                case MODE_ALARM:
                    if(isModeChange())
                    {
                      Charger.isSetStartTime = OFF ;
                      //clear blink time , Prevent red light from being snatched by others
                      disblinkerTime (BLINKER_IDX_LED) ;
                    }
                    Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;

                    //Set alarm led
                    if ((Charger.Alarm_Code != Charger.Alarm_Code_before) && (blinker[BLINKER_IDX_LED].blinkisFinish))
                    {
                        setLedMotion(LED_ACTION_ALARM);
                        Charger.Alarm_Code_before = Charger.Alarm_Code ;
                    }

                    if(Charger.Alarm_Code == 0x00)
                    {
                          Charger.Alarm_Code_before = Charger.Alarm_Code ;
                          if (Charger.Mode_Before_Alarm == MODE_CHARGING)       // in charging mode
                          {
                            if(Charger.CP_State == SYSTEM_STATE_A)      // to idle
                            {
                                Charger.cycle_info.endTimeTick = HAL_GetTick();
                                recordChargingHis(OFF, END_STATUS_CODE_NORMAL);
                                Charger.rfid.op_bits.reqStop = OFF;
                                Charger.ble.isRequestOff = OFF;
                                setChargerMode(MODE_IDLE);
                                Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                                timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                                Charger.isCP_in_B = OFF ;
                                Charger.is_RFIDKeepCharger = OFF ;
                                Charger.cycle_info.StartType = START_METHOD_NONE;
                            }
                            else        // to handshake
                            {
                                setChargerMode(MODE_HANDSHAKE);
                                Charger.isCP_in_B = ON ;
                                setLedMotion(LED_ACTION_CONNECTED);
                            }
                          }
                          else if(Charger.Mode_Before_Alarm == MODE_STOP)  // in stop mode
                          {
                            if(Charger.CP_State == SYSTEM_STATE_A)  // to idle
                            {
                                Charger.cycle_info.endTimeTick = HAL_GetTick();
                                recordChargingHis(OFF, END_STATUS_CODE_NORMAL);
                                Charger.rfid.op_bits.reqStop = OFF;
                                setChargerMode(MODE_IDLE);
                                Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                                timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                                Charger.isCP_in_B = OFF ;
                                Charger.is_RFIDKeepCharger = OFF ;
                                Charger.cycle_info.StartType = START_METHOD_NONE;
                            }
                            else if ((Charger.CP_State == SYSTEM_STATE_B) && (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_OCPP)) // OCPP
                            {
                                if ( ( ((Charger.cycle_info.StartType == START_METHOD_BLE) && (Charger.is_BLEKeepCharger == ON))||               // to handshake
                                            ((Charger.cycle_info.StartType == START_METHOD_RFID) && (Charger.is_RFIDKeepCharger == ON)) ) &&
                                            ( Charger.isCP_in_B == ON ) )
                                {
                                    setChargerMode(MODE_HANDSHAKE);
                                    setLedMotion(LED_ACTION_CONNECTED);
                                }
                                else    //to stop
                                {
                                    setChargerMode(MODE_STOP);
                                }
                            }
                            else if ((Charger.CP_State == SYSTEM_STATE_B) && (Charger.memory.EVSE_Config.data.item.AuthMode == AUTH_MODE_FREE)) //Free
                            {
                                if ( Charger.isCP_in_B == ON )  // to handshake
                                {
                                    setChargerMode(MODE_HANDSHAKE);
                                    setLedMotion(LED_ACTION_CONNECTED);
                                }
                                else    //to stop
                                {
                                    setChargerMode(MODE_STOP);
                                }
                            }
                            else    //to stop
                            {
                                setChargerMode(MODE_STOP);
                            }
                          }
                          else  // idle
                          {
                            if(timer[TIMER_IDX_STATE_E].isAlarm == ON)
                            {
                              setChargerMode(MODE_IDLE);
                            }
                          }
                        }
                    break;

                  case MODE_MAINTAIN:
                        if(isModeChange())
                        {}
                        break;

                  case MODE_DEBUG:
                        if(isModeChange())
                        {
                            setLedMotion(LED_ACTION_DEBUG);
                            Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
                            timerEnable(TIMER_IDX_DEBUG, 1000);
                        }

                        if(timer[TIMER_IDX_DEBUG].isAlarm || (Charger.Alarm_Code>0))
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                            Charger.isDebugModeCPtest = ON;
                        }

                        if(Charger.isDebugModeCPtest)
                        {
                            if(Charger.CP_State == SYSTEM_STATE_A)
                            {
                                Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                                Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;

#ifdef MODIFY_AC_EVSE_STATUS_MAX_CHARGING_CURRENT_VARIABLE
                                Charger.AC_MaxChargingCurrentOrDuty = Charger.maxRatingCurrent;
#endif
                                user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                            }
                            else if (Charger.CP_State == SYSTEM_STATE_B)
                            {
                                Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                                CpTask_CtrlCpPwm_P1();
#endif
                            }
                            else if (Charger.CP_State == SYSTEM_STATE_C)
                            {
                                Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                                CpTask_CtrlCpPwm_P1();
#endif
                            }
                        }
                        break;
                }
        }
        else if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_CSU)  //CP_CSU
        {
            /*
                MCU control mdoe with CSU
            */
#ifdef MODIFY_CPTASK_HEAD
            Proc_CpTaskHead(HTK_TRUE);
#endif
            // Cancel EV ready restart cp logic
            if (Charger.Mode != MODE_HANDSHAKE)
            {
              timerDisable(TIMER_IDX_SIMU_DISCONNECT);
            }

            switch(Charger.Mode)
            {
                case MODE_INITIAL:
                        setLedMotion(LED_ACTION_INIT);
                        user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                        HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port, OUT_Leak_Test_Pin, GPIO_PIN_SET); // for VAC LeakModule use

#ifdef FUNC_RELAY_OFF_WHEN_CSU_CMD_TIMEOUT
                        Charger.m_CSU_RxTick = HAL_GetTick();
#endif

                        if (Charger.ModelReadisOK ==PASS)
                        {
                          getRotarySwitchSetting( );
                          getGridTypeSwitchSetting( );
                          Charger.isTestLeakModule = ON ;

#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
                          if (AutoModifyCCID() == PASS)
#else
                          if(Test_LeakModule() == PASS)
#endif
                          {
                              DEBUG_INFO("Leak module self test pass when initial.\r\n");
                              osDelay(1000);

                              if(Charger.isDebugEnable)
                                  setChargerMode(MODE_DEBUG);
                              else
                              {
                                  setChargerMode(MODE_IDLE);
                                  if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                                    // Cold load pick up check
                                    if((Charger.CP_State == SYSTEM_STATE_A) && Charger.memory.coldLoadPickUp.data.item.isEnable)
                                    {
                                        recordChargingHis(OFF, END_STATUS_CODE_DROP);
                                        Charger.memory.coldLoadPickUp.data.item.isEnable = OFF;
                                        Charger.memory.coldLoadPickUp.op_bits.update = ON;
                                    }
                                  }
                              }
                          }
                          else
                          {
                              Charger.Alarm_Code |= ALARM_LEAK_MODULE_FAIL;
                              DEBUG_INFO("Leak module self test fail when initial.\r\n");
                              Charger.counter.LEAK_MODULE.isLatch = ON ;
                          }
                          Charger.isTestLeakModule = OFF ;
                        }
                    break;
                case MODE_IDLE:
                    if(isModeChange())
                    {
                        Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                        Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;
                        user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                        Charger.isSetStartTime = ON  ;
#ifdef FUNC_BLOCK_CSU_CONFIG_CP_PWM_DUTY
                        Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
#endif
                    }

                    if(Charger.am3352.isRequestOn &&
                       (Charger.CP_State != SYSTEM_STATE_A))
                    {
                        setChargerMode(MODE_HANDSHAKE);
                        if (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'E')
                          timerEnable(TIMER_IDX_SIMU_DISCONNECT, 30000);
                    }

                    break;

                case MODE_HANDSHAKE:
                    if(isModeChange())
                    {
                        Charger.isCP_in_B = OFF ;
                        Charger.isTestLeakModule = ON ;
#ifdef TRIM_CCID_SELFTEST
                        Proc_CCID_SelfTest();
#endif
                        //check Leak test pass
                        if (Charger.Test_LeakModuleisPass)
                        {

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
#ifdef MODIFY_MODE_HANDSHAKE_STOP_PWM_WITHOUT_OK_STATE
                            if (Charger.m_bSafetyRegulationGB)
                            {
                                if(Charger.CP_State == SYSTEM_STATE_B || Charger.CP_State == SYSTEM_STATE_C)
                                {
                                    CpTask_CtrlCpPwm_P0();
                                }
                            }
                            else
                            {
                                    CpTask_CtrlCpPwm_P0();
                            }
#endif //MODIFY_MODE_HANDSHAKE_STOP_PWM_WITHOUT_OK_STATE

#else //MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P0();

#endif //MODIFY_CP_TASK_CTRL_CP_PWM

                            osDelay(300);
                            DEBUG_INFO("Leak module self test pass before charging.\r\n");
                        }
                        else
                        {
                            Charger.Alarm_Code |= ALARM_LEAK_MODULE_FAIL;
                            DEBUG_INFO("Leak module self test fail before charging.\r\n");
                        }
                        Charger.isTestLeakModule = OFF ;
                    }

                    if(Charger.CP_State == SYSTEM_STATE_C)
                    {
#ifdef MODIFY_MODE_HANDSHAKE_STOP_PWM_WITHOUT_OK_STATE
                        if (Charger.m_bSafetyRegulationGB)
                        {
                            Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
                            if (Charger.m_CP_CurPWM == PWM_DUTY_FULL)
                            {
                                CpTask_CtrlCpPwm_P0();
                            }
                        }
#endif
                        setChargerMode(MODE_CHARGING);
                        timerDisable(TIMER_IDX_CP);

                        if (Charger.isSetStartTime == ON)
                        {
                          Charger.cycle_info.startTimeTick = HAL_GetTick();
                          Charger.cycle_info.startDateTime.year = Charger.memory.EVSE_Config.data.item.SystemDateTime.year;
                          Charger.cycle_info.startDateTime.month = Charger.memory.EVSE_Config.data.item.SystemDateTime.month;
                          Charger.cycle_info.startDateTime.day = Charger.memory.EVSE_Config.data.item.SystemDateTime.day;
                          Charger.cycle_info.startDateTime.hour = Charger.memory.EVSE_Config.data.item.SystemDateTime.hour;
                          Charger.cycle_info.startDateTime.min = Charger.memory.EVSE_Config.data.item.SystemDateTime.min;
                          Charger.cycle_info.startDateTime.sec = Charger.memory.EVSE_Config.data.item.SystemDateTime.sec;
                          Charger.cycle_info.meterStart = Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative;
                        }
                    }

                    if(Charger.CP_State == SYSTEM_STATE_B)
                    {
#ifdef MODIFY_MODE_HANDSHAKE_STOP_PWM_WITHOUT_OK_STATE
                        if (Charger.m_bSafetyRegulationGB)
                        {
                            Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
                            if (Charger.m_CP_CurPWM == PWM_DUTY_FULL)
                            {
                                CpTask_CtrlCpPwm_P0();
                            }
                        }
#endif
                        Charger.isCP_in_B = ON ;
                    }

                    if(((Charger.CP_State == SYSTEM_STATE_A) && Charger.isCP_in_B) || !Charger.am3352.isRequestOn)
                    {
                        user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);  // close pwm
                        setChargerMode(MODE_IDLE);
                        timerDisable(TIMER_IDX_CP);
                    }

                    // EV ready restart cp logic
                    if (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'E')
                    {
                        if(timer[TIMER_IDX_SIMU_DISCONNECT].isAlarm == ON)
                        {
                            user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_ZERO);
                            osDelay(4000);
                            user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                            osDelay(600);

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P0();
#endif
                            timerDisable(TIMER_IDX_SIMU_DISCONNECT);
                            timer[TIMER_IDX_SIMU_DISCONNECT].isAlarm = OFF ;
                        }
                    }
#ifdef MODIFY_MODE_HANDSHAKE_STOP_PWM_WITHOUT_OK_STATE
                    if (Charger.m_bSafetyRegulationGB)
                    {
                        if  (
                                (Charger.CP_State == SYSTEM_STATE_D || Charger.CP_State == SYSTEM_STATE_E) &&
                                (Charger.am3352.isRequestOn)
                            )
                        {
                            Charger.m_bBlockCsuCpPwmDuty = HTK_ENABLE;
                            user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                        }
                    }
#endif


                    break;

                case MODE_CHARGING:
                    if(isModeChange())
                    {
#ifdef MODIFY_CPTASK_CSU_0_1_CHARGE_MODE
                        CpTask_CtrlCpPwm_P0();
#endif
                    }

#ifdef MODIFY_AW_CP_TASK_CSU_0_1_CHARGING_MODE_STOP_WITHOUT_STATE_C
                    if(Charger.CP_State != SYSTEM_STATE_C || !Charger.am3352.isRequestOn)
#else
                    if(!Charger.am3352.isRequestOn)
#endif
                    {
                        setChargerMode(MODE_STOP);

                        if(Charger.CP_State != SYSTEM_STATE_C)
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;

#ifdef MODIFY_MODE_CHARGING_STOP_PWM_WITHOUT_OK_STATE
                            if (Charger.m_bSafetyRegulationGB)
                            {
                                if  (
                                        (Charger.CP_State == SYSTEM_STATE_D || Charger.CP_State == SYSTEM_STATE_E) &&
                                        (Charger.am3352.isRequestOn)
                                    )
                                {
                                    Charger.m_bBlockCsuCpPwmDuty = HTK_ENABLE;
                                    user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                                }
                            }
#endif //MODIFY_MODE_CHARGING_STOP_PWM_WITHOUT_OK_STATE
                        }
                    }
#ifdef FUNC_RELAY_OFF_WHEN_CSU_CMD_TIMEOUT
                    else if (HTK_IsTimeout(Charger.m_CSU_RxTick, CSU_CMD_TIMEOUT_SEC * 1000))
                    {
                        if (Charger.Relay_Action != GPIO_RELAY_ACTION_OFF)
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                            XP("#<CSU_TIMEOUT> RELAY => OFF\r\n");
                        }
#ifdef FUNC_REQUEST_OFF_WHEN_CSU_CMD_TIMEOUT
                        if (Charger.am3352.isRequestOn != OFF)
                        {
                            Charger.am3352.isRequestOn = OFF;
                            XP("#<CSU_TIMEOUT> REQUEST => OFF\r\n");
                        }
#endif
                    }
#endif //FUNC_RELAY_OFF_WHEN_CSU_CMD_TIMEOUT
                    else
                    {

#ifdef USE_OLD_ONE_STEP_CHARGE_FOR_AW_NOODOE
                        Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
#endif
                        duration_delta = (HAL_GetTick() - Charger.cycle_info.startTimeTick);
                        Charger.cycle_info.Duration = duration_delta;
                        Charger.cycle_info.Power_Consumption = Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative - Charger.cycle_info.meterStart;
                    }
                    break;

                case MODE_STOP:
                    if(isModeChange())
                    {
                        Charger.isSetStartTime = OFF ;
                        Charger.isCP_in_B = OFF ;
                        if (!Charger.am3352.isRequestOn)   //represent swip card stop charge in 6V
                        {
                          Charger.rfid.op_bits.reqStop = ON ;
                        }
                    }

                    if((Charger.CP_State == SYSTEM_STATE_A) || !Charger.am3352.isRequestOn)
                    {
                        if( !Charger.am3352.isRequestOn)
                        {
                            if (Charger.rfid.op_bits.reqStop == ON || (Charger.CP_State == SYSTEM_STATE_B)) //1. swip card stop charge in 6V. , 2.cp-> B then swip card stop charge
                            {
                                if(Charger.CP_State == SYSTEM_STATE_B)
                                  Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                                Charger.rfid.op_bits.reqStop = OFF;
                                user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);  // close pwm
                                timerEnable( TIMER_IDX_RFID_RELAY_OFF, 3000); //is set wait 3 sec
                                Charger.cycle_info.endTimeTick = HAL_GetTick();
                                recordChargingHis(OFF, END_STATUS_CODE_NORMAL);
                                Charger.isCP_in_B = OFF ;
                            }

                            if (timer[TIMER_IDX_RFID_RELAY_OFF].isAlarm == ON ) //is wait 3 sec
                            {
                              	timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                              	Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
#ifdef FUNC_BLOCK_CSU_CONFIG_CP_PWM_DUTY
                              	Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
#endif
                              	setChargerMode(MODE_IDLE);
                              	Charger.cycle_info.StartType = START_METHOD_NONE;
                            }
                        }
                        else //CP_State == SYSTEM_STATE_A
                        {
                              user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);  // close pwm
                              Charger.cycle_info.endTimeTick = HAL_GetTick();
                              recordChargingHis(OFF, END_STATUS_CODE_NORMAL);
                              Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
#ifdef FUNC_BLOCK_CSU_CONFIG_CP_PWM_DUTY
                              Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
#endif
                              setChargerMode(MODE_IDLE);
                              Charger.isCP_in_B = OFF ;
                        }
                    }
                    else // Charger.am3352.isRequestOn == 1
                    {
                        if((Charger.CP_State == SYSTEM_STATE_B))
                        {
                            timerDisable(TIMER_IDX_RFID_RELAY_OFF);
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                            Charger.isCP_in_B = ON ;
                        }

                        if((Charger.CP_State == SYSTEM_STATE_C) && (!Charger.am3352.isRequestOff) )
                        {
#ifdef FUNC_BLOCK_CSU_CONFIG_CP_PWM_DUTY
                            Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
#endif

#ifdef MODIFY_MODE_STOP_TO_CHARGE_PROCESS
                            setChargerMode(MODE_CHARGING);
#else
                            setChargerMode(MODE_HANDSHAKE);
#endif
                        }

#ifdef MODIFY_MODE_STOP_STOP_PWM_WITHOUT_OK_STATE
                        if (Charger.m_bSafetyRegulationGB)
                        {
                            if  (
                                    (Charger.CP_State == SYSTEM_STATE_D || Charger.CP_State == SYSTEM_STATE_E) &&
                                    (Charger.am3352.isRequestOn)
                                )
                            {
                                Charger.m_bBlockCsuCpPwmDuty = HTK_ENABLE;
                                user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                            }
                            if ((Charger.CP_State == SYSTEM_STATE_B) && (Charger.am3352.isRequestOn))
                            {
                                Charger.m_bBlockCsuCpPwmDuty = HTK_DISABLE;
                                if (Charger.m_CP_CurPWM == PWM_DUTY_FULL)
                                {
                                    CpTask_CtrlCpPwm_P0();
                                }
                            }
                        }
#endif //MODIFY_MODE_STOP_STOP_PWM_WITHOUT_OK_STATE
                    }
                    break;

                case MODE_ALARM:
                    if(isModeChange())
                    {
                        Charger.isSetStartTime = OFF ;
                        if (Charger.CSUisReady == ON )
                        {
                            //clear blink time , Prevent red light from being snatched by others
                            disblinkerTime (BLINKER_IDX_LED) ;
                            //clear led Action
                            Charger.am3352.LedActionState = 0 ;
                        }
                    }
                    Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;

                    if(Charger.Alarm_Code == 0x00)
                    {
                        Charger.am3352.LedActionState = 0 ;
                        if (Charger.Mode_Before_Alarm == MODE_CHARGING)  // in charging mode
                        {
                            if(Charger.CP_State == SYSTEM_STATE_B )       // to handshake
                            {
                                setChargerMode(MODE_HANDSHAKE);
                            }
                            else  // to idle
                            {
                                user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                                setChargerMode(MODE_IDLE);
                            }
                        }
                        else if(Charger.Mode_Before_Alarm == MODE_STOP)
                        {
                            if (Charger.isCP_in_B == ON)  // to handshake
                            {
                                setChargerMode(MODE_HANDSHAKE);
                            }
                            else  // to stop
                            {
                                setChargerMode(MODE_STOP);
                            }
                        }
                        else    // to idle
                        {
                            if(timer[TIMER_IDX_STATE_E].isAlarm == ON)
                            {
                                setChargerMode(MODE_IDLE);
                            }
                        }
                    }

                    break;
                case MODE_DEBUG:
                    if(isModeChange())
                    {
                        setLedMotion(LED_ACTION_DEBUG);
                        Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
                        timerEnable(TIMER_IDX_DEBUG, 1000);
                    }

                    if(timer[TIMER_IDX_DEBUG].isAlarm || (Charger.Alarm_Code>0))
                    {
                        Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                        Charger.isDebugModeCPtest = ON;
                    }

                    if(Charger.isDebugModeCPtest)
                    {
                        if(Charger.CP_State == SYSTEM_STATE_A)
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
                            Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;
#ifdef MODIFY_AC_EVSE_STATUS_MAX_CHARGING_CURRENT_VARIABLE
                            Charger.AC_MaxChargingCurrentOrDuty = Charger.maxRatingCurrent;
#endif
                            user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
                        }
                        else if (Charger.CP_State == SYSTEM_STATE_B)
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_OFF;
#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P1();
#endif
                        }
                        else if (Charger.CP_State == SYSTEM_STATE_C)
                        {
                            Charger.Relay_Action = GPIO_RELAY_ACTION_ON;
#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
                            CpTask_CtrlCpPwm_P1();
#endif
                        }
                    }
                    break;
                default:
                    setChargerMode(MODE_IDLE);
                    break;
            }
        }
        else
        {
            /*By Pass Mode*/
        }

        osDelay(1);
    }
  /* USER CODE END StartCpTask */
}

/* USER CODE BEGIN Header_StartAlarmTask */
/**
* @brief Function implementing the alarmTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartAlarmTask */
void StartAlarmTask(void const * argument)
{
  /* USER CODE BEGIN StartAlarmTask */
  //aalarm
  timerEnable(TIMER_IDX_PE_DETECT, 30000);
  /* Infinite loop */
  for(;;)
  {
    if(Charger.Mode != MODE_INITIAL && Charger.Mode != MODE_DEBUG)
    {
        recordAlarmHis();

        //================================
        // CP fail alarm detect
        //================================
#ifdef  CP_ALARM_PROTECT
         if ((Charger.CP_State == SYSTEM_STATE_UNKNOWN)&&(!(Charger.Alarm_Code & ALARM_MCU_TESTFAIL)))
         {
            if(Charger.counter.CP.fail >1000)
            {
                if(!(Charger.Alarm_Code & ALARM_CP_ERROR))
                {
                    Charger.counter.CP.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_CP_ERROR;
                    DEBUG_ERROR("Alarm CP occur.\r\n");
                }
            }
            else
                Charger.counter.CP.fail++;
         }

#ifdef MODIFY_ALARMTASK_CP_ERROR_RECOVER
         else if (Charger.CP_State != SYSTEM_STATE_UNKNOWN)
#else
         else if ((Charger.CP_State != SYSTEM_STATE_UNKNOWN)&&(Charger.CP_State!=SYSTEM_STATE_D)&&
                  (Charger.CP_State != SYSTEM_STATE_E)&&(Charger.CP_State != SYSTEM_STATE_F))
#endif
         {
            Charger.counter.CP.fail = 0;
            if((Charger.Alarm_Code & ALARM_CP_ERROR))
            {
                osDelay(1000);
                Charger.counter.CP.retry++;
                Charger.Alarm_Code &= ~ALARM_CP_ERROR;
                DEBUG_INFO("Alarm CP recover.\r\n");
            }
         }
#endif  //CP_ALARM_PROTECT

        //================================
        // Over voltage alarm detect
        //================================
#ifdef  OVP_PROTECT
        if(Charger.Voltage[0] > ALARM_SPEC_OV)
        {
            if(Charger.counter.OV.fail > 1000)
            {
                Charger.counter.OV.restore = 0 ;
                if(!(Charger.Alarm_Code & ALARM_OVER_VOLTAGE))
                {
                    Charger.Alarm_Code |= ALARM_OVER_VOLTAGE;
                    DEBUG_ERROR("Alarm OV occur.\r\n");
                }
            }
            else
                Charger.counter.OV.fail++;
        }
        else if(Charger.Voltage[0] < (ALARM_SPEC_OV-ALARM_SPEC_OUV_HYSTERESIS))
        {
            if((Charger.Alarm_Code & ALARM_OVER_VOLTAGE))
            {
                if (Charger.counter.OV.restore > 1000 && blinker[BLINKER_IDX_LED].blinkisFinish)
                {
                    Charger.counter.OV.fail = 0 ;
                    DEBUG_INFO("Alarm OV is coldpickup ing..... \r\n");
                    Charger.counter.OV.isOccurInCharging = ((Charger.CP_State == SYSTEM_STATE_B)?ON:OFF);
                    if (Charger.counter.OV.isOccurInCharging)
                    {
#ifdef MODIFY_COLD_LOAD_PICKUP_DELAY
                        ColdLoadPickup_Delay("Alarm OV is coldpickup ing..... ");
#else
                        osDelay((rand()%175000)+5000);
#endif
                    }
                    Charger.Alarm_Code &= ~ALARM_OVER_VOLTAGE;
                    DEBUG_INFO("Alarm OV recover.\r\n");
                }
                else
                {
                  Charger.counter.OV.restore++;
                }
            }
            else
            {
              Charger.counter.OV.fail = 0 ;
              Charger.counter.OV.restore = 0 ;
            }
	}
#endif  //OVP_PROTECT

        //================================
        // Under voltage alarm detect
        //================================
#ifdef  UVP_PROTECT
        if(Charger.Voltage[0] < ALARM_SPEC_UV)
        {
            if(Charger.counter.UV.fail > 1000)
            {
                Charger.counter.UV.restore = 0 ;
                if(!(Charger.Alarm_Code & ALARM_UNDER_VOLTAGE))
                {
                    Charger.Alarm_Code |= ALARM_UNDER_VOLTAGE;
                    DEBUG_ERROR("Alarm UV occur.\r\n");
                }
            }
            else
                Charger.counter.UV.fail++;
        }
        else if(Charger.Voltage[0] > (ALARM_SPEC_UV+ALARM_SPEC_OUV_HYSTERESIS))
        {
            if(Charger.Alarm_Code & ALARM_UNDER_VOLTAGE)
            {
                if (Charger.counter.UV.restore > 1000 && blinker[BLINKER_IDX_LED].blinkisFinish)
                {
                  Charger.counter.UV.fail = 0 ;
                  DEBUG_INFO("Alarm UV is coldpickup ing..... \r\n");
                  Charger.counter.UV.isOccurInCharging = ((Charger.CP_State == SYSTEM_STATE_B)?ON:OFF);
                  if (Charger.counter.UV.isOccurInCharging)
                  {
#ifdef MODIFY_COLD_LOAD_PICKUP_DELAY
                    ColdLoadPickup_Delay("Alarm UV is coldpickup ing..... ");
#else
                    osDelay((rand()%175000)+5000);
#endif
                  }
                  Charger.Alarm_Code &= ~ALARM_UNDER_VOLTAGE;
                  DEBUG_INFO("Alarm UV recover.\r\n");
                }
                else
                {
                    Charger.counter.UV.restore++ ;
                }
            }
            else
            {
                Charger.counter.UV.restore = 0 ;
                Charger.counter.UV.fail = 0 ;
            }
        }

#endif  //UVP_PROTECT

        //================================
        // Over current alarm detect
        //================================
#ifdef  OCP_PROTECT

#ifdef FUNC_OCP_WITH_PP
        {
            uint16_t CurMaxCurr = 0;        //A
            uint16_t OC_BegThreshold = 0;   //Occur:    0.01A
            uint16_t OC_EndThreshold = 0;   //Recover:  0.01A

            CurMaxCurr = HTK_GET_VAL_MIN(Charger.memory.EVSE_Config.data.item.MaxChargingCurrent, Charger.maxRatingCurrent);

#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
            if (Charger.m_bSetOCP_32A == 1)
            {
                CurMaxCurr = 32;
            }
#endif

////            if (Charger.m_bDetectPP)
////            {
////                CurMaxCurr = HTK_GET_VAL_MIN(CurMaxCurr, Charger.m_PPInfo.m_CurCurr);
////            }

#ifdef MODIFY_OCP_PROC_WITH_MODELNAME_IDX_3_EURO_SPEC
            if (Charger.m_bModelNameWithEuroSpecOCP)
#else
            if (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'E')
#endif
            {
                OC_BegThreshold = (CurMaxCurr * Charger.OCP_Magnification) + 0;
                OC_EndThreshold = (CurMaxCurr * Charger.OCP_Magnification) - 200;
            }
            else
            {
                if (CurMaxCurr > 20)
                {
                    OC_BegThreshold = (CurMaxCurr * Charger.OCP_Magnification) + 0;
                    OC_EndThreshold = (CurMaxCurr * Charger.OCP_Magnification) - 200;
                }
                else
                {
                    OC_BegThreshold = (CurMaxCurr * 100) + 200;
                    OC_EndThreshold = (CurMaxCurr * 100) + 0;
                }
            }

            Charger.m_OCP_CurMaxCurr = CurMaxCurr;
            Charger.m_OCP_BegThreshold = OC_BegThreshold;
            Charger.m_OCP_EndThreshold = OC_EndThreshold;

            //--------------------------------
            // L1 Over current
            if(Charger.Current[0] >= 4800)
            {
                if(Charger.counter.OC.fail > 5)
                {
                    if(!(Charger.Alarm_Code & ALARM_CIRCUIT_SHORT))
                    {
                        Charger.counter.OC.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                        Charger.Alarm_Code |= ALARM_CIRCUIT_SHORT;
                        if (Charger.counter.OC.isLatch == OFF)
                        {
                            Charger.counter.OC.isLatch = ON ;
                            setLedMotion(LED_ACTION_ALARM);
                            timerDisable(TIMER_IDX_RETRY_OC);
                        }
                        DEBUG_INFO("Correction Current[0]: %f\r\n", Charger.Current[0]/100.0);
                        DEBUG_ERROR("Alarm SCP occur.\r\n");
                    }
                }
                else
                    Charger.counter.OC.fail++;
            }
            //else if(Charger.Current[0] > (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent>=Charger.maxRatingCurrent ? Charger.maxRatingCurrent*Charger.OCP_Magnification : Charger.memory.EVSE_Config.data.item.MaxChargingCurrent*Charger.OCP_Magnification))
            else if (Charger.Current[0] > OC_BegThreshold)
            {
                if(Charger.counter.OC.fail > 6000)
                {
                    if(!(Charger.Alarm_Code & ALARM_OVER_CURRENT))
                    {
                        Charger.counter.OC.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                        Charger.Alarm_Code |= ALARM_OVER_CURRENT;
                        DEBUG_INFO("Correction Current[0]: %f\r\n", Charger.Current[0]/100.0);
                        DEBUG_ERROR("Alarm OC occur.\r\n");
                        timerEnable(TIMER_IDX_RETRY_OC, ALARM_RETRY_INTERVAL_OC);
                        Charger.counter.OC.retry++;
                    }
                }
                else
                    Charger.counter.OC.fail++;

            }
            //else if(Charger.Current[0] < (Charger.memory.EVSE_Config.data.item.MaxChargingCurrent>=Charger.maxRatingCurrent ? ((Charger.maxRatingCurrent*Charger.OCP_Magnification)-200) : ((Charger.memory.EVSE_Config.data.item.MaxChargingCurrent*Charger.OCP_Magnification)-200)))
            else if (Charger.Current[0] < OC_EndThreshold)
            {
                Charger.counter.OC.fail = 0;
                if ((Charger.counter.OC.retry > ALARM_OC_RETRY_COUNT))
                {
                    if (Charger.counter.OC.isLatch == OFF)
                    {
                        Charger.counter.OC.isLatch = ON ;
                        setLedMotion(LED_ACTION_ALARM);
                        timerDisable(TIMER_IDX_RETRY_OC);
                    }
                }
                else if((Charger.Alarm_Code & ALARM_OVER_CURRENT) &&
                        (Charger.counter.OC.retry <= ALARM_OC_RETRY_COUNT) &&
                        (timer[TIMER_IDX_RETRY_OC].isAlarm == ON) &&
                         blinker[BLINKER_IDX_LED].blinkisFinish )
                {
                    timerDisable(TIMER_IDX_RETRY_OC);
                    osDelay(1000);
                    Charger.Alarm_Code &= ~ALARM_OVER_CURRENT;
                    Charger.Alarm_Code &= ~ALARM_CIRCUIT_SHORT;
                    DEBUG_INFO("Alarm OC recover.\r\n");

                }
            }
        }

#else //FUNC_OCP_WITH_PP

    //Old Procedure (Deleted)

#endif //FUNC_OCP_WITH_PP

#endif  //OCP_PROTECT

        //================================
        // Over temperature alarm detect
        //================================
#ifdef  OTP_PROTECT
        if (Charger.temperature.SystemAmbientTemp > ALARM_SPEC_OT_2)
        {
            if(Charger.counter.OT.fail > 2000)
            {
                if (Charger.counter.OT.isLatch == OFF)
                {
                    Charger.counter.OT.isLatch = ON ;
                    setLedMotion(LED_ACTION_ALARM);
                }
                //Charger.counter.OT.isLatch = ON ;
                if(!(Charger.Alarm_Code & ALARM_OVER_TEMPERATURE))
                {
                    Charger.counter.OT.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_OVER_TEMPERATURE;
                    DEBUG_ERROR("Latch OT2 occur.\r\n");
                    DEBUG_ERROR("Tmp = %d.\r\n",Charger.temperature.SystemAmbientTemp);
                }
            }
            else
                Charger.counter.OT.fail++;
        }
        else if((Charger.temperature.SystemAmbientTemp > ALARM_SPEC_OT_1) && (!Charger.counter.OT.isLatch))
        {
            if(Charger.counter.OT.fail > 1000)
            {
                if(!(Charger.Alarm_Code & ALARM_OVER_TEMPERATURE))
                {
                    Charger.counter.OT.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_OVER_TEMPERATURE;
                    DEBUG_ERROR("Alarm OT occur.\r\n");
                }
            }
            else
                Charger.counter.OT.fail++;
        }
        else if((Charger.temperature.SystemAmbientTemp < (ALARM_SPEC_OT_1-ALARM_SPEC_OT_HYSTERESIS)) && (!Charger.counter.OT.isLatch))
        {
            Charger.counter.OT.fail = 0;

            if((Charger.Alarm_Code & ALARM_OVER_TEMPERATURE) && blinker[BLINKER_IDX_LED].blinkisFinish)
            {
                Charger.counter.OT.retry++;
                Charger.Alarm_Code &= ~ALARM_OVER_TEMPERATURE;
                DEBUG_INFO("Alarm OT recover.\r\n");
            }
        }

        /*
        // For multi step OTP logic
        if(Charger.temperature.SystemAmbientTemp > ALARM_SPEC_OT_2)
        {
            if(Charger.counter.OT.fail > 1000)
            {
                if(!(Charger.Alarm_Code & ALARM_OVER_TEMPERATURE))
                {
                    Charger.counter.OT.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_OVER_TEMPERATURE;
                    if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                      blinkerTimeSet(500, 500, 3000, 3);
                    }
                    DEBUG_ERROR("Alarm OT occur.\r\n");
                }
            }
            else
                Charger.counter.OT.fail++;
        }
        else if(Charger.temperature.SystemAmbientTemp > ALARM_SPEC_OT_1)
        {
            if(Charger.counter.OT.fail > 1000)
            {

                if(!timer[TIMER_IDX_RETRY_OT].isEnable || timer[TIMER_IDX_RETRY_OT].isAlarm)
                {
                    Charger.memory.EVSE_Config.data.item.MaxChargingCurrent *= 0.75;
                }
                timerEnable(TIMER_IDX_RETRY_OT, ALARM_RETRY_INTERVAL_OT);
            }
            else
                Charger.counter.OT.fail++;
        }
        else if(Charger.temperature.SystemAmbientTemp < (ALARM_SPEC_OT_1-ALARM_SPEC_OT_HYSTERESIS))
        {
            Charger.counter.OT.fail = 0;

            if((Charger.Alarm_Code & ALARM_OVER_TEMPERATURE) &&
               timer[TIMER_IDX_RETRY_OT].isAlarm)
            {
                Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;
                timerDisable(TIMER_IDX_RETRY_OT);
                osDelay(3000);
                Charger.counter.OT.retry++;
                Charger.Alarm_Code &= ~ALARM_OVER_TEMPERATURE;
                DEBUG_INFO("Alarm OT recover.\r\n");
            }
        }*/
#endif  //OTP_PROTECT

#ifdef FUNC_EMP_FAN_CTRL_USE_LOCKER_IO
        if (Charger.temperature.SystemAmbientTemp > 35)
        {
            if (GET_EMP_FAN == OFF)
            {
                DEBUG_ERROR("<SET_FAN_ON>\r\n");
                SET_EMP_FAN(ON);
            }
        }
        else if (Charger.temperature.SystemAmbientTemp < 25)
        {
            if (GET_EMP_FAN == ON)
            {
                DEBUG_ERROR("<SET_FAN_OFF>\r\n");
                SET_EMP_FAN(OFF);
            }
        }


#endif //FUNC_EMP_FAN_CTRL_USE_LOCKER_IO

        //================================
        // Current leakage alarm detect
        // TODO: ADC channel & spec need to check for other detection method
        //================================

#ifdef CCID_PROTECT

#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
if (Charger.m_bDisableCCID == 0 && ((HAL_GetTick() - Charger.m_BootTick) / 1000) > 30)
{
#endif

if (Charger.CCID_Module_Type == CCID_MODULE_VAC)
{
        //module test
        if((HAL_GPIO_ReadPin(IN_Leak_Error_GPIO_Port, IN_Leak_Error_Pin) == GPIO_PIN_SET) && (!Charger.isTestLeakModule))
        {
            if(Charger.counter.LEAK.fail > 1000)
            {
                if(!(Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL))
                {
                    Charger.counter.LEAK.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_LEAK_MODULE_FAIL;
                    DEBUG_ERROR("Alarm leakage module error occur.\r\n");
                    timerEnable(TIMER_IDX_RETRY_LEAK, ALARM_RETRY_INTERVAL_LEAK);
                }
            }
            else
                Charger.counter.LEAK.fail++;
        }
        else
        {
            Charger.counter.LEAK.fail = 0;

            if((Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL) &&
               (Charger.counter.LEAK.retry < ALARM_RETRY_COUNT) &&
               (timer[TIMER_IDX_RETRY_LEAK].isAlarm == ON) &&
               blinker[BLINKER_IDX_LED].blinkisFinish)
            {
                timerDisable(TIMER_IDX_RETRY_LEAK);
                Charger.Alarm_Code &= ~ALARM_LEAK_MODULE_FAIL;
                osDelay(1000);
                #ifdef DEBUG
                DEBUG_INFO("Alarm leakage module error recover.\r\n");
                #endif
            }
        }

        //DC leakage
        if((HAL_GPIO_ReadPin(IN_Leak_DC_GPIO_Port, IN_Leak_DC_Pin) == GPIO_PIN_SET) && (!Charger.isTestLeakModule))
        {
            if(Charger.counter.LEAK_DC.fail > 10)
            {
                if(!(Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC))
                {
                    Charger.counter.LEAK_DC.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_CURRENT_LEAK_DC;
                    DEBUG_ERROR("Alarm DC leakage occur.\r\n");
                    timerEnable(TIMER_IDX_RETRY_LEAK_DC, ALARM_RETRY_INTERVAL_LEAK);
                    Charger.counter.LEAK_DC.retry++;
                }

                if (timer[TIMER_IDX_RETRY_LEAK_DC].isAlarm == ON || (Charger.counter.LEAK_DC.retry >ALARM_RETRY_COUNT))
                {
                  timerDisable(TIMER_IDX_RETRY_LEAK_DC);
                  //Charger.counter.LEAK.isLatch = ON ;
                  if (Charger.counter.LEAK.isLatch == OFF)
                  {
                      Charger.counter.LEAK.isLatch = ON ;
                      setLedMotion(LED_ACTION_ALARM);
                  }

                  DEBUG_ERROR("Alarm leakage DC isLatch.\r\n");
                }
            }
            else
                Charger.counter.LEAK_DC.fail++;
        }
        else
        {
            Charger.counter.LEAK_DC.fail = 0;

            if((Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC) &&
               (Charger.counter.LEAK_DC.retry <= ALARM_RETRY_COUNT) &&
               (timer[TIMER_IDX_RETRY_LEAK_DC].isAlarm == ON) &&
                blinker[BLINKER_IDX_LED].blinkisFinish)
            {
                timerDisable(TIMER_IDX_RETRY_LEAK_DC);
                Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_DC;
                DEBUG_INFO("Alarm DC leakage recover.\r\n");
            }

        }

        //AC leakage
        if((HAL_GPIO_ReadPin(IN_Leak_AC_GPIO_Port, IN_Leak_AC_Pin) == GPIO_PIN_SET) && (!Charger.isTestLeakModule))
        {
            if(Charger.counter.LEAK_AC.fail > 10)
            {
                if(!(Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC))
                {
                    Charger.counter.LEAK_AC.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_CURRENT_LEAK_AC;
                    DEBUG_ERROR("Alarm AC leakage occur.\r\n");
                    timerEnable(TIMER_IDX_RETRY_LEAK_AC, ALARM_RETRY_INTERVAL_LEAK);
                    Charger.counter.LEAK_AC.retry++;
                }

                if (timer[TIMER_IDX_RETRY_LEAK_AC].isAlarm == ON || (Charger.counter.LEAK_AC.retry > ALARM_RETRY_COUNT))
                {
                  timerDisable(TIMER_IDX_RETRY_LEAK_AC);
                  //Charger.counter.LEAK.isLatch = ON ;
                  if (Charger.counter.LEAK.isLatch == OFF)
                  {
                      Charger.counter.LEAK.isLatch = ON ;
                      setLedMotion(LED_ACTION_ALARM);
                  }
                  DEBUG_ERROR("Alarm leakage AC isLatch.\r\n");
                }
            }
            else
                Charger.counter.LEAK_AC.fail++;
        }
        else
        {
            Charger.counter.LEAK_AC.fail = 0;

            if((Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC) &&
               (Charger.counter.LEAK_AC.retry <= ALARM_RETRY_COUNT) &&
               (timer[TIMER_IDX_RETRY_LEAK_AC].isAlarm == ON) &&
               blinker[BLINKER_IDX_LED].blinkisFinish )
            {
                timerDisable(TIMER_IDX_RETRY_LEAK_AC);
                Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_AC;
                DEBUG_INFO("Alarm AC leakage recover.\r\n");

            }
        }
}
else // Charger.CCID_Module_Type is CCID_MODULE_CORMEX
{
        if((Charger.Leak_Current >= Charger.alarm_spec.Current_LEAK_AC) && (!Charger.isTestLeakModule)) // adc correction data to check
        {
            if(Charger.counter.LEAK.fail >= 5)
            {
                if(!(Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC))
                {
#ifdef FUNC_MODIFY_LEAK_AC_DISPLAY
                    XP("#Leak_Current (%d >= %d)\r\n", Charger.Leak_Current, Charger.alarm_spec.Current_LEAK_AC);
#else
                    XP("************************************************************\r\n");
                    XP("adc_value.ADC2_IN6_GF.value = %d\r\n", adc_value.ADC2_IN6_GF.value);
                    XP("Charger.Leak_Current(mA) = %d\r\n", Charger.Leak_Current);
                    XP("Charger.alarm_spec.Current_LEAK_AC(mA) = %d\r\n", Charger.alarm_spec.Current_LEAK_AC);
                    XP("Charger.isTestLeakModule = %s\r\n", Charger.isTestLeakModule ? "ON" : "OFF");
                    XP("************************************************************\r\n");
#endif
                    Charger.counter.LEAK.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_CURRENT_LEAK_AC; //Hao##### CSU Charge error here
                    DEBUG_ERROR("Alarm leakage occur.\r\n");
                    timerEnable(TIMER_IDX_RETRY_LEAK_AC, ALARM_RETRY_INTERVAL_LEAK);
                    Charger.counter.LEAK.retry ++ ;
                }
            }
            else
            {
                Charger.counter.LEAK.fail++;
            }
        }
        else if (Charger.Leak_Current < (Charger.alarm_spec.Current_LEAK_AC - ALARM_SPEC_CURRENT_LEAK_HYSTERESIS)) // adc correction data  to check
        {
            Charger.counter.LEAK.fail = 0;

            if (Charger.counter.LEAK.retry > ALARM_LEAK_RETRY_COUNT)
            {
                if (Charger.counter.LEAK.isLatch == OFF)
                {
                    Charger.counter.LEAK.isLatch = ON ;
                    setLedMotion(LED_ACTION_ALARM);
                }
            }
            else
            {
                if(((Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)||(Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC)) &&
                (Charger.counter.LEAK.retry <= ALARM_LEAK_RETRY_COUNT) &&
                (timer[TIMER_IDX_RETRY_LEAK_AC].isAlarm == ON) &&
                 blinker[BLINKER_IDX_LED].blinkisFinish )
                {
                  timerDisable(TIMER_IDX_RETRY_LEAK_AC);
                  osDelay(1000);
                  Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_AC;
                  DEBUG_INFO("Alarm leakage recover.\r\n");

                }
            }
        }
}


#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
}
#endif

#endif  //CCID_PROTECT

        //================================
        // Ground fail alarm detect
        // TODO: Spec need to check
        //================================
#ifdef  GROUND_FAULT_PROTECT
        if(Charger.GroundingDetect==ON){

#ifdef FUNC_RELAXSPEC_GROUND_FAULT_PROTECT
            static double GF_SPEC_OCCUR = 0;
            static double GF_SPEC_RECOVER = 0;
            if (GF_SPEC_OCCUR == 0 || GF_SPEC_RECOVER == 0)
            {
                GF_SPEC_OCCUR = 3.0 / 220.0;    //GF_SPEC_OCCUR = 0.013636(3.0)
                GF_SPEC_RECOVER = 2.0 / 220.0;  //GF_SPEC_RECOVER = 0.009091(2.0)
                XP("GF_SPEC_OCCUR = %lf, GF_SPEC_RECOVER = %lf\r\n", GF_SPEC_OCCUR, GF_SPEC_RECOVER);
            }
#endif
          if (timer[TIMER_IDX_PE_DETECT].isAlarm == ON) // after 30 sec check (GMI adc_value > spec) and (GMI adc_value <= 1 )
          {
#ifdef FUNC_RELAXSPEC_GROUND_FAULT_PROTECT
            if(((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) >  (Charger.Voltage[0]*GF_SPEC_OCCUR)) || (adc_value.ADC3_IN4_GMI_VL1.value <= 1))
#else
            if(((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) >  (Charger.Voltage[0]*0.011)) || (adc_value.ADC3_IN4_GMI_VL1.value <= 1))
#endif
            {
                if(Charger.counter.GF.fail > 4000)
                {
                    if(!(Charger.Alarm_Code & ALARM_GROUND_FAIL))
                    {
                        Charger.counter.GF.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                        Charger.Alarm_Code |= ALARM_GROUND_FAIL;
                        DEBUG_ERROR("Alarm GF occur.\r\n");
                    }
                }
                else
                    Charger.counter.GF.fail++;
            }
#ifdef FUNC_RELAXSPEC_GROUND_FAULT_PROTECT
            else if((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*GF_SPEC_RECOVER))
#else
            else if((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.00566))
#endif
            {
                Charger.counter.GF.fail = 0;
                if((Charger.Alarm_Code & ALARM_GROUND_FAIL) && blinker[BLINKER_IDX_LED].blinkisFinish)
                {
                    //osDelay(3000);
                    Charger.counter.GF.retry++;
                    Charger.Alarm_Code &= ~ALARM_GROUND_FAIL;
                    DEBUG_INFO("Alarm GF recover.\r\n");
                }
            }
          }
          else  // before 30 sec check (GMI adc_value > spec)
          {
#ifdef FUNC_RELAXSPEC_GROUND_FAULT_PROTECT
            if((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) > (Charger.Voltage[0]*GF_SPEC_OCCUR))
#else
            if((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) > (Charger.Voltage[0]*0.011))
#endif
            {
                if(Charger.counter.GF.fail > 4000)
                {
                    if(!(Charger.Alarm_Code & ALARM_GROUND_FAIL))
                    {
                        Charger.counter.GF.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                        Charger.Alarm_Code |= ALARM_GROUND_FAIL;
                        DEBUG_ERROR("Alarm GF occur.\r\n");
                    }
                }
                else
                    Charger.counter.GF.fail++;
            }
#ifdef FUNC_RELAXSPEC_GROUND_FAULT_PROTECT
            else if((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*GF_SPEC_RECOVER))
#else
            else if((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.00566))
#endif
            {
                Charger.counter.GF.fail = 0;
                if((Charger.Alarm_Code & ALARM_GROUND_FAIL) && blinker[BLINKER_IDX_LED].blinkisFinish)
                {
                    //osDelay(3000);
                    Charger.counter.GF.retry++;
                    Charger.Alarm_Code &= ~ALARM_GROUND_FAIL;
                    DEBUG_INFO("Alarm GF recover.\r\n");
                }
            }
          }
        }
#endif  //GROUND_FAULT_PROTECT

        //================================
        // Relay status error detect
        // TODO: ADC channel & spec need to check
        //================================
#ifdef  RELAY_WELDING_PROTECT
#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
        if (Charger.m_bDisableRelayWelding == 0 && ((HAL_GetTick() - Charger.m_BootTick) / 1000) > 30)
        {
#endif
        //GROUNGING_SYSTEM_LL
        if (Charger.GroundingSystem == GROUNGING_SYSTEM_LL)
        {
            if((Charger.Relay_Action == GPIO_RELAY_ACTION_ON) && (Charger.Relay_isOperationCompleted == 0x11 ) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                if(adc_value.ADC2_IN5_Welding.value < ((Charger.Voltage[0]*0.0048)+3)) // for UL dloule L syste            a=0.0048 b=0.03V
                {
                    if(Charger.counter.RELAY_Drive_Fualt.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_DRIVE_FUALT))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_DRIVE_FUALT;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay ON status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY_Drive_Fualt.fail++;
                }
                else
                {
                  Charger.counter.RELAY_Drive_Fualt.fail = 0 ;

                }
            }
            else if ((Charger.Relay_Action == GPIO_RELAY_ACTION_OFF) && (Charger.Relay_isOperationCompleted == 0x00) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                //if(adc_value.ADC2_IN5_Welding.value > 24) // 0.24 V
                if(adc_value.ADC2_IN5_Welding.value > ALARM_SPEC_RELAY_LL)
                {
                    if(Charger.counter.RELAY.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_STATUS))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_STATUS;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay OFF status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY.fail++;
                }
                else
                {
                  Charger.counter.RELAY.fail = 0 ;
                }
            }
        }
        else  // GROUNGING_SYSTEM_LN
        {
            if((Charger.Relay_Action == GPIO_RELAY_ACTION_ON) && (Charger.Relay_isOperationCompleted == 0x11) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                if(adc_value.ADC2_IN5_Welding.value < ALARM_SPEC_RELAY_LN_DRIVE_FAULT )         // old spec use
                {
                    if(Charger.counter.RELAY.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_DRIVE_FUALT))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_DRIVE_FUALT;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay ON status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY.fail++;
                }
                else
                {
                  Charger.counter.RELAY.fail = 0 ;
                }
            }
            else if ((Charger.Relay_Action == GPIO_RELAY_ACTION_OFF) && (Charger.Relay_isOperationCompleted == 0x00) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                if(adc_value.ADC2_IN5_Welding.value > ALARM_SPEC_RELAY_LN_WELDING)
                {
                    if(Charger.counter.RELAY.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_STATUS))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_STATUS;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay OFF status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY.fail++;
                }
                else
                {
                  Charger.counter.RELAY.fail = 0 ;
                }
            }
        }

#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
        }
#endif
#endif  //RELAY_WELDING_PROTECT

        //================================
        // Emergency stop alarm detect
        //================================
#ifdef  EMC_BUTTON_PROTECT
        if(HAL_GPIO_ReadPin(IN_Emergency_GPIO_Port, IN_Emergency_Pin) == GPIO_PIN_RESET)
        {
            if(Charger.counter.EMO.fail > 100)
            {
                if(!(Charger.Alarm_Code & ALARM_EMERGENCY_STOP))
                {
                    Charger.counter.EMO.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                    Charger.Alarm_Code |= ALARM_EMERGENCY_STOP;
                    DEBUG_ERROR("Alarm EMO occur.\r\n");
                }
            }
            else
                Charger.counter.EMO.fail++;
        }
        else
        {
            Charger.counter.EMO.fail = 0;
            if((Charger.Alarm_Code & ALARM_EMERGENCY_STOP) && blinker[BLINKER_IDX_LED].blinkisFinish)
            {
                Charger.counter.EMO.retry++;
                Charger.Alarm_Code &= ~ALARM_EMERGENCY_STOP;
                DEBUG_INFO("Alarm EMO recover.\r\n");
            }
        }
#endif  //EMC_BUTTON_PROTECT

        //================================
        // Handshaking timeout detect
        //================================
#ifdef  HANDSHAKE_PROTECT
        if(timer[TIMER_IDX_CP].isAlarm == ON)
        {
            if(!(Charger.Alarm_Code & ALARM_HANDSHAKE_TIMEOUT))
            {
                Charger.Alarm_Code |= ALARM_HANDSHAKE_TIMEOUT;
                timerDisable(TIMER_IDX_CP);
                Charger.rfid.op_bits.reqStart = OFF;
                Charger.istoHandShakeMode = OFF ;
                DEBUG_ERROR("Alarm handshake overtime occur.\r\n");
            }
        }
        else
        {
            if((Charger.Alarm_Code & ALARM_HANDSHAKE_TIMEOUT))
            {
                osDelay(10000);
                Charger.Alarm_Code &= ~ALARM_HANDSHAKE_TIMEOUT;
                DEBUG_INFO("Alarm handshake overtime recover.\r\n");
            }
	}
#endif  //HANDSHAKE_PROTECT

        //================================
        // Rotary Switch Maxium Current Error detect
        //================================
#ifdef  ROTATE_SWITCH_CHECK
        if (Charger.isRotarySwitchError)
        {
            if(!(Charger.Alarm_Code & ALARM_ROTATORY_SWITCH_FAULT))
            {
              Charger.Alarm_Code |= ALARM_ROTATORY_SWITCH_FAULT;
              if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                blinkerTimeSet(BLINKER_IDX_LED, 200, 200, 0, 1);
              }
              DEBUG_INFO("Rotary Switch Maxium Current Error occur.\r\n");
            }
        }
#endif  //ROTATE_SWITCH_CHECK

        //================================
        // Recover alarm info in state A
        //================================
        if(Charger.CP_State == SYSTEM_STATE_A)
        {
            //SCP Recover
            if(Charger.Alarm_Code & ALARM_CIRCUIT_SHORT)
            {
               Charger.Alarm_Code &= ~ALARM_CIRCUIT_SHORT;
               DEBUG_INFO("Alarm SCP recover.\r\n");
            }
            //OCP Recover
            if(Charger.Alarm_Code & ALARM_OVER_CURRENT)
            {
               Charger.Alarm_Code &= ~ALARM_OVER_CURRENT;
               DEBUG_INFO("Alarm OC recover.\r\n");
            }
            Charger.counter.OC.fail = 0 ;
            timerDisable(TIMER_IDX_RETRY_OC);
            Charger.counter.OC.retry = 0 ;                     // clear retry times
            Charger.counter.OC.isLatch = OFF ;

            //CCID Recover
            if (Charger.CCID_Module_Type == CCID_MODULE_VAC)
            {
              if ((HAL_GPIO_ReadPin(IN_Leak_AC_GPIO_Port, IN_Leak_AC_Pin) == GPIO_PIN_RESET) && (Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC))
              {
                  Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_AC;
                  DEBUG_INFO("Alarm leakage AC recover for VAC.\r\n");
              }
              if ((HAL_GPIO_ReadPin(IN_Leak_DC_GPIO_Port, IN_Leak_DC_Pin) == GPIO_PIN_RESET) && (Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC))
              {
                  Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_DC;
                  DEBUG_INFO("Alarm leakage DC recover for VAC.\r\n");
              }
            }
            else //Charger.CCID_Module_Type is CCID_MODULE_CORMEX
            {
#ifdef MODIFY_CCID_MODULE_CORMEX_RECOVER_AC_DC
                if (Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)
                {
                    Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_AC;
                    DEBUG_INFO("Alarm leakage AC recover.\r\n");
                }
                if (Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC)
                {
                    Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_DC;
                    DEBUG_INFO("Alarm leakage DC recover.\r\n");
                }
#else //MODIFY_CCID_MODULE_CORMEX_RECOVER_AC_DC
              if((Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)||(Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC))
              {
                  Charger.Alarm_Code &= ~ALARM_CURRENT_LEAK_AC;
                  DEBUG_INFO("Alarm leakage recover.\r\n");
              }
#endif //MODIFY_CCID_MODULE_CORMEX_RECOVER_AC_DC
            }

            Charger.counter.LEAK.fail = 0;
            timerDisable(TIMER_IDX_RETRY_LEAK) ;
            timerDisable(TIMER_IDX_RETRY_LEAK_AC) ;
            timerDisable(TIMER_IDX_RETRY_LEAK_DC) ;
            Charger.counter.LEAK.retry = 0 ;            // clear latch times
            Charger.counter.LEAK_DC.retry = 0 ;         // clear latch times
            Charger.counter.LEAK_AC.retry = 0 ;         // clear latch times
            Charger.counter.LEAK.isLatch = OFF ;

            //LEAK_MODULE selfrest Recover
            if (Charger.CCID_Module_Type == CCID_MODULE_VAC)
            {
                if(Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL & (HAL_GPIO_ReadPin(IN_Leak_Error_GPIO_Port, IN_Leak_Error_Pin) == GPIO_PIN_RESET))   // leak module is VAC
                {
                  if ((Charger.counter.LEAK_MODULE.retry < 2) && (!Charger.counter.LEAK_MODULE.isLatch))
                  {
                      Charger.Alarm_Code &= ~ALARM_LEAK_MODULE_FAIL;
                      DEBUG_INFO("Alarm leakage module recover.\r\n");
                  }
                }
            }
            else //Charger.CCID_Module_Type is CCID_MODULE_CORMEX
            {
                if(Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL)  // leak module is CORMEX
                {
                  if ((Charger.counter.LEAK_MODULE.retry < 2) && (!Charger.counter.LEAK_MODULE.isLatch))
                  {
                      Charger.Alarm_Code &= ~ALARM_LEAK_MODULE_FAIL;
                      DEBUG_INFO("Alarm leakage module recover.\r\n");
                  }
                }
            }


        }
    }
    else if (Charger.Mode == MODE_DEBUG)
    {

         //================================
        // Relay status error detect
        // TODO: ADC channel & spec need to check
        //================================
#ifdef  RELAY_WELDING_PROTECT
        //GROUNGING_SYSTEM_LL
        if (Charger.GroundingSystem == GROUNGING_SYSTEM_LL)
        {
            if((Charger.Relay_Action == GPIO_RELAY_ACTION_ON) && (Charger.Relay_isOperationCompleted == 0x11 ) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                if(adc_value.ADC2_IN5_Welding.value < ((Charger.Voltage[0]*0.0048)+3)) // for UL dloule L syste            a=0.0048 b=0.03V
                {
                    if(Charger.counter.RELAY_Drive_Fualt.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_DRIVE_FUALT))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_DRIVE_FUALT;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay ON status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY_Drive_Fualt.fail++;
                }
                else
                {
                  Charger.counter.RELAY_Drive_Fualt.fail = 0 ;

                }
            }
            else if ((Charger.Relay_Action == GPIO_RELAY_ACTION_OFF) && (Charger.Relay_isOperationCompleted == 0x00) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                //if(adc_value.ADC2_IN5_Welding.value > 24) // 0.24 V
                if(adc_value.ADC2_IN5_Welding.value > ALARM_SPEC_RELAY_LL)
                {
                    if(Charger.counter.RELAY.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_STATUS))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_STATUS;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay OFF status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY.fail++;
                }
                else
                {
                  Charger.counter.RELAY.fail = 0 ;
                }
            }
        }
        else  // GROUNGING_SYSTEM_LN
        {
            if((Charger.Relay_Action == GPIO_RELAY_ACTION_ON) && (Charger.Relay_isOperationCompleted == 0x11) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                if(adc_value.ADC2_IN5_Welding.value < ALARM_SPEC_RELAY_LN_DRIVE_FAULT )         // old spec use
                {
                    if(Charger.counter.RELAY.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_DRIVE_FUALT))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_DRIVE_FUALT;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay ON status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY.fail++;
                }
                else
                {
                  Charger.counter.RELAY.fail = 0 ;
                }
            }
            else if ((Charger.Relay_Action == GPIO_RELAY_ACTION_OFF) && (Charger.Relay_isOperationCompleted == 0x00) && ((adc_value.ADC3_IN4_GMI_VL1.value*100*3.3/4095) < (Charger.Voltage[0]*0.011)) )
            {
                if(adc_value.ADC2_IN5_Welding.value > ALARM_SPEC_RELAY_LN_WELDING)
                {
                    if(Charger.counter.RELAY.fail > 1000)
                    {
                        if(!(Charger.Alarm_Code & ALARM_RELAY_STATUS))
                        {
                            Charger.counter.RELAY.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                            Charger.Alarm_Code |= ALARM_RELAY_STATUS;

                            DEBUG_ERROR("Alarm Welding Voltage = %d.\r\n",adc_value.ADC2_IN5_Welding.value);
                            DEBUG_ERROR("Alarm relay OFF status fault occur.\r\n");
                        }
                    }
                    else
                        Charger.counter.RELAY.fail++;
                }
                else
                {
                  Charger.counter.RELAY.fail = 0 ;
                }
            }
        }

#endif  //RELAY_WELDING_PROTECT
    }

    osDelay(1);
  }
  /* USER CODE END StartAlarmTask */
}

/* USER CODE BEGIN Header_StartBleTask */
/**
* @brief Function implementing the bleTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBleTask */
void StartBleTask(void const * argument)
{
  /* USER CODE BEGIN StartBleTask */
    char tmpBuf[128];
    uint8_t endFlag[4]={0x55,0xaa,0x55,0xaa};
    __IO uint32_t flash;
    uint32_t checksum;
    uint32_t rndNumber;

    //=====================================
    // Module reset
    //=====================================
    HAL_GPIO_WritePin(OUT_BLE_RESET_GPIO_Port, OUT_BLE_RESET_Pin, GPIO_PIN_RESET);
    osDelay(60);
    HAL_GPIO_WritePin(OUT_BLE_RESET_GPIO_Port, OUT_BLE_RESET_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(OUT_BLE_DSR_GPIO_Port, OUT_BLE_DSR_Pin, GPIO_PIN_SET);

    Charger.ble.initSeq = 0;
    Charger.ble.isDataMode = OFF;
    UART_BLE_Init_OK = OFF;

    osDelay(1000);
    /* Infinite loop */
    for(;;)
    {
        //=====================================
        // BLE module initialization process
        //=====================================
		switch(Charger.ble.initSeq)
        {
            case 0x00:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_RESTORE], strlen(BLE_CMD[BLE_CMD_SET_RESTORE]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x01:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_ROLE], strlen(BLE_CMD[BLE_CMD_SET_ROLE]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x02:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_DTR], strlen(BLE_CMD[BLE_CMD_SET_DTR]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x03:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_DSR], strlen(BLE_CMD[BLE_CMD_SET_DSR]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x04:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_PAIRING_MODE], strlen(BLE_CMD[BLE_CMD_SET_PAIRING_MODE]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x05:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_SECURITY_MODE], strlen(BLE_CMD[BLE_CMD_SET_SECURITY_MODE]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x06:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_SECURITY_TYPE], strlen(BLE_CMD[BLE_CMD_SET_SECURITY_TYPE]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x07:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_DISCOVERABILITY], strlen(BLE_CMD[BLE_CMD_SET_DISCOVERABILITY]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x08:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_CONNECTABILITY], strlen(BLE_CMD[BLE_CMD_SET_CONNECTABILITY]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x09:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_GET_ADDR], strlen(BLE_CMD[BLE_CMD_GET_ADDR]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x0a:
                sprintf(tmpBuf, "%s\"BYTON_EVSE_%s\"\r\n", BLE_CMD[BLE_CMD_SET_NAME], Charger.ble.peripheral_mac);
                DEBUG_INFO("BLE module set name:BYTON_EVSE_%s\r\n", Charger.ble.peripheral_mac);
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)tmpBuf, strlen(tmpBuf), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x0b:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_MAX_POWER], strlen(BLE_CMD[BLE_CMD_SET_MAX_POWER]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x0c:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_MIN_INTERVAL], strlen(BLE_CMD[BLE_CMD_SET_MIN_INTERVAL]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x0d:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_MAX_INTERVAL], strlen(BLE_CMD[BLE_CMD_SET_MAX_INTERVAL]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x0e:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_TX_PHY], strlen(BLE_CMD[BLE_CMD_SET_TX_PHY]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x0f:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_RX_PHY], strlen(BLE_CMD[BLE_CMD_SET_RX_PHY]), 0xffff);
                osDelay(BLE_INIT_DELAY);
                break;
            case 0x10:
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)BLE_CMD[BLE_CMD_SET_DATA_MODE], strlen(BLE_CMD[BLE_CMD_SET_DATA_MODE]), 0xffff);
                DEBUG_INFO("BLE module switch to data mode.\r\n");
                osDelay(BLE_INIT_DELAY);
            default:
                UART_BLE_Init_OK = ON;
                break;
        }

        //=====================================
        // BLE central device connect status
        //=====================================
        if((HAL_GPIO_ReadPin(IN_BLE_DTR_GPIO_Port, IN_BLE_DTR_Pin) ==  GPIO_PIN_SET) && (UART_BLE_Init_OK == ON))
        {
            // Device disconnect
            timerRefresh(TIMER_IDX_BLE);
            if(Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT || Charger.ble.loginRole == BLE_LOGIN_ROLE_USER)
            {
                DEBUG_INFO("BLE central device disconnect.\r\n.");
                Charger.ble.loginRole = BLE_LOGIN_ROLE_UNKOWN;
            }
        }
        else  if((HAL_GPIO_ReadPin(IN_BLE_DTR_GPIO_Port, IN_BLE_DTR_Pin) ==  GPIO_PIN_RESET) && (UART_BLE_Init_OK == ON))
        {
            // Device connect in
            if(Charger.ble.loginRole == BLE_LOGIN_ROLE_UNKOWN)
            {
                DEBUG_INFO("BLE central device connect.....wait sign in.\r\n.");
                osDelay(1000);
            }
        }

        //=====================================
        // Communication timeout process
        //=====================================
        if(timer[TIMER_IDX_BLE].isAlarm)
        {
            Charger.ble.loginRole = BLE_LOGIN_ROLE_UNKOWN;
            DEBUG_INFO("BLE no communication over time, disconnect central device.\r\n");
            timerRefresh(TIMER_IDX_BLE);

            HAL_GPIO_WritePin(OUT_BLE_DSR_GPIO_Port, OUT_BLE_DSR_Pin, GPIO_PIN_RESET);
            osDelay(100);
            HAL_GPIO_WritePin(OUT_BLE_DSR_GPIO_Port, OUT_BLE_DSR_Pin, GPIO_PIN_SET);
        }

        //=====================================
        // BLE uart recieve data process
        //=====================================
        if(UART_BLE_recv_end_flag == ON)
        {
            if((HAL_GPIO_ReadPin(IN_BLE_DTR_GPIO_Port, IN_BLE_DTR_Pin) ==  GPIO_PIN_SET) || !Charger.ble.isDataMode)
            {
                // AT command rx process
                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_RESTORE])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_ROLE])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_DTR])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_DSR])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_PAIRING_MODE])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_SECURITY_MODE])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_SECURITY_TYPE])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_DISCOVERABILITY])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_CONNECTABILITY])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_GET_ADDR])!=NULL)
                {
                    memcpy(Charger.ble.peripheral_mac, &UART_BLE_rx_buffer[strcspn((char *)UART_BLE_rx_buffer, ":")+1], 12);
                    Charger.ble.peripheral_mac[12] = '\0';
                    DEBUG_INFO("Peripheral mac address: %s\r\n", Charger.ble.peripheral_mac);
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_NAME])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_MAX_POWER])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_MIN_INTERVAL])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_MAX_INTERVAL])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_TX_PHY])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_RX_PHY])!=NULL)
                {
                    Charger.ble.initSeq++;
                }

                if(strstr((char *)UART_BLE_rx_buffer, BLE_CMD[BLE_CMD_SET_DATA_MODE])!=NULL)
                {
                    Charger.ble.isDataMode = ON;
                    Charger.ble.initSeq++;
                }
            }
            else
            {
                // Application protocol rx process
                uint8_t tx[UART_BUFFER_SIZE];
                uint8_t tx_len;
                uint8_t chksum = 0;
                uint32_t tmp;

                //HTK_ByteArray2HexStr_XP("BLE_RX: ", UART_BLE_rx_buffer, 0, 16);
                if(isValidCheckSum_BLE() && (rndNumber != ((UART_BLE_rx_buffer[3]<<0) | (UART_BLE_rx_buffer[4]<<8) | (UART_BLE_rx_buffer[5]<<16) | (UART_BLE_rx_buffer[6]<<24))))
                {
                    // Timer reset
                    timerRefresh(TIMER_IDX_BLE);
                    rndNumber = ((UART_BLE_rx_buffer[3]<<0) | (UART_BLE_rx_buffer[4]<<8) | (UART_BLE_rx_buffer[5]<<16) | (UART_BLE_rx_buffer[6]<<24));

                    switch(UART_BLE_rx_buffer[2])
                    {
                        case BLE_PROTOCOL_MESSAGE_SIGN_IN:
                            DEBUG_INFO("BLE device sign request...%d\r\n", UART_BLE_rx_buffer[7]);
                            tx_len = 5;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;
                            tx[3] = 0x00;

                            if(Charger.memory.EVSE_Config.data.item.bleConfig.isRegPuk)
                            {
                                if(UART_BLE_rx_buffer[7] == 0x00)
                                {
                                    if(memcmp(&UART_BLE_rx_buffer[8], &Charger.memory.EVSE_Config.data.item.bleConfig.idRoot[0], ((UART_BLE_rx_buffer[0]<<8) | (UART_BLE_rx_buffer[1]<<0)-9)) == 0)
                                    {
                                        // Root sign in
                                        tx[3] = 0x02;
                                        Charger.ble.loginRole = BLE_LOGIN_ROLE_ROOT;
                                        DEBUG_INFO("Sign in as root.\r\n");
                                    }
                                }
                                else
                                {
                                    if(memcmp(&UART_BLE_rx_buffer[8], &Charger.memory.whiteList.data.item[0].pin[0], ((UART_BLE_rx_buffer[0]<<8) | (UART_BLE_rx_buffer[1]<<0)-9)) == 0)
                                    {
                                        // User sign in
                                        tx[3] = 0x03;
                                        Charger.ble.loginRole = BLE_LOGIN_ROLE_USER;
                                        DEBUG_INFO("Sign in as user.\r\n");
                                    }
                                }
                            }
                            else
                            {
                                if(UART_BLE_rx_buffer[7] == 0x00)
                                {
                                    // Visitor
                                    tx[3] = 0x01;
                                    Charger.ble.loginRole = BLE_LOGIN_ROLE_VISITOR;
                                    memcpy(&Charger.ble.loginId[0], &UART_BLE_rx_buffer[8], ((UART_BLE_rx_buffer[0]<<8) | (UART_BLE_rx_buffer[1]<<0)-9) );
                                    DEBUG_WARN("Sign in as visitor.\r\n");
                                }
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_PUK_REG:
                            DEBUG_INFO("BLE device PUK registe.%02x%02x%02x%02x%02x%02x%02x%02x\r\n", UART_BLE_rx_buffer[7], UART_BLE_rx_buffer[8], UART_BLE_rx_buffer[9], UART_BLE_rx_buffer[10], UART_BLE_rx_buffer[11], UART_BLE_rx_buffer[12], UART_BLE_rx_buffer[13], UART_BLE_rx_buffer[14]);
                            tx_len = 11;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;
                            tx[3] = 0x00;

                            if(Charger.memory.EVSE_Config.data.item.bleConfig.isRegPuk)
                            {
                                 if(memcmp(&Charger.ble.loginId[0], &Charger.memory.EVSE_Config.data.item.bleConfig.idRoot[0], ARRAY_SIZE(Charger.ble.loginId)))
                                 {
                                    tx[3] = 0x02;
                                    DEBUG_INFO("ID registered exist.\r\n");
                                 }
                            }
                            else
                            {
                                if(Charger.ble.loginRole == BLE_LOGIN_ROLE_VISITOR)
                                {
                                    if(memcmp(&UART_BLE_rx_buffer[7], &Charger.memory.EVSE_Config.data.item.bleConfig.puk[0], 8) == 0x00)
                                    {
                                        tx[3] = 0x01;

                                        // PIN list generation
                                        Charger.memory.EVSE_Config.data.item.bleConfig.isGenPin = ON;
                                        for(uint8_t idx=0;idx<20;idx++)
                                        {
                                            Charger.memory.whiteList.data.item[idx].listType = WHITE_LIST_TYPE_BLE;
                                            Charger.memory.whiteList.data.item[idx].pin[0] = (rand()%0x2b)+0x30;
                                            Charger.memory.whiteList.data.item[idx].pin[1] = (rand()%0x2b)+0x30;
                                            Charger.memory.whiteList.data.item[idx].pin[2] = (rand()%0x2b)+0x30;
                                            Charger.memory.whiteList.data.item[idx].pin[3] = (rand()%0x2b)+0x30;
                                            Charger.memory.whiteList.data.item[idx].pin[4] = (rand()%0x2b)+0x30;
                                            Charger.memory.whiteList.data.item[idx].pin[5] = (rand()%0x2b)+0x30;
                                            Charger.memory.whiteList.data.item[idx].isReg = OFF;
                                        }
                                        Charger.memory.whiteList.op_bits.update = ON;

                                        Charger.memory.EVSE_Config.data.item.bleConfig.isRegPuk = ON;
                                        memcpy(&Charger.memory.EVSE_Config.data.item.bleConfig.idRoot[0], &Charger.ble.loginId[0], ARRAY_SIZE(Charger.ble.loginId));
                                        Charger.memory.EVSE_Config.op_bits.update = ON;

                                        DEBUG_INFO("Root registered and PIN list generate success.\r\n");
                                    }
                                }
                            }

                            memcpy(&tx[4], &UART_BLE_rx_buffer[7], 6);
                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[10] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_PIN_GET:
                            DEBUG_INFO("PIN get request.\r\n");
                            tx_len = 11;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;;
                            tx[3] = 0x00;

                            if(Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT)
                            {
                                tx[3] = 0x01;
                                memcpy(&tx[4], &Charger.memory.whiteList.data.item[0].pin[0], 6);
                                DEBUG_INFO("PIN: %s\r\n", Charger.memory.whiteList.data.item[0].pin);
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[10] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_PIN_RENEW:
                            DEBUG_INFO("BLE device PIN renew request.\r\n");
                            tx_len = 13;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;;
                            tx[3] = 0x00;

                            if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT))
                            {
                                for(uint8_t idx=0;idx<20;idx++)
                                {
                                    Charger.memory.whiteList.data.item[idx].listType = WHITE_LIST_TYPE_BLE;
                                    Charger.memory.whiteList.data.item[idx].pin[0] = (rand()%0x2b)+0x30;
                                    Charger.memory.whiteList.data.item[idx].pin[1] = (rand()%0x2b)+0x30;
                                    Charger.memory.whiteList.data.item[idx].pin[2] = (rand()%0x2b)+0x30;
                                    Charger.memory.whiteList.data.item[idx].pin[3] = (rand()%0x2b)+0x30;
                                    Charger.memory.whiteList.data.item[idx].pin[4] = (rand()%0x2b)+0x30;
                                    Charger.memory.whiteList.data.item[idx].pin[5] = (rand()%0x2b)+0x30;
                                    Charger.memory.whiteList.data.item[idx].isReg = OFF;
                                }
                                Charger.memory.whiteList.op_bits.update = ON;
                                tx[3] = 0x01;
                                memcpy(&tx[4], &Charger.memory.whiteList.data.item[0].pin[0], 6);

                                DEBUG_INFO("PIN list renew: %s.\r\n", Charger.memory.whiteList.data.item[0].pin);
                            }
                            else
                                DEBUG_WARN("Login id not root.\r\n");

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_CHARGING_START:
                            DEBUG_INFO("BLE device request charging start.\r\n");
                            tx_len = 0x08;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            if(Charger.Alarm_Code>0)
                            {
                                tx[3] = 0x02;
                                if((Charger.Alarm_Code & ALARM_OVER_VOLTAGE))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x00;
                                }
                                else if((Charger.Alarm_Code & ALARM_UNDER_VOLTAGE))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x03;
                                }
                                else if((Charger.Alarm_Code & ALARM_OVER_CURRENT))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x21;
                                    tx[6] = 0x16;
                                }
                                else if((Charger.Alarm_Code & ALARM_OVER_TEMPERATURE))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x23;
                                }
                                else if((Charger.Alarm_Code & ALARM_GROUND_FAIL))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x56;
                                }
                                else if((Charger.Alarm_Code & ALARM_CP_ERROR))
                                {
                                    tx[4] = 0x02;
                                    tx[5] = 0x37;
                                    tx[6] = 0x03;
                                }
                                else if((Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)||(Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x33;
                                }
                                else if((Charger.Alarm_Code & ALARM_MCU_TESTFAIL))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x57;
                                }
                                else if((Charger.Alarm_Code & ALARM_EMERGENCY_STOP))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x51;
                                }
                                else if((Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x10;
                                    tx[6] = 0x04;
                                }
                                else if((Charger.Alarm_Code & ALARM_RELAY_STATUS))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x58;
                                }
                                DEBUG_WARN("EVSE in alarm state, can not start charging.\r\n");
                            }
                            else
                            {
                                if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                                {
                                    if(Charger.Mode == MODE_IDLE)
                                    {
                                        Charger.ble.isRequestOn = ON;
                                        tx[3] = 0x01;
                                        DEBUG_INFO("Start OK.\r\n");
                                    }
                                    else
                                    {
                                        tx[3] = 0x00;
                                        DEBUG_WARN("EVSE not in IDLE.\r\n");
                                    }
                                }
                                else
                                {
                                    tx[3] = 0x00;
                                    DEBUG_WARN("Login first\r\n");
                                }

                                tx[4] = 0x00;
                                tx[5] = 0x00;
                                tx[6] = 0x00;
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[7] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_CHARGING_STOP:
                            DEBUG_INFO("BLE device request charging stop.\r\n");
                            tx_len = 0x08;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            if(Charger.Alarm_Code>0)
                            {
                                tx[3] = 0x02;
                                if((Charger.Alarm_Code & ALARM_OVER_VOLTAGE))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x00;
                                }
                                else if((Charger.Alarm_Code & ALARM_UNDER_VOLTAGE))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x03;
                                }
                                else if((Charger.Alarm_Code & ALARM_OVER_CURRENT))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x21;
                                    tx[6] = 0x16;
                                }
                                else if((Charger.Alarm_Code & ALARM_OVER_TEMPERATURE))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x23;
                                }
                                else if((Charger.Alarm_Code & ALARM_GROUND_FAIL))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x56;
                                }
                                else if((Charger.Alarm_Code & ALARM_CP_ERROR))
                                {
                                    tx[4] = 0x02;
                                    tx[5] = 0x37;
                                    tx[6] = 0x03;
                                }
                                else if((Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)||(Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x33;
                                }
                                else if((Charger.Alarm_Code & ALARM_MCU_TESTFAIL))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x57;
                                }
                                else if((Charger.Alarm_Code & ALARM_EMERGENCY_STOP))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x51;
                                }
                                else if((Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x10;
                                    tx[6] = 0x04;
                                }
                                else if((Charger.Alarm_Code & ALARM_RELAY_STATUS))
                                {
                                    tx[4] = 0x01;
                                    tx[5] = 0x22;
                                    tx[6] = 0x58;
                                }
                                DEBUG_WARN("EVSE in alarm state, can not stop charging.\r\n");
                            }
                            else
                            {
                                if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                                {
                                    if((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))
                                    {
                                        Charger.ble.isRequestOff = ON;
                                        tx[3] = 0x01;
                                        DEBUG_INFO("Stop OK.\r\n");
                                    }
                                    else
                                    {
                                        tx[3] = 0x00;
                                        DEBUG_WARN("EVSE not in CHARGING.\r\n");
                                    }
                                }
                                else
                                {
                                    tx[3] = 0x00;
                                    DEBUG_WARN("Login first\r\n");
                                }

                                tx[4] = 0x00;
                                tx[5] = 0x00;
                                tx[6] = 0x00;
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[7] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_STATUS_QUERY:
                            DEBUG_INFO("BLE device query EVSE status request.\r\n");
                            tx_len = 0x13;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            tx[3] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?Charger.Mode:0x00);
                            tx[4] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/10000)>>0) & 0xff):0x00);
                            tx[5] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/10000)>>8) & 0xff):0x00);
                            tx[6] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/10000)>>16) & 0xff):0x00);
                            tx[7] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative/10000)>>24) & 0xff):0x00);
                            tx[8] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.cycle_info.Power_Consumption/10)>>0) & 0xff):0x00);
                            tx[9] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.cycle_info.Power_Consumption/10)>>8) & 0xff):0x00);
                            tx[10] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.cycle_info.Duration/60000)>>0) & 0xff):0x00);
                            tx[11] = (((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))?(((Charger.cycle_info.Duration/60000)>>8) & 0xff):0x00);
                            if((Charger.Alarm_Code>0) && ((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER)))
                            {
                                if((Charger.Alarm_Code & ALARM_OVER_VOLTAGE))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x00;
                                }
                                else if((Charger.Alarm_Code & ALARM_UNDER_VOLTAGE))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x03;
                                }
                                else if((Charger.Alarm_Code & ALARM_OVER_CURRENT))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x21;
                                    tx[14] = 0x16;
                                }
                                else if((Charger.Alarm_Code & ALARM_OVER_TEMPERATURE))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x23;
                                }
                                else if((Charger.Alarm_Code & ALARM_GROUND_FAIL))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x56;
                                }
                                else if((Charger.Alarm_Code & ALARM_CP_ERROR))
                                {
                                    tx[12] = 0x02;
                                    tx[13] = 0x37;
                                    tx[14] = 0x03;
                                }
                                else if((Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC)||(Charger.Alarm_Code & ALARM_CURRENT_LEAK_DC))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x33;
                                }
                                else if((Charger.Alarm_Code & ALARM_MCU_TESTFAIL))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x57;
                                }
                                else if((Charger.Alarm_Code & ALARM_EMERGENCY_STOP))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x51;
                                }
                                else if((Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x10;
                                    tx[14] = 0x04;
                                }
                                else if((Charger.Alarm_Code & ALARM_RELAY_STATUS))
                                {
                                    tx[12] = 0x01;
                                    tx[13] = 0x22;
                                    tx[14] = 0x58;
                                }
                            }
                            else
                            {
                                tx[12] = 0x00;
                                tx[13] = 0x00;
                                tx[14] = 0x00;
                            }

                            tx[15] = Charger.memory.EVSE_Config.data.item.reservation.mode;
                            tx[16] = Charger.memory.EVSE_Config.data.item.reservation.hour;
                            tx[17] = Charger.memory.EVSE_Config.data.item.reservation.min;

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[18] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_RESERVATION:
                            switch(UART_BLE_rx_buffer[7])
                            {
                                case RESERVATION_DISABLE:
                                    DEBUG_INFO("BLE device reservation request disable.\r\n");
                                    break;
                                case RESERVATION_ONCE:
                                    DEBUG_INFO("BLE device reservation request once on %d:%d.\r\n", UART_BLE_rx_buffer[8], UART_BLE_rx_buffer[9]);
                                    break;
                                case RESERVATION_ALWAYS:
                                    DEBUG_INFO("BLE device reservation request always on %d:%d.\r\n", UART_BLE_rx_buffer[8], UART_BLE_rx_buffer[9]);
                                    break;
                            }

                            tx_len = 0x05;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            Charger.memory.EVSE_Config.data.item.reservation.mode = UART_BLE_rx_buffer[7];
                            Charger.memory.EVSE_Config.data.item.reservation.hour = UART_BLE_rx_buffer[8];
                            Charger.memory.EVSE_Config.data.item.reservation.min = UART_BLE_rx_buffer[9];
                            Charger.memory.EVSE_Config.op_bits.update = ON;
                            tx[3] = 0x01;

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_TIME_QUERY:
                            DEBUG_INFO("BLE device query date time request.\r\n");
                            tx_len = 0x08;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            struct tm gm_date;
                            gm_date.tm_year = Charger.memory.EVSE_Config.data.item.SystemDateTime.year-1900;
                            gm_date.tm_mon = Charger.memory.EVSE_Config.data.item.SystemDateTime.month-1;
                            gm_date.tm_mday = Charger.memory.EVSE_Config.data.item.SystemDateTime.day;
                            gm_date.tm_hour = Charger.memory.EVSE_Config.data.item.SystemDateTime.hour;
                            gm_date.tm_min = Charger.memory.EVSE_Config.data.item.SystemDateTime.min;
                            gm_date.tm_sec = Charger.memory.EVSE_Config.data.item.SystemDateTime.sec;
                            tmp = mktime(&gm_date);
                            tx[3] = ((tmp >> 0)&0xff);
                            tx[4] = ((tmp >> 8)&0xff);
                            tx[5] = ((tmp >> 16)&0xff);
                            tx[6] = ((tmp >> 24)&0xff);

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[7] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_TIME_CONFIG:
                            DEBUG_INFO("BLE device config date time.\r\n");
                            tx_len = 0x09;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                            {
                                struct tm *sm_date;
                                tmp = (UART_BLE_rx_buffer[7]<<0) | (UART_BLE_rx_buffer[8]<<8) | (UART_BLE_rx_buffer[9]<<16) | (UART_BLE_rx_buffer[10]<<24);
                                sm_date = gmtime(&tmp) ;

                                setTime.Hours = sm_date->tm_hour;
                                setTime.Minutes = sm_date->tm_min;
                                setTime.Seconds = sm_date->tm_sec;
                                setTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
                                setTime.StoreOperation = RTC_STOREOPERATION_RESET;
                                if (HAL_RTC_SetTime(&hrtc, &setTime, RTC_FORMAT_BIN) != HAL_OK)
                                {
                                    Error_Handler();
                                }

                                setDate.Year = (sm_date->tm_year + 1900)-2000;
                                setDate.Month = sm_date->tm_mon + 1;
                                setDate.Date = sm_date->tm_mday;
                                if (HAL_RTC_SetDate(&hrtc, &setDate, RTC_FORMAT_BIN) != HAL_OK)
                                {
                                    Error_Handler();
                                }

                                tx[3] = 0x01;
                                DEBUG_INFO("RTC config OK.\r\n");
                            }
                            else
                            {
                                tx[3] = 0x00;
                                DEBUG_WARN("User con not config RTC.\r\n");
                            }

                            tx[4] = UART_BLE_rx_buffer[7];
                            tx[5] = UART_BLE_rx_buffer[8];
                            tx[6] = UART_BLE_rx_buffer[9];
                            tx[7] = UART_BLE_rx_buffer[10];

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[8] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_LED_QUERY:
                            DEBUG_INFO("BLE device query led setting.\r\n");
                            tx_len = 0x08;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;
                            /*
                                TODO: Query led result here
                            */
                            if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                            {
                                tx[3] = 0xff;
                                tx[4] = 0xff;
                                tx[5] = 0xff;
                                tx[6] = 0xff;
                            }
                            else
                            {
                                tx[3] = 0x00;
                                tx[4] = 0x00;
                                tx[5] = 0x00;
                                tx[6] = 0x00;
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[7] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_LED_CONFIG:
                            DEBUG_INFO("BLE device config led setting.\r\n");
                            tx_len = 0x09;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;
                            /*
                                TODO: Config led result here
                            */
                            if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                                tx[3] = 0x01;
                            else
                                tx[3] = 0x00;

                            tx[4] = UART_BLE_rx_buffer[7];
                            tx[5] = UART_BLE_rx_buffer[8];
                            tx[6] = UART_BLE_rx_buffer[9];
                            tx[7] = UART_BLE_rx_buffer[10];

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[8] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_CURRENT_LIMIT_QUERY:
                            DEBUG_INFO("BLE device query current limit request.\r\n");
                            tx_len = 0x05;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                            {
                                tx[3] = Charger.memory.EVSE_Config.data.item.MaxChargingCurrent;
                                DEBUG_INFO("Query current limit: %02dA.\r\n", Charger.memory.EVSE_Config.data.item.MaxChargingCurrent);
                            }
                            else
                            {
                                tx[3] = 0x00;
                                DEBUG_WARN("Please login first, before query current limit.\r\n");
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[8] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_CURRENT_LIMIT_CONFIG:
                            DEBUG_INFO("BLE device config current limit.\r\n");
                            tx_len = 0x06;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                            {
                                if(UART_BLE_rx_buffer[7]>Charger.maxRatingCurrent)
                                {
                                    tx[3] = 0x02;
                                    Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;
                                    DEBUG_INFO("Setting value over max rating value, set as max rating .\r\n");
                                }
                                else
                                {
                                    tx[3] = 0x01;
                                    Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = UART_BLE_rx_buffer[7];
                                }
                                DEBUG_INFO("Config current limit: %02dA\r\n", Charger.memory.EVSE_Config.data.item.MaxChargingCurrent);
                            }
                            else
                            {
                                tx[3] = 0x00;
                                DEBUG_WARN("Please login first, before setting current limit.\r\n");
                            }

                            tx[4] = UART_BLE_rx_buffer[7];

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[5] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_FIRMWARE_VERSION_QUERY:
                            DEBUG_INFO("BLE device query firmware version.\r\n");
                            tx_len = 4 + strlen(Charger.Ver_FW);
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            for(uint16_t idx=0;idx<strlen(Charger.Ver_FW);idx++)
                            {
                                if((Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT) || (Charger.ble.loginRole == BLE_LOGIN_ROLE_USER))
                                    tx[3+idx] = Charger.Ver_FW[idx];
                                else
                                    tx[3+idx] = 0x00;
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[3+strlen(Charger.Ver_FW)] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_FIRMWARE_UPDATE_REQ:
                            tx_len = 5;
                            tx[0] = 0x00;
                            tx[1] = 0x05;
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;;

                            if(Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT)
                            {
                                binCRCTarget = (UART_BLE_rx_buffer[7] << 24) | (UART_BLE_rx_buffer[8] << 16) | (UART_BLE_rx_buffer[9] << 8) | (UART_BLE_rx_buffer[10] << 0);
                                flashdestination = NEW_CODE_ADDRESS;
                                if(FLASH_If_Erase(NEW_CODE_ADDRESS, 3)== FLASHIF_OK)
                                {
                                  DEBUG_INFO("Firmware transfer start, earase flash success....\n\r");
                                  tx[3] = 0x01;
                                }
                                else
                                {
                                  DEBUG_INFO("Firmware transfer start, earase flash fail....\n\r");
                                  tx[3] = 0x00;
                                }
                            }
                            else
                            {
                                tx[3] = 0x00;
                                DEBUG_WARN("User can not upgrade start.\r\n");
                            }


                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;
                            break;
                        case BLE_PROTOCOL_MESSAGE_FIRMWARE_TRANS_REQ:
                            tx_len = 5;
                            tx[0] = 0x00;
                            tx[1] = 0x05;
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;

                            if(Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT)
                            {
                                flashdestination = NEW_CODE_ADDRESS + ((UART_BLE_rx_buffer[7]<<24) | (UART_BLE_rx_buffer[8]<<16) | (UART_BLE_rx_buffer[9]<<8) |(UART_BLE_rx_buffer[10]<<0));
                                if (FLASH_If_Write(flashdestination, (uint32_t*) &UART_BLE_rx_buffer[11],  ((((UART_BLE_rx_buffer[1]) | (UART_BLE_rx_buffer[0])<<8)-12)>>2)) == FLASHIF_OK)
                                {
                                  DEBUG_INFO("Firmware transfer start address: 0x%x ,length: %d...Pass\n\r", flashdestination, (((UART_BLE_rx_buffer[1]) | (UART_BLE_rx_buffer[0])<<8)-12));
                                  tx[3] = 0x01;
                                }
                                else
                                {
                                  DEBUG_INFO("Firmware transfer start address: 0x%x, length: %d...Fail\n\r", flashdestination, (((UART_BLE_rx_buffer[1]) | (UART_BLE_rx_buffer[0])<<8)-12));
                                  tx[3] = 0x00;
                                }
                            }
                            else
                            {
                                tx[3] = 0x00;
                                DEBUG_WARN("User can not upgrade transfer.\r\n");
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;
                          break;
                        case BLE_PROTOCOL_MESSAGE_FIRMWARE_END_REQ:
                            tx_len = 5;
                            tx[0] = 0x00;
                            tx[1] = 0x05;
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;;

                            if(Charger.ble.loginRole == BLE_LOGIN_ROLE_ROOT)
                            {
                                flash = NEW_CODE_ADDRESS;
                                checksum = HAL_CRC_Calculate(&hcrc, (uint32_t *)flash, ((FLASH_AP_LENGTH-4)>>2));
                                flash = ((uint32_t)(NEW_CODE_ADDRESS+FLASH_AP_LENGTH-4));
                                DEBUG_INFO("Firmware transfer end, AP CRC checksum, flash: 0x%x, 0x%x\r\n", checksum, *((uint32_t *)flash) );
                                if(checksum == *((uint32_t *)flash))
                                {
                                    if (FLASH_If_Write(UPGRADE_REQ_ADDRESS,  (uint32_t *)&endFlag[0], 1) == FLASHIF_OK)
                                    {
                                        DEBUG_INFO("Firmware Confirm Tag write ok..\n\r");
                                        tx[3] = 0x01;
                                        tx[4] = 0xB5;

                                        HAL_UART_Transmit(&IAP_USART, (uint8_t *)tx, sizeof(tx), 0xffff);
                                        osDelay(1000);
                                        NVIC_SystemReset();
                                    }
                                    else
                                    {
                                        DEBUG_INFO("Firmware Confirm Tag write fail...\n\r");
                                        tx[3] = 0x00;
                                    }
                                }
                                else
                                {
                                    DEBUG_INFO("Firmware checksum compare fail...\n\r");
                                    tx[3] = 0x00;
                                }
                            }
                            else
                            {
                                tx[3] = 0x00;
                                DEBUG_WARN("User can not upgrade stop.\r\n");
                            }

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;
                          break;
                        default:
                            /*
                                TODO: Unknow command response here
                            */
                            tx_len = 5;
                            tx[0] = 0x00;
                            tx[1] = 0x05;
                            tx[2] = UART_BLE_rx_buffer[2] + 0x80;
                            tx[3] = 0x00;

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }

                            tx[4] = chksum;

                            DEBUG_ERROR("BLE unknow command.\r\n");
                            break;
                    }
                }
                else
                {
                    /*
                        TODO: Protocol check sum error response here
                    */
                    tx_len = 5;
                    tx[0] = 0x00;
                    tx[1] = 0x05;
                    tx[2] = UART_BLE_rx_buffer[2] + 0x80;
                    tx[3] = 0x00;

                    for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                    {
                        chksum ^= tx[2 + idx];
                    }

                    tx[4] = chksum;

                    DEBUG_ERROR("BLE check sum validation error.\r\n");
                }
                HAL_UART_Transmit(&BLE_USART, (uint8_t *)tx, tx_len, 0xffff);
            }

            UART_BLE_rx_len=0;
            UART_BLE_recv_end_flag = OFF;
        }
        HAL_UART_Receive_DMA(&BLE_USART, (uint8_t*)UART_BLE_rx_buffer, UART_BUFFER_SIZE);

        osDelay(1);
  }
  /* USER CODE END StartBleTask */
}

#ifdef MODIFY_FLASH_OPERATION_20241104
void Proc_EVSE_Config(void)
{
#ifdef MODIFY_UNDEFINED_MODEL_NAME_AND_SN_ISSUE
            if (Charger.memory.EVSE_Config.data.item.ModelName[0] == 0xFF ||
                Charger.memory.EVSE_Config.data.item.SerialNumber[0] == 0xFF)
            {
                Charger.memory.EVSE_Config.data.item.ModelName[MODEL_NAME_LEN - 1] = '\0';
                Charger.memory.EVSE_Config.data.item.SerialNumber[SERIAL_NUM_LEN - 1] = '\0';
                Charger.memory.EVSE_Config.op_bits.update = ON;
            }
#endif //MODIFY_UNDEFINED_MODEL_NAME_AND_SN_ISSUE

            Charger.memory.EVSE_Config.data.item.isDispDebug  = ON;
            sprintf(Charger.memory.EVSE_Config.data.item.System_ID, "%s%s", Charger.memory.EVSE_Config.data.item.ModelName, Charger.memory.EVSE_Config.data.item.SerialNumber);
            //sprintf((char *)tmpBuf, "%08x", ~HAL_CRC_Calculate(&hcrc, (uint32_t *)&Charger.memory.EVSE_Config.data.item.System_ID[0], (ARRAY_SIZE(Charger.memory.EVSE_Config.data.item.System_ID)>>2)));
            //memcpy(&Charger.memory.EVSE_Config.data.item.bleConfig.puk[0], &tmpBuf[0], ARRAY_SIZE(Charger.memory.EVSE_Config.data.item.bleConfig.puk));
            //DEBUG_INFO("BLE PUK: %s\r\n", Charger.memory.EVSE_Config.data.item.bleConfig.puk);
            srand(Charger.memory.EVSE_Config.data.item.bleConfig.puk[0] | (Charger.memory.EVSE_Config.data.item.bleConfig.puk[1]<<8));

            setTime.Hours = Charger.memory.EVSE_Config.data.item.SystemDateTime.hour;
            setTime.Minutes = Charger.memory.EVSE_Config.data.item.SystemDateTime.min;
            setTime.Seconds = Charger.memory.EVSE_Config.data.item.SystemDateTime.sec;
            setTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
            setTime.StoreOperation = RTC_STOREOPERATION_RESET;
            if (HAL_RTC_SetTime(&hrtc, &setTime, RTC_FORMAT_BIN) != HAL_OK)
            {
                Error_Handler();
            }

            setDate.Year = Charger.memory.EVSE_Config.data.item.SystemDateTime.year-2000;
            setDate.Month = Charger.memory.EVSE_Config.data.item.SystemDateTime.month;
            setDate.Date = Charger.memory.EVSE_Config.data.item.SystemDateTime.day;
            if (HAL_RTC_SetDate(&hrtc, &setDate, RTC_FORMAT_BIN) != HAL_OK)
            {
                Error_Handler();
            }

            //CCLC_Corr_Gain_Par
            //VT
#ifdef MODIFY_CORRECTION_CHECK
            if  (
                    (Charger.memory.EVSE_Config.data.item.Correction_VL1[1][MCU_DATA] > Charger.memory.EVSE_Config.data.item.Correction_VL1[2][MCU_DATA]) &&
                    (Charger.memory.EVSE_Config.data.item.Correction_VL1[1][METER_DATA] > Charger.memory.EVSE_Config.data.item.Correction_VL1[2][METER_DATA])
                )
#else
            if(Charger.memory.EVSE_Config.data.item.Correction_VL1[1][MCU_DATA] > Charger.memory.EVSE_Config.data.item.Correction_VL1[2][MCU_DATA])
#endif
            {
                CLC_Corr_Gain_Par( Charger.memory.EVSE_Config.data.item.Correction_VL1[1][METER_DATA],Charger.memory.EVSE_Config.data.item.Correction_VL1[2][METER_DATA] ,
                                    Charger.memory.EVSE_Config.data.item.Correction_VL1[1][MCU_DATA],Charger.memory.EVSE_Config.data.item.Correction_VL1[2][MCU_DATA] ,
                                    &Charger.coefficient.gain_v[0], &Charger.coefficient.offset_v[0]);
            }
            else
            {
                Charger.coefficient.gain_v[0] = 1;
                Charger.coefficient.offset_v[0] = 0;
            }

            //CT
#ifdef MODIFY_CORRECTION_CHECK
            if  (
                    (Charger.memory.EVSE_Config.data.item.Correction_CL1[1][MCU_DATA] > Charger.memory.EVSE_Config.data.item.Correction_CL1[2][MCU_DATA]) &&
                    (Charger.memory.EVSE_Config.data.item.Correction_CL1[1][METER_DATA] > Charger.memory.EVSE_Config.data.item.Correction_CL1[2][METER_DATA])
                )
#else
            if(Charger.memory.EVSE_Config.data.item.Correction_CL1[1][MCU_DATA] > Charger.memory.EVSE_Config.data.item.Correction_CL1[2][MCU_DATA])
#endif
            {
                CLC_Corr_Gain_Par(Charger.memory.EVSE_Config.data.item.Correction_CL1[1][METER_DATA],Charger.memory.EVSE_Config.data.item.Correction_CL1[2][METER_DATA] ,
                                   Charger.memory.EVSE_Config.data.item.Correction_CL1[1][MCU_DATA],Charger.memory.EVSE_Config.data.item.Correction_CL1[2][MCU_DATA] ,
                                   &Charger.coefficient.gain_c[0], &Charger.coefficient.offset_c[0]);
            }
            else
            {
                Charger.coefficient.gain_c[0] = 1;
                Charger.coefficient.offset_c[0] = 0;
            }

            //LEAK
            if(Charger.memory.EVSE_Config.data.item.Correction_Leak[1][MCU_DATA] > Charger.memory.EVSE_Config.data.item.Correction_Leak[2][MCU_DATA])
            {
                CLC_Corr_Gain_Par(Charger.memory.EVSE_Config.data.item.Correction_Leak[1][METER_DATA],Charger.memory.EVSE_Config.data.item.Correction_Leak[2][METER_DATA] ,
                                   Charger.memory.EVSE_Config.data.item.Correction_Leak[1][MCU_DATA],Charger.memory.EVSE_Config.data.item.Correction_Leak[2][MCU_DATA] ,
                                   &Charger.coefficient.gain_leak[0], &Charger.coefficient.offset_leak[0]);
            }
            else
            {
                Charger.coefficient.gain_leak[0] = 1;
                Charger.coefficient.offset_leak[0] = 0;
            }

            DEBUG_INFO("Charger.coefficient.gain_leak[0] = %f\r\n",Charger.coefficient.gain_leak[0]);
            DEBUG_INFO("Charger.coefficient.offset_leak[0] = %f\r\n",Charger.coefficient.offset_leak[0]);

            //GMI
            if(Charger.memory.EVSE_Config.data.item.Correction_GMI[1][MCU_DATA] > Charger.memory.EVSE_Config.data.item.Correction_GMI[2][MCU_DATA])
            {
                CLC_Corr_Gain_Par2(Charger.memory.EVSE_Config.data.item.Correction_GMI[1][METER_DATA],Charger.memory.EVSE_Config.data.item.Correction_GMI[2][METER_DATA] ,
                                   Charger.memory.EVSE_Config.data.item.Correction_GMI[1][MCU_DATA],Charger.memory.EVSE_Config.data.item.Correction_GMI[2][MCU_DATA] ,
                                   &Charger.coefficient.gain_gmi[0], &Charger.coefficient.offset_gmi[0], &Charger.coefficient.offsetisPosOrNeg_gmi[0]);
            }
            else
            {
                Charger.coefficient.gain_gmi[0] = 1;
                Charger.coefficient.offset_gmi[0] = 0;
            }

            //DEBUG_INFO("Charger.coefficient.gain_gmi[0] = %f\r\n",Charger.coefficient.gain_gmi[0]);
            //DEBUG_INFO("Charger.coefficient.offset_gmi[0] = %f\r\n",Charger.coefficient.offset_gmi[0]);

#ifdef FUNC_SHOW_CORRECTION_DATA
            {
                XP("[CORRECT DATA]======================\r\n");
                XP("<Correction_VL1>\r\n");
                for (int i = 0; i < 4; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_VL1[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_VL1[i][1]);
                }
                XP("<Correction_VL2>\r\n");
                for (int i = 0; i < 2; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_VL2[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_VL2[i][1]);
                }
                XP("<Correction_VL3>\r\n");
                for (int i = 0; i < 2; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_VL3[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_VL3[i][1]);
                }
                XP("<Correction_CL1>\r\n");
                for (int i = 0; i < 4; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_CL1[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_CL1[i][1]);
                }
                XP("<Correction_CL2>\r\n");
                for (int i = 0; i < 2; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_CL2[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_CL2[i][1]);
                }
                XP("<Correction_CL3>\r\n");
                for (int i = 0; i < 2; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_CL3[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_CL3[i][1]);
                }
                XP("<Correction_Leak>\r\n");
                for (int i = 0; i < 4; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_Leak[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_Leak[i][1]);
                }
                XP("<Correction_GMI>\r\n");
                for (int i = 0; i < 4; i++)
                {
                    XP("[%d][0] = 0x%04X, [%d][1] = 0x%04X\r\n",
                       i, Charger.memory.EVSE_Config.data.item.Correction_GMI[i][0],
                       i, Charger.memory.EVSE_Config.data.item.Correction_GMI[i][1]);
                }
                XP("====================================\r\n");
            }
#endif //FUNC_SHOW_CORRECTION_DATA

            //DEBUG_INFO("Read MEM_ADDR_EVSE_CONFIG block(4k byte) pass.\r\n");

            // Check MCU control mode depend on GPIO state ~again~ , Prevent W25Qx from being empty(0xFF)
            if(HAL_GPIO_ReadPin(IN_ACT_REQ_GPIO_Port, IN_ACT_REQ_Pin) == GPIO_PIN_RESET)
            {
                Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_CSU;
                DEBUG_INFO("Check MCU_Control_Mode is CSU in memmeory task\r\n");
            }
            else
            {
                Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_NO_CSU;
                if (Charger.memory.EVSE_Config.data.item.AuthMode > AUTH_MODE_FREE)
                {
                    Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_FREE ;
                    DEBUG_INFO("AuthMode is defualt AUTH_MODE_FREE \r\n");
                }

                if (Charger.memory.EVSE_Config.data.item.OfflinePolicy > RFID_USER_AUTH_NO_CHARGING)
                {
                    Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_FREE ;
                    DEBUG_INFO("OfflinePolicy is defualt RFID_USER_AUTH_FREE \r\n");
                }

                DEBUG_INFO("Check MCU_Control_Mode is NO NO NO CSU in memmeory task\r\n");
            }

            // Clean update & clear flag when model name not configured
            /*
            if(strlen(Charger.memory.EVSE_Config.data.item.ModelName)>20)
            {
                Charger.memory.EVSE_Config.op_bits.update = OFF;
                Charger.memory.EVSE_Config.op_bits.clear = OFF;
                Charger.memory.EVSE_Config.op_bits.backup = OFF;
                Charger.memory.EVSE_Config.op_bits.restore = OFF;
            }
            */
            parseVersionInfoFromModelname();
}
#endif //MODIFY_FLASH_OPERATION_20241104

/* USER CODE BEGIN Header_StartMemoryTask */
/**
* @brief Function implementing the memoryTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartMemoryTask */
void StartMemoryTask(void const * argument)
{
  /* USER CODE BEGIN StartMemoryTask */
  //mmemory
  //uint8_t tmpBuf[64];
  uint8_t isSuccess;
  uint8_t ID[2];

  BSP_W25Qx_Init();
  BSP_W25Qx_Read_ID(ID);

  DEBUG_INFO("W25Qxxx ID is : 0x%02X 0x%02X \r\n",ID[0],ID[1]);

  Charger.memory.EVSE_Config.op_bits.read = ON;
  Charger.memory.coldLoadPickUp.op_bits.read = ON;
  Charger.memory.whiteList.op_bits.read = ON;
  Charger.memory.hisAlarm.op_bits.read = ON;
  Charger.memory.hisCharging.op_bits.read = ON;

  /*
  Charger.memory.EVSE_Config.op_bits.clear = ON ;
  Charger.memory.EVSE_Config.op_bits.clear = ON;
  Charger.memory.coldLoadPickUp.op_bits.clear = ON;
  Charger.memory.whiteList.op_bits.clear = ON;
  Charger.memory.hisAlarm.op_bits.clear = ON;
  Charger.memory.hisCharging.op_bits.clear = ON;
  */

  /* Infinite loop */
  for(;;)
  {
    /*
        EVSE config operation
    */

    if(Charger.memory.EVSE_Config.op_bits.read)
    {
#ifdef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        taskENTER_CRITICAL();
#endif

#ifndef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        osDelay(100);
#endif
        // Read data from block
        if(BSP_W25Qx_Read(Charger.memory.EVSE_Config.data.value, MEM_ADDR_EVSE_CONFIG, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {

#ifdef FUNC_FLASH_RESTORE_CONFIG_WHEN_PRIMARY_LOSS

#ifdef FUNC_FLASH_CONFIG_APPEND_CRC
            u32 crc32 = HAL_CRC_Calculate(&hcrc, (u32*)Charger.memory.EVSE_Config.data.verify.buf, ((W25Q16FV_BLOCK_SIZE-4)>>2));
            if ((Charger.memory.EVSE_Config.data.verify.crc32 == crc32 /*|| Charger.memory.EVSE_Config.data.verify.crc32 == HTK_U32_MAX*/))
#else
            if (1)
#endif
            {
                DEBUG_INFO("Read MEM_ADDR_EVSE_CONFIG block(4k byte) pass.\r\n");
                Proc_EVSE_Config();
                Charger.ModelReadisOK = PASS;
            }
            else
            {
                static u8 bProc = 0;
                if (!bProc)
                {
                    bProc = 1;
                    DEBUG_WARN("MEM_ADDR_EVSE_CONFIG data area check sum error => restore from backup area.\r\n");
                    Charger.memory.EVSE_Config.op_bits.restore = ON;
                }
                else
                {
                    Proc_EVSE_Config();
                    Charger.ModelReadisOK = PASS;
                }
            }
#endif //FUNC_FLASH_RESTORE_CONFIG_WHEN_PRIMARY_LOSS


            Charger.memory.EVSE_Config.op_bits.read = OFF;
        }
        else
        {
            DEBUG_INFO("Read MEM_ADDR_EVSE_CONFIG block(4k byte) fail.\r\n");
        }
#ifdef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        taskEXIT_CRITICAL();
#endif
    }


    if(Charger.memory.EVSE_Config.op_bits.update)
    {
#ifdef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        taskENTER_CRITICAL();
#endif

#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
        Charger.memory.EVSE_Config.op_bits.update = OFF;
#endif
        isSuccess = PASS;

#ifdef FUNC_FLASH_CONFIG_APPEND_CRC
#ifndef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        osDelay(100);
#endif
        Charger.memory.EVSE_Config.data.verify.crc32 = HAL_CRC_Calculate(&hcrc, (u32*)Charger.memory.EVSE_Config.data.verify.buf, ((W25Q16FV_BLOCK_SIZE-4)>>2));
#endif
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_EVSE_CONFIG) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.EVSE_Config.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_EVSE_CONFIG+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Update MEM_ADDR_EVSE_CONFIG success.\r\n");
            else
                DEBUG_WARN("Update MEM_ADDR_EVSE_CONFIG fail.\r\n");
#ifndef FUNC_AUTO_MODIFY_CCID_MODULE
            Charger.memory.EVSE_Config.op_bits.update = OFF;
#endif

#ifdef FUNC_FLASH_UPDATE_CONFIG_BOTH_PRIMARY_AND_BACKUP
            Charger.memory.EVSE_Config.op_bits.backup = ON;
#endif
        }
        else
        {
            DEBUG_WARN("Update MEM_ADDR_EVSE_CONFIG block(4k byte) fail.\r\n");
        }
#ifdef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        taskEXIT_CRITICAL();
#endif
    }

    if(Charger.memory.EVSE_Config.op_bits.clear)
    {

        //***************
        // Erase backup block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_BACKUP_EVSE_CONFIG) == W25Qx_OK)
        {
            // Read data from block
            if(BSP_W25Qx_Read(Charger.memory.EVSE_Config.data.value, MEM_ADDR_BACKUP_EVSE_CONFIG, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
            {
                DEBUG_INFO("Erase MEM_ADDR_BACKUP_EVSE_CONFIG block(4k byte) pass.\r\n");
                Charger.memory.EVSE_Config.op_bits.clear = OFF;
            }
            else
            {
                DEBUG_WARN("Erase MEM_ADDR_BACKUP_EVSE_CONFIG block(4k byte) fail.\r\n");
            }
        }
        else
        {
            DEBUG_WARN("Erase MEM_ADDR_BACKUP_EVSE_CONFIG block(4k byte) fail.\r\n");
        }
        //***************

        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_EVSE_CONFIG) == W25Qx_OK)
        {
            // Read data from block
            if(BSP_W25Qx_Read(Charger.memory.EVSE_Config.data.value, MEM_ADDR_EVSE_CONFIG, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
            {
                DEBUG_INFO("Erase MEM_ADDR_EVSE_CONFIG block(4k byte) pass.\r\n");
                Charger.memory.EVSE_Config.op_bits.clear = OFF;
            }
            else
            {
                DEBUG_WARN("Erase MEM_ADDR_EVSE_CONFIG block(4k byte) fail.\r\n");
            }
        }
        else
        {
            DEBUG_WARN("Erase MEM_ADDR_EVSE_CONFIG block(4k byte) fail.\r\n");
        }

    }


    if(Charger.memory.EVSE_Config.op_bits.backup)
    {
#ifdef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        taskENTER_CRITICAL();
#endif
        isSuccess = PASS;
#ifndef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        osDelay(100);
#endif
		Charger.memory.EVSE_Config.data.verify.crc32 = HAL_CRC_Calculate(&hcrc, (u32*)Charger.memory.EVSE_Config.data.verify.buf, ((W25Q16FV_BLOCK_SIZE-4)>>2));

        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_BACKUP_EVSE_CONFIG) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.EVSE_Config.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_BACKUP_EVSE_CONFIG+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Backup MEM_ADDR_BACKUP_EVSE_CONFIG success.\r\n");
            else
                DEBUG_WARN("Backup MEM_ADDR_BACKUP_EVSE_CONFIG fail.\r\n");

            Charger.memory.EVSE_Config.op_bits.backup = OFF;
#ifndef FUNC_FLASH_UPDATE_CONFIG_BOTH_PRIMARY_AND_BACKUP
            //Charger.memory.EVSE_Config.op_bits.clear = ON;
#endif
        }
        else
        {
            DEBUG_WARN("Backup MEM_ADDR_BACKUP_EVSE_CONFIG block(4k byte) fail.\r\n");
        }
#ifdef FUNC_CALC_FLASH_CRC_IN_CRITICAL
        taskEXIT_CRITICAL();
#endif
    }

    if(Charger.memory.EVSE_Config.op_bits.restore)
    {
        // Restore data from backup block
        if(BSP_W25Qx_Read(Charger.memory.EVSE_Config.data.value, MEM_ADDR_BACKUP_EVSE_CONFIG, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            u32 crc32 = HAL_CRC_Calculate(&hcrc, (u32*)Charger.memory.EVSE_Config.data.verify.buf, ((W25Q16FV_BLOCK_SIZE-4)>>2));
            if(Charger.memory.EVSE_Config.data.verify.crc32 == crc32)
            {
                DEBUG_INFO("Restore MEM_ADDR_BACKUP_EVSE_CONFIG block(4k byte) pass.\r\n");

                // Update data to primary area
                Charger.memory.EVSE_Config.op_bits.update = ON;
                Proc_EVSE_Config();
                Charger.ModelReadisOK = PASS;
            }
            else
            {
                DEBUG_WARN("[FLASH] MEM_ADDR_BACKUP_EVSE_CONFIG block check sum error.\r\n");
                // TODO:

                static u8 bProc = 0;
                if (!bProc)
                {
                    bProc = 1;
                    setLedMotion(LED_ACTION_ALARM);
                    Charger.memory.EVSE_Config.op_bits.read = ON;
                }

            }
            Charger.memory.EVSE_Config.op_bits.restore = OFF;
        }
        else
        {
            DEBUG_WARN("Restore MEM_ADDR_BACKUP_EVSE_CONFIG block(4k byte) fail.\r\n");
        }
    }

#ifdef FUNC_TEST_SIMU_LOAD_BUTTON
    {
        static int buttonDownCount = 0;
        static HTK_BOOL bExec = HTK_FALSE;
        if((HAL_GPIO_ReadPin(IN_MEM_Erase_GPIO_Port, IN_MEM_Erase_Pin) == GPIO_PIN_RESET))
        {
            if (buttonDownCount > 100 && !bExec)
            {
                bExec = HTK_TRUE;
                Charger.m_bEnableSimuChargeCurrent = !Charger.m_bEnableSimuChargeCurrent;
                XP("\r\n\r\n#BUTTON:ParameterSimuCurr: %s\r\n\r\n\r\n", Charger.m_bEnableSimuChargeCurrent ? "ON" : "OFF");
            }
            else
            {
                buttonDownCount++;
            }
        }
        else
        {
            bExec = HTK_FALSE;
            buttonDownCount = 0;
        }
    }
#else //FUNC_TEST_SIMU_LOAD_BUTTON
    if((HAL_GPIO_ReadPin(IN_MEM_Erase_GPIO_Port, IN_MEM_Erase_Pin) == GPIO_PIN_RESET) && (Charger.Mode == MODE_IDLE) )
    {
        //prevent idiot to pree this button too long to cause watchdog reset
        HAL_IWDG_Refresh(&hiwdg);
        if(Charger.counter.RST_CFG>3000)
        {
            // Reset EVSE configuration to factory default value
            Charger.memory.EVSE_Config.data.item.bleConfig.isGenPin = OFF;
            Charger.memory.EVSE_Config.data.item.bleConfig.isRegPuk = OFF;
            Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_OCPP;
            Charger.memory.EVSE_Config.data.item.RFID_SN_Endian = RFID_ENDIAN_LITTLE;
            //Charger.memory.EVSE_Config.data.item.isAuthEnable = OFF;
            Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_FREE ;
            //Charger.memory.EVSE_Config.data.item.Power_Consumption_Cumulative = 0;
            Charger.memory.EVSE_Config.data.item.reservation.mode = RESERVATION_DISABLE;
            Charger.memory.EVSE_Config.op_bits.update = ON;

            // Reset cold load pick up to factory default value
            Charger.memory.coldLoadPickUp.data.item.isEnable = OFF;
            Charger.memory.coldLoadPickUp.op_bits.update = ON;

            // Reset white list to factory default value
            for(uint8_t idx=0;idx<20;idx++)
            {
                Charger.memory.whiteList.data.item[idx].listType = 0xff;
                Charger.memory.whiteList.data.item[idx].isReg = OFF;
                memset(&Charger.memory.whiteList.data.item[idx].pin[0], 0x00, 6);
                memset(&Charger.memory.whiteList.data.item[idx].listID[0], 0x00, 6);
            }
            Charger.memory.whiteList.op_bits.update = ON;

            //restore led
            setLedMotion(LED_ACTION_RESTORE_SETTING) ;
            timerEnable(TIMER_IDX_LED_TEMP, 3000);

            setChargerMode(MODE_IDLE);

            osDelay(1000);
       }
       else
           Charger.counter.RST_CFG++;
    }
    else
        Charger.counter.RST_CFG = 0;
#endif //FUNC_TEST_SIMU_LOAD_BUTTON

    /*
        Cold load pick up operation
    */
    if(Charger.memory.coldLoadPickUp.op_bits.read)
    {
        osDelay(100);
        // Read data from block
        if(BSP_W25Qx_Read(Charger.memory.coldLoadPickUp.data.value, MEM_ADDR_COLD_LOAD_PICKUP, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Read MEM_ADDR_COLD_LOAD_PICKUP block(4k byte) pass.\r\n");
            Charger.memory.coldLoadPickUp.op_bits.read = OFF;
        }
        else
        {
            DEBUG_WARN("Read MEM_ADDR_COLD_LOAD_PICKUP block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.coldLoadPickUp.op_bits.update)
    {
        isSuccess = PASS;
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_COLD_LOAD_PICKUP) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.coldLoadPickUp.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_COLD_LOAD_PICKUP+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Update MEM_ADDR_COLD_LOAD_PICKUP success.\r\n");
            else
                DEBUG_WARN("Update MEM_ADDR_COLD_LOAD_PICKUP fail.\r\n");

            Charger.memory.coldLoadPickUp.op_bits.update = OFF;
        }
        else
        {
            DEBUG_WARN("Update MEM_ADDR_COLD_LOAD_PICKUP block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.coldLoadPickUp.op_bits.clear)
    {
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_COLD_LOAD_PICKUP) == W25Qx_OK)
        {
            // Read data from block
            if(BSP_W25Qx_Read(Charger.memory.coldLoadPickUp.data.value, MEM_ADDR_COLD_LOAD_PICKUP, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
            {
                DEBUG_INFO("Erase MEM_ADDR_COLD_LOAD_PICKUP block(4k byte) pass.\r\n");
                Charger.memory.coldLoadPickUp.op_bits.clear = OFF;
            }
            else
            {
                DEBUG_WARN("Erase MEM_ADDR_COLD_LOAD_PICKUP block(4k byte) fail.\r\n");
            }
        }
        else
        {
            DEBUG_WARN("Erase MEM_ADDR_COLD_LOAD_PICKUP block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.coldLoadPickUp.op_bits.backup)
    {
        isSuccess = PASS;
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_BACKUP_COLD_LOAD_PICKUP) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.coldLoadPickUp.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_BACKUP_COLD_LOAD_PICKUP+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Backup MEM_ADDR_BACKUP_COLD_LOAD_PICKUP success.\r\n");
            else
                DEBUG_WARN("Backup MEM_ADDR_BACKUP_COLD_LOAD_PICKUP fail.\r\n");

            Charger.memory.coldLoadPickUp.op_bits.backup = OFF;
            Charger.memory.coldLoadPickUp.op_bits.clear = ON;
        }
        else
        {
            DEBUG_WARN("Backup MEM_ADDR_BACKUP_COLD_LOAD_PICKUP block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.coldLoadPickUp.op_bits.restore)
    {
        // Restore data from backup block
        if(BSP_W25Qx_Read(Charger.memory.coldLoadPickUp.data.value, MEM_ADDR_BACKUP_COLD_LOAD_PICKUP, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Restore MEM_ADDR_BACKUP_COLD_LOAD_PICKUP block(4k byte) pass.\r\n");
            Charger.memory.coldLoadPickUp.op_bits.restore = OFF;
        }
        else
        {
            DEBUG_WARN("Restore MEM_ADDR_BACKUP_COLD_LOAD_PICKUP block(4k byte) fail.\r\n");
        }
    }

    /*
        White list operation
    */
    if(Charger.memory.whiteList.op_bits.read)
    {
        osDelay(100);
        // Read data from block
        if(BSP_W25Qx_Read(Charger.memory.whiteList.data.value, MEM_ADDR_WHITE_LIST, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Read MEM_ADDR_WHITE_LIST block(4k byte) pass.\r\n");
            Charger.memory.whiteList.op_bits.read = OFF;
        }
        else
        {
            DEBUG_WARN("Read MEM_ADDR_WHITE_LIST block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.whiteList.op_bits.update)
    {
        isSuccess = PASS;
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_WHITE_LIST) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.whiteList.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_WHITE_LIST+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Update MEM_ADDR_WHITE_LIST success.\r\n");
            else
                DEBUG_WARN("Update MEM_ADDR_WHITE_LIST fail.\r\n");

            Charger.memory.whiteList.op_bits.update = OFF;
        }
        else
        {
            DEBUG_WARN("Update MEM_ADDR_WHITE_LIST block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.whiteList.op_bits.clear)
    {
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_WHITE_LIST) == W25Qx_OK)
        {
            // Read data from block
            if(BSP_W25Qx_Read(Charger.memory.whiteList.data.value, MEM_ADDR_WHITE_LIST, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
            {
                DEBUG_INFO("Erase MEM_ADDR_WHITE_LIST block(4k byte) pass.\r\n");
                Charger.memory.whiteList.op_bits.clear = OFF;
            }
            else
            {
                DEBUG_WARN("Erase MEM_ADDR_WHITE_LIST block(4k byte) fail.\r\n");
            }
        }
        else
        {
            DEBUG_WARN("Erase MEM_ADDR_WHITE_LIST block(4k byte) fail.\r\n");
        }
    }

    /*
        Alarm history operation
    */
    if(Charger.memory.hisAlarm.op_bits.read)
    {
        osDelay(100);
        // Read data from block
        if(BSP_W25Qx_Read(Charger.memory.hisAlarm.data.value, MEM_ADDR_HIS_ALARM, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Read MEM_ADDR_HIS_ALARM block(4k byte) pass.\r\n");
            Charger.memory.hisAlarm.op_bits.read = OFF;
        }
        else
        {
            DEBUG_WARN("Read MEM_ADDR_HIS_ALARM block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.hisAlarm.op_bits.update)
    {
        isSuccess = PASS;

        // Write data to block
        for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
        {
            if(BSP_W25Qx_Write(&Charger.memory.hisAlarm.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_HIS_ALARM+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
            {
                isSuccess = FAIL;
            }
        }

        if(isSuccess)
            DEBUG_INFO("Update MEM_ADDR_HIS_ALARM success.\r\n");
        else
            DEBUG_WARN("Update MEM_ADDR_HIS_ALARM fail.\r\n");

        Charger.memory.hisAlarm.op_bits.update = OFF;
    }

    if(Charger.memory.hisAlarm.op_bits.clear)
    {
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_HIS_ALARM) == W25Qx_OK)
        {
            // Read data from block
            if(BSP_W25Qx_Read(Charger.memory.hisAlarm.data.value, MEM_ADDR_HIS_ALARM, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
            {
                DEBUG_INFO("Erase MEM_ADDR_HIS_ALARM block(4k byte) pass.\r\n");
                Charger.memory.hisAlarm.op_bits.clear = OFF;
            }
            else
            {
                DEBUG_WARN("Erase MEM_ADDR_HIS_ALARM block(4k byte) fail.\r\n");
            }
        }
        else
        {
            DEBUG_WARN("Erase MEM_ADDR_HIS_ALARM block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.hisAlarm.op_bits.backup)
    {
        isSuccess = PASS;
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_BACKUP_HIS_ALARM) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.hisAlarm.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_BACKUP_HIS_ALARM+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Backup MEM_ADDR_BACKUP_HIS_ALARM success.\r\n");
            else
                DEBUG_WARN("Backup MEM_ADDR_BACKUP_HIS_ALARM fail.\r\n");

            Charger.memory.hisAlarm.op_bits.backup = OFF;
            Charger.memory.hisAlarm.op_bits.clear = ON;
        }
        else
        {
            DEBUG_WARN("Backup MEM_ADDR_BACKUP_HIS_ALARM block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.hisAlarm.op_bits.restore)
    {
        // Restore data from backup block
        if(BSP_W25Qx_Read(Charger.memory.hisAlarm.data.value, MEM_ADDR_BACKUP_HIS_ALARM, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Restore MEM_ADDR_BACKUP_HIS_ALARM block(4k byte) pass.\r\n");
            Charger.memory.hisAlarm.op_bits.restore = OFF;
        }
        else
        {
            DEBUG_WARN("Restore MEM_ADDR_BACKUP_HIS_ALARM block(4k byte) fail.\r\n");
        }
    }

    /*
        Charging history operation
    */
    if(Charger.memory.hisCharging.op_bits.read)
    {
        osDelay(100);
        // Read data from block
        if(BSP_W25Qx_Read(Charger.memory.hisCharging.data.value, MEM_ADDR_HIS_CHARGING, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Read MEM_ADDR_HIS_CHARGING block(4k byte) pass.\r\n");
            Charger.memory.hisCharging.op_bits.read = OFF;
        }
        else
        {
            DEBUG_WARN("Read MEM_ADDR_HIS_CHARGING block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.hisCharging.op_bits.update)
    {
        isSuccess = PASS;

        // Write data to block
        for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
        {
            if(BSP_W25Qx_Write(&Charger.memory.hisCharging.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_HIS_CHARGING+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
            {
                isSuccess = FAIL;
            }
        }

        if(isSuccess)
            DEBUG_INFO("Update MEM_ADDR_HIS_CHARGING success.\r\n");
        else
            DEBUG_WARN("Update MEM_ADDR_HIS_CHARGING fail.\r\n");

        Charger.memory.hisCharging.op_bits.update = OFF;

    }

    if(Charger.memory.hisCharging.op_bits.clear)
    {
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_HIS_CHARGING) == W25Qx_OK)
        {
            // Read data from block
            if(BSP_W25Qx_Read(Charger.memory.hisCharging.data.value, MEM_ADDR_HIS_CHARGING, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
            {
                DEBUG_INFO("Erase MEM_ADDR_HIS_CHARGING block(4k byte) pass.\r\n");
                Charger.memory.hisCharging.op_bits.clear = OFF;
            }
            else
            {
                DEBUG_WARN("Erase MEM_ADDR_HIS_CHARGING block(4k byte) fail.\r\n");
            }
        }
        else
        {
            DEBUG_WARN("Erase MEM_ADDR_HIS_CHARGING block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.hisCharging.op_bits.backup)
    {
        isSuccess = PASS;
        // Erase block data
        if(BSP_W25Qx_Erase_Block(MEM_ADDR_BACKUP_HIS_CHARGING) == W25Qx_OK)
        {
            // Write data to block
            for(uint16_t idx=0;idx<((W25Q16FV_BLOCK_SIZE)>>8);idx++)
            {
                if(BSP_W25Qx_Write(&Charger.memory.hisCharging.data.value[idx*W25Q16FV_PAGE_SIZE], MEM_ADDR_BACKUP_HIS_CHARGING+(idx*W25Q16FV_PAGE_SIZE), W25Q16FV_PAGE_SIZE) != W25Qx_OK)
                {
                    isSuccess = FAIL;
                }
            }

            if(isSuccess)
                DEBUG_INFO("Backup MEM_ADDR_BACKUP_HIS_CHARGING success.\r\n");
            else
                DEBUG_WARN("Backup MEM_ADDR_BACKUP_HIS_CHARGING fail.\r\n");

            Charger.memory.hisCharging.op_bits.backup = OFF;
            Charger.memory.hisCharging.op_bits.clear = ON;
        }
        else
        {
            DEBUG_WARN("Backup MEM_ADDR_BACKUP_HIS_CHARGING block(4k byte) fail.\r\n");
        }
    }

    if(Charger.memory.hisCharging.op_bits.restore)
    {
        // Restore data from backup block
        if(BSP_W25Qx_Read(Charger.memory.hisCharging.data.value, MEM_ADDR_BACKUP_HIS_CHARGING, W25Q16FV_BLOCK_SIZE)== W25Qx_OK)
        {
            DEBUG_INFO("Restore MEM_ADDR_BACKUP_HIS_CHARGING block(4k byte) pass.\r\n");
            Charger.memory.hisCharging.op_bits.restore = OFF;
        }
        else
        {
            DEBUG_WARN("Restore MEM_ADDR_BACKUP_HIS_CHARGING block(4k byte) fail.\r\n");
        }
    }

    osDelay(1);
  }
  /* USER CODE END StartMemoryTask */
}

/* USER CODE BEGIN Header_StartWifiTask */
/**
* @brief Function implementing the wifiTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartWifiTask */
void StartWifiTask(void const * argument)
{
  /* USER CODE BEGIN StartWifiTask */
  /* Infinite loop */
    char tmpBuf[128];
    //uint8_t endFlag[4]={0x55,0xaa,0x55,0xaa};
    __IO uint32_t flash;
    //uint32_t checksum;
    uint32_t rndNumber;

    //=====================================
    // Module reset
    //=====================================
    HAL_GPIO_WritePin(OUT_BLE_RESET_GPIO_Port, OUT_BLE_RESET_Pin, GPIO_PIN_RESET);
    osDelay(60);
    HAL_GPIO_WritePin(OUT_BLE_RESET_GPIO_Port, OUT_BLE_RESET_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(OUT_BLE_DSR_GPIO_Port, OUT_BLE_DSR_Pin, GPIO_PIN_SET);

    Charger.wifi.initSeq = 0;
    Charger.wifi.isDataMode = OFF;
    UART_WIFI_Init_OK = OFF;

    osDelay(1000);
    /* Infinite loop */
    for(;;)
    {
        //=====================================
        // WIFI module initialization process
        //=====================================
		switch(Charger.wifi.initSeq)
        {
            case 0x00:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_RESTORE], strlen(WIFI_CMD[WIFI_CMD_SET_RESTORE]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x01:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_DTR], strlen(WIFI_CMD[WIFI_CMD_SET_DTR]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x02:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_DSR], strlen(WIFI_CMD[WIFI_CMD_SET_DSR]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x03:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_GET_ADDR], strlen(WIFI_CMD[WIFI_CMD_GET_ADDR]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x04:
                sprintf(tmpBuf, "%s\"EVSE_AP_%sP\"\r\n", WIFI_CMD[WIFI_CMD_SET_SSID], Charger.wifi.module_mac);
                DEBUG_INFO("WIFI module set name: EVSE_AP_%s\r\n", Charger.wifi.module_mac);
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)tmpBuf, strlen(tmpBuf), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x05:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_CHANNEL], strlen(WIFI_CMD[WIFI_CMD_SET_CHANNEL]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x06:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_SECURITY_MODE], strlen(WIFI_CMD[WIFI_CMD_SET_SECURITY_MODE]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x07:
                sprintf(tmpBuf, "%s\"%s\"\r\n", WIFI_CMD[WIFI_CMD_SET_PASSWORD], Charger.memory.EVSE_Config.data.item.wifiConfig.passwd);
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)tmpBuf, strlen(tmpBuf), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x08:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_DHCPSERVER], strlen(WIFI_CMD[WIFI_CMD_SET_DHCPSERVER]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x09:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_TCPSETVER_CONFIG], strlen(WIFI_CMD[WIFI_CMD_SET_TCPSETVER_CONFIG]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x0a:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_AP_ACTIVE], strlen(WIFI_CMD[WIFI_CMD_SET_AP_ACTIVE]), 0xffff);
                osDelay(WIFI_INIT_DELAY);
                break;
            case 0x0b:
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)WIFI_CMD[WIFI_CMD_SET_DATA_MODE], strlen(WIFI_CMD[WIFI_CMD_SET_DATA_MODE]), 0xffff);
                DEBUG_INFO("WIFI module switch to data mode.\r\n");
                osDelay(WIFI_INIT_DELAY);
            default:
                UART_WIFI_Init_OK = ON;
                break;
        }

        //=====================================
        // WIFI central device connect status
        //=====================================
        if((HAL_GPIO_ReadPin(IN_BLE_DTR_GPIO_Port, IN_BLE_DTR_Pin) ==  GPIO_PIN_SET) && (UART_WIFI_Init_OK == ON))
        {
            // Device disconnect
            timerRefresh(TIMER_IDX_WIFI);
            if(Charger.wifi.loginRole == WIFI_LOGIN_ROLE_ROOT || Charger.wifi.loginRole == WIFI_LOGIN_ROLE_USER)
            {
                DEBUG_INFO("WIFI client device disconnect.\r\n.");
                Charger.wifi.loginRole = WIFI_LOGIN_ROLE_UNKOWN;
            }
        }
        else  if((HAL_GPIO_ReadPin(IN_BLE_DTR_GPIO_Port, IN_BLE_DTR_Pin) ==  GPIO_PIN_RESET) && (UART_WIFI_Init_OK == ON))
        {
            // Device connect in
            if(Charger.wifi.loginRole == WIFI_LOGIN_ROLE_UNKOWN)
            {
                DEBUG_INFO("WIFI client device connect.....wait sign in.\r\n.");
                osDelay(1000);
            }
        }

        //=====================================
        // Communication timeout process
        //=====================================
        if(timer[TIMER_IDX_WIFI].isAlarm)
        {
            Charger.wifi.loginRole = WIFI_LOGIN_ROLE_UNKOWN;
            DEBUG_INFO("WIFI no communication over time, disconnect client device.\r\n");
            timerRefresh(TIMER_IDX_WIFI);

            HAL_GPIO_WritePin(OUT_BLE_DSR_GPIO_Port, OUT_BLE_DSR_Pin, GPIO_PIN_RESET);
            osDelay(100);
            HAL_GPIO_WritePin(OUT_BLE_DSR_GPIO_Port, OUT_BLE_DSR_Pin, GPIO_PIN_SET);
        }

        //=====================================
        // WIFI uart recieve data process
        //=====================================
        if(UART_WIFI_recv_end_flag == ON)
        {
            if((HAL_GPIO_ReadPin(IN_BLE_DTR_GPIO_Port, IN_BLE_DTR_Pin) ==  GPIO_PIN_SET) || !Charger.wifi.isDataMode)
            {
                // AT command rx process
                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_RESTORE])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_DTR])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_DSR])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_GET_ADDR])!=NULL)
                {
                    memcpy(Charger.wifi.module_mac, &UART_WIFI_rx_buffer[strcspn((char *)UART_WIFI_rx_buffer, ":")+1], 12);
                    Charger.wifi.module_mac[12] = '\0';
                    DEBUG_INFO("Wifi module mac address: %s\r\n", Charger.wifi.module_mac);
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_SSID])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_CHANNEL])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_SECURITY_MODE])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_PASSWORD])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_DHCPSERVER])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_TCPSETVER_CONFIG])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_AP_ACTIVE])!=NULL)
                {
                    Charger.wifi.initSeq++;
                }

                if(strstr((char *)UART_WIFI_rx_buffer, WIFI_CMD[WIFI_CMD_SET_DATA_MODE])!=NULL)
                {
                    Charger.wifi.isDataMode = ON;
                    Charger.wifi.initSeq++;
                }
            }
            else
            {
                // Application protocol rx process
                uint8_t tx[UART_BUFFER_SIZE];
                uint8_t tx_len;
                uint8_t chksum = 0;

                if(isValidCheckSum_WIFI() && (rndNumber != ((UART_WIFI_rx_buffer[3]<<0) | (UART_WIFI_rx_buffer[4]<<8) | (UART_WIFI_rx_buffer[5]<<16) | (UART_WIFI_rx_buffer[6]<<24))))
                {
                    // Timer reset
                    timerRefresh(TIMER_IDX_WIFI);
                    rndNumber = ((UART_WIFI_rx_buffer[3]<<0) | (UART_WIFI_rx_buffer[4]<<8) | (UART_WIFI_rx_buffer[5]<<16) | (UART_WIFI_rx_buffer[6]<<24));

                    switch(UART_WIFI_rx_buffer[2])
                    {
                        case WIFI_PROTOCOL_MESSAGE_SIGN_IN:
                            DEBUG_INFO("WIFI device sign request...%d\r\n", UART_WIFI_rx_buffer[7]);
                            tx_len = 5;
                            tx[0] = (tx_len>>8)&0xff;
                            tx[1] = (tx_len&0xff);
                            tx[2] = UART_WIFI_rx_buffer[2] + 0x80;
                            tx[3] = 0x00;


                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }
                            tx[4] = chksum;

                            break;
                        default:
                            /*
                                TODO: Unknow command response here
                            */
                            tx_len = 5;
                            tx[0] = 0x00;
                            tx[1] = 0x05;
                            tx[2] = UART_WIFI_rx_buffer[2] + 0x80;
                            tx[3] = 0x00;

                            for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                            {
                                chksum ^= tx[2 + idx];
                            }
                            tx[4] = chksum;

                            DEBUG_ERROR("WIFI unknow command.\r\n");
                            break;
                    }
                }
                else
                {
                    /*
                        TODO: Protocol check sum error response here
                    */
                    tx_len = 5;
                    tx[0] = 0x00;
                    tx[1] = 0x05;
                    tx[2] = UART_WIFI_rx_buffer[2] + 0x80;
                    tx[3] = 0x00;

                    for(uint16_t idx=0;idx<((tx[1] | (tx[0]<<8))-3);idx++)
                    {
                        chksum ^= tx[2 + idx];
                    }
                    tx[4] = chksum;

                    DEBUG_ERROR("WIFI check sum validation error.\r\n");
                }
                HAL_UART_Transmit(&WIFI_USART, (uint8_t *)tx, tx_len, 0xffff);
            }

            UART_WIFI_rx_len=0;
            UART_WIFI_recv_end_flag=0;
        }
        HAL_UART_Receive_DMA(&WIFI_USART, (uint8_t*)UART_WIFI_rx_buffer, UART_BUFFER_SIZE);

        osDelay(1);
    }
  /* USER CODE END StartWifiTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

#ifdef MODIFY_IMCP

void UpdateCheckSum(uint8_t *Buf, uint16_t Len) //Len: Total package length
{
    uint16_t DataLen = Len - (IMCP_FM_HEAD_LEN + IMCP_FM_TAIL_LEN);
    uint8_t CheckSum = 0;

    //Update DataLen
    HTK_U16(Buf[IMCP_FM_DATALEN_LSB_IDX]) = DataLen;

    //Update CheckSum
    for (uint16_t i = 0; i < DataLen; i++)
    {
        CheckSum ^= Buf[IMCP_FM_DATA_BEG_IDX + i];
    }
    Buf[Len - 1] = CheckSum;
}

#ifdef FUNC_RS485_SLAVE
uint8_t isValidCheckSum_IAP(uint8_t *RxBuf)
{
    uint8_t result = OFF;
    uint8_t chksum = 0x00;

#ifdef FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
    if (RxBuf[IMCP_FM_FRAMEID_IDX] != PROTOCOL_HEAD)
    {
        return FAIL;
    }
    else if (RxBuf == UART_IAP_rx_buffer)
    {
        if (RxBuf[IMCP_FM_DSTADDR_IDX] != PROTOCOL_ADDR &&
            RxBuf[IMCP_FM_DSTADDR_IDX] != PROTOCOL_ADDR_AC_MAINBOARD &&
            RxBuf[IMCP_FM_DSTADDR_IDX] != PROTOCOL_ADDR_BROADCAST)
        {
            return FAIL;
        }
    }
    else if (RxBuf == UART_RS485_rx_buffer)
    {
        if (RxBuf[IMCP_FM_SRCADDR_IDX] != EMPX10_RS485_ADDR_CSU)
        {
            return FAIL;
        }
        else if (
            RxBuf[IMCP_FM_DSTADDR_IDX] != Charger.m_EMPX10_RS485_ClientAddr &&
            RxBuf[IMCP_FM_DSTADDR_IDX] != EMPX10_RS485_ADDR_BROADCAST)
        {
            return FAIL;
        }
    }

#else //FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
    if  (
            (RxBuf[IMCP_FM_FRAMEID_IDX] == PROTOCOL_HEAD) &&
            (
                    (RxBuf[IMCP_FM_DSTADDR_IDX] == PROTOCOL_ADDR)
                ||  (RxBuf[IMCP_FM_DSTADDR_IDX] == PROTOCOL_ADDR_AC_MAINBOARD)
                ||  (RxBuf[IMCP_FM_DSTADDR_IDX] == PROTOCOL_ADDR_BROADCAST)
            )
        )
#endif //FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
    {
        uint16_t nCheckSumIdx = IMCP_FM_DATA_BEG_IDX + HTK_U16(RxBuf[IMCP_FM_DATALEN_LSB_IDX]);
        for(uint16_t i = IMCP_FM_DATA_BEG_IDX; i < nCheckSumIdx; i++)
        {
          chksum ^= RxBuf[i];
        }

        if(chksum == RxBuf[nCheckSumIdx])
            result = ON;
    }

    return result;
}
#else //FUNC_RS485_SLAVE
uint8_t isValidCheckSum_IAP(void)
{
    uint8_t result = OFF;
    uint8_t chksum = 0x00;

    if  (
            (UART_IAP_rx_buffer[IMCP_FM_FRAMEID_IDX] == PROTOCOL_HEAD) &&
            (
                    (UART_IAP_rx_buffer[IMCP_FM_DSTADDR_IDX] == PROTOCOL_ADDR)
                ||  (UART_IAP_rx_buffer[IMCP_FM_DSTADDR_IDX] == PROTOCOL_ADDR_BROADCAST)
            )
        )
    {
        uint16_t nCheckSumIdx = IMCP_FM_DATA_BEG_IDX + HTK_U16(UART_IAP_rx_buffer[IMCP_FM_DATALEN_LSB_IDX]);
        for(uint16_t i = IMCP_FM_DATA_BEG_IDX; i < nCheckSumIdx; i++)
        {
          chksum ^= UART_IAP_rx_buffer[i];
        }

        if(chksum == UART_IAP_rx_buffer[nCheckSumIdx])
            result = ON;
    }

    return result;
}
#endif //FUNC_RS485_SLAVE

#else //MODIFY_IMCP
uint8_t isValidCheckSum_IAP(void)
{
  uint8_t result = OFF;
  uint8_t chksum = 0x00;

  if((UART_IAP_rx_buffer[0] == PROTOCOL_HEAD) &&
     ((UART_IAP_rx_buffer[2] == PROTOCOL_ADDR) | (UART_IAP_rx_buffer[2] == PROTOCOL_ADDR_BROADCAST)))
  {
    for(int idx=0;idx<(UART_IAP_rx_buffer[4] | (UART_IAP_rx_buffer[5]<<8));idx++)
    {
      chksum ^= UART_IAP_rx_buffer[6+ idx];
    }

    if(chksum == UART_IAP_rx_buffer[6+(UART_IAP_rx_buffer[4] | (UART_IAP_rx_buffer[5]<<8))])
      result = ON;
  }

  return result;
}

#endif //MODIFY_IMCP
//-------------------------------------------------------------------------------------------------
uint8_t isValidCheckSum_BLE(void)
{
    uint8_t result = OFF;
    uint8_t chksum = 0x00;

    if(((UART_BLE_rx_buffer[1] | (UART_BLE_rx_buffer[0]<<8))-1) < UART_BUFFER_SIZE)
    {
        for(int idx=2;idx<((UART_BLE_rx_buffer[1] | (UART_BLE_rx_buffer[0]<<8))-1);idx++)
        {
            chksum ^= UART_BLE_rx_buffer[idx];
        }

        if(chksum == UART_BLE_rx_buffer[(UART_BLE_rx_buffer[1] | (UART_BLE_rx_buffer[0]<<8))-1])
            result = ON;
    }

    return result;
}

//-------------------------------------------------------------------------------------------------
uint8_t isValidCheckSum_WIFI(void)
{
    uint8_t result = OFF;
    uint8_t chksum = 0x00;

    if(((UART_WIFI_rx_buffer[1] | (UART_WIFI_rx_buffer[0]<<8))-1) < UART_BUFFER_SIZE)
    {
        for(int idx=2;idx<((UART_WIFI_rx_buffer[1] | (UART_WIFI_rx_buffer[0]<<8))-1);idx++)
        {
            chksum ^= UART_WIFI_rx_buffer[idx];
        }

        if(chksum == UART_WIFI_rx_buffer[(UART_WIFI_rx_buffer[1] | (UART_WIFI_rx_buffer[0]<<8))-1])
            result = ON;
    }

    return result;
}

//-------------------------------------------------------------------------------------------------
#ifdef FUNC_DEBUG_MSG_SET_CHARGER_MODE
char* getModeName(uint8_t mode);
#endif

void setChargerMode(uint8_t mode)
{
#ifdef FUNC_DEBUG_MSG_SET_CHARGER_MODE
    XP("#SET CHARGER MODE:  [%s] >>> [%s]\r\n", getModeName(Charger.Mode_Previous), getModeName(mode));
#endif
	Charger.Mode_Previous = Charger.Mode;
	Charger.Mode = mode;
}

//-------------------------------------------------------------------------------------------------
char* getModeName(uint8_t mode)
{
    switch(mode)
    {
        case MODE_INITIAL:
            return "INITIAL";
        case MODE_IDLE:
            return "IDLE";
        case MODE_HANDSHAKE:
            return "HANDSHAKING";
        case MODE_CHARGING:
            return "CHARGING";
        case MODE_STOP:
            return "STOP";
        case MODE_ALARM:
            return "ALARM";
        case MODE_MAINTAIN:
            return "MAINTAIN";
        case MODE_DEBUG:
            return "DEBUG";
        default:
            return "UNKNOW";
    }
}

//-------------------------------------------------------------------------------------------------
uint8_t isModeChange(void)
{
	uint8_t result = NO;

	if(!isMode(Charger.Mode_Previous))
	{
        DEBUG_INFO("#MODE from %s to %s\r\n", getModeName(Charger.Mode_Previous), getModeName(Charger.Mode));
        result |= YES;
        if(Charger.Mode == MODE_ALARM)
        {
          Charger.Mode_Before_Alarm = Charger.Mode_Previous;
        }
        Charger.Mode_Previous = Charger.Mode;
	}

	return result;
}


//-------------------------------------------------------------------------------------------------
uint8_t isMode(uint8_t mode)
{
	return ((Charger.Mode == mode)? YES : NO);
}

//-------------------------------------------------------------------------------------------------
uint8_t rfidCheckSumCal(uint8_t *data, uint8_t length)
{
    uint8_t result= 0x00;

    for(uint8_t idx=0;idx<length;idx++)
      result ^= data[idx];

    return result;
}

//-------------------------------------------------------------------------------------------------
void HAL_PWR_PVDCallback(void)
{
    HAL_Delay(100);
    NVIC_SystemReset();
}

//-------------------------------------------------------------------------------------------------
uint8_t Test_LeakModule(void)
{
//      uint8_t result = PASS, DC_check = false, AC_check=false;
//      uint16_t time_out_count;
//      uint8_t retry_cnt = 0 ;

    uint8_t result = PASS;

#ifdef CCID_PROTECT

#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
if (Charger.m_bDisableCCID == 0 && ((HAL_GetTick() - Charger.m_BootTick) / 1000) > 30)
{
#endif

    uint8_t DC_check = false;
    uint8_t AC_check=false;
    uint16_t time_out_count;
    uint8_t retry_cnt = 0 ;

#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
    XP("#Test_LeakModule use CCID Module: %s\r\n", CCID_MODULE_TYPE_STR);
#endif

      if (Charger.CCID_Module_Type == CCID_MODULE_VAC)
      {
          osDelay(500);
          if(HAL_GPIO_ReadPin(IN_Leak_Error_GPIO_Port, IN_Leak_Error_Pin) == GPIO_PIN_SET)
          {
              DEBUG_INFO("VAC Leak Error pin ON.\r\n");
              result = FAIL;
          }
          else
          {
              HAL_Delay(270);
              HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port , OUT_Leak_Test_Pin , GPIO_PIN_RESET);
              HAL_Delay(50);  //40ms~1.2sec
              HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port , OUT_Leak_Test_Pin , GPIO_PIN_SET);
              //HAL_Delay(40);  //36ms

              time_out_count = 0;
              while(1)
              {
                  if(HAL_GPIO_ReadPin(IN_Leak_DC_GPIO_Port, IN_Leak_DC_Pin) == GPIO_PIN_SET)
                  {
                      DC_check = true;
                  }

                  if(HAL_GPIO_ReadPin(IN_Leak_AC_GPIO_Port, IN_Leak_AC_Pin) == GPIO_PIN_SET)
                  {
                      AC_check = true;
                  }

                  //if(DC_check&&AC_check)
                  if ((DC_check&&AC_check) && (HAL_GPIO_ReadPin(IN_Leak_AC_GPIO_Port, IN_Leak_AC_Pin) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(IN_Leak_DC_GPIO_Port, IN_Leak_DC_Pin) == GPIO_PIN_RESET))
                  {
                      break;
                  }

                  if(time_out_count>2000)
                  {
                      //result = FAIL;

                      if(retry_cnt < 1 )
                      {
                        HAL_Delay(270);
                        HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port , OUT_Leak_Test_Pin , GPIO_PIN_RESET);
                        HAL_Delay(50);  //40ms~1.2sec
                        HAL_GPIO_WritePin(OUT_Leak_Test_GPIO_Port , OUT_Leak_Test_Pin , GPIO_PIN_SET);
                        //HAL_Delay(40);  //36ms
                        retry_cnt ++ ;
                        time_out_count = 0 ;
                      }
                      else
                      {
                        DEBUG_INFO("Leak module self test Fail in timeout.\r\n");
                        result = FAIL;
                        break;
                      }
                  }
                  else
                  {
                      time_out_count++;
                      HAL_Delay(1);
                  }
              }
          }
      }
      else // Charger.CCID_Module_Type is CCID_MODULE_CORMEX
      {
            SPWM_Switch(ON);
            HAL_Delay(1000);

            XP("#[SPWM] adc_value.ADC2_IN6_GF.value = %d\r\n",adc_value.ADC2_IN6_GF.value);

            if ((adc_value.ADC2_IN6_GF.value<3000)&&(adc_value.ADC2_IN6_GF.value>2000)) //25mA
            {
                DEBUG_INFO("#Test_LeakModule(): OK\r\n");
                result = PASS ;
            }
            else
            {
                DEBUG_INFO("Test_LeakModule(): NG\r\n");
                //DEBUG_INFO("adc_value.ADC2_IN6_GF.value = %d\n\r",adc_value.ADC2_IN6_GF.value);
                result = FAIL;
            }
            SPWM_Switch(OFF);
    }

#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
}
#endif

#endif  //CCID_PROTECT
    return result;
}

//-------------------------------------------------------------------------------------------------
uint8_t Valid_RFID_SN(void)
{
    /*
        TODO: Validation logic check
    */
    uint8_t result = FAIL;
    uint32_t crc_result;
    uint8_t sn_len;
    uint8_t *buf;

    if(Charger.rfid.snType == RFID_SN_TYPE_4BYTE)
    {
      // SN length: 4
      sn_len = 4;
    }
    else if(Charger.rfid.snType == RFID_SN_TYPE_7BYTE)
    {
      // SN length: 7
      sn_len = 7;
    }
    else
    {
      // SN length: 10
      sn_len = 10;
    }

    buf = malloc(25 + sn_len);
    memcpy(buf, Charger.memory.EVSE_Config.data.item.System_ID, 25);
    memcpy(&buf[25], Charger.rfid.data_Sn, sn_len);
    crc_result = crc32(buf, 25 + sn_len);

    if(((Charger.rfid.data_Block[0] << 8) | (Charger.rfid.data_Block[1] << 0) | (Charger.rfid.data_Block[2] << 24) | (Charger.rfid.data_Block[3] << 16)) == ~crc_result)
    {
        result = PASS;
    }

    free(buf);
    return result;
}

//-------------------------------------------------------------------------------------------------
void recordAlarmHis(void)
{
    uint8_t isSuccess = FAIL;
    // Check record alarm request, if alarm code bit different with previous
    for(uint8_t errIdx=0;errIdx<32;errIdx++)
    {
        if(((Charger.Alarm_Code>>errIdx)&0x01) != ((Charger.Alarm_Code_Previous>>errIdx)&0x01))
        {
            // Find empty memory space
            for(uint16_t idx=0;idx<(W25Q16FV_BLOCK_SIZE>>4);idx++)
            {
                if((Charger.memory.hisAlarm.data.item[idx].alarmCode == 0xffffffff) &&
                   (Charger.memory.hisAlarm.data.item[idx].mode == 0xff))
                {
                    isSuccess = PASS;

                    Charger.memory.hisAlarm.data.item[idx].DateTime.year = Charger.memory.EVSE_Config.data.item.SystemDateTime.year;
                    Charger.memory.hisAlarm.data.item[idx].DateTime.month = Charger.memory.EVSE_Config.data.item.SystemDateTime.month;
                    Charger.memory.hisAlarm.data.item[idx].DateTime.day = Charger.memory.EVSE_Config.data.item.SystemDateTime.day;
                    Charger.memory.hisAlarm.data.item[idx].DateTime.hour = Charger.memory.EVSE_Config.data.item.SystemDateTime.hour;
                    Charger.memory.hisAlarm.data.item[idx].DateTime.min = Charger.memory.EVSE_Config.data.item.SystemDateTime.min;
                    Charger.memory.hisAlarm.data.item[idx].DateTime.sec = Charger.memory.EVSE_Config.data.item.SystemDateTime.sec;
                    Charger.memory.hisAlarm.data.item[idx].mode = Charger.Mode;

                    if((Charger.Alarm_Code>>errIdx)&0x01)
                    {
                        // Record alarm occur
                        Charger.memory.hisAlarm.data.item[idx].alarmCode = alarm_record_code[errIdx];
                        Charger.memory.hisAlarm.data.item[idx].isRecover = OFF;
                        Charger.Alarm_Code_Previous |= (0x00000001<<errIdx);
                    }
                    else
                    {
                        // Record alarm recover
                        Charger.memory.hisAlarm.data.item[idx].alarmCode = alarm_record_code[errIdx];
                        Charger.memory.hisAlarm.data.item[idx].isRecover = ON;
                        Charger.Alarm_Code_Previous &= ~(0x00000001<<errIdx);
                    }
                    Charger.memory.hisAlarm.op_bits.update = ON;

                    // If speace is last item, move data to backup area
                    if(idx == ((W25Q16FV_BLOCK_SIZE>>4)-1))
                    {
                        osDelay(500);
                        Charger.memory.hisAlarm.op_bits.backup = ON;
                        osDelay(500);
                    }

                    break;
                }
            }

            // If there is not any free space
            if(!isSuccess)
            {
                osDelay(500);
                Charger.memory.hisAlarm.op_bits.backup = ON;
                osDelay(500);
            }
        }
    }
}

//-------------------------------------------------------------------------------------------------
uint8_t recordChargingHis(uint8_t isColdLoadPickUp, uint32_t statusCode)
{
    uint8_t isSuccess = FAIL;

    if(isColdLoadPickUp)
    {
        for(uint16_t idx=0;idx<(W25Q16FV_BLOCK_SIZE>>6);idx++)
        {
            if((Charger.memory.hisCharging.data.item[idx].Duration == 0xffffffff) &&
               (Charger.memory.hisCharging.data.item[idx].powerSum == 0xffff) &&
               (Charger.memory.hisCharging.data.item[idx].stopStatusCode == 0xffffffff) )
            {
                isSuccess = PASS;

                Charger.memory.hisCharging.data.item[idx].DateTime.year = Charger.memory.coldLoadPickUp.data.item.DateTime.year;
                Charger.memory.hisCharging.data.item[idx].DateTime.month = Charger.memory.coldLoadPickUp.data.item.DateTime.month;
                Charger.memory.hisCharging.data.item[idx].DateTime.day = Charger.memory.coldLoadPickUp.data.item.DateTime.day;
                Charger.memory.hisCharging.data.item[idx].DateTime.hour = Charger.memory.coldLoadPickUp.data.item.DateTime.hour;
                Charger.memory.hisCharging.data.item[idx].DateTime.min = Charger.memory.coldLoadPickUp.data.item.DateTime.min;
                Charger.memory.hisCharging.data.item[idx].DateTime.sec = Charger.memory.coldLoadPickUp.data.item.DateTime.sec;
                Charger.memory.hisCharging.data.item[idx].Duration = Charger.memory.coldLoadPickUp.data.item.Duration;
                sprintf(Charger.memory.hisCharging.data.item[idx].PlugType, EVSE_CONNECTOR_TYPE);
                Charger.memory.hisCharging.data.item[idx].powerSum = Charger.memory.coldLoadPickUp.data.item.powerSum;
                Charger.memory.hisCharging.data.item[idx].startType = Charger.memory.coldLoadPickUp.data.item.startType;
                Charger.memory.hisCharging.data.item[idx].stopStatusCode = statusCode;
                memcpy(Charger.memory.hisCharging.data.item[idx].user, Charger.rfid.currentCard, 16);
                Charger.memory.hisCharging.op_bits.update = ON;

                // If speace is last item, move data to backup area
                if(idx == ((W25Q16FV_BLOCK_SIZE>>4)-1))
                {
                    osDelay(500);
                    Charger.memory.hisCharging.op_bits.backup = ON;
                }

                break;
            }
        }
    }
    else
    {
        for(uint16_t idx=0;idx<(W25Q16FV_BLOCK_SIZE>>6);idx++)
        {
            if((Charger.memory.hisCharging.data.item[idx].Duration == 0xffffffff) &&
               (Charger.memory.hisCharging.data.item[idx].powerSum == 0xffff) &&
               (Charger.memory.hisCharging.data.item[idx].stopStatusCode == 0xffffffff) )
            {
                isSuccess = PASS;

                Charger.memory.hisCharging.data.item[idx].DateTime.year = Charger.cycle_info.startDateTime.year;
                Charger.memory.hisCharging.data.item[idx].DateTime.month = Charger.cycle_info.startDateTime.month;
                Charger.memory.hisCharging.data.item[idx].DateTime.day = Charger.cycle_info.startDateTime.day;
                Charger.memory.hisCharging.data.item[idx].DateTime.hour = Charger.cycle_info.startDateTime.hour;
                Charger.memory.hisCharging.data.item[idx].DateTime.min = Charger.cycle_info.startDateTime.min;
                Charger.memory.hisCharging.data.item[idx].DateTime.sec = Charger.cycle_info.startDateTime.sec;
                Charger.memory.hisCharging.data.item[idx].Duration = Charger.cycle_info.Duration;
                sprintf(Charger.memory.hisCharging.data.item[idx].PlugType, EVSE_CONNECTOR_TYPE);
                Charger.memory.hisCharging.data.item[idx].powerSum = Charger.cycle_info.Power_Consumption;
                Charger.memory.hisCharging.data.item[idx].startType = Charger.cycle_info.StartType;
                Charger.memory.hisCharging.data.item[idx].stopStatusCode = statusCode;
                memcpy(Charger.memory.hisCharging.data.item[idx].user, Charger.rfid.currentCard, 16);
                Charger.memory.hisCharging.op_bits.update = ON;

                // If speace is last item, move data to backup area
                if(idx == ((W25Q16FV_BLOCK_SIZE>>4)-1))
                {
                    osDelay(500);
                    Charger.memory.hisCharging.op_bits.backup = ON;
                }

                break;
            }
        }
    }

    // If there is not any free space
    if(!isSuccess)
    {
        osDelay(500);
        Charger.memory.hisCharging.op_bits.backup = ON;
    }

    return isSuccess;
}

//-------------------------------------------------------------------------------------------------
void setLedMotion(uint8_t action)
{//ssetled
    //standard
    switch(action)
    {
        case LED_ACTION_INIT:
            Charger.led_R.motion = LED_MOTION_ON;
            Charger.led_G.motion = LED_MOTION_ON;
            Charger.led_B.motion = LED_MOTION_ON;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 1000, 1000, 0);
            break;
        case LED_ACTION_IDLE: //eMP: IDLE BACKEND ONLINE
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_ON;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 1000, 0, 0);
            break;
        case LED_ACTION_AUTHED:
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_ON;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 0, 1000, 0);
            break;
        case LED_ACTION_CONNECTED: //eMP: IDLE BACKEND OFFLINE
#ifdef FUNC_EMPX10_LED
            Charger.led_R.motion = LED_MOTION_ON;
            Charger.led_G.motion = LED_MOTION_ON;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 500, 0, 0);
#else
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_ON;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 0, 1000, 0);
#endif
            break;
        case LED_ACTION_CHARGING:
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_BLINK;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 0, 1000, 0);
            blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
            break;
        case LED_ACTION_STOP:
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_ON;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 0, 1000, 0);
            break;

        case LED_ACTION_ALARM:
#ifdef FUNC_EMPX10_LED_ALARM_FIX_20240730
            if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                Charger.Alarm_LED = Charger.Alarm_Code;
            }else{
                Charger.Alarm_LED = Charger.am3352.LedAlarmState;
            }

            if(Charger.Alarm_LED & ALARM_EMERGENCY_STOP)
            {
                Charger.led_R.motion = LED_MOTION_BLINK;
                Charger.led_G.motion = LED_MOTION_OFF;
                Charger.led_B.motion = LED_MOTION_OFF;
                Charger.led_W.motion = LED_MOTION_OFF;
                LedOnRGBSet(1000, 0, 0, 0);
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 7);
            }
            else
            {
                Charger.led_R.motion = LED_MOTION_ON;
                Charger.led_G.motion = LED_MOTION_OFF;
                Charger.led_B.motion = LED_MOTION_OFF;
                Charger.led_W.motion = LED_MOTION_OFF;
                LedOnRGBSet(1000, 0, 0, 0);
            }

#else //FUNC_EMPX10_LED_ALARM_FIX_20240730
            Charger.led_R.motion = LED_MOTION_BLINK;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 0, 0, 0);
            //set alarm led blink duty
            if(Charger.memory.EVSE_Config.data.item.MCU_Control_Mode == MCU_CONTROL_MODE_NO_CSU){
                Charger.Alarm_LED = Charger.Alarm_Code;
            }else{
                Charger.Alarm_LED = Charger.am3352.LedAlarmState;
            }

            if(Charger.Alarm_LED & ALARM_CP_ERROR)
                blinkerTimeSet(BLINKER_IDX_LED, 500 , 500, 0, 1);
            if(Charger.Alarm_LED & ALARM_OVER_VOLTAGE)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 1);
            if(Charger.Alarm_LED & ALARM_UNDER_VOLTAGE)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 2);
            if(Charger.Alarm_LED & ALARM_OVER_CURRENT)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 3);
            if(Charger.Alarm_LED & ALARM_OVER_TEMPERATURE)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 4);
            if(Charger.Alarm_LED & ALARM_CURRENT_LEAK_AC)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 5);
            if(Charger.Alarm_LED & ALARM_CURRENT_LEAK_DC)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 5);
            if(Charger.Alarm_LED & ALARM_GROUND_FAIL)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 6);
            if(Charger.Alarm_LED & ALARM_HANDSHAKE_TIMEOUT)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
            if(Charger.Alarm_LED & ALARM_EMERGENCY_STOP)
                blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 3000, 7);
            if(Charger.Alarm_LED & ALARM_ROTATORY_SWITCH_FAULT)
                blinkerTimeSet(BLINKER_IDX_LED, 200, 200, 0, 1);

            //OCP Latch
            if (Charger.counter.OC.isLatch == ON)
            {
              Charger.led_R.motion = LED_MOTION_ON ;
              Charger.led_B.motion = LED_MOTION_ON ;
              LedOnRGBSet(1000, 0, 1000, 0);
            }

            //CCID Latch
            if (Charger.counter.LEAK.isLatch == ON)
            {
               Charger.led_R.motion = LED_MOTION_ON ;
               Charger.led_G.motion = LED_MOTION_ON ;
               LedOnRGBSet(1000, 1000, 0, 0);
            }

            //OTP
            if (Charger.counter.OT.isLatch == ON)
            {
              Charger.led_R.motion = LED_MOTION_ON;
              Charger.led_G.motion = LED_MOTION_BLINK;
              Charger.led_B.motion = LED_MOTION_BLINK;
              Charger.led_W.motion = LED_MOTION_OFF;
              LedOnRGBSet(1000, 1000, 1000, 0);
              blinkerTimeSet(BLINKER_IDX_LED, 500 , 500, 0, 1);
            }

            //self test error
            if ((Charger.Alarm_Code & ALARM_MCU_TESTFAIL)       ||
                (Charger.Alarm_Code & ALARM_RELAY_STATUS)       ||
                (Charger.Alarm_Code & ALARM_RELAY_DRIVE_FUALT ) ||
                (Charger.Alarm_Code & ALARM_LEAK_MODULE_FAIL))
            {
                Charger.led_R.motion = LED_MOTION_ON;
                Charger.led_G.motion = LED_MOTION_OFF;
                Charger.led_B.motion = LED_MOTION_OFF;
                Charger.led_W.motion = LED_MOTION_OFF;
              LedOnRGBSet(1000, 0, 0, 0);
            }
#endif //FUNC_EMPX10_LED_ALARM_FIX_20240730
            break;

        case LED_ACTION_MAINTAIN:
#ifdef FUNC_EMPX10_LED
            Charger.led_R.motion = LED_MOTION_BLINK;
            Charger.led_G.motion = LED_MOTION_BLINK;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 500, 0, 0);
#else
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_BLINK;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 1000, 0, 0);
#endif
            blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
            break;

        case LED_ACTION_RFID_PASS:
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_BLINK;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 1000, 0, 0);
            blinkerTimeSet(BLINKER_IDX_LED, 200, 200, 0, 1);
            break;

        case LED_ACTION_RFID_FAIL:
            Charger.led_R.motion = LED_MOTION_BLINK;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 0, 0, 0);
            blinkerTimeSet(BLINKER_IDX_LED, 200, 200, 0, 1);
            break;

         case LED_ACTION_DEBUG:
            Charger.led_R.motion = LED_MOTION_BLINK;
            Charger.led_G.motion = LED_MOTION_BLINK;
            Charger.led_B.motion = LED_MOTION_BLINK;
            Charger.led_W.motion = LED_MOTION_BLINK;
            LedOnRGBSet(1000, 1000, 1000, 1000);
            blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
            break;
         case LED_ACTION_ALL_OFF:
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 0, 0, 0);
            break ;
         case LED_ACTION_HANDSHAKE_FAIL:
            Charger.led_R.motion = LED_MOTION_BLINK;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 0, 0, 0);
            blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
            break;
         case LED_ACTION_INTERNET_DISCONNECT:
            Charger.led_R.motion = LED_MOTION_ON;
            Charger.led_G.motion = LED_MOTION_ON;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(1000, 1000, 0, 0);
            break;
        case LED_ACTION_RESTORE_SETTING:
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_BLINK;
            LedOnRGBSet(0, 0, 0, 1000);
            blinkerTimeSet(BLINKER_IDX_LED, 500, 500, 0, 1);
            break;
         default :
            Charger.led_R.motion = LED_MOTION_OFF;
            Charger.led_G.motion = LED_MOTION_OFF;
            Charger.led_B.motion = LED_MOTION_OFF;
            Charger.led_W.motion = LED_MOTION_OFF;
            LedOnRGBSet(0, 0, 0, 0);
            break;


    }
    if((action != LED_ACTION_RFID_PASS) &&
       (action != LED_ACTION_RFID_FAIL) &&
       (action != LED_ACTION_BLE_CONNECT) &&
       (action != LED_ACTION_BLE_DISABLE) &&
       (action != LED_ACTION_HANDSHAKE_FAIL) &&
       (action != LED_ACTION_RESTORE_SETTING))
    {
      Charger.Led_Mode = action;
    }
}

//-------------------------------------------------------------------------------------------------
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
{
#ifdef CCID_PROTECT
#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
if (Charger.m_bDisableCCID == 0 && ((HAL_GetTick() - Charger.m_BootTick) / 1000) > 30)
{
#endif
    if (Charger.CCID_Module_Type == CCID_MODULE_CORMEX)
    {
       if(hadc->Instance == ADC2) //use watch dog to check ccid level
       {
            if (!Charger.isTestLeakModule)
            {
                if(Charger.counter.WatchDogLeak >= 5)
                {
                    if(!(Charger.Alarm_Code & ALARM_CURRENT_LEAK_AC))
                    {
                        DEBUG_INFO("leak adc watch happen\r\n");
                        Charger.counter.LEAK.isOccurInCharging = (((Charger.Mode == MODE_CHARGING) || (Charger.Mode == MODE_STOP))?ON:OFF);
                        Charger.Alarm_Code |= ALARM_CURRENT_LEAK_AC;
                        timerEnable(TIMER_IDX_RETRY_LEAK_AC, ALARM_RETRY_INTERVAL_LEAK);
                        Charger.counter.LEAK.retry++ ;
                        Charger.Relay_Action =  GPIO_RELAY_ACTION_OFF  ;
                        HAL_GPIO_WritePin(OUT_RelayDrv_L1_GPIO_Port, OUT_RelayDrv_L1_Pin, GPIO_PIN_RESET);
                        HAL_GPIO_WritePin(OUT_RelayHold_L1_GPIO_Port, OUT_RelayHold_L1_Pin, GPIO_PIN_RESET);
                        HAL_GPIO_WritePin(OUT_RelayDrv_L2_GPIO_Port, OUT_RelayDrv_L2_Pin, GPIO_PIN_RESET);
                        HAL_GPIO_WritePin(OUT_RelayHold_L2_GPIO_Port, OUT_RelayHold_L2_Pin, GPIO_PIN_RESET);

                        Charger.counter.WatchDogLeak = 0 ;
                    }
                }
                else
                {
                   Charger.counter.WatchDogLeak ++ ;
                }
            }
        }
    }
#ifdef FUNC_SWITCH_RELAY_WELDING_PROTECT
}
#endif
#endif  //CCID_PROTECT
}

//-------------------------------------------------------------------------------------------------
void SetADCWDGBoundary(void)
{
    if(!ADCWDGHighThreshold)
    {
        //220V 3200 820
        //110V 2640 1400
        ADCWDGHighThreshold = 3200;
        ADCWDGLowThreshold = 820;

    }
    ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};
    /*
    * Configure the analog watchdog
    */
    AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;

    AnalogWDGConfig.HighThreshold = ADCWDGHighThreshold;
    AnalogWDGConfig.LowThreshold = ADCWDGLowThreshold;
    AnalogWDGConfig.Channel = ADC_CHANNEL_9;
    AnalogWDGConfig.ITMode = ENABLE;
    if (HAL_ADC_AnalogWDGConfig(&hadc3, &AnalogWDGConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

//-------------------------------------------------------------------------------------------------
void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
{
    DEBUG_ERROR("Stack overflow: %s\r\n", pcTaskName);
    osDelay(500);
}

//-------------------------------------------------------------------------------------------------
void getlastRecord(void)
{
    for(uint16_t idx=0;idx<(W25Q16FV_BLOCK_SIZE>>4);idx++)
    {
        if((Charger.memory.hisCharging.data.item[idx].Duration == 0xffffffff) &&
           (Charger.memory.hisCharging.data.item[idx].powerSum == 0xffff) &&
           (Charger.memory.hisCharging.data.item[idx].stopStatusCode == 0xffffffff) )
        {
            DEBUG_INFO("Charging record last index: %d\r\n", (idx));
            break;
        }
    }

    for(uint16_t idx=0;idx<(W25Q16FV_BLOCK_SIZE>>6);idx++)
    {
        if((Charger.memory.hisAlarm.data.item[idx].alarmCode == 0xffffffff) &&
           (Charger.memory.hisAlarm.data.item[idx].mode == 0xff))
        {
            DEBUG_INFO("Alarm record last index: %d\r\n", (idx));
            break;
        }
    }
}

//-------------------------------------------------------------------------------------------------
void getRotarySwitchSetting(void)
{
    uint8_t tmpBuf = 0;

    tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set1_GPIO_Port, IN_AC_Current_Set1_Pin)?0:1)<<0;
    tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set2_GPIO_Port, IN_AC_Current_Set2_Pin)?0:1)<<1;
    tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set3_GPIO_Port, IN_AC_Current_Set3_Pin)?0:1)<<2;
    tmpBuf += (HAL_GPIO_ReadPin(IN_AC_Current_Set4_GPIO_Port, IN_AC_Current_Set4_Pin)?0:1)<<3;

    Charger.isDebugEnable = OFF;

#ifdef FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
    if (!(((sbyte)tmpBuf) >= EMPX10_RS485_ADDR_MIN && ((sbyte)tmpBuf) <= EMPX10_RS485_ADDR_MAX))
    {
        Charger.isRotarySwitchError = ON;
    }
    DEBUG_INFO("Rotary switch (RS485 Addr) Setting: %d (%s)\r\n", tmpBuf, Charger.isRotarySwitchError ? "NG" : "OK");
    Charger.m_EMPX10_RS485_ClientAddr = tmpBuf;

#ifdef FUNC_EMPX10_SET_FIXED_CURRENT_16A
    Charger.maxRatingCurrent = 16;
#else //FUNC_EMPX10_SET_FIXED_CURRENT_16A

#ifdef FUNC_EMPX10_SET_FIXED_CURRENT_20A
    Charger.maxRatingCurrent = 20;
#else
    Charger.maxRatingCurrent = EVSE_MODEL_CURRENT_RATING;
#endif

#endif //FUNC_EMPX10_SET_FIXED_CURRENT_16A


#else //FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
    switch(tmpBuf)
    {
        case 0x00:
            Charger.maxRatingCurrent = EVSE_MODEL_CURRENT_RATING;
            DEBUG_INFO("Set maxRatingCurrent is Test mode\r\n");
            Charger.isDebugEnable = ON;
            break;
        case 0x01:
            Charger.maxRatingCurrent = (6>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:6);
            Charger.isDebugEnable = OFF;
            break;
        case 0x02:
            Charger.maxRatingCurrent = (8>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:8);
            Charger.isDebugEnable = OFF;
            break;
        case 0x03:
            Charger.maxRatingCurrent = (10>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:10);
            Charger.isDebugEnable = OFF;

            break;
        case 0x04:
            Charger.maxRatingCurrent = (13>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:13);
            Charger.isDebugEnable = OFF;
            break;
        case 0x05:
            Charger.maxRatingCurrent = (16>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:16);
            Charger.isDebugEnable = OFF;
            break;
        case 0x06:
            Charger.maxRatingCurrent = (20>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:20);
            Charger.isDebugEnable = OFF;
            break;
        case 0x07:
            Charger.maxRatingCurrent = (25>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:25);
            Charger.isDebugEnable = OFF;
            break;
        case 0x08:
            Charger.maxRatingCurrent = (32>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:32);
            Charger.isDebugEnable = OFF;
            break;
        case 0x09:
            Charger.maxRatingCurrent = (32>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:32);
            Charger.isDebugEnable = OFF;
            break ;
        case 0x0a:
            Charger.maxRatingCurrent = (30>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:30); // for JARI
            Charger.isDebugEnable = OFF;
            break ;
        case 0x0b:
        case 0x0c:
        case 0x0d:
        case 0x0e:
            Charger.maxRatingCurrent = (32>EVSE_MODEL_CURRENT_RATING?EVSE_MODEL_CURRENT_RATING:32);
            Charger.isRotarySwitchError = ON ;
            Charger.isDebugEnable = OFF;
            break ;

        case 0x0f:
            Charger.maxRatingCurrent = EVSE_MODEL_CURRENT_RATING;
            DEBUG_INFO("Knob error Set maxRatingCurrent defualt 32A\r\n");
            DEBUG_INFO("EVSE is Set Slave Mode\r\n");
            Charger.isDebugEnable = OFF;
            break;

        default:
            Charger.maxRatingCurrent = EVSE_MODEL_CURRENT_RATING;
            DEBUG_INFO("knob default Set maxRatingCurrent defualt 32A\r\n");
            Charger.isDebugEnable = OFF;
            break;
    }
#endif //FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS

    DEBUG_INFO("Current rating value: %d A\r\n", Charger.maxRatingCurrent);
    Charger.memory.EVSE_Config.data.item.MaxChargingCurrent = Charger.maxRatingCurrent;

#ifdef MODIFY_AC_EVSE_STATUS_MAX_CHARGING_CURRENT_VARIABLE
    Charger.AC_MaxChargingCurrentOrDuty = Charger.maxRatingCurrent;
#endif
}

//------------------------------------------------------------------------------//
void CLC_Corr_Gain_Par(uint16_t SpecData_H ,uint16_t SpecData_L ,uint16_t MCUData_H , uint16_t MCUData_L , float *GainA , float *GainB )
{
    *GainA = (float)((float)(SpecData_H -SpecData_L) / (float)( MCUData_H - MCUData_L)) ;
    *GainB = (float)(SpecData_H - (float)(*GainA * MCUData_H)) ;
}

//------------------------------------------------------------------------------//
void CLC_Corr_Gain_Par2(uint16_t SpecData_H ,uint16_t SpecData_L ,uint16_t MCUData_H , uint16_t MCUData_L , float *GainA , float *GainB , uint8_t *PosorNeg )
{
    *GainA = (float)((float)(SpecData_H -SpecData_L) / (float)( MCUData_H - MCUData_L)) ;

    if (SpecData_H > (*GainA * MCUData_H))
    {
        *GainB = SpecData_H - (*GainA * MCUData_H) ;
        *PosorNeg = ON ;
    }
    else
    {
        *GainB = (*GainA * MCUData_H) - SpecData_H ;
        *PosorNeg = OFF ;
    }
}

//------------------------------------------------------------------------------
uint8_t Array_data_Check ( uint8_t *s1, uint8_t *s2 )
{
     uint8_t compare = 0;
     uint8_t result = PASS;

     for(compare=0;compare<sizeof(s1);compare++)
     {
         if(s1[compare]!=s2[compare])
         {
           result = FAIL;
           break;
         }
     }

     return result;
}

//------------------------------------------------------------------------------
void Relay_Control_Function (void)
{
    switch(Charger.Relay_Action)
    {
#ifdef FUNC_TEST_RELAY_ALWAYS_ON
        case GPIO_RELAY_ACTION_OFF:
#endif
        case GPIO_RELAY_ACTION_ON:

            if(Relay1_Action_Get() == GPIO_RELAY1_ACTION_OFF && Relay2_Action_Get() == GPIO_RELAY2_ACTION_OFF)
            {
              Relay_Action_Set(GPIO_RELAY1_ACTION_ON);
              Relay_Action_Set(GPIO_RELAY2_ACTION_ON);
            }

            if(timer[TIMER_IDX_RELAY_1].isAlarm == ON && timer[TIMER_IDX_RELAY_2].isAlarm == ON)
            {
              Relay_Action_Set(GPIO_RELAY1_ACTION_HOLD);
              Relay_Action_Set(GPIO_RELAY2_ACTION_HOLD);
              timerDisable(TIMER_IDX_RELAY_1);
              timerDisable(TIMER_IDX_RELAY_2);
              Charger.Relay_isOperationCompleted  |= 0x11 ;
            }

            break;
#ifndef FUNC_TEST_RELAY_ALWAYS_ON
        case GPIO_RELAY_ACTION_OFF:
            timer[TIMER_IDX_RELAY_1].isEnable = OFF;
            timer[TIMER_IDX_RELAY_2].isEnable = OFF;
            if(Relay1_Action_Get() != GPIO_RELAY1_ACTION_OFF)
            {
                Relay_Action_Set(GPIO_RELAY1_ACTION_OFF);
                Relay_Action_Set(GPIO_RELAY2_ACTION_OFF);
            }
            osDelay(10);
            Charger.Relay_isOperationCompleted &= 0x00 ;
#ifdef FUNC_GET_TRIP_TIME
            if (Charger.m_TripBeg > 0 && Charger.m_TripEnd == HTK_U32_MAX)
            {
                Charger.m_TripEnd = HAL_GetTick();
            }
#endif
            break;
#endif //FUNC_TEST_RELAY_ALWAYS_ON

        default:
            break;
    }
}

//--------------------------------------------------------------------------------
uint8_t WatchDogLeakRawDataCheck_Event(void)
{
    uint8_t result = PASS ;

    for(uint16_t idx = 0 ; idx < ADC2_SAMPLE_COUNT; idx++)
    {
        if (ADC2_Buffer_Each[1][idx] >= 4000)
        {
            result = FAIL;
            break;
        }
    }

    return result ;
}

//--------------------------------------------------------------------------------
uint16_t getBrightnessDuty(uint16_t max_duty)
{
    uint8_t Lv_Brightness = 3;
    uint16_t duty = 1000;

    Lv_Brightness = (Charger.Led_Brightness[(Charger.memory.EVSE_Config.data.item.SystemDateTime.hour/2)]>>(((Charger.memory.EVSE_Config.data.item.SystemDateTime.hour+1)%2)*4))&0xf;

    switch(Lv_Brightness)
    {
#ifdef FUNC_EMP_LED_SET_MIN_BRIGHTNESS
      case 0:
          duty = max_duty/10;
          break;
      case 1:
          duty = max_duty/10;
          break;
#else //FUNC_EMP_LED_SET_MIN_BRIGHTNESS
      case 0:
          duty = max_duty/4;
          break;
      case 1:
          duty = max_duty/3;
          break;
#endif //FUNC_EMP_LED_SET_MIN_BRIGHTNESS
      case 2:
          duty = max_duty/2;
          break;
      case 3:
          duty = max_duty;
          break;
      default:
          duty = max_duty;
          break;
    }
    return duty;
}

//--------------------------------------------------------------------------------
void parseVersionInfoFromModelname(void)
{
#ifdef FUNC_VERSION_USE_NEW_SPEC_20240926
        //do nothing
#else //FUNC_VERSION_USE_NEW_SPEC_20240926
        //--------------------------------------
        // Version Naming Rule "tx.yz.ab.cddd.vv"
        //Version Naming Rule "a"
        for(uint8_t idx=0;idx<3;idx++)
        {
                switch(Charger.memory.EVSE_Config.data.item.ModelName[7+idx])
                {
                        case '1':
                                // J1772 Plug
                                Charger.Ver_FW[6] = '4';
                                break;
                        case '2':
                                // J1772 Socket
                                Charger.Ver_FW[6] = '1';
                                break;
                        case '3':
                                // CE Plug
                                Charger.Ver_FW[6] = '5';
                                break;
                        case '4':
                                // CE Socket
                                Charger.Ver_FW[6] = '2';
                                break;
                        case '5':
                                // GB Plug
                                Charger.Ver_FW[6] = '6';
                                break;
                        case '6':
                                // GB Socket
                                Charger.Ver_FW[6] = '3';
                                break;
#ifdef FUNC_ADD_FW_VER_WITH_GUN_TYPE_NACS
                        case '9':
                                // NACS
                                Charger.Ver_FW[6] = '9';
                                break;
#endif
                }
        }
#endif //FUNC_VERSION_USE_NEW_SPEC_20240926

        //Version Naming Rule "c"
        switch(Charger.memory.EVSE_Config.data.item.ModelName[10])
        {
                case 'B':
                case 'U':
                        //Blue tooth
                        Charger.Ver_FW[9] = '3';
                        break;
                case 'W':
                        // WIFI
                        Charger.Ver_FW[9] = '1';
                        break;
                case 'T':
                        // 3G/4G
                        Charger.Ver_FW[9] = '2';
                        break;
#ifdef FUNC_ADD_FW_VER_WITH_NET_TYPE_WIFI_AND_4G
                case 'D':
                        // WIFI + 4G
                        Charger.Ver_FW[9] = '5';
                        break;
#endif
                default:
                        // LAN
                        Charger.Ver_FW[9] = '0';
                        break;
        }

        //Version Naming Rule "d3" , Get rating power from model name
        memcpy(&Charger.Ver_FW[10], &Charger.memory.EVSE_Config.data.item.ModelName[4], 0x03);

        // Get vender code from model name
        memcpy(&Charger.Ver_FW[14], &Charger.memory.EVSE_Config.data.item.ModelName[12], 0x02);

        //--------------------------------------
#ifdef MODIFY_OCP_PROC_WITH_MODELNAME_IDX_3_EURO_SPEC
        HTK_BOOL bModelNameWithEuroSpecOCP = HTK_FALSE;
#endif
        // CCID_Module_Type check
        Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
        switch(Charger.memory.EVSE_Config.data.item.ModelName[3])
        {
            case 'E': //CE / European Market
            case 'T': //TR25 / Singapor Market
            case 'Z': //EV ready / French Market


#ifdef MODIFY_OCP_PROC_WITH_MODELNAME_IDX_3_EURO_SPEC
            case 'M': //E + MID Meter
            case 'P': //E + PTB certification
            case 'I': //Z + TIC Meter pcb
            case 'F': //Z + MID Meter
                bModelNameWithEuroSpecOCP = HTK_TRUE;
#endif

                Charger.CCID_Module_Type = CCID_MODULE_VAC ;
////#ifdef MODIFY_OCP_MAGNIFICATION
////                Charger.OCP_Magnification = 125 ;
////#else
                Charger.OCP_Magnification = 115 ;
////#endif
                break;

            case 'U':
                //UL    / North America Market
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
                Charger.alarm_spec.Current_LEAK_AC = 1800 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;

            case 'G':
                //GB    / China Market
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
                Charger.alarm_spec.Current_LEAK_AC = 2500 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;

            case 'C':
                //CNS   / Taiwan Market
#ifdef FUNC_REPLACE_CORMEX_WITH_VAC_FOR_CNS_MODEL
                Charger.CCID_Module_Type = CCID_MODULE_VAC;
#else
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
#endif
                Charger.alarm_spec.Current_LEAK_AC = 2500 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;

            case 'J':
                //JARI  / Japan Market
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
                Charger.alarm_spec.Current_LEAK_AC = 2500 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;

            case 'K':
                //KC    / Korea Market
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
                Charger.alarm_spec.Current_LEAK_AC = 1800 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;

            case 'B':
                //British / UK Market
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
                Charger.alarm_spec.Current_LEAK_AC = 1800 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;

            default:
                Charger.CCID_Module_Type = CCID_MODULE_CORMEX ;
                Charger.alarm_spec.Current_LEAK_AC = 1800 ; // unit 0.01mA
                Charger.OCP_Magnification = 110 ;
                break;
        }

#ifdef MODIFY_OCP_PROC_WITH_MODELNAME_IDX_3_EURO_SPEC
        Charger.m_bModelNameWithEuroSpecOCP = bModelNameWithEuroSpecOCP;
        XP("#Use EuropeanSpecOCP: %s\r\n", Charger.m_bModelNameWithEuroSpecOCP ? "True" : "False");
#endif

#ifdef FUNC_AUTO_MODIFY_CCID_MODULE
        XP("#Use CCID Module (ModelName: %s): %s\r\n", Charger.memory.EVSE_Config.data.item.ModelName, CCID_MODULE_TYPE_STR);
        if (Charger.m_bCCID_MustModify && Charger.m_CCID_ModuleTestOK != CCID_MODULE_UNKNOW)
        {
            Charger.CCID_Module_Type = Charger.m_CCID_ModuleTestOK;
            XP("#Use CCID Module (AutoModify): %s\r\n", CCID_MODULE_TYPE_STR);
        }

#endif

#ifdef FUNC_RS485_SLAVE
        Charger.m_bRS485SlaveForDCModel =
        (
            (Charger.memory.EVSE_Config.data.item.ModelName[0] == 'D') //response to DC Model
        ) ? 1 : 0;

        Charger.m_RS485SlaveAddr = (Charger.m_bRS485SlaveForDCModel ? PROTOCOL_ADDR_AC_MAINBOARD : PROTOCOL_ADDR);
#endif

#ifdef FUNC_FORCE_RUN_CSU_MODE_WITH_DC_MODELNAME
        Charger.m_bModelNameDC =
        (
            (Charger.memory.EVSE_Config.data.item.ModelName[0] == 'D') //response to DC Model
        ) ? 1 : 0;
        Charger.m_bModelNameDCReadOK = 1;
        XP("#ModelNameDC: %s\r\n", Charger.m_bModelNameDC ? "True" : "False");
        Update_McuCtrlMode();
#endif
#ifdef FUNC_CP_ADC_MODIFY
#ifdef NEW_CP_SPEC
        CpDetectModuleInitialize(Charger.memory.EVSE_Config.data.item.ModelName[3]);
        Charger.m_bCpDetectModuleInitOK = 1;
#endif //NEW_CP_SPEC
#endif //FUNC_CP_ADC_MODIFY

#ifdef FUNC_RULE_GB_202108
        Charger.m_bSafetyRegulationGB = (Charger.memory.EVSE_Config.data.item.ModelName[3] == 'G');
#endif

#ifdef FUNC_UPDATE_ROTARY_SWITCH_SETTING_AFTER_PARSE_MODELNAME
        getRotarySwitchSetting();
#endif
}


void HTK_ByteArray2HexStr(const u8* buf, const u16 BegIdx, const u16 len, char* OutStr, u16 nMaxBytesPerLine, HTK_BOOL bSpace)
{
	char sTmp[8] = { 0 };
	//char sTmp[8] = { 0 };
	strcpy(OutStr, "\0");
	for (u16 i = BegIdx; i < (BegIdx + len); i++)
	{
		sprintf(sTmp, bSpace ? "%02X " : "%02X", buf[i]);
		strcat(OutStr, sTmp);
		if ((i - BegIdx) % nMaxBytesPerLine == (nMaxBytesPerLine - 1))
        {
			strcat(OutStr, "\r\n");
        }
	}
}


void HTK_ByteArray2HexStr_XP(const char* Title, const u8* buf, const u16 BegIdx, const u16 len)
{
    //char OutStr[256] = { 0 };
    static char OutStr[1024 * 3 + 8] = { 0 };
    HTK_ByteArray2HexStr(buf, BegIdx, len, OutStr, 0, HTK_TRUE);
    XP("[%s] %s(%d)\r\n", (Title == NULL ? "" : Title), OutStr, len);
}


void HTK_ByteArray2HexStr_XT(const char* Title, const u8* buf, const u16 BegIdx, const u16 len)
{
    //char OutStr[256] = { 0 };
    static char OutStr[1024 * 3 + 8] = { 0 };
    HTK_ByteArray2HexStr(buf, BegIdx, len, OutStr, 0, HTK_TRUE);
    XT("[%s] %s(%d)\r\n", (Title == NULL ? "" : Title), OutStr, len);
}

#ifdef ENABLE_PRINT_IMCP_MSG
int CheckPrintImcpMsg(uint8_t MsgID)
{
#ifdef ENABLE_PRINT_IMCP_SPEC_MSG
    return
        (
//                MsgID == PROTOCOL_MESSAGE_CONFIG_PARAMETER
//            ||  MsgID == PROTOCOL_MESSAGE_QUERY_METER_IC_MEAS_PARAMETER
//            ||  MsgID == PROTOCOL_MESSAGE_QUERY_METER_IC_CALI_PARAMETER
//            ||  MsgID == PROTOCOL_MESSAGE_CONFIG_METER_IC_CALI_PARAMETER
                MsgID == PROTOCOL_MESSAGE_CONFIG_RELAY_OUTPUT
            ||  MsgID == PROTOCOL_MESSAGE_CONFIG_MAX_CURRENT_PWM_DUTY
            ||  MsgID == PROTOCOL_MESSAGE_CONFIG_LEGACY_REQUEST

        );
#else
    return true;
#endif //ENABLE_PRINT_IMCP_SPEC_MSG
}
#endif //ENABLE_PRINT_IMCP_MSG

#ifdef MODIFY_COLD_LOAD_PICKUP_DELAY
void ColdLoadPickup_Delay(const char* Description)
{
    //osDelay((rand()%175000)+5000);
    int r = rand();
    if (r < 0)
    {
        r = (-1) * r;
    }
    //uint32_t dt = (r % 175000) + 5000; //ms
    uint32_t dt = (r % (COLD_LOAD_PICKUP_DELAY_TIME_MAX_RANGE_SEC * 1000)) + 5000; //ms
    XP("ColdLoadPickup_Delay(ms) [%s]: %d\r\n", Description, dt);
    osDelay(dt);
}
#endif

#ifdef MODIFY_CP_TASK_CTRL_CP_PWM
uint16_t GetCpPwmDuty(uint16_t Curr)
{
    uint16_t rtn = (uint16_t)((Curr / 0.6) * 10);
    XP("#GetCpPwmDuty(%d) => %d\r\n", Curr, rtn);
    return rtn;
}
#endif

#ifdef HTK
HTK_BOOL HTK_IsInTime(u32 BegTick, u32 MaxTick)
{
    u32 EndTick = HAL_GetTick();
    u32 ElapseTick = (EndTick >= BegTick ? EndTick - BegTick : HTK_U32_MAX - BegTick + EndTick);
    return ElapseTick <= MaxTick ? HTK_TRUE : HTK_FALSE;
}

HTK_BOOL HTK_IsTimeout(u32 BegTick, u32 MaxTick)
{
    u32 EndTick = HAL_GetTick();
    u32 ElapseTick = (EndTick >= BegTick ? EndTick - BegTick : HTK_U32_MAX - BegTick + EndTick);
    return ElapseTick > MaxTick ? HTK_TRUE : HTK_FALSE;
}

void HTK_Timer_Reset(PHTK_Timer p)
{
    XP("#<Timer reset>\r\n\r\n");
    p->m_bStart = HTK_FALSE;
    p->m_bTimeout = HTK_FALSE;
    p->m_BegTick = 0;
    p->m_MaxTick = 0;
}

void HTK_Timer_Start(PHTK_Timer p, u32 MaxTick)
{
    XP("#<Timer start>\r\n\r\n");
    p->m_bStart = HTK_TRUE;
    p->m_BegTick = HAL_GetTick();
    p->m_MaxTick = MaxTick;
}

HTK_BOOL HTK_Timer_CheckTimeout(PHTK_Timer p)
{
//    return HTK_IsTimeout(p->m_BegTick, p->m_MaxTick);
    HTK_BOOL rtn = HTK_IsTimeout(p->m_BegTick, p->m_MaxTick);
    if (rtn == HTK_TRUE)
    {
        XP("#<Timer timeout>\r\n\r\n");
        p->m_bTimeout = HTK_TRUE;
    }
    return rtn;

}

uint8_t HTK_CheckSum_Calulate(uint8_t* pBeg, uint32_t len)
{
    if (pBeg != NULL)
    {
        uint8_t CheckSum = 0;
        for (uint32_t i = 0; i < len; i++)
        {
            CheckSum ^= *(pBeg + i);
        }
        return CheckSum;
    }
    else
    {
        return 0;
    }
}

HTK_BOOL HTK_CheckSum_Update(uint8_t* pBeg, uint32_t len, uint8_t* pCheckSum)
{
    if (pBeg != NULL && pCheckSum != NULL)
    {
        uint8_t CheckSum = HTK_CheckSum_Calulate(pBeg, len);
        *pCheckSum = CheckSum;
        return HTK_TRUE;
    }
    else
    {
        return HTK_FALSE;
    }

}

HTK_BOOL HTK_CheckSum_IsOK(uint8_t* pBeg, uint32_t len, uint8_t* pCheckSum)
{
    if (pBeg != NULL && pCheckSum != NULL)
    {
        uint8_t CheckSum = HTK_CheckSum_Calulate(pBeg, len);
        return (*pCheckSum == CheckSum) ? HTK_TRUE : HTK_FALSE;
    }
    else
    {
        return HTK_FALSE;
    }
}

static HTK_MallocHandle s_MallocHandle;

void HTK_Malloc_Init(void)
{
    memset(&s_MallocHandle, 0, sizeof(s_MallocHandle));
    //XP("HTK_Malloc_Init(): %d\r\n", HTK_Malloc_BlockTest(1024));
    XP("HTK_Malloc_Init(): %d\r\n", HTK_Malloc_BlockTest(8000));
}

void* HTK_Malloc(s32 size)
{
    void* p = malloc(size);
    if (p != NULL)
    {
        s_MallocHandle.m_Allocated += size;
        s_MallocHandle.m_Reserved -= size;
        memset(p, 0, size);
    }
    XP("HTK_Malloc(%d) %s\r\n", size, (p == NULL) ? "*** NG ***" : "OK");
    return p;
}

s32 HTK_Malloc_BlockTest(s32 size)
{
    int Total = 0;
    for (int i = 1;  ; i++)
    {
        void* p = HTK_Malloc(size);
        if (p == NULL)
        {
            break;
        }
        else
        {
            Total += size;
        }

    }
    s_MallocHandle.m_Total = Total;
    s_MallocHandle.m_Allocated = 0;
    s_MallocHandle.m_Reserved = Total;

    return Total;
}
#endif //HTK

#ifdef MODIFY_CPTASK_HEAD
void Proc_CpTaskHead(HTK_BOOL bCSU)
{
    if(Charger.Alarm_Code > 0)  // alarm occur
    {
        if(Charger.Mode != MODE_ALARM)
        {
#ifdef FUNC_BLOCK_CSU_CMD_SET_DUTY_WHEN_ALARM_CP_F_STATE
            Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF = HTK_TRUE;
#endif
            HAL_GPIO_WritePin(OUT_StateE_GPIO_Port, OUT_StateE_Pin, GPIO_PIN_SET);
            setChargerMode(MODE_ALARM);
            user_pwm_setvalue(PWM_CH_CP, 0);
            timerEnable(TIMER_IDX_STATE_E, 4000);
            Charger.isAlarmSetPWM = OFF ;

        }

        // CP E or F to X1
        if(timer[TIMER_IDX_STATE_E].isAlarm == ON)
        {
            HAL_GPIO_WritePin(OUT_StateE_GPIO_Port, OUT_StateE_Pin, GPIO_PIN_RESET);
            if ( Charger.isAlarmSetPWM == OFF )
            {
                Charger.isAlarmSetPWM = ON ;
                user_pwm_setvalue(PWM_CH_CP, PWM_DUTY_FULL);
            }
#ifdef FUNC_BLOCK_CSU_CMD_SET_DUTY_WHEN_ALARM_CP_F_STATE
            if (Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF)
            {
                Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF = HTK_FALSE;
            }
#endif
        }
    }
    else
    {
        if(Charger.Mode != MODE_ALARM)
        {
            //if (!bCSU) //only in AX code
            {
                HAL_GPIO_WritePin(OUT_StateE_GPIO_Port, OUT_StateE_Pin, GPIO_PIN_RESET); //CCS communication, so skip this line
            }

            timerDisable(TIMER_IDX_STATE_E);
        }

#ifdef FIX_OUTP_PWM_WHEN_ALARM_RECOVER_IN_4SEC
#ifdef FUNC_BLOCK_CSU_CMD_SET_DUTY_WHEN_ALARM_CP_F_STATE
        if (Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF)
        {
            Charger.m_bBlockCsuCpPwmDutyWhenAlarmCpF = HTK_FALSE;
        }
#endif
#endif
    }
}
#endif //MODIFY_CPTASK_HEAD

#ifdef FUNC_FORCE_RUN_CSU_MODE_WITH_DC_MODELNAME
void Update_McuCtrlMode(void)
{
    while (!Charger.m_bModelNameDCReadOK)
    {
        osDelay(100);
    }

#ifdef FUNC_EMPX10_CUSTOMIZE_RUN_CSU_MODE
    {
        Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_CSU;
        DEBUG_INFO("#MCU_CONTROL_MODE_CSU\r\n");
    }
#else
    if (HAL_GPIO_ReadPin(IN_ACT_REQ_GPIO_Port, IN_ACT_REQ_Pin) == GPIO_PIN_RESET ||
        Charger.m_bModelNameDC == 1)
    {
        Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_CSU;
        DEBUG_INFO("#MCU_CONTROL_MODE_CSU\r\n");
    }
    else
    {
        Charger.memory.EVSE_Config.data.item.MCU_Control_Mode = MCU_CONTROL_MODE_NO_CSU;
        DEBUG_INFO("#MCU_CONTROL_MODE_NO_CSU\r\n");

//        if (Charger.memory.EVSE_Config.data.item.AuthMode > AUTH_MODE_FREE)
//        {
//            Charger.memory.EVSE_Config.data.item.AuthMode = AUTH_MODE_FREE ;
//            DEBUG_INFO("#AuthMode set defualt AUTH_MODE_FREE \r\n");
//        }
//
//        if (Charger.memory.EVSE_Config.data.item.OfflinePolicy > RFID_USER_AUTH_NO_CHARGING)
//        {
//            Charger.memory.EVSE_Config.data.item.OfflinePolicy = RFID_USER_AUTH_FREE ;
//            DEBUG_INFO("#OfflinePolicy set defualt RFID_USER_AUTH_FREE \r\n");
//        }
    }
#endif //FUNC_EMPX10_CUSTOMIZE_RUN_CSU_MODE
}
#endif //FUNC_FORCE_RUN_CSU_MODE_WITH_DC_MODELNAME

#ifdef MODIFY_DC_RS485_UPGRADE_ISSUE

void RS485_TX_Enable(void)
{
    HAL_GPIO_WritePin(OUT_Meter_485_DE_GPIO_Port, OUT_Meter_485_DE_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(OUT_Meter_485_RE_GPIO_Port, OUT_Meter_485_RE_Pin, GPIO_PIN_SET);
    osDelay(1);
}

void RS485_TX_Disable(void)
{
    HAL_GPIO_WritePin(OUT_Meter_485_DE_GPIO_Port, OUT_Meter_485_DE_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(OUT_Meter_485_RE_GPIO_Port, OUT_Meter_485_RE_Pin, GPIO_PIN_RESET);

}

void Prefix_UartTX(uint8_t* TxBuf, uint8_t* RxBuf)
{
#ifdef FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
    if (RxBuf == UART_IAP_rx_buffer)
    {
        TxBuf[1] = RxBuf[2];
    }
    else
#endif
    if (RxBuf == UART_RS485_rx_buffer)
    {
        RS485_TX_Enable();

#ifdef FUNC_EMPX10_CUSTOMIZE_RS485_CLIENT_ADDRESS
        //TxBuf[1] = RxBuf[2]; //Charger.m_EMPX10_RS485_ClientAddr;
        TxBuf[1] = Charger.m_EMPX10_RS485_ClientAddr;
#else
        TxBuf[1] = Charger.m_RS485SlaveAddr; //Update Slave Address
#endif
    }
}

void Postfix_UartTX(uint8_t* TxBuf, uint8_t* RxBuf)
{
    if (RxBuf == UART_RS485_rx_buffer)
    {
        RS485_TX_Disable();
    }
}
#endif //MODIFY_DC_RS485_UPGRADE_ISSUE

/* USER CODE END Application */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
