 bde3a47078
			
		
	
	
		bde3a47078
		
			
		
	
	
	
	
		
			
			* Git: set git attributes to automatically manage line endings. * Git: cleanup gitignore file
		
			
				
	
	
		
			854 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			854 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| 
 | |
| /******************************************************************************
 | |
|   * \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 */
 |