Skip to content

Commit

Permalink
feat(esp_msc_ota): add skip_msc_connect_wait config
Browse files Browse the repository at this point in the history
Closes #429
  • Loading branch information
lijunru-hub committed Jan 2, 2025
1 parent b2cd32d commit ed807e4
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 39 deletions.
2 changes: 1 addition & 1 deletion components/.build-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ components/touch/touch_proximity_sensor/test_apps:

components/usb/esp_msc_ota/test_apps:
enable:
- if: SOC_USB_OTG_SUPPORTED == 1
- if: IDF_TARGET in ["esp32s3"]

components/usb/usb_stream/test_apps:
enable:
Expand Down
4 changes: 4 additions & 0 deletions components/usb/esp_msc_ota/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# changelog

## v1.1.0 - 2024-12-24

* Add the `skip_msc_connect_wait` configuration to allow users to mount the file system manually.

## v1.0.0 - 2024-8-15

* Publish the official version
Expand Down
56 changes: 36 additions & 20 deletions components/usb/esp_msc_ota/esp_msc_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ static const char *TAG = "esp_msc_host";

ESP_EVENT_DEFINE_BASE(ESP_MSC_HOST_EVENT);
SemaphoreHandle_t msc_read_semaphore;

typedef struct {
usb_host_config_t host_config;
TaskHandle_t task_handle;
EventGroupHandle_t usb_flags;
const char *base_path;
esp_vfs_fat_mount_config_t mount_config;
Expand Down Expand Up @@ -150,24 +151,41 @@ static void msc_host_task(void *args)
static void usb_event_task(void *args)
{
esp_msc_host_t *msc_host = (esp_msc_host_t *)args;

// Install USB Host driver. Should only be called once in entire application
esp_err_t err = usb_host_install(&msc_host->host_config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to install USB Host library");
vTaskDelete(NULL);
}
xTaskNotifyGive(msc_host->task_handle);

bool has_clients = true;
while (1) {
bool has_devices = false;
while (has_clients) {
uint32_t event_flags;
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);

// Release devices once all clients has deregistered
ESP_ERROR_CHECK(usb_host_lib_handle_events(portMAX_DELAY, &event_flags));
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
has_clients = false;
if (usb_host_device_free_all() == ESP_OK) {
break;
ESP_LOGI(TAG, "Get FLAGS_NO_CLIENTS");
if (ESP_OK == usb_host_device_free_all()) {
ESP_LOGI(TAG, "All devices marked as free, no need to wait FLAGS_ALL_FREE event");
has_clients = false;
} else {
ESP_LOGI(TAG, "Wait for the FLAGS_ALL_FREE");
has_devices = true;
}
}
// can be deinitialized, and terminate this task.
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE && !has_clients) {
break;
if (has_devices && event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
ESP_LOGI(TAG, "Get FLAGS_ALL_FREE");
has_clients = false;
}
}
ESP_LOGI(TAG, "No more clients and devices, uninstall USB Host library");

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

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

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

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

err = msc_host_install(&msc_config);
MSC_OTA_CHECK_GOTO(err == ESP_OK, "Failed to install MSC host", usb_install_fail);
MSC_OTA_CHECK_GOTO(err == ESP_OK, "Failed to install MSC host", install_fail);

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

*handle = (esp_msc_host_handle_t)msc_host;
q_msc_host = msc_host;

ESP_LOGI(TAG, "MSC Host Install Done\n");
ESP_LOGI(TAG, "MSC Host Install Done");
return ESP_OK;

msc_install_fail:
msc_host_uninstall();
wait_for_event(msc_host->usb_flags, HOST_UNINSTALL, portMAX_DELAY);

usb_install_fail:
usb_host_uninstall();

install_fail:
if (msc_host->usb_flags != NULL) {
vEventGroupDelete(msc_host->usb_flags);
Expand All @@ -243,7 +260,6 @@ esp_err_t esp_msc_host_uninstall(esp_msc_host_handle_t handle)
ESP_LOGI(TAG, "Please remove the USB flash drive.");
xEventGroupSetBits(msc_host->usb_flags, HOST_TOBE_UNINSTALL);
wait_for_event(msc_host->usb_flags, HOST_UNINSTALL, portMAX_DELAY);
usb_host_uninstall();
if (msc_host->usb_flags != NULL) {
vEventGroupDelete(msc_host->usb_flags);
}
Expand Down
74 changes: 58 additions & 16 deletions components/usb/esp_msc_ota/esp_msc_ota.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -29,6 +29,29 @@ _Static_assert(DEFAULT_OTA_BUF_SIZE > (sizeof(esp_image_header_t) + sizeof(esp_i
/* Setting event group */
#define MSC_CONNECT (1 << 0) // MSC device connect

/**
* @brief To prevent the VFS from being unregistered during file read and write operations.
*
* @param semaphore Semaphore to take.
* @return esp_err_t
* - ESP_OK on success or if the semaphore is NULL.
* - ESP_FAIL if taking the semaphore fails.
*/
#define SEMAPHORE_TAKE(semaphore) \
((semaphore == NULL) ? ESP_OK : \
((xSemaphoreTake(semaphore, pdMS_TO_TICKS(10)) == pdTRUE) ? ESP_OK : ESP_FAIL))

/**
* @brief To prevent the VFS from being unregistered during file read and write operations.
*
* @param semaphore Semaphore to give.
* @return esp_err_t
* - ESP_OK on success or if the semaphore is NULL.
*/
#define SEMAPHORE_GIVE(semaphore) \
((semaphore == NULL) ? ESP_OK : \
(xSemaphoreGive(semaphore), ESP_OK))

typedef struct {
EventGroupHandle_t mscEventGroup;
bool bulk_flash_erase;
Expand Down Expand Up @@ -107,6 +130,7 @@ esp_msc_ota_status_t esp_msc_ota_get_status(esp_msc_ota_handle_t handle)

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

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

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

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

if (data_read == data_read_size) {
msc_ota->binary_file_read_len = data_read;
fclose(file);
return ESP_OK;
err = ESP_OK;
goto file_close;
} else if (data_read > 0 && data_read < data_read_size) {
msc_ota->binary_file_read_len = data_read;
fclose(file);
return ESP_OK;
err = ESP_OK;
goto file_close;
} else if (ferror(file)) {
err = ESP_FAIL;
ESP_LOGI(TAG, "Error reading from file");
} else if (feof(file)) {
ESP_LOGI(TAG, "End of file reached.\n");
err = ESP_FAIL;
ESP_LOGI(TAG, "End of file reached.");
}

file_close:
fclose(file);
return ESP_FAIL;
SEMAPHORE_GIVE(msc_read_semaphore);
return err;
}

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

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

ESP_LOGI(TAG, "Waiting for MSC device to connect...");
EventBits_t bits = xEventGroupWaitBits(msc_ota->mscEventGroup, MSC_CONNECT, pdFALSE, pdFALSE, config->wait_msc_connect);
MSC_OTA_CHECK_GOTO(bits & MSC_CONNECT, "TIMEOUT: MSC device not connected", msc_cleanup);
if (!config->skip_msc_connect_wait) {
ESP_LOGI(TAG, "Waiting for MSC device to connect...");
EventBits_t bits = xEventGroupWaitBits(msc_ota->mscEventGroup, MSC_CONNECT, pdFALSE, pdFALSE, config->wait_msc_connect);
MSC_OTA_CHECK_GOTO(bits & MSC_CONNECT, "TIMEOUT: MSC device not connected", msc_cleanup);
} else {
xEventGroupSetBits(msc_ota->mscEventGroup, MSC_CONNECT);
ESP_LOGI(TAG, "skip_msc_connect_wait is true, set MSC_CONNECT event directly");
}

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

err = SEMAPHORE_TAKE(msc_read_semaphore);
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
FILE *file = fopen(msc_ota->ota_bin_path, "rb");
MSC_OTA_CHECK(file != NULL, "Failed to open file for reading", ESP_ERR_NOT_FOUND);
fseek(file, msc_ota->binary_file_read_len, SEEK_CUR);
SEMAPHORE_GIVE(msc_read_semaphore);
msc_ota->file = file;
}
uint32_t *fileLength = &msc_ota->binary_file_read_len;
uint32_t *totalLength = &msc_ota->binary_file_len;
if (*fileLength < *totalLength) {
size_t readLength = *fileLength > msc_ota->ota_upgrade_buf_size ? msc_ota->ota_upgrade_buf_size : *fileLength;

BaseType_t ret = xSemaphoreTake(msc_read_semaphore, pdMS_TO_TICKS(10));
MSC_OTA_CHECK(ret == pdTRUE, "take msc_read_semaphore failed", ESP_FAIL);
err = SEMAPHORE_TAKE(msc_read_semaphore);
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
data_read = fread(msc_ota->ota_upgrade_buf, 1, readLength, msc_ota->file);
xSemaphoreGive(msc_read_semaphore);
SEMAPHORE_GIVE(msc_read_semaphore);

MSC_OTA_CHECK(data_read > 0, "Failed to read file", ESP_ERR_INVALID_SIZE);
err = esp_ota_write(msc_ota->update_handle, (const void *)msc_ota->ota_upgrade_buf, data_read);
Expand All @@ -299,7 +334,10 @@ esp_err_t esp_msc_ota_perform(esp_msc_ota_handle_t handle)
}
if (*fileLength >= *totalLength) {
msc_ota->status = ESP_MSC_OTA_SUCCESS;
err = SEMAPHORE_TAKE(msc_read_semaphore);
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
fclose(msc_ota->file);
SEMAPHORE_GIVE(msc_read_semaphore);
return ESP_OK;
}
return ESP_OK;
Expand Down Expand Up @@ -338,6 +376,7 @@ esp_err_t esp_msc_ota_end(esp_msc_ota_handle_t handle)
}
}
esp_event_handler_unregister(ESP_MSC_HOST_EVENT, ESP_EVENT_ANY_ID, &_esp_msc_host_handler);
vEventGroupDelete(msc_ota->mscEventGroup);
free(msc_ota);
esp_msc_ota_dispatch_event(ESP_MSC_OTA_FINISH, NULL, 0);
return err;
Expand All @@ -353,7 +392,10 @@ esp_err_t esp_msc_ota_abort(esp_msc_ota_handle_t handle)
case ESP_MSC_OTA_SUCCESS:
case ESP_MSC_OTA_IN_PROGRESS:
if (msc_ota->file) {
err = SEMAPHORE_TAKE(msc_read_semaphore);
MSC_OTA_CHECK(err == ESP_OK, "take msc_read_semaphore failed", ESP_FAIL);
fclose(msc_ota->file);
SEMAPHORE_GIVE(msc_read_semaphore);
}
err = esp_ota_abort(msc_ota->update_handle);
[[fallthrough]];
Expand Down
2 changes: 1 addition & 1 deletion components/usb/esp_msc_ota/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "1.0.0"
version: "1.1.0"
targets:
- esp32s2
- esp32s3
Expand Down
1 change: 1 addition & 0 deletions components/usb/esp_msc_ota/include/esp_msc_ota.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ typedef enum {
typedef struct {
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" */
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 */
bool skip_msc_connect_wait; /*!< Skip waiting for MSC device to connect, if true means MSC device is already connected */
TickType_t wait_msc_connect; /*!< Wait time for MSC device to connect */
size_t buffer_size; /*!< Buffer size for OTA write operation, must larger than 1024 */
} esp_msc_ota_config_t;
Expand Down
3 changes: 2 additions & 1 deletion components/usb/esp_msc_ota/test_apps/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dependencies:
idf: ">=5.0"
idf: '>=5.0'
espressif/esp32_s3_usb_otg: ^1.6.1
19 changes: 19 additions & 0 deletions components/usb/esp_msc_ota/test_apps/main/test_msc_ota.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "esp_msc_host.h"
#include "esp_msc_ota.h"
#include "usb/usb_host.h"
#include "bsp/esp-bsp.h"

static const char *TAG = "esp_msc_ota_test";

Expand Down Expand Up @@ -207,3 +208,21 @@ TEST_CASE("Auto MSC OTA", "[MSC OTA][Auto]")
TEST_ESP_OK(esp_msc_host_uninstall(host_handle));
vTaskDelay(1000 / portTICK_PERIOD_MS);
}

TEST_CASE("Test msc ota without msc host", "[MSC OTA][WITHOUT MSC HOST]")
{
esp_event_loop_create_default();
bsp_sdcard_mount();

char path[256];
sprintf(path, "%s/ota_test.bin", CONFIG_BSP_uSD_MOUNT_POINT);

esp_msc_ota_handle_t msc_ota_handle = NULL;
esp_msc_ota_config_t config = {
.ota_bin_path = path,
.skip_msc_connect_wait = true,
};
TEST_ESP_OK(esp_msc_ota_begin(&config, &msc_ota_handle));
TEST_ESP_OK(esp_msc_ota_abort(msc_ota_handle));
bsp_sdcard_unmount();
}

0 comments on commit ed807e4

Please sign in to comment.