Table of Contents |
---|
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:
...
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:
...