Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
breakoutModewide
languagec
// 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,&parameters);

	// 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
breakoutModewide
// 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,&parameters);

	// 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
breakoutModewide
languagec
// 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,&parameters);

	// 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
breakoutModewide
languagec
// 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,&parameters);

	// 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;