| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886 |
- /******************************************************************************
- * \attention
- *
- * <h2><center>© COPYRIGHT 2020 STMicroelectronics</center></h2>
- *
- * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * www.st.com/myliberty
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
- * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
- /*
- * PROJECT: ST25R391x firmware
- * Revision:
- * LANGUAGE: ISO C99
- */
- /*! \file rfal_nfca.c
- *
- * \author Gustavo Patricio
- *
- * \brief Provides several NFC-A convenience methods and definitions
- *
- * It provides a Poller (ISO14443A PCD) interface and as well as
- * some NFC-A Listener (ISO14443A PICC) helpers.
- *
- * The definitions and helpers methods provided by this module are only
- * up to ISO14443-3 layer
- *
- */
- /*
- ******************************************************************************
- * INCLUDES
- ******************************************************************************
- */
- #include "rfal_nfca.h"
- #include "utils.h"
- /*
- ******************************************************************************
- * ENABLE SWITCH
- ******************************************************************************
- */
- #ifndef RFAL_FEATURE_NFCA
- #define RFAL_FEATURE_NFCA false /* NFC-A module configuration missing. Disabled by default */
- #endif
- #if RFAL_FEATURE_NFCA
- /*
- ******************************************************************************
- * GLOBAL DEFINES
- ******************************************************************************
- */
- #define RFAL_NFCA_SLP_FWT \
- rfalConvMsTo1fc(1) /*!< Check 1ms for any modulation ISO14443-3 6.4.3 */
- #define RFAL_NFCA_SLP_CMD 0x50U /*!< SLP cmd (byte1) Digital 1.1 6.9.1 & Table 20 */
- #define RFAL_NFCA_SLP_BYTE2 0x00U /*!< SLP byte2 Digital 1.1 6.9.1 & Table 20 */
- #define RFAL_NFCA_SLP_CMD_POS 0U /*!< SLP cmd position Digital 1.1 6.9.1 & Table 20 */
- #define RFAL_NFCA_SLP_BYTE2_POS 1U /*!< SLP byte2 position Digital 1.1 6.9.1 & Table 20 */
- #define RFAL_NFCA_SDD_CT 0x88U /*!< Cascade Tag value Digital 1.1 6.7.2 */
- #define RFAL_NFCA_SDD_CT_LEN 1U /*!< Cascade Tag length */
- #define RFAL_NFCA_SLP_REQ_LEN 2U /*!< SLP_REQ length */
- #define RFAL_NFCA_SEL_CMD_LEN 1U /*!< SEL_CMD length */
- #define RFAL_NFCA_SEL_PAR_LEN 1U /*!< SEL_PAR length */
- #define RFAL_NFCA_SEL_SELPAR \
- rfalNfcaSelPar(7U, 0U) /*!< SEL_PAR on Select is always with 4 data/nfcid */
- #define RFAL_NFCA_BCC_LEN 1U /*!< BCC length */
- #define RFAL_NFCA_SDD_REQ_LEN \
- (RFAL_NFCA_SEL_CMD_LEN + RFAL_NFCA_SEL_PAR_LEN) /*!< SDD_REQ length */
- #define RFAL_NFCA_SDD_RES_LEN \
- (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_BCC_LEN) /*!< SDD_RES length */
- #define RFAL_NFCA_T_RETRANS 5U /*!< t RETRANSMISSION [3, 33]ms EMVCo 2.6 A.5 */
- #define RFAL_NFCA_N_RETRANS 2U /*!< Number of retries EMVCo 2.6 9.6.1.3 */
- /*! SDD_REQ (Select) Cascade Levels */
- enum {
- RFAL_NFCA_SEL_CASCADE_L1 = 0, /*!< SDD_REQ Cascade Level 1 */
- RFAL_NFCA_SEL_CASCADE_L2 = 1, /*!< SDD_REQ Cascade Level 2 */
- RFAL_NFCA_SEL_CASCADE_L3 = 2 /*!< SDD_REQ Cascade Level 3 */
- };
- /*! SDD_REQ (Select) request Cascade Level command Digital 1.1 Table 15 */
- enum {
- RFAL_NFCA_CMD_SEL_CL1 = 0x93, /*!< SDD_REQ command Cascade Level 1 */
- RFAL_NFCA_CMD_SEL_CL2 = 0x95, /*!< SDD_REQ command Cascade Level 2 */
- RFAL_NFCA_CMD_SEL_CL3 = 0x97, /*!< SDD_REQ command Cascade Level 3 */
- };
- /*
- ******************************************************************************
- * GLOBAL MACROS
- ******************************************************************************
- */
- #define rfalNfcaSelPar(nBy, nbi) \
- (uint8_t)( \
- (((nBy) << 4U) & 0xF0U) | \
- ((nbi)&0x0FU)) /*!< Calculates SEL_PAR with the bytes/bits to be sent */
- #define rfalNfcaCLn2SELCMD(cl) \
- (uint8_t)( \
- (uint8_t)(RFAL_NFCA_CMD_SEL_CL1) + \
- (2U * (cl))) /*!< Calculates SEL_CMD with the given cascade level */
- #define rfalNfcaNfcidLen2CL(len) \
- ((len) / 5U) /*!< Calculates cascade level by the NFCID length */
- #define rfalNfcaRunBlocking(e, fn) \
- do { \
- (e) = (fn); \
- rfalWorker(); \
- } while((e) == ERR_BUSY) /*!< Macro used for the blocking methods */
- /*
- ******************************************************************************
- * GLOBAL TYPES
- ******************************************************************************
- */
- /*! Colission Resolution states */
- typedef enum {
- RFAL_NFCA_CR_IDLE, /*!< IDLE state */
- RFAL_NFCA_CR_CL, /*!< New Cascading Level state */
- RFAL_NFCA_CR_SDD, /*!< Perform anticollsion state */
- RFAL_NFCA_CR_SEL, /*!< Perform CL Selection state */
- RFAL_NFCA_CR_DONE /*!< Collision Resolution done state */
- } colResState;
- /*! Colission Resolution context */
- typedef struct {
- uint8_t devLimit; /*!< Device limit to be used */
- rfalComplianceMode compMode; /*!< Compliancy mode to be used */
- rfalNfcaListenDevice*
- nfcaDevList; /*!< Location of the device list */
- uint8_t* devCnt; /*!< Location of the device counter */
- bool collPending; /*!< Collision pending flag */
- bool* collPend; /*!< Location of collision pending flag (Single CR) */
- rfalNfcaSelReq selReq; /*!< SelReqused during anticollision (Single CR) */
- rfalNfcaSelRes* selRes; /*!< Location to place of the SEL_RES(SAK) (Single CR) */
- uint8_t* nfcId1; /*!< Location to place the NFCID1 (Single CR) */
- uint8_t* nfcId1Len; /*!< Location to place the NFCID1 length (Single CR) */
- uint8_t cascadeLv; /*!< Current Cascading Level (Single CR) */
- colResState state; /*!< Single Collision Resolution state (Single CR) */
- uint8_t bytesTxRx; /*!< TxRx bytes used during anticollision loop (Single CR) */
- uint8_t bitsTxRx; /*!< TxRx bits used during anticollision loop (Single CR) */
- uint16_t rxLen;
- uint32_t tmrFDT; /*!< FDT timer used between SED_REQs (Single CR) */
- uint8_t retries; /*!< Retries to be performed upon a timeout error (Single CR)*/
- uint8_t backtrackCnt; /*!< Backtrack retries (Single CR) */
- bool doBacktrack; /*!< Backtrack flag (Single CR) */
- } colResParams;
- /*! RFAL NFC-A instance */
- typedef struct {
- colResParams CR; /*!< Collision Resolution context */
- } rfalNfca;
- /*! SLP_REQ (HLTA) format Digital 1.1 6.9.1 & Table 20 */
- typedef struct {
- uint8_t frame[RFAL_NFCA_SLP_REQ_LEN]; /*!< SLP: 0x50 0x00 */
- } rfalNfcaSlpReq;
- /*
- ******************************************************************************
- * LOCAL VARIABLES
- ******************************************************************************
- */
- static rfalNfca gNfca; /*!< RFAL NFC-A instance */
- /*
- ******************************************************************************
- * LOCAL FUNCTION PROTOTYPES
- ******************************************************************************
- */
- static uint8_t rfalNfcaCalculateBcc(const uint8_t* buf, uint8_t bufLen);
- static ReturnCode rfalNfcaPollerStartSingleCollisionResolution(
- uint8_t devLimit,
- bool* collPending,
- rfalNfcaSelRes* selRes,
- uint8_t* nfcId1,
- uint8_t* nfcId1Len);
- static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus(void);
- /*
- ******************************************************************************
- * LOCAL FUNCTIONS
- ******************************************************************************
- */
- static uint8_t rfalNfcaCalculateBcc(const uint8_t* buf, uint8_t bufLen) {
- uint8_t i;
- uint8_t BCC;
- BCC = 0;
- /* BCC is XOR over first 4 bytes of the SDD_RES Digital 1.1 6.7.2 */
- for(i = 0; i < bufLen; i++) {
- BCC ^= buf[i];
- }
- return BCC;
- }
- /*******************************************************************************/
- static ReturnCode rfalNfcaPollerStartSingleCollisionResolution(
- uint8_t devLimit,
- bool* collPending,
- rfalNfcaSelRes* selRes,
- uint8_t* nfcId1,
- uint8_t* nfcId1Len) {
- /* Check parameters */
- if((collPending == NULL) || (selRes == NULL) || (nfcId1 == NULL) || (nfcId1Len == NULL)) {
- return ERR_PARAM;
- }
- /* Initialize output parameters */
- *collPending = false; /* Activity 1.1 9.3.4.6 */
- *nfcId1Len = 0;
- ST_MEMSET(nfcId1, 0x00, RFAL_NFCA_CASCADE_3_UID_LEN);
- /* Save parameters */
- gNfca.CR.devLimit = devLimit;
- gNfca.CR.collPend = collPending;
- gNfca.CR.selRes = selRes;
- gNfca.CR.nfcId1 = nfcId1;
- gNfca.CR.nfcId1Len = nfcId1Len;
- platformTimerDestroy(gNfca.CR.tmrFDT);
- gNfca.CR.tmrFDT = 0U;
- gNfca.CR.retries = RFAL_NFCA_N_RETRANS;
- gNfca.CR.cascadeLv = (uint8_t)RFAL_NFCA_SEL_CASCADE_L1;
- gNfca.CR.state = RFAL_NFCA_CR_CL;
- gNfca.CR.doBacktrack = false;
- gNfca.CR.backtrackCnt = 3U;
- return ERR_NONE;
- }
- /*******************************************************************************/
- static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus(void) {
- ReturnCode ret;
- uint8_t collBit = 1U; /* standards mandate or recommend collision bit to be set to One. */
- /* Check if FDT timer is still running */
- if(!platformTimerIsExpired(gNfca.CR.tmrFDT) && (gNfca.CR.tmrFDT != 0U)) {
- return ERR_BUSY;
- }
- /*******************************************************************************/
- /* Go through all Cascade Levels Activity 1.1 9.3.4 */
- if(gNfca.CR.cascadeLv > (uint8_t)RFAL_NFCA_SEL_CASCADE_L3) {
- return ERR_INTERNAL;
- }
- switch(gNfca.CR.state) {
- /*******************************************************************************/
- case RFAL_NFCA_CR_CL:
- /* Initialize the SDD_REQ to send for the new cascade level */
- ST_MEMSET((uint8_t*)&gNfca.CR.selReq, 0x00, sizeof(rfalNfcaSelReq));
- gNfca.CR.bytesTxRx = RFAL_NFCA_SDD_REQ_LEN;
- gNfca.CR.bitsTxRx = 0U;
- gNfca.CR.state = RFAL_NFCA_CR_SDD;
- /* fall through */
- /*******************************************************************************/
- case RFAL_NFCA_CR_SDD: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
- /* Calculate SEL_CMD and SEL_PAR with the bytes/bits to be sent */
- gNfca.CR.selReq.selCmd = rfalNfcaCLn2SELCMD(gNfca.CR.cascadeLv);
- gNfca.CR.selReq.selPar = rfalNfcaSelPar(gNfca.CR.bytesTxRx, gNfca.CR.bitsTxRx);
- /* Send SDD_REQ (Anticollision frame) */
- ret = rfalISO14443ATransceiveAnticollisionFrame(
- (uint8_t*)&gNfca.CR.selReq,
- &gNfca.CR.bytesTxRx,
- &gNfca.CR.bitsTxRx,
- &gNfca.CR.rxLen,
- RFAL_NFCA_FDTMIN);
- /* Retry upon timeout EMVCo 2.6 9.6.1.3 */
- if((ret == ERR_TIMEOUT) && (gNfca.CR.devLimit == 0U) && (gNfca.CR.retries != 0U)) {
- gNfca.CR.retries--;
- platformTimerDestroy(gNfca.CR.tmrFDT);
- gNfca.CR.tmrFDT = platformTimerCreate(RFAL_NFCA_T_RETRANS);
- break;
- }
- /* Covert rxLen into bytes */
- gNfca.CR.rxLen = rfalConvBitsToBytes(gNfca.CR.rxLen);
- if((ret == ERR_TIMEOUT) && (gNfca.CR.backtrackCnt != 0U) && (!gNfca.CR.doBacktrack) &&
- !((RFAL_NFCA_SDD_REQ_LEN == gNfca.CR.bytesTxRx) && (0U == gNfca.CR.bitsTxRx))) {
- /* In multiple card scenarios it may always happen that some
- * collisions of a weaker tag go unnoticed. If then a later
- * collision is recognized and the strong tag has a 0 at the
- * collision position then no tag will respond. Catch this
- * corner case and then try with the bit being sent as zero. */
- rfalNfcaSensRes sensRes;
- ret = ERR_RF_COLLISION;
- rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_REQA, &sensRes);
- /* Algorithm below does a post-increment, decrement to go back to current position */
- if(0U == gNfca.CR.bitsTxRx) {
- gNfca.CR.bitsTxRx = 7;
- gNfca.CR.bytesTxRx--;
- } else {
- gNfca.CR.bitsTxRx--;
- }
- collBit =
- (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & (1U << gNfca.CR.bitsTxRx));
- collBit = (uint8_t)((0U == collBit) ? 1U : 0U); // invert the collision bit
- gNfca.CR.doBacktrack = true;
- gNfca.CR.backtrackCnt--;
- } else {
- gNfca.CR.doBacktrack = false;
- }
- if(ret == ERR_RF_COLLISION) {
- /* Check received length */
- if((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) >
- (RFAL_NFCA_SDD_RES_LEN + RFAL_NFCA_SDD_REQ_LEN)) {
- return ERR_PROTO;
- }
- if(((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) >
- (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN)) &&
- (gNfca.CR.backtrackCnt != 0U)) { /* Collision in BCC: Anticollide only UID part */
- gNfca.CR.backtrackCnt--;
- gNfca.CR.bytesTxRx = RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN - 1U;
- gNfca.CR.bitsTxRx = 7;
- collBit =
- (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & (1U << gNfca.CR.bitsTxRx)); /* Not a real collision, extract the actual bit for the subsequent code */
- }
- if((gNfca.CR.devLimit == 0U) && !(*gNfca.CR.collPend)) {
- /* Activity 1.0 & 1.1 9.3.4.12: If CON_DEVICES_LIMIT has a value of 0, then
- * NFC Forum Device is configured to perform collision detection only */
- *gNfca.CR.collPend = true;
- return ERR_IGNORE;
- }
- *gNfca.CR.collPend = true;
- /* Set and select the collision bit, with the number of bytes/bits successfully TxRx */
- if(collBit != 0U) {
- ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] =
- (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] | (1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */
- } else {
- ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] =
- (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & ~(1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */
- }
- gNfca.CR.bitsTxRx++;
- /* Check if number of bits form a byte */
- if(gNfca.CR.bitsTxRx == RFAL_BITS_IN_BYTE) {
- gNfca.CR.bitsTxRx = 0;
- gNfca.CR.bytesTxRx++;
- }
- break;
- }
- /*******************************************************************************/
- /* Check if Collision loop has failed */
- if(ret != ERR_NONE) {
- return ret;
- }
- /* If collisions are to be reported check whether the response is complete */
- if((gNfca.CR.devLimit == 0U) && (gNfca.CR.rxLen != sizeof(rfalNfcaSddRes))) {
- return ERR_PROTO;
- }
- /* Check if the received BCC match */
- if(gNfca.CR.selReq.bcc !=
- rfalNfcaCalculateBcc(gNfca.CR.selReq.nfcid1, RFAL_NFCA_CASCADE_1_UID_LEN)) {
- return ERR_PROTO;
- }
- /*******************************************************************************/
- /* Anticollision OK, Select this Cascade Level */
- gNfca.CR.selReq.selPar = RFAL_NFCA_SEL_SELPAR;
- gNfca.CR.retries = RFAL_NFCA_N_RETRANS;
- gNfca.CR.state = RFAL_NFCA_CR_SEL;
- break;
- /*******************************************************************************/
- case RFAL_NFCA_CR_SEL:
- /* Send SEL_REQ (Select command) - Retry upon timeout EMVCo 2.6 9.6.1.3 */
- ret = rfalTransceiveBlockingTxRx(
- (uint8_t*)&gNfca.CR.selReq,
- sizeof(rfalNfcaSelReq),
- (uint8_t*)gNfca.CR.selRes,
- sizeof(rfalNfcaSelRes),
- &gNfca.CR.rxLen,
- RFAL_TXRX_FLAGS_DEFAULT,
- RFAL_NFCA_FDTMIN);
- /* Retry upon timeout EMVCo 2.6 9.6.1.3 */
- if((ret == ERR_TIMEOUT) && (gNfca.CR.devLimit == 0U) && (gNfca.CR.retries != 0U)) {
- gNfca.CR.retries--;
- platformTimerDestroy(gNfca.CR.tmrFDT);
- gNfca.CR.tmrFDT = platformTimerCreate(RFAL_NFCA_T_RETRANS);
- break;
- }
- if(ret != ERR_NONE) {
- return ret;
- }
- /* Ensure proper response length */
- if(gNfca.CR.rxLen != sizeof(rfalNfcaSelRes)) {
- return ERR_PROTO;
- }
- /*******************************************************************************/
- /* Check cascade byte, if cascade tag then go next cascade level */
- if(*gNfca.CR.selReq.nfcid1 == RFAL_NFCA_SDD_CT) {
- /* Cascade Tag present, store nfcid1 bytes (excluding cascade tag) and continue for next CL */
- ST_MEMCPY(
- &gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len],
- &((uint8_t*)&gNfca.CR.selReq.nfcid1)[RFAL_NFCA_SDD_CT_LEN],
- (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN));
- *gNfca.CR.nfcId1Len += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN);
- /* Go to next cascade level */
- gNfca.CR.state = RFAL_NFCA_CR_CL;
- gNfca.CR.cascadeLv++;
- } else {
- /* UID Selection complete, Stop Cascade Level loop */
- ST_MEMCPY(
- &gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len],
- (uint8_t*)&gNfca.CR.selReq.nfcid1,
- RFAL_NFCA_CASCADE_1_UID_LEN);
- *gNfca.CR.nfcId1Len += RFAL_NFCA_CASCADE_1_UID_LEN;
- gNfca.CR.state = RFAL_NFCA_CR_DONE;
- break; /* Only flag operation complete on the next execution */
- }
- break;
- /*******************************************************************************/
- case RFAL_NFCA_CR_DONE:
- return ERR_NONE;
- /*******************************************************************************/
- default:
- return ERR_WRONG_STATE;
- }
- return ERR_BUSY;
- }
- /*
- ******************************************************************************
- * GLOBAL FUNCTIONS
- ******************************************************************************
- */
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerInitialize(void) {
- ReturnCode ret;
- EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCA, RFAL_BR_106, RFAL_BR_106));
- rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
- rfalSetGT(RFAL_GT_NFCA);
- rfalSetFDTListen(RFAL_FDT_LISTEN_NFCA_POLLER);
- rfalSetFDTPoll(RFAL_FDT_POLL_NFCA_POLLER);
- return ERR_NONE;
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerCheckPresence(rfal14443AShortFrameCmd cmd, rfalNfcaSensRes* sensRes) {
- ReturnCode ret;
- uint16_t rcvLen;
- /* Digital 1.1 6.10.1.3 For Commands ALL_REQ, SENS_REQ, SDD_REQ, and SEL_REQ, the NFC Forum Device *
- * MUST treat receipt of a Listen Frame at a time after FDT(Listen, min) as a Timeour Error */
- ret = rfalISO14443ATransceiveShortFrame(
- cmd,
- (uint8_t*)sensRes,
- (uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)),
- &rcvLen,
- RFAL_NFCA_FDTMIN);
- if((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_NOMEM) ||
- (ret == ERR_FRAMING) || (ret == ERR_PAR)) {
- ret = ERR_NONE;
- }
- return ret;
- }
- /*******************************************************************************/
- ReturnCode
- rfalNfcaPollerTechnologyDetection(rfalComplianceMode compMode, rfalNfcaSensRes* sensRes) {
- ReturnCode ret;
- EXIT_ON_ERR(
- ret,
- rfalNfcaPollerCheckPresence(
- ((compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_14443A_SHORTFRAME_CMD_WUPA :
- RFAL_14443A_SHORTFRAME_CMD_REQA),
- sensRes));
- /* Send SLP_REQ as Activity 1.1 9.2.3.6 and EMVCo 2.6 9.2.1.3 */
- if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
- rfalNfcaPollerSleep();
- }
- return ERR_NONE;
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerSingleCollisionResolution(
- uint8_t devLimit,
- bool* collPending,
- rfalNfcaSelRes* selRes,
- uint8_t* nfcId1,
- uint8_t* nfcId1Len) {
- ReturnCode ret;
- EXIT_ON_ERR(
- ret,
- rfalNfcaPollerStartSingleCollisionResolution(
- devLimit, collPending, selRes, nfcId1, nfcId1Len));
- rfalNfcaRunBlocking(ret, rfalNfcaPollerGetSingleCollisionResolutionStatus());
- return ret;
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerStartFullCollisionResolution(
- rfalComplianceMode compMode,
- uint8_t devLimit,
- rfalNfcaListenDevice* nfcaDevList,
- uint8_t* devCnt) {
- ReturnCode ret;
- rfalNfcaSensRes sensRes;
- uint16_t rcvLen;
- if((nfcaDevList == NULL) || (devCnt == NULL)) {
- return ERR_PARAM;
- }
- *devCnt = 0;
- ret = ERR_NONE;
- /*******************************************************************************/
- /* Send ALL_REQ before Anticollision if a Sleep was sent before Activity 1.1 9.3.4.1 and EMVco 2.6 9.3.2.1 */
- if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
- ret = rfalISO14443ATransceiveShortFrame(
- RFAL_14443A_SHORTFRAME_CMD_WUPA,
- (uint8_t*)&nfcaDevList->sensRes,
- (uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)),
- &rcvLen,
- RFAL_NFCA_FDTMIN);
- if(ret != ERR_NONE) {
- if((compMode == RFAL_COMPLIANCE_MODE_EMV) ||
- ((ret != ERR_RF_COLLISION) && (ret != ERR_CRC) && (ret != ERR_FRAMING) &&
- (ret != ERR_PAR))) {
- return ret;
- }
- }
- /* Check proper SENS_RES/ATQA size */
- if((ret == ERR_NONE) && (rfalConvBytesToBits(sizeof(rfalNfcaSensRes)) != rcvLen)) {
- return ERR_PROTO;
- }
- }
- /*******************************************************************************/
- /* Store the SENS_RES from Technology Detection or from WUPA */
- sensRes = nfcaDevList->sensRes;
- if(devLimit > 0U) /* MISRA 21.18 */
- {
- ST_MEMSET(nfcaDevList, 0x00, (sizeof(rfalNfcaListenDevice) * devLimit));
- }
- /* Restore the prev SENS_RES, assuming that the SENS_RES received is from first device
- * When only one device is detected it's not woken up then we'll have no SENS_RES (ATQA) */
- nfcaDevList->sensRes = sensRes;
- /* Save parameters */
- gNfca.CR.devCnt = devCnt;
- gNfca.CR.devLimit = devLimit;
- gNfca.CR.nfcaDevList = nfcaDevList;
- gNfca.CR.compMode = compMode;
- #if RFAL_FEATURE_T1T
- /*******************************************************************************/
- /* Only check for T1T if previous SENS_RES was received without a transmission *
- * error. When collisions occur bits in the SENS_RES may look like a T1T */
- /* If T1T Anticollision is not supported Activity 1.1 9.3.4.3 */
- if(rfalNfcaIsSensResT1T(&nfcaDevList->sensRes) && (devLimit != 0U) && (ret == ERR_NONE) &&
- (compMode != RFAL_COMPLIANCE_MODE_EMV)) {
- /* RID_REQ shall be performed Activity 1.1 9.3.4.24 */
- rfalT1TPollerInitialize();
- EXIT_ON_ERR(ret, rfalT1TPollerRid(&nfcaDevList->ridRes));
- *devCnt = 1U;
- nfcaDevList->isSleep = false;
- nfcaDevList->type = RFAL_NFCA_T1T;
- nfcaDevList->nfcId1Len = RFAL_NFCA_CASCADE_1_UID_LEN;
- ST_MEMCPY(&nfcaDevList->nfcId1, &nfcaDevList->ridRes.uid, RFAL_NFCA_CASCADE_1_UID_LEN);
- return ERR_NONE;
- }
- #endif /* RFAL_FEATURE_T1T */
- return rfalNfcaPollerStartSingleCollisionResolution(
- devLimit,
- &gNfca.CR.collPending,
- &nfcaDevList->selRes,
- (uint8_t*)&nfcaDevList->nfcId1,
- &nfcaDevList->nfcId1Len);
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus(void) {
- ReturnCode ret;
- uint8_t newDevType;
- if((gNfca.CR.nfcaDevList == NULL) || (gNfca.CR.devCnt == NULL)) {
- return ERR_WRONG_STATE;
- }
- /*******************************************************************************/
- /* Check whether a T1T has already been detected */
- if(rfalNfcaIsSensResT1T(&gNfca.CR.nfcaDevList->sensRes) &&
- (gNfca.CR.nfcaDevList->type == RFAL_NFCA_T1T)) {
- /* T1T doesn't support Anticollision */
- return ERR_NONE;
- }
- /*******************************************************************************/
- EXIT_ON_ERR(ret, rfalNfcaPollerGetSingleCollisionResolutionStatus());
- /* Assign Listen Device */
- newDevType = ((uint8_t)gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes.sak) &
- RFAL_NFCA_SEL_RES_CONF_MASK; /* MISRA 10.8 */
- /* PRQA S 4342 1 # MISRA 10.5 - Guaranteed that no invalid enum values are created: see guard_eq_RFAL_NFCA_T2T, .... */
- gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].type = (rfalNfcaListenDeviceType)newDevType;
- gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].isSleep = false;
- (*gNfca.CR.devCnt)++;
- /* If a collision was detected and device counter is lower than limit Activity 1.1 9.3.4.21 */
- if((*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending)) {
- /* Put this device to Sleep Activity 1.1 9.3.4.22 */
- rfalNfcaPollerSleep();
- gNfca.CR.nfcaDevList[(*gNfca.CR.devCnt - 1U)].isSleep = true;
- /* Send a new SENS_REQ to check for other cards Activity 1.1 9.3.4.23 */
- ret = rfalNfcaPollerCheckPresence(
- RFAL_14443A_SHORTFRAME_CMD_REQA, &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].sensRes);
- if(ret == ERR_TIMEOUT) {
- /* No more devices found, exit */
- gNfca.CR.collPending = false;
- } else {
- /* Another device found, continue loop */
- gNfca.CR.collPending = true;
- }
- } else {
- /* Exit loop */
- gNfca.CR.collPending = false;
- }
- /*******************************************************************************/
- /* Check if collision resolution shall continue */
- if((*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending)) {
- EXIT_ON_ERR(
- ret,
- rfalNfcaPollerStartSingleCollisionResolution(
- gNfca.CR.devLimit,
- &gNfca.CR.collPending,
- &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes,
- (uint8_t*)&gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1,
- &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1Len));
- return ERR_BUSY;
- }
- return ERR_NONE;
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerFullCollisionResolution(
- rfalComplianceMode compMode,
- uint8_t devLimit,
- rfalNfcaListenDevice* nfcaDevList,
- uint8_t* devCnt) {
- ReturnCode ret;
- EXIT_ON_ERR(
- ret, rfalNfcaPollerStartFullCollisionResolution(compMode, devLimit, nfcaDevList, devCnt));
- rfalNfcaRunBlocking(ret, rfalNfcaPollerGetFullCollisionResolutionStatus());
- return ret;
- }
- ReturnCode rfalNfcaPollerSleepFullCollisionResolution(
- uint8_t devLimit,
- rfalNfcaListenDevice* nfcaDevList,
- uint8_t* devCnt) {
- bool firstRound;
- uint8_t tmpDevCnt;
- ReturnCode ret;
- if((nfcaDevList == NULL) || (devCnt == NULL)) {
- return ERR_PARAM;
- }
- /* Only use ALL_REQ (WUPA) on the first round */
- firstRound = true;
- *devCnt = 0;
- /* Perform collision resolution until no new device is found */
- do {
- tmpDevCnt = 0;
- ret = rfalNfcaPollerFullCollisionResolution(
- (firstRound ? RFAL_COMPLIANCE_MODE_NFC : RFAL_COMPLIANCE_MODE_ISO),
- (devLimit - *devCnt),
- &nfcaDevList[*devCnt],
- &tmpDevCnt);
- if((ret == ERR_NONE) && (tmpDevCnt > 0U)) {
- *devCnt += tmpDevCnt;
- /* Check whether to seacrh for more devices */
- if(*devCnt < devLimit) {
- /* Set last found device to sleep (all others are slept already) */
- rfalNfcaPollerSleep();
- nfcaDevList[((*devCnt) - 1U)].isSleep = true;
- /* Check if any other device is present */
- ret = rfalNfcaPollerCheckPresence(
- RFAL_14443A_SHORTFRAME_CMD_REQA, &nfcaDevList[*devCnt].sensRes);
- if(ret == ERR_NONE) {
- firstRound = false;
- continue;
- }
- }
- }
- break;
- } while(true);
- return ((*devCnt > 0U) ? ERR_NONE : ret);
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerSelect(const uint8_t* nfcid1, uint8_t nfcidLen, rfalNfcaSelRes* selRes) {
- uint8_t i;
- uint8_t cl;
- uint8_t nfcidOffset;
- uint16_t rxLen;
- ReturnCode ret;
- rfalNfcaSelReq selReq;
- if((nfcid1 == NULL) || (nfcidLen > RFAL_NFCA_CASCADE_3_UID_LEN) || (selRes == NULL)) {
- return ERR_PARAM;
- }
- /* Calculate Cascate Level */
- cl = rfalNfcaNfcidLen2CL(nfcidLen);
- nfcidOffset = 0;
- /*******************************************************************************/
- /* Go through all Cascade Levels Activity 1.1 9.4.4 */
- for(i = RFAL_NFCA_SEL_CASCADE_L1; i <= cl; i++) {
- /* Assign SEL_CMD according to the CLn and SEL_PAR*/
- selReq.selCmd = rfalNfcaCLn2SELCMD(i);
- selReq.selPar = RFAL_NFCA_SEL_SELPAR;
- /* Compute NFCID/Data on the SEL_REQ command Digital 1.1 Table 18 */
- if(cl != i) {
- *selReq.nfcid1 = RFAL_NFCA_SDD_CT;
- ST_MEMCPY(
- &selReq.nfcid1[RFAL_NFCA_SDD_CT_LEN],
- &nfcid1[nfcidOffset],
- (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN));
- nfcidOffset += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN);
- } else {
- ST_MEMCPY(selReq.nfcid1, &nfcid1[nfcidOffset], RFAL_NFCA_CASCADE_1_UID_LEN);
- }
- /* Calculate nfcid's BCC */
- selReq.bcc = rfalNfcaCalculateBcc((uint8_t*)&selReq.nfcid1, sizeof(selReq.nfcid1));
- /*******************************************************************************/
- /* Send SEL_REQ */
- EXIT_ON_ERR(
- ret,
- rfalTransceiveBlockingTxRx(
- (uint8_t*)&selReq,
- sizeof(rfalNfcaSelReq),
- (uint8_t*)selRes,
- sizeof(rfalNfcaSelRes),
- &rxLen,
- RFAL_TXRX_FLAGS_DEFAULT,
- RFAL_NFCA_FDTMIN));
- /* Ensure proper response length */
- if(rxLen != sizeof(rfalNfcaSelRes)) {
- return ERR_PROTO;
- }
- }
- /* REMARK: Could check if NFCID1 is complete */
- return ERR_NONE;
- }
- /*******************************************************************************/
- ReturnCode rfalNfcaPollerSleep(void) {
- rfalNfcaSlpReq slpReq;
- uint8_t rxBuf; /* dummy buffer, just to perform Rx */
- slpReq.frame[RFAL_NFCA_SLP_CMD_POS] = RFAL_NFCA_SLP_CMD;
- slpReq.frame[RFAL_NFCA_SLP_BYTE2_POS] = RFAL_NFCA_SLP_BYTE2;
- rfalTransceiveBlockingTxRx(
- (uint8_t*)&slpReq,
- sizeof(rfalNfcaSlpReq),
- &rxBuf,
- sizeof(rxBuf),
- NULL,
- RFAL_TXRX_FLAGS_DEFAULT,
- RFAL_NFCA_SLP_FWT);
- /* ISO14443-3 6.4.3 HLTA - If PICC responds with any modulation during 1 ms this response shall be interpreted as not acknowledge
- Digital 2.0 6.9.2.1 & EMVCo 3.0 5.6.2.1 - consider the HLTA command always acknowledged
- No check to be compliant with NFC and EMVCo, and to improve interoprability (Kovio RFID Tag)
- */
- return ERR_NONE;
- }
- /*******************************************************************************/
- bool rfalNfcaListenerIsSleepReq(const uint8_t* buf, uint16_t bufLen) {
- /* Check if length and payload match */
- if((bufLen != sizeof(rfalNfcaSlpReq)) || (buf[RFAL_NFCA_SLP_CMD_POS] != RFAL_NFCA_SLP_CMD) ||
- (buf[RFAL_NFCA_SLP_BYTE2_POS] != RFAL_NFCA_SLP_BYTE2)) {
- return false;
- }
- return true;
- }
- /* If the guards here don't compile then the code above cannot work anymore. */
- extern uint8_t guard_eq_RFAL_NFCA_T2T
- [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T2T) == (uint8_t)RFAL_NFCA_T2T) ? 1 : (-1)];
- extern uint8_t guard_eq_RFAL_NFCA_T4T
- [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T4T) == (uint8_t)RFAL_NFCA_T4T) ? 1 : (-1)];
- extern uint8_t guard_eq_RFAL_NFCA_NFCDEP
- [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_NFCDEP) == (uint8_t)RFAL_NFCA_NFCDEP) ?
- 1 :
- (-1)];
- extern uint8_t guard_eq_RFAL_NFCA_T4T_NFCDEP
- [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T4T_NFCDEP) ==
- (uint8_t)RFAL_NFCA_T4T_NFCDEP) ?
- 1 :
- (-1)];
- #endif /* RFAL_FEATURE_NFCA */
|