/****************************************************************************** * \attention * *

© COPYRIGHT 2020 STMicroelectronics

* * 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: NFCC firmware * LANGUAGE: ISO C99 */ /*! \file rfal_nfcDep.c * * \author Gustavo Patricio * * \brief Implementation of NFC-DEP protocol * * NFC-DEP is also known as NFCIP - Near Field Communication * Interface and Protocol * * This implementation was based on the following specs: * - NFC Forum Digital 1.1 * - ECMA 340 3rd Edition 2013 * */ /* ****************************************************************************** * INCLUDES ****************************************************************************** */ #include "rfal_nfcDep.h" #include "rfal_nfcf.h" #include "utils.h" /* ****************************************************************************** * ENABLE SWITCH ****************************************************************************** */ #if RFAL_FEATURE_NFC_DEP /* Check for valid Block/Payload length Digital 2.0 Table 90*/ #if( (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 64) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 128) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 192) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 254) ) #error " RFAL: Invalid NFC-DEP Block Max length. Please change RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN. " #endif /* Check for valid PDU length */ #if( (RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN < RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN) ) #error " RFAL: Invalid NFC-DEP PDU Max length. Please change RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN. " #endif /* ****************************************************************************** * DEFINES ****************************************************************************** */ #define NFCIP_ATR_RETRY_MAX 2U /*!< Max consecutive retrys of an ATR REQ with transm error*/ #define NFCIP_PSLPAY_LEN (2U) /*!< PSL Payload length (BRS + FSL) */ #define NFCIP_PSLREQ_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< PSL REQ length (incl LEN) */ #define NFCIP_PSLRES_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< PSL RES length (incl LEN) */ #define NFCIP_ATRREQ_BUF_LEN (RFAL_NFCDEP_ATRREQ_MAX_LEN + RFAL_NFCDEP_LEN_LEN) /*!< ATR REQ max length (incl LEN) */ #define NFCIP_ATRRES_BUF_LEN (RFAL_NFCDEP_ATRRES_MAX_LEN + RFAL_NFCDEP_LEN_LEN) /*!< ATR RES max length (incl LEN) */ #define NFCIP_RLSREQ_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< RLS REQ length (incl LEN) */ #define NFCIP_RLSRES_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< RSL RES length (incl LEN) */ #define NFCIP_RLSRES_MIN (2U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN) */ #define NFCIP_DSLREQ_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< DSL REQ length (incl LEN) */ #define NFCIP_DSLRES_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< DSL RES length (incl LEN) */ #define NFCIP_DSLRES_MIN (2U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a DSL RES (incl LEN) */ #define NFCIP_DSLRES_MAX_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< Maximum length for a DSL RES (incl LEN) */ #define NFCIP_RLSRES_MAX_LEN (3U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN) */ #define NFCIP_TARGET_RES_MAX ( MAX( NFCIP_RLSRES_MAX_LEN, NFCIP_DSLRES_MAX_LEN) ) /*!< Max target control res length */ #define NFCIP_NO_FWT RFAL_FWT_NONE /*!< No FWT value - Target Mode */ #define NFCIP_INIT_MIN_RTOX 1U /*!< Minimum RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_INIT_MAX_RTOX 59U /*!< Maximum RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_TARG_MIN_RTOX 1U /*!< Minimum target RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_TARG_MAX_RTOX 59U /*!< Maximum target RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_TRECOV 1280U /*!< Digital 1.0 A.10 Trecov */ #define NFCIP_TIMEOUT_ADJUSTMENT 3072U /*!< Timeout Adjustment to compensate timing from end of Tx to end of frame */ #define NFCIP_RWT_ACTIVATION (0x1000001U + NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 2.2 B.11 RWT ACTIVATION 2^24 + RWT Delta + Adjustment*/ #define NFCIP_RWT_ACM_ACTIVATION (0x200001U + NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 2.2 B.11 RWT ACTIVATION 2^21 + RWT Delta + Adjustment*/ #define RFAL_NFCDEP_HEADER_PAD (RFAL_NFCDEP_DEPREQ_HEADER_LEN - RFAL_NFCDEP_LEN_MIN) /*!< Difference between expected rcvd header len and max foreseen */ #ifndef RFAL_NFCDEP_MAX_TX_RETRYS #define RFAL_NFCDEP_MAX_TX_RETRYS (uint8_t)3U /*!< Number of retransmit retyrs */ #endif /* RFAL_NFCDEP_MAX_TX_RETRYS */ #ifndef RFAL_NFCDEP_TO_RETRYS #define RFAL_NFCDEP_TO_RETRYS (uint8_t)3U /*!< Number of retrys for Timeout */ #endif /* RFAL_NFCDEP_TO_RETRYS */ #ifndef RFAL_NFCDEP_MAX_RTOX_RETRYS #define RFAL_NFCDEP_MAX_RTOX_RETRYS (uint8_t)10U /*!< Number of retrys for RTOX Digital 2.0 17.12.4.3 */ #endif /* RFAL_NFCDEP_MAX_RTOX_RETRYS */ #ifndef RFAL_NFCDEP_MAX_NACK_RETRYS #define RFAL_NFCDEP_MAX_NACK_RETRYS (uint8_t)3U /*!< Number of retrys for NACK */ #endif /* RFAL_NFCDEP_MAX_NACK_RETRYS */ #ifndef RFAL_NFCDEP_MAX_ATN_RETRYS #define RFAL_NFCDEP_MAX_ATN_RETRYS (uint8_t)3U /*!< Number of retrys for ATN */ #endif /* RFAL_NFCDEP_MAX_ATN_RETRYS */ #define NFCIP_MIN_TXERROR_LEN 4U /*!< Minimum frame length with error to be ignored Digital 1.0 14.12.5.4 */ #define NFCIP_REQ (uint8_t)0xD4U /*!= NFCIP_ST_INIT_IDLE) && ((st) <= NFCIP_ST_INIT_RLS) ) /*!< Checks if module is set as Initiator */ #define nfcipIsTarget( st ) (!nfcipIsInitiator(st)) /*!< Checks if module is set as Target */ #define nfcipIsBRAllowed( br, mBR ) (((1U<<(br)) & (mBR)) != 0U) /*!< Checks bit rate is allowed by given mask */ #define nfcipIsEmptyDEPEnabled( op ) (!nfcipIsEmptyDEPDisabled(op)) /*!< Checks if empty payload is allowed by operation config NCI 1.0 Table 81 */ #define nfcipIsEmptyDEPDisabled( op ) (((op) & RFAL_NFCDEP_OPER_EMPTY_DEP_DIS) != 0U) /*!< Checks if empty payload is not allowed by operation config NCI 1.0 Table 81 */ #define nfcipIsRTOXReqEnabled( op ) (!nfcipIsRTOXReqDisabled(op)) /*!< Checks if send a RTOX_REQ is allowed by operation config NCI 1.0 Table 81 */ #define nfcipIsRTOXReqDisabled( op ) (((op) & RFAL_NFCDEP_OPER_RTOX_REQ_DIS) != 0U) /*!< Checks if send a RTOX_REQ is not allowed by operation config NCI 1.0 Table 81 */ /*! Checks if isDeactivating callback is set and calls it, otherwise returns false */ #define nfcipIsDeactivationPending() ( (gNfcip.isDeactivating == NULL) ? false : gNfcip.isDeactivating() ) /*! Returns the RWT Activation according to the current communication mode */ #define nfcipRWTActivation() ((gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_ACTIVE) ? NFCIP_RWT_ACM_ACTIVATION : NFCIP_RWT_ACTIVATION) #define nfcipRTOXAdjust( v ) ((v) - ((v)>>3)) /*!< Adjust RTOX timer value to a percentage of the total, current 88% */ /*******************************************************************************/ // timerPollTimeoutValue is necessary after timerCalculateTimeout so that system will wake up upon timer timeout. #define nfcipTimerStart( timer, time_ms ) do{platformTimerDestroy( timer); (timer) = platformTimerCreate((uint16_t)(time_ms));} while (0) /*!< Configures and starts the RTOX timer */ #define nfcipTimerisExpired( timer ) platformTimerIsExpired( timer ) /*!< Checks RTOX timer has expired */ #define nfcipTimerDestroy( timer ) platformTimerDestroy( timer ) /*!< Destroys RTOX timer */ #define nfcipLogE(...) /*!< Macro for the error log method */ #define nfcipLogW(...) /*!< Macro for the warning log method */ #define nfcipLogI(...) /*!< Macro for the info log method */ #define nfcipLogD(...) /*!< Macro for the debug log method */ /*! Digital 1.1 - 16.12.5.2 The Target SHALL NOT attempt any error recovery and remains in Rx mode upon Transmission or a Protocol Error */ #define nfcDepReEnableRx( rxB, rxBL, rxL ) rfalTransceiveBlockingTx( NULL, 0, (rxB), (rxBL), (rxL), ( RFAL_TXRX_FLAGS_DEFAULT | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON ), RFAL_FWT_NONE ) /* ****************************************************************************** * LOCAL DATA TYPES ****************************************************************************** */ /*! Struct that holds all DEP parameters/configs for the following communications */ typedef struct{ uint8_t did; /*!< Device ID (DID) to be used */ uint8_t* txBuf; /*!< Pointer to the Tx buffer to be sent */ uint16_t txBufLen; /*!< Length of the data in the txBuf */ uint8_t txBufPaylPos; /*!< Position inside txBuf where data starts */ bool txChaining; /*!< Flag indicating chaining on transmission */ uint8_t* rxBuf; /*!< Pointer to the Rx buffer for incoming data */ uint16_t rxBufLen; /*!< Length of the data in the rxBuf */ uint8_t rxBufPaylPos; /*!< Position inside rxBuf where data is to be placed*/ uint32_t fwt; /*!< Frame Waiting Time (FWT) to be used */ uint32_t dFwt; /*!< Delta Frame Waiting Time (dFWT) to be used */ uint16_t fsc; /*!< Frame Size (FSC) to be used */ } rfalNfcDepDEPParams; /*! NFCIP module states */ typedef enum { NFCIP_ST_IDLE, NFCIP_ST_INIT_IDLE, NFCIP_ST_INIT_ATR, NFCIP_ST_INIT_PSL, NFCIP_ST_INIT_DEP_IDLE, NFCIP_ST_INIT_DEP_TX, NFCIP_ST_INIT_DEP_RX, NFCIP_ST_INIT_DEP_ATN, NFCIP_ST_INIT_DSL, NFCIP_ST_INIT_RLS, NFCIP_ST_TARG_WAIT_ATR, NFCIP_ST_TARG_WAIT_ACTV, NFCIP_ST_TARG_DEP_IDLE, NFCIP_ST_TARG_DEP_RX, NFCIP_ST_TARG_DEP_RTOX, NFCIP_ST_TARG_DEP_TX, NFCIP_ST_TARG_DEP_SLEEP } rfalNfcDepState; /*! NFCIP commands (Request, Response) */ typedef enum{ NFCIP_CMD_ATR_REQ = 0x00, NFCIP_CMD_ATR_RES = 0x01, NFCIP_CMD_WUP_REQ = 0x02, NFCIP_CMD_WUP_RES = 0x03, NFCIP_CMD_PSL_REQ = 0x04, NFCIP_CMD_PSL_RES = 0x05, NFCIP_CMD_DEP_REQ = 0x06, NFCIP_CMD_DEP_RES = 0x07, NFCIP_CMD_DSL_REQ = 0x08, NFCIP_CMD_DSL_RES = 0x09, NFCIP_CMD_RLS_REQ = 0x0A, NFCIP_CMD_RLS_RES = 0x0B } rfalNfcDepCmd; /*! Struct that holds all NFCIP data */ typedef struct{ rfalNfcDepConfigs cfg; /*!< Holds the current configuration to be used */ rfalNfcDepState state; /*!< Current state of the NFCIP module */ uint8_t pni; /*!< Packet Number Information (PNI) counter */ uint8_t lastCmd; /*!< Last command sent */ uint8_t lastPFB; /*!< Last PFB sent */ uint8_t lastPFBnATN; /*!< Last PFB sent (excluding ATN) */ uint8_t lastRTOX; /*!< Last RTOX value sent */ uint8_t cntTxRetrys; /*!< Retransmissions counter */ uint8_t cntTORetrys; /*!< Timeouts counter */ uint8_t cntRTOXRetrys; /*!< RTOX counter */ uint8_t cntNACKRetrys; /*!< NACK counter */ uint8_t cntATNRetrys; /*!< Attention (ATN) counter */ uint16_t fsc; /*!< Current Frame Size (FSC) to be used */ bool isTxChaining; /*!< Flag for chaining on Transmission */ bool isRxChaining; /*!< Flag for chaining on Reception */ uint8_t* txBuf; /*!< Pointer to the Tx buffer to be sent */ uint8_t* rxBuf; /*!< Pointer to the Rx buffer for incoming data */ uint16_t txBufLen; /*!< Length of the data in the txBuf */ uint16_t rxBufLen; /*!< Length of rxBuf buffer */ uint16_t* rxRcvdLen; /*!< Length of the data in the rxBuf */ uint8_t txBufPaylPos; /*!< Position in txBuf where data starts */ uint8_t rxBufPaylPos; /*!< Position in rxBuf where data is to be placed */ bool *isChaining; /*!< Flag for chaining on Reception */ rfalNfcDepDevice *nfcDepDev; /*!< Pointer to NFC-DEP device info */ uint32_t RTOXTimer; /*!< Timer used for RTOX */ rfalNfcDepDeactCallback isDeactivating; /*!< Deactivating flag check callback */ bool isReqPending; /*!< Flag pending REQ from Target activation */ bool isTxPending; /*!< Flag pending DEP Block while waiting RTOX Ack */ bool isWait4RTOX; /*!< Flag for waiting RTOX Ack */ rfalNfcDepPduTxRxParam PDUParam; /*!< PDU TxRx params */ uint16_t PDUTxPos; /*!< PDU Tx position */ uint16_t PDURxPos; /*!< PDU Rx position */ bool isPDURxChaining; /*!< PDU Transceive chaining flag */ }rfalNfcDep; /* ****************************************************************************** * LOCAL VARIABLES ****************************************************************************** */ static rfalNfcDep gNfcip; /*!< NFCIP module instance */ /* ****************************************************************************** * LOCAL FUNCTION PROTOTYPES ****************************************************************************** */ static ReturnCode nfcipTxRx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint32_t fwt, uint8_t* paylBuf, uint8_t paylBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rxActLen ); static ReturnCode nfcipTx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint8_t *paylBuf, uint16_t paylLen, uint8_t pfbData, uint32_t fwt ); static ReturnCode nfcipDEPControlMsg( uint8_t pfb, uint8_t RTOX ); static ReturnCode nfcipInitiatorHandleDEP( ReturnCode rxRes, uint16_t rxLen, uint16_t *outActRxLen, bool *outIsChaining ); static ReturnCode nfcipTargetHandleRX( ReturnCode rxRes, uint16_t *outActRxLen, bool *outIsChaining ); static ReturnCode nfcipTargetHandleActivation( rfalNfcDepDevice *nfcDepDev, uint8_t *outBRS ); /*! ****************************************************************************** * \brief NFCIP Configure * * Configures the nfcip layer with the given configurations * * \param[in] cfg : nfcip configuration for following communication ****************************************************************************** */ static void nfcipConfig( const rfalNfcDepConfigs * cfg ); /*! ****************************************************************************** * \brief Set DEP parameters * * This method sets the parameters/configs for following Data Exchange * Sets the nfcip module state according to the role it is configured * * * \warning To be used only after proper Initiator/Target activation: * nfcipTargetHandleActivation() or nfcipInitiatorActivate() has * returned success * * This must be called before nfcipRun() in case of Target to pass * rxBuffer * * Everytime some data needs to be transmitted call this to set it and * call nfcipRun() until done or error * * \param[in] DEPParams : the parameters to be used during Data Exchange ****************************************************************************** */ static void nfcipSetDEPParams( const rfalNfcDepDEPParams *DEPParams ); /*! ****************************************************************************** * \brief NFCIP run protocol * * This method handles all the nfcip protocol during Data Exchange (DEP * requests and responses). * * A data exchange cycle is considered a DEP REQ and a DEP RES. * * In case of Tx chaining(MI) must signal it with nfcipSetDEPParams() * In case of Rx chaining(MI) outIsChaining will be set to true and the * current data returned * * \param[out] outActRxLen : data received length * \param[out] outIsChaining : true if other peer is performing chaining(MI) * * \return ERR_NONE : Data exchange cycle completed successfully * \return ERR_TIMEOUT : Timeout occurred * \return ERR_PROTO : Protocol error occurred * \return ERR_AGAIN : Other peer is doing chaining(MI), current block * was received successfully call again until complete * ****************************************************************************** */ static ReturnCode nfcipRun( uint16_t *outActRxLen, bool *outIsChaining ); /*! ****************************************************************************** * \brief Transmission method * * This method checks if the current communication is Active or Passive * and performs the necessary procedures for each communication type * * Transmits the data hold in txBuf * * \param[in] txBuf : buffer to transmit * \param[in] txBufLen : txBuffer capacity * \param[in] fwt : fwt for current Tx * * \return ERR_NONE : No error ****************************************************************************** */ static ReturnCode nfcipDataTx( uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt ); /*! ****************************************************************************** * \brief Reception method * * This method checks if the current communication is Active or Passive * and calls the appropriate reception method * * Copies incoming data to rxBuf * * \param[in] blocking : reception is to be done blocking or non-blocking * * \return ERR_BUSY : Busy * \return ERR_NONE : No error ****************************************************************************** */ static ReturnCode nfcipDataRx( bool blocking ); /* ****************************************************************************** * LOCAL FUNCTIONS ****************************************************************************** */ /*******************************************************************************/ /*******************************************************************************/ static bool nfcipDxIsSupported( uint8_t Dx, uint8_t BRx, uint8_t BSx ) { uint8_t Bx; /* Take the min of the possible bit rates, we'll use one for both directions */ Bx = MIN(BRx, BSx); /* Lower bit rates must be supported for P2P */ if( (Dx <= (uint8_t)RFAL_NFCDEP_Dx_04_424) ) { return true; } if( (Dx == (uint8_t)RFAL_NFCDEP_Dx_08_848) && (Bx >= (uint8_t)RFAL_NFCDEP_Bx_08_848) ) { return true; } return false; } /*******************************************************************************/ static ReturnCode nfcipTxRx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint32_t fwt, uint8_t* paylBuf, uint8_t paylBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rxActLen ) { ReturnCode ret; if( (cmd == NFCIP_CMD_DEP_REQ) || (cmd == NFCIP_CMD_DEP_RES) ) /* this method cannot be used for DEPs */ { return ERR_PARAM; } /* Assign the global params for this TxRx */ gNfcip.rxBuf = rxBuf; gNfcip.rxBufLen = rxBufLen; gNfcip.rxRcvdLen = rxActLen; /*******************************************************************************/ /* Transmission */ /*******************************************************************************/ if(txBuf != NULL) /* if nothing to Tx, just do Rx */ { EXIT_ON_ERR( ret, nfcipTx( cmd, txBuf, paylBuf, paylBufLen, 0, fwt ) ); } /*******************************************************************************/ /* Reception */ /*******************************************************************************/ ret = nfcipDataRx( true ); if( ret != ERR_NONE ) { return ret; } /*******************************************************************************/ *rxActLen = *rxBuf; /* Use LEN byte instead due to with/without CRC modes */ return ERR_NONE; /* Tx and Rx completed successfully */ } /*******************************************************************************/ static ReturnCode nfcipDEPControlMsg( uint8_t pfb, uint8_t RTOX ) { uint8_t ctrlMsg[20]; rfalNfcDepCmd depCmd; uint32_t fwt; /*******************************************************************************/ /* Calculate Cmd and fwt to be used */ /*******************************************************************************/ depCmd = ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_CMD_DEP_RES : NFCIP_CMD_DEP_REQ); fwt = ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_NO_FWT : (nfcip_PFBisSTO( pfb ) ? ( (RTOX*gNfcip.cfg.fwt) + gNfcip.cfg.dFwt) : (gNfcip.cfg.fwt + gNfcip.cfg.dFwt) ) ); if( nfcip_PFBisSTO( pfb ) ) { ctrlMsg[RFAL_NFCDEP_DEPREQ_HEADER_LEN] = RTOX; return nfcipTx( depCmd, ctrlMsg, &ctrlMsg[RFAL_NFCDEP_DEPREQ_HEADER_LEN], sizeof(uint8_t), pfb, fwt ); } else { return nfcipTx( depCmd, ctrlMsg, NULL, 0, pfb, fwt ); } } /*******************************************************************************/ static void nfcipClearCounters( void ) { gNfcip.cntATNRetrys = 0; gNfcip.cntNACKRetrys = 0; gNfcip.cntTORetrys = 0; gNfcip.cntTxRetrys = 0; gNfcip.cntRTOXRetrys = 0; } /*******************************************************************************/ static ReturnCode nfcipInitiatorHandleDEP( ReturnCode rxRes, uint16_t rxLen, uint16_t *outActRxLen, bool *outIsChaining ) { ReturnCode ret; uint8_t nfcDepLen; uint8_t rxMsgIt; uint8_t rxPFB; uint8_t rxRTOX; uint8_t optHdrLen; ret = ERR_INTERNAL; rxMsgIt = 0; optHdrLen = 0; *outActRxLen = 0; *outIsChaining = false; /*******************************************************************************/ /* Handle reception errors */ /*******************************************************************************/ switch( rxRes ) { /*******************************************************************************/ /* Timeout -> Digital 1.0 14.15.5.6 */ case ERR_TIMEOUT: nfcipLogI( " NFCIP(I) TIMEOUT TORetrys:%d \r\n", gNfcip.cntTORetrys ); /* Digital 1.0 14.15.5.6 - If nTO >= Max raise protocol error */ if( gNfcip.cntTORetrys++ >= RFAL_NFCDEP_TO_RETRYS ) { return ERR_PROTO; } /*******************************************************************************/ /* Upon Timeout error, if Deactivation is pending, no more error recovery * will be done #54. * This is used to address the issue some devices that havea big TO. * Normally LLCP layer has timeout already, and NFCIP layer is still * running error handling, retrying ATN/NACKs */ /*******************************************************************************/ if( nfcipIsDeactivationPending() ) { nfcipLogI( " skipping error recovery due deactivation pending \r\n"); return ERR_TIMEOUT; } /* Digital 1.0 14.15.5.6 1) If last PDU was NACK */ if( nfcip_PFBisRNACK(gNfcip.lastPFB) ) { /* Digital 1.0 14.15.5.6 2) if NACKs failed raise protocol error */ if( gNfcip.cntNACKRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS ) { return ERR_PROTO; } /* Send NACK */ nfcipLogI( " NFCIP(I) Sending NACK retry: %d \r\n", gNfcip.cntNACKRetrys ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_NACK(gNfcip.pni), 0 ) ); return ERR_BUSY; } nfcipLogI( " NFCIP(I) Checking if to send ATN ATNRetrys: %d \r\n", gNfcip.cntATNRetrys ); /* Digital 1.0 14.15.5.6 3) Otherwise send ATN */ if( gNfcip.cntATNRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS ) { return ERR_PROTO; } /* Send ATN */ nfcipLogI( " NFCIP(I) Sending ATN \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_ATN(), 0 ) ); return ERR_BUSY; /*******************************************************************************/ /* Data rcvd with error -> Digital 1.0 14.12.5.4 */ case ERR_CRC: case ERR_PAR: case ERR_FRAMING: case ERR_RF_COLLISION: nfcipLogI( " NFCIP(I) rx Error: %d \r\n", rxRes ); /* Digital 1.0 14.12.5.4 Tx Error with data, ignore */ if( rxLen < NFCIP_MIN_TXERROR_LEN ) { nfcipLogI( " NFCIP(I) Transmission error w data \r\n" ); #if 0 if(gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_PASSIVE) { nfcipLogI( " NFCIP(I) Transmission error w data -> reEnabling Rx \r\n" ); nfcipReEnableRxTout( NFCIP_TRECOV ); return ERR_BUSY; } #endif /* 0 */ } /* Digital 1.1 16.12.5.4 if NACKs failed raise Transmission error */ if( gNfcip.cntNACKRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS ) { return ERR_FRAMING; } /* Send NACK */ nfcipLogI( " NFCIP(I) Sending NACK \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_NACK(gNfcip.pni), 0 ) ); return ERR_BUSY; case ERR_NONE: break; case ERR_BUSY: return ERR_BUSY; /* Debug purposes */ default: nfcipLogW( " NFCIP(I) Error: %d \r\n", rxRes ); return rxRes; } /*******************************************************************************/ /* Rx OK check if valid DEP PDU */ /*******************************************************************************/ /* Due to different modes on ST25R391x (with/without CRC) use NFC-DEP LEN instead of bytes retrieved */ nfcDepLen = gNfcip.rxBuf[rxMsgIt++]; nfcipLogD( " NFCIP(I) rx OK: %d bytes \r\n", nfcDepLen ); /* Digital 1.0 14.15.5.5 Protocol Error */ if( gNfcip.rxBuf[rxMsgIt++] != NFCIP_RES ) { nfcipLogW( " NFCIP(I) error %02X instead of %02X \r\n", gNfcip.rxBuf[--rxMsgIt], NFCIP_RES ); return ERR_PROTO; } /* Digital 1.0 14.15.5.5 Protocol Error */ if( gNfcip.rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_DEP_RES ) { nfcipLogW( " NFCIP(I) error %02X instead of %02X \r\n", gNfcip.rxBuf[--rxMsgIt], NFCIP_CMD_DEP_RES ); return ERR_PROTO; } rxPFB = gNfcip.rxBuf[rxMsgIt++]; /*******************************************************************************/ /* Check for valid PFB type */ if( !(nfcip_PFBisSPDU( rxPFB ) || nfcip_PFBisRPDU( rxPFB ) || nfcip_PFBisIPDU( rxPFB )) ) { return ERR_PROTO; } /*******************************************************************************/ /* Digital 1.0 14.8.2.1 check if DID is expected and match -> Protocol Error */ if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) { if( (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || !nfcip_PFBhasDID( rxPFB ) ) { return ERR_PROTO; } optHdrLen++; /* Inc header optional field cnt*/ } else if( nfcip_PFBhasDID( rxPFB ) ) /* DID not expected but rcv */ { return ERR_PROTO; } else { /* MISRA 15.7 - Empty else */ } /*******************************************************************************/ /* Digital 1.0 14.6.2.8 & 14.6.3.11 NAD must not be used */ if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) { if( (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.nad) || !nfcip_PFBhasNAD( rxPFB ) ) { return ERR_PROTO; } optHdrLen++; /* Inc header optional field cnt*/ } else if( nfcip_PFBhasNAD( rxPFB ) ) /* NAD not expected but rcv */ { return ERR_PROTO; } else { /* MISRA 15.7 - Empty else */ } /*******************************************************************************/ /* Process R-PDU */ /*******************************************************************************/ if( nfcip_PFBisRPDU( rxPFB ) ) { /*******************************************************************************/ /* R ACK */ /*******************************************************************************/ if( nfcip_PFBisRACK( rxPFB ) ) { nfcipLogI( " NFCIP(I) Rcvd ACK \r\n" ); if( gNfcip.pni == nfcip_PBF_PNI( rxPFB ) ) { /* 14.12.3.3 R-ACK with correct PNI -> Increment */ gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); /* R-ACK while not performing chaining -> Protocol error*/ if( !gNfcip.isTxChaining ) { return ERR_PROTO; } nfcipClearCounters(); gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; return ERR_NONE; /* This block has been transmitted */ } else /* Digital 1.0 14.12.4.5 ACK with wrong PNI Initiator may retransmit */ { if( gNfcip.cntTxRetrys++ >= RFAL_NFCDEP_MAX_TX_RETRYS ) { return ERR_PROTO; } /* Extended the MAY in Digital 1.0 14.12.4.5 to only reTransmit if the ACK * is for the previous DEP, otherwise raise Protocol immediately * If the PNI difference is more than 1 it is worthless to reTransmit 3x * and after raise the error */ if( nfcip_PNIDec( gNfcip.pni ) == nfcip_PBF_PNI( rxPFB ) ) { /* ReTransmit */ nfcipLogI( " NFCIP(I) Rcvd ACK prev PNI -> reTx \r\n" ); gNfcip.state = NFCIP_ST_INIT_DEP_TX; return ERR_BUSY; } nfcipLogI( " NFCIP(I) Rcvd ACK unexpected far PNI -> Error \r\n" ); return ERR_PROTO; } } else /* Digital 1.0 - 14.12.5.2 Target must never send NACK */ { return ERR_PROTO; } } /*******************************************************************************/ /* Process S-PDU */ /*******************************************************************************/ if( nfcip_PFBisSPDU( rxPFB ) ) { nfcipLogI( " NFCIP(I) Rcvd S-PDU \r\n" ); /*******************************************************************************/ /* S ATN */ /*******************************************************************************/ if( nfcip_PFBisSATN( rxPFB ) ) /* If is a S-ATN */ { nfcipLogI( " NFCIP(I) Rcvd ATN \r\n" ); if( nfcip_PFBisSATN( gNfcip.lastPFB ) ) /* Check if is expected */ { gNfcip.cntATNRetrys = 0; /* Clear ATN counter */ /* Although spec is not clear NFC Forum Digital test is expecting to * retransmit upon receiving ATN_RES */ if( nfcip_PFBisSTO( gNfcip.lastPFBnATN ) ) { nfcipLogI( " NFCIP(I) Rcvd ATN -> reTx RTOX_RES \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_TO(), gNfcip.lastRTOX ) ); } else { /* ReTransmit ? */ if( gNfcip.cntTxRetrys++ >= RFAL_NFCDEP_MAX_TX_RETRYS ) { return ERR_PROTO; } nfcipLogI( " NFCIP(I) Rcvd ATN -> reTx PNI: %d \r\n", gNfcip.pni ); gNfcip.state = NFCIP_ST_INIT_DEP_TX; } return ERR_BUSY; } else /* Digital 1.0 14.12.4.4 & 14.12.4.8 */ { return ERR_PROTO; } } /*******************************************************************************/ /* S TO */ /*******************************************************************************/ else if( nfcip_PFBisSTO( rxPFB ) ) /* If is a S-TO (RTOX) */ { nfcipLogI( " NFCIP(I) Rcvd TO \r\n" ); rxRTOX = gNfcip.rxBuf[rxMsgIt++]; /* Digital 1.1 16.12.4.3 - Initiator MAY stop accepting subsequent RTOX Req * * - RTOX request to an ATN -> Protocol error */ if( (gNfcip.cntRTOXRetrys++ > RFAL_NFCDEP_MAX_RTOX_RETRYS) || nfcip_PFBisSATN( gNfcip.lastPFB ) ) { return ERR_PROTO; } /* Digital 1.1 16.8.4.1 RTOX must be between [1,59] */ if( (rxRTOX < NFCIP_INIT_MIN_RTOX) || (rxRTOX > NFCIP_INIT_MAX_RTOX) ) { return ERR_PROTO; } EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_TO(), rxRTOX ) ); gNfcip.lastRTOX = rxRTOX; return ERR_BUSY; } else { /* Unexpected S-PDU */ return ERR_PROTO; /* PRQA S 2880 # MISRA 2.1 - Guard code to prevent unexpected behavior */ } } /*******************************************************************************/ /* Process I-PDU */ /*******************************************************************************/ if( nfcip_PFBisIPDU( rxPFB ) ) { if( gNfcip.pni != nfcip_PBF_PNI( rxPFB ) ) { nfcipLogI( " NFCIP(I) Rcvd IPDU wrong PNI curPNI: %d rxPNI: %d \r\n", gNfcip.pni , nfcip_PBF_PNI( rxPFB ) ); return ERR_PROTO; } nfcipLogD( " NFCIP(I) Rcvd IPDU OK PNI: %d \r\n", gNfcip.pni ); /* 14.12.3.3 I-PDU with correct PNI -> Increment */ gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); /* Successful data Exchange */ nfcipClearCounters(); *outActRxLen = ((uint16_t)nfcDepLen - RFAL_NFCDEP_DEP_HEADER - (uint16_t)optHdrLen); if( (&gNfcip.rxBuf[gNfcip.rxBufPaylPos] != &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen]) && (*outActRxLen > 0U) ) { ST_MEMMOVE( &gNfcip.rxBuf[gNfcip.rxBufPaylPos], &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen], *outActRxLen ); } /*******************************************************************************/ /* Check if target is indicating chaining MI */ /*******************************************************************************/ if( nfcip_PFBisIMI( rxPFB ) ) { gNfcip.isRxChaining = true; *outIsChaining = true; nfcipLogD( " NFCIP(I) Rcvd IPDU OK w MI -> ACK \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_ACK( gNfcip.pni ), gNfcip.rxBuf[rxMsgIt++] ) ); return ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/ } else { gNfcip.isRxChaining = false; gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; ret = ERR_NONE; /* Data exchange done */ } } return ret; } /*******************************************************************************/ static ReturnCode nfcipTargetHandleRX( ReturnCode rxRes, uint16_t *outActRxLen, bool *outIsChaining ) { ReturnCode ret; uint8_t nfcDepLen; uint8_t rxMsgIt; uint8_t rxPFB; uint8_t optHdrLen; uint8_t resBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_TARGET_RES_MAX]; ret = ERR_INTERNAL; rxMsgIt = 0; optHdrLen = 0; *outActRxLen = 0; *outIsChaining = false; /*******************************************************************************/ /* Handle reception errors */ /*******************************************************************************/ switch( rxRes ) { /*******************************************************************************/ case ERR_NONE: break; case ERR_LINK_LOSS: nfcipLogW( " NFCIP(T) Error: %d \r\n", rxRes ); return rxRes; case ERR_BUSY: return ERR_BUSY; /* Debug purposes */ case ERR_TIMEOUT: case ERR_CRC: case ERR_PAR: case ERR_FRAMING: case ERR_PROTO: default: /* Digital 1.1 16.12.5.2 The Target MUST NOT attempt any error recovery. * * The Target MUST always stay in receive mode when a * * Transmission Error or a Protocol Error occurs. * * * * Do not push Transmission/Protocol Errors to upper layer in Listen Mode #766 */ nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; } /*******************************************************************************/ /* Rx OK check if valid DEP PDU */ /*******************************************************************************/ /* Due to different modes on ST25R391x (with/without CRC) use NFC-DEP LEN instead of bytes retrieved */ nfcDepLen = gNfcip.rxBuf[rxMsgIt++]; nfcipLogD( " NFCIP(T) rx OK: %d bytes \r\n", nfcDepLen ); if( gNfcip.rxBuf[rxMsgIt++] != NFCIP_REQ ) { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad request */ } /*******************************************************************************/ /* Check whether target rcvd a normal DEP or deactivation request */ /*******************************************************************************/ switch( gNfcip.rxBuf[rxMsgIt++] ) { /*******************************************************************************/ case (uint8_t)NFCIP_CMD_DEP_REQ: break; /* Continue to normal DEP processing */ /*******************************************************************************/ case (uint8_t)NFCIP_CMD_DSL_REQ: nfcipLogI( " NFCIP(T) rx DSL \r\n" ); /* Digital 1.0 14.9.1.2 If DID is used and incorrect ignore it */ /* [Digital 1.0, 16.9.1.2]: If DID == 0, Target SHALL ignore DSL_REQ with DID */ if ( (((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID)) && (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) ) || ((gNfcip.cfg.did == RFAL_NFCDEP_DID_NO) && (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_NO_DID)) ) { nfcipLogI( " NFCIP(T) DSL wrong DID, ignoring \r\n" ); return ERR_BUSY; } nfcipTx( NFCIP_CMD_DSL_RES, resBuf, NULL, 0, 0, NFCIP_NO_FWT ); gNfcip.state = NFCIP_ST_TARG_DEP_SLEEP; return ERR_SLEEP_REQ; /*******************************************************************************/ case (uint8_t)NFCIP_CMD_RLS_REQ: nfcipLogI( " NFCIP(T) rx RLS \r\n" ); /* Digital 1.0 14.10.1.2 If DID is used and incorrect ignore it */ /* [Digital 1.0, 16.10.2.2]: If DID == 0, Target SHALL ignore DSL_REQ with DID */ if ( (((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID)) && (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) ) || ((gNfcip.cfg.did == RFAL_NFCDEP_DID_NO) && (nfcDepLen > RFAL_NFCDEP_DSL_RLS_LEN_NO_DID)) ) { nfcipLogI( " NFCIP(T) RLS wrong DID, ignoring \r\n" ); return ERR_BUSY; } nfcipTx( NFCIP_CMD_RLS_RES, resBuf, NULL, 0, 0, NFCIP_NO_FWT ); gNfcip.state = NFCIP_ST_TARG_DEP_IDLE; return ERR_RELEASE_REQ; /*******************************************************************************/ /*case NFCIP_CMD_PSL_REQ: PSL must be handled in Activation only */ /*case NFCIP_CMD_WUP_REQ: WUP not in NFC Forum Digital 1.0 */ default: /* Don't go to NFCIP_ST_TARG_DEP_IDLE state as it needs to ignore this * * invalid frame, and keep waiting for more frames */ nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad frame */ } /*******************************************************************************/ rxPFB = gNfcip.rxBuf[rxMsgIt++]; /* Store rcvd PFB */ /*******************************************************************************/ /* Check for valid PFB type */ if( !(nfcip_PFBisSPDU( rxPFB ) || nfcip_PFBisRPDU( rxPFB ) || nfcip_PFBisIPDU( rxPFB )) ) { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore invalid PFB */ } /*******************************************************************************/ if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) { if( !nfcip_PFBhasDID( rxPFB ) ) { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing DID */ } if( gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did ) /* MISRA 13.5 */ { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing DID */ } optHdrLen++; /* Inc header optional field cnt*/ } else if( nfcip_PFBhasDID( rxPFB ) ) /* DID not expected but rcv */ { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore unexpected DID */ } else { /* MISRA 15.7 - Empty else */ } /*******************************************************************************/ if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) { if( (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || !nfcip_PFBhasDID( rxPFB ) ) { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing DID */ } optHdrLen++; /* Inc header optional field cnt*/ } else if( nfcip_PFBhasNAD( rxPFB ) ) /* NAD not expected but rcv */ { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore unexpected NAD */ } else { /* MISRA 15.7 - Empty else */ } /*******************************************************************************/ /* Process R-PDU */ /*******************************************************************************/ if( nfcip_PFBisRPDU( rxPFB ) ) { nfcipLogD( " NFCIP(T) Rcvd R-PDU \r\n" ); /*******************************************************************************/ /* R ACK */ /*******************************************************************************/ if( nfcip_PFBisRACK( rxPFB ) ) { nfcipLogI( " NFCIP(T) Rcvd ACK \r\n" ); if( gNfcip.pni == nfcip_PBF_PNI( rxPFB ) ) { /* R-ACK while not performing chaining -> Protocol error */ if( !gNfcip.isTxChaining ) { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore unexpected ACK */ } /* This block has been transmitted and acknowledged, perform RTOX until next data is provided */ /* Digital 1.1 16.12.4.7 - If ACK rcvd continue with chaining or an RTOX */ nfcipTimerStart( gNfcip.RTOXTimer, nfcipRTOXAdjust( nfcipConv1FcToMs( rfalNfcDepWT2RWT( gNfcip.cfg.to ) )) ); gNfcip.state = NFCIP_ST_TARG_DEP_RTOX; return ERR_NONE; /* This block has been transmitted */ } /* Digital 1.0 14.12.3.4 - If last send was ATN and rx PNI is minus 1 */ else if( nfcip_PFBisSATN( gNfcip.lastPFB ) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI( rxPFB )) ) { nfcipLogI( " NFCIP(T) wrong PNI, last was ATN reTx \r\n" ); /* Spec says to leave current PNI as is, but will be Inc after Tx, remaining the same */ gNfcip.pni = nfcip_PNIDec( gNfcip.pni ); gNfcip.state = NFCIP_ST_TARG_DEP_TX; return ERR_BUSY; } else { /* MISRA 15.7 - Empty else */ } } /*******************************************************************************/ /* R NACK */ /*******************************************************************************/ /* ISO 18092 12.6.1.3.3 When rcv NACK if PNI = prev PNI sent -> reTx */ else if( nfcip_PFBisRNACK( rxPFB ) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI( rxPFB ) ) ) { nfcipLogI( " NFCIP(T) Rcvd NACK \r\n" ); gNfcip.pni = nfcip_PNIDec( gNfcip.pni ); /* Dec so that has the prev PNI */ gNfcip.state = NFCIP_ST_TARG_DEP_TX; return ERR_BUSY; } else { nfcipLogI( " NFCIP(T) Unexpected R-PDU \r\n" ); nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore unexpected R-PDU */ } } /*******************************************************************************/ /* Process S-PDU */ /*******************************************************************************/ if( nfcip_PFBisSPDU( rxPFB ) ) { nfcipLogD( " NFCIP(T) Rcvd S-PDU \r\n" ); /*******************************************************************************/ /* S ATN */ /*******************************************************************************/ /* ISO 18092 12.6.3 Attention */ if( nfcip_PFBisSATN( rxPFB ) ) /* If is a S-ATN */ { nfcipLogI( " NFCIP(T) Rcvd ATN curPNI: %d \r\n", gNfcip.pni ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_ATN(), 0 ) ); return ERR_BUSY; } /*******************************************************************************/ /* S TO */ /*******************************************************************************/ else if( nfcip_PFBisSTO( rxPFB ) ) /* If is a S-TO (RTOX) */ { if( nfcip_PFBisSTO( gNfcip.lastPFBnATN ) ) { nfcipLogI( " NFCIP(T) Rcvd TO \r\n" ); /* Digital 1.1 16.8.4.6 RTOX value in RES different that in REQ -> Protocol Error */ if( gNfcip.lastRTOX != gNfcip.rxBuf[rxMsgIt++] ) { nfcipLogI( " NFCIP(T) Mismatched RTOX value \r\n" ); nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore unexpected RTOX value */ } /* Clear waiting for RTOX Ack Flag */ gNfcip.isWait4RTOX = false; /* Check if a Tx is already pending */ if( gNfcip.isTxPending ) { nfcipLogW( " NFCIP(T) Tx pending, go immediately to TX \r\n" ); gNfcip.state = NFCIP_ST_TARG_DEP_TX; return ERR_BUSY; } /* Start RTOX timer and change to check state */ nfcipTimerStart( gNfcip.RTOXTimer, nfcipRTOXAdjust( nfcipConv1FcToMs( gNfcip.lastRTOX * rfalNfcDepWT2RWT(gNfcip.cfg.to ) ) ) ); gNfcip.state = NFCIP_ST_TARG_DEP_RTOX; return ERR_BUSY; } } else { /* Unexpected S-PDU */ nfcipLogI( " NFCIP(T) Unexpected S-PDU \r\n" ); /* PRQA S 2880 # MISRA 2.1 - Guard code to prevent unexpected behavior */ nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore unexpected S-PDU */ } } /*******************************************************************************/ /* Process I-PDU */ /*******************************************************************************/ if( nfcip_PFBisIPDU( rxPFB ) ) { if( gNfcip.pni != nfcip_PBF_PNI( rxPFB ) ) { nfcipLogI( " NFCIP(T) Rcvd IPDU wrong PNI curPNI: %d rxPNI: %d \r\n", gNfcip.pni, nfcip_PBF_PNI( rxPFB ) ); /* Digital 1.1 16.12.3.4 - If last send was ATN and rx PNI is minus 1 */ if( nfcip_PFBisSATN(gNfcip.lastPFB ) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI( rxPFB )) ) { /* Spec says to leave current PNI as is, but will be Inc after Data Tx, remaining the same */ gNfcip.pni = nfcip_PNIDec(gNfcip.pni); if( nfcip_PFBisIMI( rxPFB ) ) { nfcipLogI( " NFCIP(T) PNI = prevPNI && ATN before && chaining -> send ACK \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_ACK( gNfcip.pni ), gNfcip.rxBuf[rxMsgIt++] ) ); /* Digital 1.1 16.12.3.4 (...) leave the current PNI unchanged afterwards */ gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); } else { nfcipLogI( " NFCIP(T) PNI = prevPNI && ATN before -> reTx last I-PDU \r\n" ); gNfcip.state = NFCIP_ST_TARG_DEP_TX; } return ERR_BUSY; } nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad PNI value */ } nfcipLogD( " NFCIP(T) Rcvd IPDU OK PNI: %d \r\n", gNfcip.pni ); /*******************************************************************************/ /* Successful data exchange */ /*******************************************************************************/ *outActRxLen = ((uint16_t)nfcDepLen - RFAL_NFCDEP_DEP_HEADER - (uint16_t)optHdrLen); nfcipClearCounters(); if( (&gNfcip.rxBuf[gNfcip.rxBufPaylPos] != &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen]) && (*outActRxLen > 0U) ) { ST_MEMMOVE( &gNfcip.rxBuf[gNfcip.rxBufPaylPos], &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen], *outActRxLen ); } /*******************************************************************************/ /* Check if Initiator is indicating chaining MI */ /*******************************************************************************/ if( nfcip_PFBisIMI( rxPFB ) ) { gNfcip.isRxChaining = true; *outIsChaining = true; nfcipLogD( " NFCIP(T) Rcvd IPDU OK w MI -> ACK \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBRPDU_ACK( gNfcip.pni ), gNfcip.rxBuf[rxMsgIt++] ) ); gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); return ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/ } else { if(gNfcip.isRxChaining) { nfcipLogI( " NFCIP(T) Rcvd last IPDU chaining finished \r\n" ); } /*******************************************************************************/ /* Reception done, send to DH and start RTOX timer */ /*******************************************************************************/ nfcipTimerStart( gNfcip.RTOXTimer, nfcipRTOXAdjust( nfcipConv1FcToMs( rfalNfcDepWT2RWT( gNfcip.cfg.to ) )) ); gNfcip.state = NFCIP_ST_TARG_DEP_RTOX; gNfcip.isRxChaining = false; ret = ERR_NONE; /* Data exchange done */ } } return ret; } /*******************************************************************************/ static ReturnCode nfcipTx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint8_t *paylBuf, uint16_t paylLen, uint8_t pfbData, uint32_t fwt ) { uint16_t txBufIt; uint8_t *txBlock; uint8_t *payloadBuf; uint8_t pfb; if( txBuf == NULL ) { return ERR_PARAM; } payloadBuf = paylBuf; /* MISRA 17.8: Use intermediate variable */ if( (paylLen == 0U) || (payloadBuf == NULL) ) { payloadBuf = (uint8_t*) &txBuf[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /* If not a DEP (no Data) ensure enough space for header */ } txBufIt = 0; pfb = pfbData; /* MISRA 17.8: Use intermediate variable */ txBlock = payloadBuf; /* Point to beginning of the Data, and go backwards */ gNfcip.lastCmd = (uint8_t)cmd; /* Store last cmd sent */ gNfcip.lastPFB = NFCIP_PFB_INVALID; /* Reset last pfb sent */ /*******************************************************************************/ /* Compute outgoing NFCIP message */ /*******************************************************************************/ switch( cmd ) { /*******************************************************************************/ case NFCIP_CMD_ATR_RES: case NFCIP_CMD_ATR_REQ: rfalNfcDepSetNFCID( payloadBuf, gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen ); /* NFCID */ txBufIt += RFAL_NFCDEP_NFCID3_LEN; payloadBuf[txBufIt++] = gNfcip.cfg.did; /* DID */ payloadBuf[txBufIt++] = gNfcip.cfg.bs; /* BS */ payloadBuf[txBufIt++] = gNfcip.cfg.br; /* BR */ if( cmd == NFCIP_CMD_ATR_RES ) { payloadBuf[txBufIt++] = gNfcip.cfg.to; /* ATR_RES[ TO ] */ } if( gNfcip.cfg.gbLen > 0U) { payloadBuf[txBufIt++] = nfcip_PPwGB( gNfcip.cfg.lr ); /* PP signalling GB */ ST_MEMCPY( &payloadBuf[txBufIt], gNfcip.cfg.gb, gNfcip.cfg.gbLen ); /* set General Bytes */ txBufIt += gNfcip.cfg.gbLen; } else { payloadBuf[txBufIt++] = rfalNfcDepLR2PP( gNfcip.cfg.lr ); /* PP without GB */ } if( (txBufIt + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN) > RFAL_NFCDEP_ATRREQ_MAX_LEN ) /* Check max ATR length (ATR_REQ = ATR_RES)*/ { return ERR_PARAM; } break; /*******************************************************************************/ case NFCIP_CMD_WUP_REQ: /* ISO 18092 - 12.5.2.1 */ rfalNfcDepSetNFCID( (payloadBuf), gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen ); /* NFCID */ txBufIt += RFAL_NFCDEP_NFCID3_LEN; *(--txBlock) = gNfcip.cfg.did; /* DID */ break; /*******************************************************************************/ case NFCIP_CMD_WUP_RES: /* ISO 18092 - 12.5.2.2 */ case NFCIP_CMD_PSL_REQ: case NFCIP_CMD_PSL_RES: *(--txBlock) = gNfcip.cfg.did; /* DID */ break; /*******************************************************************************/ case NFCIP_CMD_RLS_REQ: case NFCIP_CMD_RLS_RES: case NFCIP_CMD_DSL_REQ: case NFCIP_CMD_DSL_RES: /* Digital 1.0 - 14.8.1.1 & 14.9.1.1 & 14.10.1.1 Only add DID if not 0 */ if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) { *(--txBlock) = gNfcip.cfg.did; /* DID */ } break; /*******************************************************************************/ case NFCIP_CMD_DEP_REQ: case NFCIP_CMD_DEP_RES: /* Compute optional PFB bits */ if (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) { pfb |= NFCIP_PFB_DID_BIT; } if (gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO) { pfb |= NFCIP_PFB_NAD_BIT; } if ((gNfcip.isTxChaining) && (nfcip_PFBisIPDU(pfb)) ) { pfb |= NFCIP_PFB_MI_BIT; } /* Store PFB for future handling */ gNfcip.lastPFB = pfb; /* store PFB sent */ if( !nfcip_PFBisSATN(pfb) ) { gNfcip.lastPFBnATN = pfb; /* store last PFB different then ATN */ } /* Add NAD if it is to be supported */ if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) { *(--txBlock) = gNfcip.cfg.nad; /* NAD */ } /* Digital 1.0 - 14.8.1.1 & 14.8.1.1 Only add DID if not 0 */ if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) { *(--txBlock) = gNfcip.cfg.did; /* DID */ } *(--txBlock) = pfb; /* PFB */ /* NCI 1.0 - Check if Empty frames are allowed */ if( (paylLen == 0U) && nfcipIsEmptyDEPDisabled(gNfcip.cfg.oper) && nfcip_PFBisIPDU(pfb) ) { return ERR_PARAM; } break; /*******************************************************************************/ default: return ERR_PARAM; } /*******************************************************************************/ /* Prepend Header */ /*******************************************************************************/ *(--txBlock) = (uint8_t)cmd; /* CMD */ *(--txBlock) = (uint8_t)( nfcipCmdIsReq(cmd) ? NFCIP_REQ : NFCIP_RES ); /* CMDType */ txBufIt += paylLen + (uint16_t)((uint32_t)payloadBuf - (uint32_t)txBlock); /* Calculate overall buffer size */ if( txBufIt > gNfcip.fsc ) /* Check if msg length violates the maximum payload size FSC */ { return ERR_NOTSUPP; } /*******************************************************************************/ return nfcipDataTx( txBlock, txBufIt, fwt ); } /* ****************************************************************************** * GLOBAL FUNCTIONS ****************************************************************************** */ /*******************************************************************************/ static void nfcipConfig( const rfalNfcDepConfigs * cfg ) { if (cfg == NULL) { return; } ST_MEMCPY(&gNfcip.cfg, cfg, sizeof(rfalNfcDepConfigs)); /* Copy given config to local */ gNfcip.cfg.to = MIN( RFAL_NFCDEP_WT_TRG_MAX, gNfcip.cfg.to); /* Ensure proper WT value */ gNfcip.cfg.did = nfcip_DIDMax( gNfcip.cfg.did ); /* Ensure proper DID value */ gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); /* Calculate FSC based on given LR */ gNfcip.state = ( ( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_ST_TARG_WAIT_ATR : NFCIP_ST_INIT_IDLE ); } /*******************************************************************************/ static ReturnCode nfcipRun( uint16_t *outActRxLen, bool *outIsChaining ) { ReturnCode ret; ret = ERR_SYNTAX; nfcipLogD( " NFCIP Run() state: %d \r\n", gNfcip.state ); switch( gNfcip.state ) { /*******************************************************************************/ case NFCIP_ST_IDLE: case NFCIP_ST_INIT_DEP_IDLE: case NFCIP_ST_TARG_DEP_IDLE: case NFCIP_ST_TARG_DEP_SLEEP: return ERR_NONE; /*******************************************************************************/ case NFCIP_ST_INIT_DEP_TX: nfcipLogD( " NFCIP(I) Tx PNI: %d txLen: %d \r\n", gNfcip.pni, gNfcip.txBufLen ); ret = nfcipTx( NFCIP_CMD_DEP_REQ, gNfcip.txBuf, &gNfcip.txBuf[gNfcip.txBufPaylPos], gNfcip.txBufLen, nfcip_PFBIPDU( gNfcip.pni ), (gNfcip.cfg.fwt + gNfcip.cfg.dFwt) ); switch( ret ) { case ERR_NONE: gNfcip.state = NFCIP_ST_INIT_DEP_RX; break; case ERR_PARAM: default: gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; return ret; } /* fall through */ /*******************************************************************************/ case NFCIP_ST_INIT_DEP_RX: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ ret = nfcipDataRx( false ); if( ret != ERR_BUSY ) { ret = nfcipInitiatorHandleDEP( ret, *gNfcip.rxRcvdLen, outActRxLen, outIsChaining ); } break; /*******************************************************************************/ case NFCIP_ST_TARG_DEP_RTOX: if( !nfcipTimerisExpired( gNfcip.RTOXTimer ) ) /* Do nothing until RTOX timer has expired */ { return ERR_BUSY; } /* If we cannot send a RTOX raise a Timeout error so that we do not * hold the field On forever in AP2P */ if( nfcipIsRTOXReqDisabled(gNfcip.cfg.oper) ) { /* We should reEnable Rx, and measure time between our field Off to * either report link loss or recover #287 */ nfcipLogI( " NFCIP(T) RTOX not sent due to config, NOT reenabling Rx \r\n" ); return ERR_TIMEOUT; } if( gNfcip.cntRTOXRetrys++ > RFAL_NFCDEP_MAX_RTOX_RETRYS ) /* Check maximum consecutive RTOX requests */ { return ERR_PROTO; } nfcipLogI( " NFCIP(T) RTOX sent \r\n" ); gNfcip.lastRTOX = nfcip_RTOXTargMax(gNfcip.cfg.to); /* Calculate requested RTOX value, and send it */ EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_TO(), gNfcip.lastRTOX ) ); /* Set waiting for RTOX Ack Flag */ gNfcip.isWait4RTOX = true; gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* Go back to Rx to process RTOX ack */ return ERR_BUSY; /*******************************************************************************/ case NFCIP_ST_TARG_DEP_TX: nfcipLogD( " NFCIP(T) Tx PNI: %d txLen: %d \r\n", gNfcip.pni, gNfcip.txBufLen ); ret = nfcipTx( NFCIP_CMD_DEP_RES, gNfcip.txBuf, &gNfcip.txBuf[gNfcip.txBufPaylPos], gNfcip.txBufLen, nfcip_PFBIPDU( gNfcip.pni ), NFCIP_NO_FWT ); /* Clear flags */ gNfcip.isTxPending = false; gNfcip.isWait4RTOX = false; /* Digital 1.0 14.12.3.4 Increment the current PNI after Tx */ gNfcip.pni = nfcip_PNIInc( gNfcip.pni ); switch( ret ) { case ERR_NONE: gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* All OK, goto Rx state */ break; case ERR_PARAM: default: gNfcip.state = NFCIP_ST_TARG_DEP_IDLE; /* Upon Tx error, goto IDLE state */ return ret; } /* fall through */ /*******************************************************************************/ case NFCIP_ST_TARG_DEP_RX: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ if( gNfcip.isReqPending ) /* if already has Data should be from a DEP from nfcipTargetHandleActivation() */ { nfcipLogD( " NFCIP(T) Skipping Rx Using DEP from Activation \r\n" ); gNfcip.isReqPending = false; ret = ERR_NONE; } else { ret = nfcipDataRx( false ); } if( ret != ERR_BUSY ) { ret = nfcipTargetHandleRX( ret, outActRxLen, outIsChaining ); } break; /*******************************************************************************/ default: /* MISRA 16.4: no empty default statement (a comment being enough) */ break; } return ret; } /*******************************************************************************/ void rfalNfcDepSetDeactivatingCallback( rfalNfcDepDeactCallback pFunc ) { gNfcip.isDeactivating = pFunc; } /*******************************************************************************/ void rfalNfcDepInitialize( void ) { nfcipLogD( " NFCIP Ini() \r\n" ); gNfcip.state = NFCIP_ST_IDLE; gNfcip.isDeactivating = NULL; gNfcip.isTxPending = false; gNfcip.isWait4RTOX = false; gNfcip.isReqPending = false; gNfcip.cfg.oper = (RFAL_NFCDEP_OPER_FULL_MI_DIS | RFAL_NFCDEP_OPER_EMPTY_DEP_EN | RFAL_NFCDEP_OPER_ATN_EN | RFAL_NFCDEP_OPER_RTOX_REQ_EN); gNfcip.cfg.did = RFAL_NFCDEP_DID_NO; gNfcip.cfg.nad = RFAL_NFCDEP_NAD_NO; gNfcip.cfg.br = RFAL_NFCDEP_Bx_NO_HIGH_BR; gNfcip.cfg.bs = RFAL_NFCDEP_Bx_NO_HIGH_BR; gNfcip.cfg.lr = RFAL_NFCDEP_LR_254; gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); gNfcip.cfg.gbLen = 0; gNfcip.cfg.fwt = RFAL_NFCDEP_MAX_FWT; gNfcip.cfg.dFwt = RFAL_NFCDEP_MAX_FWT; gNfcip.pni = 0; /* Destroy any ongoing RTOX timer*/ nfcipTimerDestroy( gNfcip.RTOXTimer ); gNfcip.RTOXTimer = 0U; gNfcip.PDUTxPos = 0; gNfcip.PDURxPos = 0; gNfcip.PDUParam.rxLen = NULL; gNfcip.PDUParam.rxBuf = NULL; gNfcip.PDUParam.txBuf = NULL; nfcipClearCounters(); } /*******************************************************************************/ static void nfcipSetDEPParams( const rfalNfcDepDEPParams *DEPParams ) { nfcipLogD( " NFCIP SetDEP() txLen: %d \r\n", DEPParams->txBufLen ); gNfcip.isTxChaining = DEPParams->txChaining; gNfcip.txBuf = DEPParams->txBuf; gNfcip.rxBuf = DEPParams->rxBuf; gNfcip.txBufLen = DEPParams->txBufLen; gNfcip.rxBufLen = DEPParams->rxBufLen; gNfcip.txBufPaylPos = DEPParams->txBufPaylPos; gNfcip.rxBufPaylPos = DEPParams->rxBufPaylPos; if( DEPParams->did != RFAL_NFCDEP_DID_KEEP ) { gNfcip.cfg.did = nfcip_DIDMax( DEPParams->did ); } gNfcip.cfg.fwt = DEPParams->fwt; gNfcip.cfg.dFwt = DEPParams->dFwt; gNfcip.fsc = DEPParams->fsc; if(gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) { /* If there's any data to be sent go for Tx */ if(DEPParams->txBufLen > 0U) { /* Ensure that an RTOX Ack is not being expected at moment */ if( !gNfcip.isWait4RTOX ) { gNfcip.state = NFCIP_ST_TARG_DEP_TX; return; } else { /* If RTOX Ack is expected, signal a pending Tx to be transmitted right after */ gNfcip.isTxPending = true; nfcipLogW( " NFCIP(T) Waiting RTOX, queueing outgoing DEP Block \r\n" ); } } /*Digital 1.0 14.12.4.1 In target mode the first PDU MUST be sent by the Initiator */ gNfcip.state = NFCIP_ST_TARG_DEP_RX; return; } /* New data TxRx request clear previous error counters for consecutive TxRx without reseting communication/protocol layer*/ nfcipClearCounters(); gNfcip.state = NFCIP_ST_INIT_DEP_TX; } /*******************************************************************************/ bool rfalNfcDepTargetRcvdATR( void ) { return ( (gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) && nfcipIsTarget(gNfcip.state) && (gNfcip.state > NFCIP_ST_TARG_WAIT_ATR) ); } /*******************************************************************************/ bool rfalNfcDepIsAtrReq( const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid3 ) { uint8_t msgIt; msgIt = 0; if ( (bufLen < RFAL_NFCDEP_ATRREQ_MIN_LEN) || (bufLen > RFAL_NFCDEP_ATRREQ_MAX_LEN) ) { return false; } if ( buf[msgIt++] != NFCIP_REQ ) { return false; } if( buf[msgIt++] != (uint8_t)NFCIP_CMD_ATR_REQ ) { return false; } /* Output NFID3 if requested */ if( nfcid3 != NULL ) { ST_MEMCPY( nfcid3, &buf[RFAL_NFCDEP_ATR_REQ_NFCID3_POS], RFAL_NFCDEP_NFCID3_LEN ); } return true; } /*******************************************************************************/ static ReturnCode nfcipTargetHandleActivation( rfalNfcDepDevice *nfcDepDev, uint8_t *outBRS ) { ReturnCode ret; uint8_t msgIt; uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_PSLRES_LEN]; /*******************************************************************************/ /* Check if we are in correct state */ /*******************************************************************************/ if( gNfcip.state != NFCIP_ST_TARG_WAIT_ACTV ) { return ERR_WRONG_STATE; } /*******************************************************************************/ /* Check required parameters */ /*******************************************************************************/ if( outBRS == NULL ) { return ERR_PARAM; } /*******************************************************************************/ /* Wait and process incoming cmd (PSL / DEP) */ /*******************************************************************************/ ret = nfcipDataRx( false ); if( ret != ERR_NONE ) { return ret; } msgIt = 0; *outBRS = RFAL_NFCDEP_BRS_MAINTAIN; /* set out BRS to be maintained */ msgIt++; /* Skip LEN byte */ if ( gNfcip.rxBuf[msgIt++] != NFCIP_REQ ) { return ERR_PROTO; } if( gNfcip.rxBuf[msgIt] == (uint8_t)NFCIP_CMD_PSL_REQ ) { msgIt++; if( gNfcip.rxBuf[msgIt++] != gNfcip.cfg.did ) /* Checking DID */ { return ERR_PROTO; } nfcipLogI( " NFCIP(T) PSL REQ rcvd \r\n" ); *outBRS = gNfcip.rxBuf[msgIt++]; /* assign output BRS value */ /* Store FSL(LR) and update current config */ gNfcip.cfg.lr = (gNfcip.rxBuf[msgIt++] & RFAL_NFCDEP_LR_VAL_MASK); gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); /*******************************************************************************/ /* Update NFC-DDE Device info */ if( nfcDepDev != NULL ) { /* Update Bitrate info */ /* PRQA S 4342 2 # MISRA 10.5 - Layout of enum rfalBitRate and definition of rfalNfcDepBRS2DSI guarantee no invalid enum values to be created */ nfcDepDev->info.DSI = (rfalBitRate)rfalNfcDepBRS2DSI( *outBRS ); /* DSI codes the bit rate from Initiator to Target */ nfcDepDev->info.DRI = (rfalBitRate)rfalNfcDepBRS2DRI( *outBRS ); /* DRI codes the bit rate from Target to Initiator */ /* Update Length Reduction and Frame Size */ nfcDepDev->info.LR = gNfcip.cfg.lr; nfcDepDev->info.FS = gNfcip.fsc; /* Update PPi byte */ nfcDepDev->activation.Initiator.ATR_REQ.PPi &= ~RFAL_NFCDEP_PP_LR_MASK; nfcDepDev->activation.Initiator.ATR_REQ.PPi |= rfalNfcDepLR2PP( gNfcip.cfg.lr ); } rfalSetBitRate( RFAL_BR_KEEP, gNfcip.nfcDepDev->info.DSI ); EXIT_ON_ERR( ret, nfcipTx( NFCIP_CMD_PSL_RES, txBuf, NULL, 0, 0, NFCIP_NO_FWT ) ); } else { if( gNfcip.rxBuf[msgIt] == (uint8_t)NFCIP_CMD_DEP_REQ ) { msgIt++; /*******************************************************************************/ /* Digital 1.0 14.12.3.1 PNI must be initialized to 0 */ if( nfcip_PBF_PNI( gNfcip.rxBuf[msgIt] ) != 0U ) { return ERR_PROTO; } /*******************************************************************************/ /* Digital 1.0 14.8.2.1 check if DID is expected and match -> Protocol Error */ if( nfcip_PFBhasDID( gNfcip.rxBuf[ msgIt] ) ) { if( gNfcip.rxBuf[++msgIt] != gNfcip.cfg.did ) { return ERR_PROTO; } } else if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) /* DID expected but not rcv */ { return ERR_PROTO; } else { /* MISRA 15.7 - Empty else */ } } /* Signal Request pending to be digested on normal Handling (DEP_REQ, DSL_REQ, RLS_REQ) */ gNfcip.isReqPending = true; } gNfcip.state = NFCIP_ST_TARG_DEP_RX; return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepATR( const rfalNfcDepAtrParam* param, rfalNfcDepAtrRes *atrRes, uint8_t* atrResLen ) { ReturnCode ret; rfalNfcDepConfigs cfg; uint16_t rxLen; uint8_t msgIt; uint8_t txBuf[RFAL_NFCDEP_ATRREQ_MAX_LEN]; uint8_t rxBuf[NFCIP_ATRRES_BUF_LEN]; if( (param == NULL) || (atrRes == NULL) || (atrResLen == NULL) ) { return ERR_PARAM; } /*******************************************************************************/ /* Configure NFC-DEP layer */ /*******************************************************************************/ cfg.did = param->DID; cfg.nad = param->NAD; cfg.fwt = RFAL_NFCDEP_MAX_FWT; cfg.dFwt = RFAL_NFCDEP_MAX_FWT; cfg.br = param->BR; cfg.bs = param->BS; cfg.lr = param->LR; cfg.to = RFAL_NFCDEP_WT_TRG_MAX; /* Not used in Initiator mode */ cfg.gbLen = param->GBLen; if( cfg.gbLen > 0U ) /* MISRA 21.18 */ { ST_MEMCPY( cfg.gb, param->GB, cfg.gbLen ); } cfg.nfcidLen = param->nfcidLen; if( cfg.nfcidLen > 0U ) /* MISRA 21.18 */ { ST_MEMCPY( cfg.nfcid, param->nfcid, cfg.nfcidLen ); } cfg.role = RFAL_NFCDEP_ROLE_INITIATOR; cfg.oper = param->operParam; cfg.commMode = param->commMode; rfalNfcDepInitialize(); nfcipConfig( &cfg ); /*******************************************************************************/ /* Send ATR_REQ */ /*******************************************************************************/ EXIT_ON_ERR( ret, nfcipTxRx(NFCIP_CMD_ATR_REQ, txBuf, nfcipRWTActivation(), NULL, 0, rxBuf, NFCIP_ATRRES_BUF_LEN, &rxLen ) ); /*******************************************************************************/ /* ATR sent, check response */ /*******************************************************************************/ msgIt = 0; rxLen = ((uint16_t)rxBuf[msgIt++] - RFAL_NFCDEP_LEN_LEN); /* use LEN byte */ if( (rxLen < RFAL_NFCDEP_ATRRES_MIN_LEN) || (rxLen > RFAL_NFCDEP_ATRRES_MAX_LEN) ) /* Checking length: ATR_RES */ { return ERR_PROTO; } if( rxBuf[msgIt++] != NFCIP_RES ) /* Checking if is a response*/ { return ERR_PROTO; } if( rxBuf[msgIt++] != (uint8_t)NFCIP_CMD_ATR_RES ) /* Checking if is a ATR RES */ { return ERR_PROTO; } ST_MEMCPY( (uint8_t*)atrRes, (rxBuf + RFAL_NFCDEP_LEN_LEN), rxLen ); *atrResLen = (uint8_t)rxLen; return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepPSL( uint8_t BRS, uint8_t FSL ) { ReturnCode ret; uint16_t rxLen; uint8_t msgIt; uint8_t txBuf[NFCIP_PSLREQ_LEN + NFCIP_PSLPAY_LEN]; uint8_t rxBuf[NFCIP_PSLRES_LEN]; msgIt = NFCIP_PSLREQ_LEN; txBuf[msgIt++] = BRS; txBuf[msgIt++] = FSL; /*******************************************************************************/ /* Send PSL REQ and wait for response */ /*******************************************************************************/ EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_PSL_REQ, txBuf, nfcipRWTActivation(), &txBuf[NFCIP_PSLREQ_LEN], (msgIt - NFCIP_PSLREQ_LEN), rxBuf, NFCIP_PSLRES_LEN, &rxLen ) ); /*******************************************************************************/ /* PSL sent, check response */ /*******************************************************************************/ msgIt = 0; rxLen = (uint16_t)(rxBuf[msgIt++]); /* use LEN byte */ if( rxLen < NFCIP_PSLRES_LEN ) /* Checking length: LEN + RLS_RES */ { return ERR_PROTO; } if( rxBuf[msgIt++] != NFCIP_RES ) /* Checking if is a response */ { return ERR_PROTO; } if( rxBuf[msgIt++] != (uint8_t)NFCIP_CMD_PSL_RES ) /* Checking if is a PSL RES */ { return ERR_PROTO; } if( rxBuf[msgIt++] != gNfcip.cfg.did ) /* Checking DID */ { return ERR_PROTO; } return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepDSL( void ) { ReturnCode ret; uint8_t txBuf[ RFAL_NFCDEP_HEADER_PAD + NFCIP_DSLREQ_LEN]; uint8_t rxBuf[NFCIP_DSLRES_LEN]; uint8_t rxMsgIt; uint16_t rxLen = 0; if( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET ) { return ERR_NONE; /* Target has no deselect procedure */ } /* Repeating a DSL REQ is optional, not doing it */ EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_DSL_REQ, txBuf, nfcipRWTActivation(), NULL, 0, rxBuf, (uint16_t)sizeof(rxBuf), &rxLen ) ); /*******************************************************************************/ rxMsgIt = 0; if( rxBuf[rxMsgIt++] < NFCIP_DSLRES_MIN ) /* Checking length: LEN + DSL_RES */ { return ERR_PROTO; } if( rxBuf[rxMsgIt++] != NFCIP_RES ) /* Checking if is a response */ { return ERR_PROTO; } if( rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_DSL_RES ) /* Checking if is DSL RES */ { return ERR_PROTO; } if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) { if ( rxBuf[rxMsgIt++] != gNfcip.cfg.did ) { return ERR_PROTO; } } return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepRLS( void ) { ReturnCode ret; uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_RLSREQ_LEN]; uint8_t rxBuf[NFCIP_RLSRES_LEN]; uint8_t rxMsgIt; uint16_t rxLen = 0; if ( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET ) /* Target has no release procedure */ { return ERR_NONE; } /* Repeating a RLS REQ is optional, not doing it */ EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_RLS_REQ, txBuf, nfcipRWTActivation(), NULL, 0, rxBuf, (uint16_t)sizeof(rxBuf), &rxLen ) ); /*******************************************************************************/ rxMsgIt = 0; if( rxBuf[rxMsgIt++] < NFCIP_RLSRES_MIN ) /* Checking length: LEN + RLS_RES */ { return ERR_PROTO; } if( rxBuf[rxMsgIt++] != NFCIP_RES ) /* Checking if is a response */ { return ERR_PROTO; } if( rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_RLS_RES ) /* Checking if is RLS RES */ { return ERR_PROTO; } if( gNfcip.cfg.did != RFAL_NFCDEP_DID_NO ) { if ( rxBuf[rxMsgIt++] != gNfcip.cfg.did ) { return ERR_PROTO; } } return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepInitiatorHandleActivation( rfalNfcDepAtrParam* param, rfalBitRate desiredBR, rfalNfcDepDevice* nfcDepDev ) { ReturnCode ret; uint8_t maxRetyrs; uint8_t PSL_BRS; uint8_t PSL_FSL; bool sendPSL; if( (param == NULL) || (nfcDepDev == NULL) ) { return ERR_PARAM; } param->NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1 16.6.2.9 Initiator SHALL NOT use NAD */ maxRetyrs = NFCIP_ATR_RETRY_MAX; /*******************************************************************************/ /* Send ATR REQ and wait for response */ /*******************************************************************************/ do{ /* Upon transmission error ATR REQ should be retried */ ret = rfalNfcDepATR( param, &nfcDepDev->activation.Target.ATR_RES, &nfcDepDev->activation.Target.ATR_RESLen ); if( nfcipIsTransmissionError(ret) ) { continue; } break; } while( (maxRetyrs--) != 0U ); if( ret != ERR_NONE ) { return ret; } /*******************************************************************************/ /* Compute NFC-DEP device with ATR_RES */ /*******************************************************************************/ nfcDepDev->info.GBLen = (nfcDepDev->activation.Target.ATR_RESLen - RFAL_NFCDEP_ATRRES_MIN_LEN); nfcDepDev->info.DID = nfcDepDev->activation.Target.ATR_RES.DID; nfcDepDev->info.NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1 16.6.3.11 Initiator SHALL ignore b1 of PPt */ nfcDepDev->info.LR = rfalNfcDepPP2LR( nfcDepDev->activation.Target.ATR_RES.PPt ); nfcDepDev->info.FS = rfalNfcDepLR2FS( nfcDepDev->info.LR ); nfcDepDev->info.WT = (nfcDepDev->activation.Target.ATR_RES.TO & RFAL_NFCDEP_WT_MASK); nfcDepDev->info.FWT = rfalNfcDepCalculateRWT( nfcDepDev->info.WT ); nfcDepDev->info.dFWT = RFAL_NFCDEP_WT_DELTA; rfalGetBitRate( &nfcDepDev->info.DSI, &nfcDepDev->info.DRI ); /*******************************************************************************/ /* Check if a PSL needs to be sent */ /*******************************************************************************/ sendPSL = false; PSL_BRS = rfalNfcDepDx2BRS( nfcDepDev->info.DSI ); /* Set current bit rate divisor on both directions */ PSL_FSL = nfcDepDev->info.LR; /* Set current Frame Size */ /* Activity 1.0 9.4.4.15 & 9.4.6.3 NFC-DEP Activation PSL * Activity 2.0 9.4.4.17 & 9.4.6.6 NFC-DEP Activation PSL * * PSL_REQ shall only be sent if desired bit rate is different from current (Activity 1.0) * PSL_REQ shall be sent to update LR or bit rate (Activity 2.0) * */ #if 0 /* PSL due to LR is disabled, can be enabled if desired*/ /*******************************************************************************/ /* Check Frame Size */ /*******************************************************************************/ if( gNfcip.cfg.lr < nfcDepDev->info.LR ) /* If our Length reduction is smaller */ { sendPSL = true; nfcDepDev->info.LR = MIN( nfcDepDev->info.LR, gNfcip.cfg.lr ); gNfcip.cfg.lr = nfcDepDev->info.LR; /* Update nfcip LR to be used */ gNfcip.fsc = rfalNfcDepLR2FS( gNfcip.cfg.lr ); /* Update nfcip FSC to be used */ PSL_FSL = gNfcip.cfg.lr; /* Set LR to be sent */ nfcipLogI( " NFCIP(I) Frame Size differ, PSL new fsc: %d \r\n", gNfcip.fsc ); } #endif /*******************************************************************************/ /* Check Baud rates */ /*******************************************************************************/ if( (nfcDepDev->info.DSI != desiredBR) && (desiredBR != RFAL_BR_KEEP) ) /* if desired BR is different */ { if( nfcipDxIsSupported( (uint8_t)desiredBR, nfcDepDev->activation.Target.ATR_RES.BRt, nfcDepDev->activation.Target.ATR_RES.BSt ) ) /* if desired BR is supported */ /* MISRA 13.5 */ { sendPSL = true; PSL_BRS = rfalNfcDepDx2BRS( desiredBR ); nfcipLogI( " NFCIP(I) BR differ, PSL BR: 0x%02X \r\n", PSL_BRS ); } } /*******************************************************************************/ if( sendPSL ) { /*******************************************************************************/ /* Send PSL REQ and wait for response */ /*******************************************************************************/ EXIT_ON_ERR( ret, rfalNfcDepPSL(PSL_BRS, PSL_FSL) ); /* Check if bit rate has been changed */ if( nfcDepDev->info.DSI != desiredBR ) { /* Check if device was in Passive NFC-A and went to higher bit rates, use NFC-F */ if( (nfcDepDev->info.DSI == RFAL_BR_106) && (gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_PASSIVE) ) { #if RFAL_FEATURE_NFCF /* If Passive initialize NFC-F module */ rfalNfcfPollerInitialize( desiredBR ); #else /* RFAL_FEATURE_NFCF */ return ERR_NOTSUPP; #endif /* RFAL_FEATURE_NFCF */ } nfcDepDev->info.DRI = desiredBR; /* DSI Bit Rate coding from Initiator to Target */ nfcDepDev->info.DSI = desiredBR; /* DRI Bit Rate coding from Target to Initiator */ rfalSetBitRate( nfcDepDev->info.DSI, nfcDepDev->info.DRI ); } return ERR_NONE; /* PSL has been sent */ } return ERR_NONE; /* No PSL has been sent */ } /*******************************************************************************/ uint32_t rfalNfcDepCalculateRWT( uint8_t wt ) { /* Digital 1.0 14.6.3.8 & Digital 1.1 16.6.3.9 */ /* Digital 1.1 16.6.3.9 treat all RFU values as WT=14 */ uint8_t responseWaitTime = MIN( RFAL_NFCDEP_WT_INI_MAX, wt ); return (uint32_t)rfalNfcDepWT2RWT(responseWaitTime); } /*******************************************************************************/ static ReturnCode nfcipDataTx( uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt ) { return rfalTransceiveBlockingTx( txBuf, txBufLen, gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen, (RFAL_TXRX_FLAGS_DEFAULT | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON), ((fwt == NFCIP_NO_FWT) ? RFAL_FWT_NONE : fwt) ); } /*******************************************************************************/ static ReturnCode nfcipDataRx( bool blocking ) { ReturnCode ret; /* Perform Rx either blocking or non-blocking */ if( blocking ) { ret = rfalTransceiveBlockingRx(); } else { ret = rfalGetTransceiveStatus(); } if( ret != ERR_BUSY ) { if( gNfcip.rxRcvdLen != NULL ) { (*gNfcip.rxRcvdLen) = rfalConvBitsToBytes( *gNfcip.rxRcvdLen ); if( (ret == ERR_NONE) && (gNfcip.rxBuf != NULL) ) { /* Digital 1.1 16.4.1.3 - Length byte LEN SHALL have a value between 3 and 255 -> otherwise treat as Transmission Error * * - Ensure that actual received and frame length do match, otherwise treat as Transmission error */ if( (*gNfcip.rxRcvdLen != (uint16_t)*gNfcip.rxBuf) || (*gNfcip.rxRcvdLen < RFAL_NFCDEP_LEN_MIN) || (*gNfcip.rxRcvdLen > RFAL_NFCDEP_LEN_MAX) ) { return ERR_FRAMING; } } } } return ret; } /*******************************************************************************/ ReturnCode rfalNfcDepListenStartActivation( const rfalNfcDepTargetParam *param, const uint8_t *atrReq, uint16_t atrReqLength, rfalNfcDepListenActvParam rxParam ) { ReturnCode ret; rfalNfcDepConfigs cfg; if( (param == NULL) || (atrReq == NULL) || (rxParam.rxLen == NULL) ) { return ERR_PARAM; } /*******************************************************************************/ /* Check whether is a valid ATR_REQ Compute NFC-DEP device */ if( !rfalNfcDepIsAtrReq( atrReq, atrReqLength, NULL ) ) { return ERR_PARAM; } rxParam.nfcDepDev->activation.Initiator.ATR_REQLen = (uint8_t)atrReqLength; /* nfcipIsAtrReq() is already checking Min and Max buffer lengths */ if( atrReqLength > 0U ) /* MISRA 21.18 */ { ST_MEMCPY( (uint8_t*)&rxParam.nfcDepDev->activation.Initiator.ATR_REQ, atrReq, atrReqLength ); } rxParam.nfcDepDev->info.GBLen = (uint8_t)(atrReqLength - RFAL_NFCDEP_ATRREQ_MIN_LEN); rxParam.nfcDepDev->info.DID = rxParam.nfcDepDev->activation.Initiator.ATR_REQ.DID; rxParam.nfcDepDev->info.NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1 16.6.2.9 Initiator SHALL NOT use NAD */ rxParam.nfcDepDev->info.LR = rfalNfcDepPP2LR( rxParam.nfcDepDev->activation.Initiator.ATR_REQ.PPi ); rxParam.nfcDepDev->info.FS = rfalNfcDepLR2FS( rxParam.nfcDepDev->info.LR ); rxParam.nfcDepDev->info.WT = 0; rxParam.nfcDepDev->info.FWT = NFCIP_NO_FWT; rxParam.nfcDepDev->info.dFWT = NFCIP_NO_FWT; rfalGetBitRate( &rxParam.nfcDepDev->info.DSI, &rxParam.nfcDepDev->info.DRI ); /* Store Device Info location, updated upon a PSL */ gNfcip.nfcDepDev = rxParam.nfcDepDev; /*******************************************************************************/ cfg.did = rxParam.nfcDepDev->activation.Initiator.ATR_REQ.DID; cfg.nad = RFAL_NFCDEP_NAD_NO; cfg.fwt = RFAL_NFCDEP_MAX_FWT; cfg.dFwt = RFAL_NFCDEP_MAX_FWT; cfg.br = param->brt; cfg.bs = param->bst; cfg.lr = rfalNfcDepPP2LR(param->ppt); cfg.gbLen = param->GBtLen; if( cfg.gbLen > 0U ) /* MISRA 21.18 */ { ST_MEMCPY(cfg.gb, param->GBt, cfg.gbLen); } cfg.nfcidLen = RFAL_NFCDEP_NFCID3_LEN; ST_MEMCPY(cfg.nfcid, param->nfcid3, RFAL_NFCDEP_NFCID3_LEN); cfg.to = param->to; cfg.role = RFAL_NFCDEP_ROLE_TARGET; cfg.oper = param->operParam; cfg.commMode = param->commMode; rfalNfcDepInitialize(); nfcipConfig( &cfg ); /*******************************************************************************/ /* Reply with ATR RES to Initiator */ /*******************************************************************************/ gNfcip.rxBuf = (uint8_t*)rxParam.rxBuf; gNfcip.rxBufLen = sizeof(rfalNfcDepBufFormat); gNfcip.rxRcvdLen = rxParam.rxLen; gNfcip.rxBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; gNfcip.isChaining = rxParam.isRxChaining; gNfcip.txBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; EXIT_ON_ERR( ret, nfcipTx( NFCIP_CMD_ATR_RES, (uint8_t*) gNfcip.rxBuf, NULL, 0, 0, NFCIP_NO_FWT ) ); gNfcip.state = NFCIP_ST_TARG_WAIT_ACTV; return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepListenGetActivationStatus( void ) { ReturnCode err; uint8_t BRS; BRS = RFAL_NFCDEP_BRS_MAINTAIN; err = nfcipTargetHandleActivation( gNfcip.nfcDepDev, &BRS ); switch (err) { case ERR_NONE: if( BRS != RFAL_NFCDEP_BRS_MAINTAIN ) { /* DSI codes the bit rate from Initiator to Target */ /* DRI codes the bit rate from Target to Initiator */ if( gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_ACTIVE ) { EXIT_ON_ERR( err, rfalSetMode( RFAL_MODE_LISTEN_ACTIVE_P2P, gNfcip.nfcDepDev->info.DRI, gNfcip.nfcDepDev->info.DSI )); } else { EXIT_ON_ERR( err, rfalSetMode( ((RFAL_BR_106 == gNfcip.nfcDepDev->info.DRI) ? RFAL_MODE_LISTEN_NFCA : RFAL_MODE_LISTEN_NFCF), gNfcip.nfcDepDev->info.DRI, gNfcip.nfcDepDev->info.DSI )); } } break; case ERR_BUSY: // do nothing break; case ERR_PROTO: default: // re-enable receiving of data nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); break; } return err; } /*******************************************************************************/ ReturnCode rfalNfcDepStartTransceive( const rfalNfcDepTxRxParam *param ) { rfalNfcDepDEPParams nfcDepParams; nfcDepParams.txBuf = (uint8_t *)param->txBuf; nfcDepParams.txBufLen = param->txBufLen; nfcDepParams.txChaining = param->isTxChaining; nfcDepParams.txBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; /* position in txBuf where actual outgoing data is located */ nfcDepParams.did = RFAL_NFCDEP_DID_KEEP; nfcDepParams.rxBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN; nfcDepParams.rxBuf = (uint8_t *)param->rxBuf; nfcDepParams.rxBufLen = sizeof(rfalNfcDepBufFormat); nfcDepParams.fsc = param->FSx; nfcDepParams.fwt = param->FWT; nfcDepParams.dFwt = param->dFWT; gNfcip.rxRcvdLen = param->rxLen; gNfcip.isChaining = param->isRxChaining; nfcipSetDEPParams(&nfcDepParams); return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepGetTransceiveStatus( void ) { return nfcipRun( gNfcip.rxRcvdLen, gNfcip.isChaining ); } /*******************************************************************************/ static void rfalNfcDepPdu2BLockParam( rfalNfcDepPduTxRxParam pduParam, rfalNfcDepTxRxParam *blockParam, uint16_t txPos, uint16_t rxPos ) { uint16_t maxInfLen; NO_WARNING(rxPos); /* Keep this param for future use */ blockParam->DID = pduParam.DID; blockParam->FSx = pduParam.FSx; blockParam->FWT = pduParam.FWT; blockParam->dFWT = pduParam.dFWT; /* Calculate max INF/Payload to be sent to other device */ maxInfLen = (blockParam->FSx - (RFAL_NFCDEP_HEADER + RFAL_NFCDEP_DEP_PFB_LEN)); maxInfLen += ((blockParam->DID != RFAL_NFCDEP_DID_NO) ? RFAL_NFCDEP_DID_LEN : 0U); if( (pduParam.txBufLen - txPos) > maxInfLen ) { blockParam->isTxChaining = true; blockParam->txBufLen = maxInfLen; } else { blockParam->isTxChaining = false; blockParam->txBufLen = (pduParam.txBufLen - txPos); } /* TxBuf is moved to the beginning for every Block */ blockParam->txBuf = (rfalNfcDepBufFormat*)pduParam.txBuf; /* PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */ blockParam->rxBuf = pduParam.tmpBuf; /* Simply using the pdu buffer is not possible because of current ACK handling */ blockParam->isRxChaining = &gNfcip.isPDURxChaining; blockParam->rxLen = pduParam.rxLen; } /*******************************************************************************/ ReturnCode rfalNfcDepStartPduTransceive( rfalNfcDepPduTxRxParam param ) { rfalNfcDepTxRxParam txRxParam; /* Initialize and store APDU context */ gNfcip.PDUParam = param; gNfcip.PDUTxPos = 0; gNfcip.PDURxPos = 0; /* Convert PDU TxRxParams to Block TxRxParams */ rfalNfcDepPdu2BLockParam( gNfcip.PDUParam, &txRxParam, gNfcip.PDUTxPos, gNfcip.PDURxPos ); return rfalNfcDepStartTransceive( &txRxParam ); } /*******************************************************************************/ ReturnCode rfalNfcDepGetPduTransceiveStatus( void ) { ReturnCode ret; rfalNfcDepTxRxParam txRxParam; ret = rfalNfcDepGetTransceiveStatus(); switch( ret ) { /*******************************************************************************/ case ERR_NONE: /* Check if we are still doing chaining on Tx */ if( gNfcip.isTxChaining ) { /* Add already Tx bytes */ gNfcip.PDUTxPos += gNfcip.txBufLen; /* Convert APDU TxRxParams to I-Block TxRxParams */ rfalNfcDepPdu2BLockParam( gNfcip.PDUParam, &txRxParam, gNfcip.PDUTxPos, gNfcip.PDURxPos ); if( txRxParam.txBufLen > 0U ) /* MISRA 21.18 */ { /* Move next Block to beginning of APDU Tx buffer */ ST_MEMCPY( gNfcip.PDUParam.txBuf->pdu, &gNfcip.PDUParam.txBuf->pdu[gNfcip.PDUTxPos], txRxParam.txBufLen ); } EXIT_ON_ERR( ret, rfalNfcDepStartTransceive( &txRxParam ) ); return ERR_BUSY; } /* PDU TxRx is done */ /* fall through */ /*******************************************************************************/ case ERR_AGAIN: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */ /* Check if no PDU transceive has been started before (data from rfalNfcDepListenStartActivation) */ if( gNfcip.PDUParam.rxLen == NULL ) { /* In Listen mode first chained packet cannot be retrieved via APDU interface */ if( ret == ERR_AGAIN ) { return ERR_NOTSUPP; } /* TxRx is complete and full data is already available */ return ERR_NONE; } if( (*gNfcip.PDUParam.rxLen) > 0U ) /* MISRA 21.18 */ { /* Ensure that data in tmpBuf still fits into PDU buffer */ if( (uint16_t)((uint16_t)gNfcip.PDURxPos + (*gNfcip.PDUParam.rxLen)) > RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN ) { return ERR_NOMEM; } /* Copy chained packet from tmp buffer to PDU buffer */ ST_MEMCPY( &gNfcip.PDUParam.rxBuf->pdu[gNfcip.PDURxPos], gNfcip.PDUParam.tmpBuf->inf, *gNfcip.PDUParam.rxLen ); gNfcip.PDURxPos += *gNfcip.PDUParam.rxLen; } /* Update output param rxLen */ *gNfcip.PDUParam.rxLen = gNfcip.PDURxPos; /* Wait for following Block or PDU TxRx is done */ return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE); /*******************************************************************************/ default: /* MISRA 16.4: no empty default statement (a comment being enough) */ break; } return ret; } #endif /* RFAL_FEATURE_NFC_DEP */