Discover a contactless card or listening device.

        .. note:: The :meth:`sense` method is intended for experts
                  with a good understanding of the commands and
                  responses exchanged during target activation (the
                  notion used for commands and responses follows the
                  NFC Forum Digital Specification). If the greater
                  level of control is not needed it is recommended to
                  use the :meth:`connect` method.

        All positional arguments build the list of potential *targets*
        to discover and must be of type :class:`RemoteTarget`. Keyword
        argument *options* may be the number of ``iterations`` of the
        sense loop set by *targets* and the ``interval`` between
        iterations. The return value is either a :class:`RemoteTarget`
        instance or :const:`None`.

        >>> import nfc, nfc.clf
        >>> clf = nfc.ContactlessFrontend("usb")
        >>> target1 = nfc.clf.RemoteTarget("106A")
        >>> target2 = nfc.clf.RemoteTarget("212F")
        >>> print(clf.sense(target1, target2, iterations=5, interval=0.2))
        106A(sdd_res=04497622D93881, sel_res=00, sens_res=4400)

        A **Type A Target** is specified with the technology letter
        ``A`` following the bitrate to be used for the SENS_REQ
        command (almost always must the bitrate be 106 kbps). To
        discover only a specific Type A target, the NFCID1 (UID) can
        be set with a 4, 7, or 10 byte ``sel_req`` attribute (cascade
        tags are handled internally).

        >>> target = nfc.clf.RemoteTarget("106A")
        >>> print(clf.sense(target))
        106A sdd_res=04497622D93881 sel_res=00 sens_res=4400
        >>> target.sel_req = bytearray.fromhex("04497622D93881")
        >>> print(clf.sense(target))
        106A sdd_res=04497622D93881 sel_res=00 sens_res=4400
        >>> target.sel_req = bytearray.fromhex("04497622")
        >>> print(clf.sense(target))
        None

        A **Type B Target** is specified with the technology letter
        ``B`` following the bitrate to be used for the SENSB_REQ
        command (almost always must the bitrate be 106 kbps). A
        specific application family identifier can be set with the
        first byte of a ``sensb_req`` attribute (the second byte PARAM
        is ignored when it can not be set to local device, 00h is a
        safe value in all cases).

        >>> target = nfc.clf.RemoteTarget("106B")
        >>> print(clf.sense(target))
        106B sens_res=50E5DD3DC900000011008185
        >>> target.sensb_req = bytearray.fromhex("0000")
        >>> print(clf.sense(target))
        106B sens_res=50E5DD3DC900000011008185
        >>> target.sensb_req = bytearray.fromhex("FF00")
        >>> print(clf.sense(target))
        None

        A **Type F Target** is specified with the technology letter
        ``F`` following the bitrate to be used for the SENSF_REQ
        command (the typically supported bitrates are 212 and 424
        kbps). The default SENSF_REQ command allows all targets to
        answer, requests system code information, and selects a single
        time slot for the SENSF_RES response. This can be changed with
        the ``sensf_req`` attribute.

        >>> target = nfc.clf.RemoteTarget("212F")
        >>> print(clf.sense(target))
        212F sensf_res=0101010601B00ADE0B03014B024F4993FF12FC
        >>> target.sensf_req = bytearray.fromhex("0012FC0000")
        >>> print(clf.sense(target))
        212F sensf_res=0101010601B00ADE0B03014B024F4993FF
        >>> target.sensf_req = bytearray.fromhex("00ABCD0000")
        >>> print(clf.sense(target))
        None

        An **Active Communication Mode P2P Target** search is selected
        with an ``atr_req`` attribute. The choice of bitrate and
        modulation type is 106A, 212F, and 424F.

        >>> atr = bytearray.fromhex("D4000102030405060708091000000030")
        >>> target = clf.sense(nfc.clf.RemoteTarget("106A", atr_req=atr))
        >>> if target and target.atr_res: print(target.atr_res.encode("hex"))
        d501c023cae6b3182afe3dee0000000e3246666d01011103020013040196
        >>> target = clf.sense(nfc.clf.RemoteTarget("424F", atr_req=atr))
        >>> if target and target.atr_res: print(target.atr_res.encode("hex"))
        d501dc0104f04584e15769700000000e3246666d01011103020013040196

        Some drivers must modify the ATR_REQ to cope with hardware
        limitations, for example change length reduction value to
        reduce the maximum size of target responses. The ATR_REQ that
        has been send is given by the ``atr_req`` attribute of the
        returned RemoteTarget object.

        A **Passive Communication Mode P2P Target** responds to 106A
        discovery with bit 6 of SEL_RES set to 1, and to 212F/424F
        discovery (when the request code RC is 0 in the SENSF_REQ
        command) with an NFCID2 that starts with 01FEh in the
        SENSF_RES response. Responses below are from a Nexus 5
        configured for NFC-DEP Protocol (SEL_RES bit 6 is set) and
        Type 4A Tag (SEL_RES bit 5 is set).

        >>> print(clf.sense(nfc.clf.RemoteTarget("106A")))
        106A sdd_res=08796BEB sel_res=60 sens_res=0400
        >>> sensf_req = bytearray.fromhex("00FFFF0000")
        >>> print(clf.sense(nfc.clf.RemoteTarget("424F", sensf_req=sensf_req)))
        424F sensf_res=0101FE1444EFB88FD50000000000000000

        Errors found in the *targets* argument list raise exceptions
        only if exactly one target is given. If multiple targets are
        provided, any target that is not supported or has invalid
        attributes is just ignored (but is logged as a debug message).

        **Exceptions**

        * :exc:`~exceptions.IOError` (ENODEV) when a local contacless
          communication device has not been opened or communication
          with the local device is no longer possible.

        * :exc:`nfc.clf.UnsupportedTargetError` if the single target
          supplied as input is not supported by the active driver.
          This exception is never raised when :meth:`sense` is called
          with multiple targets, those unsupported are then silently
          ignored.

def sense(self, *targets, **options):
        """Discover a contactless card or listening device.

        .. note:: The :meth:`sense` method is intended for experts
                  with a good understanding of the commands and
                  responses exchanged during target activation (the
                  notion used for commands and responses follows the
                  NFC Forum Digital Specification). If the greater
                  level of control is not needed it is recommended to
                  use the :meth:`connect` method.

        All positional arguments build the list of potential *targets*
        to discover and must be of type :class:`RemoteTarget`. Keyword
        argument *options* may be the number of ``iterations`` of the
        sense loop set by *targets* and the ``interval`` between
        iterations. The return value is either a :class:`RemoteTarget`
        instance or :const:`None`.

        >>> import nfc, nfc.clf
        >>> clf = nfc.ContactlessFrontend("usb")
        >>> target1 = nfc.clf.RemoteTarget("106A")
        >>> target2 = nfc.clf.RemoteTarget("212F")
        >>> print(clf.sense(target1, target2, iterations=5, interval=0.2))
        106A(sdd_res=04497622D93881, sel_res=00, sens_res=4400)

        A **Type A Target** is specified with the technology letter
        ``A`` following the bitrate to be used for the SENS_REQ
        command (almost always must the bitrate be 106 kbps). To
        discover only a specific Type A target, the NFCID1 (UID) can
        be set with a 4, 7, or 10 byte ``sel_req`` attribute (cascade
        tags are handled internally).

        >>> target = nfc.clf.RemoteTarget("106A")
        >>> print(clf.sense(target))
        106A sdd_res=04497622D93881 sel_res=00 sens_res=4400
        >>> target.sel_req = bytearray.fromhex("04497622D93881")
        >>> print(clf.sense(target))
        106A sdd_res=04497622D93881 sel_res=00 sens_res=4400
        >>> target.sel_req = bytearray.fromhex("04497622")
        >>> print(clf.sense(target))
        None

        A **Type B Target** is specified with the technology letter
        ``B`` following the bitrate to be used for the SENSB_REQ
        command (almost always must the bitrate be 106 kbps). A
        specific application family identifier can be set with the
        first byte of a ``sensb_req`` attribute (the second byte PARAM
        is ignored when it can not be set to local device, 00h is a
        safe value in all cases).

        >>> target = nfc.clf.RemoteTarget("106B")
        >>> print(clf.sense(target))
        106B sens_res=50E5DD3DC900000011008185
        >>> target.sensb_req = bytearray.fromhex("0000")
        >>> print(clf.sense(target))
        106B sens_res=50E5DD3DC900000011008185
        >>> target.sensb_req = bytearray.fromhex("FF00")
        >>> print(clf.sense(target))
        None

        A **Type F Target** is specified with the technology letter
        ``F`` following the bitrate to be used for the SENSF_REQ
        command (the typically supported bitrates are 212 and 424
        kbps). The default SENSF_REQ command allows all targets to
        answer, requests system code information, and selects a single
        time slot for the SENSF_RES response. This can be changed with
        the ``sensf_req`` attribute.

        >>> target = nfc.clf.RemoteTarget("212F")
        >>> print(clf.sense(target))
        212F sensf_res=0101010601B00ADE0B03014B024F4993FF12FC
        >>> target.sensf_req = bytearray.fromhex("0012FC0000")
        >>> print(clf.sense(target))
        212F sensf_res=0101010601B00ADE0B03014B024F4993FF
        >>> target.sensf_req = bytearray.fromhex("00ABCD0000")
        >>> print(clf.sense(target))
        None

        An **Active Communication Mode P2P Target** search is selected
        with an ``atr_req`` attribute. The choice of bitrate and
        modulation type is 106A, 212F, and 424F.

        >>> atr = bytearray.fromhex("D4000102030405060708091000000030")
        >>> target = clf.sense(nfc.clf.RemoteTarget("106A", atr_req=atr))
        >>> if target and target.atr_res: print(target.atr_res.encode("hex"))
        d501c023cae6b3182afe3dee0000000e3246666d01011103020013040196
        >>> target = clf.sense(nfc.clf.RemoteTarget("424F", atr_req=atr))
        >>> if target and target.atr_res: print(target.atr_res.encode("hex"))
        d501dc0104f04584e15769700000000e3246666d01011103020013040196

        Some drivers must modify the ATR_REQ to cope with hardware
        limitations, for example change length reduction value to
        reduce the maximum size of target responses. The ATR_REQ that
        has been send is given by the ``atr_req`` attribute of the
        returned RemoteTarget object.

        A **Passive Communication Mode P2P Target** responds to 106A
        discovery with bit 6 of SEL_RES set to 1, and to 212F/424F
        discovery (when the request code RC is 0 in the SENSF_REQ
        command) with an NFCID2 that starts with 01FEh in the
        SENSF_RES response. Responses below are from a Nexus 5
        configured for NFC-DEP Protocol (SEL_RES bit 6 is set) and
        Type 4A Tag (SEL_RES bit 5 is set).

        >>> print(clf.sense(nfc.clf.RemoteTarget("106A")))
        106A sdd_res=08796BEB sel_res=60 sens_res=0400
        >>> sensf_req = bytearray.fromhex("00FFFF0000")
        >>> print(clf.sense(nfc.clf.RemoteTarget("424F", sensf_req=sensf_req)))
        424F sensf_res=0101FE1444EFB88FD50000000000000000

        Errors found in the *targets* argument list raise exceptions
        only if exactly one target is given. If multiple targets are
        provided, any target that is not supported or has invalid
        attributes is just ignored (but is logged as a debug message).

        **Exceptions**

        * :exc:`~exceptions.IOError` (ENODEV) when a local contacless
          communication device has not been opened or communication
          with the local device is no longer possible.

        * :exc:`nfc.clf.UnsupportedTargetError` if the single target
          supplied as input is not supported by the active driver.
          This exception is never raised when :meth:`sense` is called
          with multiple targets, those unsupported are then silently
          ignored.

        """
        def sense_tta(target):
            if target.sel_req and len(target.sel_req) not in (4, 7, 10):
                raise ValueError("sel_req must be 4, 7, or 10 byte")
            target = self.device.sense_tta(target)
            log.debug("found %s", target)
            if target and len(target.sens_res) != 2:
                error = "SENS Response Format Error (wrong length)"
                log.debug(error)
                raise ProtocolError(error)
            if target and target.sens_res[0] & 0b00011111 == 0:
                if target.sens_res[1] & 0b00001111 != 0b1100:
                    error = "SENS Response Data Error (T1T config)"
                    log.debug(error)
                    raise ProtocolError(error)
                if not target.rid_res:
                    error = "RID Response Error (no response received)"
                    log.debug(error)
                    raise ProtocolError(error)
                if len(target.rid_res) != 6:
                    error = "RID Response Format Error (wrong length)"
                    log.debug(error)
                    raise ProtocolError(error)
                if target.rid_res[0] >> 4 != 0b0001:
                    error = "RID Response Data Error (invalid HR0)"
                    log.debug(error)
                    raise ProtocolError(error)
            return target

        def sense_ttb(target):
            return self.device.sense_ttb(target)

        def sense_ttf(target):
            return self.device.sense_ttf(target)

        def sense_dep(target):
            if len(target.atr_req) < 16:
                raise ValueError("minimum atr_req length is 16 byte")
            if len(target.atr_req) > 64:
                raise ValueError("maximum atr_req length is 64 byte")
            return self.device.sense_dep(target)

        for target in targets:
            if not isinstance(target, RemoteTarget):
                raise ValueError("invalid target argument type: %r" % target)

        with self.lock:
            if self.device is None:
                raise IOError(errno.ENODEV, os.strerror(errno.ENODEV))

            self.target = None  # forget captured target
            self.device.mute()  # deactivate the rf field

            for i in xrange(max(1, options.get('iterations', 1))):
                started = time.time()
                for target in targets:
                    log.debug("sense {0}".format(target))
                    try:
                        if target.atr_req is not None:
                            self.target = sense_dep(target)
                        elif target.brty.endswith('A'):
                            self.target = sense_tta(target)
                        elif target.brty.endswith('B'):
                            self.target = sense_ttb(target)
                        elif target.brty.endswith('F'):
                            self.target = sense_ttf(target)
                        else:
                            info = "unknown technology type in %r"
                            raise UnsupportedTargetError(info % target.brty)
                    except UnsupportedTargetError as error:
                        if len(targets) == 1:
                            raise error
                        else:
                            log.debug(error)
                    except CommunicationError as error:
                        log.debug(error)
                    else:
                        if self.target is not None:
                            log.debug("found {0}".format(self.target))
                            return self.target
                if len(targets) > 0:
                    self.device.mute()  # deactivate the rf field
                if i < options.get('iterations', 1) - 1:
                    elapsed = time.time() - started
                    time.sleep(max(0, options.get('interval', 0.1)-elapsed))