832 lines
29 KiB
Plaintext
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 */
|