/* * Module_Payment_Ominixpay.c * * Created on: 2022/04/29 * Author: Folus Wen */ #include "Module_Payment_Bazel8.h" struct COMMAND commandRaw; struct timespec tmr[TIMER_CNT]; //========================================== // 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 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; read(uart, rx, RAW_DATA_LENGTH); //show_raw(rx, rx_len, YES); if(calChksum(&rx[0]) == rx[(((rx[1] << 8) | (rx[1]))+3)]) { result = PASS; } 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 preAuthRequest(int uart) { char xmlBody[512]={0}; 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 "CurrCode", BAD_CAST "840"); xmlNewChild(node_param_Txn, NULL, BAD_CAST "TxnAmt", BAD_CAST "100"); xmlAddChild(node_param, node_param_Txn); xmlAddChild(node_req, node_param); xmlNodeDump(outputXmlPtr, NULL, (xmlNode *)node_req, 0, 0); sprintf(xmlBody, "%s", (const char *)outputXmlPtr->content); 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)); return pollingRequest(uart, commandRaw.requestData); } int preAuthResponse(int uart) { int result = pollingResponse(uart, commandRaw.responseData); //char *xmlTestBody = "21PLEASE PRESENT CARD"; //char *xmlTestBody = "27AUTHORIZING. PLEASE WAIT..."; //char *xmlTestBody = "TxnStartResp001FTransactionDeferred62"; char xmlTestBody[512] = {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"); 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"))); sprintf(ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId, "%s", xmlNodeGetContent(find_node(root_element, "TxnId"))); ShmSysConfigAndInfo->SysInfo.bazel8.txResp.isGetOn = ON; DEBUG_INFO("Status code: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusCode); DEBUG_INFO("Status text: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.statusText); DEBUG_INFO("TxnId: %s\n", ShmSysConfigAndInfo->SysInfo.bazel8.txResp.txnId); } else { DEBUG_INFO("===== Get unknown node =======================\n"); } xmlFreeDoc(doc); xmlCleanupParser(); xmlMemoryDump(); } return result; } //========================================== // Main loop //========================================== int main(void) { int UartFd; int preAuthRetry = 0; int cmdRepeatCount = 0; //=============================================== // Initialization //=============================================== #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"); //=============================================== // Main loop //=============================================== for(;;) { 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)) { if(preAuthResponse(UartFd)) { if(ShmSysConfigAndInfo->SysInfo.bazel8.event.isGetOn) { /* * TODO: * 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; }