Table of Contents |
---|
That series of tutorials use Kizis as the squeleton to build from scratch a basic payment application.
Use ACE to trace and monitor behaviors (open ‘'Console Log’' to see traces).
These examples have been built using a Visa configuration (Ipaywave213_ICC/CONF_01)
Tutorial #1: set communication and traces using ACE
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;
} |
Tutorial #2: initialize language and payment context
View file | ||
---|---|---|
|
...
breakoutMode | wide |
---|---|
language | c |
...
Table of Contents |
---|
That series of tutorials:
Use Kizis as the squeleton to build from scratch a basic payment application.
Use ACE to trace and monitor behaviors (open ‘'Console Log’', Signal tab, Processing tab to see traces).
These examples have been built using a Visa configuration (paywave213_ICC/CONF_01).
Tutorial #1: set communication and traces using ACE
The very step to avoid difficult integration times: unit test the external communication with ACE.
Topics covered:
Trace in ACE
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;
} |
Tutorial #2: initialize language and payment context
Topics covered:
Init payment contexts
Languages management
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #2
// PURPOSE.... This code presents how to intialize language and payment contexts
//
// 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]="";
// Trace for debugging
char tmp[100]="";
// Payment Contexts
tPaymentContext* pay = &gPaymentCtx;
tOutComeParameter* out = &gOutcome;
// System's language
tByte availableLanguage=0;
tByte currentLanguage = 0;
// 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 up ACE's options
aceSetUIDisplay(bTRUE);
aceOut("Training Session - BEGIN\n");
aceOut("Hello World!\n");// set default language (merchant language indeed)
// Initialize lines, columns and set string table from lang.ini
gpiInitializeDisplay("lang.ini",&availableLanguage,NULL);
sprintf(tmp,"Available lang.: %i\n",availableLanguage);
aceOut(tmp);
// Initialize payment context and outcome
pmwInitializePaymentContext(pay);
pmwSetLanguage(pay,currentLanguage); // Don't forget to propagate language in payment context for further processing
currentLanguage = pmwGetLanguage(pay);
pmwInitializeOutComeParameter(out);
// Important to perform these initializations after pmwInitializePaymentContext
pay->mAmount = &gAmount;
pay->mCashBack = &gCashBack;
pay->mTransactionType = (tTransactionType)0x00;
gAmount = gCashBack = 0;
gpiDisplayMessageByID(gpi_true,currentLanguage,WELCOME);
gpiDisplayMessageByID(gpi_true,currentLanguage+1,THANKS); // Assuming that there are at least 2 languages
aceOut("Training Session - END\n");
return 0;
} |
Tutorial #3: manage ACE requests
Topics covered:
Shared RAM example
Inbound requests from ACE:
TERMINAL
PROCESSING
ENTRY POINT
CAKeys
Code Block | ||
---|---|---|
| ||
// NAME....... Tutorial #3
// PURPOSE.... This code presents how to intialize language and payment contexts
//
// 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
//
//---------------------------------------------------------
// CreateFile
//---------------------------------------------------------
void createFile(char* fileName, tByte* buffer, tWord len)
{
tFileHandler ifp = 0;
if (fileName)
{
gpiFileDelete(fileName);
if(gpiFileOpen(fileName,&ifp,CREATE|BINARY)==filNO_ERROR)
{
gpiFileWrite(ifp,buffer,len);
gpiFileClose(ifp);
}
}
}
//---------------------------------------------------------
// Main
//---------------------------------------------------------
int main(int argc, char** argv)
{
// Communication
int port, length;
char address[50]="";
// Trace for debugging
char tmp[100]="";
// Payment contexts
tPaymentContext* pay = &gPaymentCtx;
tOutComeParameter* out = &gOutcome;
// System's language
tByte availableLanguage=0, currentLanguage = 0;
// Get Communication parameters from ini file
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 up ACE's options
aceSetUIDisplay(bTRUE);
aceOut("Training Session - BEGIN\n");
aceOut("Hello World!\n");// set default language (merchant language indeed)
// Initialize lines, columns and set string table from lang.ini
gpiInitializeDisplay("lang.ini",&availableLanguage,NULL);
sprintf(tmp,"Available lang.: %i\n",availableLanguage);
aceOut(tmp);
// Initialize payment context and outcome
pmwInitializePaymentContext(pay);
pmwSetLanguage(pay,currentLanguage); // Don't forget to propagate language in payment context for further processing
currentLanguage = pmwGetLanguage(pay);
pmwInitializeOutComeParameter(out);
// Important to perform these initializations after pmwInitializePaymentContext
pay->mAmount = &gAmount;
pay->mCashBack = &gCashBack;
pay->mTransactionType = (tTransactionType)0x00;
gAmount = gCashBack = 0;
tByte *buffer = NULL;
tDataFileSize size=0;
tWord len=0;
char c, workingString[1000]="";
gpiGetTotalRAM(&buffer,&size);
if (!buffer)
return 0;
len=0;
gpiMemSet(buffer,0x00,size);
gpiMemSet(workingString,0x00,sizeof(workingString));
// Wait for inbound sale request
do
{
gpiDisplayMessageByID(gpi_true,currentLanguage,WELCOME);
c = aceGetRequest(buffer,&len);
if (INIT == c)
{
sprintf(workingString,"%sTERMINAL","./AGNOS/");
createFile(workingString,buffer+1,len-1);
gpiDisplayMessage(gpi_true,"TERMINAL Updated" );
}
else if (CONFIG == c)
{
sprintf(workingString,"%sPROCESSING","./AGNOS/");
createFile(workingString,buffer+1,len-1);
gpiDisplayMessage(gpi_true,"PROCESSING Updated" );
}
else if ( CL_ENTRY_POINT == c)
{
sprintf(workingString,"%sENTRY_POINT","./AGNOS/");
createFile(workingString,buffer+1,len-1);
gpiDisplayMessage(gpi_true,"ENTRY_POINT Updated" );
}
else if ((CAPK == c) && (len >= 21))
{
sprintf(workingString,"%sCAKeys","./AGNOS/");
createFile(workingString,buffer+1,len-1-20);
gpiDisplayMessage(gpi_true,"CAPK Updated" );
}
aceSendResponse((unsigned char*)"\x30\x30",2);
} while (c != PAYMENT);
gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS);
aceOut("Training Session - END\n");
return 0;
} |
Tutorial #4: manage a payment request
For this tutorial, code examples rely on previous tutorial. Let’s focus on how to manage a transaction payment transaction ans set tPaymentContext accordingly. A comprehensive example is provided below.
Topics covered:
Process and acknowledge a PAYMENT request from ACE
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #4
// PURPOSE.... This code presents how to process a payment request
//
// 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
// Display contexts BEFORE processing ACE request
outPaymentContext(pay);
outOutcomeParameter(out);
// Process ACE request for a payment. Set pay as per TRD contents
processRequest(buffer+1,len-1,pay);
// Display contexts AFTER processing ACE request
outPaymentContext(pay);
outOutcomeParameter(out);
// Acknowledge ACE
aceSendResponse((unsigned char*)"\x30\x30",2);
gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS);
aceOut("Training Session - END\n");
return 0;
} |
Tutorial #5: perform a contactless transaction
Topics covered:
Configure Agnos Framework
Configure GPI for polling
Preparing Agnos Framework for contactless transaction
Execute a transaction with entry point
Complete a transaction by building up a receipt to ACE
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); } //-------------------------------------------------- int main(int argc, char** argv) { // Communication int port, length; char address[50]=""; // Trace for debugging char tmp[100]=""; // Payment Contexts tPaymentContext* pay = &gPaymentCtx; tOutComeParameter* out = &gOutcome; // System's language tByte availableLanguage=0; tByte currentLanguage = 0; // 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------- // 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); // SetLoad upavailable ACE'skernels options aceSetUIDisplay(bTRUEenpConnectPaymentServices("./AGNOS/"); aceOut("Training Session - BEGIN\n"); aceOut("Hello World!\n");// set default language (merchant language indeed) // Initialize lines, columns and set string table from lang.ini gpiInitializeDisplay("lang.ini",&availableLanguage,NULL); sprintf(tmp,"Available lang.: %i\n",availableLanguage); aceOut(tmp); // Initialize payment context and outcome pmwInitializePaymentContext(pay); pmwSetLanguage(pay,currentLanguage); // Don't forget to propagate language in payment context for further processing currentLanguage = pmwGetLanguage(pay); pmwInitializeOutComeParameter(out); // Important to perform these initializations after pmwInitializePaymentContext pay->mAmount = &gAmount; pay->mCashBack = &gCashBack; pay->mTransactionType = (tTransactionType)0x00; gAmount = gCashBack = 0; // 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,WELCOMETHANKS); gpiDisplayMessageByIDgpiSwitchLED(LED_1,gpi_true,currentLanguage+1,THANKS); // Assuming that there are at least 2 languages _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
...
#6: add some logs to analyze the transaction
Topics covered:
Log signals to ACE
Log last APDU
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #3#6 // PURPOSE.... This code presents how to intializelog languagea and payment contexts // // Hypothesis and optimizations: // Communication between ACE and acceptance device is IP // // PROJECT.... Wiki // REFERENCES. --transaction for analysis // // Hypothesis Copyright ©2005-2020 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved // //--------------------------------------------------------- // CreateFile //--------------------------------------------------------- void createFile(char* fileName, tByte* buffer, tWord len) { tFileHandler ifp = 0; if (fileName) { gpiFileDelete(fileName); if(gpiFileOpen(fileName,&ifp,CREATE|BINARY)==filNO_ERROR) { gpiFileWrite(ifp,buffer,len); gpiFileClose(ifp); } } }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) { // Communication int port, length; char address[50]=""; // Trace for debugging char tmp[100]=""; // Payment contexts tPaymentContext* pay = &gPaymentCtx; tOutComeParameter* out = &gOutcome; // System's language tByte availableLanguage=0, currentLanguage = 0 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]=""; // GetInitialize CommunicationGPI parameters // fromThis iniis file xgpiIniSetFilename("agnos.ini"); xgpiIniGetString("COM", "Address", 50, address, &length); xgpiIniGetNumeric("COM", "Port", &portplatform dependent. On Kizis AVT, this set PCSC readers' name from agnos.ini gpiMain(0,¶meters); // InitializeLoad ACEavailable // Initialize generic communication interface assert(tcpInit(0) == TCP_NO_ERRORkernels enpConnectPaymentServices("./AGNOS/"); // CreateSet servercontactless and clientconfigurations 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 up ACE's options aceSetUIDisplay(bTRUE); aceOut("Training Session - BEGIN\n"); aceOut("Hello World!\n");// set default language (merchant language indeed) // Initialize lines, columns and set string table from lang.ini gpiInitializeDisplay("lang.ini",&availableLanguage,NULL); sprintf(tmp,"Available lang.: %i\n",availableLanguage); aceOut(tmp); // Initialize payment context and outcome pmwInitializePaymentContext(pay); pmwSetLanguage(pay,currentLanguage); // Don't forget to propagate language in payment context for further processing currentLanguage = pmwGetLanguage(pay); pmwInitializeOutComeParameter(out); // Important to perform these initializations after pmwInitializePaymentContext pay->mAmount = &gAmount; pay->mCashBack = &gCashBack; pay->mTransactionType = (tTransactionType)0x00; gAmount = gCashBack = 0; tByte *buffer = NULL; tDataFileSize size=0; tWord len=0; char c, workingString[1000]=""; gpiGetTotalRAM(&buffer,&size); if (!buffer) return 0; len=0; gpiMemSet(buffer,0x00,size); gpiMemSet(workingString,0x00,sizeof(workingString)); // Wait for inbound sale request do { gpiDisplayMessageByID(gpi_true,currentLanguage,WELCOME); c = aceGetRequest(buffer,&len); if (INIT == c) { sprintf(workingString,"%sTERMINAL","./AGNOS/"); createFile(workingString,buffer+1,len-1); gpiDisplayMessage(gpi_true,"TERMINAL Updated" ); } else if (CONFIG == c) { sprintf(workingString,"%sPROCESSING","./AGNOS/"); createFile(workingString,buffer+1,len-1); gpiDisplayMessage(gpi_true,"PROCESSING Updated" ); } else if ( CL_ENTRY_POINT == c) { sprintf(workingString,"%sENTRY_POINT","./AGNOS/"); createFile(workingString,buffer+1,len-1); gpiDisplayMessage(gpi_true,"ENTRY_POINT Updated" ); } else if ((CAPK == c) && (len >= 21)) { sprintf(workingString,"%sCAKeys","./AGNOS/"); createFile(workingString,buffer+1,len-1-20); gpiDisplayMessage(gpi_true,"CAPK Updated" ); } aceSendResponse((unsigned char*)"\x30\x30",2); } while (c != PAYMENT); gpiDisplayMessageByID(gpi_true,currentLanguage,THANKSdtmInitializeFromFile("./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 #4: manage a payment request
For this tutorial, code examples rely on previous tutorial. Let’s focus on how to manage a transaction payment transaction ans set tPaymentContext accordingly. A comprehensive example is provided below.
View file | ||
---|---|---|
|
} |
Tutorial #7: log APDU exchanges in batch mode
Topics covered:
Log APDU offline
Display offline APDU to ACE
Close session
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #4#7 // PURPOSE.... This code presents how to log processAPDU ain paymentbatch requestmode // // 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 All Rights Reserved // //--------------------------------------------------------- // Main //--------------------------------------------------------- int main(int argc, char** argv) { // See previous examples to get a PAYMENT request from ACE // Display contexts BEFORE processing ACE request outPaymentContext(pay); outOutcomeParameter(out); // Process ACE request for a payment. Set pay as per TRD contents processRequest(buffer+1,len-1,pay); // Display contexts AFTER processing ACE request outPaymentContext(pay); outOutcomeParameter(out); // Acknowledge ACE aceSendResponse((unsigned char*)"\x30\x30",2); gpiDisplayMessageByID(gpi_true,currentLanguage,THANKS); aceOut("Training Session - END\n"); return 0; } |
Tutorial #5: perform a contactless transaction
View file | ||
---|---|---|
|
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"); gpiGetString(pmwGetLanguage(pay),PRESENT_CARD,&string); 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- 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
Send an online authorization message
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+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; } |
Tutorial
...
#9: integrate Data Exchange for contactless
Topics covered:
Create a DE/DS callback
Intercept contactless card processing flow
Code Block | ||||
---|---|---|---|---|
| ||||
// NAME....... Tutorial #6#9 // PURPOSE.... This code presents how to logintegrated adata transactionexchange 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 , 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"); gpiGetString(pmwGetLanguage(pay),PRESENT_CARD,&string); if(pay->mAmount-- 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(line2tmp,"AMOUNT: %.2f",(*pay->mAmount)/100.0)No Tap\n"); aceOut(tmp); } else { sprintf(line2tmp,"--CARD DETECTED FROM L3\n"); } gpiSetPollingMessage(line1,line2,NULL); // aceOut are to slow aceOut(tmp); // Let'sUse useDF12 some- testingTAGS signalsto theREAD same- wayinside acontactless TA would do combination // EvenDF12015A will iftrigger enpInitializethe setdata signalexchange =mechanism bTRUE,when needtag to5A dowill morebe stufffound tSignal signal pay->mDataExchange.mCallback = &myDEProcess; aceSetSignal(bTRUE); // Activate signal in ACE aceSetDigitalSignal(bTRUE pay->mDataExchange.mDEList = &gDEListCtx; enpSkipPollingOnNextStartB(gpiError); enpExecutePaymentTransaction(sp,pay,out); // 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); 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+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; } |