Example 8 - NDEF URI
An example showing how to create an NDEF URI record using the SparkFun ST25DV64KC Arduino Library.
- Writing the tag's Capability Container (CC)
- Writing an NDEF URI record
- Reading an NDEF URI record
NFC Forum Type 5 Tag and NDEF
From the ST website:
"Near Field Communication (NFC) Type 5 tags (T5T) and labels operate in the high-frequency (HF) 13.56 MHz range and comply with the NFC-V Technology specification from the NFC Forum. The data stored in these Type 5 tags and labels is transferred to NFC smartphones or professional NFC/RFID HF readers that support the NFC Forum standardized NFC Data Exchange Format (NDEF)."
"ST25 Type 5 Tag chips are certified by the NFC Forum and comply with the industrial ISO/IEC 15693 RFID specifications, providing interoperability across NFC implementations in NFC smartphones and NFC/RFID HF readers."
Creating a Capability Container
Up until now, the library examples have been writing 'unformatted data' to the tag's memory. To allow the data to be read and understood by the NFC App on your smart phone, we need to write the data in NFC Data Exchange Format (NDEF).
To begin, we need to write a Capability Container at the very start of the tag's memory (Address 0x0000). This is an 8-byte (or 4-byte) number which describes the tag's version, access condition and encoded memory length.
For the 8-kByte ST25DV64KC, the CC is set to:
- E2 40 00 01 00 00 04 00h to work properly with smartphone
- E2 40 00 01 00 00 03 FFh for NFC Forum certification
This library defaults to using the NFC Forum value:
/* The Capacity Container File is written to the first eight bytes of user memory: 0xE2 0x40 0x00 0x01 0x00 0x00 0x03 0xFF Byte 0: Magic Number The ST25DV64KC has 8kBytes of user memory so we need to select 0xE2 to select two-byte addressing Byte 1: Version and Access Condition b7 b6 = 0b01 Major Version b5 b4 = 0b00 Minor Version b3 b2 = 0x00 Read Access: Always b1 b0 = 0x00 Write Access: Always Byte 2: 0x00 Byte 3: Additional Feature Information b7 b6 b5 = 0b000 RFU (Reserved Future Use) b4 = 0b0 Special Frame b3 = 0b0 Lock Block b2 b1 = 0b00 RFU b0 = 0b1 MBREAD: Read Multiple Block is supported Byte 4: 0x00 RFU (Reserved Future Use) Byte 5: 0x00 RFU (Reserved Future Use) Byte 6 + Byte 7: MLEN Encoded Memory Length MLEN = T5T_Area / 8 MLEN encoding for a ST25DV64K (8192 bytes memory size) and 8 bytes capability container (CC): If the entire user memory full, user memory is used to store NDEF, T5T_Area=8192-8 MLEN = (8192 – 8) / 8 = 1023 (0x03FF) */
Example 8 begins by clearing the tag's memory, just in case it contains any 'old' information. This is done with
writeEEPROM - see Example 2 for more details.
The default Capability Container is written by calling
// Write the Type 5 CC File - eight bytes - starting at address zero Serial.println(F("Writing CC_File")); tag.writeCCFile8Byte();
If you want to use a non-standard CC, you can define your own e.g. by calling:
If you are using a small tag, like the ST25DV04K, you could call:
// Write the Type 5 CC File - four bytes - starting at address zero Serial.println(F("Writing CC_File")); tag.writeCCFile4Byte();
To write a non-standard CC to the ST25DV04K, you could call:
Creating an NDEF URI Record
Now that the T5T CC has been written, we can start adding NDEF records.
One of the most useful records is the Well-Known Uniform Resource Identifier (URI) which covers web address URLs (Uniform Reference Locator).
If we want to write a single URI into the tag, we can simply call:
This writes the URI
https://www.sparkfun.com in shorthand format using the HTTPS WWW ID Code to save memory.
We could have called:
but the first way is more memory-efficient.
SFE_ST25DV_NDEF_URI_ID_CODE_NONE is the default ID Code, so we could have simply called:
writeNDEFURI does all of the heavy lifting for us. It formats the NDEF data correctly, adding:
- The NDEF Message Type Field
- The Length Field - correctly formatted as 1-Byte or 3-Bytes as appropriate
- The Header, Length and Payload data for the URI Value itself
- The Terminator
/* To create a single NDEF URI short record: 0x03 0x11 0xD1 0x01 0x0D 0x55 0x02 sparkfun.com 0xFE Byte 0: Type5 Tag TLV-Format: T (Type field) 0x03 = NDEF Message TLV Byte 1: Type5 Tag TLV-Format: L (Length field) (1-Byte Format) 0x11 = 17 Bytes Bytes 2-18: Type5 Tag TLV-Format: V (Value field) Byte 2: Record Header = 0xD1 b7 = 0b1 MB (Message Begin) b6 = 0b1 ME (Message End) b5 = 0b0 CF (Chunk Flag) b4 = 0b1 SR (Short Record) b3 = 0b0 IL (ID Length) b2 b1 b0 = 0b001 TNF (Type Name Format): NFC Forum Well-Known Type Byte 3: Type Length 0x01 = 1 Byte Byte 4: Payload Length 0x0D = 13 bytes Byte 5: Record Type 0x55 = "U" URI Record Byte 6: URI Prefix Code 0x02 = https://www. Bytes 7-18: URI (12 bytes) sparkfun.com Byte 19: Type5 Tag TLV-Format: T (Type field) 0xFE = Terminator TLV */
To be able to use the extra NDEF methods, we need to use the
SFE_ST25DV64KC_NDEF class, instead of
SFE_ST25DV64KC_NDEF inherits all of the
SFE_ST25DV64KC methods, so we can do everything with a single
Writing multiple NDEF URI Records
If we want to write multiple records, we need to keep track of which address each URI is written to, so the URIs can be concatenated correctly.
We also need to tell
writeNDEFURI which is the first record (Message Begin = 1) and which is the last (Message End = 1).
The code becomes:
uint16_t memoryLocation = tag.getCCFileLen(); // Start writing at the memory location immediately after the CC File tag.writeNDEFURI("sparkfun.com", SFE_ST25DV_NDEF_URI_ID_CODE_HTTPS_WWW, &memoryLocation, true, false); // Message Begin = 1, Message End = 0 tag.writeNDEFURI("github.com/sparkfun", SFE_ST25DV_NDEF_URI_ID_CODE_HTTPS, &memoryLocation, false, false); // Message Begin = 0, Message End = 0 tag.writeNDEFURI("twitter.com/sparkfun", SFE_ST25DV_NDEF_URI_ID_CODE_HTTPS, &memoryLocation, false, true); // Message Begin = 0, Message End = 1
writeNDEFURI is called, it starts writing at
memoryLocation. When the write is complete,
memoryLocation is updated
so that the next record is written starting at the next memory location.
The three URIs written by the example are:
It is possible to write multiple URI, WiFi and Text records into a single tag.
Reading an NDEF URI Record
There may be times when we want to read back a URI from the tag. E.g. if you have updated the tag using your smart phone and want to use the new URI in your Arduino code.
The code to do this is:
// Read back the third URI char theURI; Serial.println(F("Reading the third NDEF URI record:")); if (tag.readNDEFURI(theURI, 30, 3)) Serial.println(theURI); else Serial.println(F("Read failed!"));
theURI is a 30-byte char array which will hold the URI. It needs to be long enough to contain the whole URI, including the
readNDEFURI(theURI, 30, 3) performs the read. The URI is written into
readNDEFURI how many chars
theURI can hold.
If the URI is too long for
readNDEFURI will return false. Finally, the
readNDEFURI to return the third URI from tag memory.
To read the first URI, we could have called
readNDEFURI(theURI, 30) as the URI defaults to 1.
If we call
readNDEFURI(theURI, 30, 4), the result is false as the tag only contains three URIs. This is a trick we can use to determine how many URIs the tag contains.
You can use "NFC Tap" to check the NDEF data.
Just for fun, you can "swipe left" on a URI record in NFC Tap, change the URI, and then write it back to the tag.
If you comment out the first part of the example, leaving only the
readNDEFURI, you will be able to read the new URI.