diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 7e30805cce..23c490d375 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -63,6 +63,9 @@ typedef struct _usb_device_t { USBD_HandleTypeDef hUSBDDevice; usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state; usbd_cdc_itf_t usbd_cdc_itf; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_itf_t usbd_cdc2_itf; + #endif usbd_hid_itf_t usbd_hid_itf; } usb_device_t; @@ -127,6 +130,9 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H usbd->pClass = &USBD_CDC_MSC_HID; usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; + #if MICROPY_HW_USB_ENABLE_CDC2 + usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base; + #endif usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; @@ -178,6 +184,15 @@ void usb_vcp_send_strn(const char *str, int len) { } } +usbd_cdc_itf_t *usb_vcp_get(int idx) { + #if MICROPY_HW_USB_ENABLE_CDC2 + if (idx == 1) { + return &usb_device.usbd_cdc2_itf; + } + #endif + return &usb_device.usbd_cdc_itf; +} + /******************************************************************************/ // MicroPython bindings for USB @@ -285,6 +300,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC_MSC; } mode = USBD_MODE_CDC_MSC; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC2_MSC; + } + mode = USBD_MODE_CDC2_MSC; + #endif } 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; @@ -358,21 +380,33 @@ typedef struct _pyb_usb_vcp_obj_t { } pyb_usb_vcp_obj_t; STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf}; +#if MICROPY_HW_USB_ENABLE_CDC2 +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf}; +#endif STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - mp_print_str(print, "USB_VCP()"); + int id = ((pyb_usb_vcp_obj_t*)self_in)->cdc_itf - &usb_device.usbd_cdc_itf; + mp_printf(print, "USB_VCP(%u)", id); } /// \classmethod \constructor() /// Create a new USB_VCP object. STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments - mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_arg_check_num(n_args, n_kw, 0, 1, false); // TODO raise exception if USB is not configured for VCP - // return the USB VCP object - return (mp_obj_t)&pyb_usb_vcp_obj; + int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]); + if (id == 0) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (id == 1) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj); + #endif + } else { + mp_raise_ValueError(NULL); + } } STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) { diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 6b43af00fa..1de9e5d0e5 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -36,6 +36,7 @@ #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) #define USBD_PID_MSC (0x9803) +#define USBD_PID_CDC2_MSC (0x9804) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 3ab6157c46..4c464dbf33 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -69,6 +69,11 @@ uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { cdc->tx_buf_ptr_wait_count = 0; cdc->tx_need_empty_packet = 0; cdc->dev_is_connected = 0; + #if MICROPY_HW_USB_ENABLE_CDC2 + cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc; + #else + cdc->attached_to_repl = 1; + #endif // Return the buffer to place the first USB OUT packet return cdc->rx_packet_buf; @@ -143,10 +148,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui // This function is called to process outgoing data. We hook directly into the // SOF (start of frame) callback so that it is called exactly at the time it is // needed (reducing latency), and often enough (increasing bandwidth). -void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { - usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc; - +static void usbd_cdc_sof(PCD_HandleTypeDef *hpcd, usbd_cdc_itf_t *cdc) { if (cdc == NULL || !cdc->dev_is_connected) { // CDC device is not connected to a host, so we are unable to send any data return; @@ -199,11 +201,19 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // the host waits for all data to arrive (ie, waits for a packet < max packet size). // To flush a packet of exactly max packet size, we need to send a zero-size packet. // See eg http://www.cypress.com/?id=4&rID=92719 - cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); + cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); } } } +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { + usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc); + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc2); + #endif +} + // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL @@ -212,7 +222,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { // copy the incoming data into the circular buffer for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) { - if (mp_interrupt_char != -1 && *src == mp_interrupt_char) { + if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) { pendsv_kbd_intr(); } else { uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1); diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index bfcdfaf333..cdf556d4ec 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -50,8 +50,12 @@ typedef struct _usbd_cdc_itf_t { uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size volatile uint8_t dev_is_connected; // indicates if we are connected + uint8_t attached_to_repl; // indicates if interface is connected to REPL } usbd_cdc_itf_t; +// This is implemented in usb.c +usbd_cdc_itf_t *usb_vcp_get(int idx); + static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) { return cdc->dev_is_connected; } diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d4a09459b8..7829dcce68 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -368,7 +368,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { if (pdev->id == USB_PHY_FS_ID) { // Set LL Driver parameters pcd_fs_handle.Instance = USB_OTG_FS; + #if MICROPY_HW_USB_ENABLE_CDC2 + pcd_fs_handle.Init.dev_endpoints = 6; + #else pcd_fs_handle.Init.dev_endpoints = 4; + #endif pcd_fs_handle.Init.use_dedicated_ep1 = 0; pcd_fs_handle.Init.ep0_mps = 0x40; pcd_fs_handle.Init.dma_enable = 0; @@ -393,11 +397,22 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_fs_handle); - HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); + // We have 320 32-bit words in total to use here + #if MICROPY_HW_USB_ENABLE_CDC2 + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 16); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 32); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 4, 16); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 5, 32); // CDC2 DATA + #else + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA + #endif } #endif #if MICROPY_HW_USB_HS @@ -406,11 +421,13 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Set LL Driver parameters pcd_hs_handle.Instance = USB_OTG_HS; - pcd_hs_handle.Init.dev_endpoints = 4; + pcd_hs_handle.Init.dev_endpoints = 6; pcd_hs_handle.Init.use_dedicated_ep1 = 0; pcd_hs_handle.Init.ep0_mps = 0x40; pcd_hs_handle.Init.dma_enable = 0; pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.lpm_enable = DISABLE; + pcd_hs_handle.Init.battery_charging_enable = DISABLE; #if defined(STM32F723xx) || defined(STM32F733xx) pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; #else @@ -436,11 +453,14 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { // Initialize LL Driver HAL_PCD_Init(&pcd_hs_handle); - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); + // We have 1024 32-bit words in total to use here + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 512); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 256); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 64); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 32); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 64); // CDC2 DATA #else // !MICROPY_HW_USB_HS_IN_FS diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index e68cbd9a4b..1f8e754a2b 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -37,7 +37,7 @@ #include #include -#define USBD_MAX_NUM_INTERFACES 1 +#define USBD_MAX_NUM_INTERFACES 4 #define USBD_MAX_NUM_CONFIGURATION 1 #define USBD_MAX_STR_DESC_SIZ 0x100 #define USBD_SELF_POWERED 0 diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index 8bf454558a..a4f81f10d9 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -20,7 +20,11 @@ // Needed for the CDC+MSC+HID state and should be maximum of all template // config descriptors defined in usbd_cdc_msc_hid.c +#if MICROPY_HW_USB_ENABLE_CDC2 +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#else #define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) +#endif // CDC, MSC and HID packet sizes #define MSC_FS_MAX_PACKET (64) @@ -46,6 +50,7 @@ typedef struct { uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment uint8_t iface_num; uint8_t in_ep; + uint8_t out_ep; uint8_t cur_request; uint8_t cur_length; volatile uint8_t tx_in_progress; @@ -120,6 +125,9 @@ typedef struct _usbd_cdc_msc_hid_state_t { __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; usbd_cdc_state_t *cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_state_t *cdc2; + #endif usbd_hid_state_t *hid; } usbd_cdc_msc_hid_state_t; diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 95fc693a00..c876dcf298 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -34,9 +34,11 @@ 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, + USBD_MODE_CDC2 = 0x08, + USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC, + USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID, + USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID, + USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2, USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above } usb_device_mode_t; diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 6def258c60..d0b922d761 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -34,6 +34,10 @@ #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) #define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) +#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8) +#define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) #define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) #define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) @@ -57,6 +61,7 @@ #define CDC_IFACE_NUM_ALONE (0) #define CDC_IFACE_NUM_WITH_MSC (1) +#define CDC2_IFACE_NUM_WITH_MSC (3) #define CDC_IFACE_NUM_WITH_HID (1) #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) @@ -66,6 +71,10 @@ #define CDC_OUT_EP (0x03) #define CDC_CMD_EP (0x82) +#define CDC2_IN_EP (0x85) +#define CDC2_OUT_EP (0x05) +#define CDC2_CMD_EP (0x84) + #define HID_IN_EP_WITH_CDC (0x81) #define HID_OUT_EP_WITH_CDC (0x01) #define HID_IN_EP_WITH_MSC (0x83) @@ -625,6 +634,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: { + usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE; + uint8_t *d = usbd->usbd_config_desc; + memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); + d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength + d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); + d[4] = 5; // bNumInterfaces + memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58); + d += 9 + 23 + (8 + 58); + d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface + d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber + d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface + d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface + d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface + d[38] = CDC2_CMD_EP; // bEndpointAddress + d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber + d[54] = CDC2_OUT_EP; // bEndpointAddress + d[61] = CDC2_IN_EP; // bEndpointAddress + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + break; + } + #endif + case USBD_MODE_CDC_HID: usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); @@ -657,8 +691,16 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode if (usbd->usbd_mode & USBD_MODE_CDC) { usbd->cdc->in_ep = CDC_IN_EP; + usbd->cdc->out_ep = CDC_OUT_EP; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + usbd->cdc2->in_ep = CDC2_IN_EP; + usbd->cdc2->out_ep = CDC2_OUT_EP; + } + #endif + // configure the HID descriptor, if needed if (usbd->usbd_mode & USBD_MODE_HID) { uint8_t *hid_desc = usbd->hid->desc; @@ -677,6 +719,26 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode return 0; } +static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) { + int mp = usbd_cdc_max_packet(pdev); + + // Open endpoints + USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE); + + // Init state + cdc->usbd = usbd; + cdc->cur_request = 0xff; + cdc->tx_in_progress = 0; + + // Init interface + uint8_t *buf = usbd_cdc_init(cdc); + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp); +} + static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { #if !USBD_SUPPORT_HS_MODE if (pdev->dev_speed == USBD_SPEED_HIGH) { @@ -689,39 +751,16 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { if (usbd->usbd_mode & USBD_MODE_CDC) { // CDC VCP component - - int mp = usbd_cdc_max_packet(pdev); - - // Open EP IN - USBD_LL_OpenEP(pdev, - CDC_IN_EP, - USBD_EP_TYPE_BULK, - mp); - - // Open EP OUT - USBD_LL_OpenEP(pdev, - CDC_OUT_EP, - USBD_EP_TYPE_BULK, - mp); - - // Open Command IN EP - USBD_LL_OpenEP(pdev, - CDC_CMD_EP, - USBD_EP_TYPE_INTR, - CDC_CMD_PACKET_SIZE); - - // Init Xfer states - usbd->cdc->usbd = usbd; - usbd->cdc->cur_request = 0xff; - usbd->cdc->tx_in_progress = 0; - - // Init physical Interface components - uint8_t *buf = usbd_cdc_init(usbd->cdc); - - // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); + usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + // CDC VCP #2 component + usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -785,6 +824,17 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) USBD_LL_CloseEP(pdev, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) { + // CDC VCP #2 component + + // close endpoints + USBD_LL_CloseEP(pdev, CDC2_IN_EP); + USBD_LL_CloseEP(pdev, CDC2_OUT_EP); + USBD_LL_CloseEP(pdev, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -830,11 +880,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Work out the recipient of the setup request uint8_t mode = usbd->usbd_mode; uint8_t recipient = 0; + usbd_cdc_state_t *cdc; switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { case USB_REQ_RECIPIENT_INTERFACE: { uint16_t iface = req->wIndex; if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) { recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { recipient = USBD_MODE_MSC; } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) { @@ -846,6 +903,12 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp uint8_t ep = req->wIndex & 0x7f; if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { recipient = USBD_MODE_MSC; } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) { @@ -869,18 +932,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request - usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); - USBD_CtlSendData(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } else { // host-to-device request - usbd->cdc->cur_request = req->bRequest; - usbd->cdc->cur_length = req->wLength; - USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength); + cdc->cur_request = req->bRequest; + cdc->cur_length = req->wLength; + USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } } else { // Not a Data request // Transfer the command to the interface layer - return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue); + return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue); } } else if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { @@ -1002,6 +1065,12 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length); usbd->cdc->cur_request = 0xff; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length); + usbd->cdc2->cur_request = 0xff; + } + #endif return USBD_OK; } @@ -1011,6 +1080,11 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) { usbd->cdc->tx_in_progress = 0; return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) { + usbd->cdc2->tx_in_progress = 0; + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); return USBD_OK; @@ -1035,6 +1109,12 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) usbd_cdc_receive(usbd->cdc, len); return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + usbd_cdc_receive(usbd->cdc2, len); + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); return USBD_OK; @@ -1046,11 +1126,31 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) return USBD_OK; } +#if USBD_SUPPORT_HS_MODE +static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; +} +#endif + static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; #if USBD_SUPPORT_HS_MODE uint8_t *cdc_desc = NULL; + #if MICROPY_HW_USB_ENABLE_CDC2 + uint8_t *cdc2_desc = NULL; + #endif uint8_t *msc_desc = NULL; switch (usbd->usbd_mode) { case USBD_MODE_MSC: @@ -1062,6 +1162,14 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: + cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + #endif + case USBD_MODE_CDC_HID: cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; break; @@ -1073,20 +1181,15 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t * // configure CDC descriptors, if needed if (cdc_desc != NULL) { - uint32_t mp = usbd_cdc_max_packet(pdev); - cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); - cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); - uint8_t interval; // polling interval in frames of 1ms - if (pdev->dev_speed == USBD_SPEED_HIGH) { - interval = 0x09; - } else { - interval = 0x20; - } - cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; + usbd_cdc_desc_config_max_packet(pdev, cdc_desc); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (cdc2_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc2_desc); + } + #endif + if (msc_desc != NULL) { uint32_t mp = usbd_msc_max_packet(pdev); msc_desc[13] = LOBYTE(mp); @@ -1135,7 +1238,7 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(cdc->usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); + USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); return USBD_OK; }