mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-24 22:07:14 +03:00
bf8fd71c00
* nfc magic: introduce nfc app to work with magic cards * nfc: add nfc device functions to API * nfc magic: add bacis scenes * nfc magic: add wrong card and write confirm scenes * nfc magic: introduce magic lib * nfc magic: write magic lib * nfc magic: add write commands to magic lib * nfc magic: work on worker * furi_hal_nfc: add bits data exchage method to API * nfc magic: rework with new API * nfc magic: add check and wipe scenes * nfc magic: add icons, gui fixes * nfc: format python src Co-authored-by: あく <alleteam@gmail.com>
4816 lines
198 KiB
C
4816 lines
198 KiB
C
|
|
/******************************************************************************
|
|
* \attention
|
|
*
|
|
* <h2><center>© COPYRIGHT 2020 STMicroelectronics</center></h2>
|
|
*
|
|
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
|
|
* You may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* www.st.com/myliberty
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
|
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* PROJECT: 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 */
|
|
RfalStateChangedCallback state_changed_cb;
|
|
void* ctx;
|
|
} 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 : 4bit length
|
|
* 64 : Half a bit duration due to ST25R3916 Coherent receiver (1/fc) */
|
|
#define RFAL_FWT_A_ADJUSTMENT (512U + 64U)
|
|
|
|
/*! FWT ISO14443B adjustment:
|
|
* SOF (14etu) + 1Byte (10etu) + 1etu (IRQ comes 1etu after first byte) - 3etu (ST25R3916 sends TXE 3etu after) */
|
|
#define RFAL_FWT_B_ADJUSTMENT ((14U + 10U + 1U - 3U) * 128U)
|
|
|
|
/*! FWT FeliCa 212 adjustment:
|
|
* 1024 : Length of the two Sync bytes at 212kbps */
|
|
#define RFAL_FWT_F_212_ADJUSTMENT 1024U
|
|
|
|
/*! FWT FeliCa 424 adjustment:
|
|
* 512 : Length of the two Sync bytes at 424kbps */
|
|
#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) = 303us ; 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
|
|
* 1s for transmission and reception of a 4K message at 106kpbs (~425ms 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));
|
|
|
|
// 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));
|
|
|
|
/*******************************************************************************/
|
|
/* 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;
|
|
gRFAL.callbacks.state_changed_cb = NULL;
|
|
gRFAL.callbacks.ctx = 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;
|
|
}
|
|
|
|
void rfal_set_state_changed_callback(RfalStateChangedCallback callback) {
|
|
gRFAL.callbacks.state_changed_cb = callback;
|
|
}
|
|
|
|
void rfal_set_callback_context(void* context) {
|
|
gRFAL.callbacks.ctx = context;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
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();
|
|
}
|
|
|
|
ReturnCode rfalTransceiveBitsBlockingTx(
|
|
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 = {
|
|
.rxBuf = rxBuf,
|
|
.rxBufLen = rxBufLen,
|
|
.rxRcvdLen = actLen,
|
|
.txBuf = txBuf,
|
|
.txBufLen = txBufLen,
|
|
.flags = flags,
|
|
.fwt = 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;
|
|
}
|
|
|
|
ReturnCode rfalTransceiveBitsBlockingTxRx(
|
|
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, rfalTransceiveBitsBlockingTx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt));
|
|
ret = rfalTransceiveBlockingRx();
|
|
|
|
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(gRFAL.callbacks.ctx);
|
|
}
|
|
/*******************************************************************************/
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
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(gRFAL.callbacks.ctx);
|
|
}
|
|
/*******************************************************************************/
|
|
|
|
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;
|
|
|
|
// Call callback on state change
|
|
if(gRFAL.callbacks.state_changed_cb) {
|
|
gRFAL.callbacks.state_changed_cb(gRFAL.callbacks.ctx);
|
|
}
|
|
|
|
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, ®);
|
|
gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
|
|
}
|
|
|
|
if((irqs & ST25R3916_IRQ_MASK_WPH) != 0U) {
|
|
st25r3916ReadRegister(ST25R3916_REG_PHASE_MEASURE_RESULT, ®);
|
|
gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
|
|
}
|
|
|
|
if((irqs & ST25R3916_IRQ_MASK_WCAP) != 0U) {
|
|
st25r3916ReadRegister(ST25R3916_REG_CAPACITANCE_MEASURE_RESULT, ®);
|
|
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(®);
|
|
|
|
/* 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(®);
|
|
|
|
/* 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;
|
|
|
|
platformDisableIrqCallback();
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalLowPowerModeStop(void) {
|
|
ReturnCode ret;
|
|
|
|
platformEnableIrqCallback();
|
|
|
|
/* 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, ®_opc);
|
|
st25r3916ReadRegister(ST25R3916_REG_MODE, ®_mode);
|
|
st25r3916ReadRegister(ST25R3916_REG_RX_CONF1, ®_conf1);
|
|
st25r3916ReadRegister(ST25R3916_REG_RX_CONF2, ®_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)];
|