Merge branch 'feature/app_update_add_api' into 'master'
Add API to write data in a non-contiguous manner See merge request espressif/esp-idf!8650
This commit is contained in:
commit
e8035c3eff
3 changed files with 142 additions and 0 deletions
|
@ -250,6 +250,43 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
|||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, size_t size, uint32_t offset)
|
||||
{
|
||||
const uint8_t *data_bytes = (const uint8_t *)data;
|
||||
esp_err_t ret;
|
||||
ota_ops_entry_t *it;
|
||||
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "write data is invalid");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// find ota handle in linked list
|
||||
for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) {
|
||||
if (it->handle == handle) {
|
||||
// must erase the partition before writing to it
|
||||
assert(it->erased_size > 0 && "must erase the partition before writing to it");
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
if (esp_flash_encryption_enabled() && (size % 16)) {
|
||||
ESP_LOGE(TAG, "Size should be 16byte aligned for flash encryption case");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ret = esp_partition_write(it->part, offset, data_bytes, size);
|
||||
if (ret == ESP_OK) {
|
||||
it->wrote_size += size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// OTA handle is not found in linked list
|
||||
ESP_LOGE(TAG,"OTA handle not found");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
{
|
||||
ota_ops_entry_t *it;
|
||||
|
|
|
@ -117,6 +117,29 @@ esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp
|
|||
*/
|
||||
esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Write OTA update data to partition
|
||||
*
|
||||
* This function can write data in non contiguous manner.
|
||||
* If flash encryption is enabled, data should be 16 byte aligned.
|
||||
*
|
||||
* @param handle Handle obtained from esp_ota_begin
|
||||
* @param data Data buffer to write
|
||||
* @param size Size of data buffer in bytes
|
||||
* @param offset Offset in flash partition
|
||||
*
|
||||
* @note While performing OTA, if the packets arrive out of order, esp_ota_write_with_offset() can be used to write data in non contiguous manner.
|
||||
* Use of esp_ota_write_with_offset() in combination with esp_ota_write() is not recommended.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Data was written to flash successfully.
|
||||
* - ESP_ERR_INVALID_ARG: handle is invalid.
|
||||
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte.
|
||||
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
|
||||
* - ESP_ERR_OTA_SELECT_INFO_INVALID: OTA data partition has invalid contents
|
||||
*/
|
||||
esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, size_t size, uint32_t offset);
|
||||
|
||||
/**
|
||||
* @brief Finish OTA update and validate newly written app image.
|
||||
*
|
||||
|
|
|
@ -55,6 +55,29 @@ static void copy_app_partition(esp_ota_handle_t update_handle, const esp_partiti
|
|||
ESP_LOGI(TAG, "finish the copy process");
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition using handle.
|
||||
*
|
||||
* @param[in] update_handle - Handle of API ota.
|
||||
* @param[in] cur_app - Current app.
|
||||
*/
|
||||
static void copy_app_partition_with_offset(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
spi_flash_mmap_handle_t data_map;
|
||||
ESP_LOGI(TAG, "start the copy process");
|
||||
uint32_t offset = 0, bytes_to_write = curr_app->size;
|
||||
uint32_t write_bytes;
|
||||
while (bytes_to_write > 0) {
|
||||
write_bytes = (bytes_to_write > (4 * 1024)) ? (4 * 1024) : bytes_to_write;
|
||||
TEST_ESP_OK(esp_partition_mmap(curr_app, offset, write_bytes, SPI_FLASH_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_ota_write_with_offset(update_handle, (const void *)partition_bin, write_bytes, offset));
|
||||
spi_flash_munmap(data_map);
|
||||
bytes_to_write -= write_bytes;
|
||||
offset += write_bytes;
|
||||
}
|
||||
ESP_LOGI(TAG, "finish the copy process");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
|
||||
/* @brief Copies partition from source partition to destination partition.
|
||||
*
|
||||
|
@ -105,6 +128,26 @@ static void copy_current_app_to_next_part(const esp_partition_t *cur_app_partiti
|
|||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
|
||||
*
|
||||
* @param[in] cur_app_partition - Current app.
|
||||
* @param[in] next_app_partition - Next app for boot.
|
||||
*/
|
||||
static void copy_current_app_to_next_part_with_offset(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
|
||||
{
|
||||
esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", next_app_partition->subtype, next_app_partition->address);
|
||||
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
|
||||
copy_app_partition_with_offset(update_handle, cur_app_partition);
|
||||
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Erase otadata partition
|
||||
*/
|
||||
static void erase_ota_data(void)
|
||||
|
@ -133,6 +176,16 @@ static void copy_current_app_to_next_part_and_reboot(void)
|
|||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) using esp_ota_write_with_offest(), after that ESP is rebooting and run this (the next) OTAx.
|
||||
*/
|
||||
static void copy_current_app_to_next_part_with_offset_and_reboot(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "copy current app to next part");
|
||||
copy_current_app_to_next_part_with_offset(cur_app, get_next_update_partition());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Get running app.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
|
@ -740,3 +793,32 @@ static void test_erase_last_app_rollback(void)
|
|||
// 4 Stage: run OTA1 -> check it -> erase OTA0 and rollback -> reboot
|
||||
// 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Test erase_last_boot_app_partition. factory, OTA1, OTA0, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_rollback);
|
||||
|
||||
static void test_flow6(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
copy_current_app_to_next_part_with_offset_and_reboot();
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
erase_ota_data();
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0 using esp_ota_write_with_offset", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow6, test_flow6);
|
||||
|
|
Loading…
Reference in a new issue