/*
 * 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  phLlcNfc_Frame.c
* \brief To append the I or S or U frames (LLC header).
*
* Project: NFC-FRI-1.1
*
* $Date: Tue Jun  1 14:41:26 2010 $
* $Author: ing02260 $
* $Revision: 1.88 $
* $Aliases: NFC_FRI1.1_WK1023_R35_1 $
*
*/

/*************************** Includes *******************************/
#include <phNfcTypes.h>
#include <phNfcStatus.h>
#include <phOsalNfc.h>
#include <phOsalNfc_Timer.h>
#include <phNfcInterface.h>
#include <phLlcNfc_DataTypes.h>
#include <phLlcNfc_Frame.h>
#include <phLlcNfc_Interface.h>
#include <phLlcNfc_Timer.h>
#ifdef ANDROID
#include <string.h>
#endif

/*********************** End of includes ****************************/

/***************************** Macros *******************************/

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

/***************************** Global variables *******************************/

#ifdef LLC_RELEASE_FLAG
    extern uint8_t             g_release_flag;
#endif /* #ifdef LLC_RELEASE_FLAG */
/************************ End of global variables *****************************/

/*********************** Local functions ****************************/
static 
void 
phLlcNfc_H_UpdateCrc(
    uint8_t     crcByte, 
    uint16_t    *pCrc
);

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions <b>process the received U frame</b> function
*
* \copydoc page_reg This function is to process the U frame received from 
*       the device
*
* \param[in] psLlcCtxt          Llc main structure information
* \param[in] llcPacket          LLC packet information, inlcuding length information
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
static 
NFCSTATUS 
phLlcNfc_H_ProcessUFrame (  
    phLlcNfc_Context_t      *psLlcCtxt 
);

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions <b>process the received S frame</b> function
*
* \copydoc page_reg This function is to process the S frame received from 
*       the device
*
* \param[in] psLlcCtxt          Llc main structure information
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
static 
void 
phLlcNfc_H_ProcessSFrame (  
    phLlcNfc_Context_t      *psLlcCtxt
);

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions <b>Update I frame list</b> function
*
* \copydoc page_reg This function checks the nr value with the stored I frames 
*   and deletes the nodes which has been acknowledged.
*
* \param[in/out] psFrameInfo    Frame structure information
* \param[in/out] psListInfo     List information
*
* \retval number of deleted frames
*
*/
static 
uint8_t 
phLlcNfc_H_UpdateIFrameList(
    phLlcNfc_Frame_t        *psFrameInfo, 
    phLlcNfc_StoreIFrame_t  *psListInfo
);

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions \b Delete list function
*
* \copydoc page_reg Delete the front node from the list
*
* \param[in] psFrameInfo    Frame structure information
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
static 
void 
phLlcNfc_H_DeleteIFrame (
                             phLlcNfc_StoreIFrame_t      *psList
                             );

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions <b>Get the LLC header</b> function
*
* \copydoc page_reg This function checks for the correctness fo the llc header
*
* \param[in] llcHeader      The byte which gives the header information
*
* \retval phLlcNfc_eU_frame      U frame type.
* \retval phLlcNfc_eI_frame      I frame type.
* \retval phLlcNfc_eS_frame      S frame type.
* \retval phLlcNfc_eErr_frame    Error type
*
*/
static
phLlcNfc_FrameType_t 
phLlcNfc_H_ChkGetLlcFrameType (
                               uint8_t     llcHeader
                               );

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions \b Peek the data function
*
* \copydoc page_reg Get the packet information from the front node from the list
*
* \param[in] psListInfo The List information
* \param[in] packetinfo The packet information from the front node of the list 
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
static
NFCSTATUS  
phLlcNfc_H_IFrameList_Peek (
                           phLlcNfc_StoreIFrame_t      *psList, 
                           phLlcNfc_LlcPacket_t        **psPacketinfo, 
                           uint8_t                     position
                           );

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions <b>Update U frame information</b> function
*
* \copydoc page_reg This function updates the U frame information in the 
*       phLlcNfc_sFrame_t structure
*
* \param[in/out] psFrameInfo        Frame information structure
* \param[in]     llcPayload         Llc payload information
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
static
NFCSTATUS 
phLlcNfc_H_Update_ReceivedRSETInfo (    
                            phLlcNfc_Frame_t    *psFrameInfo, 
                            phLlcNfc_Payload_t  llcInfo
                            );

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC Reset frame information function
*
* \copydoc page_reg resets ns and nr value, when ack for U frame is received
*
* \param[in, out] psLlcCtxt     Llc main structure information
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
static 
void 
phLlcNfc_H_ResetFrameInfo (
                      phLlcNfc_Context_t  *psLlcCtxt
                      );

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC Reset frame sending function
*
* \copydoc page_reg Send URSET frame to PN544
*
* \param[in, out] psLlcCtxt     Llc main structure information
*
* \retval NFCSTATUS_SUCCESS                 Operation successful.
* \retval NFCSTATUS_BUSY                    Write is pended, so wait till it completes.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
NFCSTATUS  
phLlcNfc_H_SendRSETFrame (
                      phLlcNfc_Context_t  *psLlcCtxt
                      );

/**
* \ingroup grp_hal_nfc_llc_helper
*
* \brief LLC helper functions <b>process the received I frame</b> function
*
* \copydoc page_reg This function is to process the I frame received from 
*       the device
*
* \param[in] psLlcCtxt          Llc main structure information
*
* \retval NFCSTATUS_SUCCESS                Operation successful.
* \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
*
*/
void 
phLlcNfc_H_ProcessIFrame (  
    phLlcNfc_Context_t      *psLlcCtxt 
);

/******************** End of Local functions ************************/

/********************** Global variables ****************************/

/******************** End of Global Variables ***********************/

void phLlcNfc_H_Frame_Init (
    phLlcNfc_Context_t  *psLlcCtxt
)
{
    
    if (NULL != psLlcCtxt)
    {
        /* Set all the other values to 0 */
        (void)memset (&psLlcCtxt->s_frameinfo.s_llcpacket, 0, 
                    sizeof(phLlcNfc_LlcPacket_t));

        psLlcCtxt->s_frameinfo.window_size = 
            PH_LLCNFC_U_FRAME_MAX_WIN_SIZE;
        /* Initialise the window size, N(S) and N(R) */
#ifdef PIGGY_BACK
        psLlcCtxt->s_frameinfo.s_recv_store.winsize_cnt = 0;
#endif
        psLlcCtxt->s_frameinfo.s_send_store.winsize_cnt = 0;
        psLlcCtxt->s_frameinfo.n_s = 0;
        psLlcCtxt->s_frameinfo.n_r = 0;
        psLlcCtxt->s_frameinfo.rejected_ns = DEFAULT_PACKET_INPUT;
    }
}

void 
phLlcNfc_H_Frame_DeInit (
    phLlcNfc_Frame_t    *psFrameInfo
)
{
    if (NULL != psFrameInfo)
    {
        /* Empty the frame information */
        (void)memset(&psFrameInfo->s_llcpacket, 0,
            sizeof(phLlcNfc_LlcPacket_t));
    }
}

NFCSTATUS
phLlcNfc_H_CreateUFramePayload (
    phLlcNfc_Context_t      *psLlcCtxt, 
    phLlcNfc_LlcPacket_t    *psLlcPacket, 
    uint8_t                 *pLlcPacketLength, 
    phLlcNfc_LlcCmd_t       cmdType
)
{
    /* 
        U frame packet (RSET)
        Byte 0 = Length (4 to 6 bytes) 
        Byte 1 = Header
        Byte 2 = window size (2 >= window size <= 4)
        Byte 3 = capabilities (SREJ option enable/disable) (optional)
        Byte 4 = Baud rate (optional)
        Byte 5 = CRC1
        Byte 6 = CRC2
    */
    NFCSTATUS           result = PHNFCSTVAL(CID_NFC_LLC, 
                                            NFCSTATUS_INVALID_PARAMETER);
    phLlcNfc_Buffer_t   *ps_llc_buf = NULL;
    uint8_t             index = 0;

    if ((NULL != psLlcCtxt) && (NULL != psLlcPacket) 
        && (NULL != pLlcPacketLength) && 
        ((phLlcNfc_e_rset == cmdType) || (phLlcNfc_e_ua == cmdType)))
    {
        result = NFCSTATUS_SUCCESS;
        ps_llc_buf = &(psLlcPacket->s_llcbuf);
        /* Get the header information */
        ps_llc_buf->sllcpayload.llcheader = 
                            (uint8_t)PH_LLCNFC_U_HEADER_INIT;
        if (phLlcNfc_e_rset == cmdType)
        {
            /* RSET command */
            ps_llc_buf->sllcpayload.llcheader = 
                        (uint8_t)SET_BITS8(
                            ps_llc_buf->sllcpayload.llcheader, 
                            PH_LLCNFC_U_FRAME_START_POS, 
                            PH_LLCNFC_U_FRAME_NO_OF_POS, 
                            (uint8_t)phLlcNfc_e_rset);
            /* Default window size */
            ps_llc_buf->sllcpayload.llcpayload[index] = 
                                PH_LLCNFC_U_FRAME_MAX_WIN_SIZE;
            index++;
            /* Endpoint capabilities, SREJ not supported */
            ps_llc_buf->sllcpayload.llcpayload[index] = 
                                PH_LLCNFC_SREJ_BYTE_VALUE;
            index++;
#ifdef ENABLE_BAUDRATE
            /* baud rate 0x00 = 9600, 0x05 = 115200 */
            ps_llc_buf->sllcpayload.llcpayload[index] = 
                            (uint8_t)phLlcNfc_e_115200;
            index++;
#endif /* #ifdef ENABLE_BAUDRATE */
            
        }
        else
        {
            /* UA frame */
            ps_llc_buf->sllcpayload.llcheader = (uint8_t)
                SET_BITS8(ps_llc_buf->sllcpayload.llcheader, 
                            PH_LLCNFC_U_FRAME_START_POS,
                            PH_LLCNFC_U_FRAME_NO_OF_POS, 
                            (uint8_t)phLlcNfc_e_ua);          
        }
        /* LLC length byte updated (index + 2 CRC bytes + 
        1 byte of header) */
        ps_llc_buf->llc_length_byte = (index + 
                            PH_LLCNFC_NUM_OF_CRC_BYTES + 1);
        /* Total LLC buffer size */
        *pLlcPacketLength = psLlcPacket->llcbuf_len = 
                        (ps_llc_buf->llc_length_byte + 1);
        /* 
        psLlcPacket->s_llcbuf : 
                consists llc length byte + llc header + data + CRC 
                (which needs to be calculated by the below function)
        psLlcPacket->llcbuf_len : 
                Total length of the above buffer
        psLlcPacket->llcbuf_len - 2 : 
                -2 because the CRC has to be calculated, only for the 
                bytes which has llc length byte + llc header + data. 
                But total length (llcbuf_len) consists of above mentioned 
                things with 2 byte CRC 
        psLlcPacket->s_llcbuf.sllcpayload.llcpayload : 
                consists only data (no length byte and no llc header)
        (psLlcPacket->llcbuf_len - 4) : 
                is the array index of the first CRC byte to be calculated
        (psLlcPacket->llcbuf_len - 3) : 
                is the array index of the second CRC byte to be calculated
        */
        index = psLlcPacket->llcbuf_len;

        phLlcNfc_H_ComputeCrc((uint8_t *)ps_llc_buf, 
                (psLlcPacket->llcbuf_len - 2),
                &(ps_llc_buf->sllcpayload.llcpayload[(index - 4)]),
                &(ps_llc_buf->sllcpayload.llcpayload[(index - 3)]));
    }

    return result;
}

NFCSTATUS
phLlcNfc_H_CreateSFramePayload (
    phLlcNfc_Frame_t    *psFrameInfo, 
    phLlcNfc_LlcPacket_t    *psLlcPacket,
    phLlcNfc_LlcCmd_t   cmdType
)
{
    /* 
        S frame packet (RR or RNR or REJ or SREJ). Total bytes = 4
        Byte 0 = Length (Length = 3 always for S frame) 
        Byte 1 = Header
        Byte 2 = CRC1
        Byte 3 = CRC2
    */
    NFCSTATUS               result = NFCSTATUS_SUCCESS;
    phLlcNfc_Buffer_t       *ps_llc_buf = NULL;
    uint8_t                 length = 0;
    
    ps_llc_buf = &(psLlcPacket->s_llcbuf);

    /* Initial S frame header */
    ps_llc_buf->sllcpayload.llcheader = PH_LLCNFC_S_HEADER_INIT;
    /* Update the N(R) value */
    ps_llc_buf->sllcpayload.llcheader = (uint8_t)SET_BITS8(
                                ps_llc_buf->sllcpayload.llcheader, 
                                PH_LLCNFC_NR_START_BIT_POS, 
                                PH_LLCNFC_NR_NS_NO_OF_BITS, 
                                psFrameInfo->n_r);

    /* Update the type bits of S frame */
    ps_llc_buf->sllcpayload.llcheader = (uint8_t)
                (ps_llc_buf->sllcpayload.llcheader | (uint8_t)cmdType);

    /* Maximum S frame length */
    psLlcPacket->llcbuf_len = (uint8_t)PH_LLCNFC_MAX_S_FRAME_LEN;
    /* S frame length byte value */
    ps_llc_buf->llc_length_byte = (uint8_t)
                            (psLlcPacket->llcbuf_len - 1);

    /* 
        psFrameInfo->s_llcpacket.s_llcbuf : 
                consists llc length byte + llc header + data + CRC 
                (which needs to be calculated by the below function)
        psFrameInfo->s_llcpacket.llcbuf_len : 
                Total length of the above buffer
        psFrameInfo->s_llcpacket.llcbuf_len - 2 : 
                -2 because the CRC has to be calculated, only for the 
                bytes which has llc length byte + llc header + data. 
                But total length (llcbuf_len) consists of above mentioned 
                things with 2 byte CRC 
        psFrameInfo->s_llcpacket.s_llcbuf.sllcpayload.llcpayload : 
                consists only data (no length byte and no llc header)
        psFrameInfo->s_llcpacket.s_llcbuf.sllcpayload.llcpayload : 
                contains only data sent by user. 
        (psFrameInfo->s_llcpacket.llcbuf_len - 4) : 
                is the array index of the first CRC byte to be calculated
        (psFrameInfo->s_llcpacket.llcbuf_len - 3) : 
                is the array index of the second CRC byte to be calculated
    */
    length = psLlcPacket->llcbuf_len;
    phLlcNfc_H_ComputeCrc(
        (uint8_t *)ps_llc_buf, (length - 2),
        &(ps_llc_buf->sllcpayload.llcpayload[(length - 4)]),
        &(ps_llc_buf->sllcpayload.llcpayload[(length - 3)]));

    return result;
}

NFCSTATUS
phLlcNfc_H_CreateIFramePayload (
    phLlcNfc_Frame_t        *psFrameInfo, 
    phLlcNfc_LlcPacket_t    *psLlcPacket, 
    uint8_t                 *pLlcBuf, 
    uint8_t                 llcBufLength
)
{
    NFCSTATUS           result = PHNFCSTVAL(CID_NFC_LLC, 
                                            NFCSTATUS_INVALID_PARAMETER);
    phLlcNfc_Buffer_t   *ps_llc_buf = NULL;

    if ((NULL != psFrameInfo) && (NULL != psLlcPacket) && 
        (NULL != pLlcBuf) && (llcBufLength > 0))
    {
        result = NFCSTATUS_SUCCESS;
        ps_llc_buf = &(psLlcPacket->s_llcbuf);

        (void)memcpy(&(ps_llc_buf->sllcpayload.llcpayload[0]),
                        pLlcBuf, llcBufLength);

        psLlcPacket->llcbuf_len = (uint8_t)llcBufLength; 
        
        /* I frame header byte */
        ps_llc_buf->sllcpayload.llcheader = PH_LLCNFC_I_HEADER_INIT;

        /* Set the N(S) value */
        ps_llc_buf->sllcpayload.llcheader = (uint8_t)
            SET_BITS8(
                    ps_llc_buf->sllcpayload.llcheader, 
                    PH_LLCNFC_NS_START_BIT_POS, 
                    PH_LLCNFC_NR_NS_NO_OF_BITS, 
                    psFrameInfo->n_s);

        /* Set the N(R) value */
        ps_llc_buf->sllcpayload.llcheader = (uint8_t)
            SET_BITS8(
                    ps_llc_buf->sllcpayload.llcheader, 
                    PH_LLCNFC_NR_START_BIT_POS, 
                    PH_LLCNFC_NR_NS_NO_OF_BITS, 
                    psFrameInfo->n_r);
            
        /* Update the length byte, llc length byte value includes 
            data + CRC bytes + llc length byte */
        ps_llc_buf->llc_length_byte = 
                (psLlcPacket->llcbuf_len + 
                PH_LLCNFC_NUM_OF_CRC_BYTES + 1);

        /* Update total length, Total length is always equal to 
            llc length byte + 1 */
        psLlcPacket->llcbuf_len = 
                (ps_llc_buf->llc_length_byte + 1);
        
        /* 
            psFrameInfo->s_llcpacket.s_llcbuf : 
                    consists llc length byte + llc header + data + CRC (which 
                    needs to be calculated by the below function)
            psFrameInfo->s_llcpacket.llcbuf_len : 
                    Total length of the above buffer
            psFrameInfo->s_llcpacket.llcbuf_len - 2 : 
                    -2 because the CRC has to be calculated, only for the 
                    bytes which has llc length byte + llc header + data. 
                    But total length (llcbuf_len) consists of above mentioned 
                    things with 2 byte CRC 
            psFrameInfo->s_llcpacket.s_llcbuf.sllcpayload.llcpayload : 
                    contains only data sent by user. 
            (psFrameInfo->s_llcpacket.llcbuf_len - 4) : 
                    is the array index of the first CRC byte to be calculated
            (psFrameInfo->s_llcpacket.llcbuf_len - 3) : 
                    is the array index of the second CRC byte to be calculated

        */
        phLlcNfc_H_ComputeCrc(
            (uint8_t*)ps_llc_buf, 
            (psLlcPacket->llcbuf_len - 2),
            &(ps_llc_buf->sllcpayload.llcpayload
                        [(psLlcPacket->llcbuf_len - 4)]), 
            &(ps_llc_buf->sllcpayload.llcpayload
                        [(psLlcPacket->llcbuf_len - 3)]));


    }

    return result;
}

static
phLlcNfc_FrameType_t 
phLlcNfc_H_ChkGetLlcFrameType (
    uint8_t llcHeader
)
{
    phLlcNfc_FrameType_t    frame_type = phLlcNfc_eErr_frame;

    /* Mask the header byte to know the actual frame types */
    switch((llcHeader & PH_LLCNFC_LLC_HEADER_MASK))
    {
        case PH_LLCNFC_U_HEADER_INIT:
        {
            frame_type = phLlcNfc_eU_frame;
            break;
        }

        case PH_LLCNFC_S_HEADER_INIT:
        {
            frame_type = phLlcNfc_eS_frame;
            break;
        }

        default:
        {
            if (PH_LLCNFC_I_HEADER_INIT == 
                (PH_LLCNFC_I_FRM_HEADER_MASK & llcHeader))
            {
                frame_type = phLlcNfc_eI_frame;
            }
            else
            {
                frame_type = phLlcNfc_eErr_frame;
            }
            break;
        }
    }
    return frame_type;
}

static
NFCSTATUS 
phLlcNfc_H_Update_ReceivedRSETInfo (    
    phLlcNfc_Frame_t    *psFrameInfo, 
    phLlcNfc_Payload_t  llcInfo
)
{
    NFCSTATUS   result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT);
    uint8_t     payload_index = 0;

    if ((llcInfo.llcpayload[payload_index] >= PH_LLCNFC_U_FRAME_MIN_WIN_SIZE) && 
        (llcInfo.llcpayload[payload_index] <= PH_LLCNFC_U_FRAME_MAX_WIN_SIZE))
    {
        result = NFCSTATUS_SUCCESS;
        /* From the received buffer, get the window size from the 
            3rd byte (recvUBufLen[3]) of the buffer */
        psFrameInfo->window_size = llcInfo.llcpayload[payload_index];
        payload_index = (uint8_t)(payload_index + 1);

        /* If 4th byte of the receive buffer (pRecvUBuf[4]) is 
            0x01 then SREJ can come from the device*/
        psFrameInfo->srej_on_off = ((PH_LLCNFC_SREJ_BYTE_VALUE == 
                        llcInfo.llcpayload[payload_index])?
                        PH_LLCNFC_SREJ_BYTE_VALUE:0);

        /* For present implementation, this should be always false 
        later stage remove if statement to work */
        if (PH_LLCNFC_SREJ_BYTE_VALUE != psFrameInfo->srej_on_off)
        {
            result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT);
        }
        else
        {
            payload_index = (uint8_t)(payload_index + 1);

            
            if (llcInfo.llcpayload[payload_index] > 
                (uint8_t)phLlcNfc_e_1228000)
            {
                /* Error byte */
                result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT);
            }
            else
            {
                /* Get the baud rate from the 5th byte of the receive buffer */
                psFrameInfo->baud_rate = (phLlcNfc_LlcBaudRate_t)
                                        (llcInfo.llcpayload[payload_index]);
            }
        }
    }

    return result;
}

static 
uint8_t 
phLlcNfc_H_UpdateIFrameList(
    phLlcNfc_Frame_t        *psFrameInfo, 
    phLlcNfc_StoreIFrame_t  *psListInfo
)
{
    NFCSTATUS               result = NFCSTATUS_SUCCESS;
    phLlcNfc_LlcPacket_t    *pspktInfo = NULL;
    uint8_t                 while_exit = FALSE;
    uint8_t                 nr = 0;
    uint8_t                 ns = 0;
    uint8_t                 no_of_del_frames = 0;

    PHNFC_UNUSED_VARIABLE(result);
    if(0 == psListInfo->winsize_cnt)
    {
        while_exit = TRUE;
    }
    while (FALSE == while_exit)
    {
        /* Get the first node from the list */
        result = phLlcNfc_H_IFrameList_Peek (psListInfo, &pspktInfo, 
                                            DEFAULT_PACKET_INPUT);
        if (NULL != pspktInfo)
        {
            /* Get the N(R) value of the received packet and N(S) value of the 
                sent stored i frame */
            ns = (uint8_t)GET_BITS8 ( 
                    pspktInfo->s_llcbuf.sllcpayload.llcheader, 
                    PH_LLCNFC_NS_START_BIT_POS, 
                    PH_LLCNFC_NR_NS_NO_OF_BITS);

            nr = (uint8_t)GET_BITS8( 
                    psFrameInfo->s_recvpacket.s_llcbuf.sllcpayload.llcheader, 
                    PH_LLCNFC_NR_START_BIT_POS, 
                    PH_LLCNFC_NR_NS_NO_OF_BITS);            
            
            /* Check the value of each i frame N(S) and 
                received ACKs N(R) */
#if 0
            if(((ns <= nr) && ((nr - ns) <= psFrameInfo->window_size)) 
                || ((ns > nr) && (((PH_LLCNFC_MOD_NS_NR + nr) - ns) <= 
                PH_LLCNFC_U_FRAME_MAX_WIN_SIZE)))
#endif
            if(((ns < nr) && ((nr - ns) <= psFrameInfo->window_size)) 
                || ((ns > nr) && (((PH_LLCNFC_MOD_NS_NR + nr) - ns) <= 
                PH_LLCNFC_U_FRAME_MAX_WIN_SIZE)))
            {
                phLlcNfc_H_DeleteIFrame (psListInfo);
                no_of_del_frames = (uint8_t)(no_of_del_frames + 1);
            }
            else
            {
                while_exit = TRUE;
            }

            if(0 == psListInfo->winsize_cnt)
            {
                while_exit = TRUE;
            }
        }
        else
        {
            while_exit = TRUE;
        }
    }
    return no_of_del_frames;
}

NFCSTATUS 
phLlcNfc_H_SendUserIFrame (
    phLlcNfc_Context_t      *psLlcCtxt, 
    phLlcNfc_StoreIFrame_t  *psListInfo
)
{
    NFCSTATUS               result = NFCSTATUS_SUCCESS;    
    phLlcNfc_Frame_t        *ps_frame_info = NULL;
    phLlcNfc_LlcPacket_t    s_create_packet;
    phLlcNfc_LlcPacket_t    *ps_get_packet = NULL;
    phLlcNfc_Payload_t      *ps_llc_payload = NULL;
    phLlcNfc_StoreIFrame_t  *ps_store_frame = NULL;
    uint8_t                 llc_header = 0, 
                            length = 0;

    if ((NULL == psLlcCtxt) || (NULL == psListInfo))
    {
        result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER);
    }
    else if (0 == psListInfo->winsize_cnt)
    {
        result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED);
    }
    else
    {
        ps_frame_info = &(psLlcCtxt->s_frameinfo);
        ps_store_frame = &(ps_frame_info->s_send_store);

        if (
            (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + 
            ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR))
            )
        {
            /* Get the stored I frame, only if the new frame is sent 
                from the upper layer */
            result = phLlcNfc_H_IFrameList_Peek (psListInfo, &ps_get_packet,
                                                ps_frame_info->n_s);
        }

        if (NULL != ps_get_packet)
        {
            llc_header = ps_get_packet->s_llcbuf.sllcpayload.llcheader;

            /* Update n(r) value for the header */
            llc_header = (uint8_t)(llc_header | ps_frame_info->n_r);

            /* Create the packet */
            (void)memcpy ((void *)&(s_create_packet), (void *)ps_get_packet,
                        sizeof (phLlcNfc_LlcPacket_t));

            s_create_packet.s_llcbuf.sllcpayload.llcheader = llc_header;
            ps_llc_payload = &(s_create_packet.s_llcbuf.sllcpayload);

            /* Length of the complete llc buffer, sent to PN544 */
            length = s_create_packet.llcbuf_len;

            /* Compute CRC for the created packet */
            phLlcNfc_H_ComputeCrc ((uint8_t *)&(s_create_packet.s_llcbuf),
                        (length - 2),
                        (uint8_t *)&(ps_llc_payload->llcpayload[(length - 4)]), 
                        (uint8_t *)&(ps_llc_payload->llcpayload[(length - 3)]));

            /* Send the i frame */
            result = phLlcNfc_Interface_Write (psLlcCtxt,
                            (uint8_t *)&(s_create_packet.s_llcbuf),
                            (uint32_t)s_create_packet.llcbuf_len);

            ps_frame_info->write_status = result;

            if (NFCSTATUS_BUSY == PHNFCSTATUS (result))
            {
                /* The below check is added because, write is already pended by some other 
                    operation, so it has to complete, when it completes, then immediately 
                    next write shall be called using the below updated variable 

                    The below variable is checked for the resend or rejected i frame 
                    because if due to timer or reject frame from PN544, an I frame 
                    has been sent (means write has been pended then the variable shall 
                    not be overwritten.
                */
                ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t)
                            (((resend_i_frame == ps_frame_info->write_wait_call) || 
                            (rejected_i_frame == ps_frame_info->write_wait_call)) ? 
                            ps_frame_info->write_wait_call : user_i_frame);
            }
            else
            {
                if (NFCSTATUS_PENDING == result)
                {
                    /* Start the timer */
                    (void)phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER, 
                                                ps_frame_info->n_s);
                    
                    /* "sent_frame_type is updated" only if the data is 
                        written to the lower layer */
                    ps_frame_info->sent_frame_type = user_i_frame;
                }
            }
        }
    }
    return result;
}

NFCSTATUS 
phLlcNfc_H_SendRejectedIFrame (
    phLlcNfc_Context_t      *psLlcCtxt, 
    phLlcNfc_StoreIFrame_t  *psListInfo, 
    uint8_t                 ns_rejected
)
{
    NFCSTATUS               result = NFCSTATUS_SUCCESS;    
    phLlcNfc_Frame_t        *ps_frame_info = NULL;
    phLlcNfc_LlcPacket_t    s_create_packet;
    phLlcNfc_LlcPacket_t    *ps_get_packet = NULL;
    phLlcNfc_Payload_t      *ps_llc_payload = NULL;
    phLlcNfc_StoreIFrame_t  *ps_store_frame = NULL;
    uint8_t                 llc_header = 0;
    uint8_t                 length = 0;

    if ((NULL == psLlcCtxt) || (NULL == psListInfo))
    {
        result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER);
    }
    else if (0 == psListInfo->winsize_cnt)
    {
        result = PHNFCSTVAL (CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED);
    }
    else
    {
        ps_frame_info = &(psLlcCtxt->s_frameinfo);
        ps_store_frame = &(ps_frame_info->s_send_store);


        if (ns_rejected < (uint8_t)(ps_store_frame->winsize_cnt + 
            ps_store_frame->start_pos))
        {
            /* To send rejected frame, first thing shall be done is 
                windows size count shall be checked. if the 
                start position 
                */
            if (invalid_frame != 
                ps_store_frame->s_llcpacket[ns_rejected].frame_to_send)
            {
                /* Above check is added to know only if   */
                result = phLlcNfc_H_IFrameList_Peek (psListInfo, &ps_get_packet,
                                                    ns_rejected);
            }
            else
            {
                ps_frame_info->rejected_ns = DEFAULT_PACKET_INPUT;
                /* Get the stored I frame, only if the new frame is sent 
                    from the upper layer */
                result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, psListInfo);
            }
        }

        if (NULL != ps_get_packet)
        {
            llc_header = ps_get_packet->s_llcbuf.sllcpayload.llcheader;

            /* Update n(r) value for the header */
            llc_header = (uint8_t)(llc_header | ps_frame_info->n_r);

            /* Create the packet */
            (void)memcpy ((void *)&(s_create_packet), (void *)ps_get_packet,
                        sizeof (phLlcNfc_LlcPacket_t));

            s_create_packet.s_llcbuf.sllcpayload.llcheader = llc_header;
            ps_llc_payload = &(s_create_packet.s_llcbuf.sllcpayload);

            /* Length of the complete llc buffer, sent to PN544 */
            length = s_create_packet.llcbuf_len;

            /* Compute CRC for the created packet */
            phLlcNfc_H_ComputeCrc ((uint8_t *)&(s_create_packet.s_llcbuf),
                        (length - 2),
                        (uint8_t *)&(ps_llc_payload->llcpayload[(length - 4)]), 
                        (uint8_t *)&(ps_llc_payload->llcpayload[(length - 3)]));

            /* Send the i frame */
            result = phLlcNfc_Interface_Write (psLlcCtxt, 
                            (uint8_t *)&(s_create_packet.s_llcbuf),
                            (uint32_t)s_create_packet.llcbuf_len);

            ps_frame_info->write_status = result;

            if (NFCSTATUS_BUSY == PHNFCSTATUS (result))
            {
                /* Already a frame is sent and response is waited for the sent frame, 
                    so update the below variable */
                ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t)
                                (((ns_rejected != ps_store_frame->start_pos) && 
                                (resend_i_frame != ps_frame_info->write_wait_call))?
                                rejected_i_frame : ps_frame_info->write_wait_call);
            }
            else
            {
                /* NFCSTATUS_PENDING means that the no other write is pending, apart  
                    from the present write 

                Start the timer */
                (void)phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER, ns_rejected);
                
                /* "sent_frame_type is updated" only if the data is 
                    written to the lower layer. This will be used in the write 
                    response callback and also indicates, what is the frame sent 
                    and why
                 */
                ps_frame_info->sent_frame_type = rejected_i_frame;

                if ((ns_rejected + 1) < ps_frame_info->n_s)
                {
                    ps_frame_info->rejected_ns = (uint8_t)(ns_rejected + 1);

                    ps_frame_info->write_status = PHNFCSTVAL(CID_NFC_LLC, 
                                                    NFCSTATUS_BUSY);

                    if (invalid_frame == 
                        ps_store_frame->s_llcpacket[ns_rejected].frame_to_send)
                    {
                        ps_frame_info->rejected_ns = DEFAULT_PACKET_INPUT;
                        ps_frame_info->write_wait_call = user_i_frame; 
                    }
                    else
                    {                        
                        ps_frame_info->write_wait_call = rejected_i_frame;
                    }
                }
                else
                {
                    ps_frame_info->rejected_ns = DEFAULT_PACKET_INPUT;
                    /* This check is added to see that new frame has arrived 
                        from the upper layer */
                    if (ps_frame_info->n_s < (ps_store_frame->start_pos + 
                        ps_store_frame->winsize_cnt))
                    {
                        ps_frame_info->write_wait_call = user_i_frame;
                    }
                }
            }
        }
    }
    return result;
}

NFCSTATUS 
phLlcNfc_H_SendTimedOutIFrame (
    phLlcNfc_Context_t      *psLlcCtxt, 
    phLlcNfc_StoreIFrame_t  *psListInfo, 
    uint8_t                 frame_to_send
)
{
    NFCSTATUS               result = NFCSTATUS_SUCCESS;    
    phLlcNfc_Frame_t        *ps_frame_info = NULL;
    phLlcNfc_Timerinfo_t    *ps_timer_info = NULL;
    phLlcNfc_LlcPacket_t    s_create_packet;
    phLlcNfc_LlcPacket_t    *ps_get_packet = NULL;
    phLlcNfc_Payload_t      *ps_llc_payload = NULL;
    phLlcNfc_StoreIFrame_t  *ps_store_frame = NULL;
        
    PHNFC_UNUSED_VARIABLE(frame_to_send);
    if((NULL == psLlcCtxt) || (NULL == psListInfo))
    {
        result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER);
    }
    else if (psListInfo->winsize_cnt == 0)
    {
        result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_NOT_ALLOWED);
    }
    else
    {
        uint8_t                 llc_header = 0;
        uint8_t                 length = 0;
        uint8_t                 timer_count = 0;
        uint8_t                 timer_index = 0;
        uint8_t                 ns_index = 0;

        ps_frame_info = &(psLlcCtxt->s_frameinfo);
        ps_timer_info = &(psLlcCtxt->s_timerinfo);
        ps_store_frame = &(ps_frame_info->s_send_store);        
        
        timer_index = ps_timer_info->index_to_send;
        timer_count = ps_timer_info->guard_to_count;
        ns_index = ps_timer_info->timer_ns_value[timer_index];

        PH_LLCNFC_DEBUG("SEND TIMEOUT CALL WIN SIZE CNT : 0x%02X\n", ps_store_frame->winsize_cnt);
        PH_LLCNFC_DEBUG("SEND TIMEOUT CALL START POS : 0x%02X\n", ps_store_frame->start_pos);
        PH_LLCNFC_DEBUG("SEND TIMEOUT CALL N S value : 0x%02X\n", ps_frame_info->n_s);
        PH_LLCNFC_DEBUG("SEND TIMEOUT TIMER INDEX : 0x%02X\n", timer_index);
        PH_LLCNFC_DEBUG("SEND TIMEOUT CALL frame type : 0x%02X\n", ps_timer_info->frame_type[timer_index]);

        if (resend_i_frame == ps_timer_info->frame_type[timer_index])
        {
            /* Get the stored I frame */
            result = phLlcNfc_H_IFrameList_Peek (psListInfo, &ps_get_packet,
                                                ns_index);
        }        

        PH_LLCNFC_DEBUG("SEND TIMEOUT CALL Packet : 0x%p\n", ps_get_packet);
        if (NULL != ps_get_packet)
        {
            llc_header = ps_get_packet->s_llcbuf.sllcpayload.llcheader;

            /* Update n(r) value for the header */
            llc_header = (uint8_t)(llc_header | ps_frame_info->n_r);

            /* create the packet */
            (void)memcpy ((void *)&(s_create_packet), (void *)ps_get_packet,
                        sizeof (phLlcNfc_LlcPacket_t));

            s_create_packet.s_llcbuf.sllcpayload.llcheader = llc_header;
            ps_llc_payload = &(s_create_packet.s_llcbuf.sllcpayload);

            /* Length of the complete llc buffer, sent to PN544 */
            length = s_create_packet.llcbuf_len;

            /* Compute CRC */
            phLlcNfc_H_ComputeCrc((uint8_t *)&(s_create_packet.s_llcbuf),
                        (length - 2),
                        (uint8_t *)&(ps_llc_payload->llcpayload[(length - 4)]),
                        (uint8_t *)&(ps_llc_payload->llcpayload[(length - 3)]));

            /* Send the i frame */
            result = phLlcNfc_Interface_Write (psLlcCtxt, 
                            (uint8_t *)&(s_create_packet.s_llcbuf),
                            (uint32_t)s_create_packet.llcbuf_len);

            ps_frame_info->write_status = result;
            PH_LLCNFC_DEBUG("SEND TIMEOUT CALL Write status : 0x%02X\n", result);

            if (NFCSTATUS_BUSY == PHNFCSTATUS (result))
            {
                ps_frame_info->write_wait_call = resend_i_frame;
            }
            else
            {
                /* result = NFCSTATUS_PENDING and 
                    Timer is not started because the remaining timer 
                    will be running */
                uint16_t                time_out_value = 0;

                /* Each frame has the send count, so increment this 
                    as soon as the frame is sent */
                ps_timer_info->iframe_send_count[timer_index] = (uint8_t)
                            (ps_timer_info->iframe_send_count[timer_index] + 1);

                PH_LLCNFC_DEBUG("SEND TIMEOUT CALL timer index : 0x%02X\n", timer_index);

                if (timer_index > 0)
                {                    
                    PH_LLCNFC_DEBUG("SEND TIMEOUT CALL GUARD TO VALUE : 0x%02X\n", ps_timer_info->guard_to_value[(timer_index - 1)]);
                    /* Copy the maximum time-out value. */
                    time_out_value = (uint16_t)
                        ((ps_timer_info->guard_to_value[(timer_index - 1)] >= 
                        PH_LLCNFC_GUARD_TO_VALUE) ? 
                        (ps_timer_info->guard_to_value[(timer_index - 1)] + 
                        PH_LLCNFC_RESOLUTION): 
                        PH_LLCNFC_GUARD_TO_VALUE);
                }
                else
                {
                    /* If the timer_index is 0 means, the previous timed out  
                        frame is the last frame in the list */
                    time_out_value = (uint16_t)
                        ((ps_timer_info->guard_to_value[(timer_count - 1)] >= 
                        PH_LLCNFC_GUARD_TO_VALUE) ? 
                        (ps_timer_info->guard_to_value[(timer_count - 1)] + 
                        PH_LLCNFC_RESOLUTION):
                        PH_LLCNFC_GUARD_TO_VALUE);
                }

                ps_timer_info->guard_to_value[timer_index] = time_out_value;

                ps_frame_info->sent_frame_type = resend_i_frame;

                ps_timer_info->frame_type[timer_index] = invalid_frame;

                PH_LLCNFC_DEBUG("SEND TIMEOUT CALL Next frame type : 0x%02X\n", ps_timer_info->frame_type[((timer_index + 1) % PH_LLCNFC_MAX_ACK_GUARD_TIMER)]);
                /* Now check if next timer has expired, if yes, 
                    set the index to next, on receiving the write response 
                    callback for this send, then next frame can be sent */
                if (resend_i_frame == 
                    ps_timer_info->frame_type[((timer_index + 1) % 
                    PH_LLCNFC_MAX_ACK_GUARD_TIMER)])
                {
                    /* If next frame has to be sent, then update write wait */
                    ps_frame_info->write_status = NFCSTATUS_BUSY;
                    ps_frame_info->write_wait_call = resend_i_frame;
                    ps_timer_info->index_to_send = (uint8_t)
                                            ((timer_index + 1) % 
                                            PH_LLCNFC_MAX_ACK_GUARD_TIMER);
                }
                else
                {
                    /* Timer is not expired, 
                        Now, Check if the new frame is ready to be sent, if yes, 
                        then update the variable */
                    if (
                        (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + 
                        ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR))
                        )
                    {
                        ps_frame_info->write_status = PHNFCSTVAL (CID_NFC_LLC, 
                                                    NFCSTATUS_BUSY);
                        ps_frame_info->write_wait_call = user_i_frame;
                    }
                }

#if 0
                result = phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER, 
                                        ((llc_header >> 
                                        PH_LLCNFC_NS_START_BIT_POS) | 
                                        MAX_NS_NR_VALUE));
#endif /* #if 0 */

            }            
        }
        else
        {
            if (
                (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + 
                ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR))
                )
            {
                ps_frame_info->write_status = PHNFCSTVAL (CID_NFC_LLC, 
                                            NFCSTATUS_BUSY);
                ps_frame_info->write_wait_call = user_i_frame;
            }
        }
    }
    
    return result;
}


void 
phLlcNfc_H_ProcessIFrame (  
    phLlcNfc_Context_t      *psLlcCtxt 
)
{
    NFCSTATUS                   result = NFCSTATUS_SUCCESS;
    uint8_t                     ns_index = 0;    
#if defined (LLC_SEND_RR_ACK)
    /* uint8_t                     nr_index = 0; */
#endif /* #if defined (LLC_SEND_RR_ACK) */
    phLlcNfc_Frame_t            *ps_frame_info = NULL;
    phLlcNfc_StoreIFrame_t      *ps_store_frame = NULL;
    phLlcNfc_LlcPacket_t        *ps_recv_pkt = NULL;
    phLlcNfc_LlcCmd_t           cmdtype = phLlcNfc_e_error;
    phLlcNfc_eSentFrameType_t   eframe_type = invalid_frame;
    uint8_t                     dont_send_s_frame = FALSE;
    uint8_t                     no_of_del_frames = 0;
    phNfc_sCompletionInfo_t     notifyinfo = {0,0,0};

#ifdef RECV_NR_CHECK_ENABLE
    uint8_t                     recvd_nr = 0;    
#endif /* #ifdef RECV_NR_CHECK_ENABLE */

    ps_frame_info = &(psLlcCtxt->s_frameinfo);
    ps_store_frame = &(ps_frame_info->s_send_store);
    ps_recv_pkt = &(ps_frame_info->s_recvpacket);

    PHNFC_UNUSED_VARIABLE(result);
    /* Received buffer, N(S) value */
    ns_index = (uint8_t)GET_BITS8( 
                        ps_recv_pkt->s_llcbuf.sllcpayload.llcheader, 
                        PH_LLCNFC_NS_START_BIT_POS, 
                        PH_LLCNFC_NR_NS_NO_OF_BITS);

    PH_LLCNFC_DEBUG("NS START POS BEFORE DEL : 0x%02X\n", ps_store_frame->start_pos);
    PH_LLCNFC_DEBUG("WIN SIZE BEFORE DEL : 0x%02X\n", ps_store_frame->winsize_cnt);

    /* Correct frame is received, so remove the stored i frame info */
    no_of_del_frames = phLlcNfc_H_UpdateIFrameList (ps_frame_info, 
                                &(ps_frame_info->s_send_store));

    PH_LLCNFC_DEBUG("NS START POS AFTER DEL : 0x%02X\n", ps_store_frame->start_pos);
    PH_LLCNFC_DEBUG("WIN SIZE AFTER DEL : 0x%02X\n", ps_store_frame->winsize_cnt);

#ifdef RECV_NR_CHECK_ENABLE

    recvd_nr = (uint8_t)GET_BITS8( 
                        ps_recv_pkt->s_llcbuf.sllcpayload.llcheader, 
                        PH_LLCNFC_NR_START_BIT_POS, 
                        PH_LLCNFC_NR_NS_NO_OF_BITS);

    if (((ps_frame_info->n_s > recvd_nr) && 
        (0 == ((ps_frame_info->n_s + 1) % PH_LLCNFC_MOD_NS_NR)))
        || (recvd_nr > ps_frame_info->n_s))

#else /* #ifdef RECV_NR_CHECK_ENABLE */

    if (no_of_del_frames > 0)

#endif /* #ifdef RECV_NR_CHECK_ENABLE */
    {
        phLlcNfc_StopTimers (PH_LLCNFC_GUARDTIMER, no_of_del_frames);
    }

    /* Received buffer, N(S) value = N(R) of host (our 
        structure) then send RR type of s frame else send 
        REJ type of s frame */
    if (ns_index == ps_frame_info->n_r
#if defined (LLC_SEND_RR_ACK)

        || ((ns_index < ps_frame_info->n_r) && 
            ((ps_frame_info->n_r - ns_index) < ps_frame_info->window_size))
        || ((ns_index > ps_frame_info->n_r) && 
            ((ns_index - ps_frame_info->n_r) > ps_frame_info->window_size))

#endif /* #if defined (LLC_SEND_RR_ACK) */
         )
    {
        PH_LLCNFC_PRINT(" Type bits of S frame to be sent is RR \n");
        ps_frame_info->recv_error_count = 0;
        ps_frame_info->send_error_count = 0;

        psLlcCtxt->recvbuf_length = (ps_recv_pkt->llcbuf_len - 
                                    PH_LLCNFC_LEN_APPEND);

        (void)memcpy ((void *)psLlcCtxt->precv_buf, (void *)(
                        ps_recv_pkt->s_llcbuf.sllcpayload.llcpayload), 
                        psLlcCtxt->recvbuf_length);
        
#if defined (LLC_SEND_RR_ACK)

        if (((ns_index < ps_frame_info->n_r) && 
            ((ps_frame_info->n_r - ns_index) < ps_frame_info->window_size))
            || ((ns_index > ps_frame_info->n_r) && 
            ((ns_index - ps_frame_info->n_r) > ps_frame_info->window_size)))
        {
            ps_frame_info->n_r = ((ns_index + 1) 
                                % PH_LLCNFC_MOD_NS_NR);
        }
        else

#endif /* #if defined (LLC_SEND_RR_ACK) */
        {            
            /* Update the N(R) value in I and S frame context  */
            ps_frame_info->n_r = ((ps_frame_info->n_r + 1)
                                    % PH_LLCNFC_MOD_NS_NR);

#ifdef PIGGY_BACK
            ps_frame_info->resp_recvd_count = (uint8_t)
                                    (ps_frame_info->resp_recvd_count + 1);
#endif /* #ifdef PIGGY_BACK */

        }

        if (NFCSTATUS_BUSY == PHNFCSTATUS (ps_frame_info->write_status))
        {
            /* Any how write cannot be done and some frame is ready to be sent 
            so this frame will act as the ACK */            
            result = phLlcNfc_H_WriteWaitCall (psLlcCtxt);
        }
        else 
        {
            if (
                (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + 
                ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR))
                )
            {
                /* If user has sent a frame and DAL write is busy, then 
                it has to be sent */
                result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_frame);
            }
        }

        if (NFCSTATUS_PENDING == result)
        {
            dont_send_s_frame = TRUE;
#ifdef LLC_UPP_LAYER_NTFY_WRITE_RSP_CB
            phLlcNfc_H_SendInfo (psLlcCtxt);
#endif /* #ifdef LLC_UPP_LAYER_NTFY_WRITE_RSP_CB */        
        }
        else
        {
            cmdtype = phLlcNfc_e_rr;
            /* If i frame is sent from the stored list, it got the correct 
                acknowledge i frame, so now for an i frame , s frame acknowledge 
                is sent */
            eframe_type = ((resend_i_frame == ps_frame_info->sent_frame_type)?
                            resend_s_frame : s_frame);
        }

#ifdef PIGGY_BACK
        phLlcNfc_H_SendInfo (psLlcCtxt);
#endif /* #ifdef PIGGY_BACK */

    }
    else
    {
        ps_frame_info->send_error_count = (uint8_t)
                                (ps_frame_info->send_error_count + 1);

#ifdef LLC_SEND_ERROR_COUNT

        if (ps_frame_info->send_error_count < RECV_ERROR_FRAME_COUNT)

#endif /* #ifdef LLC_SEND_ERROR_COUNT */
        {

#ifdef LLC_RR_INSTEAD_OF_REJ

            if (((ps_frame_info->n_r > 0) && (ns_index == (ps_frame_info->n_r - 1)))
                || ((0 == ps_frame_info->n_r) &&
                (ns_index == (PH_LLCNFC_MOD_NS_NR - 1))))
            {
                cmdtype = phLlcNfc_e_rr;
                eframe_type = rej_rr_s_frame;
            }
            else

#endif /* #ifdef LLC_RR_INSTEAD_OF_REJ */
            {
                cmdtype = phLlcNfc_e_rej;
                eframe_type = ((resend_i_frame == ps_frame_info->sent_frame_type)?
                                resend_rej_s_frame : reject_s_frame);
            }
        }

#ifdef LLC_SEND_ERROR_COUNT
        else
        {
#ifdef LLC_RSET_INSTEAD_OF_EXCEPTION

            result = phLlcNfc_H_SendRSETFrame (psLlcCtxt);

#else /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */

            dont_send_s_frame = TRUE;
            PH_LLCNFC_DEBUG("SEND ERROR COUNT : 0x%02X\n", ps_frame_info->send_error_count);
            /* Error count has reached the limit, raise exception */
            notifyinfo.status = PHNFCSTVAL(CID_NFC_LLC, 
                                            NFCSTATUS_BOARD_COMMUNICATION_ERROR);
#if 0
            phOsalNfc_RaiseException(phOsalNfc_e_UnrecovFirmwareErr,1); 
#endif /* #if 0 */
                /* Resend done, no answer from the device */
            psLlcCtxt->cb_for_if.notify (
                            psLlcCtxt->cb_for_if.pif_ctxt,
                            psLlcCtxt->phwinfo, 
                            NFC_NOTIFY_DEVICE_ERROR, 
                            &notifyinfo);

#endif /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */
        }
#endif /* #ifdef LLC_SEND_ERROR_COUNT */
    }

#ifdef LLC_RELEASE_FLAG

    if (FALSE == g_release_flag)

#endif /* #ifdef LLC_RELEASE_FLAG */
    {
        (void)phLlcNfc_Interface_Read(psLlcCtxt,
                        PH_LLCNFC_READWAIT_OFF, 
                        &(ps_recv_pkt->s_llcbuf.llc_length_byte),
                        (uint8_t)PH_LLCNFC_BYTES_INIT_READ);
    
#ifdef PIGGY_BACK
        /* Check if any write call is performed or not */
        if (NFCSTATUS_PENDING != result)
        {
            /* No write is performed, So, now check */
            if (NFCSTATUS_BUSY == PHNFCSTATUS (ps_frame_info->write_status))
            {
                /* Any how write cannot be done and some frame is ready to be sent
                so this frame will act as the ACK */
                result = phLlcNfc_H_WriteWaitCall (psLlcCtxt);
            }
        }

        if (NFCSTATUS_PENDING != result)
        {
            if (ps_frame_info->window_size == ps_frame_info->resp_recvd_count)
            {
                phLlcNfc_LlcPacket_t    s_packet_info;
                /* Create S frame */
                (void)phLlcNfc_H_CreateSFramePayload (ps_frame_info, &(s_packet_info), cmdtype);

                result = phLlcNfc_Interface_Write(psLlcCtxt,
                            (uint8_t *)&(s_packet_info.s_llcbuf),
                            (uint32_t)(s_packet_info.llcbuf_len));


                if (0 == ps_frame_info->send_error_count)
                {
                    ps_frame_info->write_wait_call = invalid_frame;
                }
                ps_frame_info->sent_frame_type = eframe_type;
            }
            else
            {
                result = phLlcNfc_StartTimers (PH_LLCNFC_ACKTIMER, 0);
            }
        }
#else /* #ifdef PIGGY_BACK */

        if ((TRUE != ps_frame_info->write_pending) &&  
            (PH_LLCNFC_READPEND_REMAIN_BYTE != ps_frame_info->read_pending) && 
            (FALSE == dont_send_s_frame))
        {
            phLlcNfc_LlcPacket_t    s_packet_info = {0};
            /* Create S frame */
            (void)phLlcNfc_H_CreateSFramePayload (ps_frame_info, &(s_packet_info), cmdtype);

            result = phLlcNfc_Interface_Write(psLlcCtxt,
                        (uint8_t *)&(s_packet_info.s_llcbuf),
                        (uint32_t)(s_packet_info.llcbuf_len));


            if (0 == ps_frame_info->send_error_count)
            {
                ps_frame_info->write_wait_call = invalid_frame;
            }
            ps_frame_info->sent_frame_type = eframe_type;
        }
#endif /* #ifdef PIGGY_BACK */
    }

    return ;
}

static 
NFCSTATUS 
phLlcNfc_H_ProcessUFrame (  
    phLlcNfc_Context_t      *psLlcCtxt
)
{
    NFCSTATUS                   result = NFCSTATUS_SUCCESS;
    phLlcNfc_Frame_t            *ps_frame_info = NULL;
    phLlcNfc_LlcPacket_t        *ps_uframe_pkt = NULL;
#ifdef LLC_URSET_NO_DELAY
    phNfc_sCompletionInfo_t     notifyinfo = {0,0,0};
#else /* #ifdef LLC_URSET_NO_DELAY */
    uint32_t                    delay_timer_id = 
                                PH_OSALNFC_INVALID_TIMER_ID;
#endif /* #ifdef LLC_URSET_NO_DELAY */
    uint8_t                     cmdtype = phLlcNfc_e_error;

    phLlcNfc_StopTimers(PH_LLCNFC_CONNECTIONTIMER, 0);
    ps_frame_info = &(psLlcCtxt->s_frameinfo);
    ps_uframe_pkt = &(ps_frame_info->s_recvpacket);
    /* Check the command type */
    cmdtype = (ps_uframe_pkt->s_llcbuf.sllcpayload.llcheader & 
                PH_LLCNFC_U_FRAME_MODIFIER_MASK);
    PHNFC_UNUSED_VARIABLE(result);
    switch(cmdtype)
    {
        case phLlcNfc_e_rset:
        {
            psLlcCtxt->s_frameinfo.rset_recvd = TRUE;
            /* command type is RSET, so update the U frame parameters */
            result = phLlcNfc_H_Update_ReceivedRSETInfo (ps_frame_info, 
                                ps_uframe_pkt->s_llcbuf.sllcpayload);
            /* Create a UA frame */
            result = phLlcNfc_H_CreateUFramePayload(psLlcCtxt, 
                                            ps_uframe_pkt, 
                                            &(ps_uframe_pkt->llcbuf_len), 
                                            phLlcNfc_e_ua);

            if (NFCSTATUS_SUCCESS == result)
            {
                /* Call DAL write */
                result = phLlcNfc_Interface_Write( psLlcCtxt, 
                                    (uint8_t*)&(ps_uframe_pkt->s_llcbuf), 
                                    (uint32_t)ps_uframe_pkt->llcbuf_len);

                phLlcNfc_H_ResetFrameInfo(psLlcCtxt);
                ps_frame_info->write_status = result;
                ps_frame_info->write_wait_call = invalid_frame;
                if (NFCSTATUS_PENDING == result)
                {
                    ps_frame_info->sent_frame_type = 
                            ((ps_frame_info->sent_frame_type != init_u_rset_frame) ?
                            u_a_frame : init_u_a_frame);
                }
                else
                {
                    if (NFCSTATUS_BUSY == PHNFCSTATUS(result))
                    {
                        ps_frame_info->write_wait_call = 
                            ((ps_frame_info->sent_frame_type != init_u_rset_frame) ?
                            u_a_frame : init_u_a_frame);
                        result = NFCSTATUS_PENDING;
                    }
                }
            }
            break;
        }
        case phLlcNfc_e_ua:
        {
            phLlcNfc_H_ResetFrameInfo (psLlcCtxt);
            /* Add timer here, to delay the next command to the PN544 */
#ifdef LLC_URSET_NO_DELAY
            if (ps_frame_info->s_send_store.winsize_cnt > 0)
            {
#if 0
                /* Resend I frame */
                result = phLlcNfc_H_SendTimedOutIFrame (psLlcCtxt, 
                                &(ps_frame_info->s_send_store, 0);
#else
                result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, 
                                &(ps_frame_info->s_send_store));
#endif /* #if 0 */
            }
            else 
            {
                if ((init_u_rset_frame == ps_frame_info->sent_frame_type) && 
                    (NULL != psLlcCtxt->cb_for_if.notify))
                {
                    ps_frame_info->sent_frame_type = write_resp_received;
                    notifyinfo.status = NFCSTATUS_SUCCESS;
                    /* Send the notification to the upper layer */
                    psLlcCtxt->cb_for_if.notify(
                                psLlcCtxt->cb_for_if.pif_ctxt, 
                                psLlcCtxt->phwinfo, 
                                NFC_NOTIFY_INIT_COMPLETED, 
                                &notifyinfo);
                }
            }
#else /* #ifdef LLC_URSET_NO_DELAY */
            delay_timer_id = phOsalNfc_Timer_Create ();
            phOsalNfc_Timer_Start (delay_timer_id, LLC_URSET_DELAY_TIME_OUT, 
                                    phLlcNfc_URSET_Delay_Notify, (void*)0);
#endif /* #ifdef LLC_URSET_NO_DELAY */
            break;
        }
        default:
        {
            result = PHNFCSTVAL(CID_NFC_LLC, 
                                NFCSTATUS_INVALID_FORMAT);
            break;
        }
    }
    return result;
}

static 
void 
phLlcNfc_H_ProcessSFrame (  
    phLlcNfc_Context_t      *psLlcCtxt)
{
    NFCSTATUS                   result = NFCSTATUS_SUCCESS;
    uint8_t                     cmdtype = phLlcNfc_e_error;
#if 0
                                prev_win_count = 0;
#endif /* #if 0 */
    phNfc_sTransactionInfo_t    compinfo = {0, 0, 0, 0, 0};
    phLlcNfc_Frame_t            *ps_frame_info = NULL;
    phLlcNfc_StoreIFrame_t      *ps_store_frame = NULL;
    phLlcNfc_LlcPacket_t        *ps_recv_pkt = NULL;
    uint8_t                     no_of_del_frames = 0;
    phNfc_sCompletionInfo_t     notifyinfo = {0,0,0};
    
    ps_frame_info = &(psLlcCtxt->s_frameinfo);
    ps_recv_pkt = &(ps_frame_info->s_recvpacket);
    ps_store_frame = &(ps_frame_info->s_send_store);

    cmdtype = (ps_recv_pkt->s_llcbuf.sllcpayload.llcheader & 
                PH_LLCNFC_S_FRAME_TYPE_MASK);
    PHNFC_UNUSED_VARIABLE(result);

    PH_LLCNFC_DEBUG("NS START POS BEFORE DEL : 0x%02X\n", ps_store_frame->start_pos);
    PH_LLCNFC_DEBUG("WIN SIZE BEFORE DEL : 0x%02X\n", ps_store_frame->winsize_cnt);

    /* Correct frame is received, so remove the 
        stored i frame info for the acknowledged frames */
    no_of_del_frames = phLlcNfc_H_UpdateIFrameList (ps_frame_info, 
                                        &(ps_frame_info->s_send_store));

    PH_LLCNFC_DEBUG("NS START POS AFTER DEL : 0x%02X\n", ps_store_frame->start_pos);
    PH_LLCNFC_DEBUG("WIN SIZE AFTER DEL : 0x%02X\n", ps_store_frame->winsize_cnt);

#if 0
    prev_win_count = ps_frame_info->s_send_store.winsize_cnt;
#endif /* #if 0 */

    /* Pend the read */
    result = phLlcNfc_Interface_Read (psLlcCtxt, 
                            PH_LLCNFC_READWAIT_OFF, 
                            &(ps_recv_pkt->s_llcbuf.llc_length_byte),
                            (uint8_t)PH_LLCNFC_BYTES_INIT_READ);    
    switch(cmdtype)
    {
        case phLlcNfc_e_rr:
        case phLlcNfc_e_rej:
        {
            /* RR frame received */
            phLlcNfc_StopTimers (PH_LLCNFC_GUARDTIMER, no_of_del_frames);

            if (phLlcNfc_e_rr == cmdtype)
            {
                ps_frame_info->recv_error_count = 0;
                ps_frame_info->send_error_count = 0;
            }
            else
            {
                ps_frame_info->recv_error_count = (uint8_t)
                                (ps_frame_info->recv_error_count + 1);
            }

            if (ps_frame_info->recv_error_count >= RECV_ERROR_FRAME_COUNT)
            {
                /* Do nothing */
            }
            else if (NFCSTATUS_BUSY == PHNFCSTATUS(ps_frame_info->write_status))
            {
                result = phLlcNfc_H_WriteWaitCall (psLlcCtxt);
            }
            else 
            {
                if (
                    (ps_frame_info->n_s != ((ps_store_frame->winsize_cnt + 
                    ps_store_frame->start_pos) % PH_LLCNFC_MOD_NS_NR))
                    )
                {
                    /* If user has sent a frame and DAL write is busy, then 
                        it has to be sent */
                    result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_frame);
                }
            }

            if ((0 != psLlcCtxt->send_cb_len) && 
                (ps_store_frame->winsize_cnt < ps_frame_info->window_size))
            {
                /* Due to the window size count (i.e., count has reached 
                    the limit), send completion was not sent for the previous 
                    send from the upper layer. So to allow next send from the 
                    upper layer, send completion is called */
                compinfo.length = (uint16_t)psLlcCtxt->send_cb_len;
                compinfo.status = NFCSTATUS_SUCCESS;
                
                if (NULL != psLlcCtxt->cb_for_if.send_complete)
                {
                    psLlcCtxt->send_cb_len = 0;
                    /* Call the send callback, if the window size 
                        count becomes less than actual window size */
                    psLlcCtxt->cb_for_if.send_complete (
                                psLlcCtxt->cb_for_if.pif_ctxt, 
                                psLlcCtxt->phwinfo, &compinfo);
                }
            }
            break;
        }

#if 0
        case phLlcNfc_e_rej:
        {
            ps_frame_info->recv_error_count = (uint8_t)
                                (ps_frame_info->recv_error_count + 1);
            /* RR frame received */
            phLlcNfc_StopTimers (PH_LLCNFC_GUARDTIMER, no_of_del_frames);

            if (ps_frame_info->recv_error_count < RECV_ERROR_FRAME_COUNT)
            {
                /* Below check is added because if PN544 sends REJ to a frame, but 
                    the next frame has already been sent from PN544, then 
                Send the user I frame */
                result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_frame);
            }
            break;
        }
#endif /* #if 0 */

        case phLlcNfc_e_rnr:
        {
            phLlcNfc_StopAllTimers ();
            ps_frame_info->recv_error_count = (uint8_t)
                                (ps_frame_info->recv_error_count + 1);
            break;
        }

        case phLlcNfc_e_srej:
        default:
        {
            ps_frame_info->recv_error_count = (uint8_t)
                                (ps_frame_info->recv_error_count + 1);
            result = PHNFCSTVAL (CID_NFC_LLC, 
                                NFCSTATUS_INVALID_FORMAT);
            break;
        }
    }

    if (ps_frame_info->recv_error_count >= RECV_ERROR_FRAME_COUNT)
    {
#ifdef LLC_RSET_INSTEAD_OF_EXCEPTION

        result = phLlcNfc_H_SendRSETFrame (psLlcCtxt);

#else /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */

        PH_LLCNFC_DEBUG("RECV ERROR COUNT : 0x%02X\n", ps_frame_info->recv_error_count);
        /* Raise the exception for CRC error received from the  */
        notifyinfo.status = PHNFCSTVAL(CID_NFC_LLC, 
                                NFCSTATUS_BOARD_COMMUNICATION_ERROR);
#if 0
        phOsalNfc_RaiseException(phOsalNfc_e_UnrecovFirmwareErr,1); 
#endif /* #if 0 */
        /* Resend done, no answer from the device */
        psLlcCtxt->cb_for_if.notify (
                        psLlcCtxt->cb_for_if.pif_ctxt,
                        psLlcCtxt->phwinfo, 
                        NFC_NOTIFY_DEVICE_ERROR, 
                        &notifyinfo);

#endif /* #ifdef LLC_RSET_INSTEAD_OF_EXCEPTION */
    }

    return ;
}


void 
phLlcNfc_H_ComputeCrc(
    uint8_t     *pData, 
    uint8_t     length,
    uint8_t     *pCrc1, 
    uint8_t     *pCrc2
)
{
    uint8_t     crc_byte = 0, 
                index = 0;
    uint16_t    crc = 0;

#ifdef CRC_A
        crc = 0x6363; /* ITU-V.41 */
#else
        crc = 0xFFFF; /* ISO/IEC 13239 (formerly ISO/IEC 3309) */
#endif /* #ifdef CRC_A */

    do 
    {
        crc_byte = pData[index];
        phLlcNfc_H_UpdateCrc(crc_byte, &crc);
        index++;
    } while (index < length);

#ifndef INVERT_CRC
    crc = ~crc; /* ISO/IEC 13239 (formerly ISO/IEC 3309) */
#endif /* #ifndef INVERT_CRC */

    *pCrc1 = (uint8_t) (crc & 0xFF);
    *pCrc2 = (uint8_t) ((crc >> 8) & 0xFF);
    return;
}

static 
void 
phLlcNfc_H_UpdateCrc(
    uint8_t     crcByte, 
    uint16_t    *pCrc
)
{
    crcByte = (crcByte ^ (uint8_t)((*pCrc) & 0x00FF));
    crcByte = (crcByte ^ (uint8_t)(crcByte << 4));
    *pCrc = (*pCrc >> 8) ^ ((uint16_t)crcByte << 8) ^
                ((uint16_t)crcByte << 3) ^
                ((uint16_t)crcByte >> 4);
}

NFCSTATUS 
phLlcNfc_H_StoreIFrame (
    phLlcNfc_StoreIFrame_t      *psList,
    phLlcNfc_LlcPacket_t        sPacketInfo
)
{
    NFCSTATUS   result = NFCSTATUS_SUCCESS;
    uint8_t     ns_index = 0, 
                llc_header = 0;

    if ((NULL == psList) || (0 == sPacketInfo.llcbuf_len) || 
        (PH_LLCNFC_I_HEADER_INIT != 
        (sPacketInfo.s_llcbuf.sllcpayload.llcheader & 
        PH_LLCNFC_I_FRM_HEADER_MASK)))
    {
        result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_PARAMETER);
    }
    else
    {
        /* Get the index from the start index */
        if(psList->winsize_cnt > 0)
        {
            ns_index = (uint8_t)((psList->start_pos + psList->winsize_cnt) % 
                                PH_LLCNFC_MOD_NS_NR);
        }
        else
        {
            ns_index = psList->start_pos;
        }

        llc_header = (uint8_t)(PH_LLCNFC_I_HEADER_INIT | (ns_index << 
                        PH_LLCNFC_NS_START_BIT_POS));
        sPacketInfo.s_llcbuf.sllcpayload.llcheader = llc_header;

        (void)memcpy (&(psList->s_llcpacket[ns_index]), 
                        &(sPacketInfo), sizeof(phLlcNfc_LlcPacket_t));

        /* This variable says that LLC has to send complete 
            callback for stored I frame */
        psList->s_llcpacket[ns_index].frame_to_send = invalid_frame;

        psList->winsize_cnt++;        
    }
    return result;
}

static
void 
phLlcNfc_H_DeleteIFrame (
    phLlcNfc_StoreIFrame_t      *psList
)
{    
    if (NULL != psList)
    {
        (void)memset( &(psList->s_llcpacket[psList->start_pos]), 
                        0, sizeof(phLlcNfc_LlcPacket_t));

        /* Go to next N(S) position */
        psList->start_pos = ((psList->start_pos + 1) % 
                            PH_LLCNFC_MOD_NS_NR);

        if (psList->winsize_cnt > 0)
        {
            psList->winsize_cnt--;
        }
    }
}

static
NFCSTATUS  
phLlcNfc_H_IFrameList_Peek (
    phLlcNfc_StoreIFrame_t      *psList, 
    phLlcNfc_LlcPacket_t        **psPacketinfo, 
    uint8_t                     position
)
{
    NFCSTATUS   result = NFCSTATUS_SUCCESS;
    uint8_t     index = 0;

    *psPacketinfo = NULL;
    if ((NULL != psList) && (psList->winsize_cnt > 0))
    {
        result = NFCSTATUS_SUCCESS;
        if ((position < (psList->start_pos + psList->winsize_cnt)) || 
            (DEFAULT_PACKET_INPUT == position))
        {
            index = (uint8_t)((DEFAULT_PACKET_INPUT == position) ? 
                    psList->start_pos : position);
            *psPacketinfo = &(psList->s_llcpacket[index]);
        }
    }

    return result;
}

NFCSTATUS 
phLlcNfc_H_ProRecvFrame (
    phLlcNfc_Context_t      *psLlcCtxt
)
{
    NFCSTATUS               result = PHNFCSTVAL(CID_NFC_LLC, 
                                    NFCSTATUS_INVALID_PARAMETER);
    phLlcNfc_FrameType_t    frame_type = phLlcNfc_eErr_frame;
#ifdef LLC_DATA_BYTES
    uint8_t                 *print_buf = (uint8_t *)
                            &(psLlcCtxt->s_frameinfo.s_recvpacket.s_llcbuf);
    uint8_t                 buf_len = 
                            psLlcCtxt->s_frameinfo.s_recvpacket.llcbuf_len;
    PH_LLCNFC_STRING("** Response ");
    
#endif /* LLC_DATA_BYTES */
    if (NULL != psLlcCtxt)
    {
        result = NFCSTATUS_SUCCESS;
        /* Get the received frame type */
        frame_type = phLlcNfc_H_ChkGetLlcFrameType(
            psLlcCtxt->s_frameinfo.s_recvpacket.s_llcbuf.sllcpayload.llcheader);

        /* Depending on the received frame type, process the 
        received buffer */
        switch(frame_type)
        {
            case phLlcNfc_eU_frame:
            {
                PH_LLCNFC_PRINT("U frame received \n");
                PH_LLCNFC_STRING("U frame ");
                PH_LLCNFC_PRINT_DATA(print_buf, buf_len);
                PH_LLCNFC_STRING(";\n");
                result = phLlcNfc_H_ProcessUFrame(psLlcCtxt);
                break;
            }
            case phLlcNfc_eI_frame:
            {
                PH_LLCNFC_PRINT("I frame received \n");
                PH_LLCNFC_STRING("I frame ");
                PH_LLCNFC_PRINT_DATA(print_buf, buf_len);
                PH_LLCNFC_STRING(";\n");
                phLlcNfc_H_ProcessIFrame(psLlcCtxt);
                break;
            }
            case phLlcNfc_eS_frame:
            {
                PH_LLCNFC_PRINT("S frame received \n");
                PH_LLCNFC_STRING("S frame ");
                PH_LLCNFC_PRINT_DATA(print_buf, buf_len);
                PH_LLCNFC_STRING(";\n");
                phLlcNfc_H_ProcessSFrame(psLlcCtxt);
                break;
            }
            case phLlcNfc_eErr_frame:
            default:
            {
                PH_LLCNFC_PRINT("Error frame received \n");
                result = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_INVALID_FORMAT);
                break;
            }
        }
        
    }
    return result;
}

#ifdef CRC_ERROR_REJ
NFCSTATUS 
phLlcNfc_H_SendRejectFrame(
                      phLlcNfc_Context_t  *psLlcCtxt
                      )
{
    NFCSTATUS       result = NFCSTATUS_SUCCESS;
    phLlcNfc_LlcPacket_t    s_packet_info = {0};

    result = phLlcNfc_H_CreateSFramePayload(
                                    &(psLlcCtxt->s_frameinfo),
                                    &(s_packet_info),
                                    phLlcNfc_e_rej);
    /* Send the "S" frame to the lower layer */
    result = phLlcNfc_Interface_Write(psLlcCtxt,
        (uint8_t *)&(s_packet_info.s_llcbuf),
        (uint32_t)(s_packet_info.llcbuf_len));

    if (NFCSTATUS_PENDING == result)
    {
        /* Increment the retry count of the reject frame */
        psLlcCtxt->s_frameinfo.recv_error_count = 
                        (psLlcCtxt->s_frameinfo.recv_error_count + 1);
    }


    return result;                  
}
#endif /* #ifdef CRC_ERROR_REJ */

static 
void 
phLlcNfc_H_ResetFrameInfo (
    phLlcNfc_Context_t  *psLlcCtxt
)
{
    uint8_t                     i = 0, 
                                win_cnt = 0, 
                                pos = 0, 
                                while_exit = FALSE, 
                                index_flag = FALSE;
    phLlcNfc_StoreIFrame_t      *ps_send_store = NULL;
    phLlcNfc_Buffer_t           *ps_buffer = NULL;

    ps_send_store = &(psLlcCtxt->s_frameinfo.s_send_store);
    win_cnt = ps_send_store->winsize_cnt;
    pos = ps_send_store->start_pos;
    PH_LLCNFC_PRINT ("\n\nLLC : phLlcNfc_H_ResetFrameInfo called\n\n");
    PH_LLCNFC_DEBUG ("\n\nLLC : ps_send_store->start_pos %08X\n", ps_send_store->start_pos);
    PH_LLCNFC_DEBUG ("\n\nLLC : ps_send_store->winsize_cnt before reset %08X\n", ps_send_store->winsize_cnt);


    if (0 != pos)
    {
        /* If the start position of the ns = 0, then 
            no need to shift the stored llc data, 
            Else it has to be shifted to the first 
            index of the array */
        if(TRUE == ((pos + win_cnt) / 
                    PH_LLCNFC_MAX_I_FRAME_STORE))
        {
            /* 'i' is the array index, So to store data in the array, 
                windows size count shall be subtracted by 1 */
            i = (win_cnt - 1);
            /* if window size > 1 and ns for 2 frames are 7 and 0, then 
                to reset the ns index to 0, the frames are copied from 
                the reverse order, so to do it a flag is declared */
            index_flag = TRUE;
            pos = (((pos - 1) + win_cnt) % PH_LLCNFC_MAX_I_FRAME_STORE);
        }

        while (FALSE == while_exit)
        {
            (void)memcpy ((void *)&(ps_send_store->s_llcpacket[i]),  
                        (void *)&(ps_send_store->s_llcpacket[pos]), 
                        sizeof (phLlcNfc_LlcPacket_t));

            ps_send_store->s_llcpacket[i].frame_to_send = invalid_frame;
            
            ps_buffer = &(ps_send_store->s_llcpacket[i].s_llcbuf);
            /* change n(s) value */
            ps_buffer->sllcpayload.llcheader = (uint8_t)
                                    (PH_LLCNFC_I_HEADER_INIT | 
                                    (i << PH_LLCNFC_NS_START_BIT_POS));
            if(TRUE == index_flag)
            {
                if(0 == i)
                {
                    while_exit = TRUE;
                }
                else
                {
                    i = ((i - 1) % PH_LLCNFC_MAX_I_FRAME_STORE);
                    if (0 == pos)
                    {
                        pos = (PH_LLCNFC_MAX_I_FRAME_STORE - 1);
                    }
                    else
                    {
                        pos = ((pos - 1) % PH_LLCNFC_MAX_I_FRAME_STORE);
                    }
                }                
            }
            else
            {
                if (i >= win_cnt)
                {
                    while_exit = TRUE;
                }
                else
                {
                    i = ((i + 1) % PH_LLCNFC_MAX_I_FRAME_STORE);
                    pos = ((pos + 1) % PH_LLCNFC_MAX_I_FRAME_STORE);
                }
                
            }
        }
    }
    psLlcCtxt->s_timerinfo.guard_to_count = 0;
    psLlcCtxt->s_timerinfo.timer_flag = 0;
    ps_send_store->start_pos = 0;
    psLlcCtxt->s_frameinfo.n_r = psLlcCtxt->s_frameinfo.n_s = 0;
    if (ps_send_store->winsize_cnt > 0)
    {
        psLlcCtxt->s_frameinfo.rejected_ns = 0;
    }
    else
    {
        psLlcCtxt->s_frameinfo.rejected_ns = DEFAULT_PACKET_INPUT;
    }

    PH_LLCNFC_DEBUG ("\n\nLLC : ps_send_store->winsize_cnt after reset %08X\n", ps_send_store->winsize_cnt);
    return;
}

NFCSTATUS 
phLlcNfc_H_WriteWaitCall (
    phLlcNfc_Context_t  *psLlcCtxt
    )
{
    NFCSTATUS                   result = NFCSTATUS_SUCCESS;
    phLlcNfc_StoreIFrame_t      *ps_store_info = NULL;
    phLlcNfc_Frame_t            *ps_frame_info = NULL;
    
    ps_frame_info = &(psLlcCtxt->s_frameinfo);
    ps_store_info = &(ps_frame_info->s_send_store);

    PH_LLCNFC_PRINT ("\nLLC : phLlcNfc_H_WriteWaitCall call ..\n");
    PH_LLCNFC_DEBUG ("\n\nLLC : ps_frame_info->write_wait_call before call %08X\n", ps_frame_info->write_wait_call);

    ps_frame_info->write_status = NFCSTATUS_PENDING;
    switch (ps_frame_info->write_wait_call)
    {
        case user_i_frame:
        {
            ps_frame_info->write_wait_call = invalid_frame;
            result = phLlcNfc_H_SendUserIFrame (psLlcCtxt, ps_store_info);
            break;
        }

        case resend_i_frame:
        {
            ps_frame_info->write_wait_call = invalid_frame;
            result = phLlcNfc_H_SendTimedOutIFrame (psLlcCtxt, ps_store_info, 0);
            break;
        }

        case rejected_i_frame:
        {
            ps_frame_info->write_wait_call = invalid_frame;
            result = phLlcNfc_H_SendRejectedIFrame (psLlcCtxt, ps_store_info, 
                                                    ps_frame_info->rejected_ns);
            break;
        }

        case resend_s_frame:
        case reject_s_frame:
        case resend_rej_s_frame:
        {
            ps_frame_info->write_wait_call = invalid_frame;
            break;
        }

        case u_rset_frame:
        {
            ps_frame_info->write_wait_call = invalid_frame;
            result = phLlcNfc_H_SendRSETFrame (psLlcCtxt);
            break;
        }

        default :
        {
            ps_frame_info->write_wait_call = invalid_frame;
            break;
        }
    }

    PH_LLCNFC_DEBUG ("\n\nLLC : ps_frame_info->write_wait_call after call %08X\n", ps_frame_info->write_wait_call);
    PH_LLCNFC_PRINT ("\nLLC : phLlcNfc_H_WriteWaitCall end ..\n");
    return result;
}

NFCSTATUS  
phLlcNfc_H_SendRSETFrame (
                      phLlcNfc_Context_t  *psLlcCtxt
                      )
{
    NFCSTATUS                   result = NFCSTATUS_SUCCESS;
    phLlcNfc_LlcPacket_t        s_packet_info;
    phLlcNfc_Frame_t            *ps_frame_info = NULL;
    
    ps_frame_info = &(psLlcCtxt->s_frameinfo);

    result = phLlcNfc_H_CreateUFramePayload(psLlcCtxt,
                                    &(s_packet_info),
                                    &(s_packet_info.llcbuf_len),
                                    phLlcNfc_e_rset);

    if (NFCSTATUS_SUCCESS == result)
    {
        /* Call DAL write */
        result = phLlcNfc_Interface_Write(psLlcCtxt,
                            (uint8_t*)&(s_packet_info.s_llcbuf),
                            (uint32_t)s_packet_info.llcbuf_len);
    }

    ps_frame_info->write_status = result;
    if (NFCSTATUS_PENDING == result)
    {
        /* Start the timer */
        result = phLlcNfc_StartTimers (PH_LLCNFC_CONNECTIONTIMER, 0);
        if (NFCSTATUS_SUCCESS == result)
        {
            ps_frame_info->sent_frame_type = u_rset_frame;
            result = NFCSTATUS_PENDING;
        }
    }
    else
    {
        ps_frame_info->write_wait_call = u_rset_frame;
    }

    return result;
}


