def _finish(self, command, do_wait=True): buffer = None cbk_fn, setup_packet, _ = command length_transferred = c_ulong() rc = WinUsb_GetOverlappedResult(self._winusb, self._overlapped.ptr, byref(length_transferred), do_wait) if rc == 0: # failed (any value other than 0 is success) rc = kernel32.GetLastError() if rc not in [ kernel32.ERROR_IO_INCOMPLETE, kernel32.ERROR_IO_PENDING ]: kernel32.ResetEvent(self._event) log.warning('ControlTransferAsync._finish result: %s', kernel32.get_error_str(rc)) else: kernel32.ResetEvent(self._event) rc = 0 pkt = usb_core.RequestType(value=setup_packet.request_type) duration = time.time() - self._time_start if pkt.direction == 'in' and setup_packet.length: log.debug( 'ControlTransferAsync._finish duration=%.6f s, length: %s, %s', duration, setup_packet.length, length_transferred.value) buffer = bytes( self._overlapped.data[:length_transferred.value]) else: log.debug('ControlTransferAsync._finish duration=%.6f s', duration) response = usb_core.ControlTransferResponse(setup_packet, rc, buffer) cbk_fn(response)
def _issue(self): if not self._commands: return True cbk_fn, setup_packet, buffer = self._commands[0] pkt = usb_core.RequestType(value=setup_packet.request_type) self._overlapped.reset() if pkt.direction == 'out': if setup_packet.length > 0: log.debug('ControlTransferAsync._issue buffer type: %s', type(buffer)) self._overlapped.data[:setup_packet.length] = np.frombuffer( buffer, dtype=np.uint8) result = WinUsb_ControlTransfer(self._winusb, setup_packet, self._overlapped.b, setup_packet.length, None, self._overlapped.ptr) result = sanitize_boolean_return_code(result) self._time_start = time.time() if result != kernel32.ERROR_IO_PENDING: if self.stop_code is None: self.stop_code = DeviceEvent.COMMUNICATION_ERROR log.warning('ControlTransferAsync._issue %s', kernel32.get_error_str(result)) response = usb_core.ControlTransferResponse( setup_packet, result, None) cbk_fn(response) return False return True
def _abort_all(self): commands, self._commands = self._commands, [] for cbk_fn, setup_packet, _ in commands: try: response = usb_core.ControlTransferResponse(setup_packet, TransferStatus.CANCELLED, None) cbk_fn(response) except Exception: log.exception('in callback while aborting')
def _control_transfer_pend(self, cbk_fn, setup_packet, data): if self._control_transfer is None: rsp = usb_core.ControlTransferResponse(setup_packet, TransferStatus.NO_DEVICE, None) cbk_fn(rsp) return False return self._control_transfer.pend(cbk_fn, setup_packet, data)
def close(self): commands, self._commands = self._commands, [] if self._transfer_pending: log.info('ControlTransferAsync.close cancel pending transfer, %d', len(commands)) transfer, self._transfer_pending = self._transfer_pending, None transfer.transfer[0].callback = _transfer_callback_discard_fn _lib.libusb_cancel_transfer(transfer.transfer) # callback function will be invoked later else: log.info('ControlTransferAsync.close %d', len(commands)) for cbk_fn, setup_packet, _ in commands: try: response = usb_core.ControlTransferResponse( setup_packet, TransferStatus.CANCELLED, None) cbk_fn(response) except Exception: log.exception('while closing in callback')
def close(self): self._commands, commands = [], self._commands # cannot abort control pipe using WinUSB! commands_len = len(commands) if commands: command = commands.pop(0) self._finish(command, do_wait=False) while commands: cbk_fn, setup_packet, _ = commands.pop(0) cbk_fn(usb_core.ControlTransferResponse(setup_packet, False, None)) if commands_len == 0: if self._event: kernel32.CloseHandle(self._event) self._event = None if self._overlapped: self._overlapped = None else: pass # defer to _close_event
def _finish(self, command, transfer): buffer = None rc = transfer.transfer[0].status cbk_fn, setup_packet, _ = command pkt = usb_core.RequestType(value=setup_packet.request_type) duration = time.time() - self._time_start if rc == TransferStatus.NO_DEVICE: log.warning('device_removed') if self.stop_code is None: self.stop_code = DeviceEvent.COMMUNICATION_ERROR if pkt.direction == 'out': log.debug('ControlTransferAsync._finish rc=%d, duration=%.6f s', rc, duration) else: actual_length = transfer.transfer[0].actual_length log.debug('ControlTransferAsync._finish rc=%d, duration=%.6f s, length: %s, %s', rc, duration, setup_packet.length, actual_length) buffer = bytes(transfer.buffer[8:(actual_length+8)]) response = usb_core.ControlTransferResponse(setup_packet, rc, buffer) cbk_fn(response)
def pend(self, cbk_fn, setup_packet: usb_core.SetupPacket, buffer=None): """Pend an asynchronous Control Transfer. :param cbk_fn: The function to call when the control transfer completes. A :class:`usb_core.ControlTransferResponse` is the sole argument. :param setup_packet: :param buffer: The buffer (if length > 0) for write transactions. :return: True if pending, False on error. """ if self.stop_code is not None: response = usb_core.ControlTransferResponse(setup_packet, self.stop_code, None) cbk_fn(response) return False command = [cbk_fn, setup_packet, buffer] was_empty = not bool(self._commands) self._commands.append(command) if was_empty: return self._issue() return True
def close(self): self._commands, commands = [], self._commands # cannot abort control pipe using WinUSB! commands_len = len(commands) if commands: command = commands.pop(0) rc = kernel32.WaitForSingleObject(self._event, int(CONTROL_TIMEOUT * 1100)) if rc != kernel32.WAIT_OBJECT_0: # transfer done log.warning('ControlTransferAsync.close but transaction hung') self._finish(command) while commands: cbk_fn, setup_packet, _ = commands.pop(0) cbk_fn(usb_core.ControlTransferResponse(setup_packet, False, None)) if commands_len == 0: if self._event: kernel32.CloseHandle(self._event) self._event = None if self._overlapped: self._overlapped = None else: pass # defer to _close_event