Skip to content

Commit 556a126

Browse files
committed
wip: getting closer
1 parent 2b4c88d commit 556a126

6 files changed

Lines changed: 104 additions & 17 deletions

File tree

shared-bindings/usb_hid/__init__.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@
4040
//| """Tuple of all active HID device interfaces."""
4141
//|
4242

43-
//| def configure_usb(devices: Sequence[Device, ...]=) -> None:
43+
//| def configure_usb(devices: Optional[Sequence[Device, ...]]) -> None:
4444
//| """Configure the USB HID devices that will be available.
4545
//| Can be called in ``boot.py``, before USB is connected.
4646
//|
4747
//| :param Sequence devices: `Device` objects.
4848
//| If `devices` is empty, HID is disabled. The order of the ``Devices``
4949
//| may matter to the host. For instance, for MacOS, put the mouse device
50-
//| before any Gamepad or Digitizer HID device.
50+
//| before any Gamepad or Digitizer HID device or else it will not work.
5151
//| ...
5252
//|
5353
STATIC mp_obj_t usb_hid_configure_usb(mp_obj_t devices) {
@@ -61,10 +61,15 @@ STATIC mp_obj_t usb_hid_configure_usb(mp_obj_t devices) {
6161
}
6262
}
6363

64-
if (!common_hal_usb_hid_configure_usb(descriptors)) {
65-
mp_raise_RuntimeError(translate("Cannot change USB devices now"));
64+
switch (common_hal_usb_hid_configure_usb(descriptors)) {
65+
case USB_CONFIG_TOO_LATE:
66+
mp_raise_RuntimeError(translate("Cannot change USB devices now"));
67+
break;
68+
case USB_CONFIG_NON_DEVICE:
69+
mp_raise_ValueError_varg(translate("non-Device in %q", MP_QSTR_devices));
70+
break;
71+
default:
6672
}
67-
6873
return mp_const_none;
6974
}
7075
MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_configure_usb_obj, usb_hid_configure_usb);

shared-bindings/usb_hid/__init__.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,12 @@
3232

3333
extern mp_obj_tuple_t common_hal_usb_hid_devices;
3434

35+
typedef enum {
36+
USB_CONFIG_OK = 0,
37+
USB_CONFIG_TOO_LATE = 1,
38+
USB_CONFIG_NON_DEVICE = 2,
39+
} usb_hid_configure_status;
40+
41+
usb_hid_configure_status common_hal_usb_hid_configure_usb(mp_obj_t devices);
42+
3543
#endif // SHARED_BINDINGS_USB_HID_H

shared-module/usb_hid/Device.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,13 @@ const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = {
156156

157157
void common_hal_usb_hid_device_construct(usb_hid_dev_obj_t *self, mp_obj_array_t *descriptor, uint8_t usage_page, uint8_t usage, uint8_t in_report_length, uint8_t out_report_length, uint8_t report_id_index) {
158158
// report buffer pointers are NULL at start, and are created on demand.
159-
self->descriptor = descriptor;
159+
self->descriptor_obj = descriptor;
160+
161+
mp_buffer_info_t bufinfo;
162+
mp_get_buffer_raise(descriptor, &bufinfo, MP_BUFFER_READ);
163+
self->descriptor = bufinfo.buf;
164+
self->descriptor_length = bufinfo.len;
165+
160166
self->usage_page = usage_page;
161167
self->usage = usage;
162168
self->in_report_length = in_report_length;

shared-module/usb_hid/Device.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@
3434

3535
typedef struct {
3636
mp_obj_base_t base;
37+
// If not MP_OBJ_NULL, points to Python array object whose contents are the descriptor.
38+
mp_obj_t descriptor_obj;
39+
// If not NULL, points to raw bytes that are the descriptor.
40+
uint8_t *descriptor;
3741
uint8_t *in_report_buffer;
3842
uint8_t *out_report_buffer;
39-
uint8_t *descriptor;
4043
uint16_t descriptor_length;
4144
uint8_t usage_page;
4245
uint8_t usage;

shared-module/usb_hid/__init__.c

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,18 @@ static const uint8_t usb_hid_descriptor_template[] = {
5353

5454
// Is the HID device enabled?
5555
bool usb_hid_enabled;
56-
mp_obj_t usb_hid_devices;
56+
supervisor_allocation *combined_hid_report_descriptor_allocation;
57+
supervisor_allocation *devices_allocation;
5758

59+
60+
// This is the interface descriptor, not the report descriptor.
5861
size_t usb_hid_descriptor_length(void) {
5962
return sizeof(usb_hid_descriptor);
6063
}
6164

62-
static const char[] usb_hid_interface_name = USB_INTERFACE_NAME " Mass Storage";
65+
static const char[] usb_hid_interface_name = USB_INTERFACE_NAME " HID";
6366

67+
// This is the interface descriptor, nto the report descriptor.
6468
size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interface, uint8_t *current_endpoint, uint8_t* current_interface_string, uint16_t report_descriptor_length) {
6569
memcpy(descriptor_buf, usb_hid_descriptor_template, sizeof(usb_hid_descriptor_template));
6670

@@ -74,23 +78,79 @@ size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
7478
return sizeof(usb_hid_descriptor_template);
7579
}
7680

77-
void usb_hid_build_report_descriptor() {
78-
}
79-
80-
bool common_hal_usb_hid_configure_usb(mp_obj_t devices) {
81+
usb_hid_configure_status common_hal_usb_hid_configure_usb(mp_obj_t devices) {
8182
// We can't change the devices once we're connected.
8283
if (tud_connected()) {
83-
return false;
84+
return USB_CONFIG_TOO_LATE;
8485
}
8586

8687
// Assume no devices to start.
8788
usb_hid_enabled = false;
8889
if (devices == mp_const_none) {
89-
return true;
90+
return USB_CONFIG_OK;
9091
}
91-
}
9292

93-
void usb_hid_build_report
93+
size_t total_report_descriptors_length = 0;
94+
95+
// Build a combined report descriptor
96+
97+
mp_int_t len = mp_obj_get_int(mp_obj_len(devices));
98+
99+
// First get the total size.
100+
for (size_t i = 0; i < len; i++) {
101+
mp_obj_t item = mp_obj_subscr(devices, mp_obj_new_small_int(i), MP_OBJ_SENTINEL);
102+
if (!MP_OBJ_IS_TYPE(item, &usb_hid_device_type)) {
103+
return USB_CONFIG_NON_DEVICE; for (size_t i = 0; i < len; i++) {
104+
mp_obj_t item = (devices, mp_obj_new_small_int(i), MP_OBJ_SENTINEL);
105+
if (!MP_OBJ_IS_TYPE(item, &usb_hid_device_type)) {
106+
return USB_CONFIG_NON_DEVICE;
107+
}
108+
total_report_descriptors_length += device->report_descriptor_length;
109+
}
110+
111+
}
112+
total_report_descriptors_length += device->report_descriptor_length;
113+
}
114+
if (len == 1) {
115+
// Don't need space for a report id if there's only one device.
116+
total_report_descriptors_length -= 2;
117+
}
118+
119+
// Allocate storage that persists across VMs to build the combined descriptor
120+
// and to remember the device details.
121+
122+
// allocate_memory(length, highaddress=false, movable=true)
123+
combined_hid_report_descriptor_allocation = allocate_memory(total_report_descriptors_length, false, true);
124+
125+
devices_allocation = allocate_memory(sizeof(usb_hid_device_obj_t) * len);
126+
usb_hid_device_obj_t devices[] = (devices[]) device_details_allocation->ptr;
127+
128+
uint8_t *descriptor_start = combined_hid_report_descriptor_allocation->ptr;
129+
130+
for (size_t i = 0; i < len; i++) {
131+
usb_hid_device_obj_t *device = MP_OBJ_TO_PTR(devices, mp_obj_new_small_int(i), MP_OBJ_SENTINEL);
132+
133+
// Copy the report descriptor for this device.
134+
if (len == 1) {
135+
// Theres only one device, so it shouldn't have a report ID.
136+
// Copy the descriptor, but splice out the report id indicator and value (2 bytes).
137+
memcpy(descriptor_start, device->descriptor, device->report_id_index - 1);
138+
descriptor_start += device->report_id_index - 1;
139+
memcpy(descriptor_start, device->descriptor + device->report_id_index + 1,
140+
device->report_descriptor_length - device->report_id_index - 1);
141+
} else {
142+
// Copy the whole descriptor and fill in the report id.
143+
memcpy(descriptor_start, device->descriptor, device->descriptor_len);
144+
descriptor_start[device->report_id_index] = i + 1;
145+
descriptor_start += device->descriptor_len;
146+
}
147+
148+
// Copy the device data and discard any descriptor-bytes object pointer.
149+
memcpy(&devices[i], device, sizeof(usb_hid_device_obj_t));
150+
devices[i].descriptor_obj = mp_const_none;
151+
}
152+
153+
}
94154

95155
void usb_hid_gc_collect(void) {
96156
// Once tud_mounted() is true, we're done with the constructed descriptors.

supervisor/shared/memory.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ enum {
4545
,
4646
CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT =
4747
0
48+
#if CIRCUITPY_USB_HID
49+
+ 2
50+
#endif
4851
#if CIRCUITPY_DISPLAYIO
4952
#if CIRCUITPY_TERMINALIO
5053
+ 1
@@ -308,9 +311,11 @@ void supervisor_move_memory(void) {
308311

309312
// Notify clients that their movable allocations may have moved.
310313
old_allocations = &old_allocations_array[0];
314+
311315
#if CIRCUITPY_DISPLAYIO
312316
supervisor_display_move_memory();
313317
#endif
318+
314319
// Add calls to further clients here.
315320
old_allocations = NULL;
316321
}

0 commit comments

Comments
 (0)