Skip to content

Commit ed807e4

Browse files
committed
feat(esp_msc_ota): add skip_msc_connect_wait config
Closes #429
1 parent b2cd32d commit ed807e4

File tree

8 files changed

+122
-39
lines changed

8 files changed

+122
-39
lines changed

components/.build-rules.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ components/touch/touch_proximity_sensor/test_apps:
1212

1313
components/usb/esp_msc_ota/test_apps:
1414
enable:
15-
- if: SOC_USB_OTG_SUPPORTED == 1
15+
- if: IDF_TARGET in ["esp32s3"]
1616

1717
components/usb/usb_stream/test_apps:
1818
enable:

components/usb/esp_msc_ota/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# changelog
22

3+
## v1.1.0 - 2024-12-24
4+
5+
* Add the `skip_msc_connect_wait` configuration to allow users to mount the file system manually.
6+
37
## v1.0.0 - 2024-8-15
48

59
* Publish the official version

components/usb/esp_msc_ota/esp_msc_host.c

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ static const char *TAG = "esp_msc_host";
1717

1818
ESP_EVENT_DEFINE_BASE(ESP_MSC_HOST_EVENT);
1919
SemaphoreHandle_t msc_read_semaphore;
20-
2120
typedef struct {
21+
usb_host_config_t host_config;
22+
TaskHandle_t task_handle;
2223
EventGroupHandle_t usb_flags;
2324
const char *base_path;
2425
esp_vfs_fat_mount_config_t mount_config;
@@ -150,24 +151,41 @@ static void msc_host_task(void *args)
150151
static void usb_event_task(void *args)
151152
{
152153
esp_msc_host_t *msc_host = (esp_msc_host_t *)args;
154+
155+
// Install USB Host driver. Should only be called once in entire application
156+
esp_err_t err = usb_host_install(&msc_host->host_config);
157+
if (err != ESP_OK) {
158+
ESP_LOGE(TAG, "Failed to install USB Host library");
159+
vTaskDelete(NULL);
160+
}
161+
xTaskNotifyGive(msc_host->task_handle);
162+
153163
bool has_clients = true;
154-
while (1) {
164+
bool has_devices = false;
165+
while (has_clients) {
155166
uint32_t event_flags;
156-
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
157-
158-
// Release devices once all clients has deregistered
167+
ESP_ERROR_CHECK(usb_host_lib_handle_events(portMAX_DELAY, &event_flags));
159168
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
160-
has_clients = false;
161-
if (usb_host_device_free_all() == ESP_OK) {
162-
break;
169+
ESP_LOGI(TAG, "Get FLAGS_NO_CLIENTS");
170+
if (ESP_OK == usb_host_device_free_all()) {
171+
ESP_LOGI(TAG, "All devices marked as free, no need to wait FLAGS_ALL_FREE event");
172+
has_clients = false;
173+
} else {
174+
ESP_LOGI(TAG, "Wait for the FLAGS_ALL_FREE");
175+
has_devices = true;
163176
}
164177
}
165-
// can be deinitialized, and terminate this task.
166-
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE && !has_clients) {
167-
break;
178+
if (has_devices && event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
179+
ESP_LOGI(TAG, "Get FLAGS_ALL_FREE");
180+
has_clients = false;
168181
}
169182
}
183+
ESP_LOGI(TAG, "No more clients and devices, uninstall USB Host library");
170184

185+
// Clean up USB Host
186+
vTaskDelay(100); // Short delay to allow clients clean-up
187+
usb_host_uninstall();
188+
ESP_LOGD(TAG, "USB Host library is uninstalled");
171189
xEventGroupSetBits(msc_host->usb_flags, HOST_UNINSTALL);
172190
vTaskDelete(NULL);
173191
}
@@ -192,8 +210,8 @@ esp_err_t esp_msc_host_install(esp_msc_host_config_t *config, esp_msc_host_handl
192210
msc_host->usb_flags = xEventGroupCreate();
193211
MSC_OTA_CHECK_GOTO(msc_host->usb_flags != NULL, "Failed to create event group", install_fail);
194212

195-
err = usb_host_install(&config->host_config);
196-
MSC_OTA_CHECK_GOTO(err == ESP_OK, "Failed to install USB host", install_fail);
213+
msc_host->host_config = config->host_config;
214+
msc_host->task_handle = xTaskGetCurrentTaskHandle();
197215

198216
MSC_OTA_CHECK_CONTINUE(config->host_driver_config.callback == NULL, "The specified callback will be overridden by the internal callback function");
199217
msc_host_driver_config_t msc_config = {0};
@@ -202,27 +220,26 @@ esp_err_t esp_msc_host_install(esp_msc_host_config_t *config, esp_msc_host_handl
202220
msc_config.callback_arg = msc_host;
203221

204222
BaseType_t task_created = xTaskCreate(usb_event_task, "usb_event", 4096, msc_host, 2, NULL);
205-
MSC_OTA_CHECK_GOTO(task_created == pdPASS, "Failed to create USB events task", usb_install_fail);
223+
MSC_OTA_CHECK_GOTO(task_created == pdPASS, "Failed to create USB events task", install_fail);
224+
uint32_t notify_value = ulTaskNotifyTake(false, pdMS_TO_TICKS(1000));
225+
MSC_OTA_CHECK_GOTO(notify_value != 0, "USB host library not installed", install_fail);
206226

207227
err = msc_host_install(&msc_config);
208-
MSC_OTA_CHECK_GOTO(err == ESP_OK, "Failed to install MSC host", usb_install_fail);
228+
MSC_OTA_CHECK_GOTO(err == ESP_OK, "Failed to install MSC host", install_fail);
209229

210230
task_created = xTaskCreate(msc_host_task, "msc_host", 4096, msc_host, 5, NULL);
211231
MSC_OTA_CHECK_GOTO(task_created == pdPASS, "Failed to create MSC host task", msc_install_fail);
212232

213233
*handle = (esp_msc_host_handle_t)msc_host;
214234
q_msc_host = msc_host;
215235

216-
ESP_LOGI(TAG, "MSC Host Install Done\n");
236+
ESP_LOGI(TAG, "MSC Host Install Done");
217237
return ESP_OK;
218238

219239
msc_install_fail:
220240
msc_host_uninstall();
221241
wait_for_event(msc_host->usb_flags, HOST_UNINSTALL, portMAX_DELAY);
222242

223-
usb_install_fail:
224-
usb_host_uninstall();
225-
226243
install_fail:
227244
if (msc_host->usb_flags != NULL) {
228245
vEventGroupDelete(msc_host->usb_flags);
@@ -243,7 +260,6 @@ esp_err_t esp_msc_host_uninstall(esp_msc_host_handle_t handle)
243260
ESP_LOGI(TAG, "Please remove the USB flash drive.");
244261
xEventGroupSetBits(msc_host->usb_flags, HOST_TOBE_UNINSTALL);
245262
wait_for_event(msc_host->usb_flags, HOST_UNINSTALL, portMAX_DELAY);
246-
usb_host_uninstall();
247263
if (msc_host->usb_flags != NULL) {
248264
vEventGroupDelete(msc_host->usb_flags);
249265
}

components/usb/esp_msc_ota/esp_msc_ota.c

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -29,6 +29,29 @@ _Static_assert(DEFAULT_OTA_BUF_SIZE > (sizeof(esp_image_header_t) + sizeof(esp_i
2929
/* Setting event group */
3030
#define MSC_CONNECT (1 << 0) // MSC device connect
3131

32+
/**
33+
* @brief To prevent the VFS from being unregistered during file read and write operations.
34+
*
35+
* @param semaphore Semaphore to take.
36+
* @return esp_err_t
37+
* - ESP_OK on success or if the semaphore is NULL.
38+
* - ESP_FAIL if taking the semaphore fails.
39+
*/
40+
#define SEMAPHORE_TAKE(semaphore) \
41+
((semaphore == NULL) ? ESP_OK : \
42+
((xSemaphoreTake(semaphore, pdMS_TO_TICKS(10)) == pdTRUE) ? ESP_OK : ESP_FAIL))
43+
44+
/**
45+
* @brief To prevent the VFS from being unregistered during file read and write operations.
46+
*
47+
* @param semaphore Semaphore to give.
48+
* @return esp_err_t
49+
* - ESP_OK on success or if the semaphore is NULL.
50+
*/
51+
#define SEMAPHORE_GIVE(semaphore) \
52+
((semaphore == NULL) ? ESP_OK : \
53+
(xSemaphoreGive(semaphore), ESP_OK))
54+
3255
typedef struct {
3356
EventGroupHandle_t mscEventGroup;
3457
bool bulk_flash_erase;
@@ -107,6 +130,7 @@ esp_msc_ota_status_t esp_msc_ota_get_status(esp_msc_ota_handle_t handle)
107130

108131
static esp_err_t _read_header(esp_msc_ota_t *msc_ota)
109132
{
133+
esp_err_t err = ESP_OK;
110134
EventBits_t bits = xEventGroupWaitBits(msc_ota->mscEventGroup, MSC_CONNECT, pdFALSE, pdFALSE, 0);
111135
MSC_OTA_CHECK(bits & MSC_CONNECT, "msc can't be disconnect", ESP_ERR_INVALID_STATE);
112136
/*
@@ -115,6 +139,8 @@ static esp_err_t _read_header(esp_msc_ota_t *msc_ota)
115139
int data_read_size = IMAGE_HEADER_SIZE;
116140
int data_read = 0;
117141

142+
err = SEMAPHORE_TAKE(msc_read_semaphore);
143+
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
118144
FILE *file = fopen(msc_ota->ota_bin_path, "rb");
119145
MSC_OTA_CHECK(file != NULL, "Failed to open file for reading", ESP_ERR_NOT_FOUND);
120146

@@ -125,27 +151,28 @@ static esp_err_t _read_header(esp_msc_ota_t *msc_ota)
125151
data_read_size = data_read_size > fileLength ? fileLength : data_read_size;
126152
ESP_LOGI(TAG, "Reading file %s, size: %d, total size: %"PRIu32"", msc_ota->ota_bin_path, data_read_size, fileLength);
127153

128-
BaseType_t ret = xSemaphoreTake(msc_read_semaphore, pdMS_TO_TICKS(10));
129-
MSC_OTA_CHECK(ret == pdTRUE, "take msc_read_semaphore failed", ESP_FAIL);
130154
data_read = fread(msc_ota->ota_upgrade_buf, 1, data_read_size, file);
131-
xSemaphoreGive(msc_read_semaphore);
132155

133156
if (data_read == data_read_size) {
134157
msc_ota->binary_file_read_len = data_read;
135-
fclose(file);
136-
return ESP_OK;
158+
err = ESP_OK;
159+
goto file_close;
137160
} else if (data_read > 0 && data_read < data_read_size) {
138161
msc_ota->binary_file_read_len = data_read;
139-
fclose(file);
140-
return ESP_OK;
162+
err = ESP_OK;
163+
goto file_close;
141164
} else if (ferror(file)) {
165+
err = ESP_FAIL;
142166
ESP_LOGI(TAG, "Error reading from file");
143167
} else if (feof(file)) {
144-
ESP_LOGI(TAG, "End of file reached.\n");
168+
err = ESP_FAIL;
169+
ESP_LOGI(TAG, "End of file reached.");
145170
}
146171

172+
file_close:
147173
fclose(file);
148-
return ESP_FAIL;
174+
SEMAPHORE_GIVE(msc_read_semaphore);
175+
return err;
149176
}
150177

151178
static esp_err_t _ota_verify_chip_id(const void *arg)
@@ -198,9 +225,14 @@ esp_err_t esp_msc_ota_begin(esp_msc_ota_config_t *config, esp_msc_ota_handle_t *
198225

199226
esp_event_handler_register(ESP_MSC_HOST_EVENT, ESP_EVENT_ANY_ID, &_esp_msc_host_handler, msc_ota);
200227

201-
ESP_LOGI(TAG, "Waiting for MSC device to connect...");
202-
EventBits_t bits = xEventGroupWaitBits(msc_ota->mscEventGroup, MSC_CONNECT, pdFALSE, pdFALSE, config->wait_msc_connect);
203-
MSC_OTA_CHECK_GOTO(bits & MSC_CONNECT, "TIMEOUT: MSC device not connected", msc_cleanup);
228+
if (!config->skip_msc_connect_wait) {
229+
ESP_LOGI(TAG, "Waiting for MSC device to connect...");
230+
EventBits_t bits = xEventGroupWaitBits(msc_ota->mscEventGroup, MSC_CONNECT, pdFALSE, pdFALSE, config->wait_msc_connect);
231+
MSC_OTA_CHECK_GOTO(bits & MSC_CONNECT, "TIMEOUT: MSC device not connected", msc_cleanup);
232+
} else {
233+
xEventGroupSetBits(msc_ota->mscEventGroup, MSC_CONNECT);
234+
ESP_LOGI(TAG, "skip_msc_connect_wait is true, set MSC_CONNECT event directly");
235+
}
204236

205237
msc_ota->update_partition = NULL;
206238
ESP_LOGI(TAG, "Starting OTA...");
@@ -272,20 +304,23 @@ esp_err_t esp_msc_ota_perform(esp_msc_ota_handle_t handle)
272304
MSC_OTA_CHECK(bits & MSC_CONNECT, "msc can't be disconnect", ESP_ERR_INVALID_STATE);
273305
if (msc_ota->file == NULL) {
274306

307+
err = SEMAPHORE_TAKE(msc_read_semaphore);
308+
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
275309
FILE *file = fopen(msc_ota->ota_bin_path, "rb");
276310
MSC_OTA_CHECK(file != NULL, "Failed to open file for reading", ESP_ERR_NOT_FOUND);
277311
fseek(file, msc_ota->binary_file_read_len, SEEK_CUR);
312+
SEMAPHORE_GIVE(msc_read_semaphore);
278313
msc_ota->file = file;
279314
}
280315
uint32_t *fileLength = &msc_ota->binary_file_read_len;
281316
uint32_t *totalLength = &msc_ota->binary_file_len;
282317
if (*fileLength < *totalLength) {
283318
size_t readLength = *fileLength > msc_ota->ota_upgrade_buf_size ? msc_ota->ota_upgrade_buf_size : *fileLength;
284319

285-
BaseType_t ret = xSemaphoreTake(msc_read_semaphore, pdMS_TO_TICKS(10));
286-
MSC_OTA_CHECK(ret == pdTRUE, "take msc_read_semaphore failed", ESP_FAIL);
320+
err = SEMAPHORE_TAKE(msc_read_semaphore);
321+
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
287322
data_read = fread(msc_ota->ota_upgrade_buf, 1, readLength, msc_ota->file);
288-
xSemaphoreGive(msc_read_semaphore);
323+
SEMAPHORE_GIVE(msc_read_semaphore);
289324

290325
MSC_OTA_CHECK(data_read > 0, "Failed to read file", ESP_ERR_INVALID_SIZE);
291326
err = esp_ota_write(msc_ota->update_handle, (const void *)msc_ota->ota_upgrade_buf, data_read);
@@ -299,7 +334,10 @@ esp_err_t esp_msc_ota_perform(esp_msc_ota_handle_t handle)
299334
}
300335
if (*fileLength >= *totalLength) {
301336
msc_ota->status = ESP_MSC_OTA_SUCCESS;
337+
err = SEMAPHORE_TAKE(msc_read_semaphore);
338+
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
302339
fclose(msc_ota->file);
340+
SEMAPHORE_GIVE(msc_read_semaphore);
303341
return ESP_OK;
304342
}
305343
return ESP_OK;
@@ -338,6 +376,7 @@ esp_err_t esp_msc_ota_end(esp_msc_ota_handle_t handle)
338376
}
339377
}
340378
esp_event_handler_unregister(ESP_MSC_HOST_EVENT, ESP_EVENT_ANY_ID, &_esp_msc_host_handler);
379+
vEventGroupDelete(msc_ota->mscEventGroup);
341380
free(msc_ota);
342381
esp_msc_ota_dispatch_event(ESP_MSC_OTA_FINISH, NULL, 0);
343382
return err;
@@ -353,7 +392,10 @@ esp_err_t esp_msc_ota_abort(esp_msc_ota_handle_t handle)
353392
case ESP_MSC_OTA_SUCCESS:
354393
case ESP_MSC_OTA_IN_PROGRESS:
355394
if (msc_ota->file) {
395+
err = SEMAPHORE_TAKE(msc_read_semaphore);
396+
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
356397
fclose(msc_ota->file);
398+
SEMAPHORE_GIVE(msc_read_semaphore);
357399
}
358400
err = esp_ota_abort(msc_ota->update_handle);
359401
[[fallthrough]];

components/usb/esp_msc_ota/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "1.0.0"
1+
version: "1.1.0"
22
targets:
33
- esp32s2
44
- esp32s3

components/usb/esp_msc_ota/include/esp_msc_ota.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ typedef enum {
5252
typedef struct {
5353
const char *ota_bin_path; /*!< OTA binary name, must be an exact match. Note: By default file names cannot exceed 11 bytes e.g. "/usb/ota.bin" */
5454
bool bulk_flash_erase; /*!< Erase entire flash partition during initialization. By default flash partition is erased during write operation and in chunk of 4K sector size */
55+
bool skip_msc_connect_wait; /*!< Skip waiting for MSC device to connect, if true means MSC device is already connected */
5556
TickType_t wait_msc_connect; /*!< Wait time for MSC device to connect */
5657
size_t buffer_size; /*!< Buffer size for OTA write operation, must larger than 1024 */
5758
} esp_msc_ota_config_t;
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
dependencies:
2-
idf: ">=5.0"
2+
idf: '>=5.0'
3+
espressif/esp32_s3_usb_otg: ^1.6.1

components/usb/esp_msc_ota/test_apps/main/test_msc_ota.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "esp_msc_host.h"
1919
#include "esp_msc_ota.h"
2020
#include "usb/usb_host.h"
21+
#include "bsp/esp-bsp.h"
2122

2223
static const char *TAG = "esp_msc_ota_test";
2324

@@ -207,3 +208,21 @@ TEST_CASE("Auto MSC OTA", "[MSC OTA][Auto]")
207208
TEST_ESP_OK(esp_msc_host_uninstall(host_handle));
208209
vTaskDelay(1000 / portTICK_PERIOD_MS);
209210
}
211+
212+
TEST_CASE("Test msc ota without msc host", "[MSC OTA][WITHOUT MSC HOST]")
213+
{
214+
esp_event_loop_create_default();
215+
bsp_sdcard_mount();
216+
217+
char path[256];
218+
sprintf(path, "%s/ota_test.bin", CONFIG_BSP_uSD_MOUNT_POINT);
219+
220+
esp_msc_ota_handle_t msc_ota_handle = NULL;
221+
esp_msc_ota_config_t config = {
222+
.ota_bin_path = path,
223+
.skip_msc_connect_wait = true,
224+
};
225+
TEST_ESP_OK(esp_msc_ota_begin(&config, &msc_ota_handle));
226+
TEST_ESP_OK(esp_msc_ota_abort(msc_ota_handle));
227+
bsp_sdcard_unmount();
228+
}

0 commit comments

Comments
 (0)