Files
NxpNfcRdLib/.svn/pristine/8b/8b102b3f43313d0ae381f69d2eaf3a1dc6da5fbe.svn-base
2024-07-08 21:03:06 +08:00

275 lines
9.7 KiB
Plaintext

/*----------------------------------------------------------------------------*/
/* Copyright 2020 NXP */
/* */
/* NXP Confidential. This software is owned or controlled by NXP and may only */
/* be used strictly in accordance with the applicable license terms. */
/* By expressly accepting such terms or by downloading, installing, */
/* activating and/or otherwise using the software, you are agreeing that you */
/* have read, and that you agree to comply with and are bound by, such */
/* license terms. If you do not agree to be bound by the applicable license */
/* terms, then you may not retain, install, activate or otherwise use the */
/* software. */
/*----------------------------------------------------------------------------*/
/** \file
* Example Source for NfcrdlibEx1_EmvcoProfile.c that uses the Discovery loop implementation.
* Uses EMVCo POLL mode of discovery loop. Once a EMVCo Tag is been activated selected SELECT PPSE Exchange
* will be perform and print the Response of the same.
* This example will load/configure Discovery loop with user values based on EMVCo Profile via SetConfig.
*
* $Author$
* $Revision$ (v07.10.00)
* $Date$
*/
#include <phApp_Init.h>
#include <NfcrdlibEx1_DiscoveryLoop.h>
#include <NfcrdlibEx1_EmvcoProfile.h>
#ifdef ENABLE_EMVCO_PROF
/*******************************************************************************
** Static Defines
*******************************************************************************/
#define PRETTY_PRINTING /**< Enable pretty printing */
#define MiN_VALID_DATA_SIZE 6
#define PHAC_EMVCO_MAX_BUFFSIZE 600 /**< Maximum buffer size for Emvco. */
//#define RUN_TEST_SUIT
typedef enum{
eEmdRes_EOT = 0x70,
eEmdRes_SW_0 = 0x90,
eEmdRes_SW_1 = 0x00,
}eEmvcoRespByte;
#ifdef RUN_TEST_SUIT
/* EMVCo: Select PPSE Command */
static uint8_t PPSE_SELECT_APDU[] = { 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 };
#else
uint8_t PPSE_response_buffer[256];
uint8_t PPSE_respsize;
/*Define Macro for the PPSE command with different P2 value in PPSE command*/
#define PPSE_FCI
//#define PPSE_FMD
//#define PPSE_FCP
//#define PPSE_NO_LE
/* CLA = 0x00
* INS = 0xA4
* P1 = 0x04
* P2 = 0x00
* LC = 0x0E,
* DF = 0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31
* LE = 0x00
*/
/*P2 parameter values of
* 000000xxb = Return FCI template, optional use of FCI tag and length ,
* 000001xxb = Return FCP template, mandatory use of FCP tag and length,
* 000010xxb = Return FMD template, mandatory use of FMD tag and length,
* 000011xxb = No response data if Le field absent, or proprietary if Le field present
* */
#ifdef PPSE_FCI
/* EMVCo: Select PPSE Command */
static uint8_t PPSE_SELECT_APDU[] = { 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 };
#endif
#ifdef PPSE_FCP
/* EMVCo: Select PPSE Command */
static uint8_t PPSE_SELECT_APDU[] = { 0x00, 0xA4, 0x04, 0x04, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 };
#endif
#ifdef PPSE_FMD
/* EMVCo: Select PPSE Command */
static uint8_t PPSE_SELECT_APDU[] = { 0x00, 0xA4, 0x04, 0x08, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 };
#endif
#ifdef PPSE_NO_LE
/* EMVCo: Select PPSE Command */
static uint8_t PPSE_SELECT_APDU[] = { 0x00, 0xA4, 0x04, 0x0C, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31 };
#endif
#endif
uint8_t command_buffer[PHAC_EMVCO_MAX_BUFFSIZE];
uint8_t *response_buffer;
static phStatus_t EmvcoDataExchange(uint8_t * com_buffer, uint8_t cmdsize, uint8_t ** resp_buffer, uint32_t * wRxLength);
static void EmvcoRfReset(phacDiscLoop_Sw_DataParams_t * pDataParams);
static phStatus_t EmvcoDataLoopBack(phacDiscLoop_Sw_DataParams_t * pDataParams);
void EmvcoProfileProcess (phacDiscLoop_Sw_DataParams_t * pDataParams,phStatus_t eDiscStatus)
{
phStatus_t status = eDiscStatus;
if((status & PH_ERR_MASK) == PHAC_DISCLOOP_DEVICE_ACTIVATED)
{
status = EmvcoDataLoopBack(pDataParams);
}
if((status & PH_ERR_MASK) != PHAC_DISCLOOP_NO_TECH_DETECTED)
{
/* Perform RF Reset */
EmvcoRfReset(pDataParams);
}
}
/**
* \brief Perform RF Reset as per Emvco Specification
* \return Status code
* \retval #PH_ERR_SUCCESS Operation successful.
* \retval Other Depending on implementation and underlying component.
*/
static void EmvcoRfReset(phacDiscLoop_Sw_DataParams_t * pDataParams)
{
phStatus_t status = PH_ERR_SUCCESS;
/*RF Field OFF*/
status = phhalHw_FieldOff(pDataParams->pHalDataParams);
CHECK_STATUS(status);
status = phhalHw_Wait(pDataParams->pHalDataParams,PHHAL_HW_TIME_MICROSECONDS, 5100);
CHECK_STATUS(status);
/*RF Field ON*/
status = phhalHw_FieldOn(pDataParams->pHalDataParams);
CHECK_STATUS(status);
}
/**
* \brief EMVCo Loop-Back function
* This Loop-Back function converts each received R-APDU into the next C-APDU (by stripping the
* status words), and sends this C-APDU back to the card simulator.
* Also this function send SELECT_PPSE command after card activation.
* Loop-Back Function exist when EOT (End Of Test) Command is received from the card simulator.
* \return Status code
* \retval #PH_ERR_SUCCESS Operation successful.
* \retval Other Depending on implementation and underlying component.
*/
static phStatus_t EmvcoDataLoopBack(phacDiscLoop_Sw_DataParams_t * pDataParams)
{
uint32_t cmdsize, respsize;
phStatus_t status;
uint8_t bEndOfLoopBack = 0;
uint8_t bRemovalProcedure = PH_OFF;
cmdsize = sizeof(PPSE_SELECT_APDU);
status = EmvcoDataExchange(PPSE_SELECT_APDU, cmdsize, &response_buffer, &respsize);
#ifndef RUN_TEST_SUIT
/*Check if P1 is 0x04 which means that the data field consists of DF name */
if(PPSE_SELECT_APDU[2] == 0x04)
{
DEBUG_PRINTF("\n DF Name: \n");
/* DF Size = Total Command size - size of(PDU Header + Expected Len(Le))*/
phApp_Print_Buff(&PPSE_SELECT_APDU[5], PPSE_SELECT_APDU[4]);
}
if (respsize > 0)
{
memcpy(&PPSE_response_buffer[0],response_buffer,respsize);
DEBUG_PRINTF("\n SELECT_PPSE Res:\n");
/* Status word removed */
phApp_Print_Buff(PPSE_response_buffer, (respsize - 2));
DEBUG_PRINTF("\nTransaction Done Remove card\n");
}
else
{
DEBUG_PRINTF("\nFCI not recieved\n");
#ifdef PPSE_NO_LE
DEBUG_PRINTF("Transaction Done Remove card\n");
#else
DEBUG_PRINTF("Transaction Failed Replace the card\n");
#endif
}
#endif
while (!bEndOfLoopBack)
{
if (respsize > 0)
{
if (respsize >= MiN_VALID_DATA_SIZE)
{
/* EOT (End Of Test) Command. Exit the loop */
if (eEmdRes_EOT == response_buffer[1])
{
/* Second byte = 0x70, stop the loopback */
bEndOfLoopBack = 1;
bRemovalProcedure = PH_ON;
}
else if (eEmdRes_SW_0 == response_buffer[respsize - 2])
{
/* Format the card response into a new command without the status word 0x90 0x00 */
cmdsize = respsize - 2; /* To Remove two bytes of status word */
memcpy(command_buffer, response_buffer, cmdsize);
/* Send back(Command) : Received Response - Status_Word */
status = EmvcoDataExchange(command_buffer, cmdsize, &response_buffer, &respsize);
}
else
{
/* error Abort Loopback */
bEndOfLoopBack = 1;
}
}
else/*if (respsize <6)*/
{
/* re-send the select appli APDU */
status = EmvcoDataExchange(PPSE_SELECT_APDU, cmdsize, &response_buffer, &respsize);
if (respsize == 0)
{
bEndOfLoopBack = 1;
}
}
}/*if(respsize > 0)*/
else
{
bEndOfLoopBack = 1;
}
}/*while (!bEndOfLoopBack)*/
if(bRemovalProcedure == PH_ON)
{
/* Set Poll state to perform Tag removal procedure*/
status = phacDiscLoop_SetConfig(pDataParams, PHAC_DISCLOOP_CONFIG_NEXT_POLL_STATE, PHAC_DISCLOOP_POLL_STATE_REMOVAL);
CHECK_STATUS(status);
status = phacDiscLoop_Run(pDataParams, PHAC_DISCLOOP_ENTRY_POINT_POLL);
}
return status;
}
/**
* \brief Exchange Data APDU Packets for EMVCO (ISO14443-4 Exchange)
* This function will Exchange APDU data packets provided by Loop-Back Application
* \return Status code
* \retval #PH_ERR_SUCCESS Operation successful.
* \retval Other Depending on implementation and underlying component.
*/
static phStatus_t EmvcoDataExchange(uint8_t * com_buffer, uint8_t cmdsize, uint8_t ** resp_buffer, uint32_t * wRxLength)
{
phStatus_t status;
uint8_t *ppRxBuffer;
uint16_t wRxLen = 0;
status = phpalI14443p4_Exchange(phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4), PH_EXCHANGE_DEFAULT,
com_buffer, cmdsize, &ppRxBuffer, &wRxLen);
if (PH_ERR_SUCCESS == status)
{
/* set the pointer to the start of the R-APDU */
*resp_buffer = &ppRxBuffer[0];
}
else
{
/* Exchange not successful, reset the number of rxd bytes */
wRxLen = 0x00;
}
*wRxLength = wRxLen;
return status;
}
#endif /* ENABLE_EMVCO_PROF */