stmhal: Add Python-configurable USB HID mode.

Different HID modes can be configured in Python.  You can either use
predefined mouse or keyboard, or write your own report descriptor.
This commit is contained in:
Damien George 2014-11-01 21:26:06 +00:00
parent b384bcc5de
commit d39c7aa517
13 changed files with 462 additions and 203 deletions

View file

@ -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``.

View file

@ -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.

View file

@ -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

View file

@ -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_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_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_hid), (mp_obj_t)&pyb_hid_send_report_obj },
{ 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 },

View file

@ -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; \
\

View file

@ -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)

View file

@ -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 },
@ -329,6 +448,88 @@ const mp_obj_type_t pyb_usb_vcp_type = {
.locals_dict = (mp_obj_t)&pyb_usb_vcp_locals_dict,
};
/******************************************************************************/
// 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

View file

@ -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);

View file

@ -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);

View file

@ -31,6 +31,8 @@
******************************************************************************
*/
#include <stdint.h>
#include "usbd_cdc_msc_hid.h"
#include "usbd_msc_storage.h"

View file

@ -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__

View file

@ -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_

View file

@ -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 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
};
__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
};
#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) {