diff --git a/components/usb/host_test/.build-test-rules.yml b/components/usb/host_test/.build-test-rules.yml new file mode 100644 index 0000000000..23eb8e9b6f --- /dev/null +++ b/components/usb/host_test/.build-test-rules.yml @@ -0,0 +1,7 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/usb/host_test: + enable: + - if: IDF_TARGET == "linux" + depends_components: + - usb diff --git a/components/usb/host_test/usb_host_layer_test/CMakeLists.txt b/components/usb/host_test/usb_host_layer_test/CMakeLists.txt new file mode 100644 index 0000000000..6fea6e4ad7 --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) + +list(APPEND EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/mocks/usb/usb_host_layer_mock/usb" + + # The following line would be needed to include the freertos mock component if this test used mocked FreeRTOS. + #"$ENV{IDF_PATH}/tools/mocks/freertos/" + ) + +project(host_test_usb_host_layer) diff --git a/components/usb/host_test/usb_host_layer_test/README.md b/components/usb/host_test/usb_host_layer_test/README.md new file mode 100644 index 0000000000..07071d4359 --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/README.md @@ -0,0 +1,37 @@ +| Supported Targets | Linux | +| ----------------- | ----- | + +# Description + +This directory contains test code for `USB Host layer` of USB Host stack. Namely: +* USB Host public API calls to install and uninstall the USB Host driver with partially mocked USB Host stack to test Linux build and Cmock run for this partial Mock +* Mocked are all layers of the USB Host stack below the USB Host layer, which is used as a real component + +Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework, use CMock, so you must install Ruby on your machine to run them. + +This test directory uses freertos as real component + +# Build + +Tests build regularly like an idf project. Currently only working on Linux machines. + +``` +idf.py --preview set-target linux +idf.py build +``` + +# Run + +The build produces an executable in the build folder. + +Just run: + +``` +idf.py monitor +``` + +or run the executable directly: + +``` +./build/host_test_usb_host_layer.elf +``` \ No newline at end of file diff --git a/components/usb/host_test/usb_host_layer_test/main/CMakeLists.txt b/components/usb/host_test/usb_host_layer_test/main/CMakeLists.txt new file mode 100644 index 0000000000..4c5f2bc29c --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/main/CMakeLists.txt @@ -0,0 +1,12 @@ +set(srcs) +list(APPEND srcs "test_main.cpp" + "usb_host_install_unit_test.cpp" + ) + +idf_component_register(SRCS ${srcs} + REQUIRES cmock usb + WHOLE_ARCHIVE) + +# The following line would be needed to provide the 'main' function if this test used mocked FreeRTOS. +# As this test uses the real FreeRTOS implementation, we don't need Catch2 to provide 'main'. +#target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain) diff --git a/components/usb/host_test/usb_host_layer_test/main/idf_component.yml b/components/usb/host_test/usb_host_layer_test/main/idf_component.yml new file mode 100644 index 0000000000..f7982136b9 --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/main/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + espressif/catch2: "^3.4.0" diff --git a/components/usb/host_test/usb_host_layer_test/main/test_main.cpp b/components/usb/host_test/usb_host_layer_test/main/test_main.cpp new file mode 100644 index 0000000000..43729e8838 --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/main/test_main.cpp @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +extern "C" void app_main(void) +{ + int argc = 1; + const char *argv[2] = { + "target_test_main", + NULL + }; + + auto result = Catch::Session().run(argc, argv); + if (result != 0) { + printf("Test failed with result %d\n", result); + } else { + printf("Test passed.\n"); + } + fflush(stdout); + exit(result); +} diff --git a/components/usb/host_test/usb_host_layer_test/main/usb_host_install_unit_test.cpp b/components/usb/host_test/usb_host_layer_test/main/usb_host_install_unit_test.cpp new file mode 100644 index 0000000000..b1cbb4fa9f --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/main/usb_host_install_unit_test.cpp @@ -0,0 +1,254 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "usb_host.h" // Real implementation of usb_host.h + +// Test all the mocked headers defined for this mock +extern "C" { +#include "Mockusb_phy.h" +#include "Mockhcd.h" +#include "Mockusbh.h" +#include "Mockenum.h" +#include "Mockhub.h" +} + +SCENARIO("USB Host pre-uninstall") +{ + // No USB Host driver previously installed + GIVEN("No USB Host previously installed") { + + // Uninstall not-installed USB Host + SECTION("Uninstalling not installed USB Host") { + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_uninstall()); + } + } +} + +SCENARIO("USB Host install") +{ + // USB Host config is not valid, USB Host driver is not installed from previous test case + GIVEN("No USB Host config, USB Host driver not installed") { + + // Try to install the USB Host driver with usb_host_config set to nullptr + SECTION("USB Host config is nullptr") { + + // Call the DUT function, expect ESP_ERR_INVALID_ARG + REQUIRE(ESP_ERR_INVALID_ARG == usb_host_install(nullptr)); + } + } + + // USB Host config struct + usb_host_config_t usb_host_config = { + .skip_phy_setup = false, + .root_port_unpowered = false, + .intr_flags = 1, + .enum_filter_cb = nullptr, + }; + + // USB host config is valid, USB Host driver is not installed from previous test case + GIVEN("USB Host config, USB Host driver not installed") { + + // Try to install the USB Host driver, with PHY install error + SECTION("Fail to install USB Host - PHY Install error") { + + // Make the PHY install to fail + usb_new_phy_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE); + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + + // Try to install the USB Host driver, with HCD Install error, use internal PHY + SECTION("Fail to install USB Host - HCD Install error (internal PHY)") { + + // Make the PHY install to pass + usb_phy_handle_t phy_handle; + usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK); + usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle); + + // make the HCD port install to fail + hcd_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE); + + // goto hcd_err: We must uninstall the PHY + usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK); + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + + // Try to install the USB Host driver, with HCD Install error, use external PHY + SECTION("Fail to install USB Host - HCD Install error (external PHY)") { + + // Skip the PHY Setup (external phy) + usb_host_config.skip_phy_setup = true; + + // make the HCD port install to fail + hcd_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE); + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + + // Try to install the USB Host driver, with USBH Install error, use internal PHY + SECTION("Fail to install USB Host - USBH install error") { + + // Make the PHY install to pass + usb_phy_handle_t phy_handle; + usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK); + usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle); + + // make the HCD port install to pass + hcd_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the USBH install to fail + usbh_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE); + + // goto usbh_err: We must uninstall HCD port and PHY + hcd_uninstall_ExpectAndReturn(ESP_OK); + usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK); + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + + // Try to install the USB Host driver, with Enum driver Install error, use internal PHY + SECTION("Fail to install USB Host - Enum driver install error") { + + // Make the PHY install to pass + usb_phy_handle_t phy_handle; + usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK); + usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle); + + // make the HCD port install to pass + hcd_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the USBH install to pass + usbh_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the ENUM Driver to fail + enum_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE); + + // goto enum_err: We must uninstall USBH, HCD port and PHY + usbh_uninstall_ExpectAndReturn(ESP_OK); + hcd_uninstall_ExpectAndReturn(ESP_OK); + usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK); + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + + // Try to install the USB Host driver, with Hub driver Install error, use internal PHY + SECTION("Fail to install USB Host - Hub driver install error") { + + // Make the PHY install to pass + usb_phy_handle_t phy_handle; + usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK); + usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle); + + // make the HCD port install to pass + hcd_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the USBH install to pass + usbh_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the ENUM Driver to pass + enum_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the HUB Driver to fail + hub_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE); + + // goto hub_err: We must uninstall Enum driver, USBH, HCD port and PHY + enum_uninstall_ExpectAndReturn(ESP_OK); + usbh_uninstall_ExpectAndReturn(ESP_OK); + hcd_uninstall_ExpectAndReturn(ESP_OK); + usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK); + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + + // Successfully install the USB Host driver + SECTION("Successfully install the USB Host driver") { + + // Make the PHY install to pass + usb_phy_handle_t phy_handle; + usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK); + usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle); + + // make the HCD port install to pass + hcd_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the USBH install to pass + usbh_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the ENUM Driver to pass + enum_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make the HUB Driver to pass + hub_install_ExpectAnyArgsAndReturn(ESP_OK); + + // Make hub_root_start() to pass + hub_root_start_ExpectAndReturn(ESP_OK); + + // Call the DUT function, expect ESP_OK + REQUIRE(ESP_OK == usb_host_install(&usb_host_config)); + } + } + + // USB Host config is valid, USB Host driver was successfully installed in previous test case + GIVEN("USB Host config, USB Host driver previously installed") { + + // Try to install USB Host driver again, after it has been successfully installed + SECTION("Fail to install already installed USB Host driver") { + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config)); + } + } + +} + +SCENARIO("USB Host post-uninstall") +{ + // USB Host driver successfully installed from previous test case + GIVEN("USB Host previously installed") { + + // Uninstall successfully installed USB Host driver + SECTION("Successfully uninstall the USB Host driver") { + + // Make the hub_root_stop() to pass + hub_root_stop_ExpectAndReturn(ESP_OK); + + // Make uninstalling of all the drivers to pass + hub_uninstall_ExpectAndReturn(ESP_OK); + enum_uninstall_ExpectAndReturn(ESP_OK); + usbh_uninstall_ExpectAndReturn(ESP_OK); + hcd_uninstall_ExpectAndReturn(ESP_OK); + + // Make the usb_del_phy() to pass + usb_del_phy_ExpectAnyArgsAndReturn(ESP_OK); + + // Call the DUT function, expect ESP_OK + REQUIRE(ESP_OK == usb_host_uninstall()); + } + } + + // USB Host driver successfully uninstalled from previous test case + GIVEN("USB Host successfully uninstalled") { + + // USB Host successfully uninstalled, try to uninstall it again + SECTION("Uninstall already uninstalled USB Host driver") { + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usb_host_uninstall()); + } + } +} diff --git a/components/usb/host_test/usb_host_layer_test/pytest_usb_host_layer_linux.py b/components/usb/host_test/usb_host_layer_test/pytest_usb_host_layer_linux.py new file mode 100644 index 0000000000..15933483c1 --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/pytest_usb_host_layer_linux.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize + + +@pytest.mark.host_test +@idf_parametrize('target', ['linux'], indirect=['target']) +def test_usb_host_host_layer_linux(dut: Dut) -> None: + dut.expect_exact('All tests passed', timeout=5) diff --git a/components/usb/host_test/usb_host_layer_test/sdkconfig.defaults b/components/usb/host_test/usb_host_layer_test/sdkconfig.defaults new file mode 100644 index 0000000000..f9bc9d6780 --- /dev/null +++ b/components/usb/host_test/usb_host_layer_test/sdkconfig.defaults @@ -0,0 +1,4 @@ + +CONFIG_IDF_TARGET="linux" +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/components/usb/host_test/usbh_layer_test/CMakeLists.txt b/components/usb/host_test/usbh_layer_test/CMakeLists.txt new file mode 100644 index 0000000000..60b0b79172 --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) + +list(APPEND EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/mocks/usb/usbh_layer_mock/usb" + + # The following line would be needed to include the freertos mock component if this test used mocked FreeRTOS. + #"$ENV{IDF_PATH}/tools/mocks/freertos/" + ) + +project(host_test_usbh_layer) diff --git a/components/usb/host_test/usbh_layer_test/README.md b/components/usb/host_test/usbh_layer_test/README.md new file mode 100644 index 0000000000..44200aed3b --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/README.md @@ -0,0 +1,37 @@ +| Supported Targets | Linux | +| ----------------- | ----- | + +# Description + +This directory contains test code for `USBH layer` of USB Host stack. Namely: +* USBH public API calls to install and uninstall the USBH driver with partially mocked USB Host stack to test Linux build and Cmock run for this partial Mock +* Mocked are all layers of the USB Host stack below the USBH layer, which is used as a real component + +Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework, use CMock, so you must install Ruby on your machine to run them. + +This test directory uses freertos as a real component + +# Build + +Tests build regularly like an idf project. Currently only working on Linux machines. + +``` +idf.py --preview set-target linux +idf.py build +``` + +# Run + +The build produces an executable in the build folder. + +Just run: + +``` +idf.py monitor +``` + +or run the executable directly: + +``` +./build/host_test_usbh_layer.elf +``` \ No newline at end of file diff --git a/components/usb/host_test/usbh_layer_test/main/CMakeLists.txt b/components/usb/host_test/usbh_layer_test/main/CMakeLists.txt new file mode 100644 index 0000000000..b2e1716276 --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/main/CMakeLists.txt @@ -0,0 +1,12 @@ +set(srcs) +list(APPEND srcs "test_main.cpp" + "usbh_install_unit_test.cpp" + ) + +idf_component_register(SRCS ${srcs} + REQUIRES cmock usb + WHOLE_ARCHIVE) + +# The following line would be needed to provide the 'main' function if this test used mocked FreeRTOS. +# As this test uses the real FreeRTOS implementation, we don't need Catch2 to provide 'main'. +#target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain) diff --git a/components/usb/host_test/usbh_layer_test/main/idf_component.yml b/components/usb/host_test/usbh_layer_test/main/idf_component.yml new file mode 100644 index 0000000000..f7982136b9 --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/main/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + espressif/catch2: "^3.4.0" diff --git a/components/usb/host_test/usbh_layer_test/main/test_main.cpp b/components/usb/host_test/usbh_layer_test/main/test_main.cpp new file mode 100644 index 0000000000..43729e8838 --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/main/test_main.cpp @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +extern "C" void app_main(void) +{ + int argc = 1; + const char *argv[2] = { + "target_test_main", + NULL + }; + + auto result = Catch::Session().run(argc, argv); + if (result != 0) { + printf("Test failed with result %d\n", result); + } else { + printf("Test passed.\n"); + } + fflush(stdout); + exit(result); +} diff --git a/components/usb/host_test/usbh_layer_test/main/usbh_install_unit_test.cpp b/components/usb/host_test/usbh_layer_test/main/usbh_install_unit_test.cpp new file mode 100644 index 0000000000..7467eff3e3 --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/main/usbh_install_unit_test.cpp @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "usbh.h" // Real implementation of usbh.h + +// Test all the mocked headers defined for this mock +extern "C" { +#include "Mockhcd.h" +#include "Mockusb_private.h" +} + +SCENARIO("USBH pre-uninstall") +{ + // No USBH driver previously installed + GIVEN("No USBH previously installed") { + + // Uninstall not-installed USBH driver + SECTION("Uninstalling not installed USBH driver") { + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usbh_uninstall()); + } + } +} + +SCENARIO("USBH install") +{ + // USBH config is not valid, USBH driver is not previously installed + GIVEN("No USBH config, USBH driver not installed") { + + // Try to install the USBH driver with usbh_config set to nullptr + SECTION("USBH config is nullptr") { + + // Call the DUT function, expect ESP_ERR_INVALID_ARG + REQUIRE(ESP_ERR_INVALID_ARG == usbh_install(nullptr)); + } + } + + // USBH config struct + usbh_config_t usbh_config = {}; + + // USBH config is valid, USBH driver is not previously installed + GIVEN("USBH config, USBH driver not installed") { + + // Successfully install the USBH Driver + SECTION("Successfully install the USBH Driver") { + + // Call the DUT function, expect ESP_OK + REQUIRE(ESP_OK == usbh_install(&usbh_config)); + } + } + + // USBH config is valid, USBH driver is previously installed + GIVEN("USBH config, USBH driver previously installed") { + + SECTION("Fail to install already installed USBH driver") { + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usbh_install(&usbh_config)); + } + } +} + +SCENARIO("USBH post-uninstall") +{ + + // USBH driver successfully installed from previous test case + GIVEN("USBH driver previously installed") { + + // Uninstall successfully installed USBH driver + SECTION("Successfully uninstall the USBH driver") { + + // Call the DUT function, expect ESP_OK + REQUIRE(ESP_OK == usbh_uninstall()); + } + } + + // USBH driver successfully uninstalled from previous test case + GIVEN("USBH successfully uninstalled") { + + // USBH successfully uninstalled, try to uninstall it again + SECTION("Uninstall already uninstalled USBH driver") { + + // Call the DUT function, expect ESP_ERR_INVALID_STATE + REQUIRE(ESP_ERR_INVALID_STATE == usbh_uninstall()); + } + } +} diff --git a/components/usb/host_test/usbh_layer_test/pytest_usbh_layer_linux.py b/components/usb/host_test/usbh_layer_test/pytest_usbh_layer_linux.py new file mode 100644 index 0000000000..3742598f9e --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/pytest_usbh_layer_linux.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize + + +@pytest.mark.host_test +@idf_parametrize('target', ['linux'], indirect=['target']) +def test_usbh_layer_linux(dut: Dut) -> None: + dut.expect_exact('All tests passed', timeout=5) diff --git a/components/usb/host_test/usbh_layer_test/sdkconfig.defaults b/components/usb/host_test/usbh_layer_test/sdkconfig.defaults new file mode 100644 index 0000000000..f9bc9d6780 --- /dev/null +++ b/components/usb/host_test/usbh_layer_test/sdkconfig.defaults @@ -0,0 +1,4 @@ + +CONFIG_IDF_TARGET="linux" +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/tools/mocks/usb/CMakeLists.txt b/tools/mocks/usb/usb_host_full_mock/usb/CMakeLists.txt similarity index 94% rename from tools/mocks/usb/CMakeLists.txt rename to tools/mocks/usb/usb_host_full_mock/usb/CMakeLists.txt index 0e0d0b0e0c..043349f6be 100644 --- a/tools/mocks/usb/CMakeLists.txt +++ b/tools/mocks/usb/usb_host_full_mock/usb/CMakeLists.txt @@ -1,6 +1,8 @@ # NOTE: This kind of mocking currently works on Linux targets only. # On Espressif chips, too many dependencies are missing at the moment. -message(STATUS "building USB HOST MOCKS") + +# Full USB Host mock +message(STATUS "building full USB HOST MOCKS") idf_component_get_property(original_usb_dir usb COMPONENT_OVERRIDEN_DIR) diff --git a/tools/mocks/usb/usb_host_full_mock/usb/README.md b/tools/mocks/usb/usb_host_full_mock/usb/README.md new file mode 100644 index 0000000000..b8b539dd7e --- /dev/null +++ b/tools/mocks/usb/usb_host_full_mock/usb/README.md @@ -0,0 +1,4 @@ +# Full USB Host stack mock + +This mock mocks all the USB Host stack layers, none of the USB Host stack layers are used as real. +This mock is useful for mock testing of the layers above the USB Host stack, EG USB Host Class drivers. diff --git a/tools/mocks/usb/include/mock_add_usb_device.h b/tools/mocks/usb/usb_host_full_mock/usb/include/mock_add_usb_device.h similarity index 100% rename from tools/mocks/usb/include/mock_add_usb_device.h rename to tools/mocks/usb/usb_host_full_mock/usb/include/mock_add_usb_device.h diff --git a/tools/mocks/usb/mock/mock_config.yaml b/tools/mocks/usb/usb_host_full_mock/usb/mock/mock_config.yaml similarity index 100% rename from tools/mocks/usb/mock/mock_config.yaml rename to tools/mocks/usb/usb_host_full_mock/usb/mock/mock_config.yaml diff --git a/tools/mocks/usb/mock_add_usb_device.c b/tools/mocks/usb/usb_host_full_mock/usb/mock_add_usb_device.c similarity index 100% rename from tools/mocks/usb/mock_add_usb_device.c rename to tools/mocks/usb/usb_host_full_mock/usb/mock_add_usb_device.c diff --git a/tools/mocks/usb/usb_host_layer_mock/usb/CMakeLists.txt b/tools/mocks/usb/usb_host_layer_mock/usb/CMakeLists.txt new file mode 100644 index 0000000000..3a23007940 --- /dev/null +++ b/tools/mocks/usb/usb_host_layer_mock/usb/CMakeLists.txt @@ -0,0 +1,26 @@ +# NOTE: This kind of mocking currently works on Linux targets only. +# On Espressif chips, too many dependencies are missing at the moment. + +# USB Host layer mock +message(STATUS "building USB HOST Layer MOCKS") + +idf_component_get_property(original_usb_dir usb COMPONENT_OVERRIDEN_DIR) + +idf_component_mock(INCLUDE_DIRS "${original_usb_dir}/include" + "${original_usb_dir}/include/esp_private" + "${original_usb_dir}/include/usb" + "${original_usb_dir}/private_include" + MOCK_HEADER_FILES ${original_usb_dir}/private_include/enum.h + ${original_usb_dir}/private_include/hcd.h + ${original_usb_dir}/private_include/hub.h + ${original_usb_dir}/private_include/usbh.h + ${original_usb_dir}/include/esp_private/usb_phy.h + REQUIRES freertos) + +# We do not mock usb_host.c, we use the original implementation of it +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_host.c") +# Original implementation of usb_private.c to allocate memory for transfers +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_private.c") +# We do not mock usb_helpers. We use the original implementation +# This way, we can test descriptor parsing +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_helpers.c") diff --git a/tools/mocks/usb/usb_host_layer_mock/usb/Kconfig b/tools/mocks/usb/usb_host_layer_mock/usb/Kconfig new file mode 100644 index 0000000000..ed6fae4ce5 --- /dev/null +++ b/tools/mocks/usb/usb_host_layer_mock/usb/Kconfig @@ -0,0 +1,14 @@ +# Config item from the original USB component needed for this CMock build + +menu "USB Host Layer mock" + + config USB_HOST_CONTROL_TRANSFER_MAX_SIZE + int "Largest size (in bytes) of transfers to/from default endpoints" + default 256 + help + Each USB device attached is allocated a dedicated buffer for its OUT/IN transfers to/from the device's + control endpoint. The maximum size of that buffer is determined by this option. The limited size of the + transfer buffer have the following implications: + - The maximum length of control transfers is limited + - Device's with configuration descriptors larger than this limit cannot be supported +endmenu diff --git a/tools/mocks/usb/usb_host_layer_mock/usb/README.md b/tools/mocks/usb/usb_host_layer_mock/usb/README.md new file mode 100644 index 0000000000..79f3d2665e --- /dev/null +++ b/tools/mocks/usb/usb_host_layer_mock/usb/README.md @@ -0,0 +1,4 @@ +# USB Host layer mock + +This mock mocks all the USB layers below the USB Host layer. USB Host layer is used as a real component. +This mock is useful for mock testing of the USB Host layer, as all the below layers are mocked. diff --git a/tools/mocks/usb/usb_host_layer_mock/usb/mock/mock_config.yaml b/tools/mocks/usb/usb_host_layer_mock/usb/mock/mock_config.yaml new file mode 100644 index 0000000000..bbca5f4e3c --- /dev/null +++ b/tools/mocks/usb/usb_host_layer_mock/usb/mock/mock_config.yaml @@ -0,0 +1,7 @@ +:cmock: + :plugins: + - expect + - expect_any_args + - return_thru_ptr + - ignore + - ignore_arg diff --git a/tools/mocks/usb/usbh_layer_mock/usb/CMakeLists.txt b/tools/mocks/usb/usbh_layer_mock/usb/CMakeLists.txt new file mode 100644 index 0000000000..909e5a014d --- /dev/null +++ b/tools/mocks/usb/usbh_layer_mock/usb/CMakeLists.txt @@ -0,0 +1,23 @@ +# NOTE: This kind of mocking currently works on Linux targets only. +# On Espressif chips, too many dependencies are missing at the moment. + +# USBH Layer mock +message(STATUS "building USBH Layer MOCKS") + +idf_component_get_property(original_usb_dir usb COMPONENT_OVERRIDEN_DIR) + +idf_component_mock(INCLUDE_DIRS "${original_usb_dir}/include" + "${original_usb_dir}/include/esp_private" + "${original_usb_dir}/include/usb" + "${original_usb_dir}/private_include" + MOCK_HEADER_FILES ${original_usb_dir}/private_include/hcd.h + ${original_usb_dir}/private_include/usb_private.h + REQUIRES freertos) + + +# We do not mock usbh.c, we use the original implementation of it +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usbh.c") +# Additionally, we include following src files from the above layers +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_host.c") +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/enum.c") +target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/hub.c") diff --git a/tools/mocks/usb/usbh_layer_mock/usb/Kconfig b/tools/mocks/usb/usbh_layer_mock/usb/Kconfig new file mode 100644 index 0000000000..03fb2a0bcb --- /dev/null +++ b/tools/mocks/usb/usbh_layer_mock/usb/Kconfig @@ -0,0 +1,68 @@ +# Config items from the original USB component needed for this CMock build + +menu "USBH Layer mock" + + config USB_HOST_CONTROL_TRANSFER_MAX_SIZE + int "Largest size (in bytes) of transfers to/from default endpoints" + default 256 + help + Each USB device attached is allocated a dedicated buffer for its OUT/IN transfers to/from the device's + control endpoint. The maximum size of that buffer is determined by this option. The limited size of the + transfer buffer have the following implications: + - The maximum length of control transfers is limited + - Device's with configuration descriptors larger than this limit cannot be supported + + menu "Hub Driver Configuration" + + menu "Root Port configuration" + + config USB_HOST_DEBOUNCE_DELAY_MS + int "Debounce delay in ms" + default 250 + help + On connection of a USB device, the USB 2.0 specification requires + a "debounce interval with a minimum duration of 100ms" to allow the connection to stabilize + (see USB 2.0 chapter 7.1.7.3 for more details). + During the debounce interval, no new connection/disconnection events are registered. + + The default value is set to 250 ms to be safe. + + config USB_HOST_RESET_HOLD_MS + int "Reset hold in ms" + default 30 + help + The reset signaling can be generated on any Hub or Host Controller port by request from + the USB System Software. The USB 2.0 specification requires that "the reset signaling must + be driven for a minimum of 10ms" (see USB 2.0 chapter 7.1.7.5 for more details). + After the reset, the hub port will transition to the Enabled state (refer to Section 11.5). + + The default value is set to 30 ms to be safe. + + config USB_HOST_RESET_RECOVERY_MS + int "Reset recovery delay in ms" + default 30 + help + After a port stops driving the reset signal, the USB 2.0 specification requires that + the "USB System Software guarantees a minimum of 10 ms for reset recovery" before the + attached device is expected to respond to data transfers (see USB 2.0 chapter 7.1.7.3 for + more details). + The device may ignore any data transfers during the recovery interval. + + The default value is set to 30 ms to be safe. + + + config USB_HOST_SET_ADDR_RECOVERY_MS + int "SetAddress() recovery time in ms" + default 10 + help + "After successful completion of the Status stage, the device is allowed a SetAddress() + recovery interval of 2 ms. At the end of this interval, the device must be able to accept + Setup packets addressed to the new address. Also, at the end of the recovery interval, the + device must not respond to tokens sent to the old address (unless, of course, the old and new + address is the same)." See USB 2.0 chapter 9.2.6.3 for more details. + + The default value is set to 10 ms to be safe. + + endmenu #Root Hub configuration + endmenu #Hub Driver Configuration +endmenu diff --git a/tools/mocks/usb/usbh_layer_mock/usb/README.md b/tools/mocks/usb/usbh_layer_mock/usb/README.md new file mode 100644 index 0000000000..a5b72579ab --- /dev/null +++ b/tools/mocks/usb/usbh_layer_mock/usb/README.md @@ -0,0 +1,4 @@ +# USBH layer mock + +This mock mocks all the USB layers below the USBH layer. USBH layer is used as a real component. +This mock is useful for mock testing of the USBH layer, as all the below layers are mocked. diff --git a/tools/mocks/usb/usbh_layer_mock/usb/mock/mock_config.yaml b/tools/mocks/usb/usbh_layer_mock/usb/mock/mock_config.yaml new file mode 100644 index 0000000000..bbca5f4e3c --- /dev/null +++ b/tools/mocks/usb/usbh_layer_mock/usb/mock/mock_config.yaml @@ -0,0 +1,7 @@ +:cmock: + :plugins: + - expect + - expect_any_args + - return_thru_ptr + - ignore + - ignore_arg