Amadis

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Grid Analysis

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

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

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

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

  • No labels