libNDEF library for the STMicroelectronics X-NUCLEO-NFC04A1

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

Files at this revision

API Documentation at this revision

Comitter:
DiegoOstuni
Date:
Thu Nov 14 10:34:11 2019 +0000
Commit message:
Add files

Changed in this revision

.gitignore Show annotated file Show diff for this revision Revisions of this file
LICENSE Show annotated file Show diff for this revision Revisions of this file
NDEFcommon.h Show annotated file Show diff for this revision Revisions of this file
README.md Show annotated file Show diff for this revision Revisions of this file
lib_NDEF.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_AAR.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_AAR.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Bluetooth.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Bluetooth.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Email.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Email.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Geo.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Geo.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Handover.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Handover.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_MyApp.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_MyApp.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_SMS.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_SMS.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Text.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Text.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_URI.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_URI.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Vcard.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Vcard.h Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Wifi.cpp Show annotated file Show diff for this revision Revisions of this file
lib_NDEF_Wifi.h Show annotated file Show diff for this revision Revisions of this file
lib_wrapper.h Show annotated file Show diff for this revision Revisions of this file
tagtype5_wrapper.cpp Show annotated file Show diff for this revision Revisions of this file
tagtype5_wrapper.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r de13951f30f6 .gitignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gitignore	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,32 @@
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
diff -r 000000000000 -r de13951f30f6 LICENSE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+
+   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.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff -r 000000000000 -r de13951f30f6 NDEFcommon.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NDEFcommon.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,85 @@
+/**
+  ******************************************************************************
+  * @file    common.h 
+  * @author  MMY Application Team
+  * @version $Revision: 3343 $
+  * @date    $Date: 2017-01-24 16:07:22 +0100 (Tue, 24 Jan 2017) $
+  * @brief   Header for main.c module
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2017 STMicroelectronics</center></h2>
+  *
+  * Licensed under MMY-ST Liberty SW License Agreement V2, (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/software_license_agreement_liberty_v2
+  *
+  * 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.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __COMMON_H
+#define __COMMON_H
+
+/* Includes ------------------------------------------------------------------*/
+//#include "x_nucleo_nfc04a1_nfctag.h"
+#include <string.h>
+#include "stdint.h"
+
+/* Exported types ------------------------------------------------------------*/
+//typedef uint8_t boolean;
+
+/**
+ * @brief  GPO status information structure definition
+ */
+typedef struct
+{
+  uint8_t WritenEEPROM;
+  uint8_t RfBusy;
+  uint8_t FieldOn;
+  uint8_t FieldOff;
+  uint8_t MsgInMailbox;
+  uint8_t MailboxMsgRead;
+  uint8_t RfInterrupt;
+  uint8_t Rfuser;
+} IT_GPO_STATUS;
+
+/* Exported macro ------------------------------------------------------------*/
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+/*
+#undef FAIL
+#define FAIL 0
+
+#undef PASS
+#define PASS !FAIL
+*/
+
+#define NFCTAG_4K_SIZE            ((uint32_t) 0x200)
+#define NFCTAG_16K_SIZE           ((uint32_t) 0x800)
+#define NFCTAG_64K_SIZE           ((uint32_t) 0x2000)
+
+/* Exported constants --------------------------------------------------------*/
+#define MAX_NDEF_MEM                 0x200
+#define ST25DV_MAX_SIZE              NFCTAG_4K_SIZE
+#define ST25DV_NDEF_MAX_SIZE         MIN(ST25DV_MAX_SIZE,MAX_NDEF_MEM)
+#define NFC_DEVICE_MAX_NDEFMEMORY    ST25DV_NDEF_MAX_SIZE
+
+#define RESULTOK                     0x00
+#define ERRORCODE_GENERIC            1
+
+/* Exported functions ------------------------------------------------------- */
+
+#endif /* __COMMON_H */
+
+/************************ (C) COPYRIGHT 2017 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,4 @@
+# libNDEF
+libNDEF is a library used for STMicroelectronics X-NUCLEO-NFC04A1 expansion board.
+# Overview
+It is the library used to manage the content of the TAG (data). But also the specific feature of the tag, for instance: password, gpo, and so on.
diff -r 000000000000 -r de13951f30f6 lib_NDEF.cpp
--- /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****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,268 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF.h
+  * @author  MMY Application Team
+  * @version $Revision: 2762 $
+  * @date    $Date: 2016-08-10 16:40:40 +0200 (Wed, 10 Aug 2016) $
+  * @brief   This file help to manage NDEF file.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_H
+#define __LIB_NDEF_H
+
+/* Includes ------------------------------------------------------------------*/
+/* include file which match the HW configuration */
+#include "lib_wrapper.h"
+#include <string.h>
+
+
+   
+#define NDEF_ACTION_COMPLETED       0x9000
+
+#ifndef errorchk
+#define errorchk(fCall) if (status = (fCall), status != NDEF_ACTION_COMPLETED) \
+  {goto Error;} else
+#endif
+
+/* Error codes for Higher level */
+#define NDEF_OK                     RESULTOK
+#define NDEF_ERROR                  ERRORCODE_GENERIC
+#define NDEF_ERROR_MEMORY_TAG       2
+#define NDEF_ERROR_MEMORY_INTERNAL  3
+#define NDEF_ERROR_LOCKED           4
+#define NDEF_ERROR_NOT_FORMATED     5
+
+//#define NDEF_MAX_SIZE               NFC_DEVICE_MAX_NDEFMEMORY
+//#define NDEF_RECORD_MAX_SIZE        (512)
+#define NDEF_MAX_SIZE               (100)
+#define NDEF_RECORD_MAX_SIZE        (100)
+ 
+#define NDEF_SIZE_OFFSET            0
+#define FIRST_RECORD_OFFSET         0
+
+#define RECORD_FLAG_FIELD           1
+#define TYPE_LENGTH_FIELD           1
+#define ID_LENGTH_FIELD             1
+
+
+#define	MB_Mask                     ((uint8_t)(0x80))
+#define ME_Mask                     ((uint8_t)(0x40))
+#define CF_Mask                     ((uint8_t)(0x20))
+#define SR_Mask                     ((uint8_t)(0x10))
+#define IL_Mask                     ((uint8_t)(0x08))
+#define TNF_Mask                    ((uint8_t)(0x07))
+
+#define TNF_Empty                   0x00
+#define TNF_WellKnown               0x01
+#define TNF_MediaType               0x02
+#define TNF_AbsoluteURI             0x03
+#define TNF_NFCForumExternal        0x04
+#define TNF_Unknown                 0x05
+#define TNF_Unchanged               0x06
+#define TNF_Reserved                0x07
+
+#define SP_MAX_RECORD               4
+
+#define AAR_TYPE_STRING                         "android.com:pkg"
+#define AAR_TYPE_STRING_LENGTH                  15
+
+#define M24SR_DISCOVERY_APP_STRING              "st.com:m24sr_discovery_democtrl"
+#define M24SR_DISCOVERY_APP_STRING_LENGTH       31
+
+#define VCARD_TYPE_STRING                       "text/vcard"
+#define VCARD_TYPE_STRING_LENGTH                10
+
+#define XVCARD_TYPE_STRING                      "text/x-vCard"
+#define XVCARD_TYPE_STRING_LENGTH               12
+
+#define XVCARD2_TYPE_STRING                     "text/x-vcard"
+#define XVCARD2_TYPE_STRING_LENGTH              12
+
+#define SMART_POSTER_TYPE_STRING                "Sp"
+#define SMART_POSTER_TYPE_STRING_LENGTH         2
+	 
+#define URI_TYPE_STRING                         "U"
+#define URI_TYPE_STRING_LENGTH                  1
+	 
+#define SMS_TYPE_STRING                         "sms:"
+#define SMS_TYPE_STRING_LENGTH                  4
+
+#define GEO_TYPE_STRING                         "geo:"
+#define GEO_TYPE_STRING_LENGTH                  4
+
+#define URI_LATITUDE_END                        ","
+#define URI_LATITUDE_END_LENGTH                 1
+
+#define EMAIL_TYPE_STRING                       "mailto:"
+#define EMAIL_TYPE_STRING_LENGTH                7
+
+#define URI_FIRST_DATA_END                      "?"
+#define URI_FIRST_DATA_END_LENGTH               1
+
+#define SUBJECT_BEGIN_STRING                    "subject="
+#define SUBJECT_BEGIN_STRING_LENGTH             8
+
+#define MESSAGE_BEGIN_STRING                    "body="
+#define MESSAGE_BEGIN_STRING_LENGTH             5
+
+#define URI_SECOND_DATA_END                     "&"
+#define URI_SECOND_DATA_END_LENGTH              1
+
+#define TEXT_TYPE_STRING                        "T"
+#define TEXT_TYPE_STRING_LENGTH                 1
+
+#define ISO_ENGLISH_CODE_STRING                 "en"
+#define ISO_ENGLISH_CODE_STRING_LENGTH          2
+
+
+#define URI_ID_0x00                 0x00
+#define URI_ID_0x01                 0x01
+#define URI_ID_0x02                 0x02
+#define URI_ID_0x03                 0x03
+#define URI_ID_0x04                 0x04
+#define URI_ID_0x05                 0x05
+#define URI_ID_0x06                 0x06
+#define URI_ID_0x07                 0x07
+#define URI_ID_0x08                 0x08
+#define URI_ID_0x09                 0x09
+#define URI_ID_0x0A                 0x0A
+#define URI_ID_0x0B                 0x0B
+#define URI_ID_0x0C                 0x0C
+#define URI_ID_0x0D                 0x0D
+#define URI_ID_0x0E                 0x0E
+#define URI_ID_0x0F                 0x0F
+#define URI_ID_0x10                 0x10
+#define URI_ID_0x11                 0x11
+#define URI_ID_0x12                 0x12
+#define URI_ID_0x13                 0x13
+#define URI_ID_0x14                 0x14
+#define URI_ID_0x15                 0x15
+#define URI_ID_0x16                 0x16
+#define URI_ID_0x17                 0x17
+#define URI_ID_0x18                 0x18
+#define URI_ID_0x19                 0x19
+#define URI_ID_0x1A                 0x1A
+#define URI_ID_0x1B                 0x1B
+#define URI_ID_0x1C                 0x1C
+#define URI_ID_0x1D                 0x1D
+#define URI_ID_0x1E                 0x1E
+#define URI_ID_0x1F                 0x1F
+#define URI_ID_0x20                 0x20
+#define URI_ID_0x21                 0x21
+#define URI_ID_0x22                 0x22
+#define URI_ID_0x23                 0x23
+#define URI_RFU                     0x24
+
+#define URI_ID_0x01_STRING          "http://www.\0"
+#define URI_ID_0x02_STRING          "https://www.\0"
+#define URI_ID_0x03_STRING          "http://\0"
+#define URI_ID_0x04_STRING          "https://\0"
+#define URI_ID_0x05_STRING          "tel:\0"
+#define URI_ID_0x06_STRING          "mailto:\0"
+#define URI_ID_0x07_STRING          "ftp://anonymous:anonymous@\0"
+#define URI_ID_0x08_STRING          "ftp://ftp.\0"
+#define URI_ID_0x09_STRING          "ftps://\0"
+#define URI_ID_0x0A_STRING          "sftp://\0"
+#define URI_ID_0x0B_STRING          "smb://\0"
+#define URI_ID_0x0C_STRING          "nfs://\0"
+#define URI_ID_0x0D_STRING          "ftp://\0"
+#define URI_ID_0x0E_STRING          "dav://\0"
+#define URI_ID_0x0F_STRING          "news:\0"
+#define URI_ID_0x10_STRING          "telnet://\0"
+#define URI_ID_0x11_STRING          "imap:\0"
+#define URI_ID_0x12_STRING          "rtsp://\0"
+#define URI_ID_0x13_STRING          "urn:\0"
+#define URI_ID_0x14_STRING          "pop:\0"
+#define URI_ID_0x15_STRING          "sip:\0"
+#define URI_ID_0x16_STRING          "sips:\0"
+#define URI_ID_0x17_STRING          "tftp:\0"
+#define URI_ID_0x18_STRING          "btspp://\0"
+#define URI_ID_0x19_STRING          "btl2cap://\0"
+#define URI_ID_0x1A_STRING          "btgoep://\0"
+#define URI_ID_0x1B_STRING          "tcpobex://\0"
+#define URI_ID_0x1C_STRING          "irdaobex://\0"
+#define URI_ID_0x1D_STRING          "file://\0"
+#define URI_ID_0x1E_STRING          "urn:epc:id:\0"
+#define URI_ID_0x1F_STRING          "urn:epc:tag\0"
+#define URI_ID_0x20_STRING          "urn:epc:pat:\0"
+#define URI_ID_0x21_STRING          "urn:epc:raw:\0"
+#define URI_ID_0x22_STRING          "urn:epc:\0"
+#define URI_ID_0x23_STRING          "urn:nfc:\0"
+
+// exported variables
+extern uint8_t NDEF_Buffer[NDEF_MAX_SIZE];
+extern uint32_t NDEF_Buffer_size;
+extern uint8_t NDEF_Record_Buffer [NDEF_RECORD_MAX_SIZE];
+extern uint32_t NDEF_Record_Buffer_size;
+
+typedef enum
+{
+  UNKNOWN_TYPE = 0,
+  VCARD_TYPE,
+  WELL_KNOWN_ABRIDGED_URI_TYPE,
+  URI_SMS_TYPE,
+  URI_GEO_TYPE,
+  URI_EMAIL_TYPE,
+  SMARTPOSTER_TYPE,
+  URL_TYPE,
+  TEXT_TYPE,
+  HANDOVER_TYPE,
+  /* list of "external type" known by this demo, other external type will be addressed as UNKNWON_TYPE */
+  M24SR_DISCOVERY_APP_TYPE,
+  BT_TYPE,
+  BLE_TYPE,
+  URI_WIFITOKEN_TYPE
+} NDEF_TypeDef;
+
+typedef struct sRecordInfo sRecordInfo_t;
+
+struct sRecordInfo
+{
+  uint8_t RecordFlags;
+  uint8_t TypeLength;
+  uint32_t PayloadLength;
+  uint8_t IDLength;
+  uint8_t Type[20];
+  uint8_t ID[20];
+  uint16_t PayloadOffset;
+  uint8_t* PayloadBufferAdd;    /* add where payload content has been stored */
+  NDEF_TypeDef NDEF_Type;  /* to store identification ID for application */
+  sRecordInfo_t *SPRecordStructAdd[SP_MAX_RECORD]; /*in case of smart poster array to store add of other sRecordInfo struct */
+  uint8_t NbOfRecordInSPPayload;
+};
+
+uint16_t NDEF_IdentifyNDEF( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF, I2C* mi2cChannel );
+uint16_t NDEF_IdentifyBuffer( sRecordInfo_t *pRecordStruct, uint8_t* pNDEF );
+uint16_t NDEF_ReadNDEF( uint8_t *pNDEF, I2C* mi2cChannel );
+uint16_t NDEF_WriteNDEF( uint16_t NDEF_Size, uint8_t *pNDEF, I2C* mi2cChannel );
+uint16_t NDEF_ClearNDEF(I2C* mi2cChannel);
+uint16_t NDEF_getNDEFSize(uint16_t* Size, I2C* mi2cChannel);
+uint32_t NDEF_WriteRecord( sRecordInfo_t *pRecord, uint8_t* pNDEF, I2C* mi2cChannel );
+uint16_t NDEF_AppendRecord(sRecordInfo_t  *Record, I2C* mi2cChannel );
+uint32_t NDEF_GetRecordLength( sRecordInfo_t *pRecord );
+
+#endif /* __LIB_NDEF_H */
+
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_AAR.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_AAR.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,133 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_AAR.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 add AAR to NDEF file.
+  ******************************************************************************
+  * @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_AAR.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.
+  */
+
+/**
+ * @brief  This buffer contains the data send/received by TAG
+ */
+extern uint8_t NDEF_Buffer [];
+
+/** @defgroup libAAR_Private_Functions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @defgroup libAAR_Public_Functions
+  * @{
+  * @brief  This file is used to manage AAR (stored or loaded in tag)
+  */ 
+
+
+/**
+  * @brief  This function add AAR (Android Application Record) in the tag.
+  * @param  pAARStruct : pointer on structure that contain AAR information.
+  * @retval NDEF_OK : AAR added.
+  * @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_AddAAR( const sAARInfo *pAARStruct, I2C* mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR;
+
+/* AAR: External Type Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- IL=0, CF=0 and SR=1 TNF=4 NFC Forum external type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  /* <---- Not Used  */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  /* <---- Not Used  */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  /* <---- Not Used  */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*           ID LENGTH              */  /* <---- Not Used  */
+/*----------------------------------*/
+/*             TYPE                 */  /* android.com:pkg */
+/*----------------------------------*/
+/*              ID                  */  /* <---- Not Used  */
+/************************************/
+
+  /* Do we have to add AAR to an existing NDEF message */
+  /* retrieve current NDEF size and current record flag*/
+  sRecordInfo_t AARrecord;
+
+  /* fill AAR record header */
+  AARrecord.RecordFlags = SR_Mask | TNF_NFCForumExternal;
+  AARrecord.TypeLength = AAR_TYPE_STRING_LENGTH;
+
+  memcpy( AARrecord.Type, AAR_TYPE_STRING, AAR_TYPE_STRING_LENGTH );
+
+  /* fill AAR payload */
+  AARrecord.PayloadBufferAdd = (uint8_t*)pAARStruct->PackageName;
+  AARrecord.PayloadLength= strlen(pAARStruct->PackageName) ;
+
+  status = NDEF_AppendRecord(&AARrecord, mi2cChannel);
+
+   return status;
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_AAR.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_AAR.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,49 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_AAR.h
+  * @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 AAR.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_AAR_H
+#define __LIB_NDEF_AAR_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+typedef struct
+{
+  char PackageName[80];
+}sAARInfo;
+	 	 
+uint16_t NDEF_AddAAR( const sAARInfo *pAARStruct, I2C* mi2cChannel );
+
+
+
+#endif /* __LIB_NDEF_AAR_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Bluetooth.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Bluetooth.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,554 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Bluetooth.c
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @ingroup LibNDEF_Bluetooth
+  * @brief   This file help to manage a NDEF file representing a Bluetooth pairing info.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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_Bluetooth.h"
+
+
+
+/** @addtogroup lib_NDEF_Bluetooth Bluetooth OOB library
+  * @ingroup libNDEF
+  * @{
+  * @brief    This module is used to manage a Bluetooth Out-Of-Band NDEF message, to start a communication based on Bluetooth.
+  * @details  The Bluetooth OOB format is described by the Bluetooth v4.0 core specification.
+  *           It consists in a list of Extended Inquiry Responses formated as length-type-value.
+  *           This module allows to build, write & read such data embedded in a NDEF message.
+  * @section      Bluetooth_Library_Usage Bluetooth NDEF Library usage
+  * @subsection   Bluetooth_Write_BrEdr How to write a Bluetooth Br/Edr OOB
+  *               1. Instanciate & initialize a `Ndef_Bluetooth_OOB_t` structure, specifying:
+  *                 - the `NDEF_BLUETOOTH_BREDR` type.
+  *                 - the mandatory Device Address field.
+  *                 - any other optional EIRs.
+  *
+  *                       Ndef_Bluetooth_OOB_t w_bredr_oob = {  .Type = NDEF_BLUETOOTH_BREDR,
+  *                                                             .DeviceAddress = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+  *                                                             .OptionalMask = NDEF_BLUETOOTH_OPTION(BLUETOOTH_EIR_COMPLETE_LOCAL_NAME) |
+  *                                                                             NDEF_BLUETOOTH_OPTION(BLUETOOTH_EIR_DEVICE_CLASS) |
+  *                                                                             NDEF_BLUETOOTH_OPTION(BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_16),
+  *                                                             .LocalName = "MyDevice",
+  *                                                             .nbUUID16 = 2,
+  *                                                             .ClassUUID16 = {0x111E,0x110B},
+  *                                                             .DeviceClass = {0x04,0x04,0x20}
+  *                                                           };
+  *               2. Clear the NDEF message and call the `NDEF_AppendBluetoothOOB` function to write the OOB:
+  * 
+  *                      NDEF_ClearNDEF();
+  *                      NDEF_AppendBluetoothOOB ( &w_bredr_oob, NULL );
+  *                 @note Second parameter of `NDEF_AppendBluetoothOOB` can be used to specify an ID for the OOB record (useful for the NDEF Handover message, where specifying an ID is mandatory)
+  * @subsection   Bluetooth_Write_Ble How to write a Bluetooth LE OOB
+  *               1. Instanciate & initialize a `Ndef_Bluetooth_OOB_t` structure, specifying:
+  *                 - the `NDEF_BLUETOOTH_BLE` type.
+  *                 - the mandatory Device Address & LE Role fields.
+  *                 - any other optional EIRs.
+  *
+  *                        Ndef_Bluetooth_OOB_t w_ble_oob = { .Type = NDEF_BLUETOOTH_BLE,
+  *                                                           .DeviceAddress = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+  *                                                           .DeviceAddressType = NDEF_BLE_PUBLIC_ADDRESS_TYPE,
+  *                                                           .Role = NDEF_BLE_ROLE_PERIPH_ONLY,
+  *                                                           .OptionalMask = NDEF_BLUETOOTH_OPTION(BLUETOOTH_EIR_COMPLETE_LOCAL_NAME),
+  *                                                           .LocalName = "MyDeviceName",                                
+  *                                                         };
+  *
+  *               2. Clear the NDEF message and call the `NDEF_AppendBluetoothOOB` function to write the OOB:
+  * 
+  *                      NDEF_ClearNDEF();
+  *                      NDEF_AppendBluetoothOOB ( &w_ble_oob, NULL );
+  *                 @note Second parameter of `NDEF_AppendBluetoothOOB` can be used to specify an ID for the OOB record (useful for the NDEF Handover message, where specifying an ID is mandatory)
+  *
+  * @subsection   Bluetooth_Read How to read a Bluetooth OOB
+  *               1. Read the 1st record of the NDEF message:
+  *
+  *                      sRecordInfo_t record;
+  *                      NDEF_ReadNDEF(NDEF_Buffer);
+  *                      NDEF_IdentifyBuffer(record,NDEF_Buffer);
+  *               2. Decode the Bluetooth OOB:
+  *
+  *                       Ndef_Bluetooth_OOB_t bluetooth_oob;
+  *                       NDEF_ReadBluetoothOOB(&record,&bluetooth_oob);
+  *               3. Use the data from the `Ndef_Bluetooth_OOB_t` structure to start a Bluetooth connexion.
+  *                       
+  *                                              
+  *
+  */
+
+
+/**
+  * @brief  This function copies an array, changing its endianness, usefull to convert data to BLE endianess.
+  * @param  dst Pointer on 1st element of the destination array.
+  * @param  src pointer on 1st element of the source array .
+  * @param  length Number of element to copy.
+  * @return Pointer to the destination array.
+  */
+uint8_t* NDEF_BluetoothCopy(uint8_t* dst, uint8_t* src, uint32_t length)
+{
+  uint32_t index;
+  for(index = 0 ; index < length; index++)
+  {
+    dst[index] = src[length - index - 1];
+  }  
+  return dst;
+}
+
+/**
+  * @brief  This function reads a NDEF record and retrieves Bluetooth (BR/EDR or BLE) OOB information if present.
+  * @param  pRecord       Pointer on the record structure.
+  * @param  pBluetooth    Pointer on the structure to fill .
+  * @retval NDEF_OK       OOB information has been retrieved from the NDEF record.
+  * @retval NDEF_ERROR    OOB information cannot be retrieved.
+  */
+uint16_t NDEF_ReadBluetoothOOB( sRecordInfo_t *pRecord, Ndef_Bluetooth_OOB_t *pBluetooth )
+{
+  uint8_t* pData = pRecord->PayloadBufferAdd;
+  uint8_t* OOBEnd = pRecord->PayloadBufferAdd + pRecord->PayloadLength;
+
+  pBluetooth->OptionalMask = 0;
+  pBluetooth->nbServiceData = 0;
+  pBluetooth->Role = NDEF_BLE_ROLE_UNDEF;
+  pBluetooth->DeviceAddressType = NDEF_BLE_UNDEF_ADDRESS_TYPE;
+  pBluetooth->nbUUID16 = 0;
+  pBluetooth->nbUUID32 = 0;
+  pBluetooth->nbUUID128 = 0;
+  pBluetooth->nbServiceSolicitation16 = 0;
+  pBluetooth->nbServiceSolicitation128 = 0;
+  
+  if((pRecord->TypeLength == strlen(NDEF_BLUETOOTH_BREDR_MIME_TYPE)) &&
+    !memcmp(pRecord->Type,NDEF_BLUETOOTH_BREDR_MIME_TYPE,strlen(NDEF_BLUETOOTH_BREDR_MIME_TYPE)))
+  {
+    pBluetooth->Type = NDEF_BLUETOOTH_BREDR;
+    /* Retrieve mandatory OOB data:                   */
+    /* 2 bytes for length and 6 bytes for device addr */
+    NDEF_BluetoothCopy((uint8_t*)pBluetooth->DeviceAddress,&pData[2],sizeof(pBluetooth->DeviceAddress));
+    pData += 8;
+  } else if ((pRecord->TypeLength == strlen(NDEF_BLUETOOTH_BLE_MIME_TYPE)) &&
+    !memcmp(pRecord->Type,NDEF_BLUETOOTH_BLE_MIME_TYPE,strlen(NDEF_BLUETOOTH_BLE_MIME_TYPE)))
+  {
+    pBluetooth->Type = NDEF_BLUETOOTH_BLE;
+    /* for BLE, mandatory fields are in EIR */
+  } else {
+    /* This is an unknown MIME type */
+    return NDEF_ERROR;
+  }
+
+  /* EIR format: 1 byte for length, 1 byte for type, n bytes for data */  
+  while (pData < OOBEnd)
+  {
+    NDEF_EIR_t* rEIR = (NDEF_EIR_t*)pData;
+    /* +1 for EIR length byte */
+    pData += rEIR->length + 1;
+
+    /* keep track of all EIR found */
+    if(rEIR->type < 0x20)
+      NDEF_BLUETOOTH_SET_OPTIONAL_MASK(pBluetooth,rEIR->type);
+
+    switch (rEIR->type)
+    {
+      case BLUETOOTH_EIR_FLAGS:
+        pBluetooth->Flags = *rEIR->value;
+      break;
+      
+      case BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_16:
+      case BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_16:
+        pBluetooth->nbUUID16 = (rEIR->length - 1) / 2 ;
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->ClassUUID16,rEIR->value,rEIR->length-1); 
+      break;
+      
+      case BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_32:
+      case BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_32:
+        pBluetooth->nbUUID32 = (rEIR->length - 1) / 4 ;
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->ClassUUID32,rEIR->value,rEIR->length-1);
+      break;
+      
+      case BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_128:
+      case BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_128:
+        pBluetooth->nbUUID128 = (rEIR->length - 1) / 16 ;
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->ClassUUID128,rEIR->value,rEIR->length-1);
+      break;
+      
+      case BLUETOOTH_EIR_SHORT_LOCAL_NAME:
+      case BLUETOOTH_EIR_COMPLETE_LOCAL_NAME:
+        /* No worry about name length as max EIR length is 0xff using 1 byte for the type metadata  */
+        memcpy(pBluetooth->LocalName,rEIR->value,rEIR->length-1);
+        pBluetooth->LocalName[rEIR->length] = '\0';
+      break;
+      
+      case BLUETOOTH_EIR_TX_POWER_LEVEL:
+        pBluetooth->TxPowerLevel = *rEIR->value;
+      break;
+            
+      case BLUETOOTH_EIR_DEVICE_CLASS:
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->DeviceClass,rEIR->value,sizeof(pBluetooth->DeviceClass));
+      break;
+      
+      case BLUETOOTH_EIR_SIMPLE_PAIRING_HASH:
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->SimplePairingHash,rEIR->value,sizeof(pBluetooth->SimplePairingHash));
+     break;
+      
+      case BLUETOOTH_EIR_SIMPLE_PAIRING_RANDOMIZER:
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->SimplePairingRandomizer,rEIR->value,sizeof(pBluetooth->SimplePairingRandomizer));
+      break;
+
+      case BLUETOOTH_EIR_SECURITY_MANAGER_TK_VALUE:
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->SecureManagerTK,rEIR->value,sizeof(pBluetooth->SecureManagerTK));       
+      break;
+      
+     case BLUETOOTH_EIR_SECURITY_MANAGER_FLAGS:
+        pBluetooth->SMFlags = *rEIR->value;
+      break;
+        
+     case BLUETOOTH_EIR_SLAVE_CONNECTION_INTERVAL_RANGE:
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->SlaveConnIntervalRange,rEIR->value,sizeof(pBluetooth->SlaveConnIntervalRange));
+      break;
+                
+      case BLUETOOTH_EIR_SERVICE_SOLICITATION_16:
+        pBluetooth->nbServiceSolicitation16 = (rEIR->length - 1) / 2 ;
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->ServiceSolicitation16,rEIR->value,rEIR->length-1);
+      break;
+                
+      case BLUETOOTH_EIR_SERVICE_SOLICITATION_128:
+        pBluetooth->nbServiceSolicitation128 = (rEIR->length - 1) / 16 ;
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->ServiceSolicitation128,rEIR->value,rEIR->length-1);
+      break;
+      
+      case BLUETOOTH_EIR_SERVICE_DATA:
+        /* a specific function should be used for this EIR */
+        pBluetooth->nbServiceData++;
+      break;
+                
+      case BLUETOOTH_EIR_MANUFACTURER_DATA:
+        /* a specific function should be used for this EIR */
+        pBluetooth->nbManufacturerData++;
+      break;
+                
+     case BLUETOOTH_EIR_APPEARANCE:
+        pBluetooth->Appearance = *(uint16_t *)rEIR->value;
+      break;
+      
+      case BLUETOOTH_EIR_BLE_DEVICE_ADDRESS:
+        NDEF_BluetoothCopy((uint8_t*)pBluetooth->DeviceAddress,rEIR->value,sizeof(pBluetooth->DeviceAddress));
+        pBluetooth->DeviceAddressType = (Ndef_BLE_Address_Type_t)rEIR->value[sizeof(pBluetooth->DeviceAddress)];
+      break;
+      
+      case BLUETOOTH_EIR_BLE_ROLE:
+        pBluetooth->Role = (Ndef_BLE_Role_t) *rEIR->value;
+      break;
+      
+      default:
+        pBluetooth->nbUnknown++;
+      break;
+    } /* switch rEIR->type */
+  } /* while (pData < OOBEnd) */
+    /* Check that BLE mandatory fields are there */
+  if((pBluetooth->Type == NDEF_BLUETOOTH_BLE) &&
+    (!NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_BLE_DEVICE_ADDRESS) ||
+      !NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_BLE_ROLE)))
+      return NDEF_ERROR;
+    
+  return NDEF_OK;
+}
+
+/**
+  * @brief  This function appends a Bluetooth OOB record to the NDEF message, using the OOB data given in the input structure.
+  * @param  pBluetooth  Pointer on a `Ndef_Bluetooth_OOB_t` structure containing the OOB information.
+  * @param  RecordID    ID to be used for this record (required for Handover case, can be set to NULL in other cases).
+  * @retval NDEF_OK                     The Bluetooth OOB record has been appended.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL  The Bluetooth OOB record cannot be appended due to memory size limitation.
+  * @retval NDEF_ERROR                  The Bluetooth OOB record cannot be appended.
+  */
+uint16_t NDEF_AppendBluetoothOOB( Ndef_Bluetooth_OOB_t *pBluetooth, char* RecordID, I2C* mi2cChannel )
+{
+  sRecordInfo_t Record;
+  uint16_t status;
+  
+  Record.RecordFlags = TNF_MediaType;
+  Record.RecordFlags |= (RecordID != NULL) ? IL_Mask : 0;
+  Record.IDLength = strlen(RecordID);
+  memcpy(Record.ID,RecordID,Record.IDLength);
+  
+  if(pBluetooth->Type == NDEF_BLUETOOTH_BREDR)
+  {
+    Record.TypeLength = strlen(NDEF_BLUETOOTH_BREDR_MIME_TYPE);
+    memcpy(Record.Type, NDEF_BLUETOOTH_BREDR_MIME_TYPE, Record.TypeLength); 
+  }
+  else if (pBluetooth->Type == NDEF_BLUETOOTH_BLE)
+  {
+    Record.TypeLength = strlen(NDEF_BLUETOOTH_BLE_MIME_TYPE);
+    memcpy(Record.Type, NDEF_BLUETOOTH_BLE_MIME_TYPE, Record.TypeLength); 
+  }
+  else
+  {
+    return NDEF_ERROR;
+  }
+  
+  /* Generate OOB payload */
+  Record.PayloadLength = NDEF_GetBluetoothOOBLength(pBluetooth);
+  Record.PayloadBufferAdd = NDEF_Record_Buffer;
+  if(Record.PayloadLength > NDEF_RECORD_MAX_SIZE)
+    return NDEF_ERROR_MEMORY_INTERNAL;
+
+  /* pData: pointer to ease increment of record buffer address (byte granularity) */
+  uint8_t* pData = Record.PayloadBufferAdd;  
+  
+  /* for BR-EDR Device address & length are managed outside EIR */
+  if(pBluetooth->Type == NDEF_BLUETOOTH_BREDR)
+  {
+    *pData = Record.PayloadLength;
+    pData += 2;
+    NDEF_BluetoothCopy(pData,(uint8_t*)pBluetooth->DeviceAddress,sizeof(pBluetooth->DeviceAddress));
+    pData+=sizeof(pBluetooth->DeviceAddress);
+  }
+  
+  /* wEIR: pointer to ease write to the buffer.
+   * length always set with an additional +1 corresponding to the EIR type byte.
+   * pData increment is always done with an additional +1 corresponding to the EIR length byte.
+   */
+  NDEF_EIR_t* wEIR;
+
+  
+  if(pBluetooth->Type == NDEF_BLUETOOTH_BLE)
+  {
+    /* following EIR are mandatory for BLE */
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->DeviceAddress) + sizeof(pBluetooth->DeviceAddressType) + 1;
+      wEIR->type = BLUETOOTH_EIR_BLE_DEVICE_ADDRESS;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*)pBluetooth->DeviceAddress,sizeof(pBluetooth->DeviceAddress));
+    wEIR->value[sizeof(pBluetooth->DeviceAddress)] = pBluetooth->DeviceAddressType;
+    pData += wEIR->length + 1;
+    
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->Role) + 1;
+      wEIR->type = BLUETOOTH_EIR_BLE_ROLE;
+    wEIR->value[0] = pBluetooth->Role;
+    pData += wEIR->length + 1;
+    
+  }
+
+  /* Rely on the optional mask to know if a EIR is required or not */
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_FLAGS))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->Flags) + 1;
+    wEIR->type = BLUETOOTH_EIR_FLAGS;
+    wEIR->value[0] = pBluetooth->Flags;
+    pData += wEIR->length + 1;
+  }    
+  
+  if(pBluetooth->nbUUID16 > 0)
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = 2 * pBluetooth->nbUUID16 + 1;
+    if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_16))
+      wEIR->type = BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_16;
+    else
+      wEIR->type = BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_16;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*) pBluetooth->ClassUUID16, 2 * pBluetooth->nbUUID16);
+    pData += wEIR->length + 1;
+    
+  }
+
+  if(pBluetooth->nbUUID32 > 0)
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = 4 * pBluetooth->nbUUID32 + 1;
+    if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_32))
+      wEIR->type = BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_32;
+    else
+      wEIR->type = BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_32;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*)pBluetooth->ClassUUID32, 4 * pBluetooth->nbUUID32);
+    pData += wEIR->length + 1;
+    
+  }
+
+  if(pBluetooth->nbUUID128 > 0)
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = 16 * pBluetooth->nbUUID128 + 1;
+    if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_128))
+      wEIR->type = BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_128;
+    else
+      wEIR->type = BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_128;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*) pBluetooth->ClassUUID128, 16 * pBluetooth->nbUUID128);
+    pData += wEIR->length + 1;
+    
+  }
+
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SHORT_LOCAL_NAME) ||
+    NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_COMPLETE_LOCAL_NAME))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = strlen(pBluetooth->LocalName) + 1;
+    if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SHORT_LOCAL_NAME))
+      wEIR->type = BLUETOOTH_EIR_SHORT_LOCAL_NAME;
+    else
+      wEIR->type = BLUETOOTH_EIR_COMPLETE_LOCAL_NAME;
+    memcpy(wEIR->value, pBluetooth->LocalName,strlen(pBluetooth->LocalName));
+    pData += wEIR->length + 1;
+    
+  }
+
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_TX_POWER_LEVEL))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->TxPowerLevel) + 1;
+      wEIR->type = BLUETOOTH_EIR_TX_POWER_LEVEL;
+    wEIR->value[0] = pBluetooth->TxPowerLevel;
+    pData += wEIR->length + 1;
+  }
+
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_DEVICE_CLASS))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->DeviceClass) + 1;
+      wEIR->type = BLUETOOTH_EIR_DEVICE_CLASS;
+    NDEF_BluetoothCopy(wEIR->value, pBluetooth->DeviceClass,sizeof(pBluetooth->DeviceClass));
+    pData += wEIR->length + 1;
+    
+  }
+
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SIMPLE_PAIRING_HASH))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->SimplePairingHash) + 1;
+      wEIR->type = BLUETOOTH_EIR_SIMPLE_PAIRING_HASH;
+    NDEF_BluetoothCopy(wEIR->value, pBluetooth->SimplePairingHash,sizeof(pBluetooth->SimplePairingHash));
+    pData += wEIR->length + 1;
+    
+  }
+  
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SIMPLE_PAIRING_RANDOMIZER))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->SimplePairingRandomizer) + 1;
+      wEIR->type = BLUETOOTH_EIR_SIMPLE_PAIRING_RANDOMIZER;
+    NDEF_BluetoothCopy(wEIR->value, pBluetooth->SimplePairingRandomizer,sizeof(pBluetooth->SimplePairingRandomizer));
+    pData += wEIR->length + 1;
+    
+  }
+  
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SECURITY_MANAGER_TK_VALUE))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->SecureManagerTK) + 1;
+      wEIR->type = BLUETOOTH_EIR_SECURITY_MANAGER_TK_VALUE;
+    NDEF_BluetoothCopy(wEIR->value, pBluetooth->SecureManagerTK,sizeof(pBluetooth->SecureManagerTK));
+    pData += wEIR->length + 1;
+    
+  }
+  
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SECURITY_MANAGER_FLAGS))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->SMFlags) + 1;
+      wEIR->type = BLUETOOTH_EIR_SECURITY_MANAGER_FLAGS;
+    wEIR->value[0] = pBluetooth->SMFlags;
+    pData += wEIR->length + 1;
+    
+  }
+  
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SLAVE_CONNECTION_INTERVAL_RANGE))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->SlaveConnIntervalRange) + 1;
+      wEIR->type = BLUETOOTH_EIR_SLAVE_CONNECTION_INTERVAL_RANGE;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*)pBluetooth->SlaveConnIntervalRange,sizeof(pBluetooth->SlaveConnIntervalRange));
+    pData += wEIR->length + 1;
+    
+  }
+  
+  if(pBluetooth->nbServiceSolicitation16 > 0)
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = 2 * pBluetooth->nbServiceSolicitation16 + 1;
+      wEIR->type = BLUETOOTH_EIR_SERVICE_SOLICITATION_16;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*)pBluetooth->ServiceSolicitation16, 16 * pBluetooth->nbServiceSolicitation16);
+    pData += wEIR->length + 1;
+    
+  }
+ 
+  if(pBluetooth->nbServiceSolicitation128 > 0)
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = 16 * pBluetooth->nbServiceSolicitation128 + 1;
+      wEIR->type = BLUETOOTH_EIR_SERVICE_SOLICITATION_128;
+    NDEF_BluetoothCopy(wEIR->value, (uint8_t*) pBluetooth->ServiceSolicitation128, 16 * pBluetooth->nbServiceSolicitation128);
+    pData += wEIR->length + 1;
+    
+  }
+ 
+  if(NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_APPEARANCE))
+  {
+    wEIR = (NDEF_EIR_t*)pData;
+    wEIR->length = sizeof(pBluetooth->Appearance) + 1;
+      wEIR->type = BLUETOOTH_EIR_APPEARANCE;
+    wEIR->value[0] = pBluetooth->Appearance;
+    pData += wEIR->length + 1;
+    
+  }
+
+
+  status = NDEF_AppendRecord(&Record, mi2cChannel);
+  if(status != NDEF_OK) return status;
+  
+  return NDEF_OK;
+}
+
+/**
+  * @brief  This function computeS the payload size for the OOB, using the data given in the input `Ndef_Bluetooth_OOB_t` structure.
+  * @param  pBluetooth Pointer on a `Ndef_Bluetooth_OOB_t` structure containing the OOB information.
+  * @return Computed length in bytes.
+  */
+uint32_t NDEF_GetBluetoothOOBLength( Ndef_Bluetooth_OOB_t *pBluetooth )
+{
+  uint32_t length = (pBluetooth->Type == NDEF_BLUETOOTH_BREDR) ? sizeof(pBluetooth->DeviceAddress) + 2 : 0; // +2 is for BR/EDR mandatory length
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_FLAGS)? sizeof(pBluetooth->Flags) + 2    : 0 ;
+  length += pBluetooth->nbUUID16 ? pBluetooth->nbUUID16 * 2 + 2 : 0;
+  length += pBluetooth->nbUUID32 ? pBluetooth->nbUUID32 * 4 + 2 : 0;
+  length += pBluetooth->nbUUID128 ? pBluetooth->nbUUID128 * 16 + 2 : 0;
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SHORT_LOCAL_NAME)? strlen(pBluetooth->LocalName) + 2 : 0 ;
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_COMPLETE_LOCAL_NAME)? strlen(pBluetooth->LocalName) + 2 : 0 ;
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_TX_POWER_LEVEL)? sizeof(pBluetooth->TxPowerLevel + 2) : 0 ;   
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_DEVICE_CLASS)? sizeof(pBluetooth->DeviceClass) + 2 : 0 ;   
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SIMPLE_PAIRING_HASH)? sizeof(pBluetooth->SimplePairingHash) + 2 : 0 ;   
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SIMPLE_PAIRING_RANDOMIZER)? sizeof(pBluetooth->SimplePairingRandomizer) + 2 : 0 ;  
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SECURITY_MANAGER_TK_VALUE)? sizeof(pBluetooth->SecureManagerTK) + 2 : 0 ;
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SECURITY_MANAGER_FLAGS)? sizeof(pBluetooth->SMFlags) + 2 : 0 ;
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SLAVE_CONNECTION_INTERVAL_RANGE)? sizeof(pBluetooth->SlaveConnIntervalRange) + 2 : 0 ;   
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SERVICE_SOLICITATION_16)? pBluetooth->nbServiceSolicitation16 * 2 + 2 : 0 ;
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_SERVICE_SOLICITATION_128)? pBluetooth->nbServiceSolicitation128 * 16 + 2 : 0 ;   
+  length += NDEF_BLUETOOTH_GET_OPTIONAL_MASK(pBluetooth,BLUETOOTH_EIR_APPEARANCE)? sizeof(pBluetooth->Appearance) + 2 : 0 ;
+  length += (pBluetooth->Type == NDEF_BLUETOOTH_BLE)? sizeof(pBluetooth->DeviceAddress) + sizeof(pBluetooth->DeviceAddressType) + 2 : 0 ;   
+  length += (pBluetooth->Type == NDEF_BLUETOOTH_BLE)? sizeof(pBluetooth->Role) + 2 : 0; 
+
+  return length;
+}
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Bluetooth.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Bluetooth.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,204 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Bluetooth.h
+  * @author  MMY Application Team
+  * @version $Revision: 2475 $
+  * @date    $Date: 2016-06-24 12:11:59 +0200 (Fri, 24 Jun 2016) $
+  * @brief   This file help to manage a NDEF file representing a Bluetooth pairing info.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_BLUETOOTH_H
+#define __LIB_NDEF_BLUETOOTH_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+/** @addtogroup lib_NDEF_Bluetooth
+  * @{
+  */
+   
+/** @brief MIME type for the Bluetooth BR/EDR Out-Of-Band data. */
+#define NDEF_BLUETOOTH_BREDR_MIME_TYPE "application/vnd.bluetooth.ep.oob"
+/** @brief MIME type for the Bluetooth Low Energy Out-Of-Band data. */
+#define NDEF_BLUETOOTH_BLE_MIME_TYPE "application/vnd.bluetooth.le.oob"
+
+   
+/** @brief Enumerates the Extended Inquiry Responses, as defined in the Bluetooth v4.0 core specification. */
+typedef enum {
+  BLUETOOTH_EIR_FLAGS                           = 0x01, /**<  Bluetooth flags:\n
+                                                              b0: LE limited Discoverable Mode,\n
+                                                              b1: LE general Discoverable Mode,\n
+                                                              b2: BR/EDR not supported,\n
+                                                              b3: Simultaneous LE & BR/EDR Conroller,\n
+                                                              b4: Simultaneous LE & BR/EDR Host
+                                                          */
+  BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_16   = 0x02, /**< Bluetooth service UUID on 16-bits (partial list) */
+  BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_16  = 0x03, /**< Bluetooth service UUID on 16-bits (complete list) */
+  BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_32   = 0x04, /**< Bluetooth service UUID on 32-bits (partial list) */
+  BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_32  = 0x05, /**< Bluetooth service UUID on 32-bits (complete list) */
+  BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_128  = 0x06, /**< Bluetooth service UUID on 128-bits (partial list) */
+  BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_128 = 0x07, /**< Bluetooth service UUID on 128-bits (complete list) */
+  BLUETOOTH_EIR_SHORT_LOCAL_NAME                = 0x08, /**< Shortened local name */
+  BLUETOOTH_EIR_COMPLETE_LOCAL_NAME             = 0x09, /**< Complete local name */
+  BLUETOOTH_EIR_TX_POWER_LEVEL                  = 0x0A, /**< TX Power Level (1 byte): 0xXX:-127 to +127dBm */
+  BLUETOOTH_EIR_DEVICE_CLASS                    = 0x0D, /**< Class of device, Format defined in Assigned Numbers */
+  BLUETOOTH_EIR_SIMPLE_PAIRING_HASH             = 0x0E, /**< Simple Pairing Hash C (16 octets), Format defined in [Vol. 2], Part H Section 7.2.2*/
+  BLUETOOTH_EIR_SIMPLE_PAIRING_RANDOMIZER       = 0x0F, /**< Simple Pairing Randomizer R (16 octets), Format defined in[Vol. 2], Part H Section 7.2.2 */
+  BLUETOOTH_EIR_SECURITY_MANAGER_TK_VALUE       = 0x10, /**< TK Value: Value as used in pairing over LE Physical channel. Format defined in [Vol. 3], Part H Section 2.3*/
+  BLUETOOTH_EIR_SECURITY_MANAGER_FLAGS          = 0x11, /**< Flags (1 octet):\n
+                                                             b0: OOB Flags Field (0 = OOB data not present, 1 = OOB data present),\n
+                                                             b1: LE supported (Host) (i.e. bit 65 of LMP Extended Feature bits Page 1),\n
+                                                             b2: Simultaneous LE and BR/EDR to Same Device Capable (Host) (i.e. bit 66 of LMP Extended Feature bits Page 1)\n
+                                                             b3: Address type (0 = Public Address, 1 = Random Address)
+                                                           */
+  BLUETOOTH_EIR_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, /**< Slave Connection Interval Range: The first 2 octets defines the minimum value for the connection interval, The second 2 octets defines the maximum value for the connection interval */
+  BLUETOOTH_EIR_SERVICE_SOLICITATION_16         = 0x14, /**< Service UUIDs: List of 16 bit Service UUIDs*/
+  BLUETOOTH_EIR_SERVICE_SOLICITATION_128        = 0x15, /**< Service UUIDs: List of 128 bit Service UUID*/
+  BLUETOOTH_EIR_SERVICE_DATA                    = 0x16, /**< Service Data (2 or more octets): The first 2 octets contain the 16 bit Service UUID followed by additional service data */
+  BLUETOOTH_EIR_APPEARANCE                      = 0x19, /**< UUID for `Appearance`: The Appearance characteristic value shall be the enumerated value as defined by Bluetooth Assigned Numbers document. */
+  BLUETOOTH_EIR_BLE_DEVICE_ADDRESS              = 0x1B, /**< 6 LSB bytes: Device address, 7th byte: Address type (Public/Random) */
+  BLUETOOTH_EIR_BLE_ROLE                        = 0x1C, /**< Device Role: Periph only, Central only, Periph prefered, Central prefered */
+  BLUETOOTH_EIR_MANUFACTURER_DATA               = 0xFF  /**< Manufacturer Specific Data (2 or more octets): The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data */
+} Ndef_Bluetooth_Eir_Types_t;
+   
+   
+/** @brief Bluetooth Flag field: LE limited discovery. */ 
+#define NDEF_BLE_LIMITED_DISCOVERY_FLAG     (0x1)
+/** @brief Bluetooth Flag field: LE general discovery. */ 
+#define NDEF_BLE_GENERAL_DISCOVERY_FLAG     (0x2)
+/** @brief Bluetooth Flag field: BR/EDR compliant. */ 
+#define NDEF_BLE_NOT_BREDR_COMPLIANT_FLAG   (0x4)
+/** @brief Bluetooth Flag field: LE & BR/EDR simultaneous support. */ 
+#define NDEF_BLE_LE_BREDR_SIMULTANEOUS_FLAG (0x8)
+
+/** @brief Enumerates the Bluetooth LE address types. */
+typedef enum {
+  NDEF_BLE_PUBLIC_ADDRESS_TYPE  = 0x0, /**< Public Device Address. */
+  NDEF_BLE_RANDOM_ADDRESS_TYPE  = 0x1, /**< Random Device Address. */
+  NDEF_BLE_UNDEF_ADDRESS_TYPE   = 0xff /**< Device Address is undefined. */
+} Ndef_BLE_Address_Type_t;
+
+/** @brief Enumerates Bluetooth LE Roles */
+typedef enum {
+  NDEF_BLE_ROLE_PERIPH_ONLY       = 0x0, /**< Only Peripheral Role supported. */
+  NDEF_BLE_ROLE_CENTRAL_ONLY      = 0x1, /**< Only Central Role supported. */
+  NDEF_BLE_ROLE_PERIPH_PREFERRED  = 0x2, /**< Peripheral and Central Role supported, Peripheral Role preferred for connection establishment. */
+  NDEF_BLE_ROLE_CENTRAL_PREFERRED = 0x3, /**< Peripheral and Central Role supported, Central Role preferred for connection establishment. */
+  NDEF_BLE_ROLE_UNDEF             = 0xff /**< LE Role is undefined. */
+} Ndef_BLE_Role_t;
+
+/** @brief Enumerates Bluetooth protocols */
+typedef enum {
+  NDEF_BLUETOOTH_BREDR, /**< Standard bluetooth */
+  NDEF_BLUETOOTH_BLE    /**< Bluetooth Low Energy */
+} Ndef_Bluetooth_type_t;
+
+/** @brief Helper macro to set a particular EIR in the EIR mask of a `Ndef_Bluetooth_OOB_t` instance.
+  * @param bt     Pointer to a `Ndef_Bluetooth_OOB_t` struct
+  * @param option Index of the option based on the `Ndef_Bluetooth_Eir_Types_t` */
+#define NDEF_BLUETOOTH_SET_OPTIONAL_MASK(bt,option)   do { bt->OptionalMask |= (1<<(option)); } while (0)  
+
+/** @brief Helper macro to unset a particular EIR in the EIR mask of a `Ndef_Bluetooth_OOB_t` instance.
+  * @param bt     Pointer to a `Ndef_Bluetooth_OOB_t` struct
+  * @param option Index of the option based on the `Ndef_Bluetooth_Eir_Types_t` */
+#define NDEF_BLUETOOTH_UNSET_OPTIONAL_MASK(bt,option) do {bt->OptionalMask &= ~(1<<(option)); } while (0)  
+
+/** @brief Helper macro to know if a particular EIR is present in the EIR mask of a `Ndef_Bluetooth_OOB_t` instance.
+  * @param bt     Pointer to a `Ndef_Bluetooth_OOB_t` struct
+  * @param option Index of the option based on the `Ndef_Bluetooth_Eir_Types_t` */
+#define NDEF_BLUETOOTH_GET_OPTIONAL_MASK(bt,option) ((bt->OptionalMask & (1<<(option))) >>  (option))
+
+/** @brief Helper macro to create a mask for a particular EIR.
+  * @param option Index of the option based on the `Ndef_Bluetooth_Eir_Types_t` */
+#define NDEF_BLUETOOTH_OPTION(option)               (1<<(option))
+
+/** @brief    Bluetooth Out-Of-Band data structure.
+  * @details  Some fields are shared by both Br/Edr & LE Bluetooth, some are specific...
+  *           No union used here to comply with the Cube coding guidelines, despite the fact that it could have save memory space.
+  */
+typedef struct
+{
+  /* Mandatory fields */
+  Ndef_Bluetooth_type_t   Type;                               /**< *Mandatory*: Bluetooth type (Br/Edr or LE). */
+  char                    DeviceAddress[6];                   /**< *Mandatory*: Device address. For LE: 6 LSB of Device Address EIR. */
+  /* Optionnal common fields */
+  uint32_t                OptionalMask;                       /**< This Mask is used to keep track of EIRs present in the OOB: each bit index corresponds to a `Ndef_Bluetooth_Eir_Types_t` value. */
+  uint8_t                 Flags;                              /**< Flags from BLUETOOTH_EIR_FLAGS. */
+
+  uint16_t                ClassUUID16[0xff/2];                /**< UUIDs from BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_16 or BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_16. */
+  uint32_t                ClassUUID32[0xff/4];                /**< UUIDs from BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_32 or BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_32. */
+  uint32_t                ClassUUID128[0xff/16][4];           /**< UUIDs from BLUETOOTH_EIR_SERVICE_CLASS_UUID_PARTIAL_128 or BLUETOOTH_EIR_SERVICE_CLASS_UUID_COMPLETE_128. */
+  uint8_t                 nbUUID16;                           /**< Number of UUIDs speficied in ClassUUID16. */
+  uint8_t                 nbUUID32;                           /**< Number of UUIDs speficied in ClassUUID32. */
+  uint8_t                 nbUUID128;                          /**< Number of UUIDs speficied in ClassUUID128. */
+  
+  char                    LocalName[0xff];                    /**< Device local name from BLUETOOTH_EIR_SHORT_LOCAL_NAME or BLUETOOTH_EIR_COMPLETE_LOCAL_NAME. */
+  uint8_t                 DeviceClass[3];                     /**< Class of device from BLUETOOTH_EIR_DEVICE_CLASS. */
+  // if no TPL, TPL is unknown
+  uint8_t                 TxPowerLevel;                       /**< TX power Level from BLUETOOTH_EIR_TX_POWER_LEVEL. */
+  
+  uint8_t                 SMFlags;                            /**< Security Manager Flags from BLUETOOTH_EIR_SECURITY_MANAGER_FLAGS. */
+  uint16_t                SlaveConnIntervalRange[2];          /**< Slave Connection Interval Range from BLUETOOTH_EIR_SLAVE_CONNECTION_INTERVAL_RANGE. */
+  uint16_t                ServiceSolicitation16[0xff/2];      /**< Service Solicitation from BLUETOOTH_EIR_SERVICE_SOLICITATION_16. */
+  uint32_t                ServiceSolicitation128[0xff/16][4]; /**< Service Solicitation from BLUETOOTH_EIR_SERVICE_SOLICITATION_128. */
+  uint8_t                 nbServiceSolicitation16;            /**< Number of UUIDs in ServiceSolicitation16. */
+  uint8_t                 nbServiceSolicitation128;           /**< Number of UUIDs in ServiceSolicitation128. */
+  /* for br/edr only */
+    uint8_t                 SimplePairingHash[16];            /**< *For Br/Edr only*: Simple Pairing Hash from BLUETOOTH_EIR_SIMPLE_PAIRING_HASH. */
+    uint8_t                 SimplePairingRandomizer[16];      /**< *For Br/Edr only*: Simple Pairing Randomizer from BLUETOOTH_EIR_SIMPLE_PAIRING_RANDOMIZER. */
+  /* BLE mandatory fields */
+    Ndef_BLE_Address_Type_t DeviceAddressType;                /**< *For LE only*, *Mandatory*: Address Type, MSB of the Device Address EIR (Public or Random) */
+    Ndef_BLE_Role_t         Role;                             /**< *For LE only*, *Mandatory*: LE Role from BLUETOOTH_EIR_BLE_ROLE and defined in `Ndef_BLE_Role_t`. */
+  /* BLE optional fields */
+    uint8_t                 SecureManagerTK[16];              /**< *For LE only*: Security Manager TK from BLUETOOTH_EIR_SECURITY_MANAGER_TK_VALUE. */
+    uint16_t                Appearance;                       /**< *For LE only*: Appearance from BLUETOOTH_EIR_APPEARANCE. */
+  /* track number of unparsed EIR */
+  uint8_t                 nbUnknown;                          /**< Number of EIRs not parsed because of an unknown EIR type. */
+  uint8_t                 nbServiceData;                      /**< Number of EIRs not parsed because being of type BLUETOOTH_EIR_SERVICE_DATA. */
+  uint8_t                 nbManufacturerData;                 /**< Number of EIRs not parsed because being of type BLUETOOTH_EIR_MANUFACTURER_DATA. */
+} Ndef_Bluetooth_OOB_t ;
+
+/** @brief    Extended Inquiry Response format.
+  * @details  This structure is used to parse/build EIRs in the Bluetooth OOB.
+  */
+typedef  struct {
+  uint8_t length;   /**< Length of the EIRs, including the type field (1 byte). */
+  uint8_t type;     /**< EIR type as defined in `Ndef_Bluetooth_Eir_Types_t`. */
+  uint8_t value[1]; /**< single-element array, to keep track of the address of the EIR data */
+}  NDEF_EIR_t ;
+
+uint16_t NDEF_ReadBluetoothOOB( sRecordInfo_t *pRecordStruct, Ndef_Bluetooth_OOB_t *pBluetooth );
+uint16_t NDEF_AppendBluetoothOOB( Ndef_Bluetooth_OOB_t *pBluetooth, char* RecordID, I2C* mi2cChannel );
+void NDEF_PrepareBluetoothMessage(Ndef_Bluetooth_OOB_t  *pBluetooth, uint8_t *pNDEFMessage, uint16_t *size );
+uint32_t NDEF_GetBluetoothOOBLength( Ndef_Bluetooth_OOB_t *pBluetooth );
+
+
+
+/** @}
+  */
+
+#endif /* __LIB_NDEF_BLUETOOTH_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Email.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Email.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,438 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Email.c
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @brief   This file help to manage NDEF file that represent Email.
+  ******************************************************************************
+  * @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_Email.h"
+#include "stdlib.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.
+  */
+
+/**
+  * @brief  This buffer contains the data send/received by TAG
+  */
+extern uint8_t NDEF_Buffer [];
+
+
+/** @defgroup libEmail_Private_Functions
+  * @{
+  */
+
+
+static void NDEF_FillEmailStruct( uint8_t* pPayload, uint32_t PayloadSize, sEmailInfo *pEmailStruct );
+static void NDEF_ReadURI_Email( sRecordInfo_t *pRecordStruct, sEmailInfo *pEmailStruct );
+
+/**
+  * @brief  This function fill Email structure with information of NDEF message
+  * @param  pPayload : pointer on the payload data of the NDEF message
+  * @param  PayloadSize : number of data in the payload
+  * @param  pEmailStruct : pointer on the structure to fill
+  * @retval NONE 
+  */
+static void NDEF_FillEmailStruct( uint8_t* pPayload, uint32_t PayloadSize, sEmailInfo *pEmailStruct )
+{
+  uint8_t* pLastByteAdd, *pLook4Word, *pEndString;
+  uint32_t SizeOfKeyWord = 0;
+
+  pEndString = 0;
+
+  /* First character force to NULL in case not matching found */
+#ifdef NDEF_DYN_ALLOC
+  pEmailStruct->EmailAdd = NULL;
+  pEmailStruct->Subject = NULL;
+  pEmailStruct->Message = NULL;
+  pEmailStruct->Information = NULL;
+#else
+  *pEmailStruct->EmailAdd = 0;
+  *pEmailStruct->Subject = 0;
+  *pEmailStruct->Message = 0;
+#endif
+  
+  /* Interesting information are stored before picture if any */
+  /* Moreover picture is not used in this demonstration SW */
+  pLastByteAdd = (uint8_t*)(pPayload + PayloadSize);
+
+  /* first byte should be the "mailto:" well know URI type, skip it */
+  pLook4Word = ++pPayload;
+
+  /* Retrieve email add */
+  if( pLook4Word != pLastByteAdd )
+  {
+    pEndString = pLook4Word;
+    while( memcmp( pEndString, URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ) && (pEndString < pLastByteAdd) )
+    {
+      pEndString++;
+    }
+    if( ( !memcmp( pEndString, URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ) ) || (pEndString == pLastByteAdd) )
+    {
+#ifdef NDEF_DYN_ALLOC
+      pEmailStruct->EmailAdd = malloc(pEndString-pLook4Word + 1);
+      if(pEmailStruct->EmailAdd != NULL) 
+#endif
+      {
+        memcpy( pEmailStruct->EmailAdd, pLook4Word, pEndString-pLook4Word);
+        /* add end of string character */
+        pEmailStruct->EmailAdd[pEndString-pLook4Word] = 0;
+      }
+    }
+  }
+
+  pEndString += URI_FIRST_DATA_END_LENGTH;
+  pLook4Word = pEndString;
+
+  /* check if e-mail subject is present */
+  if( !memcmp( pLook4Word, SUBJECT_BEGIN_STRING, SUBJECT_BEGIN_STRING_LENGTH ) )
+  {
+    SizeOfKeyWord = SUBJECT_BEGIN_STRING_LENGTH;
+
+    /* Retrieve subject */
+    if( pLook4Word != pLastByteAdd )
+    {
+      pLook4Word += SizeOfKeyWord;
+      pEndString = pLook4Word;
+      while( memcmp( pEndString, URI_SECOND_DATA_END, URI_SECOND_DATA_END_LENGTH ) && (pEndString < pLastByteAdd) )
+      {
+        pEndString++;
+      }
+      if( ( !memcmp( pEndString, URI_SECOND_DATA_END, URI_SECOND_DATA_END_LENGTH ) ) || (pEndString == pLastByteAdd) )
+      {
+#ifdef NDEF_DYN_ALLOC
+       pEmailStruct->Subject = malloc(pEndString-pLook4Word + 1);
+       if(pEmailStruct->Subject != NULL) 
+#endif
+       {
+          memcpy( pEmailStruct->Subject, pLook4Word, pEndString-pLook4Word );
+          /* add end of string character */
+          pEmailStruct->Subject[pEndString-pLook4Word] = 0;	
+       }
+      }
+      pEndString += URI_SECOND_DATA_END_LENGTH;
+    }
+  }
+
+  pLook4Word = pEndString;
+
+  /* check if e-mail message is present */
+  if( !memcmp( pLook4Word, MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH ) )
+  {
+    pEndString += MESSAGE_BEGIN_STRING_LENGTH;
+    /* Retrieve message */
+#ifdef NDEF_DYN_ALLOC
+      pEmailStruct->Message = malloc(PayloadSize - (pEndString - pPayload + 1) + 1);
+      if(pEmailStruct->Message != NULL) 
+#endif
+      {
+        memcpy( pEmailStruct->Message, pEndString, PayloadSize - (pEndString - pPayload + 1) );
+        /* add end of string character */
+        pEmailStruct->Message[PayloadSize-(pEndString-pPayload+1)] = 0;
+      }
+  }
+}
+
+/**
+  * @brief  This function read the Email and store data in a structure.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pEmailStruct : pointer on the structure to fill.
+  */
+static void NDEF_ReadURI_Email( sRecordInfo_t *pRecordStruct, sEmailInfo *pEmailStruct )
+{
+  uint8_t* pPayload;
+  uint32_t PayloadSize;
+
+  PayloadSize = pRecordStruct->PayloadLength;
+
+  /* Read record header */
+  pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+
+  if( pRecordStruct->NDEF_Type == URI_EMAIL_TYPE )
+    NDEF_FillEmailStruct( pPayload , PayloadSize, pEmailStruct );
+
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup libEmail_Public_Functions
+  * @{
+  * @brief  This file is used to manage Email (stored or loaded in tag)
+  */ 
+
+/**
+  * @brief  This function read NDEF and retrieve Eamil information if any.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pEmailStruct : pointer on the structure to fill .
+  * @retval NDEF_OK : Email information from NDEF have been retrieved.
+  * @retval NDEF_ERROR : not able to read NDEF in tag.
+  */
+uint16_t NDEF_ReadEmail( sRecordInfo_t *pRecordStruct, sEmailInfo *pEmailStruct )
+{
+  uint16_t status = NDEF_ERROR;
+  sRecordInfo_t *pSPRecordStruct;
+  uint32_t PayloadSize, RecordPosition;
+  uint8_t* pData;
+
+
+  if( pRecordStruct->NDEF_Type == URI_EMAIL_TYPE )
+  {
+    NDEF_ReadURI_Email( pRecordStruct, pEmailStruct );
+    status = NDEF_OK;
+  }
+  else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE )
+  {
+    for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ )
+    {
+      pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition];
+      if( pSPRecordStruct->NDEF_Type == URI_EMAIL_TYPE )
+      {
+        NDEF_ReadURI_Email( pSPRecordStruct, pEmailStruct );
+        status = NDEF_OK;
+      }
+      if( pSPRecordStruct->NDEF_Type == TEXT_TYPE )
+      {
+        PayloadSize = pSPRecordStruct->PayloadLength;
+
+        /* The instruction content the UTF-8 language code that is not used here */
+        pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd;
+        PayloadSize -= *pData + 1; /* remove not usefull data */
+        pData += *pData + 1;
+
+        memcpy( pEmailStruct->Information, pData, PayloadSize );
+      }
+    }
+  }
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the Email data given in the structure.
+  * @param  pEmailStruct : pointer on structure that contain the Email information.
+  * @retval NDEF_OK : the function is successful.
+  * @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_WriteEmail( sEmailInfo *pEmailStruct, I2C * mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR, Offset = 0;
+
+  NDEF_PrepareEmailMessage( pEmailStruct, NDEF_Buffer, &Offset );
+
+  status = NfcTag_WriteNDEF( Offset, NDEF_Buffer, mi2cChannel );
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the Email data given in the structure.
+  * @param  pEmailStruct : pointer on structure that contain the Email information.
+  * @param  pNDEFMessage : pointer on the NDEF message.
+  * @param  size : to store the size of the NDEF message generated.
+  */
+void NDEF_PrepareEmailMessage( sEmailInfo *pEmailStruct, uint8_t *pNDEFMessage, uint16_t *size )
+{
+  uint16_t Offset = 0;
+  uint32_t emailSize = 0;
+  uint32_t infoSize = 0;
+  uint32_t totalSize = 0;
+
+  /* Email is an URI but can be included in a smart poster to add text to give instruction to user for instance */
+
+  /* Email (smart poster) Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*           ID LENGTH              */  /* <---- Not Used  */
+/*----------------------------------*/
+/*             TYPE                 */
+/*----------------------------------*/
+/*              ID                  */  /* <---- Not Used  */ 
+/************************************/
+
+  /* Email : 1+@+1+subject+1+message */
+  emailSize = 1 + strlen( pEmailStruct->EmailAdd ) + URI_FIRST_DATA_END_LENGTH + SUBJECT_BEGIN_STRING_LENGTH +
+              strlen( pEmailStruct->Subject ) + URI_SECOND_DATA_END_LENGTH + MESSAGE_BEGIN_STRING_LENGTH + strlen( pEmailStruct->Message );
+
+  /* Check if a Smart poster is needed */
+  if( pEmailStruct->Information[0] != '\0' )
+  {
+    /* Info : 1+2+info */
+    infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen( pEmailStruct->Information );
+    /* Total */
+    totalSize = 4 + emailSize + 4 + infoSize;
+    if( emailSize > 255 ) totalSize += 3; /* Normal Email size */
+    if( infoSize > 255 ) totalSize += 3;  /* Normal Info size */
+
+    /* SmartPoster header */
+    if( totalSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0xC1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = totalSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0xD1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)totalSize;
+    }
+    memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH );
+    Offset += SMART_POSTER_TYPE_STRING_LENGTH;
+  }
+
+  /* Email header */
+  pNDEFMessage[Offset] = 0x81;
+  if( emailSize < 256 ) pNDEFMessage[Offset] |= 0x10;                      // Set the SR bit
+  if( pEmailStruct->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit
+  Offset++;
+
+  pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH;
+  if( emailSize > 255 )
+  {
+    pNDEFMessage[Offset++] = (emailSize & 0xFF000000) >> 24;
+    pNDEFMessage[Offset++] = (emailSize & 0x00FF0000) >> 16;
+    pNDEFMessage[Offset++] = (emailSize & 0x0000FF00) >> 8;
+    pNDEFMessage[Offset++] = emailSize & 0x000000FF;
+  }
+  else
+  {
+    pNDEFMessage[Offset++] = (uint8_t)emailSize;
+  }
+  memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH );
+  Offset += URI_TYPE_STRING_LENGTH;
+
+  /* Email pay load */
+  pNDEFMessage[Offset++] = URI_ID_0x06;
+  memcpy( &pNDEFMessage[Offset], pEmailStruct->EmailAdd, strlen(pEmailStruct->EmailAdd) );
+  Offset += strlen( pEmailStruct->EmailAdd );
+  memcpy( &pNDEFMessage[Offset], URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH );
+  Offset += URI_FIRST_DATA_END_LENGTH;
+
+  memcpy( &pNDEFMessage[Offset], SUBJECT_BEGIN_STRING, SUBJECT_BEGIN_STRING_LENGTH );
+  Offset += SUBJECT_BEGIN_STRING_LENGTH;
+  memcpy( &pNDEFMessage[Offset], pEmailStruct->Subject, strlen(pEmailStruct->Subject) );
+  Offset += strlen( pEmailStruct->Subject );
+  memcpy( &pNDEFMessage[Offset], URI_SECOND_DATA_END, URI_SECOND_DATA_END_LENGTH );
+  Offset += URI_SECOND_DATA_END_LENGTH;
+
+  memcpy( &pNDEFMessage[Offset], MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH );
+  Offset += MESSAGE_BEGIN_STRING_LENGTH;
+  memcpy( &pNDEFMessage[Offset], pEmailStruct->Message, strlen(pEmailStruct->Message) );
+  Offset += strlen( pEmailStruct->Message );
+
+  /* Information header */
+  if( pEmailStruct->Information[0] != '\0' )
+  {
+    if( infoSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0x41;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = infoSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0x51;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)infoSize;
+    }
+
+    memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH );
+    Offset += TEXT_TYPE_STRING_LENGTH;
+    pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */
+    memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH );
+    Offset += ISO_ENGLISH_CODE_STRING_LENGTH;
+
+    /* Information payload */
+    memcpy( &pNDEFMessage[Offset], pEmailStruct->Information, strlen(pEmailStruct->Information) );
+    Offset += strlen( pEmailStruct->Information );
+
+  }
+
+  *size = (uint16_t)(Offset);
+
+}
+
+/**
+  * @brief  This function close a NDEF Email buffer freeing associated memory.
+  * @param  pEmailStruct : pointer on structure that contain the Email information.
+  */
+void NDEF_closeEmail( sEmailInfo *pEmailStruct)
+{
+#ifdef NDEF_DYN_ALLOC
+  if(pEmailStruct->EmailAdd != NULL) free(pEmailStruct->EmailAdd);
+  if(pEmailStruct->Information != NULL) free(pEmailStruct->Information);
+  if(pEmailStruct->Message != NULL) free(pEmailStruct->Message);
+  if(pEmailStruct->Subject != NULL) free(pEmailStruct->Subject);
+#endif
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Email.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Email.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,65 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Email.h
+  * @author  MMY Application Team
+  * @version $Revision: 2688 $
+  * @date    $Date: 2016-07-12 16:57:52 +0200 (Tue, 12 Jul 2016) $
+  * @brief   This file help to manage Email NDEF file.
+   ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_EMAIL_H
+#define __LIB_NDEF_EMAIL_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+/* "mailto:customer.service@st.com?subject=M24SR S/N 754FHFGJF46G329 WARRANTY&body=this is an auomatic warranty activation email" */
+
+#ifdef NDEF_DYN_ALLOC
+typedef struct
+{
+  char *EmailAdd;
+  char *Subject;
+  char *Message;
+  char *Information;
+}sEmailInfo;
+#else
+typedef struct
+{
+  char EmailAdd[64];
+  char Subject[100];
+  char Message[2000];
+  char Information[400];
+}sEmailInfo;
+#endif
+uint16_t NDEF_ReadEmail( sRecordInfo_t *pRecordStruct, sEmailInfo *pEmailStruct );
+uint16_t NDEF_WriteEmail( sEmailInfo *pEmailStruct, I2C* mi2cChannel );
+void NDEF_PrepareEmailMessage( sEmailInfo *pEmailStruct, uint8_t *pNDEFMessage, uint16_t *size );
+void NDEF_closeEmail( sEmailInfo *pEmailStruct);
+
+
+#endif /* __LIB_NDEF_EMAIL_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Geo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Geo.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,358 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Geo.c
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @brief   This file help to manage NDEF file that represent geolocation.
+  ******************************************************************************
+  * @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_Geo.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.
+  */
+
+/**
+  * @brief  This buffer contains the data send/received by TAG
+  */
+extern uint8_t NDEF_Buffer [];
+
+/** @defgroup libGeo_Private_Functions
+  * @{
+  */
+
+static void NDEF_FillGeoStruct( uint8_t* pPayload, uint32_t PayloadSize, sGeoInfo *pGeoStruct );
+static void NDEF_ReadURI_Geo( sRecordInfo_t *pRecordStruct, sGeoInfo *pGeoStruct );
+
+/**
+  * @brief  This function fill Geo structure with information of NDEF message.
+  * @param  pPayload : pointer on the payload data of the NDEF message.
+  * @param  PayloadSize : number of data in the payload.
+  * @param  pGeoStruct : pointer on the structure to fill.
+  */
+static void NDEF_FillGeoStruct( uint8_t* pPayload, uint32_t PayloadSize, sGeoInfo *pGeoStruct )
+{
+  uint8_t* pLastByteAdd, *pLook4Word, *pEndString;
+  char* pKeyWord;
+  uint32_t SizeOfKeyWord;
+  pEndString = 0;
+
+  pKeyWord = GEO_TYPE_STRING;
+  SizeOfKeyWord = GEO_TYPE_STRING_LENGTH;
+
+  /* First character force to NULL in case not matching found */
+  *pGeoStruct->Latitude = 0;
+  *pGeoStruct->Longitude = 0;
+
+  /* Interresting information are stored before picture if any */
+  /* Moreover picture is not used in this demonstration SW */
+  pLastByteAdd = (uint8_t*)(pPayload + PayloadSize);
+
+  pLook4Word = pPayload;
+  while( memcmp( pLook4Word, pKeyWord, SizeOfKeyWord ) && (pLook4Word < pLastByteAdd) )
+  {
+    pLook4Word++;
+  }
+
+  /* Retrieve phone number */
+  if( pLook4Word != pLastByteAdd )
+  {
+    pLook4Word += SizeOfKeyWord;
+    pEndString = pLook4Word;
+    while( memcmp( pEndString, URI_LATITUDE_END, URI_LATITUDE_END_LENGTH ) && (pEndString < pLastByteAdd) )
+    {
+      pEndString++;
+    }
+    if( pEndString != pLastByteAdd )
+    {
+      memcpy( pGeoStruct->Latitude, pLook4Word, pEndString-pLook4Word );
+      /* add end of string character */
+      pGeoStruct->Latitude[pEndString-pLook4Word] = 0;
+    }
+  }
+  pEndString += URI_LATITUDE_END_LENGTH;
+  pLook4Word = pEndString;
+
+  memcpy( pGeoStruct->Longitude, pEndString, PayloadSize - (pEndString - pPayload) );
+  /* add end of string character */
+  pGeoStruct->Longitude[PayloadSize-(pEndString-pPayload)] = 0;
+
+}
+
+/**
+  * @brief  This function read the geoloccation information and store data in a structure.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pGeoStruct : pointer on the structure to fill.
+  */
+static void NDEF_ReadURI_Geo( sRecordInfo_t *pRecordStruct, sGeoInfo *pGeoStruct )
+{
+  uint8_t* pPayload;
+  uint32_t PayloadSize;
+
+  PayloadSize = pRecordStruct->PayloadLength;
+
+  /* Read record header */
+  pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+
+  if( pRecordStruct->NDEF_Type == URI_GEO_TYPE )
+    NDEF_FillGeoStruct( pPayload , PayloadSize, pGeoStruct );
+
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup libGeo_Public_Functions
+  * @{
+  * @brief  This file is used to manage geolocation (stored or loaded in tag)
+  */ 
+
+/**
+  * @brief  This function read NDEF and retrieve Geo information if any.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pGeoStruct : pointer on the structure to fill .
+  * @retval NDEF_OK : Geolocation information from NDEF have been retrieved.
+  * @retval NDEF_ERROR : not able to read NDEF from tag.
+  */
+uint16_t NDEF_ReadGeo( sRecordInfo_t *pRecordStruct, sGeoInfo *pGeoStruct )
+{
+  uint16_t status = NDEF_ERROR;
+  sRecordInfo_t *pSPRecordStruct;
+  uint32_t PayloadSize, RecordPosition;
+  uint8_t* pData;
+
+  if( pRecordStruct->NDEF_Type == URI_GEO_TYPE )
+  {
+    NDEF_ReadURI_Geo( pRecordStruct, pGeoStruct );
+    status = NDEF_OK;
+  }
+  else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE )
+  {
+    for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ )
+    {
+      pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition];
+      if( pSPRecordStruct->NDEF_Type == URI_GEO_TYPE )
+      {
+        NDEF_ReadURI_Geo( pSPRecordStruct, pGeoStruct );
+        status = NDEF_OK;
+      }
+      if( pSPRecordStruct->NDEF_Type == TEXT_TYPE )
+      {
+        PayloadSize = pSPRecordStruct->PayloadLength;
+
+        /* The instruction content the UTF-8 language code that is not used here */
+        pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd;
+        PayloadSize -= *pData + 1; /* remove not usefull data */
+        pData += *pData + 1; /* set pointer on usefull data */
+
+        memcpy( pGeoStruct->Information, pData, PayloadSize );
+        /* add end of string character */
+        pGeoStruct->Information[PayloadSize] = 0;
+      }
+    }
+  }
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the geolocation data given in the structure.
+  * @param  pGeoStruct : pointer on structure that contain the geolocation information.
+  * @retval NDEF_OK : the function is succesful.
+  * @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_WriteGeo( sGeoInfo *pGeoStruct, I2C* mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR,Offset = 0;
+
+  NDEF_PrepareGeoMessage( pGeoStruct, NDEF_Buffer, &Offset );
+
+  status = NfcTag_WriteNDEF( Offset, NDEF_Buffer, mi2cChannel );
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the geolocation data given in the structure.
+  * @param  pGeoStruct : pointer on structure that contain the geolocation information.
+  * @param  pNDEFMessage : pointer on the NDEF message.
+  * @param  size : to store the size of the NDEF message generated.
+  */
+void NDEF_PrepareGeoMessage( sGeoInfo *pGeoStruct, uint8_t *pNDEFMessage, uint16_t *size )
+{
+  uint16_t Offset = 0;
+  uint32_t geoSize = 0;
+  uint32_t infoSize = 0;
+  uint32_t totalSize = 0;
+
+  /* GEO is an URI but can be included in a smart poster to add text to give instruction to user for instance */
+
+  /* GEO (smart poster) Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*          ID LENGTH               */  /* <---- Not Used  */
+/*----------------------------------*/
+/*              TYPE                */
+/*----------------------------------*/
+/*               ID                 */  /* <---- Not Used  */
+/************************************/
+
+  /* GEO : 1+geo:+latitude+1+longitude */
+  geoSize = 1 + GEO_TYPE_STRING_LENGTH + strlen(pGeoStruct->Latitude) + URI_LATITUDE_END_LENGTH + strlen(pGeoStruct->Longitude);
+
+  /* Check if a Smart poster is needed */
+  if( pGeoStruct->Information[0] != '\0' )
+  {
+    /* Info : 1+2+info */
+    infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen(pGeoStruct->Information);
+    /* Total */
+    totalSize = 4 + geoSize + 4 + infoSize;
+    if( geoSize > 255 ) totalSize += 3; /* Normal Geo size */
+    if( infoSize > 255 ) totalSize += 3;  /* Normal Info size */
+
+    /* SmartPoster header */
+    if( totalSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0xC1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = totalSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0xD1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)totalSize;
+    }
+    memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH );
+    Offset += SMART_POSTER_TYPE_STRING_LENGTH;
+  }
+
+  /* GEO header */
+  pNDEFMessage[Offset] = 0x81;
+  if( geoSize < 256 ) pNDEFMessage[Offset] |= 0x10;                      // Set the SR bit
+  if( pGeoStruct->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit
+  Offset++;
+
+  pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH;
+  if( geoSize > 255 )
+  {
+    pNDEFMessage[Offset++] = (geoSize & 0xFF000000) >> 24;
+    pNDEFMessage[Offset++] = (geoSize & 0x00FF0000) >> 16;
+    pNDEFMessage[Offset++] = (geoSize & 0x0000FF00) >> 8;
+    pNDEFMessage[Offset++] = geoSize & 0x000000FF;
+  }
+  else
+  {
+    pNDEFMessage[Offset++] = (uint8_t)geoSize;
+  }
+  memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH );
+  Offset += URI_TYPE_STRING_LENGTH;
+
+  /* GEO payload */
+  pNDEFMessage[Offset++] = URI_ID_0x00; /* URI identifier no abbreviation */
+  memcpy( &pNDEFMessage[Offset], GEO_TYPE_STRING, GEO_TYPE_STRING_LENGTH );
+  Offset += GEO_TYPE_STRING_LENGTH;
+  memcpy( &pNDEFMessage[Offset], pGeoStruct->Latitude, strlen(pGeoStruct->Latitude) );
+  Offset += strlen( pGeoStruct->Latitude );
+  memcpy( &pNDEFMessage[Offset], URI_LATITUDE_END, URI_LATITUDE_END_LENGTH );
+  Offset += URI_LATITUDE_END_LENGTH;
+  memcpy( &pNDEFMessage[Offset], pGeoStruct->Longitude, strlen(pGeoStruct->Longitude) );
+  Offset += strlen( pGeoStruct->Longitude );
+
+  /* Information header */
+  if( pGeoStruct->Information[0] != '\0' )
+  {
+    if( infoSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0x41;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = infoSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0x51;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)infoSize;
+    }
+
+    memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH );
+    Offset += TEXT_TYPE_STRING_LENGTH;
+    pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */
+    memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH );
+    Offset += ISO_ENGLISH_CODE_STRING_LENGTH;
+
+    /* Information payload */
+    memcpy( &pNDEFMessage[Offset], pGeoStruct->Information, strlen(pGeoStruct->Information) );
+    Offset += strlen( pGeoStruct->Information );
+  }
+
+  *size = (uint16_t)(Offset);
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Geo.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Geo.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Geo.h
+  * @author  MMY Application Team
+  * @version $Revision: 2475 $
+  * @date    $Date: 2016-06-24 12:11:59 +0200 (Fri, 24 Jun 2016) $
+  * @brief   This file help to manage Geolocation NDEF file.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_GEO_H
+#define __LIB_NDEF_GEO_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+typedef struct
+{
+  char Latitude[20];
+  char Longitude[20];
+  char Information[100];
+}sGeoInfo;
+
+uint16_t NDEF_ReadGeo( sRecordInfo_t *pRecordStruct, sGeoInfo *pGeoStruct );
+uint16_t NDEF_WriteGeo( sGeoInfo *pGeoStruct, I2C* mi2cChannel );
+void NDEF_PrepareGeoMessage( sGeoInfo *pGeoStruct, uint8_t *pNDEFMessage, uint16_t *size );
+
+
+#endif /* __LIB_NDEF_GEO_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Handover.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Handover.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,509 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Bluetooth.c
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @brief   This file helps to manage a NDEF Handover message.
+  * @ingroup libNDEF_Handover 
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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_Handover.h"
+
+/** @addtogroup lib_NDEF_Handover NDEF Handover library
+  * @ingroup libNDEF
+  *	@brief  This module is used to manage the NDEF Handover messages, to negociate the switch to a non-nfc protocol of communication.
+  * @details 
+  *          The NDEF Handover process is described by the NFC Forum Connection Handover specification.
+  *          It consists in a specific NDEF message construct, as:
+  *          - NDEF 1st record: Handover Request or Handover Select record
+  *            - Version
+  *            - Collision Resolution  (nested record, optional)
+  *              - Random number
+  *            - Alternative Carrier 1 (nested record)
+  *              - Power state
+  *              - Reference Data
+  *              - Auxiliary Data Reference 1
+  *              - ...
+  *              - Auxiliary Data Reference N
+  *            - ...
+  *            - Alternative Carrier N (nested record)
+  *          - NDEF record 2+: Alternative Carrier or Auxiliary Data: Connection details for one of the AC (record ID is the AC Reference Data or an Auxiliary Data Reference). 
+  *          - ...
+  *          - NDEF record N:  Alternative Carrier or Auxiliary Data: Connection details for one of the AC (record ID is the AC Reference Data or an Auxiliary Data Reference).
+  *          _________________
+  *          @section Handover_Library_Usage NDEF Handover Library usage:
+  *          @subsection Static_Handover Static Handover
+  *          The Static Handover is used when a device is only equipped with a NFC Tag (no peer-to-peer) to directly propose a set of Alternative Carriers (ACs: bluetooth, wifi,...) 
+  *          without running the full handover request-select process.\n
+  *          The Handover Select record use in that case is similar to the one used during a regular Handover negociation.\n
+  *          1. Declare & initialize an instance of `Ndef_Handover_t`, such as:
+  *
+  *                 Ndef_Handover_t wHandover = {.type = NDEF_HANDOVER_SELECT_TYPE, .version = NDEF_HANDOVER_VERSION_1_2};
+  *          2. Declare a `sRecordInfo_t` instance:
+  *
+  *                 sRecordInfo_t HandoverRecord;
+  *          3. Call the `NDEF_CreateHandover` function, to start preparing the Handover Select record
+  *
+  *                 NDEF_CreateHandover(&wHandover,&HandoverRecord);
+  *          4. Call the `NDEF_AddAlternativeCarrier` for each Alternative Carrier (such as Bluetooth, Wifi, ...) 
+  *          5. Declare and initialize as many `Ndef_Handover_alternative_carrier_t` instances as the number of non-NFC protocol available.
+  *             And then call the `NDEF_AddAlternativeCarrier` for each of them.
+  *
+  *                 Ndef_Handover_alternative_carrier_t wAC_BREDR = {.cps = NDEF_HANDOVER_AC_CPS_ACTIVE,
+  *                                                                  .aux_data_ref_count = 0};
+  *                 Ndef_Handover_alternative_carrier_t wAC_BLE = {.cps = NDEF_HANDOVER_AC_CPS_ACTIVE,
+  *                                                                .aux_data_ref_count = 0};
+  *                 Ndef_Handover_alternative_carrier_t wAC_Wifi = {.cps = NDEF_HANDOVER_AC_CPS_ACTIVE,
+  *                                                                 .aux_data_ref_count = 0};
+  *                 
+  *                 NDEF_AddAlternativeCarrier(&wAC_BREDR,"urn:nfc:handover:bredr", NULL,&HandoverRecord );
+  *                 NDEF_AddAlternativeCarrier(&wAC_BLE,"urn:nfc:handover:ble", NULL,&HandoverRecord );
+  *                 NDEF_AddAlternativeCarrier(&wAC_Wifi,"urn:nfc:handover:wifi", NULL,&HandoverRecord );
+  *             @note
+  *                 1. In this example a single `Ndef_Handover_alternative_carrier_t` could have been used, as the parameters are the same for all ACs.
+  *                 2. If more than one NDEF record is required to provide the AC connection details, the `aux_data_ref_count` must specify the number of additional records.
+  *
+  *                        Ndef_Handover_alternative_carrier_t wAC_Wifi = {.cps = NDEF_HANDOVER_AC_CPS_ACTIVE,
+  *                                                                        .aux_data_ref_count = 2};
+  *                    Then, it's required to initialize an array of pointers to these Auxiliary Data Reference, as:
+  *
+  *                        char *aux_data_ref1 = "urn:nfc:handover:wifi:aux_data_ref1";
+  *                        char *aux_data_ref2 = "urn:nfc:handover:wifi:aux_data_ref2";
+  *                        char *wifi_aux_ref_data_array[2] = {aux_data_ref1,aux_data_ref2};
+  *                    And then provide this array as the 3rd argument to the 'NDEF_AddAlternativeCarrier' function:
+  *
+  *                        NDEF_AddAlternativeCarrier(&wAC_Wifi,"urn:nfc:handover:wifi", wifi_aux_ref_data_array,&HandoverRecord );
+  *          6. Call the `NDEF_WriteHandover` function to finalize the NDEF message and write it to the tag.
+  *
+  *                 NDEF_WriteHandover(&HandoverRecord, NDEF_Buffer);
+  *          7. Then call other functions (from the libNDEF or not) to add records, describing the Alternative Carriers, to the NDEF message:
+  *
+  *                 NDEF_AppendBluetoothOOB ( &w_ble_oob, "urn:nfc:handover:ble" );
+  *                 NDEF_AppendBluetoothOOB ( &w_bredr_oob, "urn:nfc:handover:bredr" );
+  *              @note
+  *                1. The ID of these additional records (2nd argument in the above example) must match the Data Reference provided within the Handover record.
+  *                2. If Auxiliary Data References are expected they must also be added to the NDEF message, with their ID matching the ID provided to the Alternative Carrier record.
+  *
+  *          @section Reading_Handover Reading through a Handover Request message
+  *          1. Read the 1st record of the NDEF message:
+  *
+  *                 sRecordInfo_t rRecord;
+  *                 NDEF_ReadNDEF(NDEF_Buffer);
+  *                 NDEF_IdentifyBuffer(rRecord,NDEF_Buffer);
+  *          2. Decode the handover:
+  *
+  *                 Ndef_Handover_t rHandover;
+  *                 NDEF_ReadHandover(&rRecord ,  &rHandover ); 
+  *          3. Read all Alternative Carrier records, and their Auxiliary Data References if any.
+  *
+  *                 uint8_t ac_index, aux_index;
+  *                 for(ac_index=0;ac_index<rHandover.nb_alternative_carrier;ac_index++)
+  *                 {
+  *                   Ndef_Handover_alternative_carrier_t rAC;
+  *                   NDEF_ReadAC( ac_index, &rHandover  , &rAC );
+  *                   for(aux_index = 0; aux_index < rAC.aux_data_ref_count; aux_index++)
+  *                   {
+  *                     sRecordInfo_t AuxRecord;
+  *                     NDEF_ReadAuxData( aux_index, &rAC, &AuxRecord );
+  *                     // Do something with this Auxiliary Data
+  *                   }
+  *                   // Process this AC (Extract OOB/or whatever data), and decide if this Carrier is supported or not.
+  *                 }
+  *          4. Choose the prefered Carrier and write a Handover Select record with the prefered AC as described in the @ref Static_Handover section.
+  * @{
+  */
+
+
+
+/**
+  * @brief  This function searches the NDEF message to retrieve the nth Auxiliary Data record if present.
+  * @param  aux_data_nb Position of the Auxiliary Data Reference in the Alternative Carrier.
+  * @param  pAC         Pointer on the Alternative Carrier structure where to find the Auxiliary Data Reference.
+  * @param  pRecord     Pointer to return the output Auxiliary Data record.
+  * @retval NDEF_OK     The Auxiliary Data record has been retrieved.
+  * @retval NDEF_ERROR  Not able to find the Auxiliary Data in the NDEF message.
+  */
+uint16_t NDEF_ReadAuxData( uint8_t aux_data_nb, Ndef_Handover_alternative_carrier_t *pAC, sRecordInfo_t *pRecord )
+{
+  uint16_t status;
+  uint8_t* pData = pAC->aux_data_ref_start; 
+  uint8_t current_aux = 0;
+  uint8_t* aux_id;
+  uint8_t  aux_id_length;
+
+  if((pAC->aux_data_ref_start == NULL) ||
+     (pAC->aux_data_ref_end == NULL) ||
+     (pAC->aux_data_ref_count == 0) ||
+     (aux_data_nb >= pAC->aux_data_ref_count))
+    return NDEF_ERROR;
+  
+
+  while((current_aux < aux_data_nb) && (pData < pAC->aux_data_ref_end))
+  {
+    aux_id_length = *pData++;
+    aux_id = pData;
+    pData += aux_id_length;
+    current_aux++;
+   }
+
+   pData = pAC->aux_data_ref_end;
+  /* if ac has been found */
+  if(current_aux == aux_data_nb)
+  {
+    /* let's now look for the corresponding record - must be after the Handover record */
+    do {
+      status = NDEF_IdentifyBuffer(pRecord,pData);
+      if(status != NDEF_OK) return status;
+      pData  = pAC->ac_record.PayloadBufferAdd;
+
+      if((pRecord->IDLength == aux_id_length) &&
+          !memcmp(pRecord->ID, aux_id,aux_id_length))
+      {
+        /* this is the record we were looking for, so exit */
+        return NDEF_OK;
+      }
+      
+      // go to next record
+      pData  = pRecord->PayloadBufferAdd + pRecord->PayloadLength;    
+      
+    } while (!(pRecord->RecordFlags & MB_Mask));
+    
+  }
+ // if we go there, it means that the record ID is not found
+  return NDEF_ERROR;
+}
+
+
+
+/**
+  * @brief  This function reads the NDEF message and retrieves the nth Alternative Carrier record if present.
+  * @param  ac_nb       Position of the Alternative Carrier Reference in the Handover record.
+  * @param  pHandover   Pointer to the Handover record where to find the AC Reference Data.
+  * @param  pAC         Pointer used to return the output Alternative Carrier record.
+  * @retval NDEF_OK     The Alternative Carrier record has been retrieved.
+  * @retval NDEF_ERROR  Not able to find the Alternative Carrier in the NDEF message.
+  */
+uint16_t NDEF_ReadAC( uint8_t ac_nb, Ndef_Handover_t *pHandover  , Ndef_Handover_alternative_carrier_t *pAC )
+{
+  uint16_t status;
+  uint8_t* pData = pHandover->ac_start; 
+  uint8_t current_ac = 0;
+  uint8_t* ac_id;
+  uint8_t  ac_id_length;
+  sRecordInfo_t NestedRecord;
+  uint8_t ac_found = 0;
+
+  if((pHandover->ac_start == NULL) ||
+     (pHandover->ac_end == NULL) ||
+     (pHandover->nb_alternative_carrier == 0) ||
+     (ac_nb >= pHandover->nb_alternative_carrier))
+    return NDEF_ERROR;
+  
+  // Default handover init
+  pAC->aux_data_ref_count = 0;
+
+  while((current_ac <= ac_nb)&&(current_ac <= pHandover->nb_alternative_carrier) && (pData < pHandover->ac_end))
+  {
+     status = NDEF_IdentifyBuffer(&NestedRecord,pData);
+     if(status != NDEF_OK) return status;
+     // go to payload address
+     pData  = NestedRecord.PayloadBufferAdd;
+    
+     if(!memcmp(NestedRecord.Type,NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR,strlen(NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR)))
+     {  
+       if(current_ac == ac_nb)
+       {
+         // parse the AC now
+          pAC->cps = pData[0] & NDEF_HANDOVER_AC_CPS_MASK;
+          ac_id_length = pData[1];
+          ac_id = &pData[2];
+          pAC->aux_data_ref_count = pData[2 + ac_id_length];
+          pAC->aux_data_ref_start = &pData[3 + ac_id_length];
+          pAC->aux_data_ref_end = pData + NestedRecord.PayloadLength;
+          ac_found = 1;
+       }
+       current_ac++;
+     }
+     // go to next record
+     pData  += NestedRecord.PayloadLength;    
+  }
+  pData = pHandover->ac_end;
+  /* if ac has been found */
+  if(ac_found)
+  {
+    /* let's now look for the corresponding record - must be after the Handover record */
+    do {
+      status = NDEF_IdentifyBuffer(&pAC->ac_record,pData);
+      if(status != NDEF_OK) return status;
+      pData  = pAC->ac_record.PayloadBufferAdd;
+
+      if((pAC->ac_record.IDLength == ac_id_length) &&
+          !memcmp(pAC->ac_record.ID, ac_id,ac_id_length))
+      {
+        /* this is the record we were looking for, so exit */
+        return NDEF_OK;
+      }
+      
+      // go to next record
+      pData  = pAC->ac_record.PayloadBufferAdd + pAC->ac_record.PayloadLength;    
+      // TO DO: add a security condition to avoid infinite loop if NDEF file is corrupted
+    } while (!(pAC->ac_record.RecordFlags & ME_Mask));
+    
+  }
+ // if we go there, it means that the record ID is not found
+  return NDEF_ERROR;
+}
+
+
+/**
+  * @brief  This function reads a record and retrieves the Handover information if present.
+  * @param  pRecord       Pointer on the record structure to be read.
+  * @param  pHandover     Pointer used to return the Handover information.
+  * @retval NDEF_OK       Handover information has been retrieved from the record.
+  * @retval NDEF_ERROR    Not able to read the Handover information from the record.
+  */
+uint16_t NDEF_ReadHandover(sRecordInfo_t *pRecord ,  Ndef_Handover_t *pHandover )
+{
+  uint16_t status;
+  uint8_t* pData = pRecord->PayloadBufferAdd;
+  uint8_t* pEnd = pData + pRecord->PayloadLength;
+  sRecordInfo_t NestedRecord;
+
+  /* Default Handover Structure init */
+  pHandover->version =0;
+  pHandover->nb_alternative_carrier =0;
+  pHandover->has_cr = 0; 
+  pHandover->ac_start = NULL; 
+  pHandover->ac_end = NULL; 
+
+  /* A Handover record should never be the end of the NDEF message */
+  if(pRecord->RecordFlags & ME_Mask)
+    return NDEF_ERROR;
+
+  if( !memcmp(pRecord->Type,NDEF_HANDOVER_REQUEST_TYPE_STR,strlen(NDEF_HANDOVER_REQUEST_TYPE_STR)) )
+  {
+    pHandover->type = NDEF_HANDOVER_REQUEST_TYPE;
+  } else if ( !memcmp(pRecord->Type,NDEF_HANDOVER_SELECT_TYPE_STR,strlen(NDEF_HANDOVER_SELECT_TYPE_STR)) )
+  {
+    pHandover->type = NDEF_HANDOVER_SELECT_TYPE;
+  } else {
+    /* This is not a Handover record! */
+    return NDEF_ERROR;
+  }  
+
+  pHandover->version = *pData++;
+  
+  /* Following records are nested into Hr/s record */
+  while (pData < pEnd)
+  {
+     status = NDEF_IdentifyBuffer(&NestedRecord,pData);
+     if(status != NDEF_OK) return status;
+    /* save record address */
+    uint8_t* pACRecord = pData; 
+    /* go to payload address */
+     pData  = NestedRecord.PayloadBufferAdd;
+
+    /* Parse Collision Resolution if Handover request */
+    if(pHandover->type == NDEF_HANDOVER_REQUEST_TYPE)
+    {
+
+      if(!memcmp(NestedRecord.Type,NDEF_HANDOVER_COLLISION_RESOLUTION_TYPE_STR,strlen(NDEF_HANDOVER_COLLISION_RESOLUTION_TYPE_STR)))
+      {  
+        pHandover->has_cr = 1; 
+        pHandover->cr_random_number = *(uint16_t*)pData;
+      }
+    }
+
+  /* Parse AlternativeCarriers just to know how many they are */
+    else if(!memcmp(NestedRecord.Type,NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR,strlen(NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR)))
+    {  
+      pHandover->nb_alternative_carrier++;
+      if(pHandover->ac_start == NULL)
+        pHandover->ac_start = pACRecord;
+        pHandover->ac_end = pData + NestedRecord.PayloadLength;
+      /* don't parse the AC now */
+    }
+    else {
+      /* this is an unexpected type, just ignore it */
+    }
+    /* go to next record */
+     pData  += NestedRecord.PayloadLength;    
+
+  }    
+ 
+  return NDEF_OK;
+}
+
+/**
+  * @brief  This function prepares the Handover record with the data given in the Handover structure.
+  * @param  pHandover   Pointer on structure containing the handover basic information.
+  * @param  pRecord     Pointer used to return the prepared Handover record. 
+  * @retval NDEF_OK     The record has been prepared.
+  * @retval NDEF_ERROR  The record has not been prepared.
+  */
+uint16_t NDEF_CreateHandover(Ndef_Handover_t  *pHandover, sRecordInfo_t* pRecord )
+{
+  uint16_t status = NDEF_ERROR;
+
+  /* Use a static buffer to prepare the Handover record */
+  pRecord->PayloadBufferAdd = NDEF_Record_Buffer;
+  /* Alternative, where the user must first allocate the Payload buffer in the record:
+   * if (pRecord->PayloadBufferAdd == NULL)
+   *  return NDEF_ERROR;
+   */
+ 
+  /* Handover MUST be the first record (SR mask to be updated when actually writing the record) */
+  pRecord->RecordFlags = MB_Mask | ME_Mask | TNF_WellKnown;
+
+  if(pHandover->type == NDEF_HANDOVER_SELECT_TYPE)
+  {
+    pRecord->TypeLength = strlen(NDEF_HANDOVER_SELECT_TYPE_STR);
+    memcpy(pRecord->Type, NDEF_HANDOVER_SELECT_TYPE_STR,pRecord->TypeLength); 
+  }
+  else if (pHandover->type == NDEF_HANDOVER_REQUEST_TYPE)
+  {
+    pRecord->TypeLength = strlen(NDEF_HANDOVER_SELECT_TYPE_STR);
+    memcpy(pRecord->Type, NDEF_HANDOVER_REQUEST_TYPE_STR,pRecord->TypeLength); 
+  }
+  else
+    return NDEF_ERROR;
+  
+  pRecord->PayloadLength = sizeof(pHandover->version);  
+  *pRecord->PayloadBufferAdd = pHandover->version;
+  
+  /* Don't write the record for now, additionnal Alternative Carriers to come as nested records. */
+  
+  return status;
+}
+
+
+/**
+  * @brief  This function adds an Alternative Carrier record to a Handover record using the data given in the AC structure.
+  * @param  pAC             Pointer on input AC structure. 
+  * @param  CarrierDataRef  String with the Alternative Carrier Data Reference (ID of the corresponding record in the NDEF message).
+  * @param  AuxDataRefID    Array with pointers to the Auxiliary Data References (as many as defined in pAC structure).
+  * @param  pRecord         Pointer on the Handover record to be filled with the AC data, must have been previously initialized with the NDEF_CreateHandover function.
+  * @retval NDEF_OK                     The Handover record has been updated with AC information.
+  * @retval NDEF_ERROR                  The Handover record cannot be updated with the AC information.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL  The internal buffer for records is too small to add the AC information.
+  */
+uint16_t NDEF_AddAlternativeCarrier(Ndef_Handover_alternative_carrier_t *pAC,char *CarrierDataRef, char **AuxDataRefID, sRecordInfo_t* pRecord, I2C* mi2cChannel )
+{
+  /* Specific buffer to prepare the Alternative Carrier record */
+  uint8_t NDEF_AlternativeCarrier_Buffer[NDEF_AC_BUFFER_SIZE];
+  
+  /* check that there is enough space in the buffers */
+  pAC->ac_record.PayloadLength = NDEF_GetACDataLength(pAC,CarrierDataRef,AuxDataRefID);
+  if(((pRecord->PayloadLength + pAC->ac_record.PayloadLength) > NDEF_RECORD_MAX_SIZE) ||
+      (pAC->ac_record.PayloadLength > NDEF_AC_BUFFER_SIZE))
+    return NDEF_ERROR_MEMORY_INTERNAL;
+
+  /* Use specific buffer to prepare the nested record */
+  uint8_t *pData =  NDEF_AlternativeCarrier_Buffer;
+  pAC->ac_record.PayloadBufferAdd = pData;
+  /* Following line is an alternative where the user must allocate the payload buffer of the ac_record:
+   * uint8_t* pData =   pAC->ac_record.PayloadBufferAdd ;
+   */
+  
+  if ((pRecord->PayloadBufferAdd == NULL) ||
+      (pRecord->PayloadLength == 0))
+      return NDEF_ERROR;
+
+  /* AC is not the first record */
+  pAC->ac_record.RecordFlags =   TNF_WellKnown;
+
+  pAC->ac_record.TypeLength = strlen(NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR);  
+  memcpy(pAC->ac_record.Type, NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR,pAC->ac_record.TypeLength);  
+
+  /* Length : cps byte + data ref length byte + auxiliary data ref count byte + data ref length */
+  *pData++ = pAC->cps & NDEF_HANDOVER_AC_CPS_MASK;
+  *pData++ = strlen(CarrierDataRef);
+  memcpy(pData, CarrierDataRef, strlen(CarrierDataRef));
+  pData += strlen(CarrierDataRef);
+  *pData++ = pAC->aux_data_ref_count;
+  
+  uint8_t AuxDataIndex;
+  for(AuxDataIndex = 0;AuxDataIndex<pAC->aux_data_ref_count;AuxDataIndex++)
+  {
+    *pData++ = strlen(AuxDataRefID[AuxDataIndex]);
+    memcpy(pData, AuxDataRefID[AuxDataIndex], strlen(AuxDataRefID[AuxDataIndex]));
+    pData += strlen(AuxDataRefID[AuxDataIndex]);
+  }
+  
+  /* Append the nested record right after the Handover record - increase its length accordingly */
+  pRecord->PayloadLength += NDEF_WriteRecord(&pAC->ac_record,pRecord->PayloadBufferAdd + pRecord->PayloadLength, mi2cChannel);
+  return NDEF_OK;
+}
+
+
+/**
+  * @brief  This function returns the length of an Alternative Carrier record data (excluding the record metadata).
+  * @param  pAC             Pointer on the input AC structure.
+  * @param  CarrierDataRef  String with the Alternative Carrier Data Reference.
+  * @param  AuxDataRefID    Array with the Auxiliary Data References (as many as defined in the pAC structure).
+  * @return The computed length in bytes corresponding to the provided Alternative Carrier information.
+  */
+uint32_t NDEF_GetACDataLength(Ndef_Handover_alternative_carrier_t *pAC,char *CarrierDataRef, char **AuxDataRefID)
+{
+  uint8_t AuxDataIndex;
+
+  /* First compute the Data length */
+  uint32_t length =       1 +                           // cps
+                          1 +                           // Carrier data ref length
+                          strlen(CarrierDataRef) +      // Carrier data ref
+                          1 +                           // auxiliary data count
+                          pAC->aux_data_ref_count * 1;  // auxiliary data lengths
+  
+  /* Then adds the length of the Auxiliary Data */
+  for(AuxDataIndex = 0;AuxDataIndex<pAC->aux_data_ref_count;AuxDataIndex++)
+  {
+     length += strlen(AuxDataRefID[AuxDataIndex]);
+  }
+
+  return length;
+}
+
+/**
+  * @brief  This function writes the Handover record into the memory.
+  * @param  pRecord   Pointer on the input Handover record.
+  * @param  pNdef     Pointer to a NDEF buffer (used to prepare the data before actual writing to the memory).
+  * @retval NDEF_OK   The memory has been written.
+  * @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_WriteHandover( sRecordInfo_t* pRecord , uint8_t* pNdef, I2C* mi2cChannel)
+{
+  /* Note: in case of Handover Select for no matching alternative carrier, the ME bit flag must be set by the caller */
+  
+  uint32_t Size = NDEF_WriteRecord(pRecord,pNdef, mi2cChannel);
+  return NDEF_WriteNDEF(Size,pNdef, mi2cChannel);
+}
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Handover.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Handover.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,116 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Bluetooth.h
+  * @author  MMY Application Team
+  * @version $Revision: 2475 $
+  * @date    $Date: 2016-06-24 12:11:59 +0200 (Fri, 24 Jun 2016) $
+  * @brief   This file help to manage Bluetooth NDEF file.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_HANDOVER_H
+#define __LIB_NDEF_HANDOVER_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+   
+/** @addtogroup lib_NDEF_Handover NDEF Handover library
+  * @{
+  */
+   
+/** @brief SIze of the buffer used to store an Alternative Carrier (allocated on the stack).
+  * @details 128 bytes should be enough, the specification recommends to use short URIs as AC identifiers.
+  */
+#define NDEF_AC_BUFFER_SIZE                 (128)
+
+/** @brief NFC Forum Well-Known Type name for a Handover Select record */
+#define NDEF_HANDOVER_SELECT_TYPE_STR       "Hs"
+/** @brief NFC Forum Well-Known Type name for a Handover Request record */
+#define NDEF_HANDOVER_REQUEST_TYPE_STR      "Hr"
+/** @brief NFC Forum Well-Known Type name for a Handover Select Select (ascii value) */
+#define NDEF_HANDOVER_SELECT_TYPE           0x4872
+/** @brief NFC Forum Well-Known Type name for a Handover Request record (ascii value) */
+#define NDEF_HANDOVER_REQUEST_TYPE          0x4873
+/** @brief NFC Forum Handover record implemented version */
+#define NDEF_HANDOVER_VERSION_1_2           0x12
+
+/** @brief NFC Forum Well-Known Type name for a Colision Resolution record */
+#define NDEF_HANDOVER_COLLISION_RESOLUTION_TYPE_STR     "cr"
+/** @brief NFC Forum Well-Known Type name for an Alternative Carrier record */
+#define NDEF_HANDOVER_ALTERNATIVE_CARRIER_TYPE_STR      "ac"
+
+/** @brief NFC Forum Power States values mask */
+#define NDEF_HANDOVER_AC_CPS_MASK (0x3)
+/** @brief Enumerates the NFC Forum Power States possible values */
+typedef enum {
+  NDEF_HANDOVER_AC_CPS_INACTIVE   = 0x0, /**< The HW for this Alternative Carrier has to be switch on before proceeding. */
+  NDEF_HANDOVER_AC_CPS_ACTIVE     = 0x1, /**< The HW for this Alternative Carrier is currently running. */
+  NDEF_HANDOVER_AC_CPS_ACTIVATING = 0x2, /**< The HW for this Alternative Carrier is being activated. */
+  NDEF_HANDOVER_AC_CPS_UNKNOWN    = 0x3  /**< The HW for this Alternative Carrier is unknown. */
+} Ndef_Handover_ac_cps_t;
+
+
+
+typedef struct {
+  uint8_t                       cps;                /**< Current Power State for this Alternative Carrier Hardware. */
+  sRecordInfo_t                 ac_record;          /**< The record structure used to store/build the Alternative Carrier record. */
+  uint8_t                       aux_data_ref_count; /**< The number of Auxiliary Data Reference for this Alternative Carrier. */
+  /* following fields are only used when reading NDEF */
+  uint8_t*                      aux_data_ref_start; /**< Internal field, managed by the library, to keep track of the Auxiliary Data Reference start address in the AC record. */
+  uint8_t*                      aux_data_ref_end;   /**< Internal field, managed by the library, to keep track of the Auxiliary Data Reference end address in the AC record. */
+} Ndef_Handover_alternative_carrier_t;
+
+
+typedef struct {
+  uint16_t  type;                                   /**< Handover type: could be Select or Request. */
+  uint8_t   version;                                /**< Version of the Handover record. */
+  /* following fields are only used when reading NDEF */
+  uint8_t   has_cr;                                 /**< Boolean, if true this Handover has a Collision Resolution nested record. */
+  uint16_t  cr_random_number;                       /**< Random number for the Collision Resolution. */
+  uint8_t   nb_alternative_carrier;                 /**< Number of Alternative Carrier nested records un this Handover. */
+  uint8_t*  ac_start;                               /**< Internal field, managed by the library, to keep track of the Alternative Carrier Reference Data start address in the Handover record. */
+  uint8_t*  ac_end;                                 /**< Internal field, managed by the library, to keep track of the Alternative Carrier Reference Data end address in the Handover record. */
+} Ndef_Handover_t;
+
+
+
+uint16_t NDEF_ReadHandover(sRecordInfo_t *pRecord ,  Ndef_Handover_t *pHandover );
+uint16_t NDEF_ReadAC( uint8_t ac_nb, Ndef_Handover_t *pHandover  , Ndef_Handover_alternative_carrier_t *pAC );
+uint16_t NDEF_ReadAuxData( uint8_t aux_data_nb, Ndef_Handover_alternative_carrier_t *pAC, sRecordInfo_t *pRecord );
+
+uint16_t NDEF_CreateHandover(Ndef_Handover_t  *pHandover, sRecordInfo_t* pRecord );
+uint16_t NDEF_AddAlternativeCarrier(Ndef_Handover_alternative_carrier_t *pAC, char* CarrierDataRef, char **AuxDataRefID, sRecordInfo_t* pRecord );
+uint16_t NDEF_WriteHandover( sRecordInfo_t* pRecord , uint8_t* pNdef, I2C* mi2cChannel);
+
+uint32_t NDEF_GetACDataLength(Ndef_Handover_alternative_carrier_t *pAC,char *CarrierDataRef, char **AuxDataRefID);
+
+
+
+/** @}
+  */
+
+#endif /* __LIB_NDEF_HANDOVER_H */
+
+/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_MyApp.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_MyApp.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,277 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_MyApp.c
+  * @author  MMY Application Team
+  * @version $Revision: 2762 $
+  * @date    $Date: 2016-08-10 16:40:40 +0200 (Wed, 10 Aug 2016) $
+  * @brief   This file help to manage the NDEF file of a private application.
+  ******************************************************************************
+  * @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_MyApp.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, gpio... </b>
+  */
+
+
+/** @addtogroup libNFC_FORUM
+  * @{
+  * @brief  This part of the library manage data which follow NFC forum organisation.
+  */
+
+/**
+  * @brief  This buffer contains the data send/received by TAG
+  */
+extern uint8_t NDEF_Buffer [];
+
+/** @defgroup libMyApp_Private_Functions
+  * @{
+  */
+
+static void NDEF_Extract_M24SRDiscoveryApp_Input( sRecordInfo_t *pRecordStruct, sMyAppInfo *pMyAppStruct );
+
+/**
+  * @brief  This function read the NDEF file and store application data in a structure.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pMyAppStruct : pointer on the structure to fill.
+  */
+static void NDEF_Extract_M24SRDiscoveryApp_Input( sRecordInfo_t *pRecordStruct, sMyAppInfo *pMyAppStruct )
+{
+  uint8_t* pPayload;
+  uint8_t* pLook4Word;
+  uint16_t BackGroundColor, FontColor;
+  uint8_t i;
+
+  /* Read record header */
+  pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+
+  /* initialize struct in case not matching found */
+  for( i = 0; i < 8; i++ )
+  {
+    /* Set the Back Color */
+    pMyAppStruct->LineX[i].BackGroundColor = 0xFFFF;
+    /* Set the Text Color */
+    pMyAppStruct->LineX[i].FontColor = 0x0000;
+    /* Set the line number */
+    pMyAppStruct->LineX[i].LineNb = i + 1; 
+    /* Set the line content */
+    memcpy( pMyAppStruct->LineX[i].String, "                    ", 20 );
+  }
+
+  pLook4Word = pPayload;
+
+  for( i = 0; i < 4; i++ )
+    {
+      pMyAppStruct->LedBlinkConf.LedConf[i] = *pLook4Word;
+      pLook4Word++;
+    }
+    pMyAppStruct->LedBlinkConf.Speed = *pLook4Word;
+    pLook4Word++;
+
+  for( i = 0; i < 8; i++ )
+  {
+      /* Set the line number */
+      pMyAppStruct->LineX[i].LineNb = *pLook4Word; 
+      pLook4Word++;
+      /* Set the Back Color */
+      BackGroundColor = (uint16_t)(*pLook4Word << 8);
+      BackGroundColor = BackGroundColor | (uint16_t)(*++pLook4Word );
+      pMyAppStruct->LineX[i].BackGroundColor = BackGroundColor;
+      pLook4Word++;
+      /* Set the Text Color */
+      FontColor = (uint16_t)(*pLook4Word << 8);
+      FontColor = FontColor | (uint16_t)(*++pLook4Word);
+      pMyAppStruct->LineX[i].FontColor = FontColor;
+      pLook4Word++;
+      /* Set the line content */
+      memcpy( pMyAppStruct->LineX[i].String, (char*)pLook4Word, 20 );
+      pLook4Word += 20;
+    }
+
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup libMyApp_Public_Functions
+  * @{
+  * @brief  This file is used to manage proprietary NDEF (stored or loaded in tag)
+  */ 
+
+/**
+  * @brief  This function read NDEF and retrieve Application information if any.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pMyAppStruct : pointer on the structure to fill.
+  * @retval NDEF_OK : NDEF file data read in the tag.
+  * @retval NDEF_ERROR : not able to read NDEF in tag.
+  */
+uint16_t NDEF_ReadMyApp( sRecordInfo_t *pRecordStruct, sMyAppInfo *pMyAppStruct )
+{
+  uint16_t status = NDEF_ERROR;
+
+  if( pRecordStruct->NDEF_Type == M24SR_DISCOVERY_APP_TYPE )
+  {
+    NDEF_Extract_M24SRDiscoveryApp_Input( pRecordStruct, pMyAppStruct );
+    status = NDEF_OK;
+  }
+  else 
+  {
+    status = NDEF_ERROR;
+  }
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the Application data given in the structure.
+  * @brief  Only used for debug purpose in this firmware version.
+  * @param  pMyAppStruct : pointer on structure that contain the application information.
+  * @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_WriteMyApp( sMyAppInfo *pMyAppStruct, I2C * mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR;
+  uint16_t DataSize;
+  uint32_t PayloadSize;
+  uint8_t  i;
+  uint8_t* pPayload;
+
+
+/* External Type Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- IL=0, CF=0 and SR=1 TNF=4 NFC Forum external type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  /* <---- Not Used  */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  /* <---- Not Used  */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  /* <---- Not Used  */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */  /* The payload will always be 5 + 25*8=205 bytes for this application */
+/*----------------------------------*/
+/*          ID LENGTH               */  /* <---- Not Used  */
+/*----------------------------------*/
+/*              TYPE                */  /* st.com:m24sr_discovery_democtrl */
+/*----------------------------------*/
+/*               ID                 */  /* <---- Not Used  */
+/************************************/
+
+ 
+  /* fill URI record header */
+  NDEF_Buffer[0] = 0xD4;   /* Record Flag */
+  NDEF_Buffer[1] = M24SR_DISCOVERY_APP_STRING_LENGTH;
+  NDEF_Buffer[2] = 0x00; /* Will be filled at the end when payload size is known */
+
+  memcpy( &NDEF_Buffer[3], M24SR_DISCOVERY_APP_STRING, M24SR_DISCOVERY_APP_STRING_LENGTH );
+
+  pPayload = &NDEF_Buffer[ 3 + M24SR_DISCOVERY_APP_STRING_LENGTH];
+  PayloadSize = 0;
+
+  /**************************************************************/
+  /* BLINK CONFIG data */
+
+  /* led 1 blinking */
+  *pPayload = 0x03;
+  pPayload++;
+  /* led 2 blinking */
+  *pPayload = 0x02;
+  pPayload++;
+  /* led 3 blinking */
+  *pPayload = 0x02;
+  pPayload++;
+  /* led 4 blinking */
+  *pPayload = 0x03;
+  pPayload++;
+  /* speed */
+  *pPayload = 0x03;
+  pPayload++;
+
+  PayloadSize += 5;
+
+  /**************************************************************/
+
+  /**************************************************************/
+  /* SCREEN config  data */
+  for( i = 0; i < 8; i++ )
+  {
+    /* Line number */
+    *pPayload = (uint8_t)(i + 1);
+    pPayload++;
+    /* Background color */
+    *pPayload = 0xFF - (0xFF/i);
+    pPayload++;
+    *pPayload = 0xFF - (0xFF/i);
+    pPayload++;
+    /* Font Color */
+    *pPayload = 0xFF/i;
+    pPayload++;
+    *pPayload = 0xFF/i;
+    pPayload++;
+    /* String */
+    memcpy( pPayload, "ABCDEFGHIJKLMNOPQRST", 20 );
+    pPayload += 20;
+
+    PayloadSize += 25;
+
+  }
+
+  NDEF_Buffer[2] = PayloadSize & 0x000000FF;
+
+  DataSize = PayloadSize + 5 + M24SR_DISCOVERY_APP_STRING_LENGTH;
+
+  /* Write NDEF */
+  status = NfcTag_WriteNDEF(  DataSize, NDEF_Buffer, mi2cChannel );
+
+
+  return status;
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_MyApp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_MyApp.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,81 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_MyApp.h
+  * @author  MMY Application Team
+  * @version $Revision: 2822 $
+  * @date    $Date: 2016-09-05 16:18:16 +0200 (Mon, 05 Sep 2016) $
+  * @brief   This file illustrate how to use M24SR with a proprietary protocol.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_MYAPP_H
+#define __LIB_NDEF_MYAPP_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+#define BLINK_CONFIG                    "<BLINK_CONFIG>"
+#define BLINK_CONFIG_STRING_SIZE        14
+#define BLINK_CONFIG_END                "<\\BLINK_CONFIG>"
+#define BLINK_CONFIG_END_STRING_SIZE    15
+
+#define LINE_DESCR                      "<LINE_DESCR>"
+#define LINE_DESCR_STRING_SIZE          12
+#define LINE_DESCR_END                  "<\\LINE_DESCR>"
+#define LINE_DESCR_END_STRING_SIZE      13
+
+#define BLINKING_NONE                   0x00
+#define BLINKING_SLOW                   0x01
+#define BLINKING_MEDIUM                 0x02
+#define BLINKING_FAST                   0x03
+
+#define MYAPP_NB_LINES ((uint8_t)8)
+#define MYAPP_LED_CONF_INITAL_STATE ((uint8_t) 0x1)
+#define MYAPP_LED_CONF_BLINKING     ((uint8_t) 0x2)
+
+typedef struct
+{
+  uint8_t LedConf[4];
+  uint8_t Speed;
+}sLedBlinkConfig;
+
+typedef struct
+{
+  uint8_t LineNb;
+  uint16_t BackGroundColor;
+  uint16_t FontColor;
+  char String[20];
+}sLineConfig;
+
+typedef struct
+{
+  sLedBlinkConfig LedBlinkConf;
+  sLineConfig LineX[MYAPP_NB_LINES];
+}sMyAppInfo;
+
+uint16_t NDEF_ReadMyApp( sRecordInfo_t *pRecordStruct, sMyAppInfo *pMyAppStruct );
+uint16_t NDEF_WriteMyApp( sMyAppInfo *pMyAppStruct, I2C * mi2cChannel );
+
+#endif /* __LIB_NDEF_MYAPP_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_SMS.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_SMS.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,370 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_SMS.c
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @brief   This file help to manage NDEF file that represent SMS.
+ ******************************************************************************
+  * @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_SMS.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.
+  */
+
+/**
+ * @brief  This buffer contains the data send/received by TAG
+ */
+extern uint8_t NDEF_Buffer [];
+
+/** @defgroup libSMS_Private_Functions
+  * @{
+  */
+
+static void NDEF_FillSMSStruct( uint8_t* pPayload, uint32_t PayloadSize, sSMSInfo *pSMSStruct );
+static void NDEF_ReadURI_SMS( sRecordInfo_t *pRecordStruct, sSMSInfo *pSMSStruct );
+
+/**
+  * @brief  This function fill SMS structure with information of NDEF message.
+  * @param  pPayload : pointer on the payload data of the NDEF message.
+  * @param  PayloadSize : number of data in the payload.
+  * @param  pSMSStruct : pointer on the structure to fill.
+  */
+static void NDEF_FillSMSStruct( uint8_t* pPayload, uint32_t PayloadSize, sSMSInfo *pSMSStruct )
+{
+  uint8_t* pLastByteAdd, *pLook4Word, *pEndString;
+  char* pKeyWord;
+  uint32_t SizeOfKeyWord;
+  pEndString = 0;
+
+  pKeyWord = SMS_TYPE_STRING;
+  SizeOfKeyWord = SMS_TYPE_STRING_LENGTH;
+
+  /* First character force to NULL in case not matching found */
+  *pSMSStruct->PhoneNumber = 0;
+  *pSMSStruct->Message = 0;
+
+  /* Interesting information are stored before picture if any */
+  /* Moreover picture is not used in this demonstration SW */
+  pLastByteAdd = (uint8_t*)(pPayload + PayloadSize);
+
+  pLook4Word = pPayload;
+  while( memcmp( pLook4Word, pKeyWord, SizeOfKeyWord ) && (pLook4Word < pLastByteAdd) )
+  {
+    pLook4Word++;
+  }
+
+  /* Retrieve phone number */
+  if( pLook4Word != pLastByteAdd )
+  {
+    pLook4Word += SizeOfKeyWord;
+    pEndString = pLook4Word;
+    while( memcmp( pEndString, URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH ) && (pEndString < pLastByteAdd) )
+    {
+      pEndString++;
+    }
+    if( pEndString != pLastByteAdd )
+    {
+      memcpy( pSMSStruct->PhoneNumber, pLook4Word, pEndString-pLook4Word );
+      /* add end of string character */
+      pSMSStruct->PhoneNumber[pEndString-pLook4Word] = 0;
+    }
+  }
+  pEndString += URI_FIRST_DATA_END_LENGTH;
+  pLook4Word = pEndString;
+
+  /* check if e-mail subject is present */
+  if( !memcmp( pLook4Word, MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH ) )
+  {
+    pEndString += MESSAGE_BEGIN_STRING_LENGTH;
+    /* Retrieve message */
+    memcpy( pSMSStruct->Message, pEndString, PayloadSize - (pEndString - pPayload) );
+    /* add end of string character */
+    pSMSStruct->Message[PayloadSize-(pEndString-pPayload)] = 0;
+  }
+}
+
+/**
+  * @brief  This function read the SMS and store data in a structure.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pSMSStruct : pointer on the structure to fill.
+  */
+static void NDEF_ReadURI_SMS( sRecordInfo_t *pRecordStruct, sSMSInfo *pSMSStruct )
+{
+  uint8_t* pPayload;
+  uint32_t PayloadSize;
+
+  PayloadSize = pRecordStruct->PayloadLength;
+
+  /* Read record header */
+  pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+
+  if( pRecordStruct->NDEF_Type == URI_SMS_TYPE )
+    NDEF_FillSMSStruct( pPayload , PayloadSize, pSMSStruct );
+
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup libSMS_Public_Functions
+  * @{
+  * @brief  This file is used to manage SMS (stored or loaded in tag)
+  */ 
+
+/**
+  * @brief  This function read NDEF and retrieve SMS information if any.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pSMSStruct : pointer on the structure to fill.
+  * @retval NDEF_OK : SMS information from NDEF have been retrieve.
+  * @retval NDEF_ERROR : Not able to retrieve SMS information.
+  */
+uint16_t NDEF_ReadSMS( sRecordInfo_t *pRecordStruct, sSMSInfo *pSMSStruct )
+{
+  uint16_t status = NDEF_ERROR;
+  sRecordInfo_t *pSPRecordStruct;
+  uint32_t PayloadSize, RecordPosition;
+  uint8_t* pData;
+
+  if( pRecordStruct->NDEF_Type == URI_SMS_TYPE )
+  {
+    NDEF_ReadURI_SMS( pRecordStruct, pSMSStruct );
+    status = NDEF_OK;
+  }
+  else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE )
+  {
+    for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ )
+    {
+      pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition];
+      if( pSPRecordStruct->NDEF_Type == URI_SMS_TYPE )
+      {
+        NDEF_ReadURI_SMS( pSPRecordStruct, pSMSStruct );
+        status = NDEF_OK;
+      }
+      if( pSPRecordStruct->NDEF_Type == TEXT_TYPE )
+      {
+        PayloadSize = pSPRecordStruct->PayloadLength;
+
+        /* The instruction content the UTF-8 language code that is not used here */
+        pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd;
+        PayloadSize -= *pData + 1; /* remove not usefull data */
+        pData += *pData + 1; /* set pointer on usefull data */
+
+        memcpy( pSMSStruct->Information, pData, PayloadSize );
+        /* add end of string character */
+        pSMSStruct->Information[PayloadSize] = 0;
+      }
+    }
+  }
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the SMS data given in the structure.
+  * @param  pSMSStruct : pointer on structure that contain the SMS information.
+  * @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_WriteSMS( sSMSInfo *pSMSStruct, I2C* mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR, Offset = 0;
+
+  NDEF_PrepareSMSMessage( pSMSStruct, NDEF_Buffer, &Offset );
+
+  status = NfcTag_WriteNDEF( Offset , NDEF_Buffer, mi2cChannel );
+
+  return status;
+}
+
+/**
+  * @brief  This function write the NDEF file with the SMS data given in the structure.
+  * @param  pSMSStruct : pointer on structure that contain the SMS information.
+  * @param  pNDEFMessage : pointer on the NDEF message.
+  * @param  size : to store the size of the NDEF message generated.
+  */
+void NDEF_PrepareSMSMessage( sSMSInfo *pSMSStruct, uint8_t *pNDEFMessage, uint16_t *size )
+{
+  uint16_t Offset = 0;
+  uint32_t smsSize = 0;
+  uint32_t infoSize= 0;
+  uint32_t totalSize = 0;
+
+  /* SMS is an URI but can be included in a smart poster to add text to give instruction to user for instance */
+
+  /* SMS (smart poster) Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*          ID LENGTH               */  /* <---- Not Used  */
+/*----------------------------------*/
+/*              TYPE                */
+/*----------------------------------*/
+/*               ID                 */  /* <---- Not Used  */
+/************************************/
+
+  /* SMS : 1+sms:+tel+1+body=+message */
+  smsSize = 1 + SMS_TYPE_STRING_LENGTH + strlen(pSMSStruct->PhoneNumber) + URI_FIRST_DATA_END_LENGTH + 
+            MESSAGE_BEGIN_STRING_LENGTH + strlen(pSMSStruct->Message);
+
+  /* Check if a Smart poster is needed */
+  if( pSMSStruct->Information[0] != '\0' )
+  {
+    /* Info : 1+2+info */
+    infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen(pSMSStruct->Information);
+    /* Total */
+    totalSize = 4 + smsSize + 4 + infoSize;
+    if( smsSize > 255 ) totalSize += 3; /* Normal Email size */
+    if( infoSize > 255 ) totalSize += 3;  /* Normal Info size */
+
+    /* SmartPoster header */
+    if( totalSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0xC1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = totalSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0xD1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)totalSize;
+    }
+    memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH );
+    Offset += SMART_POSTER_TYPE_STRING_LENGTH;
+  }
+
+  /* SMS header */
+  pNDEFMessage[Offset] = 0x81;
+  if( smsSize < 256 ) pNDEFMessage[Offset] |= 0x10;                      // Set the SR bit
+  if( pSMSStruct->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40; // Set the ME bit
+  Offset++;
+
+  pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH;
+  if( smsSize > 255 )
+  {
+    pNDEFMessage[Offset++] = (smsSize & 0xFF000000) >> 24;
+    pNDEFMessage[Offset++] = (smsSize & 0x00FF0000) >> 16;
+    pNDEFMessage[Offset++] = (smsSize & 0x0000FF00) >> 8;
+    pNDEFMessage[Offset++] = smsSize & 0x000000FF;
+  }
+  else
+  {
+    pNDEFMessage[Offset++] = (uint8_t)smsSize;
+  }
+  memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH );
+  Offset += URI_TYPE_STRING_LENGTH;
+
+  /* SMS payload */
+  pNDEFMessage[Offset++] = URI_ID_0x00;
+  memcpy( &pNDEFMessage[Offset], SMS_TYPE_STRING, SMS_TYPE_STRING_LENGTH );
+  Offset += SMS_TYPE_STRING_LENGTH;
+  memcpy( &pNDEFMessage[Offset], pSMSStruct->PhoneNumber, strlen(pSMSStruct->PhoneNumber) );
+  Offset += strlen( pSMSStruct->PhoneNumber );
+  memcpy( &pNDEFMessage[Offset], URI_FIRST_DATA_END, URI_FIRST_DATA_END_LENGTH );
+  Offset += URI_FIRST_DATA_END_LENGTH;
+
+  memcpy( &pNDEFMessage[Offset], MESSAGE_BEGIN_STRING, MESSAGE_BEGIN_STRING_LENGTH );
+  Offset += MESSAGE_BEGIN_STRING_LENGTH;
+  memcpy( &pNDEFMessage[Offset], pSMSStruct->Message, strlen(pSMSStruct->Message) );
+  Offset += strlen( pSMSStruct->Message );
+
+  /* Information header */
+  if( pSMSStruct->Information[0] != '\0' )
+  {
+    if( infoSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0x41;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = infoSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0x51;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)infoSize;
+    }
+
+    memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH );
+    Offset += TEXT_TYPE_STRING_LENGTH;
+    pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */
+    memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH );
+    Offset += ISO_ENGLISH_CODE_STRING_LENGTH;
+
+    /* Information payload */
+    memcpy( &pNDEFMessage[Offset], pSMSStruct->Information, strlen(pSMSStruct->Information) );
+    Offset += strlen( pSMSStruct->Information );
+  }
+
+  *size = (uint16_t)(Offset);
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_SMS.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_SMS.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,53 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_SMS.h
+  * @author  MMY Application Team
+  * @version $Revision: 2475 $
+  * @date    $Date: 2016-06-24 12:11:59 +0200 (Fri, 24 Jun 2016) $
+  * @brief   This file help to manage SMS NDEF file.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_SMS_H
+#define __LIB_NDEF_SMS_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+
+typedef struct
+{
+  char PhoneNumber[16];
+  char Message[400];
+  char Information[400];
+}sSMSInfo;
+
+uint16_t NDEF_ReadSMS( sRecordInfo_t *pRecordStruct, sSMSInfo *pSMSStruct );
+uint16_t NDEF_WriteSMS( sSMSInfo *pSMSStruct, I2C* mi2cChannel );
+void NDEF_PrepareSMSMessage( sSMSInfo *pSMSStruct, uint8_t *pNDEFMessage, uint16_t *size );
+
+
+#endif /* __LIB_NDEF_SMS_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Text.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Text.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,175 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Text.h
+  * @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 Text NDEF file.
+   ******************************************************************************
+  * @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_Text.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.
+  */
+
+/**
+  * @brief  This buffer contains the data send/received by TAG
+  */
+extern uint8_t NDEF_Buffer [];
+
+/**
+  * @}
+  */
+
+/** @defgroup libEmail_Public_Functions
+  * @{
+  * @brief  This file is used to manage Email (stored or loaded in tag)
+  */ 
+
+/**
+  * @brief  This function write the text in the TAG.
+  * @param  text : text to write.
+  * @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_WriteText( char *text, I2C * mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR;
+  uint32_t textSize, Offset = 0;
+
+ 
+  /* TEXT : 1+en+message */
+  textSize = 3 + strlen(text);
+
+  /* TEXT header */
+  NDEF_Buffer[Offset] = 0xD1;
+  if( textSize < 256 ) NDEF_Buffer[Offset] |= 0x10;                   // Set the SR bit
+  Offset++;
+
+  NDEF_Buffer[Offset++] = TEXT_TYPE_STRING_LENGTH;
+  if( textSize > 255 )
+  {
+    NDEF_Buffer[Offset++] = (textSize & 0xFF000000) >> 24;
+    NDEF_Buffer[Offset++] = (textSize & 0x00FF0000) >> 16;
+    NDEF_Buffer[Offset++] = (textSize & 0x0000FF00) >> 8;
+    NDEF_Buffer[Offset++] = textSize & 0x000000FF;
+  }
+  else
+  {
+    NDEF_Buffer[Offset++] = (uint8_t)textSize;
+  }
+  memcpy( &NDEF_Buffer[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH );
+  Offset += TEXT_TYPE_STRING_LENGTH;
+
+  /* TEXT payload */
+  NDEF_Buffer[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH;
+  memcpy( &NDEF_Buffer[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH );
+  Offset += ISO_ENGLISH_CODE_STRING_LENGTH;
+
+  memcpy( &NDEF_Buffer[Offset], text, strlen(text) );
+  Offset += strlen(text);
+
+  status = NfcTag_WriteNDEF( Offset , NDEF_Buffer, mi2cChannel );
+
+  return status;
+}
+
+
+/**
+  * @brief  This function the Text information in a record if any.
+  * @param  pRecordStruct Pointer on a NDEF record structure.
+  * @param  pText A pointer on a text information structure, used to return the text & its metadata.
+  * @retval NDEF_OK                    Text information has been retrieved.
+  * @retval NDEF_ERROR                 The record is not a Text record.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL Language code or Text length is too big for the buffers.
+  */
+uint16_t NDEF_ReadText( sRecordInfo_t *pRecordStruct, NDEF_Text_info_t *pText )
+{
+  uint16_t status = NDEF_ERROR;
+
+  if( pRecordStruct->NDEF_Type == TEXT_TYPE )
+  {
+    /* Get the text metadata (status byte (encoding & language code length) + language code) */
+    NDEF_Text_metadata_t *text_record_info = (NDEF_Text_metadata_t *)pRecordStruct->PayloadBufferAdd;
+        
+    uint32_t text_length = pRecordStruct->PayloadLength           /* record length */
+                           - text_record_info->language_length    /* minus language code length */
+                           - sizeof(uint8_t);                     /* minus the status byte length */
+    
+    if((text_record_info->language_length >= NDEF_TEXT_LANGUAGE_CODE_MAX_LENGTH) || 
+        (text_length >= NDEF_TEXT_MAX_LENGTH))
+    {
+      /* One of the text info structure buffer is too small */
+      return NDEF_ERROR_MEMORY_INTERNAL;
+    }
+    
+    /* Retrieve the encoding */
+    pText->encoding =  (NDEF_Text_encoding_t)text_record_info->encoding;
+
+    /* Save the language code string (adding null char at the end) */
+    memcpy(&pText->language_code,text_record_info->language,text_record_info->language_length);
+    pText->language_code[text_record_info->language_length] = '\0';
+    
+    /* Copy the text string itself (adding null char at the end) */
+    memcpy(&pText->text, text_record_info->language + text_record_info->language_length,text_length);
+    pText->text[text_length] = '\0';
+    
+    status = NDEF_OK;
+  }
+  else 
+  {
+    /* Not a text record, exit in error */
+    status = NDEF_ERROR;
+  }
+
+  return status;
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Text.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Text.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,70 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Text.h
+  * @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 Text NDEF file.
+   ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_TEXT_H
+#define __LIB_NDEF_TEXT_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+/** @brief NDEF Text buffer length. */
+#define NDEF_TEXT_MAX_LENGTH 40  
+/** @brief NDEF Language code buffer length. */
+#define NDEF_TEXT_LANGUAGE_CODE_MAX_LENGTH 10  
+
+/** @brief NDEF Text encoding possible values. */
+typedef enum {
+  NDEF_TEXT_UTF8  = 0,
+  NDEF_TEXT_UTF16 = 1
+} NDEF_Text_encoding_t;
+
+/** @brief This structure is used to handle information from a NDEF Text record. */
+typedef struct {
+  NDEF_Text_encoding_t  encoding;                                           /**< metadata: UTF-8 / UTF-16. */
+  char                  language_code[NDEF_TEXT_LANGUAGE_CODE_MAX_LENGTH];  /**< metadata: Language code as specified by IANA. */
+  char                  text[NDEF_TEXT_MAX_LENGTH];                         /**< The text itself. */
+} NDEF_Text_info_t;  
+
+
+/** @brief This structure is used to parse the raw data from a text record and access its metadata. */
+typedef struct {
+  uint8_t  language_length:4; /**< Language code length. */
+  uint8_t  rfu:3;             /**< reserved for futur usage */
+  uint8_t  encoding:1;        /**< UTF-8 (0) or UTF-16 (1) encoding. */
+  char     language[1];       /**< IANA language code. */
+} NDEF_Text_metadata_t;  
+ 
+uint16_t NDEF_WriteText( char *text, I2C * mi2cChannel );
+uint16_t NDEF_ReadText( sRecordInfo_t *pRecordStruct, NDEF_Text_info_t *pText );
+
+
+#endif /* __LIB_NDEF_TEXT_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_URI.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_URI.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,538 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_URI.c
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @brief   This file help to manage NDEF file that represent URI.
+  ******************************************************************************
+  * @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_URI.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.
+  */
+
+/**
+  * @brief  This buffer contains the data send/received by TAG
+  */
+extern uint8_t NDEF_Buffer [];
+
+/** @defgroup libURI_Private_Functions
+  * @{
+  */
+
+static void NDEF_Parse_WellKnowType( sRecordInfo_t *pRecordStruct, sURI_Info* pURI );
+
+/**
+  * @brief  This function read the URI information and store data in a structure.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pURI : pointer on the structure to fill.
+  */
+static void NDEF_Parse_WellKnowType( sRecordInfo_t *pRecordStruct, sURI_Info* pURI )
+{
+  uint32_t PayloadSize;
+  uint8_t Offset;
+  uint8_t* pPayload;
+
+  pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+
+  switch( *pPayload )
+  {
+    case URI_ID_0x01:
+      memcpy( pURI->protocol, URI_ID_0x01_STRING, strlen(URI_ID_0x01_STRING) );
+      Offset = strlen( URI_ID_0x01_STRING );
+      break;
+
+    case URI_ID_0x02:
+      memcpy( pURI->protocol, URI_ID_0x02_STRING, strlen(URI_ID_0x02_STRING) );
+      Offset = strlen( URI_ID_0x02_STRING );
+      break;
+    case URI_ID_0x03:
+      memcpy( pURI->protocol, URI_ID_0x03_STRING, strlen(URI_ID_0x03_STRING) );
+      Offset = strlen( URI_ID_0x03_STRING );
+      break;
+
+    case URI_ID_0x04:
+      memcpy( pURI->protocol, URI_ID_0x04_STRING, strlen(URI_ID_0x04_STRING) );
+      Offset = strlen( URI_ID_0x04_STRING );
+      break;
+
+    case URI_ID_0x05:
+      memcpy( pURI->protocol, URI_ID_0x05_STRING, strlen(URI_ID_0x05_STRING) );
+      Offset = strlen( URI_ID_0x05_STRING );
+      break;
+
+    case URI_ID_0x06:
+      memcpy( pURI->protocol, URI_ID_0x06_STRING, strlen(URI_ID_0x06_STRING) );
+      Offset = strlen( URI_ID_0x06_STRING );
+      break;
+
+    case URI_ID_0x07:
+      memcpy( pURI->protocol, URI_ID_0x07_STRING, strlen(URI_ID_0x07_STRING) );
+      Offset = strlen( URI_ID_0x07_STRING );
+      break;
+
+    case URI_ID_0x08:
+      memcpy( pURI->protocol, URI_ID_0x08_STRING, strlen(URI_ID_0x08_STRING) );
+      Offset = strlen( URI_ID_0x08_STRING );
+      break;
+
+    case URI_ID_0x09:
+      memcpy( pURI->protocol, URI_ID_0x09_STRING, strlen(URI_ID_0x09_STRING) );
+      Offset = strlen( URI_ID_0x09_STRING );
+      break;
+
+    case URI_ID_0x0A:
+      memcpy( pURI->protocol, URI_ID_0x0A_STRING, strlen(URI_ID_0x0A_STRING) );
+      Offset = strlen( URI_ID_0x0A_STRING );
+      break;
+
+    case URI_ID_0x0B:
+      memcpy( pURI->protocol, URI_ID_0x0B_STRING, strlen(URI_ID_0x0B_STRING) );
+      Offset = strlen( URI_ID_0x0B_STRING );
+      break;
+
+    case URI_ID_0x0C:
+      memcpy( pURI->protocol, URI_ID_0x0C_STRING, strlen(URI_ID_0x0C_STRING) );
+      Offset = strlen( URI_ID_0x0C_STRING );
+      break;
+
+    case URI_ID_0x0D:
+      memcpy( pURI->protocol, URI_ID_0x0D_STRING, strlen(URI_ID_0x0D_STRING) );
+      Offset = strlen( URI_ID_0x0D_STRING );
+      break;
+
+    case URI_ID_0x0E:
+      memcpy( pURI->protocol, URI_ID_0x0E_STRING, strlen(URI_ID_0x0E_STRING) );
+      Offset = strlen( URI_ID_0x0E_STRING );
+      break;
+
+    case URI_ID_0x0F:
+      memcpy( pURI->protocol, URI_ID_0x0F_STRING, strlen(URI_ID_0x0F_STRING) );
+      Offset = strlen( URI_ID_0x0F_STRING );
+      break;
+
+    case URI_ID_0x10:
+      memcpy( pURI->protocol, URI_ID_0x10_STRING, strlen(URI_ID_0x10_STRING) );
+      Offset = strlen( URI_ID_0x10_STRING );
+      break;
+
+    case URI_ID_0x11:
+      memcpy( pURI->protocol, URI_ID_0x11_STRING, strlen(URI_ID_0x11_STRING) );
+      Offset = strlen( URI_ID_0x11_STRING );
+      break;
+
+    case URI_ID_0x12:
+      memcpy( pURI->protocol, URI_ID_0x12_STRING, strlen(URI_ID_0x12_STRING) );
+      Offset = strlen( URI_ID_0x12_STRING );
+      break;
+
+    case URI_ID_0x13:
+      memcpy( pURI->protocol, URI_ID_0x13_STRING, strlen(URI_ID_0x13_STRING) );
+      Offset = strlen( URI_ID_0x13_STRING );
+      break;
+
+    case URI_ID_0x14:
+      memcpy( pURI->protocol, URI_ID_0x14_STRING, strlen(URI_ID_0x14_STRING) );
+      Offset = strlen( URI_ID_0x14_STRING );
+      break;
+
+    case URI_ID_0x15:
+      memcpy( pURI->protocol, URI_ID_0x15_STRING, strlen(URI_ID_0x15_STRING) );
+      Offset = strlen( URI_ID_0x15_STRING );
+      break;
+
+    case URI_ID_0x16:
+      memcpy( pURI->protocol, URI_ID_0x16_STRING, strlen(URI_ID_0x16_STRING) );
+      Offset = strlen( URI_ID_0x16_STRING );
+      break;
+
+    case URI_ID_0x17:
+      memcpy( pURI->protocol, URI_ID_0x17_STRING, strlen(URI_ID_0x17_STRING) );
+      Offset = strlen( URI_ID_0x17_STRING );
+      break;
+
+    case URI_ID_0x18:
+      memcpy( pURI->protocol, URI_ID_0x18_STRING, strlen(URI_ID_0x18_STRING) );
+      Offset = strlen( URI_ID_0x18_STRING );
+      break;
+
+    case URI_ID_0x19:
+      memcpy( pURI->protocol, URI_ID_0x19_STRING, strlen(URI_ID_0x19_STRING) );
+      Offset = strlen( URI_ID_0x19_STRING );
+      break;
+
+    case URI_ID_0x1A:
+      memcpy( pURI->protocol, URI_ID_0x1A_STRING, strlen(URI_ID_0x1A_STRING) );
+      Offset = strlen( URI_ID_0x1A_STRING );
+      break;
+
+    case URI_ID_0x1B:
+      memcpy( pURI->protocol, URI_ID_0x1B_STRING, strlen(URI_ID_0x1B_STRING) );
+      Offset = strlen( URI_ID_0x1B_STRING );
+      break;
+
+    case URI_ID_0x1C:
+      memcpy( pURI->protocol, URI_ID_0x1C_STRING, strlen(URI_ID_0x1C_STRING) );
+      Offset = strlen( URI_ID_0x1C_STRING );
+      break;
+
+    case URI_ID_0x1D:
+      memcpy( pURI->protocol, URI_ID_0x1D_STRING, strlen(URI_ID_0x1D_STRING) );
+      Offset = strlen( URI_ID_0x1D_STRING );
+      break;
+
+    case URI_ID_0x1E:
+      memcpy( pURI->protocol, URI_ID_0x1E_STRING, strlen(URI_ID_0x1E_STRING) );
+      Offset = strlen( URI_ID_0x1E_STRING );
+      break;
+
+    case URI_ID_0x1F:
+      memcpy( pURI->protocol, URI_ID_0x1F_STRING, strlen(URI_ID_0x1F_STRING) );
+      Offset = strlen( URI_ID_0x1F_STRING );
+      break;
+
+    case URI_ID_0x20:
+      memcpy( pURI->protocol, URI_ID_0x20_STRING, strlen(URI_ID_0x20_STRING) );
+      Offset = strlen( URI_ID_0x20_STRING );
+      break;
+
+    case URI_ID_0x21:
+      memcpy( pURI->protocol, URI_ID_0x21_STRING, strlen(URI_ID_0x21_STRING) );
+      Offset = strlen( URI_ID_0x21_STRING );
+      break;
+
+    case URI_ID_0x22:
+      memcpy( pURI->protocol, URI_ID_0x22_STRING, strlen(URI_ID_0x22_STRING) );
+      Offset = strlen( URI_ID_0x22_STRING );
+      break;
+
+    case URI_ID_0x23:
+      memcpy( pURI->protocol, URI_ID_0x23_STRING, strlen(URI_ID_0x23_STRING) );
+      Offset = strlen( URI_ID_0x23_STRING );
+      break;
+    default:
+      Offset = 0;
+      /* Should not happened */
+      break;
+  }
+  /* add end of string character */
+  pURI->protocol[Offset] = '\0';
+
+  pPayload++; /* go after well know byte */
+
+  PayloadSize = pRecordStruct->PayloadLength;
+
+  PayloadSize = PayloadSize - 1; /* remove well know byte */
+
+  memcpy( pURI->URI_Message, pPayload, PayloadSize );
+  /* add end of string character */
+  pURI->URI_Message[PayloadSize] = '\0';
+
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup libURI_Public_Functions
+  * @{
+  * @brief  This file is used to manage URI (stored or loaded in tag)
+  */ 
+
+/**
+  * @brief  This function read NDEF and retrieve URI information if any.
+  * @param  pRecordStruct : Pointer on the record structure.
+  * @param  pURI : pointer on the structure to fill.
+  * @retval NDEF_OK : URI information from NDEF have been retrieved.
+  * @retval NDEF_ERROR : Not able to retrieve URI information.
+  */
+uint16_t NDEF_ReadURI( sRecordInfo_t *pRecordStruct, sURI_Info *pURI )
+{
+  uint16_t status = NDEF_ERROR;
+  sRecordInfo_t *pSPRecordStruct;
+  uint32_t PayloadSize, RecordPosition;
+  uint8_t* pData;
+
+  if( pRecordStruct->NDEF_Type == WELL_KNOWN_ABRIDGED_URI_TYPE )
+  {
+    NDEF_Parse_WellKnowType( pRecordStruct, pURI );
+    status = NDEF_OK;
+  }
+  else if( pRecordStruct->NDEF_Type == SMARTPOSTER_TYPE )
+  {
+    for( RecordPosition = 0; RecordPosition < pRecordStruct->NbOfRecordInSPPayload; RecordPosition++ )
+    {
+      pSPRecordStruct = pRecordStruct->SPRecordStructAdd[RecordPosition];
+      if( pSPRecordStruct->NDEF_Type == WELL_KNOWN_ABRIDGED_URI_TYPE )
+      {
+        NDEF_Parse_WellKnowType( pSPRecordStruct, pURI );
+        status = NDEF_OK;
+      }
+      if( pSPRecordStruct->NDEF_Type == TEXT_TYPE )
+      {
+        PayloadSize = pSPRecordStruct->PayloadLength;
+
+        /* The instruction content the UTF-8 language code that is not used here */
+        pData = (uint8_t*)pSPRecordStruct->PayloadBufferAdd;
+        PayloadSize -= *pData + 1; /* remove not usefull data */
+        pData += *pData + 1;
+
+        memcpy( pURI->Information, pData, PayloadSize );
+      }
+    }
+  }
+  else 
+  {
+    status = NDEF_ERROR;
+  }
+
+  return status;
+}
+
+/**
+  * @brief  This function prepare the NDEF message with the URI data given in the structure.
+  * @param  pURI : pointer on structure that contain the URI information.
+  * @param  pNDEFMessage : pointer on the NDEF message.
+  * @param  size : to store the size of the NDEF message generated.
+  */
+void NDEF_PrepareURIMessage( sURI_Info *pURI, uint8_t *pNDEFMessage, uint16_t *size )
+{
+  uint32_t uriSize, totalSize, Offset = 0;
+  uint32_t infoSize = 0;
+  char type;
+
+  /* An URI can be included in a smart poster to add text to give instruction to user for instance */
+
+  /* URI (smart poster) Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- CF=0, IL=0 and SR=1 TNF=1 NFC Forum Well-known type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */  /* <---- Used only if SR=0 */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*          ID LENGTH               */  /* <---- Not Used  */
+/*----------------------------------*/
+/*              TYPE                */
+/*----------------------------------*/
+/*               ID                 */  /* <---- Not Used  */
+/************************************/
+
+  /* We need to know the URI type in order to define if an abreviation is available */
+  type = getUriType( pURI->protocol );
+
+  /* URI : 1+URI for abreviate protocol*/
+  if( type != URI_ID_0x00 )
+    uriSize = 1 + strlen(pURI->URI_Message);
+  else /*: 1+protocol+URI else*/
+    uriSize = 1 + strlen(pURI->protocol) + strlen(pURI->URI_Message);
+
+  /* Check if a Smart poster is needed */
+  if( pURI->Information[0] != '\0' )
+  {
+    /* Info : 1+2+info */
+    infoSize = 1 + ISO_ENGLISH_CODE_STRING_LENGTH + strlen(pURI->Information);
+    /* Total */
+    totalSize = 4 + uriSize + 4 + infoSize;
+    if( uriSize > 255 ) totalSize += 3;   /* Normal URI size */
+    if( infoSize > 255 ) totalSize += 3;  /* Normal Info size */
+
+    /* SmartPoster header */
+    if( totalSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0xC1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (totalSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (totalSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (totalSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = totalSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0xD1;
+      pNDEFMessage[Offset++] = SMART_POSTER_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)totalSize;
+    }
+    memcpy( &pNDEFMessage[Offset], SMART_POSTER_TYPE_STRING, SMART_POSTER_TYPE_STRING_LENGTH );
+    Offset += SMART_POSTER_TYPE_STRING_LENGTH;
+  }
+
+  /* URI header */
+  pNDEFMessage[Offset] = 0x81;
+  if( uriSize < 256 ) pNDEFMessage[Offset] |= 0x10;                      // Set the SR bit
+  if( pURI->Information[0] == '\0' ) pNDEFMessage[Offset] |= 0x40;       // Set the ME bit
+  Offset++;
+
+  pNDEFMessage[Offset++] = URI_TYPE_STRING_LENGTH;
+  if( uriSize > 255 )
+  {
+    pNDEFMessage[Offset++] = (uriSize & 0xFF000000) >> 24;
+    pNDEFMessage[Offset++] = (uriSize & 0x00FF0000) >> 16;
+    pNDEFMessage[Offset++] = (uriSize & 0x0000FF00) >> 8;
+    pNDEFMessage[Offset++] = uriSize & 0x000000FF;
+  }
+  else
+  {
+    pNDEFMessage[Offset++] = (uint8_t)uriSize;
+  }
+  memcpy( &pNDEFMessage[Offset], URI_TYPE_STRING, URI_TYPE_STRING_LENGTH );
+  Offset += URI_TYPE_STRING_LENGTH;
+
+  pNDEFMessage[Offset++] = type;
+  if( type == URI_ID_0x00 ) // No abreviation
+  {
+    memcpy( &pNDEFMessage[Offset], pURI->protocol, strlen(pURI->protocol) );
+    Offset += strlen(pURI->protocol);
+  }
+
+  memcpy( &pNDEFMessage[Offset], pURI->URI_Message, strlen(pURI->URI_Message) );
+  Offset += strlen(pURI->URI_Message);
+
+  /* Information header */
+  if( pURI->Information[0] != '\0' )
+  {
+    if( infoSize > 255 )
+    {
+      pNDEFMessage[Offset++] = 0x41;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (infoSize & 0xFF000000) >> 24;
+      pNDEFMessage[Offset++] = (infoSize & 0x00FF0000) >> 16;
+      pNDEFMessage[Offset++] = (infoSize & 0x0000FF00) >> 8;
+      pNDEFMessage[Offset++] = infoSize & 0x000000FF;
+    }
+    else
+    {
+      pNDEFMessage[Offset++] = 0x51;
+      pNDEFMessage[Offset++] = TEXT_TYPE_STRING_LENGTH;
+      pNDEFMessage[Offset++] = (uint8_t)infoSize;
+    }
+
+    memcpy( &pNDEFMessage[Offset], TEXT_TYPE_STRING, TEXT_TYPE_STRING_LENGTH );
+    Offset+=TEXT_TYPE_STRING_LENGTH;
+    pNDEFMessage[Offset++] = ISO_ENGLISH_CODE_STRING_LENGTH; /* UTF-8 with x byte language code */
+    memcpy( &pNDEFMessage[Offset], ISO_ENGLISH_CODE_STRING, ISO_ENGLISH_CODE_STRING_LENGTH );
+    Offset += ISO_ENGLISH_CODE_STRING_LENGTH;
+
+    /* Information payload */
+    memcpy( &pNDEFMessage[Offset], pURI->Information, strlen(pURI->Information) );
+    Offset += strlen(pURI->Information);
+  }
+
+  *size = Offset;
+
+}
+/**
+  * @brief  This function write the NDEF file with the URI data given in the structure.
+  * @param  pURI : pointer on structure that contain the URI information.
+  * @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_WriteURI( sURI_Info *pURI, I2C* mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR, Offset = 0;
+
+  NDEF_PrepareURIMessage( pURI, NDEF_Buffer, &Offset );
+
+
+  status = NfcTag_WriteNDEF( Offset , NDEF_Buffer, mi2cChannel );
+
+  return status;
+}
+
+char getUriType( char *protocol )
+{
+  if( !memcmp( protocol, URI_ID_0x01_STRING, strlen(URI_ID_0x01_STRING) ) ) return URI_ID_0x01;
+  else if( !memcmp( protocol, URI_ID_0x02_STRING, strlen(URI_ID_0x02_STRING) ) ) return URI_ID_0x02;
+  else if( !memcmp( protocol, URI_ID_0x03_STRING, strlen(URI_ID_0x03_STRING) ) ) return URI_ID_0x03;
+  else if( !memcmp( protocol, URI_ID_0x04_STRING, strlen(URI_ID_0x04_STRING) ) ) return URI_ID_0x04;
+  else if( !memcmp( protocol, URI_ID_0x05_STRING, strlen(URI_ID_0x05_STRING) ) ) return URI_ID_0x05;
+  else if( !memcmp( protocol, URI_ID_0x06_STRING, strlen(URI_ID_0x06_STRING) ) ) return URI_ID_0x06;
+  else if( !memcmp( protocol, URI_ID_0x07_STRING, strlen(URI_ID_0x07_STRING) ) ) return URI_ID_0x07;
+  else if( !memcmp( protocol, URI_ID_0x08_STRING, strlen(URI_ID_0x08_STRING) ) ) return URI_ID_0x08;
+  else if( !memcmp( protocol, URI_ID_0x09_STRING, strlen(URI_ID_0x09_STRING) ) ) return URI_ID_0x09;
+  else if( !memcmp( protocol, URI_ID_0x0A_STRING, strlen(URI_ID_0x0A_STRING) ) ) return URI_ID_0x0A;
+  else if( !memcmp( protocol, URI_ID_0x0B_STRING, strlen(URI_ID_0x0B_STRING) ) ) return URI_ID_0x0B;
+  else if( !memcmp( protocol, URI_ID_0x0C_STRING, strlen(URI_ID_0x0C_STRING) ) ) return URI_ID_0x0C;
+  else if( !memcmp( protocol, URI_ID_0x0D_STRING, strlen(URI_ID_0x0D_STRING) ) ) return URI_ID_0x0D;
+  else if( !memcmp( protocol, URI_ID_0x0E_STRING, strlen(URI_ID_0x0E_STRING) ) ) return URI_ID_0x0E;
+  else if( !memcmp( protocol, URI_ID_0x0F_STRING, strlen(URI_ID_0x0F_STRING) ) ) return URI_ID_0x0F;
+  else if( !memcmp( protocol, URI_ID_0x10_STRING, strlen(URI_ID_0x10_STRING) ) ) return URI_ID_0x10;
+  else if( !memcmp( protocol, URI_ID_0x11_STRING, strlen(URI_ID_0x11_STRING) ) ) return URI_ID_0x11;
+  else if( !memcmp( protocol, URI_ID_0x12_STRING, strlen(URI_ID_0x12_STRING) ) ) return URI_ID_0x12;
+  else if( !memcmp( protocol, URI_ID_0x13_STRING, strlen(URI_ID_0x13_STRING) ) ) return URI_ID_0x13;
+  else if( !memcmp( protocol, URI_ID_0x14_STRING, strlen(URI_ID_0x14_STRING) ) ) return URI_ID_0x14;
+  else if( !memcmp( protocol, URI_ID_0x15_STRING, strlen(URI_ID_0x15_STRING) ) ) return URI_ID_0x15;
+  else if( !memcmp( protocol, URI_ID_0x16_STRING, strlen(URI_ID_0x16_STRING) ) ) return URI_ID_0x16;
+  else if( !memcmp( protocol, URI_ID_0x17_STRING, strlen(URI_ID_0x17_STRING) ) ) return URI_ID_0x17;
+  else if( !memcmp( protocol, URI_ID_0x18_STRING, strlen(URI_ID_0x18_STRING) ) ) return URI_ID_0x18;
+  else if( !memcmp( protocol, URI_ID_0x19_STRING, strlen(URI_ID_0x19_STRING) ) ) return URI_ID_0x19;
+  else if( !memcmp( protocol, URI_ID_0x1A_STRING, strlen(URI_ID_0x1A_STRING) ) ) return URI_ID_0x1A;
+  else if( !memcmp( protocol, URI_ID_0x1B_STRING, strlen(URI_ID_0x1B_STRING) ) ) return URI_ID_0x1B;
+  else if( !memcmp( protocol, URI_ID_0x1C_STRING, strlen(URI_ID_0x1C_STRING) ) ) return URI_ID_0x1C;
+  else if( !memcmp( protocol, URI_ID_0x1D_STRING, strlen(URI_ID_0x1D_STRING) ) ) return URI_ID_0x1D;
+  else if( !memcmp( protocol, URI_ID_0x1E_STRING, strlen(URI_ID_0x1E_STRING) ) ) return URI_ID_0x1E;
+  else if( !memcmp( protocol, URI_ID_0x1F_STRING, strlen(URI_ID_0x1F_STRING) ) ) return URI_ID_0x1F;
+  else if( !memcmp( protocol, URI_ID_0x20_STRING, strlen(URI_ID_0x20_STRING) ) ) return URI_ID_0x20;
+  else if( !memcmp( protocol, URI_ID_0x21_STRING, strlen(URI_ID_0x21_STRING) ) ) return URI_ID_0x21;
+  else if( !memcmp( protocol, URI_ID_0x22_STRING, strlen(URI_ID_0x22_STRING) ) ) return URI_ID_0x22;
+  else if( !memcmp( protocol, URI_ID_0x23_STRING, strlen(URI_ID_0x23_STRING) ) ) return URI_ID_0x23;
+  else return URI_ID_0x00; // No abreviation for this protocol	
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_URI.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_URI.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,57 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_URI.h
+  * @author  MMY Application Team
+  * @version $Revision: 2475 $
+  * @date    $Date: 2016-06-24 12:11:59 +0200 (Fri, 24 Jun 2016) $
+  * @brief   This file help to manage URI NDEF file.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_URI_H
+#define __LIB_NDEF_URI_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+typedef struct 
+{
+//  char protocol[80];
+//  char URI_Message[400];
+//  char Information[400];
+  char protocol[20];
+  char URI_Message[100];
+  char Information[20];
+}sURI_Info;
+
+uint16_t NDEF_ReadURI(sRecordInfo_t *pRecordStruct, sURI_Info *pURI);
+uint16_t NDEF_WriteURI(sURI_Info *pURI, I2C* mi2cChannel);
+
+void NDEF_PrepareURIMessage( sURI_Info *pURI, uint8_t *pNDEFMessage, uint16_t *size );
+char getUriType( char *protocol );
+
+
+#endif /* __LIB_NDEF_URI_H */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Vcard.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Vcard.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,620 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Vcard.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 that represent Vcard.
+  ******************************************************************************
+  * @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_Vcard.h"
+
+
+/** @addtogroup lib_NDEF_Vcard
+  * @ingroup libNDEF
+  * @{
+  * @brief  This part of the library manage the data which follow NFC forum organisation.
+  */
+
+/*  This buffer contains the data sent/received by TAG */
+extern uint8_t NDEF_Buffer [];
+
+static void NDEF_FillVcardStruct( uint8_t* pPayload, uint32_t PayloadSize, char* pKeyWord, uint32_t SizeOfKeyWord, uint8_t* pString );
+static void NDEF_ExtractVcard( sRecordInfo_t *pRecordStruct, sVcardInfo *pVcardStruct );
+
+/**
+  * @brief  This function extracts a Vcard particular property from a vCard.
+  * @param  pPayload      Pointer on the vCard payload data of the vCard record.
+  * @param  PayloadSize   Number of bytes in the vCard payload.
+  * @param  pKeyWord      Pointer on the vCard property keyword to look for.
+  * @param  SizeOfKeyWord Number of bytes of the vCard property keyword we are looking for.
+  * @param  pString       Pointer on a string used to return the vCard property read.
+  */
+static void NDEF_FillVcardStruct( uint8_t* pPayload, uint32_t PayloadSize, char* pKeyWord, uint32_t SizeOfKeyWord, uint8_t* pString )
+{
+  uint8_t* pLastByteAdd, *pLook4Word, *pEndString;
+
+  /* First character force to NULL in case not matching found */
+  *pString = 0;
+  
+  /* Interresting information are stored before picture if any */
+  /* Moreover picture is not used in this demonstration SW */
+  pLastByteAdd = pPayload;
+  while( memcmp( pLastByteAdd, JPEG, JPEG_STRING_SIZE ) && (pLastByteAdd < (pPayload + PayloadSize)) )
+  {
+    pLastByteAdd++;
+  }
+
+  pLook4Word = pPayload;
+  while( memcmp( pLook4Word, pKeyWord, SizeOfKeyWord ) && (pLook4Word < pLastByteAdd) )
+  {
+    pLook4Word++;
+  }
+
+  /* Word found */
+  if( pLook4Word != pLastByteAdd )
+  {
+    pLook4Word += SizeOfKeyWord;
+    pEndString = pLook4Word;
+    while( memcmp( pEndString, LIMIT, LIMIT_STRING_SIZE ) && (pEndString < pLastByteAdd) )
+    {
+      pEndString++;
+    }
+    if( pEndString != pLastByteAdd )
+    {
+      memcpy( pString, pLook4Word, pEndString-pLook4Word );
+      /* add end of string character */
+      pString += pEndString - pLook4Word;
+      *pString = '\0';
+    }
+  }	
+}
+
+/**
+  * @brief  This function reads a Vcard record and stores data in a `sVcardInfo` structure.
+  * @param  pRecordStruct Pointer on the vCard record structure.
+  * @param  pVcardStruct  Pointer on the `sCardInfo` structure to fill.
+  */
+static void NDEF_ExtractVcard( sRecordInfo_t *pRecordStruct, sVcardInfo *pVcardStruct )
+{
+  uint32_t PayloadSize;
+  uint8_t* pPayload;
+
+
+  PayloadSize = pRecordStruct->PayloadLength;
+
+  /* Read record header */
+  pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+
+  NDEF_FillVcardStruct( pPayload, PayloadSize, VERSION, VERSION_STRING_SIZE, (uint8_t*)(pVcardStruct->Version) );
+  if( !memcmp( pVcardStruct->Version, VCARD_VERSION_2_1, VCARD_VERSION_2_1_SIZE ) )
+  {
+    NDEF_FillVcardStruct( pPayload, PayloadSize, FIRSTNAME, FIRSTNAME_STRING_SIZE, (uint8_t*)(pVcardStruct->FirstName) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, TITLE, TITLE_STRING_SIZE, (uint8_t*)(pVcardStruct->Title) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, ORG, ORG_STRING_SIZE, (uint8_t*)(pVcardStruct->Org) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, HOME_ADDRESS, HOME_ADDRESS_STRING_SIZE, (uint8_t*)(pVcardStruct->HomeAddress) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, GEN_ADDRESS, strlen(GEN_ADDRESS), (uint8_t*)(pVcardStruct->Address) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, WORK_ADDRESS, WORK_ADDRESS_STRING_SIZE, (uint8_t*)(pVcardStruct->WorkAddress) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, HOME_TEL, HOME_TEL_STRING_SIZE, (uint8_t*)(pVcardStruct->HomeTel) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, WORK_TEL, WORK_TEL_STRING_SIZE, (uint8_t*)(pVcardStruct->WorkTel) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, CELL_TEL, CELL_TEL_STRING_SIZE, (uint8_t*)(pVcardStruct->CellTel) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, HOME_EMAIL, HOME_EMAIL_STRING_SIZE, (uint8_t*)(pVcardStruct->HomeEmail) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, GEN_EMAIL, strlen(GEN_EMAIL), (uint8_t*)(pVcardStruct->Email) );
+    NDEF_FillVcardStruct( pPayload, PayloadSize, WORK_EMAIL, WORK_EMAIL_STRING_SIZE, (uint8_t*)(pVcardStruct->WorkEmail) );
+  }
+  else if( !memcmp( pVcardStruct->Version, VCARD_VERSION_3_0, VCARD_VERSION_3_0_SIZE ) )
+  {
+    /* need to be implemented */
+  }
+  else
+  {
+    /* maybe new version but not supported in this sw */
+  }
+
+}
+
+/**
+  * @brief  This function reads a Vcard record and stores data in a `sVcardInfo` structure.
+  * @param  pRecordStruct Pointer on the vCard record structure.
+  * @param  pVcardStruct  Pointer on the `sCardInfo` structure to fill.
+  * @retval NDEF_OK     The Vcard information has been retrieved.
+  * @retval NDEF_ERROR  Not able to retrieve the Vcard information.
+  */
+uint16_t NDEF_ReadVcard( sRecordInfo_t *pRecordStruct, sVcardInfo *pVcardStruct )
+{
+  uint16_t status = NDEF_ERROR;
+
+  if( pRecordStruct->NDEF_Type == VCARD_TYPE )
+  {
+    NDEF_ExtractVcard( pRecordStruct, pVcardStruct );
+    status = NDEF_OK;
+  }
+
+  return status;
+}
+
+/**
+  * @brief  This function writes a NDEF message to the NFC tag with the Vcard data given in a `sVcardInfo` structure.
+  * @param  pVcardStruct Pointer on a `sVcardInfo` structure containing the Vcard information.
+  * @retval NDEF_OK                     NDEF file data written in the tag.
+  * @retval NDEF_ERROR                  Not able to store the 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_WriteVcard( sVcardInfo *pVcardStruct, I2C* mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR, Offset = 0;
+
+  NDEF_PrepareVcardMessage( pVcardStruct, NDEF_Buffer, &Offset );
+
+  status = NfcTag_WriteNDEF( Offset , NDEF_Buffer, mi2cChannel );
+
+  return status;
+}
+
+/**
+  * @brief  This function computes the size of a Vcard record from the data given in the `sVcardInfo` structure.
+  * @param  pVcardStruct Pointer on a `sVcardInfo` structure containing the Vcard information.
+  * @return vCard record data size in bytes (excluding record metadata).
+  */
+uint32_t NDEF_GetVcardLength( sVcardInfo *pVcardStruct)
+{
+
+  uint32_t PayloadSize = 0;
+
+  /* "BEGIN:VCARD\r\n" */
+  PayloadSize += BEGIN_STRING_SIZE;
+  PayloadSize += VCARD_STRING_SIZE;
+  PayloadSize += LIMIT_STRING_SIZE;
+
+  /* "VERSION:2.1\r\n" */
+  PayloadSize += VERSION_STRING_SIZE;
+  PayloadSize += VCARD_VERSION_2_1_SIZE;
+  PayloadSize += LIMIT_STRING_SIZE;
+
+  /* "N:\r\n" */
+  if(*pVcardStruct->Name != '\0')
+  {
+  PayloadSize += VCARD_NAME_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->Name );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  /* "FN:\r\n" */
+  if(*pVcardStruct->FirstName != '\0')
+  {
+    PayloadSize += FIRSTNAME_STRING_SIZE;
+    PayloadSize += strlen( pVcardStruct->FirstName );
+    PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->Title != '\0')
+  {
+  /* "TITLE:\r\n" */
+  PayloadSize += TITLE_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->Title );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->Org != '\0')
+  {
+  /* "ORG:\r\n" */
+  PayloadSize += ORG_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->Org );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->Url != '\0')
+  {
+  /* "URL:\r\n" */
+  PayloadSize += URL_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->Url );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->HomeAddress != '\0')
+  {
+  /* "ADR;HOME:\r\n" */
+  PayloadSize += HOME_ADDRESS_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->HomeAddress );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->WorkAddress != '\0')
+  {
+  /* "ADR;WORK:\r\n" */
+  PayloadSize += WORK_ADDRESS_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->WorkAddress );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->HomeTel != '\0')
+  {
+  /* "TEL;HOME:\r\n" */
+  PayloadSize += HOME_TEL_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->HomeTel );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->WorkTel != '\0')
+  {
+  /* "TEL;WORK:\r\n" */
+  PayloadSize += WORK_TEL_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->WorkTel );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->CellTel != '\0')
+  {
+  /* "TEL;CELL:\r\n" */
+  PayloadSize += CELL_TEL_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->CellTel );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->HomeEmail != '\0')
+  {
+  /* "EMAIL;HOME:\r\n" */
+  PayloadSize += HOME_EMAIL_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->HomeEmail );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->WorkEmail != '\0')
+  {
+  /* "EMAIL;WORK:\r\n" */
+  PayloadSize += WORK_EMAIL_STRING_SIZE;
+  PayloadSize += strlen( pVcardStruct->WorkEmail );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  /* "END:VCARD\r\n" */
+  PayloadSize += END_STRING_SIZE;
+  PayloadSize += VCARD_STRING_SIZE;
+ /* PayloadSize += LIMIT_STRING_SIZE;*/
+
+  return PayloadSize;
+  
+}
+
+/**
+  * @brief  This function write the NDEF file with the Vcard data given in the structure.
+  * @param  pVcardStruct : pointer on structure that contain the Vcard information.
+  * @param  pNDEFMessage : pointer on the NDEF message.
+  * @param  size : to store the size of the NDEF message generated.
+  */
+void NDEF_PrepareVcardMessage( sVcardInfo *pVcardStruct, uint8_t *pNDEFMessage, uint16_t *size )
+{
+
+  uint32_t PayloadSize = 0;
+
+  /* Vcard Record Header */
+/************************************/
+/*  7 |  6 |  5 |  4 |  3 | 2  1  0 */
+/*----------------------------------*/
+/* MB   ME   CF   SR   IL    TNF    */  /* <---- CF=0, IL=0 and SR=0 TNF=2 NFC Forum Media type*/
+/*----------------------------------*/
+/*          TYPE LENGTH             */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 3          */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 2          */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 1          */
+/*----------------------------------*/
+/*        PAYLOAD LENGTH 0          */
+/*----------------------------------*/
+/*           ID LENGTH              */  /* <---- Not Used  */
+/*----------------------------------*/
+/*              TYPE                */
+/*----------------------------------*/
+/*               ID                 */  /* <---- Not Used  */
+/************************************/
+
+  /* As we don't have embedded a jpeg encoder/decoder in this firmware */
+  /* We have made the choice to manage only string content of the vCard */
+  /* For demonstration purpose in order to fill the 8kB of the M24SR */
+  /* We have embedded a NDEF vCard in the STM32 to be able to fill M24SR */
+
+  /* fill record header */
+  uint32_t length = NDEF_GetVcardLength(pVcardStruct);
+  if(length >= 0xFF)
+  {
+  pNDEFMessage[0] = 0xC2;   /* Record Flag */
+  pNDEFMessage[1] = XVCARD_TYPE_STRING_LENGTH;
+  pNDEFMessage[5] = length & 0xff; 
+  pNDEFMessage[4] = (length>>8) & 0xff;
+  pNDEFMessage[3] = (length>>16) & 0xff;
+  pNDEFMessage[2] = length>>24;	
+  memcpy( &pNDEFMessage[6], XVCARD_TYPE_STRING, XVCARD_TYPE_STRING_LENGTH );
+
+  /* Payload is positionned in the NDEF after record header */
+  PayloadSize = 6 + XVCARD_TYPE_STRING_LENGTH;
+  } else {
+  pNDEFMessage[0] = 0xD2;   /* Record Flag */
+  pNDEFMessage[1] = XVCARD_TYPE_STRING_LENGTH;
+  pNDEFMessage[2] =  length;
+  memcpy( &pNDEFMessage[3], XVCARD_TYPE_STRING, XVCARD_TYPE_STRING_LENGTH );
+
+  /* Payload is positionned in the NDEF after record header */
+  PayloadSize = 3 + XVCARD_TYPE_STRING_LENGTH;
+  }
+
+  /* "BEGIN:VCARD\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], BEGIN, BEGIN_STRING_SIZE );
+  PayloadSize += BEGIN_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], VCARD,VCARD_STRING_SIZE );
+  PayloadSize += VCARD_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+
+  /* "VERSION:2.1\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], VERSION, VERSION_STRING_SIZE );
+  PayloadSize += VERSION_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], VCARD_VERSION_2_1, VCARD_VERSION_2_1_SIZE );
+  PayloadSize += VCARD_VERSION_2_1_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+
+  /* "N:\r\n" */
+  if(*pVcardStruct->Name != '\0')
+  {
+  memcpy( &pNDEFMessage[PayloadSize], VCARD_NAME, VCARD_NAME_STRING_SIZE );
+  PayloadSize += VCARD_NAME_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->Name, strlen(pVcardStruct->Name) );
+  PayloadSize += strlen( pVcardStruct->Name );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  /* "FN:\r\n" */
+  if(*pVcardStruct->FirstName != '\0')
+  {
+  memcpy( &pNDEFMessage[PayloadSize], FIRSTNAME, FIRSTNAME_STRING_SIZE );
+  PayloadSize += FIRSTNAME_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->FirstName, strlen(pVcardStruct->FirstName) );
+  PayloadSize += strlen( pVcardStruct->FirstName );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->HomeTel != '\0')
+  {
+
+  /* "TEL;HOME:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], HOME_TEL, HOME_TEL_STRING_SIZE );
+  PayloadSize += HOME_TEL_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->HomeTel, strlen(pVcardStruct->HomeTel) );
+  PayloadSize += strlen( pVcardStruct->HomeTel );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->WorkTel != '\0')
+  {
+
+  /* "TEL;WORK:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], WORK_TEL, WORK_TEL_STRING_SIZE );
+  PayloadSize += WORK_TEL_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->WorkTel, strlen(pVcardStruct->WorkTel) );
+  PayloadSize += strlen( pVcardStruct->WorkTel );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->CellTel != '\0')
+  {
+
+  /* "TEL;CELL:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], CELL_TEL, CELL_TEL_STRING_SIZE );
+  PayloadSize += CELL_TEL_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->CellTel, strlen(pVcardStruct->CellTel) );
+  PayloadSize += strlen( pVcardStruct->CellTel );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->HomeEmail != '\0')
+  {
+
+  /* "EMAIL;HOME:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], HOME_EMAIL, HOME_EMAIL_STRING_SIZE );
+  PayloadSize += HOME_EMAIL_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->HomeEmail, strlen(pVcardStruct->HomeEmail) );
+  PayloadSize += strlen( pVcardStruct->HomeEmail );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->WorkEmail != '\0')
+  {
+
+  /* "EMAIL;WORK:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], WORK_EMAIL, WORK_EMAIL_STRING_SIZE );
+  PayloadSize += WORK_EMAIL_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->WorkEmail, strlen(pVcardStruct->WorkEmail) );
+  PayloadSize += strlen( pVcardStruct->WorkEmail );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->HomeAddress != '\0')
+  {
+
+  /* "ADR;HOME:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], HOME_ADDRESS, HOME_ADDRESS_STRING_SIZE );
+  PayloadSize += HOME_ADDRESS_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->HomeAddress, strlen(pVcardStruct->HomeAddress) );
+  PayloadSize += strlen( pVcardStruct->HomeAddress );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->WorkAddress != '\0')
+  {
+
+  /* "ADR;WORK:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], WORK_ADDRESS, WORK_ADDRESS_STRING_SIZE );
+  PayloadSize += WORK_ADDRESS_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->WorkAddress, strlen(pVcardStruct->WorkAddress) );
+  PayloadSize += strlen( pVcardStruct->WorkAddress );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->Org != '\0')
+  {
+
+  /* "ORG:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], ORG, ORG_STRING_SIZE );
+  PayloadSize += ORG_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->Org, strlen(pVcardStruct->Org) );
+  PayloadSize += strlen( pVcardStruct->Org );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->Title != '\0')
+  {
+  /* "TITLE:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], TITLE, TITLE_STRING_SIZE );
+  PayloadSize += TITLE_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->Title, strlen(pVcardStruct->Title) );
+  PayloadSize += strlen( pVcardStruct->Title );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+  if(*pVcardStruct->Url != '\0')
+  {
+  /* "URL:\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], URL, URL_STRING_SIZE );
+  PayloadSize += URL_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], pVcardStruct->Url, strlen(pVcardStruct->Url) );
+  PayloadSize += strlen( pVcardStruct->Url );
+  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+  PayloadSize += LIMIT_STRING_SIZE;
+  }
+
+  /* "END:VCARD\r\n" */
+  memcpy( &pNDEFMessage[PayloadSize], END, END_STRING_SIZE );
+  PayloadSize += END_STRING_SIZE;
+  memcpy( &pNDEFMessage[PayloadSize], VCARD, VCARD_STRING_SIZE );
+  PayloadSize += VCARD_STRING_SIZE;
+//  memcpy( &pNDEFMessage[PayloadSize], LIMIT, LIMIT_STRING_SIZE );
+//  PayloadSize += LIMIT_STRING_SIZE;
+
+  *size = (uint16_t)(PayloadSize); /* Must not count the 2 byte that represent the NDEF size */
+/*
+  PayloadSize -= 6 + VCARD_TYPE_STRING_LENGTH;
+
+  pNDEFMessage[2] = (PayloadSize & 0xFF000000) >> 24;
+  pNDEFMessage[3] = (PayloadSize & 0x00FF0000) >> 16;
+  pNDEFMessage[4] = (PayloadSize & 0x0000FF00) >> 8;
+  pNDEFMessage[5] = PayloadSize & 0x000000FF;
+  */
+}
+
+
+/**
+  * @brief  This function extracts binary data from a base64 representation.
+  * @param  input64 : pointer on the input data in base64.
+  * @param  binary : returned binary data.
+  * @return Updated pointer on the input64 buffer (normal increment is 4 base64 char for 3 bytes of binary data, but special char are ignored)
+*/
+static uint8_t* from_base64(uint8_t *input64, uint32_t* binary)
+{
+  /* Read 4 base64 character & translate them into 3 bytes binary */ 
+  *binary = 0;
+  uint8_t base64_6bits;
+  int i = 0;
+  while(i<4)
+  {
+
+    if((*input64 >= 'A') && (*input64 <= 'Z'))
+    {
+      base64_6bits = *(input64++) - 'A';
+    } else if ((*input64 >= 'a') && (*input64 <= 'z'))
+    {
+      base64_6bits = *(input64++) - 'a' + 26;
+    } else if ((*input64 >= '0') && (*input64 <= '9')) {
+      base64_6bits = *(input64++) - '0' + 52;
+    } else if (*input64 == '+')
+    {
+      base64_6bits = 62;
+      input64++;
+    } else if (*input64 == '/')
+    {
+      base64_6bits = 63;  
+      input64++;
+    } else if (*input64 == '=') {
+      base64_6bits = 0;
+      input64++;
+    } else {
+      input64++;
+      continue;
+    }
+    
+    *binary |= base64_6bits << (6*(3-i));
+    i++;
+  }
+  *binary = ((*binary & 0xFF0000)>>16) | ((*binary & 0xFF)<<16) | (*binary & 0xFF00);
+  return input64;
+}
+
+
+/**
+  * @brief  This function return the picture stored in a VCARD.
+  * @param  pPayload : pointer on the payload data of the NDEF message.
+  * @param  PayloadSize : number of data in the payload.
+  * @param  pPict : Pointer on the dpicture buffer (must be big enough to contain the picture - warning: no check is done in the function).
+ */
+int NDEF_getVcardPicture( uint8_t* pPayload, uint32_t PayloadSize,  uint8_t* pPict )
+{
+  uint8_t* pSrcPict;
+
+  
+  /* Let's find the picture */
+  pSrcPict = pPayload;
+  while( memcmp( pSrcPict, JPEG, JPEG_STRING_SIZE ) && (pSrcPict < (pPayload + PayloadSize)) )
+  {
+    pSrcPict++;
+  }
+  while( (*pSrcPict != ':') && (pSrcPict < (pPayload + PayloadSize)) )
+  {
+    pSrcPict++;
+  }
+  /* Picture start at next char */
+  pSrcPict++;
+
+  
+  /* Word found */
+  while( memcmp( pSrcPict, LIMIT, LIMIT_STRING_SIZE ) && (pSrcPict < (pPayload + PayloadSize) ) )
+    {
+      uint32_t binary24;
+      pSrcPict = from_base64(pSrcPict, &binary24);
+      /* copy the 3 bytes read from the base64 data */
+      memcpy( pPict, &binary24, 3);
+      pPict += 3;
+      /* Ignore any line breaks */
+      while (*pSrcPict == 0x0A)
+      {
+        pSrcPict++;
+      }
+    }
+    
+    if(pSrcPict >= (pPayload + PayloadSize))
+    {
+      /* problem when parsing the picture */
+      return 1;
+    } else {
+      /* picture found */
+      return 0;
+    }
+}
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Vcard.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Vcard.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,119 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Vcard.h
+  * @author  MMY Application Team
+  * @version $Revision: 2892 $
+  * @date    $Date: 2016-09-19 11:03:26 +0200 (Mon, 19 Sep 2016) $
+  * @brief   This file help to manage Vcard NDEF file.
+  ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_VCARD_H
+#define __LIB_NDEF_VCARD_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+
+#define VCARD_VERSION_2_1             "2.1"
+#define VCARD_VERSION_2_1_SIZE        3
+
+#define VCARD_VERSION_3_0             "3.0"
+#define VCARD_VERSION_3_0_SIZE        3
+
+
+#define BEGIN                         "BEGIN:"
+#define VCARD                         "VCARD"
+#define VERSION                       "VERSION:"
+#define VCARD_NAME                     "N:"
+  // TODO: rename FIRSTNAME into FORMATTEDNAME
+#define FIRSTNAME                     "FN:"
+#define HOME_TEL                      "TEL;HOME:"
+#define WORK_TEL                      "TEL;WORK:"
+#define CELL_TEL                      "TEL;CELL:"
+#define HOME_EMAIL                    "EMAIL;HOME:"
+#define WORK_EMAIL                    "EMAIL;WORK:"
+#define GEN_EMAIL                     "EMAIL:"
+#define HOME_ADDRESS                  "ADR;HOME:"
+#define WORK_ADDRESS                  "ADR;WORK:"
+#define GEN_ADDRESS                   "ADR:"
+#define TITLE                         "TITLE:"
+#define ORG                           "ORG:"
+#define URL                           "URL:"
+#define END                           "END:"
+#define JPEG                          "JPEG"
+
+#define LIMIT                         "\r\n"
+
+#define BEGIN_STRING_SIZE             6
+#define VCARD_STRING_SIZE             5
+#define VERSION_STRING_SIZE           8
+#define VCARD_NAME_STRING_SIZE        2
+  // TODO: rename FIRSTNAME into FORMATTEDNAME
+#define FIRSTNAME_STRING_SIZE         3
+#define HOME_TEL_STRING_SIZE          9
+#define WORK_TEL_STRING_SIZE          9
+#define CELL_TEL_STRING_SIZE          9
+#define HOME_EMAIL_STRING_SIZE        11
+#define WORK_EMAIL_STRING_SIZE        11
+#define HOME_ADDRESS_STRING_SIZE      9
+#define WORK_ADDRESS_STRING_SIZE      9
+#define TITLE_STRING_SIZE             6
+#define ORG_STRING_SIZE               4
+#define URL_STRING_SIZE               4
+#define END_STRING_SIZE               4
+#define JPEG_STRING_SIZE              4	
+
+#define LIMIT_STRING_SIZE             2
+
+typedef struct
+{
+  char Version [10];
+  char Name[80];
+  // TODO: rename FirstName into FormattedName
+  char FirstName[80];
+  char Title[80];
+  char Org[80];
+  char HomeAddress[80];
+  char WorkAddress[80];
+  char Address[80];
+  char HomeTel[40];
+  char WorkTel[40];
+  char CellTel[40];
+  char HomeEmail[80];
+  char WorkEmail[80];
+  char Email[80];
+  char Url[80];
+}sVcardInfo;
+
+uint16_t NDEF_ReadVcard( sRecordInfo_t *pRecordStruct, sVcardInfo *pVcardStruct );
+uint16_t NDEF_WriteVcard( sVcardInfo *pVcardStruct, I2C* mi2cChannel );
+void NDEF_PrepareVcardMessage( sVcardInfo *pVcardStruct, uint8_t *pNDEFMessage, uint16_t *size );
+int NDEF_getVcardPicture( uint8_t* pPayload, uint32_t PayloadSize,  uint8_t* pPict );
+
+
+#endif /* __LIB_NDEF_VCARD_H */
+
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Wifi.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Wifi.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,367 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_Wifi.c
+  * @author  Central LAB
+  * @version V1.0.0
+  * @date    7-October-2015
+  * @ingroup LibNDEF_Wifi
+  * @brief   This file helps to manage a NDEF message representing a Wifi Token.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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_Wifi.h"
+#define ATTRIBUTE_ID_SSID_LSB                                               0X10
+#define ATTRIBUTE_ID_SSID_MSB                                               0X45
+
+
+#define ATTRIBUTE_ID_NETWORK_LSB                                            0X10
+#define ATTRIBUTE_ID_NETWORK_MSB                                            0X27
+
+
+/** @addtogroup lib_NDEF_Wifi Wifi OOB library (WPS)
+  * @ingroup  libNDEF
+  *	@brief    This module is used to manage a Wifi Out-Of-Band NDEF message, to start a communication based on Wifi.
+  * @details  The Wifi OOB format is described by the Wifi Protected Setup specification.
+  *           It consists in a list of data elements formated as type-length-value.
+  *           This module allows to build, write & read such data embedded in a NDEF message.
+  * @section  Wifi_Library_Usage Wifi NDEF library usage
+  * @subsection  Write_Wifi_OOB How to write a Wifi OOB
+  *           The Wifi OOB written in a NDEF record by this module has the following structure:
+  *           - Version
+  *           - Credential
+                - Network index
+                - SSID
+                - Authentication Type
+                - Encryption Type
+                - Network Key
+                - MAC Address
+                - Vendor Extension
+                  - Network Key Shareable
+                - Vendor Extension
+                  - Version2
+                  
+                To write a Wifi OOB, the user must:
+                1. Instanciate & initialize a `sWifiTokenInfo` structure, such as:
+                
+                       sWifiTokenInfo wps_oob = {.NetworkSSID        = "MY_SSID",
+                                                 .AuthenticationType = NDEF_WIFI_AUTHENTICATION_NONE,
+                                                 .EncryptionType     = NDEF_WIFI_ENCRYPTION_NONE,
+                                                 .NetworkKey         = "01234567"};
+                  @note
+                  1. `AuthenticationType` & `EncryptionType` fields must respectively be values from enums: `Ndef_Wifi_Authentication_t` & `Ndef_Wifi_Encryption_t`.
+                  2. If the `Network key` is set to an empty string, the library sets it to `00000000`.\n
+                   Even if 0-length Network Key is supposed to be supported, smartphones dont necessarily accept it.
+
+                2. Call the `NDEF_WriteWifiToken` function on a pointer on the previous struct instance:
+                
+                       NDEF_WriteWifiToken(&wps_oob);
+  * @subsection  Read_Wifi_OOB How to read a Wifi OOB
+  *          1. Read the 1st record of the NDEF message:
+  *
+  *                 sRecordInfo_t rRecord;
+  *                 NDEF_ReadNDEF(NDEF_Buffer);
+  *                 NDEF_IdentifyBuffer(rRecord,NDEF_Buffer);
+  *          2. Decode the Wifi OOB:
+  *
+  *                 sWifiTokenInfo wps;
+  *                 NDEF_ReadWifiToken(&record, &wps);
+  *             @note
+  *               Only the `NetworkSSID` & `NetworkKey` are extracted from the Wifi OOB, other fields of the `sWifiTokenInfo` structure are left un-initialized.
+  * @{
+  */
+
+/* This buffer contains the data send/received by the TAG */
+extern uint8_t NDEF_Buffer [NDEF_MAX_SIZE];
+
+
+static void NDEF_FillWifiTokenStruct( uint8_t* pPayload, uint32_t PayloadSize, sWifiTokenInfo *pWifiTokenStruct);
+static void NDEF_Read_WifiToken ( struct sRecordInfo *pRecordStruct, sWifiTokenInfo *pWifiTokenStruct );
+
+/**
+  * @brief  This function fills a WifiToken structure with information from the NDEF message.
+	* @param	pPayload Pointer on the payload data of the NDEF message.
+	* @param	PayloadSize number of data in the payload.
+	* @param	pWifiTokenStruct pointer on the structure to fill.
+  * @retval NONE 
+  */
+static void NDEF_FillWifiTokenStruct( uint8_t* pPayload, uint32_t PayloadSize, sWifiTokenInfo *pWifiTokenStruct)
+{
+	uint8_t* pLastByteAdd,data1,data2,*temp,*temp_br ;
+        uint16_t SSIDLen,NetWorkKeyLen;
+        uint8_t *dbg,dbg1;
+      
+	
+	pLastByteAdd = (uint8_t*)(pPayload + PayloadSize);
+        pPayload--;     
+        
+        while(pPayload++ != pLastByteAdd)
+        {
+          uint8_t attribute = *pPayload;
+          temp_br = pPayload;
+          switch(attribute)
+          {
+            
+          case ATTRIBUTE_ID_SSID_LSB:
+            temp = pPayload;
+            dbg = temp;
+            dbg1 = *++dbg;
+            if(dbg1 == ATTRIBUTE_ID_SSID_MSB )
+            {
+              data1 = *++dbg;
+              data2 = *++dbg;
+              SSIDLen = data1;
+              SSIDLen = SSIDLen << 8;
+              SSIDLen |= data2;
+              pPayload += 4;
+              memcpy( pWifiTokenStruct->NetworkSSID, pPayload, SSIDLen);
+              /* add end of string charactere */
+              pWifiTokenStruct->NetworkSSID[SSIDLen] = '\0';	
+              pPayload += SSIDLen - 1;
+            }
+            else if(dbg1 == ATTRIBUTE_ID_NETWORK_MSB )
+            {
+              data1 = *++dbg;
+              data2 = *++dbg;
+              NetWorkKeyLen = data1;
+              NetWorkKeyLen = NetWorkKeyLen << 8;
+              NetWorkKeyLen |= data2;
+              pPayload += 4;
+              memcpy( pWifiTokenStruct->NetworkKey, pPayload, NetWorkKeyLen);
+              /* add end of string charactere */
+              pWifiTokenStruct->NetworkKey[NetWorkKeyLen] = '\0';
+              pPayload += NetWorkKeyLen -1;
+            }
+            else
+            {
+              pPayload = temp_br;
+            }
+            
+          break; 
+           
+          default :
+            ;
+          }
+        }
+        
+}
+
+/**
+  * @brief  This fonction reads the WifiToken and store data in a structure.
+	* @param	pRecordStruct Pointer on the record structure.
+	* @param	pWifiTokenStruct Pointer on the structure to fill.
+  * @retval NONE 
+  */
+static void NDEF_Read_WifiToken ( struct sRecordInfo *pRecordStruct, sWifiTokenInfo *pWifiTokenStruct )
+{
+	uint8_t* pPayload;
+	uint32_t PayloadSize;
+	
+	PayloadSize = pRecordStruct->PayloadLength;
+	
+	/* Read record header */
+	pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd);
+	
+	if( pRecordStruct->NDEF_Type == URI_WIFITOKEN_TYPE)
+		NDEF_FillWifiTokenStruct(pPayload , PayloadSize, pWifiTokenStruct);
+  
+}
+
+
+/**
+  * @brief  This fonction reads a NDEF record and retrieves a WifiToken information if any.
+  * @param	pRecordStruct Pointer on the record structure.
+	* @param	pWifiTokenStruct Pointer on a `sWifiTokenInfo` structure to fill with the WifiToken information.
+  * @retval NDEF_OK WifiToken information from NDEF have been retrieved.
+	* @retval NDEF_ERROR Not able to retrieve the WifiToken information.
+  */
+uint16_t NDEF_ReadWifiToken(struct sRecordInfo *pRecordStruct, sWifiTokenInfo *pWifiTokenStruct)
+{
+	uint16_t status = NDEF_ERROR;
+	  
+	if( pRecordStruct->NDEF_Type == URI_WIFITOKEN_TYPE )
+	{	
+		NDEF_Read_WifiToken(pRecordStruct, pWifiTokenStruct );
+		status = NDEF_OK;
+	}
+	
+	return status;
+}
+
+
+/**
+  * @brief  This fonction writes a NDEF message built with the WifiToken data given in the structure.
+	* @param	pWifiTokenStruct Pointer on the structure containing the WifiToken information.
+  * @retval NDEF_OK The NDEF message has been successfully written.
+	* @retval NDEF_ERROR Not able to store the NDEF message inside the tag.
+  */
+uint16_t NDEF_WriteWifiToken ( sWifiTokenInfo *pWifiTokenStruct, I2C* mi2cChannel )
+{
+	uint16_t status = NDEF_ERROR;
+        uint8_t* pPayload,initStage = 0;
+        uint16_t DataSize;
+        uint32_t PayloadSize,SSIDSize,SSIDKeySize;
+
+  if(pWifiTokenStruct->NetworkKey[0] == '\0')
+  {
+    /* Empty network key is not supported by Phones */
+    strcpy(pWifiTokenStruct->NetworkKey, NDEF_WIFI_DEFAULT_NETWORK_KEY);
+  }
+  
+          uint8_t configToken1[] = {0x10,0x4A, /* Attribute ID : Version*/
+                                    0x00,0x01, /* Attribute ID Length*/
+                                    0x10,    /* Version 1.0*/
+                                    0x10,0x0E,  /* Attribute ID Credential*/  
+                                    0x00,0x48, /* Attribute ID Length*/
+                                    0x10,0x26, /* Attribute ID : Network Index*/
+                                    0x00,0x01, /* Attribute Length*/
+                                    0x01,  /* Index */
+                                    0x10,0x45, /* Attribute ID :SSID*/
+                            
+        };
+        
+      /* Fill SSID length + SSID between configToken1 and configToken3*/ 
+
+          uint8_t configToken3[] = {0x10,0x03, /* Attribute ID :Authentication Type*/
+                                    0x00,0x02, /* Attribute Length*/
+                                    0x00,0x01,  /* Attribute Type : Open*/
+                                    0x10,0x0F,  /* Attribute ID  : Encryption Type*/
+                                    0x00,0x02,  /* Attribute Length*/
+                                    0x00,0x01, /* Encryption Type : None*/
+                                    0x10,0x27};  /* Attribute ID  : Network Key */
+        
+              
+     /*Fill SSID KEY Length and SSID Key between configToken3 and configToken5*/
+
+          uint8_t configToken5[] = {0x10,0x20, /* Attribute ID  : MAC Address */
+                                    0x00,0x06, /* Attribute Length*/
+                                    0, /*MAC-ADDRESS*/
+                                    0, /*MAC-ADDRESS*/
+                                    0, /*MAC-ADDRESS*/
+                                    0, /*MAC-ADDRESS*/
+                                    0, /*MAC-ADDRESS*/
+                                    0, /*MAC-ADDRESS*/
+                                    0x10,0x49, /* Attribute ID  : Vendor Extension */
+                                    0x00,0x06, /* Attribute Length*/
+                                    0x00,0x37,0x2A, /* Vendor ID:WFA*/
+                                    0x02, /* Subelement ID:Network Key Shareable*/
+                                    0x01, /* Subelement Length*/
+                                    0x01, /*Network Key Shareable : TRUE*/
+                                    0x10,0x49, /* Attribute ID  : Vendor Extension */
+                                    0x00,0x06,/* Attribute Length*/
+                                    0x00,0x37,0x2A,/* Vendor ID:WFA*/
+                                    0x00, /* Subelement ID:Version2*/
+                                    0x01, /* Subelement Length:1*/
+                                    0x20 /* Version2*/
+        };
+               
+
+  /* Set size of the tokens */
+  const uint32_t CONFIG_TOKEN_1 = sizeof(configToken1);
+  const uint32_t CONFIG_TOKEN_3 = sizeof(configToken3);
+  const uint32_t CONFIG_TOKEN_5 = sizeof(configToken5);
+
+  /* Update Token3 for Autentication & Encryption Types, their default value is coded in token3 */
+  configToken3[CONFIG_TOKEN_3_AUTHENTICATION_TYPE_INDEX] = pWifiTokenStruct->AuthenticationType & 0xFF;
+  configToken3[CONFIG_TOKEN_3_ENCRYPTION_TYPE_INDEX] = pWifiTokenStruct->EncryptionType & 0xFF;
+
+	/* fill Wifi record header */
+	NDEF_Buffer[FIRST_RECORD_OFFSET] = 0xD2;   /* Record Flag */
+	NDEF_Buffer[FIRST_RECORD_OFFSET+1] = WIFITOKEN_TYPE_STRING_LENGTH;
+	NDEF_Buffer[FIRST_RECORD_OFFSET+2] = 76; /* needs to be autocalculated - done at the end */
+  
+	memcpy(&NDEF_Buffer[FIRST_RECORD_OFFSET+3], WIFITOKEN_TYPE_STRING, WIFITOKEN_TYPE_STRING_LENGTH);
+	
+	pPayload = &NDEF_Buffer[FIRST_RECORD_OFFSET+3+WIFITOKEN_TYPE_STRING_LENGTH];
+	PayloadSize = 0;
+	
+  /* Compute credential length */
+        
+  uint16_t credential_length =  5 +                                     // Network index
+                                4 +                                     // SSID type + length
+                                strlen(pWifiTokenStruct->NetworkSSID) + // SSID
+                                CONFIG_TOKEN_3 +
+                                2 +                                     // Network key length
+                                strlen(pWifiTokenStruct->NetworkKey) +  // Network KEY
+                                CONFIG_TOKEN_5;
+	
+  /* update credential length */
+  configToken1[CONFIG_TOKEN_1_CREDENTIAL_LENGTH_INDEX + 1] = credential_length & 0xff;
+  configToken1[CONFIG_TOKEN_1_CREDENTIAL_LENGTH_INDEX] = credential_length>>8;
+  
+  
+        for(initStage=0;initStage<CONFIG_TOKEN_1;initStage++)
+        {
+          *pPayload =configToken1[initStage];
+          pPayload++;
+        }
+        
+        /*Fill SSID length and SSID value*/
+        SSIDSize = strlen(pWifiTokenStruct->NetworkSSID);
+        *pPayload = 0x00; pPayload++;
+        *pPayload = SSIDSize & 0x000000FF; pPayload++;
+        
+        strcpy((char*)pPayload,pWifiTokenStruct->NetworkSSID);
+        pPayload = pPayload + strlen(pWifiTokenStruct->NetworkSSID);
+ 
+        for(initStage=0;initStage<CONFIG_TOKEN_3;initStage++)
+        {
+          *pPayload =configToken3[initStage];
+          pPayload++;
+        }
+        
+      /* Fill the SSIDKey length and SSIDKey value */
+        SSIDKeySize = strlen(pWifiTokenStruct->NetworkKey);
+        *pPayload = 0x00; pPayload++;
+        *pPayload = SSIDKeySize & 0x000000FF; pPayload++;
+        
+        memcpy((char*)pPayload,pWifiTokenStruct->NetworkKey,SSIDKeySize);
+        pPayload = pPayload + SSIDKeySize;
+
+        for(initStage=0;initStage<CONFIG_TOKEN_5;initStage++)
+        {
+          *pPayload =configToken5[initStage];
+          pPayload++;
+        }
+
+	PayloadSize += CONFIG_TOKEN_1 + CONFIG_TOKEN_3 + CONFIG_TOKEN_5 + SSIDSize + SSIDKeySize + 4 ; // +4 is for SSID & Key length fields
+		
+	NDEF_Buffer[FIRST_RECORD_OFFSET+2] = (PayloadSize & 0x000000FF);
+	
+	DataSize = PayloadSize + 3 + WIFITOKEN_TYPE_STRING_LENGTH;
+	
+	/* Write NDEF */
+	status = NDEF_WriteNDEF(DataSize , NDEF_Buffer, mi2cChannel);
+
+  return status;
+}
+
+
+/**
+  * @}
+  */
+
+
+
+/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/
+
+
diff -r 000000000000 -r de13951f30f6 lib_NDEF_Wifi.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_NDEF_Wifi.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,110 @@
+/**
+  ******************************************************************************
+  * @file    lib_NDEF_WifiToken.h
+  * @author  Central LAB
+  * @version V1.0.0
+  * @date    7-October-2015
+  * @brief   This file helps to manage the NDEF message representing a Wifi Token.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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.
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_NDEF_WIFIT_H
+#define __LIB_NDEF_WIFIT_H
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+/** @addtogroup lib_NDEF_Wifi Wifi OOB library (WPS)
+  * @ingroup libNDEF
+  * @{
+  */
+
+	
+/* Exported types ------------------------------------------------------------*/
+/** @brief This index points to the position of the credential length value in Token1.
+  * Its value may require to be updated if the token1 is modified.
+  */
+#define CONFIG_TOKEN_1_CREDENTIAL_LENGTH_INDEX 7
+
+/** @brief This index points to the position of the Authentication type value in Token3.
+  *        Its value may require to be updated if the token3 is modified. 
+  */
+#define CONFIG_TOKEN_3_AUTHENTICATION_TYPE_INDEX  ((uint32_t)5)
+/** @brief This index points to the position of the Encryption type value in Token3.
+  *        Its value may require to be updated if the token3 is modified.
+  */
+#define CONFIG_TOKEN_3_ENCRYPTION_TYPE_INDEX      ((uint32_t)11)
+
+/** @brief MIME type for the Wifi OOB token.
+  */
+#define WIFITOKEN_TYPE_STRING													"application/vnd.wfa.wsc"	
+/** @brief Length of the MIME type for the Wifi OOB token.
+  */
+#define WIFITOKEN_TYPE_STRING_LENGTH	 								((uint32_t)23)
+
+/**
+  * @brief Network key to be used when the Authentication is set to None.
+  *  Althought WPS defines a 0 length network key in such case, 
+  *  with tested phones a 8 digit value is required.
+  */
+#define NDEF_WIFI_DEFAULT_NETWORK_KEY	 								      "00000000"
+
+typedef enum {
+  NDEF_WIFI_ENCRYPTION_NONE = 0x0000, /**< WPS No Encryption (set to 0 for Android native support / should be 1) */
+  NDEF_WIFI_ENCRYPTION_WEP  = 0x0002, /**< WPS Encryption based on WEP  */
+  NDEF_WIFI_ENCRYPTION_TKIP = 0x0003, /**< WPS Encryption based on TKIP  */
+  NDEF_WIFI_ENCRYPTION_AES  = 0x0004 /**< WPS Encryption based on AES  */
+} Ndef_Wifi_Encryption_t;
+
+typedef enum {
+  NDEF_WIFI_AUTHENTICATION_NONE     = 0x0000, /**< WPS No Authentication (set to 0 for Android native support / should be 1)  */
+  NDEF_WIFI_AUTHENTICATION_WPAPSK   = 0x0002, /**< WPS Authentication based on WPAPSK  */
+  NDEF_WIFI_AUTHENTICATION_SHARED   = 0x0003, /**< WPS Authentication based on ??  */
+  NDEF_WIFI_AUTHENTICATION_WPA      = 0x0004, /**< WPS Authentication based on WPA  */
+  NDEF_WIFI_AUTHENTICATION_WPA2     = 0x0005, /**< WPS Authentication based on WPA2  */
+  NDEF_WIFI_AUTHENTICATION_WPA2PSK  = 0x0006 /**< WPS Authentication based on WPA2PSK  */
+} Ndef_Wifi_Authentication_t;
+
+/**
+  * @brief  WifiToken structure, to store Network SSID, Authentication Type, Encryption Type and Network Key.
+  */	 	 
+typedef struct 
+{
+	char NetworkSSID[32];                           /**< Store the Network SSID. */
+	Ndef_Wifi_Authentication_t AuthenticationType;  /**< Store the Authentication type to be used. */
+	Ndef_Wifi_Encryption_t EncryptionType;          /**< Store the Encryption to be used. */
+    char NetworkKey[32];                            /**< Store the Network Key. */
+}sWifiTokenInfo;
+
+	 	 
+uint16_t NDEF_ReadWifiToken(struct sRecordInfo *pRecordStruct, sWifiTokenInfo *pWifiTokenStruct);
+uint16_t NDEF_WriteWifiToken( sWifiTokenInfo *pWifiTokenStruct, I2C* mi2cChannel );
+
+/**
+  * @}
+  */
+
+#endif /* __LIB_NDEF_WIFIT_H */
+
+/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 lib_wrapper.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib_wrapper.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,49 @@
+/**
+  ******************************************************************************
+  * @file    lib_wrapper.h
+  * @author  MMY Application Team
+  * @version $Revision: 2702 $
+  * @date    $Date: 2016-07-13 18:45:05 +0200 (Wed, 13 Jul 2016) $
+  * @brief   This file help to have upper layer independent from HW
+ ******************************************************************************
+  * @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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LIB_WRAPPER_H
+#define __LIB_WRAPPER_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "NDEFcommon.h"
+#include "mbed.h"
+
+
+
+
+uint16_t NfcTag_ReadNDEF( uint8_t* pData,  I2C* mi2cChannel );
+uint16_t NfcTag_WriteNDEF(uint16_t Length, uint8_t* pData, I2C* mi2cChannel );
+uint16_t NfcTag_WriteProprietary(uint16_t Length, uint8_t* pData, I2C* mi2cChannel );
+uint16_t NfcTag_GetLength(uint16_t* Length, I2C* mi2cChannel);
+
+#endif /* __LIB_WRAPPER_H */
+
+
+/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 tagtype5_wrapper.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tagtype5_wrapper.cpp	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,517 @@
+/**
+  ******************************************************************************
+  * @file    tagtype5_wrapper.c 
+  * @author  MMY Application Team
+  * @version $Revision: 3210 $
+  * @date    $Date: 2016-12-05 15:37:48 +0100 (Mon, 05 Dec 2016) $
+  * @brief   This file provides an abstraction layer to the libNDEF for the NFC Forum Type5 Tag.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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 "tagtype5_wrapper.h"
+#include "BSP/x_nucleo_nfc04a1_nfctag.h"
+
+//void printDbg(char *str);
+//char tmp[40];
+/*
+typedef enum
+{
+  NFCTAG_OK      = 0,
+  NFCTAG_ERROR   = 1,
+  NFCTAG_BUSY    = 2,
+  NFCTAG_TIMEOUT = 3,
+  NFCTAG_NACK    = 4
+} NFCTAG_StatusTypeDef;
+*/
+/** @addtogroup Tag_Type_5 Type 5 Tag library
+ *  @ingroup libNFC_FORUM
+ *  @{
+ *  @brief    This module provides an abstraction layer to the NDEF library for the NFC Forum Type5 Tag.
+ *  @details  These functions manage the specificities of the Type5 Tag accesses.\n
+ *            The NFC Forum defines specific Capability Containers for the Type5 Tags.
+ *            The Capability Container provides basic information on how a tag can be accessed.
+ *            Depending on the memory size of the tag, 2 different CC will be used:
+ *             1. 4-bytes Capability Container (Memory Size < 16kbits):
+ *             |Byte0         |Byte1                        |Byte2        |Byte3           |
+ *             |:------------:|:---------------------------:|:-----------:|:--------------:|
+ *             | Magic Number | Version & Access Conditions | Memory Size | NFC Type 5 Tag |
+ *             2. 8-bytes Capability Container (Memory Size > 16kbits):
+ *             |Byte0         |Byte1                        |Byte2|Byte3           |Byte4|Byte5|Byte6      |Byte7      |
+ *             |:------------:|:---------------------------:|:---:|:--------------:|:---:|:---:|:---------:|:---------:|
+ *             | Magic Number | Version & Access Conditions | 00h | NFC Type 5 Tag |RFU  |RFU  |Memory Size|Memory Size|
+ *            @section Type5_Tag_Usage How to write a Type5 Tag Capability Container
+ *            1. Initialize the Capacity Container structure with the Tag compliant values:
+                 - Example for a 4kbits memory tag:
+
+                        CCFileStruct.MagicNumber  = NFCT5_MAGICNUMBER_E1_CCFILE;
+                        CCFileStruct.Version      = NFCT5_VERSION_V1_0;
+                        CCFileStruct.MemorySize   = 0x40;
+                        CCFileStruct.TT5Tag       = 0x0;
+
+                 - Example for a 64kbits memory tag:
+
+                        CCFileStruct.MagicNumber   = NFCT5_MAGICNUMBER_E2_CCFILE;
+                        CCFileStruct.Version       = NFCT5_VERSION_V1_0;
+                        CCFileStruct.MemorySize    = NFCT5_EXTENDED_CCFILE;
+                        CCFileStruct.ExtMemorySize = 0x400;
+                        CCFileStruct.TT5Tag        = 0x1;
+
+              2. Call the `NfcType5_TT5Init` function to write the Capability Container to the Tag:
+
+                        NfcType5_TT5Init();
+
+ */
+
+/** @brief Capability Container structure instance (global). */
+sCCFileInfo CCFileStruct;
+
+/**
+  * @brief  This function reads the data stored in the NDEF message.
+  * @param	pData Pointer on the buffer used to store the read data.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL  The buffer is too small for the NDEF message.
+  * @retval NDEF_ERROR_NOT_FORMATED     No Capability Container detected.
+  * @retval NDEF_ERROR                  Error when reading the NDEF message.
+  * @retval NDEF_OK                     NDEF message successfully read.
+  */
+uint16_t NfcTag_ReadNDEF( uint8_t* pData, I2C* mi2cChannel )
+{
+  uint16_t status = NDEF_ERROR;
+  TT5_TLV_t tlv;
+  uint8_t tlv_size = 0;
+  uint16_t DataLength;
+
+  /* Detect NDEF message in memory */
+  status = NfcType5_NDEFDetection( mi2cChannel );
+  if( status != NDEF_OK )
+  {
+    return status;
+  }
+  
+  /* Read TL of Type 5 */
+  status = BSP_NFCTAG_ReadData( (uint8_t*)&tlv, CCFileStruct.NDEF_offset, sizeof(TT5_TLV_t), mi2cChannel );
+  if( status != NDEF_OK )
+  {
+    return status;
+  }
+  
+  /* Check if L is on 3 or 1 byte and update length in buffer */
+  if( tlv.Length == NFCT5_3_BYTES_L_TLV )
+  {
+    tlv_size = 4;
+    DataLength = ((tlv.Length16 >> 8)&0xff) | ((tlv.Length16&0xff)<<8);
+  }
+  else
+  {
+    tlv_size = 2;
+    DataLength = tlv.Length;
+  }
+      /* If too many data to write return error */
+  if( DataLength > NDEF_MAX_SIZE )
+  {
+    return NDEF_ERROR_MEMORY_INTERNAL;
+  }
+  
+  /* Check CC file is in the correct mode to proceed */
+  if( CCFileStruct.State ==  TT5_INITIALIZED )
+  {
+    return NDEF_ERROR;
+  }
+
+  if( DataLength > 0 )
+  {
+    /* Read NDEF */
+    if( BSP_NFCTAG_ReadData( (pData), CCFileStruct.NDEF_offset + tlv_size, DataLength, mi2cChannel ) != NFCTAG_OK )
+    {
+      return NDEF_ERROR;
+    }
+  }
+  
+  return NDEF_OK;
+}
+uint32_t BSP_NFCTAG_GetByteSize( I2C* mi2cChannel );
+
+/**
+  * @brief  This function writes data in the NFC Tag.
+  * @param	Type    Type of the data: NDEF or Proprietary
+  * @param	Length  Number of bytes to write.
+  * @param	pData   Pointer on the buffer to copy.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL Memory size is too small for the data.
+  * @retval NDEF_ERROR_NOT_FORMATED    No Capability Container detected.
+  * @retval NDEF_ERROR                 Error when writing the Tag.
+  * @retval NDEF_OK                    The data has been successfully written.
+  */
+uint16_t NfcTag_WriteData(uint8_t Type, uint16_t Length , uint8_t *pData, I2C* mi2cChannel )
+{
+  TT5_TLV_t tlv;
+  uint8_t tlv_size;
+  uint32_t offset;
+  uint8_t NfcT5_Terminator = NFCT5_TERMINATOR_TLV;
+  
+  uint32_t max_length = BSP_NFCTAG_GetByteSize( mi2cChannel)        /* Memory size */
+                        - ((Length >= 0xFF) ? 4 : 2)    /* - TLV length */
+                        - sizeof(NfcT5_Terminator)      /* - Terminator TLV */
+                        - CCFileStruct.NDEF_offset;     /* - CCfile length */
+
+  /* If too many data to write return error */
+  if( Length > max_length )
+  {
+    return NDEF_ERROR_MEMORY_TAG;
+  }
+
+  /* Detect NDEF message in memory */
+  if( NfcType5_NDEFDetection( mi2cChannel ) != NDEF_OK )
+  {
+    return NDEF_ERROR;
+  }
+  
+  /* Prepare TLV */
+  tlv.Type = Type;
+  if(Length >= 0xFF)
+  {
+    tlv.Length = NFCT5_3_BYTES_L_TLV;
+    tlv.Length16 = ((Length&0xff)<<8) | ((Length>>8)&0xff) ;
+    tlv_size = 4;
+    
+  } else {
+    tlv.Length = Length;
+    tlv_size = 2;
+  }
+
+
+  offset = CCFileStruct.NDEF_offset;
+  /* Start write TLV to EEPROM */
+  if(BSP_NFCTAG_WriteData( (uint8_t*)&tlv, offset, tlv_size, mi2cChannel )!= NFCTAG_OK)
+    return NDEF_ERROR;
+  offset += tlv_size;
+
+  BSP_NFCTAG_WriteData( pData , offset, 4, mi2cChannel );
+
+
+
+  /* Continue write TLV data  to EEPROM */
+  if(BSP_NFCTAG_WriteData( pData , offset, Length, mi2cChannel ) != NFCTAG_OK )
+	  return NDEF_ERROR;
+	  offset +=Length;
+
+  
+  /* Write Terminator TLV */
+  if(BSP_NFCTAG_WriteData( &NfcT5_Terminator, offset, sizeof(NfcT5_Terminator), mi2cChannel ) != NFCTAG_OK)
+    return NDEF_ERROR;
+  
+  return NDEF_OK;
+
+}
+
+/**
+  * @brief  This function writes a NDEF message in the NFC Tag.
+  * @param	Length Number of bytes to write.
+  * @param	pData  Pointer on the buffer to copy.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL Memory size is too small for the data.
+  * @retval NDEF_ERROR_NOT_FORMATED    No Capability Container detected.
+  * @retval NDEF_ERROR                 Error when writing the Tag.
+  * @retval NDEF_OK                    The data has been successfully written.
+  */
+uint16_t NfcTag_WriteNDEF(uint16_t Length , uint8_t *pData, I2C* mi2cChannel )
+{
+  return NfcTag_WriteData(NFCT5_NDEF_MSG_TLV,Length,pData, mi2cChannel);
+}
+
+/**
+  * @brief  This function writes a Proprietary message to the NFC Tag.
+  * @param	Length Number of byte to write.
+  * @param	pData  Pointer on the buffer to copy.
+  * @retval NDEF_ERROR_MEMORY_INTERNAL Memory size is too small for the data.
+  * @retval NDEF_ERROR_NOT_FORMATED    No Capability Container detected.
+  * @retval NDEF_ERROR                 Error when writing the Tag.
+  * @retval NDEF_OK                    The data has been successfully written.
+  */
+uint16_t NfcTag_WriteProprietary(uint16_t Length , uint8_t *pData, I2C* mi2cChannel )
+{
+  return NfcTag_WriteData(NFCT5_PROPRIETARY_TLV,Length,pData, mi2cChannel);
+}
+
+
+/**
+  * @brief  This functions writes the Capability Container in the NFC Tag.
+  * @param  pCCBuffer Pointer on the buffer containnig the Capability Container.
+  * @retval NDEF_ERROR Error when writing the Tag.
+  * @retval NDEF_OK    The CC has been successfully written.
+  */
+uint16_t NfcType5_WriteCCFile( const uint8_t * const pCCBuffer, I2C* mi2cChannel )
+{
+  NFCTAG_StatusTypeDef ret_value;
+  
+  /* Write first block of CCFile */
+  ret_value = BSP_NFCTAG_WriteData( pCCBuffer, 0x00, 0x4, mi2cChannel );
+ 
+  /* If extended memory writes the next 4 bytes */
+  if( (pCCBuffer[2] == 0x00) && (ret_value == NFCTAG_OK) )
+  {
+    ret_value = BSP_NFCTAG_WriteData( pCCBuffer + 4, 0x04, 4, mi2cChannel );
+  }
+
+  if( ret_value != NFCTAG_OK )
+  {
+    return NDEF_ERROR;
+  }
+  
+	return NDEF_OK;
+}
+
+/**
+  * @brief  This functions reads the Capability Container from the NFC Tag.
+  * @param  pCCBuffer Pointer on the buffer used to store the CC.
+  * @retval NDEF_ERROR Error when reading the Tag.
+  * @retval NDEF_OK    The CC has been successfully read.
+  */
+uint16_t NfcType5_ReadCCFile( uint8_t * const pCCBuffer, I2C* mi2cChannel )
+{
+  NFCTAG_StatusTypeDef ret_value;
+  
+  /* Read 4 bytes of CC File */
+  ret_value = BSP_NFCTAG_ReadData( pCCBuffer, 0x00, 4, mi2cChannel );
+
+  /* If extended memory reads the next 4 bytes */
+  if( (pCCBuffer[2] == 0x00) && (ret_value == NFCTAG_OK) )
+  {
+    ret_value = BSP_NFCTAG_ReadData( pCCBuffer + 4, 0x04, 4, mi2cChannel );
+  }
+  
+  if( ret_value != NFCTAG_OK )
+  {
+    return NDEF_ERROR;
+  }
+  
+	return NDEF_OK;
+}
+
+/**
+  * @brief  This function initializes the Capability Container and an empty NDEF message in a NFC Tag.
+  * @details The Capability Container content is defined by the global variable `CCFileStruct`.
+  * @retval NDEF_ERROR The Tag has not been initialized.
+  * @retval NDEF_OK    The Tag has been successfully initialized.
+  */
+uint16_t NfcType5_TT5Init( I2C* mi2cChannel )
+{
+  NFCTAG_StatusTypeDef ret_value = NFCTAG_OK;
+  uint16_t status;
+  uint8_t accbuffer[8];
+  uint8_t cdata;
+
+  /* Prepare buffer to update CCFile */
+  accbuffer[0] = CCFileStruct.MagicNumber;
+  accbuffer[1] = CCFileStruct.Version;
+  accbuffer[2] = CCFileStruct.MemorySize;
+  accbuffer[3] = CCFileStruct.TT5Tag;
+  CCFileStruct.NDEF_offset = 0x04;
+  
+  /* If extended memory prepare the length bytes */
+  if( CCFileStruct.MemorySize == NFCT5_EXTENDED_CCFILE )
+  {
+    accbuffer[6] = (uint8_t)(CCFileStruct.ExtMemorySize >> 8);
+    accbuffer[7] = (uint8_t)(CCFileStruct.ExtMemorySize & 0xFF);
+    CCFileStruct.NDEF_offset = 0x08;
+  }
+  
+  /* Update CCFile */
+  status = NfcType5_WriteCCFile( accbuffer, mi2cChannel );
+
+
+  if( status != NDEF_OK )
+  {
+    return status;
+  }
+
+  /* Update NDEF TLV for INITIALIZED state */
+  /* Update T */
+  cdata = NFCT5_NDEF_MSG_TLV;
+  ret_value = BSP_NFCTAG_WriteData( &cdata, CCFileStruct.NDEF_offset, 1, mi2cChannel );
+  if( ret_value != NFCTAG_OK )
+  {
+    return NDEF_ERROR;
+  }
+
+  /* Update L */
+  cdata = 0x00;
+  ret_value = BSP_NFCTAG_WriteData( &cdata, (CCFileStruct.NDEF_offset + 1), 1, mi2cChannel );
+  if( ret_value != NFCTAG_OK )
+  {
+    return NDEF_ERROR;
+  }
+  
+  return NDEF_OK;
+}
+
+/**
+  * @brief    This function detects a NDEF message in a Type 5 Tag.
+  * @details  It first detects the Capability Container and then look for the NDEF TLV.
+  *           The `CCfileStruct` global variable is updated accordingly with what is detected.
+  * @retval NDEF_OK                 NDEF message Tag Type 5 detected.
+  * @retval NDEF_ERROR_NOT_FORMATED Device is not a NFC Tag Type 5 Tag.
+  */
+uint16_t NfcType5_NDEFDetection( I2C* mi2cChannel )
+{
+ uint8_t acc_buffer[8];
+  TT5_TLV_t tlv_detect;
+  uint16_t status;
+  uint32_t memory_size;
+  
+  CCFileStruct.State = TT5_NO_NDEF;
+
+  /* Read CCFile */
+  status = NfcType5_ReadCCFile( acc_buffer, mi2cChannel );
+
+  if( status != NDEF_OK )
+  {
+    return status;
+  }
+  
+  /* Check Byte 0 is equal to magic number */
+  if( ( acc_buffer[0] != NFCT5_MAGICNUMBER_E1_CCFILE ) && ( acc_buffer[0] != NFCT5_MAGICNUMBER_E2_CCFILE ) )
+  {
+   return NDEF_ERROR_NOT_FORMATED;
+  }
+  /* Check Version number */
+  else if( ( (acc_buffer[1]&0xFC) != 0x40 ) )
+  {
+    return NDEF_ERROR_NOT_FORMATED;
+  }
+  
+  /* Check if CCFile is on 4 Bytes or 8 Bytes */
+  if( acc_buffer[2] == 0x00 )
+  {
+    /* Update CCFIle structure */
+    CCFileStruct.MemorySize = 0x0;
+    CCFileStruct.ExtMemorySize = (uint16_t)acc_buffer[6];
+    CCFileStruct.ExtMemorySize = ( CCFileStruct.ExtMemorySize << 8 ) |  acc_buffer[7];
+    memory_size = CCFileStruct.ExtMemorySize;
+    CCFileStruct.NDEF_offset = 8;
+  }
+  else
+  {
+    /* Update CCFIle structure */
+    CCFileStruct.MemorySize = acc_buffer[2];
+    CCFileStruct.ExtMemorySize = 0x0;
+    memory_size = CCFileStruct.MemorySize;
+    CCFileStruct.NDEF_offset = 4;
+  }
+  
+  /* Update CCFIle structure */
+  CCFileStruct.MagicNumber = (TT5_MagicNumber_t)acc_buffer[0];
+  CCFileStruct.Version = acc_buffer[1];
+  CCFileStruct.TT5Tag = acc_buffer[3];
+  
+  /* Search for position of NDEF TLV in memory and tag status */
+  while( ( BSP_NFCTAG_ReadData( (uint8_t *)&tlv_detect, CCFileStruct.NDEF_offset, sizeof(TT5_TLV_t), mi2cChannel ) == NFCTAG_OK ) && ( CCFileStruct.NDEF_offset < memory_size ) )
+  {
+    /* Detect first NDEF Message in memory */
+    if( tlv_detect.Type == NFCT5_NDEF_MSG_TLV )
+    {
+      if( tlv_detect.Length == 0x00 )
+      {
+        CCFileStruct.State = TT5_INITIALIZED;
+      }
+      else
+      {
+        if( CCFileStruct.Version & 0x3 )
+        {
+          CCFileStruct.State = TT5_READ;
+        }
+        else
+        {
+          CCFileStruct.State = TT5_READ_WRITE;
+        }
+      }
+      return NDEF_OK;
+    }
+    /* If Proprietary NDEF jump to end of proprietary message */
+    else if( tlv_detect.Type == NFCT5_PROPRIETARY_TLV )
+    {
+      if( tlv_detect.Length == NFCT5_3_BYTES_L_TLV )
+      {
+        CCFileStruct.NDEF_offset = CCFileStruct.NDEF_offset + tlv_detect.Length16;
+        continue;
+      }
+      else
+      {
+        CCFileStruct.NDEF_offset = CCFileStruct.NDEF_offset + tlv_detect.Length;
+        continue;
+      }
+    }
+    /* if Terminator no NDEF detected */
+    else if( tlv_detect.Type == NFCT5_TERMINATOR_TLV )
+    {
+     return NDEF_ERROR_NOT_FORMATED;
+    }
+      
+    CCFileStruct.NDEF_offset++;
+  }
+  
+  return NDEF_ERROR_NOT_FORMATED;
+}
+
+
+
+/**
+  * @brief  This function reads and return the size of the NDEF message in the NFC tag.
+  * @param	Length Pointer on the NDEF size to be returned.
+  * @retval NDEF_ERROR_NOT_FORMATED Device is not a NFC Tag Type 5 Tag.
+  * @retval NDEF_ERROR              The NDEF message size has not been read.
+  * @retval NDEF_OK                 The NDEF message size has been retrieved.
+  */
+uint16_t NfcTag_GetLength(uint16_t* Length, I2C* mi2cChannel)
+{
+  
+  uint16_t status = NDEF_ERROR;
+  TT5_TLV_t tlv;
+  
+  /* Detect NDEF message in memory */
+  status = NfcType5_NDEFDetection( mi2cChannel  );
+  if( status != NDEF_OK )
+  {
+    return status;
+  }
+  
+  /* Read TL of Type 5 */
+  status = BSP_NFCTAG_ReadData( (uint8_t*)&tlv, CCFileStruct.NDEF_offset, sizeof(TT5_TLV_t), mi2cChannel );
+  if( status != NFCTAG_OK )
+  {
+    return NDEF_ERROR;
+  }
+  
+  if(tlv.Length != NFCT5_3_BYTES_L_TLV)
+  {
+    *Length = tlv.Length;
+  } else {
+    *Length = ((tlv.Length16 >> 8)&0xff) | ((tlv.Length16 & 0xff) << 8);
+  }
+  
+  return NDEF_OK;
+  
+}
+
+
+/**
+  * @}
+  */ 
+
+/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r de13951f30f6 tagtype5_wrapper.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tagtype5_wrapper.h	Thu Nov 14 10:34:11 2019 +0000
@@ -0,0 +1,126 @@
+/**
+  ******************************************************************************
+  * @file    tagtype5_wrapper.h
+  * @author  MMY Application Team
+  * @version $Revision: 3310 $
+  * @date    $Date: 2017-01-13 11:22:18 +0100 (Fri, 13 Jan 2017) $
+  * @brief   This file provides an abstraction layer to the libNDEF for the NFC Forum Type5 Tag.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 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.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __TAGTYPE5_WRAPPER_H
+#define __TAGTYPE5_WRAPPER_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "lib_NDEF.h"
+
+/** @addtogroup Tag_Type_5
+  * @{
+  */
+
+/* Exported types ------------------------------------------------------------*/
+/**
+  * @brief  Tag Type 5 State enumeration definition.
+  */
+typedef enum
+{
+  TT5_NO_NDEF = 0,  /**< No data detected in the tag. */
+  TT5_INITIALIZED,  /**< Capability container detected. */
+  TT5_READ_WRITE,   /**< Read-Write data detected. */
+  TT5_READ          /**< Read-Only data message detected. */
+} TT5_State;
+
+/** @brief Type5 Tag Capability Container Magic numbers as defined by the NFC Forum. */
+typedef enum {
+  NFCT5_MAGICNUMBER_E1_CCFILE = 0xE1, /**<  Complete data area can be read by 1-byte block adrdess commands. */
+  NFCT5_MAGICNUMBER_E2_CCFILE = 0xE2  /**<  Last part of the data area can be only read by 2-bytes block address commands.\n
+                                            The first 256 blocks can be read by 1-byte block address commands. */
+} TT5_MagicNumber_t;
+
+/**
+  * @brief  Type5 Tag Capability Container structure.
+  */
+typedef struct
+{
+  TT5_MagicNumber_t MagicNumber;  /**< CCfile[0]: Magic Number should be E1h or E2h (for extended API) */
+  uint8_t Version;                /**< CCfile[1]: Capability container version (b7-b4) and access conditions (b3-b0) */
+  uint8_t MemorySize;             /**< CCfile[2]: Memory size, expressed in 8 bytes blocks, set to 0 if tag size is greater than 16kbits. */
+  uint8_t TT5Tag;                 /**< CCfile[3]: Additionnal information on the Type5 Tag:\n
+                                                  b0: supports `read multiple block` commands\n
+                                                  b1: RFU\n
+                                                  b2: RFU\n
+                                                  b3: supports `lock block` commands\n
+                                                  b4: requires the `special frame` format
+                                    */
+  uint8_t rsved1;                 /**< RFU */
+  uint8_t rsved2;                 /**< RFU */
+  uint16_t ExtMemorySize;         /**< CCfile[6],CCfile[7]: Memory size, expressed in 8 bytes blocks, when tag size is greater than 16kbits. */
+  TT5_State State;                /**< Indicates if a NDEF message is present. */
+  uint32_t NDEF_offset;           /**< Indicates the address of a NDEF message in the tag. */
+}sCCFileInfo;
+
+/** @brief Type5 Tag Type-Length-Value structure as defined by the NFC Forum */
+typedef struct
+{
+  uint8_t   Type;     /**< NFC Forum message Type */
+  uint8_t   Length;   /**< Message length if lesser than 255 bytes */
+  uint16_t  Length16; /**< Message length if greater than or equal to 255 bytes */
+} TT5_TLV_t;
+
+
+/* Exported constants --------------------------------------------------------*/
+/** @brief Memory size value indicating that this is a 8-bytes Capability Container */
+#define NFCT5_EXTENDED_CCFILE             0x00
+/** @brief Capability container version 1.0 */
+#define NFCT5_VERSION_V1_0                0x40
+/** @brief Read access condition mask for the Capability Container byte1 */
+#define NFCT5_READ_ACCESS                 0x0C
+/** @brief Write access condition mask for the Capability Container byte1 */
+#define NFCT5_WRITE_ACCESS                0x03
+
+/** @brief Type5 Tag NDEF message TLV-Type. */
+#define NFCT5_NDEF_MSG_TLV                ((uint8_t) 0x03)
+/** @brief Type5 Tag Proprietary message TLV-Type. */
+#define NFCT5_PROPRIETARY_TLV             ((uint8_t) 0xFD)
+/** @brief Type5 Tag Terminator TLV-Type. */
+#define NFCT5_TERMINATOR_TLV              ((uint8_t) 0xFE)
+/** @brief TLV-Length indicating a 4-bytes TLV (Length coded on 2 bytes). */
+#define NFCT5_3_BYTES_L_TLV               ((uint8_t) 0xFF)
+
+/* Exported macro ------------------------------------------------------------*/
+/* External variables --------------------------------------------------------*/
+extern sCCFileInfo CCFileStruct;
+
+/* Exported functions ------------------------------------------------------- */
+uint16_t NfcType5_WriteCCFile( const uint8_t * const pCCBuffer, I2C* mi2cChannel );
+uint16_t NfcType5_ReadCCFile( uint8_t * const pCCBuffer, I2C* mi2cChannel );
+uint16_t NfcType5_TT5Init( I2C* mi2cChannel );
+uint16_t NfcType5_NDEFDetection( I2C* mi2cChannel );
+
+
+#endif /* __TAGTYPE5_WRAPPER_H */
+
+/* @}
+ */
+
+/******************* (C) COPYRIGHT 2016 STMicroelectronics *****END OF FILE****/