Enable NFC for Linux and pcscd on Dell E7470 (and others) with ControlVault2
Jacek Kowalski
2020-07-24 eb0c004c4fcb4cc7811917de0d1ca91c5c6ade7c
ControlVault 3 - initial support
1 files modified
5 files added
1 files deleted
1 files renamed
992 ■■■■ changed files
README.md 16 ●●●●● patch | view | raw | blame | history
bcm20795.py 189 ●●●●● patch | view | raw | blame | history
cv2.py 46 ●●●●● patch | view | raw | blame | history
cv3.py 43 ●●●●● patch | view | raw | blame | history
cvcomm.py 93 ●●●●● patch | view | raw | blame | history
nfc.py 76 ●●●●● patch | view | raw | blame | history
traffic_cv2.txt patch | view | raw | blame | history
traffic_cv3.txt 529 ●●●●● patch | view | raw | blame | history
README.md
@@ -1,4 +1,4 @@
# Enable NFC on Dell ControlVault2
# Enable NFC on Dell ControlVault2 and ControlVault3
## Introduction
@@ -14,7 +14,7 @@
1. Clone the repository.
1. Install python3 and python3-usb.
1. Run: `./bcm20795.py on` (use `sudo` if necessary).
1. Run: `./nfc.py on` (use `sudo` if necessary).
1. Run `pcsc_scan` or whatever you prefer.
1. Enjoy!
@@ -24,8 +24,9 @@
Currently only the following devices were tested and are known to work:
* `0a5c:5832`
* `0a5c:5834`
* `0a5c:5832` (ControlVault 2),
* `0a5c:5833` (ControlVault 3),
* `0a5c:5834` (ControlVault 2).
Firmware update (done during driver installation on Windows) may be required.
@@ -34,19 +35,20 @@
* Dell Latitude 5480
* Dell Latitude 5491
* Dell Latitude 7280
* Dell Latitude 7400
* Dell Latitude E5270
* Dell Latitude E7470
* Dell Latitude E7490
## How it works?
Python script sends the same sequence of commands the Windows driver does. The traffic was sniffed using USBPcap and Wireshark (kudos to [~jkramarz](https://github.com/jkramarz) for that).
Python script sends the same sequence of commands the Windows driver does. The traffic was sniffed using USBPcap and Wireshark (kudos to [~jkramarz](https://github.com/jkramarz) and [~lgarbarini](https://github.com/lgarbarini) and for that).
The data is sent as-is and responses are read, but no error-checking is done.
The semi-annotated traffic dump is available as [traffic.txt](traffic.txt) - feel free to decode it further!
The semi-annotated traffic dumps are available as [traffic_cv2.txt](traffic_cv2.txt) and [traffic_cv3.txt](traffic_cv3.txt) - feel free to decode it further!
The communication protocol is based on NCI (NFC Controller Interface). Unfortunately the specs are not freely available and some proprietary extensions are used. libnfc-nci and kernel sources were used to decode some structs.
The communication protocol is based on NCI (NFC Controller Interface). Unfortunately the specs are not freely available and some proprietary extensions are used. libnfc-nci and kernel sources were used to decode vendor-independent structs.
## References
bcm20795.py
File was deleted
cv2.py
New file
@@ -0,0 +1,46 @@
import cvcomm
class ControlVault2:
    NAME = 'Broadcom ControlVault 2'
    turn_on_seq1 = [
        "10 2f 04 00",
        "10 2f 1d 03 05 90 65",
        "10 2f 2d 00",
        "10 2f 11 01 f7",
        "01 27 fc 0c 08 00 01 00 01 00 00 00 00 00 00 00",
    ]
    turn_on_seq2 = [
        "10 20 00 01 01",
        "10 20 01 02 01 00",
        "10 20 02 67 01 b9 64 01 00 ff ff 50 00 8b 13 00 10 00 06 00 00 00 00 00 ff 00 00 00 ff 00 00 04 00 00 00 00 03 00 00 00 03 00 0c 00 00 0d 00 00 00 00 00 00 00 00 00 00 33 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 02 53 3b 0f 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00",
        "10 20 02 90 0a ca 05 00 00 00 00 2c 80 01 01 b0 05 01 03 03 03 08 b5 03 01 03 ff c9 0d 24 00 00 00 01 00 bb 00 e4 00 0a 01 02 d6 0d 01 02 00 00 00 00 00 01 00 01 5a 00 8a b2 02 e8 03 c8 1e 06 1f 00 0a 00 30 00 04 24 00 1c 00 75 00 77 00 76 00 1c 00 03 00 0a 00 56 01 00 00 40 04 d7 01 07 dd 32 00 00 00 29 16 08 08 06 04 00 00 00 1f 27 0a 6d 20 00 52 20 00 00 00 01 85 00 00 32 1f 00 00 02 0a 16 00 02 55 55 55 55 55 55 55 55 55 55 55 55 55 1e",
        "10 20 02 06 01 b7 03 02 00 01",
        "10 2f 06 01 01",
        "10 20 02 0e 02 51 08 20 79 ff ff ff ff ff ff 58 01 07",
        "10 21 00 07 02 04 03 02 05 03 03",
        "10 20 02 17 01 29 14 46 66 6d 01 01 11 02 02 07 ff 03 02 00 13 04 01 64 07 01 03",
        "10 20 02 1a 02 61 14 46 66 6d 01 01 11 02 02 07 ff 03 02 00 13 04 01 64 07 01 03 60 01 07",
        "10 20 02 10 05 30 01 04 31 01 00 32 01 40 38 01 00 50 01 02",
        "10 20 02 05 01 00 02 fa 00",
        "10 20 02 0b 01 c2 08 01 08 00 04 80 c3 c9 01",
        "10 21 03 0d 06 00 01 01 01 02 01 80 01 82 01 06 01",
    ]
    def __init__(self, device):
        self.device = device
        self.communicator = cvcomm.ControlVaultCommunicator(device)
    def turn_on(self):
        self.communicator.ctrl_transfer(0x41, 0, 1, 3)
        self.communicator.talk(self.turn_on_seq1)
        self.communicator.ctrl_transfer(0x41, 1, 0, 3)
        self.communicator.talk(self.turn_on_seq2)
        self.communicator.ctrl_transfer(0x41, 1, 1, 3)
    def turn_off(self):
        self.communicator.ctrl_transfer(0x41, 1, 0, 3)
        self.communicator.ctrl_transfer(0x41, 0, 0, 3)
    def reset(self):
        self.device.reset()
cv3.py
New file
@@ -0,0 +1,43 @@
import cvcomm
class ControlVault3:
    NAME = 'Broadcom ControlVault 3'
    turn_on_seq1 = [
        "20 00 01 00",
    ]
    turn_on_seq2 = [
        "20 00 01 00",
        "20 01 00",
        "20 03 02 01 52",
        "20 02 1f 0a 21 01 00 28 01 00 30 01 04 31 01 03 54 01 06 5b 01 00 60 01 07 80 01 01 81 01 01 82 01 0e",
        "21 00 10 05 04 03 02 05 03 03 01 01 01 02 01 01 03 01 01",
        "21 01 07 00 01 01 03 00 01 05",
        "20 02 09 01 b9 06 01 00 00 0b 00 00",
        "20 02 c7 11 18 01 02 2a 01 32 80 01 00 c2 02 03 02 c4 02 00 13 ca 05 00 0f 0d 03 08 cb 01 00 d6 0b 01 01 00 01 12 00 01 00 01 00 01 d8 01 01 de 04 01 00 00 00 e0 07 00 60 93 1c 63 3e 0a e1 02 79 07 e2 2a 48 07 0c 10 00 31 39 39 39 39 39 39 39 39 39 39 41 39 90 90 90 90 3f 90 90 90 88 8a 8c 94 94 28 04 07 00 00 00 00 00 00 00 00 e3 08 17 04 16 0d 10 0c 2b 0b e4 01 37 e5 1e e0 1e 02 12 00 0a 00 10 04 54 54 54 54 2b 52 50 53 4e 20 2d 18 0c 02 07 00 94 70 94 70 20 e6 2d 01 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 9e 58 4c 40 33 26 20 1e 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 5e 58 4c 40 33 2b 26 1e",
        "2f 1b 06 08 00 00 01 00 00",
        "20 02 2d 04 29 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64 2a 01 30 61 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64 62 01 30",
        "20 02 0e 04 18 01 01 32 01 40 50 01 02 00 02 2c 01",
        "21 03 0d 06 00 01 01 01 02 01 06 01 80 01 82 01",
    ]
    def __init__(self, device):
        self.device = device
        self.communicator = cvcomm.ControlVaultCommunicator(device)
    def turn_on(self):
        self.communicator.ctrl_transfer(0x41, 1, 0, 3)
        self.communicator.talk(turn_on_seq1)
        self.communicator.ctrl_transfer(0x41, 1, 1, 3)
        self.communicator.ctrl_transfer(0x41, 0, 0, 3)
        self.communicator.ctrl_transfer(0x41, 0, 1, 3)
        self.communicator.ctrl_transfer(0x41, 1, 0, 3)
        self.communicator.talk(turn_on_seq2)
        self.communicator.ctrl_transfer(0x41, 1, 1, 3)
    def turn_off(self):
        self.communicator.ctrl_transfer(0x41, 1, 0, 3)
        self.communicator.ctrl_transfer(0x41, 0, 0, 3)
    def reset(self):
        self.device.reset()
cvcomm.py
New file
@@ -0,0 +1,93 @@
import logging
import math
import struct
import usb.util
def to_hex(val):
    return ' '.join([bytes([i]).hex() for i in val])
class ControlVaultCommunicator:
    def __init__(self, device, spi_master=0x01, spi_slave=0x00, spi_crc=0x00):
        self.logger = logging.getLogger(__name__)
        self.device = device
        self.bulk_in, self.bulk_out = self._find_endpoints()
        self.spi_master = spi_master
        self.spi_slave = spi_slave
        self.spi_crc = spi_crc
        self.spi_slave_prefix = struct.pack('>BB', self.spi_slave, self.spi_crc)
    def ctrl_transfer(self, *args, **kwargs):
        self.logger.debug('Control: {} {}'.format(args, kwargs))
        return self.device.ctrl_transfer(*args, **kwargs)
    def write(self, *args, **kwargs):
        return self.bulk_out.write(*args, **kwargs)
    def read(self, *args, **kwargs):
        return self.bulk_in.read(*args, **kwargs)
    def send_packet(self, payload):
        length = len(payload)
        packet = struct.pack('>BBH', self.spi_master, self.spi_crc, length) + payload
        self.logger.debug('Put: {}'.format(to_hex(packet)))
        self.write(packet)
    def recv_packet(self):
        packet = self.read(64, timeout=5000).tobytes()
        tag = packet[0:2]
        if tag != self.spi_slave_prefix:
            raise Exception('Unknown tag: {}'.format(tag.hex()))
        length = packet[2:4]
        length = struct.unpack('>H', length)[0]
        for i in range(0, math.ceil(length/64) - 1):
            packet += self.read(64).tobytes()
        self.logger.debug('Got: {}'.format(to_hex(packet)))
        return packet[4:]
    def talk(self, exchange):
        for packet in exchange:
            self.send_packet(bytes.fromhex(packet))
            data = self.recv_packet()
            if data[1] == 0x61:
                packet = self.recv_packet()
    def _find_endpoints(self):
        self.logger.debug('Enumerating interfaces...')
        configuration = self.device.get_active_configuration()
        bcm_interface = None
        for interface in configuration:
            if interface.bInterfaceClass == 0xff and interface.iInterface == 0x08:
                if bcm_interface is not None:
                    raise Exception('More than one vendor-specific interface found!')
                bcm_interface = interface
        if bcm_interface is None:
            raise Exception('Cannot find vendor-specific interface')
        self.logger.debug('Interface found: {}'.format(bcm_interface._str()))
        self.logger.debug('Enumerating endpoints...')
        bulk_in = None
        bulk_out = None
        for endpoint in bcm_interface:
            if endpoint.bmAttributes & usb.util._ENDPOINT_TRANSFER_TYPE_MASK == usb.util.ENDPOINT_TYPE_BULK:
                if endpoint.bEndpointAddress & usb.util._ENDPOINT_DIR_MASK == usb.util.ENDPOINT_IN:
                    if bulk_in is not None:
                        raise Exception('More than one BULK IN endpoint found!')
                    bulk_in = endpoint
                    self.logger.debug('BULK IN found: {}'.format(bulk_in._str()))
                if endpoint.bEndpointAddress & usb.util._ENDPOINT_DIR_MASK == usb.util.ENDPOINT_OUT:
                    if bulk_out is not None:
                        raise Exception('More than one BULK OUT endpoint found!')
                    bulk_out = endpoint
                    self.logger.debug('BULK OUT found: {}'.format(bulk_out._str()))
        if bulk_in is None:
            raise Exception('BULK IN endpoint not found!')
        if bulk_out is None:
            raise Exception('BULK OUT endpoint not found!')
        self.logger.debug('Endpoint discovery successful.')
        return bulk_in, bulk_out
nfc.py
New file
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
import logging
import sys
import usb.core
class UsbDeviceMatcher:
    def __init__(self, properties, handler):
        self.properties = properties
        self.handler = handler
    def matches(self, candidate):
        for prop, value in self.properties.items():
            if prop not in candidate.__dict__ or candidate.__dict__[prop] != value:
                return False
        return True
class UsbDeviceFinder:
    SUPPORTED_DEVICES = [
        UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5832}, lambda device: __import__('cv2').ControlVault2(device)),
        UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5833}, lambda device: __import__('cv3').ControlVault3(device)),
        UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5834}, lambda device: __import__('cv2').ControlVault2(device)),
    ]
    @classmethod
    def _dev_matcher(cls, device):
        for matcher in cls.SUPPORTED_DEVICES:
            if matcher.matches(device):
                return True
        return False
    @classmethod
    def _cls_matcher(cls, device):
        for matcher in cls.SUPPORTED_DEVICES:
            if matcher.matches(device):
                return matcher.handler(device)
        raise Exception('Cannot find handler for device {:04X}:{:04X}'.format(dev.idVendor, dev.idProduct))
    @classmethod
    def find(cls):
        logger = logging.getLogger(__name__)
        logger.info('Looking for supported device...')
        device = usb.core.find(custom_match=cls._dev_matcher)
        if device is None:
            raise Exception('Cannot find BCM device - check list of supported devices')
        logger.info('Found {:04X}:{:04X}'.format(device.idVendor, device.idProduct))
        handler = cls._cls_matcher(device)
        logger.info('Handler {} ({})'.format(handler.__class__.__name__, handler.NAME))
        return handler
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print('Usage: {} [on|off|reset]'.format(sys.argv[0]))
        sys.exit(2)
    logging.basicConfig(level=logging.DEBUG)
    logger = logging.getLogger(__name__)
    handler = UsbDeviceFinder.find()
    if sys.argv[1] == 'on':
        logger.info('Turning NFC on...')
        handler.turn_on()
        logger.info('NFC should be turned on now!')
    elif sys.argv[1] == 'off':
        logger.info('Turning NFC off...')
        handler.turn_off()
        logger.info('NFC should be turned off now!')
    elif sys.argv[1] == 'reset':
        logger.info('Resetting device...')
        handler.reset()
        logger.info('NFC device has been reset!')
    else:
        raise Exception('Unknown option: {}'.format(sys.argv[1]))
traffic_cv2.txt
traffic_cv3.txt
New file
@@ -0,0 +1,529 @@
idVendor 0x0A5C
idProduct 0x5843
Interface 4 - Application-Specific
EP 1 IN
EP 1 OUT
EP 5 IN
Interface 5 - Smart Card
EP 2 IN
EP 2 OUT
EP 6 IN
Interface 6 - Smart Card
EP 3 IN
EP 3 OUT
EP 7 IN
Interface 7 - Vendor Specific
EP 4 IN
EP 4 OUT
EP 8 IN
Legend:
>  - New outgoing message (beginning)
>> - Message continuation (division for readability)
<  - New incoming message (beginning)
<< - Message continuation (division for readability)
# CTRL - Control endpoint communication (bmRequestType, bRequest, wValue, wIndex)
Communication via Endpoint 4
##########
TURNING ON
##########
# CTRL 0x41 0x01 0x0000 0x0003
>  01 00 00 04
   01 = SPI_MASTER
      00 = NO_CRC
         00 04 = size
>> 20 00 01 00
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      00 = NCI_MSG_CORE_RESET
         01 = NCI_CORE_PARAM_SIZE_RESET
            00 = NCI_RESET_TYPE_KEEP_CFG
<  00 00 00 06
   00 = SPI_SLAVE
      00 = NO_CRC
         00 06 = size
<< 40 00 03 00 10 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      00 = NCI_MSG_CORE_RESET
         03 = NCI_CORE_PARAM_SIZE_RESET_RSP
            00 = NCI_STATUS_OK
               10 = NCI_VERSION (1.0)
                  00 = NCI_RESET_STATUS_KEPT_CFG
# CTRL 0x41 0x01 0x0001 0x0003
# CTRL 0x41 0x00 0x0000 0x0003
# CTRL 0x41 0x00 0x0001 0x0003
# CTRL 0x41 0x01 0x0000 0x0003
>  01 00 00 04
   01 = SPI_MASTER
      00 = NO_CRC
         00 04 = size
>> 20 00 01 00
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      00 = NCI_MSG_CORE_RESET
         01 = NCI_CORE_PARAM_SIZE_RESET
            00 = NCI_RESET_TYPE_KEEP_CFG
<  00 00 00 06
   00 = SPI_SLAVE
      00 = NO_CRC
         00 06 = size
<< 40 00 03 00 11 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      00 = NCI_MSG_CORE_RESET
         03 = NCI_CORE_PARAM_SIZE_RESET_RSP
            00 = NCI_STATUS_OK
               11 = NCI_VERSION (1.1)
                  00 = NCI_RESET_STATUS_KEPT_CFG
>  01 00 00 03
   01 = SPI_MASTER
      00 = NO_CRC
         00 03 = size
>> 20 01 00
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      01 = NCI_MSG_CORE_INIT
         00 = size
<  00 00 00 1a
   00 = SPI_SLAVE
      00 = NO_CRC
         00 1a = size
<< 40 01 17 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      01 = NCI_MSG_CORE_INIT
         17 = size
            00 = NCI_STATUS_OK
<< 03 0e 02 01
   03 0e 02 01 NFCC_FEATURES
   02 = multiple NFCEEs
   01 = RF_DISCOVER_CMD supported
      08 = AID-based routing supported
      04 = Protocol-based routing supported
      02 = Technology-based routing supported
         02 = Switched-off state supported
            01 = Proprietary parameters
<< 06 00 01 02 03 81 83
   06 = num_of_ifaces (6)
      00 = NCI_INTERFACE_EE_DIRECT_RF
         01 = NCI_INTERFACE_FRAME
            02 = NCI_INTERFACE_ISO_DEP
               03 = NCI_INTERFACE_NFC_DEP
                  81 = Proprietary Interface (81)
                     83 = Proprietary Interface (83)
<< 08 00 04 ff 0f 00 2e 04 10 2b 41
   08 = num_of_conns_max (8)
      00 04 = num_of_routes_max
            ff = size_control_payload_max
               0f 00 = size_large_params_max
                     2e = manufacturer_id
                        04 10 2b 41 = manufacturer_specific
>  01 00 00 05
   01 = SPI_MASTER
      00 = NO_CRC
         00 05 = size
>> 20 03 02 01 52
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      03 = NCI_MSG_CORE_GET_CONFIG
         02 = num_of_params (2)
            01 = CON_DEVICES_LIMIT
               52 = LF_T3T_MAX
<  00 00 00 08
   00 = SPI_SLAVE
      00 = NO_CRC
         00 08 = size
<< 40 03 05 00 01 52 01 10
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      03 = NCI_MSG_CORE_GET_CONFIG
         ???
>  01 00 00 22
   01 = SPI_MASTER
      00 = NO_CRC
         00 22 = size
>> 20 02 1f 0a
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         1f = size
            0a = num_of_params (10)
>> 21 01 00
   21 = PI_BIT_RATE
      01 = size_of_param
         00 = 106 Kbit/s
>> 28 01 00
   28 = PN_NFC_DEP_SPEED
      01 = size_of_param
         00 = Highest Available Bitrate
>> 30 01 04
   30 = LA_BIT_FRAME_SDD
      01 = size_of_param
         04 = Bit Frame SDD value to be sent in Byte 1 of SENS_RES
>> 31 01 03
   31 = LA_PLATFORM_CONFIG
      01 = size_of_param
         03 = Platform Configuration value to be sent in Byte 2 of SENS_RES
>> 54 01 06
   54 = LF_CON_BITR_F
      01 = size_of_param
         02 = listen for 212 kbps
         04 = listen for 424 kbps
>> 5b 01 00
   5b = LI_BIT_RATE
      01 = size_of_param
         00 = 106 Kbit/s
>> 60 01 07
   60 = LN_WT
      01 = size_of_param
         07 = waiting time (7)
>> 80 01 01
   80 = RF_FIELD_INFO
      01 = size_of_param
         01 = RF_FIELD_INFO_NTF allowed
>> 81 01 01
   81 = RF_NFCEE_ACTION
      01 = size_of_param
         01 = send RF NFCEE Actions
>> 82 01 0e
   82 = NFCDEP_OP
      01 = size_of_param
         02 = ATTENTION only for error recovery
         04 = don't send msgs without Transport Data Bytes
         08 = chaining uses max number of Transport Data Bytes
<  00 00 00 05
   00 = SPI_SLAVE
      00 = NO_CRC
         00 05 = size
<< 40 02 02 00 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         02 = size
            00 = NCI_STATUS_OK
               00 = num_of_invalid_params (0)
>  01 00 00 13
   01 = SPI_MASTER
      00 = NO_CRC
         00 13 = size
>> 21 00 10 05
   21 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      00 = NCI_MSG_RF_DISCOVER_MAP
         10 = size (16)
            05 = num_mapping_configs
>> 04 03 02
   04 = NCI_PROTOCOL_ISO_DEP
      03 = NCI_INTERFACE_MODE_POLL_N_LISTEN
         02 = NCI_INTERFACE_ISO_DEP
>> 05 03 03
   05 = NCI_PROTOCOL_NFC_DEP
      03 = NCI_INTERFACE_MODE_POLL_N_LISTEN
         03 = NCI_INTERFACE_NFC_DEP
>> 01 01 01
   01 = PROTOCOL_T1T
      01 = NCI_INTERFACE_MODE_POLL
         01 = NCI_INTERFACE_FRAME
>> 02 01 01
   02 = PROTOCOL_T2T
      01 = NCI_INTERFACE_MODE_POLL
         01 = NCI_INTERFACE_FRAME
>> 03 01 01
   03 = PROTOCOL_T3T
      01 = NCI_INTERFACE_MODE_POLL
         01 = NCI_INTERFACE_FRAME
<  00 00 00 04
   00 = SPI_SLAVE
      00 = NO_CRC
         00 04 = size
<< 61 07 01 00
   61 = NCI_MTS_NTF | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      07 = NCI_MSG_RF_FIELD
         01 = size
            00 = No RF field
<  00 00 00 04
   00 = SPI_SLAVE
      00 = NO_CRC
         00 04 = size
<< 41 00 01 00
   41 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      00 = NCI_MSG_RF_DISCOVER_MAP
         01 = NCI_DISCOVER_PARAM_SIZE_RSP
            00 = NCI_STATUS_OK
>  01 00 00 0a
   01 = SPI_MASTER
      00 = NO_CRC
         00 0a = size
>> 21 01 07 00 01 01 03 00 01 05
   21 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      01 = NCI_MSG_RF_SET_ROUTING
         07 = size
            00 = last message
               01 = routing_entries (1)
                  01 = protocol-based routing
                     03 = length (3)
                        00 = DH NFCEE ID
                           01 = power state (1 - switched on)
                              05 = PROTOCOL_NFC_DEP
<  00 00 00 04
   00 = SPI_SLAVE
      00 = NO_CRC
         00 04 = size
<< 41 01 01 00
   41 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      01 = NCI_MSG_RF_SET_ROUTING
         01 = size
            00 = NCI_STATUS_OK
>  01 00 00 0c
   01 = SPI_MASTER
      00 = NO_CRC
         00 0c = size
>> 20 02 09 01
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         09 = size
            01 = num_of_params
>> b9 06 01 00 00 0b 00 00
   b9 = Proprietary parameter (b9)
      06 = size_of_param
<  00 00 00 05
   00 = SPI_SLAVE
      00 = NO_CRC
         00 05 = size
<< 40 02 02 00 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         02 = size
            00 = NCI_STATUS_OK
               00 = num_of_invalid_params (0)
>  01 00 00 ca
   01 = SPI_MASTER
      00 = NO_CRC
         00 ca = size
>> 20 02 c7 11
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         c7 = size
            11 = num_of_params (17)
>> 18 01 02
   18 = PF_BIT_RATE
      01 = size_of_param
         02 = 424 Kbit/s
>> 2a 01 32
   2a = PN_ATR_REQ_CONFIG
      01 = size_of_param
         30 = 0011b for LLCP
         02 = ?
>> 80 01 00
   80 = RF_FIELD_INFO
      01 = size_of_param
         00 = RF_FIELD_INFO_NTF not allowed
>> c2 02 03 02
   c2 = Proprietary parameter (c2)
      02 = size_of_param
>> c4 02 00 13
   c4 = Proprietary parameter (c4)
      02 = size_of_param
>> ca 05 00 0f 0d 03 08
   ca = Proprietary parameter (ca)
      05 = size_of_param
>> cb 01 00
   cb = Proprietary parameter (cb)
      01 = size_of_param
>> d6 0b 01 01 00 01 12 00 01 00 01 00 01
   d6 = Proprietary parameter (d6)
      0b = size_of_param
>> d8 01 01
   d8 = Proprietary parameter (d8)
      01 = size_of_param
>> de 04 01 00 00 00
   de = Proprietary parameter (de)
      04 = size_of_param
>> e0 07 00 60 93 1c 63 3e 0a
   e0 = Proprietary parameter (e0)
      07 = size_of_param
>> e1 02 79 07
   e1 = Proprietary parameter (e1)
      02 = size_of_param
>> e2 2a 48 07 0c 10 00 31 39 39 39 39 39 39 39 39 39 39 41 39 90 90 90 90 3f 90 90 90 88 8a 8c 94 94 28 04 07 00 00 00 00 00 00 00 00
   e2 = Proprietary parameter (e2)
      2a = size_of_param
>> e3 08 17 04 16 0d 10 0c 2b 0b
   e3 = Proprietary parameter (e3)
      08 = size_of_param
>> e4 01 37
   e4 = Proprietary parameter (e4)
      01 = size_of_param
>> e5 1e e0 1e 02 12 00 0a 00 10 04 54 54 54 54 2b 52 50 53 4e 20 2d 18 0c 02 07 00 94 70 94 70 20
   e5 = Proprietary parameter (e5)
      1e = size_of_param
>> e6 2d 01 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 9e 58 4c 40 33 26 20 1e 68 00 77 00 8b 00 a7 00 d6 00 22 01 c0 01 5e 58 4c 40 33 2b 26 1e
   e6 = Proprietary parameter (e6)
      2d = size_of_param
<  00 00 00 05
   00 = SPI_SLAVE
      00 = NO_CRC
         00 05 = size
<< 40 02 02 00 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         02 = size
            00 = NCI_STATUS_OK
               00 = num_of_invalid_params (0)
>  01 00 00 09
   01 = SPI_MASTER
      00 = NO_CRC
         00 09 = size
>> 2f 1b 06 08 00 00 01 00 00
   2f = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_PROP
      1b = Proprietary message (1b)
         06 = size
<  00 00 00 04
   00 = SPI_SLAVE
      00 = NO_CRC
         00 04 = size
<< 4f 1b 01 00
   4f = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_PROP
      1b = Proprietary message (1b)
         01 = size
>  01 00 00 30
   01 = SPI_MASTER
      00 = NO_CRC
         00 30 = size
>> 20 02 2d 04
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         2d = size
            04 = num_of_params (4)
>> 29 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64
   29 = PN_ATR_REQ_GEN_BYTES
      11 = size_of_param
         General Bytes for ATR_REQ
>> 2a 01 30
   2a = PN_ATR_REQ_CONFIG
      01 = size_of_param
         30 = 0011b for LLCP
>> 61 11 46 66 6d 01 01 11 02 02 03 80 03 02 00 01 04 01 64
   61 = LN_ATR_RES_GEN_BYTES
      11 = size_of_param
         General Bytes in ATR_RES
>> 62 01 30
   62 = LN_ATR_RES_CONFIG
      01 = size_of_param
         30 = 0011b for LLCP
<  00 00 00 05
   00 = SPI_SLAVE
      00 = NO_CRC
         00 05 = size
<< 40 02 02 00 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         02 = size
            00 = NCI_STATUS_OK
               00 = num_of_invalid_params (0)
>  01 00 00 11
   01 = SPI_MASTER
      00 = NO_CRC
         00 11 = size
>> 20 02 0e 04
   20 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         0e = size
            04 = num_of_params (4)
>> 18 01 01
   18 = PF_BIT_RATE
      01 = size_of_param
         01 = 212 Kbit/s
>> 32 01 40
   32 = LA_SEL_INFO
      01 = size_of_param
         40 = NFC-DEP
>> 50 01 02
   50 = LF_PROTOCOL_TYPE
      01 = size_of_param
         02 = NFC-DEP
>> 00 02 2c 01
   00 = TOTAL_DURATION
      02 = size_of_param
         2c 01 = 11 256 ms
<  00 00 00 05
   00 = SPI_SLAVE
      00 = NO_CRC
         00 05 = size
<< 40 02 02 00 00
   40 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_CORE
      02 = NCI_MSG_CORE_SET_CONFIG
         02 = size
            00 = NCI_STATUS_OK
               00 = num_of_invalid_params (0)
>  01 00 00 10
   01 = SPI_MASTER
      00 = NO_CRC
         00 10 = size
>> 21 03 0d 06
   21 = NCI_MTS_CMD | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      03 = NCI_MSG_RF_DISCOVER
         0d = size
            06 = num_of_configs (6)
>> 00 01
   00 = NFC_A_PASSIVE_POLL_MODE
      01 = every discovery period
>> 01 01
   01 = NFC_B_PASSIVE_POLL_MODE
      01 = every discovery period
>> 02 01
   02 = NFC_F_PASSIVE_POLL_MODE
      01 = every discovery period
>> 06 01
   06 = NFC_15693_PASSIVE_POLL_MODE
      01 = every discovery period
>> 80 01
   80 = NFC_A_PASSIVE_LISTEN_MODE
      01 = every discovery period
>> 82 01
   82 = NFC_F_PASSIVE_LISTEN_MODE
      01 = every discovery period
<  00 00 00 04
   00 = SPI_SLAVE
      00 = NO_CRC
         00 04 = size
<< 41 03 01 00
   41 = NCI_MTS_RSP | NCI_PBF_NO_OR_LAST | NCI_GID_RF_MANAGE
      03 = NCI_MSG_RF_DISCOVER
         01 = size
            00 = STATUS_OK
# CTRL 0x41 0x01 0x0001 0x0003