#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

#define AC_DEFAULT_VOL		220

#define	NO_DEFINE			255
#define	NDEFAULT_AC_INDEX	2

#define OVP_UVP_CHK_COUNT   3

struct SysConfigAndInfo			*ShmSysConfigAndInfo;
struct StatusCodeData 			*ShmStatusCodeData;
struct FanModuleData			*ShmFanModuleData;
struct RelayModuleData			*ShmRelayModuleData[2];
struct LedModuleData			*ShmLedModuleData;
struct PsuData 					*ShmPsuData;
struct OCPP16Data				*ShmOCPP16Data;

#define VIN_MAX_VOLTAGE_IEC         285	// 大於該值 : OVP
#define VIN_MAX_REV_VOLTAGE_IEC     275 // 小於賦歸 OVP
#define VIN_MIN_VOLTAGE_IEC         160	// 小於該值 : UVP
#define VIN_MIN_REV_VOLTAGE_IEC     170 // 大於賦歸 UVP

#define VIN_MAX_VOLTAGE_UL          315	// 大於該值 : OVP // 美規 (W)
#define VIN_MAX_REV_VOLTAGE_UL      305 // 小於賦歸 OVP
#define VIN_MIN_VOLTAGE_UL          210	// 小於該值 : UVP
#define VIN_MIN_REV_VOLTAGE_UL      220 // 大於賦歸 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		14000
#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

// LED Intensity (rate)
#define LED_INTENSITY_DARKEST		0.2
#define LED_INTENSITY_MEDIUM		0.6
#define LED_INTENSITY_BRIGHTEST		1

// EE Spec
#define LED_BRIGHTNESS_LV_HIGH		1
#define LED_BRIGHTNESS_LV_MID		0.5
#define LED_BRIGHTNESS_LV_LOW		0.2

// 最小切換 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				50
// 確認 Relay Welding 電壓
#define RELAY_WELDING_DET					300

byte gunCount;
byte acgunCount;
// 槍資訊
struct ChargingInfoData *_chargingData[CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY + GENERAL_GUN_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];

byte _threePhaseOvp[3] = {0, 0, 0};
byte _threePhaseUvp[3] = {0, 0, 0};

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;
float _beforeChargingTotalEnergy = 0.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[2];
Relay regRelay[2];
Relay TempRegRelay[2];
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, ...);

int StoreLogMsg(const char *fmt, ...);
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)*1000+ET.millitm-ST.millitm;
	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.DO360_RC1, &ver) == PASS)
	{
		// RelayModuleData
		strcpy((char *) ShmRelayModuleData[0]->version, ver.Version_FW);
		// SystemInfo
		strcpy((char *) ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev, ver.Version_FW);
		PRINTF_FUNC("GetFwAndHwVersion_RC1 s1 = %s \n", ver.Version_FW);
	}

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

void GetFwAndHwVersion_Relay2()
{
	// DO360 RC2
	if (Query_FW_Ver(Uart5Fd, Addr.DO360_RC2, &ver) == PASS)
	{
		// RelayModuleData
		strcpy((char *) ShmRelayModuleData[1]->version, ver.Version_FW);
		// SystemInfo
		strcpy((char *) ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev, ver.Version_FW);
		PRINTF_FUNC("GetFwAndHwVersion_RC2 s1 = %s \n", ver.Version_FW);
	}

	if (Query_HW_Ver(Uart5Fd, Addr.DO360_RC2, &ver) == PASS)
	{
		// SystemInfo
		strcpy((char *) ShmSysConfigAndInfo->SysInfo.Relay2ModuleHwRev, ver.Version_FW);
		PRINTF_FUNC("GetFwAndHwVersion_RC2 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");
	}

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

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 GetAcModelName()
{
	memset(ShmSysConfigAndInfo->SysConfig.AcModelName, 0x00, sizeof(ShmSysConfigAndInfo->SysConfig.AcModelName));
	if (Query_Model_Name(Uart5Fd, Addr.AcPlug, ShmSysConfigAndInfo->SysConfig.AcModelName) == PASS)
	{
		PRINTF_FUNC("ac model name = %s \n", ShmSysConfigAndInfo->SysConfig.AcModelName);
	}
}

void SetRtcData_Relay(unsigned char index)
{
	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(index == 0)
	{
		if (Config_Rtc_Data(Uart5Fd, Addr.DO360_RC1, &rtc) == PASS)
		{
			//PRINTF_FUNC("SetRtc (RB) sucessfully. \n");
		}
	}
	else
	{
		if (Config_Rtc_Data(Uart5Fd, Addr.DO360_RC2, &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.DO360_RC1, &inputVoltage) == PASS)
	{
		// resolution : 0.1
		ShmSysConfigAndInfo->SysInfo.InputVoltageR = ShmRelayModuleData[0]->InputL1Volt = inputVoltage.L1N_L12;
		ShmSysConfigAndInfo->SysInfo.InputVoltageS = ShmRelayModuleData[0]->InputL2Volt = inputVoltage.L2N_L23;
		ShmSysConfigAndInfo->SysInfo.InputVoltageT = ShmRelayModuleData[0]->InputL3Volt = inputVoltage.L3N_L31;

		//********************************************************************************************************//
		// Vin (UVP)
		if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC)
		{
		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP == NO)
		    {
                if (inputVoltage.L1N_L12 <= VIN_MIN_VOLTAGE_IEC)
                {
                    PRINTF_FUNC("In Uvp L1N_L12 = %f \n", inputVoltage.L1N_L12);
                    if (_threePhaseUvp[0] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = YES;
                    else
                        _threePhaseUvp[0] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L1N_L12 >= VIN_MIN_REV_VOLTAGE_IEC)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO;
                    _threePhaseUvp[0] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP == NO)
		    {
                if (inputVoltage.L2N_L23 <= VIN_MIN_VOLTAGE_IEC)
                {
                    PRINTF_FUNC("In Uvp L2N_L23 = %f \n", inputVoltage.L2N_L23);
                    if (_threePhaseUvp[1] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = YES;
                    else
                        _threePhaseUvp[1] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L2N_L23 >= VIN_MIN_REV_VOLTAGE_IEC)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO;
                    _threePhaseUvp[1] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP == NO)
		    {
                if (inputVoltage.L3N_L31 <= VIN_MIN_VOLTAGE_IEC)
                {
                    PRINTF_FUNC("In Uvp L3N_L31 = %f \n", inputVoltage.L3N_L31);
                    if (_threePhaseUvp[2] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = YES;
                    else
                        _threePhaseUvp[2] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L3N_L31 >= VIN_MIN_REV_VOLTAGE_IEC)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO;
                    _threePhaseUvp[2] = 0;
			    }
			}
		}
		else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL)
		{
		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP == NO)
		    {
                if (inputVoltage.L1N_L12 <= VIN_MIN_VOLTAGE_UL)
                {
                    PRINTF_FUNC("In Uvp L1N_L12 = %f \n", inputVoltage.L1N_L12);
                    if (_threePhaseUvp[0] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = YES;
                    else
                        _threePhaseUvp[0] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L1N_L12 >= VIN_MIN_REV_VOLTAGE_UL)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputUVP = NO;
                    _threePhaseUvp[0] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP == NO)
		    {
                if (inputVoltage.L2N_L23 <= VIN_MIN_VOLTAGE_UL)
                {
                    PRINTF_FUNC("In Uvp L2N_L23 = %f \n", inputVoltage.L2N_L23);
                    if (_threePhaseUvp[1] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = YES;
                    else
                        _threePhaseUvp[1] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L2N_L23 >= VIN_MIN_REV_VOLTAGE_UL)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputUVP = NO;
                    _threePhaseUvp[1] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP == NO)
		    {
                if (inputVoltage.L3N_L31 <= VIN_MIN_VOLTAGE_UL)
                {
                    PRINTF_FUNC("In Uvp L3N_L31 = %f \n", inputVoltage.L3N_L31);
                    if (_threePhaseUvp[2] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = YES;
                    else
                        _threePhaseUvp[2] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L3N_L31 >= VIN_MIN_REV_VOLTAGE_UL)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputUVP = NO;
                    _threePhaseUvp[2] = 0;
			    }
			}
		}
		//********************************************************************************************************//
		// Vin (OVP)
		if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC)
		{
		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP == NO)
		    {
                if (inputVoltage.L1N_L12 >= VIN_MAX_VOLTAGE_IEC)
                {
                    PRINTF_FUNC("In Ovp L1N_L12 = %f \n", inputVoltage.L1N_L12);
                    if (_threePhaseOvp[0] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = YES;
                    else
                        _threePhaseOvp[0] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L1N_L12 <= VIN_MAX_REV_VOLTAGE_IEC)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO;
                    _threePhaseOvp[0] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP == NO)
		    {
                if (inputVoltage.L2N_L23 >= VIN_MAX_VOLTAGE_IEC)
                {
                    PRINTF_FUNC("In Ovp L2N_L23 = %f \n", inputVoltage.L2N_L23);
                    if (_threePhaseOvp[1] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = YES;
                    else
                        _threePhaseOvp[1] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L2N_L23 <= VIN_MAX_REV_VOLTAGE_IEC)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO;
                    _threePhaseOvp[1] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP == NO)
		    {
                if (inputVoltage.L3N_L31 >= VIN_MAX_VOLTAGE_IEC)
                {
                    PRINTF_FUNC("In Ovp L3N_L31 = %f \n", inputVoltage.L3N_L31);
                    if (_threePhaseOvp[2] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = YES;
                    else
                        _threePhaseOvp[2] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L3N_L31 <= VIN_MAX_REV_VOLTAGE_IEC)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO;
                    _threePhaseOvp[2] = 0;
			    }
			}
		}
		else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL)
		{
		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP == NO)
		    {
                if (inputVoltage.L1N_L12 >= VIN_MAX_VOLTAGE_UL)
                {
                    PRINTF_FUNC("In Ovp L1N_L12 = %f \n", inputVoltage.L1N_L12);
                    if (_threePhaseOvp[0] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = YES;
                    else
                        _threePhaseOvp[0] += 0;
                }
		    }
			else
			{
			    if (inputVoltage.L1N_L12 <= VIN_MAX_REV_VOLTAGE_UL)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP = NO;
                    _threePhaseOvp[0] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP == NO)
		    {
                if (inputVoltage.L2N_L23 >= VIN_MAX_VOLTAGE_UL)
                {
                    PRINTF_FUNC("In Ovp L2N_L23 = %f \n", inputVoltage.L2N_L23);
                    if (_threePhaseOvp[1] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = YES;
                    else
                        _threePhaseOvp[1] += 0;
                }
		    }
			else
			{
			    if (inputVoltage.L2N_L23 <= VIN_MAX_REV_VOLTAGE_UL)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP = NO;
                    _threePhaseOvp[1] = 0;
			    }
			}

		    if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP == NO)
		    {
                if (inputVoltage.L3N_L31 >= VIN_MAX_VOLTAGE_UL)
                {
                    PRINTF_FUNC("In Ovp L3N_L31 = %f \n", inputVoltage.L3N_L31);
                    if (_threePhaseOvp[2] >= OVP_UVP_CHK_COUNT)
                        ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = YES;
                    else
                        _threePhaseOvp[2] += 1;
                }
		    }
			else
			{
			    if (inputVoltage.L3N_L31 <= VIN_MAX_REV_VOLTAGE_UL)
			    {
                    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP = NO;
                    _threePhaseOvp[2] = 0;
			    }
			}
		}
	}
}

// 左右槍的 Relay 前後的輸出電壓
void GetPersentOutputVol()
{
	if (Query_Present_OutputVoltage(Uart5Fd, Addr.DO360_RC1, &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[0]->Gun1FuseOutputVolt = outputVoltage.behindFuse_Voltage_C1;
		ShmRelayModuleData[0]->Gun1RelayOutputVolt = outputVoltage.behindRelay_Voltage_C1;
		ShmRelayModuleData[0]->Gun2FuseOutputVolt = outputVoltage.behindFuse_Voltage_C2;
		ShmRelayModuleData[0]->Gun2RelayOutputVolt = outputVoltage.behindRelay_Voltage_C2;

		_chargingData[0]->FuseChargingVoltage = ShmRelayModuleData[0]->Gun1FuseOutputVolt;
		_chargingData[0]->FireChargingVoltage = ShmRelayModuleData[0]->Gun1RelayOutputVolt;
	}

	// DO360 RC2
	if (Query_Present_OutputVoltage(Uart5Fd, Addr.DO360_RC2, &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[1]->Gun1FuseOutputVolt = outputVoltage.behindFuse_Voltage_C1;
		ShmRelayModuleData[1]->Gun1RelayOutputVolt = outputVoltage.behindRelay_Voltage_C1;
		ShmRelayModuleData[1]->Gun2FuseOutputVolt = outputVoltage.behindFuse_Voltage_C2;
		ShmRelayModuleData[1]->Gun2RelayOutputVolt = outputVoltage.behindRelay_Voltage_C2;

		_chargingData[1]->FuseChargingVoltage = ShmRelayModuleData[1]->Gun2FuseOutputVolt;
		_chargingData[1]->FireChargingVoltage = ShmRelayModuleData[1]->Gun2RelayOutputVolt;
	}

//		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 (regRelay[0].relay_event.bits.Gun1_N == YES && regRelay[0].relay_event.bits.Gun1_P == YES)
			_chargingData[index]->RelayK1K2Status = YES;
		else
			_chargingData[index]->RelayK1K2Status = NO;
	}
	else if (index == 1)
	{
		if (regRelay[1].relay_event.bits.Gun2_N == YES && regRelay[1].relay_event.bits.Gun2_P == YES)
			_chargingData[index]->RelayK1K2Status = YES;
		else
			_chargingData[index]->RelayK1K2Status = NO;
	}

	if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES && regRelay[0].relay_event.bits.Gun1_Parallel_P == YES &&
		regRelay[0].relay_event.bits.Gun2_Parallel_N == YES && regRelay[0].relay_event.bits.Gun2_Parallel_P == YES &&
		regRelay[1].relay_event.bits.Gun1_Parallel_N == YES && regRelay[1].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;
//				PRINTF_FUNC("GFD ******** Result = %d, Step = %d, R = %d, Vol = %d \n",
//						_chargingData[i]->GroundFaultStatus, gfd_adc.rb_step_1, gfd_adc.Resister_conn1, gfd_adc.voltage_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_PASS ||
//						_chargingData[i]->GroundFaultStatus == GFD_WARNING)
//				{
//					if (_chargingData[i]->GroundFaultStatus == GFD_WARNING)
//					{
//						PRINTF_FUNC("GFD Warning. index = %d, Result = %d, R = %d, Vol = %d \n",
//								i, _chargingData[i]->GroundFaultStatus, 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_PASS ||
//						_chargingData[i]->GroundFaultStatus == GFD_WARNING)
//				{
//					if (_chargingData[i]->GroundFaultStatus == GFD_WARNING)
//					{
//						PRINTF_FUNC("GFD Warning. index = %d, Result = %d, R = %d, Vol = %d \n",
//							i, _chargingData[i]->GroundFaultStatus, gfd_adc.Resister_conn1, gfd_adc.voltage_conn1);
//					}
//				}
//			}
//		}
//	}
}

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()
{
	{
		FanSpeed _fanSpeed;

		_setFanSpeed += fanSpeedSmoothValue;

		if (_setFanSpeed >= ShmFanModuleData->SetFan1Speed)
			_setFanSpeed = ShmFanModuleData->SetFan1Speed;

		//printf("_setFanSpeed = %d \n", _setFanSpeed);
		_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 (ShmPsuData->Work_Step >= _TEST_MODE && ShmPsuData->Work_Step <= _TEST_MODE)
	{
		if(regRelay[0].relay_event.bits.Gun1_N == NO)
			outputRelay[0].relay_event.bits.Gun1_N = YES;
		if (regRelay[0].relay_event.bits.Gun1_P == NO)
			outputRelay[0].relay_event.bits.Gun1_P = YES;
		return;
	}

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

	}
	else if (_chargingData[index]->SystemStatus == S_CCS_PRECHARGE_ST1)
	{

	}
}

void CheckAcInputOvpStatus(byte index)
{
	if (ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL1InputOVP == YES ||
			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL2InputOVP == YES ||
			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.SystemL3InputOVP == YES)
	{
//		if ((_chargingData[index]->SystemStatus >= S_PREPARNING && _chargingData[index]->SystemStatus <= S_CHARGING) ||
//				(_chargingData[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && _chargingData[index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
//		{
//			if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_IEC)
//			{
//				if (_psuInputVolR > VIN_MAX_VOLTAGE_IEC ||
//						_psuInputVolS > VIN_MAX_VOLTAGE_IEC ||
//						_psuInputVolT > VIN_MAX_VOLTAGE_IEC)
//				{
//					PRINTF_FUNC("IEC _psuInputVolR = %f, _psuInputVolS = %f, _psuInputVolT = %f \n",
//							_psuInputVolR, _psuInputVolS, _psuInputVolT);
//					_chargingData[index]->StopChargeFlag = YES;
//				}
//
//			}
//			else if (ShmSysConfigAndInfo->SysInfo.ChargerType == _CHARGER_TYPE_UL)
//			{
//				if (_psuInputVolR > VIN_MAX_VOLTAGE_UL ||
//						_psuInputVolS > VIN_MAX_VOLTAGE_UL ||
//						_psuInputVolT > VIN_MAX_VOLTAGE_UL)
//				{
//					PRINTF_FUNC("UL _psuInputVolR = %f, _psuInputVolS = %f, _psuInputVolT = %f \n",
//							_psuInputVolR, _psuInputVolS, _psuInputVolT);
//					_chargingData[index]->StopChargeFlag = YES;
//				}
//			}
//		}
//		else
			_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)
	{
		if (_chargingData[0]->SystemStatus == S_BOOTING || _chargingData[1]->SystemStatus == S_BOOTING ||
				((_chargingData[0]->SystemStatus == S_IDLE || _chargingData[0]->SystemStatus == S_MAINTAIN || _chargingData[0]->SystemStatus == S_FAULT) &&
				(_chargingData[1]->SystemStatus == S_IDLE || _chargingData[1]->SystemStatus == S_MAINTAIN || _chargingData[0]->SystemStatus == S_FAULT)))
		{
			// 初始化~ 不搭橋接
			if (regRelay[0].relay_event.bits.Gun1_Parallel_P == YES)
				outputRelay[0].relay_event.bits.Gun1_Parallel_P = NO;
			if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
				outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
			if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
				outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
			if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
				outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
			if (regRelay[1].relay_event.bits.Gun1_Parallel_P == YES)
				outputRelay[1].relay_event.bits.Gun1_Parallel_P = NO;
			if (regRelay[1].relay_event.bits.Gun1_Parallel_N == YES)
				outputRelay[1].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[0].relay_event.bits.Gun1_Parallel_N == NO)
							outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
						if (regRelay[0].relay_event.bits.Gun1_Parallel_P == NO)
							outputRelay[0].relay_event.bits.Gun1_Parallel_P = YES;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
							outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_P == NO)
							outputRelay[0].relay_event.bits.Gun2_Parallel_P = YES;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_N == NO)
							outputRelay[1].relay_event.bits.Gun1_Parallel_N = YES;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_P == NO)
							outputRelay[1].relay_event.bits.Gun1_Parallel_P = YES;
					}
					else
					{
						// 平均充 - 不搭
						if (regRelay[0].relay_event.bits.Gun1_Parallel_P == YES)
							outputRelay[0].relay_event.bits.Gun1_Parallel_P = NO;
						if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
							outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
							outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
							outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_P == YES)
							outputRelay[1].relay_event.bits.Gun1_Parallel_P = NO;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_N == YES)
							outputRelay[1].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[0].relay_event.bits.Gun1_Parallel_P == YES)
							outputRelay[0].relay_event.bits.Gun1_Parallel_P = NO;
						if (regRelay[0].relay_event.bits.Gun1_Parallel_N == YES)
							outputRelay[0].relay_event.bits.Gun1_Parallel_N = NO;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_P == YES)
							outputRelay[0].relay_event.bits.Gun2_Parallel_P = NO;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_N == YES)
							outputRelay[0].relay_event.bits.Gun2_Parallel_N = NO;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_P == YES)
							outputRelay[1].relay_event.bits.Gun1_Parallel_P = NO;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_N == YES)
							outputRelay[1].relay_event.bits.Gun1_Parallel_N = NO;
					}
					else
					{
						// 最大充 - 搭上橋接
						if (regRelay[0].relay_event.bits.Gun1_Parallel_N == NO)
							outputRelay[0].relay_event.bits.Gun1_Parallel_N = YES;
						if (regRelay[0].relay_event.bits.Gun1_Parallel_P == NO)
							outputRelay[0].relay_event.bits.Gun1_Parallel_P = YES;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_N == NO)
							outputRelay[0].relay_event.bits.Gun2_Parallel_N = YES;
						if (regRelay[0].relay_event.bits.Gun2_Parallel_P == NO)
							outputRelay[0].relay_event.bits.Gun2_Parallel_P = YES;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_N == NO)
							outputRelay[1].relay_event.bits.Gun1_Parallel_N = YES;
						if (regRelay[1].relay_event.bits.Gun1_Parallel_P == NO)
							outputRelay[1].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)
{
	byte _colorBuf = COLOR_MAX_LV * LED_INTENSITY_BRIGHTEST;

	if (ShmSysConfigAndInfo->SysConfig.LedInfo.Intensity == _LED_INTENSITY_DARKEST)
		_colorBuf = COLOR_MAX_LV * LED_INTENSITY_DARKEST;
	else if (ShmSysConfigAndInfo->SysConfig.LedInfo.Intensity == _LED_INTENSITY_MEDIUM)
		_colorBuf = COLOR_MAX_LV * LED_INTENSITY_MEDIUM;

	if (ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf)
	{
		 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 = _colorBuf;
			 led_color.Connect_1_Blue = COLOR_MIN_LV;
			 led_color.Connect_1_Red = COLOR_MIN_LV;
			 led_color.Connect_2_Green = _colorBuf;
			 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 = _colorBuf;
			 led_color.Connect_1_Red = COLOR_MIN_LV;
			 led_color.Connect_2_Green = COLOR_MIN_LV;
			 led_color.Connect_2_Blue = _colorBuf;
			 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 = _colorBuf;
			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 = _colorBuf;
			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 = _colorBuf;
			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 = _colorBuf;
			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 = _colorBuf;
		led_color.Connect_2_Green = COLOR_MIN_LV;
		led_color.Connect_2_Blue = COLOR_MIN_LV;
		led_color.Connect_2_Red = _colorBuf;
	}

	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;

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

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

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

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

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


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

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

	if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data), 0777)) < 0)
	{
		#ifdef SystemLogMessage
		DEBUG_ERROR("shmat ShmOCPP16Data NG \n");
		#endif
		result = FAIL;
	}
	else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
	{
		#ifdef SystemLogMessage
		DEBUG_ERROR("shmat ShmOCPP16Data NG \n");
		#endif
		result = 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;
		}
	}

	//DO360
	if(GENERAL_GUN_QUANTITY > 0 && target < GENERAL_GUN_QUANTITY)
	{
		ShmSysConfigAndInfo->SysInfo.ConnectorInfo[target].GeneralChargingData.Index = target;
		chargingData[target] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[target].GeneralChargingData;
		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[0].relay_event.relay_status); index++)
	{
		outputRelay[0].relay_event.relay_status[index] = 0x00;
		outputRelay[1].relay_event.relay_status[index] = 0x00;
	}

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

		sleep(1);
	}

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

			sleep(1);
		}
	}
}

bool IsNoneMatchRelayStatus(byte index)
{
	bool result = false;

	if ((regRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor) ||
		(regRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge) ||
		(regRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P) ||
		(regRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N) ||
		(regRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P) ||
		(regRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N) ||
		(regRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P) ||
		(regRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N) ||
		(regRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P) ||
		(regRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N))
	{
		if (regRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor)
		{
		    if(TempRegRelay[index].relay_event.bits.AC_Contactor != outputRelay[index].relay_event.bits.AC_Contactor)
		    {
		        PRINTF_FUNC("[%d]AC Contact Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.AC_Contactor == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.AC_Contactor = outputRelay[index].relay_event.bits.AC_Contactor;
		    }
		}
		if (regRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge)
		{
		    if(TempRegRelay[index].relay_event.bits.CCS_Precharge != outputRelay[index].relay_event.bits.CCS_Precharge)
		    {
		        PRINTF_FUNC("[%d]CCS Precharge Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.CCS_Precharge == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.CCS_Precharge = outputRelay[index].relay_event.bits.CCS_Precharge;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun1_P != outputRelay[index].relay_event.bits.Gun1_P)
		    {
		        PRINTF_FUNC("[%d]SMR1:D+ Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun1_P == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun1_P = outputRelay[index].relay_event.bits.Gun1_P;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun1_N != outputRelay[index].relay_event.bits.Gun1_N)
		    {
		        PRINTF_FUNC("[%d]SMR1:D- Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun1_N == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun1_N = outputRelay[index].relay_event.bits.Gun1_N;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun2_P != outputRelay[index].relay_event.bits.Gun2_P)
		    {
		        PRINTF_FUNC("[%d]SMR2:D+ Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun2_P == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun2_P = outputRelay[index].relay_event.bits.Gun2_P;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun2_N != outputRelay[index].relay_event.bits.Gun2_N)
		    {
		        PRINTF_FUNC("[%d]SMR2:D- Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun2_N == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun2_N = outputRelay[index].relay_event.bits.Gun2_N;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun1_Parallel_P != outputRelay[index].relay_event.bits.Gun1_Parallel_P)
		    {
		        PRINTF_FUNC("[%d]Parallel:D+ Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun1_Parallel_P == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun1_Parallel_P = outputRelay[index].relay_event.bits.Gun1_Parallel_P;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun1_Parallel_N != outputRelay[index].relay_event.bits.Gun1_Parallel_N)
		    {
		        PRINTF_FUNC("[%d]Parallel:D- Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun1_Parallel_N == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun1_Parallel_N = outputRelay[index].relay_event.bits.Gun1_Parallel_N;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun2_Parallel_P != outputRelay[index].relay_event.bits.Gun2_Parallel_P)
		    {
		        PRINTF_FUNC("[%d]Parallel2:D+ Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun2_Parallel_P == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun2_Parallel_P = outputRelay[index].relay_event.bits.Gun2_Parallel_P;
		    }
		}
		if (regRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N)
		{
		    if(TempRegRelay[index].relay_event.bits.Gun2_Parallel_N != outputRelay[index].relay_event.bits.Gun2_Parallel_N)
		    {
		        PRINTF_FUNC("[%d]Parallel2:D- Relay none match, need to %s", index,
                    outputRelay[index].relay_event.bits.Gun2_Parallel_N == YES ? "On" : "Off");
		        TempRegRelay[index].relay_event.bits.Gun2_Parallel_N = outputRelay[index].relay_event.bits.Gun2_Parallel_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[0]->Gun1FuseOutputVolt > 0 && ShmRelayModuleData[0]->Gun1RelayOutputVolt > 0 &&
			(ShmRelayModuleData[0]->Gun1FuseOutputVolt == ShmRelayModuleData[0]->Gun1RelayOutputVolt))
	{
		// Relay 前後電壓一致
		_chargingData[0]->RelayK1K2Status = 0x01;
	}
	else
		_chargingData[0]->RelayK1K2Status = 0x00;

	if (ShmRelayModuleData[1]->Gun2FuseOutputVolt > 0 && ShmRelayModuleData[1]->Gun2RelayOutputVolt > 0 &&
				(ShmRelayModuleData[1]->Gun2FuseOutputVolt == ShmRelayModuleData[1]->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_TERMINATING) ||
			(_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 &&
					_chargingData[index]->SystemStatus <= S_TERMINATING)
			{
				if (_chargingData[index]->Type == _Type_GB || _chargingData[index]->Type == _Type_Chademo)
					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 * 10;

	if ((_chargingData[index]->EvBatterytargetVoltage * 10) > 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 * 10));
			DEBUG_ERROR("[Module_InternalComm]CheckOutputPowerOverCarReq NG : fire = %f, battery = %f \n",
					_chargingData[index]->FireChargingVoltage, (_chargingData[index]->EvBatterytargetVoltage * 10));
			_chargingData[index]->StopChargeFlag = YES;
		}
	}
}

void CheckOutputVolNoneMatchFire(byte index)
{
	if ((_chargingData[index]->EvBatterytargetVoltage * 10) > 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;
		}
	}

	ShmSysConfigAndInfo->SysInfo.SystemAmbientTemp = temp;

	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 GetFanSpeedByFunction()
{
	if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES)
		return;

	// 風控修改 :
	// ******************************************************* //
	//
	//       當前PSU輸出總 KW       PSU Temp
	// 50 x -------------------- x ---------- + 0.5 x (PSU Temp - 70)
	//       當前樁最大功率 KW         50
	//
	// ******************************************************* //

	// 當前樁最大功率 KW : ShmPsuData->SystemAvailablePower
	unsigned int _maxPower = ShmPsuData->SystemAvailablePower;
	// 當前PSU輸出總 KW & PSU Temp :
	unsigned char temp = 0;
	float power = 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;
		}
		power += (_chargingData[index]->PresentChargingPower * 10);
	}

	double _pw_rate = 0;
	if (_maxPower > 0)
		_pw_rate = power / (double)_maxPower;
	double _temp_rate = 0;
	if (temp > 0)
		_temp_rate = (double)temp / 50;
	unsigned char _temp_diff = 0;
	if (temp > 70)
		_temp_diff = temp - 70;

	ShmFanModuleData->TestFanSpeed = (((50 * _pw_rate * _temp_rate) + (0.5 * _temp_diff)) / 100) * MAX_FAN_SPEED;

	if (ShmFanModuleData->TestFanSpeed > MAX_FAN_SPEED)
		ShmFanModuleData->TestFanSpeed = MAX_FAN_SPEED;

	if (ShmFanModuleData->TestFanSpeed < 0)
			ShmFanModuleData->TestFanSpeed = 0;

// -----------------------------------------------------------------------
//	printf("power = %f \n", power);
//	printf("_maxPower = %d \n", _maxPower);
//	printf("temp = %d \n", temp);
//
//	printf("_pw_rate = %f \n", _pw_rate);
//	printf("_temp_rate = %f \n", _temp_rate);
//	printf("_temp_diff = %d \n", _temp_diff);
//	printf("fan rate = %f \n", (30 * _pw_rate * _temp_rate + 14 * _temp_diff));
//	printf("ShmFanModuleData->TestFanSpeed = %d \n", ShmFanModuleData->TestFanSpeed);
}

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;

		ac_chargingInfo[0]->ConnectorPlugIn = acStatus.CpStatus;
	//	PRINTF_FUNC("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;
	}
//	else
//		PRINTF_FUNC("GetAcStatus return fail. \n");
}

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 ChangeStartOrStopDateTime(byte isStart)
{
	char cmdBuf[32];
	struct timeb csuTime;
	struct tm *tmCSU;

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

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

void OcppStartTransation(byte gunIndex)
{
	if(strcmp((char *)ac_chargingInfo[0]->StartUserId, "") == EQUAL)
		strcpy((char *)ShmOCPP16Data->StartTransaction[gunIndex].IdTag, (char *)ShmOCPP16Data->StartTransaction[gunIndex].IdTag);
	else
		strcpy((char *)ShmOCPP16Data->StartTransaction[gunIndex].IdTag, (char *)ac_chargingInfo[0]->StartUserId);

	PRINTF_FUNC("AC IdTag = %s \n", ShmOCPP16Data->StartTransaction[gunIndex].IdTag);
	ShmOCPP16Data->CpMsg.bits[gunIndex].StartTransactionReq = YES;
}

void OcppStopTransation(byte gunIndex)
{
	if(strcmp((char *)ac_chargingInfo[0]->StartUserId, "") == EQUAL)
		strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].IdTag, (char *)ShmOCPP16Data->StopTransaction[gunIndex].IdTag);
	else
		strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].IdTag, (char *)ac_chargingInfo[0]->StartUserId);

	PRINTF_FUNC("AC IdTag = %s \n", ShmOCPP16Data->StopTransaction[gunIndex].IdTag);
	ShmOCPP16Data->CpMsg.bits[gunIndex].StopTransactionReq = YES;
}

bool OcppRemoteStop(byte gunIndex)
{
	bool result = ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStopTransactionReq;

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

	return result;
}

unsigned char isModeChange()
{
	unsigned char result = NO;

	if(ac_chargingInfo[0]->SystemStatus != ac_chargingInfo[0]->PreviousSystemStatus)
	{
		result = YES;
		ac_chargingInfo[0]->PreviousSystemStatus = ac_chargingInfo[0]->SystemStatus;
	}

	return result;
}

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

			byte _status = S_NONE;

			if (ac_chargingInfo[0]->SystemStatus == S_IDLE && ac_chargingInfo[0]->IsErrorOccur)
			{
				_status = S_ALARM;
			}
			else 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 && acStatus.CpStatus == AC_SYS_A)
						_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]->ConnectorPlugIn == AC_SYS_B) &&
					ac_chargingInfo[0]->IsAvailable &&
					!ac_chargingInfo[0]->IsErrorOccur &&
					(ShmSysConfigAndInfo->SysInfo.WaitForPlugit == YES ||
						ShmSysConfigAndInfo->SysConfig.AuthorisationMode == AUTH_MODE_DISABLE))
			{
				if (ac_chargingInfo[0]->RemoteStartFlag == YES)
				{
					PRINTF_FUNC("** AC Remote \n");
					ac_chargingInfo[0]->RemoteStartFlag = NO;
					strcpy((char *)ac_chargingInfo[0]->StartUserId, "");
					ShmSysConfigAndInfo->SysInfo.WaitForPlugit = NO;
					_status = S_PREPARNING;
				}
				else if (ShmSysConfigAndInfo->SysInfo.OrderCharging == NO_DEFINE)
				{
					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;
				}
			}
			else if (ac_chargingInfo[0]->SystemStatus == S_CHARGING)
			{
				if (OcppRemoteStop(1))
					_status = S_TERMINATING;
			}

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

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

			// 設定限制最大充電電流 >= 6 ~ <= 32
			switch(ac_chargingInfo[0]->SystemStatus)
			{
				case S_IDLE:
				case S_ALARM:
				{
					if (isModeChange())
					{
						ac_chargingInfo[0]->PresentChargedEnergy = 0.0;
						ac_chargingInfo[0]->PresentChargingVoltage = 0;
						ac_chargingInfo[0]->ChargingFee = 0.0;
						strcpy((char *)ac_chargingInfo[0]->StartDateTime, "");
						strcpy((char *)ac_chargingInfo[0]->StopDateTime, "");
						_beforeChargingTotalEnergy = 0.0;
					}

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

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

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

					if (GetChargingEnergy() == PASS)
					{
						if ((acChargingEnergy.Energy - _beforeChargingTotalEnergy) > 0)
						{
							ac_chargingInfo[0]->PresentChargedEnergy += (acChargingEnergy.Energy - _beforeChargingTotalEnergy) / 100;
							if (ShmSysConfigAndInfo->SysConfig.BillingData.isBilling)
							{
								ac_chargingInfo[0]->ChargingFee += ac_chargingInfo[0]->PresentChargedEnergy * ShmSysConfigAndInfo->SysConfig.BillingData.Cur_fee;
							}
						}

						_beforeChargingTotalEnergy = acChargingEnergy.Energy;
					}

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

					ftime(&_ac_endChargingTime);
					ac_chargingInfo[0]->PresentChargedDuration = DiffTimeb(_ac_startChargingTime, _ac_endChargingTime);
					ac_chargingInfo[0]->PresentChargingVoltage = AC_DEFAULT_VOL;
					ac_chargingInfo[0]->PresentChargingCurrent = ((float)acChargingCurrent.OuputCurrentL1 / 10);

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

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

					SetLegacyReq(NO);
					if (acStatus.RelayStatus == NO)
						ac_chargingInfo[0]->SystemStatus = S_COMPLETE;
				}
					break;
				case S_COMPLETE:
				{
					if (isModeChange())
					{
						gettimeofday(&_ac_charging_comp, NULL);
						ftime(&_ac_endChargingTime);
						if (strcmp((char *)ac_chargingInfo[0]->StartDateTime, "") != EQUAL)
						{
							// AC 固定為第2把槍
							OcppStopTransation(1);
						}

						ChangeStartOrStopDateTime(NO);
						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;
	}

	memset(&outputRelay[0], 0x00, sizeof(Relay));
	memset(&outputRelay[1], 0x00, sizeof(Relay));

	if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0]) != PASS)
		PRINTF_FUNC("Config_Relay1_Output fail");
	if(Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1]) != PASS)
		PRINTF_FUNC("Config_Relay2_Output fail");

	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;

	//bool printRelayStatus = true;
	for(;;)
	{
	    if(!ShmSysConfigAndInfo->SysInfo.FirmwareUpdate)
	    {
            bool isCharging = false;
            // 程序開始之前~ 必須先確定 FW 版本與硬體版本,確認後!!~ 該模組才算是真正的 Initial Comp.
            if (ShmRelayModuleData[0]->SelfTest_Comp == NO)
            {
                // clena fw version
                memset(ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev, 0x00, 32);

                GetFwAndHwVersion_Relay();
                SetRtcData_Relay(0);
                sleep(1);

                if(strlen((char *)ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev))
                {
                    ShmRelayModuleData[0]->SelfTest_Comp = YES;
                }
            }

            // DO360 RC2
            if (ShmRelayModuleData[1]->SelfTest_Comp == NO)
            {
                // clena fw version
                memset(ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev, 0x00, 32);

                GetFwAndHwVersion_Relay2();
                SetRtcData_Relay(1);
                sleep(1);

                if (strlen((char *)ShmSysConfigAndInfo->SysInfo.Relay2ModuleFwRev) != 0)
                {
                    ShmRelayModuleData[1]->SelfTest_Comp = YES;
                }
            }

            if (ShmFanModuleData->SelfTest_Comp == NO)
            {
                // clena fw version
                memset(ShmSysConfigAndInfo->SysInfo.FanModuleFwRev, 0x00, 32);

                GetFwAndHwVersion_Fan();
                SetModelName_Fan();
                SetRtcData_Fan();
                sleep(1);
                gettimeofday(&_priority_time, NULL);

                if(strlen((char *)ShmSysConfigAndInfo->SysInfo.FanModuleFwRev) != 0)
                {
                    ShmFanModuleData->SelfTest_Comp = YES;
                }
            }

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

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

                // 讀取當前 AC relay 狀態
                if(regRelay[0].relay_event.bits.AC_Contactor != ShmSysConfigAndInfo->SysInfo.AcContactorStatus)
                {
                    PRINTF_FUNC("[%d]AC Contact Relay already %s", 0,
                        ShmSysConfigAndInfo->SysInfo.AcContactorStatus == YES ? "On" : "Off");
                }
                if(regRelay[1].relay_event.bits.AC_Contactor != ShmSysConfigAndInfo->SysInfo.AcContactorStatus)
                {
                    PRINTF_FUNC("[%d]AC Contact Relay already %s", 1,
                        ShmSysConfigAndInfo->SysInfo.AcContactorStatus == YES ? "On" : "Off");
                }
                regRelay[0].relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;
                regRelay[1].relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;

                //GetRelayOutputStatus();

                for (int i = 0; i < gunCount; 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)
                        {
                            // DO360 do not check under voltage output & any voltage difference
                            //CheckOutputPowerOverCarReq(i);
                            //CheckOutputVolNoneMatchFire(i);
                        }
                        else
                            _isOutputNoneMatch[i] = NO;
                    }
                    else
                        _chargingData[i]->IsReadyToCharging = NO;
                }

                // 橋接 relay
                SetParalleRelayStatus();

                if (isCharging ||
                    (ShmPsuData->Work_Step >= _TEST_MODE && ShmPsuData->Work_Step <= _TEST_MODE))
                {
                    isStopChargingCount = false;
                    outputRelay[0].relay_event.bits.AC_Contactor = YES;
                    outputRelay[1].relay_event.bits.AC_Contactor = YES;
                }
                else
                {
                    if (!isStopChargingCount)
                    {
                        gettimeofday(&_close_ac_contactor, NULL);
                        isStopChargingCount = true;
                    }
                    else
                    {
                        if (((outputRelay[0].relay_event.bits.AC_Contactor == YES || outputRelay[1].relay_event.bits.AC_Contactor == YES)&&
                                GetTimeoutValue(_close_ac_contactor) / 1000 >= (TEN_MINUTES * 1000)) ||
                                ShmSysConfigAndInfo->SysInfo.ForceAcContactorOff == YES)
                        {
                            outputRelay[0].relay_event.bits.AC_Contactor = NO;
                            outputRelay[1].relay_event.bits.AC_Contactor = NO;
                            ShmSysConfigAndInfo->SysInfo.ForceAcContactorOff = NO;
                        }
                    }
                }

                if (ShmPsuData->Work_Step >= _TEST_MODE && ShmPsuData->Work_Step <= _TEST_MODE)
                {
                    outputRelay[0].relay_event.bits.Gun1_N = outputRelay[0].relay_event.bits.Gun1_P = YES;
                }

                // 搭上/鬆開 Relay
                if(IsNoneMatchRelayStatus(0))
                {
                    if (Config_Relay_Output(Uart5Fd, Addr.DO360_RC1, &outputRelay[0]))
                    {
                        //regRelay.relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;
                        regRelay[0].relay_event.bits.CCS_Precharge = outputRelay[0].relay_event.bits.CCS_Precharge;
                        regRelay[0].relay_event.bits.Gun1_P = outputRelay[0].relay_event.bits.Gun1_P;
                        regRelay[0].relay_event.bits.Gun1_N = outputRelay[0].relay_event.bits.Gun1_N;
                        regRelay[0].relay_event.bits.Gun2_P = outputRelay[0].relay_event.bits.Gun2_P;
                        regRelay[0].relay_event.bits.Gun2_N = outputRelay[0].relay_event.bits.Gun2_N;
                        regRelay[0].relay_event.bits.Gun1_Parallel_P = outputRelay[0].relay_event.bits.Gun1_Parallel_P;
                        regRelay[0].relay_event.bits.Gun1_Parallel_N = outputRelay[0].relay_event.bits.Gun1_Parallel_N;
                        regRelay[0].relay_event.bits.Gun2_Parallel_P = outputRelay[0].relay_event.bits.Gun2_Parallel_P;
                        regRelay[0].relay_event.bits.Gun2_Parallel_N = outputRelay[0].relay_event.bits.Gun2_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, bri2_p = %x, bri2_n = %x \n",
//                                regRelay[0].relay_event.bits.AC_Contactor,
//                                regRelay[0].relay_event.bits.Gun1_P,
//                                regRelay[0].relay_event.bits.Gun1_N,
//                                regRelay[0].relay_event.bits.Gun2_P,
//                                regRelay[0].relay_event.bits.Gun2_N,
//                                regRelay[0].relay_event.bits.CCS_Precharge,
//                                regRelay[0].relay_event.bits.Gun1_Parallel_P,
//                                regRelay[0].relay_event.bits.Gun1_Parallel_N,
//                                regRelay[0].relay_event.bits.Gun2_Parallel_P,
//                                regRelay[0].relay_event.bits.Gun2_Parallel_N);
                    }
                }

                // 搭上/鬆開 Relay
                if(IsNoneMatchRelayStatus(1))
                {
                    if (Config_Relay_Output(Uart5Fd, Addr.DO360_RC2, &outputRelay[1]))
                    {
                        //regRelay.relay_event.bits.AC_Contactor = ShmSysConfigAndInfo->SysInfo.AcContactorStatus;
                        regRelay[1].relay_event.bits.CCS_Precharge = outputRelay[1].relay_event.bits.CCS_Precharge;
                        regRelay[1].relay_event.bits.Gun1_P = outputRelay[1].relay_event.bits.Gun1_P;
                        regRelay[1].relay_event.bits.Gun1_N = outputRelay[1].relay_event.bits.Gun1_N;
                        regRelay[1].relay_event.bits.Gun2_P = outputRelay[1].relay_event.bits.Gun2_P;
                        regRelay[1].relay_event.bits.Gun2_N = outputRelay[1].relay_event.bits.Gun2_N;
                        regRelay[1].relay_event.bits.Gun1_Parallel_P = outputRelay[1].relay_event.bits.Gun1_Parallel_P;
                        regRelay[1].relay_event.bits.Gun1_Parallel_N = outputRelay[1].relay_event.bits.Gun1_Parallel_N;
                        regRelay[1].relay_event.bits.Gun2_Parallel_P = outputRelay[1].relay_event.bits.Gun2_Parallel_P;
                        regRelay[1].relay_event.bits.Gun2_Parallel_N = outputRelay[1].relay_event.bits.Gun2_Parallel_N;

//                        PRINTF_FUNC("Match Relay2, AC = %x, g1_p = %x, g1_n = %x, g2_p = %x, g2_n = %x, pre = %x, bri_p = %x, bri_n = %x, bri2_p = %x, bri2_n = %x \n",
//                                regRelay[1].relay_event.bits.AC_Contactor,
//                                regRelay[1].relay_event.bits.Gun1_P,
//                                regRelay[1].relay_event.bits.Gun1_N,
//                                regRelay[1].relay_event.bits.Gun2_P,
//                                regRelay[1].relay_event.bits.Gun2_N,
//                                regRelay[1].relay_event.bits.CCS_Precharge,
//                                regRelay[1].relay_event.bits.Gun1_Parallel_P,
//                                regRelay[1].relay_event.bits.Gun1_Parallel_N,
//                                regRelay[1].relay_event.bits.Gun2_Parallel_P,
//                                regRelay[1].relay_event.bits.Gun2_Parallel_N);
                    }
                }
            }

            if (ShmFanModuleData->SelfTest_Comp == YES ||
                    strlen((char *)ShmSysConfigAndInfo->SysInfo.FanModuleFwRev) != 0 ||
                    ShmSysConfigAndInfo->SysInfo.FanModuleFwRev[0] != '\0')
            {
                if (GetTimeoutValue(_priority_time) / 1000 >= 1000)
                {
                    //GetPsuTempForFanSpeed();
                    GetFanSpeedByFunction();
                    GetFanSpeed();
                    ShmSysConfigAndInfo->SysInfo.SystemFanRotaSpeed = _setFanSpeed;
                    gettimeofday(&_priority_time, NULL);

                    unsigned short TargetSpeed = ShmFanModuleData->TestFanSpeed;

                    if(TargetSpeed != 0 && TargetSpeed < MIN_FAN_SPEED)
                    {
                        TargetSpeed = MIN_FAN_SPEED;
                    }
                    ShmFanModuleData->SetFan1Speed = TargetSpeed;
                    ShmFanModuleData->SetFan2Speed = TargetSpeed;
                    ShmFanModuleData->SetFan3Speed = TargetSpeed;
                    ShmFanModuleData->SetFan4Speed = TargetSpeed;

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

		usleep(10000);
	}

	return FAIL;
}