From a4d51933d588f5ae573a45c3db9bb015a1bc3fa1 Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Mon, 12 Feb 2024 09:43:02 +0100 Subject: [PATCH 1/2] refactor(cdc_acm): Separate descriptor parsing logic Update CDC-ACM test_app to IDF v5.0 --- host/class/cdc/usb_host_cdc_acm/CHANGELOG.md | 4 + .../class/cdc/usb_host_cdc_acm/CMakeLists.txt | 18 +- .../class/cdc/usb_host_cdc_acm/cdc_acm_host.c | 278 ++---------------- .../cdc_host_descriptor_parsing.c | 214 ++++++++++++++ .../cdc/usb_host_cdc_acm/idf_component.yml | 4 - .../include/usb/cdc_acm_host.h | 43 +-- .../include/usb/usb_types_cdc.h | 41 +++ .../cdc_host_descriptor_parsing.h | 58 ++++ .../cdc/usb_host_cdc_acm/test_app/README.md | 11 +- .../test_app/main/CMakeLists.txt | 7 +- .../test_app/main/idf_component.yml | 28 ++ .../test_app/main/test_cdc_acm_host.c | 46 ++- .../test_app/pytest_usb_host_cdc.py | 1 + 13 files changed, 436 insertions(+), 317 deletions(-) create mode 100644 host/class/cdc/usb_host_cdc_acm/cdc_host_descriptor_parsing.c create mode 100644 host/class/cdc/usb_host_cdc_acm/private_include/cdc_host_descriptor_parsing.h create mode 100644 host/class/cdc/usb_host_cdc_acm/test_app/main/idf_component.yml diff --git a/host/class/cdc/usb_host_cdc_acm/CHANGELOG.md b/host/class/cdc/usb_host_cdc_acm/CHANGELOG.md index c5dbf005..42daf0b6 100644 --- a/host/class/cdc/usb_host_cdc_acm/CHANGELOG.md +++ b/host/class/cdc/usb_host_cdc_acm/CHANGELOG.md @@ -1,3 +1,7 @@ +## [Unreleased] + +- Fixed CDC descriptor parsing logic, when some CDC devices could not be opened + ## 2.0.4 - Fixed Control transfer allocation size for too small EP0 Max Packet Size (https://github.com/espressif/esp-idf/issues/14345) diff --git a/host/class/cdc/usb_host_cdc_acm/CMakeLists.txt b/host/class/cdc/usb_host_cdc_acm/CMakeLists.txt index f2ff73f8..c8a67c42 100644 --- a/host/class/cdc/usb_host_cdc_acm/CMakeLists.txt +++ b/host/class/cdc/usb_host_cdc_acm/CMakeLists.txt @@ -1,15 +1,5 @@ -set(srcs) -set(include) -# As CONFIG_USB_OTG_SUPPORTED comes from Kconfig, it is not evaluated yet -# when components are being registered. -set(require usb) - -if(CONFIG_USB_OTG_SUPPORTED) - list(APPEND srcs "cdc_acm_host.c") - list(APPEND include "include") -endif() - -idf_component_register(SRCS ${srcs} - INCLUDE_DIRS ${include} - REQUIRES ${require} +idf_component_register(SRCS "cdc_acm_host.c" "cdc_host_descriptor_parsing.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES usb ) diff --git a/host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c b/host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c index 5bc563d1..50d575c7 100644 --- a/host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c +++ b/host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c @@ -4,30 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "esp_log.h" #include #include #include #include -#include "usb/usb_host.h" -#include "usb/cdc_acm_host.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/event_groups.h" +#include "esp_log.h" #include "esp_check.h" #include "esp_system.h" -static const char *TAG = "cdc_acm"; +#include "usb/usb_host.h" +#include "usb/cdc_acm_host.h" +#include "cdc_host_descriptor_parsing.h" -// CDC devices often implement Interface Association Descriptor (IAD). Parse IAD only when -// bDeviceClass = 0xEF (Miscellaneous Device Class), bDeviceSubClass = 0x02 (Common Class), bDeviceProtocol = 0x01 (Interface Association Descriptor), -// or when bDeviceClass, bDeviceSubClass, and bDeviceProtocol are 0x00 (Null class code triple), as per https://www.usb.org/defined-class-codes, "Base Class 00h (Device)" section -// @see USB Interface Association Descriptor: Device Class Code and Use Model rev 1.0, Table 1-1 -#define USB_SUBCLASS_NULL 0x00 -#define USB_SUBCLASS_COMMON 0x02 -#define USB_PROTOCOL_NULL 0x00 -#define USB_DEVICE_PROTOCOL_IAD 0x01 +static const char *TAG = "cdc_acm"; // Control transfer constants #define CDC_ACM_CTRL_TRANSFER_SIZE (64) // All standard CTRL requests and responses fit in this size @@ -104,8 +97,8 @@ struct cdc_dev_s { cdc_acm_uart_state_t serial_state; // Serial State cdc_comm_protocol_t comm_protocol; cdc_data_protocol_t data_protocol; - int num_cdc_func_desc; // Number of CDC Functional descriptors in following array - const usb_standard_desc_t **cdc_func_desc; // CDC Functional descriptors + int cdc_func_desc_cnt; // Number of CDC Functional descriptors in following array + cdc_func_array_t *cdc_func_desc; // CDC Functional descriptors SLIST_ENTRY(cdc_dev_s) list_entry; }; @@ -629,176 +622,6 @@ static esp_err_t cdc_acm_transfers_allocate(cdc_dev_t *cdc_dev, const usb_ep_des return ret; } -/** - * @brief Check if the required interface is CDC compliant - * - * @param[in] device_desc Pointer to Device descriptor - * @param[in] config_desc Pointer do Configuration descriptor - * @param[in] intf_idx Index of the required interface - * @return true The required interface is CDC compliant - * @return false The required interface is NOT CDC compliant - */ -static bool cdc_acm_is_cdc_compliant(const usb_device_desc_t *device_desc, const usb_config_desc_t *config_desc, uint8_t intf_idx) -{ - int desc_offset = 0; - if (((device_desc->bDeviceClass == USB_CLASS_MISC) && (device_desc->bDeviceSubClass == USB_SUBCLASS_COMMON) && - (device_desc->bDeviceProtocol == USB_DEVICE_PROTOCOL_IAD)) || - ((device_desc->bDeviceClass == USB_CLASS_PER_INTERFACE) && (device_desc->bDeviceSubClass == USB_SUBCLASS_NULL) && - (device_desc->bDeviceProtocol == USB_PROTOCOL_NULL))) { - const usb_standard_desc_t *this_desc = (const usb_standard_desc_t *)config_desc; - while (1) { - this_desc = usb_parse_next_descriptor_of_type( - this_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, &desc_offset); - - if (this_desc == NULL) { - break; // Reached end of configuration descriptor - } - - const usb_iad_desc_t *iad_desc = (const usb_iad_desc_t *)this_desc; - if ((iad_desc->bFirstInterface == intf_idx) && - (iad_desc->bInterfaceCount == 2) && - (iad_desc->bFunctionClass == USB_CLASS_COMM)) { - // 1. This is a composite device, that uses Interface Association Descriptor - return true; - } - }; - } else if ((device_desc->bDeviceClass == USB_CLASS_COMM) && (intf_idx == 0)) { - // 2. This is a Communication Device Class: Class defined in Device descriptor - return true; - } else if (device_desc->bDeviceClass == USB_CLASS_PER_INTERFACE) { - const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx, 0, NULL); - if (intf_desc->bInterfaceClass == USB_CLASS_COMM) { - // 3. This is a Communication Device Class: Class defined in Interface descriptor - return true; - } - } - return false; -} - -/** - * @brief Parse and save CDC functional descriptors - * - * @param[in] cdc_dev Pointer to CDC device - * @param[in] intf_desc Pointer to the required interface descriptor - * @param[in] total_len wTotalLength of the Configuration descriptor - * @param[inout] desc_offset Offset of the intf_desc in the Configuration descriptor in bytes - */ -static void cdc_acm_parse_functional_descriptors(cdc_dev_t *cdc_dev, const usb_intf_desc_t *intf_desc, uint16_t total_len, int *desc_offset) -{ - // CDC specific descriptors should be right after CDC-Communication interface descriptor - // Note: That's why we use usb_parse_next_descriptor instead of usb_parse_next_descriptor_of_type. - // The latter could return CDC specific descriptors that don't belong to this interface - int func_desc_cnt = 0; - const usb_standard_desc_t *cdc_desc = (const usb_standard_desc_t *)intf_desc; - do { - cdc_desc = usb_parse_next_descriptor(cdc_desc, total_len, desc_offset); - if ((cdc_desc == NULL) || (cdc_desc->bDescriptorType != ((USB_CLASS_COMM << 4) | USB_B_DESCRIPTOR_TYPE_INTERFACE ))) { - break; // We found all CDC specific descriptors - } - func_desc_cnt++; - void *ptr = realloc(cdc_dev->cdc_func_desc, func_desc_cnt * (sizeof(usb_standard_desc_t *))); - if (!ptr) { - // Out of memory - free(cdc_dev->cdc_func_desc); - func_desc_cnt = 0; - ESP_LOGD(TAG, "Out of mem for functional descriptors"); - break; - } - cdc_dev->cdc_func_desc = (const usb_standard_desc_t **)ptr; - cdc_dev->cdc_func_desc[func_desc_cnt - 1] = cdc_desc; - } while (1); - cdc_dev->num_cdc_func_desc = func_desc_cnt; -} - -/** - * @brief Parse CDC interface descriptor - * - * #. Check if the required interface exists - * #. Parse the interface descriptor - * #. Check if the device is CDC compliant - * #. For CDC compliant devices also parse second interface descriptor and functional descriptors - * - * @note This function is called in open procedure of CDC compliant devices only. - * @param[in] cdc_dev Pointer to CDC device - * @param[in] intf_idx Index of CDC interface that is required for this device - * @param[out] notif_ep Pointer to notification EP descriptor - * @param[out] in_ep Pointer to data IN EP descriptor - * @param[out] out_ep Pointer to data OUT EP descriptor - * @return - * - ESP_OK: Success - * - ESP_ERR_NOT_FOUND: Interfaces and endpoints NOT found - */ -static esp_err_t cdc_acm_parse_interface(cdc_dev_t *cdc_dev, uint8_t intf_idx, const usb_ep_desc_t **notif_ep, const usb_ep_desc_t **in_ep, const usb_ep_desc_t **out_ep) -{ - const usb_config_desc_t *config_desc; - const usb_device_desc_t *device_desc; - int desc_offset = 0; - - // Get required descriptors - ESP_ERROR_CHECK(usb_host_get_device_descriptor(cdc_dev->dev_hdl, &device_desc)); - ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(cdc_dev->dev_hdl, &config_desc)); - const usb_intf_desc_t *first_intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx, 0, &desc_offset); - ESP_RETURN_ON_FALSE( - first_intf_desc, - ESP_ERR_NOT_FOUND, TAG, "Required interface no %d was not found.", intf_idx); - - int temp_offset = desc_offset; - for (int i = 0; i < first_intf_desc->bNumEndpoints; i++) { - const usb_ep_desc_t *this_ep = usb_parse_endpoint_descriptor_by_index(first_intf_desc, i, config_desc->wTotalLength, &desc_offset); - assert(this_ep); - - if (USB_EP_DESC_GET_XFERTYPE(this_ep) == USB_TRANSFER_TYPE_INTR) { - cdc_dev->notif.intf_desc = first_intf_desc; - *notif_ep = this_ep; - } else if (USB_EP_DESC_GET_XFERTYPE(this_ep) == USB_TRANSFER_TYPE_BULK) { - cdc_dev->data.intf_desc = first_intf_desc; - if (USB_EP_DESC_GET_EP_DIR(this_ep)) { - *in_ep = this_ep; - } else { - *out_ep = this_ep; - } - } - desc_offset = temp_offset; - } - - const bool cdc_compliant = cdc_acm_is_cdc_compliant(device_desc, config_desc, intf_idx); - if (cdc_compliant) { - cdc_dev->notif.intf_desc = first_intf_desc; // We make sure that intf_desc is set for CDC compliant devices that use EP0 as notification element - cdc_acm_parse_functional_descriptors(cdc_dev, cdc_dev->notif.intf_desc, config_desc->wTotalLength, &desc_offset); - } - - if (!cdc_dev->data.intf_desc && cdc_compliant) { - // CDC compliant devices have data endpoints in the second interface - // Some devices offer alternate settings for data interface: - // First interface with 0 endpoints (default control pipe only) and second with standard 2 endpoints for full-duplex data - // We always select interface with 2 bulk endpoints - const int num_of_alternate = usb_parse_interface_number_of_alternate(config_desc, intf_idx + 1); - for (int i = 0; i < num_of_alternate + 1; i++) { - const usb_intf_desc_t *second_intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx + 1, i, &desc_offset); - temp_offset = desc_offset; - if (second_intf_desc && second_intf_desc->bNumEndpoints == 2) { - for (int i = 0; i < second_intf_desc->bNumEndpoints; i++) { - const usb_ep_desc_t *this_ep = usb_parse_endpoint_descriptor_by_index(second_intf_desc, i, config_desc->wTotalLength, &desc_offset); - assert(this_ep); - if (USB_EP_DESC_GET_XFERTYPE(this_ep) == USB_TRANSFER_TYPE_BULK) { - cdc_dev->data.intf_desc = second_intf_desc; - if (USB_EP_DESC_GET_EP_DIR(this_ep)) { - *in_ep = this_ep; - } else { - *out_ep = this_ep; - } - } - desc_offset = temp_offset; - } - break; - } - } - } - - // If we did not find IN and OUT data endpoints, the device cannot be used - return (*in_ep && *out_ep) ? ESP_OK : ESP_ERR_NOT_FOUND; -} - esp_err_t cdc_acm_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret) { esp_err_t ret; @@ -814,26 +637,36 @@ esp_err_t cdc_acm_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, c goto exit; } - // Find and save relevant interface and endpoint descriptors - const usb_ep_desc_t *notif_ep = NULL; - const usb_ep_desc_t *in_ep = NULL; - const usb_ep_desc_t *out_ep = NULL; + // Get Device and Configuration descriptors + const usb_config_desc_t *config_desc; + const usb_device_desc_t *device_desc; + ESP_ERROR_CHECK(usb_host_get_device_descriptor(cdc_dev->dev_hdl, &device_desc)); + ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(cdc_dev->dev_hdl, &config_desc)); + + // Parse the required interface descriptor + cdc_parsed_info_t cdc_info; ESP_GOTO_ON_ERROR( - cdc_acm_parse_interface(cdc_dev, interface_idx, ¬if_ep, &in_ep, &out_ep), + cdc_parse_interface_descriptor(device_desc, config_desc, interface_idx, &cdc_info), err, TAG, "Could not open required interface as CDC"); - // Save Communication and Data protocols - if (cdc_dev->notif.intf_desc) { + // Save all members of cdc_dev + cdc_dev->data.intf_desc = cdc_info.data_intf; + cdc_dev->data_protocol = (cdc_data_protocol_t)cdc_dev->data.intf_desc->bInterfaceProtocol; + cdc_dev->notif.intf_desc = cdc_info.notif_intf; + if (cdc_info.notif_intf) { cdc_dev->comm_protocol = (cdc_comm_protocol_t)cdc_dev->notif.intf_desc->bInterfaceProtocol; } - cdc_dev->data_protocol = (cdc_data_protocol_t)cdc_dev->data.intf_desc->bInterfaceProtocol; + cdc_dev->cdc_func_desc = cdc_info.func; + cdc_dev->cdc_func_desc_cnt = cdc_info.func_cnt; // The following line is here for backward compatibility with v1.0.* // where fixed size of IN buffer (equal to IN Maximum Packet Size) was used - const size_t in_buf_size = (dev_config->data_cb && (dev_config->in_buffer_size == 0)) ? USB_EP_DESC_GET_MPS(in_ep) : dev_config->in_buffer_size; + const size_t in_buf_size = (dev_config->data_cb && (dev_config->in_buffer_size == 0)) ? USB_EP_DESC_GET_MPS(cdc_info.in_ep) : dev_config->in_buffer_size; // Allocate USB transfers, claim CDC interfaces and return CDC-ACM handle - ESP_GOTO_ON_ERROR(cdc_acm_transfers_allocate(cdc_dev, notif_ep, in_ep, in_buf_size, out_ep, dev_config->out_buffer_size), err, TAG,); + ESP_GOTO_ON_ERROR( + cdc_acm_transfers_allocate(cdc_dev, cdc_info.notif_ep, cdc_info.in_ep, in_buf_size, cdc_info.out_ep, dev_config->out_buffer_size), + err, TAG,); ESP_GOTO_ON_ERROR(cdc_acm_start(cdc_dev, dev_config->event_cb, dev_config->data_cb, dev_config->user_arg), err, TAG,); *cdc_hdl_ret = (cdc_acm_dev_hdl_t)cdc_dev; xSemaphoreGive(p_cdc_acm_obj->open_close_mutex); @@ -900,54 +733,6 @@ esp_err_t cdc_acm_host_close(cdc_acm_dev_hdl_t cdc_hdl) return ESP_OK; } -/** - * @brief Print CDC specific descriptor in human readable form - * - * This is a callback function that is called from USB Host library, - * when it wants to print full configuration descriptor to stdout. - * - * @param[in] _desc CDC specific descriptor - */ -static void cdc_acm_print_desc(const usb_standard_desc_t *_desc) -{ - if (_desc->bDescriptorType != ((USB_CLASS_COMM << 4) | USB_B_DESCRIPTOR_TYPE_INTERFACE )) { - // Quietly return in case that this descriptor is not CDC interface descriptor - return; - } - - switch (((cdc_header_desc_t *)_desc)->bDescriptorSubtype) { - case USB_CDC_DESC_SUBTYPE_HEADER: { - cdc_header_desc_t *desc = (cdc_header_desc_t *)_desc; - printf("\t*** CDC Header Descriptor ***\n"); - printf("\tbcdCDC: %d.%d0\n", ((desc->bcdCDC >> 8) & 0xF), ((desc->bcdCDC >> 4) & 0xF)); - break; - } - case USB_CDC_DESC_SUBTYPE_CALL: { - cdc_acm_call_desc_t *desc = (cdc_acm_call_desc_t *)_desc; - printf("\t*** CDC Call Descriptor ***\n"); - printf("\tbmCapabilities: 0x%02X\n", desc->bmCapabilities.val); - printf("\tbDataInterface: %d\n", desc->bDataInterface); - break; - } - case USB_CDC_DESC_SUBTYPE_ACM: { - cdc_acm_acm_desc_t *desc = (cdc_acm_acm_desc_t *)_desc; - printf("\t*** CDC ACM Descriptor ***\n"); - printf("\tbmCapabilities: 0x%02X\n", desc->bmCapabilities.val); - break; - } - case USB_CDC_DESC_SUBTYPE_UNION: { - cdc_union_desc_t *desc = (cdc_union_desc_t *)_desc; - printf("\t*** CDC Union Descriptor ***\n"); - printf("\tbControlInterface: %d\n", desc->bControlInterface); - printf("\tbSubordinateInterface[0]: %d\n", desc->bSubordinateInterface[0]); - break; - } - default: - ESP_LOGW(TAG, "Unsupported CDC specific descriptor"); - break; - } -} - void cdc_acm_host_desc_print(cdc_acm_dev_hdl_t cdc_hdl) { assert(cdc_hdl); @@ -958,7 +743,7 @@ void cdc_acm_host_desc_print(cdc_acm_dev_hdl_t cdc_hdl) ESP_ERROR_CHECK_WITHOUT_ABORT(usb_host_get_device_descriptor(cdc_dev->dev_hdl, &device_desc)); ESP_ERROR_CHECK_WITHOUT_ABORT(usb_host_get_active_config_descriptor(cdc_dev->dev_hdl, &config_desc)); usb_print_device_descriptor(device_desc); - usb_print_config_descriptor(config_desc, cdc_acm_print_desc); + usb_print_config_descriptor(config_desc, cdc_print_desc); } /** @@ -1325,12 +1110,13 @@ esp_err_t cdc_acm_host_cdc_desc_get(cdc_acm_dev_hdl_t cdc_hdl, cdc_desc_subtype_ cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl; esp_err_t ret = ESP_ERR_NOT_FOUND; *desc_out = NULL; + cdc_func_array_t *func_desc = cdc_dev->cdc_func_desc; - for (int i = 0; i < cdc_dev->num_cdc_func_desc; i++) { - cdc_header_desc_t *_desc = (cdc_header_desc_t *)(cdc_dev->cdc_func_desc[i]); + for (int i = 0; i < cdc_dev->cdc_func_desc_cnt; i++) { + cdc_header_desc_t *_desc = (cdc_header_desc_t *)((*func_desc)[i]); if (_desc->bDescriptorSubtype == desc_type) { ret = ESP_OK; - *desc_out = cdc_dev->cdc_func_desc[i]; + *desc_out = (*func_desc)[i]; break; } } diff --git a/host/class/cdc/usb_host_cdc_acm/cdc_host_descriptor_parsing.c b/host/class/cdc/usb_host_cdc_acm/cdc_host_descriptor_parsing.c new file mode 100644 index 00000000..9c464496 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/cdc_host_descriptor_parsing.c @@ -0,0 +1,214 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_check.h" +#include "esp_log.h" +#include "usb/usb_helpers.h" +#include "usb/usb_types_cdc.h" +#include "cdc_host_descriptor_parsing.h" + +// CDC devices often implement Interface Association Descriptor (IAD). Parse IAD only when +// bDeviceClass = 0xEF (Miscellaneous Device Class), bDeviceSubClass = 0x02 (Common Class), bDeviceProtocol = 0x01 (Interface Association Descriptor), +// or when bDeviceClass, bDeviceSubClass, and bDeviceProtocol are 0x00 (Null class code triple), as per https://www.usb.org/defined-class-codes, "Base Class 00h (Device)" section +// @see USB Interface Association Descriptor: Device Class Code and Use Model rev 1.0, Table 1-1 +#define USB_SUBCLASS_NULL 0x00 +#define USB_SUBCLASS_COMMON 0x02 +#define USB_PROTOCOL_NULL 0x00 +#define USB_DEVICE_PROTOCOL_IAD 0x01 + +static const char *TAG = "cdc_acm_parsing"; + +/** + * @brief Searches interface by index and verifies its CDC-compliance + * + * @param[in] device_desc Pointer to Device descriptor + * @param[in] config_desc Pointer do Configuration descriptor + * @param[in] intf_idx Index of the required interface + * @return true The required interface is CDC compliant + * @return false The required interface is NOT CDC compliant + */ +static bool cdc_parse_is_cdc_compliant(const usb_device_desc_t *device_desc, const usb_config_desc_t *config_desc, uint8_t intf_idx) +{ + int desc_offset = 0; + if (device_desc->bDeviceClass == USB_CLASS_PER_INTERFACE) { + const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx, 0, NULL); + if (intf_desc->bInterfaceClass == USB_CLASS_COMM) { + // 1. This is a Communication Device Class: Class defined in Interface descriptor + return true; + } + } else if (((device_desc->bDeviceClass == USB_CLASS_MISC) && (device_desc->bDeviceSubClass == USB_SUBCLASS_COMMON) && + (device_desc->bDeviceProtocol == USB_DEVICE_PROTOCOL_IAD)) || + ((device_desc->bDeviceClass == USB_CLASS_PER_INTERFACE) && (device_desc->bDeviceSubClass == USB_SUBCLASS_NULL) && + (device_desc->bDeviceProtocol == USB_PROTOCOL_NULL))) { + const usb_standard_desc_t *this_desc = (const usb_standard_desc_t *)config_desc; + while ((this_desc = usb_parse_next_descriptor_of_type(this_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, &desc_offset))) { + const usb_iad_desc_t *iad_desc = (const usb_iad_desc_t *)this_desc; + if ((iad_desc->bFirstInterface == intf_idx) && + (iad_desc->bInterfaceCount == 2) && + (iad_desc->bFunctionClass == USB_CLASS_COMM)) { + // 2. This is a composite device, that uses Interface Association Descriptor + return true; + } + }; + } + return false; +} + +/** + * @brief Parse CDC functional descriptors + * + * @attention The driver must take care of memory freeing + * @param[in] intf_desc Pointer to Notification interface descriptor + * @param[in] total_len wTotalLength of the Configuration descriptor + * @param[in] desc_offset Offset of the intf_desc in the Configuration descriptor in bytes + * @param[out] desc_cnt Number of Functional descriptors found + * @return Pointer to array of pointers to Functional descriptors + */ +static cdc_func_array_t *cdc_parse_functional_descriptors(const usb_intf_desc_t *intf_desc, uint16_t total_len, int desc_offset, int *desc_cnt) +{ + // CDC specific descriptors should be right after CDC-Communication interface descriptor + // Note: That's why we use usb_parse_next_descriptor instead of usb_parse_next_descriptor_of_type. + // The latter could return CDC specific descriptors that don't belong to this interface + int func_desc_cnt = 0; + int intf_offset = desc_offset; + const usb_standard_desc_t *cdc_desc = (const usb_standard_desc_t *)intf_desc; + while ((cdc_desc = usb_parse_next_descriptor(cdc_desc, total_len, &intf_offset))) { + if (cdc_desc->bDescriptorType != ((USB_CLASS_COMM << 4) | USB_B_DESCRIPTOR_TYPE_INTERFACE )) { + if (func_desc_cnt == 0) { + return NULL; // There are no CDC specific descriptors + } else { + break; // We found all CDC specific descriptors + } + } + func_desc_cnt++; + } + + // Allocate memory for the functional descriptors pointers + cdc_func_array_t *func_desc = malloc(func_desc_cnt * (sizeof(usb_standard_desc_t *))); + if (!func_desc) { + ESP_LOGD(TAG, "Out of mem for functional descriptors"); + return NULL; + } + + // Save the descriptors + intf_offset = desc_offset; // Reset the offset counter + cdc_desc = (const usb_standard_desc_t *)intf_desc; + for (int i = 0; i < func_desc_cnt; i++) { + cdc_desc = (const usb_standard_desc_t *)usb_parse_next_descriptor(cdc_desc, total_len, &intf_offset); + (*func_desc)[i] = cdc_desc; + } + *desc_cnt = func_desc_cnt; + return func_desc; +} + +esp_err_t cdc_parse_interface_descriptor(const usb_device_desc_t *device_desc, const usb_config_desc_t *config_desc, uint8_t intf_idx, cdc_parsed_info_t *info_ret) +{ + int desc_offset = 0; + + memset(info_ret, 0, sizeof(cdc_parsed_info_t)); + const usb_intf_desc_t *first_intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx, 0, &desc_offset); + ESP_RETURN_ON_FALSE( + first_intf_desc, + ESP_ERR_NOT_FOUND, TAG, "Required interface no %d was not found.", intf_idx); + + int temp_offset = desc_offset; + for (int i = 0; i < first_intf_desc->bNumEndpoints; i++) { + const usb_ep_desc_t *this_ep = usb_parse_endpoint_descriptor_by_index(first_intf_desc, i, config_desc->wTotalLength, &desc_offset); + assert(this_ep); + + if (USB_EP_DESC_GET_XFERTYPE(this_ep) == USB_TRANSFER_TYPE_INTR) { + info_ret->notif_intf = first_intf_desc; + info_ret->notif_ep = this_ep; + } else if (USB_EP_DESC_GET_XFERTYPE(this_ep) == USB_TRANSFER_TYPE_BULK) { + info_ret->data_intf = first_intf_desc; + if (USB_EP_DESC_GET_EP_DIR(this_ep)) { + info_ret->in_ep = this_ep; + } else { + info_ret->out_ep = this_ep; + } + } + desc_offset = temp_offset; + } + + const bool cdc_compliant = cdc_parse_is_cdc_compliant(device_desc, config_desc, intf_idx); + if (cdc_compliant) { + info_ret->notif_intf = first_intf_desc; // We make sure that intf_desc is set for CDC compliant devices that use EP0 as notification element + info_ret->func = cdc_parse_functional_descriptors(first_intf_desc, config_desc->wTotalLength, desc_offset, &info_ret->func_cnt); + } + + if (!info_ret->data_intf && cdc_compliant) { + // CDC compliant devices have data endpoints in the second interface + // Some devices offer alternate settings for data interface: + // First interface with 0 endpoints (default control pipe only) and second with standard 2 endpoints for full-duplex data + // We always select interface with 2 bulk endpoints + const int num_of_alternate = usb_parse_interface_number_of_alternate(config_desc, intf_idx + 1); + for (int i = 0; i < num_of_alternate + 1; i++) { + const usb_intf_desc_t *second_intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx + 1, i, &desc_offset); + temp_offset = desc_offset; + if (second_intf_desc && second_intf_desc->bNumEndpoints == 2) { + for (int i = 0; i < second_intf_desc->bNumEndpoints; i++) { + const usb_ep_desc_t *this_ep = usb_parse_endpoint_descriptor_by_index(second_intf_desc, i, config_desc->wTotalLength, &desc_offset); + assert(this_ep); + if (USB_EP_DESC_GET_XFERTYPE(this_ep) == USB_TRANSFER_TYPE_BULK) { + info_ret->data_intf = second_intf_desc; + if (USB_EP_DESC_GET_EP_DIR(this_ep)) { + info_ret->in_ep = this_ep; + } else { + info_ret->out_ep = this_ep; + } + } + desc_offset = temp_offset; + } + break; + } + } + } + + // If we did not find IN and OUT data endpoints, the device cannot be used + return (info_ret->in_ep && info_ret->out_ep) ? ESP_OK : ESP_ERR_NOT_FOUND; +} + +void cdc_print_desc(const usb_standard_desc_t *_desc) +{ + if (_desc->bDescriptorType != ((USB_CLASS_COMM << 4) | USB_B_DESCRIPTOR_TYPE_INTERFACE )) { + // Quietly return in case that this descriptor is not CDC interface descriptor + return; + } + + switch (((cdc_header_desc_t *)_desc)->bDescriptorSubtype) { + case USB_CDC_DESC_SUBTYPE_HEADER: { + cdc_header_desc_t *desc = (cdc_header_desc_t *)_desc; + printf("\t*** CDC Header Descriptor ***\n"); + printf("\tbcdCDC: %d.%d0\n", ((desc->bcdCDC >> 8) & 0xF), ((desc->bcdCDC >> 4) & 0xF)); + break; + } + case USB_CDC_DESC_SUBTYPE_CALL: { + cdc_acm_call_desc_t *desc = (cdc_acm_call_desc_t *)_desc; + printf("\t*** CDC Call Descriptor ***\n"); + printf("\tbmCapabilities: 0x%02X\n", desc->bmCapabilities.val); + printf("\tbDataInterface: %d\n", desc->bDataInterface); + break; + } + case USB_CDC_DESC_SUBTYPE_ACM: { + cdc_acm_acm_desc_t *desc = (cdc_acm_acm_desc_t *)_desc; + printf("\t*** CDC ACM Descriptor ***\n"); + printf("\tbmCapabilities: 0x%02X\n", desc->bmCapabilities.val); + break; + } + case USB_CDC_DESC_SUBTYPE_UNION: { + cdc_union_desc_t *desc = (cdc_union_desc_t *)_desc; + printf("\t*** CDC Union Descriptor ***\n"); + printf("\tbControlInterface: %d\n", desc->bControlInterface); + printf("\tbSubordinateInterface[0]: %d\n", desc->bSubordinateInterface[0]); + break; + } + default: + ESP_LOGW(TAG, "Unsupported CDC specific descriptor"); + break; + } +} diff --git a/host/class/cdc/usb_host_cdc_acm/idf_component.yml b/host/class/cdc/usb_host_cdc_acm/idf_component.yml index c3c2ec4a..fb8fffe8 100644 --- a/host/class/cdc/usb_host_cdc_acm/idf_component.yml +++ b/host/class/cdc/usb_host_cdc_acm/idf_component.yml @@ -8,7 +8,3 @@ tags: url: https://github.com/espressif/esp-usb/tree/master/host/class/cdc/usb_host_cdc_acm dependencies: idf: ">=4.4" -targets: - - esp32s2 - - esp32s3 - - esp32p4 diff --git a/host/class/cdc/usb_host_cdc_acm/include/usb/cdc_acm_host.h b/host/class/cdc/usb_host_cdc_acm/include/usb/cdc_acm_host.h index c3ee6712..b80db0a2 100644 --- a/host/class/cdc/usb_host_cdc_acm/include/usb/cdc_acm_host.h +++ b/host/class/cdc/usb_host_cdc_acm/include/usb/cdc_acm_host.h @@ -8,7 +8,7 @@ #include #include "usb/usb_host.h" -#include "usb_types_cdc.h" +#include "usb/usb_types_cdc.h" #include "esp_err.h" #ifdef __cplusplus @@ -17,47 +17,6 @@ extern "C" { typedef struct cdc_dev_s *cdc_acm_dev_hdl_t; -/** - * @brief USB CDC PSTN Call Descriptor - * - * @see Table 3, USB CDC-PSTN specification rev. 1.2 - */ -typedef struct { - uint8_t bFunctionLength; - const uint8_t bDescriptorType; - const cdc_desc_subtype_t bDescriptorSubtype; - union { - struct { - uint8_t call_management: 1; // Device handles call management itself - uint8_t call_over_data_if: 1; // Device sends/receives call management information over Data Class interface - uint8_t reserved: 6; - }; - uint8_t val; - } bmCapabilities; - uint8_t bDataInterface; // Interface number of Data Class interface optionally used for call management -} __attribute__((packed)) cdc_acm_call_desc_t; - -/** - * @brief USB CDC PSTN Abstract Control Model Descriptor - * - * @see Table 4, USB CDC-PSTN specification rev. 1.2 - */ -typedef struct { - uint8_t bFunctionLength; - const uint8_t bDescriptorType; - const cdc_desc_subtype_t bDescriptorSubtype; - union { - struct { - uint8_t feature: 1; // Device supports Set/Clear/Get_Comm_Feature requests - uint8_t serial: 1; // Device supports Set/Get_Line_Coding, Set_Control_Line_State and Serial_State request and notifications - uint8_t send_break: 1; // Device supports Send_Break request - uint8_t network: 1; // Device supports Network_Connection notification - uint8_t reserved: 4; - }; - uint8_t val; - } bmCapabilities; -} __attribute__((packed)) cdc_acm_acm_desc_t; - /** * @brief Line Coding structure * @see Table 17, USB CDC-PSTN specification rev. 1.2 diff --git a/host/class/cdc/usb_host_cdc_acm/include/usb/usb_types_cdc.h b/host/class/cdc/usb_host_cdc_acm/include/usb/usb_types_cdc.h index 3930cde3..f18fbbaa 100644 --- a/host/class/cdc/usb_host_cdc_acm/include/usb/usb_types_cdc.h +++ b/host/class/cdc/usb_host_cdc_acm/include/usb/usb_types_cdc.h @@ -205,3 +205,44 @@ typedef struct { const uint8_t bControlInterface; // Master/controlling interface uint8_t bSubordinateInterface[]; // Slave/subordinate interfaces } __attribute__((packed)) cdc_union_desc_t; + +/** + * @brief USB CDC PSTN Call Descriptor + * + * @see Table 3, USB CDC-PSTN specification rev. 1.2 + */ +typedef struct { + uint8_t bFunctionLength; + const uint8_t bDescriptorType; + const cdc_desc_subtype_t bDescriptorSubtype; + union { + struct { + uint8_t call_management: 1; // Device handles call management itself + uint8_t call_over_data_if: 1; // Device sends/receives call management information over Data Class interface + uint8_t reserved: 6; + }; + uint8_t val; + } bmCapabilities; + uint8_t bDataInterface; // Interface number of Data Class interface optionally used for call management +} __attribute__((packed)) cdc_acm_call_desc_t; + +/** + * @brief USB CDC PSTN Abstract Control Model Descriptor + * + * @see Table 4, USB CDC-PSTN specification rev. 1.2 + */ +typedef struct { + uint8_t bFunctionLength; + const uint8_t bDescriptorType; + const cdc_desc_subtype_t bDescriptorSubtype; + union { + struct { + uint8_t feature: 1; // Device supports Set/Clear/Get_Comm_Feature requests + uint8_t serial: 1; // Device supports Set/Get_Line_Coding, Set_Control_Line_State and Serial_State request and notifications + uint8_t send_break: 1; // Device supports Send_Break request + uint8_t network: 1; // Device supports Network_Connection notification + uint8_t reserved: 4; + }; + uint8_t val; + } bmCapabilities; +} __attribute__((packed)) cdc_acm_acm_desc_t; diff --git a/host/class/cdc/usb_host_cdc_acm/private_include/cdc_host_descriptor_parsing.h b/host/class/cdc/usb_host_cdc_acm/private_include/cdc_host_descriptor_parsing.h new file mode 100644 index 00000000..05370ced --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/private_include/cdc_host_descriptor_parsing.h @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "usb/usb_types_ch9.h" + +typedef const usb_standard_desc_t *cdc_func_array_t[]; // Array of pointers to const usb_standard_desc_t + +typedef struct { + const usb_ep_desc_t *notif_ep; + const usb_ep_desc_t *in_ep; + const usb_ep_desc_t *out_ep; + const usb_intf_desc_t *notif_intf; + const usb_intf_desc_t *data_intf; + cdc_func_array_t *func; + int func_cnt; +} cdc_parsed_info_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Parse CDC interface descriptor + * + * #. Check if the required interface exists + * #. Parse the interface descriptor + * #. Check if the device is CDC compliant + * #. For CDC compliant devices also parse second interface descriptor and functional descriptors + * + * @param[in] device_desc Pointer to Device descriptor + * @param[in] config_desc Pointer do Configuration descriptor + * @param[in] intf_idx Index of the required interface + * @param[out] info_ret Array of parsed information, see cdc_parsed_info_t + * @return + * - ESP_OK: Success + * - ESP_ERR_NOT_FOUND: Interfaces and endpoints NOT found + */ +esp_err_t cdc_parse_interface_descriptor(const usb_device_desc_t *device_desc, const usb_config_desc_t *config_desc, uint8_t intf_idx, cdc_parsed_info_t *info_ret); + +/** + * @brief Print CDC specific descriptor in human readable form + * + * This is a callback function that is called from USB Host library, + * when it wants to print full configuration descriptor to stdout. + * + * @param[in] _desc CDC specific descriptor + */ +void cdc_print_desc(const usb_standard_desc_t *_desc); + +#ifdef __cplusplus +} +#endif diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/README.md b/host/class/cdc/usb_host_cdc_acm/test_app/README.md index cc35c024..b5ffabe6 100644 --- a/host/class/cdc/usb_host_cdc_acm/test_app/README.md +++ b/host/class/cdc/usb_host_cdc_acm/test_app/README.md @@ -1,15 +1,12 @@ -| Supported Targets | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-S3 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | # USB: CDC Class test application ## CDC-ACM driver -It tests basic functionality of the driver like open/close/read/write operations, -advanced features like CDC control request, multi-threaded or multi-device access, -as well as reaction to sudden disconnection and other error states. +It tests basic functionality of the driver like open/close/read/write operations, advanced features like CDC control request, multi-threaded or multi-device access, as well as reaction to sudden disconnection and other error states. ### Hardware Required -This test expects that TinyUSB dual CDC device with VID = 0x303A and PID = 0x4002 -is connected to the USB host. \ No newline at end of file +This test expects that TinyUSB dual CDC device with VID = 0x303A and PID = 0x4002 is connected to the USB host. diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/main/CMakeLists.txt b/host/class/cdc/usb_host_cdc_acm/test_app/main/CMakeLists.txt index 62b1efce..33516f85 100644 --- a/host/class/cdc/usb_host_cdc_acm/test_app/main/CMakeLists.txt +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/CMakeLists.txt @@ -1,4 +1,7 @@ -idf_component_register(SRCS "test_cdc_acm_host.c" "usb_device.c" "test_app_main.c" - INCLUDE_DIRS "." +idf_component_register(SRC_DIRS . + INCLUDE_DIRS . REQUIRES usb_host_cdc_acm unity esp_tinyusb WHOLE_ARCHIVE) + +# So we have access to private_include: +target_include_directories(${COMPONENT_LIB} PRIVATE "../../") diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/main/idf_component.yml b/host/class/cdc/usb_host_cdc_acm/test_app/main/idf_component.yml new file mode 100644 index 00000000..317eabe3 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/idf_component.yml @@ -0,0 +1,28 @@ +## IDF Component Manager Manifest File +dependencies: + # Needed as DUT + espressif/usb_host_cdc_acm: + version: "*" + override_path: "../../../usb_host_cdc_acm" + + # Needed for CDC mock device + espressif/esp_tinyusb: + version: "*" + override_path: "../../../../../../device/esp_tinyusb" + + # Following components are not needed, but this way we at least built them in CI + espressif/esp_modem_usb_dte: + version: "*" + override_path: "../../../esp_modem_usb_dte" + espressif/usb_host_vcp: + version: "*" + override_path: "../../../usb_host_vcp" + espressif/usb_host_ch34x_vcp: + version: "*" + override_path: "../../../usb_host_ch34x_vcp" + espressif/usb_host_cp210x_vcp: + version: "*" + override_path: "../../../usb_host_cp210x_vcp" + espressif/usb_host_ftdi_vcp: + version: "*" + override_path: "../../../usb_host_ftdi_vcp" diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/main/test_cdc_acm_host.c b/host/class/cdc/usb_host_cdc_acm/test_app/main/test_cdc_acm_host.c index 13383ab6..c2dc5de0 100644 --- a/host/class/cdc/usb_host_cdc_acm/test_app/main/test_cdc_acm_host.c +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/test_cdc_acm_host.c @@ -176,7 +176,6 @@ TEST_CASE("read_write", "[cdc_acm]") printf("Opening CDC-ACM device\n"); TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device) TEST_ASSERT_NOT_NULL(cdc_dev); - cdc_acm_host_desc_print(cdc_dev); vTaskDelay(10); TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000)); @@ -186,6 +185,28 @@ TEST_CASE("read_write", "[cdc_acm]") // We sent two messages, should get two responses TEST_ASSERT_EQUAL(2, nb_of_responses); + TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); + TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); + vTaskDelay(20); //Short delay to allow task to be cleaned up +} + +TEST_CASE("cdc_specific_commands", "[cdc_acm]") +{ + cdc_acm_dev_hdl_t cdc_dev = NULL; + + test_install_cdc_driver(); + + const cdc_acm_host_device_config_t dev_config = { + .connection_timeout_ms = 500, + .out_buffer_size = 64 + }; + + printf("Opening CDC-ACM device\n"); + TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device) + TEST_ASSERT_NOT_NULL(cdc_dev); + vTaskDelay(10); + + printf("Sending CDC specific commands\n"); cdc_acm_line_coding_t line_coding_get; const cdc_acm_line_coding_t line_coding_set = { .dwDTERate = 9600, @@ -200,7 +221,29 @@ TEST_CASE("read_write", "[cdc_acm]") TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); + vTaskDelay(20); +} + +/* Test descriptor print function */ +TEST_CASE("desc_print", "[cdc_acm]") +{ + cdc_acm_dev_hdl_t cdc_dev = NULL; + + test_install_cdc_driver(); + + const cdc_acm_host_device_config_t dev_config = { + .connection_timeout_ms = 500, + .out_buffer_size = 64 + }; + + printf("Opening CDC-ACM device\n"); + TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_open(0x303A, 0x4002, 0, &dev_config, &cdc_dev)); // 0x303A:0x4002 (TinyUSB Dual CDC device) + TEST_ASSERT_NOT_NULL(cdc_dev); + cdc_acm_host_desc_print(cdc_dev); + vTaskDelay(10); + TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); + TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); vTaskDelay(20); //Short delay to allow task to be cleaned up } @@ -582,7 +625,6 @@ TEST_CASE("closing", "[cdc_acm]") .out_buffer_size = 64, .event_cb = notif_cb, .data_cb = handle_rx, - .user_arg = tx_buf, }; printf("Opening CDC-ACM device\n"); diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/pytest_usb_host_cdc.py b/host/class/cdc/usb_host_cdc_acm/test_app/pytest_usb_host_cdc.py index b34aecb1..a8d39d9b 100644 --- a/host/class/cdc/usb_host_cdc_acm/test_app/pytest_usb_host_cdc.py +++ b/host/class/cdc/usb_host_cdc_acm/test_app/pytest_usb_host_cdc.py @@ -9,6 +9,7 @@ @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.usb_host @pytest.mark.parametrize('count', [ 2, From c3ad19d8f07f4316f2c621e6d3ac826639608b42 Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Fri, 20 Sep 2024 10:38:12 +0200 Subject: [PATCH 2/2] feat(class/cdc): Add parsing host tests --- .build-test-rules.yml | 4 + .github/workflows/build_and_run_host_test.yml | 29 + .../workflows/build_and_run_test_app_usb.yml | 2 +- .../usb_host_cdc_acm/host_test/CMakeLists.txt | 11 + .../cdc/usb_host_cdc_acm/host_test/README.md | 30 + .../host_test/main/CMakeLists.txt | 9 + .../host_test/main/cdc_descriptors.hpp | 633 ++++++++++++++++++ .../host_test/main/idf_component.yml | 5 + .../host_test/main/test_main.cpp | 28 + .../host_test/main/test_parsing_checker.hpp | 55 ++ .../main/test_parsing_ethernet_converters.cpp | 115 ++++ .../host_test/main/test_parsing_modems.cpp | 202 ++++++ .../main/test_parsing_tinyusb_devices.cpp | 84 +++ .../main/test_parsing_uart_converters.cpp | 130 ++++ .../host_test/sdkconfig.defaults | 8 + pytest.ini | 2 +- 16 files changed, 1345 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build_and_run_host_test.yml create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/CMakeLists.txt create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/README.md create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/CMakeLists.txt create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/cdc_descriptors.hpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/idf_component.yml create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/test_main.cpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_checker.hpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_ethernet_converters.cpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_modems.cpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_tinyusb_devices.cpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_uart_converters.cpp create mode 100644 host/class/cdc/usb_host_cdc_acm/host_test/sdkconfig.defaults diff --git a/.build-test-rules.yml b/.build-test-rules.yml index b44c0599..1bfa7b39 100644 --- a/.build-test-rules.yml +++ b/.build-test-rules.yml @@ -5,3 +5,7 @@ device/esp_tinyusb: host/class: enable: - if: SOC_USB_OTG_SUPPORTED == 1 + +host/class/cdc/usb_host_cdc_acm/host_test: + enable: + - if: IDF_TARGET in ["linux"] and (IDF_VERSION_MAJOR >= 5 and IDF_VERSION_MINOR >= 4) diff --git a/.github/workflows/build_and_run_host_test.yml b/.github/workflows/build_and_run_host_test.yml new file mode 100644 index 00000000..89282c8f --- /dev/null +++ b/.github/workflows/build_and_run_host_test.yml @@ -0,0 +1,29 @@ +name: Build and Run USB Host test + +on: + schedule: + - cron: '0 0 * * SAT' # Saturday midnight + pull_request: + types: [opened, reopened, synchronize] + +jobs: + build: + name: Build + strategy: + fail-fast: false + matrix: + idf_ver: ["latest"] + runs-on: ubuntu-20.04 + container: espressif/idf:${{ matrix.idf_ver }} + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Build USB Test Application + shell: bash + run: | + . ${IDF_PATH}/export.sh + pip install pytest pytest-cpp idf-build-apps==2.4.3 --upgrade + idf-build-apps find --target linux + idf-build-apps build --target linux + pytest host/class/cdc/usb_host_cdc_acm/host_test/build_linux diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index b3b98bb9..b4d4b7b3 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -63,4 +63,4 @@ jobs: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial pyusb - name: Run USB Test App on target - run: pytest --target=${{ matrix.idf_target }} -m usb_host --build-dir=build_${{ matrix.idf_target }} + run: pytest --embedded-services esp,idf --target=${{ matrix.idf_target }} -m usb_host --build-dir=build_${{ matrix.idf_target }} diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/CMakeLists.txt b/host/class/cdc/usb_host_cdc_acm/host_test/CMakeLists.txt new file mode 100644 index 00000000..460a5156 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) + +list(APPEND EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/mocks/usb/" + "$ENV{IDF_PATH}/tools/mocks/freertos/" + ) + +project(host_test_usb_cdc) diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/README.md b/host/class/cdc/usb_host_cdc_acm/host_test/README.md new file mode 100644 index 00000000..c11046e5 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/README.md @@ -0,0 +1,30 @@ +| Supported Targets | Linux | +| ----------------- | ----- | + +# Description + +This directory contains test code for `USB Host CDC-ACM` driver. Namely: +* Descriptor parsing + +Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework, use CMock, so you must install Ruby on your machine to run them. + +# Build + +Tests build regularly like an idf project. Currently only working on Linux machines. + +``` +idf.py --preview set-target linux +idf.py build +``` + +# Run + +The build produces an executable in the build folder. + +Just run: + +``` +./build/host_test_usb_cdc.elf +``` + +The test executable have some options provided by the test framework. diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/CMakeLists.txt b/host/class/cdc/usb_host_cdc_acm/host_test/main/CMakeLists.txt new file mode 100644 index 00000000..6fa86b66 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register(SRC_DIRS . + REQUIRES cmock usb + INCLUDE_DIRS . + PRIV_INCLUDE_DIRS "../../private_include" + WHOLE_ARCHIVE) + +# Currently 'main' for IDF_TARGET=linux is defined in freertos component. +# Since we are using a freertos mock here, need to let Catch2 provide 'main'. +target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain) diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/cdc_descriptors.hpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/cdc_descriptors.hpp new file mode 100644 index 00000000..b3b9ec17 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/cdc_descriptors.hpp @@ -0,0 +1,633 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +//------------------------------------------- CDC Descriptors ---------------------------------------------------------- + +/* + Devices list: + - USB - UART: + - FTDI chip + - TTL232 (FTDI derivative) + - CP210x + - CH340 + - USB - Ethernet: + - ASIX Electronics Corp. AX88772A Fast Ethernet (PremiumCord) + - ASIX Electronics Corp. AX88772B (i-tec) + - Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter (AXAGON) + - Modems: + - Qualcomm / Option SimTech SIM7080 (SIM7070G) + - Quectel Wireless Solutions Co., Ltd. BG96 CAT-M1/NB-IoT modem + - Qualcomm / Option SimTech, Incorporated (SIM7600E) + - Qualcomm / Option SimTech SIM7000 (SIM7000E) + - NOT TESTED: Qualcomm / Option SimTech SIM7080 (SIM7080G) + - NOT TESTED: Qualcomm / Option A76XX Series LTE Module (SIMA7672E) + - USB dongle: + - NOT TESTED: Shenzhen Rapoo Technology Co., Ltd. Rapoo 2.4G Wireless Device + - NOT TESTED: Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode) + - TinyUSB: + - tusb_composite_msc_serialdevice esp32s3 + - NOT TESTED: tusb_console esp32s3 + - NOT TESTED: tusb_hid esp32s3 + - NOT TESTED: tusb_midi esp32s3 + - NOT TESTED: tusb_msc esp32s3 + - NOT TESTED: tusb_ncm esp32s3 + - tusb_serial_device (1 x CDC) esp32s3, esp32p4 + - tusb_serial_device (2 x CDC) esp32s3, esp32p4 +*/ + +//----------------------------------------------- USB - UART ----------------------------------------------------------- + +// FTDI chip dual (populated on Wrover-kit) +const uint8_t ftdi_device_desc_fs_hs[] = { + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x03, 0x04, 0x10, 0x60, 0x00, 0x07, 0x01, 0x02, 0x00, 0x01 +}; + +const uint8_t ftdi_config_desc_fs[] = { + 0x09, 0x02, 0x37, 0x00, 0x02, 0x01, 0x00, 0x80, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x02, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x02, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t ftdi_config_desc_hs[] = { + 0x09, 0x02, 0x37, 0x00, 0x02, 0x01, 0x00, 0x80, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x02, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x02, 0x07, 0x05, 0x83, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00 +}; + +// TTL232RG (FTDI derivative) +const uint8_t ttl232_device_desc[] = { + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x03, 0x04, 0x01, 0x60, 0x00, 0x06, 0x01, 0x02, 0x03, 0x01, +}; + +const uint8_t ttl232_config_desc[] = { + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x02, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, +}; + +// CP210x +// (only FS) +const uint8_t cp210x_device_desc[] = { + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xC4, 0x10, 0x60, 0xEA, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01 +}; + +const uint8_t cp210x_config_desc[] = { + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x07, + 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; + +// CH340 +// (only FS) +const uint8_t ch340_device_desc[] = { + 0x12, 0x01, 0x10, 0x01, 0xFF, 0x00, 0x00, 0x08, 0x86, 0x1A, 0x23, 0x75, 0x54, 0x02, 0x00, 0x02, 0x00, 0x01 +}; + +const uint8_t ch340_config_desc[] = { + 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0x80, 0x30, 0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0x01, + 0x02, 0x00, 0x07, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x20, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x01 +}; + +//------------------------------------------- USB - ethernet ----------------------------------------------------------- + +// ASIX Electronics Corp. AX88772A Fast Ethernet (PremiumCord) +const uint8_t premium_cord_device_desc_fs[] = + +{0x12, 0x01, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x08, 0x95, 0x0B, 0x2A, 0x77, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t premium_cord_device_desc_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x40, 0x95, 0x0B, 0x2A, 0x77, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t premium_cord_config_desc_fs[] = + +{ + 0x09, 0x02, 0x35, 0x00, 0x01, 0x01, 0x04, 0xA0, 0x7D, 0x09, 0x04, 0x00, 0x00, 0x05, 0xFF, 0xFF, 0x00, 0x07, 0x07, + 0x05, 0x81, 0x03, 0x08, 0x00, 0xA0, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, + 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t premium_cord_config_desc_hs[] = + +{ + 0x09, 0x02, 0x35, 0x00, 0x01, 0x01, 0x04, 0xA0, 0x7D, 0x09, 0x04, 0x00, 0x00, 0x05, 0xFF, 0xFF, 0x00, 0x07, 0x07, + 0x05, 0x81, 0x03, 0x08, 0x00, 0x0B, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, 0x02, + 0x00, 0x07, 0x05, 0x84, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x05, 0x02, 0x00, 0x02, 0x00 +}; + + +// ASIX Electronics Corp. AX88772B (i-tec) +const uint8_t i_tec_device_desc_fs[] = + +{0x12, 0x01, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x08, 0x95, 0x0B, 0x2B, 0x77, 0x02, 0x00, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t i_tec_device_desc_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x40, 0x95, 0x0B, 0x2B, 0x77, 0x02, 0x00, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t i_tec_config_desc_fs[] = + +{ + 0x09, 0x02, 0x27, 0x00, 0x95, 0x0B, 0x2B, 0x77, 0x02, 0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x07, 0x07, + 0x05, 0x81, 0xA0, 0x64, 0x00, 0xA0, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, + 0x00 +}; + +const uint8_t i_tec_config_desc_hs[] = + +{ + 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x04, 0xA0, 0x64, 0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x07, 0x07, + 0x05, 0x81, 0x03, 0x08, 0x00, 0x0B, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, 0x02, + 0x00 +}; + + +// Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter (AXAGON) +const uint8_t axagon_device_desc_fs_hs[] = + +{0x12, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x40, 0xDA, 0x0B, 0x53, 0x81, 0x00, 0x30, 0x01, 0x02, 0x06, 0x02}; + +const uint8_t axagon_config_desc_fs_1[] = + +{ + 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xA0, 0x64, 0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x03, 0x02, 0x00, + 0x08 +}; + +const uint8_t axagon_config_desc_fs_2[] = + +{ + 0x09, 0x02, 0x50, 0x00, 0x02, 0x02, 0x00, 0xA0, 0x64, 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x06, 0x00, 0x05, 0x05, + 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x06, 0x00, 0x01, 0x0D, 0x24, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x05, + 0x00, 0x00, 0x00, 0x07, 0x05, 0x83, 0x03, 0x10, 0x00, 0x08, 0x09, 0x04, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x01, 0x01, 0x02, 0x0A, 0x00, 0x00, 0x04, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, + 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t axagon_config_desc_hs_1[] = + +{ + 0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xA0, 0x64, 0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x83, 0x03, 0x02, 0x00, + 0x08 +}; + +const uint8_t axagon_config_desc_hs_2[] = + +{ + 0x09, 0x02, 0x50, 0x00, 0x02, 0x02, 0x00, 0xA0, 0x64, 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x06, 0x00, 0x05, 0x05, + 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x06, 0x00, 0x01, 0x0D, 0x24, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x05, + 0x00, 0x00, 0x00, 0x07, 0x05, 0x83, 0x03, 0x10, 0x00, 0x08, 0x09, 0x04, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x01, 0x01, 0x02, 0x0A, 0x00, 0x00, 0x04, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, + 0x02, 0x00, 0x02, 0x00 +}; + + +//------------------------------------------- Modems ------------------------------------------------------------------- + + +// Qualcomm / Option SimTech SIM7080 (SIM7070G) +// lsusb device name: Qualcomm / Option SimTech SIM7080 +// IC marking: SIM7070G +const uint8_t sim7070G_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0x02, 0x00, 0x00, 0x40, 0x0E, 0x1E, 0x06, 0x92, 0x00, 0x00, 0x03, 0x02, 0x04, 0x01}; + +const uint8_t sim7070G_config_desc_fs[] = + +{ + 0x09, 0x02, 0x9A, 0x00, 0x06, 0x01, 0x01, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, + 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x00, 0x07, + 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x85, 0x02, + 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x05, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, + 0x07, 0x05, 0x86, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, + 0x00, 0x00 +}; + +const uint8_t sim7070G_config_desc_hs[] = + +{ + 0x09, 0x02, 0x9A, 0x00, 0x06, 0x01, 0x01, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, + 0x02, 0x00, 0x09, 0x04, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x84, 0x02, 0x00, 0x02, 0x00, 0x07, + 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x04, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x85, 0x02, + 0x00, 0x02, 0x00, 0x07, 0x05, 0x05, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x05, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, + 0x07, 0x05, 0x86, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x87, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x06, 0x02, 0x00, + 0x02, 0x00 +}; + + +// Quectel Wireless Solutions Co., Ltd. BG96 CAT-M1/NB-IoT modem +const uint8_t bg96_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x7C, 0x2C, 0x96, 0x02, 0x00, 0x00, 0x03, 0x02, 0x04, 0x01}; + +const uint8_t bg96_config_desc_fs[] = + +{ + 0x09, 0x02, 0x91, 0x00, 0x05, 0x01, 0x01, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x84, 0x02, 0x40, + 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0xFE, 0xFF, 0x00, 0x07, + 0x05, 0x85, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, + 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x87, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, + 0x88, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t bg96_config_desc_hs[] = + +{ + 0x09, 0x02, 0x91, 0x00, 0x05, 0x01, 0x01, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x84, 0x02, 0x00, + 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0xFE, 0xFF, 0x00, 0x07, + 0x05, 0x85, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x86, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, + 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x87, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, + 0x88, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x05, 0x02, 0x00, 0x02, 0x00 +}; + + +// Qualcomm / Option SimTech SIM7000 (SIM7000E) +// lsusb device name: Qualcomm / Option SimTech SIM7000 +// IC marking: SIM7000E +const uint8_t sim7000e_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x0E, 0x1E, 0x01, 0x90, 0x00, 0x00, 0x03, 0x02, 0x04, 0x01}; + +const uint8_t sim7000e_config_desc_fs[] = + +{ + 0x09, 0x02, 0xA8, 0x00, 0x06, 0x01, 0x01, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, + 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x05, 0x07, + 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, + 0xFE, 0xFF, 0x00, 0x07, 0x05, 0x86, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, + 0x05, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x05, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x88, 0x03, 0x40, + 0x00, 0x05, 0x07, 0x05, 0x89, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t sim7000e_config_desc_hs[] = + +{ + 0x09, 0x02, 0xA8, 0x00, 0x06, 0x01, 0x01, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, + 0x02, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x05, 0x07, + 0x05, 0x85, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, + 0xFE, 0xFF, 0x00, 0x07, 0x05, 0x86, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x87, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, + 0x05, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x05, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x88, 0x03, 0x40, + 0x00, 0x05, 0x07, 0x05, 0x89, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x06, 0x02, 0x00, 0x02, 0x00 +}; + + +// Qualcomm / Option SimTech, Incorporated (SIM7600E) +// lsusb device name: Qualcomm / Option SimTech, Incorporated +// IC marking: SIM7600E +const uint8_t sim7600e_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x0E, 0x1E, 0x01, 0x90, 0x18, 0x03, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t sim7600e_config_desc_fs[] = + +{ + 0x09, 0x02, 0x02, 0x01, 0x06, 0x01, 0x00, 0xA0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x01, 0x00, 0x03, 0xFF, + 0x00, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, + 0x06, 0x00, 0x00, 0x07, 0x05, 0x83, 0x03, 0x0A, 0x00, 0x20, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, + 0x02, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, + 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x85, 0x03, 0x0A, + 0x00, 0x20, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x03, + 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, + 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x87, 0x03, 0x0A, 0x00, 0x20, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, + 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x24, + 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, + 0x89, 0x03, 0x0A, 0x00, 0x20, 0x07, 0x05, 0x88, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, + 0x09, 0x04, 0x05, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x8B, 0x03, 0x08, 0x00, 0x20, 0x07, 0x05, 0x8A, + 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t sim7600e_config_desc_hs[] = + +{ + 0x09, 0x02, 0x02, 0x01, 0x06, 0x01, 0x00, 0xA0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x03, 0xFF, + 0x00, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, + 0x06, 0x00, 0x00, 0x07, 0x05, 0x83, 0x03, 0x0A, 0x00, 0x09, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, + 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x02, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, + 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x85, 0x03, 0x0A, + 0x00, 0x09, 0x07, 0x05, 0x84, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x03, + 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, + 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x87, 0x03, 0x0A, 0x00, 0x09, 0x07, 0x05, 0x86, 0x02, 0x00, 0x02, + 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x05, 0x24, + 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, + 0x89, 0x03, 0x0A, 0x00, 0x09, 0x07, 0x05, 0x88, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x05, 0x02, 0x00, 0x02, 0x00, + 0x09, 0x04, 0x05, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x8B, 0x03, 0x08, 0x00, 0x09, 0x07, 0x05, 0x8A, + 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x06, 0x02, 0x00, 0x02, 0x00 +}; + + +// Qualcomm / Option SimTech SIM7080 (SIM7080G) +// lsusb device name: Qualcomm / Option SimTech SIM7080 +// IC marking SIM7080G +const uint8_t sim7080g_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x0E, 0x1E, 0x05, 0x92, 0x00, 0x00, 0x04, 0x03, 0x05, 0x01}; + +const uint8_t sim7080g_config_desc_fs[] = + +{ + 0x09, 0x02, 0xBB, 0x00, 0x06, 0x01, 0x02, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, + 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x05, 0x07, + 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x08, 0x0B, 0x04, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x01, 0x02, 0x06, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, 0x0D, 0x24, 0x0F, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x05, 0x24, 0x06, 0x04, 0x05, 0x07, 0x05, 0x86, 0x03, + 0x40, 0x00, 0x05, 0x09, 0x04, 0x05, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x09, 0x04, 0x05, 0x01, 0x02, 0x0A, 0x00, + 0x00, 0x00, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t sim7080g_config_desc_hs[] = + +{ + 0x09, 0x02, 0xBB, 0x00, 0x06, 0x01, 0x02, 0xE0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, + 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, + 0x02, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x83, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, + 0x02, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x05, 0x07, + 0x05, 0x85, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 0x08, 0x0B, 0x04, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x01, 0x02, 0x06, 0x00, 0x00, 0x05, 0x24, 0x00, 0x10, 0x01, 0x0D, 0x24, 0x0F, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x05, 0x24, 0x06, 0x04, 0x05, 0x07, 0x05, 0x86, 0x03, + 0x40, 0x00, 0x05, 0x09, 0x04, 0x05, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x09, 0x04, 0x05, 0x01, 0x02, 0x0A, 0x00, + 0x00, 0x00, 0x07, 0x05, 0x87, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x05, 0x02, 0x00, 0x02, 0x00 +}; + + +// Qualcomm / Option A76XX Series LTE Module (SIMA7672E) +// lsusb device name: Qualcomm / Option A76XX Series LTE Module +// IC marking SIMA7672E +const uint8_t sima7672e_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x0E, 0x1E, 0x11, 0x90, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t sima7672e_config_desc_fs[] = + +{ + 0x09, 0x02, 0xF5, 0x00, 0x06, 0x01, 0x00, 0xC0, 0xFA, 0x08, 0x0B, 0x00, 0x02, 0xE0, 0x01, 0x03, 0x05, 0x09, 0x04, + 0x00, 0x00, 0x01, 0xE0, 0x01, 0x03, 0x05, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x00, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x87, 0x03, 0x40, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x05, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x0C, 0x02, 0x40, 0x00, 0x00, 0x09, + 0x04, 0x02, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x08, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x0B, 0x02, + 0x40, 0x00, 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x0B, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, + 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x89, 0x03, 0x40, 0x00, 0x10, + 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x0F, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x05, 0x00, 0x03, + 0xFF, 0x00, 0x00, 0x0B, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, + 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x88, 0x03, 0x40, 0x00, 0x10, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, + 0x05, 0x0A, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x08, 0x05, 0x24, 0x00, 0x10, + 0x01, 0x05, 0x24, 0x01, 0x00, 0x04, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x03, 0x04, 0x07, 0x05, 0x84, 0x03, + 0x10, 0x00, 0x10, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x0E, 0x02, 0x40, 0x00, 0x00 +}; + +const uint8_t sima7672e_config_desc_hs[] = + +{ + 0x09, 0x02, 0xF5, 0x00, 0x06, 0x01, 0x00, 0xC0, 0xFA, 0x08, 0x0B, 0x00, 0x02, 0xE0, 0x01, 0x03, 0x05, 0x09, 0x04, + 0x00, 0x00, 0x01, 0xE0, 0x01, 0x03, 0x05, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x00, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x87, 0x03, 0x40, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x05, 0x07, 0x05, 0x83, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x0C, 0x02, 0x00, 0x02, 0x00, 0x09, + 0x04, 0x02, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x08, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x0B, 0x02, + 0x00, 0x02, 0x00, 0x09, 0x04, 0x04, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x0B, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, + 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x89, 0x03, 0x40, 0x00, 0x10, + 0x07, 0x05, 0x86, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x0F, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x05, 0x00, 0x03, + 0xFF, 0x00, 0x00, 0x0B, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x01, 0x00, 0x00, 0x04, 0x24, 0x02, 0x02, 0x05, + 0x24, 0x06, 0x00, 0x00, 0x07, 0x05, 0x88, 0x03, 0x40, 0x00, 0x10, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, + 0x05, 0x0A, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x03, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x08, 0x05, 0x24, 0x00, 0x10, + 0x01, 0x05, 0x24, 0x01, 0x00, 0x04, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x03, 0x04, 0x07, 0x05, 0x84, 0x03, + 0x10, 0x00, 0x10, 0x07, 0x05, 0x85, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x0E, 0x02, 0x00, 0x02, 0x00 +}; + +// -------------------------------- USB Dongle ------------------------------------------------------------------------- + + +// Shenzhen Rapoo Technology Co., Ltd. Rapoo 2.4G Wireless Device +// (only FS) +const uint8_t rapoo_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xAE, 0x24, 0x13, 0x20, 0x10, 0x01, 0x01, 0x02, 0x00, 0x01}; + +const uint8_t rapoo_config_desc[] = + +{ + 0x09, 0x02, 0x54, 0x00, 0x03, 0x01, 0x00, 0xA0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x02, 0x00, 0x09, + 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x40, 0x00, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x0A, 0x09, 0x04, 0x01, 0x00, + 0x01, 0x03, 0x01, 0x01, 0x00, 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x5E, 0x00, 0x07, 0x05, 0x82, 0x03, 0x40, + 0x00, 0x0A, 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x01, 0x01, 0x00, 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x40, + 0x00, 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x0A +}; + + +// Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode) +const uint8_t csr_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x01, 0x40, 0x12, 0x0A, 0x01, 0x00, 0x91, 0x88, 0x00, 0x02, 0x00, 0x01}; + +const uint8_t csr_config_desc_fs[] = + +{ + 0x09, 0x02, 0xB1, 0x00, 0x02, 0x01, 0x00, 0xE0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x03, 0xE0, 0x01, 0x01, 0x00, 0x07, + 0x05, 0x81, 0x03, 0x10, 0x00, 0x01, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, + 0x01, 0x09, 0x04, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x00, 0x00, 0x01, 0x07, 0x05, + 0x83, 0x01, 0x00, 0x00, 0x01, 0x09, 0x04, 0x01, 0x01, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x09, + 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x09, 0x00, 0x01, 0x09, 0x04, 0x01, 0x02, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, + 0x05, 0x03, 0x01, 0x11, 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x11, 0x00, 0x01, 0x09, 0x04, 0x01, 0x03, 0x02, 0xE0, + 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x19, 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x19, 0x00, 0x01, 0x09, 0x04, + 0x01, 0x04, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x21, 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x21, + 0x00, 0x01, 0x09, 0x04, 0x01, 0x05, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x31, 0x00, 0x01, 0x07, + 0x05, 0x83, 0x01, 0x31, 0x00, 0x01 +}; + +const uint8_t csr_config_desc_hs[] = + +{ + 0x09, 0x02, 0xB1, 0x00, 0x02, 0x01, 0x00, 0xE0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x03, 0xE0, 0x01, 0x01, 0x00, 0x07, + 0x05, 0x81, 0x03, 0x10, 0x00, 0x01, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, + 0x01, 0x09, 0x04, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x00, 0x00, 0x01, 0x07, 0x05, + 0x83, 0x01, 0x00, 0x00, 0x01, 0x09, 0x04, 0x01, 0x01, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x09, + 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x09, 0x00, 0x01, 0x09, 0x04, 0x01, 0x02, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, + 0x05, 0x03, 0x01, 0x11, 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x11, 0x00, 0x01, 0x09, 0x04, 0x01, 0x03, 0x02, 0xE0, + 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x19, 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x19, 0x00, 0x01, 0x09, 0x04, + 0x01, 0x04, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x21, 0x00, 0x01, 0x07, 0x05, 0x83, 0x01, 0x21, + 0x00, 0x01, 0x09, 0x04, 0x01, 0x05, 0x02, 0xE0, 0x01, 0x01, 0x00, 0x07, 0x05, 0x03, 0x01, 0x31, 0x00, 0x01, 0x07, + 0x05, 0x83, 0x01, 0x31, 0x00, 0x01 +}; + + +// ------------------------------------ TinyUSB ------------------------------------------------------------------------ + + +// tusb_composite_msc_serialdevice (dev: esp32s3, host: esp32s3) +const uint8_t tusb_composite_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x3A, 0x30, 0x01, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t tusb_composite_config_desc[] = + +{ + 0x09, 0x02, 0x62, 0x00, 0x03, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x09, + 0x04, 0x02, 0x00, 0x02, 0x08, 0x06, 0x50, 0x05, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02, + 0x40, 0x00, 0x00 +}; + + +// tusb_console (dev: esp32s3, host: esp32s3) +const uint8_t tusb_console_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x3A, 0x30, 0x01, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t tusb_console_config_desc[] = + +{ + 0x09, 0x02, 0x4B, 0x00, 0x02, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; + + +// tusb_hid (dev: esp32s3, host: esp32s3) +const uint8_t tusb_hid_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3A, 0x30, 0x04, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t tusb_hid_config_desc[] = + +{ + 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xA0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x92, 0x00, 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x0A +}; + +// tusb_midi (dev: esp32s3, host: esp32s3) +const uint8_t tusb_midi_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3A, 0x30, 0x08, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t tusb_midi_config_desc[] = + +{ + 0x09, 0x02, 0x65, 0x00, 0x02, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x04, 0x09, + 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, 0x09, 0x04, 0x01, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x07, 0x24, + 0x01, 0x00, 0x01, 0x41, 0x00, 0x06, 0x24, 0x02, 0x01, 0x01, 0x00, 0x06, 0x24, 0x02, 0x02, 0x02, 0x00, 0x09, 0x24, + 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00, 0x09, 0x05, 0x01, + 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x05, 0x25, 0x01, 0x01, 0x01, 0x09, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x25, 0x01, 0x01, 0x03 +}; + + +// tusb_msc (dev: esp32s3, host: esp32s3) +const uint8_t tusb_msc_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x3A, 0x30, 0x02, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t tusb_msc_config_desc[] = + +{ + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xA0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00, 0x07, + 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00 +}; + + +// tusb_ncm (dev: esp32s3, host: esp32s3) +const uint8_t tusb_ncm_device_desc[] = + +{0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3A, 0x30, 0x00, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +const uint8_t tusb_ncm_config_desc[] = + +{ + 0x09, 0x02, 0x5E, 0x00, 0x02, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x0D, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x0D, 0x00, 0x04, 0x05, 0x24, 0x00, 0x10, 0x01, 0x05, 0x24, 0x06, 0x00, 0x01, 0x0D, 0x24, + 0x0F, 0x05, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x05, 0x00, 0x00, 0x00, 0x06, 0x24, 0x1A, 0x00, 0x01, 0x00, 0x07, 0x05, + 0x81, 0x03, 0x40, 0x00, 0x32, 0x09, 0x04, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x09, 0x04, 0x01, 0x01, 0x02, + 0x0A, 0x00, 0x01, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, +}; + + +// tusb_serial_device +const uint8_t tusb_serial_device_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x3A, 0x30, 0x01, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +// (dev: esp32s3, host: esp32s3) +const uint8_t tusb_serial_device_config_desc_fs[] = + +{ + 0x09, 0x02, 0x4B, 0x00, 0x02, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00 +}; + +// (dev: esp32p4, host: esp32p4) +const uint8_t tusb_serial_device_config_desc_hs[] = + +{ + 0x09, 0x02, 0x4B, 0x00, 0x02, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00 +}; + + +// tusb_serial_device dual +const uint8_t tusb_serial_device_dual_device_desc_fs_hs[] = + +{0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40, 0x3A, 0x30, 0x02, 0x40, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01}; + +// (dev: esp32s3, host: esp32s3) +const uint8_t tusb_serial_device_dual_config_desc_fs[] = + +{ + 0x09, 0x02, 0x8D, 0x00, 0x04, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x08, + 0x0B, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, + 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x03, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x02, 0x03, 0x07, 0x05, 0x83, + 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x03, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, + 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x00 +}; + +// (dev: esp32p4, host: esp32p4) +const uint8_t tusb_serial_device_dual_config_desc_hs[] = + +{ + 0x09, 0x02, 0x8D, 0x00, 0x04, 0x01, 0x00, 0xA0, 0x32, 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, + 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x01, 0x04, 0x24, + 0x02, 0x02, 0x05, 0x24, 0x06, 0x00, 0x01, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x01, 0x00, 0x02, + 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x08, + 0x0B, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x04, 0x05, 0x24, 0x00, + 0x20, 0x01, 0x05, 0x24, 0x01, 0x00, 0x03, 0x04, 0x24, 0x02, 0x02, 0x05, 0x24, 0x06, 0x02, 0x03, 0x07, 0x05, 0x83, + 0x03, 0x08, 0x00, 0x10, 0x09, 0x04, 0x03, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, + 0x00, 0x07, 0x05, 0x84, 0x02, 0x00, 0x02, 0x00 +}; diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/idf_component.yml b/host/class/cdc/usb_host_cdc_acm/host_test/main/idf_component.yml new file mode 100644 index 00000000..528c8f3d --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/catch2: "^3.4.0" + usb_host_cdc_acm: + version: "*" + override_path: "../../" diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/test_main.cpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_main.cpp new file mode 100644 index 00000000..c6130ffa --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_main.cpp @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + + +extern "C" void app_main(void) +{ + int argc = 1; + const char *argv[2] = { + "target_test_main", + NULL + }; + + auto result = Catch::Session().run(argc, argv); + if (result != 0) { + printf("Test failed with result %d\n", result); + } else { + printf("Test passed.\n"); + } + fflush(stdout); + exit(result); +} diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_checker.hpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_checker.hpp new file mode 100644 index 00000000..12ac943a --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_checker.hpp @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @brief Helper to check parsing result of CDC compliant devices + * + * CDC compliant device usually provides: + * #. Notification interface + * #. Data interface + * #. CDC specific descriptors + */ +#define REQUIRE_CDC_COMPLIANT(ret, parsed_result, nb_of_cdc_specific) \ + REQUIRE(ESP_OK == ret); \ + REQUIRE((parsed_result).notif_intf != nullptr); \ + REQUIRE((parsed_result).notif_ep != nullptr); \ + REQUIRE((parsed_result).data_intf != nullptr); \ + REQUIRE((parsed_result).in_ep != nullptr); \ + REQUIRE((parsed_result).out_ep != nullptr); \ + REQUIRE((parsed_result).func != nullptr); \ + REQUIRE((parsed_result).func_cnt == nb_of_cdc_specific); + +/** + * @brief Helper to check parsing result of CDC non-compliant devices + * + * CDC non-compliant device usually provides only Data interface + */ +#define REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result) \ + REQUIRE(ESP_OK == ret); \ + REQUIRE((parsed_result).notif_intf == nullptr); \ + REQUIRE((parsed_result).notif_ep == nullptr); \ + REQUIRE((parsed_result).data_intf != nullptr); \ + REQUIRE((parsed_result).in_ep != nullptr); \ + REQUIRE((parsed_result).out_ep != nullptr); \ + REQUIRE((parsed_result).func == nullptr); \ + REQUIRE((parsed_result).func_cnt == 0); + +/** + * @brief Helper to check parsing result of CDC non-compliant devices + * + * Some CDC non-compliant devices also provide Notification interface + */ +#define REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result) \ + REQUIRE(ESP_OK == ret); \ + REQUIRE((parsed_result).notif_intf != nullptr); \ + REQUIRE((parsed_result).notif_ep != nullptr); \ + REQUIRE((parsed_result).data_intf != nullptr); \ + REQUIRE((parsed_result).in_ep != nullptr); \ + REQUIRE((parsed_result).out_ep != nullptr); \ + REQUIRE((parsed_result).func == nullptr); \ + REQUIRE((parsed_result).func_cnt == 0); diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_ethernet_converters.cpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_ethernet_converters.cpp new file mode 100644 index 00000000..9c57e024 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_ethernet_converters.cpp @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "usb/usb_helpers.h" + +#include "cdc_descriptors.hpp" +#include "test_parsing_checker.hpp" +#include "cdc_host_descriptor_parsing.h" +#include "usb/cdc_acm_host.h" + +SCENARIO("Ethernet converters descriptor parsing: AX88772A", "[ethernet][AX88772A]") +{ + GIVEN("ASIX AX88772A FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)premium_cord_device_desc_fs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)premium_cord_config_desc_fs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + + GIVEN("ASIX AX88772A HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)premium_cord_device_desc_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)premium_cord_config_desc_hs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } +} + +SCENARIO("Ethernet converters descriptor parsing: AX88772B", "[ethernet][AX88772B]") +{ + GIVEN("ASIX AX88772B FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)i_tec_device_desc_fs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)i_tec_config_desc_fs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + (void)ret; + //@todo this is probably a bug in AX88772B descriptor + // It uses CTRL endpoint instead of Interrupt for notification element + // Should be solved during implementation of Ethernet drivers + //REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + + GIVEN("ASIX AX88772B HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)i_tec_device_desc_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)i_tec_config_desc_hs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } +} + +SCENARIO("Ethernet converters descriptor parsing: RTL8153", "[ethernet][RTL8153]") +{ + GIVEN("Realtek RTL8153 CFG 1 FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)axagon_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)axagon_config_desc_fs_1; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + + GIVEN("Realtek RTL8153 CFG 2 FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)axagon_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)axagon_config_desc_fs_2; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 3); + } + } + + GIVEN("Realtek RTL8153 CFG 1 HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)axagon_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)axagon_config_desc_hs_1; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + + GIVEN("Realtek RTL8153 CFG 2 HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)axagon_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)axagon_config_desc_hs_2; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 3); + } + } +} diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_modems.cpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_modems.cpp new file mode 100644 index 00000000..8b34e759 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_modems.cpp @@ -0,0 +1,202 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "usb/usb_helpers.h" + +#include "cdc_descriptors.hpp" +#include "test_parsing_checker.hpp" +#include "cdc_host_descriptor_parsing.h" +#include "usb/cdc_acm_host.h" + +SCENARIO("Modems descriptor parsing: BG96", "[modem][BG96]") +{ + GIVEN("Quactel BG96 FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)bg96_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)bg96_config_desc_fs; + + // First 2 interfaces are without notification element + for (int interface = 0; interface < 2; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + // Interface 2-4 contain notification element + for (int interface = 2; interface < 5; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + } + + GIVEN("Quactel BG96 HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)bg96_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)bg96_config_desc_hs; + + // Interface 0-1 are without notification element + for (int interface = 0; interface < 2; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + // Interface 2-4 contain notification element + for (int interface = 2; interface < 5; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + } +} + +SCENARIO("Modems descriptor parsing: 7600E", "[modem][7600E]") +{ + GIVEN("SimCom 7600E FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)sim7600e_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)sim7600e_config_desc_fs; + + // Interface 0 is without notification element + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + + // Interface 1-5 contain notification element + for (int interface = 1; interface < 6; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + } + + GIVEN("SimCom 7600E HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)sim7600e_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)sim7600e_config_desc_hs; + + // Interface 0 is without notification element + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + + // Interface 1-5 contain notification element + for (int interface = 1; interface <= 5; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + } +} + +SCENARIO("Modems descriptor parsing: 7070G", "[modem][7070G]") +{ + GIVEN("SimCom 7070G FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)sim7070G_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)sim7070G_config_desc_fs; + + // Interface 0-4 do not contain notification element + for (int interface = 0; interface <= 4; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + // Interface 5 is with notification element + SECTION("Interface 5") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 5, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + + GIVEN("SimCom 7070G HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)sim7070G_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)sim7070G_config_desc_hs; + + // Interface 0-4 do not contain notification element + for (int interface = 0; interface <= 4; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + // Interface 5 is with notification element + SECTION("Interface 5") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 5, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } +} + +SCENARIO("Modems descriptor parsing: 7000E", "[modem][7000E]") +{ + GIVEN("SimCom 7000E FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)sim7000e_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)sim7000e_config_desc_fs; + + // Interface 0-2 do not contain notification element + for (int interface = 0; interface <= 2; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + // Interface 3-5 contain notification element + for (int interface = 3; interface <= 5; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + } + + GIVEN("SimCom 7000E HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)sim7000e_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)sim7000e_config_desc_hs; + + // Interface 0-2 do not contain notification element + for (int interface = 0; interface <= 2; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + // Interface 3-5 contain notification element + for (int interface = 3; interface <= 5; ++interface) { + SECTION("Interface " + std::to_string(interface)) { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, interface, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } + } +} diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_tinyusb_devices.cpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_tinyusb_devices.cpp new file mode 100644 index 00000000..2ba22dc0 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_tinyusb_devices.cpp @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "usb/usb_helpers.h" + +#include "cdc_descriptors.hpp" +#include "test_parsing_checker.hpp" +#include "cdc_host_descriptor_parsing.h" +#include "usb/cdc_acm_host.h" + +SCENARIO("TinyUSB devices descriptor parsing", "[tinyusb]") +{ + GIVEN("TinyUSB single FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)tusb_serial_device_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)tusb_serial_device_config_desc_fs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + } + + GIVEN("TinyUSB single HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)tusb_serial_device_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)tusb_serial_device_config_desc_hs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + } + + GIVEN("TinyUSB dual FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)tusb_serial_device_dual_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)tusb_serial_device_dual_config_desc_fs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + + SECTION("Interface 2") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 2, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + } + + GIVEN("TinyUSB dual HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)tusb_serial_device_dual_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)tusb_serial_device_dual_config_desc_hs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + + SECTION("Interface 2") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 2, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + } + + GIVEN("TinyUSB CDC+MSC FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)tusb_composite_device_desc; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)tusb_composite_config_desc; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_COMPLIANT(ret, parsed_result, 4); + } + } +} diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_uart_converters.cpp b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_uart_converters.cpp new file mode 100644 index 00000000..269886ca --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/main/test_parsing_uart_converters.cpp @@ -0,0 +1,130 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "usb/usb_helpers.h" +// #include "usb/usb_host.h" + +#include "cdc_descriptors.hpp" +#include "test_parsing_checker.hpp" +#include "cdc_host_descriptor_parsing.h" +#include "usb/cdc_acm_host.h" + +// extern "C" { +// #include "Mockusb_host.h" +// } + +SCENARIO("USB-UART converters descriptor parsing: CP210x", "[uart][CP210x]") +{ + GIVEN("Silicon Labs CP210x Full-Speed") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)cp210x_device_desc; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)cp210x_config_desc; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + + /* + //@todo Run this section when we the USB host mock is complete + SECTION("Device opening") { + int num_of_devices = 1; + usb_device_handle_t dev_handle = 11; + usb_host_device_addr_list_fill_ExpectAnyArgsAndReturn(ESP_OK); + usb_host_device_addr_list_fill_ReturnThruPtr_num_dev_ret(&num_of_devices); + + usb_host_device_open_ExpectAnyArgsAndReturn(ESP_OK); + usb_host_device_open_ReturnThruPtr_dev_hdl_ret(&dev_handle); + + usb_host_get_device_descriptor_ExpectAnyArgsAndReturn(ESP_OK); + usb_host_get_device_descriptor_ReturnThruPtr_device_desc(&dev_desc); + + usb_host_device_close_ExpectAnyArgsAndReturn(ESP_OK); + + usb_host_get_device_descriptor_ExpectAnyArgsAndReturn(ESP_OK); + usb_host_get_device_descriptor_ReturnThruPtr_device_desc(&dev_desc); + + usb_host_get_active_config_descriptor_ExpectAnyArgsAndReturn(ESP_OK); + usb_host_get_active_config_descriptor_ReturnThruPtr_config_desc(&cfg_desc); + + cdc_acm_dev_hdl_t dev = nullptr; + cdc_acm_host_device_config_t config = { + .connection_timeout_ms = 1000, + .out_buffer_size = 100, + .in_buffer_size = 100, + .event_cb = nullptr, + .data_cb = nullptr, + .user_arg = nullptr, + }; + esp_err_t ret = cdc_acm_host_open(0x10C4, 0xEA60, 0, &config, &dev); + + REQUIRE(ESP_OK == ret); + REQUIRE(dev != nullptr); + } + */ + } +} + +SCENARIO("USB-UART converters descriptor parsing: FTDI", "[uart][FTDI]") +{ + GIVEN("FTDI chip FS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)ftdi_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)ftdi_config_desc_fs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } + + GIVEN("FTDI chip HS") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)ftdi_device_desc_fs_hs; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)ftdi_config_desc_hs; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + + SECTION("Interface 1") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 1, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } +} + +SCENARIO("USB-UART converters descriptor parsing: TTL232", "[uart][TTL232]") +{ + GIVEN("TTL232") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)ttl232_device_desc; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)ttl232_config_desc; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT(ret, parsed_result); + } + } +} + +SCENARIO("USB-UART converters descriptor parsing: CH340", "[uart][CH340]") +{ + GIVEN("CH340") { + const usb_device_desc_t *dev_desc = (const usb_device_desc_t *)ch340_device_desc; + const usb_config_desc_t *cfg_desc = (const usb_config_desc_t *)ch340_config_desc; + + SECTION("Interface 0") { + cdc_parsed_info_t parsed_result = {}; + esp_err_t ret = cdc_parse_interface_descriptor(dev_desc, cfg_desc, 0, &parsed_result); + REQUIRE_CDC_NONCOMPLIANT_WITH_NOTIFICATION(ret, parsed_result); + } + } +} diff --git a/host/class/cdc/usb_host_cdc_acm/host_test/sdkconfig.defaults b/host/class/cdc/usb_host_cdc_acm/host_test/sdkconfig.defaults new file mode 100644 index 00000000..14bc2aef --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/host_test/sdkconfig.defaults @@ -0,0 +1,8 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration +# +CONFIG_IDF_TARGET="linux" +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_ESP_MAIN_TASK_STACK_SIZE=12000 +CONFIG_FREERTOS_HZ=1000 +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/pytest.ini b/pytest.ini index 1f07f269..dc82314c 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,11 +1,11 @@ [pytest] # only the files with prefix `pytest_` would be recognized as pytest test scripts. python_files = pytest_*.py +cpp_files = host_test_*.elf # set traceback to "short" to prevent the overwhelming tracebacks addopts = -s - --embedded-services esp,idf --tb short markers =