summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--docs/library/pyb.USB_VCP.rst4
-rw-r--r--docs/library/pyb.rst4
-rw-r--r--stmhal/main.c48
-rw-r--r--stmhal/modpyb.c36
-rw-r--r--stmhal/mpconfigport.h2
-rw-r--r--stmhal/qstrdefsport.h12
-rw-r--r--stmhal/usb.c269
-rw-r--r--stmhal/usb.h34
-rw-r--r--stmhal/usbd_cdc_interface.c8
-rw-r--r--stmhal/usbd_msc_storage.c2
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid0.h51
-rw-r--r--stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h22
-rw-r--r--stmhal/usbdev/class/src/usbd_cdc_msc_hid.c171
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) {