diff --git a/tools/odrive/usbbulk_transport.py b/tools/odrive/usbbulk_transport.py index f513789f..5eecbd24 100644 --- a/tools/odrive/usbbulk_transport.py +++ b/tools/odrive/usbbulk_transport.py @@ -35,6 +35,12 @@ class USBBulkTransport(odrive.protocol.PacketSource, odrive.protocol.PacketSink) return string def init(self): + # Under some conditions, the Linux USB/libusb stack ends up in a corrupt + # state where there are a few packets in a receive queue but a call + # to epr.read() does not return these packet until a new packet arrives. + # This undesirable queue can be cleared by resetting the device. + self.dev.reset() + try: if self.dev.is_kernel_driver_active(1): self.dev.detach_kernel_driver(1) @@ -106,7 +112,7 @@ class USBBulkTransport(odrive.protocol.PacketSource, odrive.protocol.PacketSink) else: # Try resetting halt/stall condition try: - self.epw.clear_halt() + self.epr.clear_halt() except usb.core.USBError: raise odrive.protocol.ChannelBrokenException() # Retry transfer diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index be19adcd..a8c0e680 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -73,11 +73,15 @@ class Event(): """ Alternative to threading.Event(), enhanced by the subscribe() function that the original fails to provide. + @param Trigger: if supplied, the newly created event will be triggered + as soon as the trigger event becomes set """ - def __init__(self): + def __init__(self, trigger=None): self._evt = threading.Event() self._subscribers = [] self._mutex = threading.Lock() + if not trigger is None: + trigger.subscribe(self.set()) def is_set(self): return self._evt.is_set() @@ -120,7 +124,18 @@ class Event(): self._mutex.release() def wait(self, timeout=None): - return self._evt.wait(timeout=timeout) + if not self._evt.wait(timeout=timeout): + raise TimeoutError() + + def trigger_after(self, timeout): + """ + Triggers the event after the specified timeout. + This function returns immediately. + """ + def delayed_trigger(): + if not self.wait(timeout=timeout): + self.set() + threading.Thread(target=delayed_trigger, daemon=True).start() def wait_any(*events, timeout=None): """