From a1832e018a10e95dbe052d93893afc19a9146d1e Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Tue, 11 Jun 2024 13:10:37 +0200 Subject: [PATCH 01/13] feature(esp_tinyusb): Added tusb_teardown() call --- device/esp_tinyusb/include/tinyusb.h | 10 ++++++++++ .../cdc_and_usb_device/main/test_bvalid_sig.c | 1 - .../main/test_descriptors_config.c | 6 ------ device/esp_tinyusb/tinyusb.c | 19 +++++++++++++++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/device/esp_tinyusb/include/tinyusb.h b/device/esp_tinyusb/include/tinyusb.h index 484c86e6..887c63f6 100644 --- a/device/esp_tinyusb/include/tinyusb.h +++ b/device/esp_tinyusb/include/tinyusb.h @@ -68,6 +68,16 @@ typedef struct { */ esp_err_t tinyusb_driver_install(const tinyusb_config_t *config); +/** + * @brief This is an all-in-one helper function, including: + * 1. Stops the task to handle usb events + * 2. TinyUSB stack tearing down + * 2. Freeing resources after descriptors preparation + * 3. Deletes USB PHY + * + * @retval ESP_FAIL Uninstall driver or tinyusb stack failed because of internal error + * @retval ESP_OK Uninstall driver, tinyusb stack and USB PHY successfully + */ esp_err_t tinyusb_driver_uninstall(void); #ifdef __cplusplus diff --git a/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_bvalid_sig.c b/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_bvalid_sig.c index 1bf865ad..9bce3811 100644 --- a/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_bvalid_sig.c +++ b/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_bvalid_sig.c @@ -121,6 +121,5 @@ TEST_CASE("bvalid_signal", "[esp_tinyusb][usb_device]") // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); } #endif // SOC_USB_OTG_SUPPORTED diff --git a/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_descriptors_config.c b/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_descriptors_config.c index a7c74bd0..673761d8 100644 --- a/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_descriptors_config.c +++ b/device/esp_tinyusb/test_apps/cdc_and_usb_device/main/test_descriptors_config.c @@ -140,7 +140,6 @@ TEST_CASE("descriptors_config_all_default", "[esp_tinyusb][usb_device]") TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); __test_free(); } @@ -163,7 +162,6 @@ TEST_CASE("descriptors_config_device", "[esp_tinyusb][usb_device]") TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); __test_free(); } @@ -186,7 +184,6 @@ TEST_CASE("descriptors_config_device_and_config", "[esp_tinyusb][usb_device]") TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); __test_free(); } @@ -208,7 +205,6 @@ TEST_CASE("descriptors_config_device_and_fs_config_only", "[esp_tinyusb][usb_dev TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); __test_free(); } @@ -229,7 +225,6 @@ TEST_CASE("descriptors_config_device_and_hs_config_only", "[esp_tinyusb][usb_dev TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); __test_free(); } @@ -250,7 +245,6 @@ TEST_CASE("descriptors_config_all_configured", "[esp_tinyusb][usb_device]") TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn()); // Cleanup TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); - TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task()); __test_free(); } #endif // TUD_OPT_HIGH_SPEED diff --git a/device/esp_tinyusb/tinyusb.c b/device/esp_tinyusb/tinyusb.c index 52bc2aeb..2315ab50 100644 --- a/device/esp_tinyusb/tinyusb.c +++ b/device/esp_tinyusb/tinyusb.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,11 @@ const static char *TAG = "TinyUSB"; static usb_phy_handle_t phy_hdl; +// For the tinyusb component without tusb_teardown() implementation +#ifndef tusb_teardown +# define tusb_teardown() (true) +#endif // tusb_teardown + esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) { ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Config can't be NULL"); @@ -66,8 +71,18 @@ esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) return ESP_OK; } -esp_err_t tinyusb_driver_uninstall() +esp_err_t tinyusb_driver_uninstall(void) { + esp_err_t ret = tusb_stop_task(); + + if (ret != ESP_OK) { + return ret; + } + + if (!tusb_teardown()) { + return ESP_ERR_NOT_FINISHED; + } + tinyusb_free_descriptors(); return usb_del_phy(phy_hdl); } From d302232f24d2e5063f7643cec4b51413ba7c2ac1 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 13 Dec 2024 12:40:17 +0100 Subject: [PATCH 02/13] feature(teardown_test): Added the test_app for teardowning the cdc device --- .../test_apps/teardown_device/CMakeLists.txt | 9 ++ .../teardown_device/main/CMakeLists.txt | 4 + .../teardown_device/main/idf_component.yml | 5 + .../teardown_device/main/test_app_main.c | 62 ++++++++ .../teardown_device/main/test_teardown.c | 138 ++++++++++++++++++ .../teardown_device/pytest_teardown_device.py | 47 ++++++ .../teardown_device/sdkconfig.defaults | 16 ++ 7 files changed, 281 insertions(+) create mode 100644 device/esp_tinyusb/test_apps/teardown_device/CMakeLists.txt create mode 100644 device/esp_tinyusb/test_apps/teardown_device/main/CMakeLists.txt create mode 100644 device/esp_tinyusb/test_apps/teardown_device/main/idf_component.yml create mode 100644 device/esp_tinyusb/test_apps/teardown_device/main/test_app_main.c create mode 100644 device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c create mode 100644 device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py create mode 100644 device/esp_tinyusb/test_apps/teardown_device/sdkconfig.defaults diff --git a/device/esp_tinyusb/test_apps/teardown_device/CMakeLists.txt b/device/esp_tinyusb/test_apps/teardown_device/CMakeLists.txt new file mode 100644 index 00000000..d63d14ee --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/CMakeLists.txt @@ -0,0 +1,9 @@ +# 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) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +project(test_app_teardown_device) diff --git a/device/esp_tinyusb/test_apps/teardown_device/main/CMakeLists.txt b/device/esp_tinyusb/test_apps/teardown_device/main/CMakeLists.txt new file mode 100644 index 00000000..e81e6278 --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRC_DIRS . + INCLUDE_DIRS . + REQUIRES unity + WHOLE_ARCHIVE) diff --git a/device/esp_tinyusb/test_apps/teardown_device/main/idf_component.yml b/device/esp_tinyusb/test_apps/teardown_device/main/idf_component.yml new file mode 100644 index 00000000..b1cb5b54 --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/main/idf_component.yml @@ -0,0 +1,5 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/esp_tinyusb: + version: "*" + override_path: "../../../" diff --git a/device/esp_tinyusb/test_apps/teardown_device/main/test_app_main.c b/device/esp_tinyusb/test_apps/teardown_device/main/test_app_main.c new file mode 100644 index 00000000..b1321edd --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/main/test_app_main.c @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" + +void app_main(void) +{ + /* + _ _ _ + | | (_) | | + ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ + / _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \ + | __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) | + \___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/ + | |______ __/ | + |_|______| |___/ + _____ _____ _____ _____ + |_ _| ___/ ___|_ _| + | | | |__ \ `--. | | + | | | __| `--. \ | | + | | | |___/\__/ / | | + \_/ \____/\____/ \_/ + */ + + printf(" _ _ _ \n"); + printf(" | | (_) | | \n"); + printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n"); + printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n"); + printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n"); + printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n"); + printf(" | |______ __/ | \n"); + printf(" |_|______| |___/ \n"); + printf(" _____ _____ _____ _____ \n"); + printf("|_ _| ___/ ___|_ _| \n"); + printf(" | | | |__ \\ `--. | | \n"); + printf(" | | | __| `--. \\ | | \n"); + printf(" | | | |___/\\__/ / | | \n"); + printf(" \\_/ \\____/\\____/ \\_/ \n"); + + unity_utils_setup_heap_record(80); + unity_utils_set_leak_level(128); + unity_run_menu(); +} + +/* setUp runs before every test */ +void setUp(void) +{ + unity_utils_record_free_mem(); +} + +/* tearDown runs after every test */ +void tearDown(void) +{ + unity_utils_evaluate_leaks(); +} diff --git a/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c b/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c new file mode 100644 index 00000000..5f36168d --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" +#if SOC_USB_OTG_SUPPORTED + +// +#include +#include +// +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +// +#include "esp_system.h" +#include "esp_log.h" +#include "esp_err.h" +// +#include "unity.h" +#include "tinyusb.h" +#include "tusb_cdc_acm.h" + +static const char *TAG = "teardown"; + +SemaphoreHandle_t wait_mount = NULL; + +#define TEARDOWN_DEVICE_INIT_DELAY_MS 1000 +#define TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS 1000 +#define TEARDOWN_DEVICE_DETACH_DELAY_MS 1000 + +#define TEARDOWN_AMOUNT 10 + +#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN) + +static uint8_t const test_configuration_descriptor[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), +}; + +static const tusb_desc_device_t test_device_descriptor = { + .bLength = sizeof(test_device_descriptor), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers + .idProduct = 0x4002, + .bcdDevice = 0x100, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01 +}; + +#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 + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + xSemaphoreGive(wait_mount); +} + +/** + * @brief TinyUSB Teardown specific testcase + * + * Scenario: + * 1. Install TinyUSB device without any class + * 2. Wait SetConfiguration() (tud_mount_cb) + * 3. If attempts == 0 goto step 8 + * 4. Wait TEARDOWN_DEVICE_DETACH_DELAY_MS + * 5. Uninstall TinyUSB device + * 6. Wait TEARDOWN_DEVICE_INIT_DELAY_MS + * 7. Decrease attempts by 1, goto step 3 + * 8. Wait TEARDOWN_DEVICE_DETACH_DELAY_MS + * 9. Uninstall TinyUSB device + */ +TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]") +{ + wait_mount = xSemaphoreCreateBinary(); + TEST_ASSERT_NOT_EQUAL(NULL, wait_mount); + + // TinyUSB driver configuration + const tinyusb_config_t tusb_cfg = { + .device_descriptor = &test_device_descriptor, + .string_descriptor = NULL, + .string_descriptor_count = 0, + .external_phy = false, +#if (TUD_OPT_HIGH_SPEED) + .fs_configuration_descriptor = test_configuration_descriptor, + .hs_configuration_descriptor = test_configuration_descriptor, + .qualifier_descriptor = &device_qualifier, +#else + .configuration_descriptor = test_configuration_descriptor, +#endif // TUD_OPT_HIGH_SPEED + }; + + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg)); + // Wait for the usb event + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS))); + + int attempts = TEARDOWN_AMOUNT; + while (attempts--) { + // Keep device attached + vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS)); + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); + // Teardown + vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_INIT_DELAY_MS)); + // Reconnect + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg)); + // Wait for the usb event + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS))); + } + + // Teardown + vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS)); + TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); + // Remove primitives + vSemaphoreDelete(wait_mount); +} + +#endif diff --git a/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py b/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py new file mode 100644 index 00000000..9f12e0ef --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +import pytest +from pytest_embedded_idf.dut import IdfDut +from time import sleep, time +from usb import core, util + + +def find_tusb_dev(vid, pid): + device = core.find(idVendor=vid, idProduct=pid) + return device is not None + + +def tusb_device_presence(vid, pid, iterations): + for i in range(iterations): + print(f"\Teardown {i + 1}/{iterations}") + # Wait until the device is present + print(f"Waiting for device ...") + while not find_tusb_dev(vid, pid): + sleep(0.5) # Check every 0.5 second + print("Device detected.") + + # Wait until the device is removed + print("Waiting for the device to be removed...") + while find_tusb_dev(vid, pid): + sleep(0.5) # Check every 0.5 second + print("Device removed.") + + +def teardown_device(amount): + TUSB_VID = 0x303A # Espressif TinyUSB VID + TUSB_PID = 0x4002 # Espressif TinyUSB VID + tusb_device_presence(TUSB_VID, TUSB_PID, amount) + print("Monitoring completed.") + +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32p4 +@pytest.mark.usb_device +def test_usb_teardown_device(dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests.') + dut.write('[teardown]') + dut.expect_exact('TinyUSB: TinyUSB Driver installed') + sleep(2) # Some time for the OS to enumerate our USB device + teardown_device(10) # Teardown tusb device + diff --git a/device/esp_tinyusb/test_apps/teardown_device/sdkconfig.defaults b/device/esp_tinyusb/test_apps/teardown_device/sdkconfig.defaults new file mode 100644 index 00000000..e4377094 --- /dev/null +++ b/device/esp_tinyusb/test_apps/teardown_device/sdkconfig.defaults @@ -0,0 +1,16 @@ +# Configure TinyUSB, it will be used to mock USB devices +CONFIG_TINYUSB_CDC_ENABLED=y +CONFIG_TINYUSB_CDC_COUNT=1 + +# 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 From 3c4aa97eccd1b16d93d4738cdac5f09f62babb0f Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 13:38:07 +0100 Subject: [PATCH 03/13] change(teardown): Reverted debug output lines --- .../test_apps/teardown_device/main/test_teardown.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c b/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c index 5f36168d..3dfd2a7e 100644 --- a/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c +++ b/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c @@ -113,8 +113,11 @@ TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]") TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg)); // Wait for the usb event + ESP_LOGD(TAG, "wait mount..."); TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS))); + ESP_LOGD(TAG, "mounted"); + // Teardown routine int attempts = TEARDOWN_AMOUNT; while (attempts--) { // Keep device attached @@ -125,7 +128,9 @@ TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]") // Reconnect TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg)); // Wait for the usb event + ESP_LOGD(TAG, "wait mount..."); TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS))); + ESP_LOGD(TAG, "mounted"); } // Teardown From 9c8979ad7dc47450cf9163f02d7734d19c3da911 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 14:05:54 +0100 Subject: [PATCH 04/13] change(ci): Added libusb --- .github/workflows/build_and_run_test_app_usb.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index f6ce2f7c..3fcbbf37 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -72,6 +72,6 @@ jobs: - name: Install Python packages env: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" - run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial pyusb + run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial pyusb libusb - name: Run USB Test App on target run: pytest --embedded-services esp,idf --target=${{ matrix.idf_target }} -m ${{ matrix.runner_tag }} --build-dir=build_${{ matrix.idf_target }} From 2f2c9deadbe2593c37359fdeb154140199ed15d5 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 18:10:39 +0100 Subject: [PATCH 05/13] change(ci): Added libusb-1.0-0 backend --- .github/workflows/build_and_run_test_app_usb.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 3fcbbf37..34561705 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -69,6 +69,10 @@ jobs: - uses: actions/download-artifact@v4 with: name: usb_test_app_bin_${{ matrix.idf_ver }} + - name: ⚙️ Install System tools + run: | + apt update + apt install libusb-1.0-0 - name: Install Python packages env: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" From 34967ff9a06ce2b6b2a983918a5b477dc5b361d9 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 21:09:55 +0100 Subject: [PATCH 06/13] change(teardown): Added pytest device timeout --- .../teardown_device/pytest_teardown_device.py | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py b/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py index 9f12e0ef..031c3cd1 100644 --- a/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py +++ b/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py @@ -6,32 +6,44 @@ from time import sleep, time from usb import core, util +class DeviceNotFoundError(Exception): + """Custom exception for device not found within the timeout period.""" + pass -def find_tusb_dev(vid, pid): - device = core.find(idVendor=vid, idProduct=pid) - return device is not None +def wait_tusb_dev_appeared(vid, pid, timeout): + start_time = time() + while True: + device = core.find(idVendor=vid, idProduct=pid) + if device: + return True + if time() - start_time > timeout: + raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} not found within {timeout} seconds.") + sleep(0.5) +def wait_tusb_dev_removed(vid, pid, timeout): + start_time = time() + while True: + device = core.find(idVendor=vid, idProduct=pid) + if device is None: + return True + if time() - start_time > timeout: + raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} still present within {timeout} seconds.") + sleep(0.5) -def tusb_device_presence(vid, pid, iterations): +def tusb_device_teardown(iterations, timeout): + TUSB_VID = 0x303A # Espressif TinyUSB VID + TUSB_PID = 0x4002 # Espressif TinyUSB VID + for i in range(iterations): - print(f"\Teardown {i + 1}/{iterations}") # Wait until the device is present print(f"Waiting for device ...") - while not find_tusb_dev(vid, pid): - sleep(0.5) # Check every 0.5 second + wait_tusb_dev_appeared(TUSB_VID, TUSB_PID, timeout) print("Device detected.") # Wait until the device is removed print("Waiting for the device to be removed...") - while find_tusb_dev(vid, pid): - sleep(0.5) # Check every 0.5 second + wait_tusb_dev_removed(TUSB_VID, TUSB_PID, timeout) print("Device removed.") - - -def teardown_device(amount): - TUSB_VID = 0x303A # Espressif TinyUSB VID - TUSB_PID = 0x4002 # Espressif TinyUSB VID - tusb_device_presence(TUSB_VID, TUSB_PID, amount) print("Monitoring completed.") @pytest.mark.esp32s2 @@ -43,5 +55,14 @@ def test_usb_teardown_device(dut) -> None: dut.write('[teardown]') dut.expect_exact('TinyUSB: TinyUSB Driver installed') sleep(2) # Some time for the OS to enumerate our USB device - teardown_device(10) # Teardown tusb device - + + try: + tusb_device_teardown(10, 10) # Teardown tusb device: amount, timeout + + except DeviceNotFoundError as e: + print(f"Error: {e}") + raise + + except Exception as e: + print(f"An unexpected error occurred: {e}") + raise From 548c9052ef42b3fe07fe63936437f0a09ad7f412 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 21:36:19 +0100 Subject: [PATCH 07/13] change(teardown): Added cdc class to descriptor --- .../test_apps/teardown_device/main/test_teardown.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c b/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c index 3dfd2a7e..ee562902 100644 --- a/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c +++ b/device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c @@ -33,11 +33,13 @@ SemaphoreHandle_t wait_mount = NULL; #define TEARDOWN_AMOUNT 10 -#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN) - +// #define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN) +static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN; static uint8_t const test_configuration_descriptor[] = { // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + // TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_CONFIG_DESCRIPTOR(1, 2, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, (TUD_OPT_HIGH_SPEED ? 512 : 64)), }; static const tusb_desc_device_t test_device_descriptor = { From e17f32bb4ce8eef8e11db041f96e2924498e7c8b Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 21:37:57 +0100 Subject: [PATCH 08/13] change(ci): Trim to latest only --- .github/workflows/build_and_run_test_app_usb.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 34561705..dff1cc15 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -12,7 +12,8 @@ jobs: strategy: fail-fast: false matrix: - idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"] + # idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"] + idf_ver: ["latest"] runs-on: ubuntu-20.04 container: espressif/idf:${{ matrix.idf_ver }} steps: @@ -48,7 +49,8 @@ jobs: strategy: fail-fast: false matrix: - idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"] + # idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"] + idf_ver: ["latest"] idf_target: ["esp32s2", "esp32p4"] runner_tag: ["usb_host", "usb_device"] exclude: From 32735dd182e6bf8bfa56eaeb9684f6a0769d6dce Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 22:41:37 +0100 Subject: [PATCH 09/13] change(ci): Change docker options --- .github/workflows/build_and_run_test_app_usb.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index dff1cc15..9a2d982d 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -65,7 +65,8 @@ jobs: runs-on: [self-hosted, linux, docker, "${{ matrix.idf_target }}", "${{ matrix.runner_tag }}"] container: image: python:3.11-bookworm - options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw" + # options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw" + options: --privileged --device steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 From b451bba24b02af108ece78d2542c90274fc6f0f5 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 23:06:20 +0100 Subject: [PATCH 10/13] chage(teardown): Changed logic from usb to subprocess --- .../workflows/build_and_run_test_app_usb.yml | 7 +---- .../teardown_device/pytest_teardown_device.py | 27 ++++++++++++------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 9a2d982d..a1c6448f 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -65,17 +65,12 @@ jobs: runs-on: [self-hosted, linux, docker, "${{ matrix.idf_target }}", "${{ matrix.runner_tag }}"] container: image: python:3.11-bookworm - # options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw" - options: --privileged --device + options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw" steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: name: usb_test_app_bin_${{ matrix.idf_ver }} - - name: ⚙️ Install System tools - run: | - apt update - apt install libusb-1.0-0 - name: Install Python packages env: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" diff --git a/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py b/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py index 031c3cd1..65b64798 100644 --- a/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py +++ b/device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py @@ -3,36 +3,43 @@ import pytest from pytest_embedded_idf.dut import IdfDut +import subprocess from time import sleep, time -from usb import core, util class DeviceNotFoundError(Exception): """Custom exception for device not found within the timeout period.""" pass +def tusb_dev_in_list(vid, pid): + try: + output = subprocess.check_output(["lsusb"], text=True) + search_string = f"{vid}:{pid}" + return search_string in output + except Exception as e: + print(f"Error while executing lsusb: {e}") + raise + def wait_tusb_dev_appeared(vid, pid, timeout): start_time = time() while True: - device = core.find(idVendor=vid, idProduct=pid) - if device: + if tusb_dev_in_list(vid, pid): return True if time() - start_time > timeout: raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} not found within {timeout} seconds.") sleep(0.5) -def wait_tusb_dev_removed(vid, pid, timeout): +def wait_tusb_dev_removed(vid, pid, timeout): start_time = time() while True: - device = core.find(idVendor=vid, idProduct=pid) - if device is None: + if not tusb_dev_in_list(vid, pid): return True if time() - start_time > timeout: - raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} still present within {timeout} seconds.") - sleep(0.5) + raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} wasn't removed within {timeout} seconds.") + sleep(0.5) def tusb_device_teardown(iterations, timeout): - TUSB_VID = 0x303A # Espressif TinyUSB VID - TUSB_PID = 0x4002 # Espressif TinyUSB VID + TUSB_VID = "303a" # Espressif TinyUSB VID + TUSB_PID = "4002" # Espressif TinyUSB VID for i in range(iterations): # Wait until the device is present From d8e1c9ef625989ace3e27072239148dc82f28ab6 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Fri, 20 Dec 2024 23:35:58 +0100 Subject: [PATCH 11/13] change(ci): Added usbutils --- .github/workflows/build_and_run_test_app_usb.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index a1c6448f..348be338 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -71,9 +71,13 @@ jobs: - uses: actions/download-artifact@v4 with: name: usb_test_app_bin_${{ matrix.idf_ver }} + - name: ⚙️ Install System tools + run: | + apt update + apt install usbutils - name: Install Python packages env: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" - run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial pyusb libusb + run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial - name: Run USB Test App on target run: pytest --embedded-services esp,idf --target=${{ matrix.idf_target }} -m ${{ matrix.runner_tag }} --build-dir=build_${{ matrix.idf_target }} From 82db7a942d539e54dcb40935dc37b67ed773fa47 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Sat, 21 Dec 2024 00:08:50 +0100 Subject: [PATCH 12/13] change(ci): Added agreed on apt install --- .github/workflows/build_and_run_test_app_usb.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 348be338..4e4b9a69 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -74,7 +74,7 @@ jobs: - name: ⚙️ Install System tools run: | apt update - apt install usbutils + apt install -y usbutils - name: Install Python packages env: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" From a3bed1894ccf4c6af181f956f32dc22043f5214f Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Sun, 22 Dec 2024 13:19:40 +0100 Subject: [PATCH 13/13] change(ci): Reverted pyusb as it is required by vendor pytest --- .github/workflows/build_and_run_test_app_usb.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index 4e4b9a69..ed65b447 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -78,6 +78,6 @@ jobs: - name: Install Python packages env: PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/" - run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial + run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pyserial pyusb - name: Run USB Test App on target run: pytest --embedded-services esp,idf --target=${{ matrix.idf_target }} -m ${{ matrix.runner_tag }} --build-dir=build_${{ matrix.idf_target }}