diff options
-rw-r--r-- | docs/library/pyb.USB_VCP.rst | 4 | ||||
-rw-r--r-- | docs/library/pyb.rst | 4 | ||||
-rw-r--r-- | stmhal/main.c | 48 | ||||
-rw-r--r-- | stmhal/modpyb.c | 36 | ||||
-rw-r--r-- | stmhal/mpconfigport.h | 2 | ||||
-rw-r--r-- | stmhal/qstrdefsport.h | 12 | ||||
-rw-r--r-- | stmhal/usb.c | 269 | ||||
-rw-r--r-- | stmhal/usb.h | 34 | ||||
-rw-r--r-- | stmhal/usbd_cdc_interface.c | 8 | ||||
-rw-r--r-- | stmhal/usbd_msc_storage.c | 2 | ||||
-rw-r--r-- | stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid0.h | 51 | ||||
-rw-r--r-- | stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h | 22 | ||||
-rw-r--r-- | stmhal/usbdev/class/src/usbd_cdc_msc_hid.c | 171 |
13 files changed, 461 insertions, 202 deletions
diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst index 4d87be4a36..be1316432c 100644 --- a/docs/library/pyb.USB_VCP.rst +++ b/docs/library/pyb.USB_VCP.rst @@ -26,6 +26,10 @@ Methods Set to -1 to disable this interrupt feature. This is useful when you want to send raw bytes over the USB VCP port. +.. method:: usb_vcp.isconnected() + + Return ``True`` if USB is connected as a serial device, else ``False``. + .. method:: usb_vcp.any() Return ``True`` if any characters waiting, else ``False``. diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 79caa67d2f..f93b884ab4 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -149,11 +149,15 @@ Miscellaneous functions Return True if USB is connected as a serial device, False otherwise. + .. note:: This function is deprecated. Use pyb.USB_VCP().isconnected() instead. + .. function:: hid((buttons, x, y, z)) Takes a 4-tuple (or list) and sends it to the USB host (the PC) to signal a HID mouse-motion event. + .. note:: This function is deprecated. Use pyb.USB_HID().send(...) instead. + .. function:: info([dump_alloc_table]) Print out lots of information about the board. diff --git a/stmhal/main.c b/stmhal/main.c index f000d90c6f..5938c7e36e 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -120,14 +120,6 @@ STATIC mp_obj_t pyb_main(mp_obj_t main) { } MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main); -STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) { - if (MP_OBJ_IS_STR(usb_mode)) { - MP_STATE_PORT(pyb_config_usb_mode) = usb_mode; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_mode_obj, pyb_usb_mode); - static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n" "# can run arbitrary Python, but best to keep it minimal\r\n" @@ -309,6 +301,11 @@ int main(void) { switch_init0(); #endif +#if defined(USE_DEVICE_MODE) + // default to internal flash being the usb medium + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; +#endif + int first_soft_reset = true; soft_reset: @@ -415,10 +412,6 @@ soft_reset: // Create it if needed, mount in on /flash, and set it as current dir. init_flash_fs(reset_mode); -#if defined(USE_DEVICE_MODE) - usb_storage_medium_t usb_medium = USB_STORAGE_MEDIUM_FLASH; -#endif - #if MICROPY_HW_HAS_SDCARD // if an SD card is present then mount it on /sd/ if (sdcard_is_present()) { @@ -426,9 +419,6 @@ soft_reset: if (res != FR_OK) { printf("[SD] could not mount SD card\n"); } else { - // use SD card as current directory - f_chdrive("/sd"); - // TODO these should go before the /flash entries in the path mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib)); @@ -436,16 +426,24 @@ soft_reset: if (first_soft_reset) { // use SD card as medium for the USB MSD #if defined(USE_DEVICE_MODE) - usb_medium = USB_STORAGE_MEDIUM_SDCARD; + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD; #endif } + + #if defined(USE_DEVICE_MODE) + // only use SD card as current directory if that's what the USB medium is + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_SDCARD) + #endif + { + // use SD card as current directory + f_chdrive("/sd"); + } } } #endif // reset config variables; they should be set by boot.py MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; - MP_STATE_PORT(pyb_config_usb_mode) = MP_OBJ_NULL; // run boot.py, if it exists // TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py @@ -472,19 +470,11 @@ soft_reset: // or whose initialisation can be safely deferred until after running // boot.py. -#if defined(USE_HOST_MODE) - // USB host - pyb_usb_host_init(); -#elif defined(USE_DEVICE_MODE) - // USB device - usb_device_mode_t usb_mode = USB_DEVICE_MODE_CDC_MSC; - // if we are not in reset_mode==1, this config variable will always be NULL - if (MP_STATE_PORT(pyb_config_usb_mode) != MP_OBJ_NULL) { - if (strcmp(mp_obj_str_get_str(MP_STATE_PORT(pyb_config_usb_mode)), "CDC+HID") == 0) { - usb_mode = USB_DEVICE_MODE_CDC_HID; - } +#if defined(USE_DEVICE_MODE) + // init USB device to default setting if it was not already configured + if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) { + pyb_usb_dev_init(USBD_PID_DEFAULT, USBD_MODE_CDC_MSC, NULL); } - pyb_usb_dev_init(usb_mode, usb_medium); #endif #if MICROPY_HW_HAS_MMA7660 diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 292e7965d9..179f66fca3 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -69,7 +69,7 @@ /// \function bootloader() /// Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t pyb_bootloader(void) { - pyb_usb_dev_stop(); + pyb_usb_dev_deinit(); storage_flush(); HAL_RCC_DeInit(); @@ -465,13 +465,6 @@ STATIC mp_obj_t pyb_standby(void) { } MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby); -/// \function have_cdc() -/// Return True if USB is connected as a serial device, False otherwise. -STATIC mp_obj_t pyb_have_cdc(void ) { - return MP_BOOL(usb_vcp_is_connected()); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); - /// \function repl_uart(uart) /// Get or set the UART object that the REPL is repeated on. STATIC mp_obj_t pyb_repl_uart(mp_uint_t n_args, const mp_obj_t *args) { @@ -494,24 +487,7 @@ STATIC mp_obj_t pyb_repl_uart(mp_uint_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart); -/// \function hid((buttons, x, y, z)) -/// Takes a 4-tuple (or list) and sends it to the USB host (the PC) to -/// signal a HID mouse-motion event. -STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { - mp_obj_t *items; - mp_obj_get_array_fixed_n(arg, 4, &items); - uint8_t data[4]; - data[0] = mp_obj_get_int(items[0]); - data[1] = mp_obj_get_int(items[1]); - data[2] = mp_obj_get_int(items[2]); - data[3] = mp_obj_get_int(items[3]); - usb_hid_send_report(data); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report); - MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c -MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); // defined in main.c STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, @@ -530,12 +506,16 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&pyb_stop_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&pyb_standby_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_usb_mode), (mp_obj_t)&pyb_usb_mode_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_usb_mode), (mp_obj_t)&pyb_usb_mode_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hid_mouse), (mp_obj_t)&pyb_usb_hid_mouse_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hid_keyboard), (mp_obj_t)&pyb_usb_hid_keyboard_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_USB_VCP), (mp_obj_t)&pyb_usb_vcp_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_USB_HID), (mp_obj_t)&pyb_usb_hid_type }, + // these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead { MP_OBJ_NEW_QSTR(MP_QSTR_have_cdc), (mp_obj_t)&pyb_have_cdc_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_USB_VCP), (mp_obj_t)&pyb_usb_vcp_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_millis), (mp_obj_t)&pyb_elapsed_millis_obj }, diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 2e5d50b2a6..1c4008667d 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -133,9 +133,9 @@ extern const struct _mp_obj_module_t mp_module_network; const char *readline_hist[8]; \ \ mp_obj_t mp_const_vcp_interrupt; \ + mp_obj_t pyb_hid_report_desc; \ \ mp_obj_t pyb_config_main; \ - mp_obj_t pyb_config_usb_mode; \ \ mp_obj_t pyb_switch_callback; \ \ diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index c3c141e4f9..937998eb40 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -42,6 +42,8 @@ Q(stop) Q(standby) Q(main) Q(usb_mode) +Q(hid_mouse) +Q(hid_keyboard) Q(sync) Q(gc) Q(repl_info) @@ -53,7 +55,6 @@ Q(read) Q(readall) Q(readline) Q(write) -Q(have_cdc) Q(repl_uart) Q(hid) Q(time) @@ -98,10 +99,19 @@ Q(tell) // for USB VCP class Q(USB_VCP) Q(setinterrupt) +Q(isconnected) +Q(have_cdc) +Q(any) Q(send) Q(recv) Q(timeout) +// for USB HID class +Q(USB_HID) +Q(any) +Q(send) +Q(recv) + // for RTC class Q(RTC) Q(info) diff --git a/stmhal/usb.c b/stmhal/usb.c index 8ea5fb561c..220d01c4e8 100644 --- a/stmhal/usb.c +++ b/stmhal/usb.c @@ -34,72 +34,104 @@ #include "usbd_cdc_interface.h" #include "usbd_msc_storage.h" +#include "py/objstr.h" #include "py/runtime.h" #include "py/stream.h" #include "bufhelper.h" #include "usb.h" #include "pybioctl.h" +// this will be persistent across a soft-reset +mp_uint_t pyb_usb_flags = 0; + #ifdef USE_DEVICE_MODE USBD_HandleTypeDef hUSBDDevice; +pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; #endif -STATIC int dev_is_enabled = 0; +// predefined hid mouse data +STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { + {&mp_type_bytes}, + 0, // hash not valid + USBD_HID_MOUSE_REPORT_DESC_SIZE, + USBD_HID_MOUSE_ReportDesc, +}; +const mp_obj_tuple_t pyb_usb_hid_mouse_obj = { + {&mp_type_tuple}, + 5, + { + MP_OBJ_NEW_SMALL_INT(USBD_PID_SECONDARY), + MP_OBJ_NEW_SMALL_INT(1), // subclass: boot + MP_OBJ_NEW_SMALL_INT(2), // protocol: mouse + MP_OBJ_NEW_SMALL_INT(USBD_HID_MOUSE_MAX_PACKET), + (mp_obj_t)&pyb_usb_hid_mouse_desc_obj, + }, +}; + +// predefined hid keyboard data +STATIC const mp_obj_str_t pyb_usb_hid_keyboard_desc_obj = { + {&mp_type_bytes}, + 0, // hash not valid + USBD_HID_KEYBOARD_REPORT_DESC_SIZE, + USBD_HID_KEYBOARD_ReportDesc, +}; +const mp_obj_tuple_t pyb_usb_hid_keyboard_obj = { + {&mp_type_tuple}, + 5, + { + MP_OBJ_NEW_SMALL_INT(USBD_PID_SECONDARY), + MP_OBJ_NEW_SMALL_INT(1), // subclass: boot + MP_OBJ_NEW_SMALL_INT(1), // protocol: keyboard + MP_OBJ_NEW_SMALL_INT(USBD_HID_KEYBOARD_MAX_PACKET), + (mp_obj_t)&pyb_usb_hid_keyboard_desc_obj, + }, +}; void pyb_usb_init0(void) { // create an exception object for interrupting by VCP MP_STATE_PORT(mp_const_vcp_interrupt) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); USBD_CDC_SetInterrupt(-1, MP_STATE_PORT(mp_const_vcp_interrupt)); + MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL; } -void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium) { +void pyb_usb_dev_init(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { #ifdef USE_DEVICE_MODE - if (!dev_is_enabled) { + if (!(pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED)) { // only init USB once in the device's power-lifetime - // Windows needs a different PID to distinguish different device - // configurations, so we set it here depending on mode. - if (mode == USB_DEVICE_MODE_CDC_MSC) { - USBD_SelectMode(USBD_MODE_CDC_MSC); - USBD_SetPID(0x9800); - } else { - USBD_SelectMode(USBD_MODE_CDC_HID); - USBD_SetPID(0x9801); - } + USBD_SetPID(pid); + USBD_SelectMode(mode, hid_info); USBD_Init(&hUSBDDevice, (USBD_DescriptorsTypeDef*)&VCP_Desc, 0); USBD_RegisterClass(&hUSBDDevice, &USBD_CDC_MSC_HID); USBD_CDC_RegisterInterface(&hUSBDDevice, (USBD_CDC_ItfTypeDef*)&USBD_CDC_fops); + switch (pyb_usb_storage_medium) { #if MICROPY_HW_HAS_SDCARD - if (medium == USB_STORAGE_MEDIUM_FLASH) { - USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops); - } else { - USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops); - } -#else - USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops); + case PYB_USB_STORAGE_MEDIUM_SDCARD: + USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops); + break; #endif + default: + USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops); + break; + } USBD_Start(&hUSBDDevice); } - dev_is_enabled = 1; + pyb_usb_flags |= PYB_USB_FLAG_DEV_ENABLED; #endif } -void pyb_usb_dev_stop(void) { - if (dev_is_enabled) { +void pyb_usb_dev_deinit(void) { + if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) { USBD_Stop(&hUSBDDevice); - dev_is_enabled = 0; + pyb_usb_flags &= ~PYB_USB_FLAG_DEV_ENABLED; } } bool usb_vcp_is_enabled(void) { - return dev_is_enabled; -} - -bool usb_vcp_is_connected(void) { - return USBD_CDC_IsConnected(); + return (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) != 0; } void usb_vcp_set_interrupt_char(int c) { - if (dev_is_enabled) { + if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) { if (c != -1) { mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_const_vcp_interrupt)); } @@ -113,7 +145,7 @@ int usb_vcp_recv_byte(uint8_t *c) { void usb_vcp_send_strn(const char *str, int len) { #ifdef USE_DEVICE_MODE - if (dev_is_enabled) { + if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) { USBD_CDC_TxAlways((const uint8_t*)str, len); } #endif @@ -121,7 +153,7 @@ void usb_vcp_send_strn(const char *str, int len) { void usb_vcp_send_strn_cooked(const char *str, int len) { #ifdef USE_DEVICE_MODE - if (dev_is_enabled) { + if (pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED) { for (const char *top = str + len; str < top; str++) { if (*str == '\n') { USBD_CDC_TxAlways((const uint8_t*)"\r\n", 2); @@ -133,11 +165,86 @@ void usb_vcp_send_strn_cooked(const char *str, int len) { #endif } -void usb_hid_send_report(uint8_t *buf) { -#ifdef USE_DEVICE_MODE - USBD_HID_SendReport(&hUSBDDevice, buf, 4); +/******************************************************************************/ +// Micro Python bindings for USB + +/* +TODO think about how to expose the USB device. Currently we have: + pyb.usb_mode(None) # disable USB + pyb.usb_mode('CDC+MSC') + pyb.usb_mode('CDC+HID') # defaults to mouse + pyb.usb_mode('CDC+HID', pyb.hid_mouse) + pyb.usb_mode('CDC+HID', pyb.hid_keyboard) + pyb.usb_mode('CDC+HID', (pid, subclass, protocol, max_packet_len, report_desc)) + pyb.usb_mode('host', ...) + vcp = pyb.USB_VCP() # get the VCP device for read/write + hid = pyb.USB_HID() # get the HID device for write/poll + +We could use a more class based approach, like UART and others: + usb = pyb.USB('CDC+MSC') + usb = pyb.USB('CDC+HID', pyb.USB.hid_mouse) + usb = pyb.USB('CDC+HID', pyb.USB.hid_keyboard) + usb = pyb.USB('CDC+HID', (pid, subclass, protocol, max_packet_len, report_desc)) + usb = pyb.USB('host', ...) + usb = pyb.USB() # get currently configured object + vcp = usb.VCP() # get VCP device + hid = usb.HID() # get HID device +*/ + +STATIC mp_obj_t pyb_usb_mode(mp_uint_t n_args, const mp_obj_t *args) { + pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED; + + if (args[0] == mp_const_none) { + // disable usb + #if defined(USE_DEVICE_MODE) + pyb_usb_dev_deinit(); + #endif + return mp_const_none; + } + + const char *mode_str = mp_obj_str_get_str(args[0]); +#if defined(USE_HOST_MODE) + // USB host + if (strcmp(mode_str, "host") == 0) { + pyb_usb_host_init(); + } else { + goto bad_mode; + } +#elif defined(USE_DEVICE_MODE) + // USB device + if (strcmp(mode_str, "CDC+MSC") == 0) { + pyb_usb_dev_init(USBD_PID_DEFAULT, USBD_MODE_CDC_MSC, NULL); + } else if (strcmp(mode_str, "CDC+HID") == 0) { + mp_obj_t hid_info_obj = (mp_obj_t)&pyb_usb_hid_mouse_obj; // default is mouse mode + if (n_args == 2) { + hid_info_obj = args[1]; + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(hid_info_obj, 5, &items); + USBD_HID_ModeInfoTypeDef hid_info; + mp_int_t pid = mp_obj_get_int(items[0]); + hid_info.subclass = mp_obj_get_int(items[1]); + hid_info.protocol = mp_obj_get_int(items[2]); + hid_info.max_packet_len = mp_obj_get_int(items[3]); + MP_STATE_PORT(pyb_hid_report_desc) = items[4]; // need to keep a copy of this so report_desc does not get GC'd + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(items[4], &bufinfo, MP_BUFFER_READ); + hid_info.report_desc = bufinfo.buf; + hid_info.report_desc_len = bufinfo.len; + pyb_usb_dev_init(pid, USBD_MODE_CDC_HID, &hid_info); + } else { + goto bad_mode; + } +#else + goto bad_mode; #endif + + return mp_const_none; + +bad_mode: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad USB mode")); } +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_usb_mode_obj, 1, 2, pyb_usb_mode); /******************************************************************************/ // Micro Python bindings for USB VCP @@ -175,6 +282,17 @@ STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) } STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_vcp_setinterrupt_obj, pyb_usb_vcp_setinterrupt); +STATIC mp_obj_t pyb_usb_vcp_isconnected(mp_obj_t self_in) { + return MP_BOOL(USBD_CDC_IsConnected()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_isconnected_obj, pyb_usb_vcp_isconnected); + +// deprecated in favour of USB_VCP.isconnected +STATIC mp_obj_t pyb_have_cdc(void) { + return pyb_usb_vcp_isconnected(MP_OBJ_NULL); +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); + /// \method any() /// Return `True` if any characters waiting, else `False`. STATIC mp_obj_t pyb_usb_vcp_any(mp_obj_t self_in) { @@ -254,6 +372,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_usb_vcp___exit___obj, 4, 4, pyb_u STATIC const mp_map_elem_t pyb_usb_vcp_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_setinterrupt), (mp_obj_t)&pyb_usb_vcp_setinterrupt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&pyb_usb_vcp_isconnected_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_usb_vcp_any_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_usb_vcp_send_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_usb_vcp_recv_obj }, @@ -330,6 +449,88 @@ const mp_obj_type_t pyb_usb_vcp_type = { }; /******************************************************************************/ +// Micro Python bindings for USB HID + +typedef struct _pyb_usb_hid_obj_t { + mp_obj_base_t base; +} pyb_usb_hid_obj_t; + +STATIC const pyb_usb_hid_obj_t pyb_usb_hid_obj = {{&pyb_usb_hid_type}}; + +STATIC mp_obj_t pyb_usb_hid_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return the USB HID object + return (mp_obj_t)&pyb_usb_hid_obj; +} + +STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { +#ifdef USE_DEVICE_MODE + mp_buffer_info_t bufinfo; + byte temp_buf[8]; + // get the buffer to send from + // we accept either a byte array, or a tuple/list of integers + if (!mp_get_buffer(report_in, &bufinfo, MP_BUFFER_READ)) { + mp_obj_t *items; + mp_obj_get_array(report_in, &bufinfo.len, &items); + if (bufinfo.len > sizeof(temp_buf)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "tuple/list too large for HID report; use bytearray instead")); + } + for (int i = 0; i < bufinfo.len; i++) { + temp_buf[i] = mp_obj_get_int(items[i]); + } + bufinfo.buf = temp_buf; + } + + // send the data + USBD_HID_SendReport(&hUSBDDevice, bufinfo.buf, bufinfo.len); +#endif + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_hid_send_obj, pyb_usb_hid_send); + +// deprecated in favour of USB_HID.send +STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { + return pyb_usb_hid_send(MP_OBJ_NULL, arg); +} +MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report); + +STATIC const mp_map_elem_t pyb_usb_hid_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_usb_hid_send_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table); + +STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + mp_uint_t ret; + if (request == MP_IOCTL_POLL) { + mp_uint_t flags = arg; + ret = 0; + if ((flags & MP_IOCTL_POLL_WR) && USBD_HID_CanSendReport(&hUSBDDevice)) { + ret |= MP_IOCTL_POLL_WR; + } + } else { + *errcode = EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t pyb_usb_hid_stream_p = { + .ioctl = pyb_usb_hid_ioctl, +}; + +const mp_obj_type_t pyb_usb_hid_type = { + { &mp_type_type }, + .name = MP_QSTR_USB_HID, + .make_new = pyb_usb_hid_make_new, + .stream_p = &pyb_usb_hid_stream_p, + .locals_dict = (mp_obj_t)&pyb_usb_hid_locals_dict, +}; + +/******************************************************************************/ // code for experimental USB OTG support #ifdef USE_HOST_MODE diff --git a/stmhal/usb.h b/stmhal/usb.h index e0bfe9a76e..4ac51f3228 100644 --- a/stmhal/usb.h +++ b/stmhal/usb.h @@ -24,28 +24,40 @@ * THE SOFTWARE. */ -typedef enum { - USB_DEVICE_MODE_CDC_MSC, - USB_DEVICE_MODE_CDC_HID, -} usb_device_mode_t; +#include "usbd_cdc_msc_hid0.h" + +#define PYB_USB_FLAG_DEV_ENABLED (0x0001) +#define PYB_USB_FLAG_USB_MODE_CALLED (0x0002) + +// Windows needs a different PID to distinguish different device configurations +#define USBD_PID_DEFAULT (0x9800) +#define USBD_PID_SECONDARY (0x9801) typedef enum { - USB_STORAGE_MEDIUM_FLASH, - USB_STORAGE_MEDIUM_SDCARD, -} usb_storage_medium_t; + PYB_USB_STORAGE_MEDIUM_NONE = 0, + PYB_USB_STORAGE_MEDIUM_FLASH, + PYB_USB_STORAGE_MEDIUM_SDCARD, +} pyb_usb_storage_medium_t; +extern mp_uint_t pyb_usb_flags; +extern struct _USBD_HandleTypeDef hUSBDDevice; +extern pyb_usb_storage_medium_t pyb_usb_storage_medium; +extern const struct _mp_obj_tuple_t pyb_usb_hid_mouse_obj; +extern const struct _mp_obj_tuple_t pyb_usb_hid_keyboard_obj; extern const mp_obj_type_t pyb_usb_vcp_type; +extern const mp_obj_type_t pyb_usb_hid_type; +MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); +MP_DECLARE_CONST_FUN_OBJ(pyb_have_cdc_obj); // deprecated +MP_DECLARE_CONST_FUN_OBJ(pyb_hid_send_report_obj); // deprecated void pyb_usb_init0(void); -void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium); -void pyb_usb_dev_stop(void); +void pyb_usb_dev_init(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info); +void pyb_usb_dev_deinit(void); bool usb_vcp_is_enabled(void); -bool usb_vcp_is_connected(void); void usb_vcp_set_interrupt_char(int c); int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0 void usb_vcp_send_strn(const char* str, int len); void usb_vcp_send_strn_cooked(const char *str, int len); -void usb_hid_send_report(uint8_t *buf); // 4 bytes for mouse: ?, x, y, ? void pyb_usb_host_init(void); void pyb_usb_host_process(void); diff --git a/stmhal/usbd_cdc_interface.c b/stmhal/usbd_cdc_interface.c index 5814da6469..66bfe1a229 100644 --- a/stmhal/usbd_cdc_interface.c +++ b/stmhal/usbd_cdc_interface.c @@ -35,12 +35,15 @@ /* Includes ------------------------------------------------------------------*/ #include <stdbool.h> +#include <stdint.h> -#include "stm32f4xx_hal.h" #include "usbd_cdc_msc_hid.h" #include "usbd_cdc_interface.h" #include "pendsv.h" +#include "py/obj.h" +#include "usb.h" + // CDC control commands #define CDC_SEND_ENCAPSULATED_COMMAND 0x00 #define CDC_GET_ENCAPSULATED_RESPONSE 0x01 @@ -76,9 +79,6 @@ static uint8_t UserTxNeedEmptyPacket = 0; // used to flush the USB IN endpoint i static int user_interrupt_char = -1; static void *user_interrupt_data = NULL; -/* USB handler declaration */ -extern USBD_HandleTypeDef hUSBDDevice; - /* Private function prototypes -----------------------------------------------*/ static int8_t CDC_Itf_Init (void); static int8_t CDC_Itf_DeInit (void); diff --git a/stmhal/usbd_msc_storage.c b/stmhal/usbd_msc_storage.c index 04a2b53ae9..03483ef093 100644 --- a/stmhal/usbd_msc_storage.c +++ b/stmhal/usbd_msc_storage.c @@ -31,6 +31,8 @@ ****************************************************************************** */ +#include <stdint.h> + #include "usbd_cdc_msc_hid.h" #include "usbd_msc_storage.h" diff --git a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid0.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid0.h new file mode 100644 index 0000000000..7bf2cf955d --- /dev/null +++ b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid0.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * 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 __MICROPY_INCLUDED_STMHAL_USB_CDC_MSC_HID0_H__ +#define __MICROPY_INCLUDED_STMHAL_USB_CDC_MSC_HID0_H__ + +// these are exports for the CDC/MSC/HID interface that are independent +// from any other definitions/declarations + +// only CDC_MSC and CDC_HID are available +typedef enum { + USBD_MODE_CDC = 0x01, + USBD_MODE_MSC = 0x02, + USBD_MODE_HID = 0x04, + USBD_MODE_CDC_MSC = 0x03, + USBD_MODE_CDC_HID = 0x05, + USBD_MODE_MSC_HID = 0x06, +} usb_device_mode_t; + +typedef struct _USBD_HID_ModeInfoTypeDef { + uint8_t subclass; // 0=no sub class, 1=boot + uint8_t protocol; // 0=none, 1=keyboard, 2=mouse + uint8_t max_packet_len; // only support up to 255 + uint8_t report_desc_len; + const uint8_t *report_desc; +} USBD_HID_ModeInfoTypeDef; + +#endif // __MICROPY_INCLUDED_STMHAL_USB_CDC_MSC_HID0_H__ diff --git a/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h index 48d260bc25..bc1e33eca5 100644 --- a/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -1,6 +1,7 @@ #ifndef _USB_CDC_MSC_CORE_H_ #define _USB_CDC_MSC_CORE_H_ +#include "usbd_cdc_msc_hid0.h" #include "usbd_msc_bot.h" #include "usbd_msc_scsi.h" #include "usbd_ioreq.h" @@ -18,14 +19,6 @@ #define CDC_OUT_EP (0x03) #define CDC_CMD_EP (0x82) -// only CDC_MSC and CDC_HID are available -#define USBD_MODE_CDC (0x01) -#define USBD_MODE_MSC (0x02) -#define USBD_MODE_HID (0x04) -#define USBD_MODE_CDC_MSC (USBD_MODE_CDC | USBD_MODE_MSC) -#define USBD_MODE_CDC_HID (USBD_MODE_CDC | USBD_MODE_HID) -#define USBD_MODE_MSC_HID (USBD_MODE_MSC | USBD_MODE_HID) - typedef struct { uint32_t bitrate; uint8_t format; @@ -87,9 +80,19 @@ typedef struct { uint32_t scsi_blk_len; } USBD_MSC_BOT_HandleTypeDef; +#define USBD_HID_MOUSE_MAX_PACKET (4) +#define USBD_HID_MOUSE_REPORT_DESC_SIZE (74) + +extern const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE]; + +#define USBD_HID_KEYBOARD_MAX_PACKET (8) +#define USBD_HID_KEYBOARD_REPORT_DESC_SIZE (63) + +extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE]; + extern USBD_ClassTypeDef USBD_CDC_MSC_HID; -void USBD_SelectMode(uint32_t mode); +void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info); uint8_t USBD_CDC_RegisterInterface (USBD_HandleTypeDef *pdev, USBD_CDC_ItfTypeDef *fops); uint8_t USBD_CDC_SetTxBuffer (USBD_HandleTypeDef *pdev, uint8_t *pbuff, uint16_t length); @@ -99,6 +102,7 @@ uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev); uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops); +int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev); uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len); #endif // _USB_CDC_MSC_CORE_H_ diff --git a/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c index 02d2bba607..4386ce8149 100644 --- a/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c @@ -1,8 +1,17 @@ #include "usbd_ioreq.h" #include "usbd_cdc_msc_hid.h" -#define USB_CDC_MSC_CONFIG_DESC_SIZ (98) -#define USB_CDC_HID_CONFIG_DESC_SIZ (100) +#define CDC_MSC_CONFIG_DESC_SIZE (98) +#define CDC_HID_CONFIG_DESC_SIZE (100) +#define CDC_HID_HID_DESC_OFFSET (CDC_HID_CONFIG_DESC_SIZE - 25) +#define CDC_HID_HID_DESC_OFFSET_SUBCLASS (CDC_HID_HID_DESC_OFFSET + 6) +#define CDC_HID_HID_DESC_OFFSET_PROTOCOL (CDC_HID_HID_DESC_OFFSET + 7) +#define CDC_HID_HID_DESC_OFFSET_SUBDESC (CDC_HID_HID_DESC_OFFSET + 9) +#define CDC_HID_HID_DESC_OFFSET_REPORT_DESC_LEN (CDC_HID_HID_DESC_OFFSET + 16) +#define CDC_HID_HID_DESC_OFFSET_MAX_PACKET_LO (CDC_HID_HID_DESC_OFFSET + 22) +#define CDC_HID_HID_DESC_OFFSET_MAX_PACKET_HI (CDC_HID_HID_DESC_OFFSET + 23) +#define CDC_HID_HID_SUBDESC_LEN (9) + #define CDC_IFACE_NUM (1) #define MSC_IFACE_NUM (0) #define HID_IFACE_NUM_WITH_CDC (0) @@ -21,10 +30,6 @@ #define BOT_GET_MAX_LUN 0xFE #define BOT_RESET 0xFF -#define HID_MAX_PACKET 0x04 -#define USB_HID_DESC_SIZ 9 -#define HID_MOUSE_REPORT_DESC_SIZE 74 -#define HID_KEYBOARD_REPORT_DESC_SIZE 63 #define HID_DESCRIPTOR_TYPE 0x21 #define HID_REPORT_DESC 0x22 #define HID_REQ_SET_PROTOCOL 0x0B @@ -47,6 +52,7 @@ typedef struct { static uint8_t usbd_mode; static uint8_t hid_in_ep; static uint8_t hid_iface_num; +static const uint8_t *hid_report_desc; static USBD_CDC_ItfTypeDef *CDC_fops; static USBD_StorageTypeDef *MSC_fops; @@ -73,13 +79,13 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QU }; // USB CDC MSC device Configuration Descriptor -__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_CfgDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] __ALIGN_END = { +__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_CfgDesc[CDC_MSC_CONFIG_DESC_SIZE] __ALIGN_END = { //-------------------------------------------------------------------------- // Configuration Descriptor 0x09, // bLength: Configuration Descriptor size USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration - LOBYTE(USB_CDC_MSC_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes - HIBYTE(USB_CDC_MSC_CONFIG_DESC_SIZ), + LOBYTE(CDC_MSC_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(CDC_MSC_CONFIG_DESC_SIZE), 0x03, // bNumInterfaces: 3 interfaces 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration @@ -210,13 +216,13 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_CfgDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] _ }; // USB CDC HID device Configuration Descriptor -__ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] __ALIGN_END = { +__ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[CDC_HID_CONFIG_DESC_SIZE] __ALIGN_END = { //-------------------------------------------------------------------------- // Configuration Descriptor 0x09, // bLength: Configuration Descriptor size USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration - LOBYTE(USB_CDC_HID_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes - HIBYTE(USB_CDC_HID_CONFIG_DESC_SIZ), + LOBYTE(CDC_HID_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(CDC_HID_CONFIG_DESC_SIZE), 0x03, // bNumInterfaces: 3 interfaces 0x01, // bConfigurationValue: Configuration value 0x00, // iConfiguration: Index of string descriptor describing the configuration @@ -323,7 +329,7 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] _ 0x00, // bAlternateSetting: Alternate setting 0x01, // bNumEndpoints 0x03, // bInterfaceClass: HID Class - 0x01, // bInterfaceSubClass: 1=BOOT, 0=no boot + 0x01, // bInterfaceSubClass: 0=no sub class, 1=boot 0x02, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse 0x00, // iInterface: @@ -335,7 +341,7 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] _ 0x00, // bCountryCode: Hardware target country 0x01, // bNumDescriptors: Number of HID class descriptors to follow 0x22, // bDescriptorType - HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor + USBD_HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor 0x00, // Endpoint IN descriptor @@ -343,75 +349,53 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] _ USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type HID_IN_EP_WITH_CDC, // bEndpointAddress: IN 0x03, // bmAttributes: Interrupt endpoint type - LOBYTE(HID_MAX_PACKET), // wMaxPacketSize - HIBYTE(HID_MAX_PACKET), + LOBYTE(USBD_HID_MOUSE_MAX_PACKET), // wMaxPacketSize + HIBYTE(USBD_HID_MOUSE_MAX_PACKET), 0x08, // bInterval: Polling interval }; -/* USB HID device Configuration Descriptor */ -__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END = { - 0x09, /*bLength: HID Descriptor size*/ - HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ - 0x11, /*bcdHID: HID Class Spec release number*/ - 0x01, - 0x00, /*bCountryCode: Hardware target country*/ - 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ - 0x22, /*bDescriptorType*/ - HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/ - 0x00, -}; - -__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = { - 0x05, 0x01, - 0x09, 0x02, - 0xA1, 0x01, - 0x09, 0x01, - - 0xA1, 0x00, - 0x05, 0x09, - 0x19, 0x01, - 0x29, 0x03, - - 0x15, 0x00, - 0x25, 0x01, - 0x95, 0x03, - 0x75, 0x01, - - 0x81, 0x02, - 0x95, 0x01, - 0x75, 0x05, - 0x81, 0x01, - - 0x05, 0x01, - 0x09, 0x30, - 0x09, 0x31, - 0x09, 0x38, - - 0x15, 0x81, - 0x25, 0x7F, - 0x75, 0x08, - 0x95, 0x03, - - 0x81, 0x06, - 0xC0, 0x09, - 0x3c, 0x05, - 0xff, 0x09, - - 0x01, 0x15, - 0x00, 0x25, - 0x01, 0x75, - 0x01, 0x95, - - 0x02, 0xb1, - 0x22, 0x75, - 0x06, 0x95, - 0x01, 0xb1, - - 0x01, 0xc0 +__ALIGN_BEGIN const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = { + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x02, // Usage (Mouse), + 0xA1, 0x01, // Collection (Application), + 0x09, 0x01, // Usage (Pointer), + 0xA1, 0x00, // Collection (Physical), + 0x05, 0x09, // Usage Page (Buttons), + 0x19, 0x01, // Usage Minimum (01), + 0x29, 0x03, // Usage Maximum (03), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x95, 0x03, // Report Count (3), + 0x75, 0x01, // Report Size (1), + 0x81, 0x02, // Input(Data, Variable, Absolute), -- 3 button bits + 0x95, 0x01, // Report Count(1), + 0x75, 0x05, // Report Size(5), + 0x81, 0x01, // Input(Constant), -- 5 bit padding + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x30, // Usage (X), + 0x09, 0x31, // Usage (Y), + 0x09, 0x38, // Usage (Wheel), + 0x15, 0x81, // Logical Minimum (-127), + 0x25, 0x7F, // Logical Maximum (127), + 0x75, 0x08, // Report Size (8), + 0x95, 0x03, // Report Count (3), + 0x81, 0x06, // Input(Data, Variable, Relative), -- 3 position bytes (X,Y,Wheel) + 0xC0, // End Collection, + 0x09, 0x3c, // Usage (Motion Wakeup), + 0x05, 0xff, // Usage Page (?), + 0x09, 0x01, // Usage (?), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x75, 0x01, // Report Size(1), + 0x95, 0x02, // Report Count(2), + 0xb1, 0x22, // ? + 0x75, 0x06, // Report Size(6), + 0x95, 0x01, // Report Count(1), + 0xb1, 0x01, // ? + 0xc0 // End Collection }; -#if 0 -__ALIGN_BEGIN static const uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = { +__ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = { // From p69 of http://www.usb.org/developers/devclass_docs/HID1_11.pdf 0x05, 0x01, // Usage Page (Generic Desktop), 0x09, 0x06, // Usage (Keyboard), @@ -446,9 +430,8 @@ __ALIGN_BEGIN static const uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_D 0x81, 0x00, // Input (Data, Array), ;Key arrays (6 bytes) 0xC0 // End Collection }; -#endif -void USBD_SelectMode(uint32_t mode) { +void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { // save mode usbd_mode = mode; @@ -461,6 +444,14 @@ void USBD_SelectMode(uint32_t mode) { hid_in_ep = HID_IN_EP_WITH_MSC; hid_iface_num = HID_IFACE_NUM_WITH_MSC; } + + // configure the descriptor + USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; + USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; + USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; + USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_MAX_PACKET_LO] = hid_info->max_packet_len; + USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_MAX_PACKET_HI] = 0; + hid_report_desc = hid_info->report_desc; } } @@ -527,11 +518,16 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { if (usbd_mode & USBD_MODE_HID) { // HID component + // get max packet length from descriptor + uint16_t mps = + USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_MAX_PACKET_LO] + | (USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_MAX_PACKET_HI] << 8); + // Open EP IN USBD_LL_OpenEP(pdev, hid_in_ep, USBD_EP_TYPE_INTR, - HID_MAX_PACKET); + mps); HID_ClassData.state = HID_IDLE; } @@ -703,11 +699,12 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp uint16_t len = 0; const uint8_t *pbuf = NULL; if (req->wValue >> 8 == HID_REPORT_DESC) { - len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength); - pbuf = HID_MOUSE_ReportDesc; + len = USBD_CDC_HID_CfgDesc[CDC_HID_HID_DESC_OFFSET_REPORT_DESC_LEN]; + len = MIN(len, req->wLength); + pbuf = hid_report_desc; } else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) { - len = MIN(USB_HID_DESC_SIZ , req->wLength); - pbuf = USBD_HID_Desc; + len = MIN(CDC_HID_HID_SUBDESC_LEN, req->wLength); + pbuf = USBD_CDC_HID_CfgDesc + CDC_HID_HID_DESC_OFFSET_SUBDESC; } USBD_CtlSendData(pdev, (uint8_t*)pbuf, len); break; @@ -891,6 +888,10 @@ uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef * } } +int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev) { + return pdev->dev_state == USBD_STATE_CONFIGURED && HID_ClassData.state == HID_IDLE; +} + uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len) { if (pdev->dev_state == USBD_STATE_CONFIGURED) { if (HID_ClassData.state == HID_IDLE) { |