/*
 * 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>

static uint8_t phFriNfc_NdefRecord_TypeNameFormat ( uint8_t    *Record);
static uint8_t phFriNfc_NdefRecord_RecordFlag ( uint8_t    *Record);
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);

/*!
 *
 *  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;
}

