/****************************************************************************** * \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 */