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

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

#define ARRAY_SIZE(A)       (sizeof(A) / sizeof(A[0]))
#define PASS                1
#define FAIL                -1
#define YES                 1
#define NO                  0
#define TEN_MINUTES         600
#define ENV_TEMP_MIN        45
#define ENV_TEMP_MAX        50
#define DEFAULT_AC_INDEX    2
#define EQUAL               0
#define COLOR_MAX_LV        100
#define COLOR_MIN_LV        0

struct SysConfigAndInfo         *ShmSysConfigAndInfo;
struct StatusCodeData           *ShmStatusCodeData;
struct FanModuleData            *ShmFanModuleData;
struct RelayModuleData          *ShmRelayModuleData;
struct LedModuleData            *ShmLedModuleData;
struct CHAdeMOData              *ShmCHAdeMOData;
struct CcsData                  *ShmCcsData;
struct PsuData                  *ShmPsuData;

#define VIN_MAX_VOLTAGE_IEC     285 // 大於該值 : OVP
#define VIN_MIN_VOLTAGE_IEC     160 // 小於該值 : UVP
#define VIN_MAX_VOLTAGE_UL      315 // 大於該值 : OVP
#define VIN_MIN_VOLTAGE_UL      210 // 小於該值 : UVP

#define VIN_DROP_VOLTAGE    150 // 小於該值 : ac drop

#define VOUT_MAX_VOLTAGE    995
#define VOUT_MIN_VOLTAGE    150
#define IOUT_MAX_CURRENT    50

#define MAX_FAN_SPEED       13500
#define MIN_FAN_SPEED       3000
#define NORMAL_FAN_SPEED    7000

// GFD Status
#define GFD_IDLE            0
#define GFD_CABLECHK        1
#define GFD_PRECHARGE       2
#define GFD_CHARGING        3

// 最小切換 Relay 電壓
#define SELF_TO_CHANGE_RELAY_STATUS         600
// 透過電壓確認 Relay 是否搭上的依據電壓
#define CHECK_RELAY_STATUS                  300
#define CHECK_RELAY_STATUS_GAP              100
// 安全在停止充電程序中斷開 Relay 的電流
#define SEFETY_SWITCH_RELAY_CUR             20
// 確認 Relay Welding 電壓
#define RELAY_WELDING_DET                   300

byte gunCount;
byte acgunCount;
// 槍資訊
struct ChargingInfoData *_chargingData[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];
struct ChargingInfoData *ac_chargingInfo[AC_QUANTITY];

bool _isOutputNoneMatch[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];
struct timeval _checkOutputNoneMatchTimer[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];

bool _isRelayWelding[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];
struct timeval _checkRelayWeldingTimer[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY];

bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData);

int Uart5Fd;
char *relayRs485PortName = "/dev/ttyS5";
unsigned short fanSpeedSmoothValue = 500;

bool isStopChargingCount = false;
struct timeval _close_ac_contactor;

struct timeval _priority_time;
struct timeval _led_priority_time;

struct timeval  _ac_charging_comp;
struct timeval  _ac_preparing;
struct timeb    _ac_startChargingTime;
struct timeb    _ac_endChargingTime;

unsigned short _setFanSpeed = 0;
byte _checkLedChanged = 3;

Ver ver;
PresentInputVoltage inputVoltage;
PresentOutputVoltage outputVoltage;
FanSpeed fanSpeed;
Temperature temperature;
AuxPower auxPower;
Gfd gfd_adc;
Gfd_config gfd_config;
Gpio_in gpio_in;
Gpio_out gpio_out;
Relay outputRelay;
Relay regRelay;
Rtc rtc;
Led_Color cur_led_color;
Led_Color led_color;

Ac_Status acStatus;
Ac_Led_Status ledStatus;
Ac_Alarm_code acAlarmCode;
Ac_Charging_energy acChargingEnergy;
Ac_Charging_current acChargingCurrent;

#define AC_OVP                      1
#define AC_UVP                      2
#define AC_OCP                      4
#define AC_OTP                      8
#define AC_GMI_FAULT                16
#define AC_CP_ERROR                 32
#define AC_AC_LEAKAGE               64
#define AC_DC_LEAKAGE               128
#define AC_SYSTEM_SELFTEST_FAULT    256
#define AC_HANDSHAKE_TIMEOUT        512
#define AC_EMC_STOP                 1024
#define AC_RELAY_WELDING            2048
#define AC_GF_MODULE_FAULT          4096
#define AC_SHUTTER_FAULT            8192
#define AC_LOCKER_FAULT             16384
#define AC_POWER_DROP               32768
#define AC_CIRCUIT_SHORT            65536
#define AC_ROTARY_SWITCH_FAULT      131072
#define AC_RELAY_DRIVE_FAULT        262144

int _alarm_code[] = {AC_OVP, AC_UVP, AC_OCP, AC_OTP, AC_GMI_FAULT, AC_CP_ERROR, AC_AC_LEAKAGE
        , AC_DC_LEAKAGE, AC_SYSTEM_SELFTEST_FAULT, AC_HANDSHAKE_TIMEOUT, AC_EMC_STOP, AC_RELAY_WELDING
        , AC_GF_MODULE_FAULT, AC_SHUTTER_FAULT, AC_LOCKER_FAULT, AC_POWER_DROP, AC_CIRCUIT_SHORT
        , AC_ROTARY_SWITCH_FAULT, AC_RELAY_DRIVE_FAULT};

void PRINTF_FUNC(char *string, ...);

unsigned long GetTimeoutValue(struct timeval _sour_time);

#define DEBUG_INFO(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_WARN(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_ERROR(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args)

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

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

int StoreLogMsg(const char *fmt, ...)
{
    char Buf[4096+256];
    char buffer[4096];
    va_list args;
    struct timeb  SeqEndTime;
    struct tm *tm;

    va_start(args, fmt);
    int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    memset(Buf,0,sizeof(Buf));
    ftime(&SeqEndTime);
    SeqEndTime.time = time(NULL);
    tm=localtime(&SeqEndTime.time);

    if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES)
    {
        sprintf(Buf,"%02d:%02d:%02d.%03d - %s",
                tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm, buffer);
        printf("%s \n", Buf);
    }
    else
    {
        sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d.%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog",
                tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm,
                buffer,
                tm->tm_year+1900,tm->tm_mon+1);
        system(Buf);
    }

    return rc;
}

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

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

unsigned short MaxValue(unsigned short value1, unsigned short value2)
{
    return value1 >= value2 ? value1 : value2;
}

void PRINTF_FUNC(char *string, ...)
{
    va_list args;
    char buffer[4096];
    va_start(args, string);
    vsnprintf(buffer, sizeof(buffer), string, args);
    va_end(args);

    DEBUG_INFO("%s \n", buffer);
}

//==========================================
// Communication Function
//==========================================
void GetFwAndHwVersion_Fan()
{
    if(Query_FW_Ver(Uart5Fd, Addr.Fan, &ver) == PASS)
    {
        // FanModuleData
        strcpy((char *) ShmFanModuleData->version, ver.Version_FW);
        // SystemInfo
        strcpy((char *) ShmSysConfigAndInfo->SysInfo.FanModuleFwRev, ver.Version_FW);
        //PRINTF_FUNC("GetFwAndHwVersion_Fan s1 = %s \n", ver.Version_FW);
    }

    if (Query_HW_Ver(Uart5Fd, Addr.Fan, &ver) == PASS)
    {
        // SystemInfo
        strcpy((char *) ShmSysConfigAndInfo->SysInfo.FanModuleHwRev, ver.Version_FW);
        //PRINTF_FUNC("GetFwAndHwVersion_Fan s2 = %s \n", ver.Version_HW);
    }
}

void GetFwAndHwVersion_Relay()
{
    if (Query_FW_Ver(Uart5Fd, Addr.Relay, &ver) == PASS)
    {
        // FanModuleData
        strcpy((char *) ShmRelayModuleData->version, ver.Version_FW);
        // SystemInfo
        strcpy((char *) ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev, ver.Version_FW);
        //PRINTF_FUNC("GetFwAndHwVersion_Relay s1 = %s \n", ver.Version_FW);
    }

    if (Query_HW_Ver(Uart5Fd, Addr.Relay, &ver) == PASS)
    {
        // SystemInfo
        strcpy((char *) ShmSysConfigAndInfo->SysInfo.RelayModuleHwRev, ver.Version_FW);
        //PRINTF_FUNC("GetFwAndHwVersion_Relay s2 = %s \n", ver.Version_HW);
    }
}

void GetFwAndHwVersion_Led()
{
    if (Query_FW_Ver(Uart5Fd, Addr.Led, &ver) == PASS)
    {
        // LedModuleData
        strcpy((char *) ShmLedModuleData->version, ver.Version_FW);
        // SystemInfo
        strcpy((char *) ShmSysConfigAndInfo->SysInfo.LedModuleFwRev, ver.Version_FW);
        PRINTF_FUNC("GetFwAndHwVersion_Led s1 = %s \n", ver.Version_FW);
        ShmLedModuleData->SelfTest_Comp = YES;
    }
    else
    {
        //PRINTF_FUNC("GetFwAndHwVersion_Led fail \n");
    }
}

void GetFwVersion_AC()
{
    if (Query_FW_Ver(Uart5Fd, Addr.AcPlug, &ver) == PASS)
    {
        ac_chargingInfo[0]->SelfTest_Comp = YES;
        strcpy((char *) ac_chargingInfo[0]->version, ver.Version_FW);
    }
}

void SetRtcData_Relay()
{
    struct timeb csuTime;
    struct tm *tmCSU;

    ftime(&csuTime);
    tmCSU = localtime(&csuTime.time);
    //  PRINTF_FUNC("Time : %04d-%02d-%02d %02d:%02d:%02d \n", tmCSU->tm_year + 1900,
    //          tmCSU->tm_mon + 1, tmCSU->tm_mday, tmCSU->tm_hour, tmCSU->tm_min,
    //          tmCSU->tm_sec);

    rtc.RtcData[0] = '0' + (tmCSU->tm_year + 1900) / 1000 % 10;
    rtc.RtcData[1] = '0' + (tmCSU->tm_year + 1900) / 100 % 10;
    rtc.RtcData[2] = '0' + (tmCSU->tm_year + 1900) / 10 % 10;
    rtc.RtcData[3] = '0' + (tmCSU->tm_year + 1900) / 1 % 10;

    rtc.RtcData[4] = '0' + (tmCSU->tm_mon + 1) / 10 % 10;
    rtc.RtcData[5] = '0' + (tmCSU->tm_mon + 1) / 1 % 10;

    rtc.RtcData[6] = '0' + (tmCSU->tm_mday) / 10 % 10;
    rtc.RtcData[7] = '0' + (tmCSU->tm_mday) / 1 % 10;

    rtc.RtcData[8] = '0' + (tmCSU->tm_hour) / 10 % 10;
    rtc.RtcData[9] = '0' + (tmCSU->tm_hour) / 1 % 10;

    rtc.RtcData[10] = '0' + (tmCSU->tm_min) / 10 % 10;
    rtc.RtcData[11] = '0' + (tmCSU->tm_min) / 1 % 10;

    rtc.RtcData[12] = '0' + (tmCSU->tm_sec) / 10 % 10;
    rtc.RtcData[13] = '0' + (tmCSU->tm_sec) / 1 % 10;

    if (Config_Rtc_Data(Uart5Fd, Addr.Relay, &rtc) == PASS)
    {
        //PRINTF_FUNC("SetRtc (RB) sucessfully. \n");
    }
}

void SetRtcData_Fan()
{
    struct timeb csuTime;
    struct tm *tmCSU;

    ftime(&csuTime);
    tmCSU = localtime(&csuTime.time);
    //  PRINTF_FUNC("Time : %04d-%02d-%02d %02d:%02d:%02d \n", tmCSU->tm_year + 1900,
    //          tmCSU->tm_mon + 1, tmCSU->tm_mday, tmCSU->tm_hour, tmCSU->tm_min,
    //          tmCSU->tm_sec);

    rtc.RtcData[0] = '0' + (tmCSU->tm_year + 1900) / 1000 % 10;
    rtc.RtcData[1] = '0' + (tmCSU->tm_year + 1900) / 100 % 10;
    rtc.RtcData[2] = '0' + (tmCSU->tm_year + 1900) / 10 % 10;
    rtc.RtcData[3] = '0' + (tmCSU->tm_year + 1900) / 1 % 10;

    rtc.RtcData[4] = '0' + (tmCSU->tm_mon + 1) / 10 % 10;
    rtc.RtcData[5] = '0' + (tmCSU->tm_mon + 1) / 1 % 10;

    rtc.RtcData[6] = '0' + (tmCSU->tm_mday) / 10 % 10;
    rtc.RtcData[7] = '0' + (tmCSU->tm_mday) / 1 % 10;

    rtc.RtcData[8] = '0' + (tmCSU->tm_hour) / 10 % 10;
    rtc.RtcData[9] = '0' + (tmCSU->tm_hour) / 1 % 10;

    rtc.RtcData[10] = '0' + (tmCSU->tm_min) / 10 % 10;
    rtc.RtcData[11] = '0' + (tmCSU->tm_min) / 1 % 10;

    rtc.RtcData[12] = '0' + (tmCSU->tm_sec) / 10 % 10;
    rtc.RtcData[13] = '0' + (tmCSU->tm_sec) / 1 % 10;

    if (Config_Rtc_Data(Uart5Fd, Addr.Fan, &rtc) == PASS)
    {
        //PRINTF_FUNC("SetRtc (FB) sucessfully. \n");
    }
}

void SetModelName_Fan()
{
    if (Config_Model_Name(Uart5Fd, Addr.Fan, ShmSysConfigAndInfo->SysConfig.ModelName) == PASS)
    {
        PRINTF_FUNC("Set Model name PASS = %s \n", ShmSysConfigAndInfo->SysConfig.ModelName);
    }
}

// AC 三相輸入電壓
void GetPresentInputVol()
{
    if (Query_Present_InputVoltage(Uart5Fd, Addr.Relay, &inputVoltage) == PASS)
    {
        // resolution : 0.1
        ShmSysConfigAndInfo->SysInfo.InputVoltageR = ShmRelayModuleData->InputL1Volt = inputVoltage.L1N_L12;
        ShmSysConfigAndInfo->SysInfo.InputVoltageS = ShmRelayModuleData->InputL2Volt = inputVoltage.L2N_L23;
        ShmSysConfigAndInfo->SysInfo.InputVoltageT = ShmRelayModuleData->InputL3Volt = inputVoltage.L3N_L31;

        //********************************************************************************************************//
        // Vin (UVP)
        if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC)
        {
            if (inputVoltage.L1N_L12 < VIN_MIN_VOLTAGE_IEC)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO;

            if (inputVoltage.L2N_L23 < VIN_MIN_VOLTAGE_IEC)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO;

            if (inputVoltage.L3N_L31 < VIN_MIN_VOLTAGE_IEC)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO;
        }
        else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL)
        {
            if (inputVoltage.L1N_L12 < VIN_MIN_VOLTAGE_UL)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO;

            if (inputVoltage.L2N_L23 < VIN_MIN_VOLTAGE_UL)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO;

            if (inputVoltage.L3N_L31 < VIN_MIN_VOLTAGE_UL)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO;
        }
        //********************************************************************************************************//
        // Vin (OVP)
        if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC)
        {
            if (inputVoltage.L1N_L12 > VIN_MAX_VOLTAGE_IEC)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO;

            if (inputVoltage.L2N_L23 > VIN_MAX_VOLTAGE_IEC)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO;

            if (inputVoltage.L3N_L31 > VIN_MAX_VOLTAGE_IEC)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO;
        }
        else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL)
        {
            if (inputVoltage.L1N_L12 > VIN_MAX_VOLTAGE_UL)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO;

            if (inputVoltage.L2N_L23 > VIN_MAX_VOLTAGE_UL)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO;

            if (inputVoltage.L3N_L31 > VIN_MAX_VOLTAGE_UL)
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = YES;
            else
                ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO;
        }
    }
}

// 左右槍的 Relay 前後的輸出電壓
void GetPersentOutputVol()
{
    if (Query_Present_OutputVoltage(Uart5Fd, Addr.Relay, &outputVoltage) == PASS)
    {
//      PRINTF_FUNC("Conn1 fuse 1 = %f \n", outputVoltage.behindFuse_Voltage_C1);
//      PRINTF_FUNC("Conn1 relay 1 = %f \n", outputVoltage.behindRelay_Voltage_C1);
//      PRINTF_FUNC("Conn2 fuse 2 = %f \n", outputVoltage.behindFuse_Voltage_C2);
//      PRINTF_FUNC("Conn2 relay 2 = %f \n", outputVoltage.behindRelay_Voltage_C2);

        //PRINTF_FUNC("outputVoltage.behindFuse_Voltage_C1 = %f \n", outputVoltage.behindFuse_Voltage_C1);
        //PRINTF_FUNC("outputVoltage.behindFuse_Voltage_C2 = %f \n", outputVoltage.behindFuse_Voltage_C2);

        ShmRelayModuleData->Gun1FuseOutputVolt = outputVoltage.behindFuse_Voltage_C1;
        ShmRelayModuleData->Gun1RelayOutputVolt = outputVoltage.behindRelay_Voltage_C1;
        ShmRelayModuleData->Gun2FuseOutputVolt = outputVoltage.behindFuse_Voltage_C2;
        ShmRelayModuleData->Gun2RelayOutputVolt = outputVoltage.behindRelay_Voltage_C2;

        for (int index = 0; index < gunCount; index++)
        {
            if (index == 0)
            {
                if (_chargingData[index]->Evboard_id == 0x01)
                {
                    _chargingData[index]->FuseChargingVoltage = ShmRelayModuleData->Gun1FuseOutputVolt;
                    _chargingData[index]->FireChargingVoltage = ShmRelayModuleData->Gun1RelayOutputVolt;
                }
                else if (_chargingData[index]->Evboard_id == 0x02)
                {
                    _chargingData[index]->FuseChargingVoltage = ShmRelayModuleData->Gun2FuseOutputVolt;
                    _chargingData[index]->FireChargingVoltage = ShmRelayModuleData->Gun2RelayOutputVolt;
                }
            }
            else if (index == 1)
            {
                _chargingData[index]->FuseChargingVoltage = ShmRelayModuleData->Gun2FuseOutputVolt;
                _chargingData[index]->FireChargingVoltage = ShmRelayModuleData->Gun2RelayOutputVolt;
            }

            //unsigned short Ovp = 0;
            //unsigned short Ocp = 0;
            //Ovp = MIN [VOUT_MAX_VOLTAGE, EV_BATTERY_VOLTAGE]  // 最大輸出電壓與電池電壓最大值
            //Ocp = MIN [IOUT_MAX_CURRENT, EV_CURRENT_REQ]      // 最大輸出電流與需求電流最小值
            if (_chargingData[index]->Type == _Type_Chademo)
            {
                //Ovp = MaxValue(_chargingData[index]->MaximumChargingVoltage, _chargingData[index]->EvBatteryMaxVoltage);
                //Ocp = MaxValue(_chargingData[index]->PresentChargingCurrent, ShmCHAdeMOData->ev[_chargingData[index]->type_index].ChargingCurrentRequest);
            }
            else if (_chargingData[index]->Type == _Type_CCS_2)
            {

            }
        }
    }
}

// 風扇速度
void GetFanSpeed()
{
    //PRINTF_FUNC("Get fan board speed \n");
    if (Query_Fan_Speed(Uart5Fd, Addr.Fan, &fanSpeed) == PASS)
    {
        ShmFanModuleData->PresentFan1Speed = fanSpeed.speed[0];
        ShmFanModuleData->PresentFan2Speed = fanSpeed.speed[1];
        ShmFanModuleData->PresentFan3Speed = fanSpeed.speed[2];
        ShmFanModuleData->PresentFan4Speed = fanSpeed.speed[3];
//      PRINTF_FUNC("SystemFanRotaSpeed_1 = %d \n", fanSpeed.speed[0]);
//      PRINTF_FUNC("SystemFanRotaSpeed_2 = %d \n", fanSpeed.speed[1]);
//      PRINTF_FUNC("SystemFanRotaSpeed_3 = %d \n", fanSpeed.speed[2]);
//      PRINTF_FUNC("SystemFanRotaSpeed_4 = %d \n", fanSpeed.speed[3]);
        // Config_Fan_Speed(Uart5Fd, Addr.Fan, &fanSpeed[0]);
        //SysInfoData (SystemFanRotaSpeed)
    }
}

// 讀取 Relay 狀態
void GetRelayOutputStatus()
{
    if (Query_Relay_Output(Uart5Fd, Addr.Relay, &regRelay) == PASS)
    {
        regRelay.relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;
    }
}

// 確認 K1 K2 relay 的狀態
void CheckK1K2RelayOutput(byte index)
{
    if (index == 0)
    {
        if (_chargingData[index]->Evboard_id == 0x01)
        {
            if (regRelay.relay_event.bits.Gun1_N == YES && regRelay.relay_event.bits.Gun1_P == YES)
                _chargingData[index]->RelayK1K2Status = YES;
            else
                _chargingData[index]->RelayK1K2Status = NO;

            if(_chargingData[index]->Type == _Type_CCS_2)
            {
                if (gunCount == 1)
                {
                if (regRelay.relay_event.bits.Gun1_N == YES && regRelay.relay_event.bits.CCS_Precharge == YES)
                    _chargingData[index]->RelayKPK2Status = YES;
                else
                    _chargingData[index]->RelayKPK2Status = NO;
            }
                else
                {
                    if (_chargingData[index]->SystemStatus == S_CCS_PRECHARGE_ST0)
                        _chargingData[index]->RelayKPK2Status = YES;
                    else
                        _chargingData[index]->RelayKPK2Status = NO;
                }
            }
        }
        else if (_chargingData[index]->Evboard_id == 0x02)
        {
            if (regRelay.relay_event.bits.Gun2_N == YES && regRelay.relay_event.bits.Gun2_P == YES)
                _chargingData[index]->RelayK1K2Status = YES;
            else
                _chargingData[index]->RelayK1K2Status = NO;

            if(_chargingData[index]->Type == _Type_CCS_2)
            {
                if (regRelay.relay_event.bits.Gun2_N == YES && regRelay.relay_event.bits.CCS_Precharge == YES)
                    _chargingData[index]->RelayKPK2Status = YES;
                else
                    _chargingData[index]->RelayKPK2Status = NO;
            }
        }
    }
    else if (index == 1)
    {
        if (regRelay.relay_event.bits.Gun2_N == YES && regRelay.relay_event.bits.Gun2_P == YES)
            _chargingData[index]->RelayK1K2Status = YES;
        else
            _chargingData[index]->RelayK1K2Status = NO;

        if(_chargingData[index]->Type == _Type_CCS_2)
        {
            if (regRelay.relay_event.bits.Gun2_N == YES && regRelay.relay_event.bits.CCS_Precharge == YES)
                _chargingData[index]->RelayKPK2Status = YES;
            else
                _chargingData[index]->RelayKPK2Status = NO;
        }
    }

    if (regRelay.relay_event.bits.Gun1_Parallel_N == YES && regRelay.relay_event.bits.Gun1_Parallel_P == YES)
        ShmSysConfigAndInfo->SysInfo.BridgeRelayStatus = YES;
    else
        ShmSysConfigAndInfo->SysInfo.BridgeRelayStatus = NO;

//  PRINTF_FUNC("Check Relay Output. index = %d, RelayKPK2Status = %d, BridgeRelayStatus = %d \n",
//          index, _chargingData[index]->RelayKPK2Status, ShmSysConfigAndInfo->SysInfo.BridgeRelayStatus);
}

void GetGfdAdc()
{
    // define : 每 0.2 ~ 1 秒一次
    // occur : <= 75k 歐姆 @ 150 - 750 Vdc
    // warning : >= 100 歐姆 && <= 500 歐姆 @ 150-750 Vdc
    if (Query_Gfd_Adc(Uart5Fd, Addr.Relay, &gfd_adc) == PASS)
    {
        for (int i = 0; i < gunCount; i++)
        {
            if (_chargingData[i]->Type == 0x09 && !ShmSysConfigAndInfo->SysConfig.AlwaysGfdFlag)
            {
                if ((_chargingData[i]->PresentChargingVoltage * 10) >= VOUT_MIN_VOLTAGE)
                    _chargingData[i]->GroundFaultStatus = GFD_PASS;
                continue;
            }

            if (i == 0)
            {
                _chargingData[i]->GroundFaultStatus = gfd_adc.result_conn1;
                if (_chargingData[i]->GroundFaultStatus == GFD_FAIL)
                {
                    PRINTF_FUNC("GFD Fail. index = %d, Step = %d, R = %d, Vol = %d \n",
                            i, gfd_adc.rb_step_1, gfd_adc.Resister_conn1, gfd_adc.voltage_conn1);
                }
                else if (_chargingData[i]->GroundFaultStatus == GFD_WARNING)
                {
                  PRINTF_FUNC("GFD Warning. index = %d, R = %d, Vol = %d \n",
                      i, gfd_adc.Resister_conn1, gfd_adc.voltage_conn1);
                }
            }
            else if (i == 1)
            {
                _chargingData[i]->GroundFaultStatus = gfd_adc.result_conn2;
                if (_chargingData[i]->GroundFaultStatus == GFD_FAIL)
                {
                    PRINTF_FUNC("GFD Fail. index = %d, Step = %d, R = %d, Vol = %d \n",
                            i, gfd_adc.rb_step_2, gfd_adc.Resister_conn2, gfd_adc.voltage_conn2);
                }
                else if (_chargingData[i]->GroundFaultStatus == GFD_WARNING)
                {
                  PRINTF_FUNC("GFD Warning. index = %d, R = %d, Vol = %d \n",
                      i, gfd_adc.Resister_conn2, gfd_adc.voltage_conn2);
                }
            }
        }
    }
}

void GetGpioInput()
{
    if (Query_Gpio_Input(Uart5Fd, Addr.Aux, &gpio_in) == PASS)
    {
        // AC Contactor Status
        if (gpio_in.AC_MainBreaker == 1)
        {
            // AC Main Breaker ON
            PRINTF_FUNC("RB AC Main Breaker. \n");
        }

        if (gpio_in.SPD == 1)
        {
            // SPD (雷擊保護) ON
            PRINTF_FUNC("RB SPD. \n");
        }

        if (gpio_in.Door_Open == 1)
        {
            // Door Open
            PRINTF_FUNC("RB Door Open. \n");
        }

        if (gpio_in.GFD[0] == 1)
        {
            // GFD_1 Trigger
        }

        if (gpio_in.GFD[1] == 1)
        {
            // GFD_2 Trigger
        }

        if (gpio_in.AC_Drop == 1)
        {
            // AC Drop
            PRINTF_FUNC("RB AC Drop. \n");
        }

        if (gpio_in.Emergency_IO == 1)
        {
            // Emergency IO ON
            PRINTF_FUNC("RB Emergency IO ON. \n");
        }

        if (gpio_in.Button_Emergency_Press == 1)
        {
            // Emergency button Press
        }

        if (gpio_in.Button_On_Press == 1)
        {
            // On button Press
        }

        if (gpio_in.Button_Off_Press == 1)
        {
            // Off button Press
        }

        if (gpio_in.Key_1_Press == 1)
        {
            // key 1 press
        }

        if (gpio_in.Key_2_Press == 1)
        {
            // key 2 press
        }

        if (gpio_in.Key_3_Press == 1)
        {
            // key 3 press
        }

        if (gpio_in.Key_4_Press == 1)
        {
            // key 4 press
        }
    }
}

// 5V 12V 24V 48V
void GetAuxPower()
{
    if (Query_Aux_PowerVoltage(Uart5Fd, Addr.Fan, &auxPower) == PASS)
    {
        ShmSysConfigAndInfo->SysInfo.AuxPower48V = auxPower.voltage[0];
        ShmSysConfigAndInfo->SysInfo.AuxPower24V = auxPower.voltage[1];
        //ShmSysConfigAndInfo->SysInfo.AuxPower12V = auxPower.voltage[4];
        //ShmSysConfigAndInfo->SysInfo.AuxPower5V = auxPower.voltage[6];
        // aux power voltage
        //PRINTF_FUNC("aux1 = %x, \n", auxPower.voltage[0]);
        //PRINTF_FUNC("aux2 = %x, \n", auxPower.voltage[1]);
    }
}

void SetFanModuleSpeed()
{
    // 調整風扇速度要漸進式 : 500 rpm/p
    FanSpeed _fanSpeed;

    _setFanSpeed += fanSpeedSmoothValue;

    if (_setFanSpeed >= ShmFanModuleData->SetFan1Speed)
        _setFanSpeed = ShmFanModuleData->SetFan1Speed;
    {
        _fanSpeed.speed[0] = _setFanSpeed;
    }

    _fanSpeed.speed[1] = _setFanSpeed;
    _fanSpeed.speed[2] = _setFanSpeed;
    _fanSpeed.speed[3] = _setFanSpeed;
    if (Config_Fan_Speed(Uart5Fd, Addr.Fan, &_fanSpeed) == PASS)
    {
        //PRINTF_FUNC("successfully Fan\n");
    }
}

//==========================================
// Common Function
//==========================================
void SetK1K2RelayStatus(byte index)
{
    if (_chargingData[index]->SystemStatus < S_PREPARING_FOR_EVSE)
    {
        if (_chargingData[index]->Evboard_id == 0x01)
        {
            if(regRelay.relay_event.bits.Gun1_P == YES)
                outputRelay.relay_event.bits.Gun1_P = NO;
            else if (regRelay.relay_event.bits.Gun1_N == YES)
                outputRelay.relay_event.bits.Gun1_N = NO;

            if (gunCount == 1 && _chargingData[index]->Type == _Type_CCS_2)
            {
                if(regRelay.relay_event.bits.CCS_Precharge == YES)
                    outputRelay.relay_event.bits.CCS_Precharge = NO;
            }
        }
        else if (_chargingData[index]->Evboard_id == 0x02)
        {
            if(regRelay.relay_event.bits.Gun2_P == YES)
                outputRelay.relay_event.bits.Gun2_P = NO;
            else if (regRelay.relay_event.bits.Gun2_N == YES)
                outputRelay.relay_event.bits.Gun2_N = NO;

            if (_chargingData[index]->Type == _Type_CCS_2)
            {
                if(regRelay.relay_event.bits.CCS_Precharge == YES)
                    outputRelay.relay_event.bits.CCS_Precharge = NO;
            }
        }
    }
    else if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE &&
            _chargingData[index]->SystemStatus <= S_CHARGING))
    {
        if (_chargingData[index]->RelayWeldingCheck == YES)
        {
            if (_chargingData[index]->Evboard_id == 0x01)
            {
                if(regRelay.relay_event.bits.Gun1_N == NO)
                    outputRelay.relay_event.bits.Gun1_N = YES;
                else if (regRelay.relay_event.bits.Gun1_P == NO)
                    outputRelay.relay_event.bits.Gun1_P = YES;
            }
            else if (_chargingData[index]->Evboard_id == 0x02)
            {
                if(regRelay.relay_event.bits.Gun2_N == NO)
                    outputRelay.relay_event.bits.Gun2_N = YES;
                else if (regRelay.relay_event.bits.Gun2_P == NO)
                    outputRelay.relay_event.bits.Gun2_P = YES;
            }
        }
    }
    else if ((_chargingData[index]->SystemStatus >= S_TERMINATING &&
            _chargingData[index]->SystemStatus <= S_COMPLETE))
    {
        if ((_chargingData[index]->PresentChargingCurrent * 10) <= SEFETY_SWITCH_RELAY_CUR)
        {
            if (_chargingData[index]->Evboard_id == 0x01)
            {
                if(regRelay.relay_event.bits.Gun1_P == YES)
                    outputRelay.relay_event.bits.Gun1_P = NO;
                else if (regRelay.relay_event.bits.Gun1_N == YES)
                    outputRelay.relay_event.bits.Gun1_N = NO;
            }
            else if (_chargingData[index]->Evboard_id == 0x02)
            {
                if(regRelay.relay_event.bits.Gun2_P == YES)
                    outputRelay.relay_event.bits.Gun2_P = NO;
                else if (regRelay.relay_event.bits.Gun2_N == YES)
                    outputRelay.relay_event.bits.Gun2_N = NO;
            }
        }
    }
    else if (_chargingData[index]->SystemStatus == S_CCS_PRECHARGE_ST0)
    {
        if (_chargingData[index]->Evboard_id == 0x01)
        {
            if (_chargingData[index]->Type == _Type_CCS_2)
            {
                if (gunCount == 1)
                {
                    if (regRelay.relay_event.bits.CCS_Precharge == NO)
                        outputRelay.relay_event.bits.CCS_Precharge = YES;
                    else if (regRelay.relay_event.bits.CCS_Precharge == YES)
                        outputRelay.relay_event.bits.Gun1_P = NO;
                }
            }
        }
        else if (_chargingData[index]->Evboard_id == 0x02)
        {
            if (_chargingData[index]->Type == _Type_CCS_2)
            {
                if (regRelay.relay_event.bits.CCS_Precharge == NO)
                    outputRelay.relay_event.bits.CCS_Precharge = YES;
                else if (regRelay.relay_event.bits.CCS_Precharge == YES)
                    outputRelay.relay_event.bits.Gun2_P = NO;
            }
        }
    }
    else if (_chargingData[index]->SystemStatus == S_CCS_PRECHARGE_ST1)
    {
        if (_chargingData[index]->Evboard_id == 0x01)
        {
            if (_chargingData[index]->Type == _Type_CCS_2)
            {
                if (gunCount == 1)
                {
                    if (regRelay.relay_event.bits.Gun1_P == NO)
                        outputRelay.relay_event.bits.Gun1_P = YES;
                    else if(regRelay.relay_event.bits.Gun1_P == YES)
                        outputRelay.relay_event.bits.CCS_Precharge = NO;
                }
            }
        }
        else if (_chargingData[index]->Evboard_id == 0x02)
        {
            if (_chargingData[index]->Type == _Type_CCS_2)
            {
                if (regRelay.relay_event.bits.Gun2_P == NO)
                    outputRelay.relay_event.bits.Gun2_P = YES;
                else if(regRelay.relay_event.bits.Gun2_P == YES)
                    outputRelay.relay_event.bits.CCS_Precharge = NO;
            }
        }
    }
}

void CheckAcInputOvpStatus(byte index)
{
    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP == YES ||
        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP == YES ||
        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP == YES)
    {
        _chargingData[index]->StopChargeFlag = YES;
    }
}

void CheckPhaseLossStatus(byte index)
{
    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP == YES ||
        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP == YES ||
        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP == YES)
    {
        _chargingData[index]->StopChargeFlag = YES;
    }
}

void SetParalleRelayStatus()
{
    if (gunCount >= 2 && ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == NO)
    {
        if (_chargingData[0]->SystemStatus == S_BOOTING || _chargingData[1]->SystemStatus == S_BOOTING ||
            (_chargingData[0]->SystemStatus == S_IDLE && _chargingData[1]->SystemStatus == S_IDLE))
        {
            // 初始化~ 不搭橋接
            if (regRelay.relay_event.bits.Gun1_Parallel_P == YES)
                outputRelay.relay_event.bits.Gun1_Parallel_P = NO;
            else if (regRelay.relay_event.bits.Gun1_Parallel_N == YES)
                outputRelay.relay_event.bits.Gun1_Parallel_N = NO;
        }
        else
        {
            if (_chargingData[0]->IsReadyToCharging == YES ||
                _chargingData[1]->IsReadyToCharging == YES)
            {
                // ************需考慮在切換中 - 切開 relay 與搭回 relay 的時機點************
                if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_MAX)
                {
                    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_RELAY_M_TO_A)
                    {
                        // 最大充 - 搭上橋接
                        if (regRelay.relay_event.bits.Gun1_Parallel_N == NO)
                            outputRelay.relay_event.bits.Gun1_Parallel_N = YES;
                        else if (regRelay.relay_event.bits.Gun1_Parallel_P == NO)
                            outputRelay.relay_event.bits.Gun1_Parallel_P = YES;
                    }
                    else
                    {
                        // 平均充 - 不搭
                        if (regRelay.relay_event.bits.Gun1_Parallel_P == YES)
                            outputRelay.relay_event.bits.Gun1_Parallel_P = NO;
                        else if (regRelay.relay_event.bits.Gun1_Parallel_N == YES)
                            outputRelay.relay_event.bits.Gun1_Parallel_N = NO;
                    }
                }
                else if (ShmSysConfigAndInfo->SysInfo.MainChargingMode == _MAIN_CHARGING_MODE_AVER)
                {
                    if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_RELAY_A_TO_M)
                    {
                        // 平均充 - 不搭
                        if (regRelay.relay_event.bits.Gun1_Parallel_P == YES)
                            outputRelay.relay_event.bits.Gun1_Parallel_P = NO;
                        else if (regRelay.relay_event.bits.Gun1_Parallel_N == YES)
                            outputRelay.relay_event.bits.Gun1_Parallel_N = NO;
                    }
                    else
                    {
                        // 最大充 - 搭上橋接
                        if (regRelay.relay_event.bits.Gun1_Parallel_N == NO)
                            outputRelay.relay_event.bits.Gun1_Parallel_N = YES;
                        else if (regRelay.relay_event.bits.Gun1_Parallel_P == NO)
                            outputRelay.relay_event.bits.Gun1_Parallel_P = YES;
                    }
                }
            }
        }
    }
}

void CheckAlarmOccur()
{
    bool isErr = false;
    for(byte count = 0; count < sizeof(_alarm_code)/sizeof(_alarm_code[0]); count++)
    {
        if (acAlarmCode.AcAlarmCode & _alarm_code[count])
        {
            isErr = true;
            switch(_alarm_code[count])
            {
                case AC_OVP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcSystemInputOVP = YES; break;
                case AC_UVP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcSystemInputUVP = YES; break;
                case AC_OCP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemAcOutputOCP = YES; break;
                case AC_OTP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemAmbientOTP = YES; break;
                case AC_GMI_FAULT: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcGroundfaultFail = YES; break;
                case AC_CP_ERROR: ShmStatusCodeData->InfoCode.InfoEvents.bits.PilotFault = YES; break;
                case AC_AC_LEAKAGE: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.RcdTrip = YES; break;
                case AC_DC_LEAKAGE: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.RcdTrip = YES; break;
                case AC_SYSTEM_SELFTEST_FAULT: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.McuSelftestFail = YES; break;
                case AC_HANDSHAKE_TIMEOUT: break;
                case AC_EMC_STOP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.EmergencyStopTrip = YES; break;
                case AC_RELAY_WELDING: ShmStatusCodeData->FaultCode.FaultEvents.bits.AcOutputRelayWelding = YES; break;
                case AC_GF_MODULE_FAULT: ShmStatusCodeData->FaultCode.FaultEvents.bits.RcdSelfTestFail = YES; break;
                case AC_SHUTTER_FAULT: break;
                case AC_LOCKER_FAULT: ShmStatusCodeData->FaultCode.FaultEvents.bits.AcConnectorLockFail = YES; break;
                case AC_POWER_DROP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputDrop = YES; break;
                case AC_CIRCUIT_SHORT: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CircuitShort = YES; break;
                case AC_ROTARY_SWITCH_FAULT: break;
                case AC_RELAY_DRIVE_FAULT: ShmStatusCodeData->FaultCode.FaultEvents.bits.AcOutputRelayDrivingFault = YES; break;
            }
        }
        else
        {
            switch(_alarm_code[count])
            {
                case AC_OVP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcSystemInputOVP = NO; break;
                case AC_UVP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcSystemInputUVP = NO; break;
                case AC_OCP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemAcOutputOCP = NO; break;
                case AC_OTP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemAmbientOTP = NO; break;
                case AC_GMI_FAULT: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcGroundfaultFail = NO; break;
                case AC_CP_ERROR: ShmStatusCodeData->InfoCode.InfoEvents.bits.PilotFault = NO; break;
                case AC_AC_LEAKAGE: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.RcdTrip = NO; break;
                case AC_DC_LEAKAGE: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.RcdTrip = NO; break;
                case AC_SYSTEM_SELFTEST_FAULT: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.McuSelftestFail = NO; break;
                case AC_HANDSHAKE_TIMEOUT: break;
                case AC_EMC_STOP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.EmergencyStopTrip = NO; break;
                case AC_RELAY_WELDING: ShmStatusCodeData->FaultCode.FaultEvents.bits.AcOutputRelayWelding = NO; break;
                case AC_GF_MODULE_FAULT: ShmStatusCodeData->FaultCode.FaultEvents.bits.RcdSelfTestFail = NO; break;
                case AC_SHUTTER_FAULT: break;
                case AC_LOCKER_FAULT: ShmStatusCodeData->FaultCode.FaultEvents.bits.AcConnectorLockFail = NO; break;
                case AC_POWER_DROP: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputDrop = NO; break;
                case AC_CIRCUIT_SHORT: ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CircuitShort = NO; break;
                case AC_ROTARY_SWITCH_FAULT:  break;
                case AC_RELAY_DRIVE_FAULT: ShmStatusCodeData->FaultCode.FaultEvents.bits.AcOutputRelayDrivingFault = NO; break;
            }
        }
    }

    ac_chargingInfo[0]->IsErrorOccur = isErr;
}

bool IsNoneMatchLedColor()
{
    bool result = false;

    if (cur_led_color.Connect_1_Red != led_color.Connect_1_Red ||
        cur_led_color.Connect_1_Green != led_color.Connect_1_Green ||
        cur_led_color.Connect_1_Blue != led_color.Connect_1_Blue ||
        cur_led_color.Connect_2_Red != led_color.Connect_2_Red ||
        cur_led_color.Connect_2_Green != led_color.Connect_2_Green ||
        cur_led_color.Connect_2_Blue != led_color.Connect_2_Blue)
    {
        result = true;
    }

    return result;
}

void SetLedColor(struct ChargingInfoData *chargingData_1, struct ChargingInfoData *chargingData_2)
{
    if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf == YES)
    {
        if ((chargingData_1->SystemStatus == S_BOOTING || chargingData_1->SystemStatus == S_IDLE || chargingData_1->SystemStatus == S_RESERVATION) &&
            (chargingData_2->SystemStatus == S_BOOTING || chargingData_2->SystemStatus == S_IDLE || chargingData_2->SystemStatus == S_RESERVATION))
        {
            led_color.Connect_1_Green   = COLOR_MAX_LV;
            led_color.Connect_1_Blue    = COLOR_MIN_LV;
            led_color.Connect_1_Red     = COLOR_MIN_LV;
            led_color.Connect_2_Green   = COLOR_MAX_LV;
            led_color.Connect_2_Blue    = COLOR_MIN_LV;
            led_color.Connect_2_Red     = COLOR_MIN_LV;
        }
        else if ((chargingData_1->SystemStatus >= S_AUTHORIZING && chargingData_1->SystemStatus <= S_COMPLETE) ||
                 (chargingData_1->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_1->SystemStatus <= S_CCS_PRECHARGE_ST1) ||
                 (chargingData_2->SystemStatus >= S_AUTHORIZING && chargingData_2->SystemStatus <= S_COMPLETE) ||
                 (chargingData_2->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_2->SystemStatus <= S_CCS_PRECHARGE_ST1))
        {
            led_color.Connect_1_Green   = COLOR_MIN_LV;
            led_color.Connect_1_Blue    = COLOR_MAX_LV;
            led_color.Connect_1_Red     = COLOR_MIN_LV;
            led_color.Connect_2_Green   = COLOR_MIN_LV;
            led_color.Connect_2_Blue    = COLOR_MAX_LV;
            led_color.Connect_2_Red     = COLOR_MIN_LV;
        }
    }
    else
    {
        if (chargingData_1->SystemStatus == S_BOOTING || chargingData_1->SystemStatus == S_IDLE || chargingData_1->SystemStatus == S_RESERVATION)
        {
            led_color.Connect_1_Green   = COLOR_MAX_LV;
            led_color.Connect_1_Blue    = COLOR_MIN_LV;
            led_color.Connect_1_Red     = COLOR_MIN_LV;
        }
        else if ((chargingData_1->SystemStatus >= S_AUTHORIZING && chargingData_1->SystemStatus <= S_COMPLETE) ||
                (chargingData_1->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_1->SystemStatus <= S_CCS_PRECHARGE_ST1))
        {
            led_color.Connect_1_Green   = COLOR_MIN_LV;
            led_color.Connect_1_Blue    = COLOR_MAX_LV;
            led_color.Connect_1_Red     = COLOR_MIN_LV;
        }

        // --------------------------------------------------------------------------
        if (chargingData_2->SystemStatus == S_BOOTING || chargingData_2->SystemStatus == S_IDLE || chargingData_2->SystemStatus == S_RESERVATION)
        {
            led_color.Connect_2_Green   = COLOR_MAX_LV;
            led_color.Connect_2_Blue    = COLOR_MIN_LV;
            led_color.Connect_2_Red     = COLOR_MIN_LV;
        }
        else if ((chargingData_2->SystemStatus >= S_AUTHORIZING && chargingData_2->SystemStatus <= S_COMPLETE) ||
                (chargingData_2->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingData_2->SystemStatus <= S_CCS_PRECHARGE_ST1))
        {
            led_color.Connect_2_Green   = COLOR_MIN_LV;
            led_color.Connect_2_Blue    = COLOR_MAX_LV;
            led_color.Connect_2_Red     = COLOR_MIN_LV;
        }
    }

    if (ShmSysConfigAndInfo->SysWarningInfo.Level == 2)
    {
        led_color.Connect_1_Green   = COLOR_MIN_LV;
        led_color.Connect_1_Blue    = COLOR_MIN_LV;
        led_color.Connect_1_Red     = COLOR_MAX_LV;
        led_color.Connect_2_Green   = COLOR_MIN_LV;
        led_color.Connect_2_Blue    = COLOR_MIN_LV;
        led_color.Connect_2_Red     = COLOR_MAX_LV;
    }

    if (_checkLedChanged > 0)
    {
        if (Config_Led_Color(Uart5Fd, Addr.Led, &led_color) == PASS)
    {
            _checkLedChanged--;

            cur_led_color.Connect_1_Red = led_color.Connect_1_Red;
            cur_led_color.Connect_1_Green = led_color.Connect_1_Green;
            cur_led_color.Connect_1_Blue = led_color.Connect_1_Blue;
            cur_led_color.Connect_2_Red = led_color.Connect_2_Red;
            cur_led_color.Connect_2_Green = led_color.Connect_2_Green;
            cur_led_color.Connect_2_Blue = led_color.Connect_2_Blue;
        }
    }
    else if (IsNoneMatchLedColor())
        _checkLedChanged = 3;
}
//==========================================
// Init all share memory
//==========================================
int InitShareMemory()
{
    int result = PASS;
    int MeterSMId;

    //creat ShmSysConfigAndInfo
    if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmSysConfigAndInfo NG\n");
        #endif
        result = FAIL;
    }
    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("[shmat ShmSysConfigAndInfo NG\n");
        #endif
        result = FAIL;
     }
     //creat ShmStatusCodeData
    if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmStatusCodeData NG\n");
        #endif
        result = FAIL;
    }
    else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmStatusCodeData NG\n");
        #endif
        result = FAIL;
    }

    //creat ShmFanModuleData
    if ((MeterSMId = shmget(ShmFanBdKey, sizeof(struct FanModuleData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmFanModuleData NG\n");
        #endif
        result = FAIL;
    }
    else if ((ShmFanModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmFanModuleData NG\n");
        #endif
        result = FAIL;
     }
     memset(ShmFanModuleData,0,sizeof(struct FanModuleData));

     //creat ShmRelayModuleData
    if ((MeterSMId = shmget(ShmRelayBdKey, sizeof(struct RelayModuleData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmRelayModuleData NG\n");
        #endif
        result = FAIL;
    }
    else if ((ShmRelayModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmRelayModuleData NG\n");
        #endif
        result = FAIL;
    }

    //creat ShmLedModuleData
    if ((MeterSMId = shmget(ShmLedBdKey, sizeof(struct LedModuleData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmLedModuleData NG\n");
        #endif
        result = FAIL;
    }
    else if ((ShmLedModuleData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmLedModuleData NG\n");
        #endif
        result = FAIL;
    }
    memset(ShmLedModuleData,0,sizeof(struct LedModuleData));

    //creat ShmPsuData
    if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData),  0777)) < 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmget ShmPsuData NG \n");
        #endif
        result = FAIL;
    }
    else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("shmat ShmPsuData NG \n");
        #endif
        result = FAIL;
    }
    memset(ShmPsuData,0,sizeof(struct PsuData));

    if(CHAdeMO_QUANTITY > 0)
    {
        if ((MeterSMId = shmget(ShmCHAdeMOCommKey, sizeof(struct CHAdeMOData),  IPC_CREAT | 0777)) < 0)
        {
            #ifdef SystemLogMessage
            DEBUG_ERROR("[shmget ShmCHAdeMOData NG \n");
            #endif
            return FAIL;
        }
        else if ((ShmCHAdeMOData = shmat(MeterSMId, NULL, 0)) == (void *) -1) {
            #ifdef SystemLogMessage
            DEBUG_ERROR("shmat ShmCHAdeMOData NG \n");
            #endif
            return FAIL;
        }
    }

    if(CCS_QUANTITY > 0)
    {
        if ((MeterSMId = shmget(ShmCcsCommKey, sizeof(struct CcsData),  IPC_CREAT | 0777)) < 0)
        {
            #ifdef SystemLogMessage
            DEBUG_ERROR("shmget ShmCcsData NG \n");
            #endif
            return FAIL;
        }
        else if ((ShmCcsData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
        {
            #ifdef SystemLogMessage
            DEBUG_ERROR("shmat ShmCcsData NG \n");
            #endif
            return FAIL;
        }
    }


    return result;
}

int InitComPort()
{
    int fd;
    struct termios tios;

    fd = open(relayRs485PortName, O_RDWR);
    if(fd <= 0)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("Module_InternalComm. InitComPort NG\n");
        #endif
        if(ShmStatusCodeData!=NULL)
        {
            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CsuInitFailed=1;
        }
        sleep(5);
        return -1;
    }
    ioctl (fd, TCGETS, &tios);
    tios.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
    tios.c_lflag = 0;
    tios.c_iflag = 0;
    tios.c_oflag = 0;
    tios.c_cc[VMIN]=0;
    tios.c_cc[VTIME]=(byte)0;       // timeout 0.5 second
    tios.c_lflag=0;
    tcflush(fd, TCIFLUSH);
    ioctl (fd, TCSETS, &tios);

    return fd;
}

//================================================
// Main process
//================================================
bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData)
{
    for (byte index = 0; index < CHAdeMO_QUANTITY; index++) {
        if (ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index].Index
                == target) {
            chargingData[target] =
                    &ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index];
            return true;
        }
    }

    for (byte index = 0; index < CCS_QUANTITY; index++) {
        if (ShmSysConfigAndInfo->SysInfo.CcsChargingData[index].Index
                == target) {
            chargingData[target] =
                    &ShmSysConfigAndInfo->SysInfo.CcsChargingData[index];
            return true;
        }
    }

    for (byte index = 0; index < GB_QUANTITY; index++) {
        if (ShmSysConfigAndInfo->SysInfo.GbChargingData[index].Index
                == target) {
            chargingData[target] =
                    &ShmSysConfigAndInfo->SysInfo.GbChargingData[index];
            return true;
        }
    }

    return false;
}

bool FindAcChargingInfoData(byte target, struct ChargingInfoData **acChargingData)
{
    if (target < AC_QUANTITY)
    {
        acChargingData[target] = &ShmSysConfigAndInfo->SysInfo.AcChargingData[target];
        return true;
    }

    return false;
}

void Initialization()
{
    bool isPass = false;

    for (byte index = 0; index < ARRAY_SIZE(outputRelay.relay_event.relay_status); index++)
    {
        outputRelay.relay_event.relay_status[index] = 0x00;
    }

    while(!isPass)
    {
        isPass = true;
        for (byte _index = 0; _index < gunCount; _index++)
        {
            if (!FindChargingInfoData(_index, &_chargingData[0]))
            {
                DEBUG_ERROR("EvComm : FindChargingInfoData false \n");
                isPass = false;
                break;
            }
        }
    }

    isPass = false;

    if (acgunCount > 0)
    {
        while(!isPass)
        {
            isPass = true;
            for (byte _index = 0; _index < acgunCount; _index++)
            {
                if (!FindAcChargingInfoData(_index, &ac_chargingInfo[0]))
                {
                    DEBUG_ERROR("EvComm : FindAcChargingInfoData false \n");
                    isPass = false;
                    break;
                }
            }
        }
    }
}

bool IsNoneMatchRelayStatus()
{
    bool result = false;

    if ((regRelay.relay_event.bits.AC_Contactor != outputRelay.relay_event.bits.AC_Contactor) ||
        (regRelay.relay_event.bits.CCS_Precharge != outputRelay.relay_event.bits.CCS_Precharge) ||
        (regRelay.relay_event.bits.Gun1_P != outputRelay.relay_event.bits.Gun1_P) ||
        (regRelay.relay_event.bits.Gun1_N != outputRelay.relay_event.bits.Gun1_N) ||
        (regRelay.relay_event.bits.Gun2_P != outputRelay.relay_event.bits.Gun2_P) ||
        (regRelay.relay_event.bits.Gun2_N != outputRelay.relay_event.bits.Gun2_N) ||
        (regRelay.relay_event.bits.Gun1_Parallel_P != outputRelay.relay_event.bits.Gun1_Parallel_P) ||
        (regRelay.relay_event.bits.Gun1_Parallel_N != outputRelay.relay_event.bits.Gun1_Parallel_N))
    {
        if (regRelay.relay_event.bits.AC_Contactor != outputRelay.relay_event.bits.AC_Contactor)
            PRINTF_FUNC("AC Contact Relay none match. \n");
        if (regRelay.relay_event.bits.CCS_Precharge != outputRelay.relay_event.bits.CCS_Precharge)
            PRINTF_FUNC("CCS Precharge Relay none match. \n");
        if (regRelay.relay_event.bits.Gun1_P != outputRelay.relay_event.bits.Gun1_P)
            PRINTF_FUNC("SMR1:D+ Relay none match. \n");
        if (regRelay.relay_event.bits.Gun1_N != outputRelay.relay_event.bits.Gun1_N)
            PRINTF_FUNC("SMR1:D- Relay none match. \n");
        if (regRelay.relay_event.bits.Gun2_P != outputRelay.relay_event.bits.Gun2_P)
            PRINTF_FUNC("SMR2:D+ Relay none match. \n");
        if (regRelay.relay_event.bits.Gun2_N != outputRelay.relay_event.bits.Gun2_N)
            PRINTF_FUNC("SMR2:D- Relay none match. \n");
        if (regRelay.relay_event.bits.Gun1_Parallel_P != outputRelay.relay_event.bits.Gun1_Parallel_P)
            PRINTF_FUNC("Parallel:D+ Relay none match. \n");
        if (regRelay.relay_event.bits.Gun1_Parallel_N != outputRelay.relay_event.bits.Gun1_Parallel_N)
            PRINTF_FUNC("Parallel:D- Relay none match. \n");

        result = true;
    }

    return result;
}

void MatchRelayStatus()
{
    // 因為 AC Contactor 沒有 Feedback,所以暫時先這樣處理
    //regRelay.relay_event.bits.AC_Contactor = outputRelay.relay_event.bits.AC_Contactor;
    ShmSysConfigAndInfo->SysInfo.AcContactorStatus  = regRelay.relay_event.bits.AC_Contactor = outputRelay.relay_event.bits.AC_Contactor;
    regRelay.relay_event.bits.CCS_Precharge = outputRelay.relay_event.bits.CCS_Precharge;
    regRelay.relay_event.bits.Gun1_P = outputRelay.relay_event.bits.Gun1_P;
    regRelay.relay_event.bits.Gun1_N = outputRelay.relay_event.bits.Gun1_N;
    regRelay.relay_event.bits.Gun2_P = outputRelay.relay_event.bits.Gun2_P;
    regRelay.relay_event.bits.Gun2_N = outputRelay.relay_event.bits.Gun2_N;
    regRelay.relay_event.bits.Gun1_Parallel_P = outputRelay.relay_event.bits.Gun1_Parallel_P;
    regRelay.relay_event.bits.Gun1_Parallel_N = outputRelay.relay_event.bits.Gun1_Parallel_N;
}

void CheckRelayStatusByADC()
{
    if (ShmRelayModuleData->Gun1FuseOutputVolt > 0 && ShmRelayModuleData->Gun1RelayOutputVolt > 0 &&
        (ShmRelayModuleData->Gun1FuseOutputVolt == ShmRelayModuleData->Gun1RelayOutputVolt))
    {
        // Relay 前後電壓一致
        _chargingData[0]->RelayK1K2Status = 0x01;
    }
    else
        _chargingData[0]->RelayK1K2Status = 0x00;

    if (ShmRelayModuleData->Gun2FuseOutputVolt > 0 && ShmRelayModuleData->Gun2RelayOutputVolt > 0 &&
        (ShmRelayModuleData->Gun2FuseOutputVolt == ShmRelayModuleData->Gun2RelayOutputVolt))
    {
        // Relay 前後電壓一致
        _chargingData[1]->RelayK1K2Status = 0x01;
    }
    else
        _chargingData[1]->RelayK1K2Status = 0x00;
}

void SetGfdConfig(byte index, byte resister)
{
    gfd_config.index = index;
    gfd_config.state = resister;

    //PRINTF_FUNC("************************GFD Vol = %d, GFD Res = %d \n", gfd_config.reqVol, gfd_config.resister);
    if (Config_Gfd_Value(Uart5Fd, Addr.Relay, &gfd_config) == PASS)
    {
//      PRINTF_FUNC("Set reqVol = %f, resister = %d \n",
//              gfd_config.reqVol,
//              gfd_config.resister);
    }
}

void CableCheckDetected(byte index)
{
    // Cable Check
    // 當火線上的電壓 = 車端要求的電壓電流
    // _chargingData[targetGun]->EvBatterytargetVoltage
    // 才可以開始偵測 1s
    // Warning : Rgfd <= 150 歐/V 假設電壓為 500V 則~ Rgfd <= 75000 歐
    // Pre-Warning : 150 歐/V < Rgfd <= 500 歐/V 假設電壓為 500V 則 75000 歐 < Rgfd <= 250000
    // SO Normal : Rgfd > 500 歐/V 假設電壓為 500 V 則 Rgfd > 250000 歐
    if ((_chargingData[index]->Type >= _Type_Chademo && _chargingData[index]->Type <= _Type_GB) ||
        (_chargingData[index]->Type == 0x09 && ShmSysConfigAndInfo->SysConfig.AlwaysGfdFlag))
    {
        if ((_chargingData[index]->SystemStatus >= S_PREPARING_FOR_EVSE && _chargingData[index]->SystemStatus <= S_CHARGING) ||
            (_chargingData[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && _chargingData[index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
        {
            if (_chargingData[index]->SystemStatus == S_PREPARING_FOR_EVSE &&
                _chargingData[index]->RelayWeldingCheck == YES)
            {
                SetGfdConfig(index, GFD_CABLECHK);
            }
            else if (_chargingData[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                    _chargingData[index]->SystemStatus <= S_CCS_PRECHARGE_ST1)
            {
                SetGfdConfig(index, GFD_PRECHARGE);
            }
            else if (_chargingData[index]->SystemStatus <= S_CHARGING)
            {
                if (_chargingData[index]->Type == _Type_GB)
                    SetGfdConfig(index, GFD_IDLE);
                else
                    SetGfdConfig(index, GFD_CHARGING);
            }
        }
        else if(_chargingData[index]->SystemStatus == S_COMPLETE || _chargingData[index]->SystemStatus == S_PREPARNING
                || _chargingData[index]->SystemStatus == S_IDLE)
        {
            SetGfdConfig(index, GFD_IDLE);
        }
    }
}

void CheckOutputPowerOverCarReq(byte index)
{
    float fireV = _chargingData[index]->FireChargingVoltage;
    float carV = _chargingData[index]->EvBatterytargetVoltage;

    if (_chargingData[index]->EvBatterytargetVoltage > 1500 &&
        (_chargingData[index]->Type == _Type_Chademo ||
         _chargingData[index]->Type == _Type_CCS_2 ||
         _chargingData[index]->Type == _Type_GB))
    {
        if (fireV >= (carV + (carV * 0.1)))
        {
            PRINTF_FUNC("[Module_InternalComm]CheckOutputPowerOverCarReq NG : fire = %f, battery = %f \n",
                    _chargingData[index]->FireChargingVoltage, _chargingData[index]->EvBatterytargetVoltage);
            DEBUG_ERROR("[Module_InternalComm]CheckOutputPowerOverCarReq NG : fire = %f, battery = %f \n",
                    _chargingData[index]->FireChargingVoltage, _chargingData[index]->EvBatterytargetVoltage);
            _chargingData[index]->StopChargeFlag = YES;
        }
    }
}

void CheckOutputVolNoneMatchFire(byte index)
{
    if (_chargingData[index]->EvBatterytargetVoltage > 1500 &&
        (_chargingData[index]->Type == _Type_Chademo ||
         _chargingData[index]->Type == _Type_CCS_2 ||
         _chargingData[index]->Type == _Type_GB))
    {
        if (((_chargingData[index]->PresentChargingVoltage * 10) < _chargingData[index]->FireChargingVoltage - 300) ||
            ((_chargingData[index]->PresentChargingVoltage * 10) > _chargingData[index]->FireChargingVoltage + 300))
        {
            if (!_isOutputNoneMatch[index])
            {
                _isOutputNoneMatch[index] = YES;
                gettimeofday(&_checkOutputNoneMatchTimer[index], NULL);
            }
            else
            {
                if ((GetTimeoutValue(_checkOutputNoneMatchTimer[index]) / 1000) >= 5000)
                {
                    PRINTF_FUNC("[Module_InternalComm]CheckOutputVolNoneMatchFire NG (%d) : pre = %f, fire = %f \n",
                            index, (_chargingData[index]->PresentChargingVoltage * 10), _chargingData[index]->FireChargingVoltage);
                    DEBUG_ERROR("[Module_InternalComm]CheckOutputVolNoneMatchFire NG (%d): pre = %f, fire = %f \n",
                            index, (_chargingData[index]->PresentChargingVoltage * 10), _chargingData[index]->FireChargingVoltage);
                    _chargingData[index]->StopChargeFlag = YES;
                }
            }
        }
        else
            _isOutputNoneMatch[index] = NO;
    }
}

void CheckRelayWeldingStatus(byte index)
{
    if (!_isRelayWelding[index])
    {
        if ((_chargingData[index]->PresentChargingVoltage * 10) >= VOUT_MIN_VOLTAGE * 10)
        {
            gettimeofday(&_checkRelayWeldingTimer[index], NULL);
            _isRelayWelding[index] = YES;
        }
    }
    else
    {
        if ((GetTimeoutValue(_checkRelayWeldingTimer[index]) / 1000) >= 1000)
        {
            _chargingData[index]->RelayWeldingCheck = YES;
            return;
        }

        if (_chargingData[index]->FireChargingVoltage >= VOUT_MIN_VOLTAGE)
        {
            if (_chargingData[index]->Type == _Type_Chademo)
                ShmStatusCodeData->FaultCode.FaultEvents.bits.ChademoOutputRelayWelding = YES;
            else if (_chargingData[index]->Type == _Type_GB)
                ShmStatusCodeData->FaultCode.FaultEvents.bits.GbOutputRelayWelding = YES;
            else if (_chargingData[index]->Type == _Type_CCS_2)
                ShmStatusCodeData->FaultCode.FaultEvents.bits.CcsOutputRelayWelding = YES;

            PRINTF_FUNC("CheckRelayWeldingStatus : fail \n");
            _chargingData[index]->StopChargeFlag = YES;
        }
    }
}

void GetPsuTempForFanSpeed()
{
    char temp = 0;
    for (byte index = 0; index < ShmPsuData->GroupCount; index++)
    {
        for (byte count = 0; count < ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; count++)
        {
            if (temp < ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp)
                temp = ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp;
        }
    }

    if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == NO)
    {
    if (ShmFanModuleData->TestFanSpeed == NORMAL_FAN_SPEED)
    {
        if (temp >= ENV_TEMP_MAX)
            ShmFanModuleData->TestFanSpeed = MAX_FAN_SPEED;
    }
    else if (ShmFanModuleData->TestFanSpeed == MAX_FAN_SPEED)
    {
        if (temp <= ENV_TEMP_MIN)
            ShmFanModuleData->TestFanSpeed = NORMAL_FAN_SPEED;
    }
    else
        ShmFanModuleData->TestFanSpeed = NORMAL_FAN_SPEED;
    }
}

void GetAcStatus()
{
    if (Query_AC_Status(Uart5Fd, Addr.AcPlug, &acStatus) == PASS)
    {
        ShmSysConfigAndInfo->SysConfig.AcRatingCurrent = acStatus.MaxCurrent;

        if(ShmSysConfigAndInfo->SysConfig.AcMaxChargingCurrent == 0)
            ShmSysConfigAndInfo->SysConfig.AcMaxChargingCurrent = ShmSysConfigAndInfo->SysConfig.AcRatingCurrent;

    //              printf("CpStatus = %d \n", acStatus.CpStatus);
    //              printf("CurLimit = %d \n", acStatus.CurLimit);
    //              printf("PilotVol_P = %d \n", acStatus.PilotVol_P);
    //              printf("PilotVol_N = %d \n", acStatus.PilotVol_N);
    //              printf("LockStatus = %d \n", acStatus.LockStatus);
    //              printf("RelayStatus = %d \n", acStatus.RelayStatus);
    //              printf("ShutterStatus = %d \n", acStatus.ShutterStatus);
    //              printf("MeterStatus = %d \n", acStatus.MeterStatus);
    //              printf("PpStatus = %d \n", acStatus.PpStatus);
    //              printf("MaxCurrent = %d \n", acStatus.MaxCurrent);
    //              printf("RotateSwitchStatus = %d \n", acStatus.RelayStatus);
    //              printf("============================== \n");
    //
    //              ac_chargingInfo[0]->SystemStatus = acStatus.CpStatus;
    }
}

void GetAcAlarmCode()
{
    if (Query_AC_Alarm_Code(Uart5Fd, Addr.AcPlug, &acAlarmCode) == PASS)
    {
        CheckAlarmOccur();
    }
}

unsigned char GetChargingEnergy()
{
    return Query_Charging_Energy(Uart5Fd, Addr.AcPlug, &acChargingEnergy);
}

unsigned char GetChargingCurrent()
{
    return Query_Charging_Current(Uart5Fd, Addr.AcPlug, &acChargingCurrent);
}

void ChangeLedStatus()
{
    if (ac_chargingInfo[0]->SystemStatus == S_IDLE)
        ledStatus.ActionMode = 1;
    else if (ac_chargingInfo[0]->SystemStatus == S_PREPARNING)
        ledStatus.ActionMode = 3;
    else if (ac_chargingInfo[0]->SystemStatus == S_CHARGING)
        ledStatus.ActionMode = 4;

    Config_LED_Status(Uart5Fd, Addr.AcPlug, &ledStatus);
}

void SetLegacyReq(byte _switch)
{
    Config_Legacy_Req(Uart5Fd, Addr.AcPlug, _switch);
}

void SetCpDuty(byte _value)
{
    Config_Ac_Duty(Uart5Fd, Addr.AcPlug, _value);
}

void ChangeToCsuMode()
{
    ac_chargingInfo[0]->IsModeChagned = Config_CSU_Mode(Uart5Fd, Addr.AcPlug);

//  if (ac_chargingInfo[0]->IsModeChagned == PASS)
//  {
//      Config_Reset_MCU(Uart5Fd, Addr.AcPlug);
//  }
}

void AcChargeTypeProcess()
{
    if (acgunCount > 0)
    {
        if (ac_chargingInfo[0]->SelfTest_Comp == NO)
        {
            ac_chargingInfo[0]->IsModeChagned = NO;
            GetFwVersion_AC();
        }
        else if (ac_chargingInfo[0]->SelfTest_Comp == YES)
        {
            if (ac_chargingInfo[0]->IsModeChagned != PASS)
            {
                ChangeToCsuMode();
                return;
            }
            GetAcStatus();
            GetAcAlarmCode();

            byte _status = S_NONE;
            bool _isStatusChanged = false;

            if (acStatus.CpStatus == AC_SYS_A || ac_chargingInfo[0]->IsErrorOccur)
            {
                if (ac_chargingInfo[0]->SystemStatus == S_CHARGING)
                    _status = S_TERMINATING;
                else if (ac_chargingInfo[0]->SystemStatus >= S_TERMINATING)
                {
                    if (GetTimeoutValue(_ac_charging_comp) >= 10000000)
                        _status = S_IDLE;
                }
                else
                    _status = S_IDLE;
            }
            else if (ac_chargingInfo[0]->SystemStatus >= S_PREPARNING &&
                    ac_chargingInfo[0]->SystemStatus < S_CHARGING)
            {
                if (acStatus.CpStatus == AC_SYS_C && acStatus.RelayStatus == YES)
                    _status = S_CHARGING;
                else if (GetTimeoutValue(_ac_preparing) >= 30000000)
                    _status = S_IDLE;
            }
            else if (acStatus.CpStatus == AC_SYS_B &&
                     ac_chargingInfo[0]->IsAvailable &&
                     !ac_chargingInfo[0]->IsErrorOccur &&
                     (ShmSysConfigAndInfo->SysInfo.WaitForPlugit == YES ||
                      ShmSysConfigAndInfo->SysConfig.AuthorisationMode == AUTH_MODE_DISABLE))
            {
                PRINTF_FUNC("** UserId = %s \n", ShmSysConfigAndInfo->SysConfig.UserId);
                strcpy((char *)ac_chargingInfo[0]->StartUserId, (char *)ShmSysConfigAndInfo->SysConfig.UserId);
                PRINTF_FUNC("** CardNumber = %s \n", ac_chargingInfo[0]->StartUserId);
                strcpy((char *)ShmSysConfigAndInfo->SysConfig.UserId, "");
                ShmSysConfigAndInfo->SysInfo.WaitForPlugit = NO;
                _status = S_PREPARNING;
            }

            //printf("_status = %d \n", _status);

            if (_status != S_NONE && ac_chargingInfo[0]->SystemStatus != _status)
            {
                _isStatusChanged = true;
                ac_chargingInfo[0]->SystemStatus = _status;
            }

            // 設定限制最大充電電流 >= 6 ~ <= 32
            switch(ac_chargingInfo[0]->SystemStatus)
            {
                case S_IDLE:
                {
                    if (_isStatusChanged)
                    {
                        ac_chargingInfo[0]->PresentChargedEnergy = 0.0;
                    }

                    ChangeLedStatus();
                }
                    break;
                case S_PREPARNING:
                {
                    if (_isStatusChanged)
                    {
                        ShmSysConfigAndInfo->SysInfo.SystemPage = _LCM_NONE;
                        ShmSysConfigAndInfo->SysInfo.CurGunSelectedByAc = DEFAULT_AC_INDEX;
                        gettimeofday(&_ac_preparing, NULL);
                    }

                    if (GetChargingEnergy() == PASS)
                    {
                        ac_chargingInfo[0]->PresentChargedEnergy = acChargingEnergy.Energy / 100;
                    }

                    SetLegacyReq(YES);
                    ChangeLedStatus();
                }
                    break;
                case S_CHARGING:
                {
                    if (_isStatusChanged)
                    {
                        ftime(&_ac_startChargingTime);
                        ShmSysConfigAndInfo->SysInfo.CurGunSelectedByAc = DEFAULT_AC_INDEX;
                    }

                    if (GetChargingEnergy() == PASS)
                        ac_chargingInfo[0]->PresentChargedEnergy = acChargingEnergy.Energy / 100;

                    if (GetChargingCurrent() == PASS)
                        ac_chargingInfo[0]->PresentChargingPower = (220 * (acChargingCurrent.OuputCurrentL1 / 10)) / 1000;

                    ftime(&_ac_endChargingTime);
                    ac_chargingInfo[0]->PresentChargedDuration = DiffTimeb(_ac_startChargingTime, _ac_endChargingTime);

                    // 用以判斷是否有在輸出
                    ac_chargingInfo[0]->IsCharging = acStatus.RelayStatus;

                    SetCpDuty(ShmSysConfigAndInfo->SysConfig.AcMaxChargingCurrent);
                    ChangeLedStatus();
                }
                    break;
                case S_TERMINATING:
                {
                    if (_isStatusChanged)
                    {
                        gettimeofday(&_ac_charging_comp, NULL);
                    }

                    SetLegacyReq(NO);
                    if (acStatus.RelayStatus == NO)
                        ac_chargingInfo[0]->SystemStatus = S_COMPLETE;
                }
                    break;
                case S_COMPLETE:
                {
                    if (_isStatusChanged)
                    {
                        gettimeofday(&_ac_charging_comp, NULL);
                        ftime(&_ac_endChargingTime);
                        ac_chargingInfo[0]->PresentChargedDuration = DiffTimeb(_ac_startChargingTime, _ac_endChargingTime);
                    }
                }
                    break;
            }
        }
    }
}

int main(void)
{
    if(InitShareMemory() == FAIL)
    {
        #ifdef SystemLogMessage
        DEBUG_ERROR("InitShareMemory NG\n");
        #endif
        if(ShmStatusCodeData!=NULL)
        {
            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory=1;
        }
        sleep(5);
        return 0;
    }

    gunCount = ShmSysConfigAndInfo->SysConfig.TotalConnectorCount;
    acgunCount = ShmSysConfigAndInfo->SysConfig.AcConnectorCount;
    // Open Uart5 for RB
    Uart5Fd = InitComPort();
    Initialization();
    sleep(1);

    if(Uart5Fd < 0)
    {
        PRINTF_FUNC("(Internal) open port error. \n");
        return 0;
    }

    outputRelay.relay_event.bits.AC_Contactor = 0x00;
    outputRelay.relay_event.bits.CCS_Precharge = 0x00;
    outputRelay.relay_event.bits.Gun1_Parallel_P = 0x00;
    outputRelay.relay_event.bits.Gun1_Parallel_N = 0x00;
    outputRelay.relay_event.bits.Gun1_P = 0x00;
    outputRelay.relay_event.bits.Gun1_N = 0x00;
    outputRelay.relay_event.bits.Gun2_N = 0x00;
    outputRelay.relay_event.bits.Gun2_P = 0x00;
    if(Config_Relay_Output(Uart5Fd, Addr.Relay, &outputRelay) != PASS)
        PRINTF_FUNC("Config_Relay_Output fail \n");

    cur_led_color.Connect_1_Red = COLOR_MIN_LV;
    cur_led_color.Connect_1_Green = COLOR_MIN_LV;
    cur_led_color.Connect_1_Blue = COLOR_MIN_LV;
    cur_led_color.Connect_2_Red = COLOR_MIN_LV;
    cur_led_color.Connect_2_Green = COLOR_MIN_LV;
    cur_led_color.Connect_2_Blue = COLOR_MIN_LV;

    for(;;)
    {
        bool isCharging = false;
        // 程序開始之前~ 必須先確定 FW 版本與硬體版本,確認後!!~ 該模組才算是真正的 Initial Comp.
        if (ShmRelayModuleData->SelfTest_Comp == NO)
        {
            GetFwAndHwVersion_Relay();
            SetRtcData_Relay();
            sleep(1);
        }

        if (ShmFanModuleData->SelfTest_Comp == NO)
        {
            GetFwAndHwVersion_Fan();
            SetModelName_Fan();
            SetRtcData_Fan();
            sleep(1);
            gettimeofday(&_priority_time, NULL);
        }

        // 自檢階段處理,自檢階段如果讀不到版號則代表該系統沒有掛燈板
        if (ShmLedModuleData->SelfTest_Comp == NO)
        {
            // 自檢階段
            if (ShmSysConfigAndInfo->SysInfo.SelfTestSeq <= _STEST_PSU_CAP)
            {
            GetFwAndHwVersion_Led();
            sleep(1);
            gettimeofday(&_led_priority_time, NULL);
        }
            else
            {
                // 自檢階段沒有問到版號
                if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.LedboardStestFail == NO)
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.LedboardStestFail = YES;
            }
        }

        AcChargeTypeProcess();

        if (ShmRelayModuleData->SelfTest_Comp == YES)
        {
            // ==============優先權最高 10 ms ==============
            // 輸出電壓
            GetPersentOutputVol();

            // 三相輸入電壓
            GetPresentInputVol();

            // 讀取當前 AC relay 狀態
            regRelay.relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;
            //GetRelayOutputStatus();

            for (int i = 0; i < gunCount; i++)
            {
                // Cable check (Set)
                CableCheckDetected(i);

                // check k1 k2 relay 狀態
                CheckK1K2RelayOutput(i);

                // 依據當前各槍的狀態選擇 搭上/放開 Relay
                SetK1K2RelayStatus(i);

                if (ShmSysConfigAndInfo->SysConfig.PhaseLossPolicy == YES)
                    CheckPhaseLossStatus(i);

                CheckAcInputOvpStatus(i);

                if (_chargingData[i]->SystemStatus == S_IDLE)
                {
                    _chargingData[i]->RelayWeldingCheck = NO;
                    _isRelayWelding[i] = NO;
                }

                if (_chargingData[i]->SystemStatus == S_BOOTING ||
                    (_chargingData[i]->SystemStatus >= S_REASSIGN_CHECK && _chargingData[i]->SystemStatus <= S_COMPLETE) ||
                    (_chargingData[i]->SystemStatus >= S_CCS_PRECHARGE_ST0 && _chargingData[i]->SystemStatus <= S_CCS_PRECHARGE_ST1) ||
                    ShmSysConfigAndInfo->SysInfo.WaitForPlugit == YES ||
                    (ShmSysConfigAndInfo->SysInfo.PageIndex >= _LCM_AUTHORIZING && ShmSysConfigAndInfo->SysInfo.PageIndex <= _LCM_WAIT_FOR_PLUG))
                {
                    _chargingData[i]->IsReadyToCharging = YES;
                    isCharging = true;

                    // 限定只有在槍類別為 GBT 的時候才做 relay welding 的判斷
                    if (_chargingData[i]->Type == _Type_GB)
                    {
                    if (_chargingData[i]->SystemStatus >= S_PREPARING_FOR_EVSE &&
                            _chargingData[i]->RelayWeldingCheck == NO)
                        CheckRelayWeldingStatus(i);
                    }
                    else
                        _chargingData[i]->RelayWeldingCheck = YES;

                    if (_chargingData[i]->SystemStatus == S_CHARGING)
                    {
                        CheckOutputPowerOverCarReq(i);
                        CheckOutputVolNoneMatchFire(i);
                    }
                    else
                        _isOutputNoneMatch[i] = NO;
                    }
                else
                    _chargingData[i]->IsReadyToCharging = NO;
            }
            // Cable check (Get)
            GetGfdAdc();

            // 橋接 relay
            SetParalleRelayStatus();

            if (isCharging)
            {
                isStopChargingCount = false;
                outputRelay.relay_event.bits.AC_Contactor = YES;
            }
            else
            {
                if (!isStopChargingCount)
                {
                    gettimeofday(&_close_ac_contactor, NULL);
                    isStopChargingCount = true;
                }
                else
                {
                    if ((outputRelay.relay_event.bits.AC_Contactor == YES && GetTimeoutValue(_close_ac_contactor) / 1000 >= (TEN_MINUTES * 1000)))
                        outputRelay.relay_event.bits.AC_Contactor = NO;
                }
            }

            // 搭上/鬆開 Relay
            if(IsNoneMatchRelayStatus())
            {
                if (Config_Relay_Output(Uart5Fd, Addr.Relay, &outputRelay))
                {
                    regRelay.relay_event.bits.CCS_Precharge = outputRelay.relay_event.bits.CCS_Precharge;
                    regRelay.relay_event.bits.Gun1_P = outputRelay.relay_event.bits.Gun1_P;
                    regRelay.relay_event.bits.Gun1_N = outputRelay.relay_event.bits.Gun1_N;
                    regRelay.relay_event.bits.Gun2_P = outputRelay.relay_event.bits.Gun2_P;
                    regRelay.relay_event.bits.Gun2_N = outputRelay.relay_event.bits.Gun2_N;
                    regRelay.relay_event.bits.Gun1_Parallel_P = outputRelay.relay_event.bits.Gun1_Parallel_P;
                    regRelay.relay_event.bits.Gun1_Parallel_N = outputRelay.relay_event.bits.Gun1_Parallel_N;

                    PRINTF_FUNC("Match Relay, AC = %x, g1_p = %x, g1_n = %x, g2_p = %x, g2_n = %x, pre = %x, bri_p = %x, bri_n = %x \n",
                            regRelay.relay_event.bits.AC_Contactor,
                            regRelay.relay_event.bits.Gun1_P,
                            regRelay.relay_event.bits.Gun1_N,
                            regRelay.relay_event.bits.Gun2_P,
                            regRelay.relay_event.bits.Gun2_N,
                            regRelay.relay_event.bits.CCS_Precharge,
                            regRelay.relay_event.bits.Gun1_Parallel_P,
                            regRelay.relay_event.bits.Gun1_Parallel_N);
                }
            }
        }

        if (ShmFanModuleData->SelfTest_Comp == YES)
        {
            if (GetTimeoutValue(_priority_time) / 1000 >= 1000)
            {
                GetPsuTempForFanSpeed();

                GetFanSpeed();
                ShmSysConfigAndInfo->SysInfo.SystemFanRotaSpeed = _setFanSpeed;

                gettimeofday(&_priority_time, NULL);
                if (isCharging)
                {
                    // 在還沒問到 PSU 溫度~ 還是要有個最小轉速
                    ShmFanModuleData->SetFan1Speed = MIN_FAN_SPEED;
                    ShmFanModuleData->SetFan2Speed = MIN_FAN_SPEED;
                    ShmFanModuleData->SetFan3Speed = MIN_FAN_SPEED;
                    ShmFanModuleData->SetFan4Speed = MIN_FAN_SPEED;

                    if (ShmFanModuleData->TestFanSpeed > 0)
                    {
                        ShmFanModuleData->SetFan1Speed = ShmFanModuleData->TestFanSpeed;
                        ShmFanModuleData->SetFan2Speed = ShmFanModuleData->TestFanSpeed;
                        ShmFanModuleData->SetFan3Speed = ShmFanModuleData->TestFanSpeed;
                        ShmFanModuleData->SetFan4Speed = ShmFanModuleData->TestFanSpeed;
                    }
                }
                else
                {
                    ShmFanModuleData->SetFan1Speed = MIN_FAN_SPEED;
                    ShmFanModuleData->SetFan2Speed = MIN_FAN_SPEED;
                    ShmFanModuleData->SetFan3Speed = MIN_FAN_SPEED;
                    ShmFanModuleData->SetFan4Speed = MIN_FAN_SPEED;

                    // 停止時,如溫度還是很高,則需要維持該轉速直到溫度降低
                    if (ShmFanModuleData->TestFanSpeed >= MAX_FAN_SPEED)
                    {
                        ShmFanModuleData->SetFan1Speed = ShmFanModuleData->TestFanSpeed;
                        ShmFanModuleData->SetFan2Speed = ShmFanModuleData->TestFanSpeed;
                        ShmFanModuleData->SetFan3Speed = ShmFanModuleData->TestFanSpeed;
                        ShmFanModuleData->SetFan4Speed = ShmFanModuleData->TestFanSpeed;
                    }
                }

                //PRINTF_FUNC("set fan = %d \n", ShmFanModuleData->SetFan1Speed);
                SetFanModuleSpeed();
            }
        }

        if (ShmLedModuleData->SelfTest_Comp == YES)
        {
            if (GetTimeoutValue(_led_priority_time) / 1000 >= 1000)
            {
            if(gunCount == 1)
            {
                SetLedColor(_chargingData[0], _chargingData[0]);
            }
            else if (gunCount == 2)
            {
                SetLedColor(_chargingData[0], _chargingData[1]);
                }

                gettimeofday(&_led_priority_time, NULL);
            }
        }

        usleep(10000);
    }

    return FAIL;
}