mirror of
https://gitlab.com/fabinfra/fabhardware/FabReader2.git
synced 2025-03-13 07:01:53 +01:00
1150 lines
42 KiB
C
1150 lines
42 KiB
C
/******************************************************************************
|
|
* \attention
|
|
*
|
|
* <h2><center>© COPYRIGHT 2019 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: NDEF firmware
|
|
* Revision:
|
|
* LANGUAGE: ISO C99
|
|
*/
|
|
|
|
/*! \file
|
|
*
|
|
* \author
|
|
*
|
|
* \brief Provides NDEF methods and definitions to access NFC-V Forum T5T
|
|
*
|
|
* This module provides an interface to perform as a NFC-V Reader/Writer
|
|
* to handle a Type 5 Tag T5T
|
|
*
|
|
*/
|
|
|
|
/*
|
|
******************************************************************************
|
|
* INCLUDES
|
|
******************************************************************************
|
|
*/
|
|
#include "ndef_poller.h"
|
|
#include "ndef_t5t.h"
|
|
#include "utils.h"
|
|
|
|
/*
|
|
******************************************************************************
|
|
* ENABLE SWITCH
|
|
******************************************************************************
|
|
*/
|
|
|
|
#ifndef RFAL_FEATURE_NFCV
|
|
#error " RFAL: Module configuration missing. Please enable/disable T5T support by setting: RFAL_FEATURE_NFCV "
|
|
#endif
|
|
|
|
#if RFAL_FEATURE_NFCV
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL DEFINES
|
|
******************************************************************************
|
|
*/
|
|
|
|
#define NDEF_T5T_UID_MANUFACTURER_ID_POS 6U /*!< Manufacturer ID Offset in UID buffer (reverse) */
|
|
#define NDEF_T5T_MANUFACTURER_ID_ST 0x02U /*!< Manufacturer ID for ST */
|
|
|
|
#define NDEF_T5T_SYSINFO_MAX_LEN 22U /*!< Max length for (Extended) Get System Info response */
|
|
|
|
#define NDEF_T5T_MLEN_DIVIDER 8U /*!< T5T_area size is measured in bytes is equal to 8 * MLEN */
|
|
|
|
#define NDEF_T5T_TLV_L_3_BYTES_LEN 3U /*!< TLV L Length: 3 bytes */
|
|
#define NDEF_T5T_TLV_L_1_BYTES_LEN 1U /*!< TLV L Length: 1 bytes */
|
|
#define NDEF_T5T_TLV_T_LEN 1U /*!< TLV T Length: 1 bytes */
|
|
|
|
#define NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR 256U /*!< Max number of blocks for 1 byte addressing */
|
|
#define NDEF_T5T_MAX_MLEN_1_BYTE_ENCODING 256U /*!< MLEN max value for 1 byte encoding */
|
|
|
|
#define NDEF_T5T_TL_MAX_SIZE (NDEF_T5T_TLV_T_LEN \
|
|
+ NDEF_T5T_TLV_L_3_BYTES_LEN) /*!< Max TL size */
|
|
|
|
#define NDEF_T5T_TLV_NDEF 0x03U /*!< TLV flag NDEF value */
|
|
#define NDEF_T5T_TLV_PROPRIETARY 0xFDU /*!< TLV flag PROPRIETARY value */
|
|
#define NDEF_T5T_TLV_TERMINATOR 0xFEU /*!< TLV flag TERMINATOR value */
|
|
#define NDEF_T5T_TLV_RFU 0x00U /*!< TLV flag RFU value */
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* GLOBAL TYPES
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL MACROS
|
|
******************************************************************************
|
|
*/
|
|
|
|
#define ndefT5TisT5TDevice(device) ((device)->type == RFAL_NFC_LISTEN_TYPE_NFCV)
|
|
|
|
/*
|
|
******************************************************************************
|
|
* LOCAL VARIABLES
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
******************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
******************************************************************************
|
|
*/
|
|
|
|
static ReturnCode ndefT5TPollerReadSingleBlock(ndefContext *ctx, uint16_t blockNum, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen);
|
|
static ReturnCode ndefT5TGetSystemInformation(ndefContext *ctx, bool extended);
|
|
|
|
#if NDEF_FEATURE_ALL
|
|
static ReturnCode ndefT5TWriteCC(ndefContext *ctx);
|
|
static ReturnCode ndefT5TPollerWriteSingleBlock(ndefContext *ctx, uint16_t blockNum, const uint8_t* wrData);
|
|
static ReturnCode ndefT5TPollerReadMultipleBlocks(ndefContext *ctx, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen);
|
|
#endif /* NDEF_FEATURE_ALL */
|
|
|
|
/*
|
|
******************************************************************************
|
|
* GLOBAL FUNCTIONS
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerReadBytes(ndefContext * ctx, uint32_t offset, uint32_t len, uint8_t* buf, uint32_t * rcvdLen )
|
|
{
|
|
uint8_t lastVal;
|
|
uint8_t status;
|
|
uint16_t res;
|
|
uint16_t nbRead;
|
|
uint16_t blockLen;
|
|
uint16_t startBlock;
|
|
uint16_t startAddr;
|
|
ReturnCode result = ERR_PARAM;
|
|
uint32_t currentLen = len;
|
|
uint32_t lvRcvLen = 0U;
|
|
|
|
if ( ( ctx != NULL) && (ctx->subCtx.t5t.blockLen > 0U) && (buf != NULL) && (len > 0U) )
|
|
{
|
|
blockLen = (uint16_t )ctx->subCtx.t5t.blockLen;
|
|
if( blockLen == 0U )
|
|
{
|
|
return ERR_SYSTEM;
|
|
}
|
|
startBlock = (uint16_t) (offset / blockLen);
|
|
startAddr = (uint16_t) (startBlock * blockLen);
|
|
|
|
res = ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, blockLen + 3U, &nbRead);
|
|
if ( (res == ERR_NONE) && (ctx->subCtx.t5t.txrxBuf[0U] == 0U) && (nbRead > 0U) )
|
|
{
|
|
nbRead = (uint16_t) (nbRead + startAddr - (uint16_t)offset - 1U );
|
|
if ((uint32_t) nbRead > currentLen)
|
|
{
|
|
nbRead = (uint16_t) currentLen;
|
|
}
|
|
if (nbRead > 0U)
|
|
{
|
|
(void)ST_MEMCPY(buf, &ctx->subCtx.t5t.txrxBuf[1U - startAddr + (uint16_t)offset], (uint32_t)nbRead);
|
|
}
|
|
lvRcvLen += (uint32_t) nbRead;
|
|
currentLen -= (uint32_t) nbRead;
|
|
while (currentLen >= ((uint32_t)blockLen + 2U) )
|
|
{
|
|
startBlock++;
|
|
lastVal = buf[lvRcvLen - 1U];
|
|
res = ndefT5TPollerReadSingleBlock(ctx, startBlock, &buf[lvRcvLen - 1U], blockLen + 3U, &nbRead);
|
|
status = buf[lvRcvLen - 1U]; /* Keep status */
|
|
buf[lvRcvLen - 1U] = lastVal; /* Restore previous value */
|
|
if ( (res == ERR_NONE) && (nbRead > 0U) && (status == 0U))
|
|
{
|
|
lvRcvLen += blockLen;
|
|
currentLen -= blockLen;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (currentLen > 0U)
|
|
{
|
|
startBlock++;
|
|
res = ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, blockLen + 3U, &nbRead);
|
|
if ( (res == ERR_NONE) && (ctx->subCtx.t5t.txrxBuf[0U] == 0U) && (nbRead > 0U))
|
|
{
|
|
-- nbRead; /* remove status char */
|
|
if (nbRead > currentLen)
|
|
{
|
|
nbRead = (uint16_t)currentLen;
|
|
}
|
|
if (nbRead > 0U)
|
|
{
|
|
(void)ST_MEMCPY(&buf[lvRcvLen], & ctx->subCtx.t5t.txrxBuf[1U], nbRead);
|
|
}
|
|
lvRcvLen += nbRead;
|
|
currentLen -= nbRead;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (currentLen == 0U)
|
|
{
|
|
result = ERR_NONE;
|
|
}
|
|
if( rcvdLen != NULL )
|
|
{
|
|
* rcvdLen = lvRcvLen;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerContextInitialization(ndefContext *ctx, const rfalNfcDevice *dev)
|
|
{
|
|
ReturnCode result;
|
|
uint16_t rcvLen;
|
|
|
|
if( (ctx == NULL) || (dev == NULL) || !ndefT5TisT5TDevice(dev) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
(void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device));
|
|
|
|
/* Reset info about the card */
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
ctx->messageOffset = 0U;
|
|
ctx->messageLen = 0U;
|
|
ctx->subCtx.t5t.blockLen = 0U;
|
|
ctx->subCtx.t5t.pAddressedUid = ctx->device.dev.nfcv.InvRes.UID; /* By default work in addressed mode */
|
|
ctx->subCtx.t5t.TlvNDEFOffset = 0U; /* Offset for TLV */
|
|
|
|
ctx->subCtx.t5t.legacySTHighDensity = false;
|
|
result = ndefT5TPollerReadSingleBlock( ctx, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvLen );
|
|
if( (result != ERR_NONE) && (ctx->device.dev.nfcv.InvRes.UID[NDEF_T5T_UID_MANUFACTURER_ID_POS] == NDEF_T5T_MANUFACTURER_ID_ST) )
|
|
{
|
|
/* Try High Density Legacy mode */
|
|
ctx->subCtx.t5t.legacySTHighDensity = true;
|
|
result = ndefT5TPollerReadSingleBlock( ctx, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvLen );
|
|
if( result != ERR_NONE )
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if( (rcvLen > 1U) && (ctx->subCtx.t5t.txrxBuf[0U] == (uint8_t) 0U) )
|
|
{
|
|
ctx->subCtx.t5t.blockLen = (uint8_t) (rcvLen - 1U);
|
|
}
|
|
else
|
|
{
|
|
return ERR_PROTO;
|
|
}
|
|
|
|
if (rfalNfcvPollerSelect( (uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->device.dev.nfcv.InvRes.UID) == ERR_NONE)
|
|
{
|
|
ctx->subCtx.t5t.pAddressedUid = NULL; /* Switch to selected mode */
|
|
}
|
|
|
|
ctx->subCtx.t5t.sysInfoSupported = false;
|
|
|
|
if( !ctx->subCtx.t5t.legacySTHighDensity)
|
|
{
|
|
/* Extended Get System Info */
|
|
if( ndefT5TGetSystemInformation(ctx, true) == ERR_NONE )
|
|
{
|
|
ctx->subCtx.t5t.sysInfoSupported = true;
|
|
}
|
|
}
|
|
if( !ctx->subCtx.t5t.sysInfoSupported )
|
|
{
|
|
/* Get System Info */
|
|
if( ndefT5TGetSystemInformation(ctx, false) == ERR_NONE )
|
|
{
|
|
ctx->subCtx.t5t.sysInfoSupported = true;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerNdefDetect(ndefContext * ctx, ndefInfo *info)
|
|
{
|
|
ReturnCode result;
|
|
uint8_t tmpBuf[NDEF_T5T_TL_MAX_SIZE];
|
|
ReturnCode returnCode = ERR_REQUEST; /* Default return code */
|
|
uint16_t offset;
|
|
uint16_t length;
|
|
uint32_t TlvOffset;
|
|
bool bExit;
|
|
uint32_t rcvLen;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
ctx->cc.t5t.ccLen = 0U;
|
|
ctx->cc.t5t.memoryLen = 0U;
|
|
ctx->messageLen = 0U;
|
|
ctx->messageOffset = 0U;
|
|
|
|
if( info != NULL )
|
|
{
|
|
info->state = NDEF_STATE_INVALID;
|
|
info->majorVersion = 0U;
|
|
info->minorVersion = 0U;
|
|
info->areaLen = 0U;
|
|
info->areaAvalableSpaceLen = 0U;
|
|
info->messageLen = 0U;
|
|
}
|
|
|
|
result = ndefT5TPollerReadBytes(ctx, 0U, 8U, ctx->ccBuf, &rcvLen);
|
|
if ( (result == ERR_NONE) && (rcvLen == 8U) && ( (ctx->ccBuf[0] == (uint8_t)0xE1U) || (ctx->ccBuf[0] == (uint8_t)0xE2U) ) )
|
|
{
|
|
ctx->cc.t5t.magicNumber = ctx->ccBuf[0U];
|
|
ctx->cc.t5t.majorVersion = (ctx->ccBuf[1U] >> 6U ) & 0x03U;
|
|
ctx->cc.t5t.minorVersion = (ctx->ccBuf[1U] >> 4U ) & 0x03U;
|
|
ctx->cc.t5t.readAccess = (ctx->ccBuf[1U] >> 2U ) & 0x03U;
|
|
ctx->cc.t5t.writeAccess = (ctx->ccBuf[1U] >> 0U ) & 0x03U;
|
|
ctx->cc.t5t.memoryLen = ctx->ccBuf[2U];
|
|
ctx->cc.t5t.multipleBlockRead = (((ctx->ccBuf[3U] >> 0U ) & 0x01U) != 0U);
|
|
ctx->cc.t5t.mlenOverflow = (((ctx->ccBuf[3U] >> 2U ) & 0x01U) != 0U);
|
|
ctx->cc.t5t.lockBlock = (((ctx->ccBuf[3U] >> 3U ) & 0x01U) != 0U);
|
|
ctx->cc.t5t.specialFrame = (((ctx->ccBuf[3U] >> 4U ) & 0x01U) != 0U);
|
|
ctx->state = NDEF_STATE_INITIALIZED;
|
|
|
|
if ( ctx->cc.t5t.memoryLen != 0U)
|
|
{
|
|
ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_4_BYTES;
|
|
if( (ctx->cc.t5t.memoryLen == 0xFFU) && ctx->cc.t5t.mlenOverflow )
|
|
{
|
|
if( (ctx->subCtx.t5t.sysInfoSupported==true) && ( ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) )
|
|
{
|
|
ctx->cc.t5t.memoryLen = (uint16_t)((ctx->subCtx.t5t.sysInfo.numberOfBlock * ctx->subCtx.t5t.sysInfo.blockSize) / NDEF_T5T_MLEN_DIVIDER);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_8_BYTES;
|
|
ctx->cc.t5t.memoryLen = ((uint16_t)ctx->ccBuf[6U] << 8U) + (uint16_t)ctx->ccBuf[7U];
|
|
}
|
|
if( (ctx->subCtx.t5t.sysInfoSupported==true) &&
|
|
(ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags)!= 0U) &&
|
|
(ctx->cc.t5t.memoryLen == (uint16_t)((ctx->subCtx.t5t.sysInfo.numberOfBlock * ctx->subCtx.t5t.sysInfo.blockSize) / NDEF_T5T_MLEN_DIVIDER)) &&
|
|
(ctx->cc.t5t.memoryLen > 0U) )
|
|
{
|
|
ctx->cc.t5t.memoryLen--; /* remove CC area from memory len */
|
|
}
|
|
ctx->messageLen = 0U;
|
|
ctx->messageOffset = ctx->cc.t5t.ccLen;
|
|
TlvOffset = ctx->cc.t5t.ccLen;
|
|
bExit = false;
|
|
do
|
|
{
|
|
result = ndefT5TPollerReadBytes(ctx, TlvOffset, NDEF_T5T_TL_MAX_SIZE, tmpBuf, &rcvLen);
|
|
if ( (result != ERR_NONE) || ( rcvLen != NDEF_T5T_TL_MAX_SIZE) )
|
|
{
|
|
break;
|
|
}
|
|
offset = 2U;
|
|
length = tmpBuf[1U];
|
|
if ( length == (NDEF_SHORT_VFIELD_MAX_LEN + 1U) )
|
|
{
|
|
/* Size is encoded in 1 + 2 bytes */
|
|
length = (((uint16_t)tmpBuf[2U]) << 8U) + (uint16_t)tmpBuf[3U];
|
|
offset += 2U;
|
|
}
|
|
if (tmpBuf[0U] == (uint8_t)NDEF_T5T_TLV_NDEF)
|
|
{
|
|
/* NDEF record return it */
|
|
returnCode = ERR_NONE; /* Default */
|
|
ctx->subCtx.t5t.TlvNDEFOffset = TlvOffset; /* Offset for TLV */
|
|
ctx->messageOffset = TlvOffset + offset;
|
|
ctx->messageLen = length;
|
|
TlvOffset = 0U;
|
|
if (length == 0U)
|
|
{
|
|
/* Req 40 7.5.1.6 */
|
|
if ( (ctx->cc.t5t.readAccess == 0U) && (ctx->cc.t5t.writeAccess == 0U) )
|
|
{
|
|
ctx->state = NDEF_STATE_INITIALIZED;
|
|
}
|
|
else
|
|
{
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
returnCode = ERR_REQUEST; /* Default */
|
|
}
|
|
bExit = true;
|
|
}
|
|
else
|
|
{
|
|
if (ctx->cc.t5t.readAccess == 0U)
|
|
{
|
|
if (ctx->cc.t5t.writeAccess == 0U)
|
|
{
|
|
ctx->state = NDEF_STATE_READWRITE;
|
|
}
|
|
else
|
|
{
|
|
ctx->state = NDEF_STATE_READONLY;
|
|
}
|
|
}
|
|
bExit = true;
|
|
}
|
|
}
|
|
else if (tmpBuf[0U]== (uint8_t) NDEF_T5T_TLV_TERMINATOR)
|
|
{
|
|
/* NDEF end */
|
|
TlvOffset = 0U;
|
|
bExit = true;
|
|
}
|
|
else if (tmpBuf[0U]== (uint8_t) NDEF_T5T_TLV_PROPRIETARY)
|
|
{ /* proprietary go next, nothing to do */
|
|
TlvOffset += (uint32_t)offset + (uint32_t)length;
|
|
}
|
|
else
|
|
{
|
|
/* RFU value */
|
|
TlvOffset = 0U;
|
|
bExit = true;
|
|
}
|
|
} while ( ( TlvOffset > 0U) && (bExit == false) );
|
|
}
|
|
else
|
|
{
|
|
/* No CCFile */
|
|
returnCode = ERR_REQUEST;
|
|
if (result != ERR_NONE)
|
|
{
|
|
returnCode = result;
|
|
}
|
|
}
|
|
|
|
/* TS T5T v1.0 4.3.1.17 T5T_area size is measured in bytes is equal to 8 * MLEN */
|
|
ctx->areaLen = (uint32_t)ctx->cc.t5t.memoryLen * NDEF_T5T_MLEN_DIVIDER;
|
|
if( info != NULL )
|
|
{
|
|
info->state = ctx->state;
|
|
info->majorVersion = ctx->cc.t5t.majorVersion;
|
|
info->minorVersion = ctx->cc.t5t.minorVersion;
|
|
info->areaLen = ctx->areaLen;
|
|
info->areaAvalableSpaceLen = (uint32_t)ctx->cc.t5t.ccLen + ctx->areaLen - ctx->messageOffset;
|
|
info->messageLen = ctx->messageLen;
|
|
}
|
|
return returnCode;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen)
|
|
{
|
|
ReturnCode result;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) || (buf == NULL) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if( ctx->messageLen > bufLen )
|
|
{
|
|
return ERR_NOMEM;
|
|
}
|
|
|
|
result = ndefT5TPollerReadBytes( ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen );
|
|
return result;
|
|
}
|
|
|
|
#if NDEF_FEATURE_ALL
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t * buf, uint32_t len)
|
|
{
|
|
ReturnCode result = ERR_REQUEST;
|
|
ReturnCode res;
|
|
uint16_t nbRead;
|
|
uint16_t blockLen16;
|
|
uint16_t startBlock;
|
|
uint16_t startAddr ;
|
|
const uint8_t * wrbuf = buf;
|
|
uint32_t currentLen = len;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) || (len == 0U) || (ctx->subCtx.t5t.blockLen == 0U))
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
blockLen16 = (uint16_t )ctx->subCtx.t5t.blockLen;
|
|
if( blockLen16 == 0U )
|
|
{
|
|
return ERR_SYSTEM;
|
|
}
|
|
startBlock = (uint16_t) (offset / blockLen16);
|
|
startAddr = (uint16_t) (startBlock * blockLen16);
|
|
|
|
if (startAddr != offset)
|
|
{
|
|
/* Unaligned start offset must read the first block before */
|
|
res = ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, blockLen16 + 3U, &nbRead);
|
|
if ( (res == ERR_NONE) && (ctx->subCtx.t5t.txrxBuf[0U] == 0U) && (nbRead > 0U) )
|
|
{
|
|
nbRead = (uint16_t) ((uint32_t)nbRead - 1U + startAddr - offset);
|
|
if (nbRead > (uint32_t) currentLen)
|
|
{
|
|
nbRead = (uint16_t) currentLen;
|
|
}
|
|
if (nbRead > 0U)
|
|
{
|
|
(void)ST_MEMCPY(&ctx->subCtx.t5t.txrxBuf[1U - startAddr + (uint16_t)offset], wrbuf, nbRead);
|
|
}
|
|
res = ndefT5TPollerWriteSingleBlock(ctx, startBlock, &ctx->subCtx.t5t.txrxBuf[1U]);
|
|
if (res != ERR_NONE)
|
|
{
|
|
return res;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (res != ERR_NONE)
|
|
{
|
|
result = res;
|
|
}
|
|
else
|
|
{
|
|
result = ERR_PARAM;
|
|
}
|
|
return result;
|
|
}
|
|
currentLen -= nbRead;
|
|
wrbuf = &wrbuf[nbRead];
|
|
startBlock++;
|
|
}
|
|
while (currentLen >= blockLen16)
|
|
{
|
|
res = ndefT5TPollerWriteSingleBlock(ctx, startBlock, wrbuf);
|
|
if (res == ERR_NONE)
|
|
{
|
|
currentLen -= blockLen16;
|
|
wrbuf = &wrbuf[blockLen16];
|
|
startBlock++;
|
|
}
|
|
else
|
|
{
|
|
result = res;
|
|
break;
|
|
}
|
|
}
|
|
if ( (currentLen != 0U) && (currentLen < blockLen16) )
|
|
{
|
|
/* Unaligned end, must read the first block before */
|
|
res = ndefT5TPollerReadSingleBlock(ctx, startBlock, ctx->subCtx.t5t.txrxBuf, blockLen16 + 3U, &nbRead);
|
|
if ( (res == ERR_NONE) && (ctx->subCtx.t5t.txrxBuf[0U] == 0U) && (nbRead > 0U) )
|
|
{
|
|
if (currentLen > 0U) { (void)ST_MEMCPY(&ctx->subCtx.t5t.txrxBuf[1U], wrbuf, currentLen); }
|
|
res = ndefT5TPollerWriteSingleBlock(ctx, startBlock, &ctx->subCtx.t5t.txrxBuf[1U]);
|
|
if (res != ERR_NONE)
|
|
{
|
|
result = res;
|
|
}
|
|
else
|
|
{
|
|
currentLen = 0U;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (res != ERR_NONE)
|
|
{
|
|
result = res;
|
|
}
|
|
else
|
|
{
|
|
result = ERR_PARAM;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
if (currentLen == 0U)
|
|
{
|
|
result = ERR_NONE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen)
|
|
{
|
|
uint8_t TLV[8U];
|
|
ReturnCode result = ERR_PARAM;
|
|
uint8_t len = 0U;
|
|
|
|
if( (ctx != NULL) && ndefT5TisT5TDevice(&ctx->device))
|
|
{
|
|
if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
|
|
{
|
|
result = ERR_WRONG_STATE;
|
|
}
|
|
else
|
|
{
|
|
TLV[len] = NDEF_T5T_TLV_NDEF;
|
|
len++;
|
|
if (rawMessageLen <= NDEF_SHORT_VFIELD_MAX_LEN)
|
|
{
|
|
TLV[len] = (uint8_t) rawMessageLen;
|
|
len++;
|
|
}
|
|
else
|
|
{
|
|
TLV[len] = (uint8_t) (rawMessageLen >> 8U);
|
|
len++;
|
|
TLV[len] = (uint8_t) rawMessageLen;
|
|
len++;
|
|
}
|
|
if (rawMessageLen == 0U)
|
|
{
|
|
TLV[len] = NDEF_TERMINATOR_TLV_T; /* TLV terminator */
|
|
len++;
|
|
}
|
|
|
|
result = ndefT5TPollerWriteBytes(ctx, ctx->subCtx.t5t.TlvNDEFOffset, TLV, len);
|
|
if ((result == ERR_NONE) && (rawMessageLen != 0U))
|
|
{ /* T5T need specific terminator */
|
|
len = 0U;
|
|
TLV[len] = NDEF_TERMINATOR_TLV_T; /* TLV terminator */
|
|
len++;
|
|
result = ndefT5TPollerWriteBytes(ctx, ctx->messageOffset + rawMessageLen, TLV, len );
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerWriteRawMessage(ndefContext *ctx, const uint8_t * buf, uint32_t bufLen)
|
|
{
|
|
uint32_t len = bufLen ;
|
|
ReturnCode result;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) || (buf == NULL) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
/* TS T5T v1.0 7.5.3.1/2: T5T NDEF Detect should have been called before NDEF write procedure */
|
|
/* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF Write procedure*/
|
|
|
|
/* TS T5T v1.0 7.5.3.3: check write access condition */
|
|
if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
|
|
{
|
|
/* Conclude procedure */
|
|
return ERR_WRONG_STATE;
|
|
}
|
|
|
|
/* TS T5T v1.0 7.5.3.3: verify available space */
|
|
result = ndefT5TPollerCheckAvailableSpace(ctx, bufLen);
|
|
if( result != ERR_NONE )
|
|
{
|
|
/* Conclude procedures */
|
|
return ERR_PARAM;
|
|
}
|
|
/* TS T5T v1.0 7.5.3.4: reset L-Field to 0 */
|
|
/* and update ctx->messageOffset according to L-field len */
|
|
result = ndefT5TPollerBeginWriteMessage(ctx, bufLen);
|
|
if (result != ERR_NONE)
|
|
{
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
/* Conclude procedure */
|
|
return result;
|
|
}
|
|
if( bufLen != 0U )
|
|
{
|
|
/* TS T5T v1.0 7.5.3.5: write new NDEF message */
|
|
result = ndefT5TPollerWriteBytes(ctx, ctx->messageOffset, buf, len);
|
|
if (result != ERR_NONE)
|
|
{
|
|
/* Conclude procedure */
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
return result;
|
|
}
|
|
/* TS T5T v1.0 7.5.3.6 & 7.5.3.7: update L-Field and write Terminator TLV */
|
|
result = ndefT5TPollerEndWriteMessage(ctx, len);
|
|
if (result != ERR_NONE)
|
|
{
|
|
/* Conclude procedure */
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
return result;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
static ReturnCode ndefT5TWriteCC(ndefContext *ctx)
|
|
{
|
|
ReturnCode ret;
|
|
uint8_t* buf;
|
|
uint8_t dataIt;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
buf = ctx->ccBuf;
|
|
dataIt = 0U;
|
|
/* Encode CC */
|
|
buf[dataIt] = ctx->cc.t5t.magicNumber; /* Byte 0 */
|
|
dataIt++;
|
|
buf[dataIt] = (uint8_t)(((ctx->cc.t5t.majorVersion & 0x03U) << 6) | /* Byte 1 */
|
|
((ctx->cc.t5t.minorVersion & 0x03U) << 4) | /* */
|
|
((ctx->cc.t5t.readAccess & 0x03U) << 2) | /* */
|
|
((ctx->cc.t5t.writeAccess & 0x03U) << 0)); /* */
|
|
dataIt++;
|
|
buf[dataIt] = (ctx->cc.t5t.ccLen == NDEF_T5T_CC_LEN_8_BYTES) ? 0U : (uint8_t)ctx->cc.t5t.memoryLen; /* Byte 2 */
|
|
dataIt++;
|
|
buf[dataIt] = 0U; /* Byte 3 */
|
|
if( ctx->cc.t5t.multipleBlockRead ) { buf[dataIt] |= 0x01U; } /* Byte 3 b0 MBREAD */
|
|
if( ctx->cc.t5t.mlenOverflow ) { buf[dataIt] |= 0x04U; } /* Byte 3 b2 Android MLEN overflow */
|
|
if( ctx->cc.t5t.lockBlock ) { buf[dataIt] |= 0x08U; } /* Byte 3 b3 Lock Block */
|
|
if( ctx->cc.t5t.specialFrame ) { buf[dataIt] |= 0x10U; } /* Byte 3 b4 Special Frame */
|
|
dataIt++;
|
|
if( ctx->cc.t5t.ccLen == NDEF_T5T_CC_LEN_8_BYTES )
|
|
{
|
|
buf[dataIt] = 0U; /* Byte 4 */
|
|
dataIt++;
|
|
buf[dataIt] = 0U; /* Byte 5 */
|
|
dataIt++;
|
|
buf[dataIt] = (uint8_t)(ctx->cc.t5t.memoryLen >> 8); /* Byte 6 */
|
|
dataIt++;
|
|
buf[dataIt] = (uint8_t)(ctx->cc.t5t.memoryLen >> 0); /* Byte 7 */
|
|
dataIt++;
|
|
}
|
|
|
|
ret = ndefT5TPollerWriteBytes(ctx, 0U, buf, ctx->cc.t5t.ccLen );
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerTagFormat(ndefContext * ctx, const ndefCapabilityContainer *cc, uint32_t options)
|
|
{
|
|
uint16_t rcvdLen;
|
|
ReturnCode result;
|
|
static const uint8_t emptyNDEF[] = { 0x03U, 0x00U, 0xFEU, 0x00U};
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
/* Reset previous potential info about NDEF messages */
|
|
ctx->messageLen = 0U;
|
|
ctx->messageOffset = 0U;
|
|
ctx->subCtx.t5t.TlvNDEFOffset = 0U;
|
|
|
|
if( cc != NULL )
|
|
{
|
|
if( (cc->t5t.ccLen != NDEF_T5T_CC_LEN_8_BYTES) && (cc->t5t.ccLen != NDEF_T5T_CC_LEN_4_BYTES) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
(void)ST_MEMCPY(&ctx->cc, cc, sizeof(ndefCapabilityContainer));
|
|
}
|
|
else
|
|
{
|
|
/* Try to find the appropriate cc values */
|
|
ctx->cc.t5t.magicNumber = NDEF_T5T_CC_MAGIC_1_BYTE_ADDR_MODE; /* E1 */
|
|
ctx->cc.t5t.majorVersion = 1U;
|
|
ctx->cc.t5t.minorVersion = 0U;
|
|
ctx->cc.t5t.readAccess = 0U;
|
|
ctx->cc.t5t.writeAccess = 0U;
|
|
ctx->cc.t5t.lockBlock = false;
|
|
ctx->cc.t5t.specialFrame = false;
|
|
ctx->cc.t5t.memoryLen = 0U;
|
|
ctx->cc.t5t.mlenOverflow = false;
|
|
|
|
result = ndefT5TPollerReadMultipleBlocks(ctx, 0U, 0U, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvdLen);
|
|
ctx->cc.t5t.multipleBlockRead = (result == ERR_NONE) ? true : false;
|
|
|
|
/* Try to retrieve the tag's size using getSystemInfo and GetExtSystemInfo */
|
|
|
|
if ( (ctx->subCtx.t5t.sysInfoSupported==true) && (ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags)!=0U) )
|
|
{
|
|
ctx->cc.t5t.memoryLen = (uint16_t)((ctx->subCtx.t5t.sysInfo.numberOfBlock * ctx->subCtx.t5t.sysInfo.blockSize) / NDEF_T5T_MLEN_DIVIDER);
|
|
|
|
if( (options & NDEF_T5T_FORMAT_OPTION_NFC_FORUM) == NDEF_T5T_FORMAT_OPTION_NFC_FORUM ) /* NFC Forum format */
|
|
{
|
|
if( ctx->cc.t5t.memoryLen >= NDEF_T5T_MAX_MLEN_1_BYTE_ENCODING )
|
|
{
|
|
ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_8_BYTES;
|
|
}
|
|
if( ctx->cc.t5t.memoryLen > 0U )
|
|
{
|
|
ctx->cc.t5t.memoryLen--; /* remove CC area from memory len */
|
|
}
|
|
}
|
|
else /* Android format */
|
|
{
|
|
ctx->cc.t5t.ccLen = NDEF_T5T_CC_LEN_4_BYTES;
|
|
if( ctx->cc.t5t.memoryLen >= NDEF_T5T_MAX_MLEN_1_BYTE_ENCODING )
|
|
{
|
|
ctx->cc.t5t.mlenOverflow = true;
|
|
ctx->cc.t5t.memoryLen = 0xFFU;
|
|
}
|
|
}
|
|
|
|
if( !ctx->subCtx.t5t.legacySTHighDensity && (ctx->subCtx.t5t.sysInfo.numberOfBlock > NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR) )
|
|
{
|
|
ctx->cc.t5t.magicNumber = NDEF_T5T_CC_MAGIC_2_BYTE_ADDR_MODE; /* E2 */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ERR_REQUEST;
|
|
}
|
|
}
|
|
|
|
result = ndefT5TWriteCC(ctx);
|
|
if( result != ERR_NONE )
|
|
{
|
|
/* If write fails, try to use special frame if not yet used */
|
|
if( !ctx->cc.t5t.specialFrame )
|
|
{
|
|
platformDelay(20U); /* Wait to be sure that previous command has ended */
|
|
ctx->cc.t5t.specialFrame = true; /* Add option flag */
|
|
result = ndefT5TWriteCC(ctx);
|
|
if( result != ERR_NONE )
|
|
{
|
|
ctx->cc.t5t.specialFrame = false; /* Add option flag */
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
/* Update info about current NDEF */
|
|
|
|
ctx->subCtx.t5t.TlvNDEFOffset = ctx->cc.t5t.ccLen;
|
|
|
|
result = ndefT5TPollerWriteBytes(ctx, ctx->subCtx.t5t.TlvNDEFOffset, emptyNDEF, sizeof(emptyNDEF) );
|
|
if (result == ERR_NONE)
|
|
{
|
|
/* Update info about current NDEF */
|
|
ctx->messageOffset = (uint32_t)ctx->cc.t5t.ccLen + 0x02U;
|
|
ctx->state = NDEF_STATE_INITIALIZED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerCheckPresence(ndefContext *ctx)
|
|
{
|
|
ReturnCode ret;
|
|
uint16_t blockAddr;
|
|
uint16_t rcvLen;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
blockAddr = 0U;
|
|
|
|
ret = ndefT5TPollerReadSingleBlock( ctx, blockAddr, ctx->subCtx.t5t.txrxBuf, (uint16_t)sizeof(ctx->subCtx.t5t.txrxBuf), &rcvLen );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen)
|
|
{
|
|
uint32_t lLen;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if ( ctx->state == NDEF_STATE_INVALID )
|
|
{
|
|
return ERR_WRONG_STATE;
|
|
}
|
|
|
|
lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T5T_TLV_L_3_BYTES_LEN : NDEF_T5T_TLV_L_1_BYTES_LEN;
|
|
|
|
if( (messageLen + ctx->subCtx.t5t.TlvNDEFOffset + NDEF_T5T_TLV_T_LEN + lLen) > (ctx->areaLen + ctx->cc.t5t.ccLen) )
|
|
{
|
|
return ERR_NOMEM;
|
|
}
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen)
|
|
{
|
|
ReturnCode ret;
|
|
uint32_t lLen;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
|
|
{
|
|
return ERR_WRONG_STATE;
|
|
}
|
|
|
|
/* TS T5T v1.0 7.5.3.4: reset L-Field to 0 */
|
|
ret = ndefT5TPollerWriteRawMessageLen(ctx, 0U);
|
|
if( ret != ERR_NONE )
|
|
{
|
|
/* Conclude procedure */
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
return ret;
|
|
}
|
|
|
|
lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T5T_TLV_L_3_BYTES_LEN : NDEF_T5T_TLV_L_1_BYTES_LEN;
|
|
ctx->messageOffset = ctx->subCtx.t5t.TlvNDEFOffset;
|
|
ctx->messageOffset += NDEF_T5T_TLV_T_LEN; /* T Len */
|
|
ctx->messageOffset += lLen; /* L Len */
|
|
ctx->state = NDEF_STATE_INITIALIZED;
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
ReturnCode ndefT5TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen)
|
|
{
|
|
ReturnCode ret;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if( ctx->state != NDEF_STATE_INITIALIZED )
|
|
{
|
|
return ERR_WRONG_STATE;
|
|
}
|
|
|
|
/* TS T5T v1.0 7.5.3.6 & 7.5.3.7: update L-Field and write Terminator TLV */
|
|
ret = ndefT5TPollerWriteRawMessageLen(ctx, messageLen);
|
|
if( ret != ERR_NONE )
|
|
{
|
|
/* Conclude procedure */
|
|
ctx->state = NDEF_STATE_INVALID;
|
|
return ret;
|
|
}
|
|
ctx->messageLen = messageLen;
|
|
ctx->state = (ctx->messageLen == 0U) ? NDEF_STATE_INITIALIZED : NDEF_STATE_READWRITE;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
static ReturnCode ndefT5TPollerWriteSingleBlock(ndefContext *ctx, uint16_t blockNum, const uint8_t* wrData)
|
|
{
|
|
ReturnCode ret;
|
|
uint8_t flags;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
flags = ctx->cc.t5t.specialFrame ? ((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT | (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION): (uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT;
|
|
|
|
if( ctx->subCtx.t5t.legacySTHighDensity )
|
|
{
|
|
ret = rfalST25xVPollerM24LRWriteSingleBlock(flags, ctx->subCtx.t5t.pAddressedUid, blockNum, wrData, ctx->subCtx.t5t.blockLen);
|
|
}
|
|
else
|
|
{
|
|
if( blockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR )
|
|
{
|
|
ret = rfalNfcvPollerWriteSingleBlock(flags, ctx->subCtx.t5t.pAddressedUid, (uint8_t)blockNum, wrData, ctx->subCtx.t5t.blockLen);
|
|
}
|
|
else
|
|
{
|
|
ret = rfalNfcvPollerExtendedWriteSingleBlock(flags, ctx->subCtx.t5t.pAddressedUid, blockNum, wrData, ctx->subCtx.t5t.blockLen);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
static ReturnCode ndefT5TPollerReadMultipleBlocks(ndefContext *ctx, uint16_t firstBlockNum, uint8_t numOfBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen)
|
|
{
|
|
ReturnCode ret;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if( ctx->subCtx.t5t.legacySTHighDensity )
|
|
{
|
|
|
|
ret = rfalST25xVPollerM24LRReadMultipleBlocks((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, firstBlockNum, numOfBlocks, rxBuf, rxBufLen, rcvLen);
|
|
}
|
|
else
|
|
{
|
|
if( firstBlockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR )
|
|
{
|
|
ret = rfalNfcvPollerReadMultipleBlocks((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, (uint8_t)firstBlockNum, numOfBlocks, rxBuf, rxBufLen, rcvLen);
|
|
}
|
|
else
|
|
{
|
|
ret = rfalNfcvPollerExtendedReadMultipleBlocks((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, firstBlockNum, numOfBlocks, rxBuf, rxBufLen, rcvLen);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* NDEF_FEATURE_ALL */
|
|
|
|
/*******************************************************************************/
|
|
static ReturnCode ndefT5TPollerReadSingleBlock(ndefContext *ctx, uint16_t blockNum, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen)
|
|
{
|
|
ReturnCode ret;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if( ctx->subCtx.t5t.legacySTHighDensity )
|
|
{
|
|
|
|
ret = rfalST25xVPollerM24LRReadSingleBlock((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, blockNum, rxBuf, rxBufLen, rcvLen);
|
|
}
|
|
else
|
|
{
|
|
if( blockNum < NDEF_T5T_MAX_BLOCK_1_BYTE_ADDR )
|
|
{
|
|
ret = rfalNfcvPollerReadSingleBlock((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, (uint8_t)blockNum, rxBuf, rxBufLen, rcvLen);
|
|
}
|
|
else
|
|
{
|
|
ret = rfalNfcvPollerExtendedReadSingleBlock((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, blockNum, rxBuf, rxBufLen, rcvLen);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
static ReturnCode ndefT5TGetSystemInformation(ndefContext *ctx, bool extended)
|
|
{
|
|
ReturnCode ret;
|
|
uint8_t rxBuf[NDEF_T5T_SYSINFO_MAX_LEN];
|
|
uint16_t rcvLen;
|
|
uint8_t* resp;
|
|
|
|
if( (ctx == NULL) || !ndefT5TisT5TDevice(&ctx->device) )
|
|
{
|
|
return ERR_PARAM;
|
|
}
|
|
|
|
if( extended )
|
|
{
|
|
ret = rfalNfcvPollerExtendedGetSystemInformation((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT, ctx->subCtx.t5t.pAddressedUid, (uint8_t)RFAL_NFCV_SYSINFO_REQ_ALL, rxBuf, (uint16_t)sizeof(rxBuf), &rcvLen);
|
|
}
|
|
else
|
|
{
|
|
ret = rfalNfcvPollerGetSystemInformation(ctx->subCtx.t5t.legacySTHighDensity ? ((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT) : ((uint8_t)RFAL_NFCV_REQ_FLAG_DEFAULT), ctx->subCtx.t5t.pAddressedUid, rxBuf, (uint16_t)sizeof(rxBuf), &rcvLen);
|
|
}
|
|
|
|
if( ret != ERR_NONE )
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* FIXME check buf rcvLen */
|
|
resp = &rxBuf[0U];
|
|
/* skip Flags */
|
|
resp++;
|
|
/* get Info flags */
|
|
ctx->subCtx.t5t.sysInfo.infoFlags = *resp;
|
|
resp++;
|
|
if( extended && (ndefT5TSysInfoLenValue(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) )
|
|
{
|
|
return ERR_PROTO;
|
|
}
|
|
/* get UID */
|
|
(void)ST_MEMCPY(ctx->subCtx.t5t.sysInfo.UID, resp, RFAL_NFCV_UID_LEN);
|
|
resp = &resp[RFAL_NFCV_UID_LEN];
|
|
if( ndefT5TSysInfoDFSIDPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U)
|
|
{
|
|
ctx->subCtx.t5t.sysInfo.DFSID = *resp;
|
|
resp++;
|
|
}
|
|
if( ndefT5TSysInfoAFIPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U )
|
|
{
|
|
ctx->subCtx.t5t.sysInfo.AFI = *resp;
|
|
resp++;
|
|
}
|
|
if( ndefT5TSysInfoMemSizePresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U )
|
|
{
|
|
if ( ctx->subCtx.t5t.legacySTHighDensity || extended )
|
|
{
|
|
/* LRIS64K/M24LR16/M24LR64 */
|
|
ctx->subCtx.t5t.sysInfo.numberOfBlock = *resp;
|
|
resp++;
|
|
ctx->subCtx.t5t.sysInfo.numberOfBlock |= (((uint16_t)*resp) << 8U);
|
|
resp++;
|
|
}
|
|
else
|
|
{
|
|
ctx->subCtx.t5t.sysInfo.numberOfBlock = *resp;
|
|
resp++;
|
|
}
|
|
ctx->subCtx.t5t.sysInfo.blockSize = *resp;
|
|
resp++;
|
|
/* Add 1 to get real values*/
|
|
ctx->subCtx.t5t.sysInfo.numberOfBlock++;
|
|
ctx->subCtx.t5t.sysInfo.blockSize++;
|
|
}
|
|
if( ndefT5TSysInfoICRefPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U )
|
|
{
|
|
ctx->subCtx.t5t.sysInfo.ICRef = *resp;
|
|
resp++;
|
|
}
|
|
if( extended && (ndefT5TSysInfoCmdListPresent(ctx->subCtx.t5t.sysInfo.infoFlags) != 0U) )
|
|
{
|
|
ctx->subCtx.t5t.sysInfo.supportedCmd[0U] = *resp;
|
|
resp++;
|
|
ctx->subCtx.t5t.sysInfo.supportedCmd[1U] = *resp;
|
|
resp++;
|
|
ctx->subCtx.t5t.sysInfo.supportedCmd[2U] = *resp;
|
|
resp++;
|
|
ctx->subCtx.t5t.sysInfo.supportedCmd[3U] = *resp;
|
|
resp++;
|
|
}
|
|
return ERR_NONE;
|
|
}
|
|
|
|
#endif /* RFAL_FEATURE_NFCV */
|