wip: partial HID, still needs rework

This commit is contained in:
Dan Halbert 2021-04-23 00:18:05 -04:00
parent 64e0958916
commit 2b4c88d633
14 changed files with 407 additions and 57 deletions

View File

@ -87,6 +87,14 @@ msgstr ""
msgid "%q list must be a list"
msgstr ""
#: shared-bindings/usb_hid/Device.c
msgid "%q must be 1-255"
msgstr ""
#: shared-bindings/usb_hid/Device.c
msgid "%q must be > 1-255"
msgstr ""
#: shared-bindings/memorymonitor/AllocationAlarm.c
msgid "%q must be >= 0"
msgstr ""
@ -99,6 +107,14 @@ msgstr ""
msgid "%q must be >= 1"
msgstr ""
#: shared-bindings/usb_hid/Device.c
msgid "%q must be None or 1-255"
msgstr ""
#: shared-bindings/usb_hid/Device.c
msgid "%q must be None or > 1-255"
msgstr ""
#: shared-module/vectorio/Polygon.c
msgid "%q must be a tuple of length 2"
msgstr ""
@ -600,7 +616,8 @@ msgstr ""
msgid "Can't set CCCD on local Characteristic"
msgstr ""
#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_midi/__init__.c
#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c
#: shared-bindings/usb_midi/__init__.c
msgid "Cannot change USB devices now"
msgstr ""
@ -3470,6 +3487,10 @@ msgstr ""
msgid "no such attribute"
msgstr ""
#: shared-bindings/usb_hid/__init__.c
msgid "non-Device in %q"
msgstr ""
#: ports/nrf/common-hal/_bleio/Connection.c
msgid "non-UUID found in service_uuids_whitelist"
msgstr ""

4
main.c
View File

@ -641,6 +641,10 @@ void gc_collect(void) {
background_callback_gc_collect();
#if CIRCUITPY_USB
usb_gc_collect();
#endif
#if CIRCUITPY_ALARM
common_hal_alarm_gc_collect();
#endif

View File

@ -39,10 +39,88 @@
//| mouse.send_report()"""
//|
//| def __init__(self) -> None:
//| """Not currently dynamically supported."""
//| def __init__(self, *, descriptor: ReadableBuffer, usage_page: int, usage: int, in_report_length: int, out_report_length: Optional[int], , report_id_index: Optional[int]) -> None:
//| """Create a description of a USB HID device. To create an actual device,
//| pass a `Device` to `usb_hid.configure_usb()`.
//|
//| :param ReadableBuffer descriptor: The USB HID Report descriptor bytes. The descriptor is not
//| not verified for correctness; it is up to you to make sure it is not malformed.
//| :param int usage_page: The Usage Page value from the descriptor. Must match what is in the descriptor.
//| :param int usage: The Usage value from the descriptor. Must match what is in the descriptor.
//| :param int in_report_length: Size in bytes of the HID report sent to the host.
//| "In" is with respect to the host.
//| :param int out_report_length: Size in bytes of the HID report received from the host.
//| "Out" is with respect to the host. If no reports are expected, use ``None``.
//| :param int report_id_index: position of byte in descriptor that contains the Report ID.
//| A Report ID will be assigned when the device is created. If there is no
//| Report ID, use ``None``.
//| ...
//|
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) {
usb_hid_device_obj_t *self = m_new_obj(usb_hid_device_obj_t);
self->base.type = &usb_hid_device_type;
enum { ARG_descriptor, ARG_usage, ARG_usage_page, ARG_in_report_length, ARG_out_report_length, ARG_report_id_index };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_descriptor, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_usage_page, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_usage, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_in_report_length, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT } ,
{ MP_QSTR_out_report_length, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } },
{ MP_QSTR_report_id_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(descriptor, &bufinfo, MP_BUFFER_READ);
bytearray_obj_t descriptor = mp_obj_array_t new_bytearray(bufinfo.len, bufinfo.buf);
const mp_int_t usage_page_arg = args[ARG_usage_page].u_int;
if (usage_page_arg <= 0 || usage_arg > 255) {
mp_raise_ValueError_varg(translate("%q must be 1-255"), MP_QSTR_usage_page);
}
const uint8_t usage_page = usage_page_arg;
const mp_int_t usage_arg = args[ARG_usage].u_int;
if (usage_arg <= 0 || usage_arg > 255) {
mp_raise_ValueError_varg(translate("%q must be 1-255"), MP_QSTR_usage);
}
const uint8_t usage = usage_arg;
const mp_int_t in_report_length_arg = args[ARG_in_report_length].u_int;
if (in_report_length_arg <= 0 || in_report_length_arg > 255) {
mp_raise_ValueError_varg(translate("%q must be > 1-255"), MP_QSTR_in_report_length);
}
const uint8_t in_report_length = in_report_length_arg;
const mp_obj_t out_report_length_arg = args[ARG_out_report_length].u_obj;
if (out_report_length_arg == mp_const_none) {
self->out_report_length = 0;
}
else if (!MP_OBJ_IS_SMALL_INT(out_report_length_arg) ||
MP_OBJ_SMALL_INT_VALUE(out_report_length_arg) <= 0 ||
MP_OBJ_SMALL_INT_VALUE(out_report_length_arg) > 255) {
mp_raise_ValueError_varg(translate("%q must be None or > 1-255"), MP_QSTR_out_report_length);
}
uint8_t out_report_length = MP_OBJ_SMALL_INT_VALUE(out_report_length_arg);
const mp_obj_t report_id_index_arg = args[ARG_report_id_index].u_obj;
if (report_id_index_arg == mp_const_none) {
self->report_id_index = 0;
}
else if (!MP_OBJ_IS_SMALL_INT(report_id_index_arg) ||
MP_OBJ_SMALL_INT_VALUE(report_id_index_arg) <= 0 ||
MP_OBJ_SMALL_INT_VALUE(report_id_index_arg) > 255 ) {
mp_raise_ValueError_varg(translate("%q must be None or 1-255"), MP_QSTR_report_id_index);
}
uint8_t report_id_index = MP_OBJ_SMALL_INT_VALUE(report_id_index_arg);
common_hal_usb_hid_device_construct(self, descriptor, usage_page, usage, in_report_length, out_report_length, report_id_index);
}
//| def send_report(self, buf: ReadableBuffer) -> None:
//| """Send a HID report."""
//| ...
@ -116,8 +194,11 @@ const mp_obj_property_t usb_hid_device_usage_obj = {
STATIC const mp_rom_map_elem_t usb_hid_device_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_send_report), MP_ROM_PTR(&usb_hid_device_send_report_obj) },
{ MP_ROM_QSTR(MP_QSTR_last_received_report), MP_ROM_PTR(&usb_hid_device_last_received_report_obj) },
{ MP_ROM_QSTR(MP_QSTR_usage_page), MP_ROM_PTR(&usb_hid_device_usage_page_obj)},
{ MP_ROM_QSTR(MP_QSTR_usage), MP_ROM_PTR(&usb_hid_device_usage_obj)},
{ MP_ROM_QSTR(MP_QSTR_usage_page), MP_ROM_PTR(&usb_hid_device_usage_page_obj) },
{ MP_ROM_QSTR(MP_QSTR_usage), MP_ROM_PTR(&usb_hid_device_usage_obj) },
{ MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&usb_hid_device_keyboard_obj) },
{ MP_ROM_QSTR(MP_QSTR_MOUSE), MP_ROM_PTR(&usb_hid_device_mouse_obj) },
{ MP_ROM_QSTR(MP_QSTR_CONSUMER_CONTROL), MP_ROM_PTR(&usb_hid_device_consumer_control_obj) },
};
STATIC MP_DEFINE_CONST_DICT(usb_hid_device_locals_dict, usb_hid_device_locals_dict_table);
@ -125,5 +206,6 @@ STATIC MP_DEFINE_CONST_DICT(usb_hid_device_locals_dict, usb_hid_device_locals_di
const mp_obj_type_t usb_hid_device_type = {
{ &mp_type_type },
.name = MP_QSTR_Device,
.make_new = usb_hid_device_make_new,
.locals_dict = (mp_obj_t)&usb_hid_device_locals_dict,
};

View File

@ -31,6 +31,7 @@
extern const mp_obj_type_t usb_hid_device_type;
void common_hal_usb_hid_device_construct(usb_hid_device_obj_t *self, ***);
void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len);
uint8_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self);
uint8_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self);

View File

@ -39,8 +39,40 @@
//| devices: Tuple[Device, ...]
//| """Tuple of all active HID device interfaces."""
//|
//| def configure_usb(devices: Sequence[Device, ...]=) -> None:
//| """Configure the USB HID devices that will be available.
//| Can be called in ``boot.py``, before USB is connected.
//|
//| :param Sequence devices: `Device` objects.
//| If `devices` is empty, HID is disabled. The order of the ``Devices``
//| may matter to the host. For instance, for MacOS, put the mouse device
//| before any Gamepad or Digitizer HID device.
//| ...
//|
STATIC mp_obj_t usb_hid_configure_usb(mp_obj_t devices) {
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(devices, &iter_buf);
mp_obj_t device;
while ((device = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (!MP_OBJ_IS_TYPE(item, &usb_hid_device_type)) {
mp_raise_ValueError_varg(translate("non-Device in %q", MP_QSTR_devices));
}
}
if (!common_hal_usb_hid_configure_usb(descriptors)) {
mp_raise_RuntimeError(translate("Cannot change USB devices now"));
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_configure_usb_obj, usb_hid_configure_usb);
STATIC const mp_rom_map_elem_t usb_hid_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid) },
{ MP_ROM_QSTR(MP_QSTR_configure_usb), MP_OBJ_FROM_PTR(&usb_midi_configure_usb_obj) },
{ MP_ROM_QSTR(MP_QSTR_devices), MP_ROM_PTR(&common_hal_usb_hid_devices) },
{ MP_ROM_QSTR(MP_QSTR_Device), MP_ROM_PTR(&usb_hid_device_type) },
};

View File

@ -46,20 +46,20 @@ static const uint8_t storage_usb_msc_descriptor_template[] = {
0x09, // 0 bLength
0x04, // 1 bDescriptorType (Interface)
0xFF, // 2 bInterfaceNumber [SET AT RUNTIME]
#define MSC_INTERFACE_INDEX 2
#define MSC_INTERFACE_INDEX (2)
0x00, // 3 bAlternateSetting
0x02, // 4 bNumEndpoints 2
0x08, // 5 bInterfaceClass: MSC
0x06, // 6 bInterfaceSubClass: TRANSPARENT
0x50, // 7 bInterfaceProtocol: BULK
0xFF, // 8 iInterface (String Index) [SET AT RUNTIME]
#define MSC_INTERFACE_STRING_INDEX 8
#define MSC_INTERFACE_STRING_INDEX (8)
// MSC Endpoint IN Descriptor
0x07, // 9 bLength
0x05, // 10 bDescriptorType (Endpoint)
0xFF, // 11 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number]
#define MSC_IN_ENDPOINT_INDEX 11
#define MSC_IN_ENDPOINT_INDEX (11)
0x02, // 12 bmAttributes (Bulk)
0x40, 0x00, // 13,14 wMaxPacketSize 64
0x00, // 15 bInterval 0 (unit depends on device speed)
@ -68,7 +68,7 @@ static const uint8_t storage_usb_msc_descriptor_template[] = {
0x07, // 16 bLength
0x05, // 17 bDescriptorType (Endpoint)
0xFF, // 18 bEndpointAddress (OUT/H2D) [SET AT RUNTIME]
#define MSC_OUT_ENDPOINT_INDEX 18
#define MSC_OUT_ENDPOINT_INDEX (18)
0x02, // 19 bmAttributes (Bulk)
0x40, 0x00, // 20,21 wMaxPacketSize 64
0x00, // 22 bInterval 0 (unit depends on device speed)

View File

@ -33,6 +33,137 @@
#include "supervisor/shared/tick.h"
#include "tusb.h"
static const uint8_t keyboard_descriptor[] = {
0x05, 0x01, // 0,1 Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // 2,3 Usage (Keyboard)
0xA1, 0x01, // 4,5 Collection (Application)
0x85, 0xFF, // 6,7 Report ID [SET AT RUNTIME]
#define KEYBOARD_REPORT_ID_INDEX (7)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0xDD, // Usage Maximum (0xDD)
0x15, 0x00, // Logical Minimum (0)
0x25, 0xDD, // Logical Maximum (-35)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x05, // Report Count (5)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x03, // Report Count (3)
0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
},
const usb_hid_device_obj_t usb_hid_device_keyboard_obj = {
.descriptor = keyboard_descriptor,
.descriptor_length = sizeof(keyboard_descriptor),
.usage_page = 0x01
.usage = 0x06,
.in_report_length = 8,
.out_report_length = 1,
.report_id_index = KEYBOARD_REPORT_ID_INDEX,
};
static const uint8_t mouse_descriptor[] = {
0x05, 0x01, // 0,1 Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // 2,3 Usage (Mouse)
0xA1, 0x01, // 4,5 Collection (Application)
0x09, 0x01, // 6,7 Usage (Pointer)
0xA1, 0x00, // 8,9 Collection (Physical)
0x85, 0xFF, // 10, 11 Report ID [SET AT RUNTIME]
#define MOUSE_REPORT_ID_INDEX (11)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x05, // Usage Maximum (0x05)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
};
const usb_hid_device_obj_t usb_hid_device_mouse_obj = {
.descriptor = mouse_descriptor,
.descriptor_length = sizeof(mouse_descriptor),
.usage_page = 0x01
.usage = 0x02,
.in_report_length = 4,
.out_report_length = 0,
.descriptor = {
.report_id_index = MOUSE_REPORT_ID_INDEX,
};
static const uint8_t consumer_control_descriptor[] = {
0x05, 0x0C, // 0,1 Usage Page (Consumer)
0x09, 0x01, // 2,3 Usage (Consumer Control)
0xA1, 0x01, // 4,5 Collection (Application)
0x85, 0xFF, // 6,7 Report ID [SET AT RUNTIME]
#define CONSUMER_CONTROL_REPORT_ID_INDEX (7)
0x75, 0x10, // Report Size (16)
0x95, 0x01, // Report Count (1)
0x15, 0x01, // Logical Minimum (1)
0x26, 0x8C, 0x02, // Logical Maximum (652)
0x19, 0x01, // Usage Minimum (Consumer Control)
0x2A, 0x8C, 0x02, // Usage Maximum (AC Send)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
};
const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = {
.descriptor = consumer_control_descriptor,
.descriptor_length = sizeof(consumer_control_descriptor),
.usage_page = 0x0C
.usage = 0x01,
.in_report_length = 2,
.out_report_length = 0,
.report_id_index = CONSUMER_CONTROL_REPORT_ID_INDEX,
};
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) {
// report buffer pointers are NULL at start, and are created on demand.
self->descriptor = descriptor;
self->usage_page = usage_page;
self->usage = usage;
self->in_report_length = in_report_length;
self->out_report_length = out_report_length;
self->report_id_index = report_id_index;
}
uint8_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self) {
return self->usage_page;
}
@ -42,8 +173,8 @@ uint8_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self) {
}
void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len) {
if (len != self->report_length) {
mp_raise_ValueError_varg(translate("Buffer incorrect size. Should be %d bytes."), self->report_length);
if (len != self->in_report_length) {
mp_raise_ValueError_varg(translate("Buffer incorrect size. Should be %d bytes."), self->in_report_length);
}
// Wait until interface is ready, timeout = 2 seconds
@ -56,9 +187,9 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *
mp_raise_msg(&mp_type_OSError, translate("USB Busy"));
}
memcpy(self->report_buffer, report, len);
memcpy(self->in_report_buffer, report, len);
if (!tud_hid_report(self->report_id, self->report_buffer, len)) {
if (!tud_hid_report(self->in_report_id, self->in_report_buffer, len)) {
mp_raise_msg(&mp_type_OSError, translate("USB Error"));
}
}
@ -81,7 +212,7 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
}
// fill buffer with current report
memcpy(buffer, get_hid_device(report_id)->report_buffer, reqlen);
memcpy(buffer, get_hid_device(report_id)->in_report_buffer, reqlen);
return reqlen;
}

View File

@ -32,26 +32,21 @@
#include "py/obj.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
mp_obj_base_t base;
uint8_t *report_buffer;
uint8_t report_id;
uint8_t report_length;
uint8_t *in_report_buffer;
uint8_t *out_report_buffer;
uint8_t *descriptor;
uint16_t descriptor_length;
uint8_t usage_page;
uint8_t usage;
uint8_t *out_report_buffer;
uint8_t report_id;
uint8_t in_report_length;
uint8_t out_report_length;
} usb_hid_device_obj_t;
extern usb_hid_device_obj_t usb_hid_devices[];
#ifdef __cplusplus
}
#endif
extern usb_hid_device_obj_t usb_hid_device_keyboard_obj;
extern usb_hid_device_obj_t usb_hid_device_mouse_obj;
extern usb_hid_device_mouse_obj usb_hid_device_consumer_control_obj;
#endif /* SHARED_MODULE_USB_HID_DEVICE_H */

View File

@ -32,12 +32,12 @@ static const uint8_t usb_hid_descriptor_template[] = {
0x01, // 4 bNumDescriptors
0x22, // 5 bDescriptorType[0] (HID)
0xFF, 0xFF, // 6,7 wDescriptorLength[0] [SET AT RUNTIME: lo, hi]
#define HID_DESCRIPTOR_LENGTH_INDEX 6
#define HID_DESCRIPTOR_LENGTH_INDEX (6)
0x07, // 8 bLength
0x05, // 9 bDescriptorType (Endpoint)
0xFF, // 10 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | endpoint]
#define HID_IN_ENDPOINT_INDEX 10
#define HID_IN_ENDPOINT_INDEX (10)
0x03, // 11 bmAttributes (Interrupt)
0x40, 0x00, // 12,13 wMaxPacketSize 64
0x08, // 14 bInterval 8 (unit depends on device speed)
@ -45,7 +45,7 @@ static const uint8_t usb_hid_descriptor_template[] = {
0x07, // 15 bLength
0x05, // 16 bDescriptorType (Endpoint)
0xFF, // 17 bEndpointAddress (OUT/H2D) [SET AT RUNTIME]
#define HID_OUT_ENDPOINT_INDEX 17
#define HID_OUT_ENDPOINT_INDEX (17)
0x03, // 18 bmAttributes (Interrupt)
0x40, 0x00, // 19,20 wMaxPacketSize 64
0x08, // 21 bInterval 8 (unit depends on device speed)
@ -53,6 +53,7 @@ static const uint8_t usb_hid_descriptor_template[] = {
// Is the HID device enabled?
bool usb_hid_enabled;
mp_obj_t usb_hid_devices;
size_t usb_hid_descriptor_length(void) {
return sizeof(usb_hid_descriptor);
@ -72,3 +73,31 @@ size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
return sizeof(usb_hid_descriptor_template);
}
void usb_hid_build_report_descriptor() {
}
bool common_hal_usb_hid_configure_usb(mp_obj_t devices) {
// We can't change the devices once we're connected.
if (tud_connected()) {
return false;
}
// Assume no devices to start.
usb_hid_enabled = false;
if (devices == mp_const_none) {
return true;
}
}
void usb_hid_build_report
void usb_hid_gc_collect(void) {
// Once tud_mounted() is true, we're done with the constructed descriptors.
if (tud_mounted()) {
// GC will pick up the inaccessible blocks.
usb_hid_devices_to_configure = NULL;
} else {
gc_collect_ptr(usb_hid_devices);
}
}

View File

@ -0,0 +1,36 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHARED_MODULE_USB_HID___INIT___H
#define SHARED_MODULE_USB_HID___INIT___H
extern bool usb_hid_enabled;
extern usb_hid_device_obj_t usb_hid_devices[];
void usb_hid_gc_collect(void);
#endif // SHARED_MODULE_USB_HID___INIT___H

View File

@ -43,14 +43,14 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x09, // 0 bLength
0x04, // 1 bDescriptorType (Interface)
0xFF, // 2 bInterfaceNumber [SET AT RUNTIME]
#define MIDI_AUDIO_CONTROL_INTERFACE_NUMBER_INDEX 2
#define MIDI_AUDIO_CONTROL_INTERFACE_NUMBER_INDEX (2)
0x00, // 3 bAlternateSetting
0x00, // 4 bNumEndpoints 0
0x01, // 5 bInterfaceClass (Audio)
0x01, // 6 bInterfaceSubClass (Audio Control)
0x00, // 7 bInterfaceProtocol
0xFF, // 8 iInterface (String Index) [SET AT RUNTIME]
#define MIDI_AUDIO_CONTROL_INTERFACE_STRING_INDEX 8
#define MIDI_AUDIO_CONTROL_INTERFACE_STRING_INDEX (8)
// Audio10 Control Interface Descriptor
0x09, // 9 bLength
@ -60,20 +60,20 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x09, 0x00, // 14,15 wTotalLength 9
0x01, // 16 binCollection 0x01
0xFF, // 17 baInterfaceNr [SET AT RUNTIME: one-element list: same as 20]
#define MIDI_STREAMING_INTERFACE_NUMBER_INDEX_2 17
#define MIDI_STREAMING_INTERFACE_NUMBER_INDEX_2 (17)
// MIDI Streaming Interface Descriptor
0x09, // 18 bLength
0x04, // 19 bDescriptorType (Interface)
0xFF, // 20 bInterfaceNumber [SET AT RUNTIME]
#define MIDI_STREAMING_INTERFACE_NUMBER_INDEX 20
#define MIDI_STREAMING_INTERFACE_NUMBER_INDEX (20)
0x00, // 21 bAlternateSetting
0x02, // 22 bNumEndpoints 2
0x01, // 23 bInterfaceClass (Audio)
0x03, // 24 bInterfaceSubClass (MIDI Streaming)
0x00, // 25 bInterfaceProtocol
0xFF, // 26 iInterface (String Index) [SET AT RUNTIME]
#define MIDI_STREAMING_INTERFACE_STRING_INDEX 26
#define MIDI_STREAMING_INTERFACE_STRING_INDEX (26)
// MIDI Header Descriptor
0x07, // 27 bLength
@ -89,7 +89,7 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x01, // 37 bJackType: EMBEDDED
0x01, // 38 id (always 1)
0xFF, // 39 iJack (String Index) [SET AT RUNTIME]
#define MIDI_IN_JACK_STRING_INDEX 39
#define MIDI_IN_JACK_STRING_INDEX (39)
// MIDI External In Jack Descriptor
0x06, // 40 bLength
@ -109,7 +109,7 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x02, // 52 BaSourceID(1) (always 2)
0x01, // 53 BaSourcePin(1) (always 1)
0xFF, // 54 iJack (String Index) [SET AT RUNTIME]
#define MIDI_OUT_JACK_STRING_INDEX 54
#define MIDI_OUT_JACK_STRING_INDEX (54)
// MIDI External Out Jack Descriptor
0x09, // 55 bLength
@ -126,9 +126,9 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x07, // 64 bLength
0x05, // 65 bDescriptorType (EndPoint)
0xFF, // 66 bEndpointAddress (OUT/H2D) [SET AT RUNTIME]
#define MIDI_STREAMING_OUT_ENDPOINT_INDEX 66
#define MIDI_STREAMING_OUT_ENDPOINT_INDEX (66)
0x02, // 67 bmAttributes (Bulk)
0x40, 0x00, // 68,69 wMaxPacketSize 64
0x40, 0x00, // 68,69 wMaxPacketSize (64)
0x00, // 70 bInterval 0 (unit depends on device speed)
// MIDI Data Endpoint Descriptor
@ -142,7 +142,7 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x07, // 76 bLength
0x05, // 77 bDescriptorType: Endpoint
0xFF, // 78 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x8 | number]
#define MIDI_STREAMING_IN_ENDPOINT_INDEX 78
#define MIDI_STREAMING_IN_ENDPOINT_INDEX (78)
0x02, // 79 bmAttributes (Bulk)
0x40, 0x00, // 8081 wMaxPacketSize 64
0x00, // 82 bInterval 0 (unit depends on device speed)

View File

@ -109,6 +109,11 @@ void usb_irq_handler(void) {
usb_background_schedule();
}
void usb_gc_collect(void) {
usb_desc_gc_collect();
usb_hid_gc_collect();
}
// --------------------------------------------------------------------+
// tinyusb callbacks
// --------------------------------------------------------------------+

View File

@ -46,9 +46,9 @@
#include "genhdr/autogen_usb_descriptor.h"
// ******* TODO PROTECT AGAINST GC.
static uint8_t *device_descriptor;
static uint8_t *config_descriptor;
static uint8_t *hid_report_descriptor;
// Table for collecting interface strings (interface names) as descriptor is built.
#define MAX_INTERFACE_STRINGS 16
@ -71,18 +71,18 @@ static const uint8_t device_descriptor_template[] = {
0x00, // 6 bDeviceProtocol
0x40, // 7 bMaxPacketSize0 64
0x9A, 0x23, // 8,9 idVendor [SET AT RUNTIME: lo,hi]
#define DEVICE_VID_LO_INDEX 8
#define DEVICE_VID_HI_INDEX 9
#define DEVICE_VID_LO_INDEX (8)
#define DEVICE_VID_HI_INDEX (9)
0x, 0xFF, // 10,11 idProduct [SET AT RUNTIME: lo,hi]
#define DEVICE PID_LO_INDEX 10
#define DEVICE PID_HI_INDEX 11
#define DEVICE PID_LO_INDEX (10)
#define DEVICE PID_HI_INDEX (11)
0x00, 0x01, // 12,13 bcdDevice 2.00
0x02, // 14 iManufacturer (String Index) [SET AT RUNTIME]
#define DEVICE_MANUFACTURER_STRING_INDEX 14
#define DEVICE_MANUFACTURER_STRING_INDEX (14)
0x03, // 15 iProduct (String Index) [SET AT RUNTIME]
#define DEVICE_PRODUCT_STRING_INDEX 15
#define DEVICE_PRODUCT_STRING_INDEX (15)
0x01, // 16 iSerialNumber (String Index) [SET AT RUNTIME]
#define DEVICE_SERIAL_NUMBER_STRING_INDEX 16
#define DEVICE_SERIAL_NUMBER_STRING_INDEX (16)
0x01, // 17 bNumConfigurations 1
};
@ -90,10 +90,10 @@ static const uint8_t configuration_descriptor_template[] = {
0x09, // 0 bLength
0x02, // 1 bDescriptorType (Configuration)
0xFF, 0xFF, // 2,3 wTotalLength [SET AT RUNTIME: lo, hi]
#define CONFIG_TOTAL_LENGTH_LO_INDEX 2
#define CONFIG_TOTAL_LENGTH_HI_INDEX 3
#define CONFIG_TOTAL_LENGTH_LO_INDEX (2)
#define CONFIG_TOTAL_LENGTH_HI_INDEX (3)
0xFF, // 4 bNumInterfaces [SET AT RUNTIME]
#define CONFIG_NUM_INTERFACES_INDEX 4
#define CONFIG_NUM_INTERFACES_INDEX (4)
0x01, // 5 bConfigurationValue
0x00, // 6 iConfiguration (String Index)
0x80, // 7 bmAttributes
@ -254,7 +254,20 @@ void usb_add_interface_string(uint8_t interface_string_index, const char[] str)
}
void usb_
void usb_desc_gc_collect(void) {
// Once tud_mounted() is true, we're done with the constructed descriptors.
if (tud_mounted()) {
// GC will pick up the inaccessible blocks.
device_descriptor = NULL;
configuration_descriptor = NULL;
hid_report_descriptors = NULL;
} else {
gc_collect_ptr(device_descriptor);
gc_collect_ptr(configuration_descriptor);
gc_collect_ptr(hid_report_descriptors); // Collects children too.
}
}
// Invoked when GET DEVICE DESCRIPTOR is received.
// Application return pointer to descriptor
@ -275,7 +288,6 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
(void)itf;
return hid_report_descriptor;
}
#endif

View File

@ -52,8 +52,10 @@ void post_usb_init(void);
bool usb_enabled(void);
void usb_init(void);
void usb_disconnect(void);
void usb_gc_collect(void);
void usb_add_interface_string(uint8_t interface_string_index, const char[] str);
void usb_desc_gc_collect(void);
void usb_desc_init(void);
void usb_build_device_descriptor(uint16_t vid, uint16_t pid, uint8_t *current_interface_string);
void usb_build_configuration_descriptor(uint16_t total_length, uint8_t num_interfaces);