Type 2 Tag

The Type 2 Tag implementation is based on the NFC Forum document Type 2 Tag Technical Specification Version 1.0.

A Type 2 Tag can be read and re-written, and the memory of the tag can be write protected. The Type 2 Tag library implements a Type 2 Tag in read-only state. Read only means that the memory of the tag is write protected and cannot be erased (formatted) or re-written by the polling device.

If you use the supplied library, you do not need to know about the actual Memory layout that is used to implement the tag. You can just follow the steps outlined in Programming a tag to configure the tag data.

Memory layout

This information is not required to program the NFC tag; you can just follow the steps outlined in Programming a tag.

The NFCT data is stored in RAM, in the same way as data for other nRF52 peripherals. The data format that is implemented by this library is compliant to the Dynamic Memory Structure defined in the NFC Forum document Type 2 Tag Technical Specification Version 1.0 2017-08-28 [T2T].

The Type 2 Tag memory has a size of 1024 bytes. It is organized in the following way:

Block Number

Byte0

Byte1

Byte2

Byte3

Type

0

Internal 0

Internal 1

Internal 2

Internal 3

Reserved

1

Internal 4

Internal 5

Internal 6

Internal 7

Reserved

2

Internal 8

Internal 9

Lock 0

Lock 1

Reserved

3

CC 0

CC 1

CC 2

CC 3

Reserved

4

Data 0

Data 1

Data 2

Data 3

Data

5

Data 4

Data 5

Data

Data

15

Data 46

Data 47

Data

16

Data 48

Data 49

Data

17

Data

Data

251

Data 991

Data

252

Lock

Lock

Lock

Lock

Lock

253

Lock

Lock

Lock

Lock

Lock

254

Lock

255

Lock

Lock

Lock

Rsvd

Lock

There are three block types:

Static reserved

The static reserved bytes contain 10 internal bytes, 2 lock bytes, and 4 Capability Container bytes.

Internal bytes

The internal bytes depend on the UID length. They are set according to the following table:

Byte number

4-byte UID

7-byte UID

10-byte UID

Internal0

UID0

UID0

UID0

Internal1

UID1

UID1

UID1

Internal2

UID2

UID2

UID2

Internal3

UID3

BCC0 = CT ^ UID0 ^ UID1 ^ UID2

UID3

Internal4

BCC0 = UID0 ^ UID1 ^ UID2 ^ UID3

UID3

UID4

Internal5

0xFF

UID4

UID5

Internal6

0xFF

UID5

UID6

Internal7

0xFF

UID6

UID7

Internal8

0xFF

BCC1 = UID3 ^ UID4 ^ UID5 ^ UID6

UID8

Internal9

NFC Lib version

NFC Lib version

UID9

UID0 contains the manufacturer ID for Nordic Semiconductor and equals 0x5F.

CT stands for Cascade Tag byte and equals 0x88.

The UID bytes are stored in the nRF52 FICR registers.

If you want to use UID bytes other than the ones from the FICR registers, use the nfc_t2t_parameter_set() function with the NFC_T2T_PARAM_NFCID1 parameter. When choosing a custom UID, remember to follow the NFC Forum requirements.

Static Lock bytes

Both Static Lock bytes (Lock 0 and Lock 1) are set to 0xFF, which means that the CC area and the first 48 bytes of the data area of the tag can only be read, not written.

CC bytes

The Capability Container bytes (CC 0 - CC 3) are encoded as described in Section 4.6 of the Type 2 Tag Technical Specification. They cannot be used for storing application data. See the following table for the values of the CC bytes:

CC Byte Number

Meaning

Value

CC0

NFC magic number

0xE1

CC1

Document version number (v1.0)

0x10

CC2

Size of data area (992 bytes / 8)

0x7C

CC3

R/W access (read only)

0x0F

Data

Application data is organized in TLV blocks. The data area can contain one or more TVL blocks, up to a maximum data size of 992 bytes.

A TLV block contains the following fields:

  • T (required): block type

  • L (optional, depending on the T value): block length in number of bytes (field length if present: 1 or 3 bytes)

  • V (optional, depending on the T and L values): block value (present only if the L field is present and greater than 0), multibyte field with length equal to L field value

The following block types are defined:

TLV block name

Value of T field

Description

NULL TLV

0x00

Can be used for padding of memory areas. The NFC Forum Device shall ignore this.

Lock Control TLV

0x01

Defines details of the lock bits.

Memory Control TLV

0x02

Identifies reserved memory areas.

NDEF Message TLV

0x03

Contains an NDEF message.

Proprietary TLV

0xFD

Contains tag proprietary information.

Terminator TLV

0xFE

Contains the last TLV block in the data area.

To write data to the tag, use the Type 2 Tag library functions nfc_t2t_payload_set() or nfc_t2t_payload_raw_set(). nfc_t2t_payload_set() configures a single NDEF TLV block based on a user-provided NDEF message. nfc_t2t_payload_raw_set() does not configure a TLV block, but the provided data must be organized in a TLV structure.

Dynamic Lock and Reserved bytes

15 Dynamic Lock bytes are located after the data area. Each bit defines access conditions of 8 consecutive bytes of the tag data area, except for the first 48 bytes, whose access conditions are defined by Static Lock bytes. The Dynamic Lock bits are set to 1 to indicate that the tag is read-only.

The lock bytes are followed by 1 reserved byte (Rsvd) to get a multiple of 8 bytes.

Command set

The current version of the Type 2 Tag library supports only one Type 2 Tag command type: the READ command. When a READ command is received, the tag responds with the data that is stored for the tag.

READ command format

The READ command has the following format:

Byte number

Description

Value

1

Code

0x30

2

Number of the 4-byte data block to read from the tag data

0x00 - 0xFF

The library can send either a READ response (success) or a NACK response (failure):

  • A READ response contains the content of 4 data blocks starting with the requested data block (16 bytes).

  • A NACK response contains the error code 0x0, 0x1, 0x4, or 0x5 (4 bits).

Programming a tag

To program a tag, complete the following steps:

  1. Implement a callback function that handles events from the Type 2 Tag library and register it:

    int err;
    /* Callback for NFC events */
    static void nfc_callback(void * context,
                             enum nfc_t4t_event event,
                             const uint8_t * data,
                             size_t data_length,
                             uint32_t flags)
    {
    ...
    }
    /* Set up NFC and register application callback for NFC events. */
    err = nfc_t2t_setup(nfc_callback, NULL);
    if (err) {
              printk("Cannot setup NFC T2T library!\n");
              return err;
    }
    
  2. Configure the data for the tag. You can provide the data as NDEF message (recommended, see NFC Data Exchange Format (NDEF)) or as a raw TLV structure (advanced usage, see Type 2 Tag Memory layout).

    • Set an NDEF message:

      uint8_t ndef_msg_buf[] = ...; // Buffer with the user NDEF message
      uint32_t len           = sizeof(ndef_msg_buf);
      /* Set created message as the NFC payload. */
      err = nfc_t2t_payload_set(ndef_msg_buf, len);
      if (err) {
              printk("Cannot set payload!\n");
              return err;
      }
      
    • Alternatively, set a TLV structure:

      uint8_t tlv_buf[] = ...; // Buffer with the user TLV structure
      uint32_t len           = sizeof(tlv_buf);
      /* Set created TLV structure as the NFC payload. */
      err = nfc_t2t_payload_raw_set(tlv_buf, len);
      if (err) {
              printk("Cannot set raw payload!\n");
              return err;
      }
      
  3. Activate the NFC tag so that it starts sensing and reacts when an NFC field is detected:

    /* Start sensing NFC field. */
    err = nfc_t2t_emulation_start();
    if (err) {
         printk("Cannot start emulation!\n");
         return err;
    }
    

API documentation

group nfc_t2t_lib

The T2T emulation library interface.

Defines

NFC_T2T_SIZEOF_INTERNAL_BYTES

T2T internal byte size.

NFC_T2T_MAX_PAYLOAD_SIZE

Maximum NDEF message size. No NDEF-TLV and no implicit lock bytes at the end.

NFC_T2T_MAX_PAYLOAD_SIZE_RAW

Typedefs

typedef void (*nfc_t2t_callback_t)(void *context, enum nfc_t2t_event event, const uint8_t *data, size_t data_length)

Callback to pass events from NFC T2T Library to application.

Parameters
  • context: Application context for callback execution.

  • event: The event that occurred.

  • data: Data to send to the application (event specific).

  • data_length: Length of the data.

Enums

enum nfc_t2t_event

Events passed to the callback function.

Values:

NFC_T2T_EVENT_NONE

Not used.

NFC_T2T_EVENT_FIELD_ON

NFC tag has detected external NFC field and was selected by an NFC polling device.

NFC_T2T_EVENT_FIELD_OFF

External NFC field has been removed.

NFC_T2T_EVENT_DATA_READ

NFC polling device has read all tag data. Repeated reading in the same session i.e. before NFC_T2T_EVENT_FIELD_OFF event, will not trigger another NFC_T2T_EVENT_DATA_READ event.

NFC_T2T_EVENT_STOPPED

Reference to the application NFC callback has been released using nfc_t2t_done.

enum nfc_t2t_param_id

Values:

NFC_T2T_PARAM_TESTING

Used for unit tests.

NFC_T2T_PARAM_NFCID1

NFCID1 value, data can be 4, 7, or 10 bytes long (single, double, or triple size). To use default NFCID1 of specific length pass one byte containing requested length. Default 7-byte NFCID1 will be used if this parameter was not set. This parameter can be set before nfc_t2t_setup() to set initial NFCID1 and it can be changed later.

Functions

int nfc_t2t_setup(nfc_t2t_callback_t callback, void *context)

Function for registering the application callback for event signaling.

The callback will be called by NFC T2T Library to notify the application of relevant events. It will be called from the HAL_NFC callback context.

Parameters
  • callback: Function pointer to the callback.

  • context: Pointer to a memory area used by the callback for execution (optional).

Return Value
  • 0: If the application callback was registered successfully. If one of the arguments was invalid, an error code is returned.

int nfc_t2t_parameter_set(enum nfc_t2t_param_id id, void *data, size_t data_length)

Function for setting an NFC parameter.

This function allows to set an NFC configuration parameter.

Parameters
  • id: ID of the parameter to set.

  • data: Pointer to a buffer containing the data to set.

  • data_length: Size of the buffer containing the data to set.

Return Value
  • Zero: on success or (negative) error code otherwise.

int nfc_t2t_parameter_get(enum nfc_t2t_param_id id, void *data, size_t *max_data_length)

Function for querying an NFC parameter value.

The queried value will be placed into the passed data buffer. If the buffer is too small, max_data_length will contain the required buffer size. If the buffer is big enough, max_data_length will contain the actual size of the data.

Parameters
  • id: ID of the parameter to query.

  • data: Pointer to a buffer receiving the queried data.

  • max_data_length: Size of the buffer, receives actual size of queried data.

Return Value
  • Zero: on success or (negative) error code otherwise.

int nfc_t2t_payload_set(const uint8_t *payload, size_t payload_length)

Function for registering the payload to send on reception of a READ request.

The payload is considered to only contain the NDEF message to deliver to a reader. The required NDEF TLV will be created implicitly by NFC T2T Library.

The pointer to the payload must stay valid for the duration of the library execution, or until it is explicitly released.

If the pointer is not NULL, but the length is zero, the paypload is considered to be an empty NDEF message.

If a new payload is registered, the previously registered one is considered released.

Passing a NULL pointer releases the current payload without registering a new one.

If an invalid size is given (too big), the function returns with an error and the currently registered payload is left unchanged.

Note

Provided pointer must point to RAM region.

Parameters
  • payload: Pointer to the memory area in RAM containing the payload to send.

  • payload_length: Size of the payload in bytes.

Return Value
  • Zero: on success or (negative) error code otherwise.

int nfc_t2t_payload_raw_set(const uint8_t *payload, size_t payload_length)

Function for registering the raw payload to send on reception of a READ request.

The payload will be delivered directly as-is to the reader, without implicitly adding an NDEF TLV container. This can be used if the application wants to define the TLVs itself, for example, to provide a different memory layout.

The pointer to the payload must stay valid for the duration of the library execution, or until it is explicitly released.

If a new payload is registered, the previously registered one is considered released.

Passing a NULL pointer releases the current payload, without registering a new one.

If an invalid size is given (too big), the function returns with an error and the currently registered payload is left unchanged.

Note

Provided pointer must points to RAM region.

Parameters
  • payload: Pointer to the memory area in RAM containing the payload to send.

  • payload_length: Size of the payload in bytes.

Return Value
  • 0: If the operation was successful. If one of the arguments was invalid, an error code is returned.

int nfc_t2t_internal_set(const uint8_t *data, size_t data_length)

Function for registering the sequence of internal bytes.

This refers to the first 10 bytes of the tag memory. The library will set a sensible default for these bytes. The application can use this function to override the default.

Passing a NULL pointer reverts back to the default sequence. The data will be copied by NFC T2T Library, so the memory does not have to remain valid after the function returns.

Note

When modifying the internal bytes, remember that they must be consistent with the NFC hardware register settings

Parameters
  • data: Pointer to the memory area containing the data.

  • data_length: Size of the data in bytes.

Return Value
  • 0: If the operation was successful. If the data was not NULL and the data length was not 10, an error code is returned.

int nfc_t2t_emulation_start(void)

Function for activating the NFC frontend.

You must call this function so that events are posted to the application callback.

Return Value
  • 0: If the NFC frontend was activated successfully. If the lower layer could not be started, an error code is returned.

int nfc_t2t_emulation_stop(void)

Function for deactivating the NFC frontend.

After calling this function, no more events will be posted to the application callback.

Return Value
  • 0: If the NFC frontend was deactivated successfully. If the lower layer could not be stopped, an error code is returned.

int nfc_t2t_done(void)

Function for releasing the reference to the application callback.

After calling this function, the passed callback pointer is no longer considered valid.

Return Value
  • 0: This function always succeeds.