/* * Module_Payment.c * * Created on: 2021/03/24 * Author: Henry Yeh */ #include "Module_Payment.h" unsigned char version[] = {'D', '0', '.', '0', '4'}; unsigned char BLP_CMD_CARD_DETECT[] = {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 BLP_CMD_USI2[] = {0x09, 0, 0x03, 'P', 'C', '0', 0x29}; // Configure protocol to USI2 unsigned char BLP_CMD_SET_BAUD[] = {0x09, 0, 0x03, 'B', 'R', '7', 0x2d}; // Configure module baud rate to 115200 unsigned char BLP_CMD_RESTORE_DEFAULT[] = {0x09, 0, 0x03, 'D', 'F', 0, 0x08 }; // Restore module configuration to default setting unsigned char BLP_CMD_TLV_ENABLE[] = {0x09, 0, 0x03, 'A', 'A', 'E', 'O'}; // Enable TLV command to support EMV transaction unsigned char BLP_CMD_SET_AID[] = {0x09, 0, 0x04, 'A', 'D', '0', 0, 0x38}; // Set AID type, 0x00: user defined AID 0x01: Default AID unsigned char BLP_CMD_LED_IND[] = {0x09, 0, 0x05, 'R', 'I', 'E', 0x01, 0x01, 'R'}; // Reader LED indicator unsigned char BLP_CMD_CA_PKEY[] = {0x09, 0, 0x03, 'C', 'K', 0x01, 0x03}; // Enable user CA Key unsigned char BLP_CMD_SOFTCARD_DISABLE[]= {0x09, 0, 0x03, 'I', 'S', 'D', 'T'}; // Disable soft card wallet application unsigned char BLP_CMD_BEEP_DISABLE[] = {0x09, 0, 0x03, 'B', 'A', 'D', 'M'}; // Beep disable unsigned char BLP_CMD_ERR_BEEP_STYLE[] = {0x09, 0, 0x03, 'B', 'D', 0, 0x0c}; // Error beep style configure 2 beeps unsigned char BLP_CMD_ERR_BEEP[] = {0x09, 0, 0x03, 'B', 'T', 'D', 'X'}; // Error beep give sound unsigned char BLP_CMD_LRC_ENABLE[] = {0x09, 0, 0x03, 'L', 'C', 'E', '@'}; // Enable LRC character of track data unsigned char BLP_CMD_TX_TRACK[] = {0x09, 0, 0x03, 'T', 'K', '3', '&'}; // Configure output track data 1&2 unsigned char USI_CMD_WARM_RESET[] = {0x01, 0x00, 0x00, 0x01, 0x7f, 0x7f}; // Payment module warm reset unsigned char USI_CMD_MODULE_STATUS[] = {0x01, 0x00, 0x00, 0x01, 0x24, 0x24}; // Deactivate reader unsigned char USI_CMD_C8_DEACTIVAVE[] = {0x01, 0x00, 0x00, 0x02, 0xc8, 0x00, 0x00}; // Deactivate reader unsigned char USI_CMD_C8_POLL[] = {0x01, 0x00, 0x00, 0x2b, // STX, address, command length high byte, command length low byte 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) 0x5f, 0x36, 0x01, 0x02, // Transaction Currency Exponent, Identifies the decimal point position from the right of the transaction amount according to ISO 4217 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 0xff, 0xff, 0x82, 0x05, 0x04, 0x00, 0x00, 0x01, 0x2c, // Command timeout unit is million second, sample: 300ms 0x00}; // Checksum unsigned char USI_CMD_HALT_CARD[] = {0x01, 0x00, 0x00, 0x01, 'x', 0x78}; // Halt card unsigned char USI_CMD_SET_DATE[] = {0x01, 0, 0, 0x07, '5', '4', 0x14, 0x15, 0x05, 0x02, 0x01, 0x18}; unsigned char USI_CMD_SET_TIME[] = {0x01, 0, 0, 0x07, '5', '5', 0x0f, 0x1e, 0x20, 0, 0, 0x37}; unsigned char USI_CMD_ARM_DISABLE[] = {0x01, 0, 0, 0x02, 'H', '0', '{'}; unsigned char USI_CMD_NFC_ACTIVE[] = {0x01, 0, 0, 0x02, 'N', 0x00, 'M'}; // Enable NFC function unsigned char USI_CMD_NFC_POLL[] = {0x01, 0, 0, 0x05, 'N', ' ', '3', 0x02, 0x01, 'Z'}; // Polling FELICA(NFC Type 3, 414kbps) unsigned char USI_CMD_BEEP_CONTROL[] = {0x01, 0, 0, 0x05, 'B', '1', 0x7f, 0x09, 0x09, 0x08}; // Beep on 100ms 1 count 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]; // C9 response data without header & checksum unsigned char status; // C9 response status unsigned char pos_entry; // C9 response pos entry unsigned char u_id[20]; // Card SN unsigned char tkData[4][128]; // Card TK data for credit card unsigned char isCardPreset:1; // Card is presented on module, 0: removed 1: presented unsigned char isCommandError:1; // Polling command result, 0: normal 1: error } 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 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 0) { usleep(100000); 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 checksum error.\n"); } else { DEBUG_WARN("USI2 message header is not <01>.\n"); } return result; } /** * * @param onCnt: Buzzer on quantity */ void buzzer_on(int UartFd, uint8_t onCnt) { unsigned char rx_Array[512]={0}; USI_CMD_BEEP_CONTROL[5] = 0x30 + onCnt; USI_CMD_BEEP_CONTROL[ARRAY_SIZE(USI_CMD_BEEP_CONTROL)-1] = calChksum(USI_CMD_BEEP_CONTROL, ARRAY_SIZE(USI_CMD_BEEP_CONTROL)); system_command(UartFd, USI_CMD_BEEP_CONTROL, ARRAY_SIZE(USI_CMD_BEEP_CONTROL), rx_Array); } //========================================== // 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; time_t CurrentTime; struct tm *tm; DEBUG_INFO("Task version: %s\n", version); //=============================================== // 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); } //=============================================== // Payment module configuration set to default (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_RESTORE_DEFAULT, ARRAY_SIZE(BLP_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 to protocol_2 (BLP Protocol) //=============================================== do { rx_len =system_command(UartFd, BLP_CMD_USI2, ARRAY_SIZE(BLP_CMD_USI2), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set protocol to USI2 success.\n"); DEBUG_INFO("Wait for payment module warm-reset.\n"); sleep(10); 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)); //=============================================== // Disable self-arm mode (USI2 Protocol) //=============================================== do { USI_CMD_ARM_DISABLE[ARRAY_SIZE(USI_CMD_ARM_DISABLE)-1] = calChksum(USI_CMD_ARM_DISABLE, ARRAY_SIZE(USI_CMD_ARM_DISABLE)); system_command(UartFd, USI_CMD_ARM_DISABLE, ARRAY_SIZE(USI_CMD_ARM_DISABLE), rx_Array); rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[0] == ACK) && (rx_len >= 0)) { DEBUG_INFO("Set disable self-arm mode success.\n"); failCount = 0; } else { DEBUG_WARN("Set disable self-arm mode fail (<%02x>).\n", rx_Data[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set disable self-arm mode fail over retry limit.\n"); return FAIL; } }while((rx_Data[0] != ACK) || (rx_len < 0)); //=============================================== // Enable TLV command (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_TLV_ENABLE, ARRAY_SIZE(BLP_CMD_TLV_ENABLE), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set enable TLV command success.\n"); failCount = 0; } else { DEBUG_WARN("Set enable TLV command fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set enable TLV command fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len != 1)); //=============================================== // Set AID type (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_SET_AID, ARRAY_SIZE(BLP_CMD_SET_AID), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set AID type success.\n"); failCount = 0; } else { DEBUG_WARN("Set AID type fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set AID type fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len != 1)); //=============================================== // Set LED indicator (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_LED_IND, ARRAY_SIZE(BLP_CMD_LED_IND), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set LED indicator success.\n"); failCount = 0; } else { DEBUG_WARN("Set LED indicator fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set LED indicator over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len != 1)); //=============================================== // Set CA public key type (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_CA_PKEY, ARRAY_SIZE(BLP_CMD_CA_PKEY), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set CA public key type success.\n"); failCount = 0; } else { DEBUG_WARN("Set CA public key type fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set CA public key type over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len != 1)); //=============================================== // Set payment card detect type (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_CARD_DETECT, ARRAY_SIZE(BLP_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)); //=============================================== // Disable soft card wallet application (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_SOFTCARD_DISABLE, ARRAY_SIZE(BLP_CMD_SOFTCARD_DISABLE), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set disable soft card success.\n"); failCount = 0; } else { DEBUG_WARN("Set disable soft card fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set disable soft card fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len !=1)); //=============================================== // Disable beep (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_BEEP_DISABLE, ARRAY_SIZE(BLP_CMD_BEEP_DISABLE), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set beep disable success.\n"); failCount = 0; } else { DEBUG_WARN("Set beep disable fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set beep disable fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len !=1)); //=============================================== // Set error beep style (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_ERR_BEEP_STYLE, ARRAY_SIZE(BLP_CMD_ERR_BEEP_STYLE), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set error beep style success.\n"); failCount = 0; } else { DEBUG_WARN("Set error beep style fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set error beep style fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len !=1)); //=============================================== // Set error beep (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_ERR_BEEP, ARRAY_SIZE(BLP_CMD_ERR_BEEP), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set error beep success.\n"); failCount = 0; } else { DEBUG_WARN("Set error beep fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set error beep fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len !=1)); //=============================================== // Set enable LRC (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_LRC_ENABLE, ARRAY_SIZE(BLP_CMD_LRC_ENABLE), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set enable LRC success.\n"); failCount = 0; } else { DEBUG_WARN("Set enable LRC fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set enable LRC fail over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len !=1)); //=============================================== // Set TX data tracks (BLP Protocol) //=============================================== do { rx_len = system_command(UartFd, BLP_CMD_TX_TRACK, ARRAY_SIZE(BLP_CMD_TX_TRACK), rx_Array); if((rx_Array[0] == ACK) && (rx_len ==1)) { DEBUG_INFO("Set TX data tracks success.\n"); failCount = 0; } else { DEBUG_WARN("Set TX data tracks fail (<%02x>).\n", rx_Array[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set TX data tracks over retry limit.\n"); return FAIL; } }while((rx_Array[0] != ACK) || (rx_len !=1)); //=============================================== // Set module RTC date (USI2 Protocol) //=============================================== do { CurrentTime = time(NULL); tm=localtime(&CurrentTime); USI_CMD_SET_DATE[6] = ((tm->tm_year+1900)/100); USI_CMD_SET_DATE[7] = ((tm->tm_year+1900)%100); USI_CMD_SET_DATE[8] = (tm->tm_mon+1); USI_CMD_SET_DATE[9] = tm->tm_mday; USI_CMD_SET_DATE[10] = tm->tm_wday==0?0x07:tm->tm_wday; USI_CMD_SET_DATE[ARRAY_SIZE(USI_CMD_SET_DATE)-1] = calChksum(USI_CMD_SET_DATE, ARRAY_SIZE(USI_CMD_SET_DATE)); system_command(UartFd, USI_CMD_SET_DATE, ARRAY_SIZE(USI_CMD_SET_DATE), rx_Array); rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[0] == ACK) && (rx_len >= 0)) { DEBUG_INFO("Set module RTC date success.\n"); failCount = 0; } else { DEBUG_WARN("Set module RTC date fail (<%02x>).\n", rx_Data[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set module RTC date fail over retry limit.\n"); return FAIL; } }while((rx_Data[0] != ACK) || (rx_len < 0)); //=============================================== // Set module RTC time (USI2 Protocol) //=============================================== do { CurrentTime = time(NULL); tm=localtime(&CurrentTime); USI_CMD_SET_TIME[6] = tm->tm_hour; USI_CMD_SET_TIME[7] = tm->tm_min; USI_CMD_SET_TIME[8] = tm->tm_sec; USI_CMD_SET_TIME[ARRAY_SIZE(USI_CMD_SET_TIME)-1] = calChksum(USI_CMD_SET_TIME, ARRAY_SIZE(USI_CMD_SET_TIME)); system_command(UartFd, USI_CMD_SET_TIME, ARRAY_SIZE(USI_CMD_SET_TIME), rx_Array); rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[0] == ACK) && (rx_len >= 0)) { DEBUG_INFO("Set module RTC time success.\n"); failCount = 0; } else { DEBUG_WARN("Set module RTC time fail (<%02x>).\n", rx_Data[0]); failCount++; } if(failCount > RETRY_LIMIT) { DEBUG_ERROR("Set module RTC time fail over retry limit.\n"); return FAIL; } }while((rx_Data[0] != ACK) || (rx_len < 0)); DEBUG_INFO("Payment module initialize completed.\n"); //=============================================== // Main loop //=============================================== for(;;) { USI_CMD_NFC_ACTIVE[ARRAY_SIZE(USI_CMD_NFC_ACTIVE)-1] = calChksum(USI_CMD_NFC_ACTIVE, ARRAY_SIZE(USI_CMD_NFC_ACTIVE)); if(system_command(UartFd, USI_CMD_NFC_ACTIVE, ARRAY_SIZE(USI_CMD_NFC_ACTIVE), rx_Array) > 0) { rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[2] == 0x00) && (rx_len >= 0)) { USI_CMD_NFC_POLL[ARRAY_SIZE(USI_CMD_NFC_POLL)-1] = calChksum(USI_CMD_NFC_POLL, ARRAY_SIZE(USI_CMD_NFC_POLL)); if(system_command(UartFd, USI_CMD_NFC_POLL, ARRAY_SIZE(USI_CMD_NFC_POLL), rx_Array) > 0) { rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[2] == 0x00) && (rx_len >= 0)) { // FELICA memcpy(&C9_Result.result_data, rx_Data, rx_len); C9_Result.status = C9_Result.result_data[2]; C9_Result.pos_entry = Felica; memset(C9_Result.u_id, 0x00, ARRAY_SIZE(C9_Result.u_id)); memcpy(C9_Result.u_id, &C9_Result.result_data[6], 6); DEBUG_INFO("FELICA, UID: %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]); buzzer_on(UartFd, 1); // Wait card removed do { USI_CMD_NFC_POLL[ARRAY_SIZE(USI_CMD_NFC_POLL)-1] = calChksum(USI_CMD_NFC_POLL, ARRAY_SIZE(USI_CMD_NFC_POLL)); system_command(UartFd, USI_CMD_NFC_POLL, ARRAY_SIZE(USI_CMD_NFC_POLL), rx_Array); rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[2] != 0x00) && (rx_len >= 0)) { DEBUG_INFO("Card removed.\n"); C9_Result.isCardPreset = OFF; failCount = 0; } else if((rx_Data[0] == 0x00) && (rx_len >= 0)) { //DEBUG_INFO("Card seated.\n"); C9_Result.isCardPreset = ON; failCount = 0; } else { DEBUG_WARN("Module status read fail (<%02x>).\n", rx_Data[0]); failCount++; } if(failCount > RETRY_LIMIT) { C9_Result.isCardPreset = OFF; DEBUG_ERROR("Module status read fail over retry limit.\n"); } }while(((rx_Data[2] == 0x00) || (rx_len < 0)) && (failCount < RETRY_LIMIT)); } else { // MIFARE, IDO-15693, Credit Card, Apple Pay in query if(C8_Polling == true) { Wait_C9 = false; CurrentTime = time(NULL); tm=localtime(&CurrentTime); USI_CMD_C8_DEACTIVAVE[ARRAY_SIZE(USI_CMD_C8_DEACTIVAVE)-1] = calChksum(USI_CMD_C8_DEACTIVAVE, ARRAY_SIZE(USI_CMD_C8_DEACTIVAVE)); if(system_command(UartFd, USI_CMD_C8_DEACTIVAVE, ARRAY_SIZE(USI_CMD_C8_DEACTIVAVE), rx_Array) > 0) { rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[0] == ACK) && (rx_len >= 0)) { //DEBUG_INFO("C8 deactivate command success.\n"); failCount = 0; USI_CMD_C8_POLL[9] = decTobcd((1000/10000000000)%100); USI_CMD_C8_POLL[10] = decTobcd((1000/100000000)%100); USI_CMD_C8_POLL[11] = decTobcd((1000/1000000)%100); USI_CMD_C8_POLL[12] = decTobcd((1000/10000)%100); USI_CMD_C8_POLL[13] = decTobcd((1000/100)%100); USI_CMD_C8_POLL[14] = decTobcd((1000/1)%100); USI_CMD_C8_POLL[18] = (CURRENCY_USD>>0x08)&0xff; USI_CMD_C8_POLL[19] = (CURRENCY_USD>>0x00)&0xff; USI_CMD_C8_POLL[29] = decTobcd((tm->tm_year+1900)-2000); USI_CMD_C8_POLL[30] = decTobcd(tm->tm_mon+1); USI_CMD_C8_POLL[31] = decTobcd(tm->tm_mday); USI_CMD_C8_POLL[35] = decTobcd(tm->tm_hour); USI_CMD_C8_POLL[36] = decTobcd(tm->tm_min); USI_CMD_C8_POLL[37] = decTobcd(tm->tm_sec); USI_CMD_C8_POLL[ARRAY_SIZE(USI_CMD_C8_POLL)-1] = calChksum(USI_CMD_C8_POLL, ARRAY_SIZE(USI_CMD_C8_POLL)); if(system_command(UartFd, USI_CMD_C8_POLL, ARRAY_SIZE(USI_CMD_C8_POLL), rx_Array) > 0) { rx_len = USI2_Parse(rx_Array, rx_Data); if((rx_Data[0] == ACK) && (rx_len >= 0)) { //DEBUG_INFO("C8 polling command success.\n"); Wait_C9 = true; failCount = 0; C9_Result.isCommandError = OFF; } else { DEBUG_INFO("C8 polling command fail (<%02x>).\n", rx_Data[0]); C9_Result.isCommandError = ON; } } } else { DEBUG_INFO("C8 deactivate command fail.\n"); C9_Result.isCommandError = ON; } } 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 { //DEBUG_INFO("C9 response reading...\n"); usleep(1000000); 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); if((rx_len = USI2_Parse( rx_Array, rx_Data)) > 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[5], 16); DEBUG_INFO("Credit card SN:\n"); show_data(C9_Result.u_id, 16); for(uint8_t idx=0;idx= 0)) { DEBUG_INFO("Card removed.\n"); C9_Result.isCardPreset = OFF; failCount = 0; } else if((rx_Data[0]&0x02) && (rx_len >= 0)) { //DEBUG_INFO("Card seated.\n"); C9_Result.isCardPreset = ON; failCount = 0; } else { DEBUG_WARN("Module status read fail (<%02x>).\n", rx_Data[0]); failCount++; } if(failCount > RETRY_LIMIT) { C9_Result.isCardPreset = OFF; DEBUG_ERROR("Module status read fail over retry limit.\n"); } }while(((rx_Data[0]&0x02) || (rx_len < 0)) && (failCount < RETRY_LIMIT)); } } else { DEBUG_INFO("C9 Parsing result fail.\n"); C9_Result.isCommandError = ON; buzzer_on(UartFd, 3); // Wait card removed do { usleep(500000); system_command(UartFd, USI_CMD_MODULE_STATUS, ARRAY_SIZE(USI_CMD_MODULE_STATUS), rx_Array); rx_len = USI2_Parse(rx_Array, rx_Data); if(!(rx_Data[0]&0x02) && (rx_len >= 0)) { DEBUG_INFO("Card removed.\n"); C9_Result.isCardPreset = OFF; C9_Result.isCommandError = OFF; failCount = 0; } else if((rx_Data[0]&0x02) && (rx_len >= 0)) { //DEBUG_INFO("Card seated.\n"); C9_Result.isCardPreset = ON; failCount = 0; } else { DEBUG_WARN("Module status read fail (<%02x>).\n", rx_Data[0]); failCount++; } if(failCount > RETRY_LIMIT) { C9_Result.isCardPreset = OFF; DEBUG_ERROR("Module status read fail over retry limit.\n"); } }while(((rx_Data[0]&0x02) || (rx_len < 0)) && (failCount < RETRY_LIMIT)); } } else { DEBUG_WARN("C9 Response timeout: %d \n", failCount); buzzer_on(UartFd, 3); } } } } } } } usleep(500000); } return FAIL; }