From 456615e3010ad7294fb15709747f594a6a91b88e Mon Sep 17 00:00:00 2001
From: Jacek Kowalski <Jacek@jacekk.info>
Date: Fri, 24 Jul 2020 19:17:35 +0000
Subject: [PATCH] ControlVault 3 - initial support
---
/dev/null | 189 -----------
cv3.py | 43 ++
traffic_cv2.txt | 0
nfc.py | 76 ++++
traffic_cv3.txt | 529 +++++++++++++++++++++++++++++++
cv2.py | 46 ++
cvcomm.py | 93 +++++
README.md | 16
8 files changed, 796 insertions(+), 196 deletions(-)
diff --git a/README.md b/README.md
index 83c0e71..659ed04 100644
--- a/README.md
+++ b/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:5834` (ControlVault 2),
+* `0a5c:5843` (ControlVault 3).
Firmware update (done during driver installation on Windows) may be required.
@@ -36,19 +37,20 @@
* Dell Latitude 7280
* Dell Latitude 7290
* Dell Latitude 7390
+* 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
diff --git a/bcm20795.py b/bcm20795.py
deleted file mode 100755
index c683016..0000000
--- a/bcm20795.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env python3
-
-# Enable NFC on Linux (CCID/PCSCD)
-# Dell E7470
-# Dell ControlVault2
-# BCM20795 (20795A1)
-
-import binascii
-import logging
-import math
-import struct
-import sys
-import time
-import usb.core
-import usb.util
-
-SUPPORTED_DEVICES = [
- {'idVendor': 0x0A5C, 'idProduct': 0x5834},
- {'idVendor': 0x0A5C, 'idProduct': 0x5832},
-]
-
-logging.basicConfig(level=logging.DEBUG)
-logger = logging.getLogger(__name__)
-
-def to_hex(val):
- return ' '.join([bytes([i]).hex() for i in val])
-
-class BcmCommunicator:
- def __init__(self, device, bulk_in, bulk_out):
- self.logger = logging.getLogger(__name__)
- self.device = device
- self.bulk_in = bulk_in
- self.bulk_out = bulk_out
-
- 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):
- packet_type = 0x01
- unknown1 = 0x00
- length = len(payload)
-
- packet = struct.pack('>BBH', packet_type, unknown1, 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 != b'\x00\x00':
- 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()
-
- @staticmethod
- def _dev_match(template, candidate):
- for prop, value in template.items():
- if prop not in candidate.__dict__ or candidate.__dict__[prop] != value:
- return False
- return True
-
- @classmethod
- def _dev_matcher(cls, dev):
- for device in SUPPORTED_DEVICES:
- if cls._dev_match(device, dev):
- return True
- return False
-
- @classmethod
- def find(cls):
- logger = logging.getLogger(__name__)
- logger.info('Looking for BCM 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))
-
- logger.debug('Enumerating interfaces...')
- configuration = 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')
- logger.debug('Interface found: {}'.format(bcm_interface._str()))
-
- 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
- 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
- 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!')
-
- logger.debug('Returning {} object...'.format(cls.__name__))
- return cls(device, bulk_in, bulk_out)
-
-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 turn_on(communicator):
- communicator.ctrl_transfer(0x41, 0, 1, 3)
- communicator.talk(turn_on_seq1)
- communicator.ctrl_transfer(0x41, 1, 0, 3)
- communicator.talk(turn_on_seq2)
- communicator.ctrl_transfer(0x41, 1, 1, 3)
-
-def turn_off(communicator):
- communicator.ctrl_transfer(0x41, 1, 0, 3)
- communicator.ctrl_transfer(0x41, 0, 0, 3)
-
-
-
-if __name__ == "__main__":
- if len(sys.argv) < 2:
- print('Usage: {} [on|off]'.format(sys.argv[0]))
- sys.exit(2)
-
- communicator = BcmCommunicator.find()
- if sys.argv[1] == 'on':
- logger.info('Turning NFC on...')
- turn_on(communicator)
- logger.info('NFC should be turned on now!')
- elif sys.argv[1] == 'off':
- logger.info('Turning NFC off...')
- turn_off(communicator)
- logger.info('NFC should be turned off now!')
- else:
- raise Exception('Unknown option: {}'.format(sys.argv[1]))
diff --git a/cv2.py b/cv2.py
new file mode 100644
index 0000000..975c7d3
--- /dev/null
+++ b/cv2.py
@@ -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()
diff --git a/cv3.py b/cv3.py
new file mode 100644
index 0000000..e010616
--- /dev/null
+++ b/cv3.py
@@ -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(self.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(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()
diff --git a/cvcomm.py b/cvcomm.py
new file mode 100644
index 0000000..67ad942
--- /dev/null
+++ b/cvcomm.py
@@ -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
diff --git a/nfc.py b/nfc.py
new file mode 100755
index 0000000..444e891
--- /dev/null
+++ b/nfc.py
@@ -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': 0x5834}, lambda device: __import__('cv2').ControlVault2(device)),
+ UsbDeviceMatcher({'idVendor': 0x0A5C, 'idProduct': 0x5843}, lambda device: __import__('cv3').ControlVault3(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]))
diff --git a/traffic.txt b/traffic_cv2.txt
similarity index 100%
rename from traffic.txt
rename to traffic_cv2.txt
diff --git a/traffic_cv3.txt b/traffic_cv3.txt
new file mode 100644
index 0000000..7cc18a0
--- /dev/null
+++ b/traffic_cv3.txt
@@ -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
--
Gitblit v1.9.1