Table of Contents |
---|
...
The very step to avoid difficult integration times: unit test the external communication with ACE.
View file | ||
---|---|---|
|
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #1 // PURPOSE.... This code presents how to connect onto ACE and to use aceOut // // 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) { // Communication int port, length; char address[50]=""; // Get Communication parameters from ini file // These paramerters maybe wired inside the code for training purposes xgpiIniSetFilename("agnos.ini"); xgpiIniGetString("COM", "Address", 50, address, &length); xgpiIniGetNumeric("COM", "Port", &port); // Initialize ACE // Initialize generic communication interface assert(tcpInit(0) == TCP_NO_ERROR); // Create server and client assert(comtcpOpen(&gACEServerCOMTCP, TCP_SERVER, 0, port) == COM_NO_ERROR); assert(comtcpOpen(&gACEClientCOMTCP, TCP_CLIENT, address, 1979) == COM_NO_ERROR); // Set ACE with server and client aceInitializeCommunication(&gACEServerCOMTCP.com,&gACEClientCOMTCP.com); // Initialize running mode aceSetMode(pmSDK); // Set ACE option aceSetUIDisplay(bTRUE); // Trace into ACE aceOut("Training Session - BEGIN\n"); aceOut("Hello World!\n"); aceOut("Training Session - END\n"); return 0; } |
...
Code Block | ||
---|---|---|
| ||
// NAME....... Tutorial #5 // PURPOSE.... This code presents how to excute a contactless payment transaction // // 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 //--------------------------------------------------------- // ackPayment //--------------------------------------------------------- void ackPayment(tPaymentContext *ctx,tOutComeParameter* outcome,tBoolean isContactless) { tByte buffer[300]=""; tWord lenIn=0; tAmount amount=0, cashback=0; // CVM Results buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x34; buffer[lenIn++] = 0x03; gpiMemCpy(&buffer[lenIn],ctx->mCVMResult,sizeof(ctx->mCVMResult)); lenIn+=3; // TVR buffer[lenIn++] = 0x95; buffer[lenIn++] = 0x05; gpiMemCpy(&buffer[lenIn],ctx->mTVR,sizeof(ctx->mTVR)); lenIn+=5; // TSI buffer[lenIn++] = 0x9B; buffer[lenIn++] = 0x02; gpiMemCpy(&buffer[lenIn],ctx->mTSI,sizeof(ctx->mTSI)); lenIn+=2; // AID buffer[lenIn++] = 0x84; buffer[lenIn++] = ctx->mAIDLen; gpiMemCpy(&buffer[lenIn],ctx->mAID,ctx->mAIDLen); lenIn+=ctx->mAIDLen; // POS entry mode buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x39; buffer[lenIn++] = 0x01; buffer[lenIn++] = ctx->mPOSEntryMode; // Cardholder name buffer[lenIn++] = 0x5F; buffer[lenIn++] = 0x20; buffer[lenIn++] = ctx->mCardholderNameLen; gpiMemCpy(&buffer[lenIn],ctx->mCardholderName,ctx->mCardholderNameLen); lenIn+=ctx->mCardholderNameLen; // AC buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x26; buffer[lenIn++] = 0x08; gpiMemCpy(&buffer[lenIn],ctx->mAC,8); lenIn+=8; // Date buffer[lenIn++] = 0x9A; buffer[lenIn++] = 0x03; gpiMemCpy(&buffer[lenIn],ctx->mTransactionDate,sizeof(ctx->mTransactionDate)); lenIn+=3; // Time buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x21; buffer[lenIn++] = 0x03; gpiMemCpy(&buffer[lenIn],ctx->mTransactionTime,sizeof(ctx->mTransactionTime)); lenIn+=3; // Transaction type buffer[lenIn++] = 0x9C; buffer[lenIn++] = 0x01; buffer[lenIn++] = ctx->mTransactionType; // Amount and Cashback buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x02; buffer[lenIn++] = 0x06; if(ctx->mAmount) amount = *ctx->mAmount; else // If amount not defined then 9F02 may be modified during CL processing convertBCDToAmount(&amount,ctx->mFinal9F02,sizeof(ctx->mFinal9F02)); if(ctx->mCashBack) cashback = *ctx->mCashBack; convertAmount(amount + cashback,&buffer[lenIn]); lenIn+=6; buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x03; buffer[lenIn++] = 0x06; convertAmount(cashback,&buffer[lenIn]); lenIn+=6; // Transaction Currency Code buffer[lenIn++] = 0x5F; buffer[lenIn++] = 0x2A; buffer[lenIn++] = 0x02; buffer[lenIn++] = ctx->mTransactionCurrencyCode[0]; buffer[lenIn++] = ctx->mTransactionCurrencyCode[1]; // Transaction Currency Exponent buffer[lenIn++] = 0x5F; buffer[lenIn++] = 0x36; buffer[lenIn++] = 0x01; buffer[lenIn++] = ctx->mTransactionCurrencyExponent; // Label buffer[lenIn++] = 0x50; buffer[lenIn++] = ctx->mADF.mLabelLen; gpiMemCpy(&buffer[lenIn],ctx->mADF.mLabel,ctx->mADF.mLabelLen); lenIn+=ctx->mADF.mLabelLen; // Preferred Name buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x12; buffer[lenIn++] = ctx->mADF.mPreferredNameLen; gpiMemCpy(&buffer[lenIn],ctx->mADF.mPreferredName,ctx->mADF.mPreferredNameLen); lenIn+=ctx->mADF.mPreferredNameLen; // ISR buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x5B; buffer[lenIn++] = ctx->mIssuerScriptResultLen; gpiMemCpy(&buffer[lenIn],ctx->mIssuerScriptResult,ctx->mIssuerScriptResultLen); lenIn+=ctx->mIssuerScriptResultLen; // OASA buffer[lenIn++] = 0x9F; buffer[lenIn++] = 0x5D; if(ctx->mDataExchange.mUIRequestData.mValueQualifier == vqBALANCE) { buffer[lenIn++] = sizeof(ctx->mDataExchange.mUIRequestData.mValue); gpiMemCpy(&buffer[lenIn],ctx->mDataExchange.mUIRequestData.mValue,sizeof(ctx->mDataExchange.mUIRequestData.mValue)); lenIn+=sizeof(ctx->mDataExchange.mUIRequestData.mValue); } else buffer[lenIn++] = 0x00; // Agnos TVR buffer[lenIn++] = 0xDF; buffer[lenIn++] = 0x72; buffer[lenIn++] = sizeof(ctx->mAgnosTVR); gpiMemCpy(&buffer[lenIn],ctx->mAgnosTVR,sizeof(ctx->mAgnosTVR)); lenIn+=sizeof(ctx->mAgnosTVR); // Proprietary blob (22 bytes) // 20 bytes: SHA PAN gpiMemCpy(&buffer[lenIn],ctx->mPANSHA,20); lenIn+=20; // 1 byte: Receipt and Sign flag if(pmwIsCVMSignature(ctx) || (outcome->mCVM == cvOBTAIN_SIGNATURE)) buffer[lenIn++] = 0x31; else buffer[lenIn++] = 0x30; // Doesn't print receipt if CL + !gOutcome.mReceipt if(isContactless && !outcome->mReceipt) buffer[lenIn-1] |= 0x02; // 1 byte: outcome buffer[lenIn++] = 0x30 + outcome->mOutCome; aceSendResponse(buffer,lenIn); } //--------------------------------------------------------- // 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]=""; char *string=NULL; // 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); outPaymentContext(pay); // Trace payment request enpExecutePaymentTransaction(sp,pay,out); // Call main entry point primitive to trigger a transaction outOutcomeParameter(out); // Trace outcome // 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+1,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; } |
...
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]="";
char *string=NULL;
// 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+1,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;
} |
...
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]="";
char *string=NULL;
// 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+1,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;
}
|