/*******************************************************************************
**
** Function         rw_t2t_process_timeout
**
** Description      handles timeout event
**
** Returns          none
**
*******************************************************************************/
void rw_t2t_process_timeout (TIMER_LIST_ENT *p_tle)
{
    tRW_READ_DATA       evt_data;
    tRW_T2T_CB          *p_t2t          = &rw_cb.tcb.t2t;

    if (p_t2t->state == RW_T2T_STATE_CHECK_PRESENCE)
    {
        if (p_t2t->check_tag_halt)
        {
            p_t2t->state = RW_T2T_STATE_HALT;
            rw_t2t_handle_presence_check_rsp (NFC_STATUS_REJECTED);
        }
        else
        {
            /* Move back to idle state */
            rw_t2t_handle_presence_check_rsp (NFC_STATUS_FAILED);
        }
        return;
    }

    if (p_t2t->substate == RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR)
    {
        p_t2t->sector   = p_t2t->select_sector;
        /* Here timeout is an acknowledgment for successfull sector change */
        if (p_t2t->state == RW_T2T_STATE_SELECT_SECTOR)
        {
            /* Notify that select sector op is successfull */
            rw_t2t_handle_op_complete ();
            evt_data.status = NFC_STATUS_OK;
            evt_data.p_data = NULL;
            (*rw_cb.p_cback) (RW_T2T_SELECT_CPLT_EVT, (tRW_DATA *) &evt_data);
        }
        else
        {
            /* Resume operation from where we stopped before sector change */
            rw_t2t_resume_op ();
        }
    }
    else if (p_t2t->state != RW_T2T_STATE_IDLE)
    {
#if (BT_TRACE_VERBOSE == TRUE)
        RW_TRACE_ERROR1 ("T2T timeout. state=%s ", rw_t2t_get_state_name (p_t2t->state));
#else
        RW_TRACE_ERROR1 ("T2T timeout. state=0x%02X ", p_t2t->state);
#endif
        /* Handle timeout error as no response to the command sent */
        rw_t2t_process_error ();
    }
}
/*******************************************************************************
**
** Function         RW_T1tReadSeg
**
** Description      This function sends a RSEG command for Reader/Writer mode.
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS RW_T1tReadSeg (UINT8 segment)
{
    tNFC_STATUS status  = NFC_STATUS_FAILED;
    tRW_T1T_CB  *p_t1t  = &rw_cb.tcb.t1t;
    UINT8       adds;

    if (p_t1t->state != RW_T1T_STATE_IDLE)
    {
        RW_TRACE_WARNING1 ("RW_T1tReadSeg - Busy - State: %u", p_t1t->state);
        return (NFC_STATUS_BUSY);
    }
    if (segment >=  T1T_MAX_SEGMENTS)
    {
        RW_TRACE_ERROR1 ("RW_T1tReadSeg - Invalid Segment: %u", segment);
        return (NFC_STATUS_REFUSED);
    }
    if (rw_cb.tcb.t1t.hr[0] != T1T_STATIC_HR0)
    {
        /* send RSEG command */
        RW_T1T_BLD_ADDS ((adds), (segment));
        if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_RSEG, adds, NULL)) == NFC_STATUS_OK)
        {
            p_t1t->state = RW_T1T_STATE_READ;
        }
    }
    return status;
}
/*******************************************************************************
**
** Function         RW_T2tSectorSelect
**
** Description      This function issues the Type 2 Tag SECTOR-SELECT command
**                  packet 1. If a NACK is received as the response, the callback
**                  function will be called with a RW_T2T_SECTOR_SELECT_EVT. If
**                  an ACK is received as the response, the command packet 2 with
**                  the given sector number is sent to the peer device. When the
**                  response for packet 2 is received, the callback function will
**                  be called with a RW_T2T_SECTOR_SELECT_EVT.
**
**                  A sector is 256 contiguous blocks (1024 bytes).
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS RW_T2tSectorSelect (UINT8 sector)
{
    tNFC_STATUS status;
    tRW_T2T_CB  *p_t2t       = &rw_cb.tcb.t2t;
    UINT8       sector_byte2[1];

    if (p_t2t->state != RW_T2T_STATE_IDLE)
    {
        RW_TRACE_ERROR1 ("Error: Type 2 tag not activated or Busy - State: %u", p_t2t->state);
        return (NFC_STATUS_FAILED);
    }

    if (sector >= T2T_MAX_SECTOR)
    {
        RW_TRACE_ERROR2 ("RW_T2tSectorSelect - Invalid sector: %u, T2 Max supported sector value: %u", sector, T2T_MAX_SECTOR - 1);
        return (NFC_STATUS_FAILED);
    }

    sector_byte2[0] = 0xFF;

    if ((status = rw_t2t_send_cmd (T2T_CMD_SEC_SEL, sector_byte2)) == NFC_STATUS_OK)
    {
        p_t2t->state         = RW_T2T_STATE_SELECT_SECTOR;
        p_t2t->select_sector = sector;
        p_t2t->substate      = RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR_SUPPORT;

        RW_TRACE_EVENT0 ("RW_T2tSectorSelect Sent Sector select first command");
    }

    return status;
}
Beispiel #4
0
/*******************************************************************************
**
** Function         RW_T4tReadNDef
**
** Description      This function performs NDEF read procedure
**                  Note: RW_T4tDetectNDef () must be called before using this
**
**                  The following event will be returned
**                      RW_T4T_NDEF_READ_EVT for each segmented NDEF message
**                      RW_T4T_NDEF_READ_CPLT_EVT for the last segment or complete NDEF
**                      RW_T4T_NDEF_READ_FAIL_EVT for failure
**
** Returns          NFC_STATUS_OK if success
**                  NFC_STATUS_FAILED if T4T is busy or other error
**
*******************************************************************************/
tNFC_STATUS RW_T4tReadNDef (void)
{
    RW_TRACE_API0 ("RW_T4tReadNDef ()");

    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
    {
        RW_TRACE_ERROR1 ("RW_T4tReadNDef ():Unable to start command at state (0x%X)",
                          rw_cb.tcb.t4t.state);
        return NFC_STATUS_FAILED;
    }

    /* if NDEF has been detected */
    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
    {
        /* start reading NDEF */
        if (!rw_t4t_read_file (T4T_FILE_LENGTH_SIZE, rw_cb.tcb.t4t.ndef_length, FALSE))
        {
            return NFC_STATUS_FAILED;
        }

        rw_cb.tcb.t4t.state     = RW_T4T_STATE_READ_NDEF;
        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_READ_RESP;

        return NFC_STATUS_OK;
    }
    else
    {
        RW_TRACE_ERROR0 ("RW_T4tReadNDef ():No NDEF detected");
        return NFC_STATUS_FAILED;
    }
}
Beispiel #5
0
/*******************************************************************************
**
** Function         RW_T4tDetectNDef
**
** Description      This function performs NDEF detection procedure
**
**                  RW_T4T_NDEF_DETECT_EVT will be returned
**
** Returns          NFC_STATUS_OK if success
**                  NFC_STATUS_FAILED if T4T is busy or other error
**
*******************************************************************************/
tNFC_STATUS RW_T4tDetectNDef (void)
{
    RW_TRACE_API0 ("RW_T4tDetectNDef ()");

    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
    {
        RW_TRACE_ERROR1 ("RW_T4tDetectNDef ():Unable to start command at state (0x%X)",
                          rw_cb.tcb.t4t.state);
        return NFC_STATUS_FAILED;
    }

    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
    {
        /* NDEF Tag application has been selected then select CC file */
        if (!rw_t4t_select_file (T4T_CC_FILE_ID))
        {
            return NFC_STATUS_FAILED;
        }
        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
    }
    else
    {
        /* Select NDEF Tag Application */
        if (!rw_t4t_select_application (rw_cb.tcb.t4t.version))
        {
            return NFC_STATUS_FAILED;
        }
        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_APP;
    }

    rw_cb.tcb.t4t.state     = RW_T4T_STATE_DETECT_NDEF;

    return NFC_STATUS_OK;
}
Beispiel #6
0
/*******************************************************************************
**
** Function         RW_T4tUpdateNDef
**
** Description      This function performs NDEF update procedure
**                  Note: RW_T4tDetectNDef () must be called before using this
**                        Updating data must not be removed until returning event
**
**                  The following event will be returned
**                      RW_T4T_NDEF_UPDATE_CPLT_EVT for complete
**                      RW_T4T_NDEF_UPDATE_FAIL_EVT for failure
**
** Returns          NFC_STATUS_OK if success
**                  NFC_STATUS_FAILED if T4T is busy or other error
**
*******************************************************************************/
tNFC_STATUS RW_T4tUpdateNDef (UINT16 length, UINT8 *p_data)
{
    RW_TRACE_API1 ("RW_T4tUpdateNDef () length:%d", length);

    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
    {
        RW_TRACE_ERROR1 ("RW_T4tUpdateNDef ():Unable to start command at state (0x%X)",
                          rw_cb.tcb.t4t.state);
        return NFC_STATUS_FAILED;
    }

    /* if NDEF has been detected */
    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
    {
        /* if read-only */
        if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY)
        {
            RW_TRACE_ERROR0 ("RW_T4tUpdateNDef ():NDEF is read-only");
            return NFC_STATUS_FAILED;
        }

        if (rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size < length + T4T_FILE_LENGTH_SIZE)
        {
            RW_TRACE_ERROR2 ("RW_T4tUpdateNDef ():data (%d bytes) plus NLEN is more than max file size (%d)",
                              length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
            return NFC_STATUS_FAILED;
        }

        /* store NDEF length and data */
        rw_cb.tcb.t4t.ndef_length   = length;
        rw_cb.tcb.t4t.p_update_data = p_data;

        rw_cb.tcb.t4t.rw_offset     = T4T_FILE_LENGTH_SIZE;
        rw_cb.tcb.t4t.rw_length     = length;

        /* set NLEN to 0x0000 for the first step */
        if (!rw_t4t_update_nlen (0x0000))
        {
            return NFC_STATUS_FAILED;
        }

        rw_cb.tcb.t4t.state     = RW_T4T_STATE_UPDATE_NDEF;
        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;

        return NFC_STATUS_OK;
    }
    else
    {
        RW_TRACE_ERROR0 ("RW_T4tUpdateNDef ():No NDEF detected");
        return NFC_STATUS_FAILED;
    }
}
Beispiel #7
0
/*******************************************************************************
**
** Function         rw_t4t_process_timeout
**
** Description      process timeout event
**
** Returns          none
**
*******************************************************************************/
void rw_t4t_process_timeout (TIMER_LIST_ENT *p_tle)
{
    RW_TRACE_DEBUG1 ("rw_t4t_process_timeout () event=%d", p_tle->event);

    if (p_tle->event == NFC_TTYPE_RW_T4T_RESPONSE)
    {
        rw_t4t_handle_error (NFC_STATUS_TIMEOUT, 0, 0);
    }
    else
    {
        RW_TRACE_ERROR1 ("rw_t4t_process_timeout () unknown event=%d", p_tle->event);
    }
}
/*******************************************************************************
**
** Function         RW_T2tRead
**
** Description      This function issues the Type 2 Tag READ command. When the
**                  operation is complete the callback function will be called
**                  with a RW_T2T_READ_EVT.
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS RW_T2tRead (UINT16 block)
{
    tRW_T2T_CB  *p_t2t = &rw_cb.tcb.t2t;
    tNFC_STATUS status;

    if (p_t2t->state != RW_T2T_STATE_IDLE)
    {
        RW_TRACE_ERROR1 ("Error: Type 2 tag not activated or Busy - State: %u", p_t2t->state);
        return (NFC_STATUS_FAILED);
    }

    if ((status = rw_t2t_read (block)) == NFC_STATUS_OK)
    {
        p_t2t->state    = RW_T2T_STATE_READ;
        RW_TRACE_EVENT0 ("RW_T2tRead Sent Read command");
    }

    return status;

}
/*******************************************************************************
**
** Function         rw_t2t_sector_change
**
** Description      This function issues Type 2 Tag SECTOR-SELECT command
**                  packet 1.
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS rw_t2t_sector_change (UINT8 sector)
{
    tNFC_STATUS status;
    BT_HDR      *p_data;
    UINT8       *p;
    tRW_T2T_CB  *p_t2t = &rw_cb.tcb.t2t;

    if ((p_data = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID)) == NULL)
    {
        RW_TRACE_ERROR0 ("rw_t2t_sector_change - No buffer");
         return (NFC_STATUS_NO_BUFFERS);
    }

    p_data->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
    p = (UINT8 *) (p_data + 1) + p_data->offset;

    UINT8_TO_BE_STREAM (p, sector);
    UINT8_TO_BE_STREAM (p, 0x00);
    UINT8_TO_BE_STREAM (p, 0x00);
    UINT8_TO_BE_STREAM (p, 0x00);

    p_data->len = 4;

    if ((status = NFC_SendData (NFC_RF_CONN_ID , p_data)) == NFC_STATUS_OK)
    {
        /* Passive rsp command and suppose not to get response to this command */
        p_t2t->p_cmd_rsp_info = NULL;
        p_t2t->substate       = RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR;

        RW_TRACE_EVENT0 ("rw_t2t_sector_change Sent Second Command");
        nfc_start_quick_timer (&p_t2t->t2_timer, NFC_TTYPE_RW_T2T_RESPONSE,
                               (RW_T2T_SEC_SEL_TOUT_RESP * QUICK_TIMER_TICKS_PER_SEC) / 1000);
    }
    else
    {
        RW_TRACE_ERROR1 ("rw_t2t_sector_change Send failed at rw_t2t_send_cmd, error: %u", status);
    }

    return status;
}
/*******************************************************************************
**
** Function         RW_T2tWrite
**
** Description      This function issues the Type 2 Tag WRITE command. When the
**                  operation is complete the callback function will be called
**                  with a RW_T2T_WRITE_EVT.
**
**                  p_new_bytes points to the array of 4 bytes to be written
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS RW_T2tWrite (UINT16 block, UINT8 *p_write_data)
{
    tRW_T2T_CB  *p_t2t = &rw_cb.tcb.t2t;
    tNFC_STATUS status;

    if (p_t2t->state != RW_T2T_STATE_IDLE)
    {
        RW_TRACE_ERROR1 ("Error: Type 2 tag not activated or Busy - State: %u", p_t2t->state);
        return (NFC_STATUS_FAILED);
    }

    if ((status = rw_t2t_write (block, p_write_data)) == NFC_STATUS_OK)
    {
        p_t2t->state    = RW_T2T_STATE_WRITE;
        if (block < T2T_FIRST_DATA_BLOCK)
            p_t2t->b_read_hdr = FALSE;
        else if (block < (T2T_FIRST_DATA_BLOCK + T2T_READ_BLOCKS))
            p_t2t->b_read_data = FALSE;
        RW_TRACE_EVENT0 ("RW_T2tWrite Sent Write command");
    }

    return status;
}
/*******************************************************************************
**
** Function         rw_t2t_proc_data
**
** Description      This function handles data evt received from NFC Controller.
**
** Returns          none
**
*******************************************************************************/
static void rw_t2t_proc_data (UINT8 conn_id, tNFC_DATA_CEVT *p_data)
{
    tRW_EVENT               rw_event    = RW_RAW_FRAME_EVT;
    tRW_T2T_CB              *p_t2t      = &rw_cb.tcb.t2t;
    BT_HDR                  *p_pkt      = p_data->p_data;
    BOOLEAN                 b_notify    = TRUE;
    BOOLEAN                 b_release   = TRUE;
    UINT8                   *p;
    tRW_READ_DATA           evt_data = {0};
    tT2T_CMD_RSP_INFO       *p_cmd_rsp_info = (tT2T_CMD_RSP_INFO *) rw_cb.tcb.t2t.p_cmd_rsp_info;
    tRW_DETECT_NDEF_DATA    ndef_data;
#if (BT_TRACE_VERBOSE == TRUE)
    UINT8                   begin_state     = p_t2t->state;
#endif

    if (  (p_t2t->state == RW_T2T_STATE_IDLE)
        ||(p_cmd_rsp_info == NULL)  )
    {

#if (BT_TRACE_VERBOSE == TRUE)
        RW_TRACE_DEBUG2 ("RW T2T Raw Frame: Len [0x%X] Status [%s]", p_pkt->len, NFC_GetStatusName (p_data->status));
#else
        RW_TRACE_DEBUG2 ("RW T2T Raw Frame: Len [0x%X] Status [0x%X]", p_pkt->len, p_data->status);
#endif
        evt_data.status = p_data->status;
        evt_data.p_data = p_pkt;
        (*rw_cb.p_cback) (RW_T2T_RAW_FRAME_EVT, (tRW_DATA *)&evt_data);
        return;
    }
#if (defined (RW_STATS_INCLUDED) && (RW_STATS_INCLUDED == TRUE))
    /* Update rx stats */
    rw_main_update_rx_stats (p_pkt->len);
#endif
    /* Stop timer as response is received */
    nfc_stop_quick_timer (&p_t2t->t2_timer);

    RW_TRACE_EVENT2 ("RW RECV [%s]:0x%x RSP", t2t_info_to_str (p_cmd_rsp_info), p_cmd_rsp_info->opcode);

    if (  (  (p_pkt->len != p_cmd_rsp_info->rsp_len)
           &&(p_pkt->len != p_cmd_rsp_info->nack_rsp_len)
           &&(p_t2t->substate != RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR)  )
        ||(p_t2t->state == RW_T2T_STATE_HALT)  )
    {
#if (BT_TRACE_VERBOSE == TRUE)
        RW_TRACE_ERROR1 ("T2T Frame error. state=%s ", rw_t2t_get_state_name (p_t2t->state));
#else
        RW_TRACE_ERROR1 ("T2T Frame error. state=0x%02X command=0x%02X ", p_t2t->state);
#endif
        if (p_t2t->state != RW_T2T_STATE_HALT)
        {
            /* Retrasmit the last sent command if retry-count < max retry */
            rw_t2t_process_frame_error ();
            p_t2t->check_tag_halt = FALSE;
        }
        GKI_freebuf (p_pkt);
        return;
    }
    rw_cb.cur_retry = 0;

    /* Assume the data is just the response byte sequence */
    p = (UINT8 *) (p_pkt + 1) + p_pkt->offset;


    RW_TRACE_EVENT4 ("rw_t2t_proc_data State: %u  conn_id: %u  len: %u  data[0]: 0x%02x",
                      p_t2t->state, conn_id, p_pkt->len, *p);

    evt_data.p_data     = NULL;

    if (p_t2t->substate == RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR_SUPPORT)
    {
        /* The select process happens in two steps */
        if ((*p & 0x0f) == T2T_RSP_ACK)
        {
            if (rw_t2t_sector_change (p_t2t->select_sector) == NFC_STATUS_OK)
                b_notify = FALSE;
            else
                evt_data.status = NFC_STATUS_FAILED;
        }
        else
        {
            RW_TRACE_EVENT1 ("rw_t2t_proc_data - Received NACK response(0x%x) to SEC-SELCT CMD", (*p & 0x0f));
            evt_data.status = NFC_STATUS_REJECTED;
        }
    }
    else if (p_t2t->substate == RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR)
    {
        evt_data.status = NFC_STATUS_FAILED;
    }
    else if (  (p_pkt->len != p_cmd_rsp_info->rsp_len)
             ||((p_cmd_rsp_info->opcode == T2T_CMD_WRITE) && ((*p & 0x0f) != T2T_RSP_ACK))  )
    {
        /* Received NACK response */
        evt_data.p_data = p_pkt;
        if (p_t2t->state == RW_T2T_STATE_READ)
            b_release = FALSE;

        RW_TRACE_EVENT1 ("rw_t2t_proc_data - Received NACK response(0x%x)", (*p & 0x0f));

        if (!p_t2t->check_tag_halt)
        {
            /* Just received first NACK. Retry just one time to find if tag went in to HALT State */
            b_notify =  FALSE;
            rw_t2t_process_error ();
            /* Assume Tag is in HALT State, untill we get response to retry command */
            p_t2t->check_tag_halt = TRUE;
        }
        else
        {
            p_t2t->check_tag_halt = FALSE;
            /* Got consecutive NACK so tag not really halt after first NACK, but current operation failed */
            evt_data.status = NFC_STATUS_FAILED;
        }
    }
    else
    {
        /* If the response length indicates positive response or cannot be known from length then assume success */
        evt_data.status  = NFC_STATUS_OK;
        p_t2t->check_tag_halt = FALSE;

        /* The response data depends on what the current operation was */
        switch (p_t2t->state)
        {
        case RW_T2T_STATE_CHECK_PRESENCE:
            b_notify = FALSE;
            rw_t2t_handle_presence_check_rsp (NFC_STATUS_OK);
            break;

        case RW_T2T_STATE_READ:
            evt_data.p_data = p_pkt;
            b_release = FALSE;
            if (p_t2t->block_read == 0)
            {
                p_t2t->b_read_hdr = TRUE;
                memcpy (p_t2t->tag_hdr,  p, T2T_READ_DATA_LEN);
#if(NFC_NXP_NOT_OPEN_INCLUDED == TRUE)
                /* On Ultralight - C tag, if CC is corrupt, correct it */
                if (  (p_t2t->tag_hdr[0] == TAG_MIFARE_MID)
                    &&(p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] >= T2T_INVALID_CC_TMS_VAL0)
                    &&(p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] <= T2T_INVALID_CC_TMS_VAL1)  )
                {
                    p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] = T2T_CC2_TMS_MULC;
                }
#endif
            }
            break;

        case RW_T2T_STATE_WRITE:
            /* Write operation completed successfully */
            break;

        default:
            /* NDEF/other Tlv Operation/Format-Tag/Config Tag as Read only */
            b_notify = FALSE;
            rw_t2t_handle_rsp (p);
            break;
        }
    }

    if (b_notify)
    {
        rw_event = rw_t2t_info_to_event (p_cmd_rsp_info);

        if (rw_event == RW_T2T_NDEF_DETECT_EVT)
        {
            ndef_data.status    = evt_data.status;
            ndef_data.protocol  = NFC_PROTOCOL_T2T;
            ndef_data.flags     = RW_NDEF_FL_UNKNOWN;
            if (p_t2t->substate == RW_T2T_SUBSTATE_WAIT_READ_LOCKS)
                ndef_data.flags = RW_NDEF_FL_FORMATED;
            ndef_data.max_size  = 0;
            ndef_data.cur_size  = 0;
            /* Move back to idle state */
            rw_t2t_handle_op_complete ();
            (*rw_cb.p_cback) (rw_event, (tRW_DATA *) &ndef_data);
        }
        else
        {
            /* Move back to idle state */
            rw_t2t_handle_op_complete ();
            (*rw_cb.p_cback) (rw_event, (tRW_DATA *) &evt_data);
        }
    }

    if (b_release)
        GKI_freebuf (p_pkt);

#if (BT_TRACE_VERBOSE == TRUE)
    if (begin_state != p_t2t->state)
    {
        RW_TRACE_DEBUG2 ("RW T2T state changed:<%s> -> <%s>",
                          rw_t2t_get_state_name (begin_state),
                          rw_t2t_get_state_name (p_t2t->state));
    }
#endif
}
Beispiel #12
0
/*******************************************************************************
**
** Function         rw_t4t_sm_update_ndef
**
** Description      State machine for NDEF update procedure
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_sm_update_ndef (BT_HDR  *p_r_apdu)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
    UINT8       *p;
    UINT16      status_words;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("rw_t4t_sm_update_ndef (): sub_state:%s (%d)",
                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
#else
    RW_TRACE_DEBUG1 ("rw_t4t_sm_update_ndef (): sub_state=%d", p_t4t->sub_state);
#endif

    /* Get status words */
    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
    BE_STREAM_TO_UINT16 (status_words, p);

    if (status_words != T4T_RSP_CMD_CMPLTED)
    {
        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
        return;
    }

    switch (p_t4t->sub_state)
    {
    case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN:

        /* NLEN has been updated */
        /* if need to update data */
        if (p_t4t->p_update_data)
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_RESP;

            if (!rw_t4t_update_file ())
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                p_t4t->p_update_data = NULL;
            }
        }
        else
        {
            p_t4t->state = RW_T4T_STATE_IDLE;

            /* just finished last step of updating (updating NLEN) */
            if (rw_cb.p_cback)
            {
                rw_data.status = NFC_STATUS_OK;

                (*(rw_cb.p_cback)) (RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data);
                RW_TRACE_DEBUG0 ("rw_t4t_sm_update_ndef (): Sent RW_T4T_NDEF_UPDATE_CPLT_EVT");
            }
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP:

        /* if updating is not completed */
        if (p_t4t->rw_length > 0)
        {
            if (!rw_t4t_update_file ())
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                p_t4t->p_update_data = NULL;
            }
        }
        else
        {
            p_t4t->p_update_data = NULL;

            /* update NLEN as last step of updating file */
            if (!rw_t4t_update_nlen (p_t4t->ndef_length))
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
            }
            else
            {
                p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;
            }
        }
        break;

    default:
        RW_TRACE_ERROR1 ("rw_t4t_sm_update_ndef (): unknown sub_state = %d", p_t4t->sub_state);
        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        break;
    }
}
Beispiel #13
0
/*******************************************************************************
**
** Function         rw_t4t_sm_read_ndef
**
** Description      State machine for NDEF read procedure
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
    UINT8       *p;
    UINT16      status_words;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("rw_t4t_sm_read_ndef (): sub_state:%s (%d)",
                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
#else
    RW_TRACE_DEBUG1 ("rw_t4t_sm_read_ndef (): sub_state=%d", p_t4t->sub_state);
#endif

    /* get status words */
    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
    BE_STREAM_TO_UINT16 (status_words, p);

    if (status_words != T4T_RSP_CMD_CMPLTED)
    {
        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
        GKI_freebuf (p_r_apdu);
        return;
    }

    switch (p_t4t->sub_state)
    {
    case RW_T4T_SUBSTATE_WAIT_READ_RESP:

        /* Read partial or complete data */
        p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE;

        if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length))
        {
            p_t4t->rw_length -= p_r_apdu->len;
            p_t4t->rw_offset += p_r_apdu->len;

            if (rw_cb.p_cback)
            {
                rw_data.data.status = NFC_STATUS_OK;
                rw_data.data.p_data = p_r_apdu;

                /* if need to read more data */
                if (p_t4t->rw_length > 0)
                {
                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_EVT, &rw_data);

                    if (!rw_t4t_read_file (p_t4t->rw_offset, p_t4t->rw_length, TRUE))
                    {
                        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                    }
                }
                else
                {
                    p_t4t->state = RW_T4T_STATE_IDLE;

                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);

                    RW_TRACE_DEBUG0 ("rw_t4t_sm_read_ndef (): Sent RW_T4T_NDEF_READ_CPLT_EVT");

                }

                p_r_apdu = NULL;
            }
            else
            {
                p_t4t->rw_length = 0;
                p_t4t->state = RW_T4T_STATE_IDLE;
            }
        }
        else
        {
            RW_TRACE_ERROR2 ("rw_t4t_sm_read_ndef (): invalid payload length (%d), rw_length (%d)",
                             p_r_apdu->len, p_t4t->rw_length);
            rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
        }
        break;

    default:
        RW_TRACE_ERROR1 ("rw_t4t_sm_read_ndef (): unknown sub_state = %d", p_t4t->sub_state);
        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        break;
    }

    if (p_r_apdu)
        GKI_freebuf (p_r_apdu);
}
Beispiel #14
0
/*******************************************************************************
**
** Function         rw_t4t_sm_detect_ndef
**
** Description      State machine for NDEF detection procedure
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
    UINT8       *p, type, length;
    UINT16      status_words, nlen;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("rw_t4t_sm_detect_ndef (): sub_state:%s (%d)",
                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
#else
    RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): sub_state=%d", p_t4t->sub_state);
#endif

    /* get status words */
    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
    BE_STREAM_TO_UINT16 (status_words, p);

    if (status_words != T4T_RSP_CMD_CMPLTED)
    {
        /* try V1.0 after failing of V2.0 */
        if (  (p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP)
            &&(p_t4t->version   == T4T_VERSION_2_0)  )
        {
            p_t4t->version = T4T_VERSION_1_0;

            RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): retry with version=0x%02X",
                              p_t4t->version);

            if (!rw_t4t_select_application (T4T_VERSION_1_0))
            {
                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
            }
            return;
        }

        p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
        return;
    }

    switch (p_t4t->sub_state)
    {
    case RW_T4T_SUBSTATE_WAIT_SELECT_APP:

        /* NDEF Tag application has been selected then select CC file */
        if (!rw_t4t_select_file (T4T_CC_FILE_ID))
        {
            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        }
        else
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_SELECT_CC:

        /* CC file has been selected then read mandatory part of CC file */
        if (!rw_t4t_read_file (0x00, T4T_CC_FILE_MIN_LEN, FALSE))
        {
            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        }
        else
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE;
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_CC_FILE:

        /* CC file has been read then validate and select mandatory NDEF file */
        if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE)
        {
            p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;

            BE_STREAM_TO_UINT16 (p_t4t->cc_file.cclen, p);
            BE_STREAM_TO_UINT8 (p_t4t->cc_file.version, p);
            BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_le, p);
            BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_lc, p);

            BE_STREAM_TO_UINT8 (type, p);
            BE_STREAM_TO_UINT8 (length, p);

            if (  (type == T4T_NDEF_FILE_CONTROL_TYPE)
                &&(length == T4T_FILE_CONTROL_LENGTH)  )
            {
                BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.file_id, p);
                BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.max_file_size, p);
                BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.read_access, p);
                BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.write_access, p);

#if (BT_TRACE_VERBOSE == TRUE)
                RW_TRACE_DEBUG0 ("Capability Container (CC) file");
                RW_TRACE_DEBUG1 ("  CCLEN:  0x%04X",    p_t4t->cc_file.cclen);
                RW_TRACE_DEBUG1 ("  Version:0x%02X",    p_t4t->cc_file.version);
                RW_TRACE_DEBUG1 ("  MaxLe:  0x%04X",    p_t4t->cc_file.max_le);
                RW_TRACE_DEBUG1 ("  MaxLc:  0x%04X",    p_t4t->cc_file.max_lc);
                RW_TRACE_DEBUG0 ("  NDEF File Control TLV");
                RW_TRACE_DEBUG1 ("    FileID:      0x%04X", p_t4t->cc_file.ndef_fc.file_id);
                RW_TRACE_DEBUG1 ("    MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size);
                RW_TRACE_DEBUG1 ("    ReadAccess:  0x%02X", p_t4t->cc_file.ndef_fc.read_access);
                RW_TRACE_DEBUG1 ("    WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access);
#endif

                if (rw_t4t_validate_cc_file ())
                {
                    if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id))
                    {
                        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
                    }
                    else
                    {
                        p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
                    }
                    break;
                }
            }
        }

        /* invalid response or CC file */
        p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
        rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
        break;

    case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:

        /* NDEF file has been selected then read the first 2 bytes (NLEN) */
        if (!rw_t4t_read_file (0, T4T_FILE_LENGTH_SIZE, FALSE))
        {
            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        }
        else
        {
            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN;
        }
        break;

    case RW_T4T_SUBSTATE_WAIT_READ_NLEN:

        /* NLEN has been read then report upper layer */
        if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE)
        {
            /* get length of NDEF */
            p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
            BE_STREAM_TO_UINT16 (nlen, p);

            if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE)
            {
                p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED;

                if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
                {
                    p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
                }

                /* Get max bytes to read per command */
                if (p_t4t->cc_file.max_le >= RW_T4T_MAX_DATA_PER_READ)
                {
                    p_t4t->max_read_size = RW_T4T_MAX_DATA_PER_READ;
                }
                else
                {
                    p_t4t->max_read_size = p_t4t->cc_file.max_le;
                }

                /* Le: valid range is 0x01 to 0xFF */
                if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE)
                {
                    p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
                }

                /* Get max bytes to update per command */
                if (p_t4t->cc_file.max_lc >= RW_T4T_MAX_DATA_PER_WRITE)
                {
                    p_t4t->max_update_size = RW_T4T_MAX_DATA_PER_WRITE;
                }
                else
                {
                    p_t4t->max_update_size = p_t4t->cc_file.max_lc;
                }

                /* Lc: valid range is 0x01 to 0xFF */
                if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC)
                {
                    p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
                }

                p_t4t->ndef_length = nlen;
                p_t4t->state       = RW_T4T_STATE_IDLE;

                if (rw_cb.p_cback)
                {
                    rw_data.ndef.status   = NFC_STATUS_OK;
                    rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP;
                    rw_data.ndef.max_size = (UINT32) (p_t4t->cc_file.ndef_fc.max_file_size - (UINT16) T4T_FILE_LENGTH_SIZE);
                    rw_data.ndef.cur_size = nlen;
                    rw_data.ndef.flags    = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED;
                    if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
                    {
                        rw_data.ndef.flags    |= RW_NDEF_FL_READ_ONLY;
                    }

                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_DETECT_EVT, &rw_data);

                    RW_TRACE_DEBUG0 ("rw_t4t_sm_detect_ndef (): Sent RW_T4T_NDEF_DETECT_EVT");
                }
            }
            else
            {
                /* NLEN should be less than max file size */
                RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): NLEN (%d) + 2 must be <= max file size (%d)",
                                 nlen, p_t4t->cc_file.ndef_fc.max_file_size);

                p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
                rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
            }
        }
        else
        {
            /* response payload size should be T4T_FILE_LENGTH_SIZE */
            RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): Length (%d) of R-APDU must be %d",
                             p_r_apdu->len, T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE);

            p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
            rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
        }
        break;

    default:
        RW_TRACE_ERROR1 ("rw_t4t_sm_detect_ndef (): unknown sub_state=%d", p_t4t->sub_state);
        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
        break;
    }
}
Beispiel #15
0
/*******************************************************************************
**
** Function         rw_t4t_validate_cc_file
**
** Description      Validate CC file and mandatory NDEF TLV
**
** Returns          TRUE if success
**
*******************************************************************************/
static BOOLEAN rw_t4t_validate_cc_file (void)
{
    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;

    RW_TRACE_DEBUG0 ("rw_t4t_validate_cc_file ()");

    if (p_t4t->cc_file.cclen < T4T_CC_FILE_MIN_LEN)
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): CCLEN (%d) is too short",
                         p_t4t->cc_file.cclen);
        return FALSE;
    }

    if (T4T_GET_MAJOR_VERSION (p_t4t->cc_file.version) != T4T_GET_MAJOR_VERSION (p_t4t->version))
    {
        RW_TRACE_ERROR2 ("rw_t4t_validate_cc_file (): Peer version (0x%02X) is matched to ours (0x%02X)",
                         p_t4t->cc_file.version, p_t4t->version);
        return FALSE;
    }

    if (p_t4t->cc_file.max_le < 0x000F)
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): MaxLe (%d) is too small",
                         p_t4t->cc_file.max_le);
        return FALSE;
    }

    if (p_t4t->cc_file.max_lc < 0x0001)
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): MaxLc (%d) is too small",
                         p_t4t->cc_file.max_lc);
        return FALSE;
    }

    if (  (p_t4t->cc_file.ndef_fc.file_id == T4T_CC_FILE_ID)
        ||(p_t4t->cc_file.ndef_fc.file_id == 0xE102)
        ||(p_t4t->cc_file.ndef_fc.file_id == 0xE103)
        ||((p_t4t->cc_file.ndef_fc.file_id == 0x0000) && (p_t4t->cc_file.version == 0x20))
        ||(p_t4t->cc_file.ndef_fc.file_id == 0x3F00)
        ||(p_t4t->cc_file.ndef_fc.file_id == 0x3FFF)
        ||(p_t4t->cc_file.ndef_fc.file_id == 0xFFFF)  )
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): File ID (0x%04X) is invalid",
                          p_t4t->cc_file.ndef_fc.file_id);
        return FALSE;
    }

    if (  (p_t4t->cc_file.ndef_fc.max_file_size < 0x0005)
        ||(p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFF)  )
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): max_file_size (%d) is reserved",
                         p_t4t->cc_file.ndef_fc.max_file_size);
        return FALSE;
    }

    if (p_t4t->cc_file.ndef_fc.read_access != T4T_FC_READ_ACCESS)
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): Read Access (0x%02X) is invalid",
                          p_t4t->cc_file.ndef_fc.read_access);
        return FALSE;
    }

    if (  (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
        &&(p_t4t->cc_file.ndef_fc.write_access != T4T_FC_NO_WRITE_ACCESS)  )
    {
        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): Write Access (0x%02X) is invalid",
                          p_t4t->cc_file.ndef_fc.write_access);
        return FALSE;
    }

    return TRUE;
}
Beispiel #16
0
/*******************************************************************************
**
** Function         rw_t4t_data_cback
**
** Description      This callback function receives the data from NFCC.
**
** Returns          none
**
*******************************************************************************/
static void rw_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
{
    tRW_T4T_CB *p_t4t    = &rw_cb.tcb.t4t;
    BT_HDR     *p_r_apdu = (BT_HDR *) p_data->data.p_data;
    tRW_DATA    rw_data;

#if (BT_TRACE_VERBOSE == TRUE)
    UINT8  begin_state   = p_t4t->state;
#endif

    RW_TRACE_DEBUG1 ("rw_t4t_data_cback () event = 0x%X", event);
    nfc_stop_quick_timer (&p_t4t->timer);

    switch (event)
    {
    case NFC_DEACTIVATE_CEVT:
        NFC_SetStaticRfCback (NULL);
        p_t4t->state = RW_T4T_STATE_NOT_ACTIVATED;
        return;

    case NFC_ERROR_CEVT:
        if (p_t4t->state == RW_T4T_STATE_PRESENCE_CHECK)
        {
            p_t4t->state   = RW_T4T_STATE_IDLE;
            rw_data.status = NFC_STATUS_FAILED;
            (*(rw_cb.p_cback)) (RW_T4T_PRESENCE_CHECK_EVT, &rw_data);
        }
        else
        {
            p_t4t->state   = RW_T4T_STATE_IDLE;
            rw_data.status = (tNFC_STATUS) (*(UINT8*) p_data);
            (*(rw_cb.p_cback)) (RW_T4T_INTF_ERROR_EVT, &rw_data);
        }
        return;

    case NFC_DATA_CEVT:
        break;

    default:
        return;
    }

#if (BT_TRACE_PROTOCOL == TRUE)
    DispRWT4Tags (p_r_apdu, TRUE);
#endif

#if (BT_TRACE_VERBOSE == TRUE)
    RW_TRACE_DEBUG2 ("RW T4T state: <%s (%d)>",
                        rw_t4t_get_state_name (p_t4t->state), p_t4t->state);
#else
    RW_TRACE_DEBUG1 ("RW T4T state: %d", p_t4t->state);
#endif

    switch (p_t4t->state)
    {
    case RW_T4T_STATE_IDLE:
        /* Unexpected R-APDU, it should be raw frame response */
        /* forward to upper layer without parsing */
        if (rw_cb.p_cback)
        {
            rw_data.raw_frame.status = NFC_STATUS_OK;
            rw_data.raw_frame.p_data = p_r_apdu;
            (*(rw_cb.p_cback)) (RW_T4T_RAW_FRAME_EVT, &rw_data);
            p_r_apdu = NULL;
        }
        else
        {
            GKI_freebuf (p_r_apdu);
        }
        break;
    case RW_T4T_STATE_DETECT_NDEF:
        rw_t4t_sm_detect_ndef (p_r_apdu);
        GKI_freebuf (p_r_apdu);
        break;
    case RW_T4T_STATE_READ_NDEF:
        rw_t4t_sm_read_ndef (p_r_apdu);
        /* p_r_apdu may send upper lyaer */
        break;
    case RW_T4T_STATE_UPDATE_NDEF:
        rw_t4t_sm_update_ndef (p_r_apdu);
        GKI_freebuf (p_r_apdu);
        break;
    case RW_T4T_STATE_PRESENCE_CHECK:
        /* if any response, send presence check with ok */
        rw_data.status = NFC_STATUS_OK;
        p_t4t->state = RW_T4T_STATE_IDLE;
        (*(rw_cb.p_cback)) (RW_T4T_PRESENCE_CHECK_EVT, &rw_data);
        GKI_freebuf (p_r_apdu);
        break;
    default:
        RW_TRACE_ERROR1 ("rw_t4t_data_cback (): invalid state=%d", p_t4t->state);
        GKI_freebuf (p_r_apdu);
        break;
    }

#if (BT_TRACE_VERBOSE == TRUE)
    if (begin_state != p_t4t->state)
    {
        RW_TRACE_DEBUG2 ("RW T4T state changed:<%s> -> <%s>",
                          rw_t4t_get_state_name (begin_state),
                          rw_t4t_get_state_name (p_t4t->state));
    }
#endif
}