Skip to content

Commit 7c7d2a9

Browse files
committed
refactor(tinyusb): Changed the tinyusb task deletion to notification
1 parent 6757c6e commit 7c7d2a9

File tree

1 file changed

+74
-25
lines changed

1 file changed

+74
-25
lines changed

device/esp_tinyusb/tinyusb_task.c

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ typedef struct {
4040
tusb_rhport_init_t rhport_init; /*!< USB Device RH port initialization configuration pointer */
4141
const tinyusb_desc_config_t *desc_cfg; /*!< USB Device descriptors configuration pointer */
4242
// Task related
43-
TaskHandle_t handle; /*!< Task handle */
44-
volatile TaskHandle_t awaiting_handle; /*!< Task handle, waiting to be notified after successful start of TinyUSB stack */
43+
TaskHandle_t handle; /*!< TinyUSB Device task handle */
44+
SemaphoreHandle_t start_stop_sem; /*!< Semaphore to start or stop the task */
4545
} tinyusb_task_ctx_t;
4646

47-
static bool _task_is_running = false; // Locking flag for the task, access only from the critical section
47+
#define TASK_NOTIF_STOP_BIT (1u << 0)
48+
49+
static bool _task_is_pending = false; // Locking flag for the task, access only from the critical section
4850
static tinyusb_task_ctx_t *p_tusb_task_ctx = NULL; // TinyUSB task context
4951

5052
/**
@@ -53,10 +55,11 @@ static tinyusb_task_ctx_t *p_tusb_task_ctx = NULL; // TinyUSB task context
5355
static void tinyusb_device_task(void *arg)
5456
{
5557
tinyusb_task_ctx_t *task_ctx = (tinyusb_task_ctx_t *)arg;
58+
bool pending_stop = false;
5659

5760
// Sanity check
5861
assert(task_ctx != NULL);
59-
assert(task_ctx->awaiting_handle != NULL);
62+
assert(task_ctx->start_stop_sem != NULL);
6063

6164
ESP_LOGD(TAG, "TinyUSB task started");
6265

@@ -74,22 +77,55 @@ static void tinyusb_device_task(void *arg)
7477
}
7578

7679
TINYUSB_TASK_ENTER_CRITICAL();
77-
task_ctx->handle = xTaskGetCurrentTaskHandle(); // Save task handle
78-
p_tusb_task_ctx = task_ctx; // Save global task context pointer
80+
_task_is_pending = false;
81+
task_ctx->handle = xTaskGetCurrentTaskHandle(); // Save task handle
82+
p_tusb_task_ctx = task_ctx; // Save global task context pointer
7983
TINYUSB_TASK_EXIT_CRITICAL();
8084

81-
xTaskNotifyGive(task_ctx->awaiting_handle); // Notify parent task that TinyUSB stack was started successfully
85+
// Notify parent task that TinyUSB stack was started successfully
86+
if (xSemaphoreGive(task_ctx->start_stop_sem) != pdTRUE) {
87+
// Fail only if semaphore queue is full, should never happen
88+
ESP_LOGE(TAG, "Unable to notify that TinyUSB stack was started");
89+
goto desc_free;
90+
}
91+
92+
while (1) {
93+
// Non-blocking check to stop the task
94+
uint32_t notif = 0;
95+
if (xTaskNotifyWait(
96+
0, // don't clear any bits on entry
97+
TASK_NOTIF_STOP_BIT, // clear STOP bit on exit if it was set
98+
&notif,
99+
0 // no wait; just poll the bit
100+
) == pdTRUE && (notif & TASK_NOTIF_STOP_BIT)) {
101+
// Stop requested
102+
pending_stop = true;
103+
break;
104+
}
105+
// TinyUSB Device task
106+
tud_task_ext(2000 /* TODO: make dynamically configurable */, false);
107+
}
108+
109+
ESP_LOGD(TAG, "TinyUSB task is stopping");
82110

83-
while (1) { // RTOS forever loop
84-
tud_task();
111+
if (!tusb_rhport_teardown(task_ctx->rhport)) {
112+
ESP_LOGE(TAG, "Unable to teardown TinyUSB stack");
113+
// What to do if teardown failed?
114+
return;
85115
}
86116

87117
desc_free:
88118
tinyusb_descriptors_free();
89119
del:
90120
TINYUSB_TASK_ENTER_CRITICAL();
91-
_task_is_running = false; // Task is not running anymore
121+
_task_is_pending = false; // Task is not running anymore
122+
p_tusb_task_ctx = NULL; // Clear global task context pointer
92123
TINYUSB_TASK_EXIT_CRITICAL();
124+
125+
if (pending_stop) {
126+
// Notify that TinyUSB stack was stopped
127+
xSemaphoreGive(task_ctx->start_stop_sem);
128+
}
93129
vTaskDelete(NULL);
94130
// No return needed here: vTaskDelete(NULL) does not return
95131
}
@@ -113,8 +149,8 @@ esp_err_t tinyusb_task_start(tinyusb_port_t port, const tinyusb_task_config_t *c
113149

114150
TINYUSB_TASK_ENTER_CRITICAL();
115151
TINYUSB_TASK_CHECK_FROM_CRIT(p_tusb_task_ctx == NULL, ESP_ERR_INVALID_STATE); // Task shouldn't started
116-
TINYUSB_TASK_CHECK_FROM_CRIT(!_task_is_running, ESP_ERR_INVALID_STATE); // Task shouldn't be running
117-
_task_is_running = true; // Task is running flag, will be cleared in task in case of the error
152+
TINYUSB_TASK_CHECK_FROM_CRIT(!_task_is_pending, ESP_ERR_INVALID_STATE); // Task shouldn't be pending
153+
_task_is_pending = true; // Task is running flag, will be cleared in task in case of the error
118154
TINYUSB_TASK_EXIT_CRITICAL();
119155

120156
esp_err_t ret;
@@ -123,8 +159,13 @@ esp_err_t tinyusb_task_start(tinyusb_port_t port, const tinyusb_task_config_t *c
123159
return ESP_ERR_NO_MEM;
124160
}
125161

126-
task_ctx->awaiting_handle = xTaskGetCurrentTaskHandle(); // Save parent task handle
127-
task_ctx->handle = NULL; // TinyUSB task is not started
162+
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
163+
if (sem == NULL) {
164+
ret = ESP_ERR_NO_MEM;
165+
goto err;
166+
}
167+
168+
task_ctx->start_stop_sem = sem; // TunyUSB Device task start stop semaphore
128169
task_ctx->rhport = port; // Peripheral port number
129170
task_ctx->rhport_init.role = TUSB_ROLE_DEVICE; // Role selection: esp_tinyusb is always a device
130171
task_ctx->rhport_init.speed = (port == TINYUSB_PORT_FULL_SPEED_0) ? TUSB_SPEED_FULL : TUSB_SPEED_HIGH; // Speed selection
@@ -147,7 +188,7 @@ esp_err_t tinyusb_task_start(tinyusb_port_t port, const tinyusb_task_config_t *c
147188
}
148189

149190
// Wait until the Task notify that port is active, 5 sec is more than enough
150-
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5000)) == 0) {
191+
if (xSemaphoreTake(task_ctx->start_stop_sem, pdMS_TO_TICKS(5000)) != pdTRUE) {
151192
ESP_LOGE(TAG, "Task wasn't able to start TinyUSB stack");
152193
ret = ESP_ERR_TIMEOUT;
153194
goto err;
@@ -156,6 +197,9 @@ esp_err_t tinyusb_task_start(tinyusb_port_t port, const tinyusb_task_config_t *c
156197
return ESP_OK;
157198

158199
err:
200+
if (sem) {
201+
vSemaphoreDelete(sem);
202+
}
159203
heap_caps_free(task_ctx);
160204
return ret;
161205
}
@@ -164,20 +208,25 @@ esp_err_t tinyusb_task_stop(void)
164208
{
165209
TINYUSB_TASK_ENTER_CRITICAL();
166210
TINYUSB_TASK_CHECK_FROM_CRIT(p_tusb_task_ctx != NULL, ESP_ERR_INVALID_STATE);
211+
TINYUSB_TASK_CHECK_FROM_CRIT(!_task_is_pending, ESP_ERR_INVALID_STATE); // Task shouldn't be pending
167212
tinyusb_task_ctx_t *task_ctx = p_tusb_task_ctx;
168-
p_tusb_task_ctx = NULL;
169-
_task_is_running = false;
213+
_task_is_pending = true; // Task is pending to stop
170214
TINYUSB_TASK_EXIT_CRITICAL();
171215

172-
if (task_ctx->handle != NULL) {
173-
vTaskDelete(task_ctx->handle);
174-
task_ctx->handle = NULL;
216+
/* Request TinyUSB task to stop */
217+
if (xTaskNotify(task_ctx->handle, TASK_NOTIF_STOP_BIT, eSetBits) != pdPASS) {
218+
ESP_LOGE(TAG, "Unable to notify TinyUSB task to stop");
219+
return ESP_ERR_INVALID_STATE;
175220
}
176-
// Free descriptors
177-
tinyusb_descriptors_free();
178-
// Stop TinyUSB stack
179-
ESP_RETURN_ON_FALSE(tusb_rhport_teardown(task_ctx->rhport), ESP_ERR_NOT_FINISHED, TAG, "Unable to teardown TinyUSB stack");
180-
// Cleanup
221+
222+
/* Wait for "stop" semaphore with timeout, usually 5 sec is enough */
223+
if (xSemaphoreTake(task_ctx->start_stop_sem, pdMS_TO_TICKS(5000)) != pdTRUE) {
224+
ESP_LOGE(TAG, "Timeout while TinyUSB task stop");
225+
return ESP_ERR_TIMEOUT;
226+
}
227+
228+
/* Cleanup */
229+
vSemaphoreDelete(task_ctx->start_stop_sem);
181230
heap_caps_free(task_ctx);
182231
return ESP_OK;
183232
}

0 commit comments

Comments
 (0)