91
91
class ContactlessFrontend(object):
92
92
"""The contactless frontend is the main interface class for
93
working with contactless reader devices. A reader device is opened
94
automatically upon instance creation, see :meth:`.open` for how
95
*path* is interpeted."""
93
working with contactless reader devices. A reader device may be
94
opened when an instance is created by providing the *path*
95
argument, see :meth:`nfc.ContactlessFrontend.open` for how it must
98
The initializer method raises :exc:`IOError(errno.ENODEV)` if a
99
path is specified but no no reader are found.
97
102
def __init__(self, path=None):
98
104
self.lock = threading.Lock()
101
def open(self, path=None):
102
"""Open contactless reader device identified by *path*. If
103
*path* is not :const:`None` (default) or an empty string, the
104
first available device is used. Otherwise *path* must match
105
one of the following expressions:
107
* ``usb[:vendor[:product]]`` with *vendor* and *product* id (hex)
108
* ``usb[:bus[:device]]`` with usb *bus* and *device* number (dec)
109
* ``tty[:usb[:port]]`` with usb serial *port* number (dec)
110
* ``tty[:com[:port]]`` with serial *port* number (dec)
111
* ``udp[:host[:port]]`` with *host* IP or name and *port* number
113
:raises `IOError(ENODEV)` if no available reader device is found.
105
if path and not self.open(path):
106
raise IOError(errno.ENODEV, os.strerror(errno.ENODEV))
108
def open(self, path):
109
"""Open a contactless reader device identified by *path*.
111
:param path: search path for contactless reader
112
:returns True: if reader was found and activated
114
**Path specification:**
116
``usb[:vendor[:product]]``
117
with optional *vendor* and *product* as four digit
118
hexadecimal numbers, like ``usb:054c:06c3`` would open the
119
first Sony RC-S380 reader and ``usb:054c`` the first Sony
122
``usb[:bus[:device]]``
123
with optional *bus* and *device* number as three-digit
124
decimal numbers, like ``usb:001:023`` would specifically
125
mean the usb device with bus number 1 and device id 23
126
whereas ``usb:001`` would mean to use the first available
127
reader on bus number 1.
130
with mandatory *port* and *driver* name should be used on
131
Posix systems to open the serial port at device node
132
``/dev/tty<port>`` and load the driver from module
133
``nfc/dev/<driver>.py``. A typical example would be
134
``tty:USB0:arygon`` for the Arygon APPx/ADRx at
138
with mandatory *port* and *driver* name should be used on
139
Windows systems to open the serial port ``COM<port>`` and
140
load the ``nfc/dev/<driver>.py`` driver module.
142
``udp[:host][:port]`` with optional *host* name or address
143
and *port* number will use a fake communication channel over
144
UDP/IP. Either value may be omitted in which case *host*
145
defaults to 'localhost' and *port* defaults to 54321.
115
if not path: log.info("searching for a usable reader")
116
else: log.info("searching for reader with path '{0}'".format(path))
148
if not isinstance(path, str):
149
raise TypeError("expecting a string type argument *path*")
150
if not len(path) > 0:
151
raise ValueError("argument *path* must not be empty")
153
log.info("searching for reader with path '{0}'".format(path))
119
156
self.dev = nfc.dev.connect(path)
121
msg = "no reader found"
122
log.error(msg + " at '{0}'".format(path) if path else msg)
123
raise IOError(errno.ENODEV, os.strerror(errno.ENODEV))
159
log.error("no reader found at '{0}'".format(path))
125
161
log.info("using {0}".format(self.dev))
163
return bool(self.dev)
128
166
"""Close the contacless reader device."""
133
172
def connect(self, **options):
134
173
"""Connect with a contactless target or become connected as a
135
contactless target. Connect blocks the calling thread until an
174
contactless target. Blocks the calling thread until a single
136
175
activation and deactivation has completed. Connect options are
137
given as keyword arguments with dictionary values and at least
138
one option must be present. Possible options are:
176
given as keyword arguments with dictionary values. Possible
140
179
* ``rdwr={key: value, ...}`` - options for reader/writer operation
141
180
* ``llcp={key: value, ...}`` - options for peer to peer mode operation
267
306
100601010501b00ac30b010b00018000
309
Connect returns :const:`None` if no options were to execute,
310
:const:`False` if interrupted by a :exc:`KeyboardInterrupt`,
311
or :const:`True` if terminated normally and the 'on-connect'
312
callback function had returned :const:`True`. If the
313
'on-connect' callback had returned :const:`False` the return
314
value of connect() is the same parameters as were provided to
315
the callback function.
271
317
log.debug("connect({0})".format(options))
273
319
rdwr_options = options.get('rdwr')
274
320
llcp_options = options.get('llcp')
275
321
card_options = options.get('card')
277
323
if isinstance(rdwr_options, dict):
278
324
rdwr_options.setdefault('targets', [
279
325
TTA(br=106, cfg=None, uid=None), TTB(br=106),
317
363
if not 'on-connect' in card_options:
318
364
card_options['on-connect'] = lambda tag, command: True
319
365
elif card_options is not None:
320
raise TypeError("card_options must be a dictionary")
366
raise TypeError("argument *card* must be a dictionary")
322
368
some_options = rdwr_options or llcp_options or card_options
323
369
if not some_options:
324
370
log.warning("no options left to connect")
327
if ((llcp_options and self._llcp_connect(llcp_options, llc)) or
328
(rdwr_options and self._rdwr_connect(rdwr_options)) or
329
(card_options and self._card_connect(card_options))):
376
result = self._llcp_connect(llcp_options, llc)
377
if bool(result): return result
379
result = self._rdwr_connect(rdwr_options)
380
if bool(result): return result
382
result = self._card_connect(card_options)
383
if bool(result): return result
331
384
except KeyboardInterrupt as error:
390
457
def listen(self, target, timeout):
391
458
"""Listen for *timeout* seconds to become initialized as a
392
*target*. The *target* must be set to one of
393
:class:`nfc.clf.TTA`, :class:`nfc.clf.TTB`,
394
:class:`nfc.clf.TTF`, or :class:`nfc.clf.DEP` (note that
395
target type support depends on the hardware capabilities). The
396
return value is :const:`None` if *timeout* elapsed without
397
activation or a tuple (target, command) where target is the
398
activated target (which may differ from the requested target,
399
see below) and command is the first command received from the
459
*target*. The *target* must be one of :class:`nfc.clf.TTA`,
460
:class:`nfc.clf.TTB`, :class:`nfc.clf.TTF`, or
461
:class:`nfc.clf.DEP` (note that target type support depends on
462
the hardware capabilities). The return value is :const:`None`
463
if *timeout* elapsed without activation or a tuple (target,
464
command) where target is the activated target (which may
465
differ from the requested target, see below) and command is
466
the first command received from the initiator.
402
468
If an activated target is returned, the target type and
403
469
attributes may differ from the *target* requested. This is