blob: f37f34371541cb39a027d93296431d72f1a3711d [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2010-2012 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.h>
#include "nfc_target.h"
#if (NFC_INCLUDED == TRUE)
#include "nfc_api.h"
#include "nci_hmsgs.h"
#include "rw_api.h"
#include "rw_int.h"
#include "nfc_int.h"
#include "gki.h"
#if (defined (RW_NDEF_INCLUDED) && (RW_NDEF_INCLUDED == TRUE))
/* Local Functions */
static tNFC_STATUS rw_t1t_handle_rall_rsp (BOOLEAN *p_notify,UINT8 *p_data);
static tNFC_STATUS rw_t1t_handle_dyn_read_rsp (BOOLEAN *p_notify, UINT8 *p_data);
static tNFC_STATUS rw_t1t_handle_write_rsp (BOOLEAN *p_notify, UINT8 *p_data);
static tNFC_STATUS rw_t1t_handle_read_rsp (BOOLEAN *p_callback, UINT8 *p_data);
static tNFC_STATUS rw_t1t_handle_tlv_detect_rsp (UINT8 *p_data);
static tNFC_STATUS rw_t1t_handle_ndef_read_rsp (UINT8 *p_data);
static tNFC_STATUS rw_t1t_handle_ndef_write_rsp (UINT8 *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 data, UINT8 block, UINT8 index, UINT8 msg_len);
static tNFC_STATUS rw_t1t_send_ndef_block (UINT8 *p_data, UINT8 block);
static UINT8 rw_t1t_prepare_ndef_bytes (UINT8 *p_data, UINT8 *p_length_field, UINT8 *p_index, BOOLEAN b_one_byte, UINT8 block, UINT8 lengthfield_len);
static UINT8 rw_t1t_get_ndef_flags (void);
static UINT16 rw_t1t_get_ndef_max_size (void);
static BOOLEAN rw_t1t_is_lock_reserved_otp_byte (UINT16 index);
static BOOLEAN rw_t1t_is_read_only_byte (UINT16 index);
static UINT8 rw_t1t_get_lock_bits_for_segment (UINT8 segment,UINT8 *p_start_byte, UINT8 *p_start_bit,UINT8 *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 *p_data);
static void rw_t1t_update_tag_state (void);
const UINT8 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, BOOLEAN *p_notify, UINT8 *p_data, tNFC_STATUS *p_status)
{
tRW_EVENT rw_event;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT8 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 *) (p_data + 1), 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
**
** Returns None
**
*******************************************************************************/
void rw_t1t_extract_lock_bytes (UINT8 *p_data)
{
UINT16 end;
UINT16 start;
UINT8 num_locks;
UINT16 lock_offset = 0;
UINT16 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 = (p_t1t->segment + 1) * T1T_SEGMENT_SIZE;
}
else if (p_cmd_rsp_info->opcode == T1T_CMD_READ8)
{
start = p_data[0] * T1T_BLOCK_SIZE;
end = (p_data[0] + 1) * 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)
{
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) )
{
if (p_cmd_rsp_info->opcode == T1T_CMD_RSEG)
{
lock_offset = (offset % T1T_SEGMENT_SIZE) + T1T_ADD_LEN;
}
else if (p_cmd_rsp_info->opcode == T1T_CMD_READ8)
{
lock_offset = (offset % T1T_BLOCK_SIZE) + T1T_ADD_LEN;
}
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 num_locks = 0;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_CONTINUE;
UINT16 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 */
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_READ8, (UINT8) (offset/T1T_BLOCK_SIZE), NULL)) == 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 (BOOLEAN *p_notify, UINT8 *p_data)
{
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS status = NFC_STATUS_OK;
UINT8 num_locks;
UINT8 lock_count;
UINT8 value;
UINT8 addr;
UINT8 write_block[T1T_BLOCK_SIZE];
UINT16 offset;
UINT16 next_offset;
UINT8 num_bits;
UINT8 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) p_t1t->work_offset);
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_E, addr, p_t1t->ndef_first_block[(UINT8) p_t1t->work_offset])) != NFC_STATUS_OK)
*p_notify = TRUE;
}
else
*p_notify = TRUE;
}
}
else
{
/* send WRITE-E8 command */
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_WRITE_E8, 2, p_t1t->ndef_final_block)) != 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 */
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_WRITE_NE8, T1T_LOCK_BLOCK, write_block)) != 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));
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_NE, addr, 0xFF)) != 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));
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_NE, addr, 0xFF)) != 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) (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) (next_offset%T1T_BLOCK_SIZE)] |= tags_pow (2,next_num_bits) - 1;
}
else
break;
lock_count ++;
}
/* send WRITE-NE8 command */
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_WRITE_NE8, (UINT8) (offset/T1T_BLOCK_SIZE), write_block)) == 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) (offset/T1T_BLOCK_SIZE)), ((UINT8) (offset%T1T_BLOCK_SIZE)));
value = (UINT8) (tags_pow (2,num_bits) - 1);
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_NE, addr, value)) == 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 response received for RSEG,
** RALL, READ8 commands
**
** Returns status of the current NDEF/TLV Operation
**
*******************************************************************************/
tNFC_STATUS rw_t1t_handle_read_rsp (BOOLEAN *p_notify,UINT8 *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 count;
tRW_READ_DATA evt_data;
*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)
{
evt_data.status = status;
evt_data.p_data = NULL;
rw_t1t_handle_op_complete ();
(*rw_cb.p_cback) (RW_T1T_NDEF_READ_EVT, (tRW_DATA *) &evt_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 ();
(*rw_cb.p_cback) (RW_T1T_TLV_DETECT_EVT, (tRW_DATA *) &tlv_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) 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 ();
(*rw_cb.p_cback) (RW_T1T_NDEF_DETECT_EVT, (tRW_DATA *)&ndef_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 */
(*rw_cb.p_cback) (RW_T1T_TLV_DETECT_EVT, (tRW_DATA *) &tlv_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 */
(*rw_cb.p_cback) (RW_T1T_TLV_DETECT_EVT, (tRW_DATA *)&tlv_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 ();
(*rw_cb.p_cback) (RW_T1T_TLV_DETECT_EVT, (tRW_DATA *) &tlv_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) 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 ();
(*rw_cb.p_cback) (RW_T1T_NDEF_DETECT_EVT, (tRW_DATA *) &ndef_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) 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 ();
(*rw_cb.p_cback) (RW_T1T_NDEF_DETECT_EVT, (tRW_DATA *)&ndef_data);
}
}
}
else
{
/* Send Negative response to upper layer */
ndef_data.status = NFC_STATUS_FAILED;
ndef_data.max_size = (UINT32) 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 ();
(*rw_cb.p_cback) (RW_T1T_NDEF_DETECT_EVT, (tRW_DATA *) &ndef_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 (BOOLEAN *p_notify, UINT8 *p_data)
{
tNFC_STATUS status = NFC_STATUS_OK;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
*p_notify = FALSE;
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 (BOOLEAN *p_notify,UINT8 *p_data)
{
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
p_data += T1T_HR_LEN; /* skip HR */
memcpy (p_t1t->mem, (UINT8 *) 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 */
RW_TRACE_DEBUG0 ("rw_t1t_handle_rall_rsp ()");
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 *p_data)
{
UINT16 offset;
UINT16 len;
UINT8 xx;
UINT8 *p_readbytes;
UINT8 index;
UINT8 tlv_detect_state = RW_T1T_SUBSTATE_WAIT_TLV_DETECT;
UINT8 found_tlv = TAG_NULL_TLV;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
BOOLEAN failed = FALSE;
BOOLEAN found = FALSE;
UINT8 count = 0;
tNFC_STATUS status = NFC_STATUS_FAILED;
UINT8 start_offset = T1T_UID_LEN + T1T_CC_LEN + T1T_RES_BYTE_LEN;
UINT8 end_offset = T1T_STATIC_SIZE - (2*T1T_BLOCK_SIZE);
UINT8 bytes_read = T1T_STATIC_SIZE;
UINT8 tlv_value[T1T_DEFAULT_TLV_LEN];
UINT16 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) (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 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_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) 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) 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) 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
RW_TRACE_ERROR1 ("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
RW_TRACE_ERROR1 ("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)
{
RW_TRACE_ERROR0 ("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) 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;
/* If not found and not failed, try to read next segment in Dynamic Memory structure */
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 count;
UINT8 adds;
count = (UINT8) 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)
{
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_READ8, p_t1t->block_read, NULL)) == 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));
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_RSEG, adds, NULL)) == NFC_STATUS_OK)
{
p_t1t->state = RW_T1T_STATE_READ_NDEF;
status = NFC_STATUS_CONTINUE;
}
}
}
else
{
RW_TRACE_ERROR1 ("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 *p_data)
{
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT8 index;
UINT8 adds;
UINT8 *p_readbytes;
tT1T_CMD_RSP_INFO *p_cmd_rsp_info = (tT1T_CMD_RSP_INFO *) rw_cb.tcb.t1t.p_cmd_rsp_info;
p_readbytes = p_data + T1T_ADD_LEN;
/* 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) ((p_t1t->block_read * T1T_BLOCK_SIZE) + index)) == FALSE)
{
p_t1t->p_ndef_buffer[p_t1t->work_offset] = p_readbytes[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) (index)) == FALSE)
{
p_t1t->p_ndef_buffer[p_t1t->work_offset] = p_readbytes[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++;
if ((ndef_status = rw_t1t_send_dyn_cmd (T1T_CMD_READ8, (UINT8) (p_t1t->block_read), NULL)) == NFC_STATUS_OK)
{
ndef_status = NFC_STATUS_CONTINUE;
}
}
else
{
p_t1t->segment++;
/* send RSEG command */
RW_T1T_BLD_ADDS ((adds), (p_t1t->segment));
if ((ndef_status = rw_t1t_send_dyn_cmd (T1T_CMD_RSEG, adds, NULL)) == 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)
{
BOOLEAN b_block_write_cmd = FALSE;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
UINT8 write_block[8];
UINT8 block;
UINT8 index;
UINT8 new_lengthfield_len;
UINT8 length_field[3];
UINT16 initial_offset;
UINT8 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) ((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) (p_t1t->new_ndef_msg_len >> 8);
length_field[2] = (UINT8) (p_t1t->new_ndef_msg_len);
}
else
{
length_field[0] = (UINT8) (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 block;
UINT8 index;
UINT8 new_lengthfield_len;
UINT8 length_field[3];
UINT8 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) (p_t1t->new_ndef_msg_len >> 8);
length_field[2] = (UINT8) (p_t1t->new_ndef_msg_len);
}
else
{
length_field[0] = (UINT8) (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) (p_t1t->ndef_header_offset / T1T_BLOCK_SIZE);
p_t1t->segment = (UINT8) (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 data, UINT8 block, UINT8 index, UINT8 msg_len)
{
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT8 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 rw_t1t_prepare_ndef_bytes (UINT8 *p_data, UINT8 *p_length_field, UINT8 *p_index, BOOLEAN b_one_byte, UINT8 block, UINT8 lengthfield_len)
{
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT8 first_block = (UINT8) (p_t1t->ndef_header_offset / T1T_BLOCK_SIZE);
UINT16 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) ((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) ((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 *p_data, UINT8 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 rw_t1t_get_ndef_flags (void)
{
UINT8 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]) != NULL)
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 rw_t1t_get_ndef_max_size (void)
{
UINT16 offset;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT16 tag_size = (p_t1t->mem[T1T_CC_TMS_BYTE] +1)* T1T_BLOCK_SIZE;
const tT1T_INIT_TAG *p_ret;
UINT8 init_segment = p_t1t->segment;
p_t1t->max_ndef_msg_len = 0;
offset = p_t1t->ndef_msg_offset;
p_t1t->segment = (UINT8) (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])) != NULL) )
{
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) (offset)) == FALSE)
{
if (rw_t1t_is_read_only_byte ((UINT16) offset) == TRUE)
break;
p_t1t->max_ndef_msg_len++;
}
offset++;
if (offset % T1T_SEGMENT_SIZE == 0)
{
p_t1t->segment = (UINT8) (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 *p_data)
{
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
tNFC_STATUS ndef_status = NFC_STATUS_CONTINUE;
UINT8 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_ADD_LEN,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 count = 0;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT16 lower_offset;
UINT16 upper_offset;
UINT8 num_bytes;
UINT16 offset;
UINT8 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 rw_t1t_get_lock_bits_for_segment (UINT8 segment,UINT8 *p_start_byte, UINT8 *p_start_bit,UINT8 *p_end_byte)
{
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT16 byte_count = T1T_SEGMENT_SIZE;
UINT8 total_bits = 0;
UINT8 num_dynamic_locks = 0;
UINT8 bit_count = 0;
UINT16 tag_size = (p_t1t->mem[T1T_CC_TMS_BYTE] +1) * T1T_BLOCK_SIZE;
UINT16 lower_offset;
UINT16 upper_offset;
BOOLEAN b_all_bits_are_locks = TRUE;
UINT8 bytes_locked_per_bit;
UINT8 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 xx = 0;
UINT8 bytes_locked_per_lock_bit;
UINT8 num_static_lock_bytes = 0;
UINT8 num_dynamic_lock_bytes = 0;
UINT8 bits_covered = 0;
UINT8 bytes_covered = 0;
UINT8 block_count = 0;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT8 start_lock_byte;
UINT8 start_lock_bit;
UINT8 end_lock_byte;
UINT8 num_lock_bits;
UINT8 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 */
if ((total_bits = rw_t1t_get_lock_bits_for_segment (p_t1t->segment,&start_lock_byte, &start_lock_bit,&end_lock_byte)) != 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])
{
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 BOOLEAN rw_t1t_is_lock_reserved_otp_byte (UINT16 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 BOOLEAN rw_t1t_is_read_only_byte (UINT16 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 addr;
UINT8 *p;
if (p_t1t->state != RW_T1T_STATE_IDLE)
{
RW_TRACE_WARNING1 ("RW_T1tFormatNDef - Tag not initialized/ Busy! State: %u", p_t1t->state);
return (NFC_STATUS_FAILED);
}
if ((p_t1t->hr[0] & 0xF0) != T1T_NDEF_SUPPORTED)
{
RW_TRACE_WARNING1 ("RW_T1tFormatNDef - Cannot format tag as NDEF not supported. HR0: %u", p_t1t->hr[0]);
return (NFC_STATUS_REJECTED);
}
if ((p_ret = t1t_tag_init_data (p_t1t->hr[0])) == NULL)
{
RW_TRACE_WARNING2 ("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 */
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_WRITE_E8, 1, p_t1t->ndef_first_block)) == 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);
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_E, addr, p_t1t->ndef_first_block[0])) == 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 tlv_type)
{
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB *p_t1t= &rw_cb.tcb.t1t;
BOOLEAN b_notify;
UINT8 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)
{
RW_TRACE_WARNING1 ("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) )
{
RW_TRACE_ERROR0 ("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;
}
if (p_t1t->b_rseg == TRUE)
{
/* If already got response to RSEG 0 */
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;
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->tlv_detect = tlv_type;
p_t1t->work_offset = 0;
p_t1t->state = RW_T1T_STATE_TLV_DETECT;
p_t1t->substate = RW_T1T_SUBSTATE_NONE;
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
{
/* 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, NULL);
}
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 *p_buffer, UINT16 buf_len)
{
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
BOOLEAN b_notify;
UINT8 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)
{
RW_TRACE_WARNING1 ("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)
{
RW_TRACE_ERROR0 ("RW_T1tReadNDef - Error: NDEF not supported by the tag");
return (NFC_STATUS_REFUSED);
}
if (p_t1t->tag_attribute == RW_T1_TAG_ATTRB_INITIALIZED_NDEF)
{
RW_TRACE_WARNING1 ("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) )
{
RW_TRACE_ERROR0 ("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)
{
RW_TRACE_WARNING2 ("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, NULL);
}
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 msg_len, UINT8 *p_msg)
{
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT16 num_ndef_bytes;
UINT16 offset;
UINT8 block;
UINT8 addr;
UINT8 init_lengthfield_len;
UINT8 new_lengthfield_len;
UINT16 init_ndef_msg_offset;
if (p_t1t->state != RW_T1T_STATE_IDLE)
{
RW_TRACE_WARNING1 ("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)
{
RW_TRACE_ERROR0 ("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) )
{
RW_TRACE_ERROR0 ("RW_T1tWriteNDef - Tag cannot update NDEF");
return (NFC_STATUS_REFUSED);
}
if (msg_len > p_t1t->max_ndef_msg_len)
{
RW_TRACE_ERROR1 ("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) (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) (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) offset) == FALSE)
num_ndef_bytes++;
offset++;
if (offset % T1T_SEGMENT_SIZE == 0)
{
p_t1t->segment = (UINT8) (offset / T1T_SEGMENT_SIZE);
}
}
p_t1t->b_update = FALSE;
p_t1t->b_rseg = FALSE;
if ((p_t1t->hr[0] & 0x0F) != 1)
{
/* Dynamic data structure */
block = (UINT8) ((offset - 1)/T1T_BLOCK_SIZE);
/* Read NDEF final block before updating */
if ((status = rw_t1t_send_dyn_cmd (T1T_CMD_READ8, block, NULL)) == NFC_STATUS_OK)
{
p_t1t->num_ndef_finalblock = block;
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));
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_E, addr, 0)) == 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 (BOOLEAN b_hard_lock)
{
tNFC_STATUS status = NFC_STATUS_FAILED;
tRW_T1T_CB *p_t1t = &rw_cb.tcb.t1t;
UINT8 addr;
UINT8 num_locks;
if (p_t1t->state != RW_T1T_STATE_IDLE)
{
RW_TRACE_WARNING1 ("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));
if ((status = rw_t1t_send_static_cmd (T1T_CMD_WRITE_NE, addr, 0x0F)) == 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;
}
#if (BT_TRACE_VERBOSE == TRUE)
/*******************************************************************************
**
** Function rw_t1t_get_sub_state_name
**
** Description This function returns the sub_state name.
**
** NOTE conditionally compiled to save memory.
**
** Returns pointer to the name
**
*******************************************************************************/
static char *rw_t1t_get_sub_state_name (UINT8 sub_state)
{
switch (sub_state)
{
case RW_T1T_SUBSTATE_NONE:
return ("NONE");
case RW_T1T_SUBSTATE_WAIT_READ_TLV_VALUE:
return ("EXTRACT_TLV_VALUE");
case RW_T1T_SUBSTATE_WAIT_READ_LOCKS:
return ("READING_LOCKS");
case RW_T1T_SUBSTATE_WAIT_READ_NDEF_BLOCK:
return ("READ_NDEF_FINAL_BLOCK");
case RW_T1T_SUBSTATE_WAIT_INVALIDATE_NDEF:
return ("INVALIDATING_NDEF");
case RW_T1T_SUBSTATE_WAIT_NDEF_WRITE:
return ("WRITE_NDEF_TLV_MESSAGE");
case RW_T1T_SUBSTATE_WAIT_NDEF_UPDATED:
return ("WAITING_RSP_FOR_LAST_NDEF_WRITE");
case RW_T1T_SUBSTATE_WAIT_VALIDATE_NDEF:
return ("VALIDATING_NDEF");
case RW_T1T_SUBSTATE_WAIT_SET_CC_RWA_RO:
return ("SET_RWA_RO");
case RW_T1T_SUBSTATE_WAIT_SET_ST_LOCK_BITS:
return ("SET_STATIC_LOCK_BITS");
case RW_T1T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS:
return ("SET_DYNAMIC_LOCK_BITS");
default:
return ("???? UNKNOWN SUBSTATE");
}
}
#endif /* (BT_TRACE_VERBOSE == TRUE) */
#endif /* (defined ((RW_NDEF_INCLUDED) && (RW_NDEF_INCLUDED == TRUE)) */
#endif /* (NFC_INCLUDED == TRUE) */