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

832 lines
29 KiB
Plaintext

/*----------------------------------------------------------------------------*/
/* Copyright 2009, 2018-2021, 2023 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
* Software ISO14443-3A Component of Reader Library Framework.
* $Author$
* $Revision$ (v07.10.00)
* $Date$
*
*/
#include <ph_Status.h>
#include <phhalHw.h>
#include <phpalI14443p3a.h>
#include <ph_RefDefs.h>
#include <phNxpNfcRdLib_Config.h>
#ifdef NXPBUILD__PHPAL_I14443P3A_SW
#include "phpalI14443p3a_Sw.h"
#include "phpalI14443p3a_Sw_Int.h"
phStatus_t phpalI14443p3a_Sw_Init(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint16_t wSizeOfDataParams,
void * pHalDataParams
)
{
if (sizeof(phpalI14443p3a_Sw_DataParams_t) != wSizeOfDataParams)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_DATA_PARAMS, PH_COMP_PAL_ISO14443P3A);
}
PH_ASSERT_NULL (pDataParams);
PH_ASSERT_NULL (pHalDataParams);
/* init private data */
pDataParams->wId = PH_COMP_PAL_ISO14443P3A | PHPAL_I14443P3A_SW_ID;
pDataParams->pHalDataParams = pHalDataParams;
pDataParams->bUidLength = 0;
pDataParams->bUidComplete = 0;
pDataParams->bOpeMode = RD_LIB_MODE_NFC;
pDataParams->bPollCmd = PHPAL_I14443P3A_USE_REQA;
return PH_ERR_SUCCESS;
}
/* Emvco: Added for EMVCO This function is used to config parameter for phpalI14443p3a */
phStatus_t phpalI14443p3a_Sw_SetConfig(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint16_t wConfig,
uint16_t wValue
)
{
phStatus_t PH_MEMLOC_REM statusTmp;
switch (wConfig)
{
/* Emvco: To Define Running Mode for RdLib: Either Nfc, EMVCO, ISO */
case PHPAL_I14443P3A_CONFIG_OPE_MODE:
{
pDataParams->bOpeMode = (uint8_t)wValue;
break;
}
case PHPAL_I14443P3A_CONFIG_POLL_CMD:
{
pDataParams->bPollCmd = (uint8_t)wValue;
break;
}
case PHPAL_I14443P3A_CONFIG_TIMEOUT_VALUE_US:
{
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_TIMEOUT_VALUE_US,
wValue));
break;
}
default:
return PH_ADD_COMPCODE_FIXED(PH_ERR_UNSUPPORTED_PARAMETER, PH_COMP_PAL_ISO14443P3A);
}
return PH_ERR_SUCCESS;
}
/* Emvco: Added for EMVCO This function is used to config parameter for phpalI14443p3a */
phStatus_t phpalI14443p3a_Sw_GetConfig(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint16_t wConfig,
uint16_t *pValue
)
{
phStatus_t PH_MEMLOC_REM statusTmp;
switch (wConfig)
{
/* Emvco: To Define Running Mode for RdLib: Either Nfc, EMVCO, ISO */
case PHPAL_I14443P3A_CONFIG_OPE_MODE:
{
*pValue = (uint16_t)pDataParams->bOpeMode;
break;
}
case PHPAL_I14443P3A_CONFIG_POLL_CMD:
{
*pValue = (uint16_t)pDataParams->bPollCmd;
break;
}
case PHPAL_I14443P3A_CONFIG_TIMEOUT_VALUE_US:
{
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_GetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_TIMEOUT_VALUE_US,
pValue));
break;
}
default:
return PH_ADD_COMPCODE_FIXED(PH_ERR_UNSUPPORTED_PARAMETER, PH_COMP_PAL_ISO14443P3A);
}
return PH_ERR_SUCCESS;
}
phStatus_t phpalI14443p3a_Sw_RequestA(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t * pAtqa
)
{
return phpalI14443p3a_Sw_RequestAEx(pDataParams, PHPAL_I14443P3A_REQUEST_CMD, pAtqa);
}
phStatus_t phpalI14443p3a_Sw_WakeUpA(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t * pAtqa
)
{
return phpalI14443p3a_Sw_RequestAEx(pDataParams, PHPAL_I14443P3A_WAKEUP_CMD, pAtqa);
}
phStatus_t phpalI14443p3a_Sw_HaltA(
phpalI14443p3a_Sw_DataParams_t * pDataParams
)
{
phStatus_t PH_MEMLOC_REM status;
phStatus_t PH_MEMLOC_REM statusTmp;
uint8_t PH_MEMLOC_REM cmd[2];
uint8_t * PH_MEMLOC_REM pResp = NULL;
uint16_t PH_MEMLOC_REM wRespLength = 0;
/* Set halt timeout */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_TIMEOUT_VALUE_US,
PHPAL_I14443P3A_HALT_TIME_US + PHPAL_I14443P3A_EXT_TIME_US));
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXCRC, PH_ON));
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXCRC, PH_ON));
/* Send HltA command */
cmd[0] = PHPAL_I14443P3A_HALT_CMD;
cmd[1] = 0x00;
status = phhalHw_Exchange(pDataParams->pHalDataParams, PH_EXCHANGE_DEFAULT, cmd, 2, &pResp, &wRespLength);
switch (status & PH_ERR_MASK)
{
/* HltA command should timeout -> success */
case PH_ERR_IO_TIMEOUT:
return PH_ERR_SUCCESS;
/* Return protocol error */
case PH_ERR_SUCCESS:
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
/* Return other errors */
default:
return status;
}
}
phStatus_t phpalI14443p3a_Sw_Anticollision(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t bCascadeLevel,
uint8_t * pUidIn,
uint8_t bNvbUidIn,
uint8_t * pUidOut,
uint8_t * pNvbUidOut
)
{
phStatus_t PH_MEMLOC_REM status;
phStatus_t PH_MEMLOC_REM statusTmp;
uint8_t PH_MEMLOC_REM bIsSelect;
uint8_t PH_MEMLOC_REM bCmdBuffer[10];
uint8_t * PH_MEMLOC_REM pRcvBuffer = NULL;
uint16_t PH_MEMLOC_REM wSndBytes;
uint16_t PH_MEMLOC_REM wRcvBytes = 0;
uint16_t PH_MEMLOC_REM wRcvBits = 0;
uint8_t PH_MEMLOC_REM bUidStartIndex;
uint8_t PH_MEMLOC_REM bBitCount;
/* Check for invalid bNvbUidIn parameter */
if ((bNvbUidIn > 0x40U) || ((bNvbUidIn & 0x0FU) > 0x07U))
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_PAL_ISO14443P3A);
}
/* Check for invalid bCascadeIndex parameter */
switch (bCascadeLevel)
{
case PHPAL_I14443P3A_CASCADE_LEVEL_1:
/* Reset UID length */
pDataParams->bUidLength = 0;
case PHPAL_I14443P3A_CASCADE_LEVEL_2:
case PHPAL_I14443P3A_CASCADE_LEVEL_3:
break;
default:
return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_PAL_ISO14443P3A);
}
/* Reset UID complete flag */
pDataParams->bUidComplete = 0;
/* ANTICOLLISION: Disable CRC */
if (bNvbUidIn != 0x40U)
{
bIsSelect = 0;
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXCRC, PH_OFF));
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXCRC, PH_OFF));
}
/* SELECT: Enable CRC */
else
{
bIsSelect = 1;
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXCRC, PH_ON));
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXCRC, PH_ON));
}
/* Init. command buffer */
bCmdBuffer[0] = bCascadeLevel;
(void)memset(&bCmdBuffer[2], 0x00, 5);
/* Copy valid UID bits */
wSndBytes = (uint16_t)(((((uint16_t)bNvbUidIn) & 0xF0U) >> 4U) + (((bNvbUidIn & 0x0FU) != 0U) ? 1U : 0U));
(void)memcpy(&bCmdBuffer[2], pUidIn, (size_t)wSndBytes);
wSndBytes += 2U;
/* SELECT: Add BCC */
if (0U != (bIsSelect))
{
bNvbUidIn = 0x50;
bCmdBuffer[6] = pUidIn[0] ^ pUidIn[1] ^ pUidIn[2] ^ pUidIn[3];
++wSndBytes;
}
/* Encode NVB */
bCmdBuffer[1] = bNvbUidIn + 0x20U;
/* Adjust Rx-Align */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXALIGN, (((uint16_t)bNvbUidIn) & 0x07U)));
/* Adjust TxBits */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXLASTBITS, (((uint16_t)bNvbUidIn) & 0x07U)));
/* Send the ANTICOLLISION command */
status = phhalHw_Exchange(pDataParams->pHalDataParams, PH_EXCHANGE_DEFAULT, bCmdBuffer, wSndBytes, &pRcvBuffer, &wRcvBytes);
/* Reset RxAlignment */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXALIGN, 0));
/* Check status, Collision is allowed for anti-collision command. */
if ((bIsSelect == 0U) && ((status & PH_ERR_MASK) == PH_ERR_COLLISION_ERROR))
{
/* Retrieve number of valid bits of last byte */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_GetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXLASTBITS, &wRcvBits));
}
else
{
/* Check for protocol error */
if ((status & PH_ERR_MASK) == PH_ERR_SUCCESS_INCOMPLETE_BYTE)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Return on other errors */
else
{
PH_CHECK_SUCCESS(status);
}
/* whole byte valid */
wRcvBits = 0;
}
/* Add received data to UID */
if (bIsSelect == 0U)
{
/* Retrieve byte-starting-index of received Uid */
bUidStartIndex = (uint8_t)((bNvbUidIn & 0xF0U) >> 4U);
/* Add new bitcount */
bBitCount = (uint8_t)(((((uint16_t)bNvbUidIn) >> 4U) << 3U) + (wRcvBytes << 3U) + wRcvBits);
/* Last incomplete byte is added to wRcvBytes, so remove that again */
if (wRcvBits > 0U)
{
bBitCount -= 8U;
}
/* Convert bitcount to NVB format */
*pNvbUidOut = (uint8_t)(((bBitCount >> 3U) << 4U) + (bBitCount & 0x07U));
/* We do not tolerate more than (5u * 8 =)40 bits because it would lead to buffer overflows */
if (*pNvbUidOut > 0x50U)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* After successfull reception, the UID must be exact 40 bits */
if (((status & PH_ERR_MASK) == PH_ERR_SUCCESS) && (*pNvbUidOut != 0x50U))
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Copy received bytes to uid */
if (wRcvBytes > 0U)
{
/* Incomplete byte sent: Merge Rx-Aligned first byte */
if (0U != (bNvbUidIn & 0x07U))
{
bCmdBuffer[2U + bUidStartIndex] = (bCmdBuffer[2U + bUidStartIndex] & (uint8_t)((1U << (bNvbUidIn & 0x07U)) - 1U)) |
(pRcvBuffer[0] & (uint8_t)(0xFFU << (bNvbUidIn & 0x07U)));
}
/* Else just copy the first byte */
else
{
bCmdBuffer[2U + bUidStartIndex] = pRcvBuffer[0];
}
/* Add the rest of the uid bytes */
(void)memcpy(&bCmdBuffer[2U + bUidStartIndex + 1U], &pRcvBuffer[1], (size_t)(((uint32_t)wRcvBytes) - 1u));
}
/* Anticollision finished */
if (*pNvbUidOut > 0x40U)
{
/* Collision in BCC byte can never happen */
if (*pNvbUidOut < 0x50U)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_FRAMING_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Remove BCC from NvbUidOut */
*pNvbUidOut = 0x40;
--wRcvBytes;
/* BCC Check */
if ((bCmdBuffer[2] ^ bCmdBuffer[3] ^ bCmdBuffer[4] ^ bCmdBuffer[5]) != bCmdBuffer[6])
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_FRAMING_ERROR, PH_COMP_PAL_ISO14443P3A);
}
}
/* Copy UID */
(void)memcpy(pUidOut, &bCmdBuffer[2], (size_t)(bUidStartIndex + ((uint32_t)wRcvBytes)));
}
/* Return SAK instead of the UID */
else
{
/* only one byte allowed */
if (wRcvBytes != 1U)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Cascade Bit is set */
if (0U != (pRcvBuffer[0] & 0x04U))
{
/* If additional cascade levels are impossible -> protocol error */
if (bCascadeLevel == PHPAL_I14443P3A_CASCADE_LEVEL_3)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Cascade tag does not match -> protocol error */
if (pUidIn[0] != PHPAL_I14443P3A_CASCADE_TAG)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Ignore Cascade Tag */
(void)memcpy(&pDataParams->abUid[pDataParams->bUidLength], &pUidIn[1], 3);
/* Increment Uid length */
pDataParams->bUidLength += 3U;
}
/* Cascade Bit is cleared -> no further cascade levels */
else
{
/* Cascade tag does not match -> protocol error */
if (pUidIn[0] == PHPAL_I14443P3A_CASCADE_TAG)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
/* Copy all uid bytes except BCC */
(void)memcpy(&pDataParams->abUid[pDataParams->bUidLength], &pUidIn[0], 4);
/* Increment Uid length */
pDataParams->bUidLength += 4U;
/* Set UID complete flag */
pDataParams->bUidComplete = 1;
/* set default card timeout */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_TIMEOUT_VALUE_MS,
PHPAL_I14443P3A_TIMEOUT_DEFAULT_MS));
}
/* Copy SAK */
pUidOut[0] = pRcvBuffer[0];
}
return PH_ADD_COMPCODE(status, PH_COMP_PAL_ISO14443P3A);
}
phStatus_t phpalI14443p3a_Sw_Select(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t bCascadeLevel,
uint8_t * pUidIn,
uint8_t * pSak
)
{
uint8_t PH_MEMLOC_REM bDummy;
return phpalI14443p3a_Sw_Anticollision(pDataParams, bCascadeLevel, pUidIn, 0x40, pSak, &bDummy);
}
phStatus_t phpalI14443p3a_Sw_ActivateCard(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t * pUidIn,
uint8_t bLenUidIn,
uint8_t * pUidOut,
uint8_t * pLenUidOut,
uint8_t * pSak,
uint8_t * pMoreCardsAvailable
)
{
phStatus_t PH_MEMLOC_REM status = PH_ERR_SUCCESS;
phStatus_t PH_MEMLOC_REM statusTmp;
uint8_t PH_MEMLOC_REM bCascadeLevel;
uint8_t PH_MEMLOC_COUNT bCascadeIndex;
uint8_t PH_MEMLOC_REM bUidIndex;
uint8_t PH_MEMLOC_REM bNvbUid;
uint8_t PH_MEMLOC_REM bAtqa[2] = {0};
uint8_t PH_MEMLOC_REM bUid[4];
uint8_t PH_MEMLOC_COUNT bRetryCount;
uint8_t PH_MEMLOC_REM bCollDetected = PH_OFF;
bRetryCount = 0;
/* Parameter check */
if ((bLenUidIn != 0U) &&
(bLenUidIn != 4U) &&
(bLenUidIn != 7U) &&
(bLenUidIn != 10U)&&
(pDataParams->bPollCmd != PHPAL_I14443P3A_USE_WUPA))
{
/* Given UID length is invalid, return error */
return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_PAL_ISO14443P3A);
}
/* initialise to zero, for VS studio warning */
bCascadeLevel = 0;
/* Clear Uid */
(void)memset(bUid, 0x00, 4);
/* Clear Uid lengths */
bUidIndex = 0;
*pLenUidOut = 0;
/* Clear the more cards available flag */
*pMoreCardsAvailable = PH_OFF;
if(pDataParams->bOpeMode == RD_LIB_MODE_EMVCO)
{
status = phpalI14443p3a_Sw_WakeUpA(pDataParams, bAtqa);
/* As per EMVCo 2.6 req 9.6.1.3, wait for at least Tmin retransmission in case of timeout error. */
while (((status & PH_ERR_MASK) == PH_ERR_IO_TIMEOUT) && (bRetryCount < PH_NXPNFCRDLIB_CONFIG_EMVCO_RETRYCOUNT))
{
bRetryCount++;
/* Wait for at least Tmin retransmission delay. */
PH_CHECK_SUCCESS_FCT(status, phhalHw_Wait(
pDataParams->pHalDataParams,
PHHAL_HW_TIME_MICROSECONDS,
PH_NXPNFCRDLIB_CONFIG_EMVCO_DEFAULT_RETRANSMISSION));
status = phpalI14443p3a_Sw_WakeUpA(pDataParams, bAtqa);
}
}
else
{
if( (pDataParams->bOpeMode == RD_LIB_MODE_ISO) && (pDataParams->bPollCmd == PHPAL_I14443P3A_USE_WUPA))
{
status = phpalI14443p3a_Sw_WakeUpA(pDataParams, bAtqa);
}
else
{
if (bLenUidIn == 0U)
{
status = phpalI14443p3a_Sw_RequestA(pDataParams, bAtqa);
}
/* UidIn is given -> WupA */
else
{
status = phpalI14443p3a_Sw_WakeUpA(pDataParams, bAtqa);
}
}
}
/* Collision error may happen */
if ((status & PH_ERR_MASK) == PH_ERR_COLLISION_ERROR)
{
/* Emvco: case_id TA304_XY */
if(pDataParams->bOpeMode == RD_LIB_MODE_EMVCO)
{
return status;
}
bCollDetected = PH_ON;
/* Set the more cards available flag */
*pMoreCardsAvailable = PH_ON;
}
/* Status check */
else
{
PH_CHECK_SUCCESS(status);
}
/* Go through all cascade levels */
for (bCascadeIndex = 0; bCascadeIndex < 3U; bCascadeIndex++)
{
/* Set cascade level tags */
switch (bCascadeIndex)
{
case 0:
bCascadeLevel = PHPAL_I14443P3A_CASCADE_LEVEL_1;
break;
case 1:
bCascadeLevel = PHPAL_I14443P3A_CASCADE_LEVEL_2;
break;
case 2:
bCascadeLevel = PHPAL_I14443P3A_CASCADE_LEVEL_3;
break;
/* Default Case is not required as it will be a Dead Code due to the condition in for() loop statement. */
} /* PRQA S 2002 */
/* Copy know Uid part if neccessary */
if (bLenUidIn == (bUidIndex + 4U))
{
/* Copy whole Uid if this is the only cascade level */
(void)memcpy(&bUid[0], &pUidIn[bUidIndex], 4);
/* [Incrementing Uid index would have no effect] */
/* All bits except BCC are valid */
bNvbUid = 0x40;
}
else if (bLenUidIn > (bUidIndex + /* */ 4U))
{
/* Prepend cascade tag if we expect more cascade levels*/
bUid[0] = PHPAL_I14443P3A_CASCADE_TAG;
/* Only three more uid bytes are valid for this level */
(void)memcpy(&bUid[1], &pUidIn[bUidIndex], 3);
/* Increment Uid index */
bUidIndex += 3U;
/* All bits except BCC are valid */
bNvbUid = 0x40;
}
else
{
/* No Uid given */
bNvbUid = 0;
}
/* Anticollision Loop */
while (bNvbUid != 0x40U)
{
/* Perform single anticollision command */
status = phpalI14443p3a_Sw_Anticollision(pDataParams, bCascadeLevel, bUid, bNvbUid, bUid, &bNvbUid);
/* As per EMVCo 2.6 req 9.6.1.3, wait for at least Tmin retransmission in case of timeout error. */
if (pDataParams->bOpeMode == RD_LIB_MODE_EMVCO)
{
bRetryCount = 0;
while (((status & PH_ERR_MASK) == PH_ERR_IO_TIMEOUT) && (bRetryCount < PH_NXPNFCRDLIB_CONFIG_EMVCO_RETRYCOUNT))
{
bRetryCount++;
/* Wait for at least Tmin retransmission delay. */
PH_CHECK_SUCCESS_FCT(status, phhalHw_Wait(
pDataParams->pHalDataParams,
PHHAL_HW_TIME_MICROSECONDS,
PH_NXPNFCRDLIB_CONFIG_EMVCO_DEFAULT_RETRANSMISSION));
status = phpalI14443p3a_Sw_Anticollision(pDataParams, bCascadeLevel, bUid, bNvbUid, bUid, &bNvbUid);
}
}
/* Collision error occured, add one (zero-)bit to Uid */
if ((status & PH_ERR_MASK) == PH_ERR_COLLISION_ERROR)
{
/* Emvco: case_id TA302_00 */
if(pDataParams->bOpeMode == RD_LIB_MODE_EMVCO)
{
/* Report Error to Application and Application will perform PICC Reset */
return status;
}
/* Set the more cards available flag */
*pMoreCardsAvailable = PH_ON;
/* Increment NvbUid by one bit */
if ((bNvbUid & 0x07U) < 7U)
{
bNvbUid++;
}
/* This is more difficult if we have to increment the bytecount */
else
{
bNvbUid = (uint8_t)((((bNvbUid & 0xF0U) >> 4U) + 1U) << 4U);
}
}
else
{
/* Check success */
PH_CHECK_SUCCESS(status);
}
if(bCollDetected == PH_OFF)
{
/* Emvco: case_id 302_10 */
/*
* Digital Proto: Article 4.7.2 and 4.7.2.4
* ISO14443-3 Article 6.5.2.1
* EMVCo article 5.4.2
* So For Single UID Size The NFC Forum Device MUST set nfcid10 of a single-size NFCID1 and nfcid13
* of a double-size NFCID1 to a value different from 88h.
*/
if(
( (((bAtqa[0] & 0xC0U) == 0x00U) && (bCascadeLevel == PHPAL_I14443P3A_CASCADE_LEVEL_1))||
(((bAtqa[0] & 0xC0U) == 0x40U) && (bCascadeLevel == PHPAL_I14443P3A_CASCADE_LEVEL_2)) ) &&
(bUid[0] == PHPAL_I14443P3A_CASCADE_TAG)
)
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
}
}
statusTmp = phpalI14443p3a_Sw_Select(pDataParams, bCascadeLevel, bUid, pSak);
/* As per EMVCo 2.6 req 9.6.1.3, wait for at least Tmin retransmission in case of timeout error. */
if (pDataParams->bOpeMode == RD_LIB_MODE_EMVCO)
{
bRetryCount = 0;
while (((statusTmp & PH_ERR_MASK) == PH_ERR_IO_TIMEOUT) && (bRetryCount < PH_NXPNFCRDLIB_CONFIG_EMVCO_RETRYCOUNT))
{
bRetryCount++;
/* Wait for at least Tmin retransmission delay. */
PH_CHECK_SUCCESS_FCT(status, phhalHw_Wait(
pDataParams->pHalDataParams,
PHHAL_HW_TIME_MICROSECONDS,
PH_NXPNFCRDLIB_CONFIG_EMVCO_DEFAULT_RETRANSMISSION));
statusTmp = phpalI14443p3a_Sw_Select(pDataParams, bCascadeLevel, bUid, pSak);
}
}
/* Emvco: Case_id TA305. EMVCo Req. 9.6.1.2 */
PH_CHECK_SUCCESS(statusTmp);
/* Cascade Bit is cleared -> no further cascade levels */
if ((pSak[0] & 0x04U) == 0U)
{
break;
}
}
/* Return UID */
(void)memcpy(pUidOut, pDataParams->abUid, pDataParams->bUidLength);
*pLenUidOut = pDataParams->bUidLength;
return PH_ERR_SUCCESS;
}
phStatus_t phpalI14443p3a_Sw_Exchange(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint16_t wOption,
uint8_t * pTxBuffer,
uint16_t wTxLength,
uint8_t ** ppRxBuffer,
uint16_t * pRxLength
)
{
/* direct mapping of HAL exchange function */
return phhalHw_Exchange(
pDataParams->pHalDataParams,
wOption,
pTxBuffer,
wTxLength,
ppRxBuffer,
pRxLength);
}
phStatus_t phpalI14443p3a_Sw_RequestAEx(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t bReqCode,
uint8_t * pAtqa
)
{
phStatus_t PH_MEMLOC_REM statusTmp;
phStatus_t PH_MEMLOC_REM Status;
uint8_t PH_MEMLOC_REM cmd[1];
uint8_t * PH_MEMLOC_REM pResp = NULL;
uint16_t PH_MEMLOC_REM wRespLength = 0;
uint16_t PH_MEMLOC_REM wRegister;
/* Disable MIFARE Classic contactless IC Crypto1 */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_DISABLE_MF_CRYPTO1,
PH_ON));
/* Reset default data rates */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_TXDATARATE_FRAMING,
PHHAL_HW_RF_DATARATE_106));
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_RXDATARATE_FRAMING,
PHHAL_HW_RF_DATARATE_106));
/* Set selection timeout */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
pDataParams->pHalDataParams,
PHHAL_HW_CONFIG_TIMEOUT_VALUE_US,
PHPAL_I14443P3A_SELECTION_TIME_US + PHPAL_I14443P3A_EXT_TIME_US));
/* Retrieve RxWaitTime */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_GetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXWAIT_US, &wRegister));
/* Set RxWaitTime to 76 microseconds equivalent to 8 Bits. */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXWAIT_US, 76));
/* Switch off CRC */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXCRC, PH_OFF));
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXCRC, PH_OFF));
/* Only 7 bits are valid */
PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXLASTBITS, 7));
/* Send ReqA command */
cmd[0] = bReqCode;
statusTmp = phhalHw_Exchange(pDataParams->pHalDataParams, PH_EXCHANGE_DEFAULT, cmd, 1, &pResp, &wRespLength);
/* Restore previous RxWaitTime */
PH_CHECK_SUCCESS_FCT(Status, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXWAIT_US, wRegister));
PH_CHECK_SUCCESS(statusTmp);
/* Check and copy ATQA */
if (wRespLength == PHPAL_I14443P3A_ATQA_LENGTH)
{
(void)memcpy(pAtqa, pResp, PHPAL_I14443P3A_ATQA_LENGTH);
/* Emvco: case_id: TA304_10, TA304_11, TA304_12 */
if(pDataParams->bOpeMode == RD_LIB_MODE_EMVCO)
{
/*5.3.2*/
if(0U != (pAtqa[1] & 0xF0U)) /* Most significant nibble of byte 2 must be 0 */
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
}
else
{
/* NFCForum-TS-DigitalProtocol-1.0, Requirement 18, Section 4.6.3.3 */
if((((pAtqa[0] & 0x1FU) == 0x00U) && ((pAtqa[1] & 0x0FU) != 0x0CU)) || (((pAtqa[1] & 0x0FU) == 0x0CU) && ((pAtqa[0] & 0x1FU) != 0x00U)))
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
}
}
else
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_PAL_ISO14443P3A);
}
return PH_ERR_SUCCESS;
}
phStatus_t phpalI14443p3a_Sw_GetSerialNo(
phpalI14443p3a_Sw_DataParams_t * pDataParams,
uint8_t * pUidOut,
uint8_t * pLenUidOut
)
{
/* Return an error if UID is not complete */
if (0U == (pDataParams->bUidComplete))
{
return PH_ADD_COMPCODE_FIXED(PH_ERR_USE_CONDITION, PH_COMP_PAL_ISO14443P3A);
}
/* Copy UID */
(void)memcpy(pUidOut, pDataParams->abUid, pDataParams->bUidLength);
*pLenUidOut = pDataParams->bUidLength;
return PH_ERR_SUCCESS;
}
#endif /* NXPBUILD__PHPAL_I14443P3A_SW */