| /****************************************************************************** |
| * |
| * Copyright (C) 2010-2014 Broadcom Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * This file contains the action functions the NFA_RW state machine. |
| * |
| ******************************************************************************/ |
| #include <string.h> |
| |
| #include <android-base/stringprintf.h> |
| #include <base/logging.h> |
| |
| #include "ndef_utils.h" |
| #include "nfa_dm_int.h" |
| #include "nfa_mem_co.h" |
| #include "nfa_rw_int.h" |
| |
| using android::base::StringPrintf; |
| |
| extern bool nfc_debug_enabled; |
| |
| #define NFA_RW_OPTION_INVALID 0xFF |
| |
| /* Tag sleep req cmd*/ |
| uint8_t NFA_RW_TAG_SLP_REQ[] = {0x50, 0x00}; |
| |
| /* Local static function prototypes */ |
| static tNFC_STATUS nfa_rw_start_ndef_read(void); |
| static tNFC_STATUS nfa_rw_start_ndef_write(void); |
| static tNFC_STATUS nfa_rw_start_ndef_detection(void); |
| static tNFC_STATUS nfa_rw_config_tag_ro(bool b_hard_lock); |
| static bool nfa_rw_op_req_while_busy(tNFA_RW_MSG* p_data); |
| static void nfa_rw_error_cleanup(uint8_t event); |
| static void nfa_rw_presence_check(tNFA_RW_MSG* p_data); |
| static void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); |
| static bool nfa_rw_detect_ndef(void); |
| static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data); |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_free_ndef_rx_buf |
| ** |
| ** Description Free buffer allocated to hold incoming NDEF message |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| void nfa_rw_free_ndef_rx_buf(void) { |
| if (nfa_rw_cb.p_ndef_buf) { |
| nfa_mem_co_free(nfa_rw_cb.p_ndef_buf); |
| nfa_rw_cb.p_ndef_buf = NULL; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_store_ndef_rx_buf |
| ** |
| ** Description Store data into NDEF buffer |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_store_ndef_rx_buf(tRW_DATA* p_rw_data) { |
| uint8_t* p; |
| |
| p = (uint8_t*)(p_rw_data->data.p_data + 1) + p_rw_data->data.p_data->offset; |
| |
| /* Save data into buffer */ |
| memcpy(&nfa_rw_cb.p_ndef_buf[nfa_rw_cb.ndef_rd_offset], p, |
| p_rw_data->data.p_data->len); |
| nfa_rw_cb.ndef_rd_offset += p_rw_data->data.p_data->len; |
| |
| GKI_freebuf(p_rw_data->data.p_data); |
| p_rw_data->data.p_data = NULL; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_send_data_to_upper |
| ** |
| ** Description Send data to upper layer |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_send_data_to_upper(tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| if ((p_rw_data->status == NFC_STATUS_TIMEOUT) || |
| (p_rw_data->data.p_data == NULL)) |
| return; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("nfa_rw_send_data_to_upper: Len [0x%X] Status [%s]", |
| p_rw_data->data.p_data->len, |
| NFC_GetStatusName(p_rw_data->data.status).c_str()); |
| |
| /* Notify conn cback of NFA_DATA_EVT */ |
| conn_evt_data.data.status = p_rw_data->data.status; |
| conn_evt_data.data.p_data = |
| (uint8_t*)(p_rw_data->data.p_data + 1) + p_rw_data->data.p_data->offset; |
| conn_evt_data.data.len = p_rw_data->data.p_data->len; |
| |
| nfa_dm_act_conn_cback_notify(NFA_DATA_EVT, &conn_evt_data); |
| |
| GKI_freebuf(p_rw_data->data.p_data); |
| p_rw_data->data.p_data = NULL; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_error_cleanup |
| ** |
| ** Description Handle failure - signal command complete and notify app |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_error_cleanup(uint8_t event) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| nfa_rw_command_complete(); |
| |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| |
| nfa_dm_act_conn_cback_notify(event, &conn_evt_data); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_check_start_presence_check_timer |
| ** |
| ** Description Start timer to wait for specified time before presence check |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_check_start_presence_check_timer( |
| uint16_t presence_check_start_delay) { |
| if (!p_nfa_dm_cfg->auto_presence_check) return; |
| |
| if (nfa_rw_cb.flags & NFA_RW_FL_NOT_EXCL_RF_MODE) { |
| if (presence_check_start_delay) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("Starting presence check timer..."); |
| nfa_sys_start_timer(&nfa_rw_cb.tle, NFA_RW_PRESENCE_CHECK_TICK_EVT, |
| presence_check_start_delay); |
| } else { |
| /* Presence check now */ |
| nfa_rw_presence_check(NULL); |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_stop_presence_check_timer |
| ** |
| ** Description Stop timer for presence check |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| void nfa_rw_stop_presence_check_timer(void) { |
| nfa_sys_stop_timer(&nfa_rw_cb.tle); |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("Stopped presence check timer (if started)"); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_ndef_detect |
| ** |
| ** Description Handler for NDEF detection reader/writer event |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_ndef_detect(tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "NDEF Detection completed: cur_size=%i, max_size=%i, flags=0x%x", |
| p_rw_data->ndef.cur_size, p_rw_data->ndef.max_size, |
| p_rw_data->ndef.flags); |
| |
| /* Check if NDEF detection succeeded */ |
| if (p_rw_data->ndef.status == NFC_STATUS_OK) { |
| /* Set NDEF detection state */ |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_TRUE; |
| nfa_rw_cb.flags |= NFA_RW_FL_NDEF_OK; |
| |
| /* Store ndef properties */ |
| conn_evt_data.ndef_detect.status = NFA_STATUS_OK; |
| conn_evt_data.ndef_detect.protocol = p_rw_data->ndef.protocol; |
| conn_evt_data.ndef_detect.cur_size = nfa_rw_cb.ndef_cur_size = |
| p_rw_data->ndef.cur_size; |
| conn_evt_data.ndef_detect.max_size = nfa_rw_cb.ndef_max_size = |
| p_rw_data->ndef.max_size; |
| conn_evt_data.ndef_detect.flags = p_rw_data->ndef.flags; |
| |
| if (p_rw_data->ndef.flags & RW_NDEF_FL_READ_ONLY) |
| nfa_rw_cb.flags |= NFA_RW_FL_TAG_IS_READONLY; |
| else |
| nfa_rw_cb.flags &= ~NFA_RW_FL_TAG_IS_READONLY; |
| |
| /* Determine what operation triggered the NDEF detection procedure */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* if ndef detection was done as part of ndef-read operation, then perform |
| * ndef read now */ |
| conn_evt_data.status = nfa_rw_start_ndef_read(); |
| if (conn_evt_data.status != NFA_STATUS_OK) { |
| /* Failed to start NDEF Read */ |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| } |
| } else if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* if ndef detection was done as part of ndef-write operation, then |
| * perform ndef write now */ |
| conn_evt_data.status = nfa_rw_start_ndef_write(); |
| if (conn_evt_data.status != NFA_STATUS_OK) { |
| /* Failed to start NDEF Write. */ |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| } |
| } else { |
| /* current op was stand-alone NFA_DetectNDef. Command complete - perform |
| * cleanup and notify app */ |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| nfa_rw_command_complete(); |
| |
| nfa_dm_act_conn_cback_notify(NFA_NDEF_DETECT_EVT, &conn_evt_data); |
| } |
| } else { |
| /* NDEF detection failed... */ |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_FALSE; |
| conn_evt_data.status = p_rw_data->ndef.status; |
| |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* if ndef detection was done as part of ndef-read operation, then notify |
| * NDEF handlers of failure */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); |
| |
| /* Notify app of read status */ |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| } else if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* if ndef detection was done as part of ndef-write operation, then notify |
| * app of failure */ |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| } else if (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_NDEF) { |
| conn_evt_data.ndef_detect.protocol = p_rw_data->ndef.protocol; |
| /* current op was stand-alone NFA_DetectNDef. Notify app of failure */ |
| if (p_rw_data->ndef.status == NFC_STATUS_TIMEOUT) { |
| /* Tag could have moved away */ |
| conn_evt_data.ndef_detect.cur_size = 0; |
| conn_evt_data.ndef_detect.max_size = 0; |
| conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; |
| conn_evt_data.ndef_detect.status = NFA_STATUS_TIMEOUT; |
| } else { |
| /* NDEF Detection failed for other reasons */ |
| conn_evt_data.ndef_detect.cur_size = nfa_rw_cb.ndef_cur_size = |
| p_rw_data->ndef.cur_size; |
| conn_evt_data.ndef_detect.max_size = nfa_rw_cb.ndef_max_size = |
| p_rw_data->ndef.max_size; |
| conn_evt_data.ndef_detect.flags = p_rw_data->ndef.flags; |
| } |
| nfa_dm_act_conn_cback_notify(NFA_NDEF_DETECT_EVT, &conn_evt_data); |
| } |
| |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_tlv_detect |
| ** |
| ** Description Handler for TLV detection reader/writer event |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_tlv_detect(tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| /* Set TLV detection state */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_SET_TAG_RO) { |
| if (nfa_rw_cb.tlv_st == NFA_RW_TLV_DETECT_ST_OP_NOT_STARTED) { |
| nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_LOCK_TLV_OP_COMPLETE; |
| } else { |
| nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; |
| } |
| } else { |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_LOCK_TLV) { |
| nfa_rw_cb.tlv_st |= NFA_RW_TLV_DETECT_ST_LOCK_TLV_OP_COMPLETE; |
| } else if (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_MEM_TLV) { |
| nfa_rw_cb.tlv_st |= NFA_RW_TLV_DETECT_ST_MEM_TLV_OP_COMPLETE; |
| } |
| } |
| |
| /* Check if TLV detection succeeded */ |
| if (p_rw_data->tlv.status == NFC_STATUS_OK) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "TLV Detection succeeded: num_bytes=%i", p_rw_data->tlv.num_bytes); |
| |
| /* Store tlv properties */ |
| conn_evt_data.tlv_detect.status = NFA_STATUS_OK; |
| conn_evt_data.tlv_detect.protocol = p_rw_data->tlv.protocol; |
| conn_evt_data.tlv_detect.num_bytes = p_rw_data->tlv.num_bytes; |
| |
| /* Determine what operation triggered the TLV detection procedure */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_SET_TAG_RO) { |
| if (nfa_rw_config_tag_ro(nfa_rw_cb.b_hard_lock) != NFC_STATUS_OK) { |
| /* Failed to set tag read only */ |
| conn_evt_data.tlv_detect.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| } |
| } else { |
| /* current op was stand-alone NFA_DetectTlv. Command complete - perform |
| * cleanup and notify app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_TLV_DETECT_EVT, &conn_evt_data); |
| } |
| } |
| |
| /* Handle failures */ |
| if (p_rw_data->tlv.status != NFC_STATUS_OK) { |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| conn_evt_data.tlv_detect.status = NFA_STATUS_FAILED; |
| if ((nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_LOCK_TLV) || |
| (nfa_rw_cb.cur_op == NFA_RW_OP_DETECT_MEM_TLV)) { |
| nfa_dm_act_conn_cback_notify(NFA_TLV_DETECT_EVT, &conn_evt_data); |
| } else if (nfa_rw_cb.cur_op == NFA_RW_OP_SET_TAG_RO) { |
| if (nfa_rw_config_tag_ro(nfa_rw_cb.b_hard_lock) != NFC_STATUS_OK) { |
| /* Failed to set tag read only */ |
| conn_evt_data.tlv_detect.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| } |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_sleep_wakeup_rsp |
| ** |
| ** Description Handl sleep wakeup |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| void nfa_rw_handle_sleep_wakeup_rsp(tNFC_STATUS status) { |
| tNFC_ACTIVATE_DEVT activate_params; |
| tRW_EVENT event; |
| |
| if ((nfa_rw_cb.halt_event != RW_T2T_MAX_EVT) && |
| (nfa_rw_cb.activated_tech_mode == NFC_DISCOVERY_TYPE_POLL_A) && |
| (nfa_rw_cb.protocol == NFC_PROTOCOL_T2T) && |
| (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T)) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "nfa_rw_handle_sleep_wakeup_rsp; Attempt to wake up Type 2 tag from " |
| "HALT State is complete"); |
| if (status == NFC_STATUS_OK) { |
| /* Type 2 Tag is wakeup from HALT state */ |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "nfa_rw_handle_sleep_wakeup_rsp; Handle the NACK rsp received now"); |
| /* Initialize control block */ |
| activate_params.protocol = nfa_rw_cb.protocol; |
| activate_params.rf_tech_param.param.pa.sel_rsp = nfa_rw_cb.pa_sel_res; |
| activate_params.rf_tech_param.mode = nfa_rw_cb.activated_tech_mode; |
| |
| /* Initialize RW module */ |
| if ((RW_SetActivatedTagType(&activate_params, nfa_rw_cback)) != |
| NFC_STATUS_OK) { |
| /* Log error (stay in NFA_RW_ST_ACTIVATED state until deactivation) */ |
| LOG(ERROR) << StringPrintf("RW_SetActivatedTagType failed."); |
| if (nfa_rw_cb.halt_event == RW_T2T_READ_CPLT_EVT) { |
| if (nfa_rw_cb.rw_data.data.p_data) |
| GKI_freebuf(nfa_rw_cb.rw_data.data.p_data); |
| nfa_rw_cb.rw_data.data.p_data = NULL; |
| } |
| /* Do not try to detect NDEF again but just notify current operation |
| * failed */ |
| nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; |
| } |
| } |
| |
| /* The current operation failed with NACK rsp from type 2 tag */ |
| nfa_rw_cb.rw_data.status = NFC_STATUS_FAILED; |
| event = nfa_rw_cb.halt_event; |
| |
| /* Got NACK rsp during presence check and legacy presence check performed */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_PRESENCE_CHECK) |
| nfa_rw_cb.rw_data.status = status; |
| |
| /* If cannot Sleep wakeup tag, then NDEF Detect operation is complete */ |
| if ((status != NFC_STATUS_OK) && |
| (nfa_rw_cb.halt_event == RW_T2T_NDEF_DETECT_EVT)) |
| nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; |
| |
| nfa_rw_handle_t2t_evt(event, &nfa_rw_cb.rw_data); |
| nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; |
| |
| /* If Type 2 tag sleep wakeup failed and If in normal mode (not-exclusive RF |
| * mode) then deactivate the link if sleep wakeup failed */ |
| if ((nfa_rw_cb.flags & NFA_RW_FL_NOT_EXCL_RF_MODE) && |
| (status != NFC_STATUS_OK)) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("Sleep wakeup failed. Deactivating..."); |
| nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY); |
| } |
| } else { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "nfa_rw_handle_sleep_wakeup_rsp; Legacy presence check performed"); |
| /* Legacy presence check performed */ |
| nfa_rw_handle_presence_check_rsp(status); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_presence_check_rsp |
| ** |
| ** Description Handler RW_T#t_PRESENCE_CHECK_EVT |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| void nfa_rw_handle_presence_check_rsp(tNFC_STATUS status) { |
| NFC_HDR* p_pending_msg; |
| |
| /* Stop the presence check timer - timer may have been started when presence |
| * check started */ |
| nfa_rw_stop_presence_check_timer(); |
| if (status == NFA_STATUS_OK) { |
| /* Clear the BUSY flag and restart the presence-check timer */ |
| nfa_rw_command_complete(); |
| } else { |
| /* If presence check failed just clear the BUSY flag */ |
| nfa_rw_cb.flags &= ~NFA_RW_FL_API_BUSY; |
| } |
| |
| /* Handle presence check due to auto-presence-check */ |
| if (nfa_rw_cb.flags & NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY) { |
| nfa_rw_cb.flags &= ~NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY; |
| |
| /* If an API was called during auto-presence-check, then handle it now */ |
| if (nfa_rw_cb.p_pending_msg) { |
| /* If NFA_RwPresenceCheck was called during auto-presence-check, notify |
| * app of result */ |
| if (nfa_rw_cb.p_pending_msg->op_req.op == NFA_RW_OP_PRESENCE_CHECK) { |
| /* Notify app of presence check status */ |
| tNFA_CONN_EVT_DATA nfa_conn_evt_data; |
| nfa_conn_evt_data.status = status; |
| nfa_dm_act_conn_cback_notify(NFA_PRESENCE_CHECK_EVT, |
| &nfa_conn_evt_data); |
| GKI_freebuf(nfa_rw_cb.p_pending_msg); |
| nfa_rw_cb.p_pending_msg = NULL; |
| } |
| /* For all other APIs called during auto-presence check, perform the |
| command now (if tag is still present) */ |
| else if (status == NFC_STATUS_OK) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "Performing deferred operation after presence check..."); |
| p_pending_msg = (NFC_HDR*)nfa_rw_cb.p_pending_msg; |
| nfa_rw_cb.p_pending_msg = NULL; |
| nfa_rw_handle_event(p_pending_msg); |
| GKI_freebuf(p_pending_msg); |
| } else { |
| /* Tag no longer present. Free command for pending API command */ |
| GKI_freebuf(nfa_rw_cb.p_pending_msg); |
| nfa_rw_cb.p_pending_msg = NULL; |
| } |
| } |
| |
| /* Auto-presence check failed. Deactivate */ |
| if (status != NFC_STATUS_OK) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("Auto presence check failed. Deactivating..."); |
| nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY); |
| } |
| } |
| /* Handle presence check due to NFA_RwPresenceCheck API call */ |
| else { |
| /* Notify app of presence check status */ |
| tNFA_CONN_EVT_DATA nfa_conn_evt_data; |
| nfa_conn_evt_data.status = status; |
| nfa_dm_act_conn_cback_notify(NFA_PRESENCE_CHECK_EVT, &nfa_conn_evt_data); |
| |
| /* If in normal mode (not-exclusive RF mode) then deactivate the link if |
| * presence check failed */ |
| if ((nfa_rw_cb.flags & NFA_RW_FL_NOT_EXCL_RF_MODE) && |
| (nfa_conn_evt_data.status != NFC_STATUS_OK)) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("Presence check failed. Deactivating..."); |
| nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY); |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_t1t_evt |
| ** |
| ** Description Handler for Type-1 tag reader/writer events |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_t1t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| tNFA_TAG_PARAMS tag_params; |
| uint8_t* p_rid_rsp; |
| tNFA_STATUS activation_status; |
| |
| conn_evt_data.status = p_rw_data->data.status; |
| switch (event) { |
| case RW_T1T_RID_EVT: |
| if (p_rw_data->data.p_data != NULL) { |
| /* Assume the data is just the response byte sequence */ |
| p_rid_rsp = (uint8_t*)(p_rw_data->data.p_data + 1) + |
| p_rw_data->data.p_data->offset; |
| /* Fetch HR from RID response message */ |
| STREAM_TO_ARRAY(tag_params.t1t.hr, p_rid_rsp, T1T_HR_LEN); |
| /* Fetch UID0-3 from RID response message */ |
| STREAM_TO_ARRAY(tag_params.t1t.uid, p_rid_rsp, T1T_CMD_UID_LEN); |
| GKI_freebuf(p_rw_data->data.p_data); |
| p_rw_data->data.p_data = NULL; |
| } |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| if (p_rw_data->status == NFC_STATUS_TIMEOUT) { |
| activation_status = NFA_STATUS_TIMEOUT; |
| } else { |
| activation_status = NFA_STATUS_OK; |
| } |
| |
| nfa_dm_notify_activation_status(activation_status, &tag_params); |
| break; |
| |
| case RW_T1T_RALL_CPLT_EVT: |
| case RW_T1T_READ_CPLT_EVT: |
| case RW_T1T_RSEG_CPLT_EVT: |
| case RW_T1T_READ8_CPLT_EVT: |
| nfa_rw_send_data_to_upper(p_rw_data); |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T1T_WRITE_E_CPLT_EVT: |
| case RW_T1T_WRITE_NE_CPLT_EVT: |
| case RW_T1T_WRITE_E8_CPLT_EVT: |
| case RW_T1T_WRITE_NE8_CPLT_EVT: |
| nfa_rw_send_data_to_upper(p_rw_data); |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T1T_TLV_DETECT_EVT: |
| nfa_rw_handle_tlv_detect(p_rw_data); |
| break; |
| |
| case RW_T1T_NDEF_DETECT_EVT: |
| nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; |
| |
| if ((p_rw_data->status != NFC_STATUS_OK) && |
| (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) && |
| (p_rw_data->ndef.flags & NFA_RW_NDEF_FL_FORMATABLE) && |
| (!(p_rw_data->ndef.flags & NFA_RW_NDEF_FL_FORMATED)) && |
| (p_rw_data->ndef.flags & NFA_RW_NDEF_FL_SUPPORTED)) { |
| /* Tag is in Initialized state, Format the tag first and then Write NDEF |
| */ |
| if (RW_T1tFormatNDef() == NFC_STATUS_OK) break; |
| } |
| |
| nfa_rw_handle_ndef_detect(p_rw_data); |
| |
| break; |
| |
| case RW_T1T_NDEF_READ_EVT: |
| nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; |
| if (p_rw_data->status == NFC_STATUS_OK) { |
| /* Process the ndef record */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, |
| nfa_rw_cb.ndef_cur_size); |
| } else { |
| /* Notify app of failure */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* If current operation is READ_NDEF, then notify ndef handlers of |
| * failure */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); |
| } |
| } |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| break; |
| |
| case RW_T1T_NDEF_WRITE_EVT: |
| if (p_rw_data->data.status != NFA_STATUS_OK) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_COMPLETE; |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| /* Notify app */ |
| conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) |
| ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* Update local cursize of ndef message */ |
| nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; |
| } |
| |
| /* Notify app of ndef write complete status */ |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T1T_SET_TAG_RO_EVT: |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T1T_RAW_FRAME_EVT: |
| nfa_rw_send_data_to_upper(p_rw_data); |
| /* Command complete - perform cleanup */ |
| nfa_rw_command_complete(); |
| break; |
| |
| case RW_T1T_PRESENCE_CHECK_EVT: /* Presence check completed */ |
| nfa_rw_handle_presence_check_rsp(p_rw_data->status); |
| break; |
| |
| case RW_T1T_FORMAT_CPLT_EVT: |
| |
| if (p_rw_data->data.status == NFA_STATUS_OK) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* if format operation was done as part of ndef-write operation, now |
| * start NDEF Write */ |
| if ((p_rw_data->data.status != NFA_STATUS_OK) || |
| ((conn_evt_data.status = RW_T1tDetectNDef()) != NFC_STATUS_OK)) { |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_FALSE; |
| |
| /* if format operation failed or ndef detection did not start, then |
| * notify app of ndef-write operation failure */ |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| } |
| } else { |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); |
| } |
| break; |
| |
| case RW_T1T_INTF_ERROR_EVT: |
| nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_t2t_evt |
| ** |
| ** Description Handler for Type-2 tag reader/writer events |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| conn_evt_data.status = p_rw_data->status; |
| |
| if (p_rw_data->status == NFC_STATUS_REJECTED) { |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "; Waking the tag first before handling the " |
| "response!"); |
| /* Received NACK. Let DM wakeup the tag first (by putting tag to sleep and |
| * then waking it up) */ |
| p_rw_data->status = nfa_dm_disc_sleep_wakeup(); |
| if (p_rw_data->status == NFC_STATUS_OK) { |
| nfa_rw_cb.halt_event = event; |
| memcpy(&nfa_rw_cb.rw_data, p_rw_data, sizeof(tRW_DATA)); |
| return; |
| } |
| } |
| |
| switch (event) { |
| case RW_T2T_READ_CPLT_EVT: /* Read completed */ |
| nfa_rw_send_data_to_upper(p_rw_data); |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T2T_WRITE_CPLT_EVT: /* Write completed */ |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T2T_SELECT_CPLT_EVT: /* Sector select completed */ |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_SELECT_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T2T_NDEF_DETECT_EVT: /* NDEF detection complete */ |
| if ((p_rw_data->status == NFC_STATUS_OK) || |
| ((p_rw_data->status == NFC_STATUS_FAILED) && |
| ((p_rw_data->ndef.flags == NFA_RW_NDEF_FL_UNKNOWN) || |
| (nfa_rw_cb.halt_event == RW_T2T_MAX_EVT))) || |
| (nfa_rw_cb.skip_dyn_locks == true)) { |
| /* NDEF Detection is complete */ |
| nfa_rw_cb.skip_dyn_locks = false; |
| nfa_rw_handle_ndef_detect(p_rw_data); |
| } else { |
| /* Try to detect NDEF again, this time without reading dynamic lock |
| * bytes */ |
| nfa_rw_cb.skip_dyn_locks = true; |
| nfa_rw_detect_ndef(); |
| } |
| break; |
| |
| case RW_T2T_TLV_DETECT_EVT: /* Lock control/Mem/Prop tlv detection complete |
| */ |
| nfa_rw_handle_tlv_detect(p_rw_data); |
| break; |
| |
| case RW_T2T_NDEF_READ_EVT: /* NDEF read completed */ |
| if (p_rw_data->status == NFC_STATUS_OK) { |
| /* Process the ndef record */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, |
| nfa_rw_cb.ndef_cur_size); |
| } else { |
| /* Notify app of failure */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* If current operation is READ_NDEF, then notify ndef handlers of |
| * failure */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); |
| } |
| } |
| |
| /* Notify app of read status */ |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| |
| /* Command complete - perform cleanup */ |
| nfa_rw_command_complete(); |
| break; |
| |
| case RW_T2T_NDEF_WRITE_EVT: /* NDEF write complete */ |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| /* Notify app */ |
| conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) |
| ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* Update local cursize of ndef message */ |
| nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; |
| } |
| |
| /* Notify app of ndef write complete status */ |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| |
| break; |
| |
| case RW_T2T_SET_TAG_RO_EVT: |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T2T_RAW_FRAME_EVT: |
| nfa_rw_send_data_to_upper(p_rw_data); |
| /* Command complete - perform cleanup */ |
| if (p_rw_data->status != NFC_STATUS_CONTINUE) { |
| nfa_rw_command_complete(); |
| } |
| break; |
| |
| case RW_T2T_PRESENCE_CHECK_EVT: /* Presence check completed */ |
| nfa_rw_handle_presence_check_rsp(p_rw_data->status); |
| break; |
| |
| case RW_T2T_FORMAT_CPLT_EVT: |
| if (p_rw_data->data.status == NFA_STATUS_OK) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T2T_INTF_ERROR_EVT: |
| nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_t3t_evt |
| ** |
| ** Description Handler for Type-3 tag reader/writer events |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_t3t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| tNFA_TAG_PARAMS tag_params; |
| |
| switch (event) { |
| case RW_T3T_NDEF_DETECT_EVT: /* NDEF detection complete */ |
| nfa_rw_handle_ndef_detect(p_rw_data); |
| break; |
| |
| case RW_T3T_UPDATE_CPLT_EVT: /* Write completed */ |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| /* Notify app */ |
| conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) |
| ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* Update local cursize of ndef message */ |
| nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; |
| } |
| |
| /* Notify app of ndef write complete status */ |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| |
| break; |
| |
| case RW_T3T_CHECK_CPLT_EVT: /* Read completed */ |
| if (p_rw_data->status == NFC_STATUS_OK) { |
| /* Process the ndef record */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, |
| nfa_rw_cb.ndef_cur_size); |
| } else { |
| /* Notify app of failure */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* If current operation is READ_NDEF, then notify ndef handlers of |
| * failure */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); |
| } |
| } |
| |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T3T_CHECK_EVT: /* Segment of data received from type 3 tag */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| nfa_rw_store_ndef_rx_buf(p_rw_data); |
| } else { |
| nfa_rw_send_data_to_upper(p_rw_data); |
| } |
| break; |
| |
| case RW_T3T_RAW_FRAME_EVT: /* SendRawFrame response */ |
| nfa_rw_send_data_to_upper(p_rw_data); |
| |
| if (p_rw_data->status != NFC_STATUS_CONTINUE) { |
| /* Command complete - perform cleanup */ |
| nfa_rw_command_complete(); |
| } |
| break; |
| |
| case RW_T3T_PRESENCE_CHECK_EVT: /* Presence check completed */ |
| nfa_rw_handle_presence_check_rsp(p_rw_data->status); |
| break; |
| |
| case RW_T3T_GET_SYSTEM_CODES_EVT: /* Presence check completed */ |
| /* Command complete - perform cleanup */ |
| nfa_rw_command_complete(); |
| |
| /* System codes retrieved - notify app of ACTIVATION */ |
| if (p_rw_data->status == NFC_STATUS_OK) { |
| tag_params.t3t.num_system_codes = p_rw_data->t3t_sc.num_system_codes; |
| tag_params.t3t.p_system_codes = p_rw_data->t3t_sc.p_system_codes; |
| } else { |
| tag_params.t3t.num_system_codes = 0; |
| tag_params.t3t.p_system_codes = NULL; |
| } |
| |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &tag_params); |
| break; |
| |
| case RW_T3T_FORMAT_CPLT_EVT: /* Format completed */ |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| /* Notify app */ |
| conn_evt_data.status = (p_rw_data->data.status == NFC_STATUS_OK) |
| ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| |
| /* Notify app of ndef write complete status */ |
| nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T3T_INTF_ERROR_EVT: |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T3T_SET_READ_ONLY_CPLT_EVT: |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| break; |
| |
| default: |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("; Unhandled RW event 0x%X", event); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_t4t_evt |
| ** |
| ** Description Handler for Type-4 tag reader/writer events |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_t4t_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| switch (event) { |
| case RW_T4T_NDEF_DETECT_EVT: /* Result of NDEF detection procedure */ |
| nfa_rw_handle_ndef_detect(p_rw_data); |
| break; |
| |
| case RW_T4T_NDEF_FORMAT_CPLT_EVT: |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| nfa_rw_cb.ndef_cur_size = p_rw_data->ndef.cur_size; |
| nfa_rw_cb.ndef_max_size = p_rw_data->ndef.max_size; |
| conn_evt_data.status = (p_rw_data->status == NFC_STATUS_OK) |
| ? NFA_STATUS_OK |
| : NFA_STATUS_FAILED; |
| |
| nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T4T_NDEF_READ_EVT: /* Segment of data received from type 4 tag */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| nfa_rw_store_ndef_rx_buf(p_rw_data); |
| } else { |
| nfa_rw_send_data_to_upper(p_rw_data); |
| } |
| break; |
| |
| case RW_T4T_NDEF_READ_CPLT_EVT: /* Read operation completed */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| nfa_rw_store_ndef_rx_buf(p_rw_data); |
| |
| /* Process the ndef record */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, |
| nfa_rw_cb.ndef_cur_size); |
| |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| } else { |
| nfa_rw_send_data_to_upper(p_rw_data); |
| } |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| conn_evt_data.status = NFC_STATUS_OK; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T4T_NDEF_READ_FAIL_EVT: /* Read operation failed */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* If current operation is READ_NDEF, then notify ndef handlers of |
| * failure */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); |
| |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| } |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T4T_NDEF_UPDATE_CPLT_EVT: /* Update operation completed */ |
| case RW_T4T_NDEF_UPDATE_FAIL_EVT: /* Update operation failed */ |
| |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* Update local cursize of ndef message */ |
| nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; |
| } |
| |
| /* Notify app */ |
| if (event == RW_T4T_NDEF_UPDATE_CPLT_EVT) |
| conn_evt_data.status = NFA_STATUS_OK; |
| else |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| |
| /* Command complete - perform cleanup, notify the app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_T4T_RAW_FRAME_EVT: /* Raw Frame data event */ |
| nfa_rw_send_data_to_upper(p_rw_data); |
| |
| if (p_rw_data->status != NFC_STATUS_CONTINUE) { |
| /* Command complete - perform cleanup */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| } |
| break; |
| |
| case RW_T4T_SET_TO_RO_EVT: /* Tag is set as read only */ |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| break; |
| |
| case RW_T4T_INTF_ERROR_EVT: /* RF Interface error event */ |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); |
| |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| break; |
| |
| case RW_T4T_PRESENCE_CHECK_EVT: /* Presence check completed */ |
| nfa_rw_handle_presence_check_rsp(p_rw_data->status); |
| break; |
| |
| default: |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("; Unhandled RW event 0x%X", event); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_i93_evt |
| ** |
| ** Description Handler for ISO 15693 tag reader/writer events |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_handle_i93_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| tNFA_TAG_PARAMS i93_params; |
| |
| switch (event) { |
| case RW_I93_NDEF_DETECT_EVT: /* Result of NDEF detection procedure */ |
| nfa_rw_handle_ndef_detect(p_rw_data); |
| break; |
| |
| case RW_I93_NDEF_READ_EVT: /* Segment of data received from type 4 tag */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| nfa_rw_store_ndef_rx_buf(p_rw_data); |
| } else { |
| nfa_rw_send_data_to_upper(p_rw_data); |
| } |
| break; |
| |
| case RW_I93_NDEF_READ_CPLT_EVT: /* Read operation completed */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| nfa_rw_store_ndef_rx_buf(p_rw_data); |
| |
| /* Process the ndef record */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_OK, nfa_rw_cb.p_ndef_buf, |
| nfa_rw_cb.ndef_cur_size); |
| |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| } else { |
| nfa_rw_send_data_to_upper(p_rw_data); |
| } |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| conn_evt_data.status = NFC_STATUS_OK; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_I93_NDEF_READ_FAIL_EVT: /* Read operation failed */ |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { |
| /* If current operation is READ_NDEF, then notify ndef handlers of |
| * failure */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_FAILED, NULL, 0); |
| |
| /* Free ndef buffer */ |
| nfa_rw_free_ndef_rx_buf(); |
| } |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_I93_NDEF_UPDATE_CPLT_EVT: /* Update operation completed */ |
| case RW_I93_NDEF_UPDATE_FAIL_EVT: /* Update operation failed */ |
| |
| if (nfa_rw_cb.cur_op == NFA_RW_OP_WRITE_NDEF) { |
| /* Update local cursize of ndef message */ |
| nfa_rw_cb.ndef_cur_size = nfa_rw_cb.ndef_wr_len; |
| } |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| |
| if (event == RW_I93_NDEF_UPDATE_CPLT_EVT) |
| conn_evt_data.status = NFA_STATUS_OK; |
| else |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| |
| /* Notify app of ndef write complete status */ |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_I93_RAW_FRAME_EVT: /* Raw Frame data event */ |
| nfa_rw_send_data_to_upper(p_rw_data); |
| if (p_rw_data->status != NFC_STATUS_CONTINUE) { |
| /* Command complete - perform cleanup */ |
| nfa_rw_command_complete(); |
| } |
| break; |
| |
| case RW_I93_INTF_ERROR_EVT: /* RF Interface error event */ |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| |
| if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| |
| memset(&i93_params, 0x00, sizeof(tNFA_TAG_PARAMS)); |
| memcpy(i93_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); |
| |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); |
| } else { |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data); |
| } |
| |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| break; |
| |
| case RW_I93_PRESENCE_CHECK_EVT: /* Presence check completed */ |
| nfa_rw_handle_presence_check_rsp(p_rw_data->status); |
| break; |
| |
| case RW_I93_FORMAT_CPLT_EVT: /* Format procedure complete */ |
| if (p_rw_data->data.status == NFA_STATUS_OK) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_FORMAT_CPLT_EVT, &conn_evt_data); |
| break; |
| |
| case RW_I93_SET_TAG_RO_EVT: /* Set read-only procedure complete */ |
| nfa_rw_cb.flags |= NFA_RW_FL_TAG_IS_READONLY; |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| conn_evt_data.status = p_rw_data->status; |
| nfa_dm_act_conn_cback_notify(NFA_SET_TAG_RO_EVT, &conn_evt_data); |
| break; |
| |
| case RW_I93_INVENTORY_EVT: /* Response of Inventory */ |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| |
| conn_evt_data.i93_cmd_cplt.status = p_rw_data->i93_inventory.status; |
| conn_evt_data.i93_cmd_cplt.sent_command = I93_CMD_INVENTORY; |
| |
| conn_evt_data.i93_cmd_cplt.params.inventory.dsfid = |
| p_rw_data->i93_inventory.dsfid; |
| memcpy(conn_evt_data.i93_cmd_cplt.params.inventory.uid, |
| p_rw_data->i93_inventory.uid, I93_UID_BYTE_LEN); |
| |
| nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); |
| |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| break; |
| |
| case RW_I93_DATA_EVT: /* Response of Read, Get Multi Security */ |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| |
| conn_evt_data.data.p_data = (uint8_t*)(p_rw_data->i93_data.p_data + 1) + |
| p_rw_data->i93_data.p_data->offset; |
| |
| if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| |
| i93_params.i93.info_flags = |
| (I93_INFO_FLAG_DSFID | I93_INFO_FLAG_MEM_SIZE | I93_INFO_FLAG_AFI); |
| i93_params.i93.afi = |
| *(conn_evt_data.data.p_data + |
| nfa_rw_cb.i93_afi_location % nfa_rw_cb.i93_block_size); |
| i93_params.i93.dsfid = nfa_rw_cb.i93_dsfid; |
| i93_params.i93.block_size = nfa_rw_cb.i93_block_size; |
| i93_params.i93.num_block = nfa_rw_cb.i93_num_block; |
| memcpy(i93_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); |
| |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); |
| } else { |
| conn_evt_data.data.len = p_rw_data->i93_data.p_data->len; |
| |
| nfa_dm_act_conn_cback_notify(NFA_DATA_EVT, &conn_evt_data); |
| } |
| |
| GKI_freebuf(p_rw_data->i93_data.p_data); |
| p_rw_data->i93_data.p_data = NULL; |
| |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| break; |
| |
| case RW_I93_SYS_INFO_EVT: /* Response of System Information */ |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| |
| if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| |
| nfa_rw_cb.i93_block_size = p_rw_data->i93_sys_info.block_size; |
| nfa_rw_cb.i93_num_block = p_rw_data->i93_sys_info.num_block; |
| |
| i93_params.i93.info_flags = p_rw_data->i93_sys_info.info_flags; |
| i93_params.i93.dsfid = p_rw_data->i93_sys_info.dsfid; |
| i93_params.i93.afi = p_rw_data->i93_sys_info.afi; |
| i93_params.i93.num_block = p_rw_data->i93_sys_info.num_block; |
| i93_params.i93.block_size = p_rw_data->i93_sys_info.block_size; |
| i93_params.i93.IC_reference = p_rw_data->i93_sys_info.IC_reference; |
| memcpy(i93_params.i93.uid, p_rw_data->i93_sys_info.uid, |
| I93_UID_BYTE_LEN); |
| |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); |
| } else { |
| conn_evt_data.i93_cmd_cplt.status = p_rw_data->i93_sys_info.status; |
| conn_evt_data.i93_cmd_cplt.sent_command = I93_CMD_GET_SYS_INFO; |
| |
| conn_evt_data.i93_cmd_cplt.params.sys_info.info_flags = |
| p_rw_data->i93_sys_info.info_flags; |
| memcpy(conn_evt_data.i93_cmd_cplt.params.sys_info.uid, |
| p_rw_data->i93_sys_info.uid, I93_UID_BYTE_LEN); |
| conn_evt_data.i93_cmd_cplt.params.sys_info.dsfid = |
| p_rw_data->i93_sys_info.dsfid; |
| conn_evt_data.i93_cmd_cplt.params.sys_info.afi = |
| p_rw_data->i93_sys_info.afi; |
| conn_evt_data.i93_cmd_cplt.params.sys_info.num_block = |
| p_rw_data->i93_sys_info.num_block; |
| conn_evt_data.i93_cmd_cplt.params.sys_info.block_size = |
| p_rw_data->i93_sys_info.block_size; |
| conn_evt_data.i93_cmd_cplt.params.sys_info.IC_reference = |
| p_rw_data->i93_sys_info.IC_reference; |
| |
| /* store tag memory information for writing blocks */ |
| nfa_rw_cb.i93_block_size = p_rw_data->i93_sys_info.block_size; |
| nfa_rw_cb.i93_num_block = p_rw_data->i93_sys_info.num_block; |
| |
| nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); |
| } |
| |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| break; |
| |
| case RW_I93_CMD_CMPL_EVT: /* Command complete */ |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| |
| if (nfa_rw_cb.flags & NFA_RW_FL_ACTIVATION_NTF_PENDING) { |
| /* Reader got error code from tag */ |
| |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| |
| memset(&i93_params, 0x00, sizeof(i93_params)); |
| memcpy(i93_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); |
| |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &i93_params); |
| } else { |
| conn_evt_data.i93_cmd_cplt.status = p_rw_data->i93_cmd_cmpl.status; |
| conn_evt_data.i93_cmd_cplt.sent_command = |
| p_rw_data->i93_cmd_cmpl.command; |
| |
| if (conn_evt_data.i93_cmd_cplt.status != NFC_STATUS_OK) |
| conn_evt_data.i93_cmd_cplt.params.error_code = |
| p_rw_data->i93_cmd_cmpl.error_code; |
| |
| nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); |
| } |
| |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; /* clear current operation */ |
| break; |
| |
| default: |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("; Unhandled RW event 0x%X", event); |
| break; |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_cback |
| ** |
| ** Description Callback for reader/writer event notification |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("nfa_rw_cback: event=0x%02x", event); |
| |
| /* Call appropriate event handler for tag type */ |
| if (event < RW_T1T_MAX_EVT) { |
| /* Handle Type-1 tag events */ |
| nfa_rw_handle_t1t_evt(event, p_rw_data); |
| } else if (event < RW_T2T_MAX_EVT) { |
| /* Handle Type-2 tag events */ |
| nfa_rw_handle_t2t_evt(event, p_rw_data); |
| } else if (event < RW_T3T_MAX_EVT) { |
| /* Handle Type-3 tag events */ |
| nfa_rw_handle_t3t_evt(event, p_rw_data); |
| } else if (event < RW_T4T_MAX_EVT) { |
| /* Handle Type-4 tag events */ |
| nfa_rw_handle_t4t_evt(event, p_rw_data); |
| } else if (event < RW_I93_MAX_EVT) { |
| /* Handle ISO 15693 tag events */ |
| nfa_rw_handle_i93_evt(event, p_rw_data); |
| } else { |
| LOG(ERROR) << StringPrintf("nfa_rw_cback: unhandled event=0x%02x", event); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_start_ndef_detection |
| ** |
| ** Description Start NDEF detection on activated tag |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static tNFC_STATUS nfa_rw_start_ndef_detection(void) { |
| tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| |
| if (NFC_PROTOCOL_T1T == protocol) { |
| /* Type1Tag - NFC-A */ |
| status = RW_T1tDetectNDef(); |
| } else if (NFC_PROTOCOL_T2T == protocol) { |
| /* Type2Tag - NFC-A */ |
| if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { |
| status = RW_T2tDetectNDef(nfa_rw_cb.skip_dyn_locks); |
| } |
| } else if (NFC_PROTOCOL_T3T == protocol) { |
| /* Type3Tag - NFC-F */ |
| status = RW_T3tDetectNDef(); |
| } else if (NFC_PROTOCOL_ISO_DEP == protocol) { |
| /* ISODEP/4A,4B- NFC-A or NFC-B */ |
| status = RW_T4tDetectNDef(); |
| } else if (NFC_PROTOCOL_T5T == protocol) { |
| /* ISO 15693 */ |
| status = RW_I93DetectNDef(); |
| } |
| |
| return (status); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_start_ndef_read |
| ** |
| ** Description Start NDEF read on activated tag |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static tNFC_STATUS nfa_rw_start_ndef_read(void) { |
| tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| /* Handle zero length NDEF message */ |
| if (nfa_rw_cb.ndef_cur_size == 0) { |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("NDEF message is zero-length"); |
| |
| /* Send zero-lengh NDEF message to ndef callback */ |
| nfa_dm_ndef_handle_message(NFA_STATUS_OK, NULL, 0); |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.status = NFA_STATUS_OK; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| return NFC_STATUS_OK; |
| } |
| |
| /* Allocate buffer for incoming NDEF message (free previous NDEF rx buffer, if |
| * needed) */ |
| nfa_rw_free_ndef_rx_buf(); |
| nfa_rw_cb.p_ndef_buf = (uint8_t*)nfa_mem_co_alloc(nfa_rw_cb.ndef_cur_size); |
| if (nfa_rw_cb.p_ndef_buf == NULL) { |
| LOG(ERROR) << StringPrintf( |
| "Unable to allocate a buffer for reading NDEF (size=%i)", |
| nfa_rw_cb.ndef_cur_size); |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| return NFC_STATUS_FAILED; |
| } |
| nfa_rw_cb.ndef_rd_offset = 0; |
| |
| if (NFC_PROTOCOL_T1T == protocol) { |
| /* Type1Tag - NFC-A */ |
| status = |
| RW_T1tReadNDef(nfa_rw_cb.p_ndef_buf, (uint16_t)nfa_rw_cb.ndef_cur_size); |
| } else if (NFC_PROTOCOL_T2T == protocol) { |
| /* Type2Tag - NFC-A */ |
| if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { |
| status = RW_T2tReadNDef(nfa_rw_cb.p_ndef_buf, |
| (uint16_t)nfa_rw_cb.ndef_cur_size); |
| } |
| } else if (NFC_PROTOCOL_T3T == protocol) { |
| /* Type3Tag - NFC-F */ |
| status = RW_T3tCheckNDef(); |
| } else if (NFC_PROTOCOL_ISO_DEP == protocol) { |
| /* ISODEP/4A,4B- NFC-A or NFC-B */ |
| status = RW_T4tReadNDef(); |
| } else if (NFC_PROTOCOL_T5T == protocol) { |
| /* ISO 15693 */ |
| status = RW_I93ReadNDef(); |
| } |
| |
| return (status); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_detect_ndef |
| ** |
| ** Description Handler for NFA_RW_API_DETECT_NDEF_EVT |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_detect_ndef() { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| DLOG_IF(INFO, nfc_debug_enabled) << __func__; |
| |
| conn_evt_data.ndef_detect.status = nfa_rw_start_ndef_detection(); |
| if (conn_evt_data.ndef_detect.status != NFC_STATUS_OK) { |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.ndef_detect.cur_size = 0; |
| conn_evt_data.ndef_detect.max_size = 0; |
| conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; |
| nfa_dm_act_conn_cback_notify(NFA_NDEF_DETECT_EVT, &conn_evt_data); |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_start_ndef_write |
| ** |
| ** Description Start NDEF write on activated tag |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static tNFC_STATUS nfa_rw_start_ndef_write(void) { |
| tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| |
| if (nfa_rw_cb.flags & NFA_RW_FL_TAG_IS_READONLY) { |
| /* error: ndef tag is read-only */ |
| status = NFC_STATUS_FAILED; |
| LOG(ERROR) << StringPrintf("Unable to write NDEF. Tag is read-only"); |
| } else if (nfa_rw_cb.ndef_max_size < nfa_rw_cb.ndef_wr_len) { |
| /* error: ndef tag size is too small */ |
| status = NFC_STATUS_BUFFER_FULL; |
| LOG(ERROR) << StringPrintf( |
| "Unable to write NDEF. Tag maxsize=%i, request write size=%i", |
| nfa_rw_cb.ndef_max_size, nfa_rw_cb.ndef_wr_len); |
| } else { |
| if (NFC_PROTOCOL_T1T == protocol) { |
| /* Type1Tag - NFC-A */ |
| status = RW_T1tWriteNDef((uint16_t)nfa_rw_cb.ndef_wr_len, |
| nfa_rw_cb.p_ndef_wr_buf); |
| } else if (NFC_PROTOCOL_T2T == protocol) { |
| /* Type2Tag - NFC-A */ |
| if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { |
| status = RW_T2tWriteNDef((uint16_t)nfa_rw_cb.ndef_wr_len, |
| nfa_rw_cb.p_ndef_wr_buf); |
| } |
| } else if (NFC_PROTOCOL_T3T == protocol) { |
| /* Type3Tag - NFC-F */ |
| status = RW_T3tUpdateNDef(nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf); |
| } else if (NFC_PROTOCOL_ISO_DEP == protocol) { |
| /* ISODEP/4A,4B- NFC-A or NFC-B */ |
| status = RW_T4tUpdateNDef((uint16_t)nfa_rw_cb.ndef_wr_len, |
| nfa_rw_cb.p_ndef_wr_buf); |
| } else if (NFC_PROTOCOL_T5T == protocol) { |
| /* ISO 15693 */ |
| status = RW_I93UpdateNDef((uint16_t)nfa_rw_cb.ndef_wr_len, |
| nfa_rw_cb.p_ndef_wr_buf); |
| } |
| } |
| |
| return (status); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_read_ndef |
| ** |
| ** Description Handler for NFA_RW_API_READ_NDEF_EVT |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_read_ndef() { |
| tNFA_STATUS status = NFA_STATUS_OK; |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << __func__; |
| |
| /* Check if ndef detection has been performed yet */ |
| if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_UNKNOWN) { |
| /* Perform ndef detection first */ |
| status = nfa_rw_start_ndef_detection(); |
| } else if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_FALSE) { |
| /* Tag is not NDEF */ |
| status = NFA_STATUS_FAILED; |
| } else { |
| /* Perform the NDEF read operation */ |
| status = nfa_rw_start_ndef_read(); |
| } |
| |
| /* Handle failure */ |
| if (status != NFA_STATUS_OK) { |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.status = status; |
| nfa_dm_act_conn_cback_notify(NFA_READ_CPLT_EVT, &conn_evt_data); |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_write_ndef |
| ** |
| ** Description Handler for NFA_RW_API_WRITE_NDEF_EVT |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_write_ndef(tNFA_RW_MSG* p_data) { |
| tNDEF_STATUS ndef_status; |
| tNFA_STATUS write_status = NFA_STATUS_OK; |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| DLOG_IF(INFO, nfc_debug_enabled) << __func__; |
| |
| /* Validate NDEF message */ |
| ndef_status = NDEF_MsgValidate(p_data->op_req.params.write_ndef.p_data, |
| p_data->op_req.params.write_ndef.len, false); |
| if (ndef_status != NDEF_OK) { |
| LOG(ERROR) << StringPrintf( |
| "Invalid NDEF message. NDEF_MsgValidate returned %i", ndef_status); |
| |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.status = NFA_STATUS_FAILED; |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| return true; |
| } |
| |
| /* Store pointer to source NDEF */ |
| nfa_rw_cb.p_ndef_wr_buf = p_data->op_req.params.write_ndef.p_data; |
| nfa_rw_cb.ndef_wr_len = p_data->op_req.params.write_ndef.len; |
| |
| /* Check if ndef detection has been performed yet */ |
| if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_UNKNOWN) { |
| /* Perform ndef detection first */ |
| write_status = nfa_rw_start_ndef_detection(); |
| } else if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_FALSE) { |
| if (nfa_rw_cb.protocol == NFC_PROTOCOL_T1T) { |
| /* For Type 1 tag, NDEF can be written on Initialized tag |
| * Perform ndef detection first to check if tag is in Initialized state to |
| * Write NDEF */ |
| write_status = nfa_rw_start_ndef_detection(); |
| } else { |
| /* Tag is not NDEF */ |
| write_status = NFA_STATUS_FAILED; |
| } |
| } else { |
| /* Perform the NDEF read operation */ |
| write_status = nfa_rw_start_ndef_write(); |
| } |
| |
| /* Handle failure */ |
| if (write_status != NFA_STATUS_OK) { |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| conn_evt_data.status = write_status; |
| nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_presence_check |
| ** |
| ** Description Handler for NFA_RW_API_PRESENCE_CHECK |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| void nfa_rw_presence_check(tNFA_RW_MSG* p_data) { |
| tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; |
| uint8_t sel_res = nfa_rw_cb.pa_sel_res; |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| bool unsupported = false; |
| uint8_t option = NFA_RW_OPTION_INVALID; |
| tNFA_RW_PRES_CHK_OPTION op_param = NFA_RW_PRES_CHK_DEFAULT; |
| |
| if (NFC_PROTOCOL_T1T == protocol) { |
| /* Type1Tag - NFC-A */ |
| status = RW_T1tPresenceCheck(); |
| } else if (NFC_PROTOCOL_T2T == protocol) { |
| /* If T2T NFC-Forum, then let RW handle presence check */ |
| if (sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { |
| /* Type 2 tag have not sent NACK after activation */ |
| status = RW_T2tPresenceCheck(); |
| } else { |
| /* Will fall back to deactivate/reactivate */ |
| unsupported = true; |
| } |
| } else if (NFC_PROTOCOL_T3T == protocol) { |
| /* Type3Tag - NFC-F */ |
| status = RW_T3tPresenceCheck(); |
| } else if (NFC_PROTOCOL_ISO_DEP == protocol) { |
| /* ISODEP/4A,4B- NFC-A or NFC-B */ |
| if (p_data) { |
| op_param = p_data->op_req.params.option; |
| } |
| |
| switch (op_param) { |
| case NFA_RW_PRES_CHK_I_BLOCK: |
| option = RW_T4T_CHK_EMPTY_I_BLOCK; |
| break; |
| |
| case NFA_RW_PRES_CHK_RESET: |
| /* option is initialized to NFA_RW_OPTION_INVALID, which will Deactivate |
| * to Sleep; Re-activate */ |
| break; |
| |
| case NFA_RW_PRES_CHK_RB_CH0: |
| option = RW_T4T_CHK_READ_BINARY_CH0; |
| break; |
| |
| case NFA_RW_PRES_CHK_RB_CH3: |
| option = RW_T4T_CHK_READ_BINARY_CH3; |
| break; |
| |
| case NFA_RW_PRES_CHK_ISO_DEP_NAK: |
| if (NFC_GetNCIVersion() == NCI_VERSION_2_0) { |
| option = RW_T4T_CHK_ISO_DEP_NAK_PRES_CHK; |
| } |
| break; |
| default: |
| if (nfa_rw_cb.flags & NFA_RW_FL_NDEF_OK) { |
| /* read binary on channel 0 */ |
| option = RW_T4T_CHK_READ_BINARY_CH0; |
| } else { |
| /* NDEF DETECT failed.*/ |
| if (nfa_dm_is_raw_frame_session()) { |
| /* NFA_SendRawFrame() is called */ |
| if (p_nfa_dm_cfg->presence_check_option & |
| NFA_DM_PCO_EMPTY_I_BLOCK) { |
| /* empty I block */ |
| option = RW_T4T_CHK_EMPTY_I_BLOCK; |
| } else { |
| /* read binary on channel 3 */ |
| option = RW_T4T_CHK_READ_BINARY_CH3; |
| } |
| } else if (!(p_nfa_dm_cfg->presence_check_option & |
| NFA_DM_PCO_ISO_SLEEP_WAKE) && |
| (nfa_rw_cb.intf_type == NFC_INTERFACE_ISO_DEP)) { |
| /* the option indicates to use empty I block && ISODEP interface is |
| * activated */ |
| option = RW_T4T_CHK_EMPTY_I_BLOCK; |
| } |
| } |
| } |
| |
| if (option != NFA_RW_OPTION_INVALID) { |
| /* use the presence check with the chosen option */ |
| status = RW_T4tPresenceCheck(option); |
| } else { |
| /* use sleep/wake for presence check */ |
| unsupported = true; |
| } |
| } else if (NFC_PROTOCOL_T5T == protocol) { |
| /* T5T/ISO 15693 */ |
| status = RW_I93PresenceCheck(); |
| } else { |
| /* Protocol unsupported by RW module... */ |
| unsupported = true; |
| } |
| |
| if (unsupported) { |
| if (nfa_rw_cb.activated_tech_mode == NFC_DISCOVERY_TYPE_POLL_KOVIO) { |
| /* start Kovio presence check (deactivate and wait for activation) */ |
| status = nfa_dm_disc_start_kovio_presence_check(); |
| } else { |
| /* Let DM perform presence check (by putting tag to sleep and then waking |
| * it up) */ |
| status = nfa_dm_disc_sleep_wakeup(); |
| } |
| } |
| |
| /* Handle presence check failure */ |
| if (status != NFC_STATUS_OK) |
| nfa_rw_handle_presence_check_rsp(NFC_STATUS_FAILED); |
| else if (!unsupported) { |
| nfa_sys_start_timer(&nfa_rw_cb.tle, NFA_RW_PRESENCE_CHECK_TIMEOUT_EVT, |
| p_nfa_dm_cfg->presence_check_timeout); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_presence_check_tick |
| ** |
| ** Description Called on expiration of NFA_RW_PRESENCE_CHECK_INTERVAL |
| ** Initiate presence check |
| ** |
| ** Returns TRUE (caller frees message buffer) |
| ** |
| *******************************************************************************/ |
| bool nfa_rw_presence_check_tick(__attribute__((unused)) tNFA_RW_MSG* p_data) { |
| /* Store the current operation */ |
| nfa_rw_cb.cur_op = NFA_RW_OP_PRESENCE_CHECK; |
| nfa_rw_cb.flags |= NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY; |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("Auto-presence check starting..."); |
| |
| /* Perform presence check */ |
| nfa_rw_presence_check(NULL); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_presence_check_timeout |
| ** |
| ** Description presence check timeout: report presence check failure |
| ** |
| ** Returns TRUE (caller frees message buffer) |
| ** |
| *******************************************************************************/ |
| bool nfa_rw_presence_check_timeout(__attribute__((unused)) |
| tNFA_RW_MSG* p_data) { |
| nfa_rw_handle_presence_check_rsp(NFC_STATUS_FAILED); |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_format_tag |
| ** |
| ** Description Handler for NFA_RW_API_FORMAT_TAG |
| ** |
| ** Returns Nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_format_tag() { |
| tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| |
| if (protocol == NFC_PROTOCOL_T1T) { |
| status = RW_T1tFormatNDef(); |
| } else if ((protocol == NFC_PROTOCOL_T2T) && |
| (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T)) { |
| status = RW_T2tFormatNDef(); |
| } else if (protocol == NFC_PROTOCOL_T3T) { |
| status = RW_T3tFormatNDef(); |
| } else if (protocol == NFC_PROTOCOL_T5T) { |
| status = RW_I93FormatNDef(); |
| } else if (protocol == NFC_PROTOCOL_ISO_DEP) { |
| status = RW_T4tFormatNDef(); |
| } |
| |
| /* If unable to format NDEF, notify the app */ |
| if (status != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_FORMAT_CPLT_EVT); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_detect_tlv |
| ** |
| ** Description Handler for NFA_RW_API_DETECT_NDEF_EVT |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_detect_tlv(uint8_t tlv) { |
| DLOG_IF(INFO, nfc_debug_enabled) << __func__; |
| |
| switch (nfa_rw_cb.protocol) { |
| case NFC_PROTOCOL_T1T: |
| if (RW_T1tLocateTlv(tlv) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_TLV_DETECT_EVT); |
| break; |
| |
| case NFC_PROTOCOL_T2T: |
| if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { |
| if (RW_T2tLocateTlv(tlv) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_TLV_DETECT_EVT); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_config_tag_ro |
| ** |
| ** Description Handler for NFA_RW_OP_SET_TAG_RO |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static tNFC_STATUS nfa_rw_config_tag_ro(bool b_hard_lock) { |
| tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << __func__; |
| |
| if (NFC_PROTOCOL_T1T == protocol) { |
| /* Type1Tag - NFC-A */ |
| if ((nfa_rw_cb.tlv_st == NFA_RW_TLV_DETECT_ST_OP_NOT_STARTED) || |
| (nfa_rw_cb.tlv_st == NFA_RW_TLV_DETECT_ST_MEM_TLV_OP_COMPLETE)) { |
| status = RW_T1tLocateTlv(TAG_LOCK_CTRL_TLV); |
| return (status); |
| } else { |
| status = RW_T1tSetTagReadOnly(b_hard_lock); |
| } |
| } else if (NFC_PROTOCOL_T2T == protocol) { |
| /* Type2Tag - NFC-A */ |
| if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) { |
| status = RW_T2tSetTagReadOnly(b_hard_lock); |
| } |
| } else if (NFC_PROTOCOL_T3T == protocol) { |
| /* Type3Tag - NFC-F */ |
| status = RW_T3tSetReadOnly(b_hard_lock); |
| } else if (NFC_PROTOCOL_ISO_DEP == protocol) { |
| /* ISODEP/4A,4B- NFC-A or NFC-B */ |
| status = RW_T4tSetNDefReadOnly(); |
| } else if (NFC_PROTOCOL_T5T == protocol) { |
| /* ISO 15693 */ |
| status = RW_I93SetTagReadOnly(); |
| } |
| |
| if (status == NFC_STATUS_OK) { |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| } else { |
| nfa_rw_error_cleanup(NFA_SET_TAG_RO_EVT); |
| } |
| |
| return (status); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_rid |
| ** |
| ** Description Handler for T1T_RID API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_rid() { |
| if (RW_T1tRid() != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_rall |
| ** |
| ** Description Handler for T1T_ReadAll API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_rall() { |
| if (RW_T1tReadAll() != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_read |
| ** |
| ** Description Handler for T1T_Read API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_read(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T1T_READ* p_t1t_read = |
| (tNFA_RW_OP_PARAMS_T1T_READ*)&(p_data->op_req.params.t1t_read); |
| |
| if (RW_T1tRead(p_t1t_read->block_number, p_t1t_read->index) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_write |
| ** |
| ** Description Handler for T1T_WriteErase/T1T_WriteNoErase API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_write(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T1T_WRITE* p_t1t_write = |
| (tNFA_RW_OP_PARAMS_T1T_WRITE*)&(p_data->op_req.params.t1t_write); |
| tNFC_STATUS status; |
| |
| if (p_t1t_write->b_erase) { |
| status = RW_T1tWriteErase(p_t1t_write->block_number, p_t1t_write->index, |
| p_t1t_write->p_block_data[0]); |
| } else { |
| status = RW_T1tWriteNoErase(p_t1t_write->block_number, p_t1t_write->index, |
| p_t1t_write->p_block_data[0]); |
| } |
| |
| if (status != NFC_STATUS_OK) { |
| nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); |
| } else { |
| if (p_t1t_write->block_number == 0x01) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_rseg |
| ** |
| ** Description Handler for T1t_ReadSeg API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_rseg(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T1T_READ* p_t1t_read = |
| (tNFA_RW_OP_PARAMS_T1T_READ*)&(p_data->op_req.params.t1t_read); |
| |
| if (RW_T1tReadSeg(p_t1t_read->segment_number) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_read8 |
| ** |
| ** Description Handler for T1T_Read8 API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_read8(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T1T_READ* p_t1t_read = |
| (tNFA_RW_OP_PARAMS_T1T_READ*)&(p_data->op_req.params.t1t_read); |
| |
| if (RW_T1tRead8(p_t1t_read->block_number) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t1t_write8 |
| ** |
| ** Description Handler for T1T_WriteErase8/T1T_WriteNoErase8 API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t1t_write8(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T1T_WRITE* p_t1t_write = |
| (tNFA_RW_OP_PARAMS_T1T_WRITE*)&(p_data->op_req.params.t1t_write); |
| tNFC_STATUS status; |
| |
| if (p_t1t_write->b_erase) { |
| status = |
| RW_T1tWriteErase8(p_t1t_write->block_number, p_t1t_write->p_block_data); |
| } else { |
| status = RW_T1tWriteNoErase8(p_t1t_write->block_number, |
| p_t1t_write->p_block_data); |
| } |
| |
| if (status != NFC_STATUS_OK) { |
| nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); |
| } else { |
| if (p_t1t_write->block_number == 0x01) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t2t_read |
| ** |
| ** Description Handler for T2T_Read API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t2t_read(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T2T_READ* p_t2t_read = |
| (tNFA_RW_OP_PARAMS_T2T_READ*)&(p_data->op_req.params.t2t_read); |
| tNFC_STATUS status = NFC_STATUS_FAILED; |
| |
| if (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T) |
| status = RW_T2tRead(p_t2t_read->block_number); |
| |
| if (status != NFC_STATUS_OK) nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t2t_write |
| ** |
| ** Description Handler for T2T_Write API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t2t_write(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T2T_WRITE* p_t2t_write = |
| (tNFA_RW_OP_PARAMS_T2T_WRITE*)&(p_data->op_req.params.t2t_write); |
| |
| if (RW_T2tWrite(p_t2t_write->block_number, p_t2t_write->p_block_data) != |
| NFC_STATUS_OK) { |
| nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); |
| } else { |
| if (p_t2t_write->block_number == 0x03) |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t2t_sector_select |
| ** |
| ** Description Handler for T2T_Sector_Select API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t2t_sector_select(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T2T_SECTOR_SELECT* p_t2t_sector_select = |
| (tNFA_RW_OP_PARAMS_T2T_SECTOR_SELECT*)&( |
| p_data->op_req.params.t2t_sector_select); |
| |
| if (RW_T2tSectorSelect(p_t2t_sector_select->sector_number) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_SELECT_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t3t_read |
| ** |
| ** Description Handler for T3T_Read API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t3t_read(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T3T_READ* p_t3t_read = |
| (tNFA_RW_OP_PARAMS_T3T_READ*)&(p_data->op_req.params.t3t_read); |
| |
| if (RW_T3tCheck(p_t3t_read->num_blocks, |
| (tT3T_BLOCK_DESC*)p_t3t_read->p_block_desc) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_READ_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t3t_write |
| ** |
| ** Description Handler for T3T_Write API |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t3t_write(tNFA_RW_MSG* p_data) { |
| tNFA_RW_OP_PARAMS_T3T_WRITE* p_t3t_write = |
| (tNFA_RW_OP_PARAMS_T3T_WRITE*)&(p_data->op_req.params.t3t_write); |
| |
| if (RW_T3tUpdate(p_t3t_write->num_blocks, |
| (tT3T_BLOCK_DESC*)p_t3t_write->p_block_desc, |
| p_t3t_write->p_block_data) != NFC_STATUS_OK) |
| nfa_rw_error_cleanup(NFA_WRITE_CPLT_EVT); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_t3t_get_system_codes |
| ** |
| ** Description Get system codes (initiated by NFA after activation) |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_t3t_get_system_codes() { |
| tNFC_STATUS status; |
| tNFA_TAG_PARAMS tag_params; |
| |
| status = RW_T3tGetSystemCodes(); |
| |
| if (status != NFC_STATUS_OK) { |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| tag_params.t3t.num_system_codes = 0; |
| tag_params.t3t.p_system_codes = NULL; |
| |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &tag_params); |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_i93_command |
| ** |
| ** Description Handler for ISO 15693 command |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_i93_command(tNFA_RW_MSG* p_data) { |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| tNFC_STATUS status = NFC_STATUS_OK; |
| uint8_t i93_command = I93_CMD_STAY_QUIET; |
| |
| switch (p_data->op_req.op) { |
| case NFA_RW_OP_I93_INVENTORY: |
| i93_command = I93_CMD_INVENTORY; |
| if (p_data->op_req.params.i93_cmd.uid_present) { |
| status = RW_I93Inventory(p_data->op_req.params.i93_cmd.afi_present, |
| p_data->op_req.params.i93_cmd.afi, |
| p_data->op_req.params.i93_cmd.uid); |
| } else { |
| status = RW_I93Inventory(p_data->op_req.params.i93_cmd.afi_present, |
| p_data->op_req.params.i93_cmd.afi, NULL); |
| } |
| break; |
| |
| case NFA_RW_OP_I93_STAY_QUIET: |
| i93_command = I93_CMD_STAY_QUIET; |
| status = RW_I93StayQuiet(); |
| break; |
| |
| case NFA_RW_OP_I93_READ_SINGLE_BLOCK: |
| i93_command = I93_CMD_READ_SINGLE_BLOCK; |
| status = RW_I93ReadSingleBlock( |
| p_data->op_req.params.i93_cmd.first_block_number); |
| break; |
| |
| case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: |
| i93_command = I93_CMD_WRITE_SINGLE_BLOCK; |
| status = RW_I93WriteSingleBlock( |
| p_data->op_req.params.i93_cmd.first_block_number, |
| p_data->op_req.params.i93_cmd.p_data); |
| break; |
| |
| case NFA_RW_OP_I93_LOCK_BLOCK: |
| i93_command = I93_CMD_LOCK_BLOCK; |
| status = RW_I93LockBlock( |
| (uint8_t)p_data->op_req.params.i93_cmd.first_block_number); |
| break; |
| |
| case NFA_RW_OP_I93_READ_MULTI_BLOCK: |
| i93_command = I93_CMD_READ_MULTI_BLOCK; |
| status = RW_I93ReadMultipleBlocks( |
| p_data->op_req.params.i93_cmd.first_block_number, |
| p_data->op_req.params.i93_cmd.number_blocks); |
| break; |
| |
| case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: |
| i93_command = I93_CMD_WRITE_MULTI_BLOCK; |
| status = RW_I93WriteMultipleBlocks( |
| (uint8_t)p_data->op_req.params.i93_cmd.first_block_number, |
| p_data->op_req.params.i93_cmd.number_blocks, |
| p_data->op_req.params.i93_cmd.p_data); |
| break; |
| |
| case NFA_RW_OP_I93_SELECT: |
| i93_command = I93_CMD_SELECT; |
| status = RW_I93Select(p_data->op_req.params.i93_cmd.p_data); |
| break; |
| |
| case NFA_RW_OP_I93_RESET_TO_READY: |
| i93_command = I93_CMD_RESET_TO_READY; |
| status = RW_I93ResetToReady(); |
| break; |
| |
| case NFA_RW_OP_I93_WRITE_AFI: |
| i93_command = I93_CMD_WRITE_AFI; |
| status = RW_I93WriteAFI(p_data->op_req.params.i93_cmd.afi); |
| break; |
| |
| case NFA_RW_OP_I93_LOCK_AFI: |
| i93_command = I93_CMD_LOCK_AFI; |
| status = RW_I93LockAFI(); |
| break; |
| |
| case NFA_RW_OP_I93_WRITE_DSFID: |
| i93_command = I93_CMD_WRITE_DSFID; |
| status = RW_I93WriteDSFID(p_data->op_req.params.i93_cmd.dsfid); |
| break; |
| |
| case NFA_RW_OP_I93_LOCK_DSFID: |
| i93_command = I93_CMD_LOCK_DSFID; |
| status = RW_I93LockDSFID(); |
| break; |
| |
| case NFA_RW_OP_I93_GET_SYS_INFO: |
| i93_command = I93_CMD_GET_SYS_INFO; |
| if (p_data->op_req.params.i93_cmd.uid_present) { |
| status = RW_I93GetSysInfo(p_data->op_req.params.i93_cmd.uid); |
| } else { |
| status = RW_I93GetSysInfo(NULL); |
| } |
| break; |
| |
| case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: |
| i93_command = I93_CMD_GET_MULTI_BLK_SEC; |
| status = RW_I93GetMultiBlockSecurityStatus( |
| p_data->op_req.params.i93_cmd.first_block_number, |
| p_data->op_req.params.i93_cmd.number_blocks); |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (status != NFC_STATUS_OK) { |
| /* Command complete - perform cleanup, notify app */ |
| nfa_rw_command_complete(); |
| |
| conn_evt_data.i93_cmd_cplt.status = NFA_STATUS_FAILED; |
| conn_evt_data.i93_cmd_cplt.sent_command = i93_command; |
| |
| nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data); |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_raw_mode_data_cback |
| ** |
| ** Description Handler for incoming tag data for unsupported tag protocols |
| ** (forward data to upper layer) |
| ** |
| ** Returns nothing |
| ** |
| *******************************************************************************/ |
| static void nfa_rw_raw_mode_data_cback(__attribute__((unused)) uint8_t conn_id, |
| tNFC_CONN_EVT event, tNFC_CONN* p_data) { |
| NFC_HDR* p_msg; |
| tNFA_CONN_EVT_DATA evt_data; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event = 0x%X", event); |
| |
| if ((event == NFC_DATA_CEVT) && |
| ((p_data->data.status == NFC_STATUS_OK) || |
| (p_data->data.status == NFC_STATUS_CONTINUE))) { |
| p_msg = (NFC_HDR*)p_data->data.p_data; |
| |
| if (p_msg) { |
| evt_data.data.status = p_data->data.status; |
| evt_data.data.p_data = (uint8_t*)(p_msg + 1) + p_msg->offset; |
| evt_data.data.len = p_msg->len; |
| |
| nfa_dm_conn_cback_event_notify(NFA_DATA_EVT, &evt_data); |
| |
| GKI_freebuf(p_msg); |
| } else { |
| LOG(ERROR) << StringPrintf( |
| "received NFC_DATA_CEVT with NULL data pointer"); |
| } |
| } else if (event == NFC_DEACTIVATE_CEVT) { |
| NFC_SetStaticRfCback(NULL); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_activate_ntf |
| ** |
| ** Description Handler for NFA_RW_ACTIVATE_NTF |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| bool nfa_rw_activate_ntf(tNFA_RW_MSG* p_data) { |
| tNFC_ACTIVATE_DEVT* p_activate_params = |
| p_data->activate_ntf.p_activate_params; |
| tNFA_TAG_PARAMS tag_params; |
| bool activate_notify = true; |
| uint8_t* p; |
| |
| if ((nfa_rw_cb.halt_event != RW_T2T_MAX_EVT) && |
| (nfa_rw_cb.activated_tech_mode == NFC_DISCOVERY_TYPE_POLL_A) && |
| (nfa_rw_cb.protocol == NFC_PROTOCOL_T2T) && |
| (nfa_rw_cb.pa_sel_res == NFC_SEL_RES_NFC_FORUM_T2T)) { |
| /* Type 2 tag is wake up from HALT State */ |
| if (nfa_dm_cb.p_activate_ntf != NULL) { |
| GKI_freebuf(nfa_dm_cb.p_activate_ntf); |
| nfa_dm_cb.p_activate_ntf = NULL; |
| } |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("- Type 2 tag wake up from HALT State"); |
| return true; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) << __func__; |
| |
| /* Initialize control block */ |
| nfa_rw_cb.protocol = p_activate_params->protocol; |
| nfa_rw_cb.intf_type = p_activate_params->intf_param.type; |
| nfa_rw_cb.pa_sel_res = p_activate_params->rf_tech_param.param.pa.sel_rsp; |
| nfa_rw_cb.activated_tech_mode = p_activate_params->rf_tech_param.mode; |
| nfa_rw_cb.flags = NFA_RW_FL_ACTIVATED; |
| nfa_rw_cb.cur_op = NFA_RW_OP_MAX; |
| nfa_rw_cb.halt_event = RW_T2T_MAX_EVT; |
| nfa_rw_cb.skip_dyn_locks = false; |
| nfa_rw_cb.ndef_st = NFA_RW_NDEF_ST_UNKNOWN; |
| nfa_rw_cb.tlv_st = NFA_RW_TLV_DETECT_ST_OP_NOT_STARTED; |
| |
| memset(&tag_params, 0, sizeof(tNFA_TAG_PARAMS)); |
| |
| /* Check if we are in exclusive RF mode */ |
| if (p_data->activate_ntf.excl_rf_not_active) { |
| /* Not in exclusive RF mode */ |
| nfa_rw_cb.flags |= NFA_RW_FL_NOT_EXCL_RF_MODE; |
| } |
| |
| /* check if the protocol is activated with supported interface */ |
| if (p_activate_params->intf_param.type == NCI_INTERFACE_FRAME) { |
| if ((p_activate_params->protocol != NFA_PROTOCOL_T1T) && |
| (p_activate_params->protocol != NFA_PROTOCOL_T2T) && |
| (p_activate_params->protocol != NFA_PROTOCOL_T3T) && |
| (p_activate_params->protocol != NFA_PROTOCOL_T5T)) { |
| nfa_rw_cb.protocol = NFA_PROTOCOL_INVALID; |
| } |
| } else if (p_activate_params->intf_param.type == NCI_INTERFACE_ISO_DEP) { |
| if (p_activate_params->protocol != NFA_PROTOCOL_ISO_DEP) { |
| nfa_rw_cb.protocol = NFA_PROTOCOL_INVALID; |
| } |
| } |
| |
| if (nfa_rw_cb.protocol == NFA_PROTOCOL_INVALID) { |
| /* Only sending raw frame and presence check are supported in this state */ |
| |
| NFC_SetStaticRfCback(nfa_rw_raw_mode_data_cback); |
| |
| /* Notify app of NFA_ACTIVATED_EVT and start presence check timer */ |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, NULL); |
| nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); |
| return true; |
| } |
| |
| /* If protocol not supported by RW module, notify app of NFA_ACTIVATED_EVT and |
| * start presence check if needed */ |
| if (!nfa_dm_is_protocol_supported( |
| p_activate_params->protocol, |
| p_activate_params->rf_tech_param.param.pa.sel_rsp)) { |
| /* Notify upper layer of NFA_ACTIVATED_EVT if needed, and start presence |
| * check timer */ |
| /* Set data callback (pass all incoming data to upper layer using |
| * NFA_DATA_EVT) */ |
| NFC_SetStaticRfCback(nfa_rw_raw_mode_data_cback); |
| |
| /* Notify app of NFA_ACTIVATED_EVT and start presence check timer */ |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, NULL); |
| nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); |
| return true; |
| } |
| |
| /* Initialize RW module */ |
| if ((RW_SetActivatedTagType(p_activate_params, nfa_rw_cback)) != |
| NFC_STATUS_OK) { |
| /* Log error (stay in NFA_RW_ST_ACTIVATED state until deactivation) */ |
| LOG(ERROR) << StringPrintf("RW_SetActivatedTagType failed."); |
| return true; |
| } |
| |
| /* Perform protocol-specific actions */ |
| if (NFC_PROTOCOL_T1T == nfa_rw_cb.protocol) { |
| /* Retrieve HR and UID fields from activation notification */ |
| memcpy(tag_params.t1t.uid, p_activate_params->rf_tech_param.param.pa.nfcid1, |
| p_activate_params->rf_tech_param.param.pa.nfcid1_len); |
| |
| if (NFC_GetNCIVersion() == NCI_VERSION_2_0) { |
| memcpy(tag_params.t1t.hr, p_activate_params->rf_tech_param.param.pa.hr, |
| NFA_T1T_HR_LEN); |
| } else { |
| memcpy(tag_params.t1t.hr, |
| p_activate_params->intf_param.intf_param.frame.param, |
| NFA_T1T_HR_LEN); |
| tNFA_RW_MSG msg; |
| msg.op_req.op = NFA_RW_OP_T1T_RID; |
| nfa_rw_handle_op_req(&msg); |
| /* Delay notifying upper layer of NFA_ACTIVATED_EVT |
| until HR0/HR1 is received */ |
| activate_notify = false; |
| } |
| } else if (NFC_PROTOCOL_T2T == nfa_rw_cb.protocol) { |
| /* Retrieve UID fields from activation notification */ |
| memcpy(tag_params.t2t.uid, p_activate_params->rf_tech_param.param.pa.nfcid1, |
| p_activate_params->rf_tech_param.param.pa.nfcid1_len); |
| } else if (NFC_PROTOCOL_T3T == nfa_rw_cb.protocol) { |
| if (appl_dta_mode_flag) { |
| /* Incase of DTA mode Dont send commands to get system code. Just notify |
| * activation */ |
| activate_notify = true; |
| } else { |
| /* Delay notifying upper layer of NFA_ACTIVATED_EVT until system codes |
| * are retrieved */ |
| activate_notify = false; |
| |
| /* Issue command to get Felica system codes */ |
| tNFA_RW_MSG msg; |
| msg.op_req.op = NFA_RW_OP_T3T_GET_SYSTEM_CODES; |
| nfa_rw_handle_op_req(&msg); |
| } |
| } else if (NFA_PROTOCOL_T5T == nfa_rw_cb.protocol) { |
| /* Delay notifying upper layer of NFA_ACTIVATED_EVT to retrieve additional |
| * tag infomation */ |
| nfa_rw_cb.flags |= NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| activate_notify = false; |
| |
| /* store DSFID and UID from activation NTF */ |
| nfa_rw_cb.i93_dsfid = p_activate_params->rf_tech_param.param.pi93.dsfid; |
| |
| p = nfa_rw_cb.i93_uid; |
| ARRAY8_TO_STREAM(p, p_activate_params->rf_tech_param.param.pi93.uid); |
| |
| if ((nfa_rw_cb.i93_uid[1] == I93_UID_IC_MFG_CODE_TI) && |
| (((nfa_rw_cb.i93_uid[2] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) == |
| I93_UID_TAG_IT_HF_I_STD_CHIP_INLAY) || |
| ((nfa_rw_cb.i93_uid[2] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) == |
| I93_UID_TAG_IT_HF_I_PRO_CHIP_INLAY))) { |
| /* these don't support Get System Information Command */ |
| nfa_rw_cb.i93_block_size = I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_BLK_SIZE; |
| nfa_rw_cb.i93_afi_location = |
| I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_AFI_LOCATION; |
| |
| if ((nfa_rw_cb.i93_uid[2] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) == |
| I93_UID_TAG_IT_HF_I_STD_CHIP_INLAY) { |
| nfa_rw_cb.i93_num_block = I93_TAG_IT_HF_I_STD_CHIP_INLAY_NUM_TOTAL_BLK; |
| } else { |
| nfa_rw_cb.i93_num_block = I93_TAG_IT_HF_I_PRO_CHIP_INLAY_NUM_TOTAL_BLK; |
| } |
| |
| /* read AFI */ |
| if (RW_I93ReadSingleBlock((uint8_t)(nfa_rw_cb.i93_afi_location / |
| nfa_rw_cb.i93_block_size)) != |
| NFC_STATUS_OK) { |
| /* notify activation without AFI/IC-Ref */ |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| activate_notify = true; |
| |
| tag_params.i93.info_flags = |
| (I93_INFO_FLAG_DSFID | I93_INFO_FLAG_MEM_SIZE); |
| tag_params.i93.dsfid = nfa_rw_cb.i93_dsfid; |
| tag_params.i93.block_size = nfa_rw_cb.i93_block_size; |
| tag_params.i93.num_block = nfa_rw_cb.i93_num_block; |
| memcpy(tag_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); |
| } |
| } else { |
| /* All of ICODE supports Get System Information Command */ |
| /* Tag-it HF-I Plus Chip/Inlay supports Get System Information Command */ |
| /* just try for others */ |
| |
| if (RW_I93GetSysInfo(nfa_rw_cb.i93_uid) != NFC_STATUS_OK) { |
| /* notify activation without AFI/MEM size/IC-Ref */ |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING; |
| activate_notify = true; |
| |
| tag_params.i93.info_flags = I93_INFO_FLAG_DSFID; |
| tag_params.i93.dsfid = nfa_rw_cb.i93_dsfid; |
| tag_params.i93.block_size = 0; |
| tag_params.i93.num_block = 0; |
| memcpy(tag_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN); |
| } else { |
| /* reset memory size */ |
| nfa_rw_cb.i93_block_size = 0; |
| nfa_rw_cb.i93_num_block = 0; |
| } |
| } |
| } |
| |
| /* Notify upper layer of NFA_ACTIVATED_EVT if needed, and start presence check |
| * timer */ |
| if (activate_notify) { |
| nfa_dm_notify_activation_status(NFA_STATUS_OK, &tag_params); |
| nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); |
| } |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_deactivate_ntf |
| ** |
| ** Description Handler for NFA_RW_DEACTIVATE_NTF |
| ** |
| ** Returns TRUE (message buffer to be freed by caller) |
| ** |
| *******************************************************************************/ |
| bool nfa_rw_deactivate_ntf(__attribute__((unused)) tNFA_RW_MSG* p_data) { |
| /* Clear the activated flag */ |
| nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATED; |
| |
| /* Free buffer for incoming NDEF message, in case we were in the middle of a |
| * read operation */ |
| nfa_rw_free_ndef_rx_buf(); |
| |
| /* If there is a pending command message, then free it */ |
| if (nfa_rw_cb.p_pending_msg) { |
| if ((nfa_rw_cb.p_pending_msg->op_req.op == NFA_RW_OP_SEND_RAW_FRAME) && |
| (nfa_rw_cb.p_pending_msg->op_req.params.send_raw_frame.p_data)) { |
| GKI_freebuf(nfa_rw_cb.p_pending_msg->op_req.params.send_raw_frame.p_data); |
| } |
| |
| GKI_freebuf(nfa_rw_cb.p_pending_msg); |
| nfa_rw_cb.p_pending_msg = NULL; |
| } |
| |
| /* If we are in the process of waking up tag from HALT state */ |
| if (nfa_rw_cb.halt_event == RW_T2T_READ_CPLT_EVT) { |
| if (nfa_rw_cb.rw_data.data.p_data) |
| GKI_freebuf(nfa_rw_cb.rw_data.data.p_data); |
| nfa_rw_cb.rw_data.data.p_data = NULL; |
| } |
| |
| /* Stop presence check timer (if started) */ |
| nfa_rw_stop_presence_check_timer(); |
| |
| return true; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_handle_op_req |
| ** |
| ** Description Handler for NFA_RW_OP_REQUEST_EVT, operation request |
| ** |
| ** Returns TRUE if caller should free p_data |
| ** FALSE if caller does not need to free p_data |
| ** |
| *******************************************************************************/ |
| bool nfa_rw_handle_op_req(tNFA_RW_MSG* p_data) { |
| bool freebuf = true; |
| uint16_t presence_check_start_delay = 0; |
| |
| /* Check if activated */ |
| if (!(nfa_rw_cb.flags & NFA_RW_FL_ACTIVATED)) { |
| LOG(ERROR) << StringPrintf("nfa_rw_handle_op_req: not activated"); |
| return true; |
| } |
| /* Check if currently busy with another API call */ |
| else if (nfa_rw_cb.flags & NFA_RW_FL_API_BUSY) { |
| return (nfa_rw_op_req_while_busy(p_data)); |
| } |
| /* Check if currently busy with auto-presence check */ |
| else if (nfa_rw_cb.flags & NFA_RW_FL_AUTO_PRESENCE_CHECK_BUSY) { |
| /* Cache the command (will be handled once auto-presence check is completed) |
| */ |
| DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( |
| "Deferring operation %i until after auto-presence check is completed", |
| p_data->op_req.op); |
| nfa_rw_cb.p_pending_msg = p_data; |
| nfa_rw_cb.flags |= NFA_RW_FL_API_BUSY; |
| return false; |
| } |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("nfa_rw_handle_op_req: op=0x%02x", p_data->op_req.op); |
| |
| nfa_rw_cb.flags |= NFA_RW_FL_API_BUSY; |
| |
| /* Stop the presence check timer */ |
| nfa_rw_stop_presence_check_timer(); |
| |
| /* Store the current operation */ |
| nfa_rw_cb.cur_op = p_data->op_req.op; |
| |
| /* Call appropriate handler for requested operation */ |
| switch (p_data->op_req.op) { |
| case NFA_RW_OP_DETECT_NDEF: |
| nfa_rw_cb.skip_dyn_locks = false; |
| nfa_rw_detect_ndef(); |
| break; |
| |
| case NFA_RW_OP_READ_NDEF: |
| nfa_rw_read_ndef(); |
| break; |
| |
| case NFA_RW_OP_WRITE_NDEF: |
| nfa_rw_write_ndef(p_data); |
| break; |
| |
| case NFA_RW_OP_SEND_RAW_FRAME: |
| presence_check_start_delay = |
| p_data->op_req.params.send_raw_frame.p_data->layer_specific; |
| |
| NFC_SendData(NFC_RF_CONN_ID, p_data->op_req.params.send_raw_frame.p_data); |
| |
| /* Clear the busy flag */ |
| nfa_rw_cb.flags &= ~NFA_RW_FL_API_BUSY; |
| |
| /* Start presence_check after specified delay */ |
| nfa_rw_check_start_presence_check_timer(presence_check_start_delay); |
| break; |
| |
| case NFA_RW_OP_PRESENCE_CHECK: |
| nfa_rw_presence_check(p_data); |
| break; |
| |
| case NFA_RW_OP_FORMAT_TAG: |
| nfa_rw_format_tag(); |
| break; |
| |
| case NFA_RW_OP_DETECT_LOCK_TLV: |
| nfa_rw_detect_tlv(TAG_LOCK_CTRL_TLV); |
| break; |
| |
| case NFA_RW_OP_DETECT_MEM_TLV: |
| nfa_rw_detect_tlv(TAG_MEM_CTRL_TLV); |
| break; |
| |
| case NFA_RW_OP_SET_TAG_RO: |
| nfa_rw_cb.b_hard_lock = p_data->op_req.params.set_readonly.b_hard_lock; |
| nfa_rw_config_tag_ro(nfa_rw_cb.b_hard_lock); |
| break; |
| |
| case NFA_RW_OP_T1T_RID: |
| nfa_rw_t1t_rid(); |
| break; |
| |
| case NFA_RW_OP_T1T_RALL: |
| nfa_rw_t1t_rall(); |
| break; |
| |
| case NFA_RW_OP_T1T_READ: |
| nfa_rw_t1t_read(p_data); |
| break; |
| |
| case NFA_RW_OP_T1T_WRITE: |
| nfa_rw_t1t_write(p_data); |
| break; |
| |
| case NFA_RW_OP_T1T_RSEG: |
| nfa_rw_t1t_rseg(p_data); |
| break; |
| |
| case NFA_RW_OP_T1T_READ8: |
| nfa_rw_t1t_read8(p_data); |
| break; |
| |
| case NFA_RW_OP_T1T_WRITE8: |
| nfa_rw_t1t_write8(p_data); |
| break; |
| |
| /* Type-2 tag commands */ |
| case NFA_RW_OP_T2T_READ: |
| nfa_rw_t2t_read(p_data); |
| break; |
| |
| case NFA_RW_OP_T2T_WRITE: |
| nfa_rw_t2t_write(p_data); |
| break; |
| |
| case NFA_RW_OP_T2T_SECTOR_SELECT: |
| nfa_rw_t2t_sector_select(p_data); |
| break; |
| |
| /* Type-3 tag commands */ |
| case NFA_RW_OP_T3T_READ: |
| nfa_rw_t3t_read(p_data); |
| break; |
| |
| case NFA_RW_OP_T3T_WRITE: |
| nfa_rw_t3t_write(p_data); |
| break; |
| |
| case NFA_RW_OP_T3T_GET_SYSTEM_CODES: |
| nfa_rw_t3t_get_system_codes(); |
| break; |
| |
| /* ISO 15693 tag commands */ |
| case NFA_RW_OP_I93_INVENTORY: |
| case NFA_RW_OP_I93_STAY_QUIET: |
| case NFA_RW_OP_I93_READ_SINGLE_BLOCK: |
| case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: |
| case NFA_RW_OP_I93_LOCK_BLOCK: |
| case NFA_RW_OP_I93_READ_MULTI_BLOCK: |
| case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: |
| case NFA_RW_OP_I93_SELECT: |
| case NFA_RW_OP_I93_RESET_TO_READY: |
| case NFA_RW_OP_I93_WRITE_AFI: |
| case NFA_RW_OP_I93_LOCK_AFI: |
| case NFA_RW_OP_I93_WRITE_DSFID: |
| case NFA_RW_OP_I93_LOCK_DSFID: |
| case NFA_RW_OP_I93_GET_SYS_INFO: |
| case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: |
| nfa_rw_i93_command(p_data); |
| break; |
| |
| default: |
| LOG(ERROR) << StringPrintf("nfa_rw_handle_api: unhandled operation: %i", |
| p_data->op_req.op); |
| break; |
| } |
| |
| return (freebuf); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_op_req_while_busy |
| ** |
| ** Description Handle operation request while busy |
| ** |
| ** Returns TRUE if caller should free p_data |
| ** FALSE if caller does not need to free p_data |
| ** |
| *******************************************************************************/ |
| static bool nfa_rw_op_req_while_busy(tNFA_RW_MSG* p_data) { |
| bool freebuf = true; |
| tNFA_CONN_EVT_DATA conn_evt_data; |
| uint8_t event; |
| |
| LOG(ERROR) << StringPrintf("nfa_rw_op_req_while_busy: unable to handle API"); |
| |
| /* Return appropriate event for requested API, with status=BUSY */ |
| conn_evt_data.status = NFA_STATUS_BUSY; |
| |
| switch (p_data->op_req.op) { |
| case NFA_RW_OP_DETECT_NDEF: |
| conn_evt_data.ndef_detect.cur_size = 0; |
| conn_evt_data.ndef_detect.max_size = 0; |
| conn_evt_data.ndef_detect.flags = RW_NDEF_FL_UNKNOWN; |
| event = NFA_NDEF_DETECT_EVT; |
| break; |
| case NFA_RW_OP_READ_NDEF: |
| case NFA_RW_OP_T1T_RID: |
| case NFA_RW_OP_T1T_RALL: |
| case NFA_RW_OP_T1T_READ: |
| case NFA_RW_OP_T1T_RSEG: |
| case NFA_RW_OP_T1T_READ8: |
| case NFA_RW_OP_T2T_READ: |
| case NFA_RW_OP_T3T_READ: |
| event = NFA_READ_CPLT_EVT; |
| break; |
| case NFA_RW_OP_WRITE_NDEF: |
| case NFA_RW_OP_T1T_WRITE: |
| case NFA_RW_OP_T1T_WRITE8: |
| case NFA_RW_OP_T2T_WRITE: |
| case NFA_RW_OP_T3T_WRITE: |
| event = NFA_WRITE_CPLT_EVT; |
| break; |
| case NFA_RW_OP_FORMAT_TAG: |
| event = NFA_FORMAT_CPLT_EVT; |
| break; |
| case NFA_RW_OP_DETECT_LOCK_TLV: |
| case NFA_RW_OP_DETECT_MEM_TLV: |
| event = NFA_TLV_DETECT_EVT; |
| break; |
| case NFA_RW_OP_SET_TAG_RO: |
| event = NFA_SET_TAG_RO_EVT; |
| break; |
| case NFA_RW_OP_T2T_SECTOR_SELECT: |
| event = NFA_SELECT_CPLT_EVT; |
| break; |
| case NFA_RW_OP_I93_INVENTORY: |
| case NFA_RW_OP_I93_STAY_QUIET: |
| case NFA_RW_OP_I93_READ_SINGLE_BLOCK: |
| case NFA_RW_OP_I93_WRITE_SINGLE_BLOCK: |
| case NFA_RW_OP_I93_LOCK_BLOCK: |
| case NFA_RW_OP_I93_READ_MULTI_BLOCK: |
| case NFA_RW_OP_I93_WRITE_MULTI_BLOCK: |
| case NFA_RW_OP_I93_SELECT: |
| case NFA_RW_OP_I93_RESET_TO_READY: |
| case NFA_RW_OP_I93_WRITE_AFI: |
| case NFA_RW_OP_I93_LOCK_AFI: |
| case NFA_RW_OP_I93_WRITE_DSFID: |
| case NFA_RW_OP_I93_LOCK_DSFID: |
| case NFA_RW_OP_I93_GET_SYS_INFO: |
| case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS: |
| event = NFA_I93_CMD_CPLT_EVT; |
| break; |
| default: |
| return (freebuf); |
| } |
| nfa_dm_act_conn_cback_notify(event, &conn_evt_data); |
| |
| return (freebuf); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function nfa_rw_command_complete |
| ** |
| ** Description Handle command complete: clear the busy flag, |
| ** and start the presence check timer if applicable. |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void nfa_rw_command_complete(void) { |
| /* Clear the busy flag */ |
| nfa_rw_cb.flags &= ~NFA_RW_FL_API_BUSY; |
| |
| /* Restart presence_check timer */ |
| nfa_rw_check_start_presence_check_timer(NFA_RW_PRESENCE_CHECK_INTERVAL); |
| } |