diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 9bd1ccd8..1d24cb54 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -49,8 +49,15 @@ jobs: fail-fast: false matrix: idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"] - idf_target: ["esp32s2"] + idf_target: ["esp32s2", "esp32p4"] runner_tag: ["usb_host", "usb_device"] + exclude: + - idf_ver: "release-v5.0" # esp32p4 was added in IDF 5.3 + idf_target: "esp32p4" + - idf_ver: "release-v5.1" # esp32p4 was added in IDF 5.3 + idf_target: "esp32p4" + - idf_ver: "release-v5.2" # esp32p4 was added in IDF 5.3 + idf_target: "esp32p4" runs-on: [self-hosted, linux, docker, "${{ matrix.idf_target }}", "${{ matrix.runner_tag }}"] container: image: python:3.11-bookworm 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 b5ffabe6..ea409101 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 @@ -9,4 +9,7 @@ It tests basic functionality of the driver like open/close/read/write operations ### Hardware Required +This test requires two ESP32 development board with USB-OTG support. The development boards shall have interconnected USB peripherals, +one acting as host running CDC-ACM host driver and another CDC-ACM device driver (tinyusb). + 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/test_app_main.c b/host/class/cdc/usb_host_cdc_acm/test_app/main/test_app_main.c index b25c8df7..11c899b2 100644 --- a/host/class/cdc/usb_host_cdc_acm/test_app/main/test_app_main.c +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/test_app_main.c @@ -7,17 +7,19 @@ #include #include #include "unity.h" -#include "esp_heap_caps.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "usb/cdc_acm_host.h" -static size_t before_free_8bit; -static size_t before_free_32bit; - -#define TEST_MEMORY_LEAK_THRESHOLD (-530) -static void check_leak(size_t before_free, size_t after_free, const char *type) +void tearDown(void) { - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); + // Clean-up + ESP_ERROR_CHECK(cdc_acm_host_uninstall()); + vTaskDelay(20); // Short delay to allow task to be cleaned up + + unity_utils_evaluate_leaks(); } void app_main(void) @@ -35,23 +37,7 @@ void app_main(void) printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); printf(" \\/ \\/ \\/ \\/ \r\n"); - UNITY_BEGIN(); + unity_utils_setup_heap_record(80); + unity_utils_set_leak_level(530); unity_run_menu(); - UNITY_END(); -} - -/* setUp runs before every test */ -void setUp(void) -{ - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); -} - -/* tearDown runs after every test */ -void tearDown(void) -{ - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); } 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 54f5cf3c..7225f764 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 @@ -8,81 +8,120 @@ #if SOC_USB_OTG_SUPPORTED #include +#include #include "esp_system.h" +#include "unity.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_idf_version.h" #include "esp_log.h" #include "esp_err.h" - #include "esp_private/usb_phy.h" #include "usb/usb_host.h" #include "usb/cdc_acm_host.h" -#include - #include "esp_intr_alloc.h" -#include "unity.h" -#include "soc/usb_wrap_struct.h" - static uint8_t tx_buf[] = "HELLO"; static uint8_t tx_buf2[] = "WORLD"; static int nb_of_responses; static int nb_of_responses2; static bool new_dev_cb_called = false; static bool rx_overflow = false; + +// usb_host_lib_set_root_port_power is used to force toggle connection, primary developed for esp32p4 +// esp32p4 is supported from IDF 5.3 +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) static usb_phy_handle_t phy_hdl = NULL; +// Force connection/disconnection using PHY static void force_conn_state(bool connected, TickType_t delay_ticks) { TEST_ASSERT_NOT_EQUAL(NULL, phy_hdl); if (delay_ticks > 0) { - //Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. vTaskDelay(delay_ticks); } ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN)); } -void usb_lib_task(void *arg) +// Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing +static bool install_phy(void) { - // Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing usb_phy_config_t phy_config = { .controller = USB_PHY_CTRL_OTG, .target = USB_PHY_TARGET_INT, .otg_mode = USB_OTG_MODE_HOST, - .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device + .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device }; TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_hdl)); + // Return true, to skip_phy_setup during the usb_host_install() + return true; +} + +static void delete_phy(void) +{ + TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_hdl)); // Tear down USB PHY + phy_hdl = NULL; +} +#else // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) + +// Force connection/disconnection using root port power +static void force_conn_state(bool connected, TickType_t delay_ticks) +{ + if (delay_ticks > 0) { + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + vTaskDelay(delay_ticks); + } + ESP_ERROR_CHECK(usb_host_lib_set_root_port_power(connected)); +} + +static bool install_phy(void) +{ + // Return false, NOT to skip_phy_setup during the usb_host_install() + return false; +} + +static void delete_phy(void) {} +#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) + +void usb_lib_task(void *arg) +{ + const bool skip_phy_setup = install_phy(); // Install USB Host driver. Should only be called once in entire application const usb_host_config_t host_config = { - .skip_phy_setup = true, + .skip_phy_setup = skip_phy_setup, .intr_flags = ESP_INTR_FLAG_LEVEL1, }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_install(&host_config)); printf("USB Host installed\n"); xTaskNotifyGive(arg); - bool all_clients_gone = false; - bool all_dev_free = false; - while (!all_clients_gone || !all_dev_free) { - // Start handling system events + bool has_clients = true; + bool has_devices = false; + while (has_clients) { uint32_t event_flags; - usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + ESP_ERROR_CHECK(usb_host_lib_handle_events(portMAX_DELAY, &event_flags)); if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { - printf("No more clients\n"); - usb_host_device_free_all(); - all_clients_gone = true; + printf("Get FLAGS_NO_CLIENTS\n"); + if (ESP_OK == usb_host_device_free_all()) { + printf("All devices marked as free, no need to wait FLAGS_ALL_FREE event\n"); + has_clients = false; + } else { + printf("Wait for the FLAGS_ALL_FREE\n"); + has_devices = true; + } } - if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { - printf("All devices freed\n"); - all_dev_free = true; + if (has_devices && event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { + printf("Get FLAGS_ALL_FREE\n"); + has_clients = false; } } + printf("No more clients and devices, uninstall USB Host library\n"); // Clean up USB Host vTaskDelay(10); // Short delay to allow clients clean-up TEST_ASSERT_EQUAL(ESP_OK, usb_host_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_hdl)); //Tear down USB PHY - phy_hdl = NULL; + delete_phy(); vTaskDelete(NULL); } @@ -158,7 +197,7 @@ static void new_dev_cb(usb_device_handle_t usb_dev) /* Basic test to check CDC communication: * open/read/write/close device * CDC-ACM specific commands: set/get_line_coding, set_control_line_state */ -TEST_CASE("read_write", "[cdc_acm]") +TEST_CASE("read_write", "[cdc_acm][hs_host]") { nb_of_responses = 0; cdc_acm_dev_hdl_t cdc_dev = NULL; @@ -185,12 +224,11 @@ TEST_CASE("read_write", "[cdc_acm]") // We sent two messages, should get two responses TEST_ASSERT_EQUAL(2, nb_of_responses); + // Clean-up 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]") +TEST_CASE("cdc_specific_commands", "[cdc_acm][hs_host]") { cdc_acm_dev_hdl_t cdc_dev = NULL; @@ -219,13 +257,12 @@ TEST_CASE("cdc_specific_commands", "[cdc_acm]") TEST_ASSERT_EQUAL_MEMORY(&line_coding_set, &line_coding_get, sizeof(cdc_acm_line_coding_t)); TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_set_control_line_state(cdc_dev, true, false)); + // Clean-up 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]") +TEST_CASE("desc_print", "[cdc_acm][hs_host]") { cdc_acm_dev_hdl_t cdc_dev = NULL; @@ -242,13 +279,12 @@ TEST_CASE("desc_print", "[cdc_acm]") cdc_acm_host_desc_print(cdc_dev); vTaskDelay(10); + // Clean-up 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 communication with multiple CDC-ACM devices from one thread */ -TEST_CASE("multiple_devices", "[cdc_acm]") +TEST_CASE("multiple_devices", "[cdc_acm][hs_host]") { nb_of_responses = 0; nb_of_responses2 = 0; @@ -280,12 +316,9 @@ TEST_CASE("multiple_devices", "[cdc_acm]") TEST_ASSERT_EQUAL(1, nb_of_responses); TEST_ASSERT_EQUAL(1, nb_of_responses2); + // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev1)); TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev2)); - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - - //Short delay to allow task to be cleaned up - vTaskDelay(20); } #define MULTIPLE_THREADS_TRANSFERS_NUM 5 @@ -312,7 +345,7 @@ void tx_task(void *arg) * In this test, one CDC device is accessed from multiple threads. * It has to be opened/closed just once, though. */ -TEST_CASE("multiple_threads", "[cdc_acm]") +TEST_CASE("multiple_threads", "[cdc_acm][hs_host]") { nb_of_responses = 0; cdc_acm_dev_hdl_t cdc_dev; @@ -341,12 +374,10 @@ TEST_CASE("multiple_threads", "[cdc_acm]") // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } /* Test CDC driver reaction to USB device sudden disconnection */ -TEST_CASE("sudden_disconnection", "[cdc_acm]") +TEST_CASE("sudden_disconnection", "[cdc_acm][hs_host]") { test_install_cdc_driver(); @@ -363,9 +394,6 @@ TEST_CASE("sudden_disconnection", "[cdc_acm]") force_conn_state(false, pdMS_TO_TICKS(10)); // Simulate device disconnection TEST_ASSERT_EQUAL(1, ulTaskNotifyTake(false, pdMS_TO_TICKS(100))); // Notify will succeed only if CDC_ACM_HOST_DEVICE_DISCONNECTED notification was generated - - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); //Short delay to allow task to be cleaned up } /** @@ -383,7 +411,7 @@ TEST_CASE("sudden_disconnection", "[cdc_acm]") * -# Send unsupported CDC request * -# Write to read-only device */ -TEST_CASE("error_handling", "[cdc_acm]") +TEST_CASE("error_handling", "[cdc_acm][hs_host]") { cdc_acm_dev_hdl_t cdc_dev; cdc_acm_host_device_config_t dev_config = { @@ -437,11 +465,9 @@ TEST_CASE("error_handling", "[cdc_acm]") // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } -TEST_CASE("custom_command", "[cdc_acm]") +TEST_CASE("custom_command", "[cdc_acm][hs_host]") { test_install_cdc_driver(); @@ -462,11 +488,9 @@ TEST_CASE("custom_command", "[cdc_acm]") // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } -TEST_CASE("new_device_connection_1", "[cdc_acm]") +TEST_CASE("new_device_connection_1", "[cdc_acm][hs_host]") { // Create a task that will handle USB library events TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(usb_lib_task, "usb_lib", 4 * 4096, xTaskGetCurrentTaskHandle(), 10, NULL, 0)); @@ -485,28 +509,20 @@ TEST_CASE("new_device_connection_1", "[cdc_acm]") vTaskDelay(50); TEST_ASSERT_TRUE_MESSAGE(new_dev_cb_called, "New device callback was not called\n"); new_dev_cb_called = false; - - // Clean-up - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } -TEST_CASE("new_device_connection_2", "[cdc_acm]") +TEST_CASE("new_device_connection_2", "[cdc_acm][hs_host]") { test_install_cdc_driver(); // Option 2: Register callback after driver install - force_conn_state(false, 0); + force_conn_state(false, 50); vTaskDelay(50); TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_register_new_dev_callback(new_dev_cb)); force_conn_state(true, 0); vTaskDelay(50); TEST_ASSERT_TRUE_MESSAGE(new_dev_cb_called, "New device callback was not called\n"); new_dev_cb_called = false; - - // Clean-up - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } TEST_CASE("rx_buffer", "[cdc_acm]") @@ -559,11 +575,9 @@ TEST_CASE("rx_buffer", "[cdc_acm]") // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } -TEST_CASE("functional_descriptor", "[cdc_acm]") +TEST_CASE("functional_descriptor", "[cdc_acm][hs_host]") { test_install_cdc_driver(); @@ -605,8 +619,6 @@ TEST_CASE("functional_descriptor", "[cdc_acm]") // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); } /** @@ -614,7 +626,7 @@ TEST_CASE("functional_descriptor", "[cdc_acm]") * * -# Close already closed device */ -TEST_CASE("closing", "[cdc_acm]") +TEST_CASE("closing", "[cdc_acm][hs_host]") { cdc_acm_dev_hdl_t cdc_dev = NULL; @@ -632,16 +644,14 @@ TEST_CASE("closing", "[cdc_acm]") TEST_ASSERT_NOT_NULL(cdc_dev); vTaskDelay(10); + // Clean-up TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_close(cdc_dev)); printf("Closing already closed device \n"); 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 } /* Basic test to check CDC driver reaction to TX timeout */ -TEST_CASE("tx_timeout", "[cdc_acm]") +TEST_CASE("tx_timeout", "[cdc_acm][hs_host]") { cdc_acm_dev_hdl_t cdc_dev = NULL; @@ -668,10 +678,8 @@ TEST_CASE("tx_timeout", "[cdc_acm]") TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_data_tx_blocking(cdc_dev, tx_buf, sizeof(tx_buf), 1000)); vTaskDelay(100); + // Clean-up 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 } /** @@ -680,7 +688,7 @@ TEST_CASE("tx_timeout", "[cdc_acm]") * #. Try to open a device with all combinations of any VID/PID * #. Try to open a non-existing device with all combinations of any VID/PID */ -TEST_CASE("any_vid_pid", "[cdc_acm]") +TEST_CASE("any_vid_pid", "[cdc_acm][hs_host]") { cdc_acm_dev_hdl_t cdc_dev = NULL; test_install_cdc_driver(); @@ -706,9 +714,6 @@ TEST_CASE("any_vid_pid", "[cdc_acm]") printf("Opening non-existing CDC-ACM devices with any VID/PID\n"); TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, cdc_acm_host_open(0x1234, CDC_HOST_ANY_PID, 0, &dev_config, &cdc_dev)); TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, cdc_acm_host_open(CDC_HOST_ANY_VID, 0x1234, 0, &dev_config, &cdc_dev)); - - TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall()); - vTaskDelay(20); //Short delay to allow task to be cleaned up } /* Following test case implements dual CDC-ACM USB device that can be used as mock device for CDC-ACM Host tests */ diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/main/usb_device.c b/host/class/cdc/usb_host_cdc_acm/test_app/main/usb_device.c index 4cdfb9dc..194ceb16 100644 --- a/host/class/cdc/usb_host_cdc_acm/test_app/main/usb_device.c +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/usb_device.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,7 +8,6 @@ #include "sdkconfig.h" #include "tinyusb.h" #include "tusb_cdc_acm.h" -#include "esp_idf_version.h" static uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1]; static void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event) @@ -20,7 +19,6 @@ static void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event) tinyusb_cdcacm_write_flush(itf, 0); } -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) static const tusb_desc_device_t cdc_device_descriptor = { .bLength = sizeof(cdc_device_descriptor), .bDescriptorType = TUSB_DESC_DEVICE, @@ -39,22 +37,49 @@ static const tusb_desc_device_t cdc_device_descriptor = { }; static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN; -static const uint8_t cdc_desc_configuration[] = { +static const uint8_t cdc_fs_desc_configuration[] = { TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 64), TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 64), }; -#endif + +#if (TUD_OPT_HIGH_SPEED) +static const uint8_t cdc_hs_desc_configuration[] = { + TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 512), + TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 512), +}; + +static const tusb_desc_device_qualifier_t device_qualifier = { + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0 +}; + +#endif // TUD_OPT_HIGH_SPEED void run_usb_dual_cdc_device(void) { const tinyusb_config_t tusb_cfg = { - .external_phy = false, -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) .device_descriptor = &cdc_device_descriptor, - .configuration_descriptor = cdc_desc_configuration -#endif + .string_descriptor = NULL, + .string_descriptor_count = 0, + .external_phy = false, +#if (TUD_OPT_HIGH_SPEED) + .fs_configuration_descriptor = cdc_fs_desc_configuration, + .hs_configuration_descriptor = cdc_hs_desc_configuration, + .qualifier_descriptor = &device_qualifier, +#else + .configuration_descriptor = cdc_fs_desc_configuration, +#endif // TUD_OPT_HIGH_SPEED }; + ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); tinyusb_config_cdcacm_t amc_cfg = { 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 a8d39d9b..3cfc84ec 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 @@ -14,14 +14,18 @@ @pytest.mark.parametrize('count', [ 2, ], indirect=True) -def test_usb_host(dut: Tuple[IdfDut, IdfDut]) -> None: +def test_usb_host_cdc(dut: Tuple[IdfDut, IdfDut]) -> None: device = dut[0] host = dut[1] - # 1.1 Prepare USB device for CDC test + # 1 Prepare USB device for CDC test device.expect_exact('Press ENTER to see the list of tests.') device.write('[cdc_acm_device]') device.expect_exact('USB initialization DONE') - # 1.2 Run CDC test - host.run_all_single_board_cases(group='cdc_acm') + # 2 Run CDC test + if host.target == 'esp32p4': + # rx_buffer test can't be run for esp32p4, reason: RX buffer append is not yet supported on ESP32-P4 + host.run_all_single_board_cases(group='hs_host') + else: + host.run_all_single_board_cases(group='cdc_acm') diff --git a/host/class/hid/usb_host_hid/test_app/README.md b/host/class/hid/usb_host_hid/test_app/README.md index a87b4dca..6a7f3f27 100644 --- a/host/class/hid/usb_host_hid/test_app/README.md +++ b/host/class/hid/usb_host_hid/test_app/README.md @@ -1,4 +1,13 @@ -| Supported Targets | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-S3 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | -# USB: HID Class test application \ No newline at end of file +# USB: HID Class test application + +## HID driver + +Basic functionality such as HID device install/uninstall, class specific requests as well as reaction to sudden disconnection and other error states. + +### Hardware Required + +This test requires two ESP32 development board with USB-OTG support. The development boards shall have interconnected USB peripherals, +one acting as host running HID host driver and another HID device driver (tinyusb). \ No newline at end of file diff --git a/host/class/hid/usb_host_hid/test_app/main/hid_mock_device.c b/host/class/hid/usb_host_hid/test_app/main/hid_mock_device.c index 16e6ed65..61d2a27f 100644 --- a/host/class/hid/usb_host_hid/test_app/main/hid_mock_device.c +++ b/host/class/hid/usb_host_hid/test_app/main/hid_mock_device.c @@ -1,19 +1,16 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include -#include "sdkconfig.h" #include "tinyusb.h" #include "class/hid/hid_device.h" -#include "esp_idf_version.h" #include "hid_mock_device.h" static tusb_iface_count_t tusb_iface_count = 0; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) /************* TinyUSB descriptors ****************/ #define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_HID * TUD_HID_DESC_LEN) @@ -75,10 +72,28 @@ static const uint8_t *hid_configuration_descriptor_list[TUSB_IFACE_COUNT_MAX] = hid_configuration_descriptor_one_iface, hid_configuration_descriptor_two_ifaces }; -#endif // // esp idf >= v5.0.0 + +/** + * @brief Device qualifier + * + * This is a simple device qualifier for HS devices + */ + +#if (TUD_OPT_HIGH_SPEED) +static const tusb_desc_device_qualifier_t device_qualifier = { + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0 +}; +#endif // TUD_OPT_HIGH_SPEED /********* TinyUSB HID callbacks ***************/ -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) // Invoked when received GET HID REPORT DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) @@ -95,12 +110,6 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) } return NULL; } -#endif // esp idf >= v5.0.0 - -#if ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))) -#define HID_ITF_PROTOCOL_KEYBOARD HID_PROTOCOL_KEYBOARD -#define HID_ITF_PROTOCOL_MOUSE HID_PROTOCOL_MOUSE -#endif // 4.4.0 <= esp idf < v5.0.0 /** * @brief Get Keyboard report @@ -177,7 +186,7 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_ void hid_mock_device(tusb_iface_count_t iface_count) { if (iface_count > TUSB_IFACE_COUNT_MAX) { - printf("UHID mock device, wrong iface_count paramteter (%d)\n", + printf("HID mock device, wrong iface_count parameter (%d)\n", iface_count); return; } @@ -186,15 +195,18 @@ void hid_mock_device(tusb_iface_count_t iface_count) tusb_iface_count = iface_count; const tinyusb_config_t tusb_cfg = { - .external_phy = false, -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) .device_descriptor = NULL, .string_descriptor = hid_string_descriptor, .string_descriptor_count = sizeof(hid_string_descriptor) / sizeof(hid_string_descriptor[0]), + .external_phy = false, +#if (TUD_OPT_HIGH_SPEED) + .fs_configuration_descriptor = hid_configuration_descriptor_list[tusb_iface_count], + .hs_configuration_descriptor = hid_configuration_descriptor_list[tusb_iface_count], + .qualifier_descriptor = &device_qualifier, +#else .configuration_descriptor = hid_configuration_descriptor_list[tusb_iface_count], -#endif // esp idf >= v5.0.0 +#endif // TUD_OPT_HIGH_SPEED }; - ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); printf("HID mock device with %s has been started\n", diff --git a/host/class/hid/usb_host_hid/test_app/main/test_app_main.c b/host/class/hid/usb_host_hid/test_app/main/test_app_main.c index b25c8df7..17efe7c4 100644 --- a/host/class/hid/usb_host_hid/test_app/main/test_app_main.c +++ b/host/class/hid/usb_host_hid/test_app/main/test_app_main.c @@ -7,17 +7,12 @@ #include #include #include "unity.h" -#include "esp_heap_caps.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" -static size_t before_free_8bit; -static size_t before_free_32bit; - -#define TEST_MEMORY_LEAK_THRESHOLD (-530) -static void check_leak(size_t before_free, size_t after_free, const char *type) +void tearDown(void) { - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); + unity_utils_evaluate_leaks(); } void app_main(void) @@ -35,23 +30,7 @@ void app_main(void) printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); printf(" \\/ \\/ \\/ \\/ \r\n"); - UNITY_BEGIN(); + unity_utils_setup_heap_record(80); + unity_utils_set_leak_level(530); unity_run_menu(); - UNITY_END(); -} - -/* setUp runs before every test */ -void setUp(void) -{ - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); -} - -/* tearDown runs after every test */ -void tearDown(void) -{ - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); } diff --git a/host/class/hid/usb_host_hid/test_app/main/test_hid_basic.c b/host/class/hid/usb_host_hid/test_app/main/test_hid_basic.c index f25a5250..778056ce 100644 --- a/host/class/hid/usb_host_hid/test_app/main/test_hid_basic.c +++ b/host/class/hid/usb_host_hid/test_app/main/test_hid_basic.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "freertos/event_groups.h" #include "freertos/queue.h" #include "freertos/semphr.h" +#include "esp_idf_version.h" #include "esp_private/usb_phy.h" #include "usb/usb_host.h" @@ -22,9 +23,6 @@ #include "test_hid_basic.h" #include "hid_mock_device.h" -// USB PHY for device discinnection emulation -static usb_phy_handle_t phy_hdl = NULL; - // Global variable to verify user arg passing through callbacks static uint32_t user_arg_value = 0x8A53E0A4; // Just a constant renadom number @@ -61,16 +59,62 @@ typedef enum { HID_HOST_TEST_TOUCH_WAY_SUDDEN_DISCONNECT = 0x01, } hid_host_test_touch_way_t; +// usb_host_lib_set_root_port_power is used to force toggle connection, primary developed for esp32p4 +// esp32p4 is supported from IDF 5.3 +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) +static usb_phy_handle_t phy_hdl = NULL; + +// Force connection/disconnection using PHY static void force_conn_state(bool connected, TickType_t delay_ticks) { - TEST_ASSERT_NOT_NULL(phy_hdl); + TEST_ASSERT_NOT_EQUAL(NULL, phy_hdl); if (delay_ticks > 0) { - //Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. vTaskDelay(delay_ticks); } ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN)); } +// Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing +static bool install_phy(void) +{ + usb_phy_config_t phy_config = { + .controller = USB_PHY_CTRL_OTG, + .target = USB_PHY_TARGET_INT, + .otg_mode = USB_OTG_MODE_HOST, + .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device + }; + TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_hdl)); + // Return true, to skip_phy_setup during the usb_host_install() + return true; +} + +static void delete_phy(void) +{ + TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_hdl)); // Tear down USB PHY + phy_hdl = NULL; +} +#else + +// Force connection/disconnection using root port power +static void force_conn_state(bool connected, TickType_t delay_ticks) +{ + if (delay_ticks > 0) { + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + vTaskDelay(delay_ticks); + } + ESP_ERROR_CHECK(usb_host_lib_set_root_port_power(connected)); +} + +static bool install_phy(void) +{ + // Return false, NOT to skip_phy_setup during the usb_host_install() + return false; +} + +static void delete_phy(void) {} +#endif + void hid_host_test_interface_callback(hid_host_device_handle_t hid_device_handle, const hid_host_interface_event_t event, void *arg) @@ -458,18 +502,9 @@ void test_task_access(void) */ static void usb_lib_task(void *arg) { - // Initialize the internal USB PHY to connect to the USB OTG peripheral. - // We manually install the USB PHY for testing - usb_phy_config_t phy_config = { - .controller = USB_PHY_CTRL_OTG, - .target = USB_PHY_TARGET_INT, - .otg_mode = USB_OTG_MODE_HOST, - .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device - }; - TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_hdl)); - + const bool skip_phy_setup = install_phy(); const usb_host_config_t host_config = { - .skip_phy_setup = true, + .skip_phy_setup = skip_phy_setup, .intr_flags = ESP_INTR_FLAG_LEVEL1, }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_install(&host_config) ); @@ -504,8 +539,7 @@ static void usb_lib_task(void *arg) // Clean up USB Host vTaskDelay(10); // Short delay to allow clients clean-up TEST_ASSERT_EQUAL(ESP_OK, usb_host_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_hdl)); //Tear down USB PHY - phy_hdl = NULL; + delete_phy(); vTaskDelete(NULL); } @@ -545,7 +579,7 @@ void test_hid_setup(hid_host_driver_event_cb_t device_callback, /** * @brief Teardowns HID testing - * - Disconnect connected USB device manually by PHY triggering + * - Disconnect connected USB device manually by setting root port power * - Wait for USB lib task was closed * - Uninstall HID Host driver * - Clear the notification value to 0 diff --git a/host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py b/host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py index c4b26d85..57381025 100644 --- a/host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py +++ b/host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py @@ -9,6 +9,7 @@ @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.usb_host @pytest.mark.parametrize('count', [ 2, @@ -17,19 +18,19 @@ def test_usb_host_hid(dut: Tuple[IdfDut, IdfDut]) -> None: device = dut[0] host = dut[1] - # 3.1 Prepare USB device with one Interface for HID tests + # 1 Prepare USB device with one Interface for HID tests device.expect_exact('Press ENTER to see the list of tests.') device.write('[hid_device]') device.expect_exact('HID mock device with 1xInterface (Protocol=None) has been started') - # 3.2 Run HID tests + # 2 Run HID tests host.run_all_single_board_cases(group='hid_host') - # 3.3 Prepare USB device with two Interfaces for HID tests + # 3 Prepare USB device with two Interfaces for HID tests device.serial.hard_reset() device.expect_exact('Press ENTER to see the list of tests.') device.write('[hid_device2]') device.expect_exact('HID mock device with 2xInterfaces (Protocol=BootKeyboard, Protocol=BootMouse) has been started') - # 3.4 Run HID tests + # 4 Run HID tests host.run_all_single_board_cases(group='hid_host') diff --git a/host/class/msc/usb_host_msc/test_app/README.md b/host/class/msc/usb_host_msc/test_app/README.md index 7384992b..ec1cabe4 100644 --- a/host/class/msc/usb_host_msc/test_app/README.md +++ b/host/class/msc/usb_host_msc/test_app/README.md @@ -1,7 +1,7 @@ -| Supported Targets | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-S3 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | -# USB: CDC Class test application +# USB: MSC Class test application ## MSC driver @@ -10,5 +10,5 @@ raw access to MSC device and sudden disconnect is tested. ### Hardware Required -This test requires two ESP32-S2/S3 boards with a interconnected USB peripherals, +This test requires two ESP32 development board with USB-OTG support. The development boards shall have interconnected USB peripherals, one acting as host running MSC host driver and another MSC device driver (tinyusb). \ No newline at end of file diff --git a/host/class/msc/usb_host_msc/test_app/main/msc_device.c b/host/class/msc/usb_host_msc/test_app/main/msc_device.c index 952ae10f..b780b1f0 100644 --- a/host/class/msc/usb_host_msc/test_app/main/msc_device.c +++ b/host/class/msc/usb_host_msc/test_app/main/msc_device.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,23 +7,20 @@ #include "esp_log.h" #include "tinyusb.h" -#include "esp_idf_version.h" #include "soc/soc_caps.h" #include "test_common.h" -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #include "esp_check.h" #include "driver/gpio.h" #include "tusb_msc_storage.h" -#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#if SOC_SDMMC_HOST_SUPPORTED #include "diskio_impl.h" #include "diskio_sdmmc.h" -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ +#endif /* SOC_SDMMC_HOST_SUPPORTED */ #if SOC_USB_OTG_SUPPORTED /* sd-card configuration to be done by user */ -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#if SOC_SDMMC_HOST_SUPPORTED #define SDMMC_BUS_WIDTH 4 /* Select the bus width of SD or MMC interface (4 or 1). Note that even if 1 line mode is used, D3 pin of the SD card must have a pull-up resistor connected. Otherwise the card may enter @@ -34,13 +31,12 @@ #define PIN_D1 38 /* D1 GPIO number (applicable when width SDMMC_BUS_WIDTH is 4) */ #define PIN_D2 33 /* D2 GPIO number (applicable when width SDMMC_BUS_WIDTH is 4) */ #define PIN_D3 34 /* D3 GPIO number (applicable when width SDMMC_BUS_WIDTH is 4) */ -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ +#endif /* SOC_SDMMC_HOST_SUPPORTED */ static const char *TAG = "msc_example"; /* TinyUSB descriptors ********************************************************************* */ -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN) enum { @@ -53,14 +49,34 @@ enum { EDPT_MSC_IN = 0x81, }; -static uint8_t const desc_configuration[] = { +static uint8_t const msc_fs_desc_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 64), +}; +#if (TUD_OPT_HIGH_SPEED) +static const uint8_t msc_hs_desc_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64), + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 512), }; +static const tusb_desc_device_qualifier_t device_qualifier = { + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0 +}; +#endif // TUD_OPT_HIGH_SPEED + static tusb_desc_device_t descriptor_config = { .bLength = sizeof(descriptor_config), .bDescriptorType = TUSB_DESC_DEVICE, @@ -86,10 +102,8 @@ static char const *string_desc_arr[] = { //"123456", // 3: Serials //"Test MSC", // 4. MSC }; -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ /*********************************************************************** TinyUSB descriptors*/ -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #define VBUS_MONITORING_GPIO_NUM GPIO_NUM_4 static void configure_vbus_monitoring(void) { @@ -103,27 +117,31 @@ static void configure_vbus_monitoring(void) }; ESP_ERROR_CHECK(gpio_config(&vbus_gpio_config)); } -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ static void storage_init(void) { ESP_LOGI(TAG, "USB MSC initialization"); + const tinyusb_config_t tusb_cfg = { - .external_phy = false, -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) .device_descriptor = &descriptor_config, - .configuration_descriptor = desc_configuration, .string_descriptor = string_desc_arr, .string_descriptor_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]), + .external_phy = false, +#if (TUD_OPT_HIGH_SPEED) + .fs_configuration_descriptor = msc_fs_desc_configuration, + .hs_configuration_descriptor = msc_hs_desc_configuration, + .qualifier_descriptor = &device_qualifier, +#else + .configuration_descriptor = msc_fs_desc_configuration, +#endif // TUD_OPT_HIGH_SPEED .self_powered = true, .vbus_monitor_io = VBUS_MONITORING_GPIO_NUM -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ }; + ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); ESP_LOGI(TAG, "USB initialization DONE"); } -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) static esp_err_t storage_init_spiflash(wl_handle_t *wl_handle) { ESP_LOGI(TAG, "Initializing wear levelling"); @@ -136,28 +154,26 @@ static esp_err_t storage_init_spiflash(wl_handle_t *wl_handle) return wl_mount(data_partition, wl_handle); } -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ void device_app(void) { ESP_LOGI(TAG, "Initializing storage..."); -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) configure_vbus_monitoring(); static wl_handle_t wl_handle = WL_INVALID_HANDLE; ESP_ERROR_CHECK(storage_init_spiflash(&wl_handle)); - tinyusb_msc_spiflash_config_t config_spi; - config_spi.wl_handle = wl_handle; + const tinyusb_msc_spiflash_config_t config_spi = { + .wl_handle = wl_handle, + }; ESP_ERROR_CHECK(tinyusb_msc_storage_init_spiflash(&config_spi)); -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ storage_init(); while (1) { vTaskDelay(100); } } -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#if SOC_SDMMC_HOST_SUPPORTED static esp_err_t storage_init_sdmmc(sdmmc_card_t **card) { esp_err_t ret = ESP_OK; @@ -246,216 +262,6 @@ void device_app_sdmmc(void) vTaskDelay(100); } } -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ - -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) -// whether host does safe-eject -static bool ejected = false; - -// Some MCU doesn't have enough 8KB SRAM to store the whole disk -// We will use Flash as read-only disk with board that has -// CFG_EXAMPLE_MSC_READONLY defined - -uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { - //------------- Block0: Boot Sector -------------// - // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; - // sector_per_cluster = 1; reserved_sectors = 1; - // fat_num = 1; fat12_root_entry_num = 16; - // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0; - // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29; - // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; - // FAT magic code at offset 510-511 - { - 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, - 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', - 'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, - - // Zero up to 2 last bytes of FAT magic code - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 'F', 'A', 'T', '3', '2', ' ', ' ', ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA - }, - - //------------- Block1: FAT12 Table -------------// - { - 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file - }, - - //------------- Block2: Root Directory -------------// - { - // first entry is volume label - 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // second entry is readme file - 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D, - 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, - sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) - }, - - //------------- Block3: Readme Content -------------// - README_CONTENTS -}; - -// Invoked when received SCSI_CMD_INQUIRY -// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -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[] = "TinyUSB"; - const char pid[] = "Mass Storage"; - const char rev[] = "1.0"; - - memcpy(vendor_id, vid, strlen(vid)); - memcpy(product_id, pid, strlen(pid)); - memcpy(product_rev, rev, strlen(rev)); -} - -// Invoked when received Test Unit Ready command. -// return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun) -{ - (void) lun; - - // RAM disk is ready until ejected - if (ejected) { - tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); - return false; - } - - return true; -} - -// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size -// Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) -{ - (void) lun; - - *block_count = DISK_BLOCK_NUM; - *block_size = DISK_BLOCK_SIZE; -} - -// Invoked when received Start Stop Unit command -// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage -// - Start = 1 : active mode, if load_eject = 1 : load disk storage -bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) -{ - (void) lun; - (void) power_condition; - - if ( load_eject ) { - if (start) { - // load disk storage - } else { - // unload disk storage - ejected = true; - } - } - - return true; -} - -// Callback invoked when received READ10 command. -// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) -{ - (void) lun; - - uint8_t const *addr = msc_disk[lba] + offset; - memcpy(buffer, addr, bufsize); - - return bufsize; -} - -// Callback invoked when received WRITE10 command. -// Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) -{ - (void) lun; - -#ifndef CFG_EXAMPLE_MSC_READONLY - uint8_t *addr = msc_disk[lba] + offset; - memcpy(addr, buffer, bufsize); -#else - (void) lba; (void) offset; (void) buffer; -#endif - - return bufsize; -} - -// Callback invoked when received an SCSI command not in built-in list below -// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE -// - READ10 and WRITE10 has their own callbacks -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) -{ - // read10 & write10 has their own callback and MUST not be handled here - - void const *response = NULL; - uint16_t resplen = 0; - - // most scsi handled is input - bool in_xfer = true; - - switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; - break; - - default: - // Set Sense = Invalid Command Operation - tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - - // negative means error -> tinyusb could stall and/or response with failed status - resplen = -1; - break; - } - - // return resplen must not larger than bufsize - if ( resplen > bufsize ) { - resplen = bufsize; - } - - if ( response && (resplen > 0) ) { - if (in_xfer) { - memcpy(buffer, response, resplen); - } else { - // SCSI output - } - } - - return resplen; -} -#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ +#endif /* SOC_SDMMC_HOST_SUPPORTED */ #endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/host/class/msc/usb_host_msc/test_app/main/test_app_main.c b/host/class/msc/usb_host_msc/test_app/main/test_app_main.c index b25c8df7..17efe7c4 100644 --- a/host/class/msc/usb_host_msc/test_app/main/test_app_main.c +++ b/host/class/msc/usb_host_msc/test_app/main/test_app_main.c @@ -7,17 +7,12 @@ #include #include #include "unity.h" -#include "esp_heap_caps.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" -static size_t before_free_8bit; -static size_t before_free_32bit; - -#define TEST_MEMORY_LEAK_THRESHOLD (-530) -static void check_leak(size_t before_free, size_t after_free, const char *type) +void tearDown(void) { - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); + unity_utils_evaluate_leaks(); } void app_main(void) @@ -35,23 +30,7 @@ void app_main(void) printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); printf(" \\/ \\/ \\/ \\/ \r\n"); - UNITY_BEGIN(); + unity_utils_setup_heap_record(80); + unity_utils_set_leak_level(530); unity_run_menu(); - UNITY_END(); -} - -/* setUp runs before every test */ -void setUp(void) -{ - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); -} - -/* tearDown runs after every test */ -void tearDown(void) -{ - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); } diff --git a/host/class/msc/usb_host_msc/test_app/main/test_common.h b/host/class/msc/usb_host_msc/test_app/main/test_common.h index 20a18160..b16f5c93 100644 --- a/host/class/msc/usb_host_msc/test_app/main/test_common.h +++ b/host/class/msc/usb_host_msc/test_app/main/test_common.h @@ -1,12 +1,10 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include "esp_idf_version.h" - enum { // FatFS only allows to format disks with number of blocks greater than 128 DISK_BLOCK_NUM = 128 + 1, @@ -14,9 +12,9 @@ enum { }; void device_app(void); -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#if SOC_SDMMC_HOST_SUPPORTED void device_app_sdmmc(void); -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ +#endif /* SOC_SDMMC_HOST_SUPPORTED */ #define README_CONTENTS \ "This is tinyusb's MassStorage Class demo.\r\n\r\n\ diff --git a/host/class/msc/usb_host_msc/test_app/main/test_msc.c b/host/class/msc/usb_host_msc/test_app/main/test_msc.c index 32997e88..80974d84 100644 --- a/host/class/msc/usb_host_msc/test_app/main/test_msc.c +++ b/host/class/msc/usb_host_msc/test_app/main/test_msc.c @@ -5,20 +5,21 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "soc/soc_caps.h" +#if SOC_USB_OTG_SUPPORTED + #include "unity.h" #include #include #include -#include "esp_private/usb_phy.h" +#include "esp_idf_version.h" #include "esp_private/msc_scsi_bot.h" +#include "esp_private/usb_phy.h" #include "usb/usb_host.h" #include "usb/msc_host_vfs.h" #include "test_common.h" -#include "esp_idf_version.h" #include "../private_include/msc_common.h" -#if SOC_USB_OTG_SUPPORTED - static const char *TAG = "APP"; #define ESP_OK_ASSERT(exp) TEST_ASSERT_EQUAL(ESP_OK, exp) @@ -34,18 +35,63 @@ static SemaphoreHandle_t ready_to_deinit_usb; static msc_host_device_handle_t device; static msc_host_vfs_handle_t vfs_handle; static volatile bool waiting_for_sudden_disconnect; + +// usb_host_lib_set_root_port_power is used to force toggle connection, primary developed for esp32p4 +// esp32p4 is supported from IDF 5.3 +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) static usb_phy_handle_t phy_hdl = NULL; +// Force connection/disconnection using PHY static void force_conn_state(bool connected, TickType_t delay_ticks) { - TEST_ASSERT(phy_hdl); + TEST_ASSERT_NOT_EQUAL(NULL, phy_hdl); if (delay_ticks > 0) { - //Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. vTaskDelay(delay_ticks); } ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN)); } +// Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing +static bool install_phy(void) +{ + usb_phy_config_t phy_config = { + .controller = USB_PHY_CTRL_OTG, + .target = USB_PHY_TARGET_INT, + .otg_mode = USB_OTG_MODE_HOST, + .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device + }; + TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_hdl)); + // Return true, to skip_phy_setup during the usb_host_install() + return true; +} + +static void delete_phy(void) +{ + TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_hdl)); // Tear down USB PHY + phy_hdl = NULL; +} +#else // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) + +// Force connection/disconnection using root port power +static void force_conn_state(bool connected, TickType_t delay_ticks) +{ + if (delay_ticks > 0) { + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + vTaskDelay(delay_ticks); + } + ESP_ERROR_CHECK(usb_host_lib_set_root_port_power(connected)); +} + +static bool install_phy(void) +{ + // Return false, NOT to skip_phy_setup during the usb_host_install() + return false; +} + +static void delete_phy(void) {} +#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) + static void msc_event_cb(const msc_host_event_t *event, void *arg) { if (waiting_for_sudden_disconnect) { @@ -138,21 +184,6 @@ static void msc_task(void *args) vTaskDelete(NULL); } -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) -static void check_file_content(const char *file_path, const char *expected) -{ - ESP_LOGI(TAG, "Reading %s:", file_path); - FILE *file = fopen(file_path, "r"); - TEST_ASSERT_NOT_NULL_MESSAGE(file, "Could not open file"); - - char content[200]; - size_t read_cnt = fread(content, 1, sizeof(content), file); - TEST_ASSERT_EQUAL_MESSAGE(strlen(expected), read_cnt, "Error in reading file"); - TEST_ASSERT_EQUAL_STRING(content, expected); - fclose(file); -} -#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ - static void check_sudden_disconnect(void) { uint8_t data[512]; @@ -168,7 +199,7 @@ static void check_sudden_disconnect(void) TEST_ASSERT_EQUAL(0, fflush(file)); ESP_LOGI(TAG, "Trigger a disconnect"); - //Trigger a disconnect + // Trigger a disconnect waiting_for_sudden_disconnect = true; force_conn_state(false, 0); @@ -189,21 +220,12 @@ static void msc_test_init(void) ready_to_deinit_usb = xSemaphoreCreateBinary(); TEST_ASSERT( app_queue = xQueueCreate(5, sizeof(msc_host_event_t)) ); - - //Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing - usb_phy_config_t phy_config = { - .controller = USB_PHY_CTRL_OTG, - .target = USB_PHY_TARGET_INT, - .otg_mode = USB_OTG_MODE_HOST, - .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device - }; - ESP_OK_ASSERT(usb_new_phy(&phy_config, &phy_hdl)); + const bool skip_phy_setup = install_phy(); const usb_host_config_t host_config = { - .skip_phy_setup = true, + .skip_phy_setup = skip_phy_setup, .intr_flags = ESP_INTR_FLAG_LEVEL1, }; ESP_OK_ASSERT( usb_host_install(&host_config) ); - task_created = xTaskCreatePinnedToCore(handle_usb_events, "usb_events", 2 * 2048, NULL, 2, NULL, 0); TEST_ASSERT(task_created); } @@ -247,9 +269,7 @@ static void msc_test_deinit(void) vSemaphoreDelete(ready_to_deinit_usb); vTaskDelay(10); // Wait to finish any ongoing USB operations ESP_OK_ASSERT( usb_host_uninstall() ); - //Tear down USB PHY - ESP_OK_ASSERT(usb_del_phy(phy_hdl)); - phy_hdl = NULL; + delete_phy(); vQueueDelete(app_queue); vTaskDelay(10); // Wait for FreeRTOS to clean up deleted tasks @@ -269,8 +289,8 @@ static void write_read_sectors(void) memset(write_data, 0x55, DISK_BLOCK_SIZE); memset(read_data, 0, DISK_BLOCK_SIZE); - scsi_cmd_write10(device, write_data, 10, 1, DISK_BLOCK_SIZE); - scsi_cmd_read10(device, read_data, 10, 1, DISK_BLOCK_SIZE); + ESP_OK_ASSERT( scsi_cmd_write10(device, write_data, 10, 1, DISK_BLOCK_SIZE)); + ESP_OK_ASSERT( scsi_cmd_read10(device, read_data, 10, 1, DISK_BLOCK_SIZE)); TEST_ASSERT_EQUAL_MEMORY(write_data, read_data, DISK_BLOCK_SIZE); } @@ -306,21 +326,6 @@ TEST_CASE("sectors_can_be_written_and_read", "[usb_msc]") msc_teardown(); } -/** - * @brief Check README content - * - * This test strictly requires our implementation of USB MSC Mock device. - * This test will fail for usualW flash drives, as they don't have README.TXT file on them. - */ -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) -TEST_CASE("check_README_content", "[usb_msc]") -{ - msc_setup(); - check_file_content("/usb/README.TXT", README_CONTENTS); - msc_teardown(); -} -#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ - esp_err_t bot_execute_command(msc_device_t *device, uint8_t *cbw, void *data, size_t size); /** * @brief Error recovery testcase @@ -539,11 +544,11 @@ TEST_CASE("mock_device_app", "[usb_msc_device][ignore]") device_app(); } -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#if SOC_SDMMC_HOST_SUPPORTED TEST_CASE("mock_device_app", "[usb_msc_device_sdmmc][ignore]") { device_app_sdmmc(); } -#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ +#endif /* SOC_SDMMC_HOST_SUPPORTED */ #endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/host/class/msc/usb_host_msc/test_app/pytest_usb_host_msc.py b/host/class/msc/usb_host_msc/test_app/pytest_usb_host_msc.py index 3101b930..e144f173 100644 --- a/host/class/msc/usb_host_msc/test_app/pytest_usb_host_msc.py +++ b/host/class/msc/usb_host_msc/test_app/pytest_usb_host_msc.py @@ -9,6 +9,7 @@ @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.usb_host @pytest.mark.parametrize('count', [ 2, @@ -17,10 +18,10 @@ def test_usb_host_msc(dut: Tuple[IdfDut, IdfDut]) -> None: device = dut[0] host = dut[1] - # 2.1 Prepare USB device for MSC test + # 1 Prepare USB device for MSC test device.expect_exact('Press ENTER to see the list of tests.') device.write('[usb_msc_device]') device.expect_exact('USB initialization DONE') - # 2.2 Run MSC test + # 2 Run MSC test host.run_all_single_board_cases(group='usb_msc') diff --git a/host/class/uvc/usb_host_uvc/test_app/README.md b/host/class/uvc/usb_host_uvc/test_app/README.md index b693d60c..9af09c7b 100644 --- a/host/class/uvc/usb_host_uvc/test_app/README.md +++ b/host/class/uvc/usb_host_uvc/test_app/README.md @@ -1,4 +1,12 @@ -| Supported Targets | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-S3 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | -# USB: UVC Class test application \ No newline at end of file +# USB: UVC Class test application + +## UVC driver + +UVC descriptor parsing is checked + +### Hardware Required + +This test requires an ESP32 development board with USB-OTG support. \ No newline at end of file diff --git a/host/class/uvc/usb_host_uvc/test_app/main/test_app_main.c b/host/class/uvc/usb_host_uvc/test_app/main/test_app_main.c index b25c8df7..17efe7c4 100644 --- a/host/class/uvc/usb_host_uvc/test_app/main/test_app_main.c +++ b/host/class/uvc/usb_host_uvc/test_app/main/test_app_main.c @@ -7,17 +7,12 @@ #include #include #include "unity.h" -#include "esp_heap_caps.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" -static size_t before_free_8bit; -static size_t before_free_32bit; - -#define TEST_MEMORY_LEAK_THRESHOLD (-530) -static void check_leak(size_t before_free, size_t after_free, const char *type) +void tearDown(void) { - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); + unity_utils_evaluate_leaks(); } void app_main(void) @@ -35,23 +30,7 @@ void app_main(void) printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); printf(" \\/ \\/ \\/ \\/ \r\n"); - UNITY_BEGIN(); + unity_utils_setup_heap_record(80); + unity_utils_set_leak_level(530); unity_run_menu(); - UNITY_END(); -} - -/* setUp runs before every test */ -void setUp(void) -{ - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); -} - -/* tearDown runs after every test */ -void tearDown(void) -{ - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); } diff --git a/host/class/uvc/usb_host_uvc/test_app/pytest_usb_host_uvc.py b/host/class/uvc/usb_host_uvc/test_app/pytest_usb_host_uvc.py index 1ca9370a..bd41ad03 100644 --- a/host/class/uvc/usb_host_uvc/test_app/pytest_usb_host_uvc.py +++ b/host/class/uvc/usb_host_uvc/test_app/pytest_usb_host_uvc.py @@ -7,6 +7,7 @@ @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.usb_host def test_usb_host_uvc(dut: IdfDut) -> None: dut.run_all_single_board_cases(group='usb_uvc')