mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-23 21:34:35 +03:00
389ff92cc1
* Makefile, Scripts: new linter * About: remove ID from IC * Firmware: remove double define for DIVC/DIVR * Scripts: check folder names too. Docker: replace syntax check with make lint. * Reformat Sources and Migrate to new file naming convention * Docker: symlink clang-format-12 to clang-format * Add coding style guide
1058 lines
34 KiB
C
1058 lines
34 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: ST25R391x firmware
|
|
* Revision:
|
|
* LANGUAGE: ISO C99
|
|
*/
|
|
|
|
/*! \file rfal_nfcv.c
|
|
*
|
|
* \author Gustavo Patricio
|
|
*
|
|
* \brief Implementation of NFC-V Poller (ISO15693) device
|
|
*
|
|
* The definitions and helpers methods provided by this module are
|
|
* aligned with NFC-V (ISO15693)
|
|
*
|
|
* The definitions and helpers methods provided by this module
|
|
* are aligned with NFC-V Digital 2.1
|
|
*
|
|
*/
|
|
|
|
/*
|
|
******************************************************************************
|
|
* INCLUDES
|
|
******************************************************************************
|
|
*/
|
|
#include "rfal_nfcv.h"
|
|
#include "utils.h"
|
|
|
|
/*
|
|
******************************************************************************
|
|
* ENABLE SWITCH
|
|
******************************************************************************
|
|
*/
|
|
|
|
#ifndef RFAL_FEATURE_NFCV
|
|
#define RFAL_FEATURE_NFCV false /* NFC-V module configuration missing. Disabled by default */
|
|
#endif
|
|
|
|
#if RFAL_FEATURE_NFCV
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL DEFINES
|
|
******************************************************************************
|
|
*/
|
|
|
|
#define RFAL_NFCV_INV_REQ_FLAG \
|
|
0x06U /*!< INVENTORY_REQ INV_FLAG Digital 2.1 9.6.1 */
|
|
#define RFAL_NFCV_MASKVAL_MAX_LEN \
|
|
8U /*!< Mask value max length: 64 bits (UID length) */
|
|
#define RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN \
|
|
64U /*!< Mask value max length in 1 Slot mode in bits Digital 2.1 9.6.1.6 */
|
|
#define RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN \
|
|
60U /*!< Mask value max length in 16 Slot mode in bits Digital 2.1 9.6.1.6 */
|
|
#define RFAL_NFCV_MAX_SLOTS \
|
|
16U /*!< NFC-V max number of Slots */
|
|
#define RFAL_NFCV_INV_REQ_HEADER_LEN \
|
|
3U /*!< INVENTORY_REQ header length (INV_FLAG, CMD, MASK_LEN) */
|
|
#define RFAL_NFCV_INV_RES_LEN \
|
|
10U /*!< INVENTORY_RES length */
|
|
#define RFAL_NFCV_WR_MUL_REQ_HEADER_LEN \
|
|
4U /*!< Write Multiple header length (INV_FLAG, CMD, [UID], BNo, Bno) */
|
|
|
|
#define RFAL_NFCV_CMD_LEN \
|
|
1U /*!< Commandbyte length */
|
|
#define RFAL_NFCV_FLAG_POS \
|
|
0U /*!< Flag byte position */
|
|
#define RFAL_NFCV_FLAG_LEN \
|
|
1U /*!< Flag byte length */
|
|
#define RFAL_NFCV_DATASTART_POS \
|
|
1U /*!< Position of start of data */
|
|
#define RFAL_NFCV_DSFI_LEN \
|
|
1U /*!< DSFID length */
|
|
#define RFAL_NFCV_SLPREQ_REQ_FLAG \
|
|
0x22U /*!< SLPV_REQ request flags Digital 2.0 (Candidate) 9.7.1.1 */
|
|
#define RFAL_NFCV_RES_FLAG_NOERROR \
|
|
0x00U /*!< RES_FLAG indicating no error (checked during activation) */
|
|
|
|
#define RFAL_NFCV_MAX_COLL_SUPPORTED \
|
|
16U /*!< Maximum number of collisions supported by the Anticollision loop */
|
|
|
|
#define RFAL_NFCV_FDT_MAX \
|
|
rfalConvMsTo1fc(20) /*!< Maximum Wait time FDTV,EOF and MAX2 Digital 2.1 B.5*/
|
|
#define RFAL_NFCV_FDT_MAX1 \
|
|
4394U /*!< Read alike command FWT FDTV,LISTEN,MAX1 Digital 2.0 B.5 */
|
|
|
|
/*! Time from special frame to EOF
|
|
* ISO15693 2009 10.4.2 : 20ms
|
|
* NFC Forum defines Digital 2.0 9.7.4 : FDTV,EOF = [10 ; 20]ms
|
|
*/
|
|
#define RFAL_NFCV_FDT_EOF 20U
|
|
|
|
/*! Time between slots - ISO 15693 defines t3min depending on modulation depth and data rate.
|
|
* With only high-bitrate supported, AM modulation and a length of 12 bytes (96bits) for INV_RES we get:
|
|
* - ISO t3min = 96/26 ms + 300us = 4 ms
|
|
* - NFC Forum defines FDTV,INVENT_NORES = (4394 + 2048)/fc. Digital 2.0 B.5*/
|
|
#define RFAL_NFCV_FDT_V_INVENT_NORES 4U
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL MACROS
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*! Checks if a valid INVENTORY_RES is valid Digital 2.2 9.6.2.1 & 9.6.2.3 */
|
|
#define rfalNfcvCheckInvRes(f, l) \
|
|
(((l) == rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN)) && \
|
|
((f) == RFAL_NFCV_RES_FLAG_NOERROR))
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL TYPES
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*! NFC-V INVENTORY_REQ format Digital 2.0 9.6.1 */
|
|
typedef struct {
|
|
uint8_t INV_FLAG; /*!< Inventory Flags */
|
|
uint8_t CMD; /*!< Command code: 01h */
|
|
uint8_t MASK_LEN; /*!< Mask Value Length */
|
|
uint8_t MASK_VALUE[RFAL_NFCV_MASKVAL_MAX_LEN]; /*!< Mask Value */
|
|
} rfalNfcvInventoryReq;
|
|
|
|
/*! NFC-V SLP_REQ format Digital 2.0 (Candidate) 9.7.1 */
|
|
typedef struct {
|
|
uint8_t REQ_FLAG; /*!< Request Flags */
|
|
uint8_t CMD; /*!< Command code: 02h */
|
|
uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value */
|
|
} rfalNfcvSlpvReq;
|
|
|
|
/*! Container for a collision found during Anticollision loop */
|
|
typedef struct {
|
|
uint8_t maskLen;
|
|
uint8_t maskVal[RFAL_NFCV_MASKVAL_MAX_LEN];
|
|
} rfalNfcvCollision;
|
|
|
|
/*
|
|
******************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
******************************************************************************
|
|
*/
|
|
static ReturnCode rfalNfcvParseError(uint8_t err);
|
|
|
|
/*
|
|
******************************************************************************
|
|
* LOCAL VARIABLES
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
******************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*******************************************************************************/
|
|
static ReturnCode rfalNfcvParseError(uint8_t err) {
|
|
switch(err) {
|
|
case RFAL_NFCV_ERROR_CMD_NOT_SUPPORTED:
|
|
case RFAL_NFCV_ERROR_OPTION_NOT_SUPPORTED:
|
|
return ERR_NOTSUPP;
|
|
|
|
case RFAL_NFCV_ERROR_CMD_NOT_RECOGNIZED:
|
|
return ERR_PROTO;
|
|
|
|
case RFAL_NFCV_ERROR_WRITE_FAILED:
|
|
return ERR_WRITE;
|
|
|
|
default:
|
|
return ERR_REQUEST;
|
|
}
|
|
}
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL FUNCTIONS
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerInitialize(void) {
|
|
ReturnCode ret;
|
|
|
|
EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCV, RFAL_BR_26p48, RFAL_BR_26p48));
|
|
rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
|
|
|
|
rfalSetGT(RFAL_GT_NFCV);
|
|
rfalSetFDTListen(RFAL_FDT_LISTEN_NFCV_POLLER);
|
|
rfalSetFDTPoll(RFAL_FDT_POLL_NFCV_POLLER);
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerCheckPresence(rfalNfcvInventoryRes* invRes) {
|
|
ReturnCode ret;
|
|
|
|
/* INVENTORY_REQ with 1 slot and no Mask Activity 2.0 (Candidate) 9.2.3.32 */
|
|
ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, invRes, NULL);
|
|
|
|
if((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_FRAMING) ||
|
|
(ret == ERR_PROTO)) {
|
|
ret = ERR_NONE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerInventory(
|
|
rfalNfcvNumSlots nSlots,
|
|
uint8_t maskLen,
|
|
const uint8_t* maskVal,
|
|
rfalNfcvInventoryRes* invRes,
|
|
uint16_t* rcvdLen) {
|
|
ReturnCode ret;
|
|
rfalNfcvInventoryReq invReq;
|
|
uint16_t rxLen;
|
|
|
|
if(((maskVal == NULL) && (maskLen != 0U)) || (invRes == NULL)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
invReq.INV_FLAG = (RFAL_NFCV_INV_REQ_FLAG | (uint8_t)nSlots);
|
|
invReq.CMD = RFAL_NFCV_CMD_INVENTORY;
|
|
invReq.MASK_LEN = (uint8_t)MIN(
|
|
maskLen,
|
|
((nSlots == RFAL_NFCV_NUM_SLOTS_1) ?
|
|
RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN :
|
|
RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN)); /* Digital 2.0 9.6.1.6 */
|
|
|
|
if((rfalConvBitsToBytes(invReq.MASK_LEN) > 0U) && (maskVal != NULL)) /* MISRA 21.18 & 1.3 */
|
|
{
|
|
ST_MEMCPY(invReq.MASK_VALUE, maskVal, rfalConvBitsToBytes(invReq.MASK_LEN));
|
|
}
|
|
|
|
ret = rfalISO15693TransceiveAnticollisionFrame(
|
|
(uint8_t*)&invReq,
|
|
(uint8_t)(RFAL_NFCV_INV_REQ_HEADER_LEN + rfalConvBitsToBytes(invReq.MASK_LEN)),
|
|
(uint8_t*)invRes,
|
|
sizeof(rfalNfcvInventoryRes),
|
|
&rxLen);
|
|
|
|
/* Check for optional output parameter */
|
|
if(rcvdLen != NULL) {
|
|
*rcvdLen = rxLen;
|
|
}
|
|
|
|
if(ret == ERR_NONE) {
|
|
/* Check for valid INVENTORY_RES Digital 2.2 9.6.2.1 & 9.6.2.3 */
|
|
if(!rfalNfcvCheckInvRes(invRes->RES_FLAG, rxLen)) {
|
|
return ERR_PROTO;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerCollisionResolution(
|
|
rfalComplianceMode compMode,
|
|
uint8_t devLimit,
|
|
rfalNfcvListenDevice* nfcvDevList,
|
|
uint8_t* devCnt) {
|
|
ReturnCode ret;
|
|
uint8_t slotNum;
|
|
uint16_t rcvdLen;
|
|
uint8_t colIt;
|
|
uint8_t colCnt;
|
|
uint8_t colPos;
|
|
bool colPending;
|
|
rfalNfcvCollision colFound[RFAL_NFCV_MAX_COLL_SUPPORTED];
|
|
|
|
if((nfcvDevList == NULL) || (devCnt == NULL)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
/* Initialize parameters */
|
|
*devCnt = 0;
|
|
colIt = 0;
|
|
colCnt = 0;
|
|
colPending = false;
|
|
ST_MEMSET(colFound, 0x00, (sizeof(rfalNfcvCollision) * RFAL_NFCV_MAX_COLL_SUPPORTED));
|
|
|
|
if(devLimit > 0U) /* MISRA 21.18 */
|
|
{
|
|
ST_MEMSET(nfcvDevList, 0x00, (sizeof(rfalNfcvListenDevice) * devLimit));
|
|
}
|
|
|
|
NO_WARNING(
|
|
colPending); /* colPending is not exposed externally, in future it might become exposed/ouput parameter */
|
|
|
|
if(compMode == RFAL_COMPLIANCE_MODE_NFC) {
|
|
/* Send INVENTORY_REQ with one slot Activity 2.1 9.3.7.1 (Symbol 0) */
|
|
ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &nfcvDevList->InvRes, NULL);
|
|
|
|
if(ret == ERR_TIMEOUT) /* Exit if no device found Activity 2.1 9.3.7.2 (Symbol 1) */
|
|
{
|
|
return ERR_NONE;
|
|
}
|
|
if(ret ==
|
|
ERR_NONE) /* Device found without transmission error/collision Activity 2.1 9.3.7.3 (Symbol 2) */
|
|
{
|
|
(*devCnt)++;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/* A Collision has been identified Activity 2.1 9.3.7.4 (Symbol 3) */
|
|
colPending = true;
|
|
colCnt = 1;
|
|
|
|
/* Check if the Collision Resolution is set to perform only Collision detection Activity 2.1 9.3.7.5 (Symbol 4)*/
|
|
if(devLimit == 0U) {
|
|
return ERR_RF_COLLISION;
|
|
}
|
|
|
|
platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
|
|
|
|
/*******************************************************************************/
|
|
/* Collisions pending, Anticollision loop must be executed */
|
|
/*******************************************************************************/
|
|
} else {
|
|
/* Advance to 16 slots below without mask. Will give a good chance to identify multiple cards */
|
|
colPending = true;
|
|
colCnt = 1;
|
|
}
|
|
|
|
/* Execute until all collisions are resolved Activity 2.1 9.3.7.18 (Symbol 17) */
|
|
do {
|
|
/* Activity 2.1 9.3.7.7 (Symbol 6 / 7) */
|
|
colPending = false;
|
|
slotNum = 0;
|
|
|
|
do {
|
|
if(slotNum == 0U) {
|
|
/* Send INVENTORY_REQ with 16 slots Activity 2.1 9.3.7.9 (Symbol 8) */
|
|
ret = rfalNfcvPollerInventory(
|
|
RFAL_NFCV_NUM_SLOTS_16,
|
|
colFound[colIt].maskLen,
|
|
colFound[colIt].maskVal,
|
|
&nfcvDevList[(*devCnt)].InvRes,
|
|
&rcvdLen);
|
|
} else {
|
|
ret = rfalISO15693TransceiveEOFAnticollision(
|
|
(uint8_t*)&nfcvDevList[(*devCnt)].InvRes,
|
|
sizeof(rfalNfcvInventoryRes),
|
|
&rcvdLen);
|
|
}
|
|
slotNum++;
|
|
|
|
/*******************************************************************************/
|
|
if(ret != ERR_TIMEOUT) {
|
|
if(rcvdLen <
|
|
rfalConvBytesToBits(
|
|
RFAL_NFCV_INV_RES_LEN +
|
|
RFAL_NFCV_CRC_LEN)) { /* If only a partial frame was received make sure the FDT_V_INVENT_NORES is fulfilled */
|
|
platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
|
|
}
|
|
|
|
/* Check if response is a correct frame (no TxRx error) Activity 2.1 9.3.7.11 (Symbol 10)*/
|
|
if((ret == ERR_NONE) || (ret == ERR_PROTO)) {
|
|
/* Check if the device found is already on the list and its response is a valid INVENTORY_RES */
|
|
if(rfalNfcvCheckInvRes(nfcvDevList[(*devCnt)].InvRes.RES_FLAG, rcvdLen)) {
|
|
/* Activity 2.1 9.3.7.12 (Symbol 11) */
|
|
(*devCnt)++;
|
|
}
|
|
} else /* Treat everything else as collision */
|
|
{
|
|
/* Activity 2.1 9.3.7.17 (Symbol 16) */
|
|
colPending = true;
|
|
|
|
/*******************************************************************************/
|
|
/* Ensure that this collision still fits on the container */
|
|
if(colCnt < RFAL_NFCV_MAX_COLL_SUPPORTED) {
|
|
/* Store this collision on the container to be resolved later */
|
|
/* Activity 2.1 9.3.7.17 (Symbol 16): add the collision information
|
|
* (MASK_VAL + SN) to the list containing the collision information */
|
|
ST_MEMCPY(
|
|
colFound[colCnt].maskVal, colFound[colIt].maskVal, RFAL_NFCV_UID_LEN);
|
|
colPos = colFound[colIt].maskLen;
|
|
colFound[colCnt].maskVal[(colPos / RFAL_BITS_IN_BYTE)] &=
|
|
(uint8_t)((1U << (colPos % RFAL_BITS_IN_BYTE)) - 1U);
|
|
colFound[colCnt].maskVal[(colPos / RFAL_BITS_IN_BYTE)] |=
|
|
(uint8_t)((slotNum - 1U) << (colPos % RFAL_BITS_IN_BYTE));
|
|
colFound[colCnt].maskVal[((colPos / RFAL_BITS_IN_BYTE) + 1U)] =
|
|
(uint8_t)((slotNum - 1U) >> (RFAL_BITS_IN_BYTE - (colPos % RFAL_BITS_IN_BYTE)));
|
|
|
|
colFound[colCnt].maskLen = (colFound[colIt].maskLen + 4U);
|
|
|
|
colCnt++;
|
|
}
|
|
}
|
|
} else {
|
|
/* Timeout */
|
|
platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
|
|
}
|
|
|
|
/* Check if devices found have reached device limit Activity 2.1 9.3.7.13 (Symbol 12) */
|
|
if(*devCnt >= devLimit) {
|
|
return ERR_NONE;
|
|
}
|
|
|
|
} while(slotNum < RFAL_NFCV_MAX_SLOTS); /* Slot loop */
|
|
colIt++;
|
|
} while(colIt < colCnt); /* Collisions found loop */
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerSleepCollisionResolution(
|
|
uint8_t devLimit,
|
|
rfalNfcvListenDevice* nfcvDevList,
|
|
uint8_t* devCnt) {
|
|
uint8_t tmpDevCnt;
|
|
ReturnCode ret;
|
|
uint8_t i;
|
|
|
|
if((nfcvDevList == NULL) || (devCnt == NULL)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
*devCnt = 0;
|
|
|
|
do {
|
|
tmpDevCnt = 0;
|
|
ret = rfalNfcvPollerCollisionResolution(
|
|
RFAL_COMPLIANCE_MODE_ISO, (devLimit - *devCnt), &nfcvDevList[*devCnt], &tmpDevCnt);
|
|
|
|
for(i = *devCnt; i < (*devCnt + tmpDevCnt); i++) {
|
|
rfalNfcvPollerSleep(0x00, nfcvDevList[i].InvRes.UID);
|
|
nfcvDevList[i].isSleep = true;
|
|
}
|
|
*devCnt += tmpDevCnt;
|
|
} while((ret == ERR_NONE) && (tmpDevCnt > 0U) && (*devCnt < devLimit));
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerSleep(uint8_t flags, const uint8_t* uid) {
|
|
ReturnCode ret;
|
|
rfalNfcvSlpvReq slpReq;
|
|
uint8_t rxBuf; /* dummy buffer, just to perform Rx */
|
|
|
|
if(uid == NULL) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
/* Compute SLPV_REQ */
|
|
slpReq.REQ_FLAG =
|
|
(flags |
|
|
(uint8_t)
|
|
RFAL_NFCV_REQ_FLAG_ADDRESS); /* Should be with UID according Digital 2.0 (Candidate) 9.7.1.1 */
|
|
slpReq.CMD = RFAL_NFCV_CMD_SLPV;
|
|
ST_MEMCPY(slpReq.UID, uid, RFAL_NFCV_UID_LEN);
|
|
|
|
/* NFC Forum device SHALL wait at least FDTVpp to consider the SLPV acknowledged (FDTVpp = FDTVpoll) Digital 2.0 (Candidate) 9.7 9.8.2 */
|
|
ret = rfalTransceiveBlockingTxRx(
|
|
(uint8_t*)&slpReq,
|
|
sizeof(rfalNfcvSlpvReq),
|
|
&rxBuf,
|
|
sizeof(rxBuf),
|
|
NULL,
|
|
RFAL_TXRX_FLAGS_DEFAULT,
|
|
RFAL_NFCV_FDT_MAX1);
|
|
if(ret != ERR_TIMEOUT) {
|
|
return ret;
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerSelect(uint8_t flags, const uint8_t* uid) {
|
|
uint16_t rcvLen;
|
|
rfalNfcvGenericRes res;
|
|
|
|
if(uid == NULL) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_SELECT,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
NULL,
|
|
0U,
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerReadSingleBlock(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint8_t blockNum,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
uint8_t bn;
|
|
|
|
bn = blockNum;
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_READ_SINGLE_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
&bn,
|
|
sizeof(uint8_t),
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerWriteSingleBlock(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint8_t blockNum,
|
|
const uint8_t* wrData,
|
|
uint8_t blockLen) {
|
|
uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
|
|
uint8_t dataLen;
|
|
uint16_t rcvLen;
|
|
rfalNfcvGenericRes res;
|
|
|
|
/* Check for valid parameters */
|
|
if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
dataLen = 0U;
|
|
|
|
/* Compute Request Data */
|
|
data[dataLen++] = blockNum; /* Set Block Number (8 bits) */
|
|
ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
|
|
dataLen += blockLen;
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
data,
|
|
dataLen,
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerLockBlock(uint8_t flags, const uint8_t* uid, uint8_t blockNum) {
|
|
uint16_t rcvLen;
|
|
rfalNfcvGenericRes res;
|
|
uint8_t bn;
|
|
|
|
bn = blockNum;
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_LOCK_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
&bn,
|
|
sizeof(uint8_t),
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerReadMultipleBlocks(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint8_t firstBlockNum,
|
|
uint8_t numOfBlocks,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)];
|
|
uint8_t dataLen;
|
|
|
|
dataLen = 0U;
|
|
|
|
/* Compute Request Data */
|
|
data[dataLen++] = firstBlockNum; /* Set first Block Number */
|
|
data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
data,
|
|
dataLen,
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerWriteMultipleBlocks(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint8_t firstBlockNum,
|
|
uint8_t numOfBlocks,
|
|
uint8_t* txBuf,
|
|
uint16_t txBufLen,
|
|
uint8_t blockLen,
|
|
const uint8_t* wrData,
|
|
uint16_t wrDataLen) {
|
|
ReturnCode ret;
|
|
uint16_t rcvLen;
|
|
uint16_t reqLen;
|
|
rfalNfcvGenericRes res;
|
|
uint16_t msgIt;
|
|
|
|
/* Calculate required buffer length */
|
|
reqLen =
|
|
(uint16_t)((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) : (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
|
|
|
|
if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
|
|
((((uint16_t)numOfBlocks) * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U) ||
|
|
(wrData == NULL)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
msgIt = 0;
|
|
|
|
/* Compute Request Command */
|
|
txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
|
|
txBuf[msgIt++] = RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS;
|
|
|
|
/* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
|
|
if(uid != NULL) {
|
|
txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
|
|
ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
|
|
msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
|
|
}
|
|
|
|
txBuf[msgIt++] = firstBlockNum;
|
|
txBuf[msgIt++] = (numOfBlocks - 1U);
|
|
|
|
if(wrDataLen > 0U) /* MISRA 21.18 */
|
|
{
|
|
ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
|
|
msgIt += wrDataLen;
|
|
}
|
|
|
|
/* Transceive Command */
|
|
ret = rfalTransceiveBlockingTxRx(
|
|
txBuf,
|
|
msgIt,
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen,
|
|
RFAL_TXRX_FLAGS_DEFAULT,
|
|
RFAL_NFCV_FDT_MAX);
|
|
|
|
if(ret != ERR_NONE) {
|
|
return ret;
|
|
}
|
|
|
|
/* Check if the response minimum length has been received */
|
|
if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
|
|
return ERR_PROTO;
|
|
}
|
|
|
|
/* Check if an error has been signalled */
|
|
if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
|
|
return rfalNfcvParseError(*res.data);
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerExtendedReadSingleBlock(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint16_t blockNum,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
|
|
uint8_t dataLen;
|
|
|
|
dataLen = 0U;
|
|
|
|
/* Compute Request Data */
|
|
data[dataLen++] = (uint8_t)
|
|
blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
|
|
data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
data,
|
|
dataLen,
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerExtendedWriteSingleBlock(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint16_t blockNum,
|
|
const uint8_t* wrData,
|
|
uint8_t blockLen) {
|
|
uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
|
|
uint8_t dataLen;
|
|
uint16_t rcvLen;
|
|
rfalNfcvGenericRes res;
|
|
|
|
/* Check for valid parameters */
|
|
if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
dataLen = 0U;
|
|
|
|
/* Compute Request Data */
|
|
data[dataLen++] = (uint8_t)
|
|
blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
|
|
data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
|
|
ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
|
|
dataLen += blockLen;
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
data,
|
|
dataLen,
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode
|
|
rfalNfcvPollerExtendedLockSingleBlock(uint8_t flags, const uint8_t* uid, uint16_t blockNum) {
|
|
uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
|
|
uint8_t dataLen;
|
|
uint16_t rcvLen;
|
|
rfalNfcvGenericRes res;
|
|
|
|
dataLen = 0U;
|
|
|
|
/* Compute Request Data */
|
|
data[dataLen++] = (uint8_t)
|
|
blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
|
|
data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
data,
|
|
dataLen,
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint16_t firstBlockNum,
|
|
uint16_t numOfBlocks,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)];
|
|
uint8_t dataLen;
|
|
|
|
dataLen = 0U;
|
|
|
|
/* Compute Request Data */
|
|
data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU);
|
|
data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU);
|
|
data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU);
|
|
data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU);
|
|
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
data,
|
|
dataLen,
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint16_t firstBlockNum,
|
|
uint16_t numOfBlocks,
|
|
uint8_t* txBuf,
|
|
uint16_t txBufLen,
|
|
uint8_t blockLen,
|
|
const uint8_t* wrData,
|
|
uint16_t wrDataLen) {
|
|
ReturnCode ret;
|
|
uint16_t rcvLen;
|
|
uint16_t reqLen;
|
|
rfalNfcvGenericRes res;
|
|
uint16_t msgIt;
|
|
uint16_t nBlocks;
|
|
|
|
/* Calculate required buffer length */
|
|
reqLen =
|
|
((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) :
|
|
(RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
|
|
|
|
if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
|
|
(((uint16_t)numOfBlocks * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U)) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
msgIt = 0;
|
|
nBlocks = (numOfBlocks - 1U);
|
|
|
|
/* Compute Request Command */
|
|
txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
|
|
txBuf[msgIt++] = RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK;
|
|
|
|
/* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
|
|
if(uid != NULL) {
|
|
txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
|
|
ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
|
|
msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
|
|
}
|
|
|
|
txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 0) & 0xFFU);
|
|
txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 8) & 0xFFU);
|
|
txBuf[msgIt++] = (uint8_t)((nBlocks >> 0) & 0xFFU);
|
|
txBuf[msgIt++] = (uint8_t)((nBlocks >> 8) & 0xFFU);
|
|
|
|
if(wrDataLen > 0U) /* MISRA 21.18 */
|
|
{
|
|
ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
|
|
msgIt += wrDataLen;
|
|
}
|
|
|
|
/* Transceive Command */
|
|
ret = rfalTransceiveBlockingTxRx(
|
|
txBuf,
|
|
msgIt,
|
|
(uint8_t*)&res,
|
|
sizeof(rfalNfcvGenericRes),
|
|
&rcvLen,
|
|
RFAL_TXRX_FLAGS_DEFAULT,
|
|
RFAL_NFCV_FDT_MAX);
|
|
|
|
if(ret != ERR_NONE) {
|
|
return ret;
|
|
}
|
|
|
|
/* Check if the response minimum length has been received */
|
|
if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
|
|
return ERR_PROTO;
|
|
}
|
|
|
|
/* Check if an error has been signalled */
|
|
if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
|
|
return rfalNfcvParseError(*res.data);
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerGetSystemInformation(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_GET_SYS_INFO,
|
|
flags,
|
|
RFAL_NFCV_PARAM_SKIP,
|
|
uid,
|
|
NULL,
|
|
0U,
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerExtendedGetSystemInformation(
|
|
uint8_t flags,
|
|
const uint8_t* uid,
|
|
uint8_t requestField,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
return rfalNfcvPollerTransceiveReq(
|
|
RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO,
|
|
flags,
|
|
requestField,
|
|
uid,
|
|
NULL,
|
|
0U,
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode rfalNfcvPollerTransceiveReq(
|
|
uint8_t cmd,
|
|
uint8_t flags,
|
|
uint8_t param,
|
|
const uint8_t* uid,
|
|
const uint8_t* data,
|
|
uint16_t dataLen,
|
|
uint8_t* rxBuf,
|
|
uint16_t rxBufLen,
|
|
uint16_t* rcvLen) {
|
|
ReturnCode ret;
|
|
rfalNfcvGenericReq req;
|
|
uint8_t msgIt;
|
|
rfalBitRate rxBR;
|
|
bool fastMode;
|
|
|
|
msgIt = 0;
|
|
fastMode = false;
|
|
|
|
/* Check for valid parameters */
|
|
if((rxBuf == NULL) || (rcvLen == NULL) || ((dataLen > 0U) && (data == NULL)) ||
|
|
(dataLen > ((uid != NULL) ? RFAL_NFCV_MAX_GEN_DATA_LEN :
|
|
(RFAL_NFCV_MAX_GEN_DATA_LEN - RFAL_NFCV_UID_LEN)))) {
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
/* Check if the command is an ST's Fast command */
|
|
if((cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION)) {
|
|
/* Store current Rx bit rate and move to fast mode */
|
|
rfalGetBitRate(NULL, &rxBR);
|
|
rfalSetBitRate(RFAL_BR_KEEP, RFAL_BR_52p97);
|
|
|
|
fastMode = true;
|
|
}
|
|
|
|
/* Compute Request Command */
|
|
req.REQ_FLAG = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
|
|
req.CMD = cmd;
|
|
|
|
/* Prepend parameter on ceratin proprietary requests: IC Manuf, Parameters */
|
|
if(param != RFAL_NFCV_PARAM_SKIP) {
|
|
req.payload.data[msgIt++] = param;
|
|
}
|
|
|
|
/* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
|
|
if(uid != NULL) {
|
|
req.REQ_FLAG |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
|
|
ST_MEMCPY(&req.payload.data[msgIt], uid, RFAL_NFCV_UID_LEN);
|
|
msgIt += RFAL_NFCV_UID_LEN;
|
|
}
|
|
|
|
if(dataLen > 0U) {
|
|
ST_MEMCPY(&req.payload.data[msgIt], data, dataLen);
|
|
msgIt += (uint8_t)dataLen;
|
|
}
|
|
|
|
/* Transceive Command */
|
|
ret = rfalTransceiveBlockingTxRx(
|
|
(uint8_t*)&req,
|
|
(RFAL_NFCV_CMD_LEN + RFAL_NFCV_FLAG_LEN + (uint16_t)msgIt),
|
|
rxBuf,
|
|
rxBufLen,
|
|
rcvLen,
|
|
RFAL_TXRX_FLAGS_DEFAULT,
|
|
RFAL_NFCV_FDT_MAX);
|
|
|
|
/* If the Option Flag is set in certain commands an EOF needs to be sent after 20ms to retrieve the VICC response ISO15693-3 2009 10.4.2 & 10.4.3 & 10.4.5 */
|
|
if(((flags & (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION) != 0U) &&
|
|
((cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_LOCK_BLOCK) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK) ||
|
|
(cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK))) {
|
|
ret = rfalISO15693TransceiveEOF(rxBuf, (uint8_t)rxBufLen, rcvLen);
|
|
}
|
|
|
|
/* Restore Rx BitRate */
|
|
if(fastMode) {
|
|
rfalSetBitRate(RFAL_BR_KEEP, rxBR);
|
|
}
|
|
|
|
if(ret != ERR_NONE) {
|
|
return ret;
|
|
}
|
|
|
|
/* Check if the response minimum length has been received */
|
|
if((*rcvLen) < (uint8_t)RFAL_NFCV_FLAG_LEN) {
|
|
return ERR_PROTO;
|
|
}
|
|
|
|
/* Check if an error has been signalled */
|
|
if((rxBuf[RFAL_NFCV_FLAG_POS] & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
|
|
return rfalNfcvParseError(rxBuf[RFAL_NFCV_DATASTART_POS]);
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
#endif /* RFAL_FEATURE_NFCV */
|