NFC NDEF library
Dependents: Nucleo_NFC_Example I2C_NFC_Master Print_Entire_Nucleo_NFC01A1_Memory
Fork of lib_NDEF by
lib_NDEF.c
- Committer:
- EnricoG
- Date:
- 2014-12-15
- Revision:
- 0:3b093bd0819e
File content as of revision 0:3b093bd0819e:
/** ****************************************************************************** * @file lib_NDEF.c * @author MMY Application Team * @version V1.0.0 * @date 20-November-2013 * @brief This file help to manage NDEF file, to parse and identify them. ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT 2014 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. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "lib_NDEF.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 ( void ); static uint16_t NDEF_ParseRecordHeader ( sRecordInfo *pRecordStruct ); static void NDEF_ParseWellKnownType ( sRecordInfo *pRecordStruct ); static void NDEF_ParseMediaType ( sRecordInfo *pRecordStruct ); static void NDEF_ParseForumExternalType ( sRecordInfo *pRecordStruct ); static void NDEF_ParseURI(sRecordInfo *pRecordStruct); static void NDEF_ParseSP(sRecordInfo *pRecordStruct); static uint16_t NDEF_IdentifySPRecord ( sRecordInfo *pRecordStruct, uint8_t* pPayload ); /* In case of smart Poster composed with different record, 3 records supported so far */ sRecordInfo SPRecordStruct1, SPRecordStruct2, SPRecordStruct3; uint32_t SPRecordStructAdd[SP_MAX_RECORD] = { (uint32_t)&SPRecordStruct1, (uint32_t)&SPRecordStruct2, (uint32_t)&SPRecordStruct3 }; /** * @brief This fonction check that the tag contain a NDEF message * @param None : * @retval SUCCESS : There is a NDEF file stored in tag * @retval ERROR : No NDEF in the tag. */ static uint16_t NDEF_IsNDEFPresent ( void ) { uint16_t FileSize; uint8_t uM24SR_NDEFHeader [0x2]; /* Check NDEF existence */ ReadData ( NDEF_SIZE_OFFSET , 2 , uM24SR_NDEFHeader); FileSize = (uint16_t) ((uM24SR_NDEFHeader[0x00]<<8) | uM24SR_NDEFHeader[0x01]); if( FileSize != 0) return SUCCESS; else return ERROR; } /** * @brief This fonction 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 *pRecordStruct, uint8_t* pPayload ) { uint16_t status = 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->PayloadLength3 = 0; pRecordStruct->PayloadLength2 = 0; pRecordStruct->PayloadLength1 = 0; pRecordStruct->PayloadLength0 = 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->PayloadLength3 = pPayload[2]; pRecordStruct->PayloadLength2 = pPayload[3]; pRecordStruct->PayloadLength1 = pPayload[4]; pRecordStruct->PayloadLength0 = 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 = (uint32_t)(pPayload+SizeOfRecordHeader); status = NDEF_ParseRecordHeader(pRecordStruct); return status; } /** * @brief This fonction parse the record header and dispatch regarding TNF value * @param pRecordStruct : pointer on the record structure to fill * @retval SUCCESS : record identified and structure filled * @retval ERROR : Not supported */ static uint16_t NDEF_ParseRecordHeader ( sRecordInfo *pRecordStruct ) { uint16_t status = SUCCESS; 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 = ERROR; } return status; } /** * @brief This fonction parse the Well Known type record * @param pRecordStruct : pointer on the record structure to fill * @retval None */ static void NDEF_ParseWellKnownType ( sRecordInfo *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 pRecordStruct->NDEF_Type = UNKNOWN_TYPE; } /** * @brief This fonction parse the Media type record * @param pRecordStruct : pointer on the record structure to fill * @retval None */ static void NDEF_ParseMediaType ( sRecordInfo *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 pRecordStruct->NDEF_Type = UNKNOWN_TYPE; } /** * @brief This fonction parse the Forum External type record * @param pRecordStruct : pointer on the record structure to fill * @retval None */ static void NDEF_ParseForumExternalType ( sRecordInfo *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 fonction parse the URI type record * @param pRecordStruct : pointer on the record structure to fill * @retval None */ static void NDEF_ParseURI(sRecordInfo *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 fonction parse the Smart Poster * @param pRecordStruct : pointer on the record structure to fill * @retval None */ static void NDEF_ParseSP(sRecordInfo *pRecordStruct) { uint8_t* pPayload; uint32_t PayloadSize = 0; uint32_t SPPayloadSize = 0; uint32_t OffsetInSPPayload =0; uint32_t RecordPosition = 0; sRecordInfo *pSPRecordStruct; /* initialize variable with size of the payload and poiter on data */ PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3)<<24) | ((uint32_t)(pRecordStruct->PayloadLength2)<<16) | ((uint32_t)(pRecordStruct->PayloadLength1)<<8) | pRecordStruct->PayloadLength0; pPayload = (uint8_t*)(pRecordStruct->PayloadBufferAdd); pSPRecordStruct = (sRecordInfo *)SPRecordStructAdd[0]; /* Initailize the number of record find in the SP payload */ pRecordStruct->NbOfRecordInSPPayload = 0; do { pSPRecordStruct = (sRecordInfo *)SPRecordStructAdd[RecordPosition]; /* identify the 1st record in the SP payload */ if( NDEF_IdentifySPRecord ( pSPRecordStruct, pPayload )) { /* store add of structure that will contain the other record information */ pRecordStruct->NbOfRecordInSPPayload ++; pRecordStruct->SPRecordStructAdd[RecordPosition] = (uint32_t) pSPRecordStruct; /* After SPRecord + First Record check if we are at the end of NDEF file */ SPPayloadSize = ((uint32_t)(pSPRecordStruct->PayloadLength3)<<24) | ((uint32_t)(pSPRecordStruct->PayloadLength2)<<16) | ((uint32_t)(pSPRecordStruct->PayloadLength1)<<8) | pSPRecordStruct->PayloadLength0; OffsetInSPPayload += pSPRecordStruct->PayloadOffset + SPPayloadSize; pPayload += OffsetInSPPayload; RecordPosition++; } } while( OffsetInSPPayload < PayloadSize && RecordPosition<SP_MAX_RECORD); /* there is another record */ } /** * @} */ /** @defgroup libNDEF_Public_Functions * @{ */ /** * @brief This fonction identify the NDEF message stored in tag * @param pRecordStruct : Structure to fill with record information * @param pNDEF : pointer on the NDEF message data * @retval SUCCESS : record struct filled * @retval ERROR : record struct not updated */ uint16_t NDEF_IdentifyNDEF ( sRecordInfo *pRecordStruct, uint8_t* pNDEF ) { uint16_t status = ERROR; uint16_t SizeOfRecordHeader, TypeNbByte, PayloadLengthField, IDLengthField, IDNbByte; uint32_t PayloadSize; /* check NDEF present */ if(NDEF_IsNDEFPresent() != SUCCESS) { return ERROR; } /* Analyse record layout */ ReadData ( FIRST_RECORD_OFFSET , 1 , pNDEF); /* 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 */ ReadData ( FIRST_RECORD_OFFSET , 4 , pNDEF); TypeNbByte = pNDEF[1]; PayloadLengthField = 1; if( IDLengthField == ID_LENGTH_FIELD) IDNbByte = pNDEF[3]; else IDNbByte = 0; } else { /* Analyse normal record layout */ ReadData ( FIRST_RECORD_OFFSET , 7 , pNDEF); 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 */ ReadData ( FIRST_RECORD_OFFSET , SizeOfRecordHeader , pNDEF); /* it's a SR */ if( pNDEF[0]&SR_Mask) { pRecordStruct->RecordFlags = pNDEF[0]; pRecordStruct->TypeLength = TypeNbByte; pRecordStruct->PayloadLength3 = 0; pRecordStruct->PayloadLength2 = 0; pRecordStruct->PayloadLength1 = 0; pRecordStruct->PayloadLength0 = 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->PayloadLength3 = pNDEF[2]; pRecordStruct->PayloadLength2 = pNDEF[3]; pRecordStruct->PayloadLength1 = pNDEF[4]; pRecordStruct->PayloadLength0 = pNDEF[5]; pRecordStruct->IDLength = IDNbByte; memcpy(pRecordStruct->Type, &pNDEF[6+IDNbByte] , TypeNbByte); memcpy(pRecordStruct->ID, &pNDEF[6+IDNbByte+TypeNbByte] , IDNbByte); pRecordStruct->PayloadOffset = SizeOfRecordHeader; } PayloadSize = ((uint32_t)(pRecordStruct->PayloadLength3)<<24) | ((uint32_t)(pRecordStruct->PayloadLength2)<<16) | ((uint32_t)(pRecordStruct->PayloadLength1)<<8) | pRecordStruct->PayloadLength0; /* read Payload */ status = ReadData ( (uint16_t)((FIRST_RECORD_OFFSET) + pRecordStruct->PayloadOffset) , PayloadSize , pNDEF); if( status != NDEF_ACTION_COMPLETED) return status; else pRecordStruct->PayloadBufferAdd = (uint32_t)(pNDEF); NDEF_ParseRecordHeader(pRecordStruct); return SUCCESS; } /** * @brief This fonction read the NDEF content of the TAG * @param pNDEF : pointer on the buffer to store NDEF data * @retval SUCCESS : NDEF file data retrieve and store in the buffer * @retval ERROR : not able to read NDEF */ uint16_t NDEF_ReadNDEF( uint8_t* pNDEF) { uint16_t status = ERROR; uint16_t NDEF_Size = 0; status = ReadData( 0 , 2 , pNDEF); if( status == NDEF_ACTION_COMPLETED) { NDEF_Size = (uint16_t) (*pNDEF << 8); NDEF_Size = NDEF_Size | (uint16_t) (*++pNDEF ); status = ReadData( 0 , NDEF_Size+2 , --pNDEF); } if( status == NDEF_ACTION_COMPLETED) return SUCCESS; else return ERROR; } /** * @brief This fonction write the NDEF in the TAG * @param pNDEF : pointer on the buffer containing the NDEF data * @retval SUCCESS : NDEF file data written in the tag * @retval ERROR : not able to store NDEF in tag */ uint16_t NDEF_WriteNDEF( uint8_t *pNDEF) { uint16_t status = ERROR; uint16_t NDEF_Size = 0; NDEF_Size = (uint16_t) (*pNDEF << 8); NDEF_Size = NDEF_Size | (uint16_t) (*++pNDEF ); status = WriteData( 0 , NDEF_Size+2 , --pNDEF); if( status == NDEF_ACTION_COMPLETED) return SUCCESS; else return ERROR; } /** * @} */ /** * @} */ /** * @} */ /******************* (C) COPYRIGHT 2013 STMicroelectronics *****END OF FILE****/