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