Fork of the GitHub
Diff: rfal_nfcv.cpp
- Revision:
- 0:75fc82583a41
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rfal_nfcv.cpp Thu Nov 14 14:34:50 2019 +0000 @@ -0,0 +1,625 @@ + +/****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> + * + * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/myliberty + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/* + * PROJECT: 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) + * + */ + +/* + ****************************************************************************** + * INCLUDES + ****************************************************************************** + */ +#include <platform1.h> +#include "rfal_nfcv.h" +#include "utils.h" + +/* + ****************************************************************************** + * ENABLE SWITCH + ****************************************************************************** + */ + +#ifndef RFAL_FEATURE_NFCV + #error " RFAL: Module configuration missing. Please enable/disable NFC-V module by setting: RFAL_FEATURE_NFCV " +#endif + +#if RFAL_FEATURE_NFCV + +/* + ****************************************************************************** + * GLOBAL DEFINES + ****************************************************************************** + */ + +#define RFAL_NFCV_INV_REQ_FLAG 0x06 /*!< INVENTORY_REQ INV_FLAG Digital 2.0 9.6.1 */ +#define RFAL_NFCV_INV_REQ_FLAG 0x06 /*!< INVENTORY_REQ INV_FLAG Digital 2.0 9.6.1 */ +#define RFAL_NFCV_MASKVAL_MAX_LEN 8 /*!< Mask value max length: 64 bits (UID length) */ +#define RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN 64 /*!< Mask value max length in 1 Slot mode in bits Digital 2.0 9.6.1.6 */ +#define RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN 60 /*!< Mask value max length in 16 Slot mode in bits Digital 2.0 9.6.1.6 */ +#define RFAL_NFCV_INV_REQ_HEADER_LEN 3 /*!< INVENTORY_REQ header length (INV_FLAG, CMD, MASK_LEN) */ +#define RFAL_NFCV_INV_RES_LEN 10 /*!< INVENTORY_RES length */ +#define RFAL_NFCV_CRC_LEN 2 /*!< NFC-V CRC length */ +#define RFAL_NFCV_MAX_SLOTS 16 /*!< NFC-V max number of Slots */ +#define RFAL_NFCV_MAX_GEN_DATA_LEN (RFAL_NFCV_MAX_BLOCK_LEN + RFAL_NFCV_UID_LEN) /*!< Max number of generic data*/ + +#define RFAL_CMD_LEN 1 /*!< Commandbyte length */ +#define RFAL_NFCV_FLAG_LEN 1 /*!< Flag byte length */ +#define RFAL_NFCV_DSFI_LEN 1 /*!< DSFID length */ +#define RFAL_NFCV_SLPREQ_REQ_FLAG 0x22 /*!< SLPV_REQ request flags Digital 2.0 (Candidate) 9.7.1.1 */ + +#define RFAL_NFCV_MAX_COLL_SUPPORTED 16 /*!< Maximum number of collisions supported by the Anticollision loop */ + +#define RFAL_FDT_POLL_MAX rfalConvMsTo1fc(20) /*!< */ + + + +/*! Time between EOFs - ISO 15693 defines t3min depending on modulation depth and data rate + * - NFC Forum defines FDTV,EOF = [10 ; 20]ms ISO15693 2000 8.4 Digital 2.0 9.7.4 */ +#define RFAL_NFCV_FDT_EOF 5 + + + +/* + ****************************************************************************** + * GLOBAL MACROS + ****************************************************************************** + */ + + +/* +****************************************************************************** +* 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; + + +/*! NFC-V Generic Req format */ +typedef struct +{ + uint8_t REQ_FLAG; /*!< Request Flags */ + uint8_t CMD; /*!< Command code */ + union { + uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value */ + uint8_t data[RFAL_NFCV_MAX_GEN_DATA_LEN]; /*!< Data */ + }payload; +} rfalNfcvGenericReq; + + +/*! NFC-V Generic Response format */ +typedef struct +{ + uint8_t RES_FLAG; /*!< Response Flags */ + uint8_t data[RFAL_NFCV_MAX_GEN_DATA_LEN]; /*!< Data */ +} rfalNfcvGenericRes; + + +/*! Container for a collision found during Anticollsion loop */ +typedef struct +{ + uint8_t maskLen; + uint8_t maskVal[RFAL_NFCV_MASKVAL_MAX_LEN]; +}rfalNfcvCollision; + + +/* +****************************************************************************** +* LOCAL FUNCTION PROTOTYPES +****************************************************************************** +*/ +static ReturnCode rfalNfvParseError( uint8_t err ); + +/* +****************************************************************************** +* LOCAL VARIABLES +****************************************************************************** +*/ + +/* +****************************************************************************** +* LOCAL FUNCTIONS +****************************************************************************** +*/ + +/*******************************************************************************/ +static ReturnCode rfalNfvParseError( 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( SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + + EXIT_ON_ERR( ret, rfalSetMode( RFAL_MODE_POLL_NFCV, RFAL_BR_26p48, RFAL_BR_26p48, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ); + rfalSetErrorHandling( RFAL_ERRORHANDLING_NFC ); + + rfalSetGT( RFAL_GT_NFCV_ADJUSTED ); + rfalSetFDTListen( RFAL_FDT_LISTEN_NFCV_POLLER ); + rfalSetFDTPoll( RFAL_FDT_POLL_NFCV_POLLER ); + + return ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerCheckPresence( rfalNfcvInventoryRes *invRes, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + + /* 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, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + + 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, uint8_t *maskVal, rfalNfcvInventoryRes *invRes, uint16_t* rcvdLen, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + rfalNfcvInventoryReq invReq; + uint16_t rxLen; + + if( ((maskVal == NULL) && (maskLen != 0)) || (invRes == NULL) ) + { + return ERR_PARAM; + } + + invReq.INV_FLAG = (RFAL_NFCV_INV_REQ_FLAG | nSlots); + invReq.CMD = RFAL_NFCF_CMD_INVENTORY; + invReq.MASK_LEN = 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 */ + ST_MEMCPY( invReq.MASK_VALUE, maskVal, rfalConvBitsToBytes(invReq.MASK_LEN) ); + + ret = rfalISO15693TransceiveAnticollisionFrame( (uint8_t*)&invReq, (RFAL_NFCV_INV_REQ_HEADER_LEN + rfalConvBitsToBytes(invReq.MASK_LEN)), (uint8_t*)invRes, sizeof(rfalNfcvInventoryRes), &rxLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + + /* Check for optional output parameter */ + if( rcvdLen != NULL ) + { + *rcvdLen = rxLen; + } + + if( ret == ERR_NONE ) + { + if( rxLen != rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN) ) + { + return ERR_PROTO; + } + } + + return ret; +} + +/*******************************************************************************/ +ReturnCode rfalNfcvPollerCollisionResolution( uint8_t devLimit, rfalNfcvListenDevice *nfcvDevList, uint8_t *devCnt, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + uint8_t slotNum; + uint16_t rcvdLen; + uint8_t colIt; + uint8_t colCnt; + /* bool colPending; */ + rfalNfcvCollision colFound[RFAL_NFCV_MAX_COLL_SUPPORTED]; + + /* NO_WARNING(colPending); */ + + if( (nfcvDevList == NULL) || (devCnt == NULL) ) + { + return ERR_PARAM; + } + + /* Initialize parameters */ + *devCnt = 0; + colIt = 0; + colCnt = 0; + /* colPending = false; */ + ST_MEMSET(nfcvDevList, 0x00, (sizeof(rfalNfcvListenDevice)*devLimit) ); + ST_MEMSET(colFound, 0x00, (sizeof(rfalNfcvCollision)*RFAL_NFCV_MAX_COLL_SUPPORTED) ); + + + /* Send INVENTORY_REQ with one slot Activity 2.0 9.3.7.1 (Symbol 0) */ + ret = rfalNfcvPollerInventory( RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &nfcvDevList->InvRes, NULL, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + + if( ret == ERR_TIMEOUT ) /* Exit if no device found Activity 2.0 9.3.7.2 (Symbol 1) */ + { + return ERR_NONE; + } + if( ret == ERR_NONE ) /* Device found without transmission error/collision Activity 2.0 9.3.7.3 (Symbol 2) */ + { + (*devCnt)++; + return ERR_NONE; + } + + /* A Collision has been identified Activity 2.0 9.3.7.2 (Symbol 3) */ + /* colPending = true; */ + + /* Check if the Collision Resolution is set to perform only Collision detection Activity 2.0 9.3.7.5 (Symbol 4)*/ + if( devLimit == 0 ) + { + return ERR_RF_COLLISION; + } + + + /*******************************************************************************/ + /* Collisions pending, Anticollision loop must be executed */ + /*******************************************************************************/ + + /* Execute until all collisions are resolved Activity 2.0 9.3.7.16 (Symbol 17) */ + do + { + /* Activity 2.0 9.3.7.5 (Symbol 6) */ + slotNum = 0; + /* colPending = false; */ + + + /* Send INVENTORY_REQ with 16 slots Activity 2.0 9.3.7.7 (Symbol 8) */ + ret = rfalNfcvPollerInventory( RFAL_NFCV_NUM_SLOTS_16, colFound[colIt].maskLen, colFound[colIt].maskVal, &nfcvDevList[(*devCnt)].InvRes, &rcvdLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + + /* If collision have already been found, move to next one */ + if( colCnt > 0 ) + { + colIt++; + } + + do + { + /*******************************************************************************/ + if( ret != ERR_TIMEOUT ) + { + if( ret == ERR_NONE ) + { + /* Check if the device found is already on the list and its response is a valid INVENTORY_RES */ + if( rcvdLen == rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN) ) + { + /* Activity 2.0 9.3.7.15 (Symbol 16) */ + (*devCnt)++; + } + } + /*******************************************************************************/ + else if(ret == ERR_RF_COLLISION) + { + /* Activity 2.0 9.3.7.15 (Symbol 16) */ + /* colPending = true; */ + + /* Ensure that the frame received has at least the FLAGS + DSFI */ + if( rcvdLen <= rfalConvBytesToBits( RFAL_NFCV_FLAG_LEN + RFAL_NFCV_DSFI_LEN ) ) + { + return ERR_RF_COLLISION; + } + + /*******************************************************************************/ + /* 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 */ + colFound[colCnt].maskLen = ( rcvdLen - rfalConvBytesToBits( RFAL_NFCV_FLAG_LEN + RFAL_NFCV_DSFI_LEN ) ); + ST_MEMCPY(colFound[colCnt].maskVal, nfcvDevList[(*devCnt)].InvRes.UID, RFAL_NFCV_UID_LEN); + colCnt++; + } + } + } + + /* Check if devices found have reached device limit Activity 2.0 9.3.7.15 (Symbol 16) */ + if( *devCnt >= devLimit ) + { + return ERR_NONE; + } + + platformDelay(RFAL_NFCV_FDT_EOF); /* Fulfil FDT EOF */ + ret = rfalISO15693TransceiveAnticollisionEOF( (uint8_t*)&nfcvDevList[(*devCnt)].InvRes, sizeof(rfalNfcvInventoryRes), &rcvdLen, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + slotNum++; + + } + while( slotNum < RFAL_NFCV_MAX_SLOTS ); /* Slot loop */ + }while( colIt < colCnt ); /* Collisions found loop */ + + return ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfvPollerSleep( uint8_t flags, uint8_t* uid, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + rfalNfcvSlpvReq slpReq; + uint8_t rxBuf; /* dummy buffer, just to perform Rx */ + + if( uid == NULL ) + { + return ERR_PARAM; + } + + /* Compute SLPV_REQ */ + slpReq.REQ_FLAG = (flags | RFAL_NFCV_REQ_FLAG_ADDRESS); /* Should be with UID according Digital 2.0 (Candidate) 9.7.1.1 */ + slpReq.CMD = RFAL_NFCF_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_FDT_POLL_NFCV_POLLER, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + if( ret != ERR_TIMEOUT ) + { + return ret; + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfvSelect( uint8_t flags, uint8_t* uid, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + uint16_t rcvLen; + ReturnCode ret; + rfalNfcvGenericReq req; + rfalNfcvGenericRes res; + + if( uid == NULL ) + { + return ERR_PARAM; + } + + /* Compute Request Command */ + req.REQ_FLAG = (flags | RFAL_NFCV_REQ_FLAG_ADDRESS); + req.CMD = RFAL_NFCF_CMD_SELECT; + ST_MEMCPY( req.payload.UID, uid, RFAL_NFCV_UID_LEN ); + + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, (RFAL_CMD_LEN + RFAL_NFCV_FLAG_LEN + RFAL_NFCV_UID_LEN), (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_MAX, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + if( ret != ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( rcvLen < RFAL_NFCV_FLAG_LEN ) + { + return ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( res.RES_FLAG & RFAL_NFCV_RES_FLAG_ERROR ) + { + return rfalNfvParseError( *res.data ); + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfvReadSingleBlock( uint8_t flags, uint8_t* uid, uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + rfalNfcvGenericReq req; + rfalNfcvGenericRes *res; + uint8_t msgIt; + + msgIt = 0; + res = (rfalNfcvGenericRes*)rxBuf; + + /* Compute Request Command */ + req.REQ_FLAG = (flags & (~RFAL_NFCV_REQ_FLAG_ADDRESS & ~RFAL_NFCV_REQ_FLAG_SELECT)); + req.CMD = RFAL_NFCF_CMD_READ_SINGLE_BLOCK; + + /* Check if request is to be sent in Addressed or Selected mode */ + if( uid != NULL ) + { + req.REQ_FLAG |= RFAL_NFCV_REQ_FLAG_ADDRESS; + ST_MEMCPY( req.payload.UID, uid, RFAL_NFCV_UID_LEN ); + msgIt += RFAL_NFCV_UID_LEN; + req.payload.data[ (RFAL_NFCV_UID_LEN + msgIt++) ] = blockNum; + } + else + { + req.REQ_FLAG |= RFAL_NFCV_REQ_FLAG_SELECT; + req.payload.data[msgIt++] = blockNum; + } + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, (RFAL_CMD_LEN + RFAL_NFCV_FLAG_LEN + msgIt), rxBuf, rxBufLen, rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_MAX, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + if( ret != ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( (*rcvLen) < RFAL_NFCV_FLAG_LEN ) + { + return ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( res->RES_FLAG & RFAL_NFCV_RES_FLAG_ERROR ) + { + return rfalNfvParseError( *(res->data) ); + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfvWriteSingleBlock( uint8_t flags, uint8_t* uid, uint8_t blockNum, uint8_t* wrData, uint8_t blockLen, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + uint16_t rcvLen; + rfalNfcvGenericReq req; + rfalNfcvGenericRes res; + uint8_t msgIt; + + if( blockLen > RFAL_NFCV_MAX_BLOCK_LEN ) + { + return ERR_PARAM; + } + + msgIt = 0; + + /* Compute Request Command */ + req.REQ_FLAG = (flags & (~RFAL_NFCV_REQ_FLAG_ADDRESS & ~RFAL_NFCV_REQ_FLAG_SELECT)); + req.CMD = RFAL_NFCF_CMD_WRITE_SINGLE_BLOCK; + + /* Check if request is to be sent in Addressed or Selected mode */ + if( uid != NULL ) + { + req.REQ_FLAG |= RFAL_NFCV_REQ_FLAG_ADDRESS; + ST_MEMCPY( req.payload.UID, uid, RFAL_NFCV_UID_LEN ); + msgIt += RFAL_NFCV_UID_LEN; + req.payload.data[msgIt++] = blockNum; + ST_MEMCPY( &req.payload.data[msgIt], wrData, blockLen ); + msgIt += blockLen; + } + else + { + req.REQ_FLAG |= RFAL_NFCV_REQ_FLAG_SELECT; + req.payload.data[msgIt++] = blockNum; + ST_MEMCPY( &req.payload.data[msgIt], wrData, blockLen ); + msgIt += blockLen; + } + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, (RFAL_CMD_LEN + RFAL_NFCV_FLAG_LEN + msgIt), (uint8_t*)&res, sizeof(rfalNfcvGenericRes), &rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_MAX, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + + if( ret != ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( rcvLen < RFAL_NFCV_FLAG_LEN ) + { + return ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( res.RES_FLAG & RFAL_NFCV_RES_FLAG_ERROR ) + { + return rfalNfvParseError( *res.data ); + } + + return ERR_NONE; +} + +/*******************************************************************************/ +ReturnCode rfalNfvReadMultipleBlocks( uint8_t flags, uint8_t* uid, uint8_t firstBlockNum, uint8_t numOfBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen, SPI* mspiChannel, ST25R3911* mST25, DigitalOut* gpio_cs, InterruptIn* IRQ, DigitalOut* fieldLED_01, DigitalOut* fieldLED_02, DigitalOut* fieldLED_03, DigitalOut* fieldLED_04, DigitalOut* fieldLED_05, DigitalOut* fieldLED_06 ) +{ + ReturnCode ret; + rfalNfcvGenericReq req; + rfalNfcvGenericRes *res; + uint8_t msgIt; + + msgIt = 0; + res = (rfalNfcvGenericRes*)rxBuf; + + /* Compute Request Command */ + req.REQ_FLAG = (flags & (~RFAL_NFCV_REQ_FLAG_ADDRESS & ~RFAL_NFCV_REQ_FLAG_SELECT)); + req.CMD = RFAL_NFCF_CMD_READ_MULTIPLE_BLOCKS; + + /* Check if request is to be sent in Addressed or Selected mode */ + if( uid != NULL ) + { + req.REQ_FLAG |= RFAL_NFCV_REQ_FLAG_ADDRESS; + ST_MEMCPY( req.payload.UID, uid, RFAL_NFCV_UID_LEN ); + msgIt += RFAL_NFCV_UID_LEN; + req.payload.data[ (RFAL_NFCV_UID_LEN + msgIt++) ] = firstBlockNum; + req.payload.data[ (RFAL_NFCV_UID_LEN + msgIt++) ] = numOfBlocks; + } + else + { + req.REQ_FLAG |= RFAL_NFCV_REQ_FLAG_SELECT; + req.payload.data[msgIt++] = firstBlockNum; + req.payload.data[msgIt++] = numOfBlocks; + } + + /* Transceive Command */ + ret = rfalTransceiveBlockingTxRx( (uint8_t*)&req, (RFAL_CMD_LEN + RFAL_NFCV_FLAG_LEN + msgIt), rxBuf, rxBufLen, rcvLen, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FDT_POLL_MAX, mspiChannel, mST25, gpio_cs, IRQ, fieldLED_01, fieldLED_02, fieldLED_03, fieldLED_04, fieldLED_05, fieldLED_06 ) ; + if( ret != ERR_NONE ) + { + return ret; + } + + /* Check if the response minimum length has been received */ + if( (*rcvLen) < RFAL_NFCV_FLAG_LEN ) + { + return ERR_PROTO; + } + + /* Check if an error has been signalled */ + if( res->RES_FLAG & RFAL_NFCV_RES_FLAG_ERROR ) + { + return rfalNfvParseError( *(res->data) ); + } + + return ERR_NONE; +} + +#endif /* RFAL_FEATURE_NFCV */