...
The very step to avoid difficult integration times: unit test the external communication with ACE.
Topics covered:
Trace in ACE
...
Tutorial #6: add some logs to analyze the transaction
Topics covered:
Log signals to ACE
Log last APDU
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #6 // PURPOSE.... This code presents how to log a transaction for analysis // // Hypothesis and optimizations: // Communication between ACE and acceptance device is IP // // PROJECT.... Wiki // REFERENCES. -- // // Copyright ©2005-2020 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved // // See comprehensive example to get all functions used by this tutorial //--------------------------------------------------------- // Main //--------------------------------------------------------- int main(int argc, char** argv) { // See previous examples to get a PAYMENT request from ACE processRequest(buffer+1,len-1,pay); char* parameters; tStartingPoint sp = spSTART_A; // To initiate contactless transaction at preprocessing step char line1[100]="",line2[100]=""; // Initialize GPI // This is platform dependent. On Kizis AVT, this set PCSC readers' name from agnos.ini gpiMain(0,¶meters); // Load available kernels enpConnectPaymentServices("./AGNOS/"); // Set contactless configurations dtmInitializeFromFile("./AGNOS/",NULL,NULL,NULL,NULL,NULL,pay->mTransactionType,bFALSE); // Initialization entry point enpInitialize("","",bTRUE,bFALSE,bFALSE,pay); gpiSetTechnoToDetect(TECHNO_CL_TYPE_EMV); // Right before polling, need to tell which techno to poll on sprintf(line1,"PAY"); if(pay->mAmount) { sprintf(line2,"AMOUNT: %.2f",(*pay->mAmount)/100.0); } else { sprintf(line2,"--"); } gpiSetPollingMessage(line1,line2,NULL); // aceOut are to slow // Let's use some testing signals the same way a TA would do // Even if enpInitialize set signal = bTRUE, need to do more stuff tSignal signal; aceSetSignal(bTRUE); // Activate signal in ACE aceSetDigitalSignal(bTRUE); // Use digital signal instead of legacy strings aceGetSignal(&signal); // Get ACE signal services pmwSetSignal(&signal); // Set AgnosMW accordingly enpExecutePaymentTransaction(sp,pay,out); // Call main entry point primitive to trigger a transaction // Use ACE to trace last APDU jsut for fun tByte apduReq[MAX_APDU_LENGTH]="", apduResp[MAX_APDU_LENGTH]=""; tWord lenReq, lenResp; aceSetAPDULog(bTRUE); gpiGetLastExchangedAPDU((const char*)"",apduReq,&lenReq,apduResp,&lenResp); aceLogAPDU((const char*)"OUT",apduReq,lenReq); // Must be labelled OUT aceLogAPDU((const char*)"IN",apduResp,lenResp); // Must be labelled IN // For the same price, send all tags to ACE aceSendTag(pay); // Clean session closing (will switch antenna off) pay->mDataExchange.mError.mL1 = erL1OK; // Avoid display message within entry point out->mUIReqOnRestartPresent = bFALSE; // Avoid display message within entry point enpExecutePaymentTransaction(spNO_START,pay,out); // Acknowledge ACE and sends several tags for receipt printing... ackPayment(pay,out,((pay->mPOSEntryMode == EMV_CL_MODE) || (pay->mPOSEntryMode == MAG_CL_MODE))); // UI stuff.. gpiClearScreen(); gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS); gpiSwitchLED(LED_1,gpi_false,0); gpiSwitchLED(LED_2,gpi_false,0); gpiSwitchLED(LED_3,gpi_false,0); gpiSwitchLED(LED_4,gpi_false,0); aceOut("Training Session - END\n"); return 0; } |
...
Tutorial #7: log APDU exchanges in batch mode
Topics covered:
Log APDU offline
Display offline APDU to ACE
Close session
Code Block | ||
---|---|---|
| ||
// NAME....... Tutorial #7 // PURPOSE.... This code presents how to log APDU in batch mode // // Hypothesis and optimizations: // Communication between ACE and acceptance device is IP // // PROJECT.... Wiki // REFERENCES. -- // // Copyright ©2005-2020 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved // //--------------------------------------------------------- // Main //--------------------------------------------------------- int main(int argc, char** argv) { // See previous examples to get a PAYMENT request from ACE processRequest(buffer+1,len-1,pay); char* parameters; tStartingPoint sp = spSTART_A; // To initiate contactless transaction at preprocessing step char line1[100]="",line2[100]=""; // Initialize GPI // This is platform dependent. On Kizis AVT, this set PCSC readers' name from agnos.ini gpiMain(0,¶meters); // Load available kernels enpConnectPaymentServices("./AGNOS/"); // Set contactless configurations dtmInitializeFromFile("./AGNOS/",NULL,NULL,NULL,NULL,NULL,pay->mTransactionType,bFALSE); // Initialization entry point enpInitialize("","",bTRUE,bFALSE,bFALSE,pay); gpiSetTechnoToDetect(TECHNO_CL_TYPE_EMV); // Right before polling, need to tell which techno to poll on sprintf(line1,"PAY"); if(pay->mAmount) { sprintf(line2,"AMOUNT: %.2f",(*pay->mAmount)/100.0); } else { sprintf(line2,"--"); } gpiSetPollingMessage(line1,line2,NULL); // aceOut are to slow // Let's use some testing signals the same way a TA would do // Even if enpInitialize set signal = bTRUE, need to do more stuff tSignal signal; aceSetSignal(bTRUE); // Activate signal in ACE aceSetDigitalSignal(bTRUE); // Use digital signal instead of legacy strings aceGetSignal(&signal); // Get ACE signal services pmwSetSignal(&signal); // Set AgnosMW accordingly aceSetAPDULog(bFALSE); // Don't log APDU cmd/rsp in real-time aceSetTrace(MAX_TRACE_DEPTH+1); // Log offline enpExecutePaymentTransaction(sp,pay,out); // Call main entry point primitive to trigger a transaction // Log all batched APDU now aceLogAllBatchedAPDU(); // For the same price, send all tags to ACE aceSendTag(pay); // Clean session closing (will switch antenna off) pay->mDataExchange.mError.mL1 = erL1OK; // Avoid display message within entry point out->mUIReqOnRestartPresent = bFALSE; // Avoid display message within entry point enpExecutePaymentTransaction(spNO_START,pay,out); // Acknowledge ACE and sends several tags for receipt printing... ackPayment(pay,out,((pay->mPOSEntryMode == EMV_CL_MODE) || (pay->mPOSEntryMode == MAG_CL_MODE))); // UI stuff.. gpiClearScreen(); gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS); gpiSwitchLED(LED_1,gpi_false,0); gpiSwitchLED(LED_2,gpi_false,0); gpiSwitchLED(LED_3,gpi_false,0); gpiSwitchLED(LED_4,gpi_false,0); aceOut("Training Session - END\n"); return 0; } |
Tutorial #8: poll for card from payment application
Topics covered:
Polling from payment application
Manage gpiPolling error codes
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #8 // PURPOSE.... This code presents how to poll for card from payment application // // Hypothesis and optimizations: // Communication between ACE and acceptance device is IP // // PROJECT.... Wiki // REFERENCES. -- // // Copyright ©2005-2020 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved // //--------------------------------------------------------- // Main //--------------------------------------------------------- int main(int argc, char** argv) { // See previous examples to get a PAYMENT request from ACE processRequest(buffer+1,len-1,pay); char* parameters; tStartingPoint sp = spSTART_A; // To initiate contactless transaction at preprocessing step char line1[100]="",line2[100]=""; // Initialize GPI // This is platform dependent. On Kizis AVT, this set PCSC readers' name from agnos.ini gpiMain(0,¶meters); // Load available kernels enpConnectPaymentServices("./AGNOS/"); // Set contactless configurations dtmInitializeFromFile("./AGNOS/",NULL,NULL,NULL,NULL,NULL,pay->mTransactionType,bFALSE); // Initialization entry point enpInitialize("","",bFALSE,bFALSE,bFALSE,pay); // No more signal managed now tTerminalContext *terminalCtx = NULL; tByte technoToDetect = TECHNO_CL_TYPE_EMV; tGPIError gpiError = 0; terminalCtx = (tTerminalContext*)dtmGetData(TERMINAL_CTX); if(terminalCtx->mMagstripe) { technoToDetect |= TECHNO_MAGSTRIPE; } if(terminalCtx->mEMVContact) { technoToDetect |= TECHNO_CONTACT; } gpiSetTechnoToDetect(technoToDetect); sprintf(line1,"PAY"); if(pay->mAmount) { sprintf(line2,"AMOUNT: %.2f",(*pay->mAmount)/100.0); } else { sprintf(line2,"--"); } gpiDisplayMessage(gpi_true,line1); gpiDisplayMessage(gpi_false,line2); gpiError = gpiPolling("",5); // timeout set to 5 seconds sprintf(tmp,"GPI ERROR: 0x%.4X\n",gpiError); aceOut(tmp); if(scrINTERRUPTED == gpiError) { sprintf(tmp,"TRANSACTION INTERRUPTED\n"); aceOut(tmp); } else if(polTIMEOUT == gpiError) { sprintf(tmp,"No Tap\n"); aceOut(tmp); } else { sprintf(tmp,"CARD DETECTED FROM L3\n"); aceOut(tmp); enpSkipPollingOnNextStartB(gpiError); enpExecutePaymentTransaction(sp,pay,out); // Call main entry point primitive to trigger a transaction if (ocONLINE_REQUEST == out->mOutCome) { gpiDisplayMessage(gpi_true,"ONLINE"); length = 0; pmwGetEMVData( pay->mSession,(tByte*)"\x9F\x02\x95\x9F\x26\x9F\x27",7, pay->mDataExchange.mDataRecord.mStream,&pay->mDataExchange.mDataRecord.mLength); // For example, use ACE to emulate online auth. aceSendContactlessAuthorization(pay,bFALSE); if (TC == pay->mCID) { gpiDisplayMessage(gpi_true,"APPROVED"); } else { gpiDisplayMessage(gpi_true,"DECLINED"); } } else if (ocAPPROVED == out->mOutCome) { gpiDisplayMessage(gpi_true,"APPROVED"); } else { gpiDisplayMessage(gpi_true,"DECLINED"); } } // Clean session closing (will switch antenna off) pay->mDataExchange.mError.mL1 = erL1OK; // Avoid display message within entry point out->mUIReqOnRestartPresent = bFALSE; // Avoid display message within entry point enpExecutePaymentTransaction(spNO_START,pay,out); // Acknowledge ACE and sends several tags for receipt printing... ackPayment(pay,out,((pay->mPOSEntryMode == EMV_CL_MODE) || (pay->mPOSEntryMode == MAG_CL_MODE))); // UI stuff.. gpiClearScreen(); gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS); gpiSwitchLED(LED_1,gpi_false,0); gpiSwitchLED(LED_2,gpi_false,0); gpiSwitchLED(LED_3,gpi_false,0); gpiSwitchLED(LED_4,gpi_false,0); aceOut("Training Session - END\n"); return 0; } |
Tutorial #9: integrate Data Exchange for contactless
Topics covered:
Create a DE/DS callback
Intercept contactless card processing flow
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #9 // PURPOSE.... This code presents how to integrated data exchange // // Hypothesis and optimizations: // Communication between ACE and acceptance device is IP // // PROJECT.... Wiki // REFERENCES. -- // // Copyright ©2005-2020 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved // //--------------------------------------------------------- // Main //--------------------------------------------------------- int main(int argc, char** argv) { // See previous examples to get a PAYMENT request from ACE processRequest(buffer+1,len-1,pay); char* parameters; tStartingPoint sp = spSTART_A; // To initiate contactless transaction at preprocessing step char line1[100]="",line2[100]=""; // Initialize GPI // This is platform dependent. On Kizis AVT, this set PCSC readers' name from agnos.ini gpiMain(0,¶meters); // Load available kernels enpConnectPaymentServices("./AGNOS/"); // Set contactless configurations dtmInitializeFromFile("./AGNOS/",NULL,NULL,NULL,NULL,NULL,pay->mTransactionType,bFALSE); // Initialization entry point enpInitialize("","",bFALSE,bFALSE,bFALSE,pay); // No more signal managed now tTerminalContext *terminalCtx = NULL; tByte technoToDetect = TECHNO_CL_TYPE_EMV; tGPIError gpiError = 0; terminalCtx = (tTerminalContext*)dtmGetData(TERMINAL_CTX); if(terminalCtx->mMagstripe) { technoToDetect |= TECHNO_MAGSTRIPE; } if(terminalCtx->mEMVContact) { technoToDetect |= TECHNO_CONTACT; } gpiSetTechnoToDetect(technoToDetect); sprintf(line1,"PAY"); if(pay->mAmount) { sprintf(line2,"AMOUNT: %.2f",(*pay->mAmount)/100.0); } else { sprintf(line2,"--"); } gpiDisplayMessage(gpi_true,line1); gpiDisplayMessage(gpi_false,line2); gpiError = gpiPolling("",5); // timeout set to 5 seconds sprintf(tmp,"GPI ERROR: 0x%.4X\n",gpiError); aceOut(tmp); if(scrINTERRUPTED == gpiError) { sprintf(tmp,"TRANSACTION INTERRUPTED\n"); aceOut(tmp); } else if(polTIMEOUT == gpiError) { sprintf(tmp,"No Tap\n"); aceOut(tmp); } else { sprintf(tmp,"CARD DETECTED FROM L3\n"); aceOut(tmp); // Use DF12 - TAGS to READ - inside contactless combination // DF12015A will trigger the data exchange mechanism when tag 5A will be found pay->mDataExchange.mCallback = &myDEProcess; pay->mDataExchange.mDEList = &gDEListCtx; enpSkipPollingOnNextStartB(gpiError); enpExecutePaymentTransaction(sp,pay,out); // Call main entry point primitive to trigger a transaction if (ocONLINE_REQUEST == out->mOutCome) { gpiDisplayMessage(gpi_true,"ONLINE"); length = 0; pmwGetEMVData( pay->mSession,(tByte*)"\x9F\x02\x95\x9F\x26\x9F\x27",7, pay->mDataExchange.mDataRecord.mStream,&pay->mDataExchange.mDataRecord.mLength); // For example, use ACE to emulate online auth. aceSendContactlessAuthorization(pay,bFALSE); if (TC == pay->mCID) { gpiDisplayMessage(gpi_true,"APPROVED"); } else { gpiDisplayMessage(gpi_true,"DECLINED"); } } else if (ocAPPROVED == out->mOutCome) { gpiDisplayMessage(gpi_true,"APPROVED"); } else { gpiDisplayMessage(gpi_true,"DECLINED"); } } // Clean session closing (will switch antenna off) pay->mDataExchange.mError.mL1 = erL1OK; // Avoid display message within entry point out->mUIReqOnRestartPresent = bFALSE; // Avoid display message within entry point enpExecutePaymentTransaction(spNO_START,pay,out); // Acknowledge ACE and sends several tags for receipt printing... ackPayment(pay,out,((pay->mPOSEntryMode == EMV_CL_MODE) || (pay->mPOSEntryMode == MAG_CL_MODE))); // UI stuff.. gpiClearScreen(); gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS); gpiSwitchLED(LED_1,gpi_false,0); gpiSwitchLED(LED_2,gpi_false,0); gpiSwitchLED(LED_3,gpi_false,0); gpiSwitchLED(LED_4,gpi_false,0); aceOut("Training Session - END\n"); return 0; |