Skip to content

Commit da9fa58

Browse files
authored
Merge pull request #118 from eightycc/issue_117
Fix #117: Rework host USB ready timeout
2 parents 30097f7 + 9b398e0 commit da9fa58

File tree

4 files changed

+64
-42
lines changed

4 files changed

+64
-42
lines changed

adafruit_hid/__init__.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919

2020
# imports
2121
from __future__ import annotations
22+
import time
23+
24+
try:
25+
import supervisor
26+
except ImportError:
27+
supervisor = None
2228

2329
try:
2430
from typing import Sequence
@@ -31,17 +37,46 @@
3137

3238

3339
def find_device(
34-
devices: Sequence[usb_hid.Device], *, usage_page: int, usage: int
40+
devices: Sequence[usb_hid.Device],
41+
*,
42+
usage_page: int,
43+
usage: int,
44+
timeout: int = None,
3545
) -> usb_hid.Device:
3646
"""Search through the provided sequence of devices to find the one with the matching
37-
usage_page and usage."""
47+
usage_page and usage.
48+
49+
:param timeout: Time in seconds to wait for USB to become ready before timing out.
50+
Defaults to None to wait indefinitely."""
51+
3852
if hasattr(devices, "send_report"):
3953
devices = [devices] # type: ignore
40-
for device in devices:
54+
device = None
55+
for dev in devices:
4156
if (
42-
device.usage_page == usage_page
43-
and device.usage == usage
44-
and hasattr(device, "send_report")
57+
dev.usage_page == usage_page
58+
and dev.usage == usage
59+
and hasattr(dev, "send_report")
4560
):
46-
return device
47-
raise ValueError("Could not find matching HID device.")
61+
device = dev
62+
break
63+
if device is None:
64+
raise ValueError("Could not find matching HID device.")
65+
66+
if supervisor is None:
67+
# Blinka doesn't have supervisor (see issue Adafruit_Blinka#711), so wait
68+
# one second for USB to become ready
69+
time.sleep(1.0)
70+
elif timeout is None:
71+
# default behavior: wait indefinitely for USB to become ready
72+
while not supervisor.runtime.usb_connected:
73+
time.sleep(1.0)
74+
else:
75+
# wait up to timeout seconds for USB to become ready
76+
for _ in range(timeout):
77+
if supervisor.runtime.usb_connected:
78+
return device
79+
time.sleep(1.0)
80+
raise OSError("Failed to initialize HID device. Is USB connected?")
81+
82+
return device

adafruit_hid/consumer_control.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
# pylint: disable=wrong-import-position
2020
import struct
21-
import time
2221
from . import find_device
2322

2423
try:
@@ -31,26 +30,23 @@
3130
class ConsumerControl:
3231
"""Send ConsumerControl code reports, used by multimedia keyboards, remote controls, etc."""
3332

34-
def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
33+
def __init__(self, devices: Sequence[usb_hid.Device], timeout: int = None) -> None:
3534
"""Create a ConsumerControl object that will send Consumer Control Device HID reports.
3635
36+
:param timeout: Time in seconds to wait for USB to become ready before timing out.
37+
Defaults to None to wait indefinitely.
38+
3739
Devices can be a sequence of devices that includes a Consumer Control device or a CC device
3840
itself. A device is any object that implements ``send_report()``, ``usage_page`` and
3941
``usage``.
4042
"""
41-
self._consumer_device = find_device(devices, usage_page=0x0C, usage=0x01)
43+
self._consumer_device = find_device(
44+
devices, usage_page=0x0C, usage=0x01, timeout=timeout
45+
)
4246

4347
# Reuse this bytearray to send consumer reports.
4448
self._report = bytearray(2)
4549

46-
# Do a no-op to test if HID device is ready.
47-
# If not, wait a bit and try once more.
48-
try:
49-
self.send(0x0)
50-
except OSError:
51-
time.sleep(1)
52-
self.send(0x0)
53-
5450
def send(self, consumer_code: int) -> None:
5551
"""Send a report to do the specified consumer control action,
5652
and then stop the action (so it will not repeat).

adafruit_hid/keyboard.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
* Author(s): Scott Shawcroft, Dan Halbert
1010
"""
1111

12-
import time
1312
from micropython import const
1413
import usb_hid
1514

@@ -39,14 +38,19 @@ class Keyboard:
3938

4039
# No more than _MAX_KEYPRESSES regular keys may be pressed at once.
4140

42-
def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
41+
def __init__(self, devices: Sequence[usb_hid.Device], timeout: int = None) -> None:
4342
"""Create a Keyboard object that will send keyboard HID reports.
4443
44+
:param timeout: Time in seconds to wait for USB to become ready before timing out.
45+
Defaults to None to wait indefinitely.
46+
4547
Devices can be a sequence of devices that includes a keyboard device or a keyboard device
4648
itself. A device is any object that implements ``send_report()``, ``usage_page`` and
4749
``usage``.
4850
"""
49-
self._keyboard_device = find_device(devices, usage_page=0x1, usage=0x06)
51+
self._keyboard_device = find_device(
52+
devices, usage_page=0x1, usage=0x06, timeout=timeout
53+
)
5054

5155
# Reuse this bytearray to send keyboard reports.
5256
self.report = bytearray(8)
@@ -65,14 +69,6 @@ def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
6569
# No keyboard LEDs on.
6670
self._led_status = b"\x00"
6771

68-
# Do a no-op to test if HID device is ready.
69-
# If not, wait a bit and try once more.
70-
try:
71-
self.release_all()
72-
except OSError:
73-
time.sleep(1)
74-
self.release_all()
75-
7672
def press(self, *keycodes: int) -> None:
7773
"""Send a report indicating that the given keys have been pressed.
7874

adafruit_hid/mouse.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
99
* Author(s): Dan Halbert
1010
"""
11-
import time
12-
1311
from . import find_device
1412

1513
try:
@@ -29,14 +27,19 @@ class Mouse:
2927
MIDDLE_BUTTON = 4
3028
"""Middle mouse button."""
3129

32-
def __init__(self, devices: Sequence[usb_hid.Device]):
30+
def __init__(self, devices: Sequence[usb_hid.Device], timeout: int = None) -> None:
3331
"""Create a Mouse object that will send USB mouse HID reports.
3432
33+
:param timeout: Time in seconds to wait for USB to become ready before timing out.
34+
Defaults to None to wait indefinitely.
35+
3536
Devices can be a sequence of devices that includes a keyboard device or a keyboard device
3637
itself. A device is any object that implements ``send_report()``, ``usage_page`` and
3738
``usage``.
3839
"""
39-
self._mouse_device = find_device(devices, usage_page=0x1, usage=0x02)
40+
self._mouse_device = find_device(
41+
devices, usage_page=0x1, usage=0x02, timeout=timeout
42+
)
4043

4144
# Reuse this bytearray to send mouse reports.
4245
# report[0] buttons pressed (LEFT, MIDDLE, RIGHT)
@@ -45,14 +48,6 @@ def __init__(self, devices: Sequence[usb_hid.Device]):
4548
# report[3] wheel movement
4649
self.report = bytearray(4)
4750

48-
# Do a no-op to test if HID device is ready.
49-
# If not, wait a bit and try once more.
50-
try:
51-
self._send_no_move()
52-
except OSError:
53-
time.sleep(1)
54-
self._send_no_move()
55-
5651
def press(self, buttons: int) -> None:
5752
"""Press the given mouse buttons.
5853

0 commit comments

Comments
 (0)