libNDEF library for the STMicroelectronics X-NUCLEO-NFC04A1

Dependents:   mbed-os-nfc04a1 Wiagro-Lanza34-XDot

Revision:
0:de13951f30f6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,749 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF.c
+  * @author  MMY Application Team
+  * @version $Revision: 3210 $
+  * @date    $Date: 2016-12-05 15:37:48 +0100 (Mon, 05 Dec 2016) $
+  * @brief   This file help to manage NDEF file, to parse and identify them.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty  
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+#include "lib_NDEF_Bluetooth.h"
+#include "lib_NDEF_Handover.h"
+#include "lib_NDEF_Wifi.h"
+#include "mbed.h"
+
+/** @addtogroup NFC_libraries
+ *  @{
+ *  @brief  <b>This is the library used to manage the content of the TAG (data)
+ *          But also the specific feature of the tag, for instance
+ *          password, gpo... </b>
+ */
+
+
+/** @addtogroup libNFC_FORUM
+  * @{
+  * @brief  This part of the library manage data which follow NFC forum organisation.
+  */
+
+/** @defgroup libNDEF_Private_Functions
+  * @{
+  */
+
+
+static uint16_t NDEF_IsNDEFPresent( I2C* mi2cChannel );
+static uint16_t NDEF_ParseRecordHeader( sRecordInfo_t *pRecordStruct );
+static void NDEF_ParseWellKnownType( sRecordInfo_t *pRecordStruct );
+static void NDEF_ParseMediaType( sRecordInfo_t *pRecordStruct );
+static void NDEF_ParseForumExternalType( sRecordInfo_t *pRecordStruct );
+static void NDEF_ParseURI( sRecordInfo_t *pRecordStruct );
+static void NDEF_ParseSP( sRecordInfo_t *pRecordStruct );
+static uint16_t NDEF_IdentifySPRecord( sRecordInfo_t *pRecordStruct, uint8_t* pPayload );
+
+/** @brief This buffer is used to store the data sent/received by the TAG. */
+uint8_t NDEF_Buffer [NDEF_MAX_SIZE];
+/** @brief Size of the buffer used to build the NDEF messages. */
+uint32_t NDEF_Buffer_size = NDEF_MAX_SIZE;
+/** @brief This buffer is used when it's required to prepare a record before adding it to the NDEF_Buffer. */
+uint8_t NDEF_Record_Buffer [NDEF_RECORD_MAX_SIZE];
+/** @brief Size of the buffer used when a record has to be prepared. */
+uint32_t NDEF_Record_Buffer_size = NDEF_RECORD_MAX_SIZE;
+
+/* In case of smart Poster composed with different record, 3 records supported so far */
+sRecordInfo_t SPRecordStruct1, SPRecordStruct2, SPRecordStruct3, SPRecordStruct4;
+sRecordInfo_t *SPRecordStructAdd[SP_MAX_RECORD] = { &SPRecordStruct1, &SPRecordStruct2, &SPRecordStruct3, &SPRecordStruct4 };
+
+/**
+  * @brief  This function checks that the tag contain a NDEF message.
+  * @retval NDEF_OK : There is a NDEF file stored in tag.
+  * @retval NDEF_ERROR : No NDEF in the tag.
+  */
+static uint16_t NDEF_IsNDEFPresent( I2C* mi2cChannel )
+{
+  uint16_t FileSize;
+
+  /* Check NDEF existence */
+  NfcTag_GetLength(&FileSize, mi2cChannel);
+  
+  if( FileSize != 0 )
+    return NDEF_OK;
+  else
+    return NDEF_ERROR;
+}
+
+/**
+  * @brief  This function identify the type of record.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  * @param  pPayload : pointer on the payload.
+  * @retval Status : Status of the operation.
+  */
+static uint16_t NDEF_IdentifySPRecord( sRecordInfo_t *pRecordStruct, uint8_t* pPayload )
+{
+  uint16_t status = NDEF_ERROR;
+  uint16_t SizeOfRecordHeader, TypeNbByte, PayloadLengthField, IDLengthField, IDNbByte;
+
+  /* Is ID length field present */
+  if( (*pPayload) & IL_Mask )
+  {
+    IDLengthField = ID_LENGTH_FIELD;
+  }
+  else
+  {
+    IDLengthField = 0;
+  }
+
+  /* it's a SR */
+  if( (*pPayload) & SR_Mask )
+  {
+    TypeNbByte = pPayload[1];
+    PayloadLengthField = 1;
+    if( IDLengthField == ID_LENGTH_FIELD )
+      IDNbByte = pPayload[3];
+    else
+      IDNbByte = 0;
+  }
+  else
+  {
+    TypeNbByte = pPayload[1];
+    PayloadLengthField = 4;
+    if( IDLengthField == ID_LENGTH_FIELD )
+      IDNbByte = pPayload[6];
+    else
+      IDNbByte = 0;
+  }
+
+  SizeOfRecordHeader = RECORD_FLAG_FIELD + TYPE_LENGTH_FIELD + PayloadLengthField + IDLengthField + TypeNbByte + IDNbByte;
+
+  /* it's a SR */
+  if( pPayload[0] & SR_Mask )
+  {
+    pRecordStruct->RecordFlags = pPayload[0];
+    pRecordStruct->TypeLength = TypeNbByte;
+    pRecordStruct->PayloadLength = pPayload[2];
+    pRecordStruct->IDLength = IDNbByte;
+    memcpy( pRecordStruct->Type, &pPayload[3+IDNbByte], TypeNbByte );
+    memcpy( pRecordStruct->ID, &pPayload[3+IDNbByte+TypeNbByte], IDNbByte );
+    pRecordStruct->PayloadOffset = SizeOfRecordHeader;
+  }
+  else
+  {
+    pRecordStruct->RecordFlags = pPayload[0];
+    pRecordStruct->TypeLength = TypeNbByte;
+    pRecordStruct->PayloadLength = ( ((uint32_t)pPayload[2]) << 24 ) |
+                                   ( ((uint32_t)pPayload[3]) << 16 ) |
+                                   ( ((uint32_t)pPayload[4]) << 8 )
+                                    | pPayload[5] ;
+    pRecordStruct->IDLength = IDNbByte;
+    memcpy( pRecordStruct->Type, &pPayload[6+IDNbByte], TypeNbByte );
+    memcpy( pRecordStruct->ID, &pPayload[6+IDNbByte+TypeNbByte], IDNbByte );
+    pRecordStruct->PayloadOffset = SizeOfRecordHeader;
+  }
+
+  pRecordStruct->PayloadBufferAdd =  pPayload + SizeOfRecordHeader ;
+
+  status = NDEF_ParseRecordHeader( pRecordStruct );
+
+  return status;
+}
+
+/**
+  * @brief  This function parse the record header and dispatch regarding TNF value.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  * @retval NDEF_OK : record identified and structure filled.
+  * @retval NDEF_ERROR : Not supported.
+  */
+static uint16_t NDEF_ParseRecordHeader( sRecordInfo_t *pRecordStruct )
+{
+  uint16_t status = NDEF_OK;
+
+  switch( (pRecordStruct->RecordFlags & TNF_Mask) )
+  {
+    case TNF_WellKnown:
+      NDEF_ParseWellKnownType( pRecordStruct );
+      break;
+
+    case TNF_MediaType:
+      NDEF_ParseMediaType( pRecordStruct );
+      break;
+
+    case TNF_NFCForumExternal:
+      NDEF_ParseForumExternalType( pRecordStruct);
+      break;
+
+  default:
+      /* currently not supported or unknown*/
+      pRecordStruct->NDEF_Type = UNKNOWN_TYPE;
+      status = NDEF_ERROR;
+  }
+  return status;
+}
+
+/**
+  * @brief  This function parse the Well Known type record.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  */
+static void NDEF_ParseWellKnownType( sRecordInfo_t *pRecordStruct )
+{
+  uint8_t* pPayload;
+
+  pPayload = (uint8_t*)( pRecordStruct->PayloadBufferAdd );
+
+  if( !memcmp( &(pRecordStruct->Type), SMART_POSTER_TYPE_STRING, pRecordStruct->TypeLength ) )
+  { 
+    /* special case where	we have to parse others records */
+    pRecordStruct->NDEF_Type = SMARTPOSTER_TYPE;
+    NDEF_ParseSP( pRecordStruct );
+  }
+
+  else if( !memcmp( &(pRecordStruct->Type), URI_TYPE_STRING, pRecordStruct->TypeLength ) )
+  { 
+    /* it's an URI Type check if it's an URL or SMS or ... */
+    /* check identifier */
+    if( *pPayload == URI_ID_0x00 ) 
+    {
+      NDEF_ParseURI( pRecordStruct );
+    }
+    else if( (*pPayload > URI_ID_0x00) && (*pPayload < URI_RFU) ) 
+    {
+      /* email special case  */
+      if( *pPayload == (uint8_t) URI_ID_0x06 )
+      {
+        pRecordStruct->NDEF_Type = URI_EMAIL_TYPE;
+      }
+      else
+      {
+        pRecordStruct->NDEF_Type = WELL_KNOWN_ABRIDGED_URI_TYPE;
+      }
+    }
+    else
+    {
+      pRecordStruct->NDEF_Type = UNKNOWN_TYPE;
+    }
+  }
+
+  else if( !memcmp( &(pRecordStruct->Type), TEXT_TYPE_STRING, pRecordStruct->TypeLength ) )
+  {
+    pRecordStruct->NDEF_Type = TEXT_TYPE;
+  } else if ((!memcmp( &(pRecordStruct->Type), NDEF_HANDOVER_SELECT_TYPE_STR, pRecordStruct->TypeLength )) ||
+            (!memcmp( &(pRecordStruct->Type), NDEF_HANDOVER_REQUEST_TYPE_STR, pRecordStruct->TypeLength ) ))
+  {
+     pRecordStruct->NDEF_Type = HANDOVER_TYPE;
+  }
+  else
+    pRecordStruct->NDEF_Type = UNKNOWN_TYPE;
+}
+
+/**
+  * @brief  This function parse the Media type record.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  */
+static void NDEF_ParseMediaType( sRecordInfo_t *pRecordStruct )
+{
+  if( !memcmp( &(pRecordStruct->Type), VCARD_TYPE_STRING, pRecordStruct->TypeLength ) )
+    pRecordStruct->NDEF_Type = VCARD_TYPE;
+  else if( !memcmp( &(pRecordStruct->Type), XVCARD_TYPE_STRING, pRecordStruct->TypeLength ) )
+    pRecordStruct->NDEF_Type = VCARD_TYPE;
+  else if( !memcmp( &(pRecordStruct->Type), XVCARD2_TYPE_STRING, pRecordStruct->TypeLength ) )
+    pRecordStruct->NDEF_Type = VCARD_TYPE;
+  else if (!memcmp(&pRecordStruct->Type, NDEF_BLUETOOTH_BREDR_MIME_TYPE,  pRecordStruct->TypeLength))
+    pRecordStruct->NDEF_Type = BT_TYPE;
+  else if (!memcmp(&pRecordStruct->Type, NDEF_BLUETOOTH_BLE_MIME_TYPE,  pRecordStruct->TypeLength))
+    pRecordStruct->NDEF_Type = BLE_TYPE;
+  else if (!memcmp(&pRecordStruct->Type, WIFITOKEN_TYPE_STRING,  pRecordStruct->TypeLength))
+    pRecordStruct->NDEF_Type = URI_WIFITOKEN_TYPE;
+  else
+    pRecordStruct->NDEF_Type = UNKNOWN_TYPE;
+}
+
+/**
+  * @brief  This function parse the Forum External type record.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  */
+static void NDEF_ParseForumExternalType( sRecordInfo_t *pRecordStruct )
+{
+  if( !memcmp( &(pRecordStruct->Type), M24SR_DISCOVERY_APP_STRING, pRecordStruct->TypeLength ) )
+    pRecordStruct->NDEF_Type = M24SR_DISCOVERY_APP_TYPE;
+  else
+    pRecordStruct->NDEF_Type = UNKNOWN_TYPE;
+}
+
+/**
+  * @brief  This function parse the URI type record.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  */
+static void NDEF_ParseURI( sRecordInfo_t *pRecordStruct )
+{
+  uint8_t* pPayload;
+
+  pPayload = (uint8_t*)( pRecordStruct->PayloadBufferAdd );
+  pPayload++; /* to skip URI identifier first URI payload byte */
+
+  if( !memcmp( pPayload, SMS_TYPE_STRING, strlen(SMS_TYPE_STRING) ) )
+  {
+    pRecordStruct->NDEF_Type = URI_SMS_TYPE;
+  }
+  else if( !memcmp( pPayload, GEO_TYPE_STRING, strlen(GEO_TYPE_STRING) ) )
+  {
+    pRecordStruct->NDEF_Type = URI_GEO_TYPE;
+  }
+  else
+    pRecordStruct->NDEF_Type = UNKNOWN_TYPE;
+}
+
+/**
+  * @brief  This function parse the Smart Poster.
+  * @param  pRecordStruct : pointer on the record structure to fill.
+  */
+static void NDEF_ParseSP( sRecordInfo_t *pRecordStruct )
+{
+  uint8_t* pPayload;
+  uint32_t PayloadSize = 0;
+  uint32_t SPPayloadSize = 0;
+  uint32_t OffsetInSPPayload = 0;
+  uint32_t RecordPosition = 0;
+  sRecordInfo_t *pSPRecordStruct;
+
+  /* initialize variable with size of the payload and poiter on data */
+  PayloadSize = pRecordStruct->PayloadLength;
+
+  pPayload = (uint8_t*)( pRecordStruct->PayloadBufferAdd );
+
+  pSPRecordStruct = SPRecordStructAdd[0];
+
+  /* Initailize the number of record find in the SP payload */
+  pRecordStruct->NbOfRecordInSPPayload = 0;
+
+  do
+  {
+    pSPRecordStruct = SPRecordStructAdd[RecordPosition];
+    /* identify the record in the SP payload */
+    if( NDEF_IdentifySPRecord( pSPRecordStruct, pPayload ) == NDEF_OK )
+    {
+      /* store add of structure that will contain the other record information */
+      pRecordStruct->NbOfRecordInSPPayload++;
+      pRecordStruct->SPRecordStructAdd[RecordPosition] = pSPRecordStruct;
+
+      /* After SPRecord + First Record check if we are at the end of NDEF file */
+      SPPayloadSize = pSPRecordStruct->PayloadLength;
+
+      OffsetInSPPayload += pSPRecordStruct->PayloadOffset + SPPayloadSize;
+      pPayload += OffsetInSPPayload;
+    }
+    else /* Recommended Action Record for example */
+    {
+      SPPayloadSize = 0;
+    }
+    RecordPosition++;
+  }
+  while( (OffsetInSPPayload < PayloadSize) && RecordPosition<SP_MAX_RECORD); /* there is another record */
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup libNDEF_Public_Functions
+  * @{
+  */
+
+
+/**
+  * @brief  This function identify the NDEF message stored in tag.
+  * @param  pRecordStruct : Structure to fill with record information.
+  * @param  pNDEF : pointer on the NDEF message data.
+  * @retval NDEF_OK : record struct filled.
+  * @retval NDEF_ERROR : record struct not updated.
+  */
+uint16_t NDEF_IdentifyNDEF( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF, I2C* mi2cChannel )
+{
+  uint16_t SizeOfRecordHeader, TypeNbByte, PayloadLengthField, IDLengthField, IDNbByte;
+
+  /* check NDEF present */
+  if( NDEF_IsNDEFPresent(mi2cChannel) != NDEF_OK )
+  {
+    return NDEF_ERROR;
+  }
+
+  /* Read the NDEF file */
+  NfcTag_ReadNDEF( pNDEF, mi2cChannel );
+
+  /* Is ID length field present */
+  if( (*pNDEF) & IL_Mask )
+  {
+    IDLengthField = ID_LENGTH_FIELD;
+  }
+  else
+  {
+    IDLengthField = 0;
+  }
+
+  /* it's a SR */
+  if( (*pNDEF) & SR_Mask )
+  {
+    /* Analyse short record layout */
+    TypeNbByte = pNDEF[1];
+    PayloadLengthField = 1;
+    if( IDLengthField == ID_LENGTH_FIELD )
+      IDNbByte = pNDEF[3];
+    else
+      IDNbByte = 0;
+  }
+  else
+  {
+    /* Analyse normal record layout */
+    TypeNbByte = pNDEF[1];
+    PayloadLengthField = 4;
+    if( IDLengthField == ID_LENGTH_FIELD )
+      IDNbByte = pNDEF[6];
+    else
+      IDNbByte = 0;
+  }
+
+  SizeOfRecordHeader = RECORD_FLAG_FIELD + TYPE_LENGTH_FIELD + PayloadLengthField + IDLengthField + TypeNbByte + IDNbByte;
+
+  /* Read record header */
+  /* it's a SR */
+  if( pNDEF[0] & SR_Mask )
+  {
+    pRecordStruct->RecordFlags = pNDEF[0];
+    pRecordStruct->TypeLength = TypeNbByte;
+    pRecordStruct->PayloadLength = pNDEF[2];
+    pRecordStruct->IDLength = IDNbByte;
+    memcpy( pRecordStruct->Type, &pNDEF[3+IDNbByte], TypeNbByte );
+    memcpy( pRecordStruct->ID, &pNDEF[3+IDNbByte+TypeNbByte], IDNbByte );
+    pRecordStruct->PayloadOffset = SizeOfRecordHeader;
+  }
+  else
+  {
+    pRecordStruct->RecordFlags = pNDEF[0];
+    pRecordStruct->TypeLength = TypeNbByte;
+    pRecordStruct->PayloadLength = ( ((uint32_t)pNDEF[2]) << 24 ) |
+                                   ( ((uint32_t)pNDEF[3]) << 16 ) |
+                                   ( ((uint32_t)pNDEF[4]) << 8 )
+                                    | pNDEF[5] ;
+    pRecordStruct->IDLength = IDNbByte;
+    memcpy( pRecordStruct->Type, &pNDEF[6+IDNbByte], TypeNbByte );
+    memcpy( pRecordStruct->ID, &pNDEF[6+IDNbByte+TypeNbByte], IDNbByte );
+    pRecordStruct->PayloadOffset = SizeOfRecordHeader;
+  }
+
+  pRecordStruct->PayloadBufferAdd = pNDEF;
+
+  NDEF_ParseRecordHeader( pRecordStruct );
+
+  return NDEF_OK;
+}
+
+/**
+  * @brief  This function read the NDEF content of the TAG.
+  * @param  pNDEF : pointer on the buffer to store NDEF data.
+  * @retval NDEF_OK : NDEF file data retrieve and store in the buffer.
+  * @retval NDEF_ERROR : not able to read NDEF from tag.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot read tag.
+  * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present.
+  * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory.
+  * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be read.
+  */
+uint16_t NDEF_ReadNDEF( uint8_t* pNDEF, I2C* mi2cChannel )
+{
+   return NfcTag_ReadNDEF( pNDEF, mi2cChannel );
+}
+
+
+
+/**
+  * @brief  This function read the NDEF size of the TAG.
+  * @param  Size : pointer to a 16-bit Size (in bytes) to be returned.
+  * @retval NDEF_OK : NDEF file data retrieve and store in the buffer.
+  * @retval NDEF_ERROR : not able to read NDEF from tag.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot read tag.
+  * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present.
+  * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory.
+  * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be read.
+  */
+uint16_t NDEF_getNDEFSize(uint16_t* Size, I2C* mi2cChannel)
+{
+  return NfcTag_GetLength(Size, mi2cChannel);
+}
+/**
+  * @brief  This function write the NDEF in the TAG.
+  * @param  pNDEF : pointer on the buffer containing the NDEF data.
+  * @retval NDEF_OK : NDEF file data written in the tag.
+  * @retval NDEF_ERROR : not able to store NDEF in tag.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag.
+  * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present.
+  * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory.
+  * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write.
+  */
+uint16_t NDEF_WriteNDEF( uint16_t NDEF_Size, uint8_t *pNDEF, I2C* mi2cChannel )
+{
+  return NfcTag_WriteNDEF( NDEF_Size, pNDEF, mi2cChannel );
+
+}
+
+/**
+  * @brief  This function append the record to an the NDEF in the TAG.
+  * @param  pRecord : pointer on the record with data to be written.
+  * @retval NDEF_OK : NDEF file data written in the tag.
+  * @retval NDEF_ERROR : not able to store NDEF in tag.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL : Cannot write to tag.
+  * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported or not present.
+  * @retval NDEF_ERROR_MEMORY_TAG : Size not compatible with memory.
+  * @retval NDEF_ERROR_LOCKED : Tag locked, cannot be write.
+  */
+uint16_t NDEF_AppendRecord(sRecordInfo_t  *Record, I2C* mi2cChannel )
+{
+  uint16_t status;
+  uint16_t NDEF_Size = 0;
+  uint8_t* pData = NDEF_Buffer;
+
+  status = NDEF_getNDEFSize(&NDEF_Size, mi2cChannel);
+  if(status != NDEF_OK)  return status ;
+
+  if(NDEF_Size != 0)
+  {
+    // There are already records in the NDEF
+    Record->RecordFlags &= ~MB_Mask;
+
+    status = NfcTag_ReadNDEF(pData, mi2cChannel);
+    if(status != NDEF_OK)  return status ;
+  
+    uint8_t* pNdefRecord;
+    sRecordInfo_t   LastRecord;
+    do {
+      pNdefRecord = pData;
+      NDEF_IdentifyBuffer(&LastRecord,pData);
+      pData  += LastRecord.PayloadOffset + LastRecord.PayloadLength;
+   // TO DO: add a security condition to avoid infinite loop if NDEF file is corrupted
+    } while(!(LastRecord.RecordFlags & ME_Mask));
+    LastRecord.RecordFlags &= ~ME_Mask;
+    *pNdefRecord = LastRecord.RecordFlags;
+  } else {
+    // This will be the first message in memory
+    Record->RecordFlags |= MB_Mask;
+  }
+  Record->RecordFlags |= ME_Mask;
+  uint32_t RecordLength = NDEF_WriteRecord(Record,pData, mi2cChannel);
+  
+
+  return NfcTag_WriteNDEF( NDEF_Size + RecordLength, NDEF_Buffer, mi2cChannel );
+
+}
+
+
+
+/**
+  * @brief  This function identify the NDEF message stored in tag.
+  * @param  pRecordStruct : Structure to fill with record information.
+  * @param  pNDEF : pointer on the NDEF message data.
+  * @retval NDEF_OK : record struct filled.
+  * @retval NDEF_ERROR : record struct not updated.
+  */
+uint16_t NDEF_IdentifyBuffer( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF )
+{
+  uint16_t SizeOfRecordHeader, TypeNbByte, PayloadLengthField, IDLengthField, IDNbByte;
+
+  /* Is ID length field present */
+  if( (*pNDEF) & IL_Mask )
+  {
+    IDLengthField = ID_LENGTH_FIELD;
+  }
+  else
+  {
+    IDLengthField = 0;
+  }
+
+  /* it's a SR */
+  if( (*pNDEF) & SR_Mask )
+  {
+    /* Analyse short record layout */
+    TypeNbByte = pNDEF[1];
+    PayloadLengthField = 1;
+    if( IDLengthField == ID_LENGTH_FIELD )
+      IDNbByte = pNDEF[3];
+    else
+      IDNbByte = 0;
+  }
+  else
+  {
+    /* Analyse normal record layout */
+    TypeNbByte = pNDEF[1];
+    PayloadLengthField = 4;
+    if( IDLengthField == ID_LENGTH_FIELD )
+      IDNbByte = pNDEF[6];
+    else
+      IDNbByte = 0;
+  }
+
+  SizeOfRecordHeader = RECORD_FLAG_FIELD + TYPE_LENGTH_FIELD + PayloadLengthField + IDLengthField + TypeNbByte + IDNbByte;
+
+  /* it's a SR */
+  if( pNDEF[0] & SR_Mask )
+  {
+    pRecordStruct->RecordFlags = pNDEF[0];
+    pRecordStruct->TypeLength = TypeNbByte;
+    pRecordStruct->PayloadLength = pNDEF[2];
+    pRecordStruct->IDLength = IDNbByte;
+    memcpy( pRecordStruct->Type, &pNDEF[3+IDLengthField], TypeNbByte );
+    memcpy( pRecordStruct->ID, &pNDEF[3+IDLengthField+TypeNbByte], IDNbByte );
+    pRecordStruct->PayloadOffset = SizeOfRecordHeader;
+  }
+  else
+  {
+    pRecordStruct->RecordFlags = pNDEF[0];
+    pRecordStruct->TypeLength = TypeNbByte;
+    pRecordStruct->PayloadLength = ( ((uint32_t)pNDEF[2]) << 24 ) |
+                                   ( ((uint32_t)pNDEF[3]) << 16 ) |
+                                   ( ((uint32_t)pNDEF[4]) << 8 )
+                                    | pNDEF[5] ;
+    pRecordStruct->IDLength = IDNbByte;
+    memcpy( pRecordStruct->Type, &pNDEF[6+IDNbByte], TypeNbByte );
+    memcpy( pRecordStruct->ID, &pNDEF[6+IDNbByte+TypeNbByte], IDNbByte );
+    pRecordStruct->PayloadOffset = SizeOfRecordHeader;
+  }
+
+  pRecordStruct->PayloadBufferAdd = &pNDEF[pRecordStruct->PayloadOffset];
+
+  NDEF_ParseRecordHeader( pRecordStruct );
+
+  return NDEF_OK;
+}
+
+/**
+  * @brief  This function writes a record into a NDEF buffer. (update SR flag if required)
+  * @param  pRecord : Structure with record information to be written.
+  * @param  pNDEF : pointer on the NDEF buffer.
+  * @retval Length : Length of the written data (in bytes)
+  */
+uint32_t NDEF_WriteRecord( sRecordInfo_t *pRecord, uint8_t* pNDEF, I2C* mi2cChannel )
+{
+  /************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*           ID LENGTH              */  
+/*----------------------------------*/
+/*             TYPE                 */  
+/*----------------------------------*/
+/*              ID                  */  
+/*----------------------------------*/
+/*           PAYLOAD                */  
+/************************************/
+  uint8_t * start = pNDEF;
+
+  // start by considering payload length
+  if(pRecord->PayloadLength <= 0xFF)
+    pRecord->RecordFlags |= SR_Mask;
+  else
+    pRecord->RecordFlags &= ~SR_Mask;
+  
+  // Then start writing!
+  *pNDEF++ = pRecord->RecordFlags;
+
+  *pNDEF++ = pRecord->TypeLength;
+
+  if (!(pRecord->RecordFlags & SR_Mask))
+  {
+    *pNDEF++ = (pRecord->PayloadLength >> 24) & 0xFF;
+    *pNDEF++ = (pRecord->PayloadLength >> 16) & 0xFF ;
+    *pNDEF++ = (pRecord->PayloadLength >> 8) & 0xFF;
+  }
+  *pNDEF++ = (pRecord->PayloadLength) & 0xFF;
+
+  if(pRecord->RecordFlags & IL_Mask)
+    *pNDEF++ = (pRecord->IDLength);
+  
+  memcpy(pNDEF,pRecord->Type,pRecord->TypeLength);
+  pNDEF += pRecord->TypeLength;
+
+  if(pRecord->RecordFlags & IL_Mask)
+  {
+    memcpy(pNDEF,pRecord->ID,pRecord->IDLength);
+    pNDEF += pRecord->IDLength;
+  }
+
+  memcpy(pNDEF,pRecord->PayloadBufferAdd,pRecord->PayloadLength);
+  pNDEF += pRecord->PayloadLength;
+
+  return (pNDEF - start);
+}
+
+/**
+  * @brief  This function return the length a record data (update SR flag if required)
+  * @param  pRecord : Structure with record information
+  * @retval Length : Length of the data (in bytes)
+  */
+uint32_t NDEF_GetRecordLength( sRecordInfo_t *pRecord )
+{
+  // start by considering payload length
+  if(pRecord->PayloadLength <= 0xFF)
+    pRecord->RecordFlags |= SR_Mask;
+  else
+    pRecord->RecordFlags &= ~SR_Mask;
+  
+  // Then compute the length
+  uint32_t length = 1 +                                                         // Flags
+                    1 +                                                         // Type length
+                    ((pRecord->RecordFlags & SR_Mask)? 1 : 4) +                 // Payload length
+                    ((pRecord->RecordFlags & IL_Mask)? 1 : 0) +                 // ID length
+                    pRecord->TypeLength +                                       // Type
+                    ((pRecord->RecordFlags & IL_Mask)? pRecord->IDLength : 0) + // ID 
+                    pRecord->PayloadLength;                                     // Payload;
+  
+  return length;
+}
+
+/**
+  * @brief  This function clears the NDEF file
+  * @retval NDEF Status
+  */
+uint16_t NDEF_ClearNDEF(I2C* mi2cChannel)
+{
+  return NDEF_WriteNDEF(0 , NULL, mi2cChannel);
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/