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