diff --git a/.build-test-rules.yml b/.build-test-rules.yml index d159ea10..fe7c53c5 100644 --- a/.build-test-rules.yml +++ b/.build-test-rules.yml @@ -1,3 +1,9 @@ -test_app: +device/esp_tinyusb: enable: - if: IDF_TARGET in ["esp32s2", "esp32s3"] + disable: + - if: IDF_VERSION < 5.0 + +host/class: + enable: + - if: IDF_TARGET in ["esp32s2", "esp32s3"] \ No newline at end of file diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 261b7b15..b2bbdfa6 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -33,11 +33,12 @@ jobs: with: name: usb_test_app_bin_${{ matrix.idf_ver }} path: | - test_app/build_esp*/bootloader/bootloader.bin - test_app/build_esp*/partition_table/partition-table.bin - test_app/build_esp*/usb_test_app.bin - test_app/build_esp*/usb_test_app.elf - test_app/build_esp*/flasher_args.json + **/test_app/build_esp*/bootloader/bootloader.bin + **/test_app/build_esp*/partition_table/partition-table.bin + **/test_app/build_esp*/test_app_usb_*.bin + **/test_app/build_esp*/test_app_usb_*.elf + **/test_app/build_esp*/flasher_args.json + if-no-files-found: error run-target: name: Run USB Test App on target diff --git a/.idf_build_apps.toml b/.idf_build_apps.toml index 0143f47e..2ad117c2 100644 --- a/.idf_build_apps.toml +++ b/.idf_build_apps.toml @@ -1,8 +1,14 @@ target = "all" -paths = "test_app" +paths = [ + "device/esp_tinyusb/test_app", + "host/class/cdc/usb_host_cdc_acm/test_app", + "host/class/hid/usb_host_hid/test_app", + "host/class/msc/usb_host_msc/test_app", + "host/class/uvc/usb_host_uvc/test_app", +] recursive = true manifest_file = ".build-test-rules.yml" check_warnings = true # build related options -build_dir = "build_@t" +build_dir = "build_@t_@w" diff --git a/device/esp_tinyusb/test_app/CMakeLists.txt b/device/esp_tinyusb/test_app/CMakeLists.txt new file mode 100644 index 00000000..9298e904 --- /dev/null +++ b/device/esp_tinyusb/test_app/CMakeLists.txt @@ -0,0 +1,11 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# Set the components to include the tests for. +set(EXTRA_COMPONENT_DIRS + ../ + ) + +project(test_app_usb_device_esp_tinyusb) diff --git a/device/esp_tinyusb/test_app/README.md b/device/esp_tinyusb/test_app/README.md new file mode 100644 index 00000000..c3b5e9e9 --- /dev/null +++ b/device/esp_tinyusb/test_app/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# USB: esp_tinyusb test application \ No newline at end of file diff --git a/device/esp_tinyusb/test/CMakeLists.txt b/device/esp_tinyusb/test_app/main/CMakeLists.txt similarity index 58% rename from device/esp_tinyusb/test/CMakeLists.txt rename to device/esp_tinyusb/test_app/main/CMakeLists.txt index 00435e85..5e19c76b 100644 --- a/device/esp_tinyusb/test/CMakeLists.txt +++ b/device/esp_tinyusb/test_app/main/CMakeLists.txt @@ -1,4 +1,6 @@ -idf_component_register(SRCS "test_esp_tinyusb.c" "test_bvalid_sig.c" +include($ENV{IDF_PATH}/tools/cmake/version.cmake) + +idf_component_register(SRCS "test_esp_tinyusb.c" "test_bvalid_sig.c" "test_app_main.c" INCLUDE_DIRS "." REQUIRES unity esp_tinyusb - ) + WHOLE_ARCHIVE) \ No newline at end of file diff --git a/test_app/main/idf_component.yml b/device/esp_tinyusb/test_app/main/idf_component.yml similarity index 57% rename from test_app/main/idf_component.yml rename to device/esp_tinyusb/test_app/main/idf_component.yml index 6ffe8fef..43ab3419 100644 --- a/test_app/main/idf_component.yml +++ b/device/esp_tinyusb/test_app/main/idf_component.yml @@ -2,6 +2,6 @@ dependencies: espressif/esp_tinyusb: version: "*" - override_path: "../../device/esp_tinyusb" + override_path: "../../" rules: - - if: "idf_version >= 5.0" + - if: "idf_version >= 5.0" \ No newline at end of file diff --git a/test_app/main/usb_test_main.c b/device/esp_tinyusb/test_app/main/test_app_main.c similarity index 54% rename from test_app/main/usb_test_main.c rename to device/esp_tinyusb/test_app/main/test_app_main.c index fa97a8b7..b25c8df7 100644 --- a/test_app/main/usb_test_main.c +++ b/device/esp_tinyusb/test_app/main/test_app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,19 @@ static void check_leak(size_t before_free, size_t after_free, const char *type) void app_main(void) { + // ____ ___ ___________________ __ __ + // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ + // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. + // | | / / \ | | \ | | \ ___/ \___ \ | | + // |______/ /_______ / |______ / |__| \___ >____ > |__| + // \/ \/ \/ \/ + printf(" ____ ___ ___________________ __ __ \r\n"); + printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); + printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); + printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); + printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); + printf(" \\/ \\/ \\/ \\/ \r\n"); + UNITY_BEGIN(); unity_run_menu(); UNITY_END(); diff --git a/device/esp_tinyusb/test/test_bvalid_sig.c b/device/esp_tinyusb/test_app/main/test_bvalid_sig.c similarity index 97% rename from device/esp_tinyusb/test/test_bvalid_sig.c rename to device/esp_tinyusb/test_app/main/test_bvalid_sig.c index e1d8757b..ad74c52d 100644 --- a/device/esp_tinyusb/test/test_bvalid_sig.c +++ b/device/esp_tinyusb/test_app/main/test_bvalid_sig.c @@ -20,7 +20,6 @@ #include "soc/gpio_sig_map.h" #include "unity.h" #include "tinyusb.h" -#include "class/msc/msc_device.h" #define DEVICE_DETACH_TEST_ROUNDS 10 #define DEVICE_DETACH_ROUND_DELAY_MS 1000 @@ -66,7 +65,7 @@ void tud_umount_cb(void) dev_umounted++; } -TEST_CASE("bvalid_signal", "[esp_tinyusb]") +TEST_CASE("bvalid_signal", "[esp_tinyusb][usb_device]") { unsigned int rounds = DEVICE_DETACH_TEST_ROUNDS; diff --git a/device/esp_tinyusb/test/test_esp_tinyusb.c b/device/esp_tinyusb/test_app/main/test_esp_tinyusb.c similarity index 95% rename from device/esp_tinyusb/test/test_esp_tinyusb.c rename to device/esp_tinyusb/test_app/main/test_esp_tinyusb.c index de8a7ea6..b71d4870 100644 --- a/device/esp_tinyusb/test/test_esp_tinyusb.c +++ b/device/esp_tinyusb/test_app/main/test_esp_tinyusb.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,9 @@ #define VFS_PATH "/dev/usb-cdc1" +// idf_component_register(WHOLE_ARCHIVE) backward compatibility to IDF_v4.4 +void linker_hook(void) {}; + static const tusb_desc_device_t cdc_device_descriptor = { .bLength = sizeof(cdc_device_descriptor), .bDescriptorType = TUSB_DESC_DEVICE, diff --git a/test_app/pytest_usb_device.py b/device/esp_tinyusb/test_app/pytest_usb_device_cdc.py similarity index 94% rename from test_app/pytest_usb_device.py rename to device/esp_tinyusb/test_app/pytest_usb_device_cdc.py index 0ae37967..1b48438a 100644 --- a/test_app/pytest_usb_device.py +++ b/device/esp_tinyusb/test_app/pytest_usb_device_cdc.py @@ -1,8 +1,6 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 -from typing import Tuple - import pytest from pytest_embedded_idf.dut import IdfDut from time import sleep @@ -13,7 +11,7 @@ @pytest.mark.esp32s2 @pytest.mark.esp32s3 @pytest.mark.usb_device -def test_usb_device(dut) -> None: +def test_usb_device_cdc(dut) -> None: ''' Running the test locally: 1. Build the testa app for your DUT (ESP32-S2 or S3) 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 new file mode 100644 index 00000000..78765bcb --- /dev/null +++ b/device/esp_tinyusb/test_app/pytest_usb_device_esp_tinyusb.py @@ -0,0 +1,12 @@ +# 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 new file mode 100644 index 00000000..e68b6cd8 --- /dev/null +++ b/device/esp_tinyusb/test_app/sdkconfig.defaults @@ -0,0 +1,19 @@ +# Configure TinyUSB, it will be used to mock USB devices +CONFIG_TINYUSB=y +CONFIG_TINYUSB_MSC_ENABLED=n +CONFIG_TINYUSB_CDC_ENABLED=y +CONFIG_TINYUSB_CDC_COUNT=2 +CONFIG_TINYUSB_HID_COUNT=0 + +# Disable watchdogs, they'd get triggered during unity interactive menu +CONFIG_ESP_INT_WDT=n +CONFIG_ESP_TASK_WDT=n + +# Run-time checks of Heap and Stack +CONFIG_HEAP_POISONING_COMPREHENSIVE=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_STACK_CHECK=y + +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y + +CONFIG_COMPILER_CXX_EXCEPTIONS=y diff --git a/host/class/cdc/usb_host_cdc_acm/test/CMakeLists.txt b/host/class/cdc/usb_host_cdc_acm/test/CMakeLists.txt deleted file mode 100644 index 97c08f86..00000000 --- a/host/class/cdc/usb_host_cdc_acm/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -include($ENV{IDF_PATH}/tools/cmake/version.cmake) -set (TINYUSB_LIB) -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") - set(TINYUSB_LIB "esp_tinyusb") -else() - set(TINYUSB_LIB "tinyusb") -endif() -idf_component_register(SRCS "test_cdc_acm_host.c" "usb_device.c" - INCLUDE_DIRS "." - REQUIRES usb_host_cdc_acm unity ${TINYUSB_LIB}) diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/CMakeLists.txt b/host/class/cdc/usb_host_cdc_acm/test_app/CMakeLists.txt new file mode 100644 index 00000000..d5810946 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/CMakeLists.txt @@ -0,0 +1,20 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + ../../esp_modem_usb_dte + ../../usb_host_cdc_acm + ../../usb_host_ch34x_vcp + ../../usb_host_cp210x_vcp + ../../usb_host_ftdi_vcp + ../../usb_host_vcp + ) + +# Set the components to include the tests for. +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + list(APPEND EXTRA_COMPONENT_DIRS ../../../../../device/esp_tinyusb) +endif() + +project(test_app_usb_host_cdc) \ No newline at end of file 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 new file mode 100644 index 00000000..cc35c024 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/README.md @@ -0,0 +1,15 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# 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. + +### 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 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 new file mode 100644 index 00000000..24599850 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/CMakeLists.txt @@ -0,0 +1,23 @@ +include($ENV{IDF_PATH}/tools/cmake/version.cmake) +set (TINYUSB_LIB) +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + set(TINYUSB_LIB "esp_tinyusb") +else() + set(TINYUSB_LIB "tinyusb") +endif() + +# TODO: once IDF_v4.4 is at the EOL support, use WHOLE_ARCHIVE +idf_component_register(SRCS "test_cdc_acm_host.c" "usb_device.c" "test_app_main.c" + INCLUDE_DIRS "." + REQUIRES usb_host_cdc_acm unity ${TINYUSB_LIB}) + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE + +# Due to the backward compatibility to IDFv4.4 (in which WHOLE_ARCHIVE is not implemented) we use following approach: +# Any non-static function test_app/main/*.c (apart from test_app_main.c) file is added as an undefined symbol +# because otherwise the linker will ignore test_app/main/*.c as it has no other files depending on any +# symbols in it. + +# force-link test_cdc_acm_host.c +set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u usb_lib_task") \ No newline at end of file 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 new file mode 100644 index 00000000..b25c8df7 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/main/test_app_main.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "esp_heap_caps.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) +{ + 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"); +} + +void app_main(void) +{ + // ____ ___ ___________________ __ __ + // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ + // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. + // | | / / \ | | \ | | \ ___/ \___ \ | | + // |______/ /_______ / |______ / |__| \___ >____ > |__| + // \/ \/ \/ \/ + printf(" ____ ___ ___________________ __ __ \r\n"); + printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); + printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); + printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); + printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); + printf(" \\/ \\/ \\/ \\/ \r\n"); + + UNITY_BEGIN(); + 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/test_cdc_acm_host.c b/host/class/cdc/usb_host_cdc_acm/test_app/main/test_cdc_acm_host.c similarity index 100% rename from host/class/cdc/usb_host_cdc_acm/test/test_cdc_acm_host.c rename to host/class/cdc/usb_host_cdc_acm/test_app/main/test_cdc_acm_host.c diff --git a/host/class/cdc/usb_host_cdc_acm/test/usb_device.c b/host/class/cdc/usb_host_cdc_acm/test_app/main/usb_device.c similarity index 100% rename from host/class/cdc/usb_host_cdc_acm/test/usb_device.c rename to host/class/cdc/usb_host_cdc_acm/test_app/main/usb_device.c 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 new file mode 100644 index 00000000..b34aecb1 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/pytest_usb_host_cdc.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +from typing import Tuple + +import pytest +from pytest_embedded_idf.dut import IdfDut + + +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.usb_host +@pytest.mark.parametrize('count', [ + 2, +], indirect=True) +def test_usb_host(dut: Tuple[IdfDut, IdfDut]) -> None: + device = dut[0] + host = dut[1] + + # 1.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') diff --git a/host/class/cdc/usb_host_cdc_acm/test_app/sdkconfig.defaults b/host/class/cdc/usb_host_cdc_acm/test_app/sdkconfig.defaults new file mode 100644 index 00000000..e68b6cd8 --- /dev/null +++ b/host/class/cdc/usb_host_cdc_acm/test_app/sdkconfig.defaults @@ -0,0 +1,19 @@ +# Configure TinyUSB, it will be used to mock USB devices +CONFIG_TINYUSB=y +CONFIG_TINYUSB_MSC_ENABLED=n +CONFIG_TINYUSB_CDC_ENABLED=y +CONFIG_TINYUSB_CDC_COUNT=2 +CONFIG_TINYUSB_HID_COUNT=0 + +# Disable watchdogs, they'd get triggered during unity interactive menu +CONFIG_ESP_INT_WDT=n +CONFIG_ESP_TASK_WDT=n + +# Run-time checks of Heap and Stack +CONFIG_HEAP_POISONING_COMPREHENSIVE=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_STACK_CHECK=y + +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y + +CONFIG_COMPILER_CXX_EXCEPTIONS=y diff --git a/host/class/hid/usb_host_hid/test/CMakeLists.txt b/host/class/hid/usb_host_hid/test/CMakeLists.txt deleted file mode 100644 index 77b8b7d8..00000000 --- a/host/class/hid/usb_host_hid/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -include($ENV{IDF_PATH}/tools/cmake/version.cmake) -set (TINYUSB_LIB) -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") - set(TINYUSB_LIB "esp_tinyusb") -else() - set(TINYUSB_LIB "tinyusb") -endif() -idf_component_register(SRC_DIRS . - INCLUDE_DIRS . - REQUIRES unity usb usb_host_hid ${TINYUSB_LIB}) diff --git a/host/class/hid/usb_host_hid/test_app/CMakeLists.txt b/host/class/hid/usb_host_hid/test_app/CMakeLists.txt new file mode 100644 index 00000000..edac8918 --- /dev/null +++ b/host/class/hid/usb_host_hid/test_app/CMakeLists.txt @@ -0,0 +1,15 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + ../../usb_host_hid + ) + +# Set the components to include the tests for. +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + list(APPEND EXTRA_COMPONENT_DIRS ../../../../../device/esp_tinyusb) +endif() + +project(test_app_usb_host_hid) \ No newline at end of file diff --git a/host/class/hid/usb_host_hid/test_app/README.md b/host/class/hid/usb_host_hid/test_app/README.md new file mode 100644 index 00000000..a87b4dca --- /dev/null +++ b/host/class/hid/usb_host_hid/test_app/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# USB: HID Class test application \ No newline at end of file diff --git a/host/class/hid/usb_host_hid/test_app/main/CMakeLists.txt b/host/class/hid/usb_host_hid/test_app/main/CMakeLists.txt new file mode 100644 index 00000000..00e10eca --- /dev/null +++ b/host/class/hid/usb_host_hid/test_app/main/CMakeLists.txt @@ -0,0 +1,25 @@ +include($ENV{IDF_PATH}/tools/cmake/version.cmake) +set (TINYUSB_LIB) +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + set(TINYUSB_LIB "esp_tinyusb") +else() + set(TINYUSB_LIB "tinyusb") +endif() + +# TODO: once IDF_v4.4 is at the EOL support, use WHOLE_ARCHIVE +idf_component_register(SRC_DIRS . + INCLUDE_DIRS . + REQUIRES unity usb usb_host_hid ${TINYUSB_LIB}) + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE + +# Due to the backward compatibility to IDFv4.4 (in which WHOLE_ARCHIVE is not implemented) we use following approach: +# Any non-static function test_app/main/*.c (apart from test_app_main.c) file is added as an undefined symbol +# because otherwise the linker will ignore test_app/main/*.c as it has no other files depending on any +# symbols in it. + +# force-link test_hid_basic.c +set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u test_hid_setup") +# force-link test_hid_err_handling.c +set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u test_interface_callback_handler") diff --git a/host/class/hid/usb_host_hid/test/hid_mock_device.c b/host/class/hid/usb_host_hid/test_app/main/hid_mock_device.c similarity index 100% rename from host/class/hid/usb_host_hid/test/hid_mock_device.c rename to host/class/hid/usb_host_hid/test_app/main/hid_mock_device.c diff --git a/host/class/hid/usb_host_hid/test/hid_mock_device.h b/host/class/hid/usb_host_hid/test_app/main/hid_mock_device.h similarity index 100% rename from host/class/hid/usb_host_hid/test/hid_mock_device.h rename to host/class/hid/usb_host_hid/test_app/main/hid_mock_device.h 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 new file mode 100644 index 00000000..b25c8df7 --- /dev/null +++ b/host/class/hid/usb_host_hid/test_app/main/test_app_main.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "esp_heap_caps.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) +{ + 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"); +} + +void app_main(void) +{ + // ____ ___ ___________________ __ __ + // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ + // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. + // | | / / \ | | \ | | \ ___/ \___ \ | | + // |______/ /_______ / |______ / |__| \___ >____ > |__| + // \/ \/ \/ \/ + printf(" ____ ___ ___________________ __ __ \r\n"); + printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); + printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); + printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); + printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); + printf(" \\/ \\/ \\/ \\/ \r\n"); + + UNITY_BEGIN(); + 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/test_hid_basic.c b/host/class/hid/usb_host_hid/test_app/main/test_hid_basic.c similarity index 100% rename from host/class/hid/usb_host_hid/test/test_hid_basic.c rename to host/class/hid/usb_host_hid/test_app/main/test_hid_basic.c diff --git a/host/class/hid/usb_host_hid/test/test_hid_basic.h b/host/class/hid/usb_host_hid/test_app/main/test_hid_basic.h similarity index 100% rename from host/class/hid/usb_host_hid/test/test_hid_basic.h rename to host/class/hid/usb_host_hid/test_app/main/test_hid_basic.h diff --git a/host/class/hid/usb_host_hid/test/test_hid_err_handling.c b/host/class/hid/usb_host_hid/test_app/main/test_hid_err_handling.c similarity index 100% rename from host/class/hid/usb_host_hid/test/test_hid_err_handling.c rename to host/class/hid/usb_host_hid/test_app/main/test_hid_err_handling.c diff --git a/test_app/pytest_usb_host.py b/host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py similarity index 58% rename from test_app/pytest_usb_host.py rename to host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py index e5ec922f..c4b26d85 100644 --- a/test_app/pytest_usb_host.py +++ b/host/class/hid/usb_host_hid/test_app/pytest_usb_host_hid.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 from typing import Tuple @@ -13,29 +13,11 @@ @pytest.mark.parametrize('count', [ 2, ], indirect=True) -def test_usb_host(dut: Tuple[IdfDut, IdfDut]) -> None: +def test_usb_host_hid(dut: Tuple[IdfDut, IdfDut]) -> None: device = dut[0] host = dut[1] - # 1.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.1 Prepare USB device for MSC test - device.serial.hard_reset() - 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 - host.run_all_single_board_cases(group='usb_msc') - # 3.1 Prepare USB device with one Interface for HID tests - device.serial.hard_reset() 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') diff --git a/host/class/hid/usb_host_hid/test_app/sdkconfig.defaults b/host/class/hid/usb_host_hid/test_app/sdkconfig.defaults new file mode 100644 index 00000000..7d7d1ce3 --- /dev/null +++ b/host/class/hid/usb_host_hid/test_app/sdkconfig.defaults @@ -0,0 +1,19 @@ +# Configure TinyUSB, it will be used to mock USB devices +CONFIG_TINYUSB=y +CONFIG_TINYUSB_MSC_ENABLED=n +CONFIG_TINYUSB_CDC_ENABLED=n +CONFIG_TINYUSB_CDC_COUNT=0 +CONFIG_TINYUSB_HID_COUNT=2 + +# Disable watchdogs, they'd get triggered during unity interactive menu +CONFIG_ESP_INT_WDT=n +CONFIG_ESP_TASK_WDT=n + +# Run-time checks of Heap and Stack +CONFIG_HEAP_POISONING_COMPREHENSIVE=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_STACK_CHECK=y + +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y + +CONFIG_COMPILER_CXX_EXCEPTIONS=y diff --git a/host/class/msc/usb_host_msc/test/CMakeLists.txt b/host/class/msc/usb_host_msc/test/CMakeLists.txt deleted file mode 100644 index 8225c985..00000000 --- a/host/class/msc/usb_host_msc/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -include($ENV{IDF_PATH}/tools/cmake/version.cmake) -set (TINYUSB_LIB) -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") - set(TINYUSB_LIB "esp_tinyusb") -else() - set(TINYUSB_LIB "tinyusb") -endif() -idf_component_register(SRC_DIRS . - INCLUDE_DIRS . - REQUIRES unity usb usb_host_msc ${TINYUSB_LIB}) diff --git a/host/class/msc/usb_host_msc/test_app/CMakeLists.txt b/host/class/msc/usb_host_msc/test_app/CMakeLists.txt new file mode 100644 index 00000000..4709cf4e --- /dev/null +++ b/host/class/msc/usb_host_msc/test_app/CMakeLists.txt @@ -0,0 +1,15 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + ../../usb_host_msc + ) + +# Set the components to include the tests for. +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + list(APPEND EXTRA_COMPONENT_DIRS ../../../../../device/esp_tinyusb) +endif() + +project(test_app_usb_host_msc) \ No newline at end of file diff --git a/host/class/msc/usb_host_msc/test_app/README.md b/host/class/msc/usb_host_msc/test_app/README.md new file mode 100644 index 00000000..7384992b --- /dev/null +++ b/host/class/msc/usb_host_msc/test_app/README.md @@ -0,0 +1,14 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# USB: CDC Class test application + +## MSC driver + +Basic functionality such as MSC device install/uninstall, file operations, +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, +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/CMakeLists.txt b/host/class/msc/usb_host_msc/test_app/main/CMakeLists.txt new file mode 100644 index 00000000..e1d5d55a --- /dev/null +++ b/host/class/msc/usb_host_msc/test_app/main/CMakeLists.txt @@ -0,0 +1,24 @@ +include($ENV{IDF_PATH}/tools/cmake/version.cmake) +set (TINYUSB_LIB) +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + set(TINYUSB_LIB "esp_tinyusb") +else() + set(TINYUSB_LIB "tinyusb") +endif() + +# TODO: once IDF_v4.4 is at the EOL support, use WHOLE_ARCHIVE +idf_component_register(SRC_DIRS . + INCLUDE_DIRS . + REQUIRES unity usb usb_host_msc ${TINYUSB_LIB}) + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE + +# Due to the backward compatibility to IDFv4.4 (in which WHOLE_ARCHIVE is not implemented) we use following approach: +# Any non-static function test_app/main/*.c (apart from test_app_main.c) file is added as an undefined symbol +# because otherwise the linker will ignore test_app/main/*.c as it has no other files depending on any +# symbols in it. + +# force-link test_msc.c - void function linker_hook created because: +# no non-static function +set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u linker_hook") \ No newline at end of file diff --git a/host/class/msc/usb_host_msc/test/msc_device.c b/host/class/msc/usb_host_msc/test_app/main/msc_device.c similarity index 100% rename from host/class/msc/usb_host_msc/test/msc_device.c rename to host/class/msc/usb_host_msc/test_app/main/msc_device.c 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 new file mode 100644 index 00000000..b25c8df7 --- /dev/null +++ b/host/class/msc/usb_host_msc/test_app/main/test_app_main.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "esp_heap_caps.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) +{ + 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"); +} + +void app_main(void) +{ + // ____ ___ ___________________ __ __ + // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ + // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. + // | | / / \ | | \ | | \ ___/ \___ \ | | + // |______/ /_______ / |______ / |__| \___ >____ > |__| + // \/ \/ \/ \/ + printf(" ____ ___ ___________________ __ __ \r\n"); + printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); + printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); + printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); + printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); + printf(" \\/ \\/ \\/ \\/ \r\n"); + + UNITY_BEGIN(); + 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/test_common.h b/host/class/msc/usb_host_msc/test_app/main/test_common.h similarity index 100% rename from host/class/msc/usb_host_msc/test/test_common.h rename to host/class/msc/usb_host_msc/test_app/main/test_common.h diff --git a/host/class/msc/usb_host_msc/test/test_msc.c b/host/class/msc/usb_host_msc/test_app/main/test_msc.c similarity index 98% rename from host/class/msc/usb_host_msc/test/test_msc.c rename to host/class/msc/usb_host_msc/test_app/main/test_msc.c index bdf4048f..05f03f6e 100644 --- a/host/class/msc/usb_host_msc/test/test_msc.c +++ b/host/class/msc/usb_host_msc/test_app/main/test_msc.c @@ -1,6 +1,6 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,9 @@ #if SOC_USB_OTG_SUPPORTED +// idf_component_register(WHOLE_ARCHIVE) backward compatibility to IDF_v4.4 +void linker_hook(void) {}; + static const char *TAG = "APP"; #define ESP_OK_ASSERT(exp) TEST_ASSERT_EQUAL(ESP_OK, exp) diff --git a/test_app/partitions.csv b/host/class/msc/usb_host_msc/test_app/partitions.csv similarity index 100% rename from test_app/partitions.csv rename to host/class/msc/usb_host_msc/test_app/partitions.csv 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 new file mode 100644 index 00000000..3101b930 --- /dev/null +++ b/host/class/msc/usb_host_msc/test_app/pytest_usb_host_msc.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +from typing import Tuple + +import pytest +from pytest_embedded_idf.dut import IdfDut + + +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.usb_host +@pytest.mark.parametrize('count', [ + 2, +], indirect=True) +def test_usb_host_msc(dut: Tuple[IdfDut, IdfDut]) -> None: + device = dut[0] + host = dut[1] + + # 2.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 + host.run_all_single_board_cases(group='usb_msc') diff --git a/test_app/sdkconfig.defaults b/host/class/msc/usb_host_msc/test_app/sdkconfig.defaults similarity index 89% rename from test_app/sdkconfig.defaults rename to host/class/msc/usb_host_msc/test_app/sdkconfig.defaults index 96b2884d..37560ed4 100644 --- a/test_app/sdkconfig.defaults +++ b/host/class/msc/usb_host_msc/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=y -CONFIG_TINYUSB_CDC_ENABLED=y -CONFIG_TINYUSB_CDC_COUNT=2 -CONFIG_TINYUSB_HID_COUNT=2 +CONFIG_TINYUSB_CDC_ENABLED=n +CONFIG_TINYUSB_CDC_COUNT=0 +CONFIG_TINYUSB_HID_COUNT=0 # Disable watchdogs, they'd get triggered during unity interactive menu CONFIG_ESP_INT_WDT=n diff --git a/host/class/uvc/usb_host_uvc/test/CMakeLists.txt b/host/class/uvc/usb_host_uvc/test/CMakeLists.txt deleted file mode 100644 index aeceff91..00000000 --- a/host/class/uvc/usb_host_uvc/test/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "test_uvc.c" "libusb_parse.c" - INCLUDE_DIRS "." "../private_include" - REQUIRES usb_host_uvc usb unity) diff --git a/host/class/uvc/usb_host_uvc/test_app/CMakeLists.txt b/host/class/uvc/usb_host_uvc/test_app/CMakeLists.txt new file mode 100644 index 00000000..0385323d --- /dev/null +++ b/host/class/uvc/usb_host_uvc/test_app/CMakeLists.txt @@ -0,0 +1,15 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + ../../usb_host_uvc + ) + +# Set the components to include the tests for. +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + list(APPEND EXTRA_COMPONENT_DIRS ../../../../../device/esp_tinyusb) +endif() + +project(test_app_usb_host_uvc) \ No newline at end of file diff --git a/host/class/uvc/usb_host_uvc/test_app/README.md b/host/class/uvc/usb_host_uvc/test_app/README.md new file mode 100644 index 00000000..b693d60c --- /dev/null +++ b/host/class/uvc/usb_host_uvc/test_app/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# USB: UVC Class test application \ No newline at end of file diff --git a/host/class/uvc/usb_host_uvc/test_app/main/CMakeLists.txt b/host/class/uvc/usb_host_uvc/test_app/main/CMakeLists.txt new file mode 100644 index 00000000..bf85849f --- /dev/null +++ b/host/class/uvc/usb_host_uvc/test_app/main/CMakeLists.txt @@ -0,0 +1,24 @@ +include($ENV{IDF_PATH}/tools/cmake/version.cmake) +set (TINYUSB_LIB) +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + set(TINYUSB_LIB "esp_tinyusb") +else() + set(TINYUSB_LIB "tinyusb") +endif() + +# TODO: once IDF_v4.4 is at the EOL support, use WHOLE_ARCHIVE +idf_component_register(SRCS "test_uvc.c" "libusb_parse.c" "test_app_main.c" + INCLUDE_DIRS "." "../../private_include" + REQUIRES usb_host_uvc usb unity) + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE + +# Due to the backward compatibility to IDFv4.4 (in which WHOLE_ARCHIVE is not implemented) we use following approach: +# Any non-static function from test_app/main/*.c (apart from test_app_main.c) file is added as an undefined symbol +# because otherwise the linker will ignore test_app/main/*.c as it has no other files depending on any +# symbols in it. + +# force-link test_uvc.c - void function linker_hook created because: +# no non-static function +set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u linker_hook") diff --git a/host/class/uvc/usb_host_uvc/test/libusb_parse.c b/host/class/uvc/usb_host_uvc/test_app/main/libusb_parse.c similarity index 100% rename from host/class/uvc/usb_host_uvc/test/libusb_parse.c rename to host/class/uvc/usb_host_uvc/test_app/main/libusb_parse.c 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 new file mode 100644 index 00000000..b25c8df7 --- /dev/null +++ b/host/class/uvc/usb_host_uvc/test_app/main/test_app_main.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "esp_heap_caps.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) +{ + 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"); +} + +void app_main(void) +{ + // ____ ___ ___________________ __ __ + // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ + // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. + // | | / / \ | | \ | | \ ___/ \___ \ | | + // |______/ /_______ / |______ / |__| \___ >____ > |__| + // \/ \/ \/ \/ + printf(" ____ ___ ___________________ __ __ \r\n"); + printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); + printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); + printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); + printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); + printf(" \\/ \\/ \\/ \\/ \r\n"); + + UNITY_BEGIN(); + 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/test_uvc.c b/host/class/uvc/usb_host_uvc/test_app/main/test_uvc.c similarity index 98% rename from host/class/uvc/usb_host_uvc/test/test_uvc.c rename to host/class/uvc/usb_host_uvc/test_app/main/test_uvc.c index c8f4ccbe..fac6b014 100644 --- a/host/class/uvc/usb_host_uvc/test/test_uvc.c +++ b/host/class/uvc/usb_host_uvc/test_app/main/test_uvc.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 */ @@ -28,6 +28,9 @@ int libusb_parse_configuration(struct libusb_config_descriptor *config, const uint8_t *buffer, int size); void libusb_clear_config_descriptor(struct libusb_config_descriptor *config); +// idf_component_register(WHOLE_ARCHIVE) backward compatibility to IDF_v4.4 +void linker_hook(void) {}; + const uint8_t CANYON_CNE_CWC2[] = { 0x09, 0x02, 0x7d, 0x02, 0x04, 0x01, 0x00, 0x80, 0xfa, 0x08, 0x0b, 0x00, 0x02, 0x0e, 0x03, 0x00, 0x05, 0x09, 0x04, 0x00, 0x00, 0x01, 0x0e, 0x01, 0x00, 0x05, 0x0d, 0x24, 0x01, 0x00, 0x01, 0x4d, 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 new file mode 100644 index 00000000..1ca9370a --- /dev/null +++ b/host/class/uvc/usb_host_uvc/test_app/pytest_usb_host_uvc.py @@ -0,0 +1,12 @@ +# 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_host +def test_usb_host_uvc(dut: IdfDut) -> None: + dut.run_all_single_board_cases(group='usb_uvc') diff --git a/host/class/uvc/usb_host_uvc/test_app/sdkconfig.defaults b/host/class/uvc/usb_host_uvc/test_app/sdkconfig.defaults new file mode 100644 index 00000000..eb1b362c --- /dev/null +++ b/host/class/uvc/usb_host_uvc/test_app/sdkconfig.defaults @@ -0,0 +1,19 @@ +# Configure TinyUSB, it will be used to mock USB devices +CONFIG_TINYUSB=y +CONFIG_TINYUSB_MSC_ENABLED=n +CONFIG_TINYUSB_CDC_ENABLED=n +CONFIG_TINYUSB_CDC_COUNT=0 +CONFIG_TINYUSB_HID_COUNT=0 + +# Disable watchdogs, they'd get triggered during unity interactive menu +CONFIG_ESP_INT_WDT=n +CONFIG_ESP_TASK_WDT=n + +# Run-time checks of Heap and Stack +CONFIG_HEAP_POISONING_COMPREHENSIVE=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_STACK_CHECK=y + +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y + +CONFIG_COMPILER_CXX_EXCEPTIONS=y diff --git a/test_app/CMakeLists.txt b/test_app/CMakeLists.txt deleted file mode 100644 index 07cf44af..00000000 --- a/test_app/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# The following lines of boilerplate have to be in your project's -# CMakeLists in this exact order for cmake to work correctly -cmake_minimum_required(VERSION 3.16) -include($ENV{IDF_PATH}/tools/cmake/version.cmake) - -set(EXTRA_COMPONENT_DIRS - ../host/class/cdc/esp_modem_usb_dte - ../host/class/cdc/usb_host_cdc_acm - ../host/class/cdc/usb_host_ch34x_vcp - ../host/class/cdc/usb_host_cp210x_vcp - ../host/class/cdc/usb_host_ftdi_vcp - ../host/class/cdc/usb_host_vcp - ../host/class/hid/usb_host_hid - ../host/class/msc/usb_host_msc - ../host/class/uvc/usb_host_uvc - ) - -# Set the components to include the tests for. -set(TEST_COMPONENTS "usb_host_cdc_acm" "usb_host_msc" "usb_host_uvc" "usb_host_hid" CACHE STRING "List of components to test") -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") - list(APPEND EXTRA_COMPONENT_DIRS ../device/esp_tinyusb) - list(APPEND TEST_COMPONENTS "esp_tinyusb") -endif() - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(usb_test_app) diff --git a/test_app/README.md b/test_app/README.md deleted file mode 100644 index 968aaf5c..00000000 --- a/test_app/README.md +++ /dev/null @@ -1,26 +0,0 @@ -| Supported Targets | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | - -# USB Host Class driver test project -Main purpose of this application is to test the USB Host Class drivers. - -## 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. - -### Hardware Required - -This test expects that TinyUSB dual CDC device with VID = 0x303A and PID = 0x4002 -is connected to the USB host. - -## MSC driver - -Basic functionality such as MSC device install/uninstall, file operations, -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, -one acting as host running MSC host driver and another MSC device driver (tinyusb). diff --git a/test_app/main/CMakeLists.txt b/test_app/main/CMakeLists.txt deleted file mode 100644 index b25d15fa..00000000 --- a/test_app/main/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "usb_test_main.c" - INCLUDE_DIRS "" - REQUIRES unity driver usb)