diff options
-rw-r--r-- | stmhal/main.c | 2 | ||||
-rw-r--r-- | stmhal/qstrdefsport.h | 13 | ||||
-rw-r--r-- | stmhal/usb.c | 147 | ||||
-rw-r--r-- | stmhal/usb.h | 3 | ||||
-rw-r--r-- | stmhal/usbd_desc.c | 8 | ||||
-rw-r--r-- | stmhal/usbd_desc.h | 2 | ||||
-rw-r--r-- | stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h | 3 | ||||
-rw-r--r-- | stmhal/usbdev/class/src/usbd_cdc_msc_hid.c | 9 |
8 files changed, 127 insertions, 60 deletions
diff --git a/stmhal/main.c b/stmhal/main.c index d2aaf89acd..2cb25d8647 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -473,7 +473,7 @@ soft_reset: #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_CDC_MSC, USBD_MODE_CDC_MSC, NULL); + pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL); } #endif diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 937998eb40..3aecb7acfa 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -41,9 +41,6 @@ Q(enable_irq) Q(stop) Q(standby) Q(main) -Q(usb_mode) -Q(hid_mouse) -Q(hid_keyboard) Q(sync) Q(gc) Q(repl_info) @@ -56,7 +53,6 @@ Q(readall) Q(readline) Q(write) Q(repl_uart) -Q(hid) Q(time) Q(rng) Q(SD) @@ -96,6 +92,15 @@ Q(hashlib) Q(seek) Q(tell) +// for USB configuration +Q(usb_mode) +Q(mode) +Q(vid) +Q(pid) +Q(hid) +Q(hid_mouse) +Q(hid_keyboard) + // for USB VCP class Q(USB_VCP) Q(setinterrupt) diff --git a/stmhal/usb.c b/stmhal/usb.c index b6b9c9664e..24aae1857d 100644 --- a/stmhal/usb.c +++ b/stmhal/usb.c @@ -58,9 +58,8 @@ STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { }; const mp_obj_tuple_t pyb_usb_hid_mouse_obj = { {&mp_type_tuple}, - 5, + 4, { - MP_OBJ_NEW_SMALL_INT(USBD_PID_CDC_HID), 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), @@ -77,9 +76,8 @@ STATIC const mp_obj_str_t pyb_usb_hid_keyboard_desc_obj = { }; const mp_obj_tuple_t pyb_usb_hid_keyboard_obj = { {&mp_type_tuple}, - 5, + 4, { - MP_OBJ_NEW_SMALL_INT(USBD_PID_CDC_HID), 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), @@ -94,12 +92,14 @@ void pyb_usb_init0(void) { MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL; } -void pyb_usb_dev_init(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { #ifdef USE_DEVICE_MODE if (!(pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED)) { // only init USB once in the device's power-lifetime - USBD_SetPID(pid); - USBD_SelectMode(mode, hid_info); + USBD_SetVIDPIDRelease(vid, pid, 0x0200); + if (USBD_SelectMode(mode, hid_info) != 0) { + return false; + } USBD_Init(&hUSBDDevice, (USBD_DescriptorsTypeDef*)&USBD_Descriptors, 0); USBD_RegisterClass(&hUSBDDevice, &USBD_CDC_MSC_HID); USBD_CDC_RegisterInterface(&hUSBDDevice, (USBD_CDC_ItfTypeDef*)&USBD_CDC_fops); @@ -117,6 +117,8 @@ void pyb_usb_dev_init(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTyp } pyb_usb_flags |= PYB_USB_FLAG_DEV_ENABLED; #endif + + return true; } void pyb_usb_dev_deinit(void) { @@ -169,32 +171,47 @@ void usb_vcp_send_strn_cooked(const char *str, int len) { // 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', ...) + Philosophy of USB driver and Python API: pyb.usb_mode(...) configures the USB + on the board. The USB itself is not an entity, rather the interfaces are, and + can be accessed by creating objects, such as pyb.USB_VCP() and pyb.USB_HID(). + + We have: + + pyb.usb_mode(None) # disable USB + pyb.usb_mode('VCP') # enable with VCP interface + pyb.usb_mode('VCP+MSC') # enable with VCP and MSC interfaces + pyb.usb_mode('VCP+HID') # enable with VCP and HID, defaulting to mouse protocol + pyb.usb_mode('VCP+HID', vid=0xf055, pid=0x9800) # specify VID and PID + pyb.usb_mode('VCP+HID', hid=pyb.hid_mouse) + pyb.usb_mode('VCP+HID', hid=pyb.hid_keyboard) + pyb.usb_mode('VCP+HID', pid=0x1234, hid=(subclass, protocol, max_packet_len, report_desc)) + 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 + Possible extensions: + pyb.usb_mode('host', ...) + pyb.usb_mode('OTG', ...) + pyb.usb_mode(..., port=2) # for second USB port */ -STATIC mp_obj_t pyb_usb_mode(mp_uint_t n_args, const mp_obj_t *args) { +STATIC mp_obj_t pyb_usb_mode(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} }, + { MP_QSTR_pid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (mp_obj_t)&pyb_usb_hid_mouse_obj} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // record the fact that the usb has been explicitly configured pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED; - if (args[0] == mp_const_none) { + // check if user wants to disable the USB + if (args[0].u_obj == mp_const_none) { // disable usb #if defined(USE_DEVICE_MODE) pyb_usb_dev_deinit(); @@ -202,42 +219,72 @@ STATIC mp_obj_t pyb_usb_mode(mp_uint_t n_args, const mp_obj_t *args) { return mp_const_none; } - const char *mode_str = mp_obj_str_get_str(args[0]); + // get mode string + const char *mode_str = mp_obj_str_get_str(args[0].u_obj); + #if defined(USE_HOST_MODE) - // USB host + + // hardware configured for USB host mode + 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_CDC_MSC, 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]; + + // hardware configured for USB device mode + + // get the VID, PID and USB mode + // note: PID=-1 means select PID based on mode + // note: we support CDC as a synonym for VCP for backward compatibility + uint16_t vid = args[1].u_int; + uint16_t pid = args[2].u_int; + usb_device_mode_t mode; + if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC_MSC; + } + mode = USBD_MODE_CDC_MSC; + } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC_HID; } + mode = USBD_MODE_CDC_HID; + } else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC; + } + mode = USBD_MODE_CDC; + } else { + goto bad_mode; + } + + // get hid info if user selected such a mode + USBD_HID_ModeInfoTypeDef hid_info; + if (mode & USBD_MODE_HID) { 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_obj_get_array_fixed_n(args[3].u_obj, 4, &items); + hid_info.subclass = mp_obj_get_int(items[0]); + hid_info.protocol = mp_obj_get_int(items[1]); + hid_info.max_packet_len = mp_obj_get_int(items[2]); mp_buffer_info_t bufinfo; - mp_get_buffer_raise(items[4], &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(items[3], &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 if (strcmp(mode_str, "CDC") == 0) { - pyb_usb_dev_init(USBD_PID_CDC, USBD_MODE_CDC, NULL); - } else { + + // need to keep a copy of this so report_desc does not get GC'd + MP_STATE_PORT(pyb_hid_report_desc) = items[3]; + } + + // init the USB device + if (!pyb_usb_dev_init(vid, pid, mode, &hid_info)) { goto bad_mode; } + #else + // hardware not configured for USB goto bad_mode; #endif @@ -246,7 +293,7 @@ STATIC mp_obj_t pyb_usb_mode(mp_uint_t n_args, const mp_obj_t *args) { 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); +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj, 1, pyb_usb_mode); /******************************************************************************/ // Micro Python bindings for USB VCP @@ -274,6 +321,8 @@ STATIC mp_obj_t pyb_usb_vcp_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint // check arguments mp_arg_check_num(n_args, n_kw, 0, 0, false); + // TODO raise exception if USB is not configured for VCP + // return the USB VCP object return (mp_obj_t)&pyb_usb_vcp_obj; } @@ -463,6 +512,8 @@ STATIC mp_obj_t pyb_usb_hid_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint // check arguments mp_arg_check_num(n_args, n_kw, 0, 0, false); + // TODO raise exception if USB is not configured for HID + // return the USB HID object return (mp_obj_t)&pyb_usb_hid_obj; } diff --git a/stmhal/usb.h b/stmhal/usb.h index 70441c578e..ae16e72076 100644 --- a/stmhal/usb.h +++ b/stmhal/usb.h @@ -30,6 +30,7 @@ #define PYB_USB_FLAG_USB_MODE_CALLED (0x0002) // Windows needs a different PID to distinguish different device configurations +#define USBD_VID (0xf055) #define USBD_PID_CDC_MSC (0x9800) #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) @@ -52,7 +53,7 @@ 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(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info); +bool pyb_usb_dev_init(uint16_t vid, 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); void usb_vcp_set_interrupt_char(int c); diff --git a/stmhal/usbd_desc.c b/stmhal/usbd_desc.c index c893b4c666..212e91a576 100644 --- a/stmhal/usbd_desc.c +++ b/stmhal/usbd_desc.c @@ -80,10 +80,14 @@ __ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_EN __ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; -// set the PID -void USBD_SetPID(uint16_t pid) { +// set the VID, PID and device release number +void USBD_SetVIDPIDRelease(uint16_t vid, uint16_t pid, uint16_t device_release_num) { + hUSBDDeviceDesc[8] = LOBYTE(pid); + hUSBDDeviceDesc[9] = HIBYTE(pid); hUSBDDeviceDesc[10] = LOBYTE(pid); hUSBDDeviceDesc[11] = HIBYTE(pid); + hUSBDDeviceDesc[12] = LOBYTE(device_release_num); + hUSBDDeviceDesc[13] = HIBYTE(device_release_num); } /** diff --git a/stmhal/usbd_desc.h b/stmhal/usbd_desc.h index c16808b8a6..609fa8da86 100644 --- a/stmhal/usbd_desc.h +++ b/stmhal/usbd_desc.h @@ -26,4 +26,4 @@ extern const USBD_DescriptorsTypeDef USBD_Descriptors; -void USBD_SetPID(uint16_t pid); +void USBD_SetVIDPIDRelease(uint16_t vid, uint16_t pid, uint16_t device_release_num); diff --git a/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h index bc1e33eca5..52d845b24a 100644 --- a/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -92,7 +92,8 @@ extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_ extern USBD_ClassTypeDef USBD_CDC_MSC_HID; -void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info); +// returns 0 on success, -1 on failure +int 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); diff --git a/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c index 77852a03d5..3db7bd2201 100644 --- a/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c @@ -559,7 +559,7 @@ __ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPOR 0xC0 // End Collection }; -void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { +int USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { // save mode usbd_mode = mode; @@ -593,10 +593,14 @@ void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { hid_iface_num = HID_IFACE_NUM_WITH_MSC; break; */ + + default: + // mode not supported + return -1; } + // configure the HID descriptor, if needed if (usbd_mode & USBD_MODE_HID) { - // configure the HID descriptor hid_desc[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; hid_desc[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; @@ -605,6 +609,7 @@ void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { hid_report_desc = hid_info->report_desc; } + return 0; } static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { |