|
@@ -6,7 +6,7 @@
|
|
|
*/
|
|
|
|
|
|
#include "Module_Payment.h"
|
|
|
-unsigned char version[] = {'D', '0', '.', '0', '3'};
|
|
|
+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
|
|
@@ -16,6 +16,7 @@ unsigned char BLP_CMD_SET_AID[] = {0x09, 0, 0x04, 'A', 'D', '0', 0, 0x38};
|
|
|
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
|
|
@@ -32,14 +33,15 @@ unsigned char USI_CMD_C8_POLL[] = {0x01, 0x00, 0x00, 0x2b, // STX, a
|
|
|
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, 0x00, 0x00, // Command timeout unit is million second, sample: umlimit
|
|
|
+ 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);
|
|
@@ -305,11 +307,8 @@ int InitComPort()
|
|
|
{
|
|
|
int fd;
|
|
|
struct termios tios;
|
|
|
-#ifndef X86
|
|
|
- fd = open("/dev/ttyS3", O_RDWR);
|
|
|
-#else
|
|
|
- fd = open("/dev/ttyUSB3", O_RDWR);
|
|
|
-#endif
|
|
|
+
|
|
|
+ fd = open(TTY_PORT, O_RDWR);
|
|
|
if(fd<=0)
|
|
|
{
|
|
|
return FAIL;
|
|
@@ -395,6 +394,19 @@ int USI2_Parse(unsigned char* rx, unsigned char* rx_data)
|
|
|
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
|
|
|
//==========================================
|
|
@@ -442,7 +454,7 @@ int main(void)
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- DEBUG_INFO("ttyS3 port open success.\n");
|
|
|
+ DEBUG_INFO("%s port open success.\n", TTY_PORT);
|
|
|
}
|
|
|
|
|
|
//===============================================
|
|
@@ -665,6 +677,30 @@ int main(void)
|
|
|
}
|
|
|
}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)
|
|
|
//===============================================
|
|
@@ -825,206 +861,48 @@ int main(void)
|
|
|
}
|
|
|
}while((rx_Data[0] != ACK) || (rx_len < 0));
|
|
|
|
|
|
+ DEBUG_INFO("Payment module initialize completed.\n");
|
|
|
+
|
|
|
//===============================================
|
|
|
// Main loop
|
|
|
//===============================================
|
|
|
for(;;)
|
|
|
{
|
|
|
- if(C8_Polling == true)
|
|
|
+ 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)
|
|
|
{
|
|
|
- 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[2] == 0x00) && (rx_len >= 0))
|
|
|
{
|
|
|
- rx_len = USI2_Parse(rx_Array, rx_Data);
|
|
|
- if((rx_Data[0] == ACK) && (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)
|
|
|
{
|
|
|
- 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[2] == 0x00) && (rx_len >= 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(2000000);
|
|
|
- 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
|
|
|
+ // FELICA
|
|
|
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<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);
|
|
|
+ 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]);
|
|
|
|
|
|
- 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_WARN("Unknown pos entry.\n");
|
|
|
- if(C9_Result.status == C9_RES_C8_CMD_TIMEOUT)
|
|
|
- DEBUG_WARN("C8 command timeout.\n");
|
|
|
- else if(C9_Result.status == C9_RES_CMD_EXECUTING)
|
|
|
- DEBUG_WARN("Command executing or Wait Card to be Removed.\n");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
- failCount = 0;
|
|
|
+ buzzer_on(UartFd, 1);
|
|
|
|
|
|
// Wait card removed
|
|
|
do
|
|
|
{
|
|
|
- system_command(UartFd, USI_CMD_MODULE_STATUS, ARRAY_SIZE(USI_CMD_MODULE_STATUS), rx_Array);
|
|
|
+ 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[0]&0x02) && (rx_len >= 0))
|
|
|
+ if((rx_Data[2] != 0x00) && (rx_len >= 0))
|
|
|
{
|
|
|
DEBUG_INFO("Card removed.\n");
|
|
|
C9_Result.isCardPreset = OFF;
|
|
|
failCount = 0;
|
|
|
}
|
|
|
- else if((rx_Data[0]&0x02) && (rx_len >= 0))
|
|
|
+ else if((rx_Data[0] == 0x00) && (rx_len >= 0))
|
|
|
{
|
|
|
//DEBUG_INFO("Card seated.\n");
|
|
|
C9_Result.isCardPreset = ON;
|
|
@@ -1041,53 +919,282 @@ int main(void)
|
|
|
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));
|
|
|
+ }while(((rx_Data[2] == 0x00) || (rx_len < 0)) && (failCount < RETRY_LIMIT));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- DEBUG_INFO("C9 Parsing result fail.\n");
|
|
|
- C9_Result.isCommandError = ON;
|
|
|
- // Wait card removed
|
|
|
- do
|
|
|
+ // MIFARE, IDO-15693, Credit Card, Apple Pay in query
|
|
|
+ if(C8_Polling == true)
|
|
|
{
|
|
|
- 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
|
|
|
+ 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)
|
|
|
{
|
|
|
- DEBUG_WARN("Module status read fail (<%02x>).\n", rx_Data[0]);
|
|
|
- failCount++;
|
|
|
+ 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(failCount > RETRY_LIMIT)
|
|
|
+ if(Wait_C9 == true)
|
|
|
{
|
|
|
- C9_Result.isCardPreset = OFF;
|
|
|
- DEBUG_ERROR("Module status read fail over retry limit.\n");
|
|
|
+ //=============================================
|
|
|
+ // 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<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);
|
|
|
+ }
|
|
|
+ buzzer_on(UartFd, 1);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ buzzer_on(UartFd, 1);
|
|
|
+ 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]);
|
|
|
+ buzzer_on(UartFd, 1);
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ buzzer_on(UartFd, 1);
|
|
|
+ break;
|
|
|
+ case No_Data:
|
|
|
+ //DEBUG_INFO("No any data.\n");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DEBUG_WARN("Unknown pos entry.\n");
|
|
|
+ if(C9_Result.status == C9_RES_C8_CMD_TIMEOUT)
|
|
|
+ DEBUG_WARN("C8 command timeout.\n");
|
|
|
+ else if(C9_Result.status == C9_RES_CMD_EXECUTING)
|
|
|
+ DEBUG_WARN("Command executing or Wait Card to be Removed.\n");
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ failCount = 0;
|
|
|
+
|
|
|
+ // Wait card removed
|
|
|
+ if(C9_Result.pos_entry != No_Data)
|
|
|
+ {
|
|
|
+ do
|
|
|
+ {
|
|
|
+ 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;
|
|
|
+ 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);
|
|
|
+ }
|
|
|
}
|
|
|
- }while(((rx_Data[0]&0x02) || (rx_len < 0)) && (failCount < RETRY_LIMIT));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- DEBUG_WARN("C9 Response timeout: %d \n", failCount);
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- usleep(1000000);
|
|
|
+ usleep(500000);
|
|
|
}
|
|
|
|
|
|
return FAIL;
|