You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
USB host support on ESP32 (`--usb` builds): DisplayLink display adapters plus HID mice/keyboards, with display/panel auto-switching and hub-port recovery.
284
+
285
+
```python
286
+
from mpos import USBManager
287
+
288
+
if USBManager.is_available():
289
+
USBManager.arm_display()
290
+
USBManager.arm_hid()
291
+
```
292
+
See [USBManager](../frameworks/usb-manager.md) for details.
293
+
282
294
### SharedPreferences
283
295
Per-app configuration storage (exception to the pattern - instance-based).
Copy file name to clipboardExpand all lines: docs/frameworks/usb-manager.md
+6-2Lines changed: 6 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,14 +48,18 @@ The layers, bottom to top:
48
48
49
49
-**C module `usb`** (`c_mpos/usb/`): `Display` class (start/poll/ready, frame upload) plus module-level host functions (`bus_devices`, `lsusb`, `hub_ports`, `reset_port`, watchdog toggles) and HID transport (`hid_start/poll/drain/state/...`). Upstream Pico_USB_Disp is vendored under `c_mpos/usb/upstream/` with a few clearly-commented MPOS adaptations (hub-port watchdog, `lsusb`, held-handle hook).
50
50
-**Drivers**: `drivers/display/usb_display.py` (`USBDisplayDriver`, a `DisplayDriver` behind a shim bus) and `drivers/indev/usb_hid.py` (parser registry + `HIDHub` demux + `USBMouse` + `USBHIDKeyboard`). Report parsing is Python-side, so new device kinds never need C changes.
51
-
-**USBManager** (`mpos/usb/`): boot arming (`arm_display`, `arm_hid`), the 1 s LVGL poll timer (HID pump + display state machine + auto-switch), panel/USB swapping, touch remapping, and HID/watchdog coexistence (idle-reset suppression while HID is claimed or parked).
51
+
-**USBManager** (`mpos/usb/`): boot arming (`arm_display`, `arm_hid`), the 1 s LVGL poll timer (HID pump + display state machine + auto-switch), panel/USB swapping, touch remapping, and HID/watchdog coexistence (port-exact idle-reset skip for claimed HIDs, parked-only global suppression).
52
52
53
53
Only DisplayLink DL-1xx adapters work on ESP32-S3 (Full-Speed OTG); DL-165/DL-195 recommended. T6/MS91xx need High-Speed, i.e. ESP32-P4 only (protocol code is vendored but untested on hardware).
54
54
55
55
### HCD channel budget
56
56
57
57
The S3 DWC_OTG core has 8 host channels (~7 usable): one channel per USB *pipe*, held for the pipe's lifetime. Rule of thumb: **max 1 hub + 2 downstream devices** on S3. ESP32-P4/S31 have 16 channels, so **1 hub + 4 devices** fits there. Claim priority is display > mouse > keyboard; a claim that fails with channel exhaustion parks silently with backoff until a topology change or `usb.hid_retry()`.
58
58
59
+
### HID/watchdog coexistence
60
+
61
+
A healthy, enumerated HID reads exactly like a wedged adapter (connected + enabled, no bus growth), which the hub watchdog's idle auto-reset would otherwise `PORT_RESET`~15s after plug. Two-part answer: open HID handles resolve to their (hub, port), so the sweep skips the auto-reset exactly on HID-owned ports and logs `HID device, auto-reset skipped` inline, while other ports keep healing; parked devices have no open handle and stay covered by a global suppression (restored when the park clears). The disabled-port recovery path is never suppressed.
62
+
59
63
### Display switching
60
64
61
65
`mpos.main` arms the display at boot without waiting; the poll timer switches the UI over automatically when a monitor becomes ready and reverts on disconnect. The swap suspends the LVGL pump, tears down activities, repoints indevs to the new display (panel touch is remapped through the panel's own proven mapping — no per-board tables), moves the topmenu, and restarts the launcher. Resolution floor is 640x480: smaller modes need a sub-25 MHz pixel clock that real monitors cannot sync to.
@@ -120,6 +124,6 @@ usb.hid_loop_lag() # ms since the HID task pumped events (~100 healthy)
120
124
121
125
- ESP32-S3 only; DisplayLink DL-1xx only (tested on DL-165/DL-195).
122
126
- 640x480 minimum mode; rotation fixed to `_0`; RGB565 only.
123
-
- Full display + mouse + keyboard combo cannot fit the S3 channel budget persistently (the keyboard parks until something unplugs).
127
+
- Full display + mouse + keyboard combo cannot fit the S3 channel budget persistently (the keyboard parks until something unplugs); transient keyboard polling (`usb.hid_set_kbd_transient(True)`) holds no persistent pipe and is the experimental fit-the-combo option.
124
128
- A wedged adapter behind an externally powered hub is not recoverable by port resets — power-cut the adapter itself.
125
129
- Field upgrades across this rename need `--erase-all` or a lib re-sync: the frozen C module changed name (`usb_disp` to `usb`), so stale flash shadows will not fall back.
0 commit comments