/*----------------------------------------------------------------------------*/ /* 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 #include #include #include #include #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 */