Skip to content

Commit 4f8ff12

Browse files
committed
wip
1 parent 82a952b commit 4f8ff12

File tree

8 files changed

+286
-185
lines changed

8 files changed

+286
-185
lines changed

locale/circuitpython.pot

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,6 @@ msgstr ""
103103
msgid "%q must be %d-%d"
104104
msgstr ""
105105

106-
#: shared-bindings/usb_hid/Device.c
107-
msgid "%q must be 0-255"
108-
msgstr ""
109-
110-
#: shared-bindings/usb_hid/Device.c
111-
msgid "%q must be 1-255"
112-
msgstr ""
113-
114106
#: py/argcheck.c
115107
msgid "%q must be >= %d"
116108
msgstr ""
@@ -127,10 +119,6 @@ msgstr ""
127119
msgid "%q must be >= 1"
128120
msgstr ""
129121

130-
#: shared-bindings/usb_hid/Device.c
131-
msgid "%q must be None or between 1 and len(report_descriptor)-1"
132-
msgstr ""
133-
134122
#: py/argcheck.c
135123
msgid "%q must be a string"
136124
msgstr ""
@@ -168,6 +156,10 @@ msgstr ""
168156
msgid "%q() takes %d positional arguments but %d were given"
169157
msgstr ""
170158

159+
#: shared-bindings/usb_hid/Device.c
160+
msgid "%q, %q, and %q must all be the same length"
161+
msgstr ""
162+
171163
#: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c
172164
#, c-format
173165
msgid "%s error 0x%x"
@@ -1518,6 +1510,11 @@ msgstr ""
15181510
msgid "Missing jmp_pin. Instruction %d jumps on pin"
15191511
msgstr ""
15201512

1513+
#: shared-module/usb_hid/Device.c
1514+
#, c-format
1515+
msgid "More than %d report ids not supported"
1516+
msgstr ""
1517+
15211518
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
15221519
msgid "Must be a %q subclass."
15231520
msgstr ""

py/argcheck.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t
197197

198198
size_t mp_arg_validate_length_with_name(mp_int_t i, size_t length, qstr arg_name, qstr length_name) {
199199
if (i != (mp_int_t)length) {
200-
mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys);
200+
mp_raise_ValueError_varg(translate("%q length must be %q"), arg_name, length_name);
201201
}
202202
return (size_t)i;
203203
}

shared-bindings/usb_hid/Device.c

Lines changed: 124 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -31,46 +31,53 @@
3131
//| class Device:
3232
//| """HID Device specification"""
3333
//|
34-
//| def __init__(self, *, descriptor: ReadableBuffer, usage_page: int, usage: int, in_report_length: int, out_report_length: int = 0, report_id_index: Optional[int]) -> None:
34+
//| def __init__(self, *, descriptor: ReadableBuffer, usage_page: int, usage: int, in_report_lengths: Sequence[int], out_report_lengths: Sequence[int]) -> None:
3535
//| """Create a description of a USB HID device. The actual device is created when you
3636
//| pass a `Device` to `usb_hid.enable()`.
3737
//|
3838
//| :param ReadableBuffer report_descriptor: The USB HID Report descriptor bytes. The descriptor is not
3939
//| not verified for correctness; it is up to you to make sure it is not malformed.
4040
//| :param int usage_page: The Usage Page value from the descriptor. Must match what is in the descriptor.
4141
//| :param int usage: The Usage value from the descriptor. Must match what is in the descriptor.
42-
//| :param int in_report_length: Size in bytes of the HID report sent to the host.
43-
//| "In" is with respect to the host.
44-
//| :param int out_report_length: Size in bytes of the HID report received from the host.
45-
//| "Out" is with respect to the host. If no reports are expected, use 0.
46-
//| :param int report_id_index: position of byte in descriptor that contains the Report ID.
47-
//| A Report ID will be assigned when the device is created. If there is no
48-
//| Report ID, use ``None``.
42+
//| :param int report_ids: Sequence of report ids used by the descriptor.
43+
//| :param int in_report_lengths: Sequence of sizes in bytes of the HIDs report sent to the host.
44+
//| The sizes are in order of the ``report_ids``.
45+
//| "IN" is with respect to the host.
46+
//| :param int out_report_lengths: Size in bytes of the HID report received from the host.
47+
//| The sizes are in order of the ``report_ids``.
48+
//| "OUT" is with respect to the host.
49+
//|
50+
//| ``report_ids``, ``in_report_lengths``, and ``out_report_lengths`` must all be the same length.
4951
//| """
5052
//| ...
5153
//|
5254
//| KEYBOARD: Device
53-
//| """Standard keyboard device supporting keycodes 0x00-0xDD, modifiers 0xE-0xE7, and five LED indicators."""
55+
//| """Standard keyboard device supporting keycodes 0x00-0xDD, modifiers 0xE-0xE7, and five LED indicators.
56+
//| Uses Report ID 1 for its IN and OUT reports.
57+
//| """
5458
//|
5559
//| MOUSE: Device
5660
//| """Standard mouse device supporting five mouse buttons, X and Y relative movements from -127 to 127
57-
//| in each report, and a relative mouse wheel change from -127 to 127 in each report."""
61+
//| in each report, and a relative mouse wheel change from -127 to 127 in each report.
62+
//| Uses Report ID 2 for its IN reports.
63+
//| """
5864
//|
5965
//| CONSUMER_CONTROL: Device
60-
//| """Consumer Control device supporting sent values from 1-652, with no rollover."""
66+
//| """Consumer Control device supporting sent values from 1-652, with no rollover.
67+
//| Uses Report ID 3 for its IN reports."""
6168
//|
6269

6370
STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
6471
usb_hid_device_obj_t *self = m_new_obj(usb_hid_device_obj_t);
6572
self->base.type = &usb_hid_device_type;
66-
enum { ARG_report_descriptor, ARG_usage_page, ARG_usage, ARG_in_report_length, ARG_out_report_length, ARG_report_id_index };
73+
enum { ARG_report_descriptor, ARG_usage_page, ARG_usage, ARG_report_ids, ARG_in_report_lengths, ARG_out_report_lengths };
6774
static const mp_arg_t allowed_args[] = {
6875
{ MP_QSTR_report_descriptor, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
6976
{ MP_QSTR_usage_page, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
7077
{ MP_QSTR_usage, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
71-
{ MP_QSTR_in_report_length, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
72-
{ MP_QSTR_out_report_length, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 } },
73-
{ MP_QSTR_report_id_index, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none } },
78+
{ MP_QSTR_report_ids, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
79+
{ MP_QSTR_in_report_lengths, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
80+
{ MP_QSTR_out_report_lengths, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
7481
};
7582

7683
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -81,76 +88,128 @@ STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args
8188
mp_obj_t descriptor = mp_obj_new_bytearray(descriptor_bufinfo.len, descriptor_bufinfo.buf);
8289

8390
const mp_int_t usage_page_arg = args[ARG_usage_page].u_int;
84-
if (usage_page_arg <= 0 || usage_page_arg > 255) {
85-
mp_raise_ValueError_varg(translate("%q must be 1-255"), MP_QSTR_usage_page);
86-
}
91+
mp_arg_validate_int_range(usage_page_arg, 1, 255, MP_QSTR_usage_page);
8792
const uint8_t usage_page = usage_page_arg;
8893

8994
const mp_int_t usage_arg = args[ARG_usage].u_int;
90-
if (usage_arg <= 0 || usage_arg > 255) {
91-
mp_raise_ValueError_varg(translate("%q must be 1-255"), MP_QSTR_usage);
92-
}
95+
mp_arg_validate_int_range(usage_arg, 1, 255, MP_QSTR_usage_page);
9396
const uint8_t usage = usage_arg;
9497

95-
const mp_int_t in_report_length_arg = args[ARG_in_report_length].u_int;
96-
if (in_report_length_arg <= 0 || in_report_length_arg > 255) {
97-
mp_raise_ValueError_varg(translate("%q must be 1-255"), MP_QSTR_in_report_length);
98-
}
99-
const uint8_t in_report_length = in_report_length_arg;
98+
mp_obj_t report_ids = args[ARG_report_ids].u_obj;
99+
mp_obj_t in_report_lengths = args[ARG_in_report_lengths].u_obj;
100+
mp_obj_t out_report_lengths = args[ARG_out_report_lengths].u_obj;
100101

101-
const mp_int_t out_report_length_arg = args[ARG_out_report_length].u_int;
102-
if (out_report_length_arg < 0 || out_report_length_arg > 255) {
103-
mp_raise_ValueError_varg(translate("%q must be 0-255"), MP_QSTR_out_report_length);
102+
size_t report_ids_count = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(report_ids));
103+
if (MP_OBJ_SMALL_INT_VALUE(mp_obj_len(in_report_lengths)) != report_ids_count ||
104+
MP_OBJ_SMALL_INT_VALUE(mp_obj_len(out_report_lengths)) != report_ids_count) {
105+
mp_raise_ValueError_varg(translate("%q, %q, and %q must all be the same length"),
106+
MP_QSTR_report_ids, MP_QSTR_in_report_lengths, MP_QSTR_out_report_lengths);
104107
}
105-
const uint8_t out_report_length = out_report_length_arg;
106-
107-
const mp_obj_t report_id_index_arg = args[ARG_report_id_index].u_obj;
108-
uint8_t report_id_index = 0;
109-
if (report_id_index_arg != mp_const_none) {
110-
const mp_int_t report_id_index_int = mp_obj_int_get_checked(report_id_index_arg);
111-
if (report_id_index_int <= 0 || (uint32_t)report_id_index_int >= descriptor_bufinfo.len) {
112-
mp_raise_ValueError_varg(translate("%q must be None or between 1 and len(report_descriptor)-1"),
113-
MP_QSTR_report_id_index);
114-
}
115-
report_id_index = report_id_index_int;
108+
109+
uint8_t report_ids_array[report_ids_count];
110+
uint8_t in_report_lengths_array[report_ids_count];
111+
uint8_t out_report_lengths_array[report_ids_count];
112+
113+
// Validate the ids and lengths are all integers in range.
114+
for (size_t i = 0; i < report_ids_count; i++) {
115+
mp_obj_t i_obj = MP_OBJ_NEW_SMALL_INT(i);
116+
117+
report_ids_array[i] = (uint8_t)mp_arg_validate_int_range(
118+
// It's not the actual argument that's out of range, but its elements.
119+
// But the error message is close enough.
120+
MP_OBJ_SMALL_INT_VALUE(mp_obj_subscr(report_ids, i_obj, MP_OBJ_SENTINEL)),
121+
1, 255, MP_QSTR_report_ids);
122+
123+
in_report_lengths_array[i] = (uint8_t)mp_arg_validate_int_range(
124+
MP_OBJ_SMALL_INT_VALUE(mp_obj_subscr(in_report_lengths_array, i_obj, MP_OBJ_SENTINEL)),
125+
0, 255, MP_QSTR_in_report_lengths);
126+
127+
out_report_lengths_array[i] = (uint8_t)mp_arg_validate_int_range(
128+
MP_OBJ_SMALL_INT_VALUE(mp_obj_subscr(out_report_lengths_array, i_obj, MP_OBJ_SENTINEL)),
129+
0, 255, MP_QSTR_out_report_lengths);
116130
}
117131

118132
common_hal_usb_hid_device_construct(
119-
self, descriptor, usage_page, usage, in_report_length, out_report_length, report_id_index);
133+
self, descriptor, usage_page, usage, report_ids_count, report_ids_array, in_report_lengths_array, out_report_lengths_array);
120134
return (mp_obj_t)self;
121135
}
122136

123137

124-
//| def send_report(self, buf: ReadableBuffer) -> None:
125-
//| """Send a HID report."""
138+
//| def send_report(self, buf: ReadableBuffer, report_id: Optional[int] = None) -> None:
139+
//| """Send an HID report.
140+
//| """
126141
//| ...
127142
//|
128-
STATIC mp_obj_t usb_hid_device_send_report(mp_obj_t self_in, mp_obj_t buffer) {
129-
usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
143+
STATIC mp_obj_t usb_hid_device_send_report(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
144+
usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
145+
146+
enum { ARG_buf, ARG_report_id };
147+
static const mp_arg_t allowed_args[] = {
148+
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ },
149+
{ MP_QSTR_report_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
150+
};
151+
152+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
153+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
130154

131155
mp_buffer_info_t bufinfo;
132-
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ);
156+
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
157+
158+
uint8_t report_id = 0;
159+
if (args[ARG_report_id].u_obj != mp_const_none) {
160+
const mp_int_t report_id_arg = mp_obj_int_get_checked(args[ARG_report_id].u_obj);
161+
report_id = mp_arg_validate_int_range(report_id_arg, 1, 255, MP_QSTR_report_id);
162+
}
133163

134-
common_hal_usb_hid_device_send_report(self, ((uint8_t *)bufinfo.buf), bufinfo.len);
164+
common_hal_usb_hid_device_send_report(self, ((uint8_t *)bufinfo.buf), bufinfo.len, report_id);
135165
return mp_const_none;
136166
}
137-
MP_DEFINE_CONST_FUN_OBJ_2(usb_hid_device_send_report_obj, usb_hid_device_send_report);
167+
MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_device_send_report_obj, 2, usb_hid_device_send_report);
168+
169+
//| def get_last_received_report(self, report_id: Optional[int] = None) -> bytes:
170+
//| """Get the last received HID OUT report for the given report ID.
171+
//| The report ID may be omitted if there is no report ID, or only one report ID.
172+
//| Return `None` if nothing received.
173+
//| """
174+
//| ...
175+
//|
176+
STATIC mp_obj_t usb_hid_device_get_last_received_report(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
177+
usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
178+
179+
enum { ARG_report_id };
180+
static const mp_arg_t allowed_args[] = {
181+
{ MP_QSTR_report_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
182+
};
183+
184+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
185+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
186+
187+
uint8_t report_id = 0;
188+
if (args[ARG_report_id].u_obj != mp_const_none) {
189+
report_id = mp_obj_int_get_checked(args[ARG_report_id].u_obj);
190+
}
191+
192+
return common_hal_usb_hid_device_get_last_received_report(self, report_id);
193+
}
194+
MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_device_get_last_received_report_obj, 1, usb_hid_device_get_last_received_report);
138195

139196
//| last_received_report: bytes
140-
//| """The HID OUT report as a `bytes`. (read-only). `None` if nothing received."""
197+
//| """The HID OUT report as a `bytes`. (read-only). `None` if nothing received.
198+
//| Same as `get_last_received_report()` with no argument.
141199
//|
142-
STATIC mp_obj_t usb_hid_device_obj_get_last_received_report(mp_obj_t self_in) {
200+
//| Deprecated: will be removed in CircutPython 8.0.0. Use `get_last_received_report()` instead.
201+
//| """
202+
//|
203+
STATIC mp_obj_t usb_hid_device_obj_get_last_received_report_property(mp_obj_t self_in) {
143204
usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
144-
if (self->out_report_buffer == 0) {
145-
return mp_const_none;
146-
}
147-
return mp_obj_new_bytes(self->out_report_buffer, self->out_report_length);
205+
206+
return common_hal_usb_hid_device_get_last_received_report(self, 0);
148207
}
149-
MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_device_get_last_received_report_obj, usb_hid_device_obj_get_last_received_report);
208+
MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_device_get_last_received_report_property_obj, usb_hid_device_obj_get_last_received_report_property);
150209

151210
const mp_obj_property_t usb_hid_device_last_received_report_obj = {
152211
.base.type = &mp_type_property,
153-
.proxy = {(mp_obj_t)&usb_hid_device_get_last_received_report_obj,
212+
.proxy = {(mp_obj_t)&usb_hid_device_get_last_received_report_property_obj,
154213
MP_ROM_NONE,
155214
MP_ROM_NONE},
156215
};
@@ -192,13 +251,15 @@ const mp_obj_property_t usb_hid_device_usage_obj = {
192251
};
193252

194253
STATIC const mp_rom_map_elem_t usb_hid_device_locals_dict_table[] = {
195-
{ MP_ROM_QSTR(MP_QSTR_send_report), MP_ROM_PTR(&usb_hid_device_send_report_obj) },
196-
{ MP_ROM_QSTR(MP_QSTR_last_received_report), MP_ROM_PTR(&usb_hid_device_last_received_report_obj) },
197-
{ MP_ROM_QSTR(MP_QSTR_usage_page), MP_ROM_PTR(&usb_hid_device_usage_page_obj) },
198-
{ MP_ROM_QSTR(MP_QSTR_usage), MP_ROM_PTR(&usb_hid_device_usage_obj) },
199-
{ MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&usb_hid_device_keyboard_obj) },
200-
{ MP_ROM_QSTR(MP_QSTR_MOUSE), MP_ROM_PTR(&usb_hid_device_mouse_obj) },
201-
{ MP_ROM_QSTR(MP_QSTR_CONSUMER_CONTROL), MP_ROM_PTR(&usb_hid_device_consumer_control_obj) },
254+
{ MP_ROM_QSTR(MP_QSTR_send_report), MP_ROM_PTR(&usb_hid_device_send_report_obj) },
255+
{ MP_ROM_QSTR(MP_QSTR_get_last_received_report), MP_ROM_PTR(&usb_hid_device_get_last_received_report_obj) },
256+
{ MP_ROM_QSTR(MP_QSTR_last_received_report), MP_ROM_PTR(&usb_hid_device_last_received_report_obj) },
257+
{ MP_ROM_QSTR(MP_QSTR_usage_page), MP_ROM_PTR(&usb_hid_device_usage_page_obj) },
258+
{ MP_ROM_QSTR(MP_QSTR_usage), MP_ROM_PTR(&usb_hid_device_usage_obj) },
259+
260+
{ MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&usb_hid_device_keyboard_obj) },
261+
{ MP_ROM_QSTR(MP_QSTR_MOUSE), MP_ROM_PTR(&usb_hid_device_mouse_obj) },
262+
{ MP_ROM_QSTR(MP_QSTR_CONSUMER_CONTROL), MP_ROM_PTR(&usb_hid_device_consumer_control_obj) },
202263
};
203264

204265
STATIC MP_DEFINE_CONST_DICT(usb_hid_device_locals_dict, usb_hid_device_locals_dict_table);

shared-bindings/usb_hid/Device.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@
3333

3434
extern const mp_obj_type_t usb_hid_device_type;
3535

36-
void common_hal_usb_hid_device_construct(usb_hid_device_obj_t *self, mp_obj_t descriptor, uint8_t usage_page, uint8_t usage, uint8_t in_report_length, uint8_t out_report_length, uint8_t report_id_index);
37-
void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len);
36+
void common_hal_usb_hid_device_construct(usb_hid_device_obj_t *self, mp_obj_t report_descriptor, uint8_t usage_page, uint8_t usage, size_t report_ids_count,uint8_t *report_ids, uint8_t *in_report_lengths, uint8_t *out_report_lengths);
37+
void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len, uint8_t report_id);
38+
mp_obj_t common_hal_usb_hid_device_get_last_received_report(usb_hid_device_obj_t *self, uint8_t report_id);
3839
uint8_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self);
3940
uint8_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self);
41+
bool common_hal_usb_hid_device_valid_report_id(usb_hid_device_obj_t *self, uint8_t report_id);
4042

4143
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_HID_DEVICE_H

0 commit comments

Comments
 (0)