Amadis
Agnos Framework Tutorials
- 1 Tutorial #1: set communication and traces using ACE
- 2 Tutorial #2: initialize language and payment context
- 3 Tutorial #3: manage ACE requests
- 4 Tutorial #4: manage a payment request
- 5 Tutorial #5: perform a contactless transaction
- 6 Tutorial #6: add some logs to analyze the transaction
- 7 Tutorial #7: log APDU exchanges in batch mode
- 8 Tutorial #8: poll for card from payment application
- 9 Tutorial #9: integrate Data Exchange for contactless
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
// 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
// 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
// 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
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
Tutorial #6: add some logs to analyze the transaction
Topics covered:
Log signals to ACE
Log last APDU
Tutorial #7: log APDU exchanges in batch mode
Topics covered:
Log APDU offline
Display offline APDU to ACE
Close session
Tutorial #8: poll for card from payment application
Topics covered:
Polling from payment application
Manage gpiPolling error codes
Send an online authorization message
Tutorial #9: integrate Data Exchange for contactless
Topics covered:
Create a DE/DS callback
Intercept contactless card processing flow