Intro to Type 2 NFC Tags: Read and Write NFC Tags With React

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the The newline Guide to NFCs with React Native course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to The newline Guide to NFCs with React Native, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to NFCs with React Native

Hello, in this lesson, we will focus on how to read and write Pokemon data into NFC tags. We will first learn to understand the NFC Type 2 tag platform, which includes memory structure and command set. Then, implement our Pokemon read and write logic into our React Native app. Let's get started. As mentioned in the previous lesson, NFC Forum classifies NFC tags into different tag platforms, from Type 2 to Type 5. And each of them has its own specification published as a standard. Since we will focus on Type 2 NFC tag, or T to T in short, in our course, let's take a look at the outline of this specification. Among these chapters, I will walk you through Chapter 2, memory structure and management. And Chapter 5, command set. This is the memory structure diagram for NFC Type 2 tag. The tag itself is divided into two blocks, containing four bytes each. The number associated with a block is called block number, which starts from zero. The blocks can be further grouped into sectors. A sector is defined as 256 continuous blocks. So one sector is 1024 bytes or 1 kilobytes. However, most of the tags have a memory size less than 1 kilobyte. So they are always in sector zero. The first three blocks contain two pieces of information. First is the UID, which is used as a unique hardware identifier. We will use it to calculate our digital signature in the following lessons. The second part is the lock bytes for memory protection purpose. These three blocks are normally programmed by the NC tag manufacturer rather than us. The next block, Capability Container, or CC block for short. It's used to indicate whether the current tag complies with the NFC foreign defined tag platform specification and also contains some meta information for our NFC tags. When a tag complies with Type 2 specification, the first byte of this block should always be E1 in hex. This is a metric number defined by NFC foreign. The second byte encodes the spec version number it complies with. The third byte indicates the memory size of the data blocks divided by 8. For example, an NFC tag with 128 bytes data area should set this byte to 16 decimal or 10 in hex. The last byte indicates the read and write access capability. The high nibbo is for the read access and the low nibbo is for the write access. For both read and write, the value zero indicates the operation granted without any security concern. All value other than zero are either reserved or for proprietary usage, defined by individual tag manufacturers. As you can see, this access control mechanism doesn't provide enough gran ularity for our application. So we choose to use a tag specific password protection method for our application. Starting with block number 4, we have the data blocks, which are used to store application data. All Pokemon data in this course will be written into this area. The final lock and reserved blocks are often used by individual NFC tag manufacturers to control their proprietary features such as password protection, which will be discussed later in this course. By the way, in the NFC domain, you might hear some people use the term page rather than block. That's because some NFC manufacturers like NXP use this term in their proprietary documentation. But they mean the same thing, a 4 byte memory section in our NFC tag. In this course, we might use these two terms block and page interchangeably. Next, let's talk about the commands for the NFC Type 2 tag. First is the read command. This command has only two bytes. The first byte is the command code 30 in hex. And the second byte is the block number to start reading. The tag will respond by sending 16 bytes, starting from the block number you passed. For example, if the block number passed is 4, then blocks 4, 5, 6 and 7 are returned. We can check if the response length is equal to 16 to know whether there are any errors. Next is the write command. This command is used to write one block into our NFC tags. The first byte is the command code A2 in hex. And the second byte is the block number, followed by 4 bytes of data you'd like to write. When the write operation is successful, it will return a single byte response, A in hex or 10 in decimal. Otherwise, we can treat it as an error. In our NFC library, we can use NFC Manager.nscA handler.transcif to send the above commands. As we will see in the coding section, before jumping into write Pokemon function, let's review the full Pokemon tag creation process again. We have seen this code structure several times. The whole unpress handler has been wrapped into a try-cache finally block. In the try-block, we issue a NFCManager .request technology API. The desired NFC technology is NFCA. The finally block issues a cancel technology API to stop the NFC scanning process. The main process is further divided into three functions. Ensure password protection, write Pokemon and write signature. Here, we will focus on write Pokemon function. Let's observe the Pokemon data we'd like to write. As you can see, each Pokemon has its specific properties, such as name, description, serial number, and so on. The name and description properties are strings. For the type property, every Pokemon has its own basic type and an optional special type. So, we use an array to represent this. All other properties, such as HP, attack, defense, are all integer values. Let's move on to implement our write Pokemon function. First, we define three variables. Block data contains the data we'd like to write to the NFC tag. Response bytes are the bytes we received from the NFC tag. And also an all bytes. To concatenate all block data, we have written to the NFC tag. This information will be used when we are computing the signature in the next lesson. As mentioned previously, the data area starts from block 4. byte 0 and byte 1 will be the serial number for our Pokemon. byte 2 and byte 3 will be the basic type and the special type for the Pokemon. Because the serial number for Pokemons might be greater than 256, so we need two bytes to record it. To extract the high byte, we write shift the number by 8 bits. To extract the low byte, we use the bitwise n operator to mask the higher bits to 0. Then we assign the basic type as well as the special type. Since some Pokemon might have no special type, we set a default value to 0. Now the block data is ready. We can call NFCManager.nfc/a-handler.transcif to fire our write command. As mentioned earlier, the first byte of the write command is a2 in hex. And the second byte is the block number to write, followed by the block data to write, which should be 4 bytes long. When the write operation success, we expect to receive a single a in hex as our response. We also accumulate current blocks data into all bytes. Block 5 is used to store the HP, attack and defense value. Since it is very similar to block 4, let's simply copy the previous code and make some modifications. Block 6 is also to store special attack, special defense and speed. The codes are again very similar to the previous two blocks. The code is used to store the block data in the block. Starting from block 7 to block 11. There are 5 blocks or 20 bytes in total, first convert the string into bytes. Since the maximum length of the name is 20 bytes , we append 0 for the remaining part. Next, write a loop to iterate through these 5 blocks and perform the write operation 1 by 1. Also, remember to accumulate the name bytes into all bytes. Let's move on to the read_pokémon function. First, get rid of these fake read operations. We need 3 local variables, Pokemon, attack data and response bytes. As mentioned before, the type 2 read command is always 2 bytes long. The first byte is 30 in hex and the second byte is the starting block number. The tag will respond with 4 blocks of data for a total length of 16 bytes. We can use the response length to check whether the read command is successful or not. We also accumulate the response bytes into tag data. So we can verify the tag data along with the signature later. Recall from the write_pokémon function that we have written 8 blocks to our NFC tags. Since we can only read 4 blocks at a time, we will need to do a second read command to get the full Pokemon data. Once all the bytes are read into our program, we can start parsing these values . For the serial number, we have to combine the first and second bytes to form a single integer value. The other values are all pretty straightforward. The last part of the read_pokémon function is to parse the Pokemon name. The Pokemon name starts from the 12 bytes in our tag data array. Write a loop to iterate the remaining bytes in this array. Now the name has been extracted into a byte array. Let's convert it into a string. Finally, return the Pokemon and tag data to our caller. [BLANK_AUDIO]