From 6206302787a29fbf692dc9402621e9d7f433d0fc Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Thu, 10 Feb 2022 11:16:53 +0100 Subject: [PATCH] ci: Add USB Host CDC and MSC pytests to pipeline --- .gitlab/ci/target-test.yml | 10 +++++ .../cdc_acm_host/test/test_cdc_acm_host.c | 14 +++---- .../cdc/common/cdc_acm_host/test/usb_device.c | 29 +++++++++++++- pytest.ini | 1 + .../peripherals/usb/main/usb_test_main.c | 28 +++++++++++++ .../peripherals/usb/pytest_usb_host.py | 40 +++++++++++++++++++ .../peripherals/usb/sdkconfig.defaults | 18 +++++++++ 7 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 tools/test_apps/peripherals/usb/pytest_usb_host.py diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index 831cb9b95a..6c08c4780f 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -196,6 +196,16 @@ test_app_test_pytest_esp32c3_generic: TARGET: ESP32C3 ENV_MARKER: generic +test_app_test_pytest_esp32s2_usb_host: + extends: + - .pytest_test_apps_dir_template + - .rules:test:custom_test-esp32s2 + needs: + - build_pytest_test_apps_esp32s2 + variables: + TARGET: ESP32S2 + ENV_MARKER: usb_host + # for parallel jobs, CI_JOB_NAME will be "job_name index/total" (for example, "IT_001 1/2") # we need to convert to pattern "job_name_index.yml" .define_config_file_name: &define_config_file_name | diff --git a/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/test_cdc_acm_host.c b/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/test_cdc_acm_host.c index 4574ca4f25..9d2582c8eb 100644 --- a/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/test_cdc_acm_host.c +++ b/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/test_cdc_acm_host.c @@ -72,7 +72,7 @@ void usb_lib_task(void *arg) all_clients_gone = true; } if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { - printf("All device's freed\n"); + printf("All devices freed\n"); all_dev_free = true; } } @@ -133,7 +133,7 @@ static void notif_cb(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_host_dev_event_dat /* 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("USB Host CDC-ACM driver: Basic test", "[cdc_acm][ignore]") +TEST_CASE("read_write", "[cdc_acm]") { nb_of_responses = 0; cdc_acm_dev_hdl_t cdc_dev = NULL; @@ -180,7 +180,7 @@ TEST_CASE("USB Host CDC-ACM driver: Basic test", "[cdc_acm][ignore]") } /* Test communication with multiple CDC-ACM devices from one thread */ -TEST_CASE("USB Host CDC-ACM driver: Multiple devices test", "[cdc_acm][ignore]") +TEST_CASE("multiple_devices", "[cdc_acm]") { nb_of_responses = 0; nb_of_responses2 = 0; @@ -244,7 +244,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("USB Host CDC-ACM driver: Multiple threads test", "[cdc_acm][ignore]") +TEST_CASE("multiple_threads", "[cdc_acm]") { nb_of_responses = 0; cdc_acm_dev_hdl_t cdc_dev; @@ -278,7 +278,7 @@ TEST_CASE("USB Host CDC-ACM driver: Multiple threads test", "[cdc_acm][ignore]") } /* Test CDC driver reaction to USB device sudden disconnection */ -TEST_CASE("USB Host CDC-ACM driver: Sudden disconnection test", "[cdc_acm][ignore]") +TEST_CASE("sudden_disconnection", "[cdc_acm]") { test_install_cdc_driver(); @@ -315,7 +315,7 @@ TEST_CASE("USB Host CDC-ACM driver: Sudden disconnection test", "[cdc_acm][ignor * -# Send unsupported CDC request * -# Write to read-only device */ -TEST_CASE("USB Host CDC-ACM driver: Error handling", "[cdc_acm][ignore]") +TEST_CASE("error_handling", "[cdc_acm]") { cdc_acm_dev_hdl_t cdc_dev; cdc_acm_host_device_config_t dev_config = { @@ -375,7 +375,7 @@ TEST_CASE("USB Host CDC-ACM driver: Error handling", "[cdc_acm][ignore]") /* Following test case implements dual CDC-ACM USB device that can be used as mock device for CDC-ACM Host tests */ void run_usb_dual_cdc_device(void); -TEST_CASE("USB_CDC_Mock_Device_App", "[cdc_acm_device][ignore]") +TEST_CASE("mock_device_app", "[cdc_acm_device][ignore]") { run_usb_dual_cdc_device(); } diff --git a/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/usb_device.c b/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/usb_device.c index 6c4149f099..a2714112af 100644 --- a/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/usb_device.c +++ b/examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/usb_device.c @@ -19,9 +19,36 @@ void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event) tinyusb_cdcacm_write_flush(itf, 0); } +static const tusb_desc_device_t cdc_device_descriptor = { + .bLength = sizeof(cdc_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 = USB_ESPRESSIF_VID, + .idProduct = 0x4002, + .bcdDevice = 0x0100, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01 +}; + +const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + 2 * TUD_CDC_DESC_LEN; +static const uint8_t cdc_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), +}; + void run_usb_dual_cdc_device(void) { - const tinyusb_config_t tusb_cfg = {}; // the configuration using default values + const tinyusb_config_t tusb_cfg = { + .device_descriptor = &cdc_device_descriptor, + .configuration_descriptor = cdc_desc_configuration + }; ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); tinyusb_config_cdcacm_t amc_cfg = { diff --git a/pytest.ini b/pytest.ini index d7c768797a..bc3ba55197 100644 --- a/pytest.ini +++ b/pytest.ini @@ -25,6 +25,7 @@ markers = ip101: connected via wired 10/100M ethernet lan8720: connected via LAN8720 ethernet transceiver octal_psram: runners with octal psram + usb_host: usb host runners # log related log_cli = True diff --git a/tools/test_apps/peripherals/usb/main/usb_test_main.c b/tools/test_apps/peripherals/usb/main/usb_test_main.c index 65c83a567c..a902b52b4c 100644 --- a/tools/test_apps/peripherals/usb/main/usb_test_main.c +++ b/tools/test_apps/peripherals/usb/main/usb_test_main.c @@ -7,6 +7,18 @@ #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 (-10000) // @todo MSC test are leaking memory +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) { @@ -14,3 +26,19 @@ void app_main(void) 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/tools/test_apps/peripherals/usb/pytest_usb_host.py b/tools/test_apps/peripherals/usb/pytest_usb_host.py new file mode 100644 index 0000000000..d05b736625 --- /dev/null +++ b/tools/test_apps/peripherals/usb/pytest_usb_host.py @@ -0,0 +1,40 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.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.expect_exact('Press ENTER to see the list of tests.') + host.write('[cdc_acm]') + host.expect_unity_test_output() + host.expect_exact("Enter next test, or 'enter' to see menu") + + # 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.write('[usb_msc]') + host.expect_unity_test_output() + host.expect_exact("Enter next test, or 'enter' to see menu") diff --git a/tools/test_apps/peripherals/usb/sdkconfig.defaults b/tools/test_apps/peripherals/usb/sdkconfig.defaults index e395540cf3..09016e1710 100644 --- a/tools/test_apps/peripherals/usb/sdkconfig.defaults +++ b/tools/test_apps/peripherals/usb/sdkconfig.defaults @@ -1,4 +1,22 @@ CONFIG_TINYUSB=y CONFIG_TINYUSB_MSC_ENABLED=y +CONFIG_TINYUSB_CDC_ENABLED=y +CONFIG_TINYUSB_CDC_COUNT=2 CONFIG_ESP_INT_WDT=n CONFIG_ESP_TASK_WDT=n +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=n +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=3 +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7 +CONFIG_HEAP_POISONING_COMPREHENSIVE=y +CONFIG_SPI_FLASH_ENABLE_COUNTERS=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_STACK_CHECK=y +CONFIG_COMPILER_WARN_WRITE_STRINGS=y +CONFIG_ESP_TIMER_PROFILING=y +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y