/* * Module_RFID.c * * Created on: 2019-10-24 * Update: 2020-10-19 * Author: Eason Yang * Version: V0.03 * * History * 1. Added : Reyax code. * * * * * */ #include "Module_Systex.h" #define RequestLength 600 #define ResponseLength 600 //================================== // PRINT OUT LOG FORMAT //================================== #define SystemLogMessage #define DEBUG_INFO_1(format, args...) StoreLogMessage("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args) #define DEBUG_WARN_1(format, args...) StoreLogMessage("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args) #define DEBUG_ERROR_1(format, args...) StoreLogMessage("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args) //================================== // HOST ID, offset = 0, length = 2 bytes , //================================== unsigned char HOST_ID_Auto[] = {0x30, 0x30};//信用卡/ 電子票證/ 掃碼支付 unsigned char HOST_ID_CreditCard[] = {0x31, 0x30};//信用卡 unsigned char HOST_ID_eTicket_Polling[] = {0x35, 0x30};//電子票證 //================================== // Transaction Type, offset = 2, length = 2 bytes , //================================== //-------------尋卡--------------- unsigned char TRANS_TYPE_Search[] = {0x37, 0x32}; //讀取卡片卡號 or 條碼資料 //--------------信用卡一般消費--------------- unsigned char TRANS_TYPE_Sale[] = {0x31, 0x31}; //消費交易 : 信用卡,票證,掃碼支付 unsigned char TRANS_TYPE_Void[] = {0x30, 0x35};//取消交易 : 信用卡, unsigned char TRANS_TYPE_Refund[] = {0x31, 0x32};//退貨交易 : 信用卡,票證,掃碼支付 //--------------信用卡預授權--------------- unsigned char TRANS_TYPE_Pre_Auth[] = {0x31, 0x33}; //預授權交易 : 信用卡 unsigned char TRANS_TYPE_Pre_Auth_Complete[] = {0x33, 0x31}; //預授權完成交易 : 信用卡 unsigned char TRANS_TYPE_Pre_Auth_Cancel[] = {0x33, 0x32}; //取消預授權交易 : 信用卡 //--------------連動結帳--------------- unsigned char TRANS_TYPE_UnionSettlement[] = {0x35, 0x41}; //連動結帳請款 //================================== // SystemLog message //================================== #ifdef SystemLogMessage int StoreLogMessage(const char *fmt, ...) { char Buf[4096 + 256]; char buffer[4096]; time_t CurrentTime; struct tm *tm; 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); sprintf(Buf, "echo \"[%04d.%02d.%02d %02d:%02d:%02d] - %s\" >> /Storage/SystemLog/[%04d.%02d]RFID_SystemLog", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, buffer, tm->tm_year + 1900, tm->tm_mon + 1); system(Buf); #ifdef Debug printf("[%04d.%02d.%02d %02d:%02d:%02d] - %s", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, buffer); #endif return rc; } #endif //========================================== // Module's command send/receive //========================================== int SendRequest(int uart, unsigned char* cmd, int length) { int len, TotalRtn=0, Rtn,i; unsigned int StartTime; unsigned char LRC=0; unsigned char SendBuffer[RequestLength+4]; len=length+3; memset(SendBuffer,0,RequestLength+4); SendBuffer[0]=0x02; memcpy(SendBuffer+1,cmd,length); SendBuffer[length+1]=0x03; for(i=1;i<=length+1;i++) { LRC^=SendBuffer[i]; } SendBuffer[length+2]=LRC; //sleep(2); //required to make flush work, for some reason //for(int i=0;i0) { TotalRtn+=Rtn; if(TotalRtn>=len) { //printf("Rtn=%d,TotalRtn=%d\n",Rtn,TotalRtn); break; } } else { DEBUG_INFO_1("SendRequest: write fail (%d / %d)\n", TotalRtn,len); return -1; } } //usleep(100000); TotalRtn=0; memset(SendBuffer,0,RequestLength+4); StartTime = time(NULL); while(1) { Rtn=read(uart, SendBuffer+TotalRtn, 2-TotalRtn); if(Rtn>0) { TotalRtn+=Rtn; if(TotalRtn>=2) { if((SendBuffer[0]==0x06)&&(SendBuffer[1]==0x06)) return TotalRtn; else { DEBUG_INFO_1("SendRequest: not recv ACKACK(%x, %x)\n", SendBuffer[0],SendBuffer[1]); //read(uart, SendBuffer, RequestLength); return -1; } } } else { if((time(NULL)-StartTime)>3) { DEBUG_INFO_1("SendRequest: read fail (%d / 6)\n", TotalRtn); return -1; } } } } int RecvResponse(int uart, unsigned char* rx) { int len, TotalRtn=0, Rtn,i; unsigned int StartTime; unsigned char LRC=0, counter=0; unsigned char RecvBuffer[ResponseLength+4], tmpBuf[16]; reRecv: len=ResponseLength+3; memset(RecvBuffer,0,ResponseLength+4); LRC=0; TotalRtn=0; StartTime = time(NULL); while(1) { Rtn=read(uart, RecvBuffer+TotalRtn, len-TotalRtn); if(Rtn>0) { TotalRtn+=Rtn; //for(int i=0;i=len) { if((RecvBuffer[0]!=0x02)||(RecvBuffer[ResponseLength+1]!=0x03)) { memset(tmpBuf,0,sizeof(tmpBuf)); tmpBuf[0]=tmpBuf[1]=0x06; Rtn=write(uart, tmpBuf, 2); DEBUG_INFO_1("RecvResponse: Not Response format (STX=%c , ETX=%c)\n", RecvBuffer[0],RecvBuffer[ResponseLength+1]); return -1; } for(i=1;i<=ResponseLength+1;i++) { LRC^=RecvBuffer[i]; } if(RecvBuffer[ResponseLength+2]!=LRC) { if(counter++<2) { memset(tmpBuf,0,sizeof(tmpBuf)); tmpBuf[0]=tmpBuf[1]=0x15; Rtn=write(uart, tmpBuf, 2); goto reRecv; } else { memset(tmpBuf,0,sizeof(tmpBuf)); tmpBuf[0]=tmpBuf[1]=0x06; Rtn=write(uart, tmpBuf, 2); DEBUG_INFO_1("RecvResponse: 2 times LRC Error (%d / %d)\n", LRC,RecvBuffer[ResponseLength+2]); return -1; } } memset(tmpBuf,0,sizeof(tmpBuf)); memcpy(tmpBuf,RecvBuffer+1,8 ); if((strstr((char *)tmpBuf,"00000000")==NULL)&&(strstr((char *)tmpBuf,"000000TD")==NULL)) { DEBUG_INFO_1("RecvResponse: Response Code failed (%s)\n", tmpBuf); memset(tmpBuf,0,sizeof(tmpBuf)); tmpBuf[0]=tmpBuf[1]=0x06; Rtn=write(uart, tmpBuf, 2); return -1; } memset(tmpBuf,0,sizeof(tmpBuf)); tmpBuf[0]=tmpBuf[1]=0x06; Rtn=write(uart, tmpBuf, 2); memcpy(rx,RecvBuffer+1,ResponseLength); return ResponseLength; } } else { if((time(NULL)-StartTime)>40)//卡機30 seconds timeout { DEBUG_INFO_1("RecvResponse: read fail (%d / %d)\n", TotalRtn,len); return -1; } } } } //========================================== // CreditCardSearch // Input : // // Output : //========================================== int CreditCardSearch(int Fd,unsigned char *EVSEID, struct TransInfo *TransInfoReturn) { unsigned char Buffer[RequestLength], *ptr; memset(Buffer,0x20,RequestLength); ptr=Buffer; strncpy((char *)ptr,(char *)HOST_ID_Auto,2);//Host ID ptr+=2; strncpy((char *)ptr,(char *)TRANS_TYPE_Search,2);//Transaction type ptr+=2; /*memset(tmpbuf,0,sizeof(tmpbuf)); sprintf(tmpbuf,"%d", PreCost); if(strlen(tmpbuf)>12) { DEBUG_INFO_1("CreditCardPreAuthCancel: Wrong PreCost (PreCost=%d)\n", PreCost); return -1; } memset(ptr,0x30,12); strncpy(ptr+12-(strlen(tmpbuf)+2),tmpbuf,strlen(tmpbuf));//Trans Amount */ ptr+=12;//Trans Amount //strncpy(ptr,ApprovalNo, strlen(ApprovalNo)); ptr+=12;//Approval No //strncpy(ptr,CardNum, strlen(CardNum)); ptr+=20;//Card No strncpy((char *)ptr,(char *)EVSEID, strlen((char *)EVSEID)); ptr+=18;//Store Id //ptr+=2;//Period if(SendRequest(Fd, Buffer, RequestLength)>0) { memset(Buffer,0,RequestLength); if(RecvResponse(Fd,Buffer)>0) { strncpy((char *)TransInfoReturn->TransDate,(char *)Buffer+56,6); strncpy((char *)TransInfoReturn->TransTime,(char *)Buffer+62,6); strncpy((char *)TransInfoReturn->CardNo,(char *)Buffer+24,20); return 1; } else { DEBUG_INFO_1("CreditCardUnionSettlement: RecvResponse failed\n"); return -1; } } else { DEBUG_INFO_1("CreditCardUnionSettlement: SendRequest failed\n"); return -1; } } //========================================== // CreditCardPreAuth // Input : // PreCost : 預扣金額*100, e.g., $1234 = 123400, $1234.56=123456 // EVSEID: EVSE ID, max length is 18 // Output : // ApprovalNo : EDC簽單調閱編號或授權碼[信用卡退貨交易, max length is 12 // RRN : 信用卡交易序號, max length is 12 // CardNum: 卡號,max length is 20 // VemData : 無人自助設備交易資訊 交易別31/32 (預授權完成/預授權取消) 必要欄位 資訊來源為交易別13 (預授權)的回傳, max length is 64 //========================================== int CreditCardPreAuth(int Fd, int PreCost,unsigned char *EVSEID, struct TransInfo *TransInfoReturn) { unsigned char Buffer[RequestLength], *ptr, tmpbuf[12]; memset(Buffer,0x20,RequestLength); ptr=Buffer; strncpy((char *)ptr,(char *)HOST_ID_CreditCard,2);//Host ID ptr+=2; strncpy((char *)ptr,(char *)TRANS_TYPE_Pre_Auth,2);//Transaction type ptr+=2; memset(tmpbuf,0,sizeof(tmpbuf)); sprintf((char *)tmpbuf,"%d", PreCost); if(strlen((char *)tmpbuf)>12) { DEBUG_INFO_1("CreditCardPreAuth: Wrong PreCost (PreCost=%d)\n", PreCost); return -1; } memset(ptr,0x30,12); strncpy((char *)ptr+12-(strlen((char *)tmpbuf)+2),(char *)tmpbuf,strlen((char *)tmpbuf));//Trans Amount ptr+=12;//Trans Amount ptr+=12;//Approval No ptr+=20;//Card No strncpy((char *)ptr,(char *)EVSEID, strlen((char *)EVSEID)); ptr+=18;//Store Id //ptr+=2;//Period if(SendRequest(Fd, Buffer, RequestLength)>0) { memset(Buffer,0,RequestLength); if(RecvResponse(Fd,Buffer)>0) { //for(int i=0;iTransAmount,(char *)Buffer+44,12); strncpy((char *)TransInfoReturn->TransDate,(char *)Buffer+56,6); strncpy((char *)TransInfoReturn->TransTime,(char *)Buffer+62,6); strncpy((char *)TransInfoReturn->StoreId,(char *)Buffer+97,18); strncpy((char *)TransInfoReturn->ROC,(char *)Buffer+12,12); strncpy((char *)TransInfoReturn->ApprovalNo,(char *)Buffer+115,9); strncpy((char *)TransInfoReturn->RRN,(char *)Buffer+124,12); strncpy((char *)TransInfoReturn->CardNo,(char *)Buffer+24,20); strncpy((char *)TransInfoReturn->VemData,(char *)Buffer+246,64); return 1; } else { DEBUG_INFO_1("CreditCardPreAuth: RecvResponse failed\n"); return -1; } } else { DEBUG_INFO_1("CreditCardPreAuth: SendRequest failed\n"); return -1; } } //========================================== // CreditCardAuthComplete // Input : // PreCost : 扣金額*100, e.g., $1234 = 123400, $1234.56=123456 // EVSEID: EVSE ID, max length is 18 // VemData : the VEM data from CreditCardPreAuth, max length is 64 // Output : //========================================== int CreditCardPreAuthComplete(int Fd, int PreCost,unsigned char *EVSEID, unsigned char *VemData,struct TransInfo *TransInfoReturn) { unsigned char Buffer[RequestLength], *ptr, tmpbuf[12]; memset(Buffer,0x20,RequestLength); ptr=Buffer; strncpy((char *)ptr,(char *)HOST_ID_CreditCard,2);//Host ID ptr+=2; strncpy((char *)ptr,(char *)TRANS_TYPE_Pre_Auth_Complete,2);//Transaction type ptr+=2; memset(tmpbuf,0,sizeof(tmpbuf)); sprintf((char *)tmpbuf,"%d", PreCost); if(strlen((char *)tmpbuf)>12) { DEBUG_INFO_1("CreditCardAuthComplete: Wrong PreCost (PreCost=%d)\n", PreCost); return -1; } memset(ptr,0x30,12); strncpy((char *)ptr+12-(strlen((char *)tmpbuf)+2),(char *)tmpbuf,strlen((char *)tmpbuf));//Trans Amount ptr+=12;//Trans Amount ptr+=12;//Approval No ptr+=20;//Card No strncpy((char *)ptr,(char *)EVSEID, strlen((char *)EVSEID)); ptr+=18;//Store Id //ptr+=2;//Period strncpy((char *)Buffer+500,(char *)VemData,64); if(SendRequest(Fd, Buffer, RequestLength)>0) { memset(Buffer,0,RequestLength); if(RecvResponse(Fd,Buffer)>0) { strncpy((char *)TransInfoReturn->TransAmount,(char *)Buffer+44,12); strncpy((char *)TransInfoReturn->TransDate,(char *)Buffer+56,6); strncpy((char *)TransInfoReturn->TransTime,(char *)Buffer+62,6); strncpy((char *)TransInfoReturn->StoreId,(char *)Buffer+97,18); strncpy((char *)TransInfoReturn->ROC,(char *)Buffer+12,12); strncpy((char *)TransInfoReturn->ApprovalNo,(char *)Buffer+115,9); strncpy((char *)TransInfoReturn->RRN,(char *)Buffer+124,12); strncpy((char *)TransInfoReturn->CardNo,(char *)Buffer+24,20); strncpy((char *)TransInfoReturn->VemData,(char *)Buffer+246,64); return 1; } else { DEBUG_INFO_1("CreditCardAuthComplete: RecvResponse failed\n"); return -1; } } else { DEBUG_INFO_1("CreditCardAuthComplete: SendRequest failed\n"); return -1; } } //========================================== // CreditCardPreAuthCancel // Input : // PreCost : 預扣金額*100, e.g., $1234 = 123400, $1234.56=123456 // EVSEID: EVSE ID, max length is 18 // ApprovalNo: max length is 12 // CardNum : max length is 20 // Output : //========================================== int CreditCardPreAuthCancel(int Fd, int PreCost,unsigned char *EVSEID, unsigned char *ApprovalNo, unsigned char *CardNum,unsigned char *VemData) { unsigned char Buffer[RequestLength], *ptr, tmpbuf[12]; memset(Buffer,0x20,RequestLength); ptr=Buffer; strncpy((char *)ptr,(char *)HOST_ID_CreditCard,2);//Host ID ptr+=2; strncpy((char *)ptr,(char *)TRANS_TYPE_Pre_Auth_Cancel,2);//Transaction type ptr+=2; memset(tmpbuf,0,sizeof(tmpbuf)); sprintf((char *)tmpbuf,"%d", PreCost); if(strlen((char *)tmpbuf)>12) { DEBUG_INFO_1("CreditCardPreAuthCancel: Wrong PreCost (PreCost=%d)\n", PreCost); return -1; } memset(ptr,0x30,12); strncpy((char *)ptr+12-(strlen((char *)tmpbuf)+2),(char *)tmpbuf,strlen((char *)tmpbuf));//Trans Amount ptr+=12;//Trans Amount strncpy((char *)ptr,(char *)ApprovalNo, strlen((char *)ApprovalNo)); ptr+=12;//Approval No strncpy((char *)ptr,(char *)CardNum, strlen((char *)CardNum)); ptr+=20;//Card No strncpy((char *)ptr,(char *)EVSEID, strlen((char *)EVSEID)); ptr+=18;//Store Id //ptr+=2;//Period strncpy((char *)Buffer+500,(char *)VemData,64); if(SendRequest(Fd, Buffer, RequestLength)>0) { memset(Buffer,0,RequestLength); if(RecvResponse(Fd,Buffer)>0) { return 1; } else { DEBUG_INFO_1("CreditCardPreAuthCancel: RecvResponse failed\n"); return -1; } } else { DEBUG_INFO_1("CreditCardPreAuthCancel: SendRequest failed\n"); return -1; } } //========================================== // CreditCardUnionSettlement // Input : // // Output : //========================================== int CreditCardUnionSettlement(int Fd,unsigned char *EVSEID, struct TransInfo *TransInfoReturn) { unsigned char Buffer[RequestLength], *ptr; memset(Buffer,0x20,RequestLength); ptr=Buffer; strncpy((char *)ptr,(char *)HOST_ID_CreditCard,2);//Host ID ptr+=2; strncpy((char *)ptr,(char *)TRANS_TYPE_UnionSettlement,2);//Transaction type ptr+=2; /*memset(tmpbuf,0,sizeof(tmpbuf)); sprintf(tmpbuf,"%d", PreCost); if(strlen(tmpbuf)>12) { DEBUG_INFO_1("CreditCardPreAuthCancel: Wrong PreCost (PreCost=%d)\n", PreCost); return -1; } memset(ptr,0x30,12); strncpy(ptr+12-(strlen(tmpbuf)+2),tmpbuf,strlen(tmpbuf));//Trans Amount */ ptr+=12;//Trans Amount //strncpy(ptr,ApprovalNo, strlen(ApprovalNo)); ptr+=12;//Approval No //strncpy(ptr,CardNum, strlen(CardNum)); ptr+=20;//Card No strncpy((char *)ptr,(char *)EVSEID, strlen((char *)EVSEID)); ptr+=18;//Store Id //ptr+=2;//Period if(SendRequest(Fd, Buffer, RequestLength)>0) { memset(Buffer,0,RequestLength); if(RecvResponse(Fd,Buffer)>0) { strncpy((char *)TransInfoReturn->TransAmount,(char *)Buffer+44,12); strncpy((char *)TransInfoReturn->TransDate,(char *)Buffer+56,6); strncpy((char *)TransInfoReturn->TransTime,(char *)Buffer+62,6); strncpy((char *)TransInfoReturn->StoreId,(char *)Buffer+97,18); strncpy((char *)TransInfoReturn->ROC,(char *)Buffer+12,12); strncpy((char *)TransInfoReturn->ApprovalNo,(char *)Buffer+115,9); strncpy((char *)TransInfoReturn->RRN,(char *)Buffer+124,12); strncpy((char *)TransInfoReturn->CardNo,(char *)Buffer+24,20); strncpy((char *)TransInfoReturn->VemData,(char *)Buffer+246,64); return 1; } else { DEBUG_INFO_1("CreditCardUnionSettlement: RecvResponse failed\n"); return -1; } } else { DEBUG_INFO_1("CreditCardUnionSettlement: SendRequest failed\n"); return -1; } } #if 0 int InitComPort() { int fd; struct termios tios; fd = open("/dev/ttyS2", O_RDWR); if(fd<=0) { DEBUG_INFO_1("open /dev/ttyS2 NG\n"); 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]=(unsigned char)5; // timeout 500ms tios.c_lflag=0; tcflush(fd, TCIFLUSH); ioctl (fd, TCSETS, &tios); return fd; } int main(int argc, char *argv[]) { int UartFd; struct TransInfo ReturnTransInfo; UartFd=InitComPort(); if(UartFd<0) { printf("InitComPort NG\n"); return; } //sleep(3); memset(&ReturnTransInfo,0,sizeof(struct TransInfo)); printf("CreditCardPreAuth......\n"); if(CreditCardPreAuth(UartFd, 1000,"TCC EVSE", &ReturnTransInfo)<=0) { printf("CreditCardPreAuth NG\n"); return; } printf("ApprovalNo=%s\n",ReturnTransInfo.ApprovalNo); printf("RRN=%s\n",ReturnTransInfo.RRN); printf("CardNum=%s\n",ReturnTransInfo.CardNo); printf("VemData=%s\n",ReturnTransInfo.VemData); sleep(20); /*if(CreditCardPreAuthCancel(UartFd, 1000,"TCC EVSE", &ReturnTransInfo.ApprovalNo, &ReturnTransInfo.CardNo,&ReturnTransInfo.VemData)<=0) { printf("CreditCardPreAuthCancel NG\n"); //return; } */ printf("CreditCardPreAuthComplete......\n"); if(CreditCardPreAuthComplete(UartFd, 500,"TCC EVSE", &ReturnTransInfo.VemData, &ReturnTransInfo)<=0) { printf("CreditCardPreAuthComplete NG\n"); return; } sleep(15); if(CreditCardUnionSettlement(UartFd,"TCC EVSE",&ReturnTransInfo)<=0) { printf("CreditCardUnionSettlement NG\n"); //return; } } #endif