NFC

NFC

Device Compatibility

Overview

The following sections will go over how to install and access the NFC chip on your MATRIX Creator. This library currently implements the following:

  • Reading General Information (All tags)
  • Reading Pages (MIFARE Ultralight & NTAG)
  • Writing to a Page (MIFARE Ultralight & NTAG)
  • Reading NDEF (MIFARE Ultralight & NTAG)
  • Writing NDEF (MIFARE Ultralight & NTAG)

Helpful Smartphone Apps For NFC:

Installation

Make sure you've installed MATRIX HAL NFC before continuing.

Only one process can interact with the NFC Chip!

This applies to anything that interfaces with NFC, including the C++ library. Multiple processes using NFC will cause unpredictable errors.

Inside your Python project, run the following.

sudo python3 -m pip install pybind11
sudo python3 -m pip install matrix-lite-nfc

Import Statement

import matrix_lite_nfc as nfc

nfc

.status()

When a read or write function completes, it will return a status code to indicate the result. nfc.Status returns a string of what that number means.

nfc.status(/*number*/)

# Example output
# nfc.status(256) will return "Activation Done"

.Message()

Represents an NDEF message. Each message can contain multiple NDEF Records. Each record can hold text, cellular numbers, emails, links, etc.

# Creates an empty message
msg = nfc.Message()

# Can be initialized from a scanned tag (covered in nfc.read)
# msg = nfc.Message(tag.ndef.content)
.addUriRecord()
msg.addUriRecord("https://community.matrix.one")
msg.addUriRecord("tel:+14085551212")
msg.addUriRecord("sms:+14085551212")
msg.addUriRecord("mailto:user@example.com")
// List of URI protocols //
http://www.
https://www.
http://
https://
tel:
mailto:
ftp://anonymous:anonymous@
ftp://ftp.
ftps://
sftp://
smb://
nfs://
ftp://
dav://
news:
telnet://
imap:
rtsp://
urn:
pop:
sip:
sips:
tftp:
btspp://
btl2cap://
btgoep://
tcpobex://
irdaobex://
file://
urn:epc:id:
urn:epc:tag:
urn:epc:pat:
urn:epc:raw:
urn:epc:
urn:nfc:
.addTextRecord()
# Defaults to en
msg.addTextRecord("Hello World")

# Or uses a specified Language
msg.addTextRecord("Hola Mundo", "es")
.addMimeMediaRecord()
msg.addMimeMediaRecord("text/json", '{"answer": 42}')
.getRecords()
# Returns an array of objects representing NDEF Records
msg.getRecords()

# Example output
[
{
  tnf: 'Well Known',
  type: 'U',
  payload: '.https://community.matrix.one',
  byteSize: 33,
  typeLength: 1,
  payloadLength: 29,
  IdLength: 0
},
{
  tnf: 'Well Known',
  type: 'T',
  payload: '.enHello World',
  byteSize: 23,
  typeLength: 1,
  payloadLength: 19,
  IdLength: 0
}
]
.getRecord()
# Returns the specified NDEF Record
msg.getRecord(0)

# Example output
{
  tnf: 'Well Known',
  type: 'U',
  payload: '.https://community.matrix.one',
  byteSize: 33,
  typeLength: 1,
  payloadLength: 29,
  IdLength: 0
}
.getRecordCount()
# Returns the number of NDEF Records in an NDEF Message
msg.getRecordCount()
.getEncodedSize()
# Returns the size of the encoded representation of the NDEF message
msg.getEncodedSize()

nfc.read

NFC tags can be read from a loop in a spawned thread or a synchronous function call.

.start()
# Configure what you want to read
options = {
    "rate": 1,   # Read loop speed (Seconds)
    # At least 1 read options is required. Less options -> faster reading
    "info": True,  # Generic information for any NFC tag
    "pages": True, # All page data
    "page": 0,     # A single page(faster than pages)
    "ndef": True   # All NDEF data
}

def read_callback(tag):
    print(tag.status) # NFC activation status
    print(tag) # Object with requested NFC data

# Starts the loop
nfc.read.start(options, read_callback)
.stop()
# Kills the NFC read loop
nfc.read.stop()
.scan()
# Synchronous tag reading
tag = nfc.read.scan({
    # At least 1 read options is required. Less options -> faster reading!
    "info": True,  # Generic information for any NFC tag
    "pages": True, # All page data
    "ndef": True,  # A single page(faster than pages)
    "page": 0,     # All NDEF data
})
Reading Examples
import matrix_lite_nfc as nfc

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")
        print(tag.info)

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "info":True}, read_callback)

##* Example Output *##
"""
info {
    technology: A
    type: 2
    UID: 041F79528E6080
    ATQ: 4400
    SAK: 00
    card_family: Mifare Ultralight | NTAG
    IC_type: NTAG215
    bit_rate: -1
    storage_size: 504
    read_status: 0
}
"""
import matrix_lite_nfc as nfc

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")
        msg = nfc.Message(tag.ndef.content)
        print(msg.getRecords())

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "ndef":True}, read_callback)

##* Example Output *##
"""
[tnf: Well Known
type: U
payload: .https://community.matrix.one
byteSize: 33
typeLength: 1
payloadLength: 29
IdLength: 0
, tnf: Well Known
type: T
payload: .enHello World
byteSize: 18
typeLength: 1
payloadLength: 14
IdLength: 0
]
"""
import matrix_lite_nfc as nfc

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")
        print(tag.pages)

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "pages":True}, read_callback)

##* Example Output *##
"""
pages {
    read_complete: 1
    content: [
[ 4, 31, 121, 234, ], [ 82, 142, 96, 128, ], [ 60, 72, 0, 0, ], [ 225, 16, 62, 0, ], [ 3, 33, 209, 1, ], [ 29, 85, 0, 104, ], [ 116, 116, 112, 115, ], [ 58, 47, 47, 99, ], [ 111, 109, 109, 117, ], [ 110, 105, 116, 121, ], [ 46, 109, 97, 116, ], [ 114, 105, 120, 46, ], [ 111, 110, 101, 254, ], [ 1, 17, 85, 0, ], [ 116, 101, 108, 58, ], [ 43, 49, 52, 48, ], [ 56, 53, 53, 53, ], [ 49, 50, 49, 50, ], [ 17, 1, 14, 84, ], [ 2, 101, 110, 72, ], [ 101, 108, 108, 111, ], [ 32, 87, 111, 114, ], [ 108, 100, 81, 1, ], [ 13, 84, 2, 101, ], [ 115, 72, 111, 108, ], [ 48, 45, 59, 21, ], [ 110, 100, 111, 254, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 189, ], [ 4, 0, 0, 255, ], [ 0, 5, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], ]
    read_status: 17474
}
"""
import matrix_lite_nfc as nfc

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")
        print(tag.page)

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "page": 0}, read_callback)

#* Example Output *#
# [ 4, 63, 65, 242 ]
import matrix_lite_nfc as nfc

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")
        print(tag)

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({
    "rate": 1,
    "info": True,
    "pages": True,
    "page": 0,
    "ndef": True
}, read_callback)

##* Example Output *##
"""
{
info {
    technology: A
    type: 2
    UID: 046B3F8AA86481
    ATQ: 4400
    SAK: 00
    card_family: Mifare Ultralight | NTAG
    IC_type: NTAG215
    bit_rate: -1
    storage_size: 504
    read_status: 0
}
pages {
    read_complete: 1
    content: [
[ 4, 107, 63, 216, ], [ 138, 168, 100, 129, ], [ 199, 72, 0, 0, ], [ 225, 16, 62, 0, ], [ 3, 51, 145, 1, ], [ 29, 85, 0, 104, ], [ 116, 116, 112, 115, ], [ 58, 47, 47, 99, ], [ 111, 109, 109, 117, ], [ 110, 105, 116, 121, ], [ 46, 109, 97, 116, ], [ 114, 105, 120, 46, ], [ 111, 110, 101, 81, ], [ 1, 14, 84, 2, ], [ 101, 110, 72, 101, ], [ 108, 108, 111, 32, ], [ 87, 111, 114, 108, ], [ 100, 254, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 189, ], [ 4, 0, 0, 255, ], [ 0, 5, 0, 0, ], [ 0, 0, 0, 0, ], [ 0, 0, 0, 0, ], ]
    read_status: 17474
}
page [ 4, 107, 63, 216, ]
ndef {
    valid: 1
    content: [ 145, 1, 29, 85, 0, 104, 116, 116, 112, 115, 58, 47, 47, 99, 111, 109, 109, 117, 110, 105, 116, 121, 46, 109, 97, 116, 114, 105, 120, 46, 111, 110, 101, 81, 1, 14, 84, 2, 101, 110, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100,  ]
    read_status: 0
}
status: 256
}
"""

nfc.write

Writing allows NDEF messages to be written & erased. There is also an option to directly write to a tag's page. Writing is normally done within an NFC read loop.

.message()
# Create an NDEF message with a record
msg = nfc.Message()
msg.addUriRecord("https://community.matrix.one")

# Write the message into the NFC tag
result = nfc.write.message(msg)
# result.activation : NFC activation status
# result.write      : NFC write status
.erase()
# Erase the NDEF message on an NFC tag
result = nfc.write.erase()
# result.activation : NFC activation status
# result.write      : NFC write status
.page()

Writing to a random page may lock your NFC tag

page_index = 25           # page you want to overwrite
page_byte = [48,45,59,21] # Array of numbers that represents a page

result = nfc.write.page(page_index, page_byte)
# result.activation : NFC activation status
# result.write      : NFC write status
Writing Examples
import matrix_lite_nfc as nfc

msg = nfc.Message()
msg.addUriRecord("https://community.matrix.one")

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")

        status = nfc.write.message(msg).write
        # Exit if write was successful
        if (status == 0):
            print("Write was successful! Stopping loop.")
            nfc.read.stop()
        # Or print status code message
        else:
            print(nfc.status(status))

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "info": True}, read_callback)
import matrix_lite_nfc as nfc

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")

        status = nfc.write.erase().write
        # Exit if erase was successful
        if (status == 0):
            print("Erase was successful! Stopping loop.")
            nfc.read.stop()
        # Or print status code message
        else:
            print(nfc.status(status))

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "info": True}, read_callback)
#* DO NOT WRITE TO A PAGE IF YOU DON'T KNOW WHAT IT DOES. *#
import matrix_lite_nfc as nfc

page_index = #*insert page number*#
page_bytes = [48,45,59,21]

def read_callback(tag):
    if (tag.status == 256):
        print("Tag Was Scanned")

        status = nfc.write.page(page_index, page_bytes).write
        # Exit if write was successful
        if (status == 0):
            print("Write was successful! Stopping loop.")
            nfc.read.stop()
        # Or print status code message
        else:
            print(nfc.status(status))

    elif (tag.status == 1024):
        print("Nothing Was Scanned")

nfc.read.start({"rate": 1, "info": True}, read_callback)