Python - NFC/RFID Bricklet – Tinkerforge

- Getting Started
  - Primer
  - Tutorials
  - FAQ
- Hardware
  - Bricks
  - Bricklets
  - Master Extensions
  - Power Supplies
  - Accessories
  - Timeline
- Software
  - Brick Daemon (brickd)
  - Brick Viewer (brickv)
  - API Bindings
    - C/C++
    - C/C++ (iOS)
    - C#
    - C# (Windows Phone)
    - Delphi/Lazarus
    - Java
    - Java (Android)
    - JavaScript
    - LabVIEW
    - Mathematica
    - MATLAB/Octave
    - Perl
    - PHP
    - Python
      - Requirements
      - Installation
      - Testing an Example
      - API Reference and Examples
        - IP Connection
        - Bricks
        - Bricklets
          - Ambient Light Bricklet
          - Analog In Bricklet
          - Analog Out Bricklet
          - Barometer Bricklet
          - Color Bricklet
          - Current12 Bricklet
          - Current25 Bricklet
          - Distance IR Bricklet
          - Distance US Bricklet
          - Dual Button Bricklet
          - Dual Relay Bricklet
          - GPS Bricklet
          - Hall Effect Bricklet
          - Humidity Bricklet
          - Industrial Digital In 4 Bricklet
          - Industrial Digital Out 4 Bricklet
          - Industrial Dual 0-20mA Bricklet
          - Industrial Quad Relay Bricklet
          - IO-16 Bricklet
          - IO-4 Bricklet
          - Joystick Bricklet
          - LCD 16x2 Bricklet
          - LCD 20x4 Bricklet
          - LED Strip Bricklet
          - Line Bricklet
          - Linear Poti Bricklet
          - Moisture Bricklet
          - Motion Detector Bricklet
          - Multi Touch Bricklet
          - NFC/RFID Bricklet
            - Examples
              - Scan For Tags
              - Write Read Type2
              - Write Ndef Message
            - API
              - Basic Functions
              - Advanced Functions
              - Callback Configuration Functions
              - Callbacks
              - Constants
          - Piezo Buzzer Bricklet
          - Piezo Speaker Bricklet
          - PTC Bricklet
          - Remote Switch Bricklet
          - Rotary Encoder Bricklet
          - Rotary Poti Bricklet
          - Segment Display 4x7 Bricklet
          - Solid State Relay Bricklet
          - Sound Intensity Bricklet
          - Temperature Bricklet
          - Temperature IR Bricklet
          - Tilt Bricklet
          - Voltage Bricklet
          - Voltage/Current Bricklet
    - Ruby
    - Shell
    - Visual Basic .NET
  - Firmwares and Plugins
  - Device Identifier
  - Source Code and Bug Tracking
  - Programming Interface
- Starter Kits
  - Weather Station
  - Hardware Hacking
  - Server Room Monitoring
  - Blinkenlights
  - Internet of Things
  - Camera Slider
- Embedded Boards
  - Raspberry Pi
- Specifications
  - Technical Data
  - TCP/IP Protocol
  - Modbus Protocol
  - Wireshark Dissector

# Python - NFC/RFID Bricklet

This is the description of the Python API bindings for the NFC/RFID Bricklet. General information and technical specifications for the NFC/RFID Bricklet are summarized in its hardware description.

An installation guide for the Python API bindings is part of their general description.

## Examples

The example code below is Public Domain (CC0 1.0).

### Scan For Tags

Download (example_scan_for_tags.py)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    HOST = "localhost"
    PORT = 4223
    UID = "hjw" # Change to your UID

    from tinkerforge.ip_connection import IPConnection
    from tinkerforge.bricklet_nfc_rfid import NFCRFID

    tag_type = 0

    # Callback function for state changed callback
    def cb_state_changed(state, idle, nfc):
        # Cycle through all types
        if idle:
            global tag_type
            tag_type = (tag_type + 1) % 3
            nfc.request_tag_id(tag_type)

        if state == nfc.STATE_REQUEST_TAG_ID_READY:
            ret = nfc.get_tag_id()
            print('Found tag of type ' +
                  str(ret.tag_type) +
                  ' with ID [' +
                  ' '.join(map(str, map(hex, ret.tid[:ret.tid_length]))) +
                  "]")

    if __name__ == "__main__":
        ipcon = IPConnection() # Create IP connection
        nfc = NFCRFID(UID, ipcon) # Create device object

        ipcon.connect(HOST, PORT) # Connect to brickd
        # Don't use device before ipcon is connected

        # Register state changed callback to function cb_state_changed
        nfc.register_callback(nfc.CALLBACK_STATE_CHANGED,
                              lambda x, y: cb_state_changed(x, y, nfc))

        nfc.request_tag_id(nfc.TAG_TYPE_MIFARE_CLASSIC)

        raw_input('Press key to exit\n') # Use input() in Python 3
        ipcon.disconnect()

### Write Read Type2

Download (example_write_read_type2.py)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    HOST = "localhost"
    PORT = 4223
    UID = "hjw" # Change to your UID

    from tinkerforge.ip_connection import IPConnection
    from tinkerforge.bricklet_nfc_rfid import NFCRFID

    # Callback function for state changed callback
    def cb_state_changed(state, idle, nfc):
        if state == nfc.STATE_REQUEST_TAG_ID_READY:
            print('Tag found')

            # Write 16 byte to pages 5-8
            data_write = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
            nfc.write_page(5, data_write)
            print('Writing data...')
        elif state == nfc.STATE_WRITE_PAGE_READY:
            # Request pages 5-8
            nfc.request_page(5)
            print('Requesting data...')
        elif state == nfc.STATE_REQUEST_PAGE_READY:
            # Get and print pages
            data = nfc.get_page()
            print('Read data: [' + ' '.join(map(str, data)) + ']')
        elif state & (1 << 6):
            # All errors have bit 6 set
            print('Error: ' + str(state))

    if __name__ == "__main__":
        ipcon = IPConnection() # Create IP connection
        nfc = NFCRFID(UID, ipcon) # Create device object

        ipcon.connect(HOST, PORT) # Connect to brickd
        # Don't use device before ipcon is connected

        # Register state changed callback to function cb_state_changed
        nfc.register_callback(nfc.CALLBACK_STATE_CHANGED,
                              lambda x, y: cb_state_changed(x, y, nfc))

        # Select NFC Forum Type 2 tag
        nfc.request_tag_id(nfc.TAG_TYPE_TYPE2)

        raw_input('Press key to exit\n') # Use input() in Python 3
        ipcon.disconnect()

### Write Ndef Message

Download (example_write_ndef_message.py)

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    # The following specifications have been used
    # as a basis for writing this example.
    #
    # NFC Data Exchange Format (NDEF), NDEF 1.0:
    # https://github.com/Tinkerforge/nfc-rfid-bricklet/raw/master/datasheets/specification_ndef.pdf
    #
    # Type 1 Tag Operation Specification, T1TOP 1.1:
    # https://github.com/Tinkerforge/nfc-rfid-bricklet/raw/master/datasheets/specification_type1.pdf
    #
    # Type 2 Tag Operation Specification, T2TOP 1.1:
    # https://github.com/Tinkerforge/nfc-rfid-bricklet/raw/master/datasheets/specification_type2.pdf

    from tinkerforge.ip_connection import IPConnection
    from tinkerforge.bricklet_nfc_rfid import NFCRFID

    try:
        from Queue import Queue
    except ImportError:
        from queue import Queue

    from pprint import pprint
    import os

    class NdefMessage:
        tag_type = None
        records = []
        capability_container = [0, 0, 0, 0]

        def __init__(self, tag_type):
            self.tag_type = tag_type

        def add_record(self, record):
            self.records.append(record)

            # Set end and begin flags as needed
            if len(self.records) == 1:
                record.begin = True
                record.end = True
            else:
                self.records[-2].end = False
                self.records[-1].end = True

        def set_capability_container(self, version, tag_size, read_write_access):
            # Magic number to indicate NFC Forum defined data is stored
            self.capability_container[0] = 0xE1
            self.capability_container[1] = version
            if self.tag_type == NFCRFID.TAG_TYPE_TYPE1:
                self.capability_container[2] = tag_size/8 - 1
            else:
                self.capability_container[2] = tag_size/8

            self.capability_container[3] = read_write_access

        def get_raw_data_in_chunks(self):
            raw_data = []
            for record in self.records:
                raw_data.extend(record.get_raw_data())

            # Use Three consecutive byte format if necessary, see 2.3 TLV blocks
            data_len = len(raw_data)
            if data_len < 0xFF:
                tlv_ndef = [0x03, data_len]
            else:
                tlv_ndef = [0x03, 0xFF, data_len >> 8, data_len % 256]

            if self.tag_type == NFCRFID.TAG_TYPE_TYPE1:
                # CC set by set_capability_container
                # default lock and memory TLVs
                # NDEF TLV
                # NDEF message
                # Terminator TLV
                raw_data = self.capability_container + \
                           [0x01, 0x03, 0xF2, 0x30, 0x33, 0x02, 0x03, 0xF0, 0x02, 0x03] + \
                           tlv_ndef + \
                           raw_data + \
                           [0xFE]
            elif self.tag_type == NFCRFID.TAG_TYPE_TYPE2:
                # CC set by set_capability_container
                # NDEF TLV
                # NDEF message
                # Terminator TLV
                raw_data = self.capability_container + \
                           tlv_ndef + \
                           raw_data + \
                           [0xFE]
            else:
                # TODO: We could support TAG_TYPE_MIFARE_CLASSIC here, but mifare classic
                # it is not supported in modern smart phones anyway.
                return [[]]

            chunks = []
            for i in range(0, len(raw_data), 16):
                chunks.append(raw_data[i:i+16])

            last_chunk_length = len(chunks[-1])
            if last_chunk_length < 16:
                chunks[-1].extend([0]*(16-last_chunk_length))

            return chunks

    class NdefRecord:
        FLAG_ID_LENGTH     = 1 << 3
        FLAG_SHORT_RECORD  = 1 << 4
        FLAG_CHUNK         = 1 << 5
        FLAG_MESSAGE_END   = 1 << 6
        FLAG_MESSAGE_BEGIN = 1 << 7

        TNF_EMPTY          = 0x0
        TNF_WELL_KNOWN     = 0x01
        TNF_MIME_MEDIA     = 0x02
        TNF_ABSOLUTE_URI   = 0x03
        TNF_EXTERNAL_TYPE  = 0x04
        TNF_UNKNOWN        = 0x05
        TNF_UNCHANGED      = 0x06
        TNF_RESERVED       = 0x07

        NDEF_URIPREFIX_NONE         = 0x00
        NDEF_URIPREFIX_HTTP_WWWDOT  = 0x01
        NDEF_URIPREFIX_HTTPS_WWWDOT = 0x02
        NDEF_URIPREFIX_HTTP         = 0x03
        NDEF_URIPREFIX_HTTPS        = 0x04
        NDEF_URIPREFIX_TEL          = 0x05
        NDEF_URIPREFIX_MAILTO       = 0x06
        NDEF_URIPREFIX_FTP_ANONAT   = 0x07
        NDEF_URIPREFIX_FTP_FTPDOT   = 0x08
        NDEF_URIPREFIX_FTPS         = 0x09
        NDEF_URIPREFIX_SFTP         = 0x0A
        NDEF_URIPREFIX_SMB          = 0x0B
        NDEF_URIPREFIX_NFS          = 0x0C
        NDEF_URIPREFIX_FTP          = 0x0D
        NDEF_URIPREFIX_DAV          = 0x0E
        NDEF_URIPREFIX_NEWS         = 0x0F
        NDEF_URIPREFIX_TELNET       = 0x10
        NDEF_URIPREFIX_IMAP         = 0x11
        NDEF_URIPREFIX_RTSP         = 0x12
        NDEF_URIPREFIX_URN          = 0x13
        NDEF_URIPREFIX_POP          = 0x14
        NDEF_URIPREFIX_SIP          = 0x15
        NDEF_URIPREFIX_SIPS         = 0x16
        NDEF_URIPREFIX_TFTP         = 0x17
        NDEF_URIPREFIX_BTSPP        = 0x18
        NDEF_URIPREFIX_BTL2CAP      = 0x19
        NDEF_URIPREFIX_BTGOEP       = 0x1A
        NDEF_URIPREFIX_TCPOBEX      = 0x1B
        NDEF_URIPREFIX_IRDAOBEX     = 0x1C
        NDEF_URIPREFIX_FILE         = 0x1D
        NDEF_URIPREFIX_URN_EPC_ID   = 0x1E
        NDEF_URIPREFIX_URN_EPC_TAG  = 0x1F
        NDEF_URIPREFIX_URN_EPC_PAT  = 0x20
        NDEF_URIPREFIX_URN_EPC_RAW  = 0x21
        NDEF_URIPREFIX_URN_EPC      = 0x22
        NDEF_URIPREFIX_URN_NFC      = 0x23

        NDEF_TYPE_MIME              = 0x02
        NDEF_TYPE_URI               = 0x55
        NDEF_TYPE_TEXT              = 0x54

        begin = False
        end = False

        tnf = 0
        record_type = None
        payload = None
        identifier = None

        def set_identifier(self, identifier):
            self.identifier = identifier

        def get_raw_data(self):
            if self.record_type == None or self.payload == None:
                return []

            # Construct tnf and flags (byte 0 of header)
            header = [self.tnf]
            if self.begin:
                header[0] |= NdefRecord.FLAG_MESSAGE_BEGIN
            if self.end:
                header[0] |= NdefRecord.FLAG_MESSAGE_END
            if len(self.payload) < 256:
                header[0] |= NdefRecord.FLAG_SHORT_RECORD
            if self.identifier != None:
                header[0] |= NdefRecord.FLAG_ID_LENGTH

            # Type length (byte 1 of header)
            header.append(len(self.record_type))

            # Payload length (byte 2 of header)
            # TODO: payload > 255?
            header.append(len(self.payload))

            # ID length (byte 3 of header)
            if self.identifier != None:
                header.append(len(self.identifier))

            # Record type (byte 4ff of header)
            header.extend(self.record_type)

            # ID
            if self.identifier != None:
                header.extend(self.identifier)

            return header + self.payload

    class NdefTextRecord(NdefRecord):
        # Call with text and ISO/IANA language code
        def __init__(self, text, language='en'):
            self.tnf = NdefRecord.TNF_WELL_KNOWN
            self.record_type = [NdefRecord.NDEF_TYPE_TEXT]

            lang_list = map(ord, language)
            text_list = map(ord, text)

            # Text Record Content: Status byte, ISO/IANA language code, text
            # See NDEF 1.0: 3.2.1
            self.payload = [len(lang_list)] + lang_list + text_list

    class NdefUriRecord(NdefRecord):
        def __init__(self, uri, uri_prefix=NdefRecord.NDEF_URIPREFIX_NONE):
            self.tnf = NdefRecord.TNF_WELL_KNOWN
            self.record_type = [NdefRecord.NDEF_TYPE_URI]

            uri_list = map(ord, uri)

            # Text Record Content: URI prefix, URI
            # See NDEF 1.0: 3.2.2
            self.payload = [uri_prefix] + uri_list

    class NdefMediaRecord(NdefRecord):
        def __init__(self, mime_type, data):
            self.tnf = NdefRecord.TNF_MIME_MEDIA

            self.record_type = map(ord, mime_type)
            if type(data) == str:
                self.payload = map(ord, data)
            else:
                self.payload = data

    class ExampleNdef:
        HOST = "localhost"
        PORT = 4223
        UID = "hjw" # Change to your UID

        state_queue = Queue()
        tag_type = None
        tag_size = None

        def __init__(self, tag_type, tag_size=512):
            self.tag_type = tag_type
            self.tag_size = tag_size
            self.ipcon = IPConnection() # Create IP connection
            self.nfc = NFCRFID(self.UID, self.ipcon) # Create device object

            self.ipcon.connect(self.HOST, self.PORT) # Connect to brickd

            self.nfc.register_callback(self.nfc.CALLBACK_STATE_CHANGED, self.state_changed)

        def write_message(self):
            chunks = self.message.get_raw_data_in_chunks()
            print("Trying to write the follwing data to the tag:")
            pprint(chunks)

            self.nfc.request_tag_id(self.tag_type)
            state = self.state_queue.get()
            if state != self.nfc.STATE_REQUEST_TAG_ID:
                return -1

            state = self.state_queue.get()
            if state != self.nfc.STATE_REQUEST_TAG_ID_READY:
                return -2

            # NFC Forum Type 1 start page is 1 (start of capability container)
            # NFC Forum Type 2 start page is 3 (start of capability container)
            if self.tag_type == NFCRFID.TAG_TYPE_TYPE1:
                current_page = 1
            else:
                current_page = 3

            for chunk in chunks:
                self.nfc.write_page(current_page, chunk)
                state = self.state_queue.get()
                if state != self.nfc.STATE_WRITE_PAGE:
                    return -3

                state = self.state_queue.get()
                if state != self.nfc.STATE_WRITE_PAGE_READY:
                    return -4

                # NFC Forum Type 1 has 2 pages per chunk (16 byte)
                # NFC Forum Type 2 has 4 pages per chunk (16 byte)
                if self.tag_type == NFCRFID.TAG_TYPE_TYPE1 :
                    current_page += 2
                else:
                    current_page += 4

            return 0

        def state_changed(self, state, idle):
            self.state_queue.put(state)

        def make_message_small(self):
            self.message = NdefMessage(self.tag_type)

            # Capabilities:
            # Version 1.0               (0x10)
            # Tag size bytes            (given by self.tag_size)
            # Read/write access for all (0x00)
            self.message.set_capability_container(0x10, self.tag_size, 0x00)

            record = NdefUriRecord('tinkerforge.com', NdefRecord.NDEF_URIPREFIX_HTTP_WWWDOT)
            self.message.add_record(record)

        def make_message_large(self):
            self.message = NdefMessage(self.tag_type)

            # Capabilities:
            # Version 1.0               (0x10)
            # Tag size bytes            (given by self.tag_size)
            # Read/write access for all (0x00)
            self.message.set_capability_container(0x10, self.tag_size, 0x00)

            rec1 = NdefTextRecord('Hello World', 'en')
            self.message.add_record(rec1)
            rec2 = NdefTextRecord('Hallo Welt', 'de')
            self.message.add_record(rec2)
            rec3 = NdefUriRecord('tinkerforge.com', NdefRecord.NDEF_URIPREFIX_HTTP_WWWDOT)
            self.message.add_record(rec3)
            text = '<html><head><title>Hello</title></head><body>World!</body></html>'
            rec4 = NdefMediaRecord('text/html', text)
            self.message.add_record(rec4)

            # To test an "image/png" you can can download the file from:
            # http://download.tinkerforge.com/_stuff/tf_16x16.png
            if os.path.isfile('tf_16x16.png'):
                logo = file('tf_16x16.png').read()
                rec5 = NdefMediaRecord('image/png', map(ord, logo))
                self.message.add_record(rec5)

    if __name__ == '__main__':
        example = ExampleNdef(tag_type=NFCRFID.TAG_TYPE_TYPE2, tag_size=888)
    #    example.make_message_large() # Writes different texts, URI, html site and image
        example.make_message_small() # Writes simple URI record
        ret = example.write_message()
        if ret < 0:
            print('Could not write NDEF Message: ' + str(ret))
        else:
            print('NDEF Message written successfully')

## API

Generally, every method of the Python bindings can throw an `tinkerforge.ip_connection.Error` exception that has a `value` and a `description` property. `value` can have different values:

- Error.TIMEOUT = -1
- Error.ALREADY_CONNECTED = -7
- Error.NOT_CONNECTED = -8
- Error.INVALID_PARAMETER = -9
- Error.NOT_SUPPORTED = -10
- Error.UNKNOWN_ERROR_CODE = -11

All methods listed below are thread-safe.

### Basic Functions

`NFCRFID`(uid, ipcon)

  Parameters:

  - uid -- string
  - ipcon -- IPConnection

  Creates an object with the unique device ID `uid`:

      nfc_rfid = NFCRFID("YOUR_DEVICE_UID", ipcon)

  This object can then be used after the IP Connection is connected (see examples above).

`NFCRFID.``request_tag_id`(tag_type)

  Parameters: | tag_type -- int
  Return type: | None

  To read or write a tag that is in proximity of the NFC/RFID Bricklet you first have to call this function with the expected tag type as parameter. It is no problem if you don't know the tag type. You can cycle through the available tag types until the tag gives an answer to the request.

  Current the following tag types are supported:

  - Mifare Classic (`tag_type` = 0)
  - NFC Forum Type 1 (`tag_type` = 1)
  - NFC Forum Type 2 (`tag_type` = 2)

  After you call `request_tag_id()` the NFC/RFID Bricklet will try to read the tag ID from the tag. After this process is done the state will change. You can either register the `CALLBACK_STATE_CHANGED` callback or you can poll `get_state()` to find out about the state change.

  If the state changes to RequestTagIDError it means that either there was no tag present or that the tag is of an incompatible type. If the state changes to RequestTagIDReady it means that a compatible tag was found and that the tag ID could be read out. You can now get the tag ID by calling `get_tag_id()`.

  If two tags are in the proximity of the NFC/RFID Bricklet, this function will cycle through the tags. To select a specific tag you have to call `request_tag_id()` until the correct tag id is found.

  In case of any Error state the selection is lost and you have to start again by calling `request_tag_id()`.

  The following constants are available for this function:

  - NFCRFID.TAG_TYPE_MIFARE_CLASSIC = 0
  - NFCRFID.TAG_TYPE_TYPE1 = 1
  - NFCRFID.TAG_TYPE_TYPE2 = 2

`NFCRFID.``get_tag_id`()

  Return type: | (int, int, [int, int, int, int, int, int, int])

  Returns the tag type, tag ID and the length of the tag ID (4 or 7 bytes are possible length). This function can only be called if the NFC/RFID is currently in one of the Ready states. The returned ID is the ID that was saved through the last call of `request_tag_id()`.

  To get the tag ID of a tag the approach is as follows:

  1. Call `request_tag_id()`
  2. Wait for state to change to RequestTagIDReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)
  3. Call `get_tag_id()`

  The following constants are available for this function:

  - NFCRFID.TAG_TYPE_MIFARE_CLASSIC = 0
  - NFCRFID.TAG_TYPE_TYPE1 = 1
  - NFCRFID.TAG_TYPE_TYPE2 = 2

  The returned namedtuple has the variables `tag_type`, `tid_length` and `tid`.

`NFCRFID.``get_state`()

  Return type: | (int, bool)

  Returns the current state of the NFC/RFID Bricklet.

  On startup the Bricklet will be in the Initialization state. The initialization will only take about 20ms. After that it changes to Idle.

  The functions of this Bricklet can be called in the Idle state and all of the Ready and Error states.

  Example: If you call `request_page()`, the state will change to RequestPage until the reading of the page is finished. Then it will change to either RequestPageReady if it worked or to RequestPageError if it didn't. If the request worked you can get the page by calling `get_page()`.

  The same approach is used analogously for the other API functions.

  Possible states are:

  - Initialization = 0
  - Idle = 128
  - Error = 192
  - RequestTagID = 2
  - RequestTagIDReady = 130
  - RequestTagIDError = 194
  - AuthenticatingMifareClassicPage = 3
  - AuthenticatingMifareClassicPageReady = 131
  - AuthenticatingMifareClassicPageError = 195
  - WritePage = 4
  - WritePageReady = 132
  - WritePageError = 196
  - RequestPage = 5
  - RequestPageReady = 133
  - RequestPageError = 197

  The following constants are available for this function:

  - NFCRFID.STATE_INITIALIZATION = 0
  - NFCRFID.STATE_IDLE = 128
  - NFCRFID.STATE_ERROR = 192
  - NFCRFID.STATE_REQUEST_TAG_ID = 2
  - NFCRFID.STATE_REQUEST_TAG_ID_READY = 130
  - NFCRFID.STATE_REQUEST_TAG_ID_ERROR = 194
  - NFCRFID.STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE = 3
  - NFCRFID.STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_READY = 131
  - NFCRFID.STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_ERROR = 195
  - NFCRFID.STATE_WRITE_PAGE = 4
  - NFCRFID.STATE_WRITE_PAGE_READY = 132
  - NFCRFID.STATE_WRITE_PAGE_ERROR = 196
  - NFCRFID.STATE_REQUEST_PAGE = 5
  - NFCRFID.STATE_REQUEST_PAGE_READY = 133
  - NFCRFID.STATE_REQUEST_PAGE_ERROR = 197

  The returned namedtuple has the variables `state` and `idle`.

`NFCRFID.``authenticate_mifare_classic_page`(page, key_number, key)

  Parameters:

  - page -- int
  - key_number -- int
  - key -- [int, int, int, int, int, int]

  Return type: | None

  Mifare Classic tags use authentication. If you want to read from or write to a Mifare Classic page you have to authenticate it beforehand. Each page can be authenticated with two keys: A (`key_number` = 0) and B (`key_number` = 1). A new Mifare Classic tag that has not yet been written to can can be accessed with key A and the default key `[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]`.

  The approach to read or write a Mifare Classic page is as follows:

  1. Call `request_tag_id()`
  2. Wait for state to change to RequestTagIDReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)
  3. If looking for a specific tag then call `get_tag_id()` and check if the expected tag was found, if it was not found got back to step 1
  4. Call `authenticate_mifare_classic_page()` with page and key for the page
  5. Wait for state to change to AuthenticatingMifareClassicPageReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)
  6. Call `request_page()` or `write_page()` to read/write page

  The following constants are available for this function:

  - NFCRFID.KEY_A = 0
  - NFCRFID.KEY_B = 1

`NFCRFID.``write_page`(page, data)

  Parameters:

  - page -- int
  - data -- [int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int]

  Return type: | None

  Writes 16 bytes starting from the given page. How many pages are written depends on the tag type. The page sizes are as follows:

  - Mifare Classic page size: 16 byte (one page is written)
  - NFC Forum Type 1 page size: 8 byte (two pages are written)
  - NFC Forum Type 2 page size: 4 byte (four pages are written)

  The general approach for writing to a tag is as follows:

  1. Call `request_tag_id()`
  2. Wait for state to change to RequestTagIDReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)
  3. If looking for a specific tag then call `get_tag_id()` and check if the expected tag was found, if it was not found got back to step 1
  4. Call `write_page()` with page number and data
  5. Wait for state to change to WritePageReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)

  If you use a Mifare Classic tag you have to authenticate a page before you can write to it. See `authenticate_mifare_classic_page()`.

`NFCRFID.``request_page`(page)

  Parameters: | page -- int
  Return type: | None

  Reads 16 bytes starting from the given page and stores them into a buffer. The buffer can then be read out with `get_page()`. How many pages are read depends on the tag type. The page sizes are as follows:

  - Mifare Classic page size: 16 byte (one page is read)
  - NFC Forum Type 1 page size: 8 byte (two pages are read)
  - NFC Forum Type 2 page size: 4 byte (four pages are read)

  The general approach for reading a tag is as follows:

  1. Call `request_tag_id()`
  2. Wait for state to change to RequestTagIDReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)
  3. If looking for a specific tag then call `get_tag_id()` and check if the expected tag was found, if it was not found got back to step 1
  4. Call `request_page()` with page number
  5. Wait for state to change to RequestPageReady (see `get_state()` or `CALLBACK_STATE_CHANGED`)
  6. Call `get_page()` to retrieve the page from the buffer

  If you use a Mifare Classic tag you have to authenticate a page before you can read it. See `authenticate_mifare_classic_page()`.

`NFCRFID.``get_page`()

  Return type: | [int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int]

  Returns 16 bytes of data from an internal buffer. To fill the buffer with specific pages you have to call `request_page()` beforehand.

### Advanced Functions

`NFCRFID.``get_api_version`()

  Return type: | [int, int, int]

  Returns the version of the API definition (major, minor, revision) implemented by this API bindings. This is neither the release version of this API bindings nor does it tell you anything about the represented Brick or Bricklet.

`NFCRFID.``get_response_expected`(function_id)

  Parameters: | function_id -- int
  Return type: | bool

  Returns the response expected flag for the function specified by the function ID parameter. It is true if the function is expected to send a response, false otherwise.

  For getter functions this is enabled by default and cannot be disabled, because those functions will always send a response. For callback configuration functions it is enabled by default too, but can be disabled by `set_response_expected()`. For setter functions it is disabled by default and can be enabled.

  Enabling the response expected flag for a setter function allows to detect timeouts and other error conditions calls of this setter as well. The device will then send a response for this purpose. If this flag is disabled for a setter function then no response is send and errors are silently ignored, because they cannot be detected.

  See `set_response_expected()` for the list of function ID constants available for this function.

`NFCRFID.``set_response_expected`(function_id, response_expected)

  Parameters:

  - function_id -- int
  - response_expected -- bool

  Return type: | None

  Changes the response expected flag of the function specified by the function ID parameter. This flag can only be changed for setter (default value: false) and callback configuration functions (default value: true). For getter functions it is always enabled and callbacks it is always disabled.

  Enabling the response expected flag for a setter function allows to detect timeouts and other error conditions calls of this setter as well. The device will then send a response for this purpose. If this flag is disabled for a setter function then no response is send and errors are silently ignored, because they cannot be detected.

  The following function ID constants are available for this function:

  - NFCRFID.FUNCTION_REQUEST_TAG_ID = 1
  - NFCRFID.FUNCTION_AUTHENTICATE_MIFARE_CLASSIC_PAGE = 4
  - NFCRFID.FUNCTION_WRITE_PAGE = 5
  - NFCRFID.FUNCTION_REQUEST_PAGE = 6

`NFCRFID.``set_response_expected_all`(response_expected)

  Parameters: | response_expected -- bool
  Return type: | None

  Changes the response expected flag for all setter and callback configuration functions of this device at once.

`NFCRFID.``get_identity`()

  Return type: | (str, str, chr, [int, int, int], [int, int, int], int)

  Returns the UID, the UID where the Bricklet is connected to, the position, the hardware and firmware version as well as the device identifier.

  The position can be 'a', 'b', 'c' or 'd'.

  The device identifier numbers can be found here. There is also a constant for the device identifier of this Bricklet.

  The returned namedtuple has the variables `uid`, `connected_uid`, `position`, `hardware_version`, `firmware_version` and `device_identifier`.

### Callback Configuration Functions

`NFCRFID.``register_callback`(id, callback)

  Parameters:

  - id -- int
  - callback -- callable

  Return type: | None

  Registers a callback with ID id to the function callback. The available IDs with corresponding function signatures are listed below.

### Callbacks

Callbacks can be registered to receive time critical or recurring data from the device. The registration is done with the `register_callback()` function of the device object. The first parameter is the callback ID and the second parameter the callback function:

    def my_callback(param):
        print(param)

    nfc_rfid.register_callback(NFCRFID.CALLBACK_EXAMPLE, my_callback)

The available constants with inherent number and type of parameters are described below.

Note

Using callbacks for recurring events is always preferred compared to using getters. It will use less USB bandwidth and the latency will be a lot better, since there is no round trip time.

`NFCRFID.``CALLBACK_STATE_CHANGED`

  Parameters:

  - state -- int
  - idle -- bool

  This callback is called if the state of the NFC/RFID Bricklet changes. See `get_state()` for more information about the possible states.

  The following constants are available for this function:

  - NFCRFID.STATE_INITIALIZATION = 0
  - NFCRFID.STATE_IDLE = 128
  - NFCRFID.STATE_ERROR = 192
  - NFCRFID.STATE_REQUEST_TAG_ID = 2
  - NFCRFID.STATE_REQUEST_TAG_ID_READY = 130
  - NFCRFID.STATE_REQUEST_TAG_ID_ERROR = 194
  - NFCRFID.STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE = 3
  - NFCRFID.STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_READY = 131
  - NFCRFID.STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_ERROR = 195
  - NFCRFID.STATE_WRITE_PAGE = 4
  - NFCRFID.STATE_WRITE_PAGE_READY = 132
  - NFCRFID.STATE_WRITE_PAGE_ERROR = 196
  - NFCRFID.STATE_REQUEST_PAGE = 5
  - NFCRFID.STATE_REQUEST_PAGE_READY = 133
  - NFCRFID.STATE_REQUEST_PAGE_ERROR = 197

### Constants

`NFCRFID.``DEVICE_IDENTIFIER`

  This constant is used to identify a NFC/RFID Bricklet.

  The `get_identity()` function and the `CALLBACK_ENUMERATE` callback of the IP Connection have a `device_identifier` parameter to specify the Brick's or Bricklet's type.

The content of this page is licensed under Creative Commons Attribution 3.0 Unported License.