/*
 * 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_TopazMap.c
* \brief NFC Ndef Mapping For Remote Devices.
*
* Project: NFC-FRI
*
* $Date: Mon Dec 13 14:14:14 2010 $
* $Author: ing02260 $
* $Revision: 1.23 $
* $Aliases:  $
*
*/



#include <phFriNfc_NdefMap.h>
#include <phFriNfc_TopazMap.h>
#include <phFriNfc_MapTools.h>
#include <phFriNfc_OvrHal.h>

#ifndef PH_FRINFC_MAP_TOPAZ_DISABLED
/*! \ingroup grp_file_attributes
*  \name NDEF Mapping
*
* File: \ref phFriNfcNdefMap.c
*
*/
/*@{*/
#define PHFRINFCTOPAZMAP_FILEREVISION "$Revision: 1.23 $"
#define PHFRINFCTOPAZMAP_FILEALIASES  "$Aliases:  $"
/*@}*/
/****************** Start of macros ********************/
/* Below MACRO is used for the WRITE error scenario, 
    in case PN544 returns error for any WRITE, then 
    read the written block and byte number, to check the data 
    written to the card is correct or not 
*/
/* #define TOPAZ_RF_ERROR_WORKAROUND */

#ifdef FRINFC_READONLY_NDEF

    #define CC_BLOCK_NUMBER                                         (0x01U)
    #define LOCK_BLOCK_NUMBER                                       (0x0EU)

    #define LOCK0_BYTE_NUMBER                                       (0x00U)
    #define LOCK0_BYTE_VALUE                                        (0xFFU)

    #define LOCK1_BYTE_NUMBER                                       (0x01U)
    #define LOCK1_BYTE_VALUE                                        (0x7FU)

    #define CC_RWA_BYTE_NUMBER                                      (0x03U)
    #define CC_READ_ONLY_VALUE                                      (0x0FU)

#endif /* #ifdef FRINFC_READONLY_NDEF */

#ifdef TOPAZ_RF_ERROR_WORKAROUND

    /* Below MACROs are added for the error returned from HAL, if the 
        below error has occured during the WRITE, then read the error 
        returned blocks to confirm */
    #define FRINFC_RF_TIMEOUT_89                                    (0x89U)
    #define FRINFC_RF_TIMEOUT_90                                    (0x90U)

    /* State specific to read after the RF ERROR for the WRITE */
    #define PH_FRINFC_TOPAZ_STATE_RF_ERROR_READ                     (0x0FU)

#endif /* #ifdef TOPAZ_RF_ERROR_WORKAROUND */

/****************** End of macros ********************/

/*!
* \name Topaz Mapping - Helper Functions
*
*/
/*@{*/

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function shall read 8 bytes 
*  from the card.
*/
static NFCSTATUS phFriNfc_Tpz_H_RdBytes(phFriNfc_NdefMap_t *NdefMap,
                                        uint16_t             BlockNo,
                                        uint16_t             ByteNo);
 
/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function shall process 
* read id command
*/
static NFCSTATUS phFriNfc_Tpz_H_ProReadID(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function shall process 
* read all command
*/
static NFCSTATUS phFriNfc_Tpz_H_ProReadAll(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function depends on
* function called by the user
*/
static NFCSTATUS phFriNfc_Tpz_H_CallNxtOp(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function checks the CC 
* bytes
*/
static NFCSTATUS phFriNfc_Tpz_H_ChkCCBytes(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function finds 
* NDEF TLV
*/
static NFCSTATUS phFriNfc_Tpz_H_findNDEFTLV(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function writes a 
* byte into the card
*/
static NFCSTATUS phFriNfc_Tpz_H_WrAByte(phFriNfc_NdefMap_t *NdefMap,
                                        uint16_t             BlockNo,
                                        uint16_t             ByteNo,
                                        uint8_t              ByteVal
                                        );

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function shall process the 
* NMN write 
*/
static NFCSTATUS phFriNfc_Tpz_H_ProWrNMN(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function writes the length field of
* the NDEF TLV
*/
static NFCSTATUS phFriNfc_Tpz_H_ProWrTLV(phFriNfc_NdefMap_t *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function updates length field 
* of the NDEF TLV after complete write.
*/
static NFCSTATUS phFriNfc_Tpz_H_WrLByte(phFriNfc_NdefMap_t  *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function copies the card data
*  to the user buffer
*/
static NFCSTATUS phFriNfc_Tpz_H_CpDataToUsrBuf( phFriNfc_NdefMap_t  *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function shall process the 
* written data
*/
static NFCSTATUS phFriNfc_Tpz_H_ProWrUsrData( phFriNfc_NdefMap_t  *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function checks the block 
* number is correct or not
*/
static void phFriNfc_Tpz_H_BlkChk(phFriNfc_NdefMap_t  *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function writes the 0th 
* byte of block 1 has Zero
*/
static NFCSTATUS phFriNfc_Tpz_H_WrByte0ValE1(phFriNfc_NdefMap_t   *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function calls the 
* completion routine
*/
static void phFriNfc_Tpz_H_Complete(phFriNfc_NdefMap_t  *NdefMap,
                                    NFCSTATUS           Status);

/*!
* \brief \copydoc page_ovr Helper function for Topaz check ndef. This function checks 
* the CC byte in check ndef function
*/
static NFCSTATUS phFriNfc_Tpz_H_ChkCCinChkNdef(phFriNfc_NdefMap_t  *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz check ndef. This function checks 
* the lock bits and set a card state
*/
static void phFriNfc_Tpz_H_ChkLockBits(phFriNfc_NdefMap_t  *NdefMap);

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function writes CC bytes or 
* type of the TLV
*/
static NFCSTATUS phFriNfc_Tpz_H_WrCCorTLV(phFriNfc_NdefMap_t  *NdefMap);

#ifdef TOPAZ_RF_ERROR_WORKAROUND

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function checks the written  
* value after the 
*/
static 
NFCSTATUS 
phFriNfc_Tpz_H_CheckWrittenData (
    phFriNfc_NdefMap_t          *psNdefMap,
    uint8_t                     state_rf_error);

#endif /* #ifdef TOPAZ_RF_ERROR_WORKAROUND */

/*!
* \brief \copydoc page_ovr Helper function for Topaz. This function checks the written 
* CC bytes are correct
*/
static NFCSTATUS phFriNfc_Tpz_H_ProCCTLV(phFriNfc_NdefMap_t  *NdefMap);
/*@}*/
void phFriNfc_TopazMap_H_Reset(phFriNfc_NdefMap_t        *NdefMap)
{
    /* Initialising the Topaz structure variable */
    NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_INVALID_OPE;
    NdefMap->TopazContainer.CurrentBlock = PH_FRINFC_TOPAZ_VAL1;
    NdefMap->TopazContainer.ByteNumber = PH_FRINFC_TOPAZ_VAL0;
    NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_VAL0;
    (void)memset(NdefMap->TopazContainer.ReadBuffer, PH_FRINFC_TOPAZ_VAL0, 
                sizeof(NdefMap->TopazContainer.ReadBuffer));
    NdefMap->TopazContainer.ReadWriteCompleteFlag = PH_FRINFC_TOPAZ_FLAG0;
    NdefMap->TopazContainer.RemainingSize = PH_FRINFC_TOPAZ_VAL0;
    (void)memset(NdefMap->TopazContainer.UID, PH_FRINFC_TOPAZ_VAL0, 
                sizeof(NdefMap->TopazContainer.UID));
    NdefMap->TopazContainer.Cur_RW_Index=0;
    NdefMap->TopazContainer.ByteRWFrmCard =0;
}

/*!
* \brief Check whether a particular Remote Device is NDEF compliant.
*
* The function checks whether the peer device is NDEF compliant.
*
* \param[in] NdefMap Pointer to a valid instance of the \ref phFriNfc_NdefMap_t 
*                    structure describing the component context.
*
* \retval  NFCSTATUS_PENDING   The action has been successfully triggered.
* \retval  Others              An error has occurred.
*
*/

NFCSTATUS phFriNfc_TopazMap_ChkNdef( phFriNfc_NdefMap_t     *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, 
        NFCSTATUS_INVALID_PARAMETER);
    if ( NdefMap != NULL)
    {
        /* Update the previous operation */
        NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_CHECK_OPE;
        /* Update the CR index to know from which operation completion 
        routine has to be called */
        NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_CHK_NDEF;
        NdefMap->TopazContainer.CurrentBlock = PH_FRINFC_TOPAZ_VAL1;
        NdefMap->TopazContainer.ByteNumber = PH_FRINFC_TOPAZ_VAL0;

        /* Set card state */
        NdefMap->CardType = PH_FRINFC_NDEFMAP_TOPAZ_CARD;

        /* Change the state to Check Ndef Compliant */
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_READID;
        NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_CHECK_OPE;

#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] = PH_FRINFC_TOPAZ_CMD_READID;        
#else        
#ifdef PH_HAL4_ENABLE
        NdefMap->Cmd.JewelCmd = phHal_eJewel_RID;   
#else
        NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRid;
#endif
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
        
        Result = phFriNfc_Tpz_H_RdBytes(NdefMap, NdefMap->TopazContainer.CurrentBlock,
            NdefMap->TopazContainer.ByteNumber);
    }
    return Result;    
}

#ifdef FRINFC_READONLY_NDEF

NFCSTATUS 
phFriNfc_TopazMap_ConvertToReadOnly (
    phFriNfc_NdefMap_t          *NdefMap)
{
    NFCSTATUS               result = NFCSTATUS_SUCCESS;

    result = phFriNfc_Tpz_H_WrAByte (NdefMap, CC_BLOCK_NUMBER, 
                                    CC_RWA_BYTE_NUMBER, CC_READ_ONLY_VALUE);

    if (NFCSTATUS_PENDING == PHNFCSTATUS(result))
    {
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_WR_CC_BYTE;
    }
    return result;
}

#endif /* #ifdef FRINFC_READONLY_NDEF */

/*!
* \brief Initiates Reading of NDEF information from the Remote Device.
*
* The function initiates the reading of NDEF information from a Remote Device.
* It performs a reset of the state and starts the action (state machine).
* A periodic call of the \ref phFriNfcNdefMap_Process has to be done once the action
* has been triggered.
*/
NFCSTATUS phFriNfc_TopazMap_RdNdef( phFriNfc_NdefMap_t                  *NdefMap,
                                        uint8_t                         *PacketData,
                                        uint32_t                        *PacketDataLength,
                                        uint8_t                         Offset)
{
    NFCSTATUS               Result =    NFCSTATUS_SUCCESS;

    /* Copy user buffer to the context */
    NdefMap->ApduBuffer = PacketData;
    /* Copy user length to the context */
    NdefMap->ApduBufferSize = *PacketDataLength;
    /* Update the user memory size to a context variable */
    NdefMap->NumOfBytesRead = PacketDataLength;
    /* Number of bytes read from the card is zero. 
    This variable returns the number of bytes read 
    from the card. */
    *NdefMap->NumOfBytesRead = PH_FRINFC_TOPAZ_VAL0;
    /* Index to know the length read */
    NdefMap->ApduBuffIndex = PH_FRINFC_TOPAZ_VAL0;    
    /* Store the offset in the context */
    NdefMap->Offset = Offset;
    /* Update the CR index to know from which operation completion 
    routine has to be called */
    NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_RD_NDEF;

    if( (Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN) || ( NdefMap->PrevOperation == 
        PH_FRINFC_NDEFMAP_WRITE_OPE))
    {
        /* If previous operation is not read then the read shall 
        start from BEGIN */
        NdefMap->Offset = PH_FRINFC_NDEFMAP_SEEK_BEGIN;
        /* Initialise current block and byte number */
        NdefMap->TopazContainer.CurrentBlock = PH_FRINFC_TOPAZ_VAL1;
        NdefMap->TopazContainer.ByteNumber = PH_FRINFC_TOPAZ_VAL0;
        /* State has to be changed */
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_READALL;
        NdefMap->TopazContainer.ReadWriteCompleteFlag = 
            PH_FRINFC_TOPAZ_FLAG0;
        /* Topaz command = READALL */
#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] = PH_FRINFC_TOPAZ_CMD_READALL;
#else     

#ifdef PH_HAL4_ENABLE
        NdefMap->Cmd.JewelCmd = phHal_eJewel_ReadAll;
#else
        NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelReadAll;        
#endif

#endif /* #ifdef TOPAZ_RAW_SUPPORT */
    }
    
    NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_READ_OPE;
    /* Offset = Current, but the read has reached the End of Card */
    if( (Offset == PH_FRINFC_NDEFMAP_SEEK_CUR) &&
        (NdefMap->TopazContainer.ReadWriteCompleteFlag == 
        PH_FRINFC_TOPAZ_FLAG1))
    {
        Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, 
            NFCSTATUS_EOF_NDEF_CONTAINER_REACHED); 
    }
    else
    {
        /* if the offset is begin then call READALL else copy the data 
        from the user buffer */
        Result = ((Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN)?
            phFriNfc_Tpz_H_RdBytes(NdefMap,
            NdefMap->TopazContainer.CurrentBlock,
            NdefMap->TopazContainer.ByteNumber):
        phFriNfc_Tpz_H_CpDataToUsrBuf(NdefMap));
    }

    return Result;
}

/*!
* \brief Initiates Writing of NDEF information to the Remote Device.
*
* The function initiates the writing of NDEF information to a Remote Device.
* It performs a reset of the state and starts the action (state machine).
* A periodic call of the \ref phFriNfcNdefMap_Process has to be done once the action
* has been triggered.
*/
NFCSTATUS phFriNfc_TopazMap_WrNdef( phFriNfc_NdefMap_t     *NdefMap,
                                   uint8_t                 *PacketData,
                                   uint32_t                *PacketDataLength,
                                   uint8_t                 Offset)
{
    NFCSTATUS                   Result =    NFCSTATUS_SUCCESS;
    uint8_t TempByteVal = 0;
    /* Copy user buffer to the context */
    NdefMap->ApduBuffer = PacketData;
    /* Copy user length to the context */
    NdefMap->ApduBufferSize = *PacketDataLength;
    /* Index to know the length written */
    NdefMap->ApduBuffIndex = PH_FRINFC_TOPAZ_VAL0;
    /* Update the user memory size to a context variable */
    NdefMap->WrNdefPacketLength = PacketDataLength;
    /* Number of bytes written to the card is zero. 
    This variable returns the number of bytes written 
    to the card. */
    *NdefMap->WrNdefPacketLength = PH_FRINFC_TOPAZ_VAL0;
    /* Update the CR index to know from which operation completion 
    routine has to be called */
    NdefMap->TopazContainer.CRIndex = PH_FRINFC_NDEFMAP_CR_WR_NDEF;
    /* Store the offset in the context */
    NdefMap->Offset = Offset;


    if( (Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN) || 
        (NdefMap->PrevOperation == PH_FRINFC_NDEFMAP_READ_OPE))
    {
        NdefMap->Offset = PH_FRINFC_NDEFMAP_SEEK_BEGIN;
        /* Initialise current block and byte number */
        NdefMap->TopazContainer.CurrentBlock = PH_FRINFC_TOPAZ_VAL1;
        NdefMap->TopazContainer.ByteNumber = PH_FRINFC_TOPAZ_VAL0;
        /* State has to be changed */
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_READALL;
        /* Topaz command = READALL */

#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] = PH_FRINFC_TOPAZ_CMD_READALL;
#else
#ifdef PH_HAL4_ENABLE
        NdefMap->Cmd.JewelCmd = phHal_eJewel_ReadAll;
#else
        NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelReadAll;
#endif
#endif  /* #ifdef TOPAZ_RAW_SUPPORT */      
        NdefMap->TopazContainer.ReadWriteCompleteFlag = 
            PH_FRINFC_TOPAZ_FLAG0;
        NdefMap->TopazContainer.RemainingSize = NdefMap->CardMemSize;        
        TempByteVal = NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL1];
    }
    else
    {
        /* State has to be changed */
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE;
        /* copy the user data to write into the card */
        TempByteVal = NdefMap->ApduBuffer[NdefMap->ApduBuffIndex];
    } 

    /* Update the previous operation to write operation */
    NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_WRITE_OPE;
    if((Offset == PH_FRINFC_NDEFMAP_SEEK_CUR) &&
        (NdefMap->TopazContainer.ReadWriteCompleteFlag == 
        PH_FRINFC_TOPAZ_FLAG1))
    {
        /* Offset = Current, but the read has reached the End of Card */
        Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, 
            NFCSTATUS_EOF_NDEF_CONTAINER_REACHED); 
    }
    else
    {
        /* Check the block */
        phFriNfc_Tpz_H_BlkChk(NdefMap);
        /* if offset is begin then call READALL else start writing */
        Result = ((NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN)?
            phFriNfc_Tpz_H_RdBytes(NdefMap, NdefMap->TopazContainer.CurrentBlock,
            NdefMap->TopazContainer.ByteNumber):
            phFriNfc_Tpz_H_WrAByte(NdefMap, NdefMap->TopazContainer.CurrentBlock,
            NdefMap->TopazContainer.ByteNumber,TempByteVal));
    }

    return Result;
}


/*!
* \brief Completion Routine, Processing function, needed to avoid long blocking.
* \note The lower (Overlapped HAL) layer must register a pointer to this function as a Completion
*       Routine in order to be able to notify the component that an I/O has finished and data are
*       ready to be processed.
*
*/

void phFriNfc_TopazMap_Process( void       *Context,
                               NFCSTATUS   Status)
{

    phFriNfc_NdefMap_t              *psNdefMap = NULL;

#ifdef TOPAZ_RF_ERROR_WORKAROUND

    static uint8_t                  rf_error_state = 0;

#endif /* #ifdef TOPAZ_RF_ERROR_WORKAROUND */
#ifdef FRINFC_READONLY_NDEF
    static uint8_t                  written_lock_byte = 0;
#endif /* #ifdef FRINFC_READONLY_NDEF */

    psNdefMap = (phFriNfc_NdefMap_t *)Context;

    if ((Status & PHNFCSTBLOWER) == (NFCSTATUS_SUCCESS & PHNFCSTBLOWER))
    {
        switch (psNdefMap->State)
        {
#ifdef FRINFC_READONLY_NDEF
            case PH_FRINFC_TOPAZ_STATE_WR_CC_BYTE:
            {
                if((CC_READ_ONLY_VALUE == *psNdefMap->SendRecvBuf)  
                    && (PH_FRINFC_TOPAZ_VAL1 == *psNdefMap->SendRecvLength))
                {
                    written_lock_byte = 0;
#ifdef TOPAZ_RAW_SUPPORT
                    *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ;
#else
#ifdef PH_HAL4_ENABLE
                    psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read1;
#else
                    psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead1;
#endif /* #ifdef PH_HAL4_ENABLE */
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
                    Status = phFriNfc_Tpz_H_RdBytes (psNdefMap, LOCK_BLOCK_NUMBER, 
                                                    LOCK0_BYTE_NUMBER);

                    if (NFCSTATUS_PENDING == PHNFCSTATUS(Status))
                    {
                        psNdefMap->State = PH_FRINFC_TOPAZ_STATE_RD_LOCK0_BYTE;
                    }
                }
                else
                {
                    Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                        NFCSTATUS_INVALID_RECEIVE_LENGTH);
                }
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_RD_LOCK0_BYTE:
            {
                if (PH_FRINFC_TOPAZ_VAL1 == *psNdefMap->SendRecvLength)
                {
                    Status = phFriNfc_Tpz_H_WrAByte (psNdefMap, LOCK_BLOCK_NUMBER, 
                                                LOCK0_BYTE_NUMBER, 
                                                LOCK0_BYTE_VALUE);

                    if (NFCSTATUS_PENDING == PHNFCSTATUS(Status))
                    {
                        psNdefMap->State = PH_FRINFC_TOPAZ_STATE_WR_LOCK0_BYTE;
                    }
                }
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_WR_LOCK0_BYTE:
            {
                if((LOCK0_BYTE_VALUE == *psNdefMap->SendRecvBuf)  
                    && (PH_FRINFC_TOPAZ_VAL1 == *psNdefMap->SendRecvLength))
                {
#ifdef TOPAZ_RAW_SUPPORT
                    *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ;
#else
#ifdef PH_HAL4_ENABLE
                    psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read1;
#else
                    psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead1;
#endif /* #ifdef PH_HAL4_ENABLE */
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
                    Status = phFriNfc_Tpz_H_RdBytes (psNdefMap, LOCK_BLOCK_NUMBER, 
                                                    LOCK1_BYTE_NUMBER);

                    if (NFCSTATUS_PENDING == PHNFCSTATUS(Status))
                    {
                        psNdefMap->State = PH_FRINFC_TOPAZ_STATE_RD_LOCK1_BYTE;
                    }
                }
                else
                {
                    Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                        NFCSTATUS_INVALID_RECEIVE_LENGTH);
                }
            }

            case PH_FRINFC_TOPAZ_STATE_RD_LOCK1_BYTE:
            {
                if (PH_FRINFC_TOPAZ_VAL1 == *psNdefMap->SendRecvLength)
                {
                    written_lock_byte = (uint8_t)(*psNdefMap->SendRecvBuf | LOCK1_BYTE_VALUE);
                    Status = phFriNfc_Tpz_H_WrAByte (psNdefMap, LOCK_BLOCK_NUMBER, 
                                                LOCK1_BYTE_NUMBER, 
                                                written_lock_byte);

                    if (NFCSTATUS_PENDING == PHNFCSTATUS(Status))
                    {
                        psNdefMap->State = PH_FRINFC_TOPAZ_STATE_WR_LOCK1_BYTE;
                    }
                }
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_WR_LOCK1_BYTE:
            {
                if((written_lock_byte == *psNdefMap->SendRecvBuf)  
                    && (PH_FRINFC_TOPAZ_VAL1 == *psNdefMap->SendRecvLength))
                {
                    written_lock_byte = 0;
                    /* Do nothing */
                }
                else
                {
                    written_lock_byte = 0;
                    Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                        NFCSTATUS_INVALID_RECEIVE_LENGTH);
                }
            }
#endif /* #ifdef FRINFC_READONLY_NDEF */
            case PH_FRINFC_TOPAZ_STATE_WRITE:
            {
                Status = phFriNfc_Tpz_H_ProWrUsrData (psNdefMap);
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_READID:
            {
                Status = phFriNfc_Tpz_H_ProReadID (psNdefMap);
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_READALL:
            {
                Status = phFriNfc_Tpz_H_ProReadAll (psNdefMap);
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_WRITE_NMN:
            {
                Status = phFriNfc_Tpz_H_ProWrNMN (psNdefMap);
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_WRITE_L_TLV:
            {
                Status = phFriNfc_Tpz_H_ProWrTLV (psNdefMap);
                break;
            }

            case PH_FRINFC_TOPAZ_STATE_WR_CC_OR_TLV:
            {
                Status = phFriNfc_Tpz_H_ProCCTLV (psNdefMap);
                break;
            }

#ifdef TOPAZ_RF_ERROR_WORKAROUND

            case PH_FRINFC_TOPAZ_STATE_RF_ERROR_READ:
            {
                Status = phFriNfc_Tpz_H_CheckWrittenData (psNdefMap, 
                                                        rf_error_state);
                break;
            }

#endif /* #ifdef TOPAZ_RF_ERROR_WORKAROUND */

            default:
            {
                Status = PHNFCSTVAL (CID_FRI_NFC_NDEF_MAP,
                                    NFCSTATUS_INVALID_DEVICE_REQUEST);
                break;
            }
        }
    }
    else
    {
#ifdef TOPAZ_RF_ERROR_WORKAROUND

        if ((FRINFC_RF_TIMEOUT_89 == PHNFCSTATUS (Status)) || 
            (FRINFC_RF_TIMEOUT_90 == PHNFCSTATUS (Status)) || 
            (NFCSTATUS_RF_TIMEOUT == PHNFCSTATUS (Status)))
        {
            uint8_t             byte_number = 0;
            uint8_t             block_number = 0;

            rf_error_state = psNdefMap->State;

#ifdef TOPAZ_RAW_SUPPORT

            *psNdefMap->SendRecvBuf = PH_FRINFC_TOPAZ_CMD_READ;

#else

#ifdef PH_HAL4_ENABLE

            psNdefMap->Cmd.JewelCmd = phHal_eJewel_Read1;

#else

            psNdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelRead1;

#endif /* #ifdef PH_HAL4_ENABLE */

#endif /* #ifdef TOPAZ_RAW_SUPPORT */

            /* Update the state variable to the new work around state*/
            psNdefMap->State = PH_FRINFC_TOPAZ_STATE_RF_ERROR_READ;

            /* Switch is used to know, if the error occured during WRITE or READ */
            switch (rf_error_state)
            {
                case PH_FRINFC_TOPAZ_STATE_WRITE_NMN:
                {                    
                    /* Block and byte number is updated for NMN */
                    byte_number = PH_FRINFC_TOPAZ_VAL0;
                    block_number = PH_FRINFC_TOPAZ_VAL1;
                    break;
                }

                case PH_FRINFC_TOPAZ_STATE_WRITE_L_TLV:
                {
                    /* Get the L field of the TLV block */
                    block_number = (uint8_t)(((psNdefMap->TLVStruct.NdefTLVByte + 
                                        PH_FRINFC_TOPAZ_VAL1) > 
                                        PH_FRINFC_TOPAZ_VAL7)?
                                        (psNdefMap->TLVStruct.NdefTLVBlock + 
                                        PH_FRINFC_TOPAZ_VAL1):
                                        psNdefMap->TLVStruct.NdefTLVBlock);
                    /* Get the L byte */
                    byte_number = (uint8_t)((psNdefMap->TLVStruct.NdefTLVByte + 
                                        PH_FRINFC_TOPAZ_VAL1) % 
                                        PH_FRINFC_TOPAZ_VAL8);
                    break;
                }

                case PH_FRINFC_TOPAZ_STATE_WR_CC_OR_TLV:
                {
                    switch (psNdefMap->TopazContainer.InternalState)
                    {
                        case PH_FRINFC_TOPAZ_WR_CC_BYTE0:
                        {
                            /* Block and byte number is updated for the CC byte 0 */
                            block_number = (uint8_t)PH_FRINFC_TOPAZ_VAL1;
                            byte_number = (uint8_t)PH_FRINFC_TOPAZ_VAL0;
                            break;
                        }

                        case PH_FRINFC_TOPAZ_WR_CC_BYTE1:
                        {
                            /* Block and byte number is updated for the CC byte 1 */
                            block_number = (uint8_t)PH_FRINFC_TOPAZ_VAL1;
                            byte_number = (uint8_t)PH_FRINFC_TOPAZ_VAL1;
                            break;
                        }

                        case PH_FRINFC_TOPAZ_WR_CC_BYTE2:
                        {
                            /* Block and byte number is updated for the CC byte 2 */
                            block_number = (uint8_t)PH_FRINFC_TOPAZ_VAL1;
                            byte_number = (uint8_t)PH_FRINFC_TOPAZ_VAL2;
                            break;
                        }

                        case PH_FRINFC_TOPAZ_WR_CC_BYTE3:
                        {
                            /* Block and byte number is updated for the CC byte 3 */
                            block_number = (uint8_t)PH_FRINFC_TOPAZ_VAL1;
                            byte_number = (uint8_t)PH_FRINFC_TOPAZ_VAL3;
                            break;
                        }

                        case PH_FRINFC_TOPAZ_WR_T_OF_TLV:
                        {
                            /* Block and byte number is updated for the Type field of the TLV */
                            block_number = psNdefMap->TLVStruct.NdefTLVBlock;
                            byte_number = (uint8_t)psNdefMap->TLVStruct.NdefTLVByte;
                            break;
                        }

                        default:
                        {
                            /* Do nothing */
                            break;
                        }
                    } /* switch (psNdefMap->TopazContainer.InternalState) */
                    break;
                }

                case PH_FRINFC_TOPAZ_STATE_WRITE:                
                {
                    /* Block and byte number is updated for the written error data */                    
                    block_number = psNdefMap->TopazContainer.CurrentBlock;
                    byte_number = psNdefMap->TopazContainer.ByteNumber;                  
                    break;
                }

                default:
                {
                    /* Error occured is not during WRITE, so update 
                        state variable to the previous state */
                    psNdefMap->State = rf_error_state;
                    break;
                }
            } /* switch (rf_error_state) */

            /* The below check is added, to know if the error is for 
            the WRITE or READ scenario, 
            If the error is for READ, then state variable is not updated
            If the error is for WRITE, then state variable is updated with 
            PH_FRINFC_TOPAZ_STATE_RF_ERROR_READ value */
            if (PH_FRINFC_TOPAZ_STATE_RF_ERROR_READ == psNdefMap->State)
            {
                /* Read the data with the updated block and byte number */
                Status = phFriNfc_Tpz_H_RdBytes (psNdefMap, block_number, 
                                                byte_number);
            }
        }

#endif /* #ifdef TOPAZ_RF_ERROR_WORKAROUND */
    }

    /* Call Completion Routine, if Status != PENDING */
    if (NFCSTATUS_PENDING != Status)
    {
        phFriNfc_Tpz_H_Complete(psNdefMap, Status);
    }
}


#ifdef TOPAZ_RF_ERROR_WORKAROUND

static 
NFCSTATUS 
phFriNfc_Tpz_H_CheckWrittenData (
    phFriNfc_NdefMap_t          *psNdefMap,
    uint8_t                     state_rf_error)
{
    NFCSTATUS   result = NFCSTATUS_SUCCESS;

    switch (state_rf_error)
    {
        case PH_FRINFC_TOPAZ_STATE_WRITE:
        {
            result = phFriNfc_Tpz_H_ProWrUsrData (psNdefMap);
            break;
        }

        case PH_FRINFC_TOPAZ_STATE_WRITE_NMN:
        {
            result = phFriNfc_Tpz_H_ProWrNMN (psNdefMap);
            break;
        }

        case PH_FRINFC_TOPAZ_STATE_WRITE_L_TLV:
        {
            result = phFriNfc_Tpz_H_ProWrTLV (psNdefMap);
            break;
        }

        case PH_FRINFC_TOPAZ_STATE_WR_CC_OR_TLV:
        {
            result = phFriNfc_Tpz_H_ProCCTLV (psNdefMap);
            break;
        }

        default:
        {
            break;
        }
    }

    return result;
}


#endif /* #ifdef TOPAZ_RF_ERROR_WORKAROUND */

static NFCSTATUS phFriNfc_Tpz_H_RdBytes(phFriNfc_NdefMap_t *NdefMap,
                                        uint16_t             BlockNo,
                                        uint16_t            ByteNo)
{
    NFCSTATUS   Result = NFCSTATUS_SUCCESS;
#ifdef TOPAZ_RAW_SUPPORT
    uint8_t index = 0;
#endif /* #ifdef TOPAZ_RAW_SUPPORT */

    /* set the data for additional data exchange*/
    NdefMap->psDepAdditionalInfo.DepFlags.MetaChaining = PH_FRINFC_TOPAZ_VAL0;
    NdefMap->psDepAdditionalInfo.DepFlags.NADPresent = PH_FRINFC_TOPAZ_VAL0;
    NdefMap->psDepAdditionalInfo.NAD = PH_FRINFC_TOPAZ_VAL0;

    NdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_TopazMap_Process;
    NdefMap->MapCompletionInfo.Context = NdefMap;

    *NdefMap->SendRecvLength = NdefMap->TempReceiveLength;

    /* Depending on the jewel command, the send length is decided */
#ifdef TOPAZ_RAW_SUPPORT
    switch(NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0])
#else
    switch(NdefMap->Cmd.JewelCmd)
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
    {

#ifdef TOPAZ_RAW_SUPPORT
    case PH_FRINFC_TOPAZ_CMD_READID:
#else
#ifdef PH_HAL4_ENABLE
    case phHal_eJewel_RID:
#else
    case phHal_eJewelCmdListJewelRid:
#endif
#endif /* #ifdef TOPAZ_RAW_SUPPORT */

#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        /*Copy command to  Send Buffer*/
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0]  = PH_FRINFC_TOPAZ_CMD_READID;
        index ++;        

        /*Copy UID of the tag to  Send Buffer*/
        (void)memset(&(NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL1]),
        0x00,(0x06));
        index = index + 0x06;

        /* Update the length of the command buffer*/
        NdefMap->SendLength = index;
#else
        /* For READ ID and READ ALL, send length is 0 */
        NdefMap->SendLength = PH_FRINFC_TOPAZ_VAL0;
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
        break;

#ifdef TOPAZ_RAW_SUPPORT
    case PH_FRINFC_TOPAZ_CMD_READALL:
#else
#ifdef PH_HAL4_ENABLE
    case phHal_eJewel_ReadAll:  
#else
    case phHal_eJewelCmdListJewelReadAll:
#endif
#endif /* #ifdef TOPAZ_RAW_SUPPORT */

#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        /*Copy command to  Send Buffer*/
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0]  = PH_FRINFC_TOPAZ_CMD_READALL;
        index ++;

        /*Copy 0x00 to Send Buffer*/
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL1] = 0x00;
        index ++;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2] = 0x00;
        index ++;

        /*Copy UID of the tag to  Send Buffer*/
        (void)memcpy(&(NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL3]),
        &(NdefMap->psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid),
        TOPAZ_UID_LENGTH_FOR_READ_WRITE);

        index = (uint8_t)(index + TOPAZ_UID_LENGTH_FOR_READ_WRITE);

        /* Update the length of the command buffer*/
        NdefMap->SendLength = index;
#else
       /* For READ ID and READ ALL, send length is 0 */
        NdefMap->SendLength = PH_FRINFC_TOPAZ_VAL0;
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
        break;

#ifdef TOPAZ_RAW_SUPPORT
    case PH_FRINFC_TOPAZ_CMD_READ:
#else
#ifdef PH_HAL4_ENABLE
    case phHal_eJewel_Read1:
#else
    case phHal_eJewelCmdListJewelRead1:
#endif 

#endif /* #ifdef TOPAZ_RAW_SUPPORT */

#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        /*Copy command to  Send Buffer*/
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0]  = PH_FRINFC_TOPAZ_CMD_READ;
        index ++;

        /*Copy Address to  Send Buffer*/
        /* Calculate send length 
        7 | 6   5   4   3 | 2   1   0 | 
        |    block no   |  byte no  | 
        */
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL1] = 
                (uint8_t)((BlockNo << PH_FRINFC_TOPAZ_SHIFT3) + 
                ByteNo);
        index ++;
        /*Copy 0x00 to  Send Buffer*/
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2] = 0x00;
        index ++;

        /*Copy UID of the tag to  Send Buffer*/
        (void)memcpy(&(NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL3]),
        &(NdefMap->psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid),
        TOPAZ_UID_LENGTH_FOR_READ_WRITE);
        index = (uint8_t)(index + TOPAZ_UID_LENGTH_FOR_READ_WRITE);

        /* Update the length of the command buffer*/
        NdefMap->SendLength = index;
#else
        /* Calculate send length 
        7 | 6   5   4   3 | 2   1   0 | 
        |    block no   |  byte no  | 
        */
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] = 
                (uint8_t)((BlockNo << PH_FRINFC_TOPAZ_SHIFT3) + 
                ByteNo);
        NdefMap->SendLength = PH_FRINFC_TOPAZ_VAL1;
#endif /* #ifdef TOPAZ_RAW_SUPPORT */
        
        break;
#ifdef TOPAZ_RAW_SUPPORT
#else
#ifdef PH_HAL4_ENABLE
    case phHal_eJewel_Read:
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] = 0x00;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL1] = 0x00;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2] = 104;
        NdefMap->SendLength = 3;
    break;
#endif
#endif /* #ifdef TOPAZ_RAW_SUPPORT */

    default:
        Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                            NFCSTATUS_INVALID_DEVICE_REQUEST);
    }

    if(Result == NFCSTATUS_SUCCESS)
    {
        /* Call the Overlapped HAL Transceive function */ 
        Result = phFriNfc_OvrHal_Transceive(    NdefMap->LowerDevice,
                                                &NdefMap->MapCompletionInfo,
                                                NdefMap->psRemoteDevInfo,
                                                NdefMap->Cmd,
                                                &NdefMap->psDepAdditionalInfo,
                                                NdefMap->SendRecvBuf,
                                                NdefMap->SendLength,
                                                NdefMap->SendRecvBuf,
                                                NdefMap->SendRecvLength);
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_WrAByte(phFriNfc_NdefMap_t *NdefMap,
                                        uint16_t             BlockNo,
                                        uint16_t             ByteNo,
                                        uint8_t              ByteVal
                                        )
{
    NFCSTATUS   Result = NFCSTATUS_SUCCESS;
    uint8_t     index = 0;

    
    PHNFC_UNUSED_VARIABLE(ByteVal);
    /* set the data for additional data exchange*/
    NdefMap->psDepAdditionalInfo.DepFlags.MetaChaining = PH_FRINFC_TOPAZ_VAL0;
    NdefMap->psDepAdditionalInfo.DepFlags.NADPresent = PH_FRINFC_TOPAZ_VAL0;
    NdefMap->psDepAdditionalInfo.NAD = PH_FRINFC_TOPAZ_VAL0;

    NdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_TopazMap_Process;
    NdefMap->MapCompletionInfo.Context = NdefMap;

    *NdefMap->SendRecvLength = NdefMap->TempReceiveLength;
    /* Command used to write 1 byte */
#ifdef TOPAZ_RAW_SUPPORT
    NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
#else
#ifdef PH_HAL4_ENABLE
    NdefMap->Cmd.JewelCmd = phHal_eJewel_Write1E;
#else
    NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelWriteErase1;
#endif
#endif /* #ifdef TOPAZ_RAW_SUPPORT */   

#ifdef TOPAZ_RAW_SUPPORT
    /*Copy command to Send Buffer*/
    NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0]  = PH_FRINFC_TOPAZ_CMD_WRITE_1E;
    index ++;

    /*Copy Address to  Send Buffer*/
    /* Calculate send length 
    7 | 6   5   4   3 | 2   1   0 | 
    |    block no   |  byte no  | 
    */
    NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL1] = 
            (uint8_t)((BlockNo << PH_FRINFC_TOPAZ_SHIFT3) + 
            ByteNo);
    index ++;
    /*Copy Data byte to Send Buffer*/
    NdefMap->SendRecvBuf[index] = ByteVal;
    index ++;

    /*Copy UID of the tag to  Send Buffer*/
    (void)memcpy(&(NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL3]),
      &(NdefMap->psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid),
      TOPAZ_UID_LENGTH_FOR_READ_WRITE);
    index = (uint8_t)(index + TOPAZ_UID_LENGTH_FOR_READ_WRITE);

    /* Update the length of the command buffer*/
    NdefMap->SendLength = index;   

#else
    /* Depending on the jewel command, the send length is decided */
    /* Calculate send length 
    7 | 6   5   4   3 | 2   1   0 | 
    |    block no   |  byte no  | 
    */
    NdefMap->SendRecvBuf[index] = 
                        (uint8_t)((BlockNo << PH_FRINFC_TOPAZ_SHIFT3) + 
                        ByteNo);
    index ++;
    NdefMap->SendRecvBuf[index] = ByteVal;
    index ++;
    NdefMap->SendLength = PH_FRINFC_TOPAZ_VAL2;

#endif /* #ifdef TOPAZ_RAW_SUPPORT */

    /* Call the Overlapped HAL Transceive function */ 
    Result = phFriNfc_OvrHal_Transceive(    NdefMap->LowerDevice,
                                            &NdefMap->MapCompletionInfo,
                                            NdefMap->psRemoteDevInfo,
                                            NdefMap->Cmd,
                                            &NdefMap->psDepAdditionalInfo,
                                            NdefMap->SendRecvBuf,
                                            NdefMap->SendLength,
                                            NdefMap->SendRecvBuf,
                                            NdefMap->SendRecvLength);

    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ProReadID(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    
    if(((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] & 
        PH_FRINFC_TOPAZ_HEADROM0_CHK) == PH_FRINFC_TOPAZ_HEADROM0_VAL) && 
        (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL6))
    {
        /* Copy UID to the context, Used when the READ ALL command is used */
        (void)memcpy(NdefMap->TopazContainer.UID, 
            &NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2],
            PH_FRINFC_TOPAZ_VAL4);

        /* State has to be changed */
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_READALL;
        /* Topaz command = READALL */
#ifdef TOPAZ_RAW_SUPPORT
        NdefMap->Cmd.JewelCmd = (phNfc_eJewelCmdList_t)phHal_eJewel_Raw;
        NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] = PH_FRINFC_TOPAZ_CMD_READALL;
#else 
#ifdef PH_HAL4_ENABLE
        NdefMap->Cmd.JewelCmd = phHal_eJewel_ReadAll;
#else
        NdefMap->Cmd.JewelCmd = phHal_eJewelCmdListJewelReadAll;
#endif
#endif /* #ifdef TOPAZ_RAW_SUPPORT */ 
    
        /* Read all bytes from the card */
        Result = phFriNfc_Tpz_H_RdBytes(NdefMap, NdefMap->TopazContainer.CurrentBlock,
            NdefMap->TopazContainer.ByteNumber);
    }

    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ProReadAll(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    int32_t     memcompare = PH_FRINFC_TOPAZ_VAL0;
    
    /* Compare the UID of READ ALL command with the stored UID */
#ifdef PH_HAL4_ENABLE
    if ((NdefMap->TopazContainer.UID[0] == NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2]) &&
        (NdefMap->TopazContainer.UID[1] == NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2 + 1]) &&
        (NdefMap->TopazContainer.UID[2] == NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2 + 2]) &&
        (NdefMap->TopazContainer.UID[3] == NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2 + 3]))
    {
        memcompare = PH_FRINFC_TOPAZ_VAL0;
    }
    else
    {
        memcompare = PH_FRINFC_TOPAZ_VAL1;
    }
#else
    memcompare = memcmp(NdefMap->TopazContainer.UID, 
        &NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL2],
        PH_FRINFC_TOPAZ_VAL4);  
#endif /* #ifdef PH_HAL4_ENABLE */

    if(((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] & 
        PH_FRINFC_TOPAZ_HEADROM0_CHK) == PH_FRINFC_TOPAZ_HEADROM0_VAL) && 
        (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_READALL_RESP) && 
        (memcompare == PH_FRINFC_TOPAZ_VAL0))
    {
        /* Copy 96 bytes from the read/write memory space */
        (void)memcpy(NdefMap->TopazContainer.ReadBuffer, 
            &NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL10],
            PH_FRINFC_TOPAZ_TOTAL_RWBYTES);

        /* Check the lock bits and set the card state */
        phFriNfc_Tpz_H_ChkLockBits(NdefMap);

        Result = phFriNfc_Tpz_H_CallNxtOp(NdefMap);
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_CallNxtOp(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    /* Depending on the operation (check, read or write ndef), process the  
    read data */
    switch(NdefMap->PrevOperation)
    {
    case PH_FRINFC_NDEFMAP_CHECK_OPE:
        /* Check the capabilty container values, according 
        to the spec */
        Result = phFriNfc_Tpz_H_ChkCCinChkNdef(NdefMap);

        if (NdefMap->CardState != PH_NDEFMAP_CARD_STATE_INVALID)
        {
            /* Check the spec version */
            Result = phFriNfc_Tpz_H_ChkSpcVer( NdefMap,
                NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL1]);
            /*  Check the CC header size: Only valid ones are
            0x0C for 96 bytes. */
            if ((Result == NFCSTATUS_SUCCESS) && 
                ( NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL2] <=  
                PH_FRINFC_TOPAZ_CC_BYTE2_MAX))
            {
                Result = phFriNfc_Tpz_H_findNDEFTLV(NdefMap);
                /* As there is possibility of either having or not having TLV in 
                Topaz, no need to send the Actual status to the context*/
                Result = NFCSTATUS_SUCCESS;
            }
        }
        else
        {
            Result = NFCSTATUS_SUCCESS;
            NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INITIALIZED;
            NdefMap->CardMemSize = 
            NdefMap->TopazContainer.RemainingSize = (uint16_t)
                        /* 
                        4 is decremented from the max size because of the 4 CC bytes
                        2 is decremented because of the NDEF TLV T and L byte 
                        to get the actual data size
                        */
                        (PH_FRINFC_TOPAZ_MAX_CARD_SZ - PH_FRINFC_TOPAZ_VAL4 - 
                        PH_FRINFC_TOPAZ_VAL2);
        }
        break;

    case PH_FRINFC_NDEFMAP_READ_OPE:
        /* Check the capabilty container values, according 
        to the spec */
        Result = phFriNfc_Tpz_H_ChkCCBytes(NdefMap);

        /* If success, find the ndef TLV */
        Result = ((Result != NFCSTATUS_SUCCESS)?
                (PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                NFCSTATUS_INVALID_FORMAT)):
                phFriNfc_Tpz_H_findNDEFTLV(NdefMap));

        if(Result == NFCSTATUS_SUCCESS)
        {
            NdefMap->TopazContainer.ByteNumber += PH_FRINFC_TOPAZ_VAL2;
            /* If success, copy the read bytes to the user buffer */
            Result = phFriNfc_Tpz_H_CpDataToUsrBuf(NdefMap);
        }
        break;

    case PH_FRINFC_NDEFMAP_WRITE_OPE:
    default:
        if((NdefMap->CardState == PH_NDEFMAP_CARD_STATE_READ_WRITE) || 
            (NdefMap->CardState == PH_NDEFMAP_CARD_STATE_INITIALIZED))
        {
            /* Check the capabilty container values, according 
            to the spec */
            Result = phFriNfc_Tpz_H_ChkCCBytes(NdefMap);
            if(Result == NFCSTATUS_SUCCESS)
            {
                /* Find the NDEF TLV */
                Result = phFriNfc_Tpz_H_findNDEFTLV(NdefMap);
                
                /* Write the TLV */
                NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_T_OF_TLV;
            }
            else
            {
                NdefMap->TLVStruct.NdefTLVByte = PH_FRINFC_TOPAZ_VAL4;
                NdefMap->TLVStruct.NdefTLVBlock = PH_FRINFC_TOPAZ_VAL1;
                NdefMap->TopazContainer.ByteNumber = PH_FRINFC_TOPAZ_VAL4;
                /* Write the TLV */
                NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_CC_BYTE0;
            }
            /* Write CC bytes */ 
            Result = phFriNfc_Tpz_H_WrCCorTLV(NdefMap);
        }
        break;
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ChkCCBytes(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_NO_NDEF_SUPPORT);

    if(NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL0] == 
        PH_FRINFC_TOPAZ_CC_BYTE0)
    {
        /* Check the spec version */
        Result = phFriNfc_Tpz_H_ChkSpcVer( NdefMap,
            NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL1]);
        /*  Check the CC header size: Only valid ones are
        0x0C for 96 bytes. */
        Result = ((( NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL2] >  
                    PH_FRINFC_TOPAZ_CC_BYTE2_MAX) || (Result != 
                    NFCSTATUS_SUCCESS))?
                    (PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, 
                    NFCSTATUS_EOF_NDEF_CONTAINER_REACHED)):
                    Result);

        /* Get the read/write card memory size */
        NdefMap->TopazContainer.RemainingSize = 
                NdefMap->CardMemSize = ((Result == NFCSTATUS_SUCCESS)?
                (PH_FRINFC_TOPAZ_MAX_CARD_SZ - PH_FRINFC_TOPAZ_VAL4):
                NdefMap->CardMemSize);

        /* if the call is from write ndef then check for read write access */
        if(((NdefMap->PrevOperation == PH_FRINFC_NDEFMAP_WRITE_OPE) && 
            (NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL3] != 
            PH_FRINFC_TOPAZ_CC_BYTE3_RW) && (Result == NFCSTATUS_SUCCESS)))
        {
            Result = (PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                NFCSTATUS_INVALID_FORMAT));
        }

        /* if the call is from read ndef then check for read only or read write access */
        if(((NdefMap->PrevOperation == PH_FRINFC_NDEFMAP_READ_OPE) && 
            ((NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL3] != 
            PH_FRINFC_TOPAZ_CC_BYTE3_RW) && 
            (NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL3] != 
            PH_FRINFC_TOPAZ_CC_BYTE3_RO))&& (Result == NFCSTATUS_SUCCESS)))
        {
            Result = (PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                NFCSTATUS_INVALID_FORMAT));
        }
    }
    return Result;
}

extern NFCSTATUS phFriNfc_Tpz_H_ChkSpcVer( phFriNfc_NdefMap_t  *NdefMap,
                                          uint8_t             VersionNo)
{
    NFCSTATUS Result = NFCSTATUS_SUCCESS;
    uint8_t TagVerNo = VersionNo;

    /* To remove "warning (VS C4100) : unreferenced formal parameter" */
    PHNFC_UNUSED_VARIABLE(NdefMap);

    if ( TagVerNo == 0 )
    {
        /*Return Status Error “ Invalid Format”*/
        Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,NFCSTATUS_INVALID_FORMAT);
    }
    else
    {
        /* calculate the major and minor version number of T3VerNo */
        if( (( PH_NFCFRI_NDEFMAP_NFCDEV_MAJOR_VER_NUM == 
            PH_NFCFRI_NDEFMAP_GET_MAJOR_TAG_VERNO(TagVerNo ) )&&
            ( PH_NFCFRI_NDEFMAP_NFCDEV_MINOR_VER_NUM >= 
            PH_NFCFRI_NDEFMAP_GET_MINOR_TAG_VERNO(TagVerNo))) ||
            (( PH_NFCFRI_NDEFMAP_NFCDEV_MAJOR_VER_NUM == 
            PH_NFCFRI_NDEFMAP_GET_MAJOR_TAG_VERNO(TagVerNo ) )&&
            ( PH_NFCFRI_NDEFMAP_NFCDEV_MINOR_VER_NUM < 
            PH_NFCFRI_NDEFMAP_GET_MINOR_TAG_VERNO(TagVerNo) )))
        {
            Result = PHNFCSTVAL(CID_NFC_NONE,NFCSTATUS_SUCCESS);
        }
        else 
        {
            if (( PH_NFCFRI_NDEFMAP_NFCDEV_MAJOR_VER_NUM <
                PH_NFCFRI_NDEFMAP_GET_MAJOR_TAG_VERNO(TagVerNo) ) ||
                ( PH_NFCFRI_NDEFMAP_NFCDEV_MAJOR_VER_NUM > 
                PH_NFCFRI_NDEFMAP_GET_MAJOR_TAG_VERNO(TagVerNo)))
            {
                Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,NFCSTATUS_INVALID_FORMAT);
            }
        }
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_findNDEFTLV(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_NO_NDEF_SUPPORT);
    uint8_t     index = PH_FRINFC_TOPAZ_VAL4;

    /* If remaining size is less than 3 then, there cant be any 
    TLV present in the card */
    while((index < PH_FRINFC_TOPAZ_TOTAL_RWBYTES) && 
        (NdefMap->TopazContainer.RemainingSize >= PH_FRINFC_TOPAZ_VAL3))
    {
        switch(NdefMap->TopazContainer.ReadBuffer[index])
        {
        case PH_FRINFC_TOPAZ_NDEF_T:
            /* To get the length field of the TLV */
            index++;
            /* Type and length are not data bytes, so to know the exact
            remaining size in the card, the below operation is done */
            NdefMap->TopazContainer.RemainingSize -= PH_FRINFC_TOPAZ_VAL2;
            /* Set the card state depending on the L value */
            Result = phFriNfc_MapTool_SetCardState(NdefMap, 
                (uint32_t)NdefMap->TopazContainer.ReadBuffer[index]);
            /* Check the TLV is correct */
            if((NdefMap->TopazContainer.ReadBuffer[index] > 
                NdefMap->TopazContainer.RemainingSize) || 
                ((NdefMap->TopazContainer.ReadBuffer[index] == 
                PH_FRINFC_TOPAZ_VAL0) && (NdefMap->PrevOperation == 
                PH_FRINFC_NDEFMAP_READ_OPE)) || (Result != NFCSTATUS_SUCCESS))
            {
                /* L field value cant be greater than the remaining size, so error */
                Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                    NFCSTATUS_NO_NDEF_SUPPORT);
                /* To break out of the loop */
                index = PH_FRINFC_TOPAZ_TOTAL_RWBYTES;
            }
            else
            {
                /* So remaining size also changes, according to the position of NDEF TLV  */
                NdefMap->TLVStruct.BytesRemainLinTLV = 
                    NdefMap->TopazContainer.ReadBuffer[index];

                /* Get the byte number */
                NdefMap->TLVStruct.NdefTLVByte = (uint16_t)((index - PH_FRINFC_TOPAZ_VAL1) % 
                                                    PH_FRINFC_TOPAZ_VAL8);
                /* Get the block number */
                NdefMap->TLVStruct.NdefTLVBlock = (uint8_t)(((index - PH_FRINFC_TOPAZ_VAL1) / 
                                                    PH_FRINFC_TOPAZ_VAL8) + 
                                                    PH_FRINFC_TOPAZ_VAL1);
                /* TLV found flag is set */
                NdefMap->TLVStruct.NdefTLVFoundFlag = PH_FRINFC_TOPAZ_FLAG1;
                /* To know the position of V field in the TLV */
                NdefMap->TopazContainer.ByteNumber = (uint8_t)(((NdefMap->TLVStruct.NdefTLVBlock - 1) * 8) +
                                                    NdefMap->TLVStruct.NdefTLVByte);
                /* To break out of the loop */
                index = PH_FRINFC_TOPAZ_TOTAL_RWBYTES;
                Result = NFCSTATUS_SUCCESS;
            }
            break;

        case PH_FRINFC_TOPAZ_NULL_T:
            /* Null TLV, Skip the TLV */
            NdefMap->TopazContainer.RemainingSize--;
            index++;
            break;

        case PH_FRINFC_TOPAZ_TERM_T:
            /* No more TLV present in the card, so error */
            index = PH_FRINFC_TOPAZ_TOTAL_RWBYTES;
            Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                NFCSTATUS_NO_NDEF_SUPPORT);
            break;

        default:
            /* Go till the length field of the TLV */
            index++;
            /* Type and length is not the data, so to know the exact
            remaining size in the card, the below operation is done */
            NdefMap->TopazContainer.RemainingSize -= PH_FRINFC_TOPAZ_VAL2;
            if(NdefMap->TopazContainer.ReadBuffer[index] > 
                NdefMap->TopazContainer.RemainingSize)
            {
                /* L field value cant be greater than the remaining size, so error */
                index = PH_FRINFC_TOPAZ_TOTAL_RWBYTES;
                Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                    NFCSTATUS_NO_NDEF_SUPPORT);
            }
            else
            {
                /* Remaining size of the free space available in the card changes, 
                according to the position of NDEF TLV */
                NdefMap->TopazContainer.RemainingSize = 
                    NdefMap->TopazContainer.RemainingSize -
                    NdefMap->TopazContainer.ReadBuffer[index];

                /* Get the position of the next TLV */
                index = (uint8_t)(index + 
                    (NdefMap->TopazContainer.ReadBuffer[index] + 
                     PH_FRINFC_TOPAZ_VAL1));                
            }
            break;
        }
    }

    /* If no Ndef TLV found and operation done is read */
    if((NdefMap->TLVStruct.NdefTLVFoundFlag == PH_FRINFC_TOPAZ_FLAG0) && 
        (NdefMap->PrevOperation == PH_FRINFC_NDEFMAP_READ_OPE))
    {
        Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                            NFCSTATUS_EOF_NDEF_CONTAINER_REACHED);
    }
    if((NdefMap->TLVStruct.NdefTLVFoundFlag == PH_FRINFC_TOPAZ_FLAG0) && 
        ((NdefMap->PrevOperation == PH_FRINFC_NDEFMAP_WRITE_OPE) ||
        (NdefMap->PrevOperation == PH_FRINFC_NDEFMAP_CHECK_OPE)))
    {
        NdefMap->TLVStruct.NdefTLVByte = PH_FRINFC_TOPAZ_VAL4; 
        NdefMap->TLVStruct.NdefTLVBlock = PH_FRINFC_TOPAZ_VAL1;
        NdefMap->TopazContainer.ByteNumber = PH_FRINFC_TOPAZ_VAL4;
        NdefMap->TopazContainer.RemainingSize = PH_FRINFC_TOPAZ_TOTAL_RWBYTES1;
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_CpDataToUsrBuf(phFriNfc_NdefMap_t  *NdefMap)
{
    NFCSTATUS   Result = NFCSTATUS_SUCCESS;
    
    /* Check the the TLV size and the user size */
    if(NdefMap->ApduBufferSize >=
        NdefMap->TLVStruct.BytesRemainLinTLV)
    {
        /* Copy the read bytes to user buffer till the value (V) 
        of TLV ends */
        (void)memcpy(NdefMap->ApduBuffer,
            &(NdefMap->TopazContainer.ReadBuffer[ 
                NdefMap->TopazContainer.ByteNumber]),
                    NdefMap->TLVStruct.BytesRemainLinTLV);

                /* Update the number of read bytes to the user */
                *(NdefMap->NumOfBytesRead) = 
                    NdefMap->TLVStruct.BytesRemainLinTLV;
                /* There is no byte to read */
                NdefMap->TopazContainer.ByteNumber = 
                                                    PH_FRINFC_TOPAZ_VAL0;
                /* No further read is possible */
                NdefMap->TopazContainer.ReadWriteCompleteFlag = 
                                                    PH_FRINFC_TOPAZ_FLAG1;
                /* Remaining size in the card can be greater than length field in 
                the TLV */
                NdefMap->TopazContainer.RemainingSize = 
                    NdefMap->TopazContainer.RemainingSize -
                                        NdefMap->TLVStruct.BytesRemainLinTLV;
                /* TLV has been completely read, no more bytes to read */
                NdefMap->TLVStruct.BytesRemainLinTLV = 
                                                    PH_FRINFC_TOPAZ_VAL0;
    }
    else
    {
        /* Copy read bytes till the user buffer size */
        (void)memcpy(NdefMap->ApduBuffer,
                    &(NdefMap->TopazContainer.ReadBuffer[ 
                    NdefMap->TopazContainer.ByteNumber]),
                    NdefMap->ApduBufferSize);

        /* Update the number of read bytes to the user */
        *(NdefMap->NumOfBytesRead) = 
            NdefMap->ApduBufferSize;
        /* Get the next byte number to read */
        NdefMap->TopazContainer.ByteNumber = 
            (uint8_t)(NdefMap->TopazContainer.ByteNumber +
                      NdefMap->ApduBufferSize);
        /* Free space left in the card */
        NdefMap->TopazContainer.RemainingSize 
            = NdefMap->TopazContainer.RemainingSize 
                  - (uint16_t)NdefMap->ApduBufferSize;
        /* Bytes left in the TLV */
        NdefMap->TLVStruct.BytesRemainLinTLV = 
            NdefMap->TLVStruct.BytesRemainLinTLV -
                   (uint16_t)NdefMap->ApduBufferSize;
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ProWrNMN(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    uint8_t     BlockNo = PH_FRINFC_TOPAZ_VAL0,
        ByteNo = PH_FRINFC_TOPAZ_VAL0;

    if((NdefMap->TopazContainer.InternalState == 
        PH_FRINFC_TOPAZ_WR_NMN_0) && 
        (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
        PH_FRINFC_TOPAZ_VAL0) && 
        (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
    {
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE_L_TLV;
        /* Get the L field of the TLV block */
        BlockNo = (uint8_t)(((NdefMap->TLVStruct.NdefTLVByte + PH_FRINFC_TOPAZ_VAL1) > 
                            PH_FRINFC_TOPAZ_VAL7)?
                            (NdefMap->TLVStruct.NdefTLVBlock + PH_FRINFC_TOPAZ_VAL1):
                            NdefMap->TLVStruct.NdefTLVBlock);
        /* Get the L byte */
        ByteNo = (uint8_t)((NdefMap->TLVStruct.NdefTLVByte + PH_FRINFC_TOPAZ_VAL1) % 
                                PH_FRINFC_TOPAZ_VAL8);

        
        /* Here the NMN is written 0, so internal state is used */
        NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_L_TLV_0;
        /* Write the length value = 0x00 , Write L field of TLV  = 0  inside this*/
        Result = phFriNfc_Tpz_H_WrAByte( NdefMap, BlockNo, ByteNo,
                                        PH_FRINFC_TOPAZ_VAL0);
    }
    else 
    {
        if((NdefMap->TopazContainer.InternalState == 
            PH_FRINFC_TOPAZ_WR_NMN_E1) && 
            (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            PH_FRINFC_TOPAZ_CC_BYTE0) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            /* Card state is initialised or invalid */ 
            NdefMap->CardState = (uint8_t)((NdefMap->CardState == 
                                    PH_NDEFMAP_CARD_STATE_INITIALIZED)?
                                    PH_NDEFMAP_CARD_STATE_READ_WRITE:
                                    NdefMap->CardState);
            /* update the length to the user */
            *NdefMap->WrNdefPacketLength = NdefMap->ApduBuffIndex;
            Result = NFCSTATUS_SUCCESS;
        }
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ProWrTLV(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    if((NdefMap->TopazContainer.InternalState == 
        PH_FRINFC_TOPAZ_WR_L_TLV_0) && 
        (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
        PH_FRINFC_TOPAZ_VAL0) && 
        (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
    {
        /* state is writing user data to the card */
        NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE;      
       
        NdefMap->TopazContainer.ByteNumber++;
        /* Check the byte number */
        phFriNfc_Tpz_H_BlkChk(NdefMap);

        /* Write data to the specified location */
        /* Write the data to the card from the user buffer */
        Result = phFriNfc_Tpz_H_WrAByte( NdefMap, 
                                        NdefMap->TopazContainer.CurrentBlock,
                                        NdefMap->TopazContainer.ByteNumber,
                                        NdefMap->ApduBuffer[NdefMap->ApduBuffIndex]
                                        );
    }
    else 
    {
        if((NdefMap->TopazContainer.InternalState == 
            PH_FRINFC_TOPAZ_WR_L_TLV) && 
            (((NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN) && 
            (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            NdefMap->ApduBuffIndex)) || 
            ((NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_CUR) && 
            (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            (NdefMap->ApduBuffIndex + NdefMap->TLVStruct.BytesRemainLinTLV)))) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            /* Update the L value in the context */
            NdefMap->TLVStruct.BytesRemainLinTLV = 
                ((NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN)?
                NdefMap->ApduBuffIndex:
            (NdefMap->TLVStruct.BytesRemainLinTLV + NdefMap->ApduBuffIndex));

            /* Write 0xE1 in block number = 1 and byte number = 0 */
            Result = phFriNfc_Tpz_H_WrByte0ValE1(NdefMap);
        }
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ProWrUsrData(phFriNfc_NdefMap_t *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    /* send buffer should be equal to receive buffer */
    if((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
        NdefMap->ApduBuffer[NdefMap->ApduBuffIndex]) && 
        (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
    {
        /* Increment the index */
        NdefMap->ApduBuffIndex += PH_FRINFC_TOPAZ_VAL1;

        /* Remaining space left in the card is less by one */
        NdefMap->TopazContainer.RemainingSize -= PH_FRINFC_TOPAZ_VAL1;

        /* Increment the byte number */
        NdefMap->TopazContainer.ByteNumber++;

        /* Check the block number */
        phFriNfc_Tpz_H_BlkChk(NdefMap);

        /* check for the user space or the card size */
        if((NdefMap->ApduBufferSize == NdefMap->ApduBuffIndex) || 
            (NdefMap->TopazContainer.RemainingSize == PH_FRINFC_TOPAZ_VAL0))
        {
            /* Set write complete, if the end of card is reached */
            NdefMap->TopazContainer.ReadWriteCompleteFlag = (uint8_t)
                ((NdefMap->TopazContainer.RemainingSize == PH_FRINFC_TOPAZ_VAL0)?
                PH_FRINFC_TOPAZ_FLAG1:PH_FRINFC_TOPAZ_FLAG0);

            Result = phFriNfc_Tpz_H_WrLByte(NdefMap);
        }
        else
        {
            /* State is continued to be in write */
            NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE;           
            
            /* Write the byte to the specified location , and Byte to write */
            Result = phFriNfc_Tpz_H_WrAByte(NdefMap, NdefMap->TopazContainer.CurrentBlock,
                                            NdefMap->TopazContainer.ByteNumber,
                                            NdefMap->ApduBuffer[NdefMap->ApduBuffIndex]
                                            );
        }
    }
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_WrLByte(phFriNfc_NdefMap_t  *NdefMap)
{
    NFCSTATUS   Result = NFCSTATUS_SUCCESS;
    uint8_t     BlockNo = PH_FRINFC_TOPAZ_VAL0,
        ByteNo = PH_FRINFC_TOPAZ_VAL0;
    uint8_t TempByteVal = 0;
    BlockNo = (uint8_t)(((NdefMap->TLVStruct.NdefTLVByte + 
                            PH_FRINFC_TOPAZ_VAL1) > 
                            PH_FRINFC_TOPAZ_VAL7)?
                            (NdefMap->TLVStruct.NdefTLVBlock + 
                            PH_FRINFC_TOPAZ_VAL1):
    NdefMap->TLVStruct.NdefTLVBlock);

    ByteNo = (uint8_t)((NdefMap->TLVStruct.NdefTLVByte + 
                        PH_FRINFC_TOPAZ_VAL1) % PH_FRINFC_TOPAZ_VAL8);
    /* Update L field */
    NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE_L_TLV;
    /* Internal state for write */
    NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_L_TLV;
    /* Update the length field depending on the offset */
    TempByteVal = (uint8_t)
                    ((NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN)?
                    NdefMap->ApduBuffIndex:
                    (NdefMap->ApduBuffIndex + 
                    NdefMap->TLVStruct.BytesRemainLinTLV));
    /* Write the L field */
    Result = phFriNfc_Tpz_H_WrAByte(NdefMap, BlockNo, ByteNo,TempByteVal);
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_WrByte0ValE1(phFriNfc_NdefMap_t   *NdefMap)
{
    NFCSTATUS   Result = NFCSTATUS_SUCCESS;

    /* Update L field */
    NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE_NMN;
    /* Internal state for writing 0xE1 */
    NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_NMN_E1;
    /* Update the length field depending on the offset */                          
    /* Write the L field */
    Result = phFriNfc_Tpz_H_WrAByte(NdefMap, PH_FRINFC_TOPAZ_VAL1, 
                                    PH_FRINFC_TOPAZ_VAL0,PH_FRINFC_TOPAZ_CC_BYTE0);
    return Result;
}

static void phFriNfc_Tpz_H_Complete(phFriNfc_NdefMap_t  *NdefMap,
                                    NFCSTATUS           Status)
{
    /* set the state back to the Reset_Init state*/
    NdefMap->State =  PH_FRINFC_NDEFMAP_STATE_RESET_INIT;

    /* set the completion routine*/
    NdefMap->CompletionRoutine[NdefMap->TopazContainer.CRIndex].
        CompletionRoutine(NdefMap->CompletionRoutine->Context, Status);
}

static void phFriNfc_Tpz_H_BlkChk(phFriNfc_NdefMap_t  *NdefMap)
{
    NdefMap->TopazContainer.CurrentBlock = 
                    (uint8_t)((NdefMap->TopazContainer.ByteNumber > 
                    PH_FRINFC_TOPAZ_VAL7)?
                    (NdefMap->TopazContainer.CurrentBlock + 
                    PH_FRINFC_TOPAZ_VAL1):
                    NdefMap->TopazContainer.CurrentBlock);

    NdefMap->TopazContainer.ByteNumber = (uint8_t)(NdefMap->TopazContainer.ByteNumber % 
                                        PH_FRINFC_TOPAZ_VAL8);
}

static NFCSTATUS phFriNfc_Tpz_H_ChkCCinChkNdef(phFriNfc_NdefMap_t  *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
                                    NFCSTATUS_NO_NDEF_SUPPORT);

    if(NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL0] == 
        PH_FRINFC_TOPAZ_CC_BYTE0)
    {
        /* Check the most significant nibble of byte 3 (RWA) = 0 */
        Result = (((NdefMap->TopazContainer.ReadBuffer[PH_FRINFC_TOPAZ_VAL3] & 
                    PH_FRINFC_TOPAZ_BYTE3_MSB)== PH_FRINFC_TOPAZ_VAL0)?
                    NFCSTATUS_SUCCESS:
                    Result);

        /* Card size is initialised */ 
        NdefMap->CardMemSize = NdefMap->TopazContainer.RemainingSize = 
                            ((Result == NFCSTATUS_SUCCESS)?
                            (PH_FRINFC_TOPAZ_MAX_CARD_SZ - PH_FRINFC_TOPAZ_VAL4):
                            NdefMap->CardMemSize);
    }

    if (NdefMap->CardState != PH_NDEFMAP_CARD_STATE_READ_ONLY)
    {
        NdefMap->CardState = (uint8_t)((Result == NFCSTATUS_SUCCESS)?
                            PH_NDEFMAP_CARD_STATE_INITIALIZED:
                            PH_NDEFMAP_CARD_STATE_INVALID);
    }

    return Result;
}

static void phFriNfc_Tpz_H_ChkLockBits(phFriNfc_NdefMap_t  *NdefMap)
{
    /* Set the card state */
    NdefMap->CardState =  (uint8_t)
        (((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_LOCKBIT_BYTENO_0] == 
        PH_FRINFC_TOPAZ_LOCKBIT_BYTE114) && 
        ((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_LOCKBIT_BYTENO_1] == 
        PH_FRINFC_TOPAZ_LOCKBIT_BYTE115_1) ||
        (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_LOCKBIT_BYTENO_1] == 
        PH_FRINFC_TOPAZ_LOCKBIT_BYTE115_2)))?
        PH_NDEFMAP_CARD_STATE_READ_WRITE:
        PH_NDEFMAP_CARD_STATE_READ_ONLY);

    /* Set the card state from CC bytes */
    if (NdefMap->CardState == PH_NDEFMAP_CARD_STATE_READ_WRITE)
    {
        if (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_CC_BYTENO_3] == PH_FRINFC_TOPAZ_CC_READWRITE)
        {
            NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_WRITE;
        }
        else if (NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_CC_BYTENO_3] == PH_FRINFC_TOPAZ_CC_READONLY)
        {
            NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_ONLY;
        }
        else 
        {
            NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID;
        }
    }
}

static NFCSTATUS phFriNfc_Tpz_H_WrCCorTLV(phFriNfc_NdefMap_t  *NdefMap)
{
    NFCSTATUS   Result = NFCSTATUS_SUCCESS;
    uint8_t     ByteNo = PH_FRINFC_TOPAZ_VAL0,
        BlockNo = PH_FRINFC_TOPAZ_VAL0;
    uint8_t TempByteVal = 0;
    switch(NdefMap->TopazContainer.InternalState)
    {
    case PH_FRINFC_TOPAZ_WR_CC_BYTE0:
        /* To write the CC bytes */
        TempByteVal = PH_FRINFC_TOPAZ_CC_BYTE0;
        ByteNo = (uint8_t)PH_FRINFC_TOPAZ_VAL0;
        BlockNo = PH_FRINFC_TOPAZ_VAL1;
        break;

    case PH_FRINFC_TOPAZ_WR_CC_BYTE1:
        /* To write the CC bytes */
        TempByteVal = PH_FRINFC_TOPAZ_CC_BYTE1;
        ByteNo = (uint8_t)PH_FRINFC_TOPAZ_VAL1;
        BlockNo = PH_FRINFC_TOPAZ_VAL1;
        break;

    case PH_FRINFC_TOPAZ_WR_CC_BYTE2:
        /* To write the CC bytes */
        TempByteVal = PH_FRINFC_TOPAZ_CC_BYTE2_MAX;
        ByteNo = (uint8_t)PH_FRINFC_TOPAZ_VAL2;
        BlockNo = PH_FRINFC_TOPAZ_VAL1;
        break;

    case PH_FRINFC_TOPAZ_WR_CC_BYTE3:
        /* To write the CC bytes */
        TempByteVal = PH_FRINFC_TOPAZ_CC_BYTE3_RW;
        ByteNo = (uint8_t)PH_FRINFC_TOPAZ_VAL3;
        BlockNo = PH_FRINFC_TOPAZ_VAL1;
        break;

    case PH_FRINFC_TOPAZ_WR_T_OF_TLV:
    default:
        /* To write the NDEF TLV (if not present) */
        TempByteVal = PH_FRINFC_TOPAZ_NDEF_T;
        ByteNo = (uint8_t)NdefMap->TLVStruct.NdefTLVByte;
        BlockNo = NdefMap->TLVStruct.NdefTLVBlock;
        break;
    }
    NdefMap->State = PH_FRINFC_TOPAZ_STATE_WR_CC_OR_TLV;
    Result = phFriNfc_Tpz_H_WrAByte( NdefMap, BlockNo, ByteNo,TempByteVal);
    return Result;
}

static NFCSTATUS phFriNfc_Tpz_H_ProCCTLV(phFriNfc_NdefMap_t  *NdefMap)
{
    NFCSTATUS   Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
        NFCSTATUS_INVALID_RECEIVE_LENGTH);
    switch(NdefMap->TopazContainer.InternalState)
    {
    case PH_FRINFC_TOPAZ_WR_CC_BYTE0:
        /* Process the CC byte */
        /* Check the response */
        if((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            PH_FRINFC_TOPAZ_CC_BYTE0) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_CC_BYTE1;
            Result = phFriNfc_Tpz_H_WrCCorTLV(NdefMap);
        }
        break;

    case PH_FRINFC_TOPAZ_WR_CC_BYTE1:
        /* Process the CC byte */
        /* Check the response */
        if((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            PH_FRINFC_TOPAZ_CC_BYTE1) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_CC_BYTE2;
            Result = phFriNfc_Tpz_H_WrCCorTLV(NdefMap);
        }
        break;

    case PH_FRINFC_TOPAZ_WR_CC_BYTE2:
        /* Process the CC byte */
        /* Check the response */
        if((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            PH_FRINFC_TOPAZ_CC_BYTE2_MAX) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_CC_BYTE3;
            Result = phFriNfc_Tpz_H_WrCCorTLV(NdefMap);
        }
        break;

    case PH_FRINFC_TOPAZ_WR_CC_BYTE3:
        /* Process the CC byte */
        /* Check the response */
        if((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            PH_FRINFC_TOPAZ_CC_BYTE3_RW) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_T_OF_TLV;
            Result = phFriNfc_Tpz_H_WrCCorTLV(NdefMap);
        }
        break;

    case PH_FRINFC_TOPAZ_WR_T_OF_TLV:
    default:
        /* Check the response */
        if((NdefMap->SendRecvBuf[PH_FRINFC_TOPAZ_VAL0] == 
            PH_FRINFC_TOPAZ_NDEF_T) && 
            (*NdefMap->SendRecvLength == PH_FRINFC_TOPAZ_VAL1))
        {
            /* Increment the Byte Number */
            NdefMap->TopazContainer.ByteNumber++;
            /* Check the block and byte number */
            phFriNfc_Tpz_H_BlkChk(NdefMap);
            /* Process the T of NDEF TLV */
            NdefMap->State = PH_FRINFC_TOPAZ_STATE_WRITE_NMN;            
            
            /* Here the NMN is written 0, so internal state is used */
            NdefMap->TopazContainer.InternalState = PH_FRINFC_TOPAZ_WR_NMN_0;

            /*Inside this call Write NMN (block number 1 and byte number 0) = 0 */
            Result = phFriNfc_Tpz_H_WrAByte( NdefMap, PH_FRINFC_TOPAZ_VAL1,
                PH_FRINFC_TOPAZ_VAL0,PH_FRINFC_TOPAZ_VAL0);
        }
        break;
    }
    return Result;
}

#ifdef UNIT_TEST
#include <phUnitTestNfc_Topaz_static.c>
#endif

#endif  /* PH_FRINFC_MAP_TOPAZ_DISABLED */
