blob: e428bd59734a11dfb4e1ab3a513432d6d87a9ab6 [file] [log] [blame]
/******************************************************************************
*
* 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 implementation for Type 1 tag NDEF operation in
* Reader/Writer mode.
*
******************************************************************************/
#include <string>
#include <android-base/stringprintf.h>
#include <base/logging.h>
#include "nfc_target.h"
#include "nci_hmsgs.h"
#include "nfc_api.h"
#include "rw_api.h"
#include "rw_int.h"
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
#if (RW_NDEF_INCLUDED == TRUE)
/* Local Functions */
static tNFC_STATUS rw_t1t_handle_rall_rsp(bool* p_notify, uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_dyn_read_rsp(bool* p_notify, uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_write_rsp(bool* p_notify, uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_read_rsp(bool* p_callback, uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_tlv_detect_rsp(uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_ndef_read_rsp(uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_ndef_write_rsp(uint8_t* p_data);
static tNFC_STATUS rw_t1t_handle_ndef_rall_rsp(void);
static tNFC_STATUS rw_t1t_ndef_write_first_block(void);
static tNFC_STATUS rw_t1t_next_ndef_write_block(void);
static tNFC_STATUS rw_t1t_send_ndef_byte(uint8_t data, uint8_t block,
uint8_t index, uint8_t msg_len);
static tNFC_STATUS rw_t1t_send_ndef_block(uint8_t* p_data, uint8_t block);
static uint8_t rw_t1t_prepare_ndef_bytes(uint8_t* p_data,
uint8_t* p_length_field,
uint8_t* p_index, bool b_one_byte,
uint8_t block,
uint8_t lengthfield_len);
static uint8_t rw_t1t_get_ndef_flags(void);
static uint16_t rw_t1t_get_ndef_max_size(void);
static bool rw_t1t_is_lock_reserved_otp_byte(uint16_t index);
static bool rw_t1t_is_read_only_byte(uint16_t index);
static uint8_t rw_t1t_get_lock_bits_for_segment(uint8_t segment,
uint8_t* p_start_byte,
uint8_t* p_start_bit,
uint8_t* p_end_byte);
static void rw_t1t_update_attributes(void);
static void rw_t1t_update_lock_attributes(void);
static void rw_t1t_extract_lock_bytes(uint8_t* p_data);
static void rw_t1t_update_tag_state(void);
const uint8_t rw_t1t_mask_bits[8] = {0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80};
/*******************************************************************************
**
** Function rw_t1t_handle_rsp
**
** Description This function handles the response received for all commands
** sent to tag
**
** Returns event to be sent to application
**
*******************************************************************************/
tRW_EVENT rw_t1t_handle_rsp(const tT1T_CMD_RSP_INFO* p_info, bool* p_notify,
uint8_t* p_data, tNFC_STATUS* p_status) {
tRW_EVENT rw_event;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t adds;
if ((p_t1t->state == RW_T1T_STATE_READ) ||
(p_t1t->state == RW_T1T_STATE_WRITE)) {
return t1t_info_to_evt(p_info);
}
rw_event = rw_t1t_info_to_event(p_info);
if (p_info->opcode == T1T_CMD_RALL) {
*p_status = rw_t1t_handle_rall_rsp(p_notify, p_data);
} else if (p_info->opcode == T1T_CMD_RSEG) {
adds = *p_data;
if (adds == 0) {
p_t1t->b_rseg = true;
rw_t1t_update_tag_state();
rw_t1t_update_attributes();
rw_t1t_update_lock_attributes();
memcpy(p_t1t->mem, (uint8_t*)(p_data + T1T_ADD_LEN), T1T_SEGMENT_SIZE);
}
*p_status = rw_t1t_handle_dyn_read_rsp(p_notify, p_data);
} else if (p_info->opcode == T1T_CMD_READ8) {
*p_status = rw_t1t_handle_dyn_read_rsp(p_notify, p_data);
} else {
*p_status = rw_t1t_handle_write_rsp(p_notify, p_data);
}
return rw_event;
}
/*******************************************************************************
**
** Function rw_t1t_info_to_event
**
** Description This function returns RW event code based on the current
** state
**
** Returns RW event code
**
*******************************************************************************/
tRW_EVENT rw_t1t_info_to_event(const tT1T_CMD_RSP_INFO* p_info) {
tRW_EVENT rw_event;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
switch (p_t1t->state) {
case RW_T1T_STATE_TLV_DETECT:
if (p_t1t->tlv_detect == TAG_NDEF_TLV)
rw_event = RW_T1T_NDEF_DETECT_EVT;
else
rw_event = RW_T1T_TLV_DETECT_EVT;
break;
case RW_T1T_STATE_READ_NDEF:
rw_event = RW_T1T_NDEF_READ_EVT;
break;
case RW_T1T_STATE_WRITE_NDEF:
rw_event = RW_T1T_NDEF_WRITE_EVT;
break;
case RW_T1T_STATE_SET_TAG_RO:
rw_event = RW_T1T_SET_TAG_RO_EVT;
break;
case RW_T1T_STATE_CHECK_PRESENCE:
rw_event = RW_T1T_PRESENCE_CHECK_EVT;
break;
case RW_T1T_STATE_FORMAT_TAG:
rw_event = RW_T1T_FORMAT_CPLT_EVT;
break;
default:
rw_event = t1t_info_to_evt(p_info);
break;
}
return rw_event;
}
/*******************************************************************************
**
** Function rw_t1t_extract_lock_bytes
**
** Description This function will extract lock bytes if any present in the
** response data
**
** Parameters p_data: Data bytes in the response of RSEG/READ8/RALL
** command
**
** Returns None
**
*******************************************************************************/
void rw_t1t_extract_lock_bytes(uint8_t* p_data) {
uint16_t end;
uint16_t start;
uint8_t num_locks;
uint16_t lock_offset = 0;
uint16_t offset;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tT1T_CMD_RSP_INFO* p_cmd_rsp_info =
(tT1T_CMD_RSP_INFO*)rw_cb.tcb.t1t.p_cmd_rsp_info;
num_locks = 0;
/* Based on the Command used to read Tag, calculate the offset of the tag read
*/
if (p_cmd_rsp_info->opcode == T1T_CMD_RSEG) {
start = p_t1t->segment * T1T_SEGMENT_SIZE;
end = start + T1T_SEGMENT_SIZE;
} else if (p_cmd_rsp_info->opcode == T1T_CMD_READ8) {
start = p_t1t->block_read * T1T_BLOCK_SIZE;
end = start + T1T_BLOCK_SIZE;
} else if (p_cmd_rsp_info->opcode == T1T_CMD_RALL) {
start = 0;
end = T1T_STATIC_SIZE;
} else
return;
/* Collect lock bytes that are present in the part of the data read from Tag
*/
while (num_locks < p_t1t->num_lockbytes) {
if (p_t1t->lockbyte[num_locks].b_lock_read == false) {
/* Get the exact offset of the dynamic lock byte in the tag */
offset = p_t1t->lock_tlv[p_t1t->lockbyte[num_locks].tlv_index].offset +
p_t1t->lockbyte[num_locks].byte_index;
if ((offset < end) && (offset >= start))
{
/* This dynamic lock byte is in the response */
if (p_cmd_rsp_info->opcode == T1T_CMD_RSEG) {
lock_offset = (offset % T1T_SEGMENT_SIZE);
} else if (p_cmd_rsp_info->opcode == T1T_CMD_READ8) {
lock_offset = (offset % T1T_BLOCK_SIZE);
} else if (p_cmd_rsp_info->opcode == T1T_CMD_RALL) {
lock_offset = offset;
}
p_t1t->lockbyte[num_locks].lock_byte = p_data[lock_offset];
p_t1t->lockbyte[num_locks].b_lock_read = true;
} else
break;
}
num_locks++;
}
}
/*******************************************************************************
**
** Function rw_t1t_update_tag_attributes
**
** Description This function will update tag attributes based on cc, ndef
** message length
**
** Returns None
**
*******************************************************************************/
void rw_t1t_update_tag_state(void) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
/* Set Tag state based on CC value and NDEF Message length */
if (((p_t1t->mem[T1T_CC_NMN_BYTE] == T1T_CC_NMN) ||
(p_t1t->mem[T1T_CC_NMN_BYTE] == 0)) &&
((p_t1t->mem[T1T_CC_VNO_BYTE] == T1T_CC_VNO) ||
(p_t1t->mem[T1T_CC_VNO_BYTE] == T1T_CC_LEGACY_VNO)) &&
((p_t1t->mem[T1T_CC_RWA_BYTE] == T1T_CC_RWA_RW) ||
(p_t1t->mem[T1T_CC_RWA_BYTE] == T1T_CC_RWA_RO))) {
/* Valid CC value, so Tag is initialized */
if (p_t1t->ndef_msg_len > 0) {
if (p_t1t->mem[T1T_CC_RWA_BYTE] == T1T_CC_RWA_RO) {
/* NDEF Message presence, CC indication sets Tag as READ ONLY */
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_READ_ONLY;
} else if (p_t1t->mem[T1T_CC_RWA_BYTE] == T1T_CC_RWA_RW) {
/* NDEF Message presence, CC indication sets Tag as READ WRITE */
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_READ_WRITE;
}
} else {
/* If NDEF is not yet detected then Tag remains in Initialized state
* after NDEF Detection the Tag state may be updated */
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_INITIALIZED;
}
} else {
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_UNKNOWN;
}
}
/*******************************************************************************
**
** Function rw_t1t_read_locks
**
** Description This function will send command to read next unread locks
**
** Returns NFC_STATUS_OK, if all locks are read successfully
** NFC_STATUS_FAILED, if reading locks failed
** NFC_STATUS_CONTINUE, if reading locks is in progress
**
*******************************************************************************/
tNFC_STATUS rw_t1t_read_locks(void) {
uint8_t num_locks = 0;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_CONTINUE;
uint16_t offset;
while (num_locks < p_t1t->num_lockbytes) {
if (p_t1t->lockbyte[num_locks].b_lock_read == false) {
offset = p_t1t->lock_tlv[p_t1t->lockbyte[num_locks].tlv_index].offset +
p_t1t->lockbyte[num_locks].byte_index;
if (offset < T1T_STATIC_SIZE) {
p_t1t->lockbyte[num_locks].lock_byte = p_t1t->mem[offset];
p_t1t->lockbyte[num_locks].b_lock_read = true;
} else if (offset < (p_t1t->mem[T1T_CC_TMS_BYTE] + 1) * T1T_BLOCK_SIZE) {
/* send READ8 command */
p_t1t->block_read = (uint8_t)(offset / T1T_BLOCK_SIZE);
status = rw_t1t_send_dyn_cmd(T1T_CMD_READ8, p_t1t->block_read, nullptr);
if (status == NFC_STATUS_OK) {
/* Reading Locks */
status = NFC_STATUS_CONTINUE;
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_READ_LOCKS;
}
break;
} else {
/* Read locks failed */
status = NFC_STATUS_FAILED;
break;
}
}
num_locks++;
}
if (num_locks == p_t1t->num_lockbytes) {
/* All locks are read */
status = NFC_STATUS_OK;
}
return status;
}
/*******************************************************************************
**
** Function rw_t1t_handle_write_rsp
**
** Description This function handles response received for WRITE_E8,
** WRITE_NE8, WRITE_E, WRITE_NE commands
**
** Returns status of the current NDEF/TLV Operation
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_handle_write_rsp(bool* p_notify, uint8_t* p_data) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_OK;
uint8_t num_locks;
uint8_t lock_count;
uint8_t value;
uint8_t addr;
uint8_t write_block[T1T_BLOCK_SIZE];
uint16_t offset;
uint16_t next_offset;
uint8_t num_bits;
uint8_t next_num_bits;
*p_notify = false;
switch (p_t1t->state) {
case RW_T1T_STATE_WRITE:
*p_notify = true;
break;
case RW_T1T_STATE_FORMAT_TAG:
if (p_t1t->substate == RW_T1T_SUBSTATE_WAIT_SET_NULL_NDEF) {
if (rw_cb.tcb.t1t.hr[0] != T1T_STATIC_HR0 ||
rw_cb.tcb.t1t.hr[1] >= RW_T1T_HR1_MIN)
*p_notify = true;
else {
if (p_t1t->work_offset < (T1T_BLOCK_SIZE - 1)) {
p_t1t->work_offset++;
/* send WRITE-E command */
RW_T1T_BLD_ADD((addr), 1, (uint8_t)p_t1t->work_offset);
status = rw_t1t_send_static_cmd(
T1T_CMD_WRITE_E, addr,
p_t1t->ndef_first_block[(uint8_t)p_t1t->work_offset]);
if (status != NFC_STATUS_OK) *p_notify = true;
} else
*p_notify = true;
}
} else {
/* send WRITE-E8 command */
status =
rw_t1t_send_dyn_cmd(T1T_CMD_WRITE_E8, 2, p_t1t->ndef_final_block);
if (status != NFC_STATUS_OK)
*p_notify = true;
else
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_NULL_NDEF;
}
break;
case RW_T1T_STATE_SET_TAG_RO:
switch (p_t1t->substate) {
case RW_T1T_SUBSTATE_WAIT_SET_CC_RWA_RO:
if (!p_t1t->b_hard_lock) {
status = NFC_STATUS_OK;
*p_notify = true;
break;
}
if ((p_t1t->hr[0] & 0x0F) != 1) {
memset(write_block, 0, T1T_BLOCK_SIZE);
write_block[0] = 0xFF;
write_block[1] = 0xFF;
/* send WRITE-NE8 command */
status = rw_t1t_send_dyn_cmd(T1T_CMD_WRITE_NE8, T1T_LOCK_BLOCK,
write_block);
if (status != NFC_STATUS_OK)
*p_notify = true;
else
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS;
} else {
/* send WRITE-NE command */
RW_T1T_BLD_ADD((addr), (T1T_LOCK_BLOCK), (0));
status = rw_t1t_send_static_cmd(T1T_CMD_WRITE_NE, addr, 0xFF);
if (status != NFC_STATUS_OK)
*p_notify = true;
else
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_ST_LOCK_BITS;
}
break;
case RW_T1T_SUBSTATE_WAIT_SET_ST_LOCK_BITS:
/* send WRITE-NE command */
RW_T1T_BLD_ADD((addr), (T1T_LOCK_BLOCK), (1));
status = rw_t1t_send_static_cmd(T1T_CMD_WRITE_NE, addr, 0xFF);
if (status != NFC_STATUS_OK)
*p_notify = true;
else
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS;
break;
case RW_T1T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS:
num_locks = 0;
while (num_locks < p_t1t->num_lockbytes) {
if (p_t1t->lockbyte[num_locks].lock_status ==
RW_T1T_LOCK_UPDATE_INITIATED) {
p_t1t->lockbyte[num_locks].lock_status = RW_T1T_LOCK_UPDATED;
}
num_locks++;
}
num_locks = 0;
while (num_locks < p_t1t->num_lockbytes) {
if (p_t1t->lockbyte[num_locks].lock_status ==
RW_T1T_LOCK_NOT_UPDATED) {
offset =
p_t1t->lock_tlv[p_t1t->lockbyte[num_locks].tlv_index].offset +
p_t1t->lockbyte[num_locks].byte_index;
num_bits =
((p_t1t->lockbyte[num_locks].byte_index + 1) * 8 <=
p_t1t->lock_tlv[p_t1t->lockbyte[num_locks].tlv_index]
.num_bits)
? 8
: p_t1t->lock_tlv[p_t1t->lockbyte[num_locks].tlv_index]
.num_bits %
8;
if ((p_t1t->hr[0] & 0x0F) != 1) {
memset(write_block, 0, T1T_BLOCK_SIZE);
write_block[(uint8_t)(offset % T1T_BLOCK_SIZE)] |=
tags_pow(2, num_bits) - 1;
lock_count = num_locks + 1;
while (lock_count < p_t1t->num_lockbytes) {
next_offset =
p_t1t->lock_tlv[p_t1t->lockbyte[lock_count].tlv_index]
.offset +
p_t1t->lockbyte[lock_count].byte_index;
next_num_bits =
((p_t1t->lockbyte[lock_count].byte_index + 1) * 8 <=
p_t1t->lock_tlv[p_t1t->lockbyte[lock_count].tlv_index]
.num_bits)
? 8
: p_t1t->lock_tlv[p_t1t->lockbyte[lock_count]
.tlv_index]
.num_bits %
8;
if (next_offset / T1T_BLOCK_SIZE == offset / T1T_BLOCK_SIZE) {
write_block[(uint8_t)(next_offset % T1T_BLOCK_SIZE)] |=
tags_pow(2, next_num_bits) - 1;
} else
break;
lock_count++;
}
/* send WRITE-NE8 command */
status = rw_t1t_send_dyn_cmd(T1T_CMD_WRITE_NE8,
(uint8_t)(offset / T1T_BLOCK_SIZE),
write_block);
if (status == NFC_STATUS_OK) {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS;
while (lock_count > num_locks) {
p_t1t->lockbyte[lock_count - 1].lock_status =
RW_T1T_LOCK_UPDATE_INITIATED;
lock_count--;
}
} else
*p_notify = true;
} else {
/* send WRITE-NE command */
RW_T1T_BLD_ADD((addr), ((uint8_t)(offset / T1T_BLOCK_SIZE)),
((uint8_t)(offset % T1T_BLOCK_SIZE)));
value = (uint8_t)(tags_pow(2, num_bits) - 1);
status = rw_t1t_send_static_cmd(T1T_CMD_WRITE_NE, addr, value);
if (status == NFC_STATUS_OK) {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS;
p_t1t->lockbyte[num_locks].lock_status =
RW_T1T_LOCK_UPDATE_INITIATED;
} else
*p_notify = true;
}
break;
}
num_locks++;
}
if (num_locks == p_t1t->num_lockbytes) {
rw_t1t_update_lock_attributes();
status = NFC_STATUS_OK;
*p_notify = true;
}
break;
}
break;
case RW_T1T_STATE_WRITE_NDEF:
switch (p_t1t->substate) {
case RW_T1T_SUBSTATE_WAIT_VALIDATE_NDEF:
p_t1t->ndef_msg_len = p_t1t->new_ndef_msg_len;
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_READ_WRITE;
*p_notify = true;
break;
case RW_T1T_SUBSTATE_WAIT_NDEF_UPDATED:
status = rw_t1t_handle_ndef_write_rsp(p_data);
if (status == NFC_STATUS_OK) {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_VALIDATE_NDEF;
} else if (status == NFC_STATUS_FAILED) {
/* Send Negative response to upper layer */
*p_notify = true;
}
break;
case RW_T1T_SUBSTATE_WAIT_NDEF_WRITE:
status = rw_t1t_handle_ndef_write_rsp(p_data);
if (status == NFC_STATUS_FAILED) {
/* Send Negative response to upper layer */
*p_notify = true;
} else if (status == NFC_STATUS_OK) {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_NDEF_UPDATED;
}
break;
case RW_T1T_SUBSTATE_WAIT_INVALIDATE_NDEF:
status = rw_t1t_handle_ndef_write_rsp(p_data);
if (status == NFC_STATUS_FAILED) {
/* Send Negative response to upper layer */
*p_notify = true;
} else if (status == NFC_STATUS_CONTINUE) {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_NDEF_WRITE;
} else {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_NDEF_UPDATED;
}
break;
}
break;
}
return status;
}
/*******************************************************************************
**
** Function rw_t1t_handle_read_rsp
**
** Description This function handle the data bytes excluding ADD(S)/ADD8
** field received as part of RSEG, RALL, READ8 command response
**
** Returns status of the current NDEF/TLV Operation
**
*******************************************************************************/
tNFC_STATUS rw_t1t_handle_read_rsp(bool* p_notify, uint8_t* p_data) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_OK;
tRW_DETECT_NDEF_DATA ndef_data;
tRW_DETECT_TLV_DATA tlv_data;
uint8_t count;
*p_notify = false;
/* Handle the response based on the current state */
switch (p_t1t->state) {
case RW_T1T_STATE_READ:
*p_notify = true;
break;
case RW_T1T_STATE_READ_NDEF:
status = rw_t1t_handle_ndef_rall_rsp();
if (status != NFC_STATUS_CONTINUE) {
tRW_DATA rw_data;
rw_data.data.status = status;
rw_data.data.p_data = nullptr;
rw_t1t_handle_op_complete();
(*rw_cb.p_cback)(RW_T1T_NDEF_READ_EVT, &rw_data);
}
break;
case RW_T1T_STATE_TLV_DETECT:
switch (p_t1t->substate) {
case RW_T1T_SUBSTATE_WAIT_READ_LOCKS:
status = rw_t1t_read_locks();
if (status != NFC_STATUS_CONTINUE) {
rw_t1t_update_lock_attributes();
/* Send positive response to upper layer */
if (p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) {
tlv_data.protocol = NFC_PROTOCOL_T1T;
tlv_data.num_bytes = p_t1t->num_lockbytes;
tlv_data.status = status;
rw_t1t_handle_op_complete();
tRW_DATA rw_data;
rw_data.tlv = tlv_data;
(*rw_cb.p_cback)(RW_T1T_TLV_DETECT_EVT, &rw_data);
} else if (p_t1t->tlv_detect == TAG_NDEF_TLV) {
ndef_data.protocol = NFC_PROTOCOL_T1T;
ndef_data.flags = rw_t1t_get_ndef_flags();
ndef_data.flags |= RW_NDEF_FL_FORMATED;
ndef_data.max_size = (uint32_t)rw_t1t_get_ndef_max_size();
ndef_data.cur_size = p_t1t->ndef_msg_len;
if (ndef_data.max_size < ndef_data.cur_size) {
ndef_data.flags |= RW_NDEF_FL_READ_ONLY;
ndef_data.max_size = ndef_data.cur_size;
}
if (!(ndef_data.flags & RW_NDEF_FL_READ_ONLY)) {
ndef_data.flags |= RW_NDEF_FL_SOFT_LOCKABLE;
if (status == NFC_STATUS_OK)
ndef_data.flags |= RW_NDEF_FL_HARD_LOCKABLE;
}
ndef_data.status = status;
rw_t1t_handle_op_complete();
tRW_DATA rw_data;
rw_data.ndef = ndef_data;
(*rw_cb.p_cback)(RW_T1T_NDEF_DETECT_EVT, &rw_data);
}
}
break;
case RW_T1T_SUBSTATE_NONE:
if (p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) {
tlv_data.status = rw_t1t_handle_tlv_detect_rsp(p_t1t->mem);
tlv_data.protocol = NFC_PROTOCOL_T1T;
tlv_data.num_bytes = 0;
count = 0;
while (count < p_t1t->num_mem_tlvs) {
tlv_data.num_bytes +=
p_t1t->mem_tlv[p_t1t->num_mem_tlvs].num_bytes;
count++;
}
rw_t1t_handle_op_complete();
/* Send response to upper layer */
tRW_DATA rw_data;
rw_data.tlv = tlv_data;
(*rw_cb.p_cback)(RW_T1T_TLV_DETECT_EVT, &rw_data);
} else if (p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) {
tlv_data.status = rw_t1t_handle_tlv_detect_rsp(p_t1t->mem);
tlv_data.protocol = NFC_PROTOCOL_T1T;
tlv_data.num_bytes = p_t1t->num_lockbytes;
if (tlv_data.status == NFC_STATUS_FAILED) {
rw_t1t_handle_op_complete();
/* Send Negative response to upper layer */
tRW_DATA rw_data;
rw_data.tlv = tlv_data;
(*rw_cb.p_cback)(RW_T1T_TLV_DETECT_EVT, &rw_data);
} else {
rw_t1t_extract_lock_bytes(p_data);
status = rw_t1t_read_locks();
if (status != NFC_STATUS_CONTINUE) {
/* Send positive response to upper layer */
tlv_data.status = status;
rw_t1t_handle_op_complete();
tRW_DATA rw_data;
rw_data.tlv = tlv_data;
(*rw_cb.p_cback)(RW_T1T_TLV_DETECT_EVT, &rw_data);
}
}
} else if (p_t1t->tlv_detect == TAG_NDEF_TLV) {
ndef_data.protocol = NFC_PROTOCOL_T1T;
ndef_data.flags = rw_t1t_get_ndef_flags();
if (p_t1t->mem[T1T_CC_NMN_BYTE] == T1T_CC_NMN) {
ndef_data.status = rw_t1t_handle_tlv_detect_rsp(p_t1t->mem);
ndef_data.cur_size = p_t1t->ndef_msg_len;
if (ndef_data.status == NFC_STATUS_FAILED) {
ndef_data.max_size = (uint32_t)rw_t1t_get_ndef_max_size();
if (ndef_data.max_size < ndef_data.cur_size) {
ndef_data.flags |= RW_NDEF_FL_READ_ONLY;
ndef_data.max_size = ndef_data.cur_size;
}
if (!(ndef_data.flags & RW_NDEF_FL_READ_ONLY)) {
ndef_data.flags |= RW_NDEF_FL_SOFT_LOCKABLE;
}
/* Send Negative response to upper layer */
rw_t1t_handle_op_complete();
tRW_DATA rw_data;
rw_data.ndef = ndef_data;
(*rw_cb.p_cback)(RW_T1T_NDEF_DETECT_EVT, &rw_data);
} else {
ndef_data.flags |= RW_NDEF_FL_FORMATED;
rw_t1t_extract_lock_bytes(p_data);
status = rw_t1t_read_locks();
if (status != NFC_STATUS_CONTINUE) {
ndef_data.max_size = (uint32_t)rw_t1t_get_ndef_max_size();
if (ndef_data.max_size < ndef_data.cur_size) {
ndef_data.flags |= RW_NDEF_FL_READ_ONLY;
ndef_data.max_size = ndef_data.cur_size;
}
if (!(ndef_data.flags & RW_NDEF_FL_READ_ONLY)) {
ndef_data.flags |= RW_NDEF_FL_SOFT_LOCKABLE;
if (status == NFC_STATUS_OK)
ndef_data.flags |= RW_NDEF_FL_HARD_LOCKABLE;
}
/* Send positive response to upper layer */
ndef_data.status = status;
rw_t1t_handle_op_complete();
tRW_DATA rw_data;
rw_data.ndef = ndef_data;
(*rw_cb.p_cback)(RW_T1T_NDEF_DETECT_EVT, &rw_data);
}
}
} else {
/* Send Negative response to upper layer */
ndef_data.status = NFC_STATUS_FAILED;
ndef_data.max_size = (uint32_t)rw_t1t_get_ndef_max_size();
ndef_data.cur_size = p_t1t->ndef_msg_len;
if (ndef_data.max_size < ndef_data.cur_size) {
ndef_data.flags |= RW_NDEF_FL_READ_ONLY;
ndef_data.max_size = ndef_data.cur_size;
}
if (!(ndef_data.flags & RW_NDEF_FL_READ_ONLY)) {
ndef_data.flags |= RW_NDEF_FL_SOFT_LOCKABLE;
ndef_data.flags |= RW_NDEF_FL_SOFT_LOCKABLE;
}
rw_t1t_handle_op_complete();
tRW_DATA rw_data;
rw_data.ndef = ndef_data;
(*rw_cb.p_cback)(RW_T1T_NDEF_DETECT_EVT, &rw_data);
}
}
break;
}
break;
}
return status;
}
/*******************************************************************************
**
** Function rw_t1t_handle_dyn_read_rsp
**
** Description This function handles response received for READ8, RSEG
** commands based on the current state
**
** Returns status of the current NDEF/TLV Operation
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_handle_dyn_read_rsp(bool* p_notify, uint8_t* p_data) {
tNFC_STATUS status = NFC_STATUS_OK;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
*p_notify = false;
p_data += T1T_ADD_LEN;
rw_t1t_extract_lock_bytes(p_data);
if (p_t1t->state == RW_T1T_STATE_READ_NDEF) {
status = rw_t1t_handle_ndef_read_rsp(p_data);
if ((status == NFC_STATUS_FAILED) || (status == NFC_STATUS_OK)) {
/* Send response to upper layer */
*p_notify = true;
}
} else if (p_t1t->state == RW_T1T_STATE_WRITE_NDEF) {
status = rw_t1t_handle_ndef_write_rsp(p_data);
if (status == NFC_STATUS_FAILED) {
/* Send response to upper layer */
*p_notify = true;
} else if (status == NFC_STATUS_CONTINUE) {
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_INVALIDATE_NDEF;
}
} else {
status = rw_t1t_handle_read_rsp(p_notify, p_data);
}
return status;
}
/*****************************************************************************
**
** Function rw_t1t_handle_rall_rsp
**
** Description Handle response to RALL - Collect CC, set Tag state
**
** Returns None
**
*****************************************************************************/
static tNFC_STATUS rw_t1t_handle_rall_rsp(bool* p_notify, uint8_t* p_data) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
p_data += T1T_HR_LEN; /* skip HR */
memcpy(p_t1t->mem, (uint8_t*)p_data, T1T_STATIC_SIZE);
p_t1t->segment = 0;
rw_t1t_extract_lock_bytes(p_data);
p_data +=
T1T_UID_LEN + T1T_RES_BYTE_LEN; /* skip Block 0, UID and Reserved byte */
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
rw_t1t_update_tag_state();
rw_t1t_update_attributes();
rw_t1t_update_lock_attributes();
p_t1t->b_update = true;
return (rw_t1t_handle_read_rsp(p_notify, p_t1t->mem));
}
/*******************************************************************************
**
** Function rw_t1t_handle_tlv_detect_rsp
**
** Description Handle response to the last command sent while
** detecting tlv
**
** Returns NFC_STATUS_OK, if tlv detect is complete & success
** NFC_STATUS_FAILED,if tlv detect failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_handle_tlv_detect_rsp(uint8_t* p_data) {
uint16_t offset;
uint16_t len;
uint8_t xx;
uint8_t* p_readbytes;
uint8_t index;
uint8_t tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
uint8_t found_tlv = TAG_NULL_TLV;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
bool failed = false;
bool found = false;
uint8_t count = 0;
tNFC_STATUS status = NFC_STATUS_FAILED;
uint8_t start_offset = T1T_UID_LEN + T1T_CC_LEN + T1T_RES_BYTE_LEN;
uint8_t end_offset = T1T_STATIC_SIZE - (2 * T1T_BLOCK_SIZE);
uint8_t bytes_read = T1T_STATIC_SIZE;
uint8_t tlv_value[T1T_DEFAULT_TLV_LEN];
uint16_t bytes_count = 0;
p_readbytes = p_data;
for (offset = start_offset; offset < end_offset && !failed && !found;) {
if (rw_t1t_is_lock_reserved_otp_byte((uint16_t)(offset)) == true) {
offset++;
continue;
}
switch (tlv_detect_state) {
case RW_T1T_SUBSTATE_WAIT_TLV_DETECT:
/* Search for the tag */
found_tlv = p_readbytes[offset++];
switch (found_tlv) {
case TAG_NULL_TLV: /* May be used for padding. SHALL ignore this */
break;
case TAG_NDEF_TLV:
if (p_t1t->tlv_detect == TAG_NDEF_TLV) {
index = (offset % T1T_BLOCK_SIZE);
/* Backup ndef first block */
memcpy(&p_t1t->ndef_first_block[0], &p_readbytes[offset - index],
index);
memcpy(&p_t1t->ndef_first_block[index], &p_readbytes[offset],
T1T_BLOCK_SIZE - index);
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_FIND_LEN_FIELD_LEN;
} else if (p_t1t->tlv_detect == TAG_PROPRIETARY_TLV) {
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_FIND_LEN_FIELD_LEN;
} else if (((p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) &&
(p_t1t->num_lockbytes > 0)) ||
((p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) &&
(p_t1t->num_mem_tlvs > 0))) {
found = true;
} else {
failed = true;
}
break;
case TAG_LOCK_CTRL_TLV:
case TAG_MEM_CTRL_TLV:
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_LEN0;
break;
case TAG_PROPRIETARY_TLV:
if (p_t1t->tlv_detect == TAG_PROPRIETARY_TLV) {
index = (offset % T1T_BLOCK_SIZE);
/* Backup ndef first block */
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_FIND_LEN_FIELD_LEN;
} else {
/* NDEF/LOCK/MEM TLV can exist after Proprietary Tlv so we
* continue searching, skiping proprietary tlv */
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_FIND_LEN_FIELD_LEN;
}
break;
case TAG_TERMINATOR_TLV: /* Last TLV block in the data area. Must be
no NDEF nessage */
if (((p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) &&
(p_t1t->num_lockbytes > 0)) ||
((p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) &&
(p_t1t->num_mem_tlvs > 0))) {
found = true;
} else {
failed = true;
}
break;
default:
failed = true;
}
break;
case RW_T1T_SUBSTATE_WAIT_FIND_LEN_FIELD_LEN:
len = p_readbytes[offset];
switch (found_tlv) {
case TAG_NDEF_TLV:
p_t1t->ndef_header_offset = offset + p_t1t->work_offset;
if (len == T1T_LONG_NDEF_LEN_FIELD_BYTE0) {
/* The next two bytes constitute length bytes */
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_LEN0;
} else {
/* one byte length field */
p_t1t->ndef_msg_len = len;
bytes_count = p_t1t->ndef_msg_len;
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_VALUE;
}
break;
case TAG_PROPRIETARY_TLV:
if (len == 0xFF) {
/* The next two bytes constitute length bytes */
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_LEN0;
} else {
/* one byte length field */
bytes_count = len;
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_VALUE;
}
break;
}
offset++;
break;
case RW_T1T_SUBSTATE_WAIT_READ_TLV_LEN0:
switch (found_tlv) {
case TAG_LOCK_CTRL_TLV:
case TAG_MEM_CTRL_TLV:
len = p_readbytes[offset];
if (len == T1T_DEFAULT_TLV_LEN) {
/* Valid Lock control TLV */
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_VALUE;
bytes_count = T1T_DEFAULT_TLV_LEN;
} else if (((p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) &&
(p_t1t->num_lockbytes > 0)) ||
((p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) &&
(p_t1t->num_mem_tlvs > 0))) {
found = true;
} else {
failed = true;
}
break;
case TAG_NDEF_TLV:
case TAG_PROPRIETARY_TLV:
/* The first length byte */
bytes_count = (uint8_t)p_readbytes[offset];
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_LEN1;
break;
}
offset++;
break;
case RW_T1T_SUBSTATE_WAIT_READ_TLV_LEN1:
bytes_count = (bytes_count << 8) + p_readbytes[offset];
if (found_tlv == TAG_NDEF_TLV) {
p_t1t->ndef_msg_len = bytes_count;
}
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_READ_TLV_VALUE;
offset++;
break;
case RW_T1T_SUBSTATE_WAIT_READ_TLV_VALUE:
switch (found_tlv) {
case TAG_NDEF_TLV:
if ((bytes_count == p_t1t->ndef_msg_len) &&
(p_t1t->tlv_detect == TAG_NDEF_TLV)) {
/* The first byte offset after length field */
p_t1t->ndef_msg_offset = offset + p_t1t->work_offset;
}
if (bytes_count > 0) bytes_count--;
if (p_t1t->tlv_detect == TAG_NDEF_TLV) {
if (p_t1t->ndef_msg_len > 0) {
rw_t1t_update_tag_state();
} else {
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_INITIALIZED_NDEF;
}
found = true;
} else if (bytes_count == 0) {
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
}
break;
case TAG_LOCK_CTRL_TLV:
bytes_count--;
if ((p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) ||
(p_t1t->tlv_detect == TAG_NDEF_TLV)) {
tlv_value[2 - bytes_count] = p_readbytes[offset];
if (bytes_count == 0) {
if (p_t1t->num_lock_tlvs < RW_T1T_MAX_LOCK_TLVS) {
p_t1t->lock_tlv[p_t1t->num_lock_tlvs].offset =
(tlv_value[0] >> 4) & 0x0F;
p_t1t->lock_tlv[p_t1t->num_lock_tlvs].offset *=
(uint8_t)tags_pow(2, tlv_value[2] & 0x0F);
p_t1t->lock_tlv[p_t1t->num_lock_tlvs].offset +=
tlv_value[0] & 0x0F;
p_t1t->lock_tlv[p_t1t->num_lock_tlvs].bytes_locked_per_bit =
(uint8_t)tags_pow(2, ((tlv_value[2] & 0xF0) >> 4));
p_t1t->lock_tlv[p_t1t->num_lock_tlvs].num_bits = tlv_value[1];
count = tlv_value[1] / 8 + ((tlv_value[1] % 8 != 0) ? 1 : 0);
xx = 0;
while (xx < count) {
if (p_t1t->num_lockbytes < RW_T1T_MAX_LOCK_BYTES) {
p_t1t->lockbyte[p_t1t->num_lockbytes].tlv_index =
p_t1t->num_lock_tlvs;
p_t1t->lockbyte[p_t1t->num_lockbytes].byte_index = xx;
p_t1t->lockbyte[p_t1t->num_lockbytes].b_lock_read = false;
p_t1t->num_lockbytes++;
} else
LOG(ERROR) << StringPrintf(
"T1T Buffer overflow error. Max supported lock "
"bytes=0x%02X",
RW_T1T_MAX_LOCK_BYTES);
xx++;
}
p_t1t->num_lock_tlvs++;
rw_t1t_update_attributes();
} else
LOG(ERROR) << StringPrintf(
"T1T Buffer overflow error. Max supported lock "
"tlvs=0x%02X",
RW_T1T_MAX_LOCK_TLVS);
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
}
} else {
if (bytes_count == 0) {
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
}
}
break;
case TAG_MEM_CTRL_TLV:
bytes_count--;
if ((p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) ||
(p_t1t->tlv_detect == TAG_NDEF_TLV)) {
tlv_value[2 - bytes_count] = p_readbytes[offset];
if (bytes_count == 0) {
if (p_t1t->num_mem_tlvs >= RW_T1T_MAX_MEM_TLVS) {
LOG(ERROR) << StringPrintf(
"rw_t1t_handle_tlv_detect_rsp - Maximum buffer allocated "
"for Memory tlv has reached");
failed = true;
} else {
/* Extract dynamic reserved bytes */
p_t1t->mem_tlv[p_t1t->num_mem_tlvs].offset =
(tlv_value[0] >> 4) & 0x0F;
p_t1t->mem_tlv[p_t1t->num_mem_tlvs].offset *=
(uint8_t)tags_pow(2, tlv_value[2] & 0x0F);
p_t1t->mem_tlv[p_t1t->num_mem_tlvs].offset +=
tlv_value[0] & 0x0F;
p_t1t->mem_tlv[p_t1t->num_mem_tlvs].num_bytes = tlv_value[1];
p_t1t->num_mem_tlvs++;
rw_t1t_update_attributes();
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
}
}
} else {
if (bytes_count == 0) {
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
}
}
break;
case TAG_PROPRIETARY_TLV:
bytes_count--;
if (p_t1t->tlv_detect == TAG_PROPRIETARY_TLV)
found = true;
else {
if (bytes_count == 0) {
tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
}
}
break;
}
offset++;
break;
}
}
p_t1t->work_offset += bytes_read;
/* NDEF/Lock/Mem TLV to be found in segment 0, if not assume detection failed
*/
if (!found && !failed) {
if (((p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) &&
(p_t1t->num_lockbytes > 0)) ||
((p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) &&
(p_t1t->num_mem_tlvs > 0))) {
found = true;
} else {
if (p_t1t->tlv_detect == TAG_NDEF_TLV) {
p_t1t->tag_attribute = RW_T1_TAG_ATTRB_INITIALIZED;
}
failed = true;
}
}
status = failed ? NFC_STATUS_FAILED : NFC_STATUS_OK;
return status;
}
/*******************************************************************************
**
** Function rw_t1t_handle_ndef_rall_rsp
**
** Description Handle response to RALL command sent while reading an
** NDEF message
**
** Returns NFC_STATUS_CONTINUE, if NDEF read operation is not complete
** NFC_STATUS_OK, if NDEF read is successfull
** NFC_STATUS_FAILED,if NDEF read failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_handle_ndef_rall_rsp(void) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_CONTINUE;
uint8_t count;
uint8_t adds;
count = (uint8_t)p_t1t->ndef_msg_offset;
p_t1t->work_offset = 0;
p_t1t->segment = 0;
while (count < T1T_STATIC_SIZE && p_t1t->work_offset < p_t1t->ndef_msg_len) {
if (rw_t1t_is_lock_reserved_otp_byte(count) == false) {
p_t1t->p_ndef_buffer[p_t1t->work_offset] = p_t1t->mem[count];
p_t1t->work_offset++;
}
count++;
}
if (p_t1t->work_offset != p_t1t->ndef_msg_len) {
if ((p_t1t->hr[0] & 0x0F) != 1) {
if (p_t1t->work_offset == 0)
return NFC_STATUS_FAILED;
else {
p_t1t->block_read = T1T_STATIC_BLOCKS + 1;
p_t1t->segment++;
}
if (p_t1t->ndef_msg_len - p_t1t->work_offset <= 8) {
status = rw_t1t_send_dyn_cmd(T1T_CMD_READ8, p_t1t->block_read, nullptr);
if (status == NFC_STATUS_OK) {
p_t1t->tlv_detect = TAG_NDEF_TLV;
p_t1t->state = RW_T1T_STATE_READ_NDEF;
status = NFC_STATUS_CONTINUE;
}
} else {
/* send RSEG command */
RW_T1T_BLD_ADDS((adds), (p_t1t->segment));
status = rw_t1t_send_dyn_cmd(T1T_CMD_RSEG, adds, nullptr);
if (status == NFC_STATUS_OK) {
p_t1t->state = RW_T1T_STATE_READ_NDEF;
status = NFC_STATUS_CONTINUE;
}
}
} else {
LOG(ERROR) << StringPrintf(
"RW_T1tReadNDef - Invalid NDEF len: %u or NDEF corrupted",
p_t1t->ndef_msg_len);
status = NFC_STATUS_FAILED;
}
} else {
status = NFC_STATUS_OK;
}
return status;
}
/*******************************************************************************
**
** Function rw_t1t_handle_ndef_read_rsp
**
** Description Handle response to commands sent while reading an
** NDEF message
**
** Returns NFC_STATUS_CONTINUE, if tlv read is not yet complete
** NFC_STATUS_OK, if tlv read is complete & success
** NFC_STATUS_FAILED,if tlv read failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_handle_ndef_read_rsp(uint8_t* p_data) {
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t index;
uint8_t adds;
tT1T_CMD_RSP_INFO* p_cmd_rsp_info =
(tT1T_CMD_RSP_INFO*)rw_cb.tcb.t1t.p_cmd_rsp_info;
/* The Response received could be for Read8 or Read Segment command */
switch (p_cmd_rsp_info->opcode) {
case T1T_CMD_READ8:
if (p_t1t->work_offset == 0) {
index = p_t1t->ndef_msg_offset % T1T_BLOCK_SIZE;
} else {
index = 0;
}
p_t1t->segment = (p_t1t->block_read * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE;
while (index < T1T_BLOCK_SIZE &&
p_t1t->work_offset < p_t1t->ndef_msg_len) {
if (rw_t1t_is_lock_reserved_otp_byte((uint16_t)(
(p_t1t->block_read * T1T_BLOCK_SIZE) + index)) == false) {
p_t1t->p_ndef_buffer[p_t1t->work_offset] = p_data[index];
p_t1t->work_offset++;
}
index++;
}
break;
case T1T_CMD_RSEG:
if (p_t1t->work_offset == 0) {
index = p_t1t->ndef_msg_offset % T1T_SEGMENT_SIZE;
} else {
index = 0;
}
p_t1t->block_read = ((p_t1t->segment + 1) * T1T_BLOCKS_PER_SEGMENT) - 1;
while (index < T1T_SEGMENT_SIZE &&
p_t1t->work_offset < p_t1t->ndef_msg_len) {
if (rw_t1t_is_lock_reserved_otp_byte((uint16_t)(index)) == false) {
p_t1t->p_ndef_buffer[p_t1t->work_offset] = p_data[index];
p_t1t->work_offset++;
}
index++;
}
break;
default:
break;
}
if (p_t1t->work_offset < p_t1t->ndef_msg_len) {
if ((p_t1t->hr[0] & 0x0F) != 1) {
if ((p_t1t->ndef_msg_len - p_t1t->work_offset) <= T1T_BLOCK_SIZE) {
p_t1t->block_read++;
ndef_status = rw_t1t_send_dyn_cmd(T1T_CMD_READ8,
(uint8_t)(p_t1t->block_read), nullptr);
if (ndef_status == NFC_STATUS_OK) {
ndef_status = NFC_STATUS_CONTINUE;
}
} else {
p_t1t->segment++;
/* send RSEG command */
RW_T1T_BLD_ADDS((adds), (p_t1t->segment));
ndef_status = rw_t1t_send_dyn_cmd(T1T_CMD_RSEG, adds, nullptr);
if (ndef_status == NFC_STATUS_OK) {
ndef_status = NFC_STATUS_CONTINUE;
}
}
}
} else {
ndef_status = NFC_STATUS_OK;
}
return ndef_status;
}
/*******************************************************************************
**
** Function rw_t1t_next_ndef_write_block
**
** Description This function prepare and writes ndef blocks
**
** Returns NFC_STATUS_CONTINUE, if tlv write is not yet complete
** NFC_STATUS_OK, if tlv write is complete & success
** NFC_STATUS_FAILED,if tlv write failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_next_ndef_write_block(void) {
bool b_block_write_cmd = false;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
uint8_t write_block[8];
uint8_t block;
uint8_t index;
uint8_t new_lengthfield_len;
uint8_t length_field[3];
uint16_t initial_offset;
uint8_t count;
/* Write NDEF Message */
new_lengthfield_len = p_t1t->new_ndef_msg_len > 254 ? 3 : 1;
/* Identify the command to use for NDEF write operation */
if ((p_t1t->hr[0] & 0x0F) != 1) {
/* Dynamic memory structure */
b_block_write_cmd = false;
block = p_t1t->ndef_block_written + 1;
p_t1t->segment = (block * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE;
count = 0;
while (block <= p_t1t->mem[T1T_CC_TMS_BYTE]) {
index = 0;
if (block == p_t1t->num_ndef_finalblock) {
/* T1T_CMD_WRITE_E8 Command */
b_block_write_cmd = true;
break;
}
while (index < T1T_BLOCK_SIZE &&
p_t1t->work_offset <
(p_t1t->new_ndef_msg_len + new_lengthfield_len)) {
if (rw_t1t_is_lock_reserved_otp_byte(
(uint16_t)((block * T1T_BLOCK_SIZE) + index)) == false) {
count++;
}
index++;
}
if (count == T1T_BLOCK_SIZE) {
/* T1T_CMD_WRITE_E8 Command */
b_block_write_cmd = true;
break;
} else if (count == 0) {
index = 0;
block++;
if (p_t1t->segment != (block * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE) {
p_t1t->segment = (block * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE;
}
} else {
/* T1T_CMD_WRITE_E Command */
b_block_write_cmd = false;
break;
}
}
} else {
/* Static memory structure */
block = p_t1t->ndef_block_written;
b_block_write_cmd = false;
}
new_lengthfield_len = p_t1t->new_ndef_msg_len > 254 ? 3 : 1;
if (new_lengthfield_len == 3) {
length_field[0] = T1T_LONG_NDEF_LEN_FIELD_BYTE0;
length_field[1] = (uint8_t)(p_t1t->new_ndef_msg_len >> 8);
length_field[2] = (uint8_t)(p_t1t->new_ndef_msg_len);
} else {
length_field[0] = (uint8_t)(p_t1t->new_ndef_msg_len);
}
if (b_block_write_cmd) {
/* Dynamic memory structure */
index = 0;
p_t1t->segment = (block * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE;
initial_offset = p_t1t->work_offset;
block = rw_t1t_prepare_ndef_bytes(write_block, length_field, &index, false,
block, new_lengthfield_len);
if (p_t1t->work_offset == initial_offset) {
ndef_status = NFC_STATUS_FAILED;
} else {
/* Send WRITE_E8 command */
ndef_status = rw_t1t_send_ndef_block(write_block, block);
}
} else {
/* Static memory structure */
if (p_t1t->write_byte + 1 >= T1T_BLOCK_SIZE) {
index = 0;
block++;
} else {
index = p_t1t->write_byte + 1;
}
initial_offset = p_t1t->work_offset;
block = rw_t1t_prepare_ndef_bytes(write_block, length_field, &index, true,
block, new_lengthfield_len);
if (p_t1t->work_offset == initial_offset) {
ndef_status = NFC_STATUS_FAILED;
} else {
/* send WRITE-E command */
ndef_status = rw_t1t_send_ndef_byte(write_block[index], block, index,
new_lengthfield_len);
}
}
return ndef_status;
}
/*******************************************************************************
**
** Function rw_t1t_ndef_write_first_block
**
** Description This function writes ndef first block
**
** Returns NFC_STATUS_CONTINUE, if tlv write is not yet complete
** NFC_STATUS_OK, if tlv write is complete & success
** NFC_STATUS_FAILED,if tlv write failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_ndef_write_first_block(void) {
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t block;
uint8_t index;
uint8_t new_lengthfield_len;
uint8_t length_field[3];
uint8_t write_block[8];
/* handle positive response to invalidating existing NDEF Message */
p_t1t->work_offset = 0;
new_lengthfield_len = p_t1t->new_ndef_msg_len > 254 ? 3 : 1;
if (new_lengthfield_len == 3) {
length_field[0] = T1T_LONG_NDEF_LEN_FIELD_BYTE0;
length_field[1] = (uint8_t)(p_t1t->new_ndef_msg_len >> 8);
length_field[2] = (uint8_t)(p_t1t->new_ndef_msg_len);
} else {
length_field[0] = (uint8_t)(p_t1t->new_ndef_msg_len);
}
/* updating ndef_first_block with new ndef message */
memcpy(write_block, p_t1t->ndef_first_block, T1T_BLOCK_SIZE);
index = p_t1t->ndef_header_offset % T1T_BLOCK_SIZE;
block = (uint8_t)(p_t1t->ndef_header_offset / T1T_BLOCK_SIZE);
p_t1t->segment = (uint8_t)(p_t1t->ndef_header_offset / T1T_SEGMENT_SIZE);
if ((p_t1t->hr[0] & 0x0F) != 1) {
/* Dynamic Memory structure */
block = rw_t1t_prepare_ndef_bytes(write_block, length_field, &index, false,
block, new_lengthfield_len);
if (p_t1t->work_offset == 0) {
ndef_status = NFC_STATUS_FAILED;
} else {
/* Send WRITE-E8 command based on the prepared write_block */
ndef_status = rw_t1t_send_ndef_block(write_block, block);
}
} else {
/* Static Memory structure */
block = rw_t1t_prepare_ndef_bytes(write_block, length_field, &index, true,
block, new_lengthfield_len);
if (p_t1t->work_offset == 0) {
ndef_status = NFC_STATUS_FAILED;
} else {
/* send WRITE-E command */
ndef_status = rw_t1t_send_ndef_byte(write_block[index], block, index,
new_lengthfield_len);
}
}
return ndef_status;
}
/*******************************************************************************
**
** Function rw_t1t_send_ndef_byte
**
** Description Sends ndef message or length field byte and update
** status
**
** Returns NFC_STATUS_CONTINUE, if tlv write is not yet complete
** NFC_STATUS_OK, if tlv write is complete & success
** NFC_STATUS_FAILED,if tlv write failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_send_ndef_byte(uint8_t data, uint8_t block,
uint8_t index, uint8_t msg_len) {
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t addr;
/* send WRITE-E command */
RW_T1T_BLD_ADD((addr), (block), (index));
if (NFC_STATUS_OK == rw_t1t_send_static_cmd(T1T_CMD_WRITE_E, addr, data)) {
p_t1t->write_byte = index;
p_t1t->ndef_block_written = block;
if (p_t1t->work_offset == p_t1t->new_ndef_msg_len + msg_len) {
ndef_status = NFC_STATUS_OK;
} else {
ndef_status = NFC_STATUS_CONTINUE;
}
} else {
ndef_status = NFC_STATUS_FAILED;
}
return ndef_status;
}
/*******************************************************************************
**
** Function rw_t1t_prepare_ndef_bytes
**
** Description prepares ndef block to write
**
** Returns block number where to write
**
*******************************************************************************/
static uint8_t rw_t1t_prepare_ndef_bytes(uint8_t* p_data,
uint8_t* p_length_field,
uint8_t* p_index, bool b_one_byte,
uint8_t block,
uint8_t lengthfield_len) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t first_block = (uint8_t)(p_t1t->ndef_header_offset / T1T_BLOCK_SIZE);
uint16_t initial_offset = p_t1t->work_offset;
while (p_t1t->work_offset == initial_offset &&
block <= p_t1t->mem[T1T_CC_TMS_BYTE]) {
if ((block == p_t1t->num_ndef_finalblock) && (block != first_block)) {
memcpy(p_data, p_t1t->ndef_final_block, T1T_BLOCK_SIZE);
}
/* Update length field */
while ((*p_index < T1T_BLOCK_SIZE) &&
(p_t1t->work_offset < lengthfield_len)) {
if (rw_t1t_is_lock_reserved_otp_byte(
(uint16_t)((block * T1T_BLOCK_SIZE) + *p_index)) == false) {
p_data[*p_index] = p_length_field[p_t1t->work_offset];
p_t1t->work_offset++;
if (b_one_byte) return block;
}
(*p_index)++;
if (p_t1t->work_offset == lengthfield_len) {
break;
}
}
/* Update ndef message field */
while (*p_index < T1T_BLOCK_SIZE &&
p_t1t->work_offset < (p_t1t->new_ndef_msg_len + lengthfield_len)) {
if (rw_t1t_is_lock_reserved_otp_byte(
(uint16_t)((block * T1T_BLOCK_SIZE) + *p_index)) == false) {
p_data[*p_index] =
p_t1t->p_ndef_buffer[p_t1t->work_offset - lengthfield_len];
p_t1t->work_offset++;
if (b_one_byte) return block;
}
(*p_index)++;
}
if (p_t1t->work_offset == initial_offset) {
*p_index = 0;
block++;
if (p_t1t->segment != (block * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE) {
p_t1t->segment = (block * T1T_BLOCK_SIZE) / T1T_SEGMENT_SIZE;
}
}
}
return block;
}
/*******************************************************************************
**
** Function rw_t1t_send_ndef_block
**
** Description Sends ndef block and update status
**
** Returns NFC_STATUS_CONTINUE, if tlv write is not yet complete
** NFC_STATUS_OK, if tlv write is complete & success
** NFC_STATUS_FAILED,if tlv write failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_send_ndef_block(uint8_t* p_data, uint8_t block) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
if (NFC_STATUS_OK == rw_t1t_send_dyn_cmd(T1T_CMD_WRITE_E8, block, p_data)) {
p_t1t->ndef_block_written = block;
if (p_t1t->ndef_block_written == p_t1t->num_ndef_finalblock) {
ndef_status = NFC_STATUS_OK;
} else {
ndef_status = NFC_STATUS_CONTINUE;
}
} else {
ndef_status = NFC_STATUS_FAILED;
}
return ndef_status;
}
/*******************************************************************************
**
** Function rw_t1t_get_ndef_flags
**
** Description Prepare NDEF Flags
**
** Returns NDEF Flag value
**
*******************************************************************************/
static uint8_t rw_t1t_get_ndef_flags(void) {
uint8_t flags = 0;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
if ((p_t1t->hr[0] & 0xF0) == T1T_NDEF_SUPPORTED)
flags |= RW_NDEF_FL_SUPPORTED;
if (t1t_tag_init_data(p_t1t->hr[0]) != nullptr) flags |= RW_NDEF_FL_FORMATABLE;
if ((p_t1t->mem[T1T_CC_RWA_BYTE] & 0x0F) == T1T_CC_RWA_RO)
flags |= RW_NDEF_FL_READ_ONLY;
return flags;
}
/*******************************************************************************
**
** Function rw_t1t_get_ndef_max_size
**
** Description Calculate maximum size of NDEF message that can be written
** on to the tag
**
** Returns Maximum size of NDEF Message
**
*******************************************************************************/
static uint16_t rw_t1t_get_ndef_max_size(void) {
uint16_t offset;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint16_t tag_size = (p_t1t->mem[T1T_CC_TMS_BYTE] + 1) * T1T_BLOCK_SIZE;
const tT1T_INIT_TAG* p_ret;
uint8_t init_segment = p_t1t->segment;
p_t1t->max_ndef_msg_len = 0;
offset = p_t1t->ndef_msg_offset;
p_t1t->segment = (uint8_t)(p_t1t->ndef_msg_offset / T1T_SEGMENT_SIZE);
if ((tag_size < T1T_STATIC_SIZE) ||
(tag_size > (T1T_SEGMENT_SIZE * T1T_MAX_SEGMENTS)) ||
((p_t1t->mem[T1T_CC_NMN_BYTE] != T1T_CC_NMN) &&
(p_t1t->mem[T1T_CC_NMN_BYTE] != 0))) {
/* Tag not formated, determine maximum NDEF size from HR */
if (((p_t1t->hr[0] & 0xF0) == T1T_NDEF_SUPPORTED) &&
((p_ret = t1t_tag_init_data(p_t1t->hr[0])) != nullptr)) {
p_t1t->max_ndef_msg_len = ((p_ret->tms + 1) * T1T_BLOCK_SIZE) -
T1T_OTP_LOCK_RES_BYTES - T1T_UID_LEN -
T1T_ADD_LEN - T1T_CC_LEN - T1T_TLV_TYPE_LEN -
T1T_SHORT_NDEF_LEN_FIELD_LEN;
if (p_ret->b_dynamic) {
p_t1t->max_ndef_msg_len -=
(T1T_TLV_TYPE_LEN + T1T_DEFAULT_TLV_LEN_FIELD_LEN +
T1T_DEFAULT_TLV_LEN + T1T_TLV_TYPE_LEN +
T1T_DEFAULT_TLV_LEN_FIELD_LEN + T1T_DEFAULT_TLV_LEN);
p_t1t->max_ndef_msg_len -= T1T_DYNAMIC_LOCK_BYTES;
}
offset = tag_size;
} else {
p_t1t->segment = init_segment;
return p_t1t->max_ndef_msg_len;
}
}
/* Starting from NDEF Message offset find the first locked data byte */
while (offset < tag_size) {
if (rw_t1t_is_lock_reserved_otp_byte((uint16_t)(offset)) == false) {
if (rw_t1t_is_read_only_byte((uint16_t)offset) == true) break;
p_t1t->max_ndef_msg_len++;
}
offset++;
if (offset % T1T_SEGMENT_SIZE == 0) {
p_t1t->segment = (uint8_t)(offset / T1T_SEGMENT_SIZE);
}
}
/* NDEF Length field length changes based on NDEF size */
if ((p_t1t->max_ndef_msg_len >= T1T_LONG_NDEF_LEN_FIELD_BYTE0) &&
((p_t1t->ndef_msg_offset - p_t1t->ndef_header_offset) ==
T1T_SHORT_NDEF_LEN_FIELD_LEN)) {
p_t1t->max_ndef_msg_len -=
(p_t1t->max_ndef_msg_len == T1T_LONG_NDEF_LEN_FIELD_BYTE0)
? 1
: (T1T_LONG_NDEF_LEN_FIELD_LEN - T1T_SHORT_NDEF_LEN_FIELD_LEN);
}
p_t1t->segment = init_segment;
return p_t1t->max_ndef_msg_len;
}
/*******************************************************************************
**
** Function rw_t1t_handle_ndef_write_rsp
**
** Description Handle response to commands sent while writing an
** NDEF message
**
** Returns NFC_STATUS_CONTINUE, if tlv write is not yet complete
** NFC_STATUS_OK, if tlv write is complete & success
** NFC_STATUS_FAILED,if tlv write failed
**
*******************************************************************************/
static tNFC_STATUS rw_t1t_handle_ndef_write_rsp(uint8_t* p_data) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
uint8_t addr;
switch (p_t1t->substate) {
case RW_T1T_SUBSTATE_WAIT_READ_NDEF_BLOCK:
/* Backup ndef_final_block */
memcpy(p_t1t->ndef_final_block, p_data, T1T_BLOCK_SIZE);
/* Invalidate existing NDEF Message */
RW_T1T_BLD_ADD((addr), (T1T_CC_BLOCK), (T1T_CC_NMN_OFFSET));
if (NFC_STATUS_OK == rw_t1t_send_static_cmd(T1T_CMD_WRITE_E, addr, 0)) {
ndef_status = NFC_STATUS_CONTINUE;
p_t1t->state = RW_T1T_STATE_WRITE_NDEF;
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_INVALIDATE_NDEF;
} else {
ndef_status = NFC_STATUS_FAILED;
}
break;
case RW_T1T_SUBSTATE_WAIT_INVALIDATE_NDEF:
ndef_status = rw_t1t_ndef_write_first_block();
break;
case RW_T1T_SUBSTATE_WAIT_NDEF_WRITE:
ndef_status = rw_t1t_next_ndef_write_block();
break;
case RW_T1T_SUBSTATE_WAIT_NDEF_UPDATED:
/* Validate new NDEF Message */
RW_T1T_BLD_ADD((addr), (T1T_CC_BLOCK), (T1T_CC_NMN_OFFSET));
if (NFC_STATUS_OK ==
rw_t1t_send_static_cmd(T1T_CMD_WRITE_E, addr, T1T_CC_NMN)) {
ndef_status = NFC_STATUS_OK;
} else {
ndef_status = NFC_STATUS_FAILED;
}
break;
default:
break;
}
return ndef_status;
}
/*******************************************************************************
**
** Function rw_t1t_update_attributes
**
** Description This function will prepare attributes for the current
** segment. Every bit in the attribute refers to one byte of
** tag content.The bit corresponding to a tag byte will be set
** to '1' when the Tag byte is read only,otherwise will be set
** to '0'
**
** Returns None
**
*******************************************************************************/
static void rw_t1t_update_attributes(void) {
uint8_t count = 0;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint16_t lower_offset;
uint16_t upper_offset;
uint8_t num_bytes;
uint16_t offset;
uint8_t bits_per_byte = 8;
count = 0;
while (count < T1T_BLOCKS_PER_SEGMENT) {
p_t1t->attr[count] = 0x00;
count++;
}
lower_offset = p_t1t->segment * T1T_SEGMENT_SIZE;
upper_offset = (p_t1t->segment + 1) * T1T_SEGMENT_SIZE;
if (p_t1t->segment == 0) {
/* UID/Lock/Reserved/OTP bytes */
p_t1t->attr[0x00] = 0xFF; /* Uid bytes */
p_t1t->attr[0x0D] = 0xFF; /* Reserved bytes */
p_t1t->attr[0x0E] = 0xFF; /* lock/otp bytes */
p_t1t->attr[0x0F] = 0xFF; /* lock/otp bytes */
}
/* update attr based on lock control and mem control tlvs */
count = 0;
while (count < p_t1t->num_lockbytes) {
offset = p_t1t->lock_tlv[p_t1t->lockbyte[count].tlv_index].offset +
p_t1t->lockbyte[count].byte_index;
if (offset >= lower_offset && offset < upper_offset) {
/* Set the corresponding bit in attr to indicate - lock byte */
p_t1t->attr[(offset % T1T_SEGMENT_SIZE) / bits_per_byte] |=
rw_t1t_mask_bits[(offset % T1T_SEGMENT_SIZE) % bits_per_byte];
}
count++;
}
count = 0;
while (count < p_t1t->num_mem_tlvs) {
num_bytes = 0;
while (num_bytes < p_t1t->mem_tlv[count].num_bytes) {
offset = p_t1t->mem_tlv[count].offset + num_bytes;
if (offset >= lower_offset && offset < upper_offset) {
/* Set the corresponding bit in attr to indicate - reserved byte */
p_t1t->attr[(offset % T1T_SEGMENT_SIZE) / bits_per_byte] |=
rw_t1t_mask_bits[(offset % T1T_SEGMENT_SIZE) % bits_per_byte];
}
num_bytes++;
}
count++;
}
}
/*******************************************************************************
**
** Function rw_t1t_get_lock_bits_for_segment
**
** Description This function will identify the index of the dynamic lock
** byte that covers the current segment
**
** Parameters: segment, segment number
** p_start_byte, pointer to hold the first lock byte index
** p_start_bit, pointer to hold the first lock bit index
** p_end_byte, pointer to hold the last lock byte index
**
** Returns Total lock bits that covers the specified segment
**
*******************************************************************************/
static uint8_t rw_t1t_get_lock_bits_for_segment(uint8_t segment,
uint8_t* p_start_byte,
uint8_t* p_start_bit,
uint8_t* p_end_byte) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint16_t byte_count = T1T_SEGMENT_SIZE;
uint8_t total_bits = 0;
uint8_t num_dynamic_locks = 0;
uint8_t bit_count = 0;
uint16_t tag_size = (p_t1t->mem[T1T_CC_TMS_BYTE] + 1) * T1T_BLOCK_SIZE;
uint16_t lower_offset;
uint16_t upper_offset;
bool b_all_bits_are_locks = true;
uint8_t bytes_locked_per_bit;
uint8_t num_bits;
upper_offset = (segment + 1) * T1T_SEGMENT_SIZE;
if (upper_offset > tag_size) upper_offset = tag_size;
lower_offset = segment * T1T_SEGMENT_SIZE;
*p_start_byte = num_dynamic_locks;
*p_start_bit = 0;
while ((byte_count <= lower_offset) &&
(num_dynamic_locks < p_t1t->num_lockbytes)) {
bytes_locked_per_bit =
p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_locks].tlv_index]
.bytes_locked_per_bit;
/* Number of bits in the current lock byte */
b_all_bits_are_locks =
((p_t1t->lockbyte[num_dynamic_locks].byte_index + 1) *
TAG_BITS_PER_BYTE <=
p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_locks].tlv_index]
.num_bits);
num_bits =
b_all_bits_are_locks
? TAG_BITS_PER_BYTE
: p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_locks].tlv_index]
.num_bits %
TAG_BITS_PER_BYTE;
/* Skip lock bits that covers all previous segments */
if (bytes_locked_per_bit * num_bits + byte_count <= lower_offset) {
byte_count += bytes_locked_per_bit * num_bits;
num_dynamic_locks++;
} else {
/* The first lock bit that covers this segment is present in this segment
*/
bit_count = 0;
while (bit_count < num_bits) {
byte_count += bytes_locked_per_bit;
if (byte_count > lower_offset) {
*p_start_byte = num_dynamic_locks;
*p_end_byte = num_dynamic_locks;
*p_start_bit = bit_count;
bit_count++;
total_bits = 1;
break;
}
bit_count++;
}
}
}
if (num_dynamic_locks == p_t1t->num_lockbytes) {
return 0;
}
while ((byte_count < upper_offset) &&
(num_dynamic_locks < p_t1t->num_lockbytes)) {
bytes_locked_per_bit =
p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_locks].tlv_index]
.bytes_locked_per_bit;
/* Number of bits in the current lock byte */
b_all_bits_are_locks =
((p_t1t->lockbyte[num_dynamic_locks].byte_index + 1) *
TAG_BITS_PER_BYTE <=
p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_locks].tlv_index]
.num_bits);
num_bits =
b_all_bits_are_locks
? TAG_BITS_PER_BYTE
: p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_locks].tlv_index]
.num_bits %
TAG_BITS_PER_BYTE;
/* Collect all lock bits that covers the current segment */
if ((bytes_locked_per_bit * (num_bits - bit_count)) + byte_count <
upper_offset) {
byte_count += bytes_locked_per_bit * (num_bits - bit_count);
total_bits += num_bits - bit_count;
bit_count = 0;
*p_end_byte = num_dynamic_locks;
num_dynamic_locks++;
} else {
/* The last lock byte that covers the current segment */
bit_count = 0;
while (bit_count < num_bits) {
byte_count += bytes_locked_per_bit;
if (byte_count >= upper_offset) {
*p_end_byte = num_dynamic_locks;
total_bits += (bit_count + 1);
break;
}
bit_count++;
}
}
}
return total_bits;
}
/*******************************************************************************
**
** Function rw_t1t_update_lock_attributes
**
** Description This function will check if the tag index passed as
** argument is a locked byte and return
** TRUE or FALSE
**
** Parameters: index, the index of the byte in the tag
**
**
** Returns TRUE, if the specified index in the tag is a locked or
** reserved or otp byte
** FALSE, otherwise
**
*******************************************************************************/
static void rw_t1t_update_lock_attributes(void) {
uint8_t xx = 0;
uint8_t bytes_locked_per_lock_bit;
uint8_t num_static_lock_bytes = 0;
uint8_t num_dynamic_lock_bytes = 0;
uint8_t bits_covered = 0;
uint8_t bytes_covered = 0;
uint8_t block_count = 0;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t start_lock_byte;
uint8_t start_lock_bit;
uint8_t end_lock_byte;
uint8_t num_lock_bits;
uint8_t total_bits;
block_count = 0;
while (block_count < T1T_BLOCKS_PER_SEGMENT) {
p_t1t->lock_attr[block_count] = 0x00;
block_count++;
}
/* update lock_attr based on static lock bytes */
if (p_t1t->segment == 0) {
xx = 0;
num_static_lock_bytes = 0;
block_count = 0;
num_lock_bits = 8;
while (num_static_lock_bytes < T1T_NUM_STATIC_LOCK_BYTES) {
/* Update lock attribute based on 2 static locks */
while (xx < num_lock_bits) {
p_t1t->lock_attr[block_count] = 0x00;
if (p_t1t->mem[T1T_LOCK_0_OFFSET + num_static_lock_bytes] &
rw_t1t_mask_bits[xx++]) {
/* If the bit is set then 1 block is locked */
p_t1t->lock_attr[block_count] = 0xFF;
}
block_count++;
}
num_static_lock_bytes++;
xx = 0;
}
/* Locked bytes */
p_t1t->lock_attr[0x00] = 0xFF;
p_t1t->lock_attr[0x0D] = 0xFF;
} else {
/* update lock_attr based on segment and using dynamic lock bytes */
total_bits = rw_t1t_get_lock_bits_for_segment(
p_t1t->segment, &start_lock_byte, &start_lock_bit, &end_lock_byte);
if (total_bits != 0) {
xx = start_lock_bit;
num_dynamic_lock_bytes = start_lock_byte;
bits_covered = 0;
bytes_covered = 0;
block_count = 0;
num_lock_bits = 8;
p_t1t->lock_attr[block_count] = 0;
while (num_dynamic_lock_bytes <= end_lock_byte) {
bytes_locked_per_lock_bit =
p_t1t->lock_tlv[p_t1t->lockbyte[num_dynamic_lock_bytes].tlv_index]
.bytes_locked_per_bit;
if (num_dynamic_lock_bytes == end_lock_byte) {
num_lock_bits = (total_bits % 8 == 0) ? 8 : total_bits % 8;
}
while (xx < num_lock_bits) {
bytes_covered = 0;
while (bytes_covered < bytes_locked_per_lock_bit) {
/* Set/clear lock_attr byte bits based on whether a particular lock
* bit is set or not
* each bit in lock_attr represents one byte in Tag read only
* attribute */
if ((p_t1t->lockbyte[num_dynamic_lock_bytes].lock_byte &
rw_t1t_mask_bits[xx]) &&
(block_count < T1T_BLOCKS_PER_SEGMENT)) {
p_t1t->lock_attr[block_count] |= 0x01 << bits_covered;
}
bytes_covered++;
bits_covered++;
if (bits_covered == 8) {
bits_covered = 0;
block_count++;
if (block_count < T1T_BLOCKS_PER_SEGMENT)
p_t1t->lock_attr[block_count] = 0;
}
}
xx++;
}
num_dynamic_lock_bytes++;
xx = 0;
}
}
}
}
/*******************************************************************************
**
** Function rw_t1t_is_lock_reserved_otp_byte
**
** Description This function will check if the tag index passed as
** argument is a lock or reserved or otp byte
**
** Parameters: index, the index of the byte in the tag's current segment
**
**
** Returns TRUE, if the specified index in the tag is a locked or
** reserved or otp byte
** FALSE, otherwise
**
*******************************************************************************/
static bool rw_t1t_is_lock_reserved_otp_byte(uint16_t index) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
if (p_t1t->attr_seg != p_t1t->segment) {
/* Update p_t1t->attr to reflect the current segment */
rw_t1t_update_attributes();
p_t1t->attr_seg = p_t1t->segment;
}
index = index % T1T_SEGMENT_SIZE;
/* Every bit in p_t1t->attr indicates one specific byte of the tag is either a
* lock/reserved/otp byte or not
* So, each array element in p_t1t->attr covers one block in the tag as T1
* block size and array element size is 8
* Find the block and offset for the index (passed as argument) and Check if
* the offset bit in the
* p_t1t->attr[block] is set or not. If the bit is set then it is a
* lock/reserved/otp byte, otherwise not */
return ((p_t1t->attr[index / 8] & rw_t1t_mask_bits[index % 8]) == 0) ? false
: true;
}
/*******************************************************************************
**
** Function rw_t1t_is_read_only_byte
**
** Description This function will check if the tag index passed as
** argument is a read only byte
**
** Parameters: index, the index of the byte in the tag's current segment
**
**
** Returns TRUE, if the specified index in the tag is a locked or
** reserved or otp byte
** FALSE, otherwise
**
*******************************************************************************/
static bool rw_t1t_is_read_only_byte(uint16_t index) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
if (p_t1t->lock_attr_seg != p_t1t->segment) {
/* Update p_t1t->lock_attr to reflect the current segment */
rw_t1t_update_lock_attributes();
p_t1t->lock_attr_seg = p_t1t->segment;
}
index = index % T1T_SEGMENT_SIZE;
/* Every bit in p_t1t->lock_attr indicates one specific byte of the tag is a
* read only byte or read write byte
* So, each array element in p_t1t->lock_attr covers one block in the tag as
* T1 block size and array element size is 8
* Find the block and offset for the index (passed as argument) and Check if
* the offset bit in the
* p_t1t->lock_attr[block] is set or not. If the bit is set then it is a read
* only byte, otherwise read write byte */
return ((p_t1t->lock_attr[index / 8] & rw_t1t_mask_bits[index % 8]) == 0)
? false
: true;
}
/*****************************************************************************
**
** Function RW_T1tFormatNDef
**
** Description
** Format Tag content
**
** Returns
** NFC_STATUS_OK, Command sent to format Tag
** NFC_STATUS_REJECTED: Invalid HR0 and cannot format the tag
** NFC_STATUS_FAILED: other error
**
*****************************************************************************/
tNFC_STATUS RW_T1tFormatNDef(void) {
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_FAILED;
const tT1T_INIT_TAG* p_ret;
uint8_t addr;
uint8_t* p;
if (p_t1t->state != RW_T1T_STATE_IDLE) {
LOG(WARNING) << StringPrintf(
"RW_T1tFormatNDef - Tag not initialized/ Busy! State: %u",
p_t1t->state);
return (NFC_STATUS_FAILED);
}
if ((p_t1t->hr[0] & 0xF0) != T1T_NDEF_SUPPORTED) {
LOG(WARNING) << StringPrintf(
"RW_T1tFormatNDef - Cannot format tag as NDEF not supported. HR0: %u",
p_t1t->hr[0]);
return (NFC_STATUS_REJECTED);
}
p_ret = t1t_tag_init_data(p_t1t->hr[0]);
if (p_ret == nullptr) {
LOG(WARNING) << StringPrintf(
"RW_T1tFormatNDef - Invalid HR - HR0: %u, HR1: %u", p_t1t->hr[0],
p_t1t->hr[1]);
return (NFC_STATUS_REJECTED);
}
memset(p_t1t->ndef_first_block, 0, T1T_BLOCK_SIZE);
memset(p_t1t->ndef_final_block, 0, T1T_BLOCK_SIZE);
p = p_t1t->ndef_first_block;
/* Prepare Capability Container */
UINT8_TO_BE_STREAM(p, T1T_CC_NMN);
UINT8_TO_BE_STREAM(p, T1T_CC_VNO);
UINT8_TO_BE_STREAM(p, p_ret->tms);
UINT8_TO_BE_STREAM(p, T1T_CC_RWA_RW);
if (p_ret->b_dynamic) {
/* Prepare Lock and Memory TLV */
UINT8_TO_BE_STREAM(p, TAG_LOCK_CTRL_TLV);
UINT8_TO_BE_STREAM(p, T1T_DEFAULT_TLV_LEN);
UINT8_TO_BE_STREAM(p, p_ret->lock_tlv[0]);
UINT8_TO_BE_STREAM(p, p_ret->lock_tlv[1]);
p = p_t1t->ndef_final_block;
UINT8_TO_BE_STREAM(p, p_ret->lock_tlv[2]);
UINT8_TO_BE_STREAM(p, TAG_MEM_CTRL_TLV);
UINT8_TO_BE_STREAM(p, T1T_DEFAULT_TLV_LEN);
UINT8_TO_BE_STREAM(p, p_ret->mem_tlv[0]);
UINT8_TO_BE_STREAM(p, p_ret->mem_tlv[1]);
UINT8_TO_BE_STREAM(p, p_ret->mem_tlv[2]);
}
/* Prepare NULL NDEF TLV */
UINT8_TO_BE_STREAM(p, TAG_NDEF_TLV);
UINT8_TO_BE_STREAM(p, 0);
if (rw_cb.tcb.t1t.hr[0] != T1T_STATIC_HR0 ||
rw_cb.tcb.t1t.hr[1] >= RW_T1T_HR1_MIN) {
/* send WRITE-E8 command */
status = rw_t1t_send_dyn_cmd(T1T_CMD_WRITE_E8, 1, p_t1t->ndef_first_block);
if (status == NFC_STATUS_OK) {
p_t1t->state = RW_T1T_STATE_FORMAT_TAG;
p_t1t->b_update = false;
p_t1t->b_rseg = false;
if (p_ret->b_dynamic)
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_CC;
else
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_NULL_NDEF;
}
} else {
/* send WRITE-E command */
RW_T1T_BLD_ADD((addr), 1, 0);
status = rw_t1t_send_static_cmd(T1T_CMD_WRITE_E, addr,
p_t1t->ndef_first_block[0]);
if (status == NFC_STATUS_OK) {
p_t1t->work_offset = 0;
p_t1t->state = RW_T1T_STATE_FORMAT_TAG;
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_NULL_NDEF;
p_t1t->b_update = false;
p_t1t->b_rseg = false;
}
}
return status;
}
/*******************************************************************************
**
** Function RW_T1tLocateTlv
**
** Description This function is called to find the start of the given TLV
**
** Parameters: tlv_type, Type of TLV to find
**
** Returns NCI_STATUS_OK, if detection was started. Otherwise, error
** status.
**
*******************************************************************************/
tNFC_STATUS RW_T1tLocateTlv(uint8_t tlv_type) {
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t adds;
if (p_t1t->state != RW_T1T_STATE_IDLE) {
LOG(WARNING) << StringPrintf("RW_T1tLocateTlv - Busy - State: %u",
p_t1t->state);
return (NFC_STATUS_FAILED);
}
p_t1t->tlv_detect = tlv_type;
if ((p_t1t->tlv_detect == TAG_NDEF_TLV) &&
(((p_t1t->hr[0]) & 0xF0) != T1T_NDEF_SUPPORTED)) {
LOG(ERROR) << StringPrintf(
"RW_T1tLocateTlv - Error: NDEF not supported by the tag");
return (NFC_STATUS_REFUSED);
}
if ((p_t1t->tlv_detect == TAG_MEM_CTRL_TLV) ||
(p_t1t->tlv_detect == TAG_NDEF_TLV)) {
p_t1t->num_mem_tlvs = 0;
}
if ((p_t1t->tlv_detect == TAG_LOCK_CTRL_TLV) ||
(p_t1t->tlv_detect == TAG_NDEF_TLV)) {
p_t1t->num_lockbytes = 0;
p_t1t->num_lock_tlvs = 0;
}
/* Start reading memory, looking for the TLV */
p_t1t->segment = 0;
if ((p_t1t->hr[0] & 0x0F) != 1) {
/* send RSEG command */
RW_T1T_BLD_ADDS((adds), (p_t1t->segment));
status = rw_t1t_send_dyn_cmd(T1T_CMD_RSEG, adds, nullptr);
} else {
status = rw_t1t_send_static_cmd(T1T_CMD_RALL, 0, 0);
}
if (status == NFC_STATUS_OK) {
p_t1t->tlv_detect = tlv_type;
p_t1t->work_offset = 0;
p_t1t->state = RW_T1T_STATE_TLV_DETECT;
p_t1t->substate = RW_T1T_SUBSTATE_NONE;
}
return status;
}
/*****************************************************************************
**
** Function RW_T1tDetectNDef
**
** Description
** This function is used to perform NDEF detection on a Type 1 tag, and
** retrieve the tag's NDEF attribute information (block 0).
**
** Before using this API, the application must call RW_SelectTagType to
** indicate that a Type 1 tag has been activated.
**
** Returns
** NFC_STATUS_OK: ndef detection procedure started
** NFC_STATUS_WRONG_PROTOCOL: type 1 tag not activated
** NFC_STATUS_BUSY: another command is already in progress
** NFC_STATUS_FAILED: other error
**
*****************************************************************************/
tNFC_STATUS RW_T1tDetectNDef(void) { return RW_T1tLocateTlv(TAG_NDEF_TLV); }
/*******************************************************************************
**
** Function RW_T1tReadNDef
**
** Description This function can be called to read the NDEF message on the
** tag.
**
** Parameters: p_buffer: The buffer into which to read the NDEF message
** buf_len: The length of the buffer
**
** Returns NCI_STATUS_OK, if read was started. Otherwise, error status.
**
*******************************************************************************/
tNFC_STATUS RW_T1tReadNDef(uint8_t* p_buffer, uint16_t buf_len) {
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
bool b_notify;
uint8_t adds;
const tT1T_CMD_RSP_INFO* p_cmd_rsp_info_rall =
t1t_cmd_to_rsp_info(T1T_CMD_RALL);
const tT1T_CMD_RSP_INFO* p_cmd_rsp_info_rseg =
t1t_cmd_to_rsp_info(T1T_CMD_RSEG);
if (p_t1t->state != RW_T1T_STATE_IDLE) {
LOG(WARNING) << StringPrintf("RW_T1tReadNDef - Busy - State: %u",
p_t1t->state);
return (NFC_STATUS_FAILED);
}
/* Check HR0 if NDEF supported by the tag */
if (((p_t1t->hr[0]) & 0xF0) != T1T_NDEF_SUPPORTED) {
LOG(ERROR) << StringPrintf(
"RW_T1tReadNDef - Error: NDEF not supported by the tag");
return (NFC_STATUS_REFUSED);
}
if (p_t1t->tag_attribute == RW_T1_TAG_ATTRB_INITIALIZED_NDEF) {
LOG(WARNING) << StringPrintf(
"RW_T1tReadNDef - NDEF Message length is zero, NDEF Length : %u ",
p_t1t->ndef_msg_len);
return (NFC_STATUS_NOT_INITIALIZED);
}
if ((p_t1t->tag_attribute != RW_T1_TAG_ATTRB_READ_WRITE) &&
(p_t1t->tag_attribute != RW_T1_TAG_ATTRB_READ_ONLY)) {
LOG(ERROR) << StringPrintf(
"RW_T1tReadNDef - Error: NDEF detection not performed yet/ Tag is in "
"Initialized state");
return (NFC_STATUS_FAILED);
}
if (buf_len < p_t1t->ndef_msg_len) {
LOG(WARNING) << StringPrintf(
"RW_T1tReadNDef - buffer size: %u less than NDEF msg sise: %u",
buf_len, p_t1t->ndef_msg_len);
return (NFC_STATUS_FAILED);
}
p_t1t->p_ndef_buffer = p_buffer;
if (p_t1t->b_rseg == true) {
/* If already got response to RSEG 0 */
p_t1t->state = RW_T1T_STATE_READ_NDEF;
p_t1t->p_cmd_rsp_info = (tT1T_CMD_RSP_INFO*)p_cmd_rsp_info_rseg;
rw_t1t_handle_read_rsp(&b_notify, p_t1t->mem);
status = NFC_STATUS_OK;
} else if (p_t1t->b_update == true) {
/* If already got response to RALL */
p_t1t->state = RW_T1T_STATE_READ_NDEF;
p_t1t->p_cmd_rsp_info = (tT1T_CMD_RSP_INFO*)p_cmd_rsp_info_rall;
rw_t1t_handle_read_rsp(&b_notify, p_t1t->mem);
status = NFC_STATUS_OK;
} else {
p_t1t->segment = 0;
p_t1t->work_offset = 0;
if ((p_t1t->hr[0] & 0x0F) != 1) {
/* send RSEG command */
RW_T1T_BLD_ADDS((adds), (p_t1t->segment));
status = rw_t1t_send_dyn_cmd(T1T_CMD_RSEG, adds, nullptr);
} else {
status = rw_t1t_send_static_cmd(T1T_CMD_RALL, 0, 0);
}
if (status == NFC_STATUS_OK) p_t1t->state = RW_T1T_STATE_READ_NDEF;
}
return status;
}
/*******************************************************************************
**
** Function RW_T1tWriteNDef
**
** Description This function can be called to write an NDEF message to the
** tag.
**
** Parameters: msg_len: The length of the buffer
** p_msg: The NDEF message to write
**
** Returns NCI_STATUS_OK, if write was started. Otherwise, error
** status.
**
*******************************************************************************/
tNFC_STATUS RW_T1tWriteNDef(uint16_t msg_len, uint8_t* p_msg) {
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint16_t num_ndef_bytes;
uint16_t offset;
uint8_t addr;
uint8_t init_lengthfield_len;
uint8_t new_lengthfield_len;
uint16_t init_ndef_msg_offset;
if (p_t1t->state != RW_T1T_STATE_IDLE) {
LOG(WARNING) << StringPrintf("RW_T1tWriteNDef - Busy - State: %u",
p_t1t->state);
return (NFC_STATUS_FAILED);
}
/* Check HR0 if NDEF supported by the tag */
if (((p_t1t->hr[0]) & 0xF0) != T1T_NDEF_SUPPORTED) {
LOG(ERROR) << StringPrintf(
"RW_T1tWriteNDef - Error: NDEF not supported by the tag");
return (NFC_STATUS_REFUSED);
}
if ((p_t1t->tag_attribute != RW_T1_TAG_ATTRB_READ_WRITE) &&
(p_t1t->tag_attribute != RW_T1_TAG_ATTRB_INITIALIZED_NDEF)) {
LOG(ERROR) << StringPrintf("RW_T1tWriteNDef - Tag cannot update NDEF");
return (NFC_STATUS_REFUSED);
}
if (msg_len > p_t1t->max_ndef_msg_len) {
LOG(ERROR) << StringPrintf(
"RW_T1tWriteNDef - Cannot write NDEF of size greater than %u bytes",
p_t1t->max_ndef_msg_len);
return (NFC_STATUS_REFUSED);
}
p_t1t->p_ndef_buffer = p_msg;
p_t1t->new_ndef_msg_len = msg_len;
new_lengthfield_len = p_t1t->new_ndef_msg_len > 254 ? 3 : 1;
init_lengthfield_len =
(uint8_t)(p_t1t->ndef_msg_offset - p_t1t->ndef_header_offset);
init_ndef_msg_offset = p_t1t->ndef_msg_offset;
/* ndef_msg_offset should reflect the new ndef message offset */
if (init_lengthfield_len > new_lengthfield_len) {
p_t1t->ndef_msg_offset =
init_ndef_msg_offset -
(T1T_LONG_NDEF_LEN_FIELD_LEN - T1T_SHORT_NDEF_LEN_FIELD_LEN);
} else if (init_lengthfield_len < new_lengthfield_len) {
p_t1t->ndef_msg_offset =
init_ndef_msg_offset +
(T1T_LONG_NDEF_LEN_FIELD_LEN - T1T_SHORT_NDEF_LEN_FIELD_LEN);
}
num_ndef_bytes = 0;
offset = p_t1t->ndef_msg_offset;
p_t1t->segment = (uint8_t)(p_t1t->ndef_msg_offset / T1T_SEGMENT_SIZE);
/* Locate NDEF final block based on the size of new NDEF Message */
while (num_ndef_bytes < p_t1t->new_ndef_msg_len) {
if (rw_t1t_is_lock_reserved_otp_byte((uint16_t)offset) == false)
num_ndef_bytes++;
offset++;
if (offset % T1T_SEGMENT_SIZE == 0) {
p_t1t->segment = (uint8_t)(offset / T1T_SEGMENT_SIZE);
}
}
p_t1t->b_update = false;
p_t1t->b_rseg = false;
if ((p_t1t->hr[0] & 0x0F) != 1) {
/* Dynamic data structure */
p_t1t->block_read = (uint8_t)((offset - 1) / T1T_BLOCK_SIZE);
/* Read NDEF final block before updating */
status = rw_t1t_send_dyn_cmd(T1T_CMD_READ8, p_t1t->block_read, nullptr);
if (status == NFC_STATUS_OK) {
p_t1t->num_ndef_finalblock = p_t1t->block_read;
p_t1t->state = RW_T1T_STATE_WRITE_NDEF;
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_READ_NDEF_BLOCK;
}
} else {
/* NDEF detected and Static memory structure so send WRITE-E command */
RW_T1T_BLD_ADD((addr), (T1T_CC_BLOCK), (T1T_CC_NMN_OFFSET));
status = rw_t1t_send_static_cmd(T1T_CMD_WRITE_E, addr, 0);
if (status == NFC_STATUS_OK) {
p_t1t->state = RW_T1T_STATE_WRITE_NDEF;
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_INVALIDATE_NDEF;
}
}
if (status != NFC_STATUS_OK) {
/* if status failed, reset ndef_msg_offset to initial message */
p_t1t->ndef_msg_offset = init_ndef_msg_offset;
}
return status;
}
/*******************************************************************************
**
** Function RW_T1tSetTagReadOnly
**
** Description This function can be called to set t1 tag as read only.
**
** Parameters: None
**
** Returns NCI_STATUS_OK, if setting tag as read only was started.
** Otherwise, error status.
**
*******************************************************************************/
tNFC_STATUS RW_T1tSetTagReadOnly(bool b_hard_lock) {
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB* p_t1t = &rw_cb.tcb.t1t;
uint8_t addr;
uint8_t num_locks;
if (p_t1t->state != RW_T1T_STATE_IDLE) {
LOG(WARNING) << StringPrintf("RW_T1tSetTagReadOnly - Busy - State: %u",
p_t1t->state);
return (NFC_STATUS_BUSY);
}
p_t1t->b_hard_lock = b_hard_lock;
if ((p_t1t->tag_attribute == RW_T1_TAG_ATTRB_READ_WRITE) ||
(p_t1t->tag_attribute == RW_T1_TAG_ATTRB_INITIALIZED) ||
(p_t1t->tag_attribute == RW_T1_TAG_ATTRB_INITIALIZED_NDEF)) {
/* send WRITE-NE command */
RW_T1T_BLD_ADD((addr), (T1T_CC_BLOCK), (T1T_CC_RWA_OFFSET));
status = rw_t1t_send_static_cmd(T1T_CMD_WRITE_NE, addr, 0x0F);
if (status == NFC_STATUS_OK) {
p_t1t->b_update = false;
p_t1t->b_rseg = false;
if (p_t1t->b_hard_lock) {
num_locks = 0;
while (num_locks < p_t1t->num_lockbytes) {
p_t1t->lockbyte[num_locks].lock_status = RW_T1T_LOCK_NOT_UPDATED;
num_locks++;
}
}
p_t1t->state = RW_T1T_STATE_SET_TAG_RO;
p_t1t->substate = RW_T1T_SUBSTATE_WAIT_SET_CC_RWA_RO;
}
}
return status;
}
#endif /* (RW_NDEF_INCLUDED == TRUE) */