/*******************************************************************************
**
** Function         rw_t2t_write
**
** Description      This function issues Type 2 Tag WRITE command for the
**                  specified block.  If the specified block is in different
**                  sector then it first sends command to move to new sector
**                  and after the tag moves to new sector it issues the write
**                  command for the block.
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS rw_t2t_write (UINT16 block, UINT8 *p_write_data)
{
    tNFC_STATUS status;
    UINT8       *p;
    tRW_T2T_CB  *p_t2t = &rw_cb.tcb.t2t;
    UINT8       write_cmd[T2T_WRITE_DATA_LEN + 1];
    UINT8       sector_byte2[1];

    p_t2t->block_written = block;
    write_cmd[0] = (UINT8) (block%T2T_BLOCKS_PER_SECTOR);
    memcpy (&write_cmd[1], p_write_data, T2T_WRITE_DATA_LEN);

    if (p_t2t->sector != block/T2T_BLOCKS_PER_SECTOR)
    {
        sector_byte2[0] = 0xFF;
        /* First Move to new sector before sending Write command */
        if ((status = rw_t2t_send_cmd (T2T_CMD_SEC_SEL, sector_byte2)) == NFC_STATUS_OK)
        {
            /* Prepare command that needs to be sent after sector change op is completed */
            p_t2t->select_sector         = (UINT8) (block/T2T_BLOCKS_PER_SECTOR);
            p_t2t->p_sec_cmd_buf->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
            p = (UINT8 *) (p_t2t->p_sec_cmd_buf + 1) + p_t2t->p_sec_cmd_buf->offset;
            UINT8_TO_BE_STREAM (p, T2T_CMD_WRITE);
            memcpy (p, write_cmd, T2T_WRITE_DATA_LEN + 1);
            p_t2t->p_sec_cmd_buf->len   = 2 + T2T_WRITE_DATA_LEN;
            p_t2t->block_written  = block;

            /* Backup the current substate to move back to this substate after changing sector */
            p_t2t->prev_substate        = p_t2t->substate;
            p_t2t->substate             = RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR_SUPPORT;
            return NFC_STATUS_OK;
        }
        return NFC_STATUS_FAILED;
    }

    /* Send Write command as sector change is not needed */
    if ((status = rw_t2t_send_cmd (T2T_CMD_WRITE, write_cmd)) == NFC_STATUS_OK)
    {
        RW_TRACE_EVENT1 ("rw_t2t_write Sent Command for Block: %u", block);
    }

    return status;
}
/*******************************************************************************
**
** Function         rw_t2t_read
**
** Description      This function issues Type 2 Tag READ command for the
**                  specified block. If the specified block is in different
**                  sector then it first sends command to move to new sector
**                  and after the tag moves to new sector it issues the read
**                  command for the block.
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS rw_t2t_read (UINT16 block)
{
    tNFC_STATUS status;
    UINT8       *p;
    tRW_T2T_CB  *p_t2t = &rw_cb.tcb.t2t;
    UINT8       sector_byte2[1];
    UINT8       read_cmd[1];


    read_cmd[0] = block % T2T_BLOCKS_PER_SECTOR;
    if (p_t2t->sector != block/T2T_BLOCKS_PER_SECTOR)
    {
        sector_byte2[0] = 0xFF;
        /* First Move to new sector before sending Read command */
        if ((status = rw_t2t_send_cmd (T2T_CMD_SEC_SEL,sector_byte2)) == NFC_STATUS_OK)
        {
            /* Prepare command that needs to be sent after sector change op is completed */
            p_t2t->select_sector         = (UINT8) (block/T2T_BLOCKS_PER_SECTOR);
            p_t2t->p_sec_cmd_buf->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;

            p = (UINT8 *) (p_t2t->p_sec_cmd_buf + 1) + p_t2t->p_sec_cmd_buf->offset;
            UINT8_TO_BE_STREAM (p, T2T_CMD_READ);
            UINT8_TO_BE_STREAM (p, read_cmd[0]);
            p_t2t->p_sec_cmd_buf->len = 2;
            p_t2t->block_read = block;

            /* Backup the current substate to move back to this substate after changing sector */
            p_t2t->prev_substate = p_t2t->substate;
            p_t2t->substate      = RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR_SUPPORT;
            return NFC_STATUS_OK;
        }
        return NFC_STATUS_FAILED;
    }

    /* Send Read command as sector change is not needed */
    if ((status = rw_t2t_send_cmd (T2T_CMD_READ, (UINT8 *) read_cmd)) == NFC_STATUS_OK)
    {
        p_t2t->block_read = block;
        RW_TRACE_EVENT1 ("rw_t2t_read Sent Command for Block: %u", block);
    }

    return status;
}
Esempio n. 3
0
/*******************************************************************************
**
** Function         RW_SendRawFrame
**
** Description      This function sends a raw frame to the peer device.
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
tNFC_STATUS RW_SendRawFrame (UINT8 *p_raw_data, UINT16 data_len)
{
    tNFC_STATUS status = NFC_STATUS_FAILED;
    BT_HDR  *p_data;
    UINT8   *p;

    if (rw_cb.p_cback)
    {
        /* a valid opcode for RW - remove */
        p_data = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
        if (p_data)
        {
            p_data->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
            p = (UINT8 *) (p_data + 1) + p_data->offset;
            memcpy (p, p_raw_data, data_len);
            p_data->len = data_len;

            RW_TRACE_EVENT1 ("RW SENT raw frame (0x%x)", data_len);
            status = NFC_SendData (NFC_RF_CONN_ID, p_data);
        }

    }
    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
}