Skip to content
Draft
5 changes: 5 additions & 0 deletions .github/workflows/build_and_run_main_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_and_run_test_app_usb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion .github/workflows/build_idf_examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name: Build ESP-IDF USB examples

on:
pull_request:
types: [opened, reopened, synchronize]
types: [opened, reopened]

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions device/esp_tinyusb/test_apps/cdc/pytest_cdc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 1 addition & 1 deletion host/class/msc/usb_host_msc/test_app/main/test_app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
22 changes: 16 additions & 6 deletions host/usb/test/target_test/usb_host/main/ctrl_client_async_seq.c
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
12 changes: 10 additions & 2 deletions host/usb/test/target_test/usb_host/main/msc_client_async_dconn.c
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
11 changes: 9 additions & 2 deletions host/usb/test/target_test/usb_host/main/msc_client_async_enum.c
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
22 changes: 16 additions & 6 deletions host/usb/test/target_test/usb_host/main/msc_client_async_seq.c
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
11 changes: 9 additions & 2 deletions host/usb/test/target_test/usb_host/main/multiconf_client_async.c
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
13 changes: 12 additions & 1 deletion host/usb/test/target_test/usb_host/main/test_usb_host_async.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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:
Expand Down Expand Up @@ -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");
Expand Down
Loading