Versions Compared

Key

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

Grid Analysis

That grid may be used by project teams to support their analysis and scan all the different topics:

Image RemovedImage Added

Symbols, Options, and Constants

Following symbols, options, and constants may be adjusted depending on development stages and platform's constraints:

  • Symbols or Options: add/remove a symbol/option to define framework's behavior

  • Constant: set an appropriate value to set framework's footprint

The setup below correspond to a standard package configuration that is used to compile the framework for development and qualification.

For all symbols/options and constants: see GPI/Platform/gpi_agnos_framework_globals.h if available or in Library/File as indicated below.
For a static environment, define _STATIC_LOADER_ in AgnosEP and _STATIC_LINK_ in all CL kernels projects.

Symbol/Option/Constant

Value (Bytes)

Library/File

Comment

_ACE_

Added

CAD

Remove this symbol if ACE is not used (for production version)

_ADAPTER_

Removed

Platform
ACE2P
DualCertificationLevel3

Add this symbol if Agnos Framework doesn't use IP connection to communicate with ACE

_AGNOSISR_

Added

agnostypes.h

Remove this symbol if contact/contactless issuer scripts are not supported

_AGNOSK_

Added

agnostypes.h

Remove this symbol if contact is not supported

_AGNOSCL_

Added

agnostypes.h

Remove this symbol if contactless is not supported

_AGNOSCPL_

Added

agnostypes.h

Remove this symbol if completion is not supported

_AGNOSFMSG_

Added

agnostypes.h

Remove this symbol if advice and batch messages are not supported

_AGNOSTRACE_

Added

agnostypes.h

Remove this symbol to mute traces (for certification and production versions)

_AUTOMATION_

Added

CAD
SPED
DualCertificationLevel3

Remove this symbol if Agnos Automation is not supported (for certification and production versions)

_CONFIGURATOR_

Removed

DualCertificationLevel3

Add this symbol if AgnosGE is supported

_DEPRECATED_

Added

AgnosMW

Always added

_DUAL_POLLING_

Added

kizisapi.c

Remove this symbol if contact only is supported

_EMBEDDED_

Removed

ACE2P
DualCertificationLevel3
AtmosSTUBee

Add this symbol if Agnos runs on an embedded platform

_LOG_

Added

Platform

Remove this symbol to mute traces (for certification and production versions)

_REPLAY_

Added

CAD

Remove this symbol when card emulation is not supported (for certification and production versions)

_STATIC_LINK_

Removed

All CL Kernels

Add this symbol when a platform doesn't support dynamic library loading

_STATIC_LOADER_

Removed

AgnosEP

Add this symbol when a platform doesn't support dynamic library loading

_TIME_STAMP_

Added

Platform

Remove this symbol when performance timings are not supported (for certification and production versions)

_TRACE_

Added

AtmosSTUBee

Remove this symbol when AtmosSTUBee is not used (for certification and production versions)

FREE_RAM_SIZE

3000

sharedram.c

Always set to 3000 Bytes. Arbitrary extended RAM value to support messaging with ACE for TA. May be set to 0 for production version

ISSUER_RESPONSE_SIZE

(128 + MAX_SCRIPT_SIZE)

agnostypes.h

EMV issuer response size if _AGNOSCPL_ is defined. Minimum size to be supported is 128

MAX_AID

15

datamngr.h

Number of maximum AID per CL Kernel. Arbitrary value that may be adjusted depending on acquirer needs

MAX_CHARACTER_PER_LINE

16

display.h

Number of characters per PoP's display line. Set a value related to platform capabilities

MAX_COMBINATION_PER_TRANSACTION_TYPE

65

datamngr.h

MAX_DET_SIZE

2500

de-ds.c

Maximum DET signal size managed by L3

MAX_ITEM_NAME_LENGTH

100

select.h

Maximum length of an item in a selection list. Arbitrary value that may be adjusted depending on acquirer needs

MAX_KERNEL

25

datamngr.h

Number of maximum CL Kernels. Arbitrary value that may be adjusted depending on acquirer needs

MAX_LINES

2

display.c

Number of available PoP's display lines. Set a value related to platform capabilities

MAX_NB_ITEMS

50

select.h

Number of maximum item in a selection list. Arbitrary value that may be adjusted depending on acquirer needs

MAX_NB_LANGUAGE

2

display.h

Number of maximum languages. Arbitrary value that may be adjusted depending on acquirer needs

MAX_SCRIPT_SIZE

128

agnostypes.h

EMV issuer scripts size if _AGNOSCPL_ is defined

MAX_SIMULTANEOUS_SESSION

65

datamngr.h

Number of maximum pre-processing sessions managed simultaneously by our kernels for a given transaction type

MAX_STRING_LENGTH

50

display.h

Number of maximum characters per string (a string may be display on several lines using '\\'. Arbitrary value

MAX_SUPPORTED_ADF

10

agnoostypes.h

Number of maximum ADF supported to manage mutual supported applications between a card and a PoP

MAX_SUPPORTED_AID

30

datamngr.h

Number of maximum AID supported by PROCESSING file (including CT and CL AID)

NB_ACQUIRER_STRINGS

25

display.h

Number of strings supported by Agnos Frameowork to pass TA. May be adjusted to support acquirer needs

NB_EMV_STRINGS

34

display.h

Always set to 34. Defined as per EMVCo standard

NB_INDIVIDUAL_STRINGS

0

display.h

RFU

NB_ISSUER_STRINGS

0

display.h

RFU

ONLINE_BUFFER_SIZE

3000

datamngr.h

Always set to 3000 Bytes. Minimum RAM value to support messaging with ACE for TA. Shall be set to 3000 if torn supported (production version)

RAW_FORMAT_DATA_OBJECT_SIZE

400

datamngr.h

n/a

SIZE_FOR_CL_DATA_OBJECT

10000

sharedram.c

Maximum size available for all combinations per Transaction Type

SIZE_FOR_EMV_TAGS

11500

sharedram.c

Always set to 11500 Bytes. Theoritical value equal to:

max_number_of_SFI x max_APDU_response_size + max_configuration_tags_size

where:

max_number_of_SFI = 30
max_APDU_response_size = 255 Bytes
max_configuration_tags_size = 3850 Bytes

SIZE_FOR_EMV_UNKNOWNTAGS

2500

sharedram.c

Always set to 2500 Bytes. Arbitrary value to support unknown tags fetched from card, i.e. tags not defined in AgnosDB/emvtags.c

SIZE_FOR_PAYPASS_TORN

13500

sharedram.c

Always set to 13500 Bytes when supported (for certification and - optionally - production). May be set to 1 if torn are not supported in production

TIME_STAMP_BUFFER_SIZE

40000

log.c

Set a value related to performance testing needs (only for development version)

Code Samples

EMVCo Test Application

This sample code may be used to built a specific payment application for EMV contact card processing. It presents a basic Agnos API integration. Canadian selection processing is provided on demand.

emvco.h

Code Block
// NAME.......  emvco.h
// PURPOSE....  Support EMVCo test application specifications
// PROJECT....  Applicative baseline
//
// COMMENTS ..	This section of code is an example. It has be developed from EMVCo Book IV specifications.
//				This application is mandatory to certify Agnos' level2 contact library implementing EMVCo Books I, II, and III.
//				However, this code might be adapted (or even started fromn scrath) to support additional requirements related to level3 certifications,
//				i.e. end-to-end integration certifications validating payment network requirements for EMV contact processing (TIP, ADVT, ...)
//
//
// Copyright ©2005-2016 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved
 
#ifndef EMVCO_H
#define	EMVCO_H
 
//---------------------------------------------------------
//			Include files
//---------------------------------------------------------
//---- AgnosMW Headers ----
#include "paymentMW.h"
 
//---------------------------------------------------------
//            emvcoWhatIsYourVersion()
//---------------------------------------------------------
// This service is called to get EMVCo test application application version
//
//  Visibility: Public
//  Hypothesis: --
//  Reference: --
//
//	Service signature :
//
//		Service sends back library version
//
void emvcoWhatIsYourVersion(tString version /*out*/);
 
//---------------------------------------------------------
//            emvcoPreprocessing()
//---------------------------------------------------------
//  This service must be called before any contact transaction (Initiate/Complete sequence)
//
//  Visibility: Public
//  Hypothesis: --
//  Reference: --
//
//	Service signature :
//
//		Pointers always valid (no defensive implementation required)
//
void emvcoPreprocessing(tPaymentContext *payment);
 
//---------------------------------------------------------
//            emvcoInitiateTransaction()
//---------------------------------------------------------
//  This service is called to initiate a standard EMV transaction
//
//  Visibility: Public
//  Hypothesis: --
//  Reference: --
//
void emvcoInitiateTransaction(tPaymentContext *payment, tOutComeParameter *outcome);
 
//---------------------------------------------------------
//            emvcoCompleteTransaction()
//---------------------------------------------------------
//  This service is called to complete a standard EMV transaction
//  application.
//
//  Visibility: Public
//  Hypothesis: --
//  Reference: --
// 
void emvcoCompleteTransaction(tPaymentContext *payment, tOutComeParameter *outcome);
 
//---------------------------------------------------------
//            emvcoRelease()
//---------------------------------------------------------
//  This service is called only once at the release time (or house keeping) of Agnos Framework
//
//  Visibility: Public
//  Hypothesis: --
//  Reference: --
//
void emvcoRelease(void);
 
#endif	/* EMVCO_H */

emvco.c

Code Block
// NAME.......  emvco.c
// PURPOSE....  Support EMVCo test application specifications
// PROJECT....  Applicative baseline
//
// COMMENTS ..	This section of code is an example. It has be developed from EMVCo Book IV specifications.
//				This application is mandatory to certify Agnos' level2 contact library implementing EMVCo Books I, II, and III.
//				However, this code might be adapted (or even started fromn scratch) to support additional requirements related to level3 certifications,
//				i.e. end-to-end integration certifications validating payment network requirements for EMV contact processing (TIP, ADVT, ...)
//
//
// Copyright ©2005-2016 - 9164-4187 QUEBEC INC (“AMADIS”), All Rights Reserved
//
 
// --------------------------------------------------
//      Include Files
// --------------------------------------------------
//---- Local Headers ----
#include "emvco.h"
#include "canadianselection.h"
//---- AgnosMW Headers ----
#include "emvtag.h"
#include "payutils.h"
//---- GPI Headers ----
#include "gpi.h"
//---- System Headers ----
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
 
//---------------------------------------------------------
//			Definitions
//---------------------------------------------------------
#define	MAX_POWERON_RETRIES			3
 
#ifdef PACKING
#pragma pack(1)
#endif
typedef struct {
	tTerminalContext*		mTerminalCtx;
	tProcessingContext*		mProcessingCtx;
	tBoolean				mPSESelectionPerformed;
	tADFList 				mMutualList; // Size: MAX_SUPPORTED_ADF
	tTransactionalContext 	mTransactionalContext;
	tTLVStream 				mEMVData;
} tEMVCoContext;
#pragma pack()
 
// --------------------------------------------------
//      Macros Definitions
// --------------------------------------------------
#ifdef _AGNOSTRACE_
#define LOG(errorid, ...) gpiLogf(__FUNCTION__, errorid, agnGetStringError(errorid), __VA_ARGS__)
#else
#define LOG(...) ((void)0)
#endif
 
//---------------------------------------------------------
//			Declarations
//---------------------------------------------------------
static tEMVCoContext gEMVCoCtx;
 
//---------------------------------------------------------
//			Private primitives
//---------------------------------------------------------
tBoolean isLanguageSelectionSupported(void)
{
	if(gEMVCoCtx.mTerminalCtx)
	{
		return 	((gEMVCoCtx.mTerminalCtx->mAdditionalTerminalCapabilities[2]&0x10)||
				(gEMVCoCtx.mTerminalCtx->mAdditionalTerminalCapabilities[2]&0x20) ||
				(gEMVCoCtx.mTerminalCtx->mAdditionalTerminalCapabilities[2]&0x40) ||
				(gEMVCoCtx.mTerminalCtx->mAdditionalTerminalCapabilities[2]&0x80));
	}
 
	return bFALSE;
}
 
tBoolean powerOn(tPaymentContext *payment, tOutComeParameter *outcome)
{
	tByte powerOnTries=1;
	tByte ATR[100], ATRLen=sizeof(ATR);
	tCardStatus status;
 
	while(powerOnTries <= MAX_POWERON_RETRIES)
	{
		// Here, ATR is not analyzed but could be to detected whether ICC is EMV or not to avoid overhead
		if(gpiPowerOn(gEMVCoCtx.mTerminalCtx->mDeviceName,&status,ATR,&ATRLen) == scrNO_ERROR)
			return bTRUE;
		else
			powerOnTries++;
	}
 
	if(powerOnTries > MAX_POWERON_RETRIES)
	{
		if(status==CARD_MUTE)
		{
	    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),USING_MAGSTRIPE);
			outcome->mOutCome = ocTRY_ANOTHER_INTERFACE;
			outcome->mAlternateInterfacePreference = ipMAGSTRIPE;
			payment->mDataExchange.mError.mMessageOnError = USING_MAGSTRIPE;
		}
		else
		{
	    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),INSERT_SWIPE_OR_OTHER_CARD);
			outcome->mOutCome = ocEND_APPLICATION;
			payment->mDataExchange.mError.mMessageOnError = INSERT_SWIPE_OR_OTHER_CARD;
		}
 
		return bFALSE;
	}
 
	return bTRUE;
}
 
tPaymentError languageSelection(const tByte* language, tByte languageLen, tPaymentContext* payment)
{
	tByte lan=LANGUAGE_NOT_FOUND;
	tByte nbLan=0;
	tPaymentError error=payNO_ERROR;
 
	if(payment && language)
	{
		gpiGetLanguage(language,languageLen,&lan);
		if(lan == LANGUAGE_NOT_FOUND)
		{
			gpiGetNbLanguage(&nbLan);
			if((nbLan > 1) && isLanguageSelectionSupported())
			{
				gpiGetIdFromManualLanguageSelectionByID(pmwGetLanguage(payment),LANGUAGE,gEMVCoCtx.mTerminalCtx->mPinTimeOut,&lan);
				if(lan >= nbLan) // Cardholder cancels selection or timeout
					lan=pmwGetLanguage(payment);
			}
			else
				lan=pmwGetLanguage(payment);
		}
		pmwSetLanguage(payment,lan);
	}
 
    return error;
}
 
tPaymentError initiateAgnosTransaction(tPaymentContext	*payment)
{
	tAgnosError agnosError;
 
	agnosError = agnInitiateEMVTransaction(	payment->mSession,
											payment->mAmount,
                                            payment->mCashBack,
                                            payment->mADF.mADFName,
                                            payment->mADF.mADFLen,
                                            &payment->mCID);
 
    if		(agnosError == agnTXN_ONLINE)				return payGO_ONLINE;
	else if (agnosError == agnTXN_ACCEPTED)				return payACCEPTED;
	else if (agnosError == agnTXN_REJECTED)				return payDECLINED;
	else if (agnosError == agnSERVICE_NOT_ALLOWED)		return payNOT_ACCEPTED;
	else if (agnosError == agnPROCEED_TO_NEW_SELECTION)	return payNEW_SELECTION;
	else if (agnosError == agnSELECTION_ERROR)			return paySELECTION_ERROR;
	else if (agnosError == agnSYSTEM_ERROR)				return paySYSTEM_ERROR;
	else if (agnosError == agnNO_ERROR)					return payNO_ERROR;
	else												return payCARD_ERROR;
}
 
tPaymentError completeAgnosTransaction(tPaymentContext* payment)
{
	tAgnosError agnosError;
 
	agnosError = agnCompleteEMVTransaction(	payment->mSession,
											payment->mARC,
											&payment->mCID,
											payment->mDataExchange.mIssuerResponse.mStream,
											payment->mDataExchange.mIssuerResponse.mLength,
											payment->mUnableToGoOnline);
 
    if 		(agnosError == agnTXN_ACCEPTED)			return payACCEPTED;
	else if (agnosError == agnTXN_REJECTED)			return payDECLINED;
	else if (agnosError == agnSERVICE_NOT_ALLOWED)	return payNOT_ACCEPTED;
	else											return paySYSTEM_ERROR;
}
 
void initiateTransactionFlow(tPaymentContext *payment, tOutComeParameter *outcome)
{
	tPaymentError paymentError=payTRANSACTION_TERMINATED;
 
	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),PLEASE_WAIT);
 
	paymentError = initiateAgnosTransaction(payment);
	payment->mAdvice = pmwICCRequestAnAdvice(payment->mCID);
 
    if (paymentError == payNEW_SELECTION)
    {
    	outcome->mOutCome = ocSELECT_NEXT_NOT_ACCEPTED;
    	return;
    }
    else if (paymentError == paySELECTION_ERROR)
    {
    	outcome->mOutCome = ocSELECT_NEXT_RETRY;
    	return;
    }
    else if(paymentError == payGO_ONLINE)
    {
    	// Prepare data for online processing
    	gEMVCoCtx.mEMVData.mLength = payment->mDataExchange.mDataRecord.mLength;
    	memcpy(gEMVCoCtx.mEMVData.mStream,payment->mDataExchange.mDataRecord.mStream,gEMVCoCtx.mEMVData.mLength);
    	pmwGetEMVData(	payment->mSession,
    					gEMVCoCtx.mEMVData.mStream, gEMVCoCtx.mEMVData.mLength,
						payment->mDataExchange.mDataRecord.mStream,&payment->mDataExchange.mDataRecord.mLength);
 
    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),AUTHORIZING);
    	outcome->mOutCome = ocONLINE_REQUEST;
		return;
    }
    else if (paymentError == payACCEPTED)
    {
		payment->mBatchData=bTRUE;
        outcome->mOutCome = ocOFFLINE_APPROVED;
    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),APPROVED);
    }
    else if (paymentError == payDECLINED)
    {
    	outcome->mOutCome = ocOFFLINE_DECLINED;
    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),DECLINED);
    }
    else if (paymentError == payNOT_ACCEPTED)
    {
    	outcome->mOutCome = ocNOT_ACCEPTED;
    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),NOT_ACCEPTED);
    }
    else if (paymentError == payFALLBACK_TO_MAGSTRIPE)
    {
		outcome->mOutCome = ocTRY_ANOTHER_INTERFACE;
		outcome->mAlternateInterfacePreference = ipMAGSTRIPE;
	   	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),USE_MAGSTRIPE);
    }
    else
    {
    	// When AgnosMW return payCARD_ERROR, may also assess payment network fallback rules here
		// Else (contact level2 certification):
    	outcome->mOutCome = ocOFFLINE_FAILED;
		gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),TRANSACTION_FAILED);
    }
 
    // Prepare data for online processing
#ifdef _AGNOSFMSG_
	if(payment->mBatchData)
	{
		gEMVCoCtx.mEMVData.mLength = payment->mDataExchange.mBatchData.mLength;
    	memcpy(gEMVCoCtx.mEMVData.mStream,payment->mDataExchange.mBatchData.mStream,gEMVCoCtx.mEMVData.mLength);
    	pmwGetEMVData(	payment->mSession,
    					gEMVCoCtx.mEMVData.mStream, gEMVCoCtx.mEMVData.mLength,
						payment->mDataExchange.mBatchData.mStream,&payment->mDataExchange.mBatchData.mLength);
	}
 
	if(payment->mAdvice)
	{
		gEMVCoCtx.mEMVData.mLength = payment->mDataExchange.mAdviceData.mLength;
    	memcpy(gEMVCoCtx.mEMVData.mStream,payment->mDataExchange.mAdviceData.mStream,gEMVCoCtx.mEMVData.mLength);
    	pmwGetEMVData(	payment->mSession,
    					gEMVCoCtx.mEMVData.mStream, gEMVCoCtx.mEMVData.mLength,
						payment->mDataExchange.mAdviceData.mStream,&payment->mDataExchange.mAdviceData.mLength);
	}
#endif
}
 
//---------------------------------------------------------
//			Public primitives
//---------------------------------------------------------
void emvcoPreprocessing(tPaymentContext *payment)
{
	// Note: Mutual list is reset at selection processing initiation time
	gEMVCoCtx.mTerminalCtx = (tTerminalContext*)dtmGetData(TERMINAL_CTX);
	gEMVCoCtx.mProcessingCtx = (tProcessingContext*)dtmGetData(CONTACT_PROCESSING_CTX);
	gEMVCoCtx.mPSESelectionPerformed = bFALSE;
	memset(&gEMVCoCtx.mEMVData,0x00,sizeof(tTLVStream));
	memset(&gEMVCoCtx.mTransactionalContext,0x00,sizeof(tTransactionalContext));
 
	canSetCardholderConfirmation(gEMVCoCtx.mTerminalCtx->mProvideCardholderConfirmation);
	canSetAdditionalTerminalCapabilities(gEMVCoCtx.mTerminalCtx->mAdditionalTerminalCapabilities);
	canSetSelectionTimeout(gEMVCoCtx.mTerminalCtx->mPinTimeOut);
	canSetTerminalType(gEMVCoCtx.mTerminalCtx->mTerminalType);
	canSetTerminalCountryCode(gEMVCoCtx.mTerminalCtx->mTerminalCountryCode);
}
 
void emvcoWhatIsYourVersion(tString version)
{
	if(version)
		sprintf(version,"EMVCo Test Application 4.3e -> v3.2.5");
}
 
void emvcoInitiateTransaction(tPaymentContext *payment, tOutComeParameter *outcome)
{
	tAgnosError agnosError = agnNO_ERROR;
	tPaymentError paymentError;
	tWord SW1SW2;
 
	if(!payment || !outcome || !gEMVCoCtx.mTerminalCtx || !gEMVCoCtx.mProcessingCtx)
		return;
 
	if(powerOn(payment,outcome))
	{
		gEMVCoCtx.mPSESelectionPerformed = bFALSE;
		if(gEMVCoCtx.mTerminalCtx->mPSE)
		{
			SW1SW2 = 0;
			gEMVCoCtx.mPSESelectionPerformed = bTRUE; // ! PSE may fallback to AID selection
			agnosError = selGetMutualListFromPSE(	gEMVCoCtx.mTerminalCtx->mDeviceName,
													(tByte*)PSE_DDF_NAME,PSE_DDF_LENGTH,
													gEMVCoCtx.mProcessingCtx->mNumberOfAID,
													gEMVCoCtx.mProcessingCtx->mAIDList,
													&gEMVCoCtx.mMutualList,&SW1SW2);
		}
		else
			agnosError = selGetMutualList(	gEMVCoCtx.mTerminalCtx->mDeviceName,
											gEMVCoCtx.mProcessingCtx->mNumberOfAID,
											gEMVCoCtx.mProcessingCtx->mAIDList,
											&gEMVCoCtx.mMutualList);
 
		if(agnosError == agnSW_6A81)
		{ 	// Card blocked
			gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),NOT_ACCEPTED);
			payment->mDataExchange.mError.mMessageOnError = NOT_ACCEPTED;
			outcome->mOutCome = ocNOT_ACCEPTED;
			gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
		}
		else if(agnosError == agnSYSTEM_ERROR)
		{
			// Unexpected error
			outcome->mOutCome = ocTRY_ANOTHER_INTERFACE;
			outcome->mAlternateInterfacePreference = ipMAGSTRIPE;
			gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
		}
		else
		{
			do
			{
				// As per EMVCo definition and L2 TA requirements
		        if(memcmp(gEMVCoCtx.mTerminalCtx->mTerminalCountryCode,CANADA,sizeof(gEMVCoCtx.mTerminalCtx->mTerminalCountryCode)))
					paymentError = pmwProceedToUniversalFinalSelection(	&gEMVCoCtx.mMutualList,
																		&payment->mADFOrderNumber,
																		&gEMVCoCtx.mMutualList.mSelectionIndex,
																		gEMVCoCtx.mTerminalCtx,
																		bFALSE);
		        else {
					paymentError = canProceedToFinalSelection(	&gEMVCoCtx.mMutualList,
																&gEMVCoCtx.mMutualList.mSelectionIndex,
																bFALSE);
					payment->mADFOrderNumber = gEMVCoCtx.mMutualList.mList[gEMVCoCtx.mMutualList.mSelectionIndex].mCorrespondingAIDOrderNumber;
		        }
 
				if(paymentError!=payNO_ERROR)
				{
					if(paymentError == payTRANSACTION_CANCELLED)
					{
						gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),TRANSACTION_CANCELLED);
						payment->mDataExchange.mError.mMessageOnError = TRANSACTION_CANCELLED;
						outcome->mOutCome = ocTRANSACTION_CANCELLED;
					}
					else
					{
						gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),NOT_ACCEPTED);
						payment->mDataExchange.mError.mMessageOnError = NOT_ACCEPTED;
						outcome->mOutCome = ocNOT_ACCEPTED;
					}
 
					gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
					return;
				}
 
				memcpy(&payment->mADF, &gEMVCoCtx.mMutualList.mList[gEMVCoCtx.mMutualList.mSelectionIndex],sizeof(tADF));
				memcpy(payment->mRID,payment->mADF.mADFName,5);
 
				paymentError = languageSelection(	gEMVCoCtx.mMutualList.mList[gEMVCoCtx.mMutualList.mSelectionIndex].mLangagePreference,
													gEMVCoCtx.mMutualList.mList[gEMVCoCtx.mMutualList.mSelectionIndex].mLangagePreferenceLen,
													payment);
 
				if(paymentError!=payNO_ERROR)
				{
					if(paymentError == payTRANSACTION_CANCELLED)
					{
						gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),TRANSACTION_CANCELLED);
						payment->mDataExchange.mError.mMessageOnError = TRANSACTION_CANCELLED;
						outcome->mOutCome = ocTRANSACTION_CANCELLED;
					}
 
					gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
					return;
				}
 
				// Set transactional information calculated from configuration
				dtmSetTransactionalContext(payment->mADFOrderNumber,&gEMVCoCtx.mTransactionalContext);
 
				// Parameters independent from terminal/processing
				gEMVCoCtx.mTransactionalContext.mLanguage = pmwGetLanguage(payment);
 
				if(payment->mTransactionType == ttPURCHASE)			gEMVCoCtx.mTransactionalContext.mTxnType = TT_PURCHASE;
				if(payment->mTransactionType == ttCASH)				gEMVCoCtx.mTransactionalContext.mTxnType = TT_CASH;
				if(payment->mTransactionType == ttWITH_CASHBACK)	gEMVCoCtx.mTransactionalContext.mTxnType = TT_WITH_CASHBACK;
				if(payment->mTransactionType == ttREFUND)			gEMVCoCtx.mTransactionalContext.mTxnType = TT_REFUND;
				if(payment->mTransactionType == ttMANUAL_CASH)		gEMVCoCtx.mTransactionalContext.mTxnType = TT_MANUAL_CASH;
				if(payment->mTransactionType == ttDEPOSIT) 			gEMVCoCtx.mTransactionalContext.mTxnType = TT_DEPOSIT;
				if(payment->mTransactionType == ttINQUIRY) 			gEMVCoCtx.mTransactionalContext.mTxnType = TT_INQUIRY;
				if(payment->mTransactionType == ttPAYMENT)			gEMVCoCtx.mTransactionalContext.mTxnType = TT_PAYMENT;
				if(payment->mTransactionType == ttTRANSFER) 		gEMVCoCtx.mTransactionalContext.mTxnType = TT_TRANSFER;
				if(payment->mTransactionType == ttADMINISTRATIVE)	gEMVCoCtx.mTransactionalContext.mTxnType = TT_ADMINISTRATIVE;
 
				gEMVCoCtx.mTransactionalContext.mPOSEntryMode 				= payment->mPOSEntryMode;
				gEMVCoCtx.mTransactionalContext.mTransactionSequenceCounter = payment->mTransactionSequenceCounter;
 
				if(payment->mAmount)
				{
					gEMVCoCtx.mTransactionalContext.mAmountReferenceCurrency = *payment->mAmount;
					if(payment->mCashBack)
						gEMVCoCtx.mTransactionalContext.mAmountReferenceCurrency += *payment->mCashBack;
				}
 
				gEMVCoCtx.mTransactionalContext.mForceTRM 					= bTRUE;
				gEMVCoCtx.mTransactionalContext.mForcedOnline 				= payment->mForcedOnline;
				memcpy(	gEMVCoCtx.mTransactionalContext.mTerminalRiskManagementData,payment->mTerminalRiskManagementData,8);
 
				// Default value
				// Payment application may request user action here
				// Mantis #0000202: 5F57 set to 0xFF at GPO time
				if(payment->mAccountType!=0xFF) // Is account type not initialized, i.e. fetch from TRD
					gEMVCoCtx.mTransactionalContext.mAccountType = payment->mAccountType;
 
				memcpy(gEMVCoCtx.mTransactionalContext.mTransactionDate,payment->mTransactionDate,3);
				memcpy(gEMVCoCtx.mTransactionalContext.mTransactionTime,payment->mTransactionTime,3);
 
				// Open kernel session
				if(agnOpenSession(	gEMVCoCtx.mTerminalCtx->mDeviceName,gEMVCoCtx.mTerminalCtx->mPinPadName,
									"EMVCo",&gEMVCoCtx.mTransactionalContext,
									bTRUE,bTRUE,&payment->mSession,gEMVCoCtx.mTerminalCtx->mClipping,gEMVCoCtx.mTerminalCtx->mSRED) != agnNO_ERROR)
				{
					LOG(paySYSTEM_ERROR,"Open session error");
					pmwCloseEMVSession(payment->mSession);
					gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
					return;
				}
 
				// As per ICS Set default TAC value if supported and if not defined
				if(gEMVCoCtx.mTerminalCtx->mDefaultTAC && !gEMVCoCtx.mProcessingCtx->mAIDList[gEMVCoCtx.mMutualList.mSelectionIndex].mTAC)
				{
					agnSetEMVTag(payment->mSession,0xDF20,5,gEMVCoCtx.mTerminalCtx->mDefaultTACDefault);
					agnSetEMVTag(payment->mSession,0xDF21,5,gEMVCoCtx.mTerminalCtx->mDefaultTACDenial);
					agnSetEMVTag(payment->mSession,0xDF22,5,gEMVCoCtx.mTerminalCtx->mDefaultTACOnline);
				}
 
				// Required by 2CN_004_00 test case
				agnSetEMVTag(payment->mSession,0x9F15,sizeof(payment->mMerchantCategoryCode),payment->mMerchantCategoryCode);
				agnSetEMVTag(payment->mSession,0x9F16,sizeof(payment->mMerchantID),payment->mMerchantID);
				agnSetEMVTag(payment->mSession,0x9F4E,4,payment->mMerchantID);
 
				// Execute transaction
				pmwIncrementTransactionCounter();
				pmwResetTRMTransactionLog(); // no support for transaction log
 
				initiateTransactionFlow(payment,outcome);
 
				// Process outcome
				if(outcome->mOutCome == ocSELECT_NEXT_NOT_ACCEPTED)
				{
					// Entry Point keeps hand so no UIRequest data... local display only
					gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),NOT_ACCEPTED);
					gEMVCoCtx.mMutualList.mEliminatedADF[gEMVCoCtx.mMutualList.mSelectionIndex]=bTRUE;
					pmwCloseEMVSession(payment->mSession);
					memset(&gEMVCoCtx.mTransactionalContext,0x00,sizeof(tTransactionalContext));
				}
 
				if(outcome->mOutCome == ocSELECT_NEXT_RETRY)
				{
					// Entry Point keeps hand so no UIRequest data... local display only
					gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),RETRY);
					gEMVCoCtx.mMutualList.mEliminatedADF[gEMVCoCtx.mMutualList.mSelectionIndex]=bTRUE;
					pmwCloseEMVSession(payment->mSession);
					memset(&gEMVCoCtx.mTransactionalContext,0x00,sizeof(tTransactionalContext));
				}
 
			} while (outcome->mOutCome == ocSELECT_NEXT_NOT_ACCEPTED || outcome->mOutCome == ocSELECT_NEXT_RETRY);
		}
 
		// When not going online, power off card because transaction is completed
		// Else, it will be performed at completion time
		if(outcome->mOutCome != ocONLINE_REQUEST)
		{
			// Get post-conditions
			pmwSetEMVResult(payment);
 
			pmwCloseEMVSession(payment->mSession);
			gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
		}
	}
	else
		LOG(paySYSTEM_ERROR,"Maximum power on retries exceeded");
 
}
 
void emvcoCompleteTransaction(tPaymentContext *payment, tOutComeParameter *outcome)
{
	tPaymentError paymentError;
 
	if(!payment || !outcome || !gEMVCoCtx.mTerminalCtx || !gEMVCoCtx.mProcessingCtx)
		return;
 
	// At completion time, if advices are not supported by terminal, Level 3 shall not managed advice if it was detected at 1st GenAC
	// 2.CA.069.00 Case 01 leads to this modification
	if(!gEMVCoCtx.mTerminalCtx->mAdviceManaged)
		payment->mAdvice = bFALSE;
	//End of modification
 
	// 2CA_68_00 01 and 02 cases lead to this modification.
	if(payment->mUnableToGoOnline && payment->mAdvice)
		outcome->mOutCome = ocFAILED;
	// End of modification
	else
	{
		paymentError = completeAgnosTransaction(payment);
 
#ifdef _AGNOSISR_
		payment->mIsScriptExecuted = agnIsScriptExecuted(payment->mSession);
	    agnGetScriptResult(payment->mSession,payment->mIssuerScriptResult,&payment->mIssuerScriptResultLen);
#endif
		payment->mAdvice = pmwICCRequestAnAdvice(payment->mCID) || (pmwIsIssuerScriptSent(payment) && (paymentError != payACCEPTED));
 
		// 3030: ACCEPTED
		// 5050: UNABLE TO GO ONLINE
		// 6060: TECHNNICAL
		if (paymentError == payACCEPTED)
		{
			if(!memcmp(payment->mARC, "\x50\x50", 2) || !memcmp(payment->mARC, "\x60\x60", 2))
				payment->mReversal = bTRUE;
 
			outcome->mOutCome = ocAPPROVED;
			payment->mBatchData=bTRUE;
	    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),APPROVED);
		}
		else if (paymentError == payDECLINED)
		{
			if(!memcmp(payment->mARC, "\x30\x30", 2) || !memcmp(payment->mARC, "\x50\x50", 2) || !memcmp(payment->mARC, "\x60\x60", 2))
				payment->mReversal = bTRUE;
 
			outcome->mOutCome = ocDECLINED;
	    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),DECLINED);
		}
		else if (paymentError == payNOT_ACCEPTED)
		{
			if(!memcmp(payment->mARC, "\x30\x30", 2) || !memcmp(payment->mARC, "\x50\x50", 2) || !memcmp(payment->mARC, "\x60\x60", 2))
				payment->mReversal = bTRUE;
 
			outcome->mOutCome = ocNOT_ACCEPTED;
	    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),NOT_ACCEPTED);
		}
		else
		{
			if(!memcmp(payment->mARC, "\x30\x30", 2) || !memcmp(payment->mARC, "\x50\x50", 2) || !memcmp(payment->mARC, "\x60\x60", 2))
				payment->mReversal = bTRUE;
 
			outcome->mOutCome = ocFAILED;
	    	gpiDisplayMessageByID(gpi_true,pmwGetLanguage(payment),TRANSACTION_FAILED);
		}
 
#ifdef _AGNOSFMSG_
		if(payment->mBatchData)
		{
			gEMVCoCtx.mEMVData.mLength = payment->mDataExchange.mBatchData.mLength;
			memcpy(gEMVCoCtx.mEMVData.mStream,payment->mDataExchange.mBatchData.mStream,gEMVCoCtx.mEMVData.mLength);
			pmwGetEMVData(	payment->mSession,
							gEMVCoCtx.mEMVData.mStream, gEMVCoCtx.mEMVData.mLength,
							payment->mDataExchange.mBatchData.mStream,&payment->mDataExchange.mBatchData.mLength);
		}
 
		if(payment->mAdvice)
		{
			gEMVCoCtx.mEMVData.mLength = payment->mDataExchange.mAdviceData.mLength;
			memcpy(gEMVCoCtx.mEMVData.mStream,payment->mDataExchange.mAdviceData.mStream,gEMVCoCtx.mEMVData.mLength);
			pmwGetEMVData(	payment->mSession,
							gEMVCoCtx.mEMVData.mStream, gEMVCoCtx.mEMVData.mLength,
							payment->mDataExchange.mAdviceData.mStream,&payment->mDataExchange.mAdviceData.mLength);
		}
#endif
 
#ifdef _AGNOSCPL_
		if(payment->mReversal)
		{
			gEMVCoCtx.mEMVData.mLength = payment->mDataExchange.mReversalData.mLength;
			memcpy(gEMVCoCtx.mEMVData.mStream,payment->mDataExchange.mReversalData.mStream,gEMVCoCtx.mEMVData.mLength);
			pmwGetEMVData(	payment->mSession,
							gEMVCoCtx.mEMVData.mStream, gEMVCoCtx.mEMVData.mLength,
							payment->mDataExchange.mReversalData.mStream,&payment->mDataExchange.mReversalData.mLength);
		}
#endif
	}
 
	// Get post-conditions
	pmwSetEMVResult(payment);
 
	// Always power off card because transaction is completed
	pmwCloseEMVSession(payment->mSession);
	gpiPowerOff(gEMVCoCtx.mTerminalCtx->mDeviceName);
}
 
void emvcoRelease(void)
{
}

LED Management

There is no EMVCo's or payment networks' requirements related to LED management. However, there are 2 common sense needs that must be addressed:

  1. LED display shall be managed consistently across the brand to guaranty a user experience independent from the card's brand

  2. LED display shall allow an optimal performance measurement

Agnos manages the LED as following:

  • LED1: displayed when system polls for a card presentation

  • LED2: displayed when a card has been detected

  • LED3: displayed when a card read has been completed (along with a sound allowing a performance measurement either with the LED or with the BEEP). At this time, card may be removed

  • LED4: displayed when L3 raises a final verdict

Additionally:

  • GREEN is used as the color for accepted transactions

  • RED is used as the color for declined transacions

About the message strings display:

  • During a CL flow, a PROCESSING message may be displayed once GPO response has been received (if this message is supported by the system)

  • Message displays follow EMVCo Book A string table (CL) and EMVCo Book IV string table (CT)