913 lines
34 KiB
C
Raw Normal View History

2022-04-28 02:04:02 +02:00
/******************************************************************************
* \attention
*
* <h2><center>&copy; 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 Forum T3T
*
* This module provides an interface to perform as a NFC Reader/Writer
* to handle a Type 3 Tag T3T
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "ndef_poller.h"
#include "ndef_t3t.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_NFCF
#error " RFAL: Module configuration missing. Please enable/disable T3T module by setting: RFAL_FEATURE_NFCF "
#endif
//#define RFAL_FEATURE_NFCF
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define NDEF_T3T_MAX_DEVICE 1U /*!< T3T maximum number of device for detection */
#define NDEF_T3T_SYSTEMCODE 0x12FCU /*!< SENSF_RES System Code for T3T TS T3T 1.0 7.1.1.1 */
#define NDEF_T3T_WRITEFLAG_ON 0xFU /*!< WriteFlag ON value TS T3T 1.0 7.2.2.16 */
#define NDEF_T3T_WRITEFLAG_OFF 0x0U /*!< WriteFlag OFF value TS T3T 1.0 7.2.2.16 */
#define NDEF_T3T_AREA_OFFSET 16U /*!< T3T Area starts at block #1 */
#define NDEF_T3T_BLOCKLEN 16U /*!< T3T block len is always 16 */
#define NDEF_T3T_NBBLOCKSMAX 4U /*!< T3T max nb of blocks per read/write */
#define NDEF_T3T_FLAG_RW 1U /*!< T3T read/write flag value */
#define NDEF_T3T_FLAG_RO 0U /*!< T3T read only flag value */
#define NDEF_T3T_SENSFRES_NFCID2 2U /*!< T3T offset of UID in SENSFRES struct */
#define NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN 0xEU /*!< T3T checksum len for attribute info to compute */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_VERSION 0x0U /*!< T3T attribute info offset of version */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_NBR 1U /*!< T3T attribute info offset of number of read */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_NBW 2U /*!< T3T attribute info offset of number of write */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_MAXB 3U /*!< T3T attribute info offset of MAXB */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_W 9U /*!< T3T attribute info offset of Write flag */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_RW 10U /*!< T3T attribute info offset of Read/Write flag */
#define NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN 11U /*!< T3T attribute info offset of LN field */
#define NDEF_T3T_ATTRIB_INFO_VERSION_1_0 0x10U /*!< T3T attribute info full version number */
#define NDEF_T3T_ATTRIB_INFO_BLOCK_NB 0U /*!< T3T attribute info block number */
#define NDEF_T3T_BLOCKNB_CONF 0x80U /*!< T3T TxRx config value for Read/Write block */
#define NDEF_T3T_CHECK_NB_BLOCKS_LEN 1U /*!< T3T Length of the Nb of blocks in the CHECK reply */
#ifdef RFAL_FEATURE_NFCF
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define ndefT3TisT3TDevice(device) ((device)->type == RFAL_NFC_LISTEN_TYPE_NFCF)
#define ndefT3TIsWriteFlagON(writeFlag) ((writeFlag) == NDEF_T3T_WRITEFLAG_ON)
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static ReturnCode ndefT3TPollerReadBlocks ( ndefContext * ctx, uint16_t blockNum, uint8_t nbBlocks, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t *rcvLen );
static ReturnCode ndefT3TPollerReadAttributeInformationBlock ( ndefContext * ctx);
#if NDEF_FEATURE_ALL
static ReturnCode ndefT3TPollerWriteBlocks ( ndefContext * ctx, uint16_t blockNum, uint8_t nbBlocks, const uint8_t* dataBlocks);
static ReturnCode ndefT3TPollerWriteAttributeInformationBlock( ndefContext * ctx);
#endif /* NDEF_FEATURE_ALL */
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
static ReturnCode ndefT3TPollerReadBlocks( ndefContext *ctx, uint16_t blockNum, uint8_t nbBlocks, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *rcvLen )
{
ReturnCode ret;
uint16_t requestedDataSize;
rfalNfcfServBlockListParam servBlock;
rfalNfcfBlockListElem * listBlocks;
uint8_t index;
uint16_t rcvdLen = 0U;
rfalNfcfServ serviceCodeLst = 0x000BU; /* serviceCodeLst */
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
requestedDataSize = (uint16_t)nbBlocks * NDEF_T3T_BLOCK_SIZE;
if( rxBufLen < requestedDataSize )
{
return ERR_PARAM;
}
listBlocks = ctx->subCtx.t3t.listBlocks;
for (index = 0U; index < nbBlocks; index++ )
{
/* Write each block number (16 bits per block address) */
listBlocks[index].conf = (uint8_t) NDEF_T3T_BLOCKNB_CONF;
listBlocks[index].blockNum = (uint16_t)( blockNum + (uint16_t) index);
}
servBlock.numServ = 1U;
servBlock.servList = &serviceCodeLst;
servBlock.numBlock = nbBlocks;
servBlock.blockList = listBlocks;
ret = rfalNfcfPollerCheck(ctx->device.dev.nfcf.sensfRes.NFCID2, &servBlock, ctx->subCtx.t3t.rxbuf, (uint16_t)sizeof(ctx->subCtx.t3t.rxbuf), &rcvdLen);
if (ret != ERR_NONE)
{
return ret;
}
if( rcvdLen != (uint16_t)(NDEF_T3T_CHECK_NB_BLOCKS_LEN + requestedDataSize) )
{
return ERR_REQUEST;
}
if( requestedDataSize > 0U )
{
(void)ST_MEMCPY( rxBuf, &ctx->subCtx.t3t.rxbuf[NDEF_T3T_CHECK_NB_BLOCKS_LEN], requestedDataSize );
if (rcvLen != NULL)
{
*rcvLen = requestedDataSize;
}
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerReadBytes(ndefContext *ctx, uint32_t offset, uint32_t len, uint8_t *buf, uint32_t *rcvdLen)
{
uint16_t res;
uint16_t nbRead;
ReturnCode result = ERR_NONE;
uint32_t currentLen = len;
uint32_t lvRcvLen = 0U;
const uint16_t blockLen = (uint16_t) NDEF_T3T_BLOCKLEN;
uint16_t startBlock = (uint16_t) (offset / blockLen);
uint16_t startAddr = (uint16_t) (startBlock * blockLen);
uint16_t startOffset= (uint16_t) (offset - (uint32_t) startAddr);
uint16_t nbBlocks = (uint16_t) NDEF_T3T_NBBLOCKSMAX;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) || (len == 0U) )
{
return ERR_PARAM;
}
if (ctx->state != NDEF_STATE_INVALID)
{
nbBlocks = ctx->cc.t3t.nbR;
}
if ( startOffset != 0U )
{
/* Unaligned read, need to use a tmp buffer */
res = ndefT3TPollerReadBlocks(ctx, startBlock, 1U /* One block */ , ctx->subCtx.t3t.rxbuf, blockLen, &nbRead);
if (res != ERR_NONE)
{
/* Check result */
result = res;
}
else if (nbRead != NDEF_T3T_BLOCKLEN)
{
/* Check len */
result = ERR_MEM_CORRUPT;
}
else
{
nbRead = (uint16_t) (nbRead - (uint16_t)startOffset);
if ((uint32_t) nbRead > currentLen)
{
nbRead = (uint16_t) currentLen;
}
if (nbRead > 0U)
{
(void)ST_MEMCPY(buf, &ctx->subCtx.t3t.rxbuf[offset], (uint32_t)nbRead);
}
lvRcvLen += (uint32_t) nbRead;
currentLen -= (uint32_t) nbRead;
startBlock++;
}
}
while ( (currentLen >= (uint32_t)blockLen) && (result == ERR_NONE) )
{
if ( currentLen < ((uint32_t)blockLen * nbBlocks) )
{
/* Reduce the nb of blocks to read */
nbBlocks = (uint16_t) (currentLen / blockLen);
}
res = ndefT3TPollerReadBlocks(ctx, startBlock, (uint8_t)nbBlocks, ctx->subCtx.t3t.rxbuf, blockLen * nbBlocks, &nbRead);
if (res != ERR_NONE)
{
/* Check result */
return res;
}
else if (nbRead != (blockLen * nbBlocks))
{
/* Check len */
return ERR_MEM_CORRUPT;
}
else
{
(void)ST_MEMCPY(&buf[lvRcvLen], ctx->subCtx.t3t.rxbuf, (uint32_t)currentLen);
lvRcvLen += nbRead;
currentLen -= nbRead;
startBlock += nbBlocks;
}
}
if ( (currentLen > 0U) && (result == ERR_NONE) )
{
/* Unaligned read, need to use a tmp buffer */
res = ndefT3TPollerReadBlocks(ctx, startBlock, 1U /* One block */, ctx->subCtx.t3t.rxbuf, blockLen, &nbRead);
if (res != ERR_NONE)
{
/* Check result */
return res;
}
else if (nbRead != NDEF_T3T_BLOCKLEN)
{
/* Check len */
return ERR_MEM_CORRUPT;
}
else
{
if (currentLen > 0U)
{
(void)ST_MEMCPY(&buf[lvRcvLen], ctx->subCtx.t3t.rxbuf, (uint32_t)currentLen);
}
lvRcvLen += (uint32_t) currentLen;
currentLen -= (uint32_t) currentLen;
}
}
if ( (currentLen == 0U) && (result == ERR_NONE) )
{
result = ERR_NONE;
}
if( rcvdLen != NULL )
{
*rcvdLen = lvRcvLen;
}
return result;
}
/*******************************************************************************/
static ReturnCode ndefT3TPollerReadAttributeInformationBlock( ndefContext * ctx)
{
/* Follow 7.4.1 NDEF Detection Procedure */
ReturnCode retcode;
uint8_t * rxbuf;
uint16_t checksum_received;
uint16_t checksum_computed = 0U;
uint16_t rcvLen = 0U;
uint8_t i;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
rxbuf = ctx->ccBuf;
retcode = ndefT3TPollerReadBlocks( ctx, NDEF_T3T_ATTRIB_INFO_BLOCK_NB, 1U /* One block */, rxbuf, NDEF_T3T_BLOCK_SIZE, &rcvLen );
if ( (retcode != ERR_NONE) && (rcvLen != NDEF_T3T_BLOCK_SIZE) )
{
return retcode;
}
/* Now compute checksum */
for (i = 0U; i < NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN; i++)
{
checksum_computed += (uint16_t) rxbuf[i];
}
checksum_received = ((uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN] << 8U) + (uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_CHECKSUM_LEN+ 1U];
if (checksum_received != checksum_computed)
{
return ERR_REQUEST;
}
/* Now copy the attribute struct */
ctx->cc.t3t.majorVersion = ( rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_VERSION] >> 4U);
ctx->cc.t3t.minorVersion = ( rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_VERSION] & 0xFU);
ctx->cc.t3t.nbR = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_NBR];
ctx->cc.t3t.nbW = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_NBW];
ctx->cc.t3t.nMaxB = ((uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_MAXB] << 8U) + (uint16_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_MAXB + 1U];
ctx->cc.t3t.writeFlag = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_W];
ctx->cc.t3t.rwFlag = rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_RW];
ctx->cc.t3t.Ln = ((uint32_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN + 0U] << 0x10U)
| ((uint32_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN + 1U] << 0x8U)
| (uint32_t)rxbuf[NDEF_T3T_ATTRIB_INFO_OFFSET_FLAG_LN + 2U];
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerContextInitialization(ndefContext *ctx, const rfalNfcDevice *dev)
{
if( (ctx == NULL) || (dev == NULL) || !ndefT3TisT3TDevice(dev) )
{
return ERR_PARAM;
}
(void)ST_MEMCPY(&ctx->device, dev, sizeof(ctx->device));
ctx->state = NDEF_STATE_INVALID;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerNdefDetect(ndefContext *ctx, ndefInfo *info)
{
ReturnCode retcode;
rfalFeliCaPollRes pollRes[NDEF_T3T_MAX_DEVICE];
uint8_t devCnt = NDEF_T3T_MAX_DEVICE;
uint8_t collisions = 0U;
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) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
ctx->state = NDEF_STATE_INVALID;
/* TS T3T v1.0 7.4.1.1 the Reader/Writer SHALL send a SENSF_REQ Command with System Code set to 12FCh. */
retcode = rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, NDEF_T3T_SYSTEMCODE, (uint8_t)RFAL_FELICA_POLL_RC_NO_REQUEST, pollRes, &devCnt, &collisions );
if( retcode != ERR_NONE )
{
/* TS T3T v1.0 7.4.1.2 Conclude procedure. */
return retcode;
}
/* Check if UID of the first card is the same */
if( ST_BYTECMP(&(pollRes[0U][NDEF_T3T_SENSFRES_NFCID2]), ctx->device.dev.nfcf.sensfRes.NFCID2, RFAL_NFCF_NFCID2_LEN ) != 0 )
{
return ERR_REQUEST; /* Wrong UID */
}
/* TS T3T v1.0 7.4.1.3 The Reader/Writer SHALL read the Attribute Information Block using the CHECK Command. */
/* TS T3T v1.0 7.4.1.4 The Reader/Writer SHALL verify the value of Checksum of the Attribute Information Block. */
retcode = ndefT3TPollerReadAttributeInformationBlock(ctx);
if( retcode != ERR_NONE )
{
return retcode;
}
/* TS T3T v1.0 7.4.1.6 The Reader/Writer SHALL check if it supports the NDEF mapping version number based on the rules given in Section 7.3. */
if( ctx->cc.t3t.majorVersion != ndefMajorVersion(NDEF_T3T_ATTRIB_INFO_VERSION_1_0) )
{
return ERR_REQUEST;
}
ctx->messageLen = ctx->cc.t3t.Ln;
ctx->messageOffset = NDEF_T3T_AREA_OFFSET;
ctx->areaLen = (uint32_t)ctx->cc.t3t.nMaxB * NDEF_T3T_BLOCK_SIZE;
ctx->state = NDEF_STATE_INITIALIZED;
if (ctx->messageLen > 0U)
{
if (ctx->cc.t3t.rwFlag == NDEF_T3T_FLAG_RW)
{
ctx->state = NDEF_STATE_READWRITE;
}
else
{
if (ctx->cc.t3t.rwFlag == NDEF_T3T_FLAG_RO)
{
ctx->state = NDEF_STATE_READONLY;
}
}
}
if( info != NULL )
{
info->state = ctx->state;
info->majorVersion = ctx->cc.t3t.majorVersion;
info->minorVersion = ctx->cc.t3t.minorVersion;
info->areaLen = ctx->areaLen;
info->areaAvalableSpaceLen = ctx->areaLen;
info->messageLen = ctx->messageLen;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerReadRawMessage(ndefContext *ctx, uint8_t *buf, uint32_t bufLen, uint32_t *rcvdLen)
{
ReturnCode ret;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) || (buf == NULL) )
{
return ERR_PARAM;
}
/* TS T3T v1.0 7.4.2: This procedure assumes that the Reader/Writer has successfully performed the NDEF detection procedure. */
/* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF read procedure*/
if ( ctx->state <= NDEF_STATE_INITIALIZED )
{
return ERR_WRONG_STATE;
}
/* TS T3T v1.0 7.4.2.1: If the WriteFlag remembered during the NDEF detection procedure is set to ON, the NDEF data may be inconsistent ...*/
if( ndefT3TIsWriteFlagON(ctx->cc.t3t.writeFlag) )
{
/* TS T3T v1.0 7.4.2.1: ... the Reader/Writer SHALL conclude the NDEF read procedure*/
return ERR_WRONG_STATE;
}
if( ctx->messageLen > bufLen )
{
return ERR_NOMEM;
}
/* TS T3T v1.0 7.4.2.2: Read NDEF data */
ret = ndefT3TPollerReadBytes( ctx, ctx->messageOffset, ctx->messageLen, buf, rcvdLen );
if( ret != ERR_NONE )
{
ctx->state = NDEF_STATE_INVALID;
}
return ret;
}
#if NDEF_FEATURE_ALL
/*******************************************************************************/
static ReturnCode ndefT3TPollerWriteBlocks( ndefContext * ctx, uint16_t blockNum, uint8_t nbBlocks, const uint8_t* dataBlocks)
{
ReturnCode ret;
rfalNfcfServBlockListParam servBlock;
rfalNfcfBlockListElem * listBlocks;
uint8_t index;
rfalNfcfServ serviceCodeLst = 0x0009U;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
listBlocks = ctx->subCtx.t3t.listBlocks;
for (index = 0U; index < nbBlocks; index++)
{
/* Write each block number (16 bits per block address) */
listBlocks[index].conf = (uint8_t) NDEF_T3T_BLOCKNB_CONF;
listBlocks[index].blockNum = (uint16_t)( blockNum + (uint16_t) index);
}
servBlock.numServ = 1U;
servBlock.servList = &serviceCodeLst;
servBlock.numBlock = nbBlocks;
servBlock.blockList = listBlocks;
ret = rfalNfcfPollerUpdate( ctx->device.dev.nfcf.sensfRes.NFCID2, &servBlock, ctx->subCtx.t3t.txbuf, (uint16_t)sizeof(ctx->subCtx.t3t.txbuf), dataBlocks, ctx->subCtx.t3t.rxbuf, (uint16_t)sizeof(ctx->subCtx.t3t.rxbuf));
return ret;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerWriteBytes(ndefContext *ctx, uint32_t offset, const uint8_t *buf, uint32_t len)
{
uint16_t nbRead;
uint16_t nbWrite;
uint16_t res;
ReturnCode result = ERR_NONE;
uint32_t currentLen = len;
uint32_t txtLen = 0U;
const uint16_t blockLen = (uint16_t )NDEF_T3T_BLOCKLEN;
uint16_t nbBlocks = (uint16_t ) NDEF_T3T_NBBLOCKSMAX;
uint16_t startBlock = (uint16_t) (offset / blockLen);
uint16_t startAddr = (uint16_t) (startBlock * blockLen);
uint16_t startOffset= (uint16_t) (offset - (uint32_t) startAddr);
uint8_t tmpBuf[NDEF_T3T_BLOCKLEN];
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) || (len == 0U) )
{
return ERR_PARAM;
}
if (ctx->state != NDEF_STATE_INVALID)
{
nbBlocks = ctx->cc.t3t.nbW;
}
if ( startOffset != 0U )
{
/* Unaligned write, need to use a tmp buffer */
res = ndefT3TPollerReadBlocks(ctx, startBlock, 1, tmpBuf, blockLen, &nbRead);
if (res != ERR_NONE)
{
/* Check result */
result = res;
}
else if (nbRead != blockLen)
{
/* Check len */
result = ERR_MEM_CORRUPT;
}
else
{
/* Fill the rest of the buffer with user data */
nbWrite = NDEF_T3T_BLOCKLEN - startOffset;
if (nbWrite > len)
{
nbWrite = (uint16_t) len;
}
(void)ST_MEMCPY(&tmpBuf[startOffset], buf, nbWrite);
res = ndefT3TPollerWriteBlocks(ctx, startBlock, 1U /* One block */, tmpBuf);
if (res == ERR_NONE)
{
txtLen += (uint32_t) nbWrite;
currentLen -= (uint32_t) nbWrite;
startBlock++;
}
else
{
result = res; /* Copy the error code */
}
}
}
while ( (currentLen >= (uint32_t)blockLen) && (result == ERR_NONE) )
{
if ( currentLen < ((uint32_t)blockLen * nbBlocks) )
{
/* Reduce the nb of blocks to read */
nbBlocks = (uint16_t) (currentLen / blockLen);
}
nbWrite = blockLen * nbBlocks;
res = ndefT3TPollerWriteBlocks(ctx, startBlock, (uint8_t) nbBlocks, &buf[txtLen]);
if (res != ERR_NONE)
{
/* Check result */
result = res;
}
else
{
txtLen += nbWrite;
currentLen -= nbWrite;
startBlock += nbBlocks;
}
}
if ( (currentLen > 0U) && (result == ERR_NONE) )
{
/* Unaligned write, need to use a tmp buffer */
res = ndefT3TPollerReadBlocks(ctx, startBlock, 1U /* One block */, tmpBuf, blockLen, &nbRead);
if (res != ERR_NONE)
{
/* Check result */
result = res;
}
else if (nbRead != blockLen)
{
/* Check len */
result = ERR_MEM_CORRUPT;
}
else
{
/* Fill the beginning of the buffer with user data */
(void)ST_MEMCPY( tmpBuf, &buf[txtLen], currentLen);
res = ndefT3TPollerWriteBlocks(ctx, startBlock, 1U /* One block */, tmpBuf);
if (res == ERR_NONE)
{
currentLen = 0U;
}
else
{
result = res; /* Copy the error code */
}
}
}
if ( (currentLen == 0U) && (result == ERR_NONE) )
{
result = ERR_NONE;
}
return result;
}
/*******************************************************************************/
static ReturnCode ndefT3TPollerWriteAttributeInformationBlock(ndefContext * ctx)
{
uint8_t dataIt;
uint16_t checksum;
uint8_t * buf;
ReturnCode ret;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if ( ctx->state < NDEF_STATE_INITIALIZED )
{
return ERR_WRONG_STATE;
}
dataIt = 0U;
buf = ctx->ccBuf;
checksum = 0U;
buf[dataIt] = ((uint8_t)(ctx->cc.t3t.majorVersion << 4U)) | ctx->cc.t3t.minorVersion; /* Byte 0 Ver */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = ctx->cc.t3t.nbR; /* Byte 1 Nbr */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = ctx->cc.t3t.nbW; /* Byte 2 Nbw */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = (uint8_t)(ctx->cc.t3t.nMaxB >> 8U); /* Byte 3 NmaxB (MSB) */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = (uint8_t)(ctx->cc.t3t.nMaxB >> 0U); /* Byte 4 NmaxB (LSB) */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = 0U; /* Byte 5 RFU */
dataIt++;
buf[dataIt] = 0U; /* Byte 6 RFU */
dataIt++;
buf[dataIt] = 0U; /* Byte 7 RFU */
dataIt++;
buf[dataIt] = 0U; /* Byte 8 RFU */
dataIt++;
buf[dataIt] = ctx->cc.t3t.writeFlag; /* Byte 9 WriteFlag */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = ctx->cc.t3t.rwFlag; /* Byte 10 RWFlag */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = (uint8_t)(ctx->cc.t3t.Ln >> 16U); /* Byte 11 Ln (MSB) */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = (uint8_t)(ctx->cc.t3t.Ln >> 8U); /* Byte 12 Ln (middle) */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = (uint8_t)(ctx->cc.t3t.Ln >> 0U); /* Byte 13 Ln (LSB) */
checksum += buf[dataIt];
dataIt++;
buf[dataIt] = (uint8_t)(checksum >> 8U); /* Byte 14 checksum MSB */
dataIt++;
buf[dataIt] = (uint8_t)(checksum >> 0U); /* Byte 15 checksum LSB */
dataIt++;
ret = ndefT3TPollerWriteBlocks(ctx, NDEF_T3T_ATTRIB_INFO_BLOCK_NB, 1U /* One block */, buf);
return ret;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerWriteRawMessage(ndefContext *ctx, const uint8_t *buf, uint32_t bufLen)
{
ReturnCode ret;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) || ((buf == NULL) && (bufLen != 0U)) )
{
return ERR_PARAM;
}
/* TS T3T v1.0 7.4.3: This procedure assumes that the Reader/Writer has successfully performed the NDEF detection procedure... */
/* Warning: current tag content must not be changed between NDEF Detect procedure and NDEF read procedure*/
/* TS T3T v1.0 7.4.3: ... and that the RWFlag in the Attribute Information Block is set to 01h. */
if ( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
{
/* Conclude procedure */
return ERR_WRONG_STATE;
}
/* TS T3T v1.0 7.4.3.2: verify available space */
ret = ndefT3TPollerCheckAvailableSpace(ctx, bufLen);
if( ret != ERR_NONE )
{
/* Conclude procedure */
return ERR_PARAM;
}
/* TS T3T v1.0 7.4.3.3: update WriteFlag */
ret = ndefT3TPollerBeginWriteMessage(ctx, bufLen);
if( ret != ERR_NONE )
{
ctx->state = NDEF_STATE_INVALID;
/* Conclude procedure */
return ret;
}
if( bufLen != 0U )
{
/* TS T3T v1.0 7.4.3.4: write new NDEF message */
ret = ndefT3TPollerWriteBytes(ctx, ctx->messageOffset, buf, bufLen);
if (ret != ERR_NONE)
{
/* Conclude procedure */
ctx->state = NDEF_STATE_INVALID;
return ret;
}
}
/* TS T3T v1.0 7.4.3.5: update Ln value and set WriteFlag to OFF */
ret = ndefT3TPollerEndWriteMessage(ctx, bufLen);
if( ret != ERR_NONE )
{
/* Conclude procedure */
ctx->state = NDEF_STATE_INVALID;
return ret;
}
return ret;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerTagFormat(ndefContext *ctx, const ndefCapabilityContainer * cc, uint32_t options)
{
ReturnCode res;
rfalFeliCaPollRes buffOut [NDEF_T3T_MAX_DEVICE];
uint8_t devCnt = NDEF_T3T_MAX_DEVICE;
uint8_t collisions = 0U;
NO_WARNING(options); /* options not used in T3T */
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if ( cc == NULL)
{
/* No default CC found so have to analyse the tag */
res = ndefT3TPollerReadAttributeInformationBlock(ctx); /* Read current cc */
if (res != ERR_NONE)
{
return res;
}
}
else
{
/* Nothing to do */
(void)ST_MEMCPY(&ctx->cc, cc, sizeof(ndefCapabilityContainer));
}
/* 4.3.3 System Definition Information for SystemCode = 0x12FC (NDEF) */
res = rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, NDEF_T3T_SYSTEMCODE, (uint8_t)RFAL_FELICA_POLL_RC_NO_REQUEST, buffOut, &devCnt, &collisions );
if (res != ERR_NONE)
{
return res;
}
res = rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, NDEF_T3T_SYSTEMCODE, (uint8_t)RFAL_FELICA_POLL_RC_SYSTEM_CODE, buffOut, &devCnt, &collisions );
if (res != ERR_NONE)
{
return res;
}
ctx->state = NDEF_STATE_INITIALIZED; /* to be sure that the block will be written */
ctx->cc.t3t.Ln = 0U; /* Force actual stored NDEF size to 0 */
ctx->cc.t3t.writeFlag = 0U; /* Force WriteFlag to 0 */
res = ndefT3TPollerWriteAttributeInformationBlock(ctx);
return res;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerCheckPresence(ndefContext *ctx)
{
ReturnCode retcode;
uint16_t nbRead;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
/* Perform a simple readblock */
retcode = ndefT3TPollerReadBlocks(ctx, 0U /* First block */, 1U /* One Block */, ctx->subCtx.t3t.rxbuf, NDEF_T3T_BLOCKLEN, &nbRead);
return retcode;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerCheckAvailableSpace(const ndefContext *ctx, uint32_t messageLen)
{
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if ( ctx->state == NDEF_STATE_INVALID )
{
return ERR_WRONG_STATE;
}
if( messageLen > ctx->areaLen )
{
return ERR_NOMEM;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerBeginWriteMessage(ndefContext *ctx, uint32_t messageLen)
{
ReturnCode ret;
NO_WARNING(messageLen);
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
{
return ERR_WRONG_STATE;
}
/* Update WriteFlag */
ctx->cc.t3t.writeFlag = NDEF_T3T_WRITEFLAG_ON;
ret = ndefT3TPollerWriteAttributeInformationBlock(ctx);
if( ret != ERR_NONE )
{
/* Conclude procedure */
ctx->state = NDEF_STATE_INVALID;
return ret;
}
ctx->state = NDEF_STATE_INITIALIZED;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerEndWriteMessage(ndefContext *ctx, uint32_t messageLen)
{
ReturnCode ret;
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( ctx->state != NDEF_STATE_INITIALIZED )
{
return ERR_WRONG_STATE;
}
/* TS T3T v1.0 7.4.3.5 Update Attribute Information Block */
ctx->cc.t3t.writeFlag = NDEF_T3T_WRITEFLAG_OFF;
ctx->cc.t3t.Ln = messageLen;
ret = ndefT3TPollerWriteAttributeInformationBlock(ctx);
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;
}
/*******************************************************************************/
ReturnCode ndefT3TPollerWriteRawMessageLen(ndefContext *ctx, uint32_t rawMessageLen)
{
if( (ctx == NULL) || !ndefT3TisT3TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( (ctx->state != NDEF_STATE_INITIALIZED) && (ctx->state != NDEF_STATE_READWRITE) )
{
return ERR_WRONG_STATE;
}
return ndefT3TPollerEndWriteMessage(ctx, rawMessageLen);
}
#endif /* NDEF_FEATURE_ALL */
#endif /* RFAL_FEATURE_NFCF */