/*
 * Module_Payment_Enegate.c
 *
 *  Created on: 2022/5/4
 *      Author: folus
 */

#include "Module_Payment_Enegate.h"

ParsingRatedCur modelnameInfo	= {0};
uint8_t gunType[4] 				= {0};
struct timespec	tmr[4][TIMER_CNT];
Message	rx;
Message tx;

//==========================================
// Common routine
//==========================================
int StoreLogMsg(const char *fmt, ...)
{
	char Buf[65536+256];
	char buffer[65536];
	//char Buf[4096+256];
	//char buffer[4096];
	time_t CurrentTime;
	struct tm *tm;
	struct timeval tv;
	va_list args;

	va_start(args, fmt);
	int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
	va_end(args);
	memset(Buf,0,sizeof(Buf));
	CurrentTime = time(NULL);
	tm=localtime(&CurrentTime);
	gettimeofday(&tv, NULL); // get microseconds, 10^-6

	sprintf(Buf,"echo -n \"[%04d.%02d.%02d %02d:%02d:%02d.%03ld]%s\" >>  /Storage/SystemLog/[%04d.%02d]PaymentLog",
			tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec/1000,
			buffer,
			tm->tm_year+1900,tm->tm_mon+1);
	system((const char*)Buf);

#ifdef ConsloePrintLog
	printf("[%04d.%02d.%02d %02d:%02d:%02d.%03ld]%s", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec/1000, buffer);
#endif

	return rc;
}

/**
 * Execute shell command
 * @param cmd: shell command string
 * @return shell command execution result
 */
int runShellCmd(const char*cmd)
{
	int result = FAIL;
	char buf[256];
	FILE *fp;

	fp = popen(cmd, "r");
	if(fp != NULL)
	{
		while(fgets(buf, sizeof(buf), fp) != NULL)
		{
			DEBUG_INFO("%s\n", buf);
		}

		result = PASS;
	}
	pclose(fp);

	return result;
}

/**
 *
 * @param timer
 */
void refreshStartTimer(struct timespec *timer)
{
	clock_gettime(CLOCK_MONOTONIC, timer);
}

/**
 *
 * @param timer
 * @return
 */
int getDiffSecNow(struct timespec timer)
{
	struct timespec timerNow;

	clock_gettime(CLOCK_MONOTONIC, &timerNow);

	return (int)((((unsigned long)(timerNow.tv_sec - timer.tv_sec) * 1000) + ((unsigned long)((timerNow.tv_nsec / 1000000) - (timer.tv_nsec / 1000000))))/1000);
}

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

	ftime(&ET);
	StartTime=(long long)ST.time;
	StopTime=(long long)ET.time;
	return ((StopTime-StartTime)*1000) + (ET.millitm-ST.millitm);
}

/**
 *
 * @return
 */
int getTimePassSinceToday()
{
	int result = -1;
	time_t t;
	struct tm *tmStartToday;
	struct timeb tbStartToday;

	t=time(NULL);

	tmStartToday=localtime(&t);

	tmStartToday->tm_hour = 0;
	tmStartToday->tm_min = 0;
	tmStartToday->tm_sec = 0;

	tbStartToday.time = mktime(tmStartToday);
	tbStartToday.millitm = 0;
	result = DiffTimebWithNow(tbStartToday)/1000;

	return result;
}

/**
 *
 * @param startTime
 * @param stopTime
 * @return
 */
int isPausedService(uint8_t *startTime, uint8_t *stopTime)
{
	int result = FALSE;

	if((strlen((char*)startTime) > 0) && (strlen((char*)stopTime) > 0))
	{
		int start, stop;
		if(sscanf((char*)startTime, "%d", &start) && sscanf((char*)stopTime, "%d", &stop))
		{
			if(((getTimePassSinceToday() < ((start/100)*3600)+((start%100)*60))) || ((((stop/100)*3600)+((stop%100)*60)) <= getTimePassSinceToday()))
			{
				result = TRUE;
			}
		}
	}

	return result;
}

/**
 * Show communication raw data to debug info
 * @param data: raw data
 * @param len: data length
 * @param isRX: is receive data
 */
void show_raw(uint8_t *data, uint16_t len, uint8_t isRX)
{
	uint8_t output[512]={0};

	if(isRX)
		DEBUG_INFO("RX ---------------------------------------------\n");
	else
		DEBUG_INFO("TX ---------------------------------------------\n");

	DEBUG_INFO(" 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F \n");
	DEBUG_INFO("------------------------------------------------\n");

	memset(output, 0x00, ARRAY_SIZE(output));
	for(int idx=0;idx<len;idx++)
	{
		if(strlen((char*)output)<48)
			sprintf((char*)output, "%s%02X ", output, data[idx]);
		else
		{
			DEBUG_INFO("%s\n", output);
			memset(output, 0x00, ARRAY_SIZE(output));
			sprintf((char*)output, "%s%02X ", output, data[idx]);
		}
	}
	DEBUG_INFO("%s\n", output);
}

/**
 *
 * @param dec: number in dec
 * @return number in bcd
 */
int decTobcd(int dec)
{
	return (dec/10 * 16)+ (dec%10);
}

/**
 *
 * @param data: message array
 * @param dataLen: command & data field length in array
 * @return check sum result
 */
uint8_t calChksum(Message *data)
{
	uint8_t result = 0;

	for(uint16_t idx=1;idx<(data->size-3);idx++)
	{
		result += data->buffer[idx];
	}

	//DEBUG_INFO("calChksum: %02X\n", (result&0xff));

	return result;
}

/**
 *
 * @param result
 */
void getDateTimeString(char* result)
{
	time_t CurrentTime;
	struct tm *tm;

	CurrentTime = time(NULL);
	tm=localtime(&CurrentTime);

	sprintf(result, "%04d%02d%02d%02d%02d%02d", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
}

//==========================================
// Init share memory
//==========================================
/**
 * Share memory initialization
 * @return function result
 */
int InitShareMemory()
{
	int result = PASS;
	int MeterSMId;

#ifndef X86
	//init ShmSysConfigAndInfo
	if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0)
    {
		DEBUG_ERROR("shmget ShmSysConfigAndInfo NG\n");
		result = FAIL;
	}
    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
    	DEBUG_ERROR("shmat ShmSysConfigAndInfo NG\n");
    	result = FAIL;
   	 }
    else
    {}

	//init ShmStatusCodeData
	if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
	{
		DEBUG_ERROR("shmget ShmStatusCodeData NG\n");
		result = FAIL;
	}
	else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
	{
		DEBUG_ERROR("shmat ShmStatusCodeData NG\n");
		result = FAIL;
	}
	else
	{}

   	//init ShmOCPP16Data
   	if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data),  0777)) < 0)
	{
		DEBUG_ERROR("shmget ShmOCPP16Data NG\n");
		result = FAIL;
	}
	else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
	{
		DEBUG_ERROR("shmat ShmOCPP16Data NG\n");
		result = FAIL;
	}
	else
	{}

   	// Parsing model name to get related info about charger
	if(RatedCurrentParsing((char*)ShmSysConfigAndInfo->SysConfig.ModelName, &modelnameInfo) != -1)
	{
		DEBUG_INFO("Model name rated power: %d\n", modelnameInfo.ratedPower);
		if((ShmSysConfigAndInfo->SysConfig.ModelName[0]=='D') &&
		   ((ShmSysConfigAndInfo->SysConfig.ModelName[1]=='B') ||
			(ShmSysConfigAndInfo->SysConfig.ModelName[1]=='K') ||
			(ShmSysConfigAndInfo->SysConfig.ModelName[1]=='O'))
		   ) // 'D' means DC
		{
			// DO series
			for(int gun_index=0; gun_index<GENERAL_GUN_QUANTITY ; gun_index++)
			{
				gunType[gun_index] = GUN_TYPE_DO;

				switch(modelnameInfo.ParsingInfo[gun_index].GunType)
				{
					case Gun_Type_Chademo:
						DEBUG_INFO("Gun-%02d type: Cabinet CHAdeMO\n", gun_index);
						break;
					case Gun_Type_CCS_2:
						DEBUG_INFO("Gun-%02d type: Cabinet CCS\n", gun_index);
						break;
					case Gun_Type_GB:
						DEBUG_INFO("Gun-%02d type: Cabinet GBT\n", gun_index);
						break;
					case Gun_Type_AC:
						DEBUG_INFO("Gun-%02d type: Cabinet AC\n", gun_index);
						break;
					default:
						DEBUG_WARN("Gun-%02d type: Cabinet unknown\n", gun_index);
						break;
				}
			}
		}
		else
		{
			for(int gun_index=0;gun_index<modelnameInfo.GetGunCount;gun_index++)
			{
				switch(modelnameInfo.ParsingInfo[gun_index].GunType)
				{
					case Gun_Type_Chademo:
						gunType[gun_index] = GUN_TYPE_CHAdeMO;
						DEBUG_INFO("Gun-%02d type: CHAdeMO\n", gun_index);
						break;
					case Gun_Type_CCS_2:
						gunType[gun_index] = GUN_TYPE_CCS;
						DEBUG_INFO("Gun-%02d type: CCS\n", gun_index);
						break;
					case Gun_Type_GB:
						gunType[gun_index] = GUN_TYPE_GBT;
						DEBUG_INFO("Gun-%02d type: GBT\n", gun_index);
						break;
					case Gun_Type_AC:
						gunType[gun_index] = GUN_TYPE_AC;
						DEBUG_INFO("Gun-%02d type: AC\n", gun_index);
						break;
					default:
						DEBUG_WARN("Gun-%02d type: Unknown\n", gun_index);
						break;
				}
			}
		}
	}
	else
	{
		DEBUG_ERROR("Model name parsing fail.\n");
		result = FAIL;
	}
#endif

   	return result;
}

//==========================================
// Init com port
//==========================================
/**
 * TTY port initialization
 * @return port initial result
 */
int InitComPort()
{
	int fd;
	struct termios tios;

	fd = open(TTY_PORT, O_RDWR);
	if(fd<=0)
	{
		return FAIL;
	}
	ioctl (fd, TCGETS, &tios);
	tios.c_cflag = B9600| CS8 | CLOCAL | CREAD;
	tios.c_lflag = 0;
	tios.c_iflag = 0;
	tios.c_oflag = 0;
	tios.c_cc[VMIN]=0;						// data length threshold, 0 bytes
	tios.c_cc[VTIME]=(unsigned char)5;		// timeout threshold, 0.5 seconds
	tios.c_lflag=0;
	ioctl (fd, TCSETS, &tios);
	tcflush(fd, TCIFLUSH);

	read(fd, NULL, 512);

	return fd;
}

/**
 *
 * @param uart
 * @return
 */
int getInputBufferCount(int uart)
{
	int bytes_avail = 0;

	if(ioctl(uart, FIONREAD, &bytes_avail) < 0)
	{
		DEBUG_INFO("FIONREAD ioctl failed\n");
	}
	else
	{
		//DEBUG_INFO("bytes_avail: %d\n", bytes_avail);
	}

	return bytes_avail;
}

/**
 *
 * @param uart
 * @param rx
 * @return
 */
int pollingRequest(int uart, Message* rx)
{
	int result=FAIL;

	rx->size = read(uart, rx->buffer, ARRAY_SIZE(rx->buffer));

#ifdef DEBUG
	show_raw(rx->buffer, rx->size, YES);
#endif

	if(calChksum(rx))
	{
		result = PASS;
	}

	return result;
}

/**
 *
 * @param uart
 * @param tx
 * @return
 */
int pollingResponse(int uart, Message* tx)
{
	int result=FAIL;

	tcflush(uart,TCIOFLUSH);
	tx->buffer[tx->size-3] = calChksum(tx);

#ifdef DEBUG
	show_raw(tx->buffer, tx->size, NO);
#endif

	if(write(uart, tx->buffer, tx->size) > 0)
	{
		result = PASS;
	}
	else
	{
		DEBUG_ERROR("pollingResponse fail.\n");
	}

	return result;
}

/**
 *
 * @param gun_index
 */
void getResponseState(uint8_t gun_index, uint8_t *charger_state, uint8_t *energy)
{
	struct ChargingInfoData *targetChargingInfoData = NULL;

	// Get target gun data
	if(gunType[gun_index] == GUN_TYPE_CHAdeMO)
	{
		for (int index = 0; index < CHAdeMO_QUANTITY; index++)
		{
			if ((ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index].Index == gun_index))
			{
				targetChargingInfoData = &ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index];
				break;
			}
		}
	}
	else if(gunType[gun_index] == GUN_TYPE_CCS)
	{
		for (int index = 0; index < CCS_QUANTITY; index++)
		{
			if ((ShmSysConfigAndInfo->SysInfo.CcsChargingData[index].Index == gun_index))
			{
				targetChargingInfoData = &ShmSysConfigAndInfo->SysInfo.CcsChargingData[index];
				break;
			}
		}
	}
	else if(gunType[gun_index] == GUN_TYPE_GBT)
	{
		for (int index = 0; index < GB_QUANTITY; index++)
		{
			if ((ShmSysConfigAndInfo->SysInfo.GbChargingData[index].Index == gun_index))
			{
				targetChargingInfoData = &ShmSysConfigAndInfo->SysInfo.GbChargingData[index];
				break;
			}
		}
	}
	else if(gunType[gun_index] == GUN_TYPE_DO)
	{
		for (int index = 0; index < GENERAL_GUN_QUANTITY; index++)
		{
			if ((ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].GeneralChargingData.Index == gun_index))
			{
				targetChargingInfoData = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].GeneralChargingData;
				break;
			}
		}
	}
	else if(gunType[gun_index] == GUN_TYPE_AC)
	{
		for (int index = 0; index < AC_QUANTITY; index++)
		{
			if ((ShmSysConfigAndInfo->SysInfo.AcChargingData[index].Index == gun_index))
			{
				targetChargingInfoData = &ShmSysConfigAndInfo->SysInfo.AcChargingData[index];
				break;
			}
		}
	}

	// 1. Check gun status and cover to Enegate state code
	if(targetChargingInfoData != NULL)
	{
		if(targetChargingInfoData->SystemStatus == SYS_MODE_BOOTING)//S_IDLE
		{
			sprintf((char*)charger_state, "%05d", 0);
			memcpy(&tx.buffer[3], &charger_state[0], 5);
		}
		else if((targetChargingInfoData->SystemStatus == SYS_MODE_IDLE) || (targetChargingInfoData->SystemStatus == SYS_MODE_AUTHORIZING))//S_IDLE
		{
			if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isConnectTimeout)
			{
				if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable)
				{
					sprintf((char*)charger_state, "%05d", 1000);
					memcpy(&tx.buffer[3], &charger_state[0], 5);
				}
				else
				{
					sprintf((char*)charger_state, "%05d", 41000);
					memcpy(&tx.buffer[3], &charger_state[0], 5);
				}
			}
			else
			{
				sprintf((char*)charger_state, "%05d", 2010);
				memcpy(&tx.buffer[3], &charger_state[0], 5);
				ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isConnectTimeout = OFF;
			}
		}
		else if ( ((targetChargingInfoData->SystemStatus >= SYS_MODE_MODE_REASSIGN_CHECK)&&(targetChargingInfoData->SystemStatus <= SYS_MODE_PREPARE_FOR_EVSE)) ||
				  ((targetChargingInfoData->SystemStatus >= SYS_MODE_CCS_PRECHARGE_STEP0) && (targetChargingInfoData->SystemStatus <= SYS_MODE_CCS_PRECHARGE_STEP1) )
				) //S_PRECHARGE
		{
			if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isConnectTimeout)
			{
				if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable)
				{
					sprintf((char*)charger_state, "%05d", 2000);
					memcpy(&tx.buffer[3], &charger_state[0], 5);
				}
				else
				{
					sprintf((char*)charger_state, "%05d", 42000);
					memcpy(&tx.buffer[3], &charger_state[0], 5);
				}
			}
			else
			{
				sprintf((char*)charger_state, "%05d", 2010);
				memcpy(&tx.buffer[3], &charger_state[0], 5);
				ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isConnectTimeout = OFF;
			}
		}
		else if (targetChargingInfoData->SystemStatus == SYS_MODE_CHARGING) //S_CHARGING
		{
			if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable)
			{
				sprintf((char*)charger_state, "%05d", 3000);
				memcpy(&tx.buffer[3], &charger_state[0], 5);

				sprintf((char*)energy, "%08d", (int)(targetChargingInfoData->PresentChargedEnergy*100));
				memcpy(&tx.buffer[22], &energy[0], 8);
				memcpy(&tx.buffer[30], &energy[0], 8);
			}
			else
			{
				sprintf((char*)charger_state, "%05d", 43000);
				memcpy(&tx.buffer[3], &charger_state[0], 5);

				sprintf((char*)energy, "%08d", (int)(targetChargingInfoData->PresentChargedEnergy*100));
				memcpy(&tx.buffer[22], &energy[0], 8);
				memcpy(&tx.buffer[30], &energy[0], 8);
			}
		}
		else if ((targetChargingInfoData->SystemStatus == SYS_MODE_TERMINATING) || (targetChargingInfoData->SystemStatus == SYS_MODE_COMPLETE))
		{
			if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable)
			{
				/*
				 *	TODO:
				 *	1. Stop reason transfer
				 */
				sprintf((char*)charger_state, "%05d", 5020);
				memcpy(&tx.buffer[3], &charger_state[0], 5);

				sprintf((char*)energy, "%08d", (int)(targetChargingInfoData->PresentChargedEnergy*100));
				memcpy(&tx.buffer[22], &energy[0], 8);
				memcpy(&tx.buffer[30], &energy[0], 8);
			}
			else
			{
				/*
				 *	TODO:
				 *	1. Stop reason transfer
				 */
				sprintf((char*)charger_state, "%05d", 45020);
				memcpy(&tx.buffer[3], &charger_state[0], 5);

				sprintf((char*)energy, "%08d", (int)(targetChargingInfoData->PresentChargedEnergy*100));
				memcpy(&tx.buffer[22], &energy[0], 8);
				memcpy(&tx.buffer[30], &energy[0], 8);
			}
		}
		else if ((targetChargingInfoData->SystemStatus == SYS_MODE_MAINTAIN) || (targetChargingInfoData->SystemStatus == SYS_MODE_DEBUG) || (targetChargingInfoData->SystemStatus == SYS_MODE_UPDATE)) //  ---> Unavailable
		{
			if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable)
			{
				sprintf((char*)charger_state, "%05d", 100);
				memcpy(&tx.buffer[3], &charger_state[0], 5);
			}
			else
			{
				sprintf((char*)charger_state, "%05d", 40100);
				memcpy(&tx.buffer[3], &charger_state[0], 5);
			}
		}
		else if ((targetChargingInfoData->SystemStatus == SYS_MODE_FAULT) || (targetChargingInfoData->SystemStatus == SYS_MODE_ALARM)) //S_ALARM,S_FAULT   ---> Faulted
		{
			if(!ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable)
			{
				if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.EmergencyStopTrip)
				{
					sprintf((char*)charger_state, "%05d", 5108);
				}
				else if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.ChademoGfdTrip ||
						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.GbGfdTrip ||
						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CcsGfdTrip ||
						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcGroundfaultFail)
				{
					sprintf((char*)charger_state, "%05d", 5109);
				}
				else if(ShmStatusCodeData->FaultCode.FaultEvents.bits.ChademoConnectorLockFail ||
						ShmStatusCodeData->FaultCode.FaultEvents.bits.GbConnectorLockFail ||
						ShmStatusCodeData->FaultCode.FaultEvents.bits.AcConnectorLockFail)
				{
					sprintf((char*)charger_state, "%05d", 5104);
				}
				else if(ShmStatusCodeData->InfoCode.InfoEvents.bits.ChademoIsolationResultFail ||
						ShmStatusCodeData->InfoCode.InfoEvents.bits.ERROR_CODE_GBT_ISOLATION_RESULT_FAIL)
				{
					sprintf((char*)charger_state, "%05d", 5102);
				}
				else
				{
					sprintf((char*)charger_state, "%05d", 5107);
				}

				memcpy(&tx.buffer[3], &charger_state[0], 5);
			}
			else
			{
				if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.EmergencyStopTrip)
				{
					sprintf((char*)charger_state, "%05d", 45108);
				}
				else if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.ChademoGfdTrip ||
						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.GbGfdTrip ||
						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CcsGfdTrip ||
						ShmStatusCodeData->AlarmCode.AlarmEvents.bits.AcGroundfaultFail)
				{
					sprintf((char*)charger_state, "%05d", 45109);
				}
				else if(ShmStatusCodeData->FaultCode.FaultEvents.bits.ChademoConnectorLockFail ||
						ShmStatusCodeData->FaultCode.FaultEvents.bits.GbConnectorLockFail ||
						ShmStatusCodeData->FaultCode.FaultEvents.bits.AcConnectorLockFail)
				{
					sprintf((char*)charger_state, "%05d", 45104);
				}
				else if(ShmStatusCodeData->InfoCode.InfoEvents.bits.ChademoIsolationResultFail ||
						ShmStatusCodeData->InfoCode.InfoEvents.bits.ERROR_CODE_GBT_ISOLATION_RESULT_FAIL)
				{
					sprintf((char*)charger_state, "%05d", 45102);
				}
				else
				{
					sprintf((char*)charger_state, "%05d", 45107);
				}

				memcpy(&tx.buffer[3], &charger_state[0], 5);
			}
		}
	}
}

//==========================================
// Main loop
//==========================================
int main(void)
{
	int UartFd;

	//===============================================
	// Initialization
	//===============================================
	if(InitShareMemory() == FAIL)
	{
		DEBUG_ERROR("InitShareMemory NG\n");

		if(ShmStatusCodeData!=NULL)
		{
			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory=1;
		}
		sleep(5);
		return FAIL;
	}

	UartFd=InitComPort();
	if(UartFd<0)
	{
		DEBUG_ERROR("InitComPort NG\n");
		if(ShmStatusCodeData!=NULL)
		{
			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.CsuInitFailed=1;
		}
		sleep(5);
		return FAIL;
	}
	else
	{
		DEBUG_INFO("%s port open success.\n", TTY_PORT);
	}

	refreshStartTimer(&tmr[0][TIMER_COMM_TIMEOUT]);
	DEBUG_INFO("Payment module initialize completed...%s\n", FIRMWARE_VERSION);

	for(;;)
	{
		if(ShmSysConfigAndInfo->SysInfo.enegate.isEnable)
		{
			// Communication timeout
			if(getDiffSecNow(tmr[0][TIMER_COMM_TIMEOUT]) >= 10)
			{
				if(!ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout)
				{
					ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout = ON;
					DEBUG_WARN("Payment system communication timeout.\n");
				}
			}
			else
			{
				if(ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout)
				{
					ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout = OFF;
					DEBUG_WARN("Payment system communication recover.\n");
				}
			}

			if((getInputBufferCount(UartFd) >= 24))
			{
				if(pollingRequest(UartFd, &rx))
				{
					refreshStartTimer(&tmr[0][TIMER_COMM_TIMEOUT]);

					uint8_t charger_state[6] = {0};
					uint8_t energy[9] = {0};
					static uint8_t charger_state_previous[6] = {0};
					static uint8_t energy_previous[9] = {0};
					uint16_t cmd = ((rx.buffer[3]-0x30)*1000) + ((rx.buffer[4]-0x30)*100) + ((rx.buffer[5]-0x30)*10) + ((rx.buffer[6]-0x30)*1);
					uint8_t id = rx.buffer[1];
					uint8_t gun_index = (id-0x30-ID_OFFSET);
					tx.size = 41;
					tx.buffer[0] = STX;
					tx.buffer[1] = id;
					tx.buffer[2] = ACK;
					sprintf((char*)&tx.buffer[3], "%05d", 0);
					getDateTimeString((char*)&tx.buffer[8]);
					sprintf((char*)energy, "00000000");
					sprintf((char*)&tx.buffer[22], "00000000");
					sprintf((char*)&tx.buffer[30], "00000000");
					tx.buffer[39] = CR;
					tx.buffer[40] = LF;

					// 1. Check ID in command message
					if(((0<=gun_index) && (gun_index<(ShmSysConfigAndInfo->SysConfig.TotalConnectorCount+1))))
					{
						switch(cmd)
						{
							case HOST_CMD_GET_STATUS:
								getResponseState(gun_index, charger_state, energy);
								if((strstr((char*)charger_state_previous, (char*)charger_state) == NULL) || (strstr((char*)energy_previous, (char*)energy) == NULL))
								{
									DEBUG_INFO("id(%c)=> HOST_CMD_GET_STATUS(1000): %s, Energy: %s\n", id, charger_state, energy);
									memcpy(charger_state_previous, charger_state, ARRAY_SIZE(charger_state));
									memcpy(energy_previous, energy, ARRAY_SIZE(energy));
								}

								break;

							case HOST_CMD_AUTH_CHECKING:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizing = ON;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_AUTH_CHECKING(9000): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_AUTH_CANCEL:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizing = OFF;
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorized = ON;
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizedPass = OFF;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_AUTH_CANCEL(9001): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_AUTH_PASS:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizing = OFF;
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorized = ON;
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizedPass = ON;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_AUTH_PASS(3000): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_AUTH_FAIL:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizing = OFF;
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorized = ON;
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAuthorizedPass = OFF;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_AUTH_FAIL(3001): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_AUTO_START_ENABLE:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable = ON;
								ShmSysConfigAndInfo->SysConfig.AuthorisationMode = 1;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_AUTO_START_ENABLE(0200): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_AUTOSTART_DIABLE:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isAutoStartEnable = OFF;
								ShmSysConfigAndInfo->SysConfig.AuthorisationMode = 0;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_AUTOSTART_DIABLE(0222): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_SESSION_STOP:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isSessionStopReq = ON;

								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_SESSION_STOP(4000): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_PAUSE_ENABLE:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isStopService = ON;
								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_PAUSE_ENABLE(100): %s, Energy: %s\n", id, charger_state, energy);
								break;

							case HOST_CMD_PAUSE_DISABLE:
								ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isStopService = OFF;
								getResponseState(gun_index, charger_state, energy);
								DEBUG_INFO("id(%c)=> HOST_CMD_PAUSE_DISABLE(111): %s, Energy: %s\n", id, charger_state, energy);
								break;

							default:
								getResponseState(gun_index, charger_state, energy);
								DEBUG_WARN("id(%c)=> Unknown host command(%d): %s, Energy: %s.\n", id, cmd, charger_state, energy);
								tx.buffer[2] = NAK;
								break;
						}

						// Synchronize date time every 10 minutes
						if(getDiffSecNow(tmr[gun_index][TIMER_UPDATE_RTC]) >= 600)
						{
							struct tm tmOrg;
							struct tm *tmTarget;
							struct timeb tbTarget;
							char buf[64]={0};

							tmOrg.tm_year = (((rx.buffer[7]-0x30)*1000)+((rx.buffer[8]-0x30)*100)+((rx.buffer[9]-0x30)*10)+((rx.buffer[10]-0x30)*1)) - 1900;
							tmOrg.tm_mon = (((rx.buffer[11]-0x30)*10)+((rx.buffer[12]-0x30)*1)) - 1;
							tmOrg.tm_mday = (((rx.buffer[13]-0x30)*10)+((rx.buffer[14]-0x30)*1));
							tmOrg.tm_hour = (((rx.buffer[15]-0x30)*10)+((rx.buffer[16]-0x30)*1));
							tmOrg.tm_min = (((rx.buffer[17]-0x30)*10)+((rx.buffer[18]-0x30)*1));
							tmOrg.tm_sec = (((rx.buffer[19]-0x30)*10)+((rx.buffer[20]-0x30)*1));
							tmOrg.tm_gmtoff = 0;
							tbTarget.time = mktime(&tmOrg);
							tbTarget.timezone = 0;

							tbTarget.time -= (9*3600); // Japan always in UTC+9
							tmTarget = gmtime(&tbTarget.time);

							sprintf(buf, "date -s '%04d-%02d-%02d %02d:%02d:%02d'", (tmTarget->tm_year+1900), (tmTarget->tm_mon+1), tmTarget->tm_mday, tmTarget->tm_hour, tmTarget->tm_min, tmTarget->tm_sec);
							system(buf);
							system("/sbin/hwclock -w --systohc");

							refreshStartTimer(&tmr[gun_index][TIMER_UPDATE_RTC]);
						}
					}
					else if(id == 'a')
					{
						if(cmd == HOST_CMD_GET_SELECTED_ID)
						{
							static int previousId = -1;

							tx.buffer[1] = (0x30 + ShmSysConfigAndInfo->SysInfo.CurGunSelected + ID_OFFSET);
							sprintf((char*)&tx.buffer[3], "%05d", 9302);

							if(previousId != tx.buffer[1])
							{
								DEBUG_INFO("id(%c)=> HOST_CMD_GET_SELECTED_ID(9301): %c\n", id, tx.buffer[1]);
								previousId = tx.buffer[1];
							}
						}
						else if(cmd == HOST_CMD_SET_SERVICE_TIME)
						{
							memset(ShmSysConfigAndInfo->SysInfo.enegate.serviceStartTimestamp, 0x00, ARRAY_SIZE(ShmSysConfigAndInfo->SysInfo.enegate.serviceStartTimestamp));
							memset(ShmSysConfigAndInfo->SysInfo.enegate.serviceStopTimestamp, 0x00, ARRAY_SIZE(ShmSysConfigAndInfo->SysInfo.enegate.serviceStopTimestamp));

							sprintf((char*)&tx.buffer[3], "%05d", 9200);
							memcpy(ShmSysConfigAndInfo->SysInfo.enegate.serviceStartTimestamp, &rx.buffer[7], 4);
							memcpy(ShmSysConfigAndInfo->SysInfo.enegate.serviceStopTimestamp, &rx.buffer[11], 4);

							DEBUG_INFO("id(%c)=> HOST_CMD_SET_SERVICE_TIME(9200): %s - %s with UTC+9\n", id, ShmSysConfigAndInfo->SysInfo.enegate.serviceStartTimestamp, ShmSysConfigAndInfo->SysInfo.enegate.serviceStopTimestamp);
						}
						else
						{
							DEBUG_WARN("Wrong id(%c) with get selected id command(%d).\n", id, cmd);
							tx.buffer[2] = NAK;
						}
					}
					else
					{
						DEBUG_WARN("Wrong id(%c) with command(%d).\n", id, cmd);
						tx.buffer[2] = NAK;
					}

					/*
					 * 	TODO:
					 * 	1. Service time check locally.
					 * 	2. Usually server will send enable / disable command.
					 */
					//ShmSysConfigAndInfo->SysInfo.enegate.Operation.bits[gun_index].isStopService = isPausedService(ShmSysConfigAndInfo->SysInfo.enegate.serviceStartTimestamp, ShmSysConfigAndInfo->SysInfo.enegate.serviceStopTimestamp);
				}
				else
				{
					// Command with wron check sum.
					tx.size = 41;
					tx.buffer[0] = STX;
					tx.buffer[1] = rx.buffer[1];
					tx.buffer[2] = NAK;
					getDateTimeString((char*)&tx.buffer[8]);
					sprintf((char*)&tx.buffer[22], "00000000");
					sprintf((char*)&tx.buffer[30], "00000000");
					tx.buffer[39] = CR;
					tx.buffer[40] = LF;
				}

				pollingResponse(UartFd, &tx);
			}
		}

		usleep(100000);
	}
}