2020-10-18 22:09:48 +00:00
/******************************************************************************
* \ attention
*
* < h2 > < center > & copy ; 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 : ST25R3916 firmware
* Revision :
* LANGUAGE : ISO C99
*/
/*! \file
*
* \ author Gustavo Patricio
*
* \ brief RF Abstraction Layer ( RFAL )
*
* RFAL implementation for ST25R3916
*/
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* INCLUDES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
# include "rfal_chip.h"
# include "utils.h"
# include "st25r3916.h"
# include "st25r3916_com.h"
# include "st25r3916_irq.h"
# include "rfal_analogConfig.h"
# include "rfal_iso15693_2.h"
# include "rfal_crc.h"
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENABLE SWITCHS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
# ifndef RFAL_FEATURE_LISTEN_MODE
# define RFAL_FEATURE_LISTEN_MODE false /* Listen Mode configuration missing. Disabled by default */
# endif /* RFAL_FEATURE_LISTEN_MODE */
# ifndef RFAL_FEATURE_WAKEUP_MODE
# define RFAL_FEATURE_WAKEUP_MODE false /* Wake-Up mode configuration missing. Disabled by default */
# endif /* RFAL_FEATURE_WAKEUP_MODE */
# ifndef RFAL_FEATURE_LOWPOWER_MODE
# define RFAL_FEATURE_LOWPOWER_MODE false /* Low Power mode configuration missing. Disabled by default */
# endif /* RFAL_FEATURE_LOWPOWER_MODE */
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* GLOBAL TYPES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*! Struct that holds all involved on a Transceive including the context passed by the caller */
typedef struct {
rfalTransceiveState state ; /*!< Current transceive state */
rfalTransceiveState lastState ; /*!< Last transceive state (debug purposes) */
ReturnCode status ; /*!< Current status/error of the transceive */
rfalTransceiveContext ctx ; /*!< The transceive context given by the caller */
} rfalTxRx ;
/*! Struct that holds all context for the Listen Mode */
typedef struct {
rfalLmState state ; /*!< Current Listen Mode state */
uint32_t mdMask ; /*!< Listen Mode mask used */
uint32_t mdReg ; /*!< Listen Mode register value used */
uint32_t mdIrqs ; /*!< Listen Mode IRQs used */
rfalBitRate brDetected ; /*!< Last bit rate detected */
uint8_t * rxBuf ; /*!< Location to store incoming data in Listen Mode */
uint16_t rxBufLen ; /*!< Length of rxBuf */
uint16_t * rxLen ; /*!< Pointer to write the data length placed into rxBuf */
bool dataFlag ; /*!< Listen Mode current Data Flag */
bool iniFlag ; /*!< Listen Mode initialized Flag (FeliCa slots) */
} rfalLm ;
/*! Struct that holds all context for the Wake-Up Mode */
typedef struct {
rfalWumState state ; /*!< Current Wake-Up Mode state */
rfalWakeUpConfig cfg ; /*!< Current Wake-Up Mode context */
} rfalWum ;
/*! Struct that holds all context for the Low Power Mode */
typedef struct {
bool isRunning ;
} rfalLpm ;
/*! Struct that holds the timings GT and FDTs */
typedef struct {
uint32_t GT ; /*!< GT in 1/fc */
uint32_t FDTListen ; /*!< FDTListen in 1/fc */
uint32_t FDTPoll ; /*!< FDTPoll in 1/fc */
uint8_t nTRFW ; /*!< n*TRFW used during RF CA */
} rfalTimings ;
/*! Struct that holds the software timers */
typedef struct {
uint32_t GT ; /*!< RFAL's GT timer */
uint32_t RXE ; /*!< Timer between RXS and RXE */
uint32_t txRx ; /*!< Transceive sanity timer */
} rfalTimers ;
/*! Struct that holds the RFAL's callbacks */
typedef struct {
rfalPreTxRxCallback preTxRx ; /*!< RFAL's Pre TxRx callback */
rfalPostTxRxCallback postTxRx ; /*!< RFAL's Post TxRx callback */
} rfalCallbacks ;
/*! Struct that holds counters to control the FIFO on Tx and Rx */
typedef struct {
uint16_t expWL ; /*!< The amount of bytes expected to be Tx when a WL interrupt occours */
uint16_t bytesTotal ; /*!< Total bytes to be transmitted OR the total bytes received */
uint16_t bytesWritten ; /*!< Amount of bytes already written on FIFO (Tx) OR read (RX) from FIFO and written on rxBuffer*/
uint8_t status [ ST25R3916_FIFO_STATUS_LEN ] ; /*!< FIFO Status Registers */
} rfalFIFO ;
/*! Struct that holds RFAL's configuration settings */
typedef struct {
uint8_t obsvModeTx ; /*!< RFAL's config of the ST25R3916's observation mode while Tx */
uint8_t obsvModeRx ; /*!< RFAL's config of the ST25R3916's observation mode while Rx */
rfalEHandling eHandling ; /*!< RFAL's error handling config/mode */
} rfalConfigs ;
/*! Struct that holds NFC-F data - Used only inside rfalFelicaPoll() (static to avoid adding it into stack) */
typedef struct {
rfalFeliCaPollRes pollResponses [ RFAL_FELICA_POLL_MAX_SLOTS ] ; /* FeliCa Poll response container for 16 slots */
} rfalNfcfWorkingData ;
/*! Struct that holds NFC-V current context
*
* This buffer has to be big enough for coping with maximum response size ( hamming coded )
* - inventory requests responses : 14 * 2 + 2 bytes
* - read single block responses : ( 32 + 4 ) * 2 + 2 bytes
* - read multiple block could be very long . . . - > not supported
* - current implementation expects it be written in one bulk into FIFO
* - needs to be above FIFO water level of ST25R3916 ( 200 )
* - the coding function needs to be able to
* put more than FIFO water level bytes into it ( n * 64 + 1 ) > 200 */
typedef struct {
uint8_t codingBuffer [ ( ( 2 + 255 + 3 ) * 2 ) ] ; /*!< Coding buffer, length MUST be above 257: [257; ...] */
uint16_t nfcvOffset ; /*!< Offset needed for ISO15693 coding function */
rfalTransceiveContext origCtx ; /*!< context provided by user */
uint16_t ignoreBits ; /*!< Number of bits at the beginning of a frame to be ignored when decoding */
} rfalNfcvWorkingData ;
/*! RFAL instance */
typedef struct {
rfalState state ; /*!< RFAL's current state */
rfalMode mode ; /*!< RFAL's current mode */
rfalBitRate txBR ; /*!< RFAL's current Tx Bit Rate */
rfalBitRate rxBR ; /*!< RFAL's current Rx Bit Rate */
bool field ; /*!< Current field state (On / Off) */
rfalConfigs conf ; /*!< RFAL's configuration settings */
rfalTimings timings ; /*!< RFAL's timing setting */
rfalTxRx TxRx ; /*!< RFAL's transceive management */
rfalFIFO fifo ; /*!< RFAL's FIFO management */
rfalTimers tmr ; /*!< RFAL's Software timers */
rfalCallbacks callbacks ; /*!< RFAL's callbacks */
# if RFAL_FEATURE_LISTEN_MODE
rfalLm Lm ; /*!< RFAL's listen mode management */
# endif /* RFAL_FEATURE_LISTEN_MODE */
# if RFAL_FEATURE_WAKEUP_MODE
rfalWum wum ; /*!< RFAL's Wake-up mode management */
# endif /* RFAL_FEATURE_WAKEUP_MODE */
# if RFAL_FEATURE_LOWPOWER_MODE
rfalLpm lpm ; /*!< RFAL's Low power mode management */
# endif /* RFAL_FEATURE_LOWPOWER_MODE */
# if RFAL_FEATURE_NFCF
rfalNfcfWorkingData nfcfData ; /*!< RFAL's working data when supporting NFC-F */
# endif /* RFAL_FEATURE_NFCF */
# if RFAL_FEATURE_NFCV
rfalNfcvWorkingData nfcvData ; /*!< RFAL's working data when performing NFC-V */
# endif /* RFAL_FEATURE_NFCV */
} rfal ;
/*! Felica's command set */
typedef enum
{
FELICA_CMD_POLLING = 0x00 , /*!< Felica Poll/REQC command (aka SENSF_REQ) to identify a card */
FELICA_CMD_POLLING_RES = 0x01 , /*!< Felica Poll/REQC command (aka SENSF_RES) response */
FELICA_CMD_REQUEST_SERVICE = 0x02 , /*!< verify the existence of Area and Service */
FELICA_CMD_REQUEST_RESPONSE = 0x04 , /*!< verify the existence of a card */
FELICA_CMD_READ_WITHOUT_ENCRYPTION = 0x06 , /*!< read Block Data from a Service that requires no authentication */
FELICA_CMD_WRITE_WITHOUT_ENCRYPTION = 0x08 , /*!< write Block Data to a Service that requires no authentication */
FELICA_CMD_REQUEST_SYSTEM_CODE = 0x0C , /*!< acquire the System Code registered to a card */
FELICA_CMD_AUTHENTICATION1 = 0x10 , /*!< authenticate a card */
FELICA_CMD_AUTHENTICATION2 = 0x12 , /*!< allow a card to authenticate a Reader/Writer */
FELICA_CMD_READ = 0x14 , /*!< read Block Data from a Service that requires authentication */
FELICA_CMD_WRITE = 0x16 , /*!< write Block Data to a Service that requires authentication */
} t_rfalFeliCaCmd ;
/*! Union representing all PTMem sections */
typedef union { /* PRQA S 0750 # MISRA 19.2 - Both members are of the same type, just different names. Thus no problem can occur. */
uint8_t PTMem_A [ ST25R3916_PTM_A_LEN ] ; /*!< PT_Memory area allocated for NFC-A configuration */
uint8_t PTMem_F [ ST25R3916_PTM_F_LEN ] ; /*!< PT_Memory area allocated for NFC-F configuration */
uint8_t TSN [ ST25R3916_PTM_TSN_LEN ] ; /*!< PT_Memory area allocated for TSN - Random numbers */
} t_rfalPTMem ;
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* GLOBAL DEFINES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
# define RFAL_FIFO_IN_WL 200U /*!< Number of bytes in the FIFO when WL interrupt occurs while Tx */
# define RFAL_FIFO_OUT_WL (ST25R3916_FIFO_DEPTH - RFAL_FIFO_IN_WL) /*!< Number of bytes sent/out of the FIFO when WL interrupt occurs while Tx */
# define RFAL_FIFO_STATUS_REG1 0U /*!< Location of FIFO status register 1 in local copy */
# define RFAL_FIFO_STATUS_REG2 1U /*!< Location of FIFO status register 2 in local copy */
# define RFAL_FIFO_STATUS_INVALID 0xFFU /*!< Value indicating that the local FIFO status in invalid|cleared */
# define RFAL_ST25R3916_GPT_MAX_1FC rfalConv8fcTo1fc( 0xFFFFU ) /*!< Max GPT steps in 1fc (0xFFFF steps of 8/fc => 0xFFFF * 590ns = 38,7ms) */
# define RFAL_ST25R3916_NRT_MAX_1FC rfalConv4096fcTo1fc( 0xFFFFU ) /*!< Max NRT steps in 1fc (0xFFFF steps of 4096/fc => 0xFFFF * 302us = 19.8s ) */
# define RFAL_ST25R3916_NRT_DISABLED 0U /*!< NRT Disabled: All 0 No-response timer is not started, wait forever */
# define RFAL_ST25R3916_MRT_MAX_1FC rfalConv64fcTo1fc( 0x00FFU ) /*!< Max MRT steps in 1fc (0x00FF steps of 64/fc => 0x00FF * 4.72us = 1.2ms ) */
# define RFAL_ST25R3916_MRT_MIN_1FC rfalConv64fcTo1fc( 0x0004U ) /*!< Min MRT steps in 1fc ( 0<=mrt<=4 ; 4 (64/fc) => 0x0004 * 4.72us = 18.88us ) */
# define RFAL_ST25R3916_GT_MAX_1FC rfalConvMsTo1fc( 6000U ) /*!< Max GT value allowed in 1/fc (SFGI=14 => SFGT + dSFGT = 5.4s) */
# define RFAL_ST25R3916_GT_MIN_1FC rfalConvMsTo1fc(RFAL_ST25R3916_SW_TMR_MIN_1MS) /*!< Min GT value allowed in 1/fc */
# define RFAL_ST25R3916_SW_TMR_MIN_1MS 1U /*!< Min value of a SW timer in ms */
# define RFAL_OBSMODE_DISABLE 0x00U /*!< Observation Mode disabled */
# define RFAL_RX_INCOMPLETE_MAXLEN (uint8_t)1U /*!< Threshold value where incoming rx may be considered as incomplete */
# define RFAL_EMVCO_RX_MAXLEN (uint8_t)4U /*!< Maximum value where EMVCo to apply special error handling */
# define RFAL_NORXE_TOUT 50U /*!< Timeout to be used on a potential missing RXE - Silicon ST25R3916 Errata #TBD */
# define RFAL_ISO14443A_SDD_RES_LEN 5U /*!< SDD_RES | Anticollision (UID CLn) length - rfalNfcaSddRes */
# define RFAL_ISO14443A_CRC_INTVAL 0x6363 /*!< ISO14443 CRC Initial Value|Register */
# define RFAL_FELICA_POLL_DELAY_TIME 512U /*!< FeliCa Poll Processing time is 2.417 ms ~512*64/fc Digital 1.1 A4 */
# define RFAL_FELICA_POLL_SLOT_TIME 256U /*!< FeliCa Poll Time Slot duration is 1.208 ms ~256*64/fc Digital 1.1 A4 */
# define RFAL_LM_SENSF_RD0_POS 17U /*!< FeliCa SENSF_RES Request Data RD0 position */
# define RFAL_LM_SENSF_RD1_POS 18U /*!< FeliCa SENSF_RES Request Data RD1 position */
# define RFAL_LM_NFCID_INCOMPLETE 0x04U /*!< NFCA NFCID not complete bit in SEL_RES (SAK) */
# define RFAL_ISO15693_IGNORE_BITS rfalConvBytesToBits(2U) /*!< Ignore collisions before the UID (RES_FLAG + DSFID) */
# define RFAL_ISO15693_INV_RES_LEN 12U /*!< ISO15693 Inventory response length with CRC (bytes) */
# define RFAL_ISO15693_INV_RES_DUR 4U /*!< ISO15693 Inventory response duration @ 26 kbps (ms) */
# define RFAL_WU_MIN_WEIGHT_VAL 4U /*!< ST25R3916 minimum Wake-up weight value */
/*******************************************************************************/
# define RFAL_LM_GT rfalConvUsTo1fc(100U) /*!< Listen Mode Guard Time enforced (GT - Passive; TIRFG - Active) */
# define RFAL_FDT_POLL_ADJUSTMENT rfalConvUsTo1fc(80U) /*!< FDT Poll adjustment: Time between the expiration of GPT to the actual Tx */
# define RFAL_FDT_LISTEN_MRT_ADJUSTMENT 64U /*!< MRT jitter adjustment: timeout will be between [ tout ; tout + 64 cycles ] */
# define RFAL_AP2P_FIELDOFF_TRFW rfalConv8fcTo1fc(64U) /*!< Time after TXE and Field Off in AP2P Trfw: 37.76us -> 64 (8/fc) */
# ifndef RFAL_ST25R3916_AAT_SETTLE
# define RFAL_ST25R3916_AAT_SETTLE 5U /*!< Time in ms required for AAT pins and Osc to settle after en bit set */
# endif /* RFAL_ST25R3916_AAT_SETTLE */
/*! FWT adjustment:
* 64 : NRT jitter between TXE and NRT start */
# define RFAL_FWT_ADJUSTMENT 64U
/*! FWT ISO14443A adjustment:
* 512 : 4 bit length
* 64 : Half a bit duration due to ST25R3916 Coherent receiver ( 1 / fc ) */
# define RFAL_FWT_A_ADJUSTMENT (512U + 64U)
/*! FWT ISO14443B adjustment:
* SOF ( 14 etu ) + 1 Byte ( 10 etu ) + 1 etu ( IRQ comes 1 etu after first byte ) - 3 etu ( ST25R3916 sends TXE 3 etu after ) */
# define RFAL_FWT_B_ADJUSTMENT ((14U + 10U + 1U - 3U) * 128U)
/*! FWT FeliCa 212 adjustment:
* 1024 : Length of the two Sync bytes at 212 kbps */
# define RFAL_FWT_F_212_ADJUSTMENT 1024U
/*! FWT FeliCa 424 adjustment:
* 512 : Length of the two Sync bytes at 424 kbps */
# define RFAL_FWT_F_424_ADJUSTMENT 512U
/*! Time between our field Off and other peer field On : Tadt + (n x Trfw)
* Ecma 340 11.1 .2 - Tadt : [ 56.64 , 188.72 ] us ; n : [ 0 , 3 ] ; Trfw = 37.76 us
* Should be : 189 + ( 3 * 38 ) = 303u s ; we ' ll use a more relaxed setting : 605 us */
# define RFAL_AP2P_FIELDON_TADTTRFW rfalConvUsTo1fc(605U)
/*! FDT Listen adjustment for ISO14443A EMVCo 2.6 4.8.1.3 ; Digital 1.1 6.10
*
* 276 : Time from the rising pulse of the pause of the logic ' 1 ' ( i . e . the time point to measure the deaftime from ) ,
* to the actual end of the EOF sequence ( the point where the MRT starts ) . Please note that the ST25R391x uses the
* ISO14443 - 2 definition where the EOF consists of logic ' 0 ' followed by sequence Y .
* - 64 : Further adjustment for receiver to be ready just before first bit
*/
# define RFAL_FDT_LISTEN_A_ADJUSTMENT (276U-64U)
/*! FDT Listen adjustment for ISO14443B EMVCo 2.6 4.8.1.6 ; Digital 1.1 7.9
*
* 340 : Time from the rising edge of the EoS to the starting point of the MRT timer ( sometime after the final high
* part of the EoS is completed )
*/
# define RFAL_FDT_LISTEN_B_ADJUSTMENT 340U
/*! FDT Listen adjustment for ISO15693
* ISO15693 2000 8.4 t1 MIN = 4192 / fc
* ISO15693 2009 9.1 t1 MIN = 4320 / fc
* Digital 2.1 B .5 FDTV , LISTEN , MIN = 4310 / fc
* Set FDT Listen one step earlier than on the more recent spec versions for greater interoprability
*/
# define RFAL_FDT_LISTEN_V_ADJUSTMENT 64U
/*! FDT Poll adjustment for ISO14443B Correlator - sst 5 etu */
# define RFAL_FDT_LISTEN_B_ADJT_CORR 128U
/*! FDT Poll adjustment for ISO14443B Correlator sst window - 5 etu */
# define RFAL_FDT_LISTEN_B_ADJT_CORR_SST 20U
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* GLOBAL MACROS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*! Calculates Transceive Sanity Timer. It accounts for the slowest bit rate and the longest data format
* 1 s for transmission and reception of a 4 K message at 106 kpbs ( ~ 425 ms each direction )
* plus TxRx preparation and FIFO load over Serial Interface */
# define rfalCalcSanityTmr( fwt ) (uint16_t)(1000U + rfalConv1fcToMs((fwt)))
# define rfalGennTRFW( n ) (((n)+1U)&ST25R3916_REG_AUX_nfc_n_mask) /*!< Generates the next n*TRRW used for RFCA */
# define rfalCalcNumBytes( nBits ) (((uint32_t)(nBits) + 7U) / 8U) /*!< Returns the number of bytes required to fit given the number of bits */
# define rfalTimerStart( timer, time_ms ) do{ platformTimerDestroy( timer ); (timer) = platformTimerCreate((uint16_t)(time_ms)); } while(0) /*!< Configures and starts timer */
# define rfalTimerisExpired( timer ) platformTimerIsExpired( timer ) /*!< Checks if timer has expired */
# define rfalTimerDestroy( timer ) platformTimerDestroy( timer ) /*!< Destroys timer */
# define rfalST25R3916ObsModeDisable() st25r3916WriteTestRegister(0x01U, (0x40U)) /*!< Disable ST25R3916 Observation mode */
# define rfalST25R3916ObsModeTx() st25r3916WriteTestRegister(0x01U, (0x40U|gRFAL.conf.obsvModeTx)) /*!< Enable Tx Observation mode */
# define rfalST25R3916ObsModeRx() st25r3916WriteTestRegister(0x01U, (0x40U|gRFAL.conf.obsvModeRx)) /*!< Enable Rx Observation mode */
# define rfalCheckDisableObsMode() if(gRFAL.conf.obsvModeRx != 0U){ rfalST25R3916ObsModeDisable(); } /*!< Checks if the observation mode is enabled, and applies on ST25R3916 */
# define rfalCheckEnableObsModeTx() if(gRFAL.conf.obsvModeTx != 0U){ rfalST25R3916ObsModeTx(); } /*!< Checks if the observation mode is enabled, and applies on ST25R3916 */
# define rfalCheckEnableObsModeRx() if(gRFAL.conf.obsvModeRx != 0U){ rfalST25R3916ObsModeRx(); } /*!< Checks if the observation mode is enabled, and applies on ST25R3916 */
# define rfalGetIncmplBits( FIFOStatus2 ) (( (FIFOStatus2) >> 1) & 0x07U) /*!< Returns the number of bits from fifo status */
# define rfalIsIncompleteByteError( error ) (((error) >= ERR_INCOMPLETE_BYTE) && ((error) <= ERR_INCOMPLETE_BYTE_07)) /*!< Checks if given error is a Incomplete error */
# define rfalAdjACBR( b ) (((uint16_t)(b) >= (uint16_t)RFAL_BR_52p97) ? (uint16_t)(b) : ((uint16_t)(b)+1U)) /*!< Adjusts ST25R391x Bit rate to Analog Configuration */
# define rfalConvBR2ACBR( b ) (((rfalAdjACBR((b)))<<RFAL_ANALOG_CONFIG_BITRATE_SHIFT) & RFAL_ANALOG_CONFIG_BITRATE_MASK) /*!< Converts ST25R391x Bit rate to Analog Configuration bit rate id */
# define rfalConvTDFormat( v ) ((uint16_t)(v) << 8U) /*!< Converts a uint8_t to the format used in SW Tag Detection */
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* LOCAL VARIABLES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
static rfal gRFAL ; /*!< RFAL module instance */
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* LOCAL FUNCTION PROTOTYPES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
static void rfalTransceiveTx ( void ) ;
static void rfalTransceiveRx ( void ) ;
static ReturnCode rfalTransceiveRunBlockingTx ( void ) ;
static void rfalPrepareTransceive ( void ) ;
static void rfalCleanupTransceive ( void ) ;
static void rfalErrorHandling ( void ) ;
static ReturnCode rfalRunTransceiveWorker ( void ) ;
# if RFAL_FEATURE_LISTEN_MODE
static ReturnCode rfalRunListenModeWorker ( void ) ;
# endif /* RFAL_FEATURE_LISTEN_MODE */
# if RFAL_FEATURE_WAKEUP_MODE
static void rfalRunWakeUpModeWorker ( void ) ;
static uint16_t rfalWakeUpModeFilter ( uint16_t curRef , uint16_t curVal , uint8_t weight ) ;
# endif /* RFAL_FEATURE_WAKEUP_MODE */
static void rfalFIFOStatusUpdate ( void ) ;
static void rfalFIFOStatusClear ( void ) ;
static bool rfalFIFOStatusIsMissingPar ( void ) ;
static bool rfalFIFOStatusIsIncompleteByte ( void ) ;
static uint16_t rfalFIFOStatusGetNumBytes ( void ) ;
static uint8_t rfalFIFOGetNumIncompleteBits ( void ) ;
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* GLOBAL FUNCTIONS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*******************************************************************************/
ReturnCode rfalInitialize ( void )
{
ReturnCode err ;
EXIT_ON_ERR ( err , st25r3916Initialize ( ) ) ;
st25r3916ClearInterrupts ( ) ;
/* Disable any previous observation mode */
rfalST25R3916ObsModeDisable ( ) ;
/*******************************************************************************/
/* Apply RF Chip generic initialization */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_INIT ) ) ;
2020-11-18 13:01:25 +00:00
// TODO:
// I don't want to mess with config table ("Default Analog Configuration for Chip-Specific Reset", rfal_analogConfigTbl.h)
// so with every rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_CHIP_INIT)) currently we need to clear pulldown bits
// luckily for us this is done only here
// disable pulldowns
st25r3916ClrRegisterBits ( ST25R3916_REG_IO_CONF2 , ( ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2 ) ) ;
2020-10-18 22:09:48 +00:00
/*******************************************************************************/
/* Enable External Field Detector as: Automatics */
st25r3916ChangeRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_en_fd_mask , ST25R3916_REG_OP_CONTROL_en_fd_auto_efd ) ;
/* Clear FIFO status local copy */
rfalFIFOStatusClear ( ) ;
/*******************************************************************************/
gRFAL . state = RFAL_STATE_INIT ;
gRFAL . mode = RFAL_MODE_NONE ;
gRFAL . field = false ;
/* Set RFAL default configs */
gRFAL . conf . obsvModeRx = RFAL_OBSMODE_DISABLE ;
gRFAL . conf . obsvModeTx = RFAL_OBSMODE_DISABLE ;
gRFAL . conf . eHandling = RFAL_ERRORHANDLING_NONE ;
/* Transceive set to IDLE */
gRFAL . TxRx . lastState = RFAL_TXRX_STATE_IDLE ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_IDLE ;
/* Disable all timings */
gRFAL . timings . FDTListen = RFAL_TIMING_NONE ;
gRFAL . timings . FDTPoll = RFAL_TIMING_NONE ;
gRFAL . timings . GT = RFAL_TIMING_NONE ;
gRFAL . timings . nTRFW = 0U ;
/* Destroy any previous pending timers */
rfalTimerDestroy ( gRFAL . tmr . GT ) ;
rfalTimerDestroy ( gRFAL . tmr . txRx ) ;
rfalTimerDestroy ( gRFAL . tmr . RXE ) ;
gRFAL . tmr . GT = RFAL_TIMING_NONE ;
gRFAL . tmr . txRx = RFAL_TIMING_NONE ;
gRFAL . tmr . RXE = RFAL_TIMING_NONE ;
gRFAL . callbacks . preTxRx = NULL ;
gRFAL . callbacks . postTxRx = NULL ;
# if RFAL_FEATURE_NFCV
/* Initialize NFC-V Data */
gRFAL . nfcvData . ignoreBits = 0 ;
# endif /* RFAL_FEATURE_NFCV */
# if RFAL_FEATURE_LISTEN_MODE
/* Initialize Listen Mode */
gRFAL . Lm . state = RFAL_LM_STATE_NOT_INIT ;
gRFAL . Lm . brDetected = RFAL_BR_KEEP ;
gRFAL . Lm . iniFlag = false ;
# endif /* RFAL_FEATURE_LISTEN_MODE */
# if RFAL_FEATURE_WAKEUP_MODE
/* Initialize Wake-Up Mode */
gRFAL . wum . state = RFAL_WUM_STATE_NOT_INIT ;
# endif /* RFAL_FEATURE_WAKEUP_MODE */
# if RFAL_FEATURE_LOWPOWER_MODE
/* Initialize Low Power Mode */
gRFAL . lpm . isRunning = false ;
# endif /* RFAL_FEATURE_LOWPOWER_MODE */
/*******************************************************************************/
/* Perform Automatic Calibration (if configured to do so). *
* Registers set by rfalSetAnalogConfig will tell rfalCalibrate what to perform */
rfalCalibrate ( ) ;
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalCalibrate ( void )
{
uint16_t resValue ;
/* Check if RFAL is not initialized */
if ( gRFAL . state = = RFAL_STATE_IDLE )
{
return ERR_WRONG_STATE ;
}
/*******************************************************************************/
/* Perform ST25R3916 regulators and antenna calibration */
/*******************************************************************************/
/* Automatic regulator adjustment only performed if not set manually on Analog Configs */
if ( st25r3916CheckReg ( ST25R3916_REG_REGULATOR_CONTROL , ST25R3916_REG_REGULATOR_CONTROL_reg_s , 0x00 ) )
{
/* Adjust the regulators so that Antenna Calibrate has better Regulator values */
st25r3916AdjustRegulators ( & resValue ) ;
}
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalAdjustRegulators ( uint16_t * result )
{
return st25r3916AdjustRegulators ( result ) ;
}
/*******************************************************************************/
void rfalSetUpperLayerCallback ( rfalUpperLayerCallback pFunc )
{
st25r3916IRQCallbackSet ( pFunc ) ;
}
/*******************************************************************************/
void rfalSetPreTxRxCallback ( rfalPreTxRxCallback pFunc )
{
gRFAL . callbacks . preTxRx = pFunc ;
}
/*******************************************************************************/
void rfalSetPostTxRxCallback ( rfalPostTxRxCallback pFunc )
{
gRFAL . callbacks . postTxRx = pFunc ;
}
/*******************************************************************************/
ReturnCode rfalDeinitialize ( void )
{
/* Deinitialize chip */
st25r3916Deinitialize ( ) ;
/* Set Analog configurations for deinitialization */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_DEINIT ) ) ;
gRFAL . state = RFAL_STATE_IDLE ;
return ERR_NONE ;
}
/*******************************************************************************/
void rfalSetObsvMode ( uint8_t txMode , uint8_t rxMode )
{
gRFAL . conf . obsvModeTx = txMode ;
gRFAL . conf . obsvModeRx = rxMode ;
}
/*******************************************************************************/
void rfalGetObsvMode ( uint8_t * txMode , uint8_t * rxMode )
{
if ( txMode ! = NULL )
{
* txMode = gRFAL . conf . obsvModeTx ;
}
if ( rxMode ! = NULL )
{
* rxMode = gRFAL . conf . obsvModeRx ;
}
}
/*******************************************************************************/
void rfalDisableObsvMode ( void )
{
gRFAL . conf . obsvModeTx = RFAL_OBSMODE_DISABLE ;
gRFAL . conf . obsvModeRx = RFAL_OBSMODE_DISABLE ;
}
/*******************************************************************************/
ReturnCode rfalSetMode ( rfalMode mode , rfalBitRate txBR , rfalBitRate rxBR )
{
/* Check if RFAL is not initialized */
if ( gRFAL . state = = RFAL_STATE_IDLE )
{
return ERR_WRONG_STATE ;
}
/* Check allowed bit rate value */
if ( ( txBR = = RFAL_BR_KEEP ) | | ( rxBR = = RFAL_BR_KEEP ) )
{
return ERR_PARAM ;
}
switch ( mode )
{
/*******************************************************************************/
case RFAL_MODE_POLL_NFCA :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable ISO14443A mode */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_iso14443a ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCA_T1T :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable Topaz mode */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_topaz ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCB :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable ISO14443B mode */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_iso14443b ) ;
/* Set the EGT, SOF, EOF and EOF */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443B_1 ,
( ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask | ST25R3916_REG_ISO14443B_1_eof ) ,
( ( 0U < < ST25R3916_REG_ISO14443B_1_egt_shift ) | ST25R3916_REG_ISO14443B_1_sof_0_10etu | ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu ) ) ;
/* Set the minimum TR1, SOF, EOF and EOF12 */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443B_2 ,
( ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof | ST25R3916_REG_ISO14443B_2_no_eof ) ,
( ST25R3916_REG_ISO14443B_2_tr1_80fs80fs ) ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_B_PRIME :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable ISO14443B mode */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_iso14443b ) ;
/* Set the EGT, SOF, EOF and EOF */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443B_1 ,
( ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask | ST25R3916_REG_ISO14443B_1_eof ) ,
( ( 0U < < ST25R3916_REG_ISO14443B_1_egt_shift ) | ST25R3916_REG_ISO14443B_1_sof_0_10etu | ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu ) ) ;
/* Set the minimum TR1, EOF and EOF12 */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443B_2 ,
( ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof | ST25R3916_REG_ISO14443B_2_no_eof ) ,
( ST25R3916_REG_ISO14443B_2_tr1_80fs80fs | ST25R3916_REG_ISO14443B_2_no_sof ) ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_B_CTS :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable ISO14443B mode */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_iso14443b ) ;
/* Set the EGT, SOF, EOF and EOF */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443B_1 ,
( ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask | ST25R3916_REG_ISO14443B_1_eof ) ,
( ( 0U < < ST25R3916_REG_ISO14443B_1_egt_shift ) | ST25R3916_REG_ISO14443B_1_sof_0_10etu | ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu ) ) ;
/* Set the minimum TR1, clear SOF, EOF and EOF12 */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443B_2 ,
( ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof | ST25R3916_REG_ISO14443B_2_no_eof ) ,
( ST25R3916_REG_ISO14443B_2_tr1_80fs80fs | ST25R3916_REG_ISO14443B_2_no_sof | ST25R3916_REG_ISO14443B_2_no_eof ) ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCF :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable FeliCa mode */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_felica ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCV :
case RFAL_MODE_POLL_PICOPASS :
# if !RFAL_FEATURE_NFCV
return ERR_DISABLED ;
# else
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
# endif /* RFAL_FEATURE_NFCV */
/*******************************************************************************/
case RFAL_MODE_POLL_ACTIVE_P2P :
/* Set NFCIP1 active communication Initiator mode and Automatic Response RF Collision Avoidance to always after EOF */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_targ_init | ST25R3916_REG_MODE_om_nfc | ST25R3916_REG_MODE_nfc_ar_eof ) ) ;
/* External Field Detector enabled as Automatics on rfalInitialize() */
/* Set NRT to start at end of TX (own) field */
st25r3916ChangeRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc , ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_off ) ;
/* Set GPT to start after end of TX, as GPT is used in active communication mode to timeout the field switching off */
/* The field is turned off 37.76us after the end of the transmission Trfw */
st25r3916SetStartGPTimer ( ( uint16_t ) rfalConv1fcTo8fc ( RFAL_AP2P_FIELDOFF_TRFW ) , ST25R3916_REG_TIMER_EMV_CONTROL_gptc_etx_nfc ) ;
/* Set PPon2 timer with the max time between our field Off and other peer field On : Tadt + (n x Trfw) */
st25r3916WriteRegister ( ST25R3916_REG_PPON2 , ( uint8_t ) rfalConv1fcTo64fc ( RFAL_AP2P_FIELDON_TADTTRFW ) ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_ACTIVE_P2P :
/* Set NFCIP1 active communication Target mode and Automatic Response RF Collision Avoidance to always after EOF */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om_targ_nfcip | ST25R3916_REG_MODE_nfc_ar_eof ) ) ;
/* Set TARFG: 0 (75us+0ms=75us), as Target no Guard time needed */
st25r3916WriteRegister ( ST25R3916_REG_FIELD_ON_GT , 0U ) ;
/* External Field Detector enabled as Automatics on rfalInitialize() */
/* Set NRT to start at end of TX (own) field */
st25r3916ChangeRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc , ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_off ) ;
/* Set GPT to start after end of TX, as GPT is used in active communication mode to timeout the field switching off */
/* The field is turned off 37.76us after the end of the transmission Trfw */
st25r3916SetStartGPTimer ( ( uint16_t ) rfalConv1fcTo8fc ( RFAL_AP2P_FIELDOFF_TRFW ) , ST25R3916_REG_TIMER_EMV_CONTROL_gptc_etx_nfc ) ;
/* Set PPon2 timer with the max time between our field Off and other peer field On : Tadt + (n x Trfw) */
st25r3916WriteRegister ( ST25R3916_REG_PPON2 , ( uint8_t ) rfalConv1fcTo64fc ( RFAL_AP2P_FIELDON_TADTTRFW ) ) ;
/* Set Analog configurations for this mode and bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_NFCA :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable Passive Target NFC-A mode, disable any Collision Avoidance */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_targ_nfca | ST25R3916_REG_MODE_nfc_ar_off ) ) ;
/* Set Analog configurations for this mode */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_NFCF :
/* Disable wake up mode, if set */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
/* Enable Passive Target NFC-F mode, disable any Collision Avoidance */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_targ_nfcf | ST25R3916_REG_MODE_nfc_ar_off ) ) ;
/* Set Analog configurations for this mode */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_NFCB :
return ERR_NOTSUPP ;
/*******************************************************************************/
default :
return ERR_NOT_IMPLEMENTED ;
}
/* Set state as STATE_MODE_SET only if not initialized yet (PSL) */
gRFAL . state = ( ( gRFAL . state < RFAL_STATE_MODE_SET ) ? RFAL_STATE_MODE_SET : gRFAL . state ) ;
gRFAL . mode = mode ;
/* Apply the given bit rate */
return rfalSetBitRate ( txBR , rxBR ) ;
}
/*******************************************************************************/
rfalMode rfalGetMode ( void )
{
return gRFAL . mode ;
}
/*******************************************************************************/
ReturnCode rfalSetBitRate ( rfalBitRate txBR , rfalBitRate rxBR )
{
ReturnCode ret ;
/* Check if RFAL is not initialized */
if ( gRFAL . state = = RFAL_STATE_IDLE )
{
return ERR_WRONG_STATE ;
}
/* Store the new Bit Rates */
gRFAL . txBR = ( ( txBR = = RFAL_BR_KEEP ) ? gRFAL . txBR : txBR ) ;
gRFAL . rxBR = ( ( rxBR = = RFAL_BR_KEEP ) ? gRFAL . rxBR : rxBR ) ;
/* Update the bitrate reg if not in NFCV mode (streaming) */
if ( ( RFAL_MODE_POLL_NFCV ! = gRFAL . mode ) & & ( RFAL_MODE_POLL_PICOPASS ! = gRFAL . mode ) )
{
/* Set bit rate register */
EXIT_ON_ERR ( ret , st25r3916SetBitrate ( ( uint8_t ) gRFAL . txBR , ( uint8_t ) gRFAL . rxBR ) ) ;
}
switch ( gRFAL . mode )
{
/*******************************************************************************/
case RFAL_MODE_POLL_NFCA :
case RFAL_MODE_POLL_NFCA_T1T :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCB :
case RFAL_MODE_POLL_B_PRIME :
case RFAL_MODE_POLL_B_CTS :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCF :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_POLL_NFCV :
case RFAL_MODE_POLL_PICOPASS :
# if !RFAL_FEATURE_NFCV
return ERR_DISABLED ;
# else
if ( ( ( gRFAL . rxBR ! = RFAL_BR_26p48 ) & & ( gRFAL . rxBR ! = RFAL_BR_52p97 ) )
| | ( ( gRFAL . txBR ! = RFAL_BR_1p66 ) & & ( gRFAL . txBR ! = RFAL_BR_26p48 ) ) )
{
return ERR_PARAM ;
}
{
const struct iso15693StreamConfig * isoStreamConfig ;
struct st25r3916StreamConfig streamConf ;
iso15693PhyConfig_t config ;
config . coding = ( ( gRFAL . txBR = = RFAL_BR_1p66 ) ? ISO15693_VCD_CODING_1_256 : ISO15693_VCD_CODING_1_4 ) ;
switch ( gRFAL . rxBR ) {
case RFAL_BR_52p97 :
config . speedMode = 1 ;
break ;
default :
config . speedMode = 0 ;
break ;
}
iso15693PhyConfigure ( & config , & isoStreamConfig ) ;
/* MISRA 11.3 - Cannot point directly into different object type, copy to local var */
streamConf . din = isoStreamConfig - > din ;
streamConf . dout = isoStreamConfig - > dout ;
streamConf . report_period_length = isoStreamConfig - > report_period_length ;
streamConf . useBPSK = isoStreamConfig - > useBPSK ;
st25r3916StreamConfigure ( & streamConf ) ;
}
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
# endif /* RFAL_FEATURE_NFCV */
/*******************************************************************************/
case RFAL_MODE_POLL_ACTIVE_P2P :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_ACTIVE_P2P :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_NFCA :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_NFCF :
/* Set Analog configurations for this bit rate */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( rfalAnalogConfigId ) ( RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
break ;
/*******************************************************************************/
case RFAL_MODE_LISTEN_NFCB :
case RFAL_MODE_NONE :
return ERR_WRONG_STATE ;
/*******************************************************************************/
default :
return ERR_NOT_IMPLEMENTED ;
}
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalGetBitRate ( rfalBitRate * txBR , rfalBitRate * rxBR )
{
if ( ( gRFAL . state = = RFAL_STATE_IDLE ) | | ( gRFAL . mode = = RFAL_MODE_NONE ) )
{
return ERR_WRONG_STATE ;
}
if ( txBR ! = NULL )
{
* txBR = gRFAL . txBR ;
}
if ( rxBR ! = NULL )
{
* rxBR = gRFAL . rxBR ;
}
return ERR_NONE ;
}
/*******************************************************************************/
void rfalSetErrorHandling ( rfalEHandling eHandling )
{
switch ( eHandling )
{
case RFAL_ERRORHANDLING_NFC :
case RFAL_ERRORHANDLING_NONE :
st25r3916ClrRegisterBits ( ST25R3916_REG_EMD_SUP_CONF , ST25R3916_REG_EMD_SUP_CONF_emd_emv ) ;
break ;
case RFAL_ERRORHANDLING_EMVCO :
/* MISRA 16.4: no empty default statement (in case RFAL_SW_EMD is defined) */
# ifndef RFAL_SW_EMD
st25r3916ModifyRegister ( ST25R3916_REG_EMD_SUP_CONF ,
( ST25R3916_REG_EMD_SUP_CONF_emd_emv | ST25R3916_REG_EMD_SUP_CONF_emd_thld_mask ) ,
( ST25R3916_REG_EMD_SUP_CONF_emd_emv_on | RFAL_EMVCO_RX_MAXLEN ) ) ;
# endif /* RFAL_SW_EMD */
break ;
default :
/* MISRA 16.4: no empty default statement (a comment being enough) */
break ;
}
gRFAL . conf . eHandling = eHandling ;
}
/*******************************************************************************/
rfalEHandling rfalGetErrorHandling ( void )
{
return gRFAL . conf . eHandling ;
}
/*******************************************************************************/
void rfalSetFDTPoll ( uint32_t FDTPoll )
{
gRFAL . timings . FDTPoll = MIN ( FDTPoll , RFAL_ST25R3916_GPT_MAX_1FC ) ;
}
/*******************************************************************************/
uint32_t rfalGetFDTPoll ( void )
{
return gRFAL . timings . FDTPoll ;
}
/*******************************************************************************/
void rfalSetFDTListen ( uint32_t FDTListen )
{
gRFAL . timings . FDTListen = MIN ( FDTListen , RFAL_ST25R3916_MRT_MAX_1FC ) ;
}
/*******************************************************************************/
uint32_t rfalGetFDTListen ( void )
{
return gRFAL . timings . FDTListen ;
}
/*******************************************************************************/
void rfalSetGT ( uint32_t GT )
{
gRFAL . timings . GT = MIN ( GT , RFAL_ST25R3916_GT_MAX_1FC ) ;
}
/*******************************************************************************/
uint32_t rfalGetGT ( void )
{
return gRFAL . timings . GT ;
}
/*******************************************************************************/
bool rfalIsGTExpired ( void )
{
if ( gRFAL . tmr . GT ! = RFAL_TIMING_NONE )
{
if ( ! rfalTimerisExpired ( gRFAL . tmr . GT ) )
{
return false ;
}
}
return true ;
}
/*******************************************************************************/
ReturnCode rfalFieldOnAndStartGT ( void )
{
ReturnCode ret ;
/* Check if RFAL has been initialized (Oscillator should be running) and also
* if a direct register access has been performed and left the Oscillator Off */
if ( ! st25r3916IsOscOn ( ) | | ( gRFAL . state < RFAL_STATE_INIT ) )
{
return ERR_WRONG_STATE ;
}
ret = ERR_NONE ;
/* Set Analog configurations for Field On event */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_FIELD_ON ) ) ;
/*******************************************************************************/
/* Perform collision avoidance and turn field On if not already On */
if ( ! st25r3916IsTxEnabled ( ) | | ! gRFAL . field )
{
/* Set TARFG: 0 (75us+0ms=75us), GT is fulfilled using a SW timer */
st25r3916WriteRegister ( ST25R3916_REG_FIELD_ON_GT , 0U ) ;
/* Use Thresholds set by AnalogConfig */
ret = st25r3916PerformCollisionAvoidance ( ST25R3916_CMD_INITIAL_RF_COLLISION , ST25R3916_THRESHOLD_DO_NOT_SET , ST25R3916_THRESHOLD_DO_NOT_SET , gRFAL . timings . nTRFW ) ;
/* n * TRFW timing shall vary Activity 2.1 3.3.1.1 */
gRFAL . timings . nTRFW = rfalGennTRFW ( gRFAL . timings . nTRFW ) ;
gRFAL . field = st25r3916IsTxEnabled ( ) ; //(ret == ERR_NONE);
/* Only turn on Receiver and Transmitter if field was successfully turned On */
if ( gRFAL . field )
{
st25r3916TxRxOn ( ) ; /* Enable Tx and Rx (Tx is already On)*/
}
}
/*******************************************************************************/
/* Start GT timer in case the GT value is set */
if ( ( gRFAL . timings . GT ! = RFAL_TIMING_NONE ) )
{
/* Ensure that a SW timer doesn't have a lower value then the minimum */
rfalTimerStart ( gRFAL . tmr . GT , rfalConv1fcToMs ( MAX ( ( gRFAL . timings . GT ) , RFAL_ST25R3916_GT_MIN_1FC ) ) ) ;
}
return ret ;
}
/*******************************************************************************/
ReturnCode rfalFieldOff ( void )
{
/* Check whether a TxRx is not yet finished */
if ( gRFAL . TxRx . state ! = RFAL_TXRX_STATE_IDLE )
{
rfalCleanupTransceive ( ) ;
}
/* Disable Tx and Rx */
st25r3916TxRxOff ( ) ;
/* Set Analog configurations for Field Off event */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_FIELD_OFF ) ) ;
gRFAL . field = false ;
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalStartTransceive ( const rfalTransceiveContext * ctx )
{
uint32_t FxTAdj ; /* FWT or FDT adjustment calculation */
/* Check for valid parameters */
if ( ctx = = NULL )
{
return ERR_PARAM ;
}
/* Ensure that RFAL is already Initialized and the mode has been set */
if ( ( gRFAL . state > = RFAL_STATE_MODE_SET ) /*&& (gRFAL.TxRx.state == RFAL_TXRX_STATE_INIT )*/ )
{
/*******************************************************************************/
/* Check whether the field is already On, otherwise no TXE will be received */
if ( ! st25r3916IsTxEnabled ( ) & & ( ! rfalIsModePassiveListen ( gRFAL . mode ) & & ( ctx - > txBuf ! = NULL ) ) )
{
return ERR_WRONG_STATE ;
}
gRFAL . TxRx . ctx = * ctx ;
/*******************************************************************************/
if ( gRFAL . timings . FDTListen ! = RFAL_TIMING_NONE )
{
/* Calculate MRT adjustment accordingly to the current mode */
FxTAdj = RFAL_FDT_LISTEN_MRT_ADJUSTMENT ;
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCA ) { FxTAdj + = ( uint32_t ) RFAL_FDT_LISTEN_A_ADJUSTMENT ; }
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCA_T1T ) { FxTAdj + = ( uint32_t ) RFAL_FDT_LISTEN_A_ADJUSTMENT ; }
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCB ) { FxTAdj + = ( uint32_t ) RFAL_FDT_LISTEN_B_ADJUSTMENT ; }
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCV ) { FxTAdj + = ( uint32_t ) RFAL_FDT_LISTEN_V_ADJUSTMENT ; }
/* Ensure that MRT is using 64/fc steps */
st25r3916ClrRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step ) ;
/* If Correlator is being used further adjustment is required for NFCB */
if ( ( st25r3916CheckReg ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_dis_corr , 0x00U ) ) & & ( gRFAL . mode = = RFAL_MODE_POLL_NFCB ) )
{
FxTAdj + = ( uint32_t ) RFAL_FDT_LISTEN_B_ADJT_CORR ; /* Reduce FDT(Listen) */
st25r3916SetRegisterBits ( ST25R3916_REG_CORR_CONF1 , ST25R3916_REG_CORR_CONF1_corr_s3 ) ; /* Ensure BPSK start to 33 pilot pulses */
st25r3916ChangeRegisterBits ( ST25R3916_REG_SUBC_START_TIME , ST25R3916_REG_SUBC_START_TIME_sst_mask , RFAL_FDT_LISTEN_B_ADJT_CORR_SST ) ; /* Set sst */
}
/* Set Minimum FDT(Listen) in which PICC is not allowed to send a response */
st25r3916WriteRegister ( ST25R3916_REG_MASK_RX_TIMER , ( uint8_t ) rfalConv1fcTo64fc ( ( FxTAdj > gRFAL . timings . FDTListen ) ? RFAL_ST25R3916_MRT_MIN_1FC : ( gRFAL . timings . FDTListen - FxTAdj ) ) ) ;
}
/*******************************************************************************/
/* FDT Poll will be loaded in rfalPrepareTransceive() once the previous was expired */
/*******************************************************************************/
if ( ( gRFAL . TxRx . ctx . fwt ! = RFAL_FWT_NONE ) & & ( gRFAL . TxRx . ctx . fwt ! = 0U ) )
{
/* Ensure proper timing configuration */
if ( gRFAL . timings . FDTListen > = gRFAL . TxRx . ctx . fwt )
{
return ERR_PARAM ;
}
FxTAdj = RFAL_FWT_ADJUSTMENT ;
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCA ) { FxTAdj + = ( uint32_t ) RFAL_FWT_A_ADJUSTMENT ; }
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCA_T1T ) { FxTAdj + = ( uint32_t ) RFAL_FWT_A_ADJUSTMENT ; }
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCB ) { FxTAdj + = ( uint32_t ) RFAL_FWT_B_ADJUSTMENT ; }
if ( ( gRFAL . mode = = RFAL_MODE_POLL_NFCF ) | | ( gRFAL . mode = = RFAL_MODE_POLL_ACTIVE_P2P ) )
{
FxTAdj + = ( uint32_t ) ( ( gRFAL . txBR = = RFAL_BR_212 ) ? RFAL_FWT_F_212_ADJUSTMENT : RFAL_FWT_F_424_ADJUSTMENT ) ;
}
/* Ensure that the given FWT doesn't exceed NRT maximum */
gRFAL . TxRx . ctx . fwt = MIN ( ( gRFAL . TxRx . ctx . fwt + FxTAdj ) , RFAL_ST25R3916_NRT_MAX_1FC ) ;
/* Set FWT in the NRT */
st25r3916SetNoResponseTime ( rfalConv1fcTo64fc ( gRFAL . TxRx . ctx . fwt ) ) ;
}
else
{
/* Disable NRT, no NRE will be triggered, therefore wait endlessly for Rx */
st25r3916SetNoResponseTime ( RFAL_ST25R3916_NRT_DISABLED ) ;
}
gRFAL . state = RFAL_STATE_TXRX ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_IDLE ;
gRFAL . TxRx . status = ERR_BUSY ;
# if RFAL_FEATURE_NFCV
/*******************************************************************************/
if ( ( RFAL_MODE_POLL_NFCV = = gRFAL . mode ) | | ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) )
{ /* Exchange receive buffer with internal buffer */
gRFAL . nfcvData . origCtx = gRFAL . TxRx . ctx ;
gRFAL . TxRx . ctx . rxBuf = ( ( gRFAL . nfcvData . origCtx . rxBuf ! = NULL ) ? gRFAL . nfcvData . codingBuffer : NULL ) ;
gRFAL . TxRx . ctx . rxBufLen = ( uint16_t ) rfalConvBytesToBits ( sizeof ( gRFAL . nfcvData . codingBuffer ) ) ;
gRFAL . TxRx . ctx . flags = ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL
| ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP
| ( uint32_t ) RFAL_TXRX_FLAGS_NFCIP1_OFF
| ( uint32_t ) ( gRFAL . nfcvData . origCtx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_AGC_OFF )
| ( uint32_t ) RFAL_TXRX_FLAGS_PAR_RX_KEEP
| ( uint32_t ) RFAL_TXRX_FLAGS_PAR_TX_NONE ;
/* In NFCV a TxRx with a valid txBuf and txBufSize==0 indicates to send an EOF */
/* Skip logic below that would go directly into receive */
if ( gRFAL . TxRx . ctx . txBuf ! = NULL )
{
return ERR_NONE ;
}
}
# endif /* RFAL_FEATURE_NFCV */
/*******************************************************************************/
/* Check if the Transceive start performing Tx or goes directly to Rx */
if ( ( gRFAL . TxRx . ctx . txBuf = = NULL ) | | ( gRFAL . TxRx . ctx . txBufLen = = 0U ) )
{
/* Clear FIFO, Clear and Enable the Interrupts */
rfalPrepareTransceive ( ) ;
/* In AP2P check the field status */
if ( rfalIsModeActiveComm ( gRFAL . mode ) )
{
/* Disable our field upon a Rx reEnable, and start PPON2 manually */
st25r3916TxOff ( ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_START_PPON2_TIMER ) ;
}
/* No Tx done, enable the Receiver */
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/* Start NRT manually, if FWT = 0 (wait endlessly for Rx) chip will ignore anyhow */
st25r3916ExecuteCommand ( ST25R3916_CMD_START_NO_RESPONSE_TIMER ) ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_IDLE ;
}
return ERR_NONE ;
}
return ERR_WRONG_STATE ;
}
/*******************************************************************************/
bool rfalIsTransceiveInTx ( void )
{
return ( ( gRFAL . TxRx . state > = RFAL_TXRX_STATE_TX_IDLE ) & & ( gRFAL . TxRx . state < RFAL_TXRX_STATE_RX_IDLE ) ) ;
}
/*******************************************************************************/
bool rfalIsTransceiveInRx ( void )
{
return ( gRFAL . TxRx . state > = RFAL_TXRX_STATE_RX_IDLE ) ;
}
/*******************************************************************************/
ReturnCode rfalTransceiveBlockingTx ( uint8_t * txBuf , uint16_t txBufLen , uint8_t * rxBuf , uint16_t rxBufLen , uint16_t * actLen , uint32_t flags , uint32_t fwt )
{
ReturnCode ret ;
rfalTransceiveContext ctx ;
rfalCreateByteFlagsTxRxContext ( ctx , txBuf , txBufLen , rxBuf , rxBufLen , actLen , flags , fwt ) ;
EXIT_ON_ERR ( ret , rfalStartTransceive ( & ctx ) ) ;
return rfalTransceiveRunBlockingTx ( ) ;
}
/*******************************************************************************/
static ReturnCode rfalTransceiveRunBlockingTx ( void )
{
ReturnCode ret ;
do {
rfalWorker ( ) ;
ret = rfalGetTransceiveStatus ( ) ;
}
while ( rfalIsTransceiveInTx ( ) & & ( ret = = ERR_BUSY ) ) ;
if ( rfalIsTransceiveInRx ( ) )
{
return ERR_NONE ;
}
return ret ;
}
/*******************************************************************************/
ReturnCode rfalTransceiveBlockingRx ( void )
{
ReturnCode ret ;
do {
rfalWorker ( ) ;
ret = rfalGetTransceiveStatus ( ) ;
}
while ( rfalIsTransceiveInRx ( ) & & ( ret = = ERR_BUSY ) ) ;
return ret ;
}
/*******************************************************************************/
ReturnCode rfalTransceiveBlockingTxRx ( uint8_t * txBuf , uint16_t txBufLen , uint8_t * rxBuf , uint16_t rxBufLen , uint16_t * actLen , uint32_t flags , uint32_t fwt )
{
ReturnCode ret ;
EXIT_ON_ERR ( ret , rfalTransceiveBlockingTx ( txBuf , txBufLen , rxBuf , rxBufLen , actLen , flags , fwt ) ) ;
ret = rfalTransceiveBlockingRx ( ) ;
/* Convert received bits to bytes */
if ( actLen ! = NULL )
{
* actLen = rfalConvBitsToBytes ( * actLen ) ;
}
return ret ;
}
/*******************************************************************************/
static ReturnCode rfalRunTransceiveWorker ( void )
{
if ( gRFAL . state = = RFAL_STATE_TXRX )
{
/*******************************************************************************/
/* Check Transceive Sanity Timer has expired */
if ( gRFAL . tmr . txRx ! = RFAL_TIMING_NONE )
{
if ( rfalTimerisExpired ( gRFAL . tmr . txRx ) )
{
/* If sanity timer has expired abort ongoing transceive and signal error */
gRFAL . TxRx . status = ERR_IO ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
}
/*******************************************************************************/
/* Run Tx or Rx state machines */
if ( rfalIsTransceiveInTx ( ) )
{
rfalTransceiveTx ( ) ;
return rfalGetTransceiveStatus ( ) ;
}
if ( rfalIsTransceiveInRx ( ) )
{
rfalTransceiveRx ( ) ;
return rfalGetTransceiveStatus ( ) ;
}
}
return ERR_WRONG_STATE ;
}
/*******************************************************************************/
rfalTransceiveState rfalGetTransceiveState ( void )
{
return gRFAL . TxRx . state ;
}
/*******************************************************************************/
ReturnCode rfalGetTransceiveStatus ( void )
{
return ( ( gRFAL . TxRx . state = = RFAL_TXRX_STATE_IDLE ) ? gRFAL . TxRx . status : ERR_BUSY ) ;
}
/*******************************************************************************/
ReturnCode rfalGetTransceiveRSSI ( uint16_t * rssi )
{
uint16_t amRSSI ;
uint16_t pmRSSI ;
bool isSumMode ;
if ( rssi = = NULL )
{
return ERR_PARAM ;
}
st25r3916GetRSSI ( & amRSSI , & pmRSSI ) ;
/* Check if Correlator Summation mode is being used */
isSumMode = ( st25r3916CheckReg ( ST25R3916_REG_CORR_CONF1 , ST25R3916_REG_CORR_CONF1_corr_s4 , ST25R3916_REG_CORR_CONF1_corr_s4 ) ? st25r3916CheckReg ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_dis_corr , 0x00 ) : false ) ;
if ( isSumMode )
{
/*******************************************************************************/
/* Using SQRT from math.h and float. If due to compiler, resources or performance
* issue this cannot be used , other approaches can be foreseen with less accuracy :
* Use a simpler sqrt algorithm
* * rssi = MAX ( amRSSI , pmRSSI ) ;
* * rssi = ( ( amRSSI + pmRSSI ) / 2 ) ;
*/
* rssi = ( uint16_t ) sqrt ( ( ( double ) amRSSI * ( double ) amRSSI ) + ( ( double ) pmRSSI * ( double ) pmRSSI ) ) ; /* PRQA S 5209 # MISRA 4.9 - External function (sqrt()) requires double */
}
else
{
/* Check which channel was used */
* rssi = ( st25r3916CheckReg ( ST25R3916_REG_AUX_DISPLAY , ST25R3916_REG_AUX_DISPLAY_a_cha , ST25R3916_REG_AUX_DISPLAY_a_cha ) ? pmRSSI : amRSSI ) ;
}
return ERR_NONE ;
}
/*******************************************************************************/
void rfalWorker ( void )
{
platformProtectWorker ( ) ; /* Protect RFAL Worker/Task/Process */
switch ( gRFAL . state )
{
case RFAL_STATE_TXRX :
rfalRunTransceiveWorker ( ) ;
break ;
# if RFAL_FEATURE_LISTEN_MODE
case RFAL_STATE_LM :
rfalRunListenModeWorker ( ) ;
break ;
# endif /* RFAL_FEATURE_LISTEN_MODE */
# if RFAL_FEATURE_WAKEUP_MODE
case RFAL_STATE_WUM :
rfalRunWakeUpModeWorker ( ) ;
break ;
# endif /* RFAL_FEATURE_WAKEUP_MODE */
/* Nothing to be done */
default :
/* MISRA 16.4: no empty default statement (a comment being enough) */
break ;
}
platformUnprotectWorker ( ) ; /* Unprotect RFAL Worker/Task/Process */
}
/*******************************************************************************/
static void rfalErrorHandling ( void )
{
uint16_t fifoBytesToRead ;
fifoBytesToRead = rfalFIFOStatusGetNumBytes ( ) ;
# ifdef RFAL_SW_EMD
/*******************************************************************************/
/* EMVCo */
/*******************************************************************************/
if ( gRFAL . conf . eHandling = = RFAL_ERRORHANDLING_EMVCO )
{
bool rxHasIncParError ;
/*******************************************************************************/
/* EMD Handling - NFC Forum Digital 1.1 4.1.1.1 ; EMVCo v2.5 4.9.2 */
/* ReEnable the receiver on frames with a length < 4 bytes, upon: */
/* - Collision or Framing error detected */
/* - Residual bits are detected (hard framing error) */
/* - Parity error */
/* - CRC error */
/*******************************************************************************/
/* Check if reception has incomplete bytes or parity error */
rxHasIncParError = ( rfalFIFOStatusIsIncompleteByte ( ) ? true : rfalFIFOStatusIsMissingPar ( ) ) ; /* MISRA 13.5 */
/* In case there are residual bits decrement FIFO bytes */
/* Ensure FIFO contains some byte as the FIFO might be empty upon Framing errors */
if ( ( fifoBytesToRead > 0U ) & & rxHasIncParError )
{
fifoBytesToRead - - ;
}
if ( ( ( gRFAL . fifo . bytesTotal + fifoBytesToRead ) < RFAL_EMVCO_RX_MAXLEN ) & &
( ( gRFAL . TxRx . status = = ERR_RF_COLLISION ) | | ( gRFAL . TxRx . status = = ERR_FRAMING ) | |
( gRFAL . TxRx . status = = ERR_PAR ) | | ( gRFAL . TxRx . status = = ERR_CRC ) | |
rxHasIncParError ) )
{
/* Ignore this reception, ReEnable receiver which also clears the FIFO */
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/* Ensure that the NRT has not expired meanwhile */
if ( st25r3916CheckReg ( ST25R3916_REG_NFCIP1_BIT_RATE , ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on , 0x00 ) )
{
if ( st25r3916CheckReg ( ST25R3916_REG_AUX_DISPLAY , ST25R3916_REG_AUX_DISPLAY_rx_act , 0x00 ) )
{
/* Abort reception */
st25r3916ExecuteCommand ( ST25R3916_CMD_MASK_RECEIVE_DATA ) ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
return ;
}
}
rfalFIFOStatusClear ( ) ;
gRFAL . fifo . bytesTotal = 0 ;
gRFAL . TxRx . status = ERR_BUSY ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXS ;
}
return ;
}
# endif
/*******************************************************************************/
/* ISO14443A Mode */
/*******************************************************************************/
if ( gRFAL . mode = = RFAL_MODE_POLL_NFCA )
{
/*******************************************************************************/
/* If we received a frame with a incomplete byte we`ll raise a specific error *
* ( support for T2T 4 bit ACK / NAK , MIFARE and Kovio ) */
/*******************************************************************************/
if ( ( gRFAL . TxRx . status = = ERR_PAR ) | | ( gRFAL . TxRx . status = = ERR_CRC ) )
{
if ( rfalFIFOStatusIsIncompleteByte ( ) )
{
st25r3916ReadFifo ( ( uint8_t * ) ( gRFAL . TxRx . ctx . rxBuf ) , fifoBytesToRead ) ;
if ( ( gRFAL . TxRx . ctx . rxRcvdLen ) ! = NULL )
{
* gRFAL . TxRx . ctx . rxRcvdLen = rfalFIFOGetNumIncompleteBits ( ) ;
}
gRFAL . TxRx . status = ERR_INCOMPLETE_BYTE ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
}
}
}
/*******************************************************************************/
static void rfalCleanupTransceive ( void )
{
/*******************************************************************************/
/* Transceive flags */
/*******************************************************************************/
/* Restore default settings on NFCIP1 mode, Receiving parity + CRC bits and manual Tx Parity*/
st25r3916ClrRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ( ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par | ST25R3916_REG_ISO14443A_NFC_nfc_f0 ) ) ;
/* Restore AGC enabled */
st25r3916SetRegisterBits ( ST25R3916_REG_RX_CONF2 , ST25R3916_REG_RX_CONF2_agc_en ) ;
/*******************************************************************************/
/*******************************************************************************/
/* Transceive timers */
/*******************************************************************************/
rfalTimerDestroy ( gRFAL . tmr . txRx ) ;
rfalTimerDestroy ( gRFAL . tmr . RXE ) ;
gRFAL . tmr . txRx = RFAL_TIMING_NONE ;
gRFAL . tmr . RXE = RFAL_TIMING_NONE ;
/*******************************************************************************/
/*******************************************************************************/
/* Execute Post Transceive Callback */
/*******************************************************************************/
if ( gRFAL . callbacks . postTxRx ! = NULL )
{
gRFAL . callbacks . postTxRx ( ) ;
}
/*******************************************************************************/
}
/*******************************************************************************/
static void rfalPrepareTransceive ( void )
{
uint32_t maskInterrupts ;
uint8_t reg ;
/* If we are in RW or AP2P mode */
if ( ! rfalIsModePassiveListen ( gRFAL . mode ) )
{
/* Reset receive logic with STOP command */
st25r3916ExecuteCommand ( ST25R3916_CMD_STOP ) ;
/* Reset Rx Gain */
st25r3916ExecuteCommand ( ST25R3916_CMD_RESET_RXGAIN ) ;
}
else
{
/* In Passive Listen Mode do not use STOP as it stops FDT timer */
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
}
/*******************************************************************************/
/* FDT Poll */
/*******************************************************************************/
if ( rfalIsModePassiveComm ( gRFAL . mode ) ) /* Passive Comms */
{
/* In Passive communications General Purpose Timer is used to measure FDT Poll */
if ( gRFAL . timings . FDTPoll ! = RFAL_TIMING_NONE )
{
/* Configure GPT to start at RX end */
st25r3916SetStartGPTimer ( ( uint16_t ) rfalConv1fcTo8fc ( MIN ( gRFAL . timings . FDTPoll , ( gRFAL . timings . FDTPoll - RFAL_FDT_POLL_ADJUSTMENT ) ) ) , ST25R3916_REG_TIMER_EMV_CONTROL_gptc_erx ) ;
}
}
/*******************************************************************************/
/* Execute Pre Transceive Callback */
/*******************************************************************************/
if ( gRFAL . callbacks . preTxRx ! = NULL )
{
gRFAL . callbacks . preTxRx ( ) ;
}
/*******************************************************************************/
maskInterrupts = ( ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE |
ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_RXE |
ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC |
ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 |
ST25R3916_IRQ_MASK_NRE ) ;
/*******************************************************************************/
/* Transceive flags */
/*******************************************************************************/
reg = ( ST25R3916_REG_ISO14443A_NFC_no_tx_par_off | ST25R3916_REG_ISO14443A_NFC_no_rx_par_off | ST25R3916_REG_ISO14443A_NFC_nfc_f0_off ) ;
/* Check if NFCIP1 mode is to be enabled */
if ( ( gRFAL . TxRx . ctx . flags & ( uint8_t ) RFAL_TXRX_FLAGS_NFCIP1_ON ) ! = 0U )
{
reg | = ST25R3916_REG_ISO14443A_NFC_nfc_f0 ;
}
/* Check if Parity check is to be skipped and to keep the parity + CRC bits in FIFO */
if ( ( gRFAL . TxRx . ctx . flags & ( uint8_t ) RFAL_TXRX_FLAGS_PAR_RX_KEEP ) ! = 0U )
{
reg | = ST25R3916_REG_ISO14443A_NFC_no_rx_par ;
}
/* Check if automatic Parity bits is to be disabled */
if ( ( gRFAL . TxRx . ctx . flags & ( uint8_t ) RFAL_TXRX_FLAGS_PAR_TX_NONE ) ! = 0U )
{
reg | = ST25R3916_REG_ISO14443A_NFC_no_tx_par ;
}
/* Apply current TxRx flags on ISO14443A and NFC 106kb/s Settings Register */
st25r3916ChangeRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ( ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par | ST25R3916_REG_ISO14443A_NFC_nfc_f0 ) , reg ) ;
/* Check if AGC is to be disabled */
if ( ( gRFAL . TxRx . ctx . flags & ( uint8_t ) RFAL_TXRX_FLAGS_AGC_OFF ) ! = 0U )
{
st25r3916ClrRegisterBits ( ST25R3916_REG_RX_CONF2 , ST25R3916_REG_RX_CONF2_agc_en ) ;
}
else
{
st25r3916SetRegisterBits ( ST25R3916_REG_RX_CONF2 , ST25R3916_REG_RX_CONF2_agc_en ) ;
}
/*******************************************************************************/
/*******************************************************************************/
/* EMVCo NRT mode */
/*******************************************************************************/
if ( gRFAL . conf . eHandling = = RFAL_ERRORHANDLING_EMVCO )
{
st25r3916SetRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv ) ;
maskInterrupts | = ST25R3916_IRQ_MASK_RX_REST ;
}
else
{
st25r3916ClrRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv ) ;
}
/*******************************************************************************/
/* In Passive Listen mode additionally enable External Field interrupts */
if ( rfalIsModePassiveListen ( gRFAL . mode ) )
{
maskInterrupts | = ( ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_F ) ; /* Enable external Field interrupts to detect Link Loss and SENF_REQ auto responses */
}
/* In Active comms enable also External Field interrupts and set RF Collsion Avoindance */
if ( rfalIsModeActiveComm ( gRFAL . mode ) )
{
maskInterrupts | = ( ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_PPON2 | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_CAC ) ;
/* Set n=0 for subsequent RF Collision Avoidance */
st25r3916ChangeRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_nfc_n_mask , 0 ) ;
}
/*******************************************************************************/
/* Start transceive Sanity Timer if a FWT is used */
if ( ( gRFAL . TxRx . ctx . fwt ! = RFAL_FWT_NONE ) & & ( gRFAL . TxRx . ctx . fwt ! = 0U ) )
{
rfalTimerStart ( gRFAL . tmr . txRx , rfalCalcSanityTmr ( gRFAL . TxRx . ctx . fwt ) ) ;
}
/*******************************************************************************/
/*******************************************************************************/
/* Clear and enable these interrupts */
st25r3916GetInterrupt ( maskInterrupts ) ;
st25r3916EnableInterrupts ( maskInterrupts ) ;
/* Clear FIFO status local copy */
rfalFIFOStatusClear ( ) ;
}
/*******************************************************************************/
static void rfalTransceiveTx ( void )
{
volatile uint32_t irqs ;
uint16_t tmp ;
ReturnCode ret ;
/* Supress warning in case NFC-V feature is disabled */
ret = ERR_NONE ;
NO_WARNING ( ret ) ;
irqs = ST25R3916_IRQ_MASK_NONE ;
if ( gRFAL . TxRx . state ! = gRFAL . TxRx . lastState )
{
/* rfalLogD( "RFAL: lastSt: %d curSt: %d \r\n", gRFAL.TxRx.lastState, gRFAL.TxRx.state ); */
gRFAL . TxRx . lastState = gRFAL . TxRx . state ;
}
switch ( gRFAL . TxRx . state )
{
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_IDLE :
/* Nothing to do */
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_WAIT_GT ;
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_WAIT_GT : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
if ( ! rfalIsGTExpired ( ) )
{
break ;
}
rfalTimerDestroy ( gRFAL . tmr . GT ) ;
gRFAL . tmr . GT = RFAL_TIMING_NONE ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_WAIT_FDT ;
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_WAIT_FDT : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
/* Only in Passive communications GPT is used to measure FDT Poll */
if ( rfalIsModePassiveComm ( gRFAL . mode ) )
{
if ( st25r3916IsGPTRunning ( ) )
{
break ;
}
}
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_TRANSMIT ;
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_TRANSMIT : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
/* Clear FIFO, Clear and Enable the Interrupts */
rfalPrepareTransceive ( ) ;
/* ST25R3916 has a fixed FIFO water level */
gRFAL . fifo . expWL = RFAL_FIFO_OUT_WL ;
# if RFAL_FEATURE_NFCV
/*******************************************************************************/
/* In NFC-V streaming mode, the FIFO needs to be loaded with the coded bits */
if ( ( RFAL_MODE_POLL_NFCV = = gRFAL . mode ) | | ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) )
{
#if 0
/* Debugging code: output the payload bits by writing into the FIFO and subsequent clearing */
st25r3916WriteFifo ( gRFAL . TxRx . ctx . txBuf , rfalConvBitsToBytes ( gRFAL . TxRx . ctx . txBufLen ) ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
# endif
/* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */
gRFAL . nfcvData . nfcvOffset = 0 ;
ret = iso15693VCDCode ( gRFAL . TxRx . ctx . txBuf , rfalConvBitsToBytes ( gRFAL . TxRx . ctx . txBufLen ) , ( ( ( gRFAL . nfcvData . origCtx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL ) ! = 0U ) ? false : true ) , ( ( ( gRFAL . nfcvData . origCtx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL ) ! = 0U ) ? false : true ) , ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) ,
& gRFAL . fifo . bytesTotal , & gRFAL . nfcvData . nfcvOffset , gRFAL . nfcvData . codingBuffer , MIN ( ( uint16_t ) ST25R3916_FIFO_DEPTH , ( uint16_t ) sizeof ( gRFAL . nfcvData . codingBuffer ) ) , & gRFAL . fifo . bytesWritten ) ;
if ( ( ret ! = ERR_NONE ) & & ( ret ! = ERR_AGAIN ) )
{
gRFAL . TxRx . status = ret ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_FAIL ;
break ;
}
/* Set the number of full bytes and bits to be transmitted */
st25r3916SetNumTxBits ( ( uint16_t ) rfalConvBytesToBits ( gRFAL . fifo . bytesTotal ) ) ;
/* Load FIFO with coded bytes */
st25r3916WriteFifo ( gRFAL . nfcvData . codingBuffer , gRFAL . fifo . bytesWritten ) ;
}
/*******************************************************************************/
else
# endif /* RFAL_FEATURE_NFCV */
{
/* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */
gRFAL . fifo . bytesTotal = ( uint16_t ) rfalCalcNumBytes ( gRFAL . TxRx . ctx . txBufLen ) ;
/* Set the number of full bytes and bits to be transmitted */
st25r3916SetNumTxBits ( gRFAL . TxRx . ctx . txBufLen ) ;
/* Load FIFO with total length or FIFO's maximum */
gRFAL . fifo . bytesWritten = MIN ( gRFAL . fifo . bytesTotal , ST25R3916_FIFO_DEPTH ) ;
st25r3916WriteFifo ( gRFAL . TxRx . ctx . txBuf , gRFAL . fifo . bytesWritten ) ;
}
/*Check if Observation Mode is enabled and set it on ST25R391x */
rfalCheckEnableObsModeTx ( ) ;
/*******************************************************************************/
/* If we're in Passive Listen mode ensure that the external field is still On */
if ( rfalIsModePassiveListen ( gRFAL . mode ) )
{
if ( ! rfalIsExtFieldOn ( ) )
{
gRFAL . TxRx . status = ERR_LINK_LOSS ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_FAIL ;
break ;
}
}
/*******************************************************************************/
/* Trigger/Start transmission */
if ( ( gRFAL . TxRx . ctx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL ) ! = 0U )
{
st25r3916ExecuteCommand ( ST25R3916_CMD_TRANSMIT_WITHOUT_CRC ) ;
}
else
{
st25r3916ExecuteCommand ( ST25R3916_CMD_TRANSMIT_WITH_CRC ) ;
}
/* Check if a WL level is expected or TXE should come */
gRFAL . TxRx . state = ( ( gRFAL . fifo . bytesWritten < gRFAL . fifo . bytesTotal ) ? RFAL_TXRX_STATE_TX_WAIT_WL : RFAL_TXRX_STATE_TX_WAIT_TXE ) ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_WAIT_WL :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( ( irqs & ST25R3916_IRQ_MASK_FWL ) ! = 0U ) & & ( ( irqs & ST25R3916_IRQ_MASK_TXE ) = = 0U ) )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_RELOAD_FIFO ;
}
else
{
gRFAL . TxRx . status = ERR_IO ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_FAIL ;
break ;
}
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_RELOAD_FIFO : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
# if RFAL_FEATURE_NFCV
/*******************************************************************************/
/* In NFC-V streaming mode, the FIFO needs to be loaded with the coded bits */
if ( ( RFAL_MODE_POLL_NFCV = = gRFAL . mode ) | | ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) )
{
uint16_t maxLen ;
/* Load FIFO with the remaining length or maximum available (which fit on the coding buffer) */
maxLen = ( uint16_t ) MIN ( ( gRFAL . fifo . bytesTotal - gRFAL . fifo . bytesWritten ) , gRFAL . fifo . expWL ) ;
maxLen = ( uint16_t ) MIN ( maxLen , sizeof ( gRFAL . nfcvData . codingBuffer ) ) ;
tmp = 0 ;
/* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */
ret = iso15693VCDCode ( gRFAL . TxRx . ctx . txBuf , rfalConvBitsToBytes ( gRFAL . TxRx . ctx . txBufLen ) , ( ( ( gRFAL . nfcvData . origCtx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL ) ! = 0U ) ? false : true ) , ( ( ( gRFAL . nfcvData . origCtx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL ) ! = 0U ) ? false : true ) , ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) ,
& gRFAL . fifo . bytesTotal , & gRFAL . nfcvData . nfcvOffset , gRFAL . nfcvData . codingBuffer , maxLen , & tmp ) ;
if ( ( ret ! = ERR_NONE ) & & ( ret ! = ERR_AGAIN ) )
{
gRFAL . TxRx . status = ret ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_FAIL ;
break ;
}
/* Load FIFO with coded bytes */
st25r3916WriteFifo ( gRFAL . nfcvData . codingBuffer , tmp ) ;
}
/*******************************************************************************/
else
# endif /* RFAL_FEATURE_NFCV */
{
/* Load FIFO with the remaining length or maximum available */
tmp = MIN ( ( gRFAL . fifo . bytesTotal - gRFAL . fifo . bytesWritten ) , gRFAL . fifo . expWL ) ; /* tmp holds the number of bytes written on this iteration */
st25r3916WriteFifo ( & gRFAL . TxRx . ctx . txBuf [ gRFAL . fifo . bytesWritten ] , tmp ) ;
}
/* Update total written bytes to FIFO */
gRFAL . fifo . bytesWritten + = tmp ;
/* Check if a WL level is expected or TXE should come */
gRFAL . TxRx . state = ( ( gRFAL . fifo . bytesWritten < gRFAL . fifo . bytesTotal ) ? RFAL_TXRX_STATE_TX_WAIT_WL : RFAL_TXRX_STATE_TX_WAIT_TXE ) ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_WAIT_TXE :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_TXE ) ! = 0U )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_DONE ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_FWL ) ! = 0U )
{
break ; /* Ignore ST25R3916 FIFO WL if total TxLen is already on the FIFO */
}
else
{
gRFAL . TxRx . status = ERR_IO ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_FAIL ;
break ;
}
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_DONE : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
/* If no rxBuf is provided do not wait/expect Rx */
if ( gRFAL . TxRx . ctx . rxBuf = = NULL )
{
/*Check if Observation Mode was enabled and disable it on ST25R391x */
rfalCheckDisableObsMode ( ) ;
/* Clean up Transceive */
rfalCleanupTransceive ( ) ;
gRFAL . TxRx . status = ERR_NONE ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_IDLE ;
break ;
}
rfalCheckEnableObsModeRx ( ) ;
/* Goto Rx */
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_IDLE ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_TX_FAIL :
/* Error should be assigned by previous state */
if ( gRFAL . TxRx . status = = ERR_BUSY )
{
gRFAL . TxRx . status = ERR_SYSTEM ;
}
/*Check if Observation Mode was enabled and disable it on ST25R391x */
rfalCheckDisableObsMode ( ) ;
/* Clean up Transceive */
rfalCleanupTransceive ( ) ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_IDLE ;
break ;
/*******************************************************************************/
default :
gRFAL . TxRx . status = ERR_SYSTEM ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_TX_FAIL ;
break ;
}
}
/*******************************************************************************/
static void rfalTransceiveRx ( void )
{
volatile uint32_t irqs ;
uint16_t tmp ;
uint16_t aux ;
irqs = ST25R3916_IRQ_MASK_NONE ;
if ( gRFAL . TxRx . state ! = gRFAL . TxRx . lastState )
{
/* rfalLogD( "RFAL: lastSt: %d curSt: %d \r\n", gRFAL.TxRx.lastState, gRFAL.TxRx.state ); */
gRFAL . TxRx . lastState = gRFAL . TxRx . state ;
}
switch ( gRFAL . TxRx . state )
{
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_IDLE :
/* Clear rx counters */
gRFAL . fifo . bytesWritten = 0 ; /* Total bytes written on RxBuffer */
gRFAL . fifo . bytesTotal = 0 ; /* Total bytes in FIFO will now be from Rx */
if ( gRFAL . TxRx . ctx . rxRcvdLen ! = NULL )
{
* gRFAL . TxRx . ctx . rxRcvdLen = 0 ;
}
gRFAL . TxRx . state = ( rfalIsModeActiveComm ( gRFAL . mode ) ? RFAL_TXRX_STATE_RX_WAIT_EON : RFAL_TXRX_STATE_RX_WAIT_RXS ) ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_WAIT_RXS :
/*******************************************************************************/
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_EOF ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
/* Only raise Timeout if NRE is detected with no Rx Start (NRT EMV mode) */
if ( ( ( irqs & ST25R3916_IRQ_MASK_NRE ) ! = 0U ) & & ( ( irqs & ST25R3916_IRQ_MASK_RXS ) = = 0U ) )
{
gRFAL . TxRx . status = ERR_TIMEOUT ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
/* Only raise Link Loss if EOF is detected with no Rx Start */
if ( ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U ) & & ( ( irqs & ST25R3916_IRQ_MASK_RXS ) = = 0U ) )
{
/* In AP2P a Field On has already occurred - treat this as timeout | mute */
gRFAL . TxRx . status = ( rfalIsModeActiveComm ( gRFAL . mode ) ? ERR_TIMEOUT : ERR_LINK_LOSS ) ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
if ( ( irqs & ST25R3916_IRQ_MASK_RXS ) ! = 0U )
{
/*******************************************************************************/
/* REMARK: Silicon workaround ST25R3916 Errata #TBD */
/* Rarely on corrupted frames I_rxs gets signaled but I_rxe is not signaled */
/* Use a SW timer to handle an eventual missing RXE */
rfalTimerStart ( gRFAL . tmr . RXE , RFAL_NORXE_TOUT ) ;
/*******************************************************************************/
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXE ;
}
else
{
gRFAL . TxRx . status = ERR_IO ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
/* remove NRE that might appear together (NRT EMV mode), and remove RXS, but keep EOF if present for next state */
irqs & = ~ ( ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NRE ) ;
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_WAIT_RXE : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
/*******************************************************************************/
/* REMARK: Silicon workaround ST25R3916 Errata #TBD */
/* ST25R396 may indicate RXS without RXE afterwards, this happens rarely on */
/* corrupted frames. */
/* SW timer is used to timeout upon a missing RXE */
if ( rfalTimerisExpired ( gRFAL . tmr . RXE ) )
{
gRFAL . TxRx . status = ERR_FRAMING ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
/*******************************************************************************/
irqs | = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_RX_REST | ST25R3916_IRQ_MASK_WU_F ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_RX_REST ) ! = 0U )
{
/* RX_REST indicates that Receiver has been reseted due to EMD, therefore a RXS + RXE should *
* follow if a good reception is followed within the valid initial timeout */
/* Check whether NRT has expired already, if so signal a timeout */
if ( st25r3916GetInterrupt ( ST25R3916_IRQ_MASK_NRE ) ! = 0U )
{
gRFAL . TxRx . status = ERR_TIMEOUT ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
if ( st25r3916CheckReg ( ST25R3916_REG_NFCIP1_BIT_RATE , ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on , 0 ) ) /* MISRA 13.5 */
{
gRFAL . TxRx . status = ERR_TIMEOUT ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
/* Discard any previous RXS */
st25r3916GetInterrupt ( ST25R3916_IRQ_MASK_RXS ) ;
/* Check whether a following reception has already started */
if ( st25r3916CheckReg ( ST25R3916_REG_AUX_DISPLAY , ST25R3916_REG_AUX_DISPLAY_rx_act , ST25R3916_REG_AUX_DISPLAY_rx_act ) )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXE ;
break ;
}
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXS ;
break ;
}
if ( ( ( irqs & ST25R3916_IRQ_MASK_FWL ) ! = 0U ) & & ( ( irqs & ST25R3916_IRQ_MASK_RXE ) = = 0U ) )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_FIFO ;
break ;
}
/* Automatic responses allowed during TxRx only for the SENSF_REQ */
if ( ( irqs & ST25R3916_IRQ_MASK_WU_F ) ! = 0U )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXS ;
break ;
}
/* After RXE retrieve and check for any error irqs */
irqs | = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_COL ) ) ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_ERR_CHECK ;
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_ERR_CHECK : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
if ( ( irqs & ST25R3916_IRQ_MASK_ERR1 ) ! = 0U )
{
gRFAL . TxRx . status = ERR_FRAMING ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_DATA ;
/* Check if there's a specific error handling for this */
rfalErrorHandling ( ) ;
break ;
}
/* Discard Soft Framing errors in AP2P and CE */
else if ( rfalIsModePassivePoll ( gRFAL . mode ) & & ( ( irqs & ST25R3916_IRQ_MASK_ERR2 ) ! = 0U ) )
{
gRFAL . TxRx . status = ERR_FRAMING ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_DATA ;
/* Check if there's a specific error handling for this */
rfalErrorHandling ( ) ;
break ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_PAR ) ! = 0U )
{
gRFAL . TxRx . status = ERR_PAR ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_DATA ;
/* Check if there's a specific error handling for this */
rfalErrorHandling ( ) ;
break ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_CRC ) ! = 0U )
{
gRFAL . TxRx . status = ERR_CRC ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_DATA ;
/* Check if there's a specific error handling for this */
rfalErrorHandling ( ) ;
break ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_COL ) ! = 0U )
{
gRFAL . TxRx . status = ERR_RF_COLLISION ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_DATA ;
/* Check if there's a specific error handling for this */
rfalErrorHandling ( ) ;
break ;
}
else if ( rfalIsModePassiveListen ( gRFAL . mode ) & & ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U ) )
{
gRFAL . TxRx . status = ERR_LINK_LOSS ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_RXE ) ! = 0U )
{
/* Reception ended without any error indication, *
* check FIFO status for malformed or incomplete frames */
/* Check if the reception ends with an incomplete byte (residual bits) */
if ( rfalFIFOStatusIsIncompleteByte ( ) )
{
gRFAL . TxRx . status = ERR_INCOMPLETE_BYTE ;
}
/* Check if the reception ends missing parity bit */
else if ( rfalFIFOStatusIsMissingPar ( ) )
{
gRFAL . TxRx . status = ERR_FRAMING ;
}
else
{
/* MISRA 15.7 - Empty else */
}
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_READ_DATA ;
}
else
{
gRFAL . TxRx . status = ERR_IO ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_READ_DATA : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
tmp = rfalFIFOStatusGetNumBytes ( ) ;
/*******************************************************************************/
/* Check if CRC should not be placed in rxBuf */
if ( ( ( gRFAL . TxRx . ctx . flags & ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP ) = = 0U ) )
{
/* if received frame was bigger than CRC */
if ( ( uint16_t ) ( gRFAL . fifo . bytesTotal + tmp ) > 0U )
{
/* By default CRC will not be placed into the rxBuffer */
if ( ( tmp > RFAL_CRC_LEN ) )
{
tmp - = RFAL_CRC_LEN ;
}
/* If the CRC was already placed into rxBuffer (due to WL interrupt where CRC was already in FIFO Read)
* cannot remove it from rxBuf . Can only remove it from rxBufLen not indicate the presence of CRC */
else if ( gRFAL . fifo . bytesTotal > RFAL_CRC_LEN )
{
gRFAL . fifo . bytesTotal - = RFAL_CRC_LEN ;
}
else
{
/* MISRA 15.7 - Empty else */
}
}
}
gRFAL . fifo . bytesTotal + = tmp ; /* add to total bytes counter */
/*******************************************************************************/
/* Check if remaining bytes fit on the rxBuf available */
if ( gRFAL . fifo . bytesTotal > rfalConvBitsToBytes ( gRFAL . TxRx . ctx . rxBufLen ) )
{
tmp = ( uint16_t ) ( rfalConvBitsToBytes ( gRFAL . TxRx . ctx . rxBufLen ) - gRFAL . fifo . bytesWritten ) ;
/* Transmission errors have precedence over buffer error */
if ( gRFAL . TxRx . status = = ERR_BUSY )
{
gRFAL . TxRx . status = ERR_NOMEM ;
}
}
/*******************************************************************************/
/* Retrieve remaining bytes from FIFO to rxBuf, and assign total length rcvd */
st25r3916ReadFifo ( & gRFAL . TxRx . ctx . rxBuf [ gRFAL . fifo . bytesWritten ] , tmp ) ;
if ( gRFAL . TxRx . ctx . rxRcvdLen ! = NULL )
{
( * gRFAL . TxRx . ctx . rxRcvdLen ) = ( uint16_t ) rfalConvBytesToBits ( gRFAL . fifo . bytesTotal ) ;
if ( rfalFIFOStatusIsIncompleteByte ( ) )
{
( * gRFAL . TxRx . ctx . rxRcvdLen ) - = ( RFAL_BITS_IN_BYTE - rfalFIFOGetNumIncompleteBits ( ) ) ;
}
}
# if RFAL_FEATURE_NFCV
/*******************************************************************************/
/* Decode sub bit stream into payload bits for NFCV, if no error found so far */
if ( ( ( RFAL_MODE_POLL_NFCV = = gRFAL . mode ) | | ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) ) & & ( gRFAL . TxRx . status = = ERR_BUSY ) )
{
ReturnCode ret ;
uint16_t offset = 0 ; /* REMARK offset not currently used */
ret = iso15693VICCDecode ( gRFAL . TxRx . ctx . rxBuf , gRFAL . fifo . bytesTotal ,
gRFAL . nfcvData . origCtx . rxBuf , rfalConvBitsToBytes ( gRFAL . nfcvData . origCtx . rxBufLen ) , & offset , gRFAL . nfcvData . origCtx . rxRcvdLen , gRFAL . nfcvData . ignoreBits , ( RFAL_MODE_POLL_PICOPASS = = gRFAL . mode ) ) ;
if ( ( ( ERR_NONE = = ret ) | | ( ERR_CRC = = ret ) )
& & ( ( ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP & gRFAL . nfcvData . origCtx . flags ) = = 0U )
& & ( ( * gRFAL . nfcvData . origCtx . rxRcvdLen % RFAL_BITS_IN_BYTE ) = = 0U )
& & ( * gRFAL . nfcvData . origCtx . rxRcvdLen > = rfalConvBytesToBits ( RFAL_CRC_LEN ) )
)
{
* gRFAL . nfcvData . origCtx . rxRcvdLen - = ( uint16_t ) rfalConvBytesToBits ( RFAL_CRC_LEN ) ; /* Remove CRC */
}
#if 0
/* Debugging code: output the payload bits by writing into the FIFO and subsequent clearing */
st25r3916WriteFifo ( gRFAL . nfcvData . origCtx . rxBuf , rfalConvBitsToBytes ( * gRFAL . nfcvData . origCtx . rxRcvdLen ) ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
# endif
/* Restore original ctx */
gRFAL . TxRx . ctx = gRFAL . nfcvData . origCtx ;
gRFAL . TxRx . status = ( ( ret ! = ERR_NONE ) ? ret : ERR_BUSY ) ;
}
# endif /* RFAL_FEATURE_NFCV */
/*******************************************************************************/
/* If an error as been marked/detected don't fall into to RX_DONE */
if ( gRFAL . TxRx . status ! = ERR_BUSY )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
if ( rfalIsModeActiveComm ( gRFAL . mode ) )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_EOF ;
break ;
}
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_DONE ;
/* fall through */
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_DONE : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
/*Check if Observation Mode was enabled and disable it on ST25R391x */
rfalCheckDisableObsMode ( ) ;
/* Clean up Transceive */
rfalCleanupTransceive ( ) ;
gRFAL . TxRx . status = ERR_NONE ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_IDLE ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_READ_FIFO :
/*******************************************************************************/
/* REMARK: Silicon workaround ST25R3916 Errata #TBD */
/* Rarely on corrupted frames I_rxs gets signaled but I_rxe is not signaled */
/* Use a SW timer to handle an eventual missing RXE */
rfalTimerStart ( gRFAL . tmr . RXE , RFAL_NORXE_TOUT ) ;
/*******************************************************************************/
tmp = rfalFIFOStatusGetNumBytes ( ) ;
gRFAL . fifo . bytesTotal + = tmp ;
/*******************************************************************************/
/* Calculate the amount of bytes that still fits in rxBuf */
aux = ( ( gRFAL . fifo . bytesTotal > rfalConvBitsToBytes ( gRFAL . TxRx . ctx . rxBufLen ) ) ? ( rfalConvBitsToBytes ( gRFAL . TxRx . ctx . rxBufLen ) - gRFAL . fifo . bytesWritten ) : tmp ) ;
/*******************************************************************************/
/* Retrieve incoming bytes from FIFO to rxBuf, and store already read amount */
st25r3916ReadFifo ( & gRFAL . TxRx . ctx . rxBuf [ gRFAL . fifo . bytesWritten ] , aux ) ;
gRFAL . fifo . bytesWritten + = aux ;
/*******************************************************************************/
/* If the bytes already read were not the full FIFO WL, dump the remaining *
* FIFO so that ST25R391x can continue with reception */
if ( aux < tmp )
{
st25r3916ReadFifo ( NULL , ( tmp - aux ) ) ;
}
rfalFIFOStatusClear ( ) ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXE ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_FAIL :
/*Check if Observation Mode was enabled and disable it on ST25R391x */
rfalCheckDisableObsMode ( ) ;
/* Clean up Transceive */
rfalCleanupTransceive ( ) ;
/* Error should be assigned by previous state */
if ( gRFAL . TxRx . status = = ERR_BUSY )
{
gRFAL . TxRx . status = ERR_SYSTEM ;
}
/*rfalLogD( "RFAL: curSt: %d Error: %d \r\n", gRFAL.TxRx.state, gRFAL.TxRx.status );*/
gRFAL . TxRx . state = RFAL_TXRX_STATE_IDLE ;
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_WAIT_EON :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_PPON2 ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_EON ) ! = 0U )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_WAIT_RXS ;
}
if ( ( irqs & ST25R3916_IRQ_MASK_NRE ) ! = 0U )
{
gRFAL . TxRx . status = ERR_TIMEOUT ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
if ( ( irqs & ST25R3916_IRQ_MASK_PPON2 ) ! = 0U )
{
gRFAL . TxRx . status = ERR_LINK_LOSS ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
break ;
/*******************************************************************************/
case RFAL_TXRX_STATE_RX_WAIT_EOF :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_CAC ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_CAT ) ! = 0U )
{
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_DONE ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_CAC ) ! = 0U )
{
gRFAL . TxRx . status = ERR_RF_COLLISION ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
else
{
gRFAL . TxRx . status = ERR_IO ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
}
break ;
/*******************************************************************************/
default :
gRFAL . TxRx . status = ERR_SYSTEM ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_FAIL ;
break ;
}
}
/*******************************************************************************/
static void rfalFIFOStatusUpdate ( void )
{
if ( gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG2 ] = = RFAL_FIFO_STATUS_INVALID )
{
st25r3916ReadMultipleRegisters ( ST25R3916_REG_FIFO_STATUS1 , gRFAL . fifo . status , ST25R3916_FIFO_STATUS_LEN ) ;
}
}
/*******************************************************************************/
static void rfalFIFOStatusClear ( void )
{
gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG2 ] = RFAL_FIFO_STATUS_INVALID ;
}
/*******************************************************************************/
static uint16_t rfalFIFOStatusGetNumBytes ( void )
{
uint16_t result ;
rfalFIFOStatusUpdate ( ) ;
result = ( ( ( ( uint16_t ) gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG2 ] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask ) > > ST25R3916_REG_FIFO_STATUS2_fifo_b_shift ) < < RFAL_BITS_IN_BYTE ) ;
result | = ( ( ( uint16_t ) gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG1 ] ) & 0x00FFU ) ;
return result ;
}
/*******************************************************************************/
static bool rfalFIFOStatusIsIncompleteByte ( void )
{
rfalFIFOStatusUpdate ( ) ;
return ( ( gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG2 ] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask ) ! = 0U ) ;
}
/*******************************************************************************/
static bool rfalFIFOStatusIsMissingPar ( void )
{
rfalFIFOStatusUpdate ( ) ;
return ( ( gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG2 ] & ST25R3916_REG_FIFO_STATUS2_np_lb ) ! = 0U ) ;
}
/*******************************************************************************/
static uint8_t rfalFIFOGetNumIncompleteBits ( void )
{
rfalFIFOStatusUpdate ( ) ;
return ( ( gRFAL . fifo . status [ RFAL_FIFO_STATUS_REG2 ] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask ) > > ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift ) ;
}
# if RFAL_FEATURE_NFCA
/*******************************************************************************/
ReturnCode rfalISO14443ATransceiveShortFrame ( rfal14443AShortFrameCmd txCmd , uint8_t * rxBuf , uint8_t rxBufLen , uint16_t * rxRcvdLen , uint32_t fwt )
{
ReturnCode ret ;
uint8_t directCmd ;
/* Check if RFAL is properly initialized */
if ( ! st25r3916IsTxEnabled ( ) | | ( gRFAL . state < RFAL_STATE_MODE_SET ) | | ( ( gRFAL . mode ! = RFAL_MODE_POLL_NFCA ) & & ( gRFAL . mode ! = RFAL_MODE_POLL_NFCA_T1T ) ) )
{
return ERR_WRONG_STATE ;
}
/* Check for valid parameters */
if ( ( rxBuf = = NULL ) | | ( rxRcvdLen = = NULL ) | | ( fwt = = RFAL_FWT_NONE ) )
{
return ERR_PARAM ;
}
/*******************************************************************************/
/* Select the Direct Command to be performed */
switch ( txCmd )
{
case RFAL_14443A_SHORTFRAME_CMD_WUPA :
directCmd = ST25R3916_CMD_TRANSMIT_WUPA ;
break ;
case RFAL_14443A_SHORTFRAME_CMD_REQA :
directCmd = ST25R3916_CMD_TRANSMIT_REQA ;
break ;
default :
return ERR_PARAM ;
}
/* Disable CRC while receiving since ATQA has no CRC included */
st25r3916SetRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_no_crc_rx ) ;
/*******************************************************************************/
/* Wait for GT and FDT */
while ( ! rfalIsGTExpired ( ) ) { /* MISRA 15.6: mandatory brackets */ } ;
while ( st25r3916IsGPTRunning ( ) ) { /* MISRA 15.6: mandatory brackets */ } ;
rfalTimerDestroy ( gRFAL . tmr . GT ) ;
gRFAL . tmr . GT = RFAL_TIMING_NONE ;
/*******************************************************************************/
/* Prepare for Transceive, Receive only (bypass Tx states) */
gRFAL . TxRx . ctx . flags = ( ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL | ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP ) ;
gRFAL . TxRx . ctx . rxBuf = rxBuf ;
gRFAL . TxRx . ctx . rxBufLen = rxBufLen ;
gRFAL . TxRx . ctx . rxRcvdLen = rxRcvdLen ;
gRFAL . TxRx . ctx . fwt = fwt ;
/*******************************************************************************/
/* Load NRT with FWT */
st25r3916SetNoResponseTime ( rfalConv1fcTo64fc ( MIN ( ( fwt + RFAL_FWT_ADJUSTMENT + RFAL_FWT_A_ADJUSTMENT ) , RFAL_ST25R3916_NRT_MAX_1FC ) ) ) ;
if ( gRFAL . timings . FDTListen ! = RFAL_TIMING_NONE )
{
/* Ensure that MRT is using 64/fc steps */
st25r3916ClrRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step ) ;
/* Set Minimum FDT(Listen) in which PICC is not allowed to send a response */
st25r3916WriteRegister ( ST25R3916_REG_MASK_RX_TIMER , ( uint8_t ) rfalConv1fcTo64fc ( ( ( RFAL_FDT_LISTEN_MRT_ADJUSTMENT + RFAL_FDT_LISTEN_A_ADJUSTMENT ) > gRFAL . timings . FDTListen ) ? RFAL_ST25R3916_MRT_MIN_1FC : ( gRFAL . timings . FDTListen - ( RFAL_FDT_LISTEN_MRT_ADJUSTMENT + RFAL_FDT_LISTEN_A_ADJUSTMENT ) ) ) ) ;
}
/* In Passive communications General Purpose Timer is used to measure FDT Poll */
if ( gRFAL . timings . FDTPoll ! = RFAL_TIMING_NONE )
{
/* Configure GPT to start at RX end */
st25r3916SetStartGPTimer ( ( uint16_t ) rfalConv1fcTo8fc ( MIN ( gRFAL . timings . FDTPoll , ( gRFAL . timings . FDTPoll - RFAL_FDT_POLL_ADJUSTMENT ) ) ) , ST25R3916_REG_TIMER_EMV_CONTROL_gptc_erx ) ;
}
/*******************************************************************************/
rfalPrepareTransceive ( ) ;
/* Also enable bit collision interrupt */
st25r3916GetInterrupt ( ST25R3916_IRQ_MASK_COL ) ;
st25r3916EnableInterrupts ( ST25R3916_IRQ_MASK_COL ) ;
/*Check if Observation Mode is enabled and set it on ST25R391x */
rfalCheckEnableObsModeTx ( ) ;
/*******************************************************************************/
/* Clear nbtx bits before sending WUPA/REQA - otherwise ST25R3916 will report parity error, Note2 of the register */
st25r3916WriteRegister ( ST25R3916_REG_NUM_TX_BYTES2 , 0 ) ;
/* Send either WUPA or REQA. All affected tags will backscatter ATQA and change to READY state */
st25r3916ExecuteCommand ( directCmd ) ;
/* Wait for TXE */
if ( st25r3916WaitForInterruptsTimed ( ST25R3916_IRQ_MASK_TXE , ( uint16_t ) MAX ( rfalConv1fcToMs ( fwt ) , RFAL_ST25R3916_SW_TMR_MIN_1MS ) ) = = 0U )
{
ret = ERR_IO ;
}
else
{
/*Check if Observation Mode is enabled and set it on ST25R391x */
rfalCheckEnableObsModeRx ( ) ;
/* Jump into a transceive Rx state for reception (bypass Tx states) */
gRFAL . state = RFAL_STATE_TXRX ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_IDLE ;
gRFAL . TxRx . status = ERR_BUSY ;
/* Execute Transceive Rx blocking */
ret = rfalTransceiveBlockingRx ( ) ;
}
/* Disable Collision interrupt */
st25r3916DisableInterrupts ( ( ST25R3916_IRQ_MASK_COL ) ) ;
/* ReEnable CRC on Rx */
st25r3916ClrRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_no_crc_rx ) ;
return ret ;
}
/*******************************************************************************/
ReturnCode rfalISO14443ATransceiveAnticollisionFrame ( uint8_t * buf , uint8_t * bytesToSend , uint8_t * bitsToSend , uint16_t * rxLength , uint32_t fwt )
{
ReturnCode ret ;
rfalTransceiveContext ctx ;
uint8_t collByte ;
uint8_t collData ;
/* Check if RFAL is properly initialized */
if ( ( gRFAL . state < RFAL_STATE_MODE_SET ) | | ( gRFAL . mode ! = RFAL_MODE_POLL_NFCA ) )
{
return ERR_WRONG_STATE ;
}
/* Check for valid parameters */
if ( ( buf = = NULL ) | | ( bytesToSend = = NULL ) | | ( bitsToSend = = NULL ) | | ( rxLength = = NULL ) )
{
return ERR_PARAM ;
}
/*******************************************************************************/
/* Set speficic Analog Config for Anticolission if needed */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL ) ) ;
/*******************************************************************************/
/* Enable anti collision to recognise collision in first byte of SENS_REQ */
st25r3916SetRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ST25R3916_REG_ISO14443A_NFC_antcl ) ;
/* Disable CRC while receiving */
st25r3916SetRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_no_crc_rx ) ;
/*******************************************************************************/
/* Prepare for Transceive */
ctx . flags = ( ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL | ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP ) ;
ctx . txBuf = buf ;
ctx . txBufLen = ( uint16_t ) ( rfalConvBytesToBits ( * bytesToSend ) + * bitsToSend ) ;
ctx . rxBuf = & buf [ * bytesToSend ] ;
ctx . rxBufLen = ( uint16_t ) rfalConvBytesToBits ( RFAL_ISO14443A_SDD_RES_LEN ) ;
ctx . rxRcvdLen = rxLength ;
ctx . fwt = fwt ;
/* Disable Automatic Gain Control (AGC) for better detection of collisions if using Coherent Receiver */
ctx . flags | = ( st25r3916CheckReg ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_dis_corr , ST25R3916_REG_AUX_dis_corr ) ? ( uint32_t ) RFAL_TXRX_FLAGS_AGC_OFF : 0x00U ) ;
rfalStartTransceive ( & ctx ) ;
/* Additionally enable bit collision interrupt */
st25r3916GetInterrupt ( ST25R3916_IRQ_MASK_COL ) ;
st25r3916EnableInterrupts ( ST25R3916_IRQ_MASK_COL ) ;
/*******************************************************************************/
collByte = 0 ;
/* save the collision byte */
if ( ( * bitsToSend ) > 0U )
{
buf [ ( * bytesToSend ) ] < < = ( RFAL_BITS_IN_BYTE - ( * bitsToSend ) ) ;
buf [ ( * bytesToSend ) ] > > = ( RFAL_BITS_IN_BYTE - ( * bitsToSend ) ) ;
collByte = buf [ ( * bytesToSend ) ] ;
}
/*******************************************************************************/
/* Run Transceive blocking */
ret = rfalTransceiveRunBlockingTx ( ) ;
if ( ret = = ERR_NONE )
{
ret = rfalTransceiveBlockingRx ( ) ;
/*******************************************************************************/
if ( ( * bitsToSend ) > 0U )
{
buf [ ( * bytesToSend ) ] > > = ( * bitsToSend ) ;
buf [ ( * bytesToSend ) ] < < = ( * bitsToSend ) ;
buf [ ( * bytesToSend ) ] | = collByte ;
}
if ( ( ERR_RF_COLLISION = = ret ) )
{
/* read out collision register */
st25r3916ReadRegister ( ST25R3916_REG_COLLISION_STATUS , & collData ) ;
( * bytesToSend ) = ( ( collData > > ST25R3916_REG_COLLISION_STATUS_c_byte_shift ) & 0x0FU ) ; // 4-bits Byte information
( * bitsToSend ) = ( ( collData > > ST25R3916_REG_COLLISION_STATUS_c_bit_shift ) & 0x07U ) ; // 3-bits bit information
}
}
/*******************************************************************************/
/* Disable Collision interrupt */
st25r3916DisableInterrupts ( ( ST25R3916_IRQ_MASK_COL ) ) ;
/* Disable anti collision again */
st25r3916ClrRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ST25R3916_REG_ISO14443A_NFC_antcl ) ;
/* ReEnable CRC on Rx */
st25r3916ClrRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_no_crc_rx ) ;
/*******************************************************************************/
/* Restore common Analog configurations for this mode */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
return ret ;
}
# endif /* RFAL_FEATURE_NFCA */
# if RFAL_FEATURE_NFCV
/*******************************************************************************/
ReturnCode rfalISO15693TransceiveAnticollisionFrame ( uint8_t * txBuf , uint8_t txBufLen , uint8_t * rxBuf , uint8_t rxBufLen , uint16_t * actLen )
{
ReturnCode ret ;
rfalTransceiveContext ctx ;
/* Check if RFAL is properly initialized */
if ( ( gRFAL . state < RFAL_STATE_MODE_SET ) | | ( gRFAL . mode ! = RFAL_MODE_POLL_NFCV ) )
{
return ERR_WRONG_STATE ;
}
/*******************************************************************************/
/* Set speficic Analog Config for Anticolission if needed */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL ) ) ;
/* Ignoring collisions before the UID (RES_FLAG + DSFID) */
gRFAL . nfcvData . ignoreBits = ( uint16_t ) RFAL_ISO15693_IGNORE_BITS ;
/*******************************************************************************/
/* Prepare for Transceive */
ctx . flags = ( ( txBufLen = = 0U ) ? ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL : ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_AUTO ) | ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP | ( uint32_t ) RFAL_TXRX_FLAGS_AGC_OFF | ( ( txBufLen = = 0U ) ? ( uint32_t ) RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL : ( uint32_t ) RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO ) ; /* Disable Automatic Gain Control (AGC) for better detection of collision */
ctx . txBuf = txBuf ;
ctx . txBufLen = ( uint16_t ) rfalConvBytesToBits ( txBufLen ) ;
ctx . rxBuf = rxBuf ;
ctx . rxBufLen = ( uint16_t ) rfalConvBytesToBits ( rxBufLen ) ;
ctx . rxRcvdLen = actLen ;
ctx . fwt = rfalConv64fcTo1fc ( ISO15693_FWT ) ;
rfalStartTransceive ( & ctx ) ;
/*******************************************************************************/
/* Run Transceive blocking */
ret = rfalTransceiveRunBlockingTx ( ) ;
if ( ret = = ERR_NONE )
{
ret = rfalTransceiveBlockingRx ( ) ;
}
/* Check if a Transmission error and received data is less then expected */
if ( ( ( ret = = ERR_RF_COLLISION ) | | ( ret = = ERR_CRC ) | | ( ret = = ERR_FRAMING ) ) & & ( rfalConvBitsToBytes ( * ctx . rxRcvdLen ) < RFAL_ISO15693_INV_RES_LEN ) )
{
/* If INVENTORY_RES is shorter than expected, tag is still modulating *
* Ensure that response is complete before next frame */
platformDelay ( ( uint8_t ) ( ( RFAL_ISO15693_INV_RES_LEN - rfalConvBitsToBytes ( * ctx . rxRcvdLen ) ) / ( ( RFAL_ISO15693_INV_RES_LEN / RFAL_ISO15693_INV_RES_DUR ) + 1U ) ) ) ;
}
/* Restore common Analog configurations for this mode */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR ( gRFAL . txBR ) | RFAL_ANALOG_CONFIG_TX ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR ( gRFAL . rxBR ) | RFAL_ANALOG_CONFIG_RX ) ) ;
gRFAL . nfcvData . ignoreBits = 0 ;
return ret ;
}
/*******************************************************************************/
ReturnCode rfalISO15693TransceiveEOFAnticollision ( uint8_t * rxBuf , uint8_t rxBufLen , uint16_t * actLen )
{
uint8_t dummy ;
return rfalISO15693TransceiveAnticollisionFrame ( & dummy , 0 , rxBuf , rxBufLen , actLen ) ;
}
/*******************************************************************************/
ReturnCode rfalISO15693TransceiveEOF ( uint8_t * rxBuf , uint8_t rxBufLen , uint16_t * actLen )
{
ReturnCode ret ;
uint8_t dummy ;
/* Check if RFAL is properly initialized */
if ( ( gRFAL . state < RFAL_STATE_MODE_SET ) | | ( gRFAL . mode ! = RFAL_MODE_POLL_NFCV ) )
{
return ERR_WRONG_STATE ;
}
/*******************************************************************************/
/* Run Transceive blocking */
ret = rfalTransceiveBlockingTxRx ( & dummy ,
0 ,
rxBuf ,
rxBufLen ,
actLen ,
( ( uint32_t ) RFAL_TXRX_FLAGS_CRC_TX_MANUAL | ( uint32_t ) RFAL_TXRX_FLAGS_CRC_RX_KEEP | ( uint32_t ) RFAL_TXRX_FLAGS_AGC_ON ) ,
rfalConv64fcTo1fc ( ISO15693_FWT ) ) ;
return ret ;
}
# endif /* RFAL_FEATURE_NFCV */
# if RFAL_FEATURE_NFCF
/*******************************************************************************/
ReturnCode rfalFeliCaPoll ( rfalFeliCaPollSlots slots , uint16_t sysCode , uint8_t reqCode , rfalFeliCaPollRes * pollResList , uint8_t pollResListSize , uint8_t * devicesDetected , uint8_t * collisionsDetected )
{
ReturnCode ret ;
uint8_t frame [ RFAL_FELICA_POLL_REQ_LEN - RFAL_FELICA_LEN_LEN ] ; // LEN is added by ST25R391x automatically
uint16_t actLen ;
uint8_t frameIdx ;
uint8_t devDetected ;
uint8_t colDetected ;
rfalEHandling curHandling ;
uint8_t nbSlots ;
/* Check if RFAL is properly initialized */
if ( ( gRFAL . state < RFAL_STATE_MODE_SET ) | | ( gRFAL . mode ! = RFAL_MODE_POLL_NFCF ) )
{
return ERR_WRONG_STATE ;
}
frameIdx = 0 ;
colDetected = 0 ;
devDetected = 0 ;
nbSlots = ( uint8_t ) slots ;
/*******************************************************************************/
/* Compute SENSF_REQ frame */
frame [ frameIdx + + ] = ( uint8_t ) FELICA_CMD_POLLING ; /* CMD: SENF_REQ */
frame [ frameIdx + + ] = ( uint8_t ) ( sysCode > > 8 ) ; /* System Code (SC) */
frame [ frameIdx + + ] = ( uint8_t ) ( sysCode & 0xFFU ) ; /* System Code (SC) */
frame [ frameIdx + + ] = reqCode ; /* Communication Parameter Request (RC)*/
frame [ frameIdx + + ] = nbSlots ; /* TimeSlot (TSN) */
/*******************************************************************************/
/* NRT should not stop on reception - Use EMVCo mode to run NRT in nrt_emv *
* ERRORHANDLING_EMVCO has no special handling for NFC - F mode */
curHandling = gRFAL . conf . eHandling ;
rfalSetErrorHandling ( RFAL_ERRORHANDLING_EMVCO ) ;
/*******************************************************************************/
/* Run transceive blocking,
* Calculate Total Response Time in ( 64 / fc ) :
* 512 PICC process time + ( n * 256 Time Slot duration ) */
ret = rfalTransceiveBlockingTx ( frame ,
( uint16_t ) frameIdx ,
( uint8_t * ) gRFAL . nfcfData . pollResponses ,
RFAL_FELICA_POLL_RES_LEN ,
& actLen ,
( RFAL_TXRX_FLAGS_DEFAULT ) ,
rfalConv64fcTo1fc ( RFAL_FELICA_POLL_DELAY_TIME + ( RFAL_FELICA_POLL_SLOT_TIME * ( ( uint32_t ) nbSlots + 1U ) ) ) ) ;
/*******************************************************************************/
/* If Tx OK, Wait for all responses, store them as soon as they appear */
if ( ret = = ERR_NONE )
{
bool timeout ;
do
{
ret = rfalTransceiveBlockingRx ( ) ;
if ( ret = = ERR_TIMEOUT )
{
/* Upon timeout the full Poll Delay + (Slot time)*(nbSlots) has expired */
timeout = true ;
}
else
{
/* Reception done, reEnabled Rx for following Slot */
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_RESET_RXGAIN ) ;
/* If the reception was OK, new device found */
if ( ret = = ERR_NONE )
{
devDetected + + ;
/* Overwrite the Transceive context for the next reception */
gRFAL . TxRx . ctx . rxBuf = ( uint8_t * ) gRFAL . nfcfData . pollResponses [ devDetected ] ;
}
/* If the reception was not OK, mark as collision */
else
{
colDetected + + ;
}
/* Check whether NRT has expired meanwhile */
timeout = st25r3916CheckReg ( ST25R3916_REG_NFCIP1_BIT_RATE , ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on , 0x00 ) ;
if ( ! timeout )
{
/* Jump again into transceive Rx state for the following reception */
gRFAL . TxRx . status = ERR_BUSY ;
gRFAL . state = RFAL_STATE_TXRX ;
gRFAL . TxRx . state = RFAL_TXRX_STATE_RX_IDLE ;
}
}
} while ( ( ( nbSlots - - ) ! = 0U ) & & ! timeout ) ;
}
/*******************************************************************************/
/* Restore NRT to normal mode - back to previous error handling */
rfalSetErrorHandling ( curHandling ) ;
/*******************************************************************************/
/* Assign output parameters if requested */
if ( ( pollResList ! = NULL ) & & ( pollResListSize > 0U ) & & ( devDetected > 0U ) )
{
ST_MEMCPY ( pollResList , gRFAL . nfcfData . pollResponses , ( RFAL_FELICA_POLL_RES_LEN * ( uint32_t ) MIN ( pollResListSize , devDetected ) ) ) ;
}
if ( devicesDetected ! = NULL )
{
* devicesDetected = devDetected ;
}
if ( collisionsDetected ! = NULL )
{
* collisionsDetected = colDetected ;
}
return ( ( ( colDetected ! = 0U ) | | ( devDetected ! = 0U ) ) ? ERR_NONE : ret ) ;
}
# endif /* RFAL_FEATURE_NFCF */
/*****************************************************************************
* Listen Mode *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*******************************************************************************/
bool rfalIsExtFieldOn ( void )
{
return st25r3916IsExtFieldOn ( ) ;
}
# if RFAL_FEATURE_LISTEN_MODE
/*******************************************************************************/
ReturnCode rfalListenStart ( uint32_t lmMask , const rfalLmConfPA * confA , const rfalLmConfPB * confB , const rfalLmConfPF * confF , uint8_t * rxBuf , uint16_t rxBufLen , uint16_t * rxLen )
{
t_rfalPTMem PTMem ; /* PRQA S 0759 # MISRA 19.2 - Allocating Union where members are of the same type, just different names. Thus no problem can occur. */
uint8_t * pPTMem ;
uint8_t autoResp ;
/* Check if RFAL is initialized */
if ( gRFAL . state < RFAL_STATE_INIT )
{
return ERR_WRONG_STATE ;
}
gRFAL . Lm . state = RFAL_LM_STATE_NOT_INIT ;
gRFAL . Lm . mdIrqs = ST25R3916_IRQ_MASK_NONE ;
gRFAL . Lm . mdReg = ( ST25R3916_REG_MODE_targ_init | ST25R3916_REG_MODE_om_nfc | ST25R3916_REG_MODE_nfc_ar_off ) ;
/* By default disable all automatic responses */
autoResp = ( ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_rfu | ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p ) ;
/*******************************************************************************/
if ( ( lmMask & RFAL_LM_MASK_NFCA ) ! = 0U )
{
/* Check if the conf has been provided */
if ( confA = = NULL )
{
return ERR_PARAM ;
}
pPTMem = ( uint8_t * ) PTMem . PTMem_A ;
/*******************************************************************************/
/* Check and set supported NFCID Length */
switch ( confA - > nfcidLen )
{
case RFAL_LM_NFCID_LEN_04 :
st25r3916ChangeRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_nfc_id_mask , ST25R3916_REG_AUX_nfc_id_4bytes ) ;
break ;
case RFAL_LM_NFCID_LEN_07 :
st25r3916ChangeRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_nfc_id_mask , ST25R3916_REG_AUX_nfc_id_7bytes ) ;
break ;
default :
return ERR_PARAM ;
}
/*******************************************************************************/
/* Set NFCID */
ST_MEMCPY ( pPTMem , confA - > nfcid , RFAL_NFCID1_TRIPLE_LEN ) ;
pPTMem = & pPTMem [ RFAL_NFCID1_TRIPLE_LEN ] ; /* MISRA 18.4 */
/* Set SENS_RES */
ST_MEMCPY ( pPTMem , confA - > SENS_RES , RFAL_LM_SENS_RES_LEN ) ;
pPTMem = & pPTMem [ RFAL_LM_SENS_RES_LEN ] ; /* MISRA 18.4 */
/* Set SEL_RES */
* pPTMem + + = ( ( confA - > nfcidLen = = RFAL_LM_NFCID_LEN_04 ) ? ( confA - > SEL_RES & ~ RFAL_LM_NFCID_INCOMPLETE ) : ( confA - > SEL_RES | RFAL_LM_NFCID_INCOMPLETE ) ) ;
* pPTMem + + = ( confA - > SEL_RES & ~ RFAL_LM_NFCID_INCOMPLETE ) ;
* pPTMem + + = ( confA - > SEL_RES & ~ RFAL_LM_NFCID_INCOMPLETE ) ;
/* Write into PTMem-A */
st25r3916WritePTMem ( PTMem . PTMem_A , ST25R3916_PTM_A_LEN ) ;
/*******************************************************************************/
/* Enable automatic responses for A */
autoResp & = ~ ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ;
/* Set Target mode, Bit Rate detection and Listen Mode for NFC-F */
gRFAL . Lm . mdReg | = ( ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0 | ST25R3916_REG_MODE_nfc_ar_off ) ;
gRFAL . Lm . mdIrqs | = ( ST25R3916_IRQ_MASK_WU_A | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_RXE_PTA ) ;
}
/*******************************************************************************/
if ( ( lmMask & RFAL_LM_MASK_NFCB ) ! = 0U )
{
/* Check if the conf has been provided */
if ( confB = = NULL )
{
return ERR_PARAM ;
}
return ERR_NOTSUPP ;
}
/*******************************************************************************/
if ( ( lmMask & RFAL_LM_MASK_NFCF ) ! = 0U )
{
pPTMem = ( uint8_t * ) PTMem . PTMem_F ;
/* Check if the conf has been provided */
if ( confF = = NULL )
{
return ERR_PARAM ;
}
/*******************************************************************************/
/* Set System Code */
ST_MEMCPY ( pPTMem , confF - > SC , RFAL_LM_SENSF_SC_LEN ) ;
pPTMem = & pPTMem [ RFAL_LM_SENSF_SC_LEN ] ; /* MISRA 18.4 */
/* Set SENSF_RES */
ST_MEMCPY ( pPTMem , confF - > SENSF_RES , RFAL_LM_SENSF_RES_LEN ) ;
/* Set RD bytes to 0x00 as ST25R3916 cannot support advances features */
pPTMem [ RFAL_LM_SENSF_RD0_POS ] = 0x00 ; /* NFC Forum Digital 1.1 Table 46: 0x00 */
pPTMem [ RFAL_LM_SENSF_RD1_POS ] = 0x00 ; /* NFC Forum Digital 1.1 Table 47: No automatic bit rates */
pPTMem = & pPTMem [ RFAL_LM_SENS_RES_LEN ] ; /* MISRA 18.4 */
/* Write into PTMem-F */
st25r3916WritePTMemF ( PTMem . PTMem_F , ST25R3916_PTM_F_LEN ) ;
/*******************************************************************************/
/* Write 24 TSN "Random" Numbers at first initialization and let it rollover */
if ( ! gRFAL . Lm . iniFlag )
{
pPTMem = ( uint8_t * ) PTMem . TSN ;
* pPTMem + + = 0x12 ;
* pPTMem + + = 0x34 ;
* pPTMem + + = 0x56 ;
* pPTMem + + = 0x78 ;
* pPTMem + + = 0x9A ;
* pPTMem + + = 0xBC ;
* pPTMem + + = 0xDF ;
* pPTMem + + = 0x21 ;
* pPTMem + + = 0x43 ;
* pPTMem + + = 0x65 ;
* pPTMem + + = 0x87 ;
* pPTMem + + = 0xA9 ;
/* Write into PTMem-TSN */
st25r3916WritePTMemTSN ( PTMem . TSN , ST25R3916_PTM_TSN_LEN ) ;
}
/*******************************************************************************/
/* Enable automatic responses for F */
autoResp & = ~ ( ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r ) ;
/* Set Target mode, Bit Rate detection and Listen Mode for NFC-F */
gRFAL . Lm . mdReg | = ( ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om2 | ST25R3916_REG_MODE_nfc_ar_off ) ;
/* In CE NFC-F any data without error will be passed to FIFO, to support CUP */
gRFAL . Lm . mdIrqs | = ( ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_RXE ) ;
}
/*******************************************************************************/
if ( ( lmMask & RFAL_LM_MASK_ACTIVE_P2P ) ! = 0U )
{
/* Enable Reception of P2P frames */
autoResp & = ~ ( ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p ) ;
/* Set Target mode, Bit Rate detection and Automatic Response RF Collision Avoidance */
gRFAL . Lm . mdReg | = ( ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om2 | ST25R3916_REG_MODE_om0 | ST25R3916_REG_MODE_nfc_ar_auto_rx ) ;
/* n * TRFW timing shall vary Activity 2.1 3.4.1.1 */
st25r3916ChangeRegisterBits ( ST25R3916_REG_AUX , ST25R3916_REG_AUX_nfc_n_mask , gRFAL . timings . nTRFW ) ;
gRFAL . timings . nTRFW = rfalGennTRFW ( gRFAL . timings . nTRFW ) ;
gRFAL . Lm . mdIrqs | = ( ST25R3916_IRQ_MASK_RXE ) ;
}
/* Check if one of the modes were selected */
if ( ( gRFAL . Lm . mdReg & ST25R3916_REG_MODE_targ ) = = ST25R3916_REG_MODE_targ_targ )
{
gRFAL . state = RFAL_STATE_LM ;
gRFAL . Lm . mdMask = lmMask ;
gRFAL . Lm . rxBuf = rxBuf ;
gRFAL . Lm . rxBufLen = rxBufLen ;
gRFAL . Lm . rxLen = rxLen ;
* gRFAL . Lm . rxLen = 0 ;
gRFAL . Lm . dataFlag = false ;
gRFAL . Lm . iniFlag = true ;
/* Apply the Automatic Responses configuration */
st25r3916ChangeRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_rfu | ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p ) , autoResp ) ;
/* Disable GPT trigger source */
st25r3916ChangeRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask , ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger ) ;
/* On Bit Rate Detection Mode ST25R391x will filter incoming frames during MRT time starting on External Field On event, use 512/fc steps */
st25r3916SetRegisterBits ( ST25R3916_REG_TIMER_EMV_CONTROL , ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step_512 ) ;
st25r3916WriteRegister ( ST25R3916_REG_MASK_RX_TIMER , ( uint8_t ) rfalConv1fcTo512fc ( RFAL_LM_GT ) ) ;
/* Restore default settings on NFCIP1 mode, Receiving parity + CRC bits and manual Tx Parity*/
st25r3916ClrRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ( ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par | ST25R3916_REG_ISO14443A_NFC_nfc_f0 ) ) ;
/* External Field Detector enabled as Automatics on rfalInitialize() */
/* Set Analog configurations for generic Listen mode */
/* Not on SetState(POWER OFF) as otherwise would be applied on every Field Event */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON ) ) ;
/* Initialize as POWER_OFF and set proper mode in RF Chip */
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
return ERR_REQUEST ; /* Listen Start called but no mode was enabled */
}
return ERR_NONE ;
}
/*******************************************************************************/
static ReturnCode rfalRunListenModeWorker ( void )
{
volatile uint32_t irqs ;
uint8_t tmp ;
if ( gRFAL . state ! = RFAL_STATE_LM )
{
return ERR_WRONG_STATE ;
}
switch ( gRFAL . Lm . state )
{
/*******************************************************************************/
case RFAL_LM_STATE_POWER_OFF :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_EON ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_EON ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_IDLE ) ;
}
else
{
break ;
}
/* fall through */
/*******************************************************************************/
case RFAL_LM_STATE_IDLE : /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_RXE_PTA ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_NFCT ) ! = 0U )
{
/* Retrieve detected bitrate */
uint8_t newBr ;
st25r3916ReadRegister ( ST25R3916_REG_NFCIP1_BIT_RATE , & newBr ) ;
newBr > > = ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_shift ;
if ( newBr > ST25R3916_REG_BIT_RATE_rxrate_424 )
{
newBr = ST25R3916_REG_BIT_RATE_rxrate_424 ;
}
gRFAL . Lm . brDetected = ( rfalBitRate ) ( newBr ) ; /* PRQA S 4342 # MISRA 10.5 - Guaranteed that no invalid enum values may be created. See also equalityGuard_RFAL_BR_106 ff.*/
}
if ( ( ( irqs & ST25R3916_IRQ_MASK_WU_F ) ! = 0U ) & & ( gRFAL . Lm . brDetected ! = RFAL_BR_KEEP ) )
{
rfalListenSetState ( RFAL_LM_STATE_READY_F ) ;
}
else if ( ( ( irqs & ST25R3916_IRQ_MASK_RXE ) ! = 0U ) & & ( gRFAL . Lm . brDetected ! = RFAL_BR_KEEP ) )
{
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_ERR1 ) ) ;
if ( ( ( irqs & ST25R3916_IRQ_MASK_CRC ) ! = 0U ) | | ( ( irqs & ST25R3916_IRQ_MASK_PAR ) ! = 0U ) | | ( ( irqs & ST25R3916_IRQ_MASK_ERR1 ) ! = 0U ) )
{
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
st25r3916TxOff ( ) ;
break ; /* A bad reception occurred, remain in same state */
}
/* Retrieve received data */
* gRFAL . Lm . rxLen = st25r3916GetNumFIFOBytes ( ) ;
st25r3916ReadFifo ( gRFAL . Lm . rxBuf , MIN ( * gRFAL . Lm . rxLen , rfalConvBitsToBytes ( gRFAL . Lm . rxBufLen ) ) ) ;
/*******************************************************************************/
/* REMARK: Silicon workaround ST25R3916 Errata #TBD */
/* In bitrate detection mode CRC is now checked for NFC-A frames */
if ( ( * gRFAL . Lm . rxLen > RFAL_CRC_LEN ) & & ( gRFAL . Lm . brDetected = = RFAL_BR_106 ) )
{
if ( rfalCrcCalculateCcitt ( RFAL_ISO14443A_CRC_INTVAL , gRFAL . Lm . rxBuf , * gRFAL . Lm . rxLen ) ! = 0U )
{
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
st25r3916TxOff ( ) ;
break ; /* A bad reception occurred, remain in same state */
}
}
/*******************************************************************************/
/* Check if the data we got has at least the CRC and remove it, otherwise leave at 0 */
* gRFAL . Lm . rxLen - = ( ( * gRFAL . Lm . rxLen > RFAL_CRC_LEN ) ? RFAL_CRC_LEN : * gRFAL . Lm . rxLen ) ;
* gRFAL . Lm . rxLen = ( uint16_t ) rfalConvBytesToBits ( * gRFAL . Lm . rxLen ) ;
gRFAL . Lm . dataFlag = true ;
/*Check if Observation Mode was enabled and disable it on ST25R391x */
rfalCheckDisableObsMode ( ) ;
}
else if ( ( ( irqs & ST25R3916_IRQ_MASK_RXE_PTA ) ! = 0U ) & & ( gRFAL . Lm . brDetected ! = RFAL_BR_KEEP ) )
{
if ( ( ( gRFAL . Lm . mdMask & RFAL_LM_MASK_NFCA ) ! = 0U ) & & ( gRFAL . Lm . brDetected = = RFAL_BR_106 ) )
{
st25r3916ReadRegister ( ST25R3916_REG_PASSIVE_TARGET_STATUS , & tmp ) ;
if ( tmp > ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_idle )
{
rfalListenSetState ( RFAL_LM_STATE_READY_A ) ;
}
}
}
else if ( ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U ) & & ( ! gRFAL . Lm . dataFlag ) )
{
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
/* MISRA 15.7 - Empty else */
}
break ;
/*******************************************************************************/
case RFAL_LM_STATE_READY_F :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_WU_F ) ! = 0U )
{
break ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_RXE ) ! = 0U )
{
/* Retrieve the error flags/irqs */
irqs | = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_ERR1 ) ) ;
if ( ( ( irqs & ST25R3916_IRQ_MASK_CRC ) ! = 0U ) | | ( ( irqs & ST25R3916_IRQ_MASK_ERR1 ) ! = 0U ) )
{
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
break ; /* A bad reception occurred, remain in same state */
}
/* Retrieve received data */
* gRFAL . Lm . rxLen = st25r3916GetNumFIFOBytes ( ) ;
st25r3916ReadFifo ( gRFAL . Lm . rxBuf , MIN ( * gRFAL . Lm . rxLen , rfalConvBitsToBytes ( gRFAL . Lm . rxBufLen ) ) ) ;
/* Check if the data we got has at least the CRC and remove it, otherwise leave at 0 */
* gRFAL . Lm . rxLen - = ( ( * gRFAL . Lm . rxLen > RFAL_CRC_LEN ) ? RFAL_CRC_LEN : * gRFAL . Lm . rxLen ) ;
* gRFAL . Lm . rxLen = ( uint16_t ) rfalConvBytesToBits ( * gRFAL . Lm . rxLen ) ;
gRFAL . Lm . dataFlag = true ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
/* MISRA 15.7 - Empty else */
}
break ;
/*******************************************************************************/
case RFAL_LM_STATE_READY_A :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_WU_A ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_ACTIVE_A ) ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
/* MISRA 15.7 - Empty else */
}
break ;
/*******************************************************************************/
case RFAL_LM_STATE_ACTIVE_A :
case RFAL_LM_STATE_ACTIVE_Ax :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_RXE ) ! = 0U )
{
/* Retrieve the error flags/irqs */
irqs | = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_ERR1 ) ) ;
* gRFAL . Lm . rxLen = st25r3916GetNumFIFOBytes ( ) ;
if ( ( ( irqs & ST25R3916_IRQ_MASK_CRC ) ! = 0U ) | | ( ( irqs & ST25R3916_IRQ_MASK_ERR1 ) ! = 0U ) | |
( ( irqs & ST25R3916_IRQ_MASK_PAR ) ! = 0U ) | | ( * gRFAL . Lm . rxLen < = RFAL_CRC_LEN ) )
{
/* Clear rx context and FIFO */
* gRFAL . Lm . rxLen = 0 ;
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/* Check if we should go to IDLE or Sleep */
if ( gRFAL . Lm . state = = RFAL_LM_STATE_ACTIVE_Ax )
{
rfalListenSleepStart ( RFAL_LM_STATE_SLEEP_A , gRFAL . Lm . rxBuf , gRFAL . Lm . rxBufLen , gRFAL . Lm . rxLen ) ;
}
else
{
rfalListenSetState ( RFAL_LM_STATE_IDLE ) ;
}
st25r3916DisableInterrupts ( ST25R3916_IRQ_MASK_RXE ) ;
break ;
}
/* Remove CRC from length */
* gRFAL . Lm . rxLen - = RFAL_CRC_LEN ;
/* Retrieve received data */
st25r3916ReadFifo ( gRFAL . Lm . rxBuf , MIN ( * gRFAL . Lm . rxLen , rfalConvBitsToBytes ( gRFAL . Lm . rxBufLen ) ) ) ;
* gRFAL . Lm . rxLen = ( uint16_t ) rfalConvBytesToBits ( * gRFAL . Lm . rxLen ) ;
gRFAL . Lm . dataFlag = true ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
/* MISRA 15.7 - Empty else */
}
break ;
/*******************************************************************************/
case RFAL_LM_STATE_SLEEP_A :
case RFAL_LM_STATE_SLEEP_B :
case RFAL_LM_STATE_SLEEP_AF :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_RXE_PTA ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_NFCT ) ! = 0U )
{
uint8_t newBr ;
/* Retrieve detected bitrate */
st25r3916ReadRegister ( ST25R3916_REG_NFCIP1_BIT_RATE , & newBr ) ;
newBr > > = ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_shift ;
if ( newBr > ST25R3916_REG_BIT_RATE_rxrate_424 )
{
newBr = ST25R3916_REG_BIT_RATE_rxrate_424 ;
}
gRFAL . Lm . brDetected = ( rfalBitRate ) ( newBr ) ; /* PRQA S 4342 # MISRA 10.5 - Guaranteed that no invalid enum values may be created. See also equalityGuard_RFAL_BR_106 ff.*/
}
if ( ( ( irqs & ST25R3916_IRQ_MASK_WU_F ) ! = 0U ) & & ( gRFAL . Lm . brDetected ! = RFAL_BR_KEEP ) )
{
rfalListenSetState ( RFAL_LM_STATE_READY_F ) ;
}
else if ( ( ( irqs & ST25R3916_IRQ_MASK_RXE ) ! = 0U ) & & ( gRFAL . Lm . brDetected ! = RFAL_BR_KEEP ) )
{
/* Clear rx context and FIFO */
* gRFAL . Lm . rxLen = 0 ;
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/* REMARK: In order to support CUP or proprietary frames, handling could be added here */
}
else if ( ( ( irqs & ST25R3916_IRQ_MASK_RXE_PTA ) ! = 0U ) & & ( gRFAL . Lm . brDetected ! = RFAL_BR_KEEP ) )
{
if ( ( ( gRFAL . Lm . mdMask & RFAL_LM_MASK_NFCA ) ! = 0U ) & & ( gRFAL . Lm . brDetected = = RFAL_BR_106 ) )
{
st25r3916ReadRegister ( ST25R3916_REG_PASSIVE_TARGET_STATUS , & tmp ) ;
if ( tmp > ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_halt )
{
rfalListenSetState ( RFAL_LM_STATE_READY_Ax ) ;
}
}
}
else if ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
/* MISRA 15.7 - Empty else */
}
break ;
/*******************************************************************************/
case RFAL_LM_STATE_READY_Ax :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
if ( ( irqs & ST25R3916_IRQ_MASK_WU_A_X ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_ACTIVE_Ax ) ;
}
else if ( ( irqs & ST25R3916_IRQ_MASK_EOF ) ! = 0U )
{
rfalListenSetState ( RFAL_LM_STATE_POWER_OFF ) ;
}
else
{
/* MISRA 15.7 - Empty else */
}
break ;
/*******************************************************************************/
case RFAL_LM_STATE_CARDEMU_4A :
case RFAL_LM_STATE_CARDEMU_4B :
case RFAL_LM_STATE_CARDEMU_3 :
case RFAL_LM_STATE_TARGET_F :
case RFAL_LM_STATE_TARGET_A :
break ;
/*******************************************************************************/
default :
return ERR_WRONG_STATE ;
}
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalListenStop ( void )
{
/* Check if RFAL is initialized */
if ( gRFAL . state < RFAL_STATE_INIT )
{
return ERR_WRONG_STATE ;
}
gRFAL . Lm . state = RFAL_LM_STATE_NOT_INIT ;
/*Check if Observation Mode was enabled and disable it on ST25R391x */
rfalCheckDisableObsMode ( ) ;
/* Re-Enable the Oscillator if not running */
st25r3916OscOn ( ) ;
/* Disable Receiver and Transmitter */
rfalFieldOff ( ) ;
/* Disable all automatic responses */
st25r3916SetRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_rfu | ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p ) ) ;
/* As there's no Off mode, set default value: ISO14443A with automatic RF Collision Avoidance Off */
st25r3916WriteRegister ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_om_iso14443a | ST25R3916_REG_MODE_tr_am_ook | ST25R3916_REG_MODE_nfc_ar_off ) ) ;
st25r3916DisableInterrupts ( ( ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_WU_A | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_RFU2 | ST25R3916_IRQ_MASK_OSC ) ) ;
st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_WU_A | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_RFU2 ) ) ;
/* Set Analog configurations for Listen Off event */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_OFF ) ) ;
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalListenSleepStart ( rfalLmState sleepSt , uint8_t * rxBuf , uint16_t rxBufLen , uint16_t * rxLen )
{
/* Check if RFAL is not initialized */
if ( gRFAL . state < RFAL_STATE_INIT )
{
return ERR_WRONG_STATE ;
}
switch ( sleepSt )
{
/*******************************************************************************/
case RFAL_LM_STATE_SLEEP_A :
/* Enable automatic responses for A */
st25r3916ClrRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ) ) ;
/* Reset NFCA target */
st25r3916ExecuteCommand ( ST25R3916_CMD_GOTO_SLEEP ) ;
/* Set Target mode, Bit Rate detection and Listen Mode for NFC-A */
st25r3916ChangeRegisterBits ( ST25R3916_REG_MODE ,
( ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_nfc_ar_mask ) ,
( ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0 | ST25R3916_REG_MODE_nfc_ar_off ) ) ;
break ;
/*******************************************************************************/
case RFAL_LM_STATE_SLEEP_AF :
/* Enable automatic responses for A + F */
st25r3916ClrRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ) ) ;
/* Reset NFCA target state */
st25r3916ExecuteCommand ( ST25R3916_CMD_GOTO_SLEEP ) ;
/* Set Target mode, Bit Rate detection, Listen Mode for NFC-A and NFC-F */
st25r3916ChangeRegisterBits ( ST25R3916_REG_MODE ,
( ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_nfc_ar_mask ) ,
( ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om2 | ST25R3916_REG_MODE_om0 | ST25R3916_REG_MODE_nfc_ar_off ) ) ;
break ;
/*******************************************************************************/
case RFAL_LM_STATE_SLEEP_B :
/* REMARK: Support for CE-B would be added here */
return ERR_NOT_IMPLEMENTED ;
/*******************************************************************************/
default :
return ERR_PARAM ;
}
/* Ensure that the NFCIP1 mode is disabled */
st25r3916ClrRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ST25R3916_REG_ISO14443A_NFC_nfc_f0 ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/* Clear and enable required IRQs */
st25r3916ClearAndEnableInterrupts ( ( ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR1 |
ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF | gRFAL . Lm . mdIrqs ) ) ;
/* Check whether the field was turn off right after the Sleep request */
if ( ! rfalIsExtFieldOn ( ) )
{
/*rfalLogD( "RFAL: curState: %02X newState: %02X \r\n", gRFAL.Lm.state, RFAL_LM_STATE_NOT_INIT );*/
rfalListenStop ( ) ;
return ERR_LINK_LOSS ;
}
/*rfalLogD( "RFAL: curState: %02X newState: %02X \r\n", gRFAL.Lm.state, sleepSt );*/
/* Set the new Sleep State*/
gRFAL . Lm . state = sleepSt ;
gRFAL . state = RFAL_STATE_LM ;
gRFAL . Lm . rxBuf = rxBuf ;
gRFAL . Lm . rxBufLen = rxBufLen ;
gRFAL . Lm . rxLen = rxLen ;
* gRFAL . Lm . rxLen = 0 ;
gRFAL . Lm . dataFlag = false ;
return ERR_NONE ;
}
/*******************************************************************************/
rfalLmState rfalListenGetState ( bool * dataFlag , rfalBitRate * lastBR )
{
/* Allow state retrieval even if gRFAL.state != RFAL_STATE_LM so *
* that this Lm state can be used by caller after activation */
if ( lastBR ! = NULL )
{
* lastBR = gRFAL . Lm . brDetected ;
}
if ( dataFlag ! = NULL )
{
* dataFlag = gRFAL . Lm . dataFlag ;
}
return gRFAL . Lm . state ;
}
/*******************************************************************************/
ReturnCode rfalListenSetState ( rfalLmState newSt )
{
ReturnCode ret ;
rfalLmState newState ;
bool reSetState ;
/* Check if RFAL is initialized */
if ( gRFAL . state < RFAL_STATE_INIT )
{
return ERR_WRONG_STATE ;
}
/* SetState clears the Data flag */
gRFAL . Lm . dataFlag = false ;
newState = newSt ;
ret = ERR_NONE ;
do {
reSetState = false ;
/*******************************************************************************/
switch ( newState )
{
/*******************************************************************************/
case RFAL_LM_STATE_POWER_OFF :
/* Enable the receiver and reset logic */
st25r3916SetRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_rx_en ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_STOP ) ;
if ( ( gRFAL . Lm . mdMask & RFAL_LM_MASK_NFCA ) ! = 0U )
{
/* Enable automatic responses for A */
st25r3916ClrRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ) ;
/* Prepares the NFCIP-1 Passive target logic to wait in the Sense/Idle state */
st25r3916ExecuteCommand ( ST25R3916_CMD_GOTO_SENSE ) ;
}
if ( ( gRFAL . Lm . mdMask & RFAL_LM_MASK_NFCF ) ! = 0U )
{
/* Enable automatic responses for F */
st25r3916ClrRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r ) ) ;
}
if ( ( gRFAL . Lm . mdMask & RFAL_LM_MASK_ACTIVE_P2P ) ! = 0U )
{
/* Ensure automatic response RF Collision Avoidance is back to only after Rx */
st25r3916ChangeRegisterBits ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_nfc_ar_mask , ST25R3916_REG_MODE_nfc_ar_auto_rx ) ;
/* Ensure that our field is Off, as automatic response RF Collision Avoidance may have been triggered */
st25r3916TxOff ( ) ;
}
/*******************************************************************************/
/* Ensure that the NFCIP1 mode is disabled */
st25r3916ClrRegisterBits ( ST25R3916_REG_ISO14443A_NFC , ST25R3916_REG_ISO14443A_NFC_nfc_f0 ) ;
/*******************************************************************************/
/* Clear and enable required IRQs */
st25r3916DisableInterrupts ( ST25R3916_IRQ_MASK_ALL ) ;
st25r3916ClearAndEnableInterrupts ( ( ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_OSC |
ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF | gRFAL . Lm . mdIrqs ) ) ;
/*******************************************************************************/
/* Clear the bitRate previously detected */
gRFAL . Lm . brDetected = RFAL_BR_KEEP ;
/*******************************************************************************/
/* Apply the initial mode */
st25r3916ChangeRegisterBits ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_nfc_ar_mask ) , ( uint8_t ) gRFAL . Lm . mdReg ) ;
/*******************************************************************************/
/* Check if external Field is already On */
if ( rfalIsExtFieldOn ( ) )
{
reSetState = true ;
newState = RFAL_LM_STATE_IDLE ; /* Set IDLE state */
}
# if 1 /* Perform bit rate detection in Low power mode */
else
{
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ( ST25R3916_REG_OP_CONTROL_tx_en | ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_en ) ) ;
}
# endif
break ;
/*******************************************************************************/
case RFAL_LM_STATE_IDLE :
/*******************************************************************************/
/* Check if device is coming from Low Power bit rate detection */
if ( ! st25r3916CheckReg ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_en , ST25R3916_REG_OP_CONTROL_en ) )
{
/* Exit Low Power mode and confirm the temporarily enable */
st25r3916SetRegisterBits ( ST25R3916_REG_OP_CONTROL , ( ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en ) ) ;
if ( ! st25r3916CheckReg ( ST25R3916_REG_AUX_DISPLAY , ST25R3916_REG_AUX_DISPLAY_osc_ok , ST25R3916_REG_AUX_DISPLAY_osc_ok ) )
{
/* Wait for Oscilator ready */
if ( st25r3916WaitForInterruptsTimed ( ST25R3916_IRQ_MASK_OSC , ST25R3916_TOUT_OSC_STABLE ) = = 0U )
{
ret = ERR_IO ;
break ;
}
}
}
else
{
st25r3916GetInterrupt ( ST25R3916_IRQ_MASK_OSC ) ;
}
/*******************************************************************************/
/* In Active P2P the Initiator may: Turn its field On; LM goes into IDLE state;
* Initiator sends an unexpected frame raising a Protocol error ; Initiator
* turns its field Off and ST25R3916 performs the automatic RF Collision
* Avoidance keeping our field On ; upon a Protocol error upper layer sets
* again the state to IDLE to clear dataFlag and wait for next data .
*
* Ensure that when upper layer calls SetState ( IDLE ) , it restores initial
* configuration and that check whether an external Field is still present */
if ( ( gRFAL . Lm . mdMask & RFAL_LM_MASK_ACTIVE_P2P ) ! = 0U )
{
/* Ensure nfc_ar is reseted and back to only after Rx */
st25r3916ExecuteCommand ( ST25R3916_CMD_STOP ) ;
st25r3916ChangeRegisterBits ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_nfc_ar_mask , ST25R3916_REG_MODE_nfc_ar_auto_rx ) ;
/* Ensure that our field is Off, as automatic response RF Collision Avoidance may have been triggered */
st25r3916TxOff ( ) ;
/* If external Field is no longer detected go back to POWER_OFF */
if ( ! st25r3916IsExtFieldOn ( ) )
{
reSetState = true ;
newState = RFAL_LM_STATE_POWER_OFF ; /* Set POWER_OFF state */
}
}
/*******************************************************************************/
/* If we are in ACTIVE_A, reEnable Listen for A before going to IDLE, otherwise do nothing */
if ( gRFAL . Lm . state = = RFAL_LM_STATE_ACTIVE_A )
{
/* Enable automatic responses for A and Reset NFCA target state */
st25r3916ClrRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ) ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_GOTO_SENSE ) ;
}
/* ReEnable the receiver */
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/*******************************************************************************/
/*Check if Observation Mode is enabled and set it on ST25R391x */
rfalCheckEnableObsModeRx ( ) ;
break ;
/*******************************************************************************/
case RFAL_LM_STATE_READY_F :
/*******************************************************************************/
/* If we're coming from BitRate detection mode, the Bit Rate Definition reg
* still has the last bit rate used .
* If a frame is received between setting the mode to Listen NFCA and
* setting Bit Rate Definition reg , it will raise a framing error .
* Set the bitrate immediately , and then the normal SetMode procedure */
st25r3916SetBitrate ( ( uint8_t ) gRFAL . Lm . brDetected , ( uint8_t ) gRFAL . Lm . brDetected ) ;
/*******************************************************************************/
/* Disable automatic responses for NFC-A */
st25r3916SetRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ) ) ;
/* Set Mode NFC-F only */
ret = rfalSetMode ( RFAL_MODE_LISTEN_NFCF , gRFAL . Lm . brDetected , gRFAL . Lm . brDetected ) ;
gRFAL . state = RFAL_STATE_LM ; /* Keep in Listen Mode */
/* ReEnable the receiver */
st25r3916ExecuteCommand ( ST25R3916_CMD_CLEAR_FIFO ) ;
st25r3916ExecuteCommand ( ST25R3916_CMD_UNMASK_RECEIVE_DATA ) ;
/* Clear any previous transmission errors (if Reader polled for other/unsupported technologies) */
st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_ERR1 ) ) ;
st25r3916EnableInterrupts ( ST25R3916_IRQ_MASK_RXE ) ; /* Start looking for any incoming data */
break ;
/*******************************************************************************/
case RFAL_LM_STATE_CARDEMU_3 :
/* Set Listen NFCF mode */
ret = rfalSetMode ( RFAL_MODE_LISTEN_NFCF , gRFAL . Lm . brDetected , gRFAL . Lm . brDetected ) ;
break ;
/*******************************************************************************/
case RFAL_LM_STATE_READY_Ax :
case RFAL_LM_STATE_READY_A :
/*******************************************************************************/
/* If we're coming from BitRate detection mode, the Bit Rate Definition reg
* still has the last bit rate used .
* If a frame is received between setting the mode to Listen NFCA and
* setting Bit Rate Definition reg , it will raise a framing error .
* Set the bitrate immediately , and then the normal SetMode procedure */
st25r3916SetBitrate ( ( uint8_t ) gRFAL . Lm . brDetected , ( uint8_t ) gRFAL . Lm . brDetected ) ;
/*******************************************************************************/
/* Disable automatic responses for NFC-F */
st25r3916SetRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r ) ) ;
/* Set Mode NFC-A only */
ret = rfalSetMode ( RFAL_MODE_LISTEN_NFCA , gRFAL . Lm . brDetected , gRFAL . Lm . brDetected ) ;
gRFAL . state = RFAL_STATE_LM ; /* Keep in Listen Mode */
break ;
/*******************************************************************************/
case RFAL_LM_STATE_ACTIVE_Ax :
case RFAL_LM_STATE_ACTIVE_A :
/* Disable automatic responses for A */
st25r3916SetRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a ) ) ;
/* Clear any previous transmission errors (if Reader polled for other/unsupported technologies) */
st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_ERR1 ) ) ;
st25r3916EnableInterrupts ( ST25R3916_IRQ_MASK_RXE ) ; /* Start looking for any incoming data */
break ;
case RFAL_LM_STATE_TARGET_F :
/* Disable Automatic response SENSF_REQ */
st25r3916SetRegisterBits ( ST25R3916_REG_PASSIVE_TARGET , ( ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r ) ) ;
break ;
/*******************************************************************************/
case RFAL_LM_STATE_SLEEP_A :
case RFAL_LM_STATE_SLEEP_B :
case RFAL_LM_STATE_SLEEP_AF :
/* These sleep states have to be set by the rfalListenSleepStart() method */
return ERR_REQUEST ;
/*******************************************************************************/
case RFAL_LM_STATE_CARDEMU_4A :
case RFAL_LM_STATE_CARDEMU_4B :
case RFAL_LM_STATE_TARGET_A :
/* States not handled by the LM, just keep state context */
break ;
/*******************************************************************************/
default :
return ERR_WRONG_STATE ;
}
}
while ( reSetState ) ;
gRFAL . Lm . state = newState ;
return ret ;
}
# endif /* RFAL_FEATURE_LISTEN_MODE */
/*******************************************************************************
* Wake - Up Mode *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if RFAL_FEATURE_WAKEUP_MODE
/*******************************************************************************/
ReturnCode rfalWakeUpModeStart ( const rfalWakeUpConfig * config )
{
uint8_t aux ;
uint8_t reg ;
uint32_t irqs ;
/* Check if RFAL is not initialized */
if ( gRFAL . state < RFAL_STATE_INIT )
{
return ERR_WRONG_STATE ;
}
/* The Wake-Up procedure is explained in detail in Application Note: AN4985 */
if ( config = = NULL )
{
gRFAL . wum . cfg . period = RFAL_WUM_PERIOD_200MS ;
gRFAL . wum . cfg . irqTout = false ;
gRFAL . wum . cfg . indAmp . enabled = true ;
gRFAL . wum . cfg . indPha . enabled = false ;
gRFAL . wum . cfg . cap . enabled = false ;
gRFAL . wum . cfg . indAmp . delta = 2U ;
gRFAL . wum . cfg . indAmp . reference = RFAL_WUM_REFERENCE_AUTO ;
gRFAL . wum . cfg . indAmp . autoAvg = false ;
/*******************************************************************************/
/* Check if AAT is enabled and if so make use of the SW Tag Detection */
if ( st25r3916CheckReg ( ST25R3916_REG_IO_CONF2 , ST25R3916_REG_IO_CONF2_aat_en , ST25R3916_REG_IO_CONF2_aat_en ) )
{
gRFAL . wum . cfg . swTagDetect = true ;
gRFAL . wum . cfg . indAmp . autoAvg = true ;
gRFAL . wum . cfg . indAmp . aaWeight = RFAL_WUM_AA_WEIGHT_16 ;
}
}
else
{
gRFAL . wum . cfg = * config ;
}
/* Check for valid configuration */
if ( ( ! gRFAL . wum . cfg . cap . enabled & & ! gRFAL . wum . cfg . indAmp . enabled & & ! gRFAL . wum . cfg . indPha . enabled ) | |
( gRFAL . wum . cfg . cap . enabled & & ( gRFAL . wum . cfg . indAmp . enabled | | gRFAL . wum . cfg . indPha . enabled ) ) | |
( gRFAL . wum . cfg . cap . enabled & & gRFAL . wum . cfg . swTagDetect ) | |
( ( gRFAL . wum . cfg . indAmp . reference > RFAL_WUM_REFERENCE_AUTO ) | |
( gRFAL . wum . cfg . indPha . reference > RFAL_WUM_REFERENCE_AUTO ) | |
( gRFAL . wum . cfg . cap . reference > RFAL_WUM_REFERENCE_AUTO ) ) )
{
return ERR_PARAM ;
}
irqs = ST25R3916_IRQ_MASK_NONE ;
/* Disable Tx, Rx, External Field Detector and set default ISO14443A mode */
st25r3916TxRxOff ( ) ;
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_en_fd_mask ) ;
st25r3916ChangeRegisterBits ( ST25R3916_REG_MODE , ( ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask ) , ( ST25R3916_REG_MODE_targ_init | ST25R3916_REG_MODE_om_iso14443a ) ) ;
/* Set Analog configurations for Wake-up On event */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON ) ) ;
/*******************************************************************************/
/* Prepare Wake-Up Timer Control Register */
reg = ( uint8_t ) ( ( ( uint8_t ) gRFAL . wum . cfg . period & 0x0FU ) < < ST25R3916_REG_WUP_TIMER_CONTROL_wut_shift ) ;
reg | = ( uint8_t ) ( ( ( uint8_t ) gRFAL . wum . cfg . period < ( uint8_t ) RFAL_WUM_PERIOD_100MS ) ? ST25R3916_REG_WUP_TIMER_CONTROL_wur : 0x00U ) ;
if ( gRFAL . wum . cfg . irqTout | | gRFAL . wum . cfg . swTagDetect )
{
reg | = ST25R3916_REG_WUP_TIMER_CONTROL_wto ;
irqs | = ST25R3916_IRQ_MASK_WT ;
}
/* Check if HW Wake-up is to be used or SW Tag detection */
if ( gRFAL . wum . cfg . swTagDetect )
{
gRFAL . wum . cfg . indAmp . reference = 0U ;
gRFAL . wum . cfg . indPha . reference = 0U ;
gRFAL . wum . cfg . cap . reference = 0U ;
}
else
{
/*******************************************************************************/
/* Check if Inductive Amplitude is to be performed */
if ( gRFAL . wum . cfg . indAmp . enabled )
{
aux = ( uint8_t ) ( ( gRFAL . wum . cfg . indAmp . delta ) < < ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d_shift ) ;
aux | = ( uint8_t ) ( gRFAL . wum . cfg . indAmp . aaInclMeas ? ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aam : 0x00U ) ;
aux | = ( uint8_t ) ( ( ( uint8_t ) gRFAL . wum . cfg . indAmp . aaWeight < < ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_shift ) & ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_mask ) ;
aux | = ( uint8_t ) ( gRFAL . wum . cfg . indAmp . autoAvg ? ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_ae : 0x00U ) ;
st25r3916WriteRegister ( ST25R3916_REG_AMPLITUDE_MEASURE_CONF , aux ) ;
/* Only need to set the reference if not using Auto Average */
if ( ! gRFAL . wum . cfg . indAmp . autoAvg )
{
if ( gRFAL . wum . cfg . indAmp . reference = = RFAL_WUM_REFERENCE_AUTO )
{
st25r3916MeasureAmplitude ( & aux ) ;
gRFAL . wum . cfg . indAmp . reference = aux ;
}
st25r3916WriteRegister ( ST25R3916_REG_AMPLITUDE_MEASURE_REF , ( uint8_t ) gRFAL . wum . cfg . indAmp . reference ) ;
}
reg | = ST25R3916_REG_WUP_TIMER_CONTROL_wam ;
irqs | = ST25R3916_IRQ_MASK_WAM ;
}
/*******************************************************************************/
/* Check if Inductive Phase is to be performed */
if ( gRFAL . wum . cfg . indPha . enabled )
{
aux = ( uint8_t ) ( ( gRFAL . wum . cfg . indPha . delta ) < < ST25R3916_REG_PHASE_MEASURE_CONF_pm_d_shift ) ;
aux | = ( uint8_t ) ( gRFAL . wum . cfg . indPha . aaInclMeas ? ST25R3916_REG_PHASE_MEASURE_CONF_pm_aam : 0x00U ) ;
aux | = ( uint8_t ) ( ( ( uint8_t ) gRFAL . wum . cfg . indPha . aaWeight < < ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_shift ) & ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_mask ) ;
aux | = ( uint8_t ) ( gRFAL . wum . cfg . indPha . autoAvg ? ST25R3916_REG_PHASE_MEASURE_CONF_pm_ae : 0x00U ) ;
st25r3916WriteRegister ( ST25R3916_REG_PHASE_MEASURE_CONF , aux ) ;
/* Only need to set the reference if not using Auto Average */
if ( ! gRFAL . wum . cfg . indPha . autoAvg )
{
if ( gRFAL . wum . cfg . indPha . reference = = RFAL_WUM_REFERENCE_AUTO )
{
st25r3916MeasurePhase ( & aux ) ;
gRFAL . wum . cfg . indPha . reference = aux ;
}
st25r3916WriteRegister ( ST25R3916_REG_PHASE_MEASURE_REF , ( uint8_t ) gRFAL . wum . cfg . indPha . reference ) ;
}
reg | = ST25R3916_REG_WUP_TIMER_CONTROL_wph ;
irqs | = ST25R3916_IRQ_MASK_WPH ;
}
/*******************************************************************************/
/* Check if Capacitive is to be performed */
if ( gRFAL . wum . cfg . cap . enabled )
{
/*******************************************************************************/
/* Perform Capacitive sensor calibration */
/* Disable Oscillator and Field */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ( ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_tx_en ) ) ;
/* Sensor gain should be configured on Analog Config: RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON */
/* Perform calibration procedure */
st25r3916CalibrateCapacitiveSensor ( NULL ) ;
/*******************************************************************************/
aux = ( uint8_t ) ( ( gRFAL . wum . cfg . cap . delta ) < < ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d_shift ) ;
aux | = ( uint8_t ) ( gRFAL . wum . cfg . cap . aaInclMeas ? ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aam : 0x00U ) ;
aux | = ( uint8_t ) ( ( ( uint8_t ) gRFAL . wum . cfg . cap . aaWeight < < ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_shift ) & ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_mask ) ;
aux | = ( uint8_t ) ( gRFAL . wum . cfg . cap . autoAvg ? ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_ae : 0x00U ) ;
st25r3916WriteRegister ( ST25R3916_REG_CAPACITANCE_MEASURE_CONF , aux ) ;
/* Only need to set the reference if not using Auto Average */
if ( ! gRFAL . wum . cfg . cap . autoAvg | | gRFAL . wum . cfg . swTagDetect )
{
if ( gRFAL . wum . cfg . indPha . reference = = RFAL_WUM_REFERENCE_AUTO )
{
st25r3916MeasureCapacitance ( & aux ) ;
gRFAL . wum . cfg . cap . reference = aux ;
}
st25r3916WriteRegister ( ST25R3916_REG_CAPACITANCE_MEASURE_REF , ( uint8_t ) gRFAL . wum . cfg . cap . reference ) ;
}
reg | = ST25R3916_REG_WUP_TIMER_CONTROL_wcap ;
irqs | = ST25R3916_IRQ_MASK_WCAP ;
}
}
/* Disable and clear all interrupts except Wake-Up IRQs */
st25r3916DisableInterrupts ( ST25R3916_IRQ_MASK_ALL ) ;
st25r3916GetInterrupt ( irqs ) ;
st25r3916EnableInterrupts ( irqs ) ;
/* Enable Low Power Wake-Up Mode (Disable: Oscilattor, Tx, Rx and External Field Detector) */
st25r3916WriteRegister ( ST25R3916_REG_WUP_TIMER_CONTROL , reg ) ;
st25r3916ChangeRegisterBits ( ST25R3916_REG_OP_CONTROL ,
( ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en |
ST25R3916_REG_OP_CONTROL_en_fd_mask | ST25R3916_REG_OP_CONTROL_wu ) ,
ST25R3916_REG_OP_CONTROL_wu ) ;
gRFAL . wum . state = RFAL_WUM_STATE_ENABLED ;
gRFAL . state = RFAL_STATE_WUM ;
return ERR_NONE ;
}
/*******************************************************************************/
bool rfalWakeUpModeHasWoke ( void )
{
return ( gRFAL . wum . state > = RFAL_WUM_STATE_ENABLED_WOKE ) ;
}
/*******************************************************************************/
static uint16_t rfalWakeUpModeFilter ( uint16_t curRef , uint16_t curVal , uint8_t weight )
{
uint16_t newRef ;
/* Perform the averaging|filter as describded in ST25R3916 DS */
/* Avoid signed arithmetics by spliting in two cases */
if ( curVal > curRef )
{
newRef = curRef + ( ( curVal - curRef ) / weight ) ;
/* In order for the reference to converge to final value *
* increment once the diff is smaller that the weight */
if ( ( curVal ! = curRef ) & & ( curRef = = newRef ) )
{
newRef & = 0xFF00U ;
newRef + = 0x0100U ;
}
}
else
{
newRef = curRef - ( ( curRef - curVal ) / weight ) ;
/* In order for the reference to converge to final value *
* decrement once the diff is smaller that the weight */
if ( ( curVal ! = curRef ) & & ( curRef = = newRef ) )
{
newRef & = 0xFF00U ;
}
}
return newRef ;
}
/*******************************************************************************/
static void rfalRunWakeUpModeWorker ( void )
{
uint32_t irqs ;
uint8_t reg ;
uint16_t value ;
uint16_t delta ;
if ( gRFAL . state ! = RFAL_STATE_WUM )
{
return ;
}
switch ( gRFAL . wum . state )
{
case RFAL_WUM_STATE_ENABLED :
case RFAL_WUM_STATE_ENABLED_WOKE :
irqs = st25r3916GetInterrupt ( ( ST25R3916_IRQ_MASK_WT | ST25R3916_IRQ_MASK_WAM | ST25R3916_IRQ_MASK_WPH | ST25R3916_IRQ_MASK_WCAP ) ) ;
if ( irqs = = ST25R3916_IRQ_MASK_NONE )
{
break ; /* No interrupt to process */
}
/*******************************************************************************/
/* Check and mark which measurement(s) cause interrupt */
if ( ( irqs & ST25R3916_IRQ_MASK_WAM ) ! = 0U )
{
st25r3916ReadRegister ( ST25R3916_REG_AMPLITUDE_MEASURE_RESULT , & reg ) ;
gRFAL . wum . state = RFAL_WUM_STATE_ENABLED_WOKE ;
}
if ( ( irqs & ST25R3916_IRQ_MASK_WPH ) ! = 0U )
{
st25r3916ReadRegister ( ST25R3916_REG_PHASE_MEASURE_RESULT , & reg ) ;
gRFAL . wum . state = RFAL_WUM_STATE_ENABLED_WOKE ;
}
if ( ( irqs & ST25R3916_IRQ_MASK_WCAP ) ! = 0U )
{
st25r3916ReadRegister ( ST25R3916_REG_CAPACITANCE_MEASURE_RESULT , & reg ) ;
gRFAL . wum . state = RFAL_WUM_STATE_ENABLED_WOKE ;
}
if ( ( irqs & ST25R3916_IRQ_MASK_WT ) ! = 0U )
{
/*******************************************************************************/
if ( gRFAL . wum . cfg . swTagDetect )
{
/* Enable Ready mode and wait the settle time */
st25r3916ChangeRegisterBits ( ST25R3916_REG_OP_CONTROL , ( ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_wu ) , ST25R3916_REG_OP_CONTROL_en ) ;
platformDelay ( RFAL_ST25R3916_AAT_SETTLE ) ;
/*******************************************************************************/
if ( gRFAL . wum . cfg . indAmp . enabled )
{
/* Perform amplitude measurement */
st25r3916MeasureAmplitude ( & reg ) ;
/* Convert inputs to TD format */
value = rfalConvTDFormat ( reg ) ;
delta = rfalConvTDFormat ( gRFAL . wum . cfg . indAmp . delta ) ;
/* Set first measurement as reference */
if ( gRFAL . wum . cfg . indAmp . reference = = 0U )
{
gRFAL . wum . cfg . indAmp . reference = value ;
}
/* Check if device should be woken */
if ( ( value > = ( gRFAL . wum . cfg . indAmp . reference + delta ) ) | |
( value < = ( gRFAL . wum . cfg . indAmp . reference - delta ) ) )
{
gRFAL . wum . state = RFAL_WUM_STATE_ENABLED_WOKE ;
break ;
}
/* Update moving reference if enabled */
if ( gRFAL . wum . cfg . indAmp . autoAvg )
{
gRFAL . wum . cfg . indAmp . reference = rfalWakeUpModeFilter ( gRFAL . wum . cfg . indAmp . reference , value , ( RFAL_WU_MIN_WEIGHT_VAL < < ( uint8_t ) gRFAL . wum . cfg . indAmp . aaWeight ) ) ;
}
}
/*******************************************************************************/
if ( gRFAL . wum . cfg . indPha . enabled )
{
/* Perform Phase measurement */
st25r3916MeasurePhase ( & reg ) ;
/* Convert inputs to TD format */
value = rfalConvTDFormat ( reg ) ;
delta = rfalConvTDFormat ( gRFAL . wum . cfg . indPha . delta ) ;
/* Set first measurement as reference */
if ( gRFAL . wum . cfg . indPha . reference = = 0U )
{
gRFAL . wum . cfg . indPha . reference = value ;
}
/* Check if device should be woken */
if ( ( value > = ( gRFAL . wum . cfg . indPha . reference + delta ) ) | |
( value < = ( gRFAL . wum . cfg . indPha . reference - delta ) ) )
{
gRFAL . wum . state = RFAL_WUM_STATE_ENABLED_WOKE ;
break ;
}
/* Update moving reference if enabled */
if ( gRFAL . wum . cfg . indPha . autoAvg )
{
gRFAL . wum . cfg . indPha . reference = rfalWakeUpModeFilter ( gRFAL . wum . cfg . indPha . reference , value , ( RFAL_WU_MIN_WEIGHT_VAL < < ( uint8_t ) gRFAL . wum . cfg . indPha . aaWeight ) ) ;
}
}
/* Re-Enable low power Wake-Up mode for wto to trigger another measurement(s) */
st25r3916ChangeRegisterBits ( ST25R3916_REG_OP_CONTROL , ( ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_wu ) , ( ST25R3916_REG_OP_CONTROL_wu ) ) ;
}
}
break ;
default :
/* MISRA 16.4: no empty default statement (a comment being enough) */
break ;
}
}
/*******************************************************************************/
ReturnCode rfalWakeUpModeStop ( void )
{
/* Check if RFAL is in Wake-up mode */
if ( gRFAL . state ! = RFAL_STATE_WUM )
{
return ERR_WRONG_STATE ;
}
gRFAL . wum . state = RFAL_WUM_STATE_NOT_INIT ;
/* Disable Wake-Up Mode */
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_wu ) ;
st25r3916DisableInterrupts ( ( ST25R3916_IRQ_MASK_WT | ST25R3916_IRQ_MASK_WAM | ST25R3916_IRQ_MASK_WPH | ST25R3916_IRQ_MASK_WCAP ) ) ;
/* Re-Enable External Field Detector as: Automatics */
st25r3916ChangeRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_en_fd_mask , ST25R3916_REG_OP_CONTROL_en_fd_auto_efd ) ;
/* Re-Enable the Oscillator */
st25r3916OscOn ( ) ;
/* Set Analog configurations for Wake-up Off event */
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_WAKEUP_OFF ) ) ;
return ERR_NONE ;
}
# endif /* RFAL_FEATURE_WAKEUP_MODE */
/*******************************************************************************
* Low - Power Mode *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if RFAL_FEATURE_LOWPOWER_MODE
/*******************************************************************************/
ReturnCode rfalLowPowerModeStart ( void )
{
/* Check if RFAL is not initialized */
if ( gRFAL . state < RFAL_STATE_INIT )
{
return ERR_WRONG_STATE ;
}
/* Stop any ongoing activity and set the device in low power by disabling oscillator, transmitter, receiver and external field detector */
st25r3916ExecuteCommand ( ST25R3916_CMD_STOP ) ;
st25r3916ClrRegisterBits ( ST25R3916_REG_OP_CONTROL , ( ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
ST25R3916_REG_OP_CONTROL_wu | ST25R3916_REG_OP_CONTROL_tx_en |
ST25R3916_REG_OP_CONTROL_en_fd_mask ) ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_ON ) ) ;
gRFAL . state = RFAL_STATE_IDLE ;
gRFAL . lpm . isRunning = true ;
2021-04-29 08:51:48 +00:00
platformDisableIrqCallback ( ) ;
2020-10-18 22:09:48 +00:00
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalLowPowerModeStop ( void )
{
ReturnCode ret ;
2021-04-29 08:51:48 +00:00
platformEnableIrqCallback ( ) ;
2020-10-18 22:09:48 +00:00
/* Check if RFAL is on right state */
if ( ! gRFAL . lpm . isRunning )
{
return ERR_WRONG_STATE ;
}
/* Re-enable device */
EXIT_ON_ERR ( ret , st25r3916OscOn ( ) ) ;
st25r3916ChangeRegisterBits ( ST25R3916_REG_OP_CONTROL , ST25R3916_REG_OP_CONTROL_en_fd_mask , ST25R3916_REG_OP_CONTROL_en_fd_auto_efd ) ;
rfalSetAnalogConfig ( ( RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_OFF ) ) ;
gRFAL . state = RFAL_STATE_INIT ;
return ERR_NONE ;
}
# endif /* RFAL_FEATURE_LOWPOWER_MODE */
/*******************************************************************************
* RF Chip *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*******************************************************************************/
ReturnCode rfalChipWriteReg ( uint16_t reg , const uint8_t * values , uint8_t len )
{
if ( ! st25r3916IsRegValid ( ( uint8_t ) reg ) )
{
return ERR_PARAM ;
}
return st25r3916WriteMultipleRegisters ( ( uint8_t ) reg , values , len ) ;
}
/*******************************************************************************/
ReturnCode rfalChipReadReg ( uint16_t reg , uint8_t * values , uint8_t len )
{
if ( ! st25r3916IsRegValid ( ( uint8_t ) reg ) )
{
return ERR_PARAM ;
}
return st25r3916ReadMultipleRegisters ( ( uint8_t ) reg , values , len ) ;
}
/*******************************************************************************/
ReturnCode rfalChipExecCmd ( uint16_t cmd )
{
if ( ! st25r3916IsCmdValid ( ( uint8_t ) cmd ) )
{
return ERR_PARAM ;
}
return st25r3916ExecuteCommand ( ( uint8_t ) cmd ) ;
}
/*******************************************************************************/
ReturnCode rfalChipWriteTestReg ( uint16_t reg , uint8_t value )
{
return st25r3916WriteTestRegister ( ( uint8_t ) reg , value ) ;
}
/*******************************************************************************/
ReturnCode rfalChipReadTestReg ( uint16_t reg , uint8_t * value )
{
return st25r3916ReadTestRegister ( ( uint8_t ) reg , value ) ;
}
/*******************************************************************************/
ReturnCode rfalChipChangeRegBits ( uint16_t reg , uint8_t valueMask , uint8_t value )
{
if ( ! st25r3916IsRegValid ( ( uint8_t ) reg ) )
{
return ERR_PARAM ;
}
return st25r3916ChangeRegisterBits ( ( uint8_t ) reg , valueMask , value ) ;
}
/*******************************************************************************/
ReturnCode rfalChipChangeTestRegBits ( uint16_t reg , uint8_t valueMask , uint8_t value )
{
st25r3916ChangeTestRegisterBits ( ( uint8_t ) reg , valueMask , value ) ;
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalChipSetRFO ( uint8_t rfo )
{
return st25r3916ChangeRegisterBits ( ST25R3916_REG_TX_DRIVER , ST25R3916_REG_TX_DRIVER_d_res_mask , rfo ) ;
}
/*******************************************************************************/
ReturnCode rfalChipGetRFO ( uint8_t * result )
{
ReturnCode ret ;
ret = st25r3916ReadRegister ( ST25R3916_REG_TX_DRIVER , result ) ;
( * result ) = ( ( * result ) & ST25R3916_REG_TX_DRIVER_d_res_mask ) ;
return ret ;
}
/*******************************************************************************/
ReturnCode rfalChipMeasureAmplitude ( uint8_t * result )
{
ReturnCode err ;
uint8_t reg_opc , reg_mode , reg_conf1 , reg_conf2 ;
/* Save registers which will be adjusted below */
st25r3916ReadRegister ( ST25R3916_REG_OP_CONTROL , & reg_opc ) ;
st25r3916ReadRegister ( ST25R3916_REG_MODE , & reg_mode ) ;
st25r3916ReadRegister ( ST25R3916_REG_RX_CONF1 , & reg_conf1 ) ;
st25r3916ReadRegister ( ST25R3916_REG_RX_CONF2 , & reg_conf2 ) ;
/* Set values as per defaults of DS. These regs/bits influence receiver chain and change amplitude */
/* Doing so achieves an amplitude comparable over a complete polling cylce */
st25r3916WriteRegister ( ST25R3916_REG_OP_CONTROL , ( reg_opc & ~ ST25R3916_REG_OP_CONTROL_rx_chn ) ) ;
st25r3916WriteRegister ( ST25R3916_REG_MODE , ST25R3916_REG_MODE_om_iso14443a
| ST25R3916_REG_MODE_targ_init
| ST25R3916_REG_MODE_tr_am_ook
| ST25R3916_REG_MODE_nfc_ar_off ) ;
st25r3916WriteRegister ( ST25R3916_REG_RX_CONF1 , ( reg_conf1 & ~ ST25R3916_REG_RX_CONF1_ch_sel_AM ) ) ;
st25r3916WriteRegister ( ST25R3916_REG_RX_CONF2 , ( ( reg_conf2 & ~ ( ST25R3916_REG_RX_CONF2_demod_mode | ST25R3916_REG_RX_CONF2_amd_sel ) )
| ST25R3916_REG_RX_CONF2_amd_sel_peak ) ) ;
/* Perform the actual measurement */
err = st25r3916MeasureAmplitude ( result ) ;
/* Restore values */
st25r3916WriteRegister ( ST25R3916_REG_OP_CONTROL , reg_opc ) ;
st25r3916WriteRegister ( ST25R3916_REG_MODE , reg_mode ) ;
st25r3916WriteRegister ( ST25R3916_REG_RX_CONF1 , reg_conf1 ) ;
st25r3916WriteRegister ( ST25R3916_REG_RX_CONF2 , reg_conf2 ) ;
return err ;
}
/*******************************************************************************/
ReturnCode rfalChipMeasurePhase ( uint8_t * result )
{
st25r3916MeasurePhase ( result ) ;
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalChipMeasureCapacitance ( uint8_t * result )
{
st25r3916MeasureCapacitance ( result ) ;
return ERR_NONE ;
}
/*******************************************************************************/
ReturnCode rfalChipMeasurePowerSupply ( uint8_t param , uint8_t * result )
{
* result = st25r3916MeasurePowerSupply ( param ) ;
return ERR_NONE ;
}
/*******************************************************************************/
extern uint8_t invalid_size_of_stream_configs [ ( sizeof ( struct st25r3916StreamConfig ) = = sizeof ( struct iso15693StreamConfig ) ) ? 1 : ( - 1 ) ] ;