31
31
//| class Device:
32
32
//| """HID Device specification"""
33
33
//|
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:
35
35
//| """Create a description of a USB HID device. The actual device is created when you
36
36
//| pass a `Device` to `usb_hid.enable()`.
37
37
//|
38
38
//| :param ReadableBuffer report_descriptor: The USB HID Report descriptor bytes. The descriptor is not
39
39
//| not verified for correctness; it is up to you to make sure it is not malformed.
40
40
//| :param int usage_page: The Usage Page value from the descriptor. Must match what is in the descriptor.
41
41
//| :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.
49
51
//| """
50
52
//| ...
51
53
//|
52
54
//| 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
+ //| """
54
58
//|
55
59
//| MOUSE: Device
56
60
//| """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
+ //| """
58
64
//|
59
65
//| 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."""
61
68
//|
62
69
63
70
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 ) {
64
71
usb_hid_device_obj_t * self = m_new_obj (usb_hid_device_obj_t );
65
72
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 };
67
74
static const mp_arg_t allowed_args [] = {
68
75
{ MP_QSTR_report_descriptor , MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
69
76
{ MP_QSTR_usage_page , MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
70
77
{ 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 },
74
81
};
75
82
76
83
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
81
88
mp_obj_t descriptor = mp_obj_new_bytearray (descriptor_bufinfo .len , descriptor_bufinfo .buf );
82
89
83
90
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 );
87
92
const uint8_t usage_page = usage_page_arg ;
88
93
89
94
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 );
93
96
const uint8_t usage = usage_arg ;
94
97
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 ;
100
101
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 );
104
107
}
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 );
116
130
}
117
131
118
132
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 );
120
134
return (mp_obj_t )self ;
121
135
}
122
136
123
137
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
+ //| """
126
141
//| ...
127
142
//|
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 );
130
154
131
155
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
+ }
133
163
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 );
135
165
return mp_const_none ;
136
166
}
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 );
138
195
139
196
//| 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.
141
199
//|
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 ) {
143
204
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 );
148
207
}
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 );
150
209
151
210
const mp_obj_property_t usb_hid_device_last_received_report_obj = {
152
211
.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 ,
154
213
MP_ROM_NONE ,
155
214
MP_ROM_NONE },
156
215
};
@@ -192,13 +251,15 @@ const mp_obj_property_t usb_hid_device_usage_obj = {
192
251
};
193
252
194
253
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 ) },
202
263
};
203
264
204
265
STATIC MP_DEFINE_CONST_DICT (usb_hid_device_locals_dict , usb_hid_device_locals_dict_table );
0 commit comments