36  NFC Reader Simulation Lab

In 60 Seconds

This interactive ESP32-based simulation demonstrates NFC reader behavior without requiring physical hardware. You will parse NDEF messages with TLV containers, identify NFC Forum Tag Types 1-5, understand anti-collision protocols for multi-tag environments, and analyze security concepts including relay attacks and authentication mechanisms.

Sammy the Sensor was curious: “I want to learn about NFC readers, but I do not have the special hardware!” Max the Microcontroller smiled and said, “No problem! We can use a simulation – it is like a video game version of an NFC reader. It shows you exactly how the reader talks to tags, reads their data, and checks if they are real or fake.” Bella the Battery added, “The simulation even shows what happens when two tags are near the reader at the same time. The reader has a clever trick called anti-collision where it asks each tag to identify itself one at a time, like a teacher calling roll.” Lila the LED chimed in, “And the best part? You can see what a hacker attack looks like and how the reader catches it. It is like being a security detective!”

36.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Deconstruct NDEF Messages: Parse TLV containers, interpret record header flags, and extract payload structures from raw byte sequences
  • Classify NFC Tag Types: Differentiate NFC Forum Tag Types 1-5 by memory capacity, security features, and appropriate deployment scenarios
  • Trace Anti-Collision Protocols: Diagram the REQA/ATQA/SELECT sequence that resolves multiple simultaneous tags in the RF field
  • Critique NFC Security Mechanisms: Evaluate authentication levels, encryption schemes, and relay attack vectors across different tag types
  • Construct NFC Simulations: Build software models that replicate NFC reader detection, NDEF parsing, and security validation behaviors

What is this chapter? An interactive ESP32-based simulation that demonstrates NFC concepts without requiring physical hardware.

Why simulation? Real NFC communication requires specialized RF hardware operating at 13.56 MHz. This simulation models the logical behavior of NFC systems, helping you understand protocols and data structures.

Prerequisites:

What you’ll learn:

  • NDEF message structure and parsing
  • URI prefix compression
  • Tag type characteristics
  • Security and anti-collision protocols

36.2 Prerequisites

Before diving into this lab, you should be familiar with:

  • NFC Fundamentals: Understanding NDEF message structure and tag types
  • NFC Tag Programming: Basic NFC programming concepts
  • C++ Basics: Understanding of Arduino/ESP32 programming for the simulation code

Prerequisites:

Next Steps:

Practice:

36.3 NFC Reader Lab: Interactive Simulation

Time: ~30 min | Level: Advanced | Unit: P08.C22.U02

36.3.1 What You Will Learn

This interactive lab simulates an ESP32-based NFC reader system. Since NFC hardware (like the PN532 module) cannot be physically simulated in Wokwi, we demonstrate NFC concepts through software simulation that models:

  • NFC Tag Detection: How readers detect and identify tags in range
  • NDEF Message Parsing: Decoding the NFC Data Exchange Format structure
  • Tag Type Identification: Differentiating between NFC Forum Tag Types 1-5
  • URL and Text Records: Processing common NDEF record types
  • Security Concepts: Understanding authentication, encryption, and relay attack prevention
Why Simulation?

Real NFC communication requires specialized RF hardware operating at 13.56 MHz. This simulation models the logical behavior of NFC systems, helping you understand protocols and data structures before working with physical hardware.

36.3.2 Interactive Wokwi Simulation

Setup Instructions
  1. Copy the complete code below into the Wokwi editor
  2. Click the green “Play” button to start the simulation
  3. Open the Serial Monitor (115200 baud) to view output
  4. The simulation will automatically cycle through NFC scenarios

36.3.3 Complete NFC Simulation Code

Copy this code into the Wokwi ESP32 project:

/*
 * NFC Reader Simulation Lab
 *
 * This educational simulation demonstrates NFC concepts including:
 * - NDEF message structure and parsing
 * - Tag type identification (Types 1-5)
 * - URL and Text record handling
 * - Security concepts (authentication, encryption indicators)
 * - Anti-collision and tag detection simulation
 *
 * Author: IoT Class Educational Materials
 * License: MIT
 */

#include <Arduino.h>

// =============================================================================
// SECTION 1: NFC CONSTANTS AND DEFINITIONS
// =============================================================================

// NFC Forum Tag Types
enum NFCTagType {
    TAG_TYPE_1 = 1,  // Topaz, 96-2000 bytes, simple
    TAG_TYPE_2 = 2,  // NTAG, MIFARE Ultralight, 48-888 bytes
    TAG_TYPE_3 = 3,  // FeliCa, 1-9 KB, Japan transit
    TAG_TYPE_4 = 4,  // DESFire, JCOP, up to 32KB, ISO 14443-4
    TAG_TYPE_5 = 5   // ICODE SLIX, ISO 15693
};

// NDEF Record Type Name Format (TNF)
enum NDEFTypeName {
    TNF_EMPTY = 0x00,
    TNF_WELL_KNOWN = 0x01,
    TNF_MIME_MEDIA = 0x02,
    TNF_ABSOLUTE_URI = 0x03,
    TNF_EXTERNAL = 0x04,
    TNF_UNKNOWN = 0x05,
    TNF_UNCHANGED = 0x06,
    TNF_RESERVED = 0x07
};

// Well-Known Record Types
#define RTD_TEXT    'T'
#define RTD_URI     'U'
#define RTD_SMART_POSTER 'S'

// URI Identifier Codes (prefix compression)
const char* URI_PREFIXES[] = {
    "",                           // 0x00 - No prefix
    "http://www.",               // 0x01
    "https://www.",              // 0x02
    "http://",                   // 0x03
    "https://",                  // 0x04
    "tel:",                      // 0x05
    "mailto:",                   // 0x06
    "ftp://anonymous:anonymous@", // 0x07
    "ftp://ftp.",                // 0x08
    "ftps://",                   // 0x09
    "sftp://",                   // 0x0A
    "smb://",                    // 0x0B
    "nfs://",                    // 0x0C
    "ftp://",                    // 0x0D
    "dav://",                    // 0x0E
    "news:",                     // 0x0F
    "telnet://",                 // 0x10
    "imap:",                     // 0x11
    "rtsp://",                   // 0x12
    "urn:",                      // 0x13
    "pop:",                      // 0x14
    "sip:",                      // 0x15
    "sips:",                     // 0x16
    "tftp:",                     // 0x17
    "btspp://",                  // 0x18
    "btl2cap://",                // 0x19
    "btgoep://",                 // 0x1A
    "tcpobex://",                // 0x1B
    "irdaobex://",               // 0x1C
    "file://",                   // 0x1D
    "urn:epc:id:",               // 0x1E
    "urn:epc:tag:",              // 0x1F
    "urn:epc:pat:",              // 0x20
    "urn:epc:raw:",              // 0x21
    "urn:epc:",                  // 0x22
    "urn:nfc:"                   // 0x23
};
#define URI_PREFIX_COUNT 36

// =============================================================================
// SECTION 2: DATA STRUCTURES
// =============================================================================

// NDEF Record Structure
struct NDEFRecord {
    uint8_t tnf;           // Type Name Format (3 bits)
    bool mb;               // Message Begin flag
    bool me;               // Message End flag
    bool cf;               // Chunk Flag
    bool sr;               // Short Record (payload < 256 bytes)
    bool il;               // ID Length present
    uint8_t typeLength;
    uint32_t payloadLength;
    uint8_t idLength;
    char type[64];
    uint8_t payload[256];
    char id[64];
};

// NFC Tag Structure
struct NFCTag {
    uint8_t uid[7];        // Unique Identifier (4 or 7 bytes)
    uint8_t uidLength;
    NFCTagType tagType;
    uint16_t memorySize;   // Total memory in bytes
    uint16_t usedMemory;
    bool isLocked;
    bool hasPassword;
    uint8_t ndefData[512];
    uint16_t ndefLength;
    char tagName[32];

    // Security features
    bool hasAuthentication;
    bool isEncrypted;
    uint8_t securityLevel; // 0=none, 1=password, 2=AES, 3=3DES
};

// NFC Reader State
enum ReaderState {
    STATE_IDLE,
    STATE_POLLING,
    STATE_DETECTED,
    STATE_AUTHENTICATING,
    STATE_READING,
    STATE_WRITING,
    STATE_ERROR
};

// =============================================================================
// SECTION 3: SIMULATED NFC TAG DATABASE
// =============================================================================

// Pre-configured simulated tags
NFCTag simulatedTags[5];
int numSimulatedTags = 5;

void initializeSimulatedTags() {
    // Tag 1: Simple URL Tag (NTAG213)
    simulatedTags[0] = {
        .uid = {0x04, 0xA3, 0xB2, 0xC1, 0xD4, 0x5E, 0x80},
        .uidLength = 7,
        .tagType = TAG_TYPE_2,
        .memorySize = 144,
        .usedMemory = 45,
        .isLocked = false,
        .hasPassword = false,
        .ndefData = {0},
        .ndefLength = 0,
        .tagName = "URL Tag (NTAG213)",
        .hasAuthentication = false,
        .isEncrypted = false,
        .securityLevel = 0
    };

    // Create NDEF message for URL tag
    // NDEF TLV: Type=03, Length, NDEF Message
    uint8_t urlNdef[] = {
        0x03, 0x14,                    // NDEF TLV, length 20
        0xD1,                          // MB=1, ME=1, CF=0, SR=1, IL=0, TNF=01
        0x01,                          // Type Length = 1
        0x10,                          // Payload Length = 16
        0x55,                          // Type = 'U' (URI)
        0x04,                          // URI prefix: https://
        'i', 'o', 't', 'c', 'l', 'a', 's', 's',  // Payload
        '.', 'e', 'x', 'a', 'm', 'p', 'l', 'e',
        0xFE                           // Terminator TLV
    };
    memcpy(simulatedTags[0].ndefData, urlNdef, sizeof(urlNdef));
    simulatedTags[0].ndefLength = sizeof(urlNdef);

    // Tag 2: Text Record Tag (NTAG216)
    simulatedTags[1] = {
        .uid = {0x04, 0xE7, 0xF8, 0x92, 0x1A, 0x3C, 0x70},
        .uidLength = 7,
        .tagType = TAG_TYPE_2,
        .memorySize = 888,
        .usedMemory = 128,
        .isLocked = false,
        .hasPassword = true,
        .ndefData = {0},
        .ndefLength = 0,
        .tagName = "Text Tag (NTAG216)",
        .hasAuthentication = false,
        .isEncrypted = false,
        .securityLevel = 1
    };

    // NDEF message with text record
    uint8_t textNdef[] = {
        0x03, 0x21,                    // NDEF TLV, length 33
        0xD1,                          // MB=1, ME=1, CF=0, SR=1, IL=0, TNF=01
        0x01,                          // Type Length = 1
        0x1D,                          // Payload Length = 29
        0x54,                          // Type = 'T' (Text)
        0x02,                          // Status byte: UTF-8, lang len=2
        'e', 'n',                      // Language code: English
        'W', 'e', 'l', 'c', 'o', 'm', 'e', ' ',
        't', 'o', ' ', 'I', 'o', 'T', ' ', 'C',
        'l', 'a', 's', 's', ' ', 'L', 'a', 'b', '!',
        0xFE                           // Terminator TLV
    };
    memcpy(simulatedTags[1].ndefData, textNdef, sizeof(textNdef));
    simulatedTags[1].ndefLength = sizeof(textNdef);

    // Tag 3: Smart Poster (NTAG215)
    simulatedTags[2] = {
        .uid = {0x04, 0xB5, 0xC6, 0xD7, 0xE8, 0xF9, 0x0A},
        .uidLength = 7,
        .tagType = TAG_TYPE_2,
        .memorySize = 504,
        .usedMemory = 256,
        .isLocked = true,
        .hasPassword = false,
        .ndefData = {0},
        .ndefLength = 0,
        .tagName = "Smart Poster (NTAG215)",
        .hasAuthentication = false,
        .isEncrypted = false,
        .securityLevel = 0
    };

    // Smart poster with URL and title
    uint8_t posterNdef[] = {
        0x03, 0x35,                    // NDEF TLV, length 53
        // Record 1: Smart Poster (container)
        0x91,                          // MB=1, ME=0, CF=0, SR=1, IL=0, TNF=01
        0x02,                          // Type Length = 2
        0x2F,                          // Payload Length = 47
        'S', 'p',                      // Type = "Sp" (Smart Poster)
        // Nested Record 1: URI
        0x91,                          // MB=1, ME=0
        0x01, 0x10, 0x55, 0x04,       // URI record
        'g', 'i', 't', 'h', 'u', 'b', '.', 'c', 'o', 'm',
        '/', 'i', 'o', 't',
        // Nested Record 2: Title
        0x51,                          // MB=0, ME=1
        0x01, 0x0F, 0x54, 0x02,       // Text record
        'e', 'n',
        'I', 'o', 'T', ' ', 'P', 'r', 'o', 'j', 'e', 'c', 't',
        0xFE                           // Terminator
    };
    memcpy(simulatedTags[2].ndefData, posterNdef, sizeof(posterNdef));
    simulatedTags[2].ndefLength = sizeof(posterNdef);

    // Tag 4: Secure Access Card (MIFARE DESFire)
    simulatedTags[3] = {
        .uid = {0x04, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC},
        .uidLength = 7,
        .tagType = TAG_TYPE_4,
        .memorySize = 8192,
        .usedMemory = 512,
        .isLocked = false,
        .hasPassword = true,
        .ndefData = {0},
        .ndefLength = 0,
        .tagName = "Access Card (DESFire)",
        .hasAuthentication = true,
        .isEncrypted = true,
        .securityLevel = 3
    };

    // Secure tag with encrypted payload indicator
    uint8_t secureNdef[] = {
        0x03, 0x28,                    // NDEF TLV
        0xD2,                          // TNF=02 (MIME type)
        0x18,                          // Type length = 24
        0x0C,                          // Payload length = 12
        'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o', 'n', '/',
        'v', 'n', 'd', '.', 'a', 'c', 'c', 'e', 's', 's', '-', 'c',
        0xAE, 0x7B, 0xC2, 0x8F, 0x51, 0xD4, 0x33, 0x19,  // Encrypted data
        0x8A, 0xE2, 0x1C, 0x44,
        0xFE
    };
    memcpy(simulatedTags[3].ndefData, secureNdef, sizeof(secureNdef));
    simulatedTags[3].ndefLength = sizeof(secureNdef);

    // Tag 5: vCard Contact (NTAG424)
    simulatedTags[4] = {
        .uid = {0x04, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA},
        .uidLength = 7,
        .tagType = TAG_TYPE_4,
        .memorySize = 416,
        .usedMemory = 280,
        .isLocked = false,
        .hasPassword = true,
        .ndefData = {0},
        .ndefLength = 0,
        .tagName = "Contact Card (NTAG424)",
        .hasAuthentication = true,
        .isEncrypted = false,
        .securityLevel = 2
    };

    // vCard MIME type record
    uint8_t vcardNdef[] = {
        0x03, 0x42,                    // NDEF TLV
        0xD2,                          // TNF=02 (MIME type)
        0x0A,                          // Type length = 10
        0x34,                          // Payload length = 52
        't', 'e', 'x', 't', '/', 'v', 'c', 'a', 'r', 'd',
        'B', 'E', 'G', 'I', 'N', ':', 'V', 'C', 'A', 'R', 'D', '\n',
        'F', 'N', ':', 'I', 'o', 'T', ' ', 'L', 'a', 'b', '\n',
        'T', 'E', 'L', ':', '+', '1', '5', '5', '5', '1', '2', '3', '4', '\n',
        'E', 'N', 'D', ':', 'V', 'C', 'A', 'R', 'D',
        0xFE
    };
    memcpy(simulatedTags[4].ndefData, vcardNdef, sizeof(vcardNdef));
    simulatedTags[4].ndefLength = sizeof(vcardNdef);
}

// =============================================================================
// SECTION 4: NFC READER SIMULATION CLASS
// =============================================================================

class NFCReaderSimulator {
private:
    ReaderState state;
    int currentTagIndex;
    unsigned long lastPollTime;
    unsigned long pollInterval;
    bool verboseMode;

public:
    NFCReaderSimulator() {
        state = STATE_IDLE;
        currentTagIndex = -1;
        lastPollTime = 0;
        pollInterval = 3000;  // 3 seconds between tag reads
        verboseMode = true;
    }

    void begin() {
        Serial.println("\n" + String('=', 60));
        Serial.println("       NFC READER SIMULATION - IoT Class Lab");
        Serial.println(String('=', 60));
        Serial.println("\nInitializing simulated PN532 NFC reader...");
        delay(500);

        // Simulate hardware initialization
        printProgress("Checking I2C connection", 300);
        printProgress("Loading firmware version 1.6", 200);
        printProgress("Configuring RF field", 300);
        printProgress("Setting ISO14443A mode", 200);

        Serial.println("\n[OK] NFC Reader initialized successfully!");
        Serial.println("     Hardware: Simulated PN532 via I2C");
        Serial.println("     Firmware: v1.6 (simulation)");
        Serial.println("     Frequency: 13.56 MHz");
        Serial.println("     Protocols: ISO14443A/B, ISO15693, FeliCa");
        Serial.println("\n[INFO] Starting tag polling...\n");

        state = STATE_POLLING;
    }

    void printProgress(const char* message, int delayMs) {
        Serial.print("  ");
        Serial.print(message);
        Serial.print("...");
        delay(delayMs);
        Serial.println(" OK");
    }

    void poll() {
        if (millis() - lastPollTime < pollInterval) {
            return;
        }
        lastPollTime = millis();

        // Cycle through simulated tags
        currentTagIndex = (currentTagIndex + 1) % numSimulatedTags;

        Serial.println("\n" + String('-', 60));
        Serial.println("POLLING: Searching for NFC tags...");
        delay(200);

        // Simulate RF field activation and detection
        simulateTagDetection(&simulatedTags[currentTagIndex]);
    }

    void simulateTagDetection(NFCTag* tag) {
        state = STATE_DETECTED;

        Serial.println("\n[DETECTED] NFC Tag Found!");
        Serial.println(String('-', 40));

        // Print UID
        Serial.print("UID: ");
        for (int i = 0; i < tag->uidLength; i++) {
            if (i > 0) Serial.print(":");
            if (tag->uid[i] < 0x10) Serial.print("0");
            Serial.print(tag->uid[i], HEX);
        }
        Serial.println();

        // Print tag info
        Serial.print("Tag Name: ");
        Serial.println(tag->tagName);
        Serial.print("Tag Type: NFC Forum Type ");
        Serial.println(tag->tagType);
        Serial.print("Memory: ");
        Serial.print(tag->usedMemory);
        Serial.print("/");
        Serial.print(tag->memorySize);
        Serial.println(" bytes");

        // Security info
        printSecurityInfo(tag);

        // Handle authentication if needed
        if (tag->hasAuthentication) {
            simulateAuthentication(tag);
        }

        // Read NDEF data
        state = STATE_READING;
        readNDEFMessage(tag);

        state = STATE_POLLING;
    }

    void printSecurityInfo(NFCTag* tag) {
        Serial.println("\n[SECURITY]");
        Serial.print("  Locked: ");
        Serial.println(tag->isLocked ? "Yes (Read-Only)" : "No (Read/Write)");
        Serial.print("  Password Protected: ");
        Serial.println(tag->hasPassword ? "Yes" : "No");
        Serial.print("  Authentication: ");
        Serial.println(tag->hasAuthentication ? "Required" : "Not Required");
        Serial.print("  Encryption: ");
        Serial.println(tag->isEncrypted ? "Yes" : "No");
        Serial.print("  Security Level: ");
        switch(tag->securityLevel) {
            case 0: Serial.println("0 - None"); break;
            case 1: Serial.println("1 - Password (32-bit)"); break;
            case 2: Serial.println("2 - AES-128"); break;
            case 3: Serial.println("3 - 3DES/AES-256"); break;
        }
    }

    void simulateAuthentication(NFCTag* tag) {
        Serial.println("\n[AUTHENTICATION]");
        state = STATE_AUTHENTICATING;

        if (tag->securityLevel >= 2) {
            Serial.println("  Initiating mutual authentication...");
            delay(100);
            Serial.print("  Generating random challenge: ");
            for (int i = 0; i < 8; i++) {
                Serial.print(random(256), HEX);
            }
            Serial.println();

            delay(150);
            Serial.println("  Verifying cryptographic response...");
            delay(100);
            Serial.println("  [OK] Authentication successful!");
        } else if (tag->hasPassword) {
            Serial.println("  Using default password for simulation...");
            delay(100);
            Serial.println("  [OK] Password accepted!");
        }
    }

    void readNDEFMessage(NFCTag* tag) {
        Serial.println("\n[NDEF MESSAGE]");

        if (tag->ndefLength == 0) {
            Serial.println("  No NDEF data found on tag.");
            return;
        }

        // Parse TLV structure
        int pos = 0;
        while (pos < tag->ndefLength) {
            uint8_t tlvType = tag->ndefData[pos++];

            if (tlvType == 0x00) {
                // NULL TLV - skip
                continue;
            } else if (tlvType == 0xFE) {
                // Terminator TLV
                Serial.println("  [END] NDEF Terminator TLV");
                break;
            } else if (tlvType == 0x03) {
                // NDEF Message TLV
                uint8_t length = tag->ndefData[pos++];
                Serial.print("  NDEF TLV: Length = ");
                Serial.print(length);
                Serial.println(" bytes");

                // Parse NDEF records
                parseNDEFRecords(&tag->ndefData[pos], length);
                pos += length;
            }
        }
    }

    void parseNDEFRecords(uint8_t* data, int length) {
        int pos = 0;
        int recordNum = 1;

        while (pos < length) {
            // Parse record header
            uint8_t header = data[pos++];

            bool mb = (header & 0x80) != 0;  // Message Begin
            bool me = (header & 0x40) != 0;  // Message End
            bool cf = (header & 0x20) != 0;  // Chunk Flag
            bool sr = (header & 0x10) != 0;  // Short Record
            bool il = (header & 0x08) != 0;  // ID Length present
            uint8_t tnf = header & 0x07;     // Type Name Format

            uint8_t typeLength = data[pos++];
            uint32_t payloadLength = sr ? data[pos++] :
                ((uint32_t)data[pos] << 24) | ((uint32_t)data[pos+1] << 16) |
                ((uint32_t)data[pos+2] << 8) | data[pos+3];
            if (!sr) pos += 4;

            uint8_t idLength = il ? data[pos++] : 0;

            Serial.println();
            Serial.print("  Record #");
            Serial.print(recordNum++);
            Serial.println(":");
            Serial.print("    Flags: MB=");
            Serial.print(mb);
            Serial.print(" ME=");
            Serial.print(me);
            Serial.print(" SR=");
            Serial.print(sr);
            Serial.print(" TNF=");
            Serial.println(tnf);

            // Get type
            char type[65] = {0};
            for (int i = 0; i < typeLength && i < 64; i++) {
                type[i] = data[pos++];
            }

            // Skip ID if present
            pos += idLength;

            Serial.print("    Type: ");
            printTNFDescription(tnf);
            Serial.print(" - \"");
            Serial.print(type);
            Serial.println("\"");

            Serial.print("    Payload Length: ");
            Serial.print(payloadLength);
            Serial.println(" bytes");

            // Parse payload based on type
            if (tnf == TNF_WELL_KNOWN) {
                if (type[0] == RTD_URI) {
                    parseURIPayload(&data[pos], payloadLength);
                } else if (type[0] == RTD_TEXT) {
                    parseTextPayload(&data[pos], payloadLength);
                } else if (type[0] == 'S' && type[1] == 'p') {
                    Serial.println("    [SMART POSTER - Contains nested records]");
                    parseNDEFRecords(&data[pos], payloadLength);
                }
            } else if (tnf == TNF_MIME_MEDIA) {
                parseMIMEPayload(type, &data[pos], payloadLength);
            }

            pos += payloadLength;

            if (me) break;  // Last record
        }
    }

    void printTNFDescription(uint8_t tnf) {
        switch(tnf) {
            case TNF_EMPTY: Serial.print("Empty"); break;
            case TNF_WELL_KNOWN: Serial.print("Well-Known"); break;
            case TNF_MIME_MEDIA: Serial.print("MIME-Type"); break;
            case TNF_ABSOLUTE_URI: Serial.print("Absolute-URI"); break;
            case TNF_EXTERNAL: Serial.print("External"); break;
            case TNF_UNKNOWN: Serial.print("Unknown"); break;
            case TNF_UNCHANGED: Serial.print("Unchanged"); break;
            default: Serial.print("Reserved"); break;
        }
    }

    void parseURIPayload(uint8_t* payload, int length) {
        uint8_t prefixCode = payload[0];

        Serial.print("    URI Prefix Code: 0x");
        if (prefixCode < 0x10) Serial.print("0");
        Serial.println(prefixCode, HEX);

        String uri = "";
        if (prefixCode < URI_PREFIX_COUNT) {
            uri = URI_PREFIXES[prefixCode];
        }

        for (int i = 1; i < length; i++) {
            uri += (char)payload[i];
        }

        Serial.print("    Full URI: ");
        Serial.println(uri);

        // Analyze URI type
        Serial.print("    URI Type: ");
        if (uri.startsWith("https://")) {
            Serial.println("Secure Web Link (HTTPS)");
        } else if (uri.startsWith("http://")) {
            Serial.println("Web Link (HTTP) - Not secure!");
        } else if (uri.startsWith("tel:")) {
            Serial.println("Phone Number");
        } else if (uri.startsWith("mailto:")) {
            Serial.println("Email Address");
        } else {
            Serial.println("Other URI Scheme");
        }
    }

    void parseTextPayload(uint8_t* payload, int length) {
        uint8_t statusByte = payload[0];
        bool utf16 = (statusByte & 0x80) != 0;
        uint8_t langLength = statusByte & 0x3F;

        Serial.print("    Encoding: ");
        Serial.println(utf16 ? "UTF-16" : "UTF-8");

        String lang = "";
        for (int i = 0; i < langLength; i++) {
            lang += (char)payload[1 + i];
        }
        Serial.print("    Language: ");
        Serial.println(lang);

        String text = "";
        for (int i = 1 + langLength; i < length; i++) {
            text += (char)payload[i];
        }
        Serial.print("    Text: \"");
        Serial.print(text);
        Serial.println("\"");
    }

    void parseMIMEPayload(const char* mimeType, uint8_t* payload, int length) {
        Serial.print("    MIME Type: ");
        Serial.println(mimeType);

        if (strstr(mimeType, "vcard") != NULL) {
            Serial.println("    [vCard Contact Data]");
            Serial.print("    Content: ");
            for (int i = 0; i < length && i < 80; i++) {
                if (payload[i] >= 32 && payload[i] < 127) {
                    Serial.print((char)payload[i]);
                } else {
                    Serial.print(".");
                }
            }
            Serial.println();
        } else if (strstr(mimeType, "access") != NULL) {
            Serial.println("    [Access Control Data - Encrypted]");
            Serial.print("    Encrypted Bytes: ");
            for (int i = 0; i < length && i < 16; i++) {
                if (payload[i] < 0x10) Serial.print("0");
                Serial.print(payload[i], HEX);
                Serial.print(" ");
            }
            Serial.println();
        } else {
            Serial.print("    Raw Data (");
            Serial.print(length);
            Serial.println(" bytes)");
        }
    }

    void demonstrateAntiCollision() {
        Serial.println("\n" + String('=', 60));
        Serial.println("DEMONSTRATION: NFC Anti-Collision");
        Serial.println(String('=', 60));

        Serial.println("\nWhen multiple tags are in RF field simultaneously:");
        Serial.println("1. Reader sends REQA (Request Type A) command");
        Serial.println("2. All tags respond with ATQA (Answer To Request)");
        Serial.println("3. Reader initiates anti-collision loop:");
        Serial.println("   - Sends SELECT command with partial UID");
        Serial.println("   - Tags with matching bits respond");
        Serial.println("   - Collisions detected via Manchester encoding");
        Serial.println("   - Reader narrows down bit-by-bit");
        Serial.println("4. Single tag selected, others remain quiet");
        Serial.println("5. Process repeats for remaining tags");

        delay(500);
        Serial.println("\nSimulating multi-tag detection...");
        delay(300);

        Serial.println("\n[RF FIELD] Activated at 13.56 MHz");
        delay(200);
        Serial.println("[REQA] Sent: 0x26");
        delay(100);
        Serial.println("[ATQA] Received: 0x0004 (NTAG family)");
        delay(100);
        Serial.println("[COLLISION] Detected at bit position 24");
        delay(150);
        Serial.println("[SELECT] NVB=40, UID prefix: 04:A3:B2:C1");
        delay(100);
        Serial.println("[SAK] Received: 0x00 (UID complete)");
        delay(100);
        Serial.println("[SELECTED] Tag 1 active, others halted");

        Serial.println("\n[OK] Anti-collision complete - 1 tag selected");
    }

    void demonstrateRelayAttack() {
        Serial.println("\n" + String('=', 60));
        Serial.println("SECURITY: Relay Attack Demonstration");
        Serial.println(String('=', 60));

        Serial.println("\nRelay Attack Concept:");
        Serial.println("Attacker uses two devices to extend NFC range:");
        Serial.println("");
        Serial.println("  [Victim Card] <--NFC--> [Attacker A]");
        Serial.println("                             |");
        Serial.println("                         (relay link)");
        Serial.println("                             |");
        Serial.println("  [Payment Terminal] <--NFC--> [Attacker B]");
        Serial.println("");

        Serial.println("Timeline of attack:");
        Serial.println("  T+0ms:   Terminal activates, requests payment");
        Serial.println("  T+5ms:   Attacker B relays request to Attacker A");
        Serial.println("  T+50ms:  Attacker A presents request to victim");
        Serial.println("  T+55ms:  Victim's card responds (auto-response)");
        Serial.println("  T+60ms:  Response relayed back to terminal");
        Serial.println("  T+65ms:  Terminal accepts payment");
        Serial.println("");

        Serial.println("Detection/Prevention Methods:");
        Serial.println("  1. Distance bounding: Measure round-trip time");
        Serial.println("     - Light travels ~30cm in 1ns");
        Serial.println("     - NFC range: ~10cm = ~0.3ns");
        Serial.println("     - Relay adds >100ns delay = DETECTED!");
        Serial.println("");
        Serial.println("  2. Require user interaction:");
        Serial.println("     - Biometric (fingerprint/face)");
        Serial.println("     - PIN entry");
        Serial.println("     - Button press");
        Serial.println("");
        Serial.println("  3. Payment limits for contactless:");
        Serial.println("     - UK: GBP 100 limit without PIN");
        Serial.println("     - US: $100-200 typical limit");
        Serial.println("");

        Serial.println("[!] Always require authentication for high-value NFC operations!");
    }

    void printTagTypeInfo() {
        Serial.println("\n" + String('=', 60));
        Serial.println("NFC FORUM TAG TYPES REFERENCE");
        Serial.println(String('=', 60));

        Serial.println("\nType 1 (TOPAZ, Broadcom):");
        Serial.println("  Memory: 96 - 2000 bytes");
        Serial.println("  Read/Write: Yes (lockable)");
        Serial.println("  Speed: 106 kbps");
        Serial.println("  Use: Low-cost tags, one-time URLs");

        Serial.println("\nType 2 (NTAG, MIFARE Ultralight):");
        Serial.println("  Memory: 48 - 888 bytes");
        Serial.println("  Read/Write: Yes (optional password)");
        Serial.println("  Speed: 106 kbps");
        Serial.println("  Use: Smart posters, IoT triggers");
        Serial.println("  Examples: NTAG213 (144B), NTAG215 (504B), NTAG216 (888B)");

        Serial.println("\nType 3 (FeliCa, Sony):");
        Serial.println("  Memory: 1 - 9 KB");
        Serial.println("  Read/Write: Yes");
        Serial.println("  Speed: 212/424 kbps");
        Serial.println("  Use: Japan transit (Suica), e-wallets");

        Serial.println("\nType 4 (DESFire, JCOP, ISO 14443-4):");
        Serial.println("  Memory: Up to 32 KB");
        Serial.println("  Read/Write: Yes");
        Serial.println("  Speed: 106-848 kbps");
        Serial.println("  Security: AES-128, 3DES encryption");
        Serial.println("  Use: Access control, payments, secure ID");
        Serial.println("  Examples: MIFARE DESFire, NTAG424");

        Serial.println("\nType 5 (ICODE SLIX, ISO 15693):");
        Serial.println("  Memory: Up to 8 KB");
        Serial.println("  Read/Write: Yes");
        Serial.println("  Speed: 6.6 - 26 kbps (slower)");
        Serial.println("  Range: Up to 1 meter (extended)");
        Serial.println("  Use: Library books, industrial RFID");
    }
};

// =============================================================================
// SECTION 5: GLOBAL OBJECTS AND SETUP
// =============================================================================

NFCReaderSimulator nfcReader;
unsigned long demoStartTime;
int demoPhase = 0;

void setup() {
    Serial.begin(115200);
    while (!Serial) delay(10);

    delay(1000);

    // Initialize simulated tag database
    initializeSimulatedTags();

    // Initialize reader
    nfcReader.begin();

    demoStartTime = millis();
}

void loop() {
    unsigned long elapsed = millis() - demoStartTime;

    // Run through demonstration phases
    switch(demoPhase) {
        case 0:
            // Phase 0: Poll through all tags (0-18 seconds)
            if (elapsed < 18000) {
                nfcReader.poll();
            } else {
                demoPhase = 1;
            }
            break;

        case 1:
            // Phase 1: Show tag type reference
            nfcReader.printTagTypeInfo();
            delay(3000);
            demoPhase = 2;
            break;

        case 2:
            // Phase 2: Anti-collision demo
            nfcReader.demonstrateAntiCollision();
            delay(2000);
            demoPhase = 3;
            break;

        case 3:
            // Phase 3: Security demo
            nfcReader.demonstrateRelayAttack();
            delay(2000);
            demoPhase = 4;
            break;

        case 4:
            // Phase 4: Summary and restart
            Serial.println("\n" + String('=', 60));
            Serial.println("LAB COMPLETE - SUMMARY");
            Serial.println(String('=', 60));
            Serial.println("\nKey concepts demonstrated:");
            Serial.println("  [x] NDEF message structure and TLV parsing");
            Serial.println("  [x] URI and Text record decoding");
            Serial.println("  [x] Tag type identification (Types 1-5)");
            Serial.println("  [x] Security levels and authentication");
            Serial.println("  [x] Anti-collision protocol");
            Serial.println("  [x] Relay attack awareness");
            Serial.println("\nRestarting demonstration in 10 seconds...\n");
            delay(10000);
            demoPhase = 0;
            demoStartTime = millis();
            break;
    }

    delay(100);  // Small delay for loop
}

// =============================================================================
// SECTION 6: UTILITY FUNCTIONS
// =============================================================================

// Calculate NDEF message checksum (for validation)
uint8_t calculateNDEFChecksum(uint8_t* data, int length) {
    uint8_t checksum = 0;
    for (int i = 0; i < length; i++) {
        checksum ^= data[i];
    }
    return checksum;
}

// Format UID for display
String formatUID(uint8_t* uid, int length) {
    String result = "";
    for (int i = 0; i < length; i++) {
        if (i > 0) result += ":";
        if (uid[i] < 0x10) result += "0";
        result += String(uid[i], HEX);
    }
    result.toUpperCase();
    return result;
}

// Convert byte array to hex string
String bytesToHex(uint8_t* bytes, int length) {
    String result = "";
    for (int i = 0; i < length; i++) {
        if (bytes[i] < 0x10) result += "0";
        result += String(bytes[i], HEX);
    }
    result.toUpperCase();
    return result;
}

36.4 Understanding the Code

The simulation demonstrates these key NFC concepts:

1. NDEF Message Structure

The NFC Data Exchange Format (NDEF) is the standard for encoding data on NFC tags:

+---------------------+
| TLV Container       |
| Type: 0x03 (NDEF)   |
| Length: varies      |
+---------------------+
| NDEF Record 1       |
| - Header flags      |
| - Type (U/T/Sp)     |
| - Payload           |
+---------------------+
| NDEF Record N...    |
+---------------------+
| Terminator TLV      |
| Type: 0xFE          |
+---------------------+

Header Flags:

  • MB (Message Begin): First record in message
  • ME (Message End): Last record in message
  • CF (Chunk Flag): Record is chunked
  • SR (Short Record): Payload < 256 bytes
  • IL (ID Length): ID field present
  • TNF (Type Name Format): 3-bit type classification

The NDEF header byte packs 8 flags into a single byte: \(\text{Header} = (\text{MB} \ll 7) | (\text{ME} \ll 6) | (\text{CF} \ll 5) | (\text{SR} \ll 4) | (\text{IL} \ll 3) | \text{TNF}\). Worked example: For a single URI record, MB=1, ME=1, CF=0, SR=1, IL=0, TNF=0x01 gives \(\text{0xD1} = (1 \ll 7) | (1 \ll 6) | (0 \ll 5) | (1 \ll 4) | (0 \ll 3) | 0x01 = 0b11010001 = 0xD1\).

Try It: NDEF Header Byte Builder

Toggle the NDEF record header flags and TNF value to see how they combine into a single header byte. This demonstrates the bit-packing used in every NDEF record.

2. URI Prefix Compression

NFC uses prefix codes to save space on small tags:

Code Prefix Savings
0x01 http://www. 11 bytes
0x02 https://www. 12 bytes
0x03 http:// 7 bytes
0x04 https:// 8 bytes
0x05 tel: 4 bytes
0x06 mailto: 7 bytes

Example: https://iotclass.example becomes: 0x04 + iotclass.example (saves 8 bytes)

Try It: URI Prefix Compression Calculator

Enter a URL to see how NFC compresses it using prefix codes. The widget shows the original size versus the compressed NDEF payload size, demonstrating why prefix compression matters for small-memory tags.

3. Tag Type Selection

The simulation demonstrates all five NFC Forum tag types:

Type Example IC Memory Security Use Case
1 Topaz 96-2KB None Low-cost labels
2 NTAG213/215/216 48-888B Password Smart posters
3 FeliCa 1-9KB Crypto Transit cards
4 DESFire 32KB AES/3DES Payments, access
5 ICODE 8KB Password Industrial RFID
Try It: NFC Tag Type Selector

Select a use case to see which NFC Forum Tag Type best fits your requirements. Adjust the memory and security needs to compare tag options side by side.

36.5 Challenge Exercises

Challenge 1: Add a New Tag Type

Modify the code to add a sixth simulated tag with these specifications: - Tag Type: 5 (ICODE SLIX) - Memory: 256 bytes - Contains: A custom external type record with an application identifier

Hints:

  • Add a new entry to simulatedTags[] array
  • Use TNF_EXTERNAL (0x04) for the record type
  • Update numSimulatedTags to 6
Challenge 2: Implement Write Simulation

Add a function to simulate writing NDEF data to a tag:

void simulateWriteNDEF(NFCTag* tag, const char* url) {
    // Your implementation:
    // 1. Check if tag is locked (reject if true)
    // 2. Check if tag has password (simulate auth)
    // 3. Build NDEF TLV with URI record
    // 4. Check if data fits in tag memory
    // 5. Update tag->ndefData and tag->ndefLength
}
Challenge 3: Add Distance-Based Detection

Modify simulateTagDetection() to include simulated RSSI/distance:

// Add to tag detection:
float distance = random(1, 100) / 10.0;  // 0.1 - 10.0 cm
if (distance > 4.0) {
    Serial.println("  [WARNING] Tag at edge of range");
    Serial.println("  Signal may be unstable");
}

Then add logic to occasionally “fail” detection when distance > 8cm.

Challenge 4: Implement Multi-Record Messages

Create a function that builds Smart Poster NDEF messages with: - A URI record (the link) - A Title record (display text) - An Action record (recommended action)

Reference the existing posterNdef[] array structure.

36.6 Expected Outcomes

After completing this lab, you should be able to:

  1. Explain NDEF structure: Describe the TLV container format, record headers, and payload organization

  2. Parse NFC data: Read and interpret raw NDEF bytes including:

    • Type Name Format (TNF) classification
    • Record type identification (U, T, Sp, MIME)
    • Payload decoding for URI and Text records
  3. Identify tag types: Recognize NFC Forum Tag Types 1-5 and their characteristics:

    • Memory capacity ranges
    • Security features (none, password, crypto)
    • Appropriate use cases
  4. Understand security: Explain NFC security concepts including:

    • Authentication mechanisms
    • Encryption levels (none, AES, 3DES)
    • Relay attack vectors and mitigations
    • Distance bounding protocols
  5. Design NFC applications: Select appropriate tag types and record formats for:

    • Smart posters and marketing
    • Access control and authentication
    • Device pairing and IoT triggers
    • Payment and secure transactions
Try It: Relay Attack Timing Simulator

Adjust the relay distance to see how it affects round-trip timing. Distance bounding protocols detect relay attacks by measuring whether the response arrives faster than the speed of light would allow at the claimed distance.

Next Steps

After mastering this simulation, practice with real hardware:

  1. Arduino + PN532: Use the Adafruit PN532 library with actual NFC tags
  2. Mobile development: Build Android NFC apps using the NfcAdapter API
  3. Security testing: Explore tools like Proxmark3 for NFC security research

36.7 Knowledge Check

Question 1: In the NDEF TLV structure, what does the terminator byte 0xFE indicate?

Question 2: Why does the simulation’s anti-collision protocol use bit-by-bit UID resolution?

Question 3: In the simulation, the secure access card (MIFARE DESFire) has security level 3. What does this mean?

Problem: A smart building deploys 200 NFC tags at conference room doors for room booking. After 2 weeks, facilities reports that “30% of tags don’t work.” Users report inconsistent reads - sometimes tags work, sometimes they don’t.

Initial Investigation:

Test 1: Physical inspection

  • All 60 “failed” tags are still physically attached
  • No visible damage to stickers
  • Tags are NTAG213 (144 bytes, Type 2)

Test 2: Try with multiple phones

  • iPhone 13: Reads 40 of 60 tags
  • Samsung Galaxy S21: Reads 50 of 60 tags
  • Pixel 6: Reads 55 of 60 tags

Observation: Same tag works with some phones but not others. This rules out “dead tag” theory.

Step 1: Check Tag Placement

Use simulation code to understand NFC antenna locations:

// Add to simulation to show antenna positions
void printAntennaLocations() {
  Serial.println("NFC Antenna Locations by Phone:");
  Serial.println("  iPhone 13: Top center (near camera)");
  Serial.println("  Galaxy S21: Center back (upper)");
  Serial.println("  Pixel 6: Center back (middle)");
  Serial.println();
  Serial.println("Common user error: Tapping bottom of phone");
  Serial.println("  → Phone's NFC antenna is NOT near charging port!");
  Serial.println("  → Must tap with TOP or CENTER BACK of phone");
}

Discovery 1: Site visit reveals users are tapping the BOTTOM of their phones near charging port, not the NFC antenna area.

Step 2: Check Tag Placement Surfaces

Inspect the 10 tags that don’t work with ANY phone:

// Add surface material detection to simulation
struct TagEnvironment {
  const char* surface;
  float metalContent;
  float expectedRSSI;
  bool willWork;
};

TagEnvironment surfaces[] = {
  {"Plastic door sign", 0.0, -50, true},
  {"Wooden door", 0.0, -45, true},
  {"Glass", 0.0, -48, true},
  {"Metal door frame", 1.0, -95, false},  // PROBLEM!
  {"Metal light switch plate", 0.8, -88, false}  // PROBLEM!
};

Discovery 2: 10 problematic tags are mounted on metal door frames or near metal light switches. Metal detunes the NFC antenna, reducing read range from 4 cm to <1 cm or completely blocking reads.

Step 3: Verify NDEF Data Corruption

Read tags that “sometimes work”:

// Simulation of corrupted NDEF data
uint8_t corruptedNDEF[] = {
  0x03, 0x14,                    // NDEF TLV
  0xD1,                          // Header: MB=1, ME=1, SR=1
  0x01,                          // Type length
  0x10,                          // Payload length
  0x55,                          // Type: URI
  0x04,                          // Prefix: https://
  'r', 'o', 'o', 'm', '.', 'e', 'x', 'a',  // Payload (partial)
  // MISSING BYTES! Payload should be 16 bytes, only 8 present
  0xFE                           // Terminator (wrong position)
};

void validateNDEF(uint8_t* data, int length) {
  int pos = 2;  // Skip TLV header
  uint8_t payloadLen = data[pos + 2];
  int expectedEnd = pos + 3 + 1 + payloadLen;  // header + type + payload

  if (expectedEnd > length) {
    Serial.println("[ERROR] NDEF payload length exceeds actual data!");
    Serial.printf("  Expected: %d bytes, Actual: %d bytes\n",
                  expectedEnd, length);
  }
}

Discovery 3: 5 tags have truncated NDEF data. Users tapped too quickly during initial programming, causing incomplete writes.

Step 4: Measure Read Distance

Add distance simulation:

float calculateReadDistance(float tagRSSI, const char* surface) {
  float baseDistance = 4.0;  // cm

  // Adjust for surface
  if (strstr(surface, "metal")) {
    baseDistance *= 0.1;  // 90% reduction on metal
  } else if (strstr(surface, "glass")) {
    baseDistance *= 0.9;  // 10% reduction on glass
  }

  // Adjust for signal strength
  if (tagRSSI < -80) {
    baseDistance *= 0.3;  // Weak signal
  }

  return baseDistance;
}

Discovery 4: Tags on plastic surfaces have 4 cm read range. Tags on glass have 3.6 cm range. Tags on metal have 0.4 cm range (essentially non-functional).

Root Causes Identified:

Issue Affected Tags Cause
User tapping wrong phone area 50 tags User error - tapping bottom not top
Metal surface detuning 10 tags Installation error - mounted on metal
Corrupted NDEF data 5 tags Incomplete write during programming
Intermittent reader 3 tags Dirty/damaged tag surface

Solutions Implemented:

1. User education (50 tags fixed):

  • Created visual guides showing NFC antenna locations
  • Added “tap here” dots to conference room signs
  • Sent email with diagrams to all staff

2. Tag relocation (10 tags fixed):

  • Moved tags from metal door frames to plastic door signs
  • Added ferrite shielding sheets ($0.50 each) between tag and metal for tags that can’t be relocated

3. Reprogram corrupted tags (5 tags fixed):

// Proper NDEF write procedure
void writeNDEFSafely(Tag tag, const char* url) {
  // 1. Check tag capacity
  if (strlen(url) + 10 > tag.capacity) {
    Serial.println("ERROR: URL too long for tag");
    return;
  }

  // 2. Write NDEF message
  NdefMessage message = createUriMessage(url);
  bool success = tag.write(message);

  // 3. CRITICAL: Verify write
  delay(100);  // Wait for write to complete
  NdefMessage readBack = tag.read();

  if (!readBack.equals(message)) {
    Serial.println("ERROR: Write verification failed");
    // Retry up to 3 times
  } else {
    Serial.println("SUCCESS: Tag written and verified");
  }

  // 4. Lock tag to prevent accidental overwrites
  tag.lockPermanently();
}

4. Replace damaged tags (3 tags fixed):

  • Physical damage to antenna coil
  • Replaced with new NTAG213 tags
  • Total cost: 3 × $0.20 = $0.60

Results After Fixes:

  • Success rate: 30% → 98%
  • Average read time: 1.5 seconds → 0.3 seconds
  • User satisfaction: “frustrating” → “works great”

Lessons Learned:

  1. NFC antenna location varies by phone - Always provide visual guides
  2. Metal surfaces kill NFC - Test all installation locations before bulk deployment
  3. Verify every write operation - 2.5% of NFC writes fail if tag is removed too soon
  4. Site survey matters - Don’t assume “4 cm range” works everywhere
  5. User training is critical - Even the best technology fails without user education

Prevention Checklist for Future Deployments:

Concept Relationships

Builds on:

Key Concepts Demonstrated:

  • NDEF Message Structure - TLV containers, record headers (MB/ME/CF/SR/IL/TNF)
  • URI Prefix Compression - 36 codes (0x01-0x23) saving 4-12 bytes per URL
  • Tag Type Identification - Types 1-5 memory/security characteristics
  • Anti-Collision Protocol - REQA/ATQA/SELECT for multi-tag handling
  • Security Concepts - Relay attacks, distance bounding, authentication

Why Simulation?

  • Real NFC requires specialized 13.56 MHz RF hardware (PN532, etc.)
  • Simulation models logical behavior without physical constraints
  • Enables learning NDEF parsing and security concepts before hardware investment

Extends to:

  • NFC Real-World Applications - Applying concepts to payments, smart home, authentication
  • Physical hardware implementation with PN532 modules
See Also

Hardware Next Steps:

NDEF Specification:

Security Research:

Common Pitfalls

NFC simulations typically assume perfect coupling and no environmental interference. Real-world factors (tag orientation, metal proximity, reader sensitivity variation) are not modelled. Fix: always validate simulation results with physical NFC hardware before deployment.

An NFC application tested with one reader-tag pair may fail with a different vendor’s hardware due to RF parameter variations. Fix: test with at least three different NFC reader chipsets and tag manufacturers to verify interoperability.

Simulations rarely inject errors (CRC failures, anti-collision conflicts). Fix: manually inject error conditions (corrupt frames, timeout events) in the simulation to verify that the application handles them gracefully.

36.8 Summary

This lab demonstrated NFC concepts through interactive simulation:

  • NDEF Message Parsing: TLV container structure, record headers with MB/ME/CF/SR/IL/TNF flags, and payload processing for URI/Text/MIME types
  • URI Prefix Compression: How NFC saves space using 36 standardized prefix codes (0x01-0x23) to compress common URL schemes
  • Tag Type Identification: Characteristics of NFC Forum Types 1-5 including memory capacity, security levels, and appropriate use cases
  • Anti-Collision Protocol: REQA/ATQA/SELECT sequence for handling multiple tags using bit-by-bit UID resolution
  • Security Demonstrations: Relay attack mechanics, distance bounding countermeasures, and authentication requirements

36.9 What’s Next

Chapter Focus
NFC Real-World Applications Mobile payments, smart home automation, product authentication, and security analysis tools
NFC Security and Comparisons EMV payment security, relay attack countermeasures, and NFC vs RFID vs BLE comparisons
NFC Hands-On Lab Physical hardware exercises with PN532 modules and real NFC tags