code: def exchange(self, send_data, timeout):
          
          with self.lock:
              if self.device is None:
                  raise IOError(errno.ENODEV, os.strerror(errno.ENODEV))
  
              log.debug(">>> %s timeout=%s", print_data(send_data), str(timeout))
  
              if isinstance(self.target, RemoteTarget):
                  exchange = self.device.send_cmd_recv_rsp
              elif isinstance(self.target, LocalTarget):
                  exchange = self.device.send_rsp_recv_cmd
              else:
                  log.error("no target for data exchange")
                  return None
  
              send_time = time.time()
              rcvd_data = exchange(self.target, send_data, timeout)
              recv_time = time.time() - send_time
  
              log.debug("<<< %s %.3fs", print_data(rcvd_data), recv_time)
              return rcvd_data
docs: Exchange data with an activated target (*send_data* is a command
          frame) or as an activated target (*send_data* is a response
          frame). Returns a target response frame (if data is send to an
          activated target) or a next command frame (if data is send
          from an activated target). Returns None if the communication
          link broke during exchange (if data is sent as a target). The
          timeout is the number of seconds to wait for data to return,
          if the timeout expires an nfc.clf.TimeoutException is
          raised. Other nfc.clf.CommunicationError exceptions may be raised if
          an error is detected during communication.