/*
 * Module_Payment_Ominixpay.c
 *
 *  Created on: 2022/04/29
 *      Author: Folus Wen
 *      run_evse_stop.sh
 */

#include "Module_Payment_Bazel8.h"

struct COMMAND commandRaw;
struct timespec	tmr[TIMER_CNT];
uint16_t nSerial=0;

//==========================================
// 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.%06ld]%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,
			buffer,
			tm->tm_year+1900,tm->tm_mon+1);
	system((const char*)Buf);

#ifdef ConsloePrintLog
	printf("[%04d.%02d.%02d %02d:%02d:%02d.%06ld]%s", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec, 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;
	static time_t lastTime;
	time_t t;
	struct tm *tmStartToday;
	struct timeb tbStartToday;

	t=time(NULL);
	if(difftime(t, lastTime)>0)
	{
		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;
		lastTime = t;
	}

	return result;
}
/**
 * Calculate time differential
 * @param ST: start time
 * @param ET: end time
 * @return time differential in million seconds
 */
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;
}

/**
 * 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
 */
int calChksum(unsigned char *data)
{
	int result = 0;

	for(uint16_t idx=1;idx<(((data[1] << 8) | (data[2]))+3); idx++)
	{
		result ^= data[idx];
	}
    // printf("\n\rThe checksum : %x \n\r", result);
	return (result&0xff);
}

//==========================================
// 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
	{}
#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;
	tcflush(fd, TCIFLUSH);
	ioctl (fd, TCSETS, &tios);

	return fd;
}

/**
 *
 * @param serial port handle
 * @param request message data
 * @param response message data
 * @return
 */
int pollingRequest(int uart, unsigned char* cmd)
{
	int result=FAIL;
	int length;

	tcflush(uart,TCIOFLUSH);
	
	length = ((cmd[1]<<8)|cmd[2])+4;
	cmd[(length-1)] = calChksum(cmd);

	// show_raw(cmd, length, NO);
	
	if(write(uart, cmd, length ) > 0)
	{
		result = PASS;
	}
	else
	{
		DEBUG_ERROR("pollingRequest fail.\n");
	}

	return result;
}

/**
 *
 * @param uart
 * @param rx
 * @return
 */
int pollingResponse(int uart, unsigned char* rx)
{
	int result =FAIL;
	int len = 0;
	int Total_len[2] = {0, 0};
	int CSUM[2]={0,0};
	uint8_t buf[512];
    
    // DEBUG_INFO("\n\r===== Prepare to read serial data. ===============\n\r");
    
    do {
        len =read(uart, buf, 512);
        if(len == 0)
            break;
            
        // printf ("This is a string %d chars long\n", len);
        for (int i=0; i<len; i++)
        {
            rx[(Total_len[0]+i)] =buf[i];
        }
        
        memcpy(&rx[(Total_len[0])], buf, len);
        
        if(Total_len[0] == 0)
            Total_len[1] = ((buf[1] << 8) | (buf[2]))+4;           // lead 3 + csum
        Total_len[0] = Total_len[0] + len;
        
	    usleep(10);
	} while (Total_len[0] < Total_len[1]);
	
	if(Total_len[0] >0)
	{
	    // show_raw(rx, Total_len[1], YES);

        CSUM[0] = rx[(((rx[1] << 8) | (rx[2]))+3)];
        CSUM[1] = calChksum(&rx[0]);
    
	    if(CSUM[0] == CSUM[1])
	    {
		    result = PASS;
		    DEBUG_INFO("\n\r===== Receive data checksum (%x , %x) OK. ===============\n\r", CSUM[0], CSUM[1]);
	    }
	    else 
        {
            DEBUG_INFO("\n\r===== Receive data checksum (%x , %x) Fail. ===============\n\r", CSUM[0], CSUM[1]);
        }
    }
	return result;
}

/**
 *
 * @param uart
 * @return
 */
int getInputBufferCount(int uart)
{
	int bytes_avail;
	
	ioctl(uart, FIONREAD, &bytes_avail);

	return bytes_avail;
}

/**
 *
 * @param node
 * @param node_name
 * @return
 */
xmlNode *find_node(xmlNode *node, char *node_name)
{
	xmlNode *result;

	if (node == NULL) return NULL;

	while(node)
	{
		if((node->type == XML_ELEMENT_NODE) && (strcmp((char*)node->name, node_name) == 0)) return node;

		if((result = find_node(node->children, node_name))) return result;

		node = node->next;
	}

  return NULL;
}

//==========================================
// Reader operation function
//==========================================
int InfoMgmtRequest(int uart)
{
	char xmlBody[1024]={0};
	int n;

	xmlBuffer * outputXmlPtr = xmlBufferCreate();
	xmlDocPtr doc = NULL;
	xmlNodePtr node_req = NULL;
	xmlNodePtr node_cmd = NULL;
	xmlNodePtr node_param = NULL;
	xmlNodePtr node_param_Info = NULL;

	// Create xml message
	doc = xmlNewDoc(BAD_CAST "1.0");
	node_req = xmlNewNode(NULL, BAD_CAST "Req");
	xmlDocSetRootElement(doc, node_req);

	node_cmd = xmlNewNode(NULL, BAD_CAST "Cmd");
	xmlNewChild(node_cmd, NULL, BAD_CAST "CmdId", BAD_CAST "InfoMgmt");
	xmlNewChild(node_cmd, NULL, BAD_CAST "CmdTout", BAD_CAST "30");
	xmlAddChild(node_req, node_cmd);

	node_param = xmlNewNode(NULL, BAD_CAST "Param");
	node_param_Info = xmlNewNode(NULL, BAD_CAST "Info");
	
	xmlNewChild(node_param_Info, NULL, BAD_CAST "Id", BAD_CAST "GetSystemVer");

	xmlAddChild(node_param, node_param_Info);
	xmlAddChild(node_req, node_param);

    xmlNodeDump(outputXmlPtr, NULL, (xmlNode *)node_req, 0, 0);
    n = sprintf(xmlBody, "%s", (const char *)outputXmlPtr->content);
    
    DEBUG_INFO("[%s] is a string %d chars long\n", xmlBody, n);

    xmlBufferFree(outputXmlPtr);
    xmlFreeDoc(doc);
    xmlCleanupParser();
    xmlMemoryDump();

	// Create protocol message
	memset(commandRaw.requestData, 0x00, ARRAY_SIZE(commandRaw.requestData));

	commandRaw.requestData[0] = STX;
	commandRaw.requestData[1] = (strlen(xmlBody)>>8)&0xff;
	commandRaw.requestData[2] = (strlen(xmlBody)>>0)&0xff;
	memcpy(&commandRaw.requestData[3], xmlBody, strlen(xmlBody));

    //show_raw(&commandRaw.requestData[0], (strlen(xmlBody)+3), NO);

	return pollingRequest(uart, commandRaw.requestData);
}

int preAuthRequest(int uart)
{
	char xmlBody[1024]={0};
	int n;

	xmlBuffer * outputXmlPtr = xmlBufferCreate();
	xmlDocPtr doc = NULL;
	xmlNodePtr node_req = NULL;
	xmlNodePtr node_cmd = NULL;
	xmlNodePtr node_param = NULL;
	xmlNodePtr node_param_Txn = NULL;

	// Create xml message
	doc = xmlNewDoc(BAD_CAST "1.0");
	node_req = xmlNewNode(NULL, BAD_CAST "Req");
	xmlDocSetRootElement(doc, node_req);

	node_cmd = xmlNewNode(NULL, BAD_CAST "Cmd");
	xmlNewChild(node_cmd, NULL, BAD_CAST "CmdId", BAD_CAST "TxnStart");
	xmlNewChild(node_cmd, NULL, BAD_CAST "CmdTout", BAD_CAST "30");
	xmlAddChild(node_req, node_cmd);

	node_param = xmlNewNode(NULL, BAD_CAST "Param");
	node_param_Txn = xmlNewNode(NULL, BAD_CAST "Txn");
	xmlNewChild(node_param_Txn, NULL, BAD_CAST "TxnType", BAD_CAST "AuthOnly");
	xmlNewChild(node_param_Txn, NULL, BAD_CAST "AccType", BAD_CAST "Default");
	xmlNewChild(node_param_Txn, NULL, BAD_CAST "CurrCode", BAD_CAST ISO_4217_Currency_Code[ShmSysConfigAndInfo->SysConfig.BillingData.Currency]);
	//xmlNewChild(node_param_Txn, NULL, BAD_CAST "CurrCode", BAD_CAST "840");
	xmlNewChild(node_param_Txn, NULL, BAD_CAST "TxnAmt", BAD_CAST ShmOCPP16Data->ConfigurationTable.CoreProfile[PreAuthAmount].ItemData);
	//xmlNewChild(node_param_Txn, NULL, BAD_CAST "TxnAmt", BAD_CAST "0001.00");

	xmlAddChild(node_param, node_param_Txn);
	xmlAddChild(node_req, node_param);

    xmlNodeDump(outputXmlPtr, NULL, (xmlNode *)node_req, 0, 0);
    n = sprintf(xmlBody, "%s", (const char *)outputXmlPtr->content);
    
    DEBUG_INFO("[%s] is a string %d chars long\n", xmlBody, n);

    xmlBufferFree(outputXmlPtr);
    xmlFreeDoc(doc);
    xmlCleanupParser();
    xmlMemoryDump();

	// Create protocol message
	memset(commandRaw.requestData, 0x00, ARRAY_SIZE(commandRaw.requestData));

	commandRaw.requestData[0] = STX;
	commandRaw.requestData[1] = (strlen(xmlBody)>>8)&0xff;
	commandRaw.requestData[2] = (strlen(xmlBody)>>0)&0xff;
	memcpy(&commandRaw.requestData[3], xmlBody, strlen(xmlBody));

    //show_raw(&commandRaw.requestData[0], (strlen(xmlBody)+3), NO);

	return pollingRequest(uart, commandRaw.requestData);
}

int preAuthResponse(int uart)
{
	int result = pollingResponse(uart, commandRaw.responseData);
	
	//char *xmlTestBody = "<Event><MesgId>21</MesgId><MesgStr>PLEASE PRESENT CARD</MesgStr></Event>";
	//char *xmlTestBody = "<Event><MesgId>27</MesgId><MesgStr>AUTHORIZING. PLEASE WAIT...</MesgStr></Event>";
	//char *xmlTestBody = "<Resp><Cmd><CmdId>TxnStartResp</CmdId><StatusCode>001F</StatusCode><StatusText>TransactionDeferred</StatusText></Cmd><Data><Txn><TxnId>62</TxnId></Txn></Data></Resp>";
	
	char xmlTestBody[1024] = {0};

	if(result == PASS)
	{
		memcpy(xmlTestBody, &commandRaw.responseData[3], ((commandRaw.responseData[1] << 8) | commandRaw.responseData[2]));

		xmlDocPtr doc = xmlParseDoc((const xmlChar *)xmlTestBody);
		xmlNode *root_element = xmlDocGetRootElement(doc);

		if(find_node(root_element, "Event") != NULL)
		{
			DEBUG_INFO("===== Get event =======================\n");
			ShmSysConfigAndInfo->SysInfo.bazel8.event.messageId = atoi((char*)xmlNodeGetContent(find_node(root_element, "MesgId")));
			sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.event.messageString, "%s", xmlNodeGetContent(find_node(root_element, "MesgId")));
			ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn = ON;

			DEBUG_INFO("Message id: %d\n", ShmSysConfigAndInfo->SysInfo.bazel8.event.messageId);
			DEBUG_INFO("%s: %s\n", root_element->children->next->name, xmlNodeGetContent(root_element->children->next));
		}
		else if((find_node(root_element, "Resp") != NULL) && (strstr((char*)xmlNodeGetContent(find_node(root_element, "CmdId")), "TxnStartResp") != NULL))
		{
			DEBUG_INFO("===== Get response =======================\n");
			ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = ON;
			
			sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode, "%s", xmlNodeGetContent(find_node(root_element, "StatusCode")));
			sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusText, "%s", xmlNodeGetContent(find_node(root_element, "StatusText")));

			DEBUG_INFO("Status code: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode);
			DEBUG_INFO("Status text: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusText);
			
			if(strstr(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode,"0000") != NULL)
			{
			    sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId, "%s", xmlNodeGetContent(find_node(root_element, "TxnId")));
			    DEBUG_INFO("TxnId: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId);
			}
		}
		else
		{
			DEBUG_INFO("===== Get unknown node =======================\n");
		}
        
        //DEBUG_INFO("===== End 0 =======================\n");
	    xmlFreeDoc(doc);
	    //DEBUG_INFO("===== End 1 =======================\n");
	    xmlCleanupParser();
	    //DEBUG_INFO("===== End 2 =======================\n");
	    xmlMemoryDump();
	    //DEBUG_INFO("===== End 3 =======================\n");
	}
	else 
    {
        if((nSerial++ % 5)==0)
            DEBUG_INFO("===== Get preAuth Response is Fail =====( %d)==========\n", (nSerial-1));
        nSerial %= 0xffff;
    }

	return result;
}

int InfoMgmtResponse(int uart)
{
	int result = pollingResponse(uart, commandRaw.responseData);
	
	//char *xmlTestBody = "<Resp><Cmd><CmdId>InfoMgmtResp</CmdId><StatusCode>001F</StatusCode><StatusText>TransactionDeferred</StatusText></Cmd>
	//                     <Data><Info><Id>InfoMgmt</Id><SysVer>[System Firmware Version]</SysVer>
	//                     <AppVer>[Application Version]</AppVer><SerialNum>[Serial Number]</SerialNum></Info></Data></Resp>";
	
	char xmlTestBody[1024] = {0};

	if(result == PASS)
	{
		memcpy(xmlTestBody, &commandRaw.responseData[3], ((commandRaw.responseData[1] << 8) | commandRaw.responseData[2]));

		xmlDocPtr doc = xmlParseDoc((const xmlChar *)xmlTestBody);
		xmlNode *root_element = xmlDocGetRootElement(doc);

		if((find_node(root_element, "Resp") != NULL) && (strstr((char*)xmlNodeGetContent(find_node(root_element, "CmdId")), "InfoMgmtResp") != NULL))
		{
			DEBUG_INFO("===== Get InfoMgmt response =======================\n");
			// ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = ON;
			
			sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode, "%s", xmlNodeGetContent(find_node(root_element, "StatusCode")));
			sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusText, "%s", xmlNodeGetContent(find_node(root_element, "StatusText")));

			DEBUG_INFO("Status code: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode);
			DEBUG_INFO("Status text: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusText);
			
			if(strstr(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode,"0000") != NULL)
			{
			    ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = ON;
			    sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId, "%s", xmlNodeGetContent(find_node(root_element, "SysVer")));
			    DEBUG_INFO("System Firmware Version: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId);
			    sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId, "%s", xmlNodeGetContent(find_node(root_element, "AppVer")));
			    DEBUG_INFO("Application Version: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId);
			    sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId, "%s", xmlNodeGetContent(find_node(root_element, "SerialNum")));
			    DEBUG_INFO("Serial Number: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId);
			}
		}
		else
		{
			DEBUG_INFO("===== Get unknown node =======================\n");
		}
        
        //DEBUG_INFO("===== End 0 =======================\n");
	    xmlFreeDoc(doc);
	    //DEBUG_INFO("===== End 1 =======================\n");
	    xmlCleanupParser();
	    //DEBUG_INFO("===== End 2 =======================\n");
	    xmlMemoryDump();
	    //DEBUG_INFO("===== End 3 =======================\n");
	}
	else 
    {
        if((nSerial++ % 5)==0)
            DEBUG_INFO("===== Get InfoMgmt Response is Fail =====( %d)==========\n", (nSerial-1));
        nSerial %= 0xffff;
    }

	return result;
}
//==========================================
// Main loop
//==========================================
int main(void)
{
	int UartFd;
	//int preAuthRetry = 0;
	int cmdRepeatCount = 0;
	
	// Henry
	int state[2] = {s_NONE, s_NONE};
	//uint8_t Rx_Cir_Buf[1024];
	//uint8_t Rx_Buf[1024];
    //int Rx_Cir_Idx[2], Rx_Buf_Idx;
    
    
	//===============================================
	// Initialization
	//===============================================
	
//	Rx_Cir_Idx[0] = Rx_Cir_Idx[1] = Rx_Buf_Idx = 0;
//	
//	for (int i=0; i<1024; i++)
//    {
//        Rx_Cir_Buf[i] =Rx_Buf[i] =0;
//    }
		
#ifndef X86
	if(InitShareMemory() == FAIL)
	{
		DEBUG_ERROR("InitShareMemory NG\n");

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

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

	DEBUG_INFO("Payment module initialize completed.\n");

    ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;                // from CSU 
	ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isWaitRes = false;
	ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = false;
	ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = false;
	ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout = false;

	//===============================================
	// Main loop
	//===============================================
    
    while (1) {
//         if(state[0] != state[1])
//         {
//            state[1] = 1;
//            
//            preAuthRequest(UartFd);
//                        
//         }
//         
//         if(state[1] == 1)
//         {
//            // pollingResponse(UartFd, Rx_Buf);
//            preAuthResponse(UartFd);
//         }

         /*
         CSU 將 cmdPreAuth.isReq 設定 true 的同時也要將 cmdPreAuth.isRes 設定為 false,然後等 cmdPreAuth.isRes 為 true 才表示交易已完成。         
         */
         switch(state[0])
         {
         case s_NONE:
            state[0] = s_INFO;
            state[1] = s_NONE;
            DEBUG_INFO(">> PayError: %d\n", ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout);
            break;
         case s_INFO:
            if(state[0] != state[1])
            {
                state[1] = state[0];
                cmdRepeatCount = 0;
                DEBUG_INFO("Perpare Selftest...\n");
            }
                
            if(InfoMgmtRequest(UartFd))
            {
                cmdRepeatCount = 0;
                refreshStartTimer(&tmr[TIMER_READ_RESPONSE]);       
                state[0] = s_INFO_WAIT_RESPONE;
            }
            else 
            {
                cmdRepeatCount++;
                if(cmdRepeatCount > SPEC_REQUEST_RETRY)
			    {   
				    DEBUG_WARN("preAuthRequest fail over count(%d).", cmdRepeatCount);
				
				    cmdRepeatCount = 0;
				    // Raise a error for Payment Task.
				    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout = true;
				    DEBUG_INFO(" Raise a error for Payment Task...\n");
				    DEBUG_INFO(">> PayError: %d\n", ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout);  
				    
				    state[0] = s_NONE;
			    }
            }
            break;
         case s_INFO_WAIT_RESPONE:
            if(state[0] != state[1])
            {
                state[1] = state[0];
                ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = OFF; 
                nSerial = 0;
                DEBUG_INFO("Wait Selftest Respone...\n");
            }
            
            do {
                if( InfoMgmtResponse(UartFd) )
                {
                    if(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn)
					{
					    state[0] = s_IDLE;
					    ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout = false;
					}
                }
                
                if((getDiffSecNow(tmr[TIMER_READ_RESPONSE]) > TIMEOUT_REQUEST))
				{   
					DEBUG_WARN("Wait pre auth response timeout(%d secs).\n", TIMEOUT_REQUEST);
					
					// Raise a error for Payment Task.
					ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout = true;
					DEBUG_INFO(" Raise a error for Payment Task...\n");
					DEBUG_INFO(">> PayError: %d\n", ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PaymentCommTimeout);
					
					state[0] = s_NONE;					
					break;
				}
				
            } while (ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn != ON);
            break;
         case s_IDLE:
            if(state[0] != state[1])
            {
                state[1] = state[0];
                DEBUG_INFO(" Enter the Idle state...\n");
                
                ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;
                DEBUG_INFO(">> isResultPass: %d\n", ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass);
                DEBUG_INFO(">> isRes: %d\n", ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes);                
            }
                
            if(ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq)
            {
                DEBUG_INFO(" Raise the isReq flag...\n");
                
                ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;
                
                strcpy((char *)ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId, "");
                strcpy((char *)ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode, "");
                strcpy((char *)ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusText, "");
                
                ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = false;
	            ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = false;     // The CSU should be set to false.
                
                state[0] = s_SEND_AUTH_ONLY;
            }
            break;
         case s_SEND_AUTH_ONLY:
            if(state[0] != state[1])
            {
                state[1] = state[0];
                cmdRepeatCount = 0;
                DEBUG_INFO(" Send Auth-Only state...\n");
            }
                 
            if(preAuthRequest(UartFd))
            {
               refreshStartTimer(&tmr[TIMER_READ_RESPONSE]); 
                
               cmdRepeatCount = 0;      
               state[0] = s_WAIT_RESPONE;
            }
            else 
            {
                cmdRepeatCount++;
                if(cmdRepeatCount > SPEC_REQUEST_RETRY)
			    {
				    DEBUG_WARN("preAuthRequest fail over count(%d).", cmdRepeatCount);
				
				    cmdRepeatCount = 0;
				    ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;
				    ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = false;
				    ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = true;            // To tell CSU is done.
				
				    state[0] = s_IDLE;
			    }
            }
            break;
         case s_WAIT_RESPONE:
            if(state[0] != state[1])
            {
                state[1] = state[0];
                ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = OFF;   
                ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn = OFF;
                nSerial = 0;
                DEBUG_INFO(" Wait Auth-Only Respone state...\n");
            }
            
            do {
                if( preAuthResponse(UartFd) )
                {
                    if(ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn)
					{
					    // *	1. Announce CSU event content.
							 
						ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn = false;
					}
					else if(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn)
					{
						ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = \
						    ((strstr(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode, "0000") != NULL)?true:false);
						        
						ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = true;    // To tell CSU is done.
						
						DEBUG_INFO(">> isResultPass: %d\n", ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass);
                        DEBUG_INFO(">> isRes: %d\n", ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes);
					}
                }
                
                if((getDiffSecNow(tmr[TIMER_READ_RESPONSE]) > TIMEOUT_REQUEST))
				{   
					DEBUG_WARN("Wait pre auth response timeout(%d secs).\n", TIMEOUT_REQUEST);
					
					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = false;
					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = true;        // To tell CSU is done.
					break;
				}
				
            } while (ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn != ON);
            
            state[0] = s_IDLE;
            break;
         default:
            state[0] = s_IDLE;
            break;
         }
    }
	
	return FAIL;
	
//	for(;;)
//	{
//        
//        // need to run the script first : run_evse_stop.sh
//
//		if(ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq)
//		{
//		    
//			// Pre auth request
//			if(!ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isWaitRes)
//			{
//				ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = false;
//				ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn = false;
//				ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = false;
//
//				if(preAuthRequest(UartFd))
//				{
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isWaitRes = true;
//					cmdRepeatCount = 0;
//					refreshStartTimer(&tmr[TIMER_READ_RESPONSE]);
//				}
//
//				if(cmdRepeatCount > SPEC_REQUEST_RETRY)
//				{
//					DEBUG_WARN("preAuthRequest fail over count(%d).", cmdRepeatCount);
//					cmdRepeatCount = 0;
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = false;
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = true;
//				}
//				else
//				{
//					cmdRepeatCount += 1;
//				}
//			}
//			else
//			{
//				if((getInputBufferCount(UartFd) >= RAW_DATA_LENGTH))
//				{				    
//
//				    //DEBUG_INFO("\n\rTo wait Payment preAuth Response.\n\r");
//				    
//					if(preAuthResponse(UartFd))
//					{
//						if(ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn)
//						{
//
//							 // *	1. Announce CSU event content.
//							 
//							ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn = false;
//						}
//						else if(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn)
//						{
//							ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = ((strstr(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode, "0000") != NULL)?true:false);
//
//							if(ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass || (preAuthRetry++ >= 3))
//							{
//								ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;
//								ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = true;
//
//								preAuthRetry = 0;
//							}
//							ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isWaitRes = false;
//						}
//					}
//				}
//
//				if((getDiffSecNow(tmr[TIMER_READ_RESPONSE]) > TIMEOUT_REQUEST))
//				{
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isReq = false;
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isWaitRes = false;
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isResultPass = false;
//					ShmSysConfigAndInfo->SysInfo.bazel8.cmdPreAuth.isRes = true;
//					DEBUG_WARN("Wait pre auth response timeout(%d secs).", TIMEOUT_REQUEST);
//				}
//			}
//		}
//
//		sleep(3);
//	}
//
//	return FAIL;
}