| /* |
| * Copyright (C) 2010 NXP Semiconductors |
| * |
| * 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. |
| */ |
| |
| /*! |
| * \file phFriNfc_NdefRecord.c |
| * \brief NFC Ndef Record component file. |
| * |
| * Project: NFC-FRI |
| * |
| * $Date: Thu Jun 25 11:01:24 2009 $ |
| * $Author: ing07336 $ |
| * $Revision: 1.4 $ |
| * $Aliases: NFC_FRI1.1_WK926_R28_1,NFC_FRI1.1_WK928_R29_1,NFC_FRI1.1_WK930_R30_1,NFC_FRI1.1_WK934_PREP_1,NFC_FRI1.1_WK934_R31_1,NFC_FRI1.1_WK941_PREP1,NFC_FRI1.1_WK941_PREP2,NFC_FRI1.1_WK941_1,NFC_FRI1.1_WK943_R32_1,NFC_FRI1.1_WK949_PREP1,NFC_FRI1.1_WK943_R32_10,NFC_FRI1.1_WK943_R32_13,NFC_FRI1.1_WK943_R32_14,NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $ |
| * |
| */ |
| |
| |
| /*! \ingroup grp_file_attributes |
| * \name \name NDEF Record Tools Header |
| * |
| * File: \ref phFriNfc_NdefRecord.h |
| * |
| */ |
| /*@{*/ |
| #define PHFRINFCNDEFRECORD_FILEREVISION "$Revision: 1.4 $" |
| #define PHFRINFCNDEFRECORD_FILEALIASES "$Aliases: NFC_FRI1.1_WK926_R28_1,NFC_FRI1.1_WK928_R29_1,NFC_FRI1.1_WK930_R30_1,NFC_FRI1.1_WK934_PREP_1,NFC_FRI1.1_WK934_R31_1,NFC_FRI1.1_WK941_PREP1,NFC_FRI1.1_WK941_PREP2,NFC_FRI1.1_WK941_1,NFC_FRI1.1_WK943_R32_1,NFC_FRI1.1_WK949_PREP1,NFC_FRI1.1_WK943_R32_10,NFC_FRI1.1_WK943_R32_13,NFC_FRI1.1_WK943_R32_14,NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $" |
| /*@}*/ |
| |
| #include <phFriNfc_NdefRecord.h> |
| #include <phNfcCompId.h> |
| #include <stdlib.h> |
| |
| /* Harsha: To Fix: 0000358: phFriNfc_NdefRecord.h: includes should be moved */ |
| #include <string.h> |
| |
| |
| /*! |
| * |
| * Get a specific NDEF record from the data, provided by the caller. The data is a buffer holding |
| * one or more (nested) NDEF records within a NDEF packet (received via the NFC link, for example). |
| * |
| * \param[in] Buffer The data buffer holding the NDEF Message, as provided by the caller. |
| * \param[in] BufferLength The data length, as provided by the caller. |
| * \param[in,out] RawRecords Array of pointers, receiving the references to the found Ndef Records |
| * in the Message. The caller has to provide the array of pointers. |
| * The array is filled with valid pointers up to the number of records |
| * found or the array size if the number of found records exceeds the size. |
| * If the value is NULL the function only yields the number of records |
| * without filling in pointers. |
| * \param[in] IsChunked This boolean tells the user that the record of a certain position within |
| * an array has the CHUNKED flag set (is a partial record). The number |
| * of caller-provided array positions has to be the same as "NumberOfRawRecords". |
| * In case that this parameter is NULL the function ignores it. |
| * \param[in,out] NumberOfRawRecords Length of the Record pointer array. The caller has to provide |
| * the number of pointers provided in the NDEF Type array. \n |
| * The value is set by the extracting function to the actual number of |
| * records found in the data. If the user specifies 0 (zero) the function |
| * only yields the number of records without filling in pointers.\n |
| * The value of NULL is invalid. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. |
| * |
| * \note The correct number of found records is returned by the function also in case that: |
| * - The "RawRecords" array is too short to hold all values: It is filled up to the allowed maximum. |
| * - The "RawRecords" array is NULL: Only the number is returned. |
| * - The "NumberOfRawRecords" parameter is 0 (zero): The array is not filled, just the number is returned. |
| * . |
| * This can be exploited for targeted memory allocation: Specify NULL for "RawRecords" and/or |
| * 0 (zero) for "NumberOfRawRecords" and the function yields the correct array size to allocate |
| * for a second call. |
| * |
| */ |
| NFCSTATUS phFriNfc_NdefRecord_GetRecords( uint8_t *Buffer, |
| uint32_t BufferLength, |
| uint8_t *RawRecords[], |
| uint8_t IsChunked[], |
| uint32_t *NumberOfRawRecords) |
| { |
| NFCSTATUS Status = NFCSTATUS_SUCCESS; |
| uint8_t PayloadLengthByte = 0, |
| TypeLengthByte = 0, |
| TypeLength = 0, |
| IDLengthByte = 0, |
| NoOfRecordsReturnFlag = 0, |
| IDLength = 0; |
| uint32_t Count = 0, |
| PayloadLength = 0, |
| BytesTraversed = 0; |
| |
| /* Validate the input parameters */ |
| if (Buffer == NULL || BufferLength == 0 || NumberOfRawRecords == NULL) |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_PARAMETER); |
| return Status; |
| } |
| |
| if((*NumberOfRawRecords) > 0) |
| { |
| /* The number of caller-provided array positions for the array IsChunked |
| has to be the same as NumberOfRawRecords. Hence, |
| if NumberOfRawRecords > 0, the array IsChunked cannot be null */ |
| if(IsChunked == NULL) |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_PARAMETER); |
| return Status; |
| } |
| } |
| |
| /* Check Raw Records input is NULL and Number of Raw records is 0*/ |
| if ( RawRecords == NULL || *NumberOfRawRecords == 0) |
| { |
| /* This flag is set, to return only number of records |
| this is done when the Raw Records is NULL or |
| Number of Raw records is 0 */ |
| NoOfRecordsReturnFlag = 1; |
| } |
| |
| /* Check for the MB bit*/ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_MB) != |
| PH_FRINFC_NDEFRECORD_FLAGS_MB ) |
| { |
| /* MB Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| |
| /* Number of valid records found in the message is 0 */ |
| *NumberOfRawRecords = 0; |
| return Status; |
| } |
| |
| /* Check for Tnf bits 0x07 is reserved for future use */ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) == |
| PH_FRINFC_NDEFRECORD_TNF_RESERVED) |
| { |
| /* TNF 07 Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| /* Number of valid records found in the message is 0 */ |
| *NumberOfRawRecords = 0; |
| return Status; |
| } |
| |
| /* Check the First Record(MB = 0) for TNF = 0x06(Unchanged) */ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_MB) == PH_FRINFC_NDEFRECORD_FLAGS_MB && |
| (*Buffer & PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) == PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| /* Number of valid records found in the message is 0 */ |
| *NumberOfRawRecords = 0; |
| return Status; |
| } |
| |
| /* First Record i.e., MB = 1, TNF != 0x05 and TypeLength = 0 */ |
| if ( (*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_MB) == PH_FRINFC_NDEFRECORD_FLAGS_MB && |
| (*Buffer & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) != PH_FRINFC_NDEFRECORD_TNF_UNKNOWN && |
| (*Buffer & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) != PH_FRINFC_NDEFRECORD_TNF_EMPTY && |
| *(Buffer + 1) == 0) |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| /* Number of valid records found in the message is 0 */ |
| *NumberOfRawRecords = 0; |
| return Status; |
| } |
| |
| /* Check till Buffer Length exceeds */ |
| while ( BytesTraversed < BufferLength ) |
| { |
| if (Buffer == NULL) |
| { |
| break; |
| } |
| |
| /* For Each Record Check whether it contains the ME bit set and CF bit Set |
| if YES return ERROR*/ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_CF) == |
| PH_FRINFC_NDEFRECORD_FLAGS_CF && |
| (*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_ME) == |
| PH_FRINFC_NDEFRECORD_FLAGS_ME) |
| { |
| /* CF and ME Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| |
| if (NoOfRecordsReturnFlag == 0) |
| { |
| /* Harsha: Fix for 0000241: [gk], NDEF Tools: GetRecords() overshoots |
| a given array boundary if the number of records != 0. */ |
| /* Actual Number of Records should not exceed Number of records |
| required by caller*/ |
| if(Count >= *NumberOfRawRecords) |
| { |
| break; |
| } |
| /* To fix the mantis entry 0388 */ |
| if((Buffer != NULL)&&(RawRecords!=NULL))/*QMOR FIX*/ |
| { |
| RawRecords[Count] = Buffer; |
| } |
| else |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_PARAMETER); |
| break; |
| } |
| } |
| |
| /* To Calculate the IDLength and PayloadLength for |
| short or normal record */ |
| Status = phFriNfc_NdefRecord_RecordIDCheck ( Buffer, |
| &TypeLength, |
| &TypeLengthByte, |
| &PayloadLengthByte, |
| &PayloadLength, |
| &IDLengthByte, |
| &IDLength); |
| if (Status != NFCSTATUS_SUCCESS) |
| { |
| break; |
| } |
| |
| /* Check for the Chunk Flag */ |
| if (NoOfRecordsReturnFlag == 0) |
| { |
| /* If NoOfRecordsReturnFlag = 0, that means we have enough space */ |
| /* in the array IsChunked, to write */ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_CF) == |
| PH_FRINFC_NDEFRECORD_FLAGS_CF) |
| { |
| IsChunked [Count] = PHFRINFCNDEFRECORD_CHUNKBIT_SET; |
| } |
| else |
| { |
| IsChunked [Count] = PHFRINFCNDEFRECORD_CHUNKBIT_SET_ZERO; |
| } |
| } |
| |
| /* Check the record is not the first record */ |
| if (Count > 0) |
| { |
| /* Not a first record, if chunk record is present and IL bit is set |
| also if the MB bit is set */ |
| if(((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_CF) == PH_FRINFC_NDEFRECORD_FLAGS_CF && |
| (*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_IL) == PH_FRINFC_NDEFRECORD_FLAGS_IL && |
| (*Buffer & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) == PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) || |
| (*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_MB) == PH_FRINFC_NDEFRECORD_FLAGS_MB) |
| { |
| /* IL or MB Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| |
| /* Check for the Chunk Flag */ |
| if (NoOfRecordsReturnFlag == 0) |
| { |
| /* If NoOfRecordsReturnFlag = 0, that means the array IsChunked |
| contains valid values. So, cannot check the value |
| of IsChunked if NoOfRecordsReturnFlag = 1. */ |
| |
| /* Check whether the previous record has the chunk flag and |
| TNF of present record is not 0x06 */ |
| if (IsChunked [Count - 1] == PHFRINFCNDEFRECORD_CHUNKBIT_SET && |
| (*Buffer & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) != |
| PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) |
| { |
| /* CF or TNF Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| |
| /* Check whether the previous record doesnot have the chunk flag and |
| TNF of present record is 0x06 */ |
| if (IsChunked [Count - 1] == PHFRINFCNDEFRECORD_CHUNKBIT_SET_ZERO && |
| (*Buffer & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) == |
| PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) |
| { |
| /* CF or TNF Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| |
| /* Check for the last chunk */ |
| if (IsChunked [Count - 1] == PHFRINFCNDEFRECORD_CHUNKBIT_SET && |
| IsChunked [Count] == PHFRINFCNDEFRECORD_CHUNKBIT_SET_ZERO) |
| { |
| /* Check for the TypeLength, IDLength = 0 */ |
| if (TypeLength != 0 || IDLength != 0) |
| { |
| /* last chunk record Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| } |
| } /* if (NoOfRecordsReturnFlag == 0) */ |
| } /* if (Count > 0) */ |
| |
| /* Calculate the bytes already traversed. */ |
| BytesTraversed = (BytesTraversed + PayloadLengthByte + IDLengthByte + TypeLength |
| + IDLength + TypeLengthByte + PayloadLength |
| + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| |
| if(BytesTraversed == BufferLength) |
| { |
| /* We have reached the last record, and everything is fine. */ |
| /* Check for the ME Byte */ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_ME) == |
| PH_FRINFC_NDEFRECORD_FLAGS_ME) |
| { |
| Count++; |
| break; |
| } |
| else |
| { |
| /* Each message must have ME flag in the last record, Since |
| ME is not set raise an error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| } |
| else |
| { |
| /* Buffer Overshoot: Inconsistency in the message length |
| and actual value of the bytes in the message detected. |
| Report error.*/ |
| if(BytesTraversed > BufferLength) |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| break; |
| } |
| } |
| /* For Each Record Check whether it contains the ME bit set |
| if YES return*/ |
| if ((*Buffer & PH_FRINFC_NDEFRECORD_FLAGS_ME) == |
| PH_FRINFC_NDEFRECORD_FLAGS_ME) |
| { |
| Count++; |
| break; |
| } |
| |
| /* +1 is for first byte */ |
| Buffer = (Buffer + PayloadLengthByte + IDLengthByte + TypeLength |
| + TypeLengthByte + IDLength + PayloadLength |
| + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| |
| /* Increment the number of valid records found in the message */ |
| Count++; |
| } |
| |
| /* Whatever is the error, update the NumberOfRawRecords with the number |
| of proper records found till the error was detected in the message. */ |
| *NumberOfRawRecords = Count; |
| return Status; |
| } |
| |
| /* to check the bitfields in the Flags Byte and return the status flag */ |
| static uint8_t phFriNfc_NdefRecord_NdefFlag(uint8_t Flags,uint8_t Mask) |
| { |
| uint8_t check_flag = 0x00; |
| check_flag = Flags & Mask; |
| return check_flag; |
| } |
| |
| uint32_t phFriNfc_NdefRecord_GetLength(phFriNfc_NdefRecord_t *Record) |
| { |
| uint32_t RecordLength=1; |
| uint8_t FlagCheck=0; |
| |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Tnf,PH_FRINFC_NDEFRECORD_TNFBYTE_MASK); |
| /* Type length is present only for following TNF |
| PH_FRINFC_NDEFRECORD_TNF_NFCWELLKNOWN |
| PH_FRINFC_NDEFRECORD_TNF_MEDIATYPE |
| PH_FRINFC_NDEFRECORD_TNF_ABSURI |
| PH_FRINFC_NDEFRECORD_TNF_NFCEXT |
| */ |
| |
| /* ++ is for the Type Length Byte */ |
| RecordLength++; |
| if( FlagCheck != PH_FRINFC_NDEFRECORD_TNF_EMPTY && |
| FlagCheck != PH_FRINFC_NDEFRECORD_TNF_UNKNOWN && |
| FlagCheck != PH_FRINFC_NDEFRECORD_TNF_UNCHANGED ) |
| { |
| RecordLength += Record->TypeLength; |
| } |
| |
| /* to check if payloadlength is 8bit or 32bit*/ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Flags,PH_FRINFC_NDEFRECORD_FLAGS_SR); |
| if(FlagCheck!=0) |
| { |
| /* ++ is for the Payload Length Byte */ |
| RecordLength++;/* for short record*/ |
| } |
| else |
| { |
| /* + PHFRINFCNDEFRECORD_NORMAL_RECORD_BYTE is for the Payload Length Byte */ |
| RecordLength += PHFRINFCNDEFRECORD_NORMAL_RECORD_BYTE;/* for normal record*/ |
| } |
| |
| /* for non empty record */ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Tnf,PH_FRINFC_NDEFRECORD_TNFBYTE_MASK); |
| if(FlagCheck != PH_FRINFC_NDEFRECORD_TNF_EMPTY) |
| { |
| RecordLength += Record->PayloadLength; |
| } |
| |
| /* ID and IDlength are present only if IL flag is set*/ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Flags,PH_FRINFC_NDEFRECORD_FLAGS_IL); |
| if(FlagCheck!=0) |
| { |
| RecordLength +=Record->IdLength; |
| /* ++ is for the ID Length Byte */ |
| RecordLength ++; |
| } |
| return RecordLength; |
| } |
| |
| /*! |
| * |
| * Extract a specific NDEF record from the data, provided by the caller. The data is a buffer holding |
| * at least the entire NDEF record (received via the NFC link, for example). |
| * |
| * \param[out] Record The NDEF record structure. The storage for the structure has to be provided by the |
| * caller matching the requirements for \b Extraction, as described in the compound |
| * documentation. |
| * \param[in] RawRecord The Pointer to the buffer, selected out of the array returned by |
| * the \ref phFriNfc_NdefRecord_GetRecords function. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. |
| * |
| * \note There are some caveats: |
| * - The "RawRecord" Data buffer must exist at least as long as the function execution time plus the time |
| * needed by the caller to evaluate the extracted information. No copying of the contained data is done. |
| * - Using the "RawRecord" and "RawRecordMaxSize" parameters the function internally checks whether the |
| * data to extract are within the bounds of the buffer. |
| * |
| * |
| */ |
| NFCSTATUS phFriNfc_NdefRecord_Parse(phFriNfc_NdefRecord_t *Record, |
| uint8_t *RawRecord) |
| { |
| NFCSTATUS Status = NFCSTATUS_SUCCESS; |
| uint8_t PayloadLengthByte = 0, |
| TypeLengthByte = 0, |
| TypeLength = 0, |
| IDLengthByte = 0, |
| IDLength = 0, |
| Tnf = 0; |
| uint32_t PayloadLength = 0; |
| |
| if (Record == NULL || RawRecord == NULL) |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_PARAMETER); |
| } |
| |
| else |
| { |
| |
| /* Calculate the Flag Value */ |
| Record->Flags = phFriNfc_NdefRecord_RecordFlag ( RawRecord); |
| |
| /* Calculate the Type Namr format of the record */ |
| Tnf = phFriNfc_NdefRecord_TypeNameFormat( RawRecord); |
| if(Tnf != 0xFF) |
| { |
| Record->Tnf = Tnf; |
| /* To Calculate the IDLength and PayloadLength for short or normal record */ |
| Status = phFriNfc_NdefRecord_RecordIDCheck ( RawRecord, |
| &TypeLength, |
| &TypeLengthByte, |
| &PayloadLengthByte, |
| &PayloadLength, |
| &IDLengthByte, |
| &IDLength); |
| Record->TypeLength = TypeLength; |
| Record->PayloadLength = PayloadLength; |
| Record->IdLength = IDLength; |
| RawRecord = (RawRecord + PayloadLengthByte + IDLengthByte + TypeLengthByte + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| Record->Type = RawRecord; |
| |
| RawRecord = (RawRecord + Record->TypeLength); |
| |
| if (Record->IdLength != 0) |
| { |
| Record->Id = RawRecord; |
| } |
| |
| RawRecord = RawRecord + Record->IdLength; |
| Record->PayloadData = RawRecord; |
| } |
| else |
| { |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_PARAMETER); |
| } |
| } |
| return Status; |
| } |
| |
| |
| |
| /*! |
| * The function writes one NDEF record to a specified memory location. Called within a loop, it is possible to |
| * write more records into a contiguous buffer, in each cycle advancing by the number of bytes written for |
| * each record. |
| * |
| * \param[in] Record The Array of NDEF record structures to append. The structures |
| * have to be filled by the caller matching the requirements for |
| * \b Composition, as described in the documentation of |
| * the \ref phFriNfc_NdefRecord_t "NDEF Record" structure. |
| * \param[in] Buffer The pointer to the buffer. |
| * \param[in] MaxBufferSize The data buffer's maximum size, provided by the caller. |
| * \param[out] BytesWritten The actual number of bytes written to the buffer. This can be used by |
| * the caller to serialise more than one record into the same buffer before |
| * handing it over to another instance. |
| * |
| * \retval NFCSTATUS_SUCCESS Operation successful. |
| * \retval NFCSTATUS_INVALID_PARAMETER At least one parameter of the function is invalid. |
| * \retval NFCSTATUS_BUFFER_TOO_SMALL The data buffer, provided by the caller is to small to |
| * hold the composed NDEF record. The existing content is not changed. |
| * |
| */ |
| NFCSTATUS phFriNfc_NdefRecord_Generate(phFriNfc_NdefRecord_t *Record, |
| uint8_t *Buffer, |
| uint32_t MaxBufferSize, |
| uint32_t *BytesWritten) |
| { |
| uint8_t FlagCheck, |
| TypeCheck=0, |
| *temp, |
| i; |
| uint32_t i_data=0; |
| |
| if(Record==NULL ||Buffer==NULL||BytesWritten==NULL||MaxBufferSize == 0) |
| { |
| return (PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, NFCSTATUS_INVALID_PARAMETER)); |
| } |
| |
| if (Record->Tnf == PH_FRINFC_NDEFRECORD_TNF_RESERVED) |
| { |
| return (PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, NFCSTATUS_INVALID_FORMAT)); |
| } |
| |
| /* calculate the length of the record and check with the buffersize if it exceeds return */ |
| i_data=phFriNfc_NdefRecord_GetLength(Record); |
| if(i_data > MaxBufferSize) |
| { |
| return (PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, NFCSTATUS_BUFFER_TOO_SMALL)); |
| } |
| *BytesWritten = i_data; |
| |
| /*fill the first byte of the message(all the flags) */ |
| /*increment the buffer*/ |
| *Buffer = ( (Record->Flags & PH_FRINFC_NDEFRECORD_FLAG_MASK) | (Record->Tnf & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK)); |
| Buffer++; |
| |
| /* check the TypeNameFlag for PH_FRINFC_NDEFRECORD_TNF_EMPTY */ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Tnf,PH_FRINFC_NDEFRECORD_TNFBYTE_MASK); |
| if(FlagCheck == PH_FRINFC_NDEFRECORD_TNF_EMPTY) |
| { |
| /* fill the typelength idlength and payloadlength with zero(empty message)*/ |
| for(i=0;i<3;i++) |
| { |
| *Buffer=PH_FRINFC_NDEFRECORD_BUF_TNF_VALUE; |
| Buffer++; |
| } |
| return (PHNFCSTVAL(CID_NFC_NONE, NFCSTATUS_SUCCESS)); |
| } |
| |
| /* check the TypeNameFlag for PH_FRINFC_NDEFRECORD_TNF_RESERVED */ |
| /* TNF should not be reserved one*/ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Tnf,PH_FRINFC_NDEFRECORD_TNFBYTE_MASK); |
| if(FlagCheck == PH_FRINFC_NDEFRECORD_TNF_RESERVED) |
| { |
| return (PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, NFCSTATUS_INVALID_PARAMETER)); |
| } |
| |
| /* check for TNF Unknown or Unchanged */ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Tnf,PH_FRINFC_NDEFRECORD_TNFBYTE_MASK); |
| if(FlagCheck == PH_FRINFC_NDEFRECORD_TNF_UNKNOWN || \ |
| FlagCheck == PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) |
| { |
| *Buffer = PH_FRINFC_NDEFRECORD_BUF_TNF_VALUE; |
| Buffer++; |
| } |
| else |
| { |
| *Buffer = Record->TypeLength; |
| Buffer++; |
| TypeCheck=1; |
| } |
| |
| /* check for the short record bit if it is then payloadlength is only one byte */ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Flags,PH_FRINFC_NDEFRECORD_FLAGS_SR); |
| if(FlagCheck!=0) |
| { |
| *Buffer = (uint8_t)(Record->PayloadLength & 0x000000ff); |
| Buffer++; |
| } |
| else |
| { |
| /* if it is normal record payloadlength is 4 byte(32 bit)*/ |
| *Buffer = (uint8_t)((Record->PayloadLength & 0xff000000) >> PHNFCSTSHL24); |
| Buffer++; |
| *Buffer = (uint8_t)((Record->PayloadLength & 0x00ff0000) >> PHNFCSTSHL16); |
| Buffer++; |
| *Buffer = (uint8_t)((Record->PayloadLength & 0x0000ff00) >> PHNFCSTSHL8); |
| Buffer++; |
| *Buffer = (uint8_t)((Record->PayloadLength & 0x000000ff)); |
| Buffer++; |
| } |
| |
| /*check for IL bit set(Flag), if so then IDlength is present*/ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Flags,PH_FRINFC_NDEFRECORD_FLAGS_IL); |
| if(FlagCheck!=0) |
| { |
| *Buffer=Record->IdLength; |
| Buffer++; |
| } |
| |
| /*check for TNF and fill the Type*/ |
| temp=Record->Type; |
| if(TypeCheck!=0) |
| { |
| for(i=0;i<(Record->TypeLength);i++) |
| { |
| *Buffer = *temp; |
| Buffer++; |
| temp++; |
| } |
| } |
| |
| /*check for IL bit set(Flag), if so then IDlength is present and fill the ID*/ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Flags,PH_FRINFC_NDEFRECORD_FLAGS_IL); |
| temp=Record->Id; |
| if(FlagCheck!=0) |
| { |
| for(i=0;i<(Record->IdLength);i++) |
| { |
| *Buffer = *temp; |
| Buffer++; |
| temp++; |
| } |
| } |
| |
| temp=Record->PayloadData; |
| /*check for SR bit and then correspondingly use the payload length*/ |
| FlagCheck=phFriNfc_NdefRecord_NdefFlag(Record->Flags,PH_FRINFC_NDEFRECORD_FLAGS_SR); |
| for(i_data=0;i_data < (Record->PayloadLength) ;i_data++) |
| { |
| *Buffer = *temp; |
| Buffer++; |
| temp++; |
| } |
| |
| return (PHNFCSTVAL(CID_NFC_NONE, NFCSTATUS_SUCCESS)); |
| } |
| |
| /* Calculate the Flags of the record */ |
| static uint8_t phFriNfc_NdefRecord_RecordFlag ( uint8_t *Record) |
| { |
| uint8_t flag = 0; |
| |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_MB) == PH_FRINFC_NDEFRECORD_FLAGS_MB ) |
| { |
| flag = flag | PH_FRINFC_NDEFRECORD_FLAGS_MB; |
| } |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_ME) == PH_FRINFC_NDEFRECORD_FLAGS_ME ) |
| { |
| flag = flag | PH_FRINFC_NDEFRECORD_FLAGS_ME; |
| } |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_CF) == PH_FRINFC_NDEFRECORD_FLAGS_CF ) |
| { |
| flag = flag | PH_FRINFC_NDEFRECORD_FLAGS_CF; |
| } |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_SR) == PH_FRINFC_NDEFRECORD_FLAGS_SR ) |
| { |
| flag = flag | PH_FRINFC_NDEFRECORD_FLAGS_SR; |
| } |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_IL) == PH_FRINFC_NDEFRECORD_FLAGS_IL ) |
| { |
| flag = flag | PH_FRINFC_NDEFRECORD_FLAGS_IL; |
| } |
| return flag; |
| } |
| |
| /* Calculate the Type Name Format for the record */ |
| static uint8_t phFriNfc_NdefRecord_TypeNameFormat ( uint8_t *Record) |
| { |
| uint8_t tnf = 0; |
| |
| switch (*Record & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) |
| { |
| case PH_FRINFC_NDEFRECORD_TNF_EMPTY: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_EMPTY; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_NFCWELLKNOWN: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_NFCWELLKNOWN; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_MEDIATYPE: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_MEDIATYPE; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_ABSURI: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_ABSURI; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_NFCEXT: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_NFCEXT; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_UNKNOWN: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_UNKNOWN; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_UNCHANGED: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_UNCHANGED; |
| break; |
| |
| case PH_FRINFC_NDEFRECORD_TNF_RESERVED: |
| tnf = PH_FRINFC_NDEFRECORD_TNF_RESERVED; |
| break; |
| default : |
| tnf = 0xFF; |
| break; |
| } |
| |
| return tnf; |
| } |
| |
| |
| static NFCSTATUS phFriNfc_NdefRecord_RecordIDCheck ( uint8_t *Record, |
| uint8_t *TypeLength, |
| uint8_t *TypeLengthByte, |
| uint8_t *PayloadLengthByte, |
| uint32_t *PayloadLength, |
| uint8_t *IDLengthByte, |
| uint8_t *IDLength) |
| { |
| NFCSTATUS Status = NFCSTATUS_SUCCESS; |
| |
| /* Check for Tnf bits 0x07 is reserved for future use */ |
| if ((*Record & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) == |
| PH_FRINFC_NDEFRECORD_TNF_RESERVED) |
| { |
| /* TNF 07 Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| return Status; |
| } |
| |
| /* Check for Type Name Format depending on the TNF, Type Length value is set*/ |
| if ((*Record & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK)== |
| PH_FRINFC_NDEFRECORD_TNF_EMPTY) |
| { |
| *TypeLength = *(Record + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| |
| if (*(Record + PH_FRINFC_NDEFRECORD_BUF_INC1) != 0) |
| { |
| /* Type Length Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| return Status; |
| } |
| |
| *TypeLengthByte = 1; |
| |
| /* Check for Short Record */ |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_SR) == PH_FRINFC_NDEFRECORD_FLAGS_SR) |
| { |
| /* For Short Record, Payload Length Byte is 1 */ |
| *PayloadLengthByte = 1; |
| /* 1 for Header byte */ |
| *PayloadLength = *(Record + *TypeLengthByte + 1); |
| if (*PayloadLength != 0) |
| { |
| /* PayloadLength Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| return Status; |
| } |
| } |
| else |
| { |
| /* For Normal Record, Payload Length Byte is 4 */ |
| *PayloadLengthByte = PHFRINFCNDEFRECORD_NORMAL_RECORD_BYTE; |
| *PayloadLength = ((((uint32_t)(*(Record + PH_FRINFC_NDEFRECORD_BUF_INC2))) << PHNFCSTSHL24) + |
| (((uint32_t)(*(Record + PH_FRINFC_NDEFRECORD_BUF_INC3))) << PHNFCSTSHL16) + |
| (((uint32_t)(*(Record + PH_FRINFC_NDEFRECORD_BUF_INC4))) << PHNFCSTSHL8) + |
| *(Record + PH_FRINFC_NDEFRECORD_BUF_INC5)); |
| if (*PayloadLength != 0) |
| { |
| /* PayloadLength Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| return Status; |
| } |
| } |
| |
| /* Check for ID Length existence */ |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_IL) == PH_FRINFC_NDEFRECORD_FLAGS_IL) |
| { |
| /* Length Byte exists and it is 1 byte */ |
| *IDLengthByte = 1; |
| /* 1 for Header byte */ |
| *IDLength = (uint8_t)*(Record + *PayloadLengthByte + *TypeLengthByte + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| if (*IDLength != 0) |
| { |
| /* IDLength Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| return Status; |
| } |
| } |
| else |
| { |
| *IDLengthByte = 0; |
| *IDLength = 0; |
| } |
| } |
| else |
| { |
| if ((*Record & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK)== PH_FRINFC_NDEFRECORD_TNF_UNKNOWN |
| || (*Record & PH_FRINFC_NDEFRECORD_TNFBYTE_MASK) == |
| PH_FRINFC_NDEFRECORD_TNF_UNCHANGED) |
| { |
| if (*(Record + PH_FRINFC_NDEFRECORD_BUF_INC1) != 0) |
| { |
| /* Type Length Error */ |
| Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_RECORD, |
| NFCSTATUS_INVALID_FORMAT); |
| return Status; |
| } |
| *TypeLength = 0; |
| *TypeLengthByte = 1; |
| } |
| else |
| { |
| /* 1 for Header byte */ |
| *TypeLength = *(Record + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| *TypeLengthByte = 1; |
| } |
| |
| /* Check for Short Record */ |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_SR) == |
| PH_FRINFC_NDEFRECORD_FLAGS_SR) |
| { |
| /* For Short Record, Payload Length Byte is 1 */ |
| *PayloadLengthByte = 1; |
| /* 1 for Header byte */ |
| *PayloadLength = *(Record + *TypeLengthByte + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| } |
| else |
| { |
| /* For Normal Record, Payload Length Byte is 4 */ |
| *PayloadLengthByte = PHFRINFCNDEFRECORD_NORMAL_RECORD_BYTE; |
| *PayloadLength = ((((uint32_t)(*(Record + PH_FRINFC_NDEFRECORD_BUF_INC2))) << PHNFCSTSHL24) + |
| (((uint32_t)(*(Record + PH_FRINFC_NDEFRECORD_BUF_INC3))) << PHNFCSTSHL16) + |
| (((uint32_t)(*(Record + PH_FRINFC_NDEFRECORD_BUF_INC4))) << PHNFCSTSHL8) + |
| *(Record + PH_FRINFC_NDEFRECORD_BUF_INC5)); |
| } |
| |
| /* Check for ID Length existence */ |
| if ((*Record & PH_FRINFC_NDEFRECORD_FLAGS_IL) == |
| PH_FRINFC_NDEFRECORD_FLAGS_IL) |
| { |
| *IDLengthByte = 1; |
| /* 1 for Header byte */ |
| *IDLength = (uint8_t)*(Record + *PayloadLengthByte + *TypeLengthByte + PH_FRINFC_NDEFRECORD_BUF_INC1); |
| } |
| else |
| { |
| *IDLengthByte = 0; |
| *IDLength = 0; |
| } |
| } |
| return Status; |
| } |
| |