/*
 * 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  phHciNfc_RFReaderA.c                                                 *
* \brief HCI Reader A Management Routines.                                    *
*                                                                             *
*                                                                             *
* Project: NFC-FRI-1.1                                                        *
*                                                                             *
* $Date: Wed Feb 17 16:19:04 2010 $                                           *
* $Author: ing02260 $                                                         *
* $Revision: 1.57 $                                                           *
* $Aliases: NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $
*                                                                             *
* =========================================================================== *
*/

/*
***************************** Header File Inclusion ****************************
*/
#include <phNfcCompId.h>
#include <phHciNfc_Pipe.h>
#include <phHciNfc_RFReader.h>
#include <phHciNfc_RFReaderA.h>
#include <phOsalNfc.h>
/*
****************************** Macro Definitions *******************************
*/

/* Registry used for getting the data */
#define RDR_A_DATA_RATE_MAX_INDEX           0x01U
#define RDR_A_UID_INDEX                     0x02U
#define RDR_A_SAK_INDEX                     0x03U
#define RDR_A_ATQA_INDEX                    0x04U
#define RDR_A_APP_DATA_INDEX                0x05U
#define RDR_A_FWI_SFGT_INDEX                0x06U

/* Registry index for auto activation */
#define NXP_AUTO_ACTIVATION_INDEX           0x10U

#define RDR_A_SAK_FWI_SFGT_LENGTH           0x01U

#define RDR_A_SINGLE_TAG_FOUND              0x00U
#define RDR_A_MULTIPLE_TAGS_FOUND           0x03U

#define RDR_A_MAX_APP_DATA_LEN              0x30U

/* Time out */
#define RDR_A_MIFARE_STATUS                 0x00U

#define RDR_A_MIFARE_RAW_LENGTH             0x03U

/*
*************************** Structure and Enumeration ***************************
*/


/*
*************************** Static Function Declaration **************************
*/

static 
NFCSTATUS
phHciNfc_Recv_ReaderA_Response(
                        void                *psContext,
                        void                *pHwRef,
                        uint8_t             *pResponse,
#ifdef ONE_BYTE_LEN
                        uint8_t             length
#else
                        uint16_t            length
#endif
                       );

static
NFCSTATUS
phHciNfc_Recv_ReaderA_Event(
                             void               *psContext,
                             void               *pHwRef,
                             uint8_t            *pEvent,
#ifdef ONE_BYTE_LEN
                             uint8_t            length
#else
                             uint16_t           length
#endif
                       );

static
NFCSTATUS
phHciNfc_ReaderA_InfoUpdate(
                            phHciNfc_sContext_t     *psHciContext,
                            uint8_t                 index,
                            uint8_t                 *reg_value,
                            uint8_t                 reg_length
                         );

static
NFCSTATUS
phHciNfc_Recv_Mifare_Packet(
                            phHciNfc_sContext_t *psHciContext,
                            uint8_t             cmd,
                            uint8_t             *pResponse,
#ifdef ONE_BYTE_LEN
                            uint8_t             length
#else
                            uint16_t            length
#endif
                            );

static
NFCSTATUS
phHciNfc_Recv_Iso_A_Packet(
                           phHciNfc_sContext_t  *psHciContext,
                           uint8_t              *pResponse,
#ifdef ONE_BYTE_LEN
                            uint8_t             length
#else
                            uint16_t            length
#endif
                           );
/*
*************************** Function Definitions ***************************
*/
NFCSTATUS
phHciNfc_ReaderA_Get_PipeID(
                             phHciNfc_sContext_t        *psHciContext,
                             uint8_t                    *ppipe_id
                             )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;

    if( (NULL != psHciContext)
        && ( NULL != ppipe_id )
        && ( NULL != psHciContext->p_reader_a_info ) 
        )
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
            psHciContext->p_reader_a_info ;
        *ppipe_id =  p_rdr_a_info->pipe_id  ;
    }
    else 
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    return status;
}


NFCSTATUS
phHciNfc_ReaderA_Init_Resources(
                                phHciNfc_sContext_t     *psHciContext
                         )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
    if( NULL == psHciContext )
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else
    {
        if(
            ( NULL == psHciContext->p_reader_a_info ) &&
             (phHciNfc_Allocate_Resource((void **)(&p_rdr_a_info),
            sizeof(phHciNfc_ReaderA_Info_t))== NFCSTATUS_SUCCESS)
          )
        {
            psHciContext->p_reader_a_info = p_rdr_a_info;
            p_rdr_a_info->current_seq = RDR_A_INVALID_SEQ;
            p_rdr_a_info->next_seq = RDR_A_INVALID_SEQ;
            p_rdr_a_info->pipe_id = (uint8_t)HCI_UNKNOWN_PIPE_ID;
        }
        else
        {
            status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INSUFFICIENT_RESOURCES);
        }
        
    }
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Update_PipeInfo(
                                  phHciNfc_sContext_t     *psHciContext,
                                  uint8_t                 pipeID,
                                  phHciNfc_Pipe_Info_t    *pPipeInfo
                                  )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;

    if( NULL == psHciContext )
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if(NULL == psHciContext->p_reader_a_info)
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t *p_rdr_a_info=NULL;
        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                                psHciContext->p_reader_a_info ;
        /* Update the pipe_id of the reader A Gate obtained from the HCI Response */
        p_rdr_a_info->pipe_id = pipeID;
        p_rdr_a_info->p_pipe_info = pPipeInfo;
        if (NULL != pPipeInfo)
        {
            /* Update the Response Receive routine of the reader A Gate */
            pPipeInfo->recv_resp = &phHciNfc_Recv_ReaderA_Response;
            /* Update the event Receive routine of the reader A Gate */
            pPipeInfo->recv_event = &phHciNfc_Recv_ReaderA_Event;
        }
    }

    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Info_Sequence (
                       void             *psHciHandle,
                       void             *pHwRef
                       )
{
    NFCSTATUS               status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t     *psHciContext = ((phHciNfc_sContext_t *)psHciHandle);

    HCI_PRINT ("HCI : phHciNfc_ReaderA_Info_Sequence called... \n");
    if( (NULL == psHciContext) 
        || (NULL == pHwRef)
      )
    {
      status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }   
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_Pipe_Info_t        *p_pipe_info=NULL;
        uint8_t                     pipeid = 0;
        
        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                                psHciContext->p_reader_a_info ;
        p_pipe_info = p_rdr_a_info->p_pipe_info;
        if(NULL == p_pipe_info )
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                            NFCSTATUS_INVALID_HCI_SEQUENCE);
        }
        else
        {
            HCI_DEBUG ("HCI : p_rdr_a_info->current_seq : %02X\n", p_rdr_a_info->current_seq);
            switch(p_rdr_a_info->current_seq)
            {
                case RDR_A_UID:
                {
                    p_pipe_info->reg_index = RDR_A_UID_INDEX;
                    pipeid = p_rdr_a_info->pipe_id ;
                    /* Fill the data buffer and send the command to the 
                            device */
                    status = 
                        phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                        pipeid, (uint8_t)ANY_GET_PARAMETER);
                    if(NFCSTATUS_PENDING == status )
                    {
                        p_rdr_a_info->next_seq = RDR_A_SAK;
                    }
                    break;
                }
                case RDR_A_SAK:
                {
                    p_pipe_info->reg_index = RDR_A_SAK_INDEX;
                    pipeid = p_rdr_a_info->pipe_id ;
                    /* Fill the data buffer and send the command to the 
                            device */
                    status = 
                        phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                        pipeid, (uint8_t)ANY_GET_PARAMETER);
                    if(NFCSTATUS_PENDING == status )
                    {
                        p_rdr_a_info->next_seq = RDR_A_ATQA;
                    }
                    break;
                }
                case RDR_A_ATQA:
                {
                    p_pipe_info->reg_index = RDR_A_ATQA_INDEX;
                    pipeid = p_rdr_a_info->pipe_id ;
                    /* Fill the data buffer and send the command to the 
                            device */
                    status = 
                        phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                        pipeid, (uint8_t)ANY_GET_PARAMETER);
                    if(NFCSTATUS_PENDING == status )
                    {
                        p_rdr_a_info->next_seq = RDR_A_END_SEQUENCE;
                    }
                    break;
                }
                case RDR_A_END_SEQUENCE:
                {
                    phNfc_sCompletionInfo_t     CompInfo;
                    if (RDR_A_MULTIPLE_TAGS_FOUND == 
                        p_rdr_a_info->multiple_tgts_found)
                    {
                        CompInfo.status = NFCSTATUS_MULTIPLE_TAGS;
                    }
                    else
                    {
                        CompInfo.status = NFCSTATUS_SUCCESS;
                    }
                    
                    CompInfo.info = &(p_rdr_a_info->reader_a_info);

                    p_rdr_a_info->reader_a_info.RemDevType = phHal_eISO14443_A_PICC;
                    p_rdr_a_info->current_seq = RDR_A_UID;
                    p_rdr_a_info->next_seq = RDR_A_UID;
                    status = NFCSTATUS_SUCCESS;
                    HCI_DEBUG ("HCI : p_rdr_a_info->reader_a_info.RemDevType : %02X\n", p_rdr_a_info->reader_a_info.RemDevType);
                    HCI_DEBUG ("HCI : status notified: %02X\n", CompInfo.status);
                    /* Notify to the upper layer */
                    phHciNfc_Tag_Notify(psHciContext, 
                        pHwRef, 
                        NFC_NOTIFY_TARGET_DISCOVERED, 
                        &CompInfo);
                    break;
                }
                default:
                {
                    status = PHNFCSTVAL(CID_NFC_HCI, 
                                    NFCSTATUS_INVALID_HCI_RESPONSE);
                    break;
                }
            }
            HCI_DEBUG ("HCI : p_rdr_a_info->current_seq after : %02X\n", p_rdr_a_info->current_seq);
            HCI_DEBUG ("HCI : p_rdr_a_info->next_seq : %02X\n", p_rdr_a_info->next_seq);
        }
    }

    HCI_PRINT ("HCI : phHciNfc_ReaderA_Info_Sequence end \n");
    return status;
}


static
NFCSTATUS
phHciNfc_ReaderA_InfoUpdate(
                                phHciNfc_sContext_t     *psHciContext,
                                uint8_t                 index,
                                uint8_t                 *reg_value,
                                uint8_t                 reg_length
                         )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
    phHal_sIso14443AInfo_t        *p_tag_a_info = NULL;
                                
    p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                                (psHciContext->p_reader_a_info );
    p_tag_a_info = &(p_rdr_a_info->reader_a_info.RemoteDevInfo.Iso14443A_Info);
    
    switch(index)
    {
        case RDR_A_UID_INDEX:
        {
            /* Maximum UID length can go upto 10 bytes */
            if (reg_length <= PHHAL_MAX_UID_LENGTH)
            {
                HCI_PRINT_BUFFER("\tReader A UID", reg_value, reg_length);
                /* Update UID buffer and length */
                p_tag_a_info->UidLength = reg_length;
                (void)memcpy(
                        p_tag_a_info->Uid, 
                        reg_value, 
                        p_tag_a_info->UidLength);
            } 
            else
            {
                status = PHNFCSTVAL(CID_NFC_HCI, 
                    NFCSTATUS_INVALID_HCI_RESPONSE);
            }
            break;
        }
        case RDR_A_SAK_INDEX:
        {
            /* SAK length is 1 byte */
            if (RDR_A_SAK_FWI_SFGT_LENGTH == reg_length)
            {
                HCI_PRINT_BUFFER("\tReader A SAK", reg_value, reg_length);
                /* Copy SAK byte */
                p_tag_a_info->Sak = *reg_value;
            } 
            else
            {
                status = PHNFCSTVAL(CID_NFC_HCI, 
                    NFCSTATUS_INVALID_HCI_RESPONSE);
            }
            break;
        }
        case RDR_A_ATQA_INDEX:
        {
            /* ATQA length shall be 2 bytes */
            if (PHHAL_ATQA_LENGTH == reg_length)
            {
                HCI_PRINT_BUFFER("\tReader A ATQA", reg_value, reg_length);
                /* Copy ATQA */
                (void)memcpy(p_tag_a_info->AtqA,
                    reg_value, 
                    reg_length);
            } 
            else
            {
                status = PHNFCSTVAL(CID_NFC_HCI, 
                    NFCSTATUS_INVALID_HCI_RESPONSE);
            }
            break;
        }
        case RDR_A_APP_DATA_INDEX:
        {
            /* Remote device info provided by the user */
            p_tag_a_info = 
                    &(psHciContext->p_target_info->RemoteDevInfo.Iso14443A_Info);
            /* Historical bytes length shall be 2 bytes */
            if (reg_length <= RDR_A_MAX_APP_DATA_LEN)
            {
                HCI_PRINT_BUFFER("\tReader A APP DATA", reg_value, reg_length);
                p_tag_a_info->AppDataLength = reg_length;
                /* Historical bytes */
                (void)memcpy(p_tag_a_info->AppData, 
                    reg_value, 
                    reg_length);
            } 
            else
            {
                status = PHNFCSTVAL(CID_NFC_HCI, 
                    NFCSTATUS_INVALID_HCI_RESPONSE);
            }
            break;
        }
        case RDR_A_FWI_SFGT_INDEX:
        {
            if (RDR_A_SAK_FWI_SFGT_LENGTH == reg_length)
            {
                HCI_PRINT_BUFFER("\tReader A FWI SFGT", reg_value, reg_length);
                p_tag_a_info->Fwi_Sfgt = *reg_value;
            } 
            else
            {
                status = PHNFCSTVAL(CID_NFC_HCI, 
                    NFCSTATUS_INVALID_HCI_RESPONSE);
            }
            break;
        }
        default:
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                            NFCSTATUS_INVALID_HCI_RESPONSE);
            break;
        }
    }
    return status;
}


static 
NFCSTATUS
phHciNfc_Recv_ReaderA_Response(
                        void                *psContext,
                        void                *pHwRef,
                        uint8_t             *pResponse,
#ifdef ONE_BYTE_LEN
                        uint8_t             length
#else
                        uint16_t            length
#endif
                       )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t         *psHciContext = 
                                (phHciNfc_sContext_t *)psContext ;
    

    if( (NULL == psHciContext) || (NULL == pHwRef) || (NULL == pResponse)
        || (length == 0))
    {
      status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if(NULL == psHciContext->p_reader_a_info)
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        uint8_t                     prev_cmd = ANY_GET_PARAMETER;
        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                            psHciContext->p_reader_a_info ;
        if( NULL == p_rdr_a_info->p_pipe_info)
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                            NFCSTATUS_INVALID_HCI_SEQUENCE);
        }
        else
        {
            prev_cmd = p_rdr_a_info->p_pipe_info->prev_msg ;
            switch(prev_cmd)
            {
                case ANY_GET_PARAMETER:
                {
                    status = phHciNfc_ReaderA_InfoUpdate(psHciContext,
                                    p_rdr_a_info->p_pipe_info->reg_index, 
                                    &pResponse[HCP_HEADER_LEN],
                                    (uint8_t)(length - HCP_HEADER_LEN));
#if 0
                    status = phHciNfc_ReaderMgmt_Update_Sequence(psHciContext, 
                                                                UPDATE_SEQ);
#endif
                    break;
                }
                case ANY_SET_PARAMETER:
                {
                    HCI_PRINT("Reader A Parameter Set \n");
                    status = phHciNfc_ReaderMgmt_Update_Sequence(psHciContext, 
                                                    UPDATE_SEQ);
                    p_rdr_a_info->next_seq = RDR_A_UID;
                    break;
                }
                case ANY_OPEN_PIPE:
                {
                    HCI_PRINT("Reader A open pipe complete\n");
                    status = phHciNfc_ReaderMgmt_Update_Sequence(psHciContext, 
                                                    UPDATE_SEQ);
                    p_rdr_a_info->next_seq = RDR_A_UID;
                    break;
                }
                case ANY_CLOSE_PIPE:
                {
                    HCI_PRINT("Reader A close pipe complete\n");
                    status = phHciNfc_ReaderMgmt_Update_Sequence(psHciContext, 
                                                    UPDATE_SEQ);
                    break;
                }
                case NXP_WRA_CONTINUE_ACTIVATION:
                case NXP_WR_ACTIVATE_ID:
                {
                    HCI_PRINT("Reader A continue activation or ");
                    HCI_PRINT("reactivation completed \n");
                    status = phHciNfc_ReaderMgmt_Update_Sequence(psHciContext, 
                                                    UPDATE_SEQ);
                    break;
                }
                case NXP_MIFARE_RAW:
                case NXP_MIFARE_CMD:
                {
                    if (length > HCP_HEADER_LEN)
                    {
                        HCI_PRINT("Mifare packet received \n");
                        /* Copy buffer to the receive buffer */
                        phHciNfc_Append_HCPFrame(psHciContext->recv_buffer, 
                            0, pResponse, length);
                        psHciContext->rx_total = length;
                        status = phHciNfc_Recv_Mifare_Packet(psHciContext, 
                                                prev_cmd, 
                                                &pResponse[HCP_HEADER_LEN],
                                                (length - HCP_HEADER_LEN));

                    } 
                    else if (length == HCP_HEADER_LEN)
                    {
                        psHciContext->rx_total = length;
                        psHciContext->rx_index = HCP_HEADER_LEN;

                    }
                    else
                    {
                        status = PHNFCSTVAL(CID_NFC_HCI, 
                                        NFCSTATUS_INVALID_HCI_RESPONSE);
                    }
                    break;
                }
                case WR_XCHGDATA:
                {
                    if (length >= HCP_HEADER_LEN)
                    {
                        uint8_t         i = 1;
                        HCI_PRINT("ISO 14443-4A received \n");
                        /* Copy buffer to the receive buffer */
                        phHciNfc_Append_HCPFrame(psHciContext->recv_buffer, 
                            0, pResponse, (length - i));
                        psHciContext->rx_total = (length - i);
                        status = phHciNfc_Recv_Iso_A_Packet(psHciContext, 
                                                    &pResponse[HCP_HEADER_LEN],
                                                    (length - HCP_HEADER_LEN));
                    } 
                    else
                    {
                        status = PHNFCSTVAL(CID_NFC_HCI, 
                                            NFCSTATUS_INVALID_HCI_RESPONSE);
                    }
                    break;
                }
                case NXP_WR_PRESCHECK:
                {
                    HCI_PRINT("Presence check completed \n");
                    break;
                }
                case NXP_WR_ACTIVATE_NEXT:
                {
                    if (length > HCP_HEADER_LEN)
                    {
                        if (RDR_A_MULTIPLE_TAGS_FOUND == pResponse[HCP_HEADER_LEN])
                        {
                            p_rdr_a_info->multiple_tgts_found = 
                                RDR_A_MULTIPLE_TAGS_FOUND;
                        }
                        else
                        {
                            p_rdr_a_info->multiple_tgts_found = FALSE;
                        }
                        HCI_PRINT("Activate next completed \n");
                    }
                    else
                    {
                        status = PHNFCSTVAL(CID_NFC_HCI, 
                                        NFCSTATUS_INVALID_HCI_RESPONSE);
                    }
                    break;
                }
                case NXP_WR_DISPATCH_TO_UICC:
                {
                    switch(length)
                    {
                        case HCP_HEADER_LEN:
                        {
                            /* Optional error code, if no error code field 
                                in the response, then this command is 
                                successfully completed */
                            p_rdr_a_info->uicc_activation = 
                                    UICC_CARD_ACTIVATION_SUCCESS;
                            break;
                        }
                        case (HCP_HEADER_LEN + 1):
                        {
                            p_rdr_a_info->uicc_activation = 
                                        pResponse[HCP_HEADER_LEN];
                            break;
                        } /* End of case (HCP_HEADER_LEN + index) */
                        default:
                        {                            
                            status = PHNFCSTVAL(CID_NFC_HCI, 
                                                NFCSTATUS_INVALID_HCI_RESPONSE);
                            break;
                        }
                    } /* End of switch(length) */
                    if (NFCSTATUS_SUCCESS == status)
                    {
                        status = phHciNfc_ReaderMgmt_Update_Sequence(psHciContext, 
                                                                    UPDATE_SEQ);
                    }
                    break;
                }
                default:
                {
                    status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_RESPONSE);
                    break;
                }
            } /* End of switch(prev_cmd) */
            if( NFCSTATUS_SUCCESS == status )
            {
                p_rdr_a_info->p_pipe_info->prev_status = NFCSTATUS_SUCCESS;
                p_rdr_a_info->current_seq = p_rdr_a_info->next_seq;
            }
        }
    }
    return status;
}

static
NFCSTATUS
phHciNfc_Recv_Iso_A_Packet(
                            phHciNfc_sContext_t *psHciContext,
                            uint8_t             *pResponse,
#ifdef ONE_BYTE_LEN
                            uint8_t             length
#else
                            uint16_t            length
#endif
                            )
{
    NFCSTATUS       status = NFCSTATUS_SUCCESS;
    uint8_t         i = 1;
    
    psHciContext->rx_index = HCP_HEADER_LEN;
    /* command WRA_XCHG_DATA: so give ISO 14443-4A data to the upper layer */
    if(FALSE != pResponse[(length - i)])
    {
        status = PHNFCSTVAL(CID_NFC_HCI, 
                            NFCSTATUS_RF_ERROR);
    }
    HCI_PRINT_BUFFER("ISO 14443- 4A Bytes received", pResponse, length);
    
    return status;
}

static
NFCSTATUS
phHciNfc_Recv_Mifare_Packet(
                           phHciNfc_sContext_t  *psHciContext,
                           uint8_t              cmd,
                           uint8_t              *pResponse,
#ifdef ONE_BYTE_LEN
                           uint8_t              length
#else
                           uint16_t             length
#endif
                           )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;

    /* To remove "warning (VS C4100) : unreferenced formal parameter" */
    PHNFC_UNUSED_VARIABLE(pResponse);
    PHNFC_UNUSED_VARIABLE(length);
    
    if (NXP_MIFARE_RAW == cmd)
    {
#ifdef ENABLE_MIFARE_RAW
        uint8_t                 index = 0;
#ifndef HAL_SW_3A_STATUS
        if(phHal_eISO14443_3A_PICC == psHciContext->p_target_info->RemDevType)
        {
            index++;
            psHciContext->rx_index = (index + HCP_HEADER_LEN);
            HCI_PRINT_BUFFER("Mifare Bytes received", &pResponse[index], (length - index));
        }
        else
#endif
        if (RDR_A_MIFARE_STATUS == pResponse[index])  /* Status byte */
        {
            index++;
            psHciContext->rx_index = (index + HCP_HEADER_LEN);
            HCI_PRINT_BUFFER("Mifare Bytes received", &pResponse[index], (length - index));
        }
        else
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                                NFCSTATUS_INVALID_HCI_RESPONSE);
        }
#else
        psHciContext->rx_index = HCP_HEADER_LEN;
        /* Give Mifare data to the upper layer */
        HCI_PRINT_BUFFER("Mifare Bytes received", pResponse, length);        
#endif /* #ifdef ENABLE_MIFARE_RAW */
    } 
    else
    {
        psHciContext->rx_index = HCP_HEADER_LEN;
        /* command NXP_MIFARE_CMD: so give Mifare data to the upper layer */
        HCI_PRINT_BUFFER("Mifare Bytes received", pResponse, length);
    }
    
    return status;
}

static
NFCSTATUS
phHciNfc_Recv_ReaderA_Event(
                             void               *psContext,
                             void               *pHwRef,
                             uint8_t            *pEvent,
#ifdef ONE_BYTE_LEN
                             uint8_t            length
#else
                             uint16_t           length
#endif
                       )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t         *psHciContext = 
                                (phHciNfc_sContext_t *)psContext ;

    HCI_PRINT ("HCI : phHciNfc_Recv_ReaderA_Event called...\n");
    if( (NULL == psHciContext) || (NULL == pHwRef) || (NULL == pEvent)
        || (length == 0))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_HCP_Packet_t       *p_packet = NULL;
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_HCP_Message_t      *message = NULL;
        uint8_t                     instruction=0, 
                                    i = 0;

        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                        psHciContext->p_reader_a_info ;
        p_packet = (phHciNfc_HCP_Packet_t *)pEvent;
        message = &p_packet->msg.message;
        /* Get the instruction bits from the Message Header */
        instruction = (uint8_t) GET_BITS8( message->msg_header,
            HCP_MSG_INSTRUCTION_OFFSET, HCP_MSG_INSTRUCTION_LEN);

        HCI_DEBUG ("HCI : instruction : %02X\n", instruction);
        HCI_DEBUG ("HCI : Multiple tag found : %02X\n", message->payload[i]);

        if ((EVT_TARGET_DISCOVERED == instruction) 
            && ((RDR_A_MULTIPLE_TAGS_FOUND == message->payload[i] ) 
                || (RDR_A_SINGLE_TAG_FOUND == message->payload[i])) 
          )
        {
            phNfc_sCompletionInfo_t pCompInfo;

            if (RDR_A_MULTIPLE_TAGS_FOUND == message->payload[i])
            {
                p_rdr_a_info->multiple_tgts_found = RDR_A_MULTIPLE_TAGS_FOUND;
                pCompInfo.status = NFCSTATUS_MULTIPLE_TAGS;
            }
            else
            {
                p_rdr_a_info->multiple_tgts_found = FALSE;
                pCompInfo.status = NFCSTATUS_SUCCESS;
            }
            
            psHciContext->host_rf_type = phHal_eISO14443_A_PCD;
            p_rdr_a_info->reader_a_info.RemDevType = phHal_eISO14443_A_PICC;
            p_rdr_a_info->current_seq = RDR_A_UID;

            HCI_DEBUG ("HCI : psHciContext->host_rf_type : %02X\n", psHciContext->host_rf_type);
            HCI_DEBUG ("HCI : p_rdr_a_info->reader_a_info.RemDevType : %02X\n", p_rdr_a_info->reader_a_info.RemDevType);
            HCI_DEBUG ("HCI : p_rdr_a_info->current_seq : %02X\n", p_rdr_a_info->current_seq);

            /* Notify to the HCI Generic layer To Update the FSM */
            phHciNfc_Notify_Event(psHciContext, pHwRef, 
                                    NFC_NOTIFY_TARGET_DISCOVERED, 
                                    &pCompInfo);

        }
        else
        {
            status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_RESPONSE);
        }
    }
    HCI_PRINT ("HCI : phHciNfc_Recv_ReaderA_Event end\n");
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Auto_Activate(
                               void         *psContext,
                               void         *pHwRef,
                               uint8_t      activate_enable
                               )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t         *psHciContext = 
                                (phHciNfc_sContext_t *)psContext ;
    if( (NULL == psHciContext) || (NULL == pHwRef))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_Pipe_Info_t        *p_pipe_info=NULL;
        uint8_t                     pipeid = 0;

        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                                psHciContext->p_reader_a_info ;
        p_pipe_info = p_rdr_a_info->p_pipe_info;
        p_pipe_info->reg_index = NXP_AUTO_ACTIVATION_INDEX;
        p_pipe_info->param_info = &activate_enable;
        p_pipe_info->param_length = sizeof(activate_enable);
        pipeid = p_rdr_a_info->pipe_id ;
        status = phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                pipeid, (uint8_t)ANY_SET_PARAMETER);
        if(NFCSTATUS_PENDING == status )
        {
            status = NFCSTATUS_SUCCESS;
        }
    }
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Set_DataRateMax(
                               void         *psContext,
                               void         *pHwRef,
                               uint8_t      data_rate_value
                               )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t         *psHciContext = 
        (phHciNfc_sContext_t *)psContext ;
    if( (NULL == psHciContext) || (NULL == pHwRef))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_Pipe_Info_t        *p_pipe_info=NULL;
        uint8_t                     pipeid = 0;

        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                            psHciContext->p_reader_a_info ;
        p_pipe_info = p_rdr_a_info->p_pipe_info;
        p_pipe_info->reg_index = RDR_A_DATA_RATE_MAX_INDEX;
        p_pipe_info->param_info = &data_rate_value;
        p_pipe_info->param_length = sizeof(data_rate_value);
        pipeid = p_rdr_a_info->pipe_id ;
        status = phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                                    pipeid, (uint8_t)ANY_SET_PARAMETER);
    }
    return status;
}


NFCSTATUS
phHciNfc_Send_ReaderA_Command(
                              phHciNfc_sContext_t   *psHciContext,
                              void                  *pHwRef,
                              uint8_t               pipe_id,
                              uint8_t               cmd
                              )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    
    if( (NULL == psHciContext) || (NULL == pHwRef) )
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate) || 
        (HCI_UNKNOWN_PIPE_ID == 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        pipe_id) || 
        (pipe_id != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        pipe_id))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_Pipe_Info_t        *p_pipe_info=NULL;
        phHciNfc_HCP_Packet_t       *hcp_packet = NULL;
        phHciNfc_HCP_Message_t      *hcp_message = NULL;
        uint8_t                     i = 0;
        uint16_t                    length = HCP_HEADER_LEN;
        
        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                            psHciContext->p_reader_a_info ;
        p_pipe_info = p_rdr_a_info->p_pipe_info;
        if(NULL == p_pipe_info )
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                        NFCSTATUS_INVALID_HCI_SEQUENCE);
        }
        else
        {
            psHciContext->tx_total = 0 ;
            hcp_packet = (phHciNfc_HCP_Packet_t *) psHciContext->send_buffer;
            /* Construct the HCP Frame */
            switch(cmd)
            {
                case NXP_WRA_CONTINUE_ACTIVATION:
                case NXP_WR_ACTIVATE_ID:
                {
                    phHciNfc_Build_HCPFrame(hcp_packet,HCP_CHAINBIT_DEFAULT,
                        (uint8_t) pipe_id, HCP_MSG_TYPE_COMMAND, cmd);
                    break;
                }

                case NXP_MIFARE_RAW:
                {
                    if (p_pipe_info->param_length < RDR_A_MIFARE_RAW_LENGTH) 
                    {
                        status = PHNFCSTVAL(CID_NFC_HCI, 
                                            NFCSTATUS_INVALID_PARAMETER);
                    }
                    else
                    {
                        /*  
                            Buffer shall be updated with 
                            TO -              Time out (1 byte)
                            Status -          b0 to b2 indicate valid bits (1 byte)
                            Data (with CRC) - params received from this function 
                        */
                        hcp_message = &(hcp_packet->msg.message);
#ifdef ENABLE_MIFARE_RAW
                        /* Time out */
                        hcp_message->payload[i++] = NXP_MIFARE_XCHG_TIMEOUT ;
                        /* Status */
                        hcp_message->payload[i++] = RDR_A_MIFARE_STATUS;
#else
                        cmd = NXP_MIFARE_CMD;
#endif /* #ifdef ENABLE_MIFARE_RAW */
                        phHciNfc_Build_HCPFrame(hcp_packet,HCP_CHAINBIT_DEFAULT,
                            (uint8_t) pipe_id, HCP_MSG_TYPE_COMMAND, cmd);

                        phHciNfc_Append_HCPFrame((uint8_t *)hcp_message->payload,
                            i, (uint8_t *)p_pipe_info->param_info,
#ifdef ENABLE_MIFARE_RAW
                            p_pipe_info->param_length);
#else
                            (p_pipe_info->param_length - 2));
#endif /* #ifdef ENABLE_MIFARE_RAW */

#ifdef ENABLE_MIFARE_RAW
                        length =(uint16_t)(length + i + p_pipe_info->param_length);
#else
                        length =(uint16_t)(length + i + p_pipe_info->param_length - 2);
#endif /* #ifdef ENABLE_MIFARE_RAW */
                    }
                    break;
                }
                case NXP_MIFARE_CMD:
                {
                    /* 
                        Buffer shall be updated with 
                        Cmd -               Authentication A/B, read/write 
                                            (1 byte)
                        Addr -              Address associated with Mifare cmd
                                            (1 byte)
                        Data  -             params received from this function 
                    */
                    phHciNfc_Build_HCPFrame(hcp_packet,HCP_CHAINBIT_DEFAULT,
                                (uint8_t) pipe_id, HCP_MSG_TYPE_COMMAND, cmd);
                    hcp_message = &(hcp_packet->msg.message);

                    /* Command */
                    hcp_message->payload[i++] = 
                                   psHciContext->p_xchg_info->params.tag_info.cmd_type ;
                     /* Address */
                    hcp_message->payload[i++] = 
                                    psHciContext->p_xchg_info->params.tag_info.addr ;
                    phHciNfc_Append_HCPFrame((uint8_t *)hcp_message->payload,
                        i, (uint8_t *)p_pipe_info->param_info,
                        p_pipe_info->param_length);
                    length =(uint16_t)(length + i + p_pipe_info->param_length);
                    break;
                }
                default:
                {
                    status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_COMMAND);
                    break;
                }
            }
            if (NFCSTATUS_SUCCESS == status)
            {
                p_pipe_info->sent_msg_type = (uint8_t)HCP_MSG_TYPE_COMMAND;
                p_pipe_info->prev_msg = cmd;
                psHciContext->tx_total = length;
                psHciContext->response_pending = TRUE;

                /* Send the Constructed HCP packet to the lower layer */
                status = phHciNfc_Send_HCP( psHciContext, pHwRef);
                p_pipe_info->prev_status = status;
            }
        }
    }
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Cont_Activate (
                              phHciNfc_sContext_t       *psHciContext,
                              void                      *pHwRef
                              )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    
    if( (NULL == psHciContext) || (NULL == pHwRef) )
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                                    psHciContext->p_reader_a_info;
        /* 
            NXP_WRA_CONTINUE_ACTIVATION:
            for activation command */
        status = phHciNfc_Send_ReaderA_Command(psHciContext, 
                        pHwRef, (uint8_t)p_rdr_a_info->pipe_id, 
                        (uint8_t)NXP_WRA_CONTINUE_ACTIVATION);
    }
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Update_Info(
                             phHciNfc_sContext_t        *psHciContext,
                             uint8_t                    infotype,
                             void                       *rdr_a_info
                             )
{
    NFCSTATUS                   status = NFCSTATUS_SUCCESS;
    
    if (NULL == psHciContext)
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if(NULL == psHciContext->p_reader_a_info)
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
                        psHciContext->p_reader_a_info ;

        switch(infotype)
        {
            case HCI_READER_A_ENABLE:
            {
                if(NULL != rdr_a_info)
                {
                    p_rdr_a_info->enable_rdr_a_gate = 
                                    *((uint8_t *)rdr_a_info);
                }
                break;
            }
            case HCI_READER_A_INFO_SEQ:
            {
                p_rdr_a_info->current_seq = RDR_A_UID;
                p_rdr_a_info->next_seq = RDR_A_UID;
                break;
            }           
            default:
            {
                status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
                break;
            }
        }
    }
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_App_Data (
                                void             *psHciHandle,
                                void             *pHwRef
                                )
{
    NFCSTATUS               status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t     *psHciContext = ((phHciNfc_sContext_t *)psHciHandle);
    if( (NULL == psHciContext) 
        || (NULL == pHwRef)
        )
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }   
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_Pipe_Info_t        *p_pipe_info=NULL;
        uint8_t                     pipeid = 0;

        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
            psHciContext->p_reader_a_info ;
        p_pipe_info = p_rdr_a_info->p_pipe_info;
        if(NULL == p_pipe_info )
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                NFCSTATUS_INVALID_HCI_SEQUENCE);
        }
        else
        {
            p_pipe_info->reg_index = RDR_A_APP_DATA_INDEX;
            pipeid = p_rdr_a_info->pipe_id ;
            /* Fill the data buffer and send the command to the 
            device */
            status = 
                phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                pipeid, (uint8_t)ANY_GET_PARAMETER);
        }
    }
    return status;
}

NFCSTATUS
phHciNfc_ReaderA_Fwi_Sfgt (
                           void             *psHciHandle,
                           void             *pHwRef
                           )
{
    NFCSTATUS               status = NFCSTATUS_SUCCESS;
    phHciNfc_sContext_t     *psHciContext = ((phHciNfc_sContext_t *)psHciHandle);
    if( (NULL == psHciContext) 
        || (NULL == pHwRef)
        )
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
    }
    else if((NULL == psHciContext->p_reader_a_info) || 
        (HCI_READER_A_ENABLE != 
        ((phHciNfc_ReaderA_Info_t *)(psHciContext->p_reader_a_info))->
        enable_rdr_a_gate))
    {
        status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
    }   
    else
    {
        phHciNfc_ReaderA_Info_t     *p_rdr_a_info=NULL;
        phHciNfc_Pipe_Info_t        *p_pipe_info=NULL;
        uint8_t                     pipeid = 0;

        p_rdr_a_info = (phHciNfc_ReaderA_Info_t *)
            psHciContext->p_reader_a_info ;
        p_pipe_info = p_rdr_a_info->p_pipe_info;
        if(NULL == p_pipe_info )
        {
            status = PHNFCSTVAL(CID_NFC_HCI, 
                NFCSTATUS_INVALID_HCI_SEQUENCE);
        }
        else
        {
            p_pipe_info->reg_index = RDR_A_FWI_SFGT_INDEX;
            pipeid = p_rdr_a_info->pipe_id ;
            /* Fill the data buffer and send the command to the 
            device */
            status = 
                phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef, 
                pipeid, (uint8_t)ANY_GET_PARAMETER);
        }
    }
    return status;
}