/****************************************************************************** * \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 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 */