diff --git a/.github/workflows/build_and_run_main_ci.yml b/.github/workflows/build_and_run_main_ci.yml index 4615c9af..1a5a2c18 100644 --- a/.github/workflows/build_and_run_main_ci.yml +++ b/.github/workflows/build_and_run_main_ci.yml @@ -7,6 +7,11 @@ name: Build and Run Test apps on: + schedule: + - cron: "0 0 * * *" # 00:00 UTC + - cron: "0 2 * * *" # 02:00 UTC + - cron: "0 4 * * *" # 04:00 UTC + - cron: "0 6 * * *" # 06:00 UTC pull_request: types: [opened, reopened, synchronize] diff --git a/.github/workflows/build_and_run_test_app_usb.yml b/.github/workflows/build_and_run_test_app_usb.yml index fe7058ef..93da260a 100644 --- a/.github/workflows/build_and_run_test_app_usb.yml +++ b/.github/workflows/build_and_run_test_app_usb.yml @@ -136,6 +136,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 pytest-rerunfailures - name: Run USB Test App on target run: pytest --target=${{ matrix.idf_target }} -m ${{ matrix.runner_tag }} --build-dir=build_${{ matrix.idf_target }}_default diff --git a/.github/workflows/build_idf_examples.yml b/.github/workflows/build_idf_examples.yml index ec04b9fb..1c25b6fa 100644 --- a/.github/workflows/build_idf_examples.yml +++ b/.github/workflows/build_idf_examples.yml @@ -10,7 +10,7 @@ name: Build ESP-IDF USB examples on: pull_request: - types: [opened, reopened, synchronize] + types: [opened, reopened] jobs: build: diff --git a/device/esp_tinyusb/test_apps/cdc/pytest_cdc.py b/device/esp_tinyusb/test_apps/cdc/pytest_cdc.py index 821aa2f6..21f71efb 100644 --- a/device/esp_tinyusb/test_apps/cdc/pytest_cdc.py +++ b/device/esp_tinyusb/test_apps/cdc/pytest_cdc.py @@ -12,6 +12,7 @@ @pytest.mark.esp32s3 @pytest.mark.esp32p4 @pytest.mark.usb_device +@pytest.mark.flaky(reruns=2, reruns_delay=5) def test_usb_device_cdc(dut: IdfDut) -> None: ''' Running the test locally: diff --git a/device/esp_tinyusb/test_apps/msc_storage/main/test_app_main.c b/device/esp_tinyusb/test_apps/msc_storage/main/test_app_main.c index 1451b0d7..ff468cf3 100644 --- a/device/esp_tinyusb/test_apps/msc_storage/main/test_app_main.c +++ b/device/esp_tinyusb/test_apps/msc_storage/main/test_app_main.c @@ -68,6 +68,6 @@ void app_main(void) printf(" \\_/ \\____/\\____/ \\_/ \n"); unity_utils_setup_heap_record(80); - unity_utils_set_leak_level(1048); // 128 (default) + 820 (wl_mount) + 100 (in case of driver format) + unity_utils_set_leak_level(4000); // 128 (default) + 820 (wl_mount) + 100 (in case of driver format) unity_run_menu(); } diff --git a/device/esp_tinyusb/test_apps/runtime_config/main/CMakeLists.txt b/device/esp_tinyusb/test_apps/runtime_config/main/CMakeLists.txt index 1944d3db..0d87f259 100644 --- a/device/esp_tinyusb/test_apps/runtime_config/main/CMakeLists.txt +++ b/device/esp_tinyusb/test_apps/runtime_config/main/CMakeLists.txt @@ -1,6 +1,12 @@ +set(priv_req "") + +if(${IDF_VERSION_MAJOR} LESS 6) + list(APPEND priv_req "usb") +endif() + idf_component_register(SRC_DIRS . INCLUDE_DIRS . PRIV_INCLUDE_DIRS "../../../include_private" - PRIV_REQUIRES usb + PRIV_REQUIRES ${priv_req} REQUIRES unity WHOLE_ARCHIVE) diff --git a/host/class/msc/usb_host_msc/test_app/main/test_app_main.c b/host/class/msc/usb_host_msc/test_app/main/test_app_main.c index ce807923..a05fe68f 100644 --- a/host/class/msc/usb_host_msc/test_app/main/test_app_main.c +++ b/host/class/msc/usb_host_msc/test_app/main/test_app_main.c @@ -36,6 +36,6 @@ void app_main(void) printf(" \\/ \\/ \\/ \\/ \r\n"); unity_utils_setup_heap_record(80); - unity_utils_set_leak_level(530); + unity_utils_set_leak_level(4000); unity_run_menu(); } diff --git a/host/usb/test/target_test/usb_host/main/ctrl_client_async_seq.c b/host/usb/test/target_test/usb_host/main/ctrl_client_async_seq.c index bf4b8900..fc7d4a31 100644 --- a/host/usb/test/target_test/usb_host/main/ctrl_client_async_seq.c +++ b/host/usb/test/target_test/usb_host/main/ctrl_client_async_seq.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -82,6 +82,7 @@ static void ctrl_client_event_cb(const usb_host_client_event_msg_t *event_msg, v ctrl_client_obj_t *ctrl_obj = (ctrl_client_obj_t *)arg; switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: + printf("\t-> New device\n"); TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, ctrl_obj->cur_stage); ctrl_obj->next_stage = TEST_STAGE_DEV_OPEN; ctrl_obj->dev_addr = event_msg->new_dev.address; @@ -119,24 +120,33 @@ void ctrl_client_async_seq_task(void *arg) } // Wait to be started by main thread - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000)), "Ctrl client not started from main thread"); ESP_LOGD(CTRL_CLIENT_TAG, "Starting"); + // Handle device enumeration separately, wait for 1000ms for the device to be enumerated + // Catch an error in case the device is not enumerated correctly + esp_err_t enum_ret = usb_host_client_handle_events(ctrl_obj.client_hdl, pdMS_TO_TICKS(1000)); + TEST_ASSERT_EQUAL_MESSAGE(TEST_STAGE_DEV_OPEN, ctrl_obj.next_stage, "USB_HOST_CLIENT_EVENT_NEW_DEV not generated on time"); + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, enum_ret, "Client handle events timed out"); + bool exit_loop = false; - bool skip_event_handling = false; + bool skip_event_handling = true; // Skip first event handling (we have handled the new device event separately) while (!exit_loop) { if (!skip_event_handling) { + //ESP_LOGI(CTRL_CLIENT_TAG, "Handling events"); TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_handle_events(ctrl_obj.client_hdl, portMAX_DELAY)); + //ESP_LOGI(CTRL_CLIENT_TAG, "Events handled"); } skip_event_handling = false; if (ctrl_obj.cur_stage == ctrl_obj.next_stage) { + //ESP_LOGW(CTRL_CLIENT_TAG, "Skip event handling"); continue; } ctrl_obj.cur_stage = ctrl_obj.next_stage; switch (ctrl_obj.next_stage) { case TEST_STAGE_DEV_OPEN: { - ESP_LOGD(CTRL_CLIENT_TAG, "Open"); + ESP_LOGI(CTRL_CLIENT_TAG, "Open"); // Open the device TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_host_device_open(ctrl_obj.client_hdl, ctrl_obj.dev_addr, &ctrl_obj.dev_hdl), "Failed to open the device"); // Get device info to get device speed @@ -177,7 +187,7 @@ void ctrl_client_async_seq_task(void *arg) break; } case TEST_STAGE_DEV_CLOSE: { - ESP_LOGD(CTRL_CLIENT_TAG, "Close"); + ESP_LOGI(CTRL_CLIENT_TAG, "Close"); vTaskDelay(10); // Give USB Host Lib some time to process all transfers TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(ctrl_obj.client_hdl, ctrl_obj.dev_hdl)); exit_loop = true; @@ -193,6 +203,6 @@ void ctrl_client_async_seq_task(void *arg) TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(ctrl_xfer[i])); } TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(ctrl_obj.client_hdl)); - ESP_LOGD(CTRL_CLIENT_TAG, "Done"); + ESP_LOGI(CTRL_CLIENT_TAG, "Done"); vTaskDelete(NULL); } diff --git a/host/usb/test/target_test/usb_host/main/msc_client_async_dconn.c b/host/usb/test/target_test/usb_host/main/msc_client_async_dconn.c index 2475536d..cf6215f7 100644 --- a/host/usb/test/target_test/usb_host/main/msc_client_async_dconn.c +++ b/host/usb/test/target_test/usb_host/main/msc_client_async_dconn.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -107,11 +107,13 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo msc_client_obj_t *msc_obj = (msc_client_obj_t *)arg; switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: + printf("\t-> New device\n"); TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage); msc_obj->next_stage = TEST_STAGE_DEV_OPEN; msc_obj->dev_addr = event_msg->new_dev.address; break; case USB_HOST_CLIENT_EVENT_DEV_GONE: + printf("\t-> Device gone\n"); msc_obj->event_count++; // If all transfers dequeued and device gone event occurred. Go to next stage if (msc_obj->event_count >= msc_obj->num_data_transfers + 1) { @@ -167,8 +169,14 @@ void msc_client_async_dconn_task(void *arg) ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(MSC_CLIENT_TAG, "Starting"); + // Handle device enumeration separately, wait for 1000ms for the device to be enumerated + // Catch an error in case the device is not enumerated correctly + esp_err_t enum_ret = usb_host_client_handle_events(msc_obj.client_hdl, pdMS_TO_TICKS(1000)); + TEST_ASSERT_EQUAL_MESSAGE(TEST_STAGE_DEV_OPEN, msc_obj.next_stage, "USB_HOST_CLIENT_EVENT_NEW_DEV not generated on time"); + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, enum_ret, "Client handle events timed out"); + bool exit_loop = false; - bool skip_event_handling = false; + bool skip_event_handling = true; // Skip first event handling (we have handled the new device event separately) int dconn_iter = 0; while (!exit_loop) { if (!skip_event_handling) { diff --git a/host/usb/test/target_test/usb_host/main/msc_client_async_enum.c b/host/usb/test/target_test/usb_host/main/msc_client_async_enum.c index c0e41da6..bff3e88b 100644 --- a/host/usb/test/target_test/usb_host/main/msc_client_async_enum.c +++ b/host/usb/test/target_test/usb_host/main/msc_client_async_enum.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -56,6 +56,7 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo msc_client_obj_t *msc_obj = (msc_client_obj_t *)arg; switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: + printf("\t-> New device\n"); TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage); msc_obj->next_stage = TEST_STAGE_DEV_OPEN; msc_obj->dev_addr_to_open = event_msg->new_dev.address; @@ -91,8 +92,14 @@ void msc_client_async_enum_task(void *arg) ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(MSC_CLIENT_TAG, "Starting"); + // Handle device enumeration separately, wait for 1000ms for the device to be enumerated + // Catch an error in case the device is not enumerated correctly + esp_err_t enum_ret = usb_host_client_handle_events(msc_obj.client_hdl, pdMS_TO_TICKS(1000)); + TEST_ASSERT_EQUAL_MESSAGE(TEST_STAGE_DEV_OPEN, msc_obj.next_stage, "USB_HOST_CLIENT_EVENT_NEW_DEV not generated on time"); + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, enum_ret, "Client handle events timed out"); + bool exit_loop = false; - bool skip_event_handling = false; + bool skip_event_handling = true; // Skip first event handling (we have handled the new device event separately) int enum_iter = 0; while (!exit_loop) { if (!skip_event_handling) { diff --git a/host/usb/test/target_test/usb_host/main/msc_client_async_seq.c b/host/usb/test/target_test/usb_host/main/msc_client_async_seq.c index b0a5e181..3a726fde 100644 --- a/host/usb/test/target_test/usb_host/main/msc_client_async_seq.c +++ b/host/usb/test/target_test/usb_host/main/msc_client_async_seq.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -110,6 +110,7 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo msc_client_obj_t *msc_obj = (msc_client_obj_t *)arg; switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: + printf("\t-> New device\n"); TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage); msc_obj->next_stage = TEST_STAGE_DEV_OPEN; msc_obj->dev_addr = event_msg->new_dev.address; @@ -154,24 +155,33 @@ void msc_client_async_seq_task(void *arg) usb_transfer_t *xfer_out = NULL; // Wait to be started by main thread - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000)), "MSC client not started from main thread"); ESP_LOGD(MSC_CLIENT_TAG, "Starting"); + // Handle device enumeration separately, wait for 1000ms for the device to be enumerated + // Catch an error in case the device is not enumerated correctly + esp_err_t enum_ret = usb_host_client_handle_events(msc_obj.client_hdl, pdMS_TO_TICKS(1000)); + TEST_ASSERT_EQUAL_MESSAGE(TEST_STAGE_DEV_OPEN, msc_obj.next_stage, "USB_HOST_CLIENT_EVENT_NEW_DEV not generated on time"); + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, enum_ret, "Client handle events timed out"); + bool exit_loop = false; - bool skip_event_handling = false; + bool skip_event_handling = true; // Skip first event handling (we have handled the new device event separately) while (!exit_loop) { if (!skip_event_handling) { + //ESP_LOGI(MSC_CLIENT_TAG, "Handling events"); TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_handle_events(msc_obj.client_hdl, portMAX_DELAY)); + //ESP_LOGI(MSC_CLIENT_TAG, "Events handled"); } skip_event_handling = false; if (msc_obj.cur_stage == msc_obj.next_stage) { + //ESP_LOGW(MSC_CLIENT_TAG, "Skip event handling"); continue; } msc_obj.cur_stage = msc_obj.next_stage; switch (msc_obj.cur_stage) { case TEST_STAGE_DEV_OPEN: { - ESP_LOGD(MSC_CLIENT_TAG, "Open"); + ESP_LOGI(MSC_CLIENT_TAG, "Open"); // Open the device TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr, &msc_obj.dev_hdl)); // Get device info to get device speed @@ -264,7 +274,7 @@ void msc_client_async_seq_task(void *arg) break; } case TEST_STAGE_DEV_CLOSE: { - ESP_LOGD(MSC_CLIENT_TAG, "Close"); + ESP_LOGI(MSC_CLIENT_TAG, "Close"); TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, msc_obj.dev_info->bInterfaceNumber)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl)); exit_loop = true; @@ -279,6 +289,6 @@ void msc_client_async_seq_task(void *arg) TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_out)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_in)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(msc_obj.client_hdl)); - ESP_LOGD(MSC_CLIENT_TAG, "Done"); + ESP_LOGI(MSC_CLIENT_TAG, "Done"); vTaskDelete(NULL); } diff --git a/host/usb/test/target_test/usb_host/main/multiconf_client_async.c b/host/usb/test/target_test/usb_host/main/multiconf_client_async.c index 60122981..09dbc5c3 100644 --- a/host/usb/test/target_test/usb_host/main/multiconf_client_async.c +++ b/host/usb/test/target_test/usb_host/main/multiconf_client_async.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -66,6 +66,7 @@ static void multiconf_client_event_cb(const usb_host_client_event_msg_t *event_m multiconf_client_obj_t *multiconf_obj = (multiconf_client_obj_t *)arg; switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: + printf("\t-> New device\n"); TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, multiconf_obj->cur_stage); multiconf_obj->next_stage = TEST_STAGE_DEV_OPEN; multiconf_obj->dev_addr = event_msg->new_dev.address; @@ -105,8 +106,14 @@ void multiconf_client_async_task(void *arg) ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(MULTICONF_CLIENT_TAG, "Starting"); + // Handle device enumeration separately, wait for 1000ms for the device to be enumerated + // Catch an error in case the device is not enumerated correctly + esp_err_t enum_ret = usb_host_client_handle_events(multiconf_obj.client_hdl, pdMS_TO_TICKS(1000)); + TEST_ASSERT_EQUAL_MESSAGE(TEST_STAGE_DEV_OPEN, multiconf_obj.next_stage, "USB_HOST_CLIENT_EVENT_NEW_DEV not generated on time"); + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, enum_ret, "Client handle events timed out"); + bool exit_loop = false; - bool skip_event_handling = false; + bool skip_event_handling = true; // Skip first event handling (we have handled the new device event separately) while (!exit_loop) { if (!skip_event_handling) { TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_handle_events(multiconf_obj.client_hdl, portMAX_DELAY)); diff --git a/host/usb/test/target_test/usb_host/main/test_usb_host_async.c b/host/usb/test/target_test/usb_host/main/test_usb_host_async.c index 8ef2335a..b607e9fa 100644 --- a/host/usb/test/target_test/usb_host/main/test_usb_host_async.c +++ b/host/usb/test/target_test/usb_host/main/test_usb_host_async.c @@ -165,6 +165,7 @@ static void test_async_client_cb(const usb_host_client_event_msg_t *event_msg, v switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: + printf("\t-> New device\n"); if (dev_addr == 0) { dev_addr = event_msg->new_dev.address; } else { @@ -173,6 +174,7 @@ static void test_async_client_cb(const usb_host_client_event_msg_t *event_msg, v *stage = CLIENT_TEST_STAGE_CONN; break; case USB_HOST_CLIENT_EVENT_DEV_GONE: + printf("\t-> Device gone\n"); *stage = CLIENT_TEST_STAGE_DCONN; break; default: @@ -201,16 +203,25 @@ TEST_CASE("Test USB Host async API", "[usb_host][low_speed][full_speed][high_spe client_config.async.callback_arg = (void *)&client1_stage; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &client1_hdl)); + TickType_t timeout_ticks = pdMS_TO_TICKS(1000); + TimeOut_t enumeration_timeout; + vTaskSetTimeOutState(&enumeration_timeout); + // Wait until the device connects and the clients receive the event while (!(client0_stage == CLIENT_TEST_STAGE_CONN && client1_stage == CLIENT_TEST_STAGE_CONN)) { usb_host_lib_handle_events(0, NULL); usb_host_client_handle_events(client0_hdl, 0); usb_host_client_handle_events(client1_hdl, 0); vTaskDelay(pdMS_TO_TICKS(10)); + + // Check if the device is enumerated within 1000 ms + if (xTaskCheckForTimeOut(&enumeration_timeout, &timeout_ticks) == pdTRUE) { + break; + } } // Check that both clients can open the device - TEST_ASSERT_NOT_EQUAL(0, dev_addr); + TEST_ASSERT_NOT_EQUAL_MESSAGE(0, dev_addr, "Device not enumerated"); usb_device_handle_t client0_dev_hdl; usb_device_handle_t client1_dev_hdl; printf("Opening device\n");