Skip to content

Commit 6ec9db1

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 6ec9db1

File tree

2 files changed

+158
-21
lines changed

2 files changed

+158
-21
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: 116 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,66 +29,161 @@
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();
4451
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
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+
}
75+
76+
// Notify the parent task that the task completed the job
77+
xSemaphoreGive(sem_done);
78+
// Delete task
79+
vTaskDelete(NULL);
80+
}
81+
82+
// USB PHY
83+
84+
static usb_phy_handle_t test_init_phy(void)
6385
{
6486
usb_phy_handle_t phy_hdl = NULL;
65-
// Install the PHY externally
6687
usb_phy_config_t phy_conf = {
6788
.controller = USB_PHY_CTRL_OTG,
6889
.target = USB_PHY_TARGET_INT,
6990
.otg_mode = USB_OTG_MODE_DEVICE,
7091
};
7192
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_conf, &phy_hdl), "Unable to install USB PHY ");
93+
return phy_hdl;
94+
}
95+
96+
static void test_deinit_phy(usb_phy_handle_t phy_hdl)
97+
{
98+
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Unable to delete USB PHY ");
99+
}
72100

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

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

188+
94189
#endif // SOC_USB_OTG_SUPPORTED

0 commit comments

Comments
 (0)