X_NUCLEO_NFC02A1 library for M24LR

Dependencies:   ST_INTERFACES

Dependents:   HelloWorld_NFC02A1_mbedOS HelloWorld_NFC02A1laatste HelloWorld_NFC02A1

Fork of X_NUCLEO_NFC02A1 by ST Expansion SW Team

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NDefNfcTagM24LR.cpp Source File

NDefNfcTagM24LR.cpp

00001 /**
00002   ******************************************************************************
00003   * @file       NdefNfcTagM24LR.cpp
00004   * @author     AMG Central Lab
00005   * @version    V2.0.0
00006   * @date       19 May 2017
00007   * @brief      Wrapper class of the NDefLib library to write/read NDEF messages.
00008   ******************************************************************************
00009   * @attention
00010   *
00011   * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
00012   *
00013   * Redistribution and use in source and binary forms, with or without modification,
00014   * are permitted provided that the following conditions are met:
00015   *   1. Redistributions of source code must retain the above copyright notice,
00016   *      this list of conditions and the following disclaimer.
00017   *   2. Redistributions in binary form must reproduce the above copyright notice,
00018   *      this list of conditions and the following disclaimer in the documentation
00019   *      and/or other materials provided with the distribution.
00020   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00021   *      may be used to endorse or promote products derived from this software
00022   *      without specific prior written permission.
00023   *
00024   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00025   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00028   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00030   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00032   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034   *
00035   ******************************************************************************
00036   */
00037 
00038 
00039 #include <cmath>
00040 #include "NDefNfcTagM24LR.h"
00041 
00042 
00043 /* wait 1sec, driver is configured to let 200ms for command to complete */
00044 /* which is enough for all commands except GetSession if RF session is already opened */
00045 /* Smartphone generally releases the session within the second, anyway the user can modify this value */
00046 #define OPENSESSION_NTRIALS 5
00047 
00048 #define CC_FILE_LENGTH_BYTE 15
00049 
00050 
00051 #define NFCT5_MAGICNUMBER_E1_CCFILE       0xE1
00052 #define NFCT5_MAGICNUMBER_E2_CCFILE       0xE2
00053 #define NFCT5_EXTENDED_CCFILE             0xFF
00054 #define NFCT5_VERSION_V1_0                0x40
00055 #define NFCT5_READ_ACCESS                 0x0C
00056 #define NFCT5_WRITE_ACCESS                0x03
00057 
00058 #define NFCT5_NDEF_MSG_TLV                0x03
00059 #define NFCT5_PROPRIETARY_TLV             0xFD
00060 #define NFCT5_TERMINATOR_TLV              0xFE
00061 #define NFCT5_3_BYTES_L_TLV               0xFF
00062     
00063 
00064 #define NDEF_MAX_SIZE               NFC_DEVICE_MAX_NDEFMEMORY
00065 
00066 #define NDEF_SIZE_OFFSET            0
00067 #define FIRST_RECORD_OFFSET         2
00068 
00069 #ifndef MIN
00070 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
00071 #endif
00072 
00073 #define NFCTAG_4M_SIZE            0x200
00074 #define NFCTAG_16M_SIZE           0x800
00075 #define NFCTAG_64M_SIZE           0x2000
00076 
00077 #define MAX_NDEF_MEM                 0x200
00078 #define M24LR_MAX_SIZE               NFCTAG_4M_SIZE
00079 #define M24LR_NDEF_MAX_SIZE          MIN(M24LR_MAX_SIZE,MAX_NDEF_MEM)
00080 #define NFC_DEVICE_MAX_NDEFMEMORY    M24LR_NDEF_MAX_SIZE
00081 
00082 /**
00083   * @brief  This function read the data stored in NDEF file at defined offset.
00084   * @param  Offset : Offset in the NDEF file.
00085   * @param  DataSize : Number of byte to read.
00086   * @param  pData : pointer on buffer to store read data.
00087   * @retval NDEF_ERROR_MEMORY_INTERNAL : Size not compatible with memory.
00088   * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported.
00089   * @retval NDEF_ERROR : No NDEF in the tag.
00090   * @retval NDEF_OK : The operation is completed.
00091   */
00092 uint16_t NDefNfcTagM24LR::ReadData( uint16_t Offset , uint16_t DataSize , uint8_t* pData )
00093 {
00094   uint16_t status = NDEF_ERROR;
00095   uint8_t atlv_detect[4];
00096   uint8_t index = 0;
00097   
00098   /* If too many data to write return error */
00099   if ( DataSize > NDEF_MAX_SIZE ) {
00100     return NDEF_ERROR_MEMORY_INTERNAL;
00101   }
00102   
00103   /* Detect NDEF message in memory */
00104   status = NfcType5_NDEFDetection( );
00105   if ( status != NDEF_OK ) {
00106     return status;
00107   }
00108 
00109   /* Read TL of Type 5 */
00110   status = NDefReadByte(CCFileStruct.NDEF_offset, 4, atlv_detect);
00111   if ( status != NDEF_OK ){
00112     return status;
00113   }
00114   
00115   if ( atlv_detect[1] == NFCT5_3_BYTES_L_TLV ) {
00116     index = 2;
00117   }
00118 
00119   if (Offset==0 && DataSize>=2) {
00120     if ( atlv_detect[1] == NFCT5_3_BYTES_L_TLV ) {
00121       pData[0] = atlv_detect[2];
00122       pData[1] = atlv_detect[3];
00123     } else {
00124       pData[0] = 0x00;
00125       pData[1] = atlv_detect[1];
00126     }
00127     DataSize -= 2;
00128     pData += 2;
00129   }
00130 
00131   /* Check CC file is in the correct mode to proceed */
00132   if ( CCFileStruct.State ==  TT5_INITIALIZED ) {
00133     return NDEF_ERROR;
00134   }
00135 
00136   if (DataSize > 0) {
00137     /* Read NDEF */
00138     if ( NDefReadByte(CCFileStruct.NDEF_offset + index + Offset, DataSize, pData) != NFC_SUCCESS ) {
00139       return NDEF_ERROR;
00140     }
00141   }
00142   
00143   return NDEF_OK;
00144 }
00145 
00146 /**
00147   * @brief  This function writes data in NDEF file at defined offset.
00148   * @param  Offset : Offset in the NDEF file.
00149   * @param  DataSize : Number of byte to write.
00150   * @param  pData : pointer on buffer to copy.
00151   * @retval NDEF_ERROR_MEMORY_INTERNAL : Size not compatible with memory.
00152   * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported.
00153   * @retval NDEF_ERROR : No NDEF in the tag.
00154   * @retval NDEF_OK : The operation is completed.
00155   */
00156 uint16_t NDefNfcTagM24LR::WriteData( uint16_t Offset , uint32_t DataSize , uint8_t *pData )
00157 {
00158   uint8_t atlv[4];
00159   uint8_t index = 0;
00160   uint16_t NDEF_Size = 0;
00161   bool status;
00162 
00163   /* Do not include length bytes */
00164   DataSize -= FIRST_RECORD_OFFSET;
00165   
00166   /* If too many data to write return error */
00167   if ( DataSize > NDEF_MAX_SIZE ) {
00168     return NDEF_ERROR_MEMORY_INTERNAL;
00169   }
00170   
00171   /* Detect NDEF message in memory */
00172   if ( NfcType5_NDEFDetection( ) != NDEF_OK ) {
00173     return NDEF_ERROR;
00174   }
00175  
00176   /* Extract NDEF Size from buffer */
00177   NDEF_Size = (uint16_t)(pData[0] << 8);
00178   NDEF_Size = NDEF_Size | (uint16_t)(pData[1] );
00179   
00180   /* If entire NDEF is written, update Length of Type 5 */
00181   if ( DataSize == NDEF_Size ) {
00182     /* Check if L is on 3 or 1 byte */
00183     if ( NDEF_Size >= NFCT5_3_BYTES_L_TLV ) {
00184       /* First init L with 0, will be updated at the end */
00185       atlv[1] = 0x00;
00186       atlv[2] = 0x00;
00187       atlv[3] = 0x00;
00188       status = NDefWriteByte( (atlv + 1), 3, (CCFileStruct.NDEF_offset + 1));
00189       index += 4; 
00190     } else {
00191       /* First inti L with 0, will be updated at the end */
00192       atlv[1] = 0x00;
00193       status = NDefWriteByte( (atlv + 1), 1, (CCFileStruct.NDEF_offset + 1));
00194       index += 2;
00195     }
00196   }
00197   
00198   /* Start write NDEF message to EEPROM */
00199   status = NDefWriteByte( (pData + FIRST_RECORD_OFFSET), DataSize, CCFileStruct.NDEF_offset + index + Offset);
00200   if ( status != NFC_SUCCESS ) {
00201     return NDEF_ERROR;
00202   }
00203   
00204   /* If entire NDEF is written, update Length of Type 5 */
00205   if ( DataSize == NDEF_Size ) {
00206     /* Check if L is on 3 or 1 byte */
00207     if ( NDEF_Size >= NFCT5_3_BYTES_L_TLV ) {
00208       /* Update Length value */
00209       atlv[1] = NFCT5_3_BYTES_L_TLV;
00210       atlv[2] = pData[0];
00211       atlv[3] = pData[1];
00212       status = NDefWriteByte( (atlv + 1), 3, (CCFileStruct.NDEF_offset + 1));
00213     } else {
00214       /* Update Length value */
00215       atlv[1] = pData[1];
00216       status = NDefWriteByte( (atlv + 1), 1, (CCFileStruct.NDEF_offset + 1));
00217     }
00218 
00219     /* Write Terminator TLV */
00220     atlv[0] = NFCT5_TERMINATOR_TLV;
00221     status = NDefWriteByte( atlv, 1, CCFileStruct.NDEF_offset + index + NDEF_Size);
00222   }
00223   
00224   return NDEF_OK;
00225 }
00226 
00227 /**
00228   * @brief  This functions writes CCFile in EEPROM.
00229   * @param  pCCBuffer : pointer on the buffer containnig CC file.
00230   * @retval NFCTAG status.
00231   */
00232 uint16_t NDefNfcTagM24LR::NfcType5_WriteCCFile( const uint8_t * const pCCBuffer )
00233 {
00234   bool ret_value;
00235   
00236   /* Write first block of CCFile */
00237   ret_value = NDefWriteByte( pCCBuffer, 0x4, 0x00);
00238  
00239   /* If extended memory writes the next 4 bytes */
00240   if ( (pCCBuffer[2] == 0x00) && (ret_value == NFC_SUCCESS) ) {
00241     ret_value = NDefWriteByte( pCCBuffer + 4, 4, 0x04);
00242   }
00243 
00244   if ( ret_value != NFC_SUCCESS ) {
00245     return NDEF_ERROR;
00246   }
00247   
00248   return NDEF_OK;
00249 }
00250 
00251 /**
00252   * @brief  This functions reads CCFile from EEPROM.
00253   * @param  pCCBuffer : pointer on the buffer containnig CC file.
00254   * @retval NFCTAG status.
00255   */
00256 uint16_t NDefNfcTagM24LR::NfcType5_ReadCCFile( uint8_t * const pCCBuffer )
00257 {
00258   bool ret_value;
00259   
00260   /* Read 4 bytes of CC File */
00261   ret_value = NDefReadByte(0x00, 4, pCCBuffer);
00262 
00263   /* If extended memory reads the next 4 bytes */
00264   if ( (pCCBuffer[2] == 0x00) && (ret_value == NFC_SUCCESS) ) {
00265     ret_value = NDefReadByte(0x04, 4, pCCBuffer + 4 );
00266   }
00267   
00268   if ( ret_value != NFC_SUCCESS ) {
00269     return NDEF_ERROR;
00270   }
00271   
00272   return NDEF_OK;
00273 }
00274 
00275 /**
00276   * @brief  This functions initializes Nfc Type.
00277   * @param  None.
00278   * @retval NFCTAG status.
00279   */
00280 uint16_t NDefNfcTagM24LR::NfcType5_TT5Init( void )
00281 {
00282   bool ret_value ;
00283   uint16_t status;
00284   uint8_t accbuffer[8];
00285   uint8_t cdata;
00286 
00287   /* Prepare buffer to update CCFile */
00288   accbuffer[0] = CCFileStruct.MagicNumber;
00289   accbuffer[1] = CCFileStruct.Version;
00290   accbuffer[2] = CCFileStruct.MemorySize;
00291   accbuffer[3] = CCFileStruct.TT5Tag;
00292   CCFileStruct.NDEF_offset = 0x04;
00293   
00294   /* If extended memory prepare the length bytes */
00295   if ( CCFileStruct.MemorySize == NFCT5_EXTENDED_CCFILE ) {
00296     accbuffer[6] = (uint8_t)(CCFileStruct.ExtMemorySize >> 8);
00297     accbuffer[7] = (uint8_t)(CCFileStruct.ExtMemorySize & 0xFF);
00298     CCFileStruct.NDEF_offset = 0x08;
00299   }
00300   
00301   /* Update CCFile */
00302   status = NfcType5_WriteCCFile( accbuffer );
00303   if ( status != NDEF_OK ) {
00304     return status;
00305   }
00306   
00307   /* Update NDEF TLV for INITIALIZED state */
00308   /* Update T */
00309   cdata = NFCT5_NDEF_MSG_TLV;
00310   ret_value = NDefWriteByte( &cdata, 1, CCFileStruct.NDEF_offset);
00311   if ( ret_value != NFC_SUCCESS ) {
00312     return NDEF_ERROR;
00313   }
00314 
00315   /* Update L */
00316   cdata = 0x00;
00317   ret_value = NDefWriteByte( &cdata, 1, (CCFileStruct.NDEF_offset + 1));
00318   if ( ret_value != NFC_SUCCESS ) {
00319     return NDEF_ERROR;
00320   }
00321   
00322   return NDEF_OK;
00323 }
00324 
00325 /**
00326   * @brief  This functions detects Nfc Tyoe.
00327   * @param  None.
00328   * @retval NDEF_ERROR_NOT_FORMATED : CCFile data not supported.
00329   * @retval NDEF_OK : The operation is completed.
00330   */
00331 uint16_t NDefNfcTagM24LR::NfcType5_NDEFDetection( void )
00332 {
00333   uint8_t acc_buffer[8];
00334   uint8_t atlv_detect[4];
00335   uint16_t status;
00336   uint32_t memory_size;
00337   
00338   CCFileStruct.State = TT5_NO_NDEF;
00339   
00340   /* Read CCFile */
00341   status = NfcType5_ReadCCFile( acc_buffer );
00342   if ( status != NDEF_OK ) {
00343     return status;
00344   }
00345   
00346   /* Check Byte 0 is equal to magic number */
00347   if ( ( acc_buffer[0] != NFCT5_MAGICNUMBER_E1_CCFILE ) && ( acc_buffer[0] != NFCT5_MAGICNUMBER_E2_CCFILE ) ) {
00348     return NDEF_ERROR_NOT_FORMATED;
00349   } else if ( ( (acc_buffer[1]&0xFC) != 0x40 ) ) { /* Check Version number */
00350     return NDEF_ERROR_NOT_FORMATED;
00351   }
00352   
00353   /* Check if CCFile is on 4 Bytes or 8 Bytes */
00354   if ( acc_buffer[2] == 0x00 ) {
00355     /* Update CCFIle structure */
00356     CCFileStruct.MemorySize = 0x0;
00357     CCFileStruct.ExtMemorySize = (uint16_t)acc_buffer[6];
00358     CCFileStruct.ExtMemorySize = ( CCFileStruct.ExtMemorySize << 8 ) |  acc_buffer[7];
00359     memory_size = CCFileStruct.ExtMemorySize;
00360     CCFileStruct.NDEF_offset = 8;
00361   } else {
00362     /* Update CCFIle structure */
00363     CCFileStruct.MemorySize = acc_buffer[2];
00364     CCFileStruct.ExtMemorySize = 0x0;
00365     memory_size = CCFileStruct.MemorySize;
00366     CCFileStruct.NDEF_offset = 4;
00367   }
00368   
00369   /* Update CCFIle structure */
00370   CCFileStruct.MagicNumber = acc_buffer[0];
00371   CCFileStruct.Version = acc_buffer[1];
00372   CCFileStruct.TT5Tag = acc_buffer[3];
00373   
00374   /* Search for position of NDEF TLV in memory and tag status */
00375   while( ( NDefReadByte(CCFileStruct.NDEF_offset, 4, atlv_detect) == NFC_SUCCESS ) && ( CCFileStruct.NDEF_offset < memory_size ) ) {
00376     /* Detect first NDEF Message in memory */
00377     if ( atlv_detect[0] == NFCT5_NDEF_MSG_TLV ) {
00378       if ( atlv_detect[1] == 0x00 ) {
00379         CCFileStruct.State = TT5_INITIALIZED;
00380       } else {
00381         if ( CCFileStruct.Version & 0x3 ) {
00382           CCFileStruct.State = TT5_READ;
00383         } else {
00384           CCFileStruct.State = TT5_READ_WRITE;
00385         }
00386       }
00387       return NDEF_OK;
00388     } else if ( atlv_detect[0] == NFCT5_PROPRIETARY_TLV ) { /* If Proprietary NDEF jump to end of proprietary message */
00389       if ( atlv_detect[1] == NFCT5_3_BYTES_L_TLV ) {
00390         CCFileStruct.NDEF_offset = CCFileStruct.NDEF_offset + ( (uint32_t)atlv_detect[2] << 8 ) + atlv_detect[3];
00391         continue;
00392       } else {
00393         CCFileStruct.NDEF_offset = CCFileStruct.NDEF_offset + atlv_detect[1];
00394         continue;
00395       }
00396     } else if ( atlv_detect[0] == NFCT5_TERMINATOR_TLV ) { /* if Terminator no NDEF detected */
00397       return NDEF_ERROR_NOT_FORMATED;
00398     }
00399 
00400     CCFileStruct.NDEF_offset++;
00401   }
00402   
00403   return NDEF_ERROR_NOT_FORMATED;
00404 }
00405 
00406 /**
00407   * @brief  This functions opens a session.
00408   * @param  force : force the opening.
00409   * @retval true.
00410   */
00411 bool NDefNfcTagM24LR::open_session(bool force) {
00412   uint16_t status = NfcType5_NDEFDetection();
00413 
00414   if ( status != NDEF_OK ) {
00415     CCFileStruct.MagicNumber = NFCT5_MAGICNUMBER_E1_CCFILE;
00416     CCFileStruct.Version = NFCT5_VERSION_V1_0;
00417     CCFileStruct.MemorySize = ( M24LR_MAX_SIZE / 8 ) & 0xFF;
00418     CCFileStruct.TT5Tag = 0x05;
00419     /* Init of the Type Tag 5 component (M24LR) */
00420     while ( NfcType5_TT5Init( ) != NDEF_OK );
00421   }
00422 
00423   mIsSessionOpen = 1;
00424 
00425   return true;
00426 }
00427 
00428 
00429 /**
00430   * @brief  This functions closes a session.
00431   * @param  None.
00432   * @retval true.
00433   */
00434 bool NDefNfcTagM24LR::close_session() 
00435 {
00436     return true;
00437 }
00438 
00439 /**
00440   * @brief  This functions writes bytes.
00441   * @param  byffer : the buffer containing data.
00442   * @param  length: the length of the buffer in bytes.
00443   * @param  offset: the offset of the buffer in bytes.
00444   * @retval true if written, false otherwise.
00445   */
00446 bool NDefNfcTagM24LR::writeByte(const uint8_t *buffer, uint16_t length, uint16_t offset,
00447     byteOperationCallback_t callback,CallbackStatus_t *callbackStatus)
00448 {
00449   if (WriteData(offset, length, (uint8_t*)buffer)== NDEF_OK) {
00450     callback(callbackStatus,true,buffer,length);
00451     return true;
00452   }
00453 
00454   callback(callbackStatus,false,buffer,length);
00455   return false;
00456 }
00457 
00458 /**
00459   * @brief  This functions reads bytes.
00460   * @param  byteOffset : the offset of the buffer in bytes.
00461   * @param  length: the length of the buffer in bytes.
00462   * @param  buffer : the buffer containing data.
00463   * @param  callback : a function to call after reading data.
00464   * @param  callbackStatus : the status of the callback.
00465   * @retval true if read, false otherwise.
00466   */       
00467 bool NDefNfcTagM24LR::readByte(const uint16_t byteOffset, const uint16_t length,
00468     uint8_t *buffer, byteOperationCallback_t callback, CallbackStatus_t *callbackStatus)
00469 {
00470   
00471   //first it reads the 2 byte for the length then when it will have the callback it reads the real message
00472   if (ReadData(byteOffset, length, (uint8_t*)buffer)== NDEF_OK){
00473     callback(callbackStatus,true,buffer,length);
00474     return true;
00475   }
00476 
00477   callback(callbackStatus,false,buffer,length);
00478   return false;
00479 }
00480 
00481 /**
00482   * @brief  This functions writes bytes.
00483   * @param  byffer : the buffer containing data.
00484   * @param  length: the length of the buffer in bytes.
00485   * @param  offset: the offset of the buffer in bytes.
00486   * @retval NFCTAG status.
00487   */
00488 uint16_t NDefNfcTagM24LR::NDefWriteByte(const uint8_t *buffer, uint16_t length, uint16_t offset)
00489 {
00490     uint16_t status;
00491     do {
00492         uint8_t writeLength =(uint8_t) std::min<uint16_t>(0xFF,length);
00493         status = mDevice.update_binary(offset, writeLength, (uint8_t*)buffer);
00494         offset+=writeLength;
00495         buffer+=writeLength;
00496         length-=writeLength;
00497     } while (status==NDEF_OK && length!=0);
00498 
00499     return status;
00500 }
00501 
00502 /**
00503   * @brief  This functions reads bytes.
00504   * @param  byteOffset : the offset of the buffer in bytes.
00505   * @param  length: the length of the buffer in bytes.
00506   * @param  buffer : the buffer containing data.
00507   * @retval NFCTAG status.
00508   */
00509 uint16_t NDefNfcTagM24LR::NDefReadByte(uint16_t byteOffset, uint16_t length, uint8_t *buffer)
00510 {
00511     uint16_t status;
00512     do {
00513         uint8_t readBuffer = (uint8_t)std::min<uint16_t>(0xFF,length);
00514         status= mDevice.read_binary(byteOffset, readBuffer, (uint8_t*)buffer);
00515         byteOffset+=readBuffer;
00516         buffer+=readBuffer;
00517         length-=readBuffer;
00518     } while (status==NDEF_OK && length!=0);
00519 
00520   return status;
00521 }
00522 
00523 
00524 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/