Merge branch 'feature/ota_incremental_erase_during_write' into 'master'

Feature/ota incremental erase during write

See merge request espressif/esp-idf!9726
This commit is contained in:
Mahavir Jain
2020-09-04 20:00:07 +08:00
5 changed files with 38 additions and 24 deletions

View File

@@ -52,7 +52,7 @@
typedef struct ota_ops_entry_ { typedef struct ota_ops_entry_ {
uint32_t handle; uint32_t handle;
const esp_partition_t *part; const esp_partition_t *part;
uint32_t erased_size; bool need_erase;
uint32_t wrote_size; uint32_t wrote_size;
uint8_t partial_bytes; uint8_t partial_bytes;
uint8_t partial_data[16]; uint8_t partial_data[16];
@@ -158,16 +158,17 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
} }
#endif #endif
// If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition if (image_size != OTA_WITH_SEQUENTIAL_WRITES) {
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) { // If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
ret = esp_partition_erase_range(partition, 0, partition->size); if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
} else { ret = esp_partition_erase_range(partition, 0, partition->size);
const int aligned_erase_size = (image_size + SPI_FLASH_SEC_SIZE - 1) & ~(SPI_FLASH_SEC_SIZE - 1); } else {
ret = esp_partition_erase_range(partition, 0, aligned_erase_size); const int aligned_erase_size = (image_size + SPI_FLASH_SEC_SIZE - 1) & ~(SPI_FLASH_SEC_SIZE - 1);
} ret = esp_partition_erase_range(partition, 0, aligned_erase_size);
}
if (ret != ESP_OK) { if (ret != ESP_OK) {
return ret; return ret;
}
} }
new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1); new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1);
@@ -177,14 +178,9 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
LIST_INSERT_HEAD(&s_ota_ops_entries_head, new_entry, entries); LIST_INSERT_HEAD(&s_ota_ops_entries_head, new_entry, entries);
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
new_entry->erased_size = partition->size;
} else {
new_entry->erased_size = image_size;
}
new_entry->part = partition; new_entry->part = partition;
new_entry->handle = ++s_ota_ops_last_handle; new_entry->handle = ++s_ota_ops_last_handle;
new_entry->need_erase = (image_size == OTA_WITH_SEQUENTIAL_WRITES);
*out_handle = new_entry->handle; *out_handle = new_entry->handle;
return ESP_OK; return ESP_OK;
} }
@@ -203,8 +199,22 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
// find ota handle in linked list // find ota handle in linked list
for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) {
if (it->handle == handle) { if (it->handle == handle) {
// must erase the partition before writing to it if (it->need_erase) {
assert(it->erased_size > 0 && "must erase the partition before writing to it"); // must erase the partition before writing to it
uint32_t first_sector = it->wrote_size / SPI_FLASH_SEC_SIZE;
uint32_t last_sector = (it->wrote_size + size) / SPI_FLASH_SEC_SIZE;
ret = ESP_OK;
if ((it->wrote_size % SPI_FLASH_SEC_SIZE) == 0) {
ret = esp_partition_erase_range(it->part, it->wrote_size, ((last_sector - first_sector) + 1) * SPI_FLASH_SEC_SIZE);
} else if (first_sector != last_sector) {
ret = esp_partition_erase_range(it->part, (first_sector + 1) * SPI_FLASH_SEC_SIZE, (last_sector - first_sector) * SPI_FLASH_SEC_SIZE);
}
if (ret != ESP_OK) {
return ret;
}
}
if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0 && data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) { if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0 && data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) {
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]); ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]);
return ESP_ERR_OTA_VALIDATE_FAILED; return ESP_ERR_OTA_VALIDATE_FAILED;
@@ -270,7 +280,7 @@ esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, s
for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) {
if (it->handle == handle) { if (it->handle == handle) {
// must erase the partition before writing to it // must erase the partition before writing to it
assert(it->erased_size > 0 && "must erase the partition before writing to it"); assert(it->need_erase == 0 && "must erase the partition before writing to it");
/* esp_ota_write_with_offset is used to write data in non contiguous manner. /* esp_ota_write_with_offset is used to write data in non contiguous manner.
* Hence, unaligned data(less than 16 bytes) cannot be cached if flash encryption is enabled. * Hence, unaligned data(less than 16 bytes) cannot be cached if flash encryption is enabled.
@@ -310,7 +320,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
/* 'it' holds the ota_ops_entry_t for 'handle' */ /* 'it' holds the ota_ops_entry_t for 'handle' */
// esp_ota_end() is only valid if some data was written to this handle // esp_ota_end() is only valid if some data was written to this handle
if ((it->erased_size == 0) || (it->wrote_size == 0)) { if (it->wrote_size == 0) {
ret = ESP_ERR_INVALID_ARG; ret = ESP_ERR_INVALID_ARG;
goto cleanup; goto cleanup;
} }

View File

@@ -29,6 +29,7 @@ extern "C"
#endif #endif
#define OTA_SIZE_UNKNOWN 0xffffffff /*!< Used for esp_ota_begin() if new image size is unknown */ #define OTA_SIZE_UNKNOWN 0xffffffff /*!< Used for esp_ota_begin() if new image size is unknown */
#define OTA_WITH_SEQUENTIAL_WRITES 0xfffffffe /*!< Used for esp_ota_begin() if new image size is unknown and erase can be done in incremental manner (assuming write operation is in continuous sequence) */
#define ESP_ERR_OTA_BASE 0x1500 /*!< Base error code for ota_ops api */ #define ESP_ERR_OTA_BASE 0x1500 /*!< Base error code for ota_ops api */
#define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< Error if request was to write or erase the current running partition */ #define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< Error if request was to write or erase the current running partition */

View File

@@ -30,6 +30,7 @@ typedef esp_err_t(*http_client_init_cb_t)(esp_http_client_handle_t);
typedef struct { typedef struct {
const esp_http_client_config_t *http_config; /*!< ESP HTTP client configuration */ const esp_http_client_config_t *http_config; /*!< ESP HTTP client configuration */
http_client_init_cb_t http_client_init_cb; /*!< Callback after ESP HTTP client is initialised */ http_client_init_cb_t http_client_init_cb; /*!< Callback after ESP HTTP client is initialised */
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 */
} esp_https_ota_config_t; } esp_https_ota_config_t;
#define ESP_ERR_HTTPS_OTA_BASE (0x9000) #define ESP_ERR_HTTPS_OTA_BASE (0x9000)

View File

@@ -39,6 +39,7 @@ struct esp_https_ota_handle {
size_t ota_upgrade_buf_size; size_t ota_upgrade_buf_size;
int binary_file_len; int binary_file_len;
esp_https_ota_state state; esp_https_ota_state state;
bool bulk_flash_erase;
}; };
typedef struct esp_https_ota_handle esp_https_ota_t; typedef struct esp_https_ota_handle esp_https_ota_t;
@@ -207,7 +208,7 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_
goto http_cleanup; goto http_cleanup;
} }
https_ota_handle->ota_upgrade_buf_size = alloc_size; https_ota_handle->ota_upgrade_buf_size = alloc_size;
https_ota_handle->bulk_flash_erase = ota_config->bulk_flash_erase;
https_ota_handle->binary_file_len = 0; https_ota_handle->binary_file_len = 0;
*handle = (esp_https_ota_handle_t)https_ota_handle; *handle = (esp_https_ota_handle_t)https_ota_handle;
https_ota_handle->state = ESP_HTTPS_OTA_BEGIN; https_ota_handle->state = ESP_HTTPS_OTA_BEGIN;
@@ -280,9 +281,10 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
esp_err_t err; esp_err_t err;
int data_read; int data_read;
const int erase_size = handle->bulk_flash_erase ? OTA_SIZE_UNKNOWN : OTA_WITH_SEQUENTIAL_WRITES;
switch (handle->state) { switch (handle->state) {
case ESP_HTTPS_OTA_BEGIN: case ESP_HTTPS_OTA_BEGIN:
err = esp_ota_begin(handle->update_partition, OTA_SIZE_UNKNOWN, &handle->update_handle); err = esp_ota_begin(handle->update_partition, erase_size, &handle->update_handle);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
return err; return err;

View File

@@ -183,7 +183,7 @@ static void ota_example_task(void *pvParameter)
image_header_was_checked = true; image_header_was_checked = true;
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
http_cleanup(client); http_cleanup(client);