Skip to content

Commit 0c6cf9e

Browse files
committed
refactor(esp_tinyusb): runtime_config test applicaton, multitask access test
- Fixed concurrent access to the nb_of_success var from several tasks - Changed the logic of getting notification from the worker thread to sem_done - Added the test case for uninstall the tinyusb driver via several tasks - Added README.md
1 parent 26c84d9 commit 0c6cf9e

File tree

2 files changed

+161
-22
lines changed

2 files changed

+161
-22
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
2+
| ----------------- | -------- | -------- | -------- | -------- |
3+
4+
# Espressif's Additions to TinyUSB - Runtime Configuration Test Application
5+
6+
This directory contains Unity tests that validate Espressif-specific integration of TinyUSB.
7+
8+
The tests focus on:
9+
10+
- TinyUSB configuration helpers (default macros, per-port config).
11+
- USB Device descriptors (FS/HS, string descriptors, edge cases).
12+
- USB peripheral / PHY configuration for full-speed and high-speed.
13+
- TinyUSB task configuration (CPU pinning, invalid parameters).
14+
- Multitask access to the TinyUSB driver (concurrent installs).
15+
16+
The test prints a numbered menu, for example:
17+
18+
```
19+
(1) "Config: Default macros arguments" [runtime_config][default]
20+
(2) "Config: Full-speed (High-speed)" [runtime_config][full_speed]
21+
...
22+
```
23+
24+
You can run all tests by running `pytest` or select individual ones by name and number.
25+
26+
## Tags
27+
28+
Each test is tagged with categories and modes:
29+
30+
### Categories
31+
32+
- [runtime_config] – Tests focusing on `tinyusb_config_t` and runtime configuration.
33+
- [periph] – Tests that directly exercise the USB peripheral (USB OTG 1.1 or USB OTG 2.0).
34+
- [task] – Tests related to the dedicated TinyUSB task configuration.
35+
36+
### Speed / Mode
37+
38+
- [default] – Generic, target-agnostic.
39+
- [full_speed] – Tests specific to USB OTG 1.1 / Full-speed port.
40+
- [high_speed] – Tests specific to USB OTG 2.0 / High-speed port.
41+
42+
These tags can be used by test runners / CI to select or filter tests.

device/esp_tinyusb/test_apps/runtime_config/main/test_multitask_access.c

Lines changed: 119 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,66 +29,163 @@
2929

3030
#define MULTIPLE_THREADS_TASKS_NUM 5
3131

32-
static int nb_of_success = 0;
32+
static SemaphoreHandle_t sem_done = NULL;
33+
TaskHandle_t test_task_handles[MULTIPLE_THREADS_TASKS_NUM];
34+
35+
// Unlocked spinlock, ready to use
36+
static portMUX_TYPE _spinlock = portMUX_INITIALIZER_UNLOCKED;
37+
static volatile int nb_of_success = 0;
3338

3439
static void test_task_install(void *arg)
3540
{
36-
TaskHandle_t parent_task_handle = (TaskHandle_t)arg;
37-
41+
(void) arg;
3842
// Install TinyUSB driver
3943
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(test_device_event_handler);
4044
tusb_cfg.phy.skip_setup = true; // Skip phy setup to allow multiple tasks to install the driver
4145

46+
// Wait to be started by main thread
47+
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
48+
4249
if (tinyusb_driver_install(&tusb_cfg) == ESP_OK) {
4350
test_device_wait();
44-
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
51+
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, tinyusb_driver_uninstall(), "Unable to uninstall driver after install in worker");
52+
taskENTER_CRITICAL(&_spinlock);
4553
nb_of_success++;
54+
taskEXIT_CRITICAL(&_spinlock);
4655
}
4756

4857
// Notify the parent task that the task completed the job
49-
xTaskNotifyGive(parent_task_handle);
58+
xSemaphoreGive(sem_done);
5059
// Delete task
5160
vTaskDelete(NULL);
5261
}
5362

54-
// ============================= Tests =========================================
5563

56-
/**
57-
* @brief TinyUSB Task specific testcase
58-
*
59-
* Scenario: Trying to install driver from several tasks
60-
* Note: when skip_phy_setup = false, the task access will be determined by the first task install the phy
61-
*/
62-
TEST_CASE("Multitask: Install", "[runtime_config][full_speed][high_speed]")
64+
static void test_task_uninstall(void *arg)
65+
{
66+
(void) arg;
67+
// Wait to be started by main thread
68+
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
69+
70+
if (tinyusb_driver_uninstall() == ESP_OK) {
71+
taskENTER_CRITICAL(&_spinlock);
72+
nb_of_success++;
73+
taskEXIT_CRITICAL(&_spinlock);
74+
} else {
75+
TEST_ASSERT_TRUE_MESSAGE(true, "Unable to uninstall driver in worker");
76+
}
77+
78+
// Notify the parent task that the task completed the job
79+
xSemaphoreGive(sem_done);
80+
// Delete task
81+
vTaskDelete(NULL);
82+
}
83+
84+
// USB PHY
85+
86+
static usb_phy_handle_t test_init_phy(void)
6387
{
6488
usb_phy_handle_t phy_hdl = NULL;
65-
// Install the PHY externally
6689
usb_phy_config_t phy_conf = {
6790
.controller = USB_PHY_CTRL_OTG,
6891
.target = USB_PHY_TARGET_INT,
6992
.otg_mode = USB_OTG_MODE_DEVICE,
7093
};
7194
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_conf, &phy_hdl), "Unable to install USB PHY ");
95+
return phy_hdl;
96+
}
97+
98+
static void test_deinit_phy(usb_phy_handle_t phy_hdl)
99+
{
100+
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Unable to delete USB PHY ");
101+
}
72102

103+
// ============================= Tests =========================================
104+
105+
/**
106+
* @brief TinyUSB Task specific testcase
107+
*
108+
* Scenario: Trying to install driver from several tasks
109+
* Note: when phy.skip_setup = false, the task access will be determined by the first task install the phy
110+
*/
111+
TEST_CASE("Multitask: Install", "[runtime_config][default]")
112+
{
113+
usb_phy_handle_t phy_hdl = test_init_phy();
114+
115+
// Create counting semaphore to wait for all tasks to complete
116+
sem_done = xSemaphoreCreateCounting(MULTIPLE_THREADS_TASKS_NUM, 0);
117+
TEST_ASSERT_NOT_NULL(sem_done);
118+
119+
// No task are running yet
73120
nb_of_success = 0;
121+
74122
// Create tasks that will start the driver
75123
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
76-
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreate(test_task_install,
124+
TEST_ASSERT_EQUAL(pdPASS, xTaskCreate(test_task_install,
77125
"InstallTask",
78126
4096,
79-
(void *) xTaskGetCurrentTaskHandle(),
127+
NULL,
80128
4 + i,
81-
NULL));
129+
&test_task_handles[i]));
130+
}
131+
132+
// Start all tasks
133+
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
134+
xTaskNotifyGive(test_task_handles[i]);
135+
}
136+
137+
// Wait for all tasks to complete
138+
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
139+
TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, xSemaphoreTake(sem_done, pdMS_TO_TICKS(5000)), "Not all tasks completed in time");
82140
}
83141

84-
// Wait until all tasks are finished
85-
vTaskDelay(pdMS_TO_TICKS(5000));
86-
// Check if all tasks finished, we should get all notification from the tasks
87-
TEST_ASSERT_EQUAL_MESSAGE(MULTIPLE_THREADS_TASKS_NUM, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5000)), "Not all tasks finished");
88142
// There should be only one task that was able to install the driver
89143
TEST_ASSERT_EQUAL_MESSAGE(1, nb_of_success, "Only one task should be able to install the driver");
90144
// Clean-up
91-
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Unable to delete PHY");
145+
test_deinit_phy(phy_hdl);
146+
vSemaphoreDelete(sem_done);
147+
}
148+
149+
TEST_CASE("Multitask: Uninstall", "[runtime_config][default]")
150+
{
151+
usb_phy_handle_t phy_hdl = test_init_phy();
152+
// Create counting semaphore to wait for all tasks to complete
153+
sem_done = xSemaphoreCreateCounting(MULTIPLE_THREADS_TASKS_NUM, 0);
154+
TEST_ASSERT_NOT_NULL(sem_done);
155+
156+
// No task are running yet
157+
nb_of_success = 0;
158+
159+
// Install the driver once
160+
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(test_device_event_handler);
161+
tusb_cfg.phy.skip_setup = true; // Skip phy setup to allow multiple tasks
162+
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, tinyusb_driver_install(&tusb_cfg), "Unable to install TinyUSB driver ");
163+
// Create tasks that will uninstall the driver
164+
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
165+
TEST_ASSERT_EQUAL(pdPASS, xTaskCreate(test_task_uninstall,
166+
"UninstallTask",
167+
4096,
168+
NULL,
169+
4 + i,
170+
&test_task_handles[i]));
171+
}
172+
173+
// Start all tasks
174+
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
175+
xTaskNotifyGive(test_task_handles[i]);
176+
}
177+
// Wait for all tasks to complete
178+
for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) {
179+
TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, xSemaphoreTake(sem_done, pdMS_TO_TICKS(5000)), "Not all tasks completed in time");
180+
}
181+
182+
// There should be only one task that was able to uninstall the driver
183+
TEST_ASSERT_EQUAL_MESSAGE(1, nb_of_success, "Only one task should be able to uninstall the driver");
184+
185+
// Clean-up
186+
test_deinit_phy(phy_hdl);
187+
vSemaphoreDelete(sem_done);
92188
}
93189

190+
94191
#endif // SOC_USB_OTG_SUPPORTED

0 commit comments

Comments
 (0)