/******************************************************************************* ** ** 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; }
/******************************************************************************* ** ** 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 }