From c14eebbff577905a6d0a7b29dd30ea68629efe8a Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Tue, 11 Jun 2024 13:11:56 +0200 Subject: [PATCH] feature(esp_tinyusb): Added test for usb device class reconfiguration --- .../test_app/main/test_bvalid_sig.c | 2 +- .../test_app/main/test_descriptors_config.c | 267 +++++++++++++++++- .../esp_tinyusb/test_app/pytest_usb_device.py | 0 .../test_app/pytest_usb_device_esp_tinyusb.py | 12 - .../esp_tinyusb/test_app/sdkconfig.defaults | 4 +- 5 files changed, 264 insertions(+), 21 deletions(-) create mode 100644 device/esp_tinyusb/test_app/pytest_usb_device.py delete mode 100644 device/esp_tinyusb/test_app/pytest_usb_device_esp_tinyusb.py diff --git a/device/esp_tinyusb/test_app/main/test_bvalid_sig.c b/device/esp_tinyusb/test_app/main/test_bvalid_sig.c index f80432f7..6b1edc18 100644 --- a/device/esp_tinyusb/test_app/main/test_bvalid_sig.c +++ b/device/esp_tinyusb/test_app/main/test_bvalid_sig.c @@ -68,7 +68,7 @@ void test_bvalid_sig_umount_cb(void) dev_umounted++; } -TEST_CASE("bvalid_signal", "[esp_tinyusb][usb_device]") +TEST_CASE("bvalid_signal", "[usb_device]") { unsigned int rounds = DEVICE_DETACH_TEST_ROUNDS; diff --git a/device/esp_tinyusb/test_app/main/test_descriptors_config.c b/device/esp_tinyusb/test_app/main/test_descriptors_config.c index 23e5e8fc..2962a9ed 100644 --- a/device/esp_tinyusb/test_app/main/test_descriptors_config.c +++ b/device/esp_tinyusb/test_app/main/test_descriptors_config.c @@ -104,7 +104,7 @@ void test_descriptors_config_umount_cb(void) } -TEST_CASE("descriptors_config_all_default", "[esp_tinyusb][usb_device]") +TEST_CASE("descriptors_config_all_default", "[usb_device]") { TEST_ASSERT_EQUAL(true, __test_prep()); // Install TinyUSB driver @@ -125,7 +125,7 @@ TEST_CASE("descriptors_config_all_default", "[esp_tinyusb][usb_device]") __test_free(); } -TEST_CASE("descriptors_config_device", "[esp_tinyusb][usb_device]") +TEST_CASE("descriptors_config_device", "[usb_device]") { TEST_ASSERT_EQUAL(true, __test_prep()); // Install TinyUSB driver @@ -146,7 +146,7 @@ TEST_CASE("descriptors_config_device", "[esp_tinyusb][usb_device]") __test_free(); } -TEST_CASE("descriptors_config_device_and_config", "[esp_tinyusb][usb_device]") +TEST_CASE("descriptors_config_device_and_config", "[usb_device]") { TEST_ASSERT_EQUAL(true, __test_prep()); // Install TinyUSB driver @@ -168,7 +168,7 @@ TEST_CASE("descriptors_config_device_and_config", "[esp_tinyusb][usb_device]") } #if (TUD_OPT_HIGH_SPEED) -TEST_CASE("descriptors_config_device_and_fs_config_only", "[esp_tinyusb][usb_device]") +TEST_CASE("descriptors_config_device_and_fs_config_only", "[usb_device]") { TEST_ASSERT_EQUAL(true, __test_prep()); // Install TinyUSB driver @@ -187,7 +187,7 @@ TEST_CASE("descriptors_config_device_and_fs_config_only", "[esp_tinyusb][usb_dev __test_free(); } -TEST_CASE("descriptors_config_device_and_hs_config_only", "[esp_tinyusb][usb_device]") +TEST_CASE("descriptors_config_device_and_hs_config_only", "[usb_device]") { TEST_ASSERT_EQUAL(true, __test_prep()); // Install TinyUSB driver @@ -206,7 +206,7 @@ TEST_CASE("descriptors_config_device_and_hs_config_only", "[esp_tinyusb][usb_dev __test_free(); } -TEST_CASE("descriptors_config_all_configured", "[esp_tinyusb][usb_device]") +TEST_CASE("descriptors_config_all_configured", "[usb_device]") { TEST_ASSERT_EQUAL(true, __test_prep()); // Install TinyUSB driver @@ -226,4 +226,259 @@ TEST_CASE("descriptors_config_all_configured", "[esp_tinyusb][usb_device]") } #endif // TUD_OPT_HIGH_SPEED +// +// HID Class device configuration +// +#define TUSB_HID_CONFIG_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_HID * TUD_HID_DESC_LEN) + +static const tusb_desc_device_t test_hid_class_dev_desc = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0210, // 2.10 + .bDeviceClass = TUSB_CLASS_UNSPECIFIED, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x413C, // Dell Computer Corp + .idProduct = 0x301A, // Dell MS116 Optical Mouse + .bcdDevice = 0x0100, // 1.00 + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +const uint8_t test_hid_report_descriptor[] = { + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_ITF_PROTOCOL_KEYBOARD)), + TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_ITF_PROTOCOL_MOUSE)) +}; + +const char *test_hid_string_descriptor[5] = { + (char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + "Espressif", // 1: Manufacturer + "USB Test HID Class", // 2: Product + "123456", // 3: Serials, should use chip ID + "Test HID Interface", // 4: HID +}; + +static const uint8_t test_hid_fs_configuration_descriptor[] = { + // Configuration number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_HID_CONFIG_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_HID_DESCRIPTOR(0, 4, false, sizeof(test_hid_report_descriptor), 0x81, 16, 10), +}; + + +#if (TUD_OPT_HIGH_SPEED) +static uint8_t const test_hid_hs_configuration_descriptor[] = { + // Config number, interface count, string index, total length, attribute, power in mA + // Configuration number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_HID_CONFIG_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + // Interface number, string index, boot protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(0, 4, false, sizeof(test_hid_report_descriptor), 0x81, 16, 10), +}; +#endif // TUD_OPT_HIGH_SPEED + +uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) +{ + return test_hid_report_descriptor; +} + +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) +{ + return 0; +} + +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) +{ + +} + +// +// CDC Class 1x Interface +// +#define TUSB_CDC_CONFIG_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 1 * TUD_CDC_DESC_LEN) + +const tusb_desc_device_t test_cdc_class_dev_desc = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = 64, + .idVendor = 0x0001, + .idProduct = 0x0002, + .bcdDevice = 0x0000, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01 +}; + +const char *test_cdc_string_descriptor[5] = { + (char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + "Espressif", // 1: Manufacturer + "USB Test CDC Class", // 2: Product + "123456", // 3: Serials, should use chip ID + "Test CDC Interface", // 4: CDC +}; + +static const uint8_t test_cdc_fs_configuration_descriptor[] = { + // Configuration number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_CDC_CONFIG_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 64), +}; + +// +// MSC Class +// +#define TUSB_MSC_CONFIG_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN) + + +const tusb_desc_device_t test_msc_class_dev_desc = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0210, // 2.10 + .bDeviceClass = TUSB_CLASS_MSC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x0781, // SanDisk Corp + .idProduct = 0x5595, + .bcdDevice = 0x0100, // 1.00 + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01 +}; + +const char *test_msc_string_descriptor[4] = { + (char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + "Espressif", // 1: Manufacturer + "USB Test MSC Class", // 2: Product + NULL, // 3: NULL +}; + +static const uint8_t test_msc_fs_configuration_descriptor[] = { + // Configuration number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_MSC_CONFIG_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_MSC_DESCRIPTOR(1, 0, 0x01, 0x81, 64), +}; + +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + (void) lun; + // Our device doesn't have any media for testing purpose + return false; +} + +void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) +{ + (void) lun; + *block_count = 0; + *block_size = 0; +} + +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + (void) lun; + const char vid[] = "USB"; + const char pid[] = "MSC Class"; + const char rev[] = "0.1"; + + memcpy(vendor_id, vid, strlen(vid)); + memcpy(product_id, pid, strlen(pid)); + memcpy(product_rev, rev, strlen(rev)); +} + +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) +{ + return 0; +} + +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) +{ + return 0; +} + +int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) +{ + return 0; +} + +// +// Configuration array +// + +enum { + TEST_CFG_HID_CLASS = 0, + TEST_CFG_CDC_CLASS, + TEST_CFG_MSC_CLASS, +}; + +const tinyusb_config_t tusb_cfg[] = { + // HID Class + { + .external_phy = false, + .device_descriptor = &test_hid_class_dev_desc, + .string_descriptor = test_hid_string_descriptor, + .string_descriptor_count = sizeof(test_hid_string_descriptor) / sizeof(test_hid_string_descriptor[0]), + .configuration_descriptor = test_hid_fs_configuration_descriptor, +#if (TUD_OPT_HIGH_SPEED) + .hs_configuration_descriptor = test_hid_hs_configuration_descriptor, +#endif // TUD_OPT_HIGH_SPEED + }, + // CDC Class + { + .external_phy = false, + .device_descriptor = &test_cdc_class_dev_desc, + .string_descriptor = test_cdc_string_descriptor, + .string_descriptor_count = sizeof(test_cdc_string_descriptor) / sizeof(test_cdc_string_descriptor[0]), + .configuration_descriptor = test_cdc_fs_configuration_descriptor, +#if (TUD_OPT_HIGH_SPEED) + .hs_configuration_descriptor = test_cdc_hs_configuration_descriptor, +#endif // TUD_OPT_HIGH_SPEED + }, + // MSC Class + { + .external_phy = false, + .device_descriptor = &test_msc_class_dev_desc, + .string_descriptor = test_msc_string_descriptor, + .string_descriptor_count = sizeof(test_msc_string_descriptor) / sizeof(test_msc_string_descriptor[0]), + .configuration_descriptor = test_msc_fs_configuration_descriptor, +#if (TUD_OPT_HIGH_SPEED) + .hs_configuration_descriptor = test_msc_hs_configuration_descriptor, +#endif // TUD_OPT_HIGH_SPEED + }, +}; + + +TEST_CASE("device_class_reconfiguration", "[usb_device]") +{ + TEST_ASSERT_EQUAL(true, __test_prep()); + // Install HID Class only + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg[TEST_CFG_HID_CLASS])); + // Wait for mounted callback + TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); + // Cleanup + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); + + // Install CDC Class only + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg[TEST_CFG_CDC_CLASS])); + // Wait for mounted callback + TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); + // Cleanup + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); + + // Install MSC Class only + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg[TEST_CFG_MSC_CLASS])); + // Wait for mounted callback + TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); + // Cleanup + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); + + __test_free(); +} + #endif // SOC_USB_OTG_SUPPORTED diff --git a/device/esp_tinyusb/test_app/pytest_usb_device.py b/device/esp_tinyusb/test_app/pytest_usb_device.py new file mode 100644 index 00000000..e69de29b diff --git a/device/esp_tinyusb/test_app/pytest_usb_device_esp_tinyusb.py b/device/esp_tinyusb/test_app/pytest_usb_device_esp_tinyusb.py deleted file mode 100644 index 78765bcb..00000000 --- a/device/esp_tinyusb/test_app/pytest_usb_device_esp_tinyusb.py +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: Apache-2.0 - -import pytest -from pytest_embedded_idf.dut import IdfDut - - -@pytest.mark.esp32s2 -@pytest.mark.esp32s3 -@pytest.mark.usb_device -def test_usb_device_esp_tinyusb(dut: IdfDut) -> None: - dut.run_all_single_board_cases(group='usb_device') diff --git a/device/esp_tinyusb/test_app/sdkconfig.defaults b/device/esp_tinyusb/test_app/sdkconfig.defaults index e68b6cd8..fab9f21c 100644 --- a/device/esp_tinyusb/test_app/sdkconfig.defaults +++ b/device/esp_tinyusb/test_app/sdkconfig.defaults @@ -1,9 +1,9 @@ # Configure TinyUSB, it will be used to mock USB devices CONFIG_TINYUSB=y -CONFIG_TINYUSB_MSC_ENABLED=n +CONFIG_TINYUSB_MSC_ENABLED=y CONFIG_TINYUSB_CDC_ENABLED=y CONFIG_TINYUSB_CDC_COUNT=2 -CONFIG_TINYUSB_HID_COUNT=0 +CONFIG_TINYUSB_HID_COUNT=1 # Disable watchdogs, they'd get triggered during unity interactive menu CONFIG_ESP_INT_WDT=n