/******************************************************************************
* \attention
*
*
© COPYRIGHT 2019 STMicroelectronics
*
* 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 Forum T2T
*
* This module provides an interface to perform as a NFC Reader/Writer
* to handle a Type 2 Tag T2T
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "ndef_poller.h"
#include "ndef_t2t.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_T2T
#error " RFAL: Module configuration missing. Please enable/disable T2T module by setting: RFAL_FEATURE_T2T "
#endif
#if RFAL_FEATURE_T2T
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define NDEF_T2T_BLOCK_SIZE 4U /*!< block size */
#define NDEF_T2T_MAX_SECTOR 255U /*!< Max Number of Sector in Sector Select Command */ /* 00h -- FEh: 255 sectors */
#define NDEF_T2T_BLOCKS_PER_SECTOR 256U /*!< Number of Block per Sector */
#define NDEF_T2T_BYTES_PER_SECTOR (NDEF_T2T_BLOCKS_PER_SECTOR * NDEF_T2T_BLOCK_SIZE) /*!< Number of Bytes per Sector */
#define NDEF_T2T_MAX_OFFSET (NDEF_T2T_BYTES_PER_SECTOR * NDEF_T2T_MAX_SECTOR) /*!< Maximum offset allowed */
#define NDEF_T2T_3_BYTES_TLV_LEN 0xFFU /* FFh indicates the use of 3 bytes got the L field */
#define NDEF_T2T_STATIC_MEM_SIZE 48U /* Static memory size */
#define NDEF_T2T_CC_OFFSET 12U /*!< CC offset */
#define NDEF_T2T_CC_LEN 4U /*!< CC length */
#define NDEF_T2T_AREA_OFFSET 16U /*!< T2T Area starts at block #4 */
#define NDEF_T2T_MAGIC 0xE1U /*!< CC Magic Number */
#define NDEF_T2T_CC_0 0U /*!< CC_0: Magic Number */
#define NDEF_T2T_CC_1 1U /*!< CC_1: Version */
#define NDEF_T2T_CC_2 2U /*!< CC_2: Size */
#define NDEF_T2T_CC_3 3U /*!< CC_3: Access conditions */
#define NDEF_T2T_VERSION_1_0 0x10U /*!< Version 1.0 */
#define NDEF_T2T_SIZE_DIVIDER 8U /*!< T2T_area size is measured in bytes is equal to 8 * Size */
#define NDEF_T2T_TLV_NULL 0x00U /*!< Null TLV */
#define NDEF_T2T_TLV_LOCK_CTRL 0x01U /*!< Lock Control TLV */
#define NDEF_T2T_TLV_MEMORY_CTRL 0x02U /*!< Memory Control TLV */
#define NDEF_T2T_TLV_NDEF_MESSAGE 0x03U /*!< NDEF Message TLV */
#define NDEF_T2T_TLV_PROPRIETRARY 0xFDU /*!< Proprietary TLV */
#define NDEF_T2T_TLV_TERMINATOR 0xFEU /*!< Terminator TLV */
#define NDEF_T2T_TLV_L_3_BYTES_LEN 3U /*!< TLV L Length: 3 bytes */
#define NDEF_T2T_TLV_L_1_BYTES_LEN 1U /*!< TLV L Length: 1 bytes */
#define NDEF_T2T_TLV_T_LEN 1U /*!< TLV T Length: 1 bytes */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define ndefT2TisT2TDevice(device) ((((device)->type == RFAL_NFC_LISTEN_TYPE_NFCA) && ((device)->dev.nfca.type == RFAL_NFCA_T2T)))
#define ndefT2TInvalidateCache(ctx) { (ctx)->subCtx.t2t.cacheAddr = 0xFFFFFFFFU; }
#define ndefT2TIsReadOnlyAccessGranted(ctx) (((ctx)->cc.t2t.readAccess == 0x0U) && ((ctx)->cc.t2t.writeAccess == 0xFU))
#define ndefT2TIsReadWriteAccessGranted(ctx) (((ctx)->cc.t2t.readAccess == 0x0U) && ((ctx)->cc.t2t.writeAccess == 0x0U))
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static ReturnCode ndefT2TPollerReadBlock(ndefContext *ctx, uint16_t blockAddr, uint8_t *buf);
#if NDEF_FEATURE_ALL
static ReturnCode ndefT2TPollerWriteBlock(ndefContext *ctx, uint16_t blockAddr, const uint8_t *buf);
#endif /* NDEF_FEATURE_ALL */
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
static ReturnCode ndefT2TPollerReadBlock(ndefContext *ctx, uint16_t blockAddr, uint8_t *buf)
{
ReturnCode ret;
uint8_t secNo;
uint8_t blNo;
uint16_t rcvdLen;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) || (buf == NULL) )
{
return ERR_PARAM;
}
secNo = (uint8_t)(blockAddr >> 8U);
blNo = (uint8_t)blockAddr;
if( secNo != ctx->subCtx.t2t.currentSecNo )
{
ret = rfalT2TPollerSectorSelect(secNo);
if( ret != ERR_NONE )
{
return ret;
}
ctx->subCtx.t2t.currentSecNo = secNo;
}
ret = rfalT2TPollerRead(blNo, buf, NDEF_T2T_READ_RESP_SIZE, &rcvdLen);
if( (ret == ERR_NONE) && (rcvdLen != NDEF_T2T_READ_RESP_SIZE) )
{
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen)
{
ReturnCode ret;
uint8_t le;
uint32_t lvOffset = offset;
uint32_t lvLen = len;
uint8_t * lvBuf = buf;
uint16_t blockAddr;
uint8_t byteNo;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) || (lvLen == 0U) || (offset > NDEF_T2T_MAX_OFFSET) )
{
return ERR_PARAM;
}
if( (offset >= ctx->subCtx.t2t.cacheAddr) && (offset < (ctx->subCtx.t2t.cacheAddr + NDEF_T2T_READ_RESP_SIZE)) && ((offset + len) < (ctx->subCtx.t2t.cacheAddr + NDEF_T2T_READ_RESP_SIZE)) )
{
/* data in cache buffer */
(void)ST_MEMCPY(lvBuf, &ctx->subCtx.t2t.cacheBuf[offset - ctx->subCtx.t2t.cacheAddr], len);
}
else
{
do {
blockAddr = (uint16_t)(lvOffset / NDEF_T2T_BLOCK_SIZE);
byteNo = (uint8_t)(lvOffset % NDEF_T2T_BLOCK_SIZE);
le = (lvLen < NDEF_T2T_READ_RESP_SIZE) ? (uint8_t)lvLen : (uint8_t)NDEF_T2T_READ_RESP_SIZE;
if( (byteNo != 0U ) || (lvLen < NDEF_T2T_READ_RESP_SIZE) )
{
ret = ndefT2TPollerReadBlock(ctx, blockAddr, ctx->subCtx.t2t.cacheBuf);
if( ret != ERR_NONE )
{
ndefT2TInvalidateCache(ctx);
return ret;
}
ctx->subCtx.t2t.cacheAddr = (uint32_t)blockAddr * NDEF_T2T_BLOCK_SIZE;
if( (NDEF_T2T_READ_RESP_SIZE - byteNo) < le )
{
le = NDEF_T2T_READ_RESP_SIZE - byteNo;
}
if( le > 0U)
{
(void)ST_MEMCPY(lvBuf, &ctx->subCtx.t2t.cacheBuf[byteNo], le);
}
}
else
{
ret = ndefT2TPollerReadBlock(ctx, blockAddr, lvBuf);
if( ret != ERR_NONE )
{
return ret;
}
if( lvLen == le )
{
/* cache the last read block */
(void)ST_MEMCPY(&ctx->subCtx.t2t.cacheBuf[0], lvBuf, NDEF_T2T_READ_RESP_SIZE);
ctx->subCtx.t2t.cacheAddr = (uint32_t)blockAddr * NDEF_T2T_BLOCK_SIZE;
}
}
lvBuf = &lvBuf[le];
lvOffset += le;
lvLen -= le;
} while( lvLen != 0U );
}
if( rcvdLen != NULL )
{
*rcvdLen = len;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerContextInitialization(ndefContext *ctx, const rfalNfcDevice *dev)
{
if( (ctx == NULL) || (dev == NULL) || !ndefT2TisT2TDevice(dev) )
{
return ERR_PARAM;
}
(void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device));
ctx->state = NDEF_STATE_INVALID;
ctx->subCtx.t2t.currentSecNo = 0U;
ndefT2TInvalidateCache(ctx);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerNdefDetect(ndefContext *ctx, ndefInfo *info)
{
ReturnCode ret;
uint8_t data[2];
uint32_t offset;
uint16_t lenTLV;
uint8_t typeTLV;
if( info != NULL )
{
info->state = NDEF_STATE_INVALID;
info->majorVersion = 0U;
info->minorVersion = 0U;
info->areaLen = 0U;
info->areaAvalableSpaceLen = 0U;
info->messageLen = 0U;
}
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
ctx->state = NDEF_STATE_INVALID;
/* Read CC TS T2T v1.0 7.5.1.1 */
ret = ndefT2TPollerReadBytes(ctx, NDEF_T2T_CC_OFFSET, NDEF_T2T_CC_LEN, ctx->ccBuf, NULL);
if( ret != ERR_NONE )
{
/* Conclude procedure */
return ret;
}
ctx->cc.t2t.magicNumber = ctx->ccBuf[NDEF_T2T_CC_0];
ctx->cc.t2t.majorVersion = ndefMajorVersion(ctx->ccBuf[NDEF_T2T_CC_1]);
ctx->cc.t2t.minorVersion = ndefMinorVersion(ctx->ccBuf[NDEF_T2T_CC_1]);
ctx->cc.t2t.size = ctx->ccBuf[NDEF_T2T_CC_2];
ctx->cc.t2t.readAccess = (uint8_t)(ctx->ccBuf[NDEF_T2T_CC_3] >> 4U);
ctx->cc.t2t.writeAccess = (uint8_t)(ctx->ccBuf[NDEF_T2T_CC_3] & 0xFU);
ctx->areaLen = (uint32_t)ctx->cc.t2t.size * NDEF_T2T_SIZE_DIVIDER;
/* Check version number TS T2T v1.0 7.5.1.2 */
if( (ctx->cc.t2t.magicNumber != NDEF_T2T_MAGIC) || (ctx->cc.t2t.majorVersion > ndefMajorVersion(NDEF_T2T_VERSION_1_0)) )
{
/* Conclude procedure TS T2T v1.0 7.5.1.2 */
return ERR_REQUEST;
}
/* Search for NDEF message TLV TS T2T v1.0 7.5.1.3 */
offset = NDEF_T2T_AREA_OFFSET;
while ( (offset < (NDEF_T2T_AREA_OFFSET + ctx->areaLen)) )
{
ret = ndefT2TPollerReadBytes(ctx, offset, 1, data, NULL);
if( ret != ERR_NONE )
{
/* Conclude procedure */
return ret;
}
typeTLV = data[0];
if( typeTLV == NDEF_T2T_TLV_NDEF_MESSAGE )
{
ctx->subCtx.t2t.offsetNdefTLV = offset;
}
offset++;
if( typeTLV == NDEF_T2T_TLV_TERMINATOR )
{
break;
}
if( typeTLV == NDEF_T2T_TLV_NULL )
{
continue;
}
/* read TLV Len */
ret = ndefT2TPollerReadBytes(ctx, offset, 1, data, NULL);
if( ret != ERR_NONE )
{
/* Conclude procedure */
return ret;
}
offset++;
lenTLV = data[0];
if( lenTLV == NDEF_T2T_3_BYTES_TLV_LEN )
{
ret = ndefT2TPollerReadBytes(ctx, offset, 2, data, NULL);
if( ret != ERR_NONE )
{
/* Conclude procedure */
return ret;
}
offset += 2U;
lenTLV = GETU16(&data[0]);
}
if( (typeTLV == NDEF_T2T_TLV_LOCK_CTRL) || (typeTLV == NDEF_T2T_TLV_MEMORY_CTRL) )
{
/* No support of Lock control or Memory control in this version */
return ERR_REQUEST;
}
/* NDEF message present TLV TS T2T v1.0 7.5.1.4 */
if( typeTLV == NDEF_T2T_TLV_NDEF_MESSAGE )
{
/* Read length TS T2T v1.0 7.5.1.5 */
ctx->messageLen = lenTLV;
ctx->messageOffset = offset;
if( ctx->messageLen == 0U )
{
if( !(ndefT2TIsReadWriteAccessGranted(ctx)) )
{
/* Conclude procedure */
return ERR_REQUEST;
}
/* Empty message found TS T2T v1.0 7.5.1.6 & TS T2T v1.0 7.4.2.1 */
ctx->state = NDEF_STATE_INITIALIZED;
}
else
{
if( (ndefT2TIsReadWriteAccessGranted(ctx)) )
{
/* Empty message found TS T2T v1.0 7.5.1.7 & TS T2T v1.0 7.4.3.1 */
ctx->state = NDEF_STATE_READWRITE;
}
else
{
if( !(ndefT2TIsReadOnlyAccessGranted(ctx)) )
{
/* Conclude procedure */
return ERR_REQUEST;
}
/* Empty message found TS T2T v1.0 7.5.1.7 & TS T2T v1.0 7.4.4.1 */
ctx->state = NDEF_STATE_READONLY;
}
}
if( info != NULL )
{
info->state = ctx->state;
info->majorVersion = ndefMajorVersion(ctx->cc.t4t.vNo);
info->minorVersion = ndefMinorVersion(ctx->cc.t4t.vNo);
info->areaLen = ctx->areaLen;
info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset;
info->messageLen = ctx->messageLen;
}
return ERR_NONE;
}
offset += lenTLV;
}
return ERR_REQUEST;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen)
{
ReturnCode ret;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) || (buf == NULL) )
{
return ERR_PARAM;
}
/* TS T2T v1.0 7.5.2.1: T2T NDEF Detect should have been called before NDEF read procedure */
/* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF read procedure*/
/* TS T2T v1.0 7.5.2.3: check presence of NDEF message */
if ( ctx->state <= NDEF_STATE_INITIALIZED )
{
/* Conclude procedure TS T4T v1.0 7.2.2.2 */
return ERR_WRONG_STATE;
}
if( ctx->messageLen > bufLen )
{
return ERR_NOMEM;
}
/* Current implementation does not support Rsvd_area */
ret = ndefT2TPollerReadBytes( ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen );
if( ret != ERR_NONE )
{
ctx->state = NDEF_STATE_INVALID;
}
return ret;
}
#if NDEF_FEATURE_ALL
/*******************************************************************************/
static ReturnCode ndefT2TPollerWriteBlock(ndefContext *ctx, uint16_t blockAddr, const uint8_t *buf)
{
ReturnCode ret;
uint8_t secNo;
uint8_t blNo;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) || (buf == NULL) )
{
return ERR_PARAM;
}
secNo = (uint8_t)(blockAddr >> 8U);
blNo = (uint8_t)blockAddr;
if( secNo != ctx->subCtx.t2t.currentSecNo )
{
ret = rfalT2TPollerSectorSelect(secNo);
if( ret != ERR_NONE )
{
return ret;
}
ctx->subCtx.t2t.currentSecNo = secNo;
}
ret = rfalT2TPollerWrite(blNo, buf);
return ret;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len)
{
ReturnCode ret;
uint32_t lvOffset = offset;
uint32_t lvLen = len;
const uint8_t * lvBuf = buf;
uint16_t blockAddr;
uint8_t byteNo;
uint8_t le;
uint8_t tempBuf[NDEF_T2T_READ_RESP_SIZE];
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) || (lvLen == 0U) )
{
return ERR_PARAM;
}
ndefT2TInvalidateCache(ctx);
do
{
blockAddr = (uint16_t)(lvOffset / NDEF_T2T_BLOCK_SIZE);
byteNo = (uint8_t)(lvOffset % NDEF_T2T_BLOCK_SIZE);
le = (lvLen < NDEF_T2T_BLOCK_SIZE) ? (uint8_t)lvLen : (uint8_t)NDEF_T2T_BLOCK_SIZE;
if( (byteNo != 0U ) || (lvLen < NDEF_T2T_BLOCK_SIZE) )
{
ret = ndefT2TPollerReadBlock(ctx, blockAddr, tempBuf);
if( ret != ERR_NONE )
{
return ret;
}
if( (NDEF_T2T_BLOCK_SIZE - byteNo) < le )
{
le = NDEF_T2T_BLOCK_SIZE - byteNo;
}
if( le > 0U )
{
(void)ST_MEMCPY(&tempBuf[byteNo], lvBuf, le);
}
ret = ndefT2TPollerWriteBlock(ctx, blockAddr, tempBuf);
if( ret != ERR_NONE )
{
return ret;
}
}
else
{
ret = ndefT2TPollerWriteBlock(ctx, blockAddr, lvBuf);
if( ret != ERR_NONE )
{
return ret;
}
}
lvBuf = &lvBuf[le];
lvOffset += le;
lvLen -= le;
} while( lvLen != 0U );
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen)
{
ReturnCode ret;
uint8_t buf[NDEF_T2T_BLOCK_SIZE];
uint8_t dataIt;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
{
return ERR_WRONG_STATE;
}
dataIt = 0U;
buf[dataIt] = NDEF_T2T_TLV_NDEF_MESSAGE;
dataIt++;
if( rawMessageLen <= NDEF_SHORT_VFIELD_MAX_LEN )
{
buf[dataIt] = (uint8_t) rawMessageLen;
dataIt++;
}
else
{
buf[dataIt] = (uint8_t) (rawMessageLen >> 8U);
dataIt++;
buf[dataIt] = (uint8_t) rawMessageLen;
dataIt++;
}
if( rawMessageLen == 0U )
{
buf[dataIt] = NDEF_T2T_TLV_TERMINATOR;
dataIt++;
}
ret = ndefT2TPollerWriteBytes(ctx, ctx->subCtx.t2t.offsetNdefTLV, buf, dataIt);
if( (ret != ERR_NONE) && (rawMessageLen != 0U) && ((ctx->messageOffset + rawMessageLen) < ctx->areaLen) )
{
/* Write Terminator TLV */
dataIt = 0U;
buf[dataIt] = NDEF_T2T_TLV_TERMINATOR;
dataIt++;
(void)ndefT2TPollerWriteBytes(ctx, ctx->messageOffset + rawMessageLen, buf, dataIt );
}
return ret;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen)
{
ReturnCode ret;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) || ((buf == NULL) && (bufLen != 0U)) )
{
return ERR_PARAM;
}
/* TS T2T v1.0 7.5.3.1/2: T4T 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 T2T 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 T2T v1.0 7.5.3.3: verify available space */
ret = ndefT2TPollerCheckAvailableSpace(ctx, bufLen);
if( ret != ERR_NONE )
{
/* Conclude procedures */
return ERR_PARAM;
}
/* TS T2T v1.0 7.5.3.4: reset L_Field to 0 */
/* and update ctx->messageOffset according to L-field len */
ret = ndefT2TPollerBeginWriteMessage(ctx, bufLen);
if( ret != ERR_NONE )
{
ctx->state = NDEF_STATE_INVALID;
/* Conclude procedure */
return ret;
}
if( bufLen != 0U )
{
/* TS T2T v1.0 7.5.3.5: write new NDEF message */
ret = ndefT2TPollerWriteBytes(ctx, ctx->messageOffset, buf, bufLen);
if (ret != ERR_NONE)
{
/* Conclude procedure */
ctx->state = NDEF_STATE_INVALID;
return ret;
}
/* TS T2T v1.0 7.5.3.6 & 7.5.3.7: update L_Field and write Terminator TLV */
ret = ndefT2TPollerEndWriteMessage(ctx, bufLen);
if( ret != ERR_NONE )
{
/* Conclude procedure */
ctx->state = NDEF_STATE_INVALID;
return ret;
}
}
return ret;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer *cc, uint32_t options)
{
ReturnCode ret;
uint8_t dataIt;
static const uint8_t emptyNdef[] = {NDEF_T2T_TLV_NDEF_MESSAGE, 0x00U, NDEF_T2T_TLV_TERMINATOR, 0x00U};
NO_WARNING(options);
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
/*
* Read CC area
*/
ret = ndefT2TPollerReadBytes(ctx, NDEF_T2T_CC_OFFSET, NDEF_T2T_CC_LEN, ctx->ccBuf, NULL);
if( ret != ERR_NONE )
{
return ret;
}
ndefT2TInvalidateCache(ctx);
/*
* Write CC only in case of virgin CC area
*/
if( (ctx->ccBuf[NDEF_T2T_CC_0] == 0U) && (ctx->ccBuf[NDEF_T2T_CC_1] == 0U) && (ctx->ccBuf[NDEF_T2T_CC_2] == 0U) && (ctx->ccBuf[NDEF_T2T_CC_3] == 0U) )
{
dataIt = 0U;
if( cc == NULL )
{
/* Use default values if no cc provided */
ctx->ccBuf[dataIt] = NDEF_T2T_MAGIC;
dataIt++;
ctx->ccBuf[dataIt] = NDEF_T2T_VERSION_1_0;
dataIt++;
ctx->ccBuf[dataIt] = NDEF_T2T_STATIC_MEM_SIZE / NDEF_T2T_SIZE_DIVIDER;
dataIt++;
ctx->ccBuf[dataIt] = 0x00U;
dataIt++;
}
else
{
ctx->ccBuf[dataIt] = cc->t2t.magicNumber;
dataIt++;
ctx->ccBuf[dataIt] = (uint8_t)(cc->t2t.majorVersion << 4U) | cc->t2t.minorVersion;
dataIt++;
ctx->ccBuf[dataIt] = cc->t2t.size;
dataIt++;
ctx->ccBuf[dataIt] = (uint8_t)(cc->t2t.readAccess << 4U) | cc->t2t.writeAccess;
dataIt++;
}
ret = ndefT2TPollerWriteBlock(ctx, NDEF_T2T_CC_OFFSET/NDEF_T2T_BLOCK_SIZE, ctx->ccBuf);
if( ret != ERR_NONE )
{
return ret;
}
}
/*
* Write NDEF place holder
*/
ret = ndefT2TPollerWriteBlock(ctx, NDEF_T2T_AREA_OFFSET/NDEF_T2T_BLOCK_SIZE, emptyNdef);
return ret;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerCheckPresence(ndefContext *ctx)
{
ReturnCode ret;
uint16_t blockAddr;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
blockAddr = 0U;
ret = ndefT2TPollerReadBlock(ctx, blockAddr, ctx->subCtx.t2t.cacheBuf);
if( ret != ERR_NONE )
{
ndefT2TInvalidateCache(ctx);
return ret;
}
ctx->subCtx.t2t.cacheAddr = (uint32_t)blockAddr * NDEF_T2T_BLOCK_SIZE;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen)
{
uint32_t lLen;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if ( ctx->state == NDEF_STATE_INVALID )
{
return ERR_WRONG_STATE;
}
lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T2T_TLV_L_3_BYTES_LEN : NDEF_T2T_TLV_L_1_BYTES_LEN;
if( (messageLen + ctx->subCtx.t2t.offsetNdefTLV + NDEF_T2T_TLV_T_LEN + lLen) > (ctx->areaLen + NDEF_T2T_AREA_OFFSET) )
{
return ERR_NOMEM;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen)
{
ReturnCode ret;
uint32_t lLen;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
{
return ERR_WRONG_STATE;
}
/* TS T2T v1.0 7.5.3.4: reset L_Field to 0 */
ret = ndefT2TPollerWriteRawMessageLen(ctx, 0U);
if( ret != ERR_NONE )
{
/* Conclude procedure */
ctx->state = NDEF_STATE_INVALID;
return ret;
}
lLen = ( messageLen > NDEF_SHORT_VFIELD_MAX_LEN) ? NDEF_T2T_TLV_L_3_BYTES_LEN : NDEF_T2T_TLV_L_1_BYTES_LEN;
ctx->messageOffset = ctx->subCtx.t2t.offsetNdefTLV;
ctx->messageOffset += NDEF_T2T_TLV_T_LEN; /* T Len */
ctx->messageOffset += lLen; /* L Len */
ctx->state = NDEF_STATE_INITIALIZED;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT2TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen)
{
ReturnCode ret;
if( (ctx == NULL) || !ndefT2TisT2TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( ctx->state != NDEF_STATE_INITIALIZED )
{
return ERR_WRONG_STATE;
}
/* TS T2T v1.0 7.5.3.6 & 7.5.3.7: update L_Field and write Terminator TLV */
ret = ndefT2TPollerWriteRawMessageLen(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;
}
#endif /* NDEF_FEATURE_ALL */
#endif /* RFAL_FEATURE_T2T */