...
That grid may be used by project teams to support their analysis and scan all the different topics:
...
Symbols, Options, and Constants
...
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 | 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 | 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 | 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: |
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:
...