Open a contactless reader identified by the search *path*.

        The :meth:`open` method searches and then opens a contactless
        reader device for further communication. The *path* argument
        can be flexibly constructed to identify more or less precisely
        the device to open. A *path* that only partially identifies a
        device is completed by search. The first device that is found
        and successfully opened causes :meth:`open` to return True. If
        no device is found return value is False. If a device was
        found but could not be opened then :meth:`open` returns False
        if *path* was partial or raise :exc:`~exceptions.IOError` if
        *path* was fully qualified. Typical I/O error reasons are
        :data:`errno.EACCES` if the calling process has insufficient
        access rights or :data:`errno.EBUSY` if the device is used by
        another process.

        A path is constructed as follows:

        ``usb[:vendor[:product]]``

           with optional *vendor* and *product* as four digit
           hexadecimal numbers. For example, ``usb:054c:06c3`` would
           open the first Sony RC-S380 reader while ``usb:054c`` would
           open the first Sony reader found on USB.

        ``usb[:bus[:device]]``

           with optional *bus* and *device* number as three-digit
           decimals. For example, ``usb:001:023`` would open the
           device enumerated as number 23 on bus 1 while ``usb:001``
           would open the first device found on bust 1. Note that a
           new device number is generated every time the device is
           plugged into USB. Bus and device numbers are shown by
           ``lsusb``.

        ``tty:port:driver``

           with mandatory *port* and *driver* name. This is for Posix
           systems to open the serial port ``/dev/tty<port>`` and use
           the driver module ``nfc/dev/<driver>.py`` for access. For
           example, ``tty:USB0:arygon`` would open ``/dev/ttyUSB0``
           and load the Arygon APPx/ADRx driver.

        ``com:port:driver``

           with mandatory *port* and *driver* name. This is for
           Windows systems to open the serial port ``COM<port>`` and
           use the driver module ``nfc/dev/<driver>.py`` for access.

        ``udp[:host][:port]``

           with optional *host* name or address and *port*
           number. This will emulate a communication channel over
           UDP/IP. The defaults for *host* and *port* are
           ``localhost:54321``.

def open(self, path):
        """Open a contactless reader identified by the search *path*.

        The :meth:`open` method searches and then opens a contactless
        reader device for further communication. The *path* argument
        can be flexibly constructed to identify more or less precisely
        the device to open. A *path* that only partially identifies a
        device is completed by search. The first device that is found
        and successfully opened causes :meth:`open` to return True. If
        no device is found return value is False. If a device was
        found but could not be opened then :meth:`open` returns False
        if *path* was partial or raise :exc:`~exceptions.IOError` if
        *path* was fully qualified. Typical I/O error reasons are
        :data:`errno.EACCES` if the calling process has insufficient
        access rights or :data:`errno.EBUSY` if the device is used by
        another process.

        A path is constructed as follows:

        ``usb[:vendor[:product]]``

           with optional *vendor* and *product* as four digit
           hexadecimal numbers. For example, ``usb:054c:06c3`` would
           open the first Sony RC-S380 reader while ``usb:054c`` would
           open the first Sony reader found on USB.

        ``usb[:bus[:device]]``

           with optional *bus* and *device* number as three-digit
           decimals. For example, ``usb:001:023`` would open the
           device enumerated as number 23 on bus 1 while ``usb:001``
           would open the first device found on bust 1. Note that a
           new device number is generated every time the device is
           plugged into USB. Bus and device numbers are shown by
           ``lsusb``.

        ``tty:port:driver``

           with mandatory *port* and *driver* name. This is for Posix
           systems to open the serial port ``/dev/tty<port>`` and use
           the driver module ``nfc/dev/<driver>.py`` for access. For
           example, ``tty:USB0:arygon`` would open ``/dev/ttyUSB0``
           and load the Arygon APPx/ADRx driver.

        ``com:port:driver``

           with mandatory *port* and *driver* name. This is for
           Windows systems to open the serial port ``COM<port>`` and
           use the driver module ``nfc/dev/<driver>.py`` for access.

        ``udp[:host][:port]``

           with optional *host* name or address and *port*
           number. This will emulate a communication channel over
           UDP/IP. The defaults for *host* and *port* are
           ``localhost:54321``.

        """
        if not isinstance(path, str):
            raise TypeError("expecting a string type argument *path*")
        if not len(path) > 0:
            raise ValueError("argument *path* must not be empty")

        # Close current device driver if this is not the first
        # open. This allows to use several devices sequentially or
        # re-initialize a device.
        self.close()

        # Acquire the lock and search for a device on *path*
        with self.lock:
            log.info("searching for reader on path " + path)
            self.device = device.connect(path)
            if self.device:
                log.info("using {0}".format(self.device))
            else:
                log.error("no reader available on path " + path)
            return bool(self.device)