Send a command and receive a response.

        This low level method sends an arbitrary command with the
        8-bit integer *cmd_code*, followed by the captured tag
        identifier (IDm) if *send_idm* is :const:`True` and the byte
        string or bytearray *cmd_data*. It then waits *timeout*
        seconds for a response, verifies that the response is
        correctly formatted and, if *check_status* is :const:`True`,
        that the status flags do not indicate an error.

        All errors raise a :exc:`~nfc.tag.TagCommandError`
        exception. Errors from response status flags produce an
        :attr:`~nfc.tag.TagCommandError.errno` that is greater than
        255, all other errors are below 256.

def send_cmd_recv_rsp(self, cmd_code, cmd_data, timeout,
                          send_idm=True, check_status=True):
        """Send a command and receive a response.

        This low level method sends an arbitrary command with the
        8-bit integer *cmd_code*, followed by the captured tag
        identifier (IDm) if *send_idm* is :const:`True` and the byte
        string or bytearray *cmd_data*. It then waits *timeout*
        seconds for a response, verifies that the response is
        correctly formatted and, if *check_status* is :const:`True`,
        that the status flags do not indicate an error.

        All errors raise a :exc:`~nfc.tag.TagCommandError`
        exception. Errors from response status flags produce an
        :attr:`~nfc.tag.TagCommandError.errno` that is greater than
        255, all other errors are below 256.

        """
        idm = self.idm if send_idm else bytearray()
        cmd = chr(2+len(idm)+len(cmd_data)) + chr(cmd_code) + idm + cmd_data
        log.debug(">> {0:02x} {1:02x} {2} {3} ({4}s)".format(
            cmd[0], cmd[1], hexlify(cmd[2:10]), hexlify(cmd[10:]), timeout))

        started = time.time()
        for retry in range(3):
            try:
                rsp = self.clf.exchange(cmd, timeout)
                break
            except nfc.clf.CommunicationError as error:
                reason = error.__class__.__name__
                log.debug("%s after %d retries" % (reason, retry))
        else:
            if type(error) is nfc.clf.TimeoutError:
                raise Type3TagCommandError(nfc.tag.TIMEOUT_ERROR)
            if type(error) is nfc.clf.TransmissionError:
                raise Type3TagCommandError(nfc.tag.RECEIVE_ERROR)
            if type(error) is nfc.clf.ProtocolError:  # pragma: no branch
                raise Type3TagCommandError(nfc.tag.PROTOCOL_ERROR)

        if rsp[0] != len(rsp):
            log.debug("incorrect response length {0:02x}".format(rsp[0]))
            raise Type3TagCommandError(RSP_LENGTH_ERROR)
        if rsp[1] != cmd_code + 1:
            log.debug("incorrect response code {0:02x}".format(rsp[1]))
            raise Type3TagCommandError(RSP_CODE_ERROR)
        if send_idm and rsp[2:10] != self.idm:
            log.debug("wrong tag or transaction id " + hexlify(rsp[2:10]))
            raise Type3TagCommandError(TAG_IDM_ERROR)
        if not send_idm:
            log.debug("<< {0:02x} {1:02x} {2}".format(
                rsp[0], rsp[1], hexlify(rsp[2:])))
            return rsp[2:]
        if check_status and rsp[10] != 0:
            log.debug("tag returned error status " + hexlify(rsp[10:12]))
            raise Type3TagCommandError(unpack(">H", rsp[10:12])[0])
        if not check_status:
            log.debug("<< {0:02x} {1:02x} {2} {3}".format(
                rsp[0], rsp[1], hexlify(rsp[2:10]), hexlify(rsp[10:])))
            return rsp[10:]
        log.debug("<< {0:02x} {1:02x} {2} {3} {4} ({elapsed:f}s)".format(
            rsp[0], rsp[1], hexlify(rsp[2:10]), hexlify(rsp[10:12]),
            hexlify(rsp[12:]), elapsed=time.time()-started))
        return rsp[12:]