def run_with_result(self, command: BaseCommand, *args) -> bytes: """ Run a command against the Kraken hardware and fetch the result :param command: The command tuple :param args: Argument list (varargs) :return: Raw response bytes """ try: with self.device_open(): if not self._run_command(command, *args): return None self._last_cmd_time = smart_delay(DELAY_TIME, self._last_cmd_time, 0) resp = self._dev.read(REPORT_LENGTH_IN, timeout_ms=500) self._hexdump(resp, '<-- ') if resp is None or len(resp) == 0: return None assert resp[0] == REPORT_ID_IN, \ 'Inbound report should have id %02x (was %02x)' % \ (REPORT_ID_IN, resp[0]) return resp[1:command.length + 1] except (OSError, IOError) as err: self.logger.exception('Caught exception running command', exc_info=err) return None
def _run_command(self, command: BaseCommand, *args) -> bool: try: data = UChromaHeadset._pack_request(command, *args) self._hexdump(data, '--> ') self._last_cmd_time = smart_delay(DELAY_TIME, self._last_cmd_time, 0) self._dev.write(data, report_id=to_byte(REPORT_ID_OUT)) return True except (OSError, IOError) as err: self.logger.exception('Caught exception running command', exc_info=err) return False
def run(self, delay: float = None, timeout_cb=None) -> bool: """ Run this report and retrieve the result from the hardware. Sends the feature report and parses the result. A small delay is required between calls to the hardware or a BUSY status will be returned. This delay may need adjusted on a per-model basis. If debug loglevel is enabled, the raw report data from both the request and the response will be logged. :param delay: Time to delay between requests (defaults to 0.005 sec) :param timeout_cb: Callback to run when a TIMEOUT is returned :return: The parsed result from the hardware """ if delay is None: delay = RazerReport.CMD_DELAY_TIME retry_count = 3 with self._driver.device_open(): while retry_count > 0: try: req = self._pack_request() self._hexdump(req, '--> ') if self._remaining_packets == 0: self._driver.last_cmd_time = smart_delay( delay, self._driver.last_cmd_time, self._remaining_packets) self._driver.hid.send_feature_report( req, self.REQ_REPORT_ID) if self._remaining_packets > 0: return True self._driver.last_cmd_time = smart_delay( delay, self._driver.last_cmd_time, self._remaining_packets) resp = self._driver.hid.get_feature_report( self.RSP_REPORT_ID, self.BUF_SIZE) self._hexdump(resp, '<-- ') if self._unpack_response(resp): if timeout_cb is not None: timeout_cb(self.status, None) return True if self.status == Status.FAIL or self.status == Status.UNSUPPORTED: self._logger.error("Command failed with status %s", self.status.name) return False if timeout_cb is not None and self.status == Status.TIMEOUT: timeout_cb(self.status, self.result) return False self._logger.warning( "Retrying request due to status %s (%d)", self.status.name, retry_count) time.sleep(0.1) retry_count -= 1 except (OSError, IOError): self._status = Status.OSERROR raise return False