123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- /*
- * Module_Payment.c
- *
- * Created on: 2021/03/24
- * Author: Henry Yeh
- */
- #include "Module_Payment.h"
- unsigned char version[] = {'D', '0', '.', '0', '1'};
- unsigned char CMD_C8[30] = {0xc8,0x01, // Activate the reader
- 0x9f,0x02,0x06,0x00,0x00,0x00,0x01,0x00,0x00, // Amount, Authorized, sample: 100.00 dollar
- 0x5f,0x2a,0x02,0x08,0x40, // Transaction Currency Code follow ISO-4217, sample: 0840(USD)
- 0x9c,0x01,0x00, // Transaction Type, sample: 00
- 0x9a,0x03,0x21,0x03,0x24, // Transaction Date, sample: 2021/03/24
- 0x9f,0x21,0x03,0x13,0x36,0x10 }; // Transaction Time, sample: 13:36:10
- unsigned char CMD_CARD_DETECT[11] = {0x09, 0, 0x07, 'M','F','1','4','1','2','1', 0x32}; // Enable payment, MIFARE, 15693 card; Detect Payment Card First; Enable ApplePay VAS
- unsigned char CMD_USI2[7] = {0x09, 0, 0x03, 'P', 'C', '0', 0x29}; // Configure protocol to USI2
- unsigned char CMD_SET_BAUD[7] = {0x09, 0, 0x03, 'B', 'R', '7', 0x2d}; // Configure module baud rate to 115200
- unsigned char CMD_RESTORE_DEFAULT[7] = {0x09, 0, 0x03, 'D', 'F', 0, 0x08 }; // Restore module configuration to default setting
- int system_command(int uart, unsigned char* cmd, int cmd_len, unsigned char* rx);
- int USI2_Parse(unsigned char* rx, unsigned char* rx_data);
- struct C9_RESULT
- {
- unsigned char result_data[512];
-
- unsigned char status;
- unsigned char pos_entry;
- unsigned char u_id[20];
- unsigned char tkData[4][128];
- } C9_Result;
- //==========================================
- // 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;
- }
- /**
- * 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[8192];
- memset(output, 0x00, ARRAY_SIZE(output));
- sprintf((char*)output, "%s", (isRX?"RX: ":"TX: "));
- for(uint16_t idx = 0;idx<len;idx++)
- {
- sprintf((char*)output, "%s%02x ", output, data[idx]);
- }
- DEBUG_INFO("%s\n", output);
- }
- /**
- * Show data to debug info
- * @param dat: data content
- * @param len: data length
- */
- void show_data(unsigned char *dat, unsigned int len)
- {
- uint8_t output[8192];
- memset(output, 0x00, ARRAY_SIZE(output));
- sprintf((char*)output, "Data: ");
- for(uint16_t idx = 0;idx<len;idx++)
- {
- if(dat[idx] > 31 && dat[idx] < 128 )
- sprintf((char*)output, "%s%c", output, dat[idx]);
- else
- sprintf((char*)output, "%s<%x>", output, dat[idx]);
- }
- DEBUG_INFO("%s\n", output);
- }
- /**
- * Get sentinel quantity in data array
- * @param data: message array address
- * @param dataLen: array seek size
- * @return how many sentinel flag found
- */
- int getSentinelQuantity(unsigned char *data, unsigned int dataLen)
- {
- int result = 0;
- for(uint16_t idx=0;idx<dataLen;idx++)
- {
- if(data[idx] == '?')
- result++;
- }
- return result;
- }
- /**
- * Get sentinel position in array
- * @param data: message array address
- * @param dataLen: array seek size
- * @param idxSentinel: which sentinel idx want to find, since 0 start
- * @return sentinel position in array
- */
- int getSentinelPosition(unsigned char *data, unsigned int dataLen, unsigned char idxSentinel)
- {
- int result = -1;
- int foundCnt = -1;
- for(uint16_t idx=0;idx<dataLen;idx++)
- {
- if(data[idx] == '?')
- foundCnt++;
- if(foundCnt == idxSentinel)
- {
- result = idx;
- break;
- }
- }
- return result;
- }
- //==========================================
- // Init share memory
- //==========================================
- /**
- * Share memory initialization
- * @return function result
- */
- int InitShareMemory()
- {
- int result = PASS;
- int MeterSMId;
- //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
- {}
- return result;
- }
- //==========================================
- // Init com port
- //==========================================
- /**
- * TTY port initialization
- * @return port initial result
- */
- int InitComPort()
- {
- int fd;
- struct termios tios;
- fd = open("/dev/ttyS3", 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;
- tios.c_cc[VTIME]=(unsigned char)5; // timeout 0.5 seconds
- tios.c_lflag=0;
- tcflush(fd, TCIFLUSH);
- ioctl (fd, TCSETS, &tios);
- return fd;
- }
- /**
- * Send command to UIC680fg module.
- * @param uart: port handle
- * @param cmd: command buffer
- * @param cmd_len: command length
- * @param rx: receive buffer
- * @return receive data length
- */
- int system_command(int uart, unsigned char* cmd, int cmd_len, unsigned char* rx)
- {
- int rx_len = 0;
- tcflush(uart,TCIOFLUSH);
- show_raw(cmd, cmd_len, NO);
- if(write(uart, cmd, cmd_len) > 0)
- {
- /*
- * TODO: Improve sleep time.
- */
- usleep(1000000);
- rx_len = read(uart, rx, 512);
- show_raw(rx, rx_len, YES);
- }
- else
- {
- DEBUG_ERROR("system command write fail.\n");
- }
- return rx_len;
- }
- /**
- * Parsing raw data to USI data
- * @param rx: raw data
- * @param rx_data: parsing result data
- * @return parsing result data length
- */
- int USI2_Parse(unsigned char* rx, unsigned char* rx_data)
- {
- int result = -1;
- unsigned int data_len =0;
- unsigned int chksum = 0;
-
- if(rx[0] == SOH) // SOH = 0x01
- {
- data_len = (unsigned int)rx[2] <<8;
- data_len |= rx[3];
-
- for(int idx=0;idx<(data_len+4);idx++)
- {
- chksum ^= rx[idx];
- }
-
- if((chksum&0xff) == rx[(data_len+4)])
- {
- memcpy(rx_data, &rx[4], data_len);
- result = data_len;
- }
- }
- else
- {
- DEBUG_WARN("USI2 message header is not <01>.\n");
- }
- return result;
- }
- //==========================================
- // Main loop
- //==========================================
- int main(void)
- {
- int UartFd;
- uint16_t failCount = 0;
- unsigned char rx_Array[512]={0}, rx_Data[512]={0};
- char C8_Polling = true;
- char Wait_C9 = false;
- int rx_len = 0;
- int data_len = 0;
- DEBUG_INFO("Task version: %s\n", version);
- //===============================================
- // 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("ttyS3 port open success.\n");
- }
- //===============================================
- // Payment module configuration set to default.
- //===============================================
- do
- {
- rx_len = system_command(UartFd, CMD_RESTORE_DEFAULT, ARRAY_SIZE(CMD_RESTORE_DEFAULT), rx_Array);
- if((rx_Array[0] == ACK) && (rx_len ==1))
- {
- DEBUG_INFO("Set to the default success.\n");
- failCount = 0;
- }
- else
- {
- DEBUG_WARN("Set to the default fail (<%02x>).\n", rx_Array[0]);
- failCount++;
- }
- if(failCount > RETRY_LIMIT)
- {
- DEBUG_ERROR("Set to the default fail over retry limit.\n");
- return FAIL;
- }
- }while((rx_Array[0] != ACK) || (rx_len !=1));
-
- //===============================================
- // set payment card detect type.
- //===============================================
- do
- {
- rx_len = system_command(UartFd, CMD_CARD_DETECT, ARRAY_SIZE(CMD_CARD_DETECT), rx_Array);
- if((rx_Array[0] == ACK) && (rx_len ==1))
- {
- DEBUG_INFO("Set payment card type success.\n");
- failCount = 0;
- }
- else
- {
- DEBUG_WARN("Set payment card type fail (<%02x>).\n", rx_Array[0]);
- failCount++;
- }
- if(failCount > RETRY_LIMIT)
- {
- DEBUG_ERROR("Set payment card type fail over retry limit.\n");
- return FAIL;
- }
- }while((rx_Array[0] != ACK) || (rx_len !=1));
- //===============================================
- // set to protocol_2
- //===============================================
- do
- {
- rx_len =system_command(UartFd, CMD_USI2, ARRAY_SIZE(CMD_USI2), rx_Array);
- if((rx_Array[0] == ACK) && (rx_len ==1))
- {
- DEBUG_INFO("Set protocol to USI2 success.\n");
- failCount = 0;
- }
- else
- {
- DEBUG_WARN("Set protocol to USI2 fail (<%02x>).\n", rx_Array[0]);
- failCount++;
- }
- if(failCount > RETRY_LIMIT)
- {
- DEBUG_ERROR("Set protocol to USI2 fail over retry limit.\n");
- return FAIL;
- }
- }while((rx_Array[0] != ACK) || (rx_len !=1));
-
- //===============================================
- // Main loop
- //===============================================
- for(;;)
- {
- if(C8_Polling == true)
- {
- Wait_C9 = false;
-
- /*
- * TODO:
- * 1. C8 parameter configure
- */
- rx_len =system_command(UartFd, CMD_C8, sizeof(CMD_C8), rx_Array);
- if((rx_Array[0] == ACK) && (rx_len ==1))
- {
- DEBUG_INFO("Polling C8 command get response.\n");
- Wait_C9 = true;
- failCount = 0;
- }
-
- if(Wait_C9 == true)
- {
- //=============================================
- // wait card to attach the reader and wait C9
- //=============================================
- tcflush(UartFd,TCIOFLUSH);
- memset(rx_Array, 0x00, ARRAY_SIZE(rx_Array));
- rx_len = 0;
-
- do
- {
- sleep(1);
- rx_len = read(UartFd, rx_Array, ARRAY_SIZE(rx_Array)); // read response if data count match 512 or timeout.
- failCount++;
- } while ((rx_len == 0) && (failCount < RETRY_LIMIT));
-
- //=============================================
- // Parse rx_Array to rx_Data
- //=============================================
- if((rx_len > 3) && (failCount < RETRY_LIMIT))
- {
- // print this raw data before parse it.
- show_data(rx_Array, rx_len);
-
- rx_len = USI2_Parse( rx_Array, rx_Data);
- if(rx_len > 0)
- {
- // debug the input data message
- show_data(rx_Data, rx_len);
-
- // Copy RAW data to structure
- memcpy(&C9_Result.result_data, rx_Data, rx_len);
- C9_Result.status = C9_Result.result_data[1];
- C9_Result.pos_entry = C9_Result.result_data[2];
-
- switch(C9_Result.pos_entry)
- {
- case VISA_qVSDC:
- case VISA_MSD:
- case MASTER_MChip:
- case Master_MagStripe:
- case AMEX_EMV:
- case AMEX_MSD:
- memset(C9_Result.u_id, 0x00, ARRAY_SIZE(C9_Result.u_id));
- memcpy(C9_Result.u_id, &C9_Result.result_data[4], 16);
- DEBUG_INFO("Credit card SN:\n");
- show_data(C9_Result.u_id, 16);
- DEBUG_INFO("Payment card\n");
- for(uint8_t idx=0;idx<getSentinelQuantity(C9_Result.result_data, rx_len);idx++)
- {
- memset(C9_Result.tkData[idx], 0x00, ARRAY_SIZE(C9_Result.tkData[idx]));
- memcpy(C9_Result.tkData[idx],
- &C9_Result.result_data[((idx==0)?3:getSentinelPosition(C9_Result.result_data, rx_len, idx-1)+2)],
- (idx==0?getSentinelPosition(C9_Result.result_data, rx_len, idx)+1-3+1:getSentinelPosition(C9_Result.result_data, rx_len, idx)+1-getSentinelPosition(C9_Result.result_data, rx_len, idx-1)+2+1));
- DEBUG_INFO("TK[%d]: \n", idx);
- show_data(C9_Result.tkData[idx], getSentinelPosition(C9_Result.tkData[idx], ARRAY_SIZE(C9_Result.tkData[idx]), 0)+2);
- }
- break;
- case Mifare:
- data_len = C9_Result.result_data[6];
- memset(C9_Result.u_id, 0x00, ARRAY_SIZE(C9_Result.u_id));
- memcpy(C9_Result.u_id, &C9_Result.result_data[7], data_len);
- switch(C9_Result.result_data[3])
- {
- case MIFARE_ULTRALIGHT:
- DEBUG_INFO("MIFARE Ultralight, UID: %02X-%02X-%02X-%02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3], C9_Result.u_id[4], C9_Result.u_id[5], C9_Result.u_id[6]);
- break;
- case MIFARE_CLASSIC_1K:
- DEBUG_INFO("MIFARE Classic 1K, UID: %02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3]);
- break;
- case MIFARE_CLASSIC_4K:
- DEBUG_INFO("MIFARE Classic 4K, UID: %02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3]);
- break;
- case MIFARE_DESFIRE:
- DEBUG_INFO("MIFARE DESFire, UID: %02X-%02X-%02X-%02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3], C9_Result.u_id[4], C9_Result.u_id[5], C9_Result.u_id[6]);
- break;
- case MIFARE_PLUS_2K:
- DEBUG_INFO("MIFARE Plus 2k, UID: %02X-%02X-%02X-%02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3], C9_Result.u_id[4], C9_Result.u_id[5], C9_Result.u_id[6]);
- break;
- case MIFARE_MINI:
- DEBUG_INFO("MIFARE Mini, UID: %02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3]);
- break;
- case MIFARE_RESERVE:
- DEBUG_INFO("MIFARE Reserve, UID: \n");
- break;
- case MIFARE_JEWEL:
- DEBUG_INFO("MIFARE Jewel, UID: \n");
- break;
- case MIFARE_JCOP31:
- DEBUG_INFO("MIFARE JCOP31, UID: \n");
- break;
- }
- break;
- case ISO_15693:
- data_len =(C9_Result.result_data[5]<<8) | C9_Result.result_data[6];
- memset(C9_Result.u_id, 0x00, ARRAY_SIZE(C9_Result.u_id));
- memcpy(C9_Result.u_id, &C9_Result.result_data[4+data_len-8], 8);
- DEBUG_INFO("ISO_15693, UID: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", C9_Result.u_id[0], C9_Result.u_id[1], C9_Result.u_id[2], C9_Result.u_id[3], C9_Result.u_id[4], C9_Result.u_id[5], C9_Result.u_id[6], C9_Result.u_id[7]);
- break;
- case Apple_Pay:
- DEBUG_INFO("Apple_Pay VAS only.\n");
- for(uint8_t idx=0;idx<getSentinelQuantity(C9_Result.result_data, rx_len);idx++)
- {
- memcpy(C9_Result.tkData[idx],
- &C9_Result.result_data[((idx==0)?3:getSentinelPosition(C9_Result.result_data, rx_len, idx-1)+2)],
- (idx==0?getSentinelPosition(C9_Result.result_data, rx_len, idx)+1-3+1:getSentinelPosition(C9_Result.result_data, rx_len, idx)+1-getSentinelPosition(C9_Result.result_data, rx_len, idx-1)+2+1));
- DEBUG_INFO("TK[%d]: \n", idx);
- show_data(C9_Result.tkData[idx], getSentinelPosition(C9_Result.tkData[idx], ARRAY_SIZE(C9_Result.tkData[idx]), 0)+2);
- }
- break;
- case No_Data:
- DEBUG_INFO("--> No any data.\n");
- break;
- default:
- DEBUG_INFO("--> Unknown pos entry.\n");
- break;
- }
- failCount = 0;
- }
- else
- {
- DEBUG_INFO("C9 Parsing result fail.\n");
- }
- }
- else
- {
- DEBUG_WARN("C9 Response timeout: %d \n", failCount);
- }
- }
- }
- usleep(500000);
- }
- return FAIL;
- }
|