Fork of the GitHub
rfal_nfcDep.cpp
- Committer:
- DiegoOstuni
- Date:
- 2019-11-14
- Revision:
- 0:75fc82583a41
File content as of revision 0:75fc82583a41:
/****************************************************************************** * @attention * * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> * * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://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 <platform1.h> #include "rfal_nfcDep.h" #include "rfal_nfcf.h" #include "utils.h" /* ****************************************************************************** * ENABLE SWITCH ****************************************************************************** */ #ifndef RFAL_FEATURE_NFC_DEP #error " RFAL: Module configuration missing. Please enable/disable NFC-DEP module by setting: RFAL_FEATURE_NFC_DEP " #endif #if RFAL_FEATURE_NFC_DEP /* ****************************************************************************** * DEFINES ****************************************************************************** */ #define NFCIP_LOOP_MAX 0x0005FFFF /*!< Max blocking reRuns */ #define NFCIP_ATR_RETRY_MAX 2 /*!< Max consecutive retrys of an ATR REQ with transm error*/ #define NFCIP_PSLPAY_LEN (2) /*!< PSL Payload length (BRS + FSL) */ #define NFCIP_PSLREQ_LEN (3 + RFAL_NFCDEP_LEN_LEN) /*!< PSL REQ length (incl LEN) */ #define NFCIP_PSLRES_LEN (3 + 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 (3 + RFAL_NFCDEP_LEN_LEN) /*!< RLS REQ length (incl LEN) */ #define NFCIP_RLSRES_LEN (3 + RFAL_NFCDEP_LEN_LEN) /*!< RSL RES length (incl LEN) */ #define NFCIP_RLSRES_MIN (2 + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN) */ #define NFCIP_DSLREQ_LEN (3 + RFAL_NFCDEP_LEN_LEN) /*!< DSL REQ length (incl LEN) */ #define NFCIP_DSLRES_LEN (3 + RFAL_NFCDEP_LEN_LEN) /*!< DSL RES length (incl LEN) */ #define NFCIP_DSLRES_MIN (2 + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a DSL RES (incl LEN) */ #define NFCIP_DSLRES_MAX_LEN (3 + RFAL_NFCDEP_LEN_LEN) /*!< Maximum length for a DSL RES (incl LEN) */ #define NFCIP_RLSRES_MAX_LEN (3 + 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 1 /*!< Minimum RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_INIT_MAX_RTOX 59 /*!< Maximum RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_TARG_MIN_RTOX 1 /*!< Minimum target RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_TARG_MAX_RTOX 59 /*!< Maximum target RTOX value Digital 1.0 14.8.4.1 */ #define NFCIP_TRECOV (1280 / 64) /*!< Digital 1.0 A.10 Trecov */ #define NFCIP_TIMEOUT_ADJUSTMENT 8 /*!< Timeout Adjustment to compensate timing from end of Tx to end of frame: (512/64)/fc */ #define NFCIP_RWT_ACTIVATION (0x40001 + NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 1.0 A.10 RWT ACTIVATION 2^24/64[64/fc] + 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 */ #define NFCIP_MAX_TX_RETRYS 3 /*!< Number of retransmit retyrs */ #define NFCIP_MAX_TO_RETRYS 3 /*!< Number of retrys for Timeout */ #define NFCIP_MAX_RTOX_RETRYS 3 /*!< Number of retrys for RTOX */ #define NFCIP_MAX_NACK_RETRYS 3 /*!< Number of retrys for NACK */ #define NFCIP_MAX_ATN_RETRYS 3 /*!< Number of retrys for ATN */ #define NFCIP_MIN_TXERROR_LEN 4 /*!< Minimum frame length with error to be ignored Digital 1.0 14.12.5.4 */ #define NFCIP_REQ 0xD4 /*!<NFCIP REQuest code */ #define NFCIP_RES 0xD5 /*!<NFCIP RESponce code */ #define NFCIP_BS_MASK 0x0F /*!< Bit mask for BS value on a ATR REQ/RES */ #define NFCIP_BR_MASK NFCIP_BS_MASK /*!< Bit mask for BR value on a ATR REQ/RES */ #define NFCIP_PP_GB_MASK 0x02 /*!< Bit mask for GB value in PP byte on a ATR REQ/RES */ #define NFCIP_PP_NAD_MASK 0x01 /*!< Bit mask for NAD value in PP byte on a ATR REQ/RES */ #define NFCIP_PFB_xPDU_MASK 0xE0 /*!< Bit mask for PDU type */ #define NFCIP_PFB_IPDU 0x00 /*!< Bit mask indicating a Information PDU */ #define NFCIP_PFB_RPDU 0x40 /*!< Bit mask indicating a Response PDU */ #define NFCIP_PFB_SPDU 0x80 /*!< Bit mask indicating a Supervisory PDU */ #define NFCIP_PFB_MI_BIT 0x10 /*!< Bit mask for the chaining bit (MI) of PFB */ #define NFCIP_PFB_DID_BIT 0x04 /*!< Bit mask for the DID presence bit of PFB */ #define NFCIP_PFB_NAD_BIT 0x08 /*!< Bit mask for the NAD presence bit of PFB */ #define NFCIP_PFB_PNI_MASK 0x03 /*!< Bit mask for the Packet Number Information */ #define NFCIP_PFB_Rx_MASK 0x10 /*!< Bit mask for the R-PDU type */ #define NFCIP_PFB_ACK 0x00 /*!< Bit mask for R-PDU indicating ACK */ #define NFCIP_PFB_NACK 0x10 /*!< Bit mask for R-PDU indicating NAK */ #define NFCIP_PFB_Sx_MASK 0x10 /*!< Bit mask for the R-PDU type */ #define NFCIP_PFB_ATN 0x00 /*!< Bit mask for R-PDU indicating ACK */ #define NFCIP_PFB_TO 0x10 /*!< Bit mask for R-PDU indicating NAK */ #define NFCIP_PFB_INVALID 0xFF /*!< Invalid PFB value */ /* ****************************************************************************** * MACROS ****************************************************************************** */ #define nfcipIsTransmissionError(e) ( (ERR_NO_MASK(e) == ERR_CRC) || (ERR_NO_MASK(e) == ERR_FRAMING) || (ERR_NO_MASK(e) == ERR_PAR) ) /*!< Checks if is a Trasmission error */ #define nfcipConv1FcToMs( v ) (((v * 64) / 13560) + 1) /*!< Converts value v 1fc into milliseconds (fc=13.56) */ #define nfcipCmdIsReq( cmd ) ((cmd % 2) == 0) /*!< Checks if the nfcip cmd is a REQ */ #define nfcip_PFBhasDID( pfb ) ( (pfb & NFCIP_PFB_DID_BIT) == NFCIP_PFB_DID_BIT) /*!< Checks if pfb is signalling DID */ #define nfcip_PFBhasNAD( pfb ) ( (pfb & NFCIP_PFB_NAD_BIT) == NFCIP_PFB_NAD_BIT) /*!< Checks if pfb is signalling NAD */ #define nfcip_PFBisIPDU( pfb ) ( (pfb & NFCIP_PFB_xPDU_MASK) == NFCIP_PFB_IPDU) /*!< Checks if pfb is a Information PDU */ #define nfcip_PFBisRPDU( pfb ) ( (pfb & NFCIP_PFB_xPDU_MASK) == NFCIP_PFB_RPDU) /*!< Checks if pfb is Response PDU */ #define nfcip_PFBisSPDU( pfb ) ( (pfb & NFCIP_PFB_xPDU_MASK) == NFCIP_PFB_SPDU) /*!< Checks if pfb is a Supervisory PDU */ #define nfcip_PFBisIMI( pfb ) ( nfcip_PFBisIPDU( pfb ) && (pfb & NFCIP_PFB_MI_BIT) == NFCIP_PFB_MI_BIT) /*!< Checks if pfb is a Information PDU indicating MI chaining */ #define nfcip_PFBisRNACK( pfb ) ( nfcip_PFBisRPDU( pfb ) && ((pfb & NFCIP_PFB_Rx_MASK) == NFCIP_PFB_NACK)) /*!< Checks if pfb is a R-PDU indicating NACK */ #define nfcip_PFBisRACK( pfb ) ( nfcip_PFBisRPDU( pfb ) && ((pfb & NFCIP_PFB_Rx_MASK) == NFCIP_PFB_ACK )) /*!< Checks if pfb is a R-PDU indicating ACK */ #define nfcip_PFBisSATN( pfb ) ( nfcip_PFBisSPDU( pfb ) && ((pfb & NFCIP_PFB_Sx_MASK) == NFCIP_PFB_ATN)) /*!< Checks if pfb is a R-PDU indicating ATN */ #define nfcip_PFBisSTO( pfb ) ( nfcip_PFBisSPDU( pfb ) && ((pfb & NFCIP_PFB_Sx_MASK) == NFCIP_PFB_TO) ) /*!< Checks if pfb is a R-PDU indicating TO */ #define nfcip_PFBIPDU( pni ) ( (uint8_t)( 0x00 | NFCIP_PFB_IPDU | (pni & NFCIP_PFB_PNI_MASK) ))/*!< Returns a PFB I-PDU with the given packet number (pni) */ #define nfcip_PFBIPDU_MI( pni ) ( (uint8_t)(isoDep_PCBIBlock(pni) | NFCIP_PFB_MI_BIT)) /*!< Returns a PFB I-PDU with the given packet number (pni) indicating chaing */ #define nfcip_PFBRPDU( pni ) ( (uint8_t)( 0x00 | NFCIP_PFB_RPDU | (pni & NFCIP_PFB_PNI_MASK) ))/*!< Returns a PFB R-PDU with the given packet number (pni) */ #define nfcip_PFBRPDU_NACK( pni ) ( (uint8_t)(nfcip_PFBRPDU(pni) | NFCIP_PFB_NACK)) /*!< Returns a PFB R-PDU with the given packet number (pni) indicating NACK */ #define nfcip_PFBRPDU_ACK( pni ) ( (uint8_t)(nfcip_PFBRPDU(pni) | NFCIP_PFB_ACK)) /*!< Returns a PFB R-PDU with the given packet number (pni) indicating ACK */ #define nfcip_PFBSPDU() ( (uint8_t)( 0x00 | NFCIP_PFB_SPDU )) /*!< Returns a PFB S-PDU */ #define nfcip_PFBSPDU_ATN() ( (uint8_t)(nfcip_PFBSPDU() | NFCIP_PFB_ATN)) /*!< Returns a PFB S-PDU indicating ATN */ #define nfcip_PFBSPDU_TO() ( (uint8_t)(nfcip_PFBSPDU() | NFCIP_PFB_TO)) /*!< Returns a PFB S-PDU indicating TO */ #define nfcip_PNIInc( pni ) ( (uint8_t) ((pni+1) & NFCIP_PFB_PNI_MASK) ) /*!< Returns a incremented PNI from the given (pni) */ #define nfcip_PNIDec( pni ) ( (uint8_t) ((pni-1) & NFCIP_PFB_PNI_MASK) ) /*!< Returns a decremented PNI from the given (pni) */ #define nfcip_PBF_PNI( pfb ) ( (uint8_t) (pfb & NFCIP_PFB_PNI_MASK )) /*!< Returns the Packet Number Information (pni) */ #define nfcip_PPwGB( lr ) ( rfalNfcDepLR2PP( lr ) | NFCIP_PP_GB_MASK) /*!< Returns a PP byte containing the given PP value indicating GB */ #define nfcip_DIDMax( did ) ( MIN( (did), RFAL_NFCDEP_DID_MAX) ) /*!< Ensures that the given did has proper value Digital 14.6.2.3 DID [0 14] */ #define nfcip_RTOXTargMax( wt ) ( MIN( (RFAL_NFCDEP_RWT_TRG_MAX / rfalNfcDepWT2RWT(wt)), NFCIP_TARG_MAX_RTOX) )/*!< Calculates the Maximum RTOX value for the given wt as a Target */ #define nfcipIsInitiator( st ) ( ((st) >= 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 ) (((1<<(br)) & mBR) != 0) /*!< 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) != 0) /*!< 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) != 0) /*!< 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() ) #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 ) timer = platformTimerCreate(time_ms) /*!< Configures and starts the RTOX timer */ #define nfcipTimerisExpired( timer ) platformTimerIsExpired( timer ) /*!< Checks RTOX timer has expired */ #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 | RFAL_TXRX_FLAGS_NFCIP1_ON ), RFAL_FWT_NONE, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) uint8_t txBuf[RFAL_NFCDEP_ATRREQ_MAX_LEN]; uint8_t rxBuf[NFCIP_ATRRES_BUF_LEN]; uint8_t txBufPSL[NFCIP_PSLREQ_LEN]; uint8_t pslBufPSL[NFCIP_PSLPAY_LEN]; uint8_t rxBufPSL[NFCIP_PSLRES_LEN]; uint8_t txBufDSL[ RFAL_NFCDEP_HEADER_PAD + NFCIP_DSLREQ_LEN]; uint8_t rxBufDSL[NFCIP_DSLRES_LEN]; uint8_t txBufRLS[RFAL_NFCDEP_HEADER_PAD + NFCIP_RLSREQ_LEN]; uint8_t rxBufRLS[NFCIP_RLSRES_LEN]; /* ****************************************************************************** * 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 */ uint8_t 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 NfcipState { 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 */ }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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); static ReturnCode nfcipTx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint8_t *paylBuf, uint16_t paylLen, uint8_t pfb, uint32_t fwt, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); static ReturnCode nfcipDEPControlMsg( uint8_t pfb, uint8_t RTOX, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); static ReturnCode nfcipInitiatorHandleDEP( ReturnCode rxRes, uint16_t rxLen, uint16_t *outActRxLen, bool *outIsChaining, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); static ReturnCode nfcipTargetHandleRX( ReturnCode rxRes, uint16_t *outActRxLen, bool *outIsChaining, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); static ReturnCode nfcipTargetHandleActivation( rfalNfcDepDevice *nfcDepDev, uint8_t *outBRS, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); /*! ****************************************************************************** * \brief NFCIP Congigure * * Configures the nfcip layer with the given configurations * * \param[in] cfg : nfcip configuration for following communication ****************************************************************************** */ static void nfcipConfig( 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( 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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); /*! ****************************************************************************** * \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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ); /*! ****************************************************************************** * \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[out] rxBuf : buffer to hold incomming data * \param[in] rxBufLen : rxBuf capacity * \param[out] actualRxLen : length of the data received * * \return ERR_NONE : No error ****************************************************************************** */ static ReturnCode nfcipDataRx( void ); /* ****************************************************************************** * 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 <= RFAL_NFCDEP_Dx_04_424) ) { return true; } if( (Dx == RFAL_NFCDEP_Dx_08_848) && (Bx >= 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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode ret; uint32_t reRun; reRun = NFCIP_LOOP_MAX; /* set maximum loop reRuns */ 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); } /*******************************************************************************/ /* Reception */ /*******************************************************************************/ do /* call Rx() until done or max reRuns reached */ { ret = nfcipDataRx(); rfalWorker( mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; if( !reRun-- ) /* if max reRuns reached return error */ { return ERR_MAX_RERUNS; } } while( ret == ERR_NO_MASK(ERR_BUSY) ); 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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { 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 ) ) { return nfcipTx( depCmd, ctrlMsg, &RTOX, sizeof(RTOX), pfb, fwt, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } else { return nfcipTx( depCmd, ctrlMsg, 0, 0, pfb, fwt, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } } /*******************************************************************************/ 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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { 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++ >= NFCIP_MAX_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++ >= NFCIP_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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); 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++ >= NFCIP_MAX_NACK_RETRYS ) { return ERR_PROTO; } /* Send ATN */ nfcipLogI( " NFCIP(I) Sending ATN \r\n" ); EXIT_ON_ERR( ret, nfcipDEPControlMsg( nfcip_PFBSPDU_ATN(), 0, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); 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++ >= NFCIP_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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); 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++] != 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( !nfcip_PFBhasDID( rxPFB ) || gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did ) { return ERR_PROTO; } optHdrLen++; /* Inc header optional field cnt*/ } else if( nfcip_PFBhasDID( rxPFB ) ) /* DID not expected but rcv */ { return ERR_PROTO; } /*******************************************************************************/ /* 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( !nfcip_PFBhasNAD( rxPFB ) || gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.nad ) { return ERR_PROTO; } optHdrLen++; /* Inc header optional field cnt*/ } else if( nfcip_PFBhasNAD( rxPFB ) ) /* NAD not expected but rcv */ { return ERR_PROTO; } /*******************************************************************************/ /* 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++ >= NFCIP_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`s 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); } else { /* ReTransmit ? */ if( gNfcip.cntTxRetrys++ >= NFCIP_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++ > NFCIP_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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); gNfcip.lastRTOX = rxRTOX; return ERR_BUSY; } /* Unexpected S-PDU */ return ERR_PROTO; } /*******************************************************************************/ /* 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 = (nfcDepLen - RFAL_NFCDEP_DEP_HEADER - optHdrLen); if( (gNfcip.rxBuf + gNfcip.rxBufPaylPos) != (gNfcip.rxBuf + RFAL_NFCDEP_DEP_HEADER + optHdrLen) ) { 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++], mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); 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; return ERR_NONE; /* Data exchange done */ } } return ret; } /*******************************************************************************/ static ReturnCode nfcipTargetHandleRX( ReturnCode rxRes, uint16_t *outActRxLen, bool *outIsChaining, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode ret; uint8_t nfcDepLen; uint8_t rxMsgIt; uint8_t rxPFB; uint8_t optHdrLen; uint8_t resBuf[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_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; case ERR_LINK_LOSS: nfcipLogW( " NFCIP(T) Error: %d \r\n", rxRes ); return rxRes; case ERR_BUSY: return ERR_BUSY; /* Debug purposes */ } /*******************************************************************************/ /* 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 NFCIP_CMD_DEP_REQ: break; /* Continue to normal DEP processing */ /*******************************************************************************/ case 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.cfg.did != RFAL_NFCDEP_DID_NO) && ((nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID) || (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did)) ) ||((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, 0, 0, 0, NFCIP_NO_FWT, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; gNfcip.state = NFCIP_ST_TARG_DEP_SLEEP; return ERR_SLEEP_REQ; /*******************************************************************************/ case 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.cfg.did != RFAL_NFCDEP_DID_NO) && ((nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID) || (gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did)) ) ||( (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, 0, 0, 0, NFCIP_NO_FWT, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; 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 ) || gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did ) { 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 */ } /*******************************************************************************/ if( gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO ) { if( !nfcip_PFBhasNAD( rxPFB ) || gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.nad ) { nfcDepReEnableRx( gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen ); return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing NAD */ } 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 */ } /*******************************************************************************/ /* 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; } } /*******************************************************************************/ /* 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; } 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); 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; } } /* Unexpected S-PDU */ nfcipLogI( " NFCIP(T) Unexpected S-PDU \r\n" ); 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++], mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /* 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 = (nfcDepLen - RFAL_NFCDEP_DEP_HEADER - optHdrLen); nfcipClearCounters(); if( (gNfcip.rxBuf + gNfcip.rxBufPaylPos) != (gNfcip.rxBuf + RFAL_NFCDEP_DEP_HEADER + optHdrLen) ) { 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++], mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); 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; return ERR_NONE; /* Data exchange done */ } } return ret; } /*******************************************************************************/ static ReturnCode nfcipTx( rfalNfcDepCmd cmd, uint8_t* txBuf, uint8_t *paylBuf, uint16_t paylLen, uint8_t pfb, uint32_t fwt, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { uint16_t txBufIt; uint8_t *txBlock; if( txBuf == NULL ) { return ERR_PARAM; } if( (paylLen == 0) || (paylBuf == NULL) ) { paylBuf = (txBuf + RFAL_NFCDEP_DEPREQ_HEADER_LEN); /* If not a DEP (no Data) ensure enough space for header */ } txBufIt = 0; txBlock = paylBuf; /* Point to beginning of the Data, and go backwards */ gNfcip.lastCmd = 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( paylBuf, gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen ); /* NFCID */ txBufIt += RFAL_NFCDEP_NFCID3_LEN; *(paylBuf + txBufIt++) = gNfcip.cfg.did; /* DID */ *(paylBuf + txBufIt++) = gNfcip.cfg.bs; /* BS */ *(paylBuf + txBufIt++) = gNfcip.cfg.br; /* BR */ if( cmd == NFCIP_CMD_ATR_RES ) { *(paylBuf + txBufIt++) = gNfcip.cfg.to; /* ATR_RES[ TO ] */ } if( gNfcip.cfg.gbLen > 0) { *(paylBuf + txBufIt++) = nfcip_PPwGB( gNfcip.cfg.lr ); /* PP signalling GB */ ST_MEMCPY( (paylBuf + txBufIt), gNfcip.cfg.gb, gNfcip.cfg.gbLen ); /* set General Bytes */ txBufIt += gNfcip.cfg.gbLen; } else { *(paylBuf + 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( (paylBuf), 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 == 0) && nfcipIsEmptyDEPDisabled(gNfcip.cfg.oper) && nfcip_PFBisIPDU(pfb) ) { return ERR_PARAM; } break; /*******************************************************************************/ default: return ERR_PARAM; } /*******************************************************************************/ /* Prepend Header */ /*******************************************************************************/ *(--txBlock) = (uint8_t)cmd; /* CMD */ *(--txBlock) = ( nfcipCmdIsReq(cmd) ? NFCIP_REQ : NFCIP_RES ); /* CMDType */ txBufIt += paylLen + (paylBuf - 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } /* ****************************************************************************** * GLOBAL FUNCTIONS ****************************************************************************** */ /*******************************************************************************/ static void nfcipConfig( rfalNfcDepConfigs cfg ) { 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, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { 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), mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; switch( ERR_NO_MASK(ret) ) { case ERR_PARAM: default: gNfcip.state = NFCIP_ST_INIT_DEP_IDLE; return ret; case ERR_NONE: gNfcip.state = NFCIP_ST_INIT_DEP_RX; } /* fall through */ /*******************************************************************************/ case NFCIP_ST_INIT_DEP_RX: ret = nfcipDataRx(); if( ret != ERR_NO_MASK(ERR_BUSY) ) { ret = nfcipInitiatorHandleDEP( ret, *gNfcip.rxRcvdLen, outActRxLen, outIsChaining, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } 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++ > NFCIP_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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /* 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; /* 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( ERR_NO_MASK(ret) ) { case ERR_PARAM: default: gNfcip.state = NFCIP_ST_TARG_DEP_IDLE; /* Upon Tx error, goto IDLE state */ return ret; case ERR_NONE: gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* All OK, goto Rx state */ } /* fall through */ /*******************************************************************************/ case NFCIP_ST_TARG_DEP_RX: 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(); } if( ret != ERR_NO_MASK(ERR_BUSY) ) { ret = nfcipTargetHandleRX( ret, outActRxLen, outIsChaining, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } break; /*******************************************************************************/ default: 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; gNfcip.RTOXTimer = 0; nfcipClearCounters(); } /*******************************************************************************/ static void nfcipSetDEPParams( 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 > 0) { /* 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( 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++) != NFCIP_CMD_ATR_REQ ) { return false; } /* Output NFID2 if requested */ if( nfcid3 != NULL ) { ST_MEMCPY( nfcid3, (uint8_t*)(buf + RFAL_NFCDEP_ATR_REQ_NFCID3_POS), RFAL_NFCDEP_NFCID3_LEN ); } return true; } /*******************************************************************************/ static ReturnCode nfcipTargetHandleActivation( rfalNfcDepDevice *nfcDepDev, uint8_t *outBRS, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { 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(); 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) == 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 */ 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 ); } EXIT_ON_ERR( ret, nfcipTx( NFCIP_CMD_PSL_RES, txBuf, 0, 0, 0, NFCIP_NO_FWT, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); } else { if( *(gNfcip.rxBuf + msgIt) == 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) ) != 0 ) { 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; } } /* 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( rfalNfcDepAtrParam* param, rfalNfcDepAtrRes *atrRes, uint8_t* atrResLen, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode ret; rfalNfcDepConfigs cfg; uint16_t rxLen; uint8_t msgIt; 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; ST_MEMCPY( cfg.gb, param->GB, cfg.gbLen ); cfg.nfcidLen = param->nfcidLen; ST_MEMCPY( cfg.nfcid, param->nfcid, param->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, NFCIP_RWT_ACTIVATION, NULL, 0, rxBuf, NFCIP_ATRRES_BUF_LEN, &rxLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /*******************************************************************************/ /* 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++) != NFCIP_CMD_ATR_RES ) /* Checking if is a ATR RES */ { return ERR_PROTO; } ST_MEMCPY(atrRes, (rxBuf + RFAL_NFCDEP_LEN_LEN), rxLen); *atrResLen = (uint8_t)rxLen; return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepPSL( uint8_t BRS, uint8_t FSL, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode ret; uint16_t rxLen; uint8_t msgIt; msgIt = 0; //changed here in plsbufPSL pslBufPSL[msgIt++] = BRS; pslBufPSL[msgIt++] = FSL; /*******************************************************************************/ /* Send PSL REQ and wait for response */ /*******************************************************************************/ EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_PSL_REQ, txBufPSL, NFCIP_RWT_ACTIVATION, pslBufPSL, msgIt, rxBufPSL, NFCIP_PSLRES_LEN, &rxLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /*******************************************************************************/ /* 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++) != 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( SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode ret; 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, txBufDSL, NFCIP_RWT_ACTIVATION, 0, 0, rxBufDSL, RFAL_NFCDEP_ATRRES_MAX_LEN, &rxLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /*******************************************************************************/ 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++) != NFCIP_CMD_DSL_RES ) /* Checking if is DSL RES */ { return ERR_PROTO; } if( (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) && (*(rxBuf + rxMsgIt++) != gNfcip.cfg.did ) ) { return ERR_PROTO; } return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepRLS( SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode ret; uint8_t rxMsgIt; uint16_t rxLen = 0; if( gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET ) return ERR_NONE; /* Target has no release procedure */ /* Repeating a RLS REQ is optional, not doing it */ EXIT_ON_ERR( ret, nfcipTxRx( NFCIP_CMD_RLS_REQ, txBufRLS, NFCIP_RWT_ACTIVATION, 0, 0, rxBufRLS, RFAL_NFCDEP_ATRRES_MAX_LEN, &rxLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /*******************************************************************************/ 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++) != NFCIP_CMD_RLS_RES ) /* Checking if is RLS RES */ { return ERR_PROTO; } if( (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) && (*(rxBuf + rxMsgIt++) != gNfcip.cfg.did ) ) { return ERR_PROTO; } return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepInitiatorHandleActivation( rfalNfcDepAtrParam* param, rfalBitRate desiredBR, rfalNfcDepDevice* nfcDepDev, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; if( nfcipIsTransmissionError(ret) ) { continue; } break; } while( (maxRetyrs--) ); if( ERR_NO_MASK(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 = rfalNfcDepCalculateRWT( 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 */ #if 0 /* Activity 1.0 * 9.4.6.3 NFC-F NFC-DEP Activation * 9.4.4.15 NFC-A NFC-DEP Activation * * PSL_REQ shall only be sent if desired bit rate is different from current * */ /*******************************************************************************/ /* 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) && nfcipDxIsSupported( desiredBR, nfcDepDev->activation.Target.ATR_RES.BRt, nfcDepDev->activation.Target.ATR_RES.BSt )) /* if desired BR is different and supported */ /* || (target->brt != RFAL_NFCDEP_Bx_NO_HIGH_BR) || (target->bst != RFAL_NFCDEP_Bx_NO_HIGH_BR) */ ) /* if target supports higher BR, must send PSL? */ { 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); /* 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; #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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } 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 */ wt = MIN( RFAL_NFCDEP_WT_INI_MAX, wt ); return rfalNfcDepWT2RWT(wt); } /*******************************************************************************/ static ReturnCode nfcipDataTx( uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { return rfalTransceiveBlockingTx( txBuf, txBufLen, gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen, (RFAL_TXRX_FLAGS_DEFAULT | RFAL_TXRX_FLAGS_NFCIP1_ON), ((fwt == NFCIP_NO_FWT) ? RFAL_FWT_NONE : rfalConv64fcTo1fc(fwt)), mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } /*******************************************************************************/ static ReturnCode nfcipDataRx( void ) { ReturnCode ret; ret = rfalGetTransceiveStatus(); if( ret != ERR_BUSY ) { (*gNfcip.rxRcvdLen) = rfalConvBitsToBytes( *gNfcip.rxRcvdLen ); if( (ret == ERR_NONE) && (gNfcip.rxRcvdLen != NULL) && (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( rfalNfcDepTargetParam *param, uint8_t *atrReq, uint16_t atrReqLength, rfalNfcDepListenActvParam rxParam, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { 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 = atrReqLength; /* nfcipIsAtrReq() is already checking Min and Max buffer lengths */ ST_MEMCPY( (uint8_t*)&rxParam.nfcDepDev->activation.Initiator.ATR_REQ, atrReq, atrReqLength ); rxParam.nfcDepDev->info.GBLen = (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; 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); gNfcip.state = NFCIP_ST_TARG_WAIT_ACTV; return ERR_NONE; } /*******************************************************************************/ ReturnCode rfalNfcDepListenGetActivationStatus( SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { ReturnCode err; uint8_t BRS; BRS = RFAL_NFCDEP_BRS_MAINTAIN; err = nfcipTargetHandleActivation( gNfcip.nfcDepDev, &BRS, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); } 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); } } 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( 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( SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) { return nfcipRun( gNfcip.rxRcvdLen, gNfcip.isChaining, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; } #endif /* RFAL_FEATURE_NFC_DEP */