Skip to content

Commit 01cc684

Browse files
djthorpeclaude
andauthored
Added usb support (#15)
* Added usb support * Added libusb code * Added libusb code * Updated USB * Updated test * Updated * Add HID boot-protocol keyboard/mouse classification Names hw_usb_device_protocol_t's keyboard(1)/mouse(2) codes and adds hw_usb_device_protocol_to_string(), so an interface's boot-protocol role is visible directly rather than as a raw byte - verified against real composite keyboard/mouse hardware on rpi3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Updates after PR comments * Added TODO --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 9fcc9ee commit 01cc684

30 files changed

Lines changed: 2334 additions & 94 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ if(DEFINED PICO_BOARD)
7575
add_compile_definitions(PICO_CYW43_SUPPORTED=1)
7676
endif()
7777

78+
if(PICOFUSE_USB)
79+
# Every RP2040/RP2350 board has the same on-chip dual-role USB
80+
# controller (unlike CYW43 above, nothing board-specific to check).
81+
# hw/pico/usb.c (compiled instead of the stub only when PICOFUSE_USB
82+
# holds - see its own CMakeLists.txt) needs the TinyUSB host stack;
83+
# tusb_config.h (include/runtime/pico) configures it for host-only,
84+
# no interface class drivers - see that file's own doc.
85+
list(APPEND _picosdk_targets tinyusb_host)
86+
endif()
87+
7888
# Generate the combined Pico SDK bundle
7989
set(_pico_clib_interface_dir ${PICO_SDK_PATH}/src/rp2_common/pico_clib_interface)
8090
set(_pico_runtime_dir ${PICO_SDK_PATH}/src/rp2_common/pico_runtime)

‎doxygen/modules_diagram.dox.inc‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ digraph modules {
3939
UART [label="UART", URL="\ref UART"];
4040
DeviceIO [label="Device I/O", URL="\ref DeviceIO"];
4141
Watchdog [label="Watchdog", URL="\ref Watchdog"];
42+
USB [label="USB", URL="\ref USB"];
4243
SPI [label="SPI", URL="\ref SPI"];
4344
I2C [label="I2C", URL="\ref I2C"];
4445
Device [label="Device", URL="\ref Device"];
@@ -87,6 +88,7 @@ digraph modules {
8788
Hardware -> UART;
8889
Hardware -> DeviceIO;
8990
Hardware -> Watchdog;
91+
Hardware -> USB;
9092
DeviceIO -> SPI;
9193
DeviceIO -> I2C;
9294
Device -> BME680;

‎include/picofuse/app.h‎

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ typedef enum {
7171
///< it from there. Has no effect when
7272
///< the platform has no watchdog
7373
///< backend.
74+
app_flag_usb = (1 << 8), ///< Initialize the USB host subsystem
75+
///< and register it with HID (see
76+
///< @ref app_usb and @ref app_hid) -
77+
///< hotplug activity flows in as
78+
///< hid_event_type_usb events
79+
///< automatically. Call
80+
///< hw_usb_set_callback() directly on
81+
///< the returned handle to replace that
82+
///< with your own callback instead. Has
83+
///< no effect when the platform has no
84+
///< USB host backend.
7485
} app_flag_t;
7586

7687
/**
@@ -133,13 +144,15 @@ typedef void (*app_callback_event_t)(app_t *app, sys_event_t event,
133144
* internal temperature sensor as a HID metric source if
134145
* @ref app_flag_temperature is set, enables the watchdog if
135146
* @ref app_flag_watchdog is set and available (see @ref app_watchdog),
136-
* then runs the event loop across every available core if
137-
* @ref app_flag_multicore is set, or on the calling thread alone
138-
* otherwise. Every run loop tick calls `hw_poll()`, which feeds the
139-
* watchdog when enabled (see `hw_watchdog_enable()`). Blocks until
140-
* @ref app_shutdown is called from within a callback (or from another
141-
* thread), then tears down (`hid_deinit()`, `hw_led_deinit()`,
142-
* `hw_watchdog_deinit()`, `hw_exit()`, `sys_exit()`).
147+
* initializes the USB host subsystem and registers it with HID if
148+
* @ref app_flag_usb is set and available (see @ref app_usb and
149+
* hw_usb_register_hid()), then runs the event loop across every
150+
* available core if @ref app_flag_multicore is set, or on the calling
151+
* thread alone otherwise. Every run loop tick calls `hw_poll()`, which
152+
* feeds the watchdog when enabled (see `hw_watchdog_enable()`). Blocks
153+
* until @ref app_shutdown is called from within a callback (or from
154+
* another thread), then tears down (`hid_deinit()`, `hw_led_deinit()`,
155+
* `hw_watchdog_deinit()`, `hw_usb_deinit()`, `hw_exit()`, `sys_exit()`).
143156
*/
144157
int app_main(int argc, char *argv[], app_flag_t flags,
145158
app_callback_start_t on_start, app_callback_event_t on_event,
@@ -188,6 +201,20 @@ hw_led_t *app_led(const app_t *app);
188201
*/
189202
hw_watchdog_t *app_watchdog(const app_t *app);
190203

204+
/**
205+
* @brief Get the USB host handle initialized for this app.
206+
* @ingroup Application
207+
* @param app Application instance.
208+
* @return USB host handle, or NULL if @ref app_flag_usb was not passed to
209+
* app_main(), or the platform has no USB host backend (see hw_usb_init()).
210+
*
211+
* Already registered with HID (see @ref app_hid) via hw_usb_register_hid()
212+
* - hotplug activity flows in as hid_event_type_usb events. Call
213+
* hw_usb_set_callback() directly on this handle to replace that with your
214+
* own callback instead.
215+
*/
216+
hw_usb_t *app_usb(const app_t *app);
217+
191218
/** @} */
192219

193220
///////////////////////////////////////////////////////////////////////////////

‎include/picofuse/hid/device.h‎

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -305,28 +305,6 @@ hid_device_t *hid_register_timer(hid_t *instance, uint32_t id,
305305
*/
306306
hid_device_t *hid_register_signal(hid_t *instance, void *userdata);
307307

308-
/**
309-
* @brief Register a USB host hotplug observer.
310-
* @ingroup HID
311-
* @param instance HID instance that owns the USB registration.
312-
* @return Registered HID device descriptor, or NULL on failure (for
313-
* example, if the platform has no USB host controller support built in).
314-
*
315-
* Initializes the USB host subsystem (see `hw_usb_init()`), which
316-
* enumerates already-attached devices through the same attach/detach
317-
* callback used for live hotplug. Only one USB registration is permitted
318-
* at a time, since `hw_usb_init()` is itself a process-wide singleton.
319-
*
320-
* Attach/detach activity is currently only logged via `sys_debugf()`; it
321-
* is not yet delivered as HID events.
322-
*
323-
* @todo Not implemented yet - always returns NULL. There is no
324-
* `hw_usb_init()`/`hw_usb_t` backend anywhere in this codebase yet (see
325-
* `src/picofuse/hid/usb.c`); this needs a real USB host module under
326-
* `picofuse/hw` before this can do anything.
327-
*/
328-
hid_device_t *hid_register_usb(hid_t *instance);
329-
330308
/**
331309
* @brief Register a Wi-Fi connection-state observer.
332310
* @ingroup HID

‎include/picofuse/hid/event.h‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#pragma once
2727
#include "device.h"
2828
#include "keycode.h"
29+
#include <picofuse/hw/usb.h>
2930
#include <picofuse/hw/wifi.h>
3031
#include <picofuse/pix/types.h>
3132
#include <picofuse/sys/date.h>
@@ -60,6 +61,7 @@ typedef enum {
6061
hid_event_type_wifi = 6,
6162
hid_event_type_iostream = 7,
6263
hid_event_type_time = 8,
64+
hid_event_type_usb = 9,
6365
} hid_event_type_t;
6466

6567
/**
@@ -126,6 +128,25 @@ typedef struct {
126128
bool has_network; ///< True if network is populated.
127129
} hid_wifi_t;
128130

131+
/**
132+
* @brief USB-hotplug-oriented HID event payload.
133+
* @ingroup HIDEvents
134+
*
135+
* @p device is copied by value into this event at the point it's queued -
136+
* unlike hw_usb_callback_t's own @p device parameter (which some backends
137+
* pass as a pointer to worker-thread-local storage, valid only for the
138+
* duration of that callback), this is safe to read at any point up until
139+
* hid_event_free(). @p has_device is false for the enumeration-complete
140+
* marker (see hw_usb_init()'s own doc), in which case @p device itself is
141+
* unspecified.
142+
*/
143+
typedef struct {
144+
hw_usb_event_t event; ///< USB hotplug event (see hw_usb_event_t).
145+
hw_usb_device_t device; ///< Associated device - only valid if has_device
146+
///< is true.
147+
bool has_device; ///< True if device is populated.
148+
} hid_usb_t;
149+
129150
/**
130151
* @brief Stream-readiness-oriented HID event payload.
131152
* @ingroup HIDEvents
@@ -161,6 +182,7 @@ typedef struct {
161182
hid_wifi_t wifi;
162183
hid_iostream_t iostream;
163184
hid_time_t time;
185+
hid_usb_t usb;
164186
} data; ///< Payload selected by type.
165187
} hid_event_t;
166188

@@ -237,6 +259,19 @@ bool hid_event_queue_signal(hid_device_t *device, sys_env_signal_t signal);
237259
bool hid_event_queue_wifi(hid_device_t *device, hw_wifi_event_t event,
238260
const hw_wifi_network_t *network);
239261

262+
/**
263+
* @brief Queue a USB hotplug HID event to the owning HID instance queue.
264+
* @ingroup HIDEvents
265+
* @param device HID device associated with the event.
266+
* @param event USB hotplug event to publish (see hw_usb_event_t).
267+
* @param usb_device Associated device, or NULL for the enumeration-complete
268+
* marker. Copied by value into the queued event - see hid_usb_t.
269+
* @retval true Event queued successfully.
270+
* @retval false Queueing failed.
271+
*/
272+
bool hid_event_queue_usb(hid_device_t *device, hw_usb_event_t event,
273+
const hw_usb_device_t *usb_device);
274+
240275
/**
241276
* @brief Queue a stream-readiness HID event to the owning HID instance
242277
* queue.

‎include/picofuse/hw.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
#include "hw/pwm.h"
1818
#include "hw/spi.h"
1919
#include "hw/uart.h"
20+
#include "hw/usb.h"
2021
#include "hw/watchdog.h"
2122
#include "hw/wifi.h"

0 commit comments

Comments
 (0)