Fork of the GitHub
Diff: rfal_nfcDep.cpp
- Revision:
- 0:75fc82583a41
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rfal_nfcDep.cpp Thu Nov 14 14:34:50 2019 +0000 @@ -0,0 +1,2488 @@ + +/****************************************************************************** + * @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 */