forked from espressif/esp-idf
feat(app_update): OTA update bootloader, partition_table and other partitions
Passive app partition can be used as the staging partition where a new image is loaded. Then copy it to the final partition. Closes: https://github.com/espressif/esp-idf/issues/14195 Closes: https://github.com/espressif/esp-idf/issues/13824
This commit is contained in:
@@ -31,13 +31,19 @@
|
||||
#include "esp_attr.h"
|
||||
#include "esp_bootloader_desc.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_flash_internal.h"
|
||||
|
||||
#define SUB_TYPE_ID(i) (i & 0x0F)
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
/* Partial_data is word aligned so no reallocation is necessary for encrypted flash write */
|
||||
typedef struct ota_ops_entry_ {
|
||||
uint32_t handle;
|
||||
const esp_partition_t *part;
|
||||
struct {
|
||||
const esp_partition_t *staging; /*!< New image will be downloaded in this staging partition. */
|
||||
const esp_partition_t *final; /*!< Final destination partition which is intended to be updated. Its type/subtype shall be used for verification. */
|
||||
bool finalize_with_copy; /*!< Flag to copy the image from staging partition to the final partition at the end of OTA update */
|
||||
} partition;
|
||||
bool need_erase;
|
||||
uint32_t wrote_size;
|
||||
uint8_t partial_bytes;
|
||||
@@ -52,6 +58,8 @@ static uint32_t s_ota_ops_last_handle = 0;
|
||||
|
||||
const static char *TAG = "esp_ota_ops";
|
||||
|
||||
static ota_ops_entry_t *get_ota_ops_entry(esp_ota_handle_t handle);
|
||||
|
||||
/* Return true if this is an OTA app partition */
|
||||
static bool is_ota_partition(const esp_partition_t *p)
|
||||
{
|
||||
@@ -114,8 +122,6 @@ static esp_ota_img_states_t set_new_state_otadata(void)
|
||||
esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)
|
||||
{
|
||||
ota_ops_entry_t *new_entry;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if ((partition == NULL) || (out_handle == NULL)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -125,36 +131,26 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!is_ota_partition(partition)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (partition->type == ESP_PARTITION_TYPE_APP) {
|
||||
// The staging partition cannot be of type Factory, but the final partition can be.
|
||||
if (!is_ota_partition(partition)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const esp_partition_t* running_partition = esp_ota_get_running_partition();
|
||||
if (partition == running_partition) {
|
||||
return ESP_ERR_OTA_PARTITION_CONFLICT;
|
||||
}
|
||||
const esp_partition_t* running_partition = esp_ota_get_running_partition();
|
||||
if (partition == running_partition) {
|
||||
return ESP_ERR_OTA_PARTITION_CONFLICT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
esp_ota_img_states_t ota_state_running_part;
|
||||
if (esp_ota_get_state_partition(running_partition, &ota_state_running_part) == ESP_OK) {
|
||||
if (ota_state_running_part == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
ESP_LOGE(TAG, "Running app has not confirmed state (ESP_OTA_IMG_PENDING_VERIFY)");
|
||||
return ESP_ERR_OTA_ROLLBACK_INVALID_STATE;
|
||||
esp_ota_img_states_t ota_state_running_part;
|
||||
if (esp_ota_get_state_partition(running_partition, &ota_state_running_part) == ESP_OK) {
|
||||
if (ota_state_running_part == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
ESP_LOGE(TAG, "Running app has not confirmed state (ESP_OTA_IMG_PENDING_VERIFY)");
|
||||
return ESP_ERR_OTA_ROLLBACK_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (image_size != OTA_WITH_SEQUENTIAL_WRITES) {
|
||||
// If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
|
||||
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
|
||||
ret = esp_partition_erase_range(partition, 0, partition->size);
|
||||
} else {
|
||||
const int aligned_erase_size = (image_size + partition->erase_size - 1) & ~(partition->erase_size - 1);
|
||||
ret = esp_partition_erase_range(partition, 0, aligned_erase_size);
|
||||
}
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
new_entry = (ota_ops_entry_t *) calloc(1, sizeof(ota_ops_entry_t));
|
||||
@@ -164,10 +160,60 @@ 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);
|
||||
|
||||
new_entry->part = partition;
|
||||
new_entry->partition.staging = partition;
|
||||
new_entry->partition.final = partition;
|
||||
new_entry->partition.finalize_with_copy = false;
|
||||
new_entry->handle = ++s_ota_ops_last_handle;
|
||||
new_entry->need_erase = (image_size == OTA_WITH_SEQUENTIAL_WRITES);
|
||||
*out_handle = new_entry->handle;
|
||||
|
||||
if (partition->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
esp_image_bootloader_offset_set(partition->address);
|
||||
}
|
||||
if (partition->type == ESP_PARTITION_TYPE_BOOTLOADER || partition->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
|
||||
esp_flash_set_dangerous_write_protection(esp_flash_default_chip, false);
|
||||
}
|
||||
|
||||
if (image_size != OTA_WITH_SEQUENTIAL_WRITES) {
|
||||
// If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
|
||||
size_t erase_size;
|
||||
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
|
||||
erase_size = partition->size;
|
||||
} else {
|
||||
erase_size = ALIGN_UP(image_size, partition->erase_size);
|
||||
}
|
||||
return esp_partition_erase_range(partition, 0, erase_size);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_set_final_partition(esp_ota_handle_t handle, const esp_partition_t *final, bool finalize_with_copy)
|
||||
{
|
||||
ota_ops_entry_t *it = get_ota_ops_entry(handle);
|
||||
if (final == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (it == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
if (it->wrote_size != 0) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (it->partition.staging != final) {
|
||||
const esp_partition_t* final_partition = esp_partition_verify(final);
|
||||
if (final_partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
ESP_LOGI(TAG,"Staging partition - <%s>. Final partition - <%s>.", it->partition.staging->label, final_partition->label);
|
||||
it->partition.final = final_partition;
|
||||
it->partition.finalize_with_copy = finalize_with_copy;
|
||||
if (final_partition->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
esp_image_bootloader_offset_set(it->partition.staging->address);
|
||||
}
|
||||
if (final_partition->type == ESP_PARTITION_TYPE_BOOTLOADER || final_partition->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
|
||||
esp_flash_set_dangerous_write_protection(esp_flash_default_chip, false);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -192,23 +238,33 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
if (it->handle == handle) {
|
||||
if (it->need_erase) {
|
||||
// must erase the partition before writing to it
|
||||
uint32_t first_sector = it->wrote_size / it->part->erase_size; // first affected sector
|
||||
uint32_t last_sector = (it->wrote_size + size - 1) / it->part->erase_size; // last affected sector
|
||||
uint32_t first_sector = it->wrote_size / it->partition.staging->erase_size; // first affected sector
|
||||
uint32_t last_sector = (it->wrote_size + size - 1) / it->partition.staging->erase_size; // last affected sector
|
||||
|
||||
ret = ESP_OK;
|
||||
if ((it->wrote_size % it->part->erase_size) == 0) {
|
||||
ret = esp_partition_erase_range(it->part, it->wrote_size, ((last_sector - first_sector) + 1) * it->part->erase_size);
|
||||
if ((it->wrote_size % it->partition.staging->erase_size) == 0) {
|
||||
ret = esp_partition_erase_range(it->partition.staging, it->wrote_size, ((last_sector - first_sector) + 1) * it->partition.staging->erase_size);
|
||||
} else if (first_sector != last_sector) {
|
||||
ret = esp_partition_erase_range(it->part, (first_sector + 1) * it->part->erase_size, (last_sector - first_sector) * it->part->erase_size);
|
||||
ret = esp_partition_erase_range(it->partition.staging, (first_sector + 1) * it->partition.staging->erase_size, (last_sector - first_sector) * it->partition.staging->erase_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) {
|
||||
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0) {
|
||||
if (it->partition.final->type == ESP_PARTITION_TYPE_APP || it->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
if (data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) {
|
||||
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
} else if (it->partition.final->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
|
||||
if (*(uint16_t*)data_bytes != (uint16_t)ESP_PARTITION_MAGIC) {
|
||||
ESP_LOGE(TAG, "Partition table image has invalid magic word (expected 0x50AA, saw 0x%04x)", *(uint16_t*)data_bytes);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (esp_flash_encryption_enabled()) {
|
||||
@@ -224,7 +280,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
return ESP_OK; /* nothing to write yet, just filling buffer */
|
||||
}
|
||||
/* write 16 byte to partition */
|
||||
ret = esp_partition_write(it->part, it->wrote_size, it->partial_data, 16);
|
||||
ret = esp_partition_write(it->partition.staging, it->wrote_size, it->partial_data, 16);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
@@ -243,7 +299,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
ret = esp_partition_write(it->part, it->wrote_size, data_bytes, size);
|
||||
ret = esp_partition_write(it->partition.staging, it->wrote_size, data_bytes, size);
|
||||
if(ret == ESP_OK){
|
||||
it->wrote_size += size;
|
||||
}
|
||||
@@ -280,7 +336,7 @@ esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, s
|
||||
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);
|
||||
ret = esp_partition_write(it->partition.staging, offset, data_bytes, size);
|
||||
if (ret == ESP_OK) {
|
||||
it->wrote_size += size;
|
||||
}
|
||||
@@ -316,6 +372,34 @@ esp_err_t esp_ota_abort(esp_ota_handle_t handle)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t ota_verify_partition(ota_ops_entry_t *ota_ops)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (ota_ops->partition.final->type == ESP_PARTITION_TYPE_APP || ota_ops->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = ota_ops->partition.staging->address,
|
||||
.size = ota_ops->partition.staging->size,
|
||||
};
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
} else if (ota_ops->partition.final->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
|
||||
const esp_partition_info_t *partition_table = NULL;
|
||||
esp_partition_mmap_handle_t partition_table_map;
|
||||
ret = esp_partition_mmap(ota_ops->partition.staging, 0, ESP_PARTITION_TABLE_MAX_LEN, ESP_PARTITION_MMAP_DATA, (const void**)&partition_table, &partition_table_map);
|
||||
if (ret == ESP_OK) {
|
||||
int num_partitions;
|
||||
if (esp_partition_table_verify(partition_table, true, &num_partitions) != ESP_OK) {
|
||||
esp_partition_munmap(partition_table_map);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
esp_partition_munmap(partition_table_map);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
{
|
||||
ota_ops_entry_t *it = get_ota_ops_entry(handle);
|
||||
@@ -335,7 +419,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
|
||||
if (it->partial_bytes > 0) {
|
||||
/* Write out last 16 bytes, if necessary */
|
||||
ret = esp_partition_write(it->part, it->wrote_size, it->partial_data, 16);
|
||||
ret = esp_partition_write(it->partition.staging, it->wrote_size, it->partial_data, 16);
|
||||
if (ret != ESP_OK) {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
goto cleanup;
|
||||
@@ -344,18 +428,21 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
it->partial_bytes = 0;
|
||||
}
|
||||
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = it->part->address,
|
||||
.size = it->part->size,
|
||||
};
|
||||
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
|
||||
ret = ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
goto cleanup;
|
||||
ret = ota_verify_partition(it);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "New image failed verification");
|
||||
} else {
|
||||
if (it->partition.finalize_with_copy) {
|
||||
ESP_LOGI(TAG, "Copy from <%s> staging partition to <%s>...", it->partition.staging->label, it->partition.final->label);
|
||||
ret = esp_partition_copy(it->partition.final, 0, it->partition.staging, 0, it->partition.final->size);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (it->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
// In esp_ota_begin, bootloader offset was updated, here we return it to default.
|
||||
esp_image_bootloader_offset_set(ESP_PRIMARY_BOOTLOADER_OFFSET);
|
||||
}
|
||||
LIST_REMOVE(it, entries);
|
||||
free(it);
|
||||
return ret;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -82,7 +82,11 @@ int esp_ota_get_app_elf_sha256(char* dst, size_t size) __attribute__((deprecated
|
||||
* it will lead to the ESP_ERR_OTA_ROLLBACK_INVALID_STATE error. Confirm the running app before to run download a new app,
|
||||
* use esp_ota_mark_app_valid_cancel_rollback() function for it (this should be done as early as possible when you first download a new application).
|
||||
*
|
||||
* @param partition Pointer to info for partition which will receive the OTA update. Required.
|
||||
* Note: Rollback is applicable only for app type partitions.
|
||||
*
|
||||
* @param partition Pointer to info for partition which will receive the OTA update. Required.
|
||||
* This is considered as the staging partition (where OTA is downloaded), be default this also considered as the final partition which supposed to be updated.
|
||||
* The final partition can be overwritten using esp_ota_set_final_partition() after calling esp_ota_begin() to relocate contents to the final destination partition.
|
||||
* @param image_size Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased.
|
||||
* @param out_handle On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls.
|
||||
|
||||
@@ -99,6 +103,31 @@ int esp_ota_get_app_elf_sha256(char* dst, size_t size) __attribute__((deprecated
|
||||
*/
|
||||
esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp_ota_handle_t* out_handle);
|
||||
|
||||
/**
|
||||
* @brief Set the final destination partition for OTA update
|
||||
*
|
||||
* This function configures the specified final partition as the destination for the OTA update.
|
||||
* It also allows setting a flag to indicate if the image should be copied from the staging
|
||||
* partition to the final partition after the OTA update completes. Otherwise, copying will need
|
||||
* to be handled by custom code using esp_partition_copy().
|
||||
*
|
||||
* @note This can be called after esp_ota_begin() and before the OTA update has started (before esp_ota_write()).
|
||||
*
|
||||
* @param handle OTA update handle obtained from esp_ota_begin().
|
||||
* @param final Pointer to the final destination partition where the new image will be verified and potentially finalized.
|
||||
* This partition must not be NULL.
|
||||
* @param finalize_with_copy Boolean flag indicating if the downloaded image should be copied
|
||||
* from the staging partition to the final partition upon completion.
|
||||
* Set to False if you intend to perform the final copy process manually later.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: final destination partition set successfully.
|
||||
* - ESP_ERR_INVALID_STATE: Once the OTA update has started, changing the final destination partition is prohibited.
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments were passed (e.g., final partition is NULL).
|
||||
* - ESP_ERR_NOT_FOUND: OTA handle not found or final partition verification failed.
|
||||
*/
|
||||
esp_err_t esp_ota_set_final_partition(esp_ota_handle_t handle, const esp_partition_t *final, bool finalize_with_copy);
|
||||
|
||||
/**
|
||||
* @brief Write OTA update data to partition
|
||||
*
|
||||
@@ -113,9 +142,8 @@ esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp
|
||||
* @return
|
||||
* - ESP_OK: Data was written to flash successfully, or size = 0
|
||||
* - ESP_ERR_INVALID_ARG: handle is invalid.
|
||||
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte.
|
||||
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid 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_INVALID_SIZE: if write would go out of bounds of the partition
|
||||
* - or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
@@ -138,9 +166,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size);
|
||||
* @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);
|
||||
|
||||
@@ -150,6 +176,11 @@ esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, s
|
||||
* @param handle Handle obtained from esp_ota_begin().
|
||||
*
|
||||
* @note After calling esp_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result).
|
||||
* @note If either the final or staging partitions were for the bootloader, then at the end of this function,
|
||||
* the bootloader is reset to its default offset: esp_image_bootloader_offset_set(ESP_PRIMARY_BOOTLOADER_OFFSET)
|
||||
*
|
||||
* If the finalize_with_copy option is set, the staging partition will be copied to the final partition at the end of this function.
|
||||
* Otherwise, copying will need to be handled by custom code using esp_partition_copy().
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Newly written OTA app image is valid.
|
||||
@@ -258,7 +289,7 @@ esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, es
|
||||
* @brief Returns the description structure of the bootloader.
|
||||
*
|
||||
* @param[in] bootloader_partition Pointer to bootloader partition.
|
||||
* If NULL, then the current bootloader is used (the default location).
|
||||
* If NULL, then the PRIMARY bootloader is used (the default location).
|
||||
* offset = CONFIG_BOOTLOADER_OFFSET_IN_FLASH,
|
||||
* size = CONFIG_PARTITION_TABLE_OFFSET - CONFIG_BOOTLOADER_OFFSET_IN_FLASH,
|
||||
* @param[out] desc Structure of info about bootloader.
|
||||
|
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_flash_internal.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "unity.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "test";
|
||||
|
||||
static uint8_t buffer[SPI_FLASH_SEC_SIZE];
|
||||
|
||||
// Find the unused offset after the last partition, checking that it is of the required size
|
||||
static uint32_t find_unused_space(size_t required_size)
|
||||
{
|
||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
TEST_ASSERT_NOT_NULL(it);
|
||||
const esp_partition_t* latest_partition = esp_partition_get(it);
|
||||
for (; it != NULL; it = esp_partition_next(it)) {
|
||||
const esp_partition_t *p = esp_partition_get(it);
|
||||
if (p->address > latest_partition->address) {
|
||||
latest_partition = p;
|
||||
}
|
||||
}
|
||||
esp_partition_iterator_release(it);
|
||||
TEST_ASSERT_NOT_NULL(latest_partition);
|
||||
|
||||
#if CONFIG_IDF_TARGET_LINUX
|
||||
uint32_t flash_chip_size;
|
||||
esp_flash_get_size(NULL, &flash_chip_size);
|
||||
#else
|
||||
uint32_t flash_chip_size = esp_flash_default_chip->size;
|
||||
#endif // CONFIG_IDF_TARGET_LINUX
|
||||
uint32_t unused_offset = latest_partition->address + latest_partition->size;
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_UINT32(required_size, flash_chip_size - unused_offset);
|
||||
return unused_offset;
|
||||
}
|
||||
|
||||
static void check_after_reboot(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "App runs");
|
||||
}
|
||||
|
||||
static void download_new_image_from_partition(esp_ota_handle_t update_handle, const esp_partition_t *copy_from_part)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
ESP_LOGI(TAG, "Downloading image...");
|
||||
do {
|
||||
TEST_ESP_OK(esp_partition_read(copy_from_part, offset, buffer, sizeof(buffer)));
|
||||
TEST_ESP_OK(esp_ota_write(update_handle, buffer, sizeof(buffer)));
|
||||
offset += sizeof(buffer);
|
||||
} while (offset < copy_from_part->size);
|
||||
}
|
||||
|
||||
static void start_bootloader_ota_update_via_ota_bootloader_part(void)
|
||||
{
|
||||
const esp_partition_t *primary_bootloader;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
|
||||
|
||||
const esp_partition_t *ota_bootloader;
|
||||
const uint32_t ota_bootloader_offset = find_unused_space(ESP_BOOTLOADER_SIZE);
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ota_bootloader_offset, ESP_BOOTLOADER_SIZE, "OtaBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_OTA, &ota_bootloader));
|
||||
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(ota_bootloader, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_bootloader, true));
|
||||
download_new_image_from_partition(update_handle, primary_bootloader);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
TEST_ESP_OK(esp_partition_deregister_external(primary_bootloader));
|
||||
TEST_ESP_OK(esp_partition_deregister_external(ota_bootloader));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("OTA update of bootloader via temp partition", "[bootloader_ota][reset=SW_CPU_RESET]", start_bootloader_ota_update_via_ota_bootloader_part, check_after_reboot);
|
||||
|
||||
static void start_bootloader_ota_update_via_primary_bootloader_part(void)
|
||||
{
|
||||
const esp_partition_t *primary_bootloader;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
|
||||
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(primary_bootloader, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
download_new_image_from_partition(update_handle, primary_bootloader);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
TEST_ESP_OK(esp_partition_deregister_external(primary_bootloader));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("OTA update of bootloader via primary partition", "[bootloader_ota][reset=SW_CPU_RESET]", start_bootloader_ota_update_via_primary_bootloader_part, check_after_reboot);
|
||||
|
||||
static void start_partition_table_ota_update_via_ota_part_table(void)
|
||||
{
|
||||
const esp_partition_t *primary_partition_table;
|
||||
const esp_partition_t *ota_partition_table;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
|
||||
|
||||
uint32_t ota_partition_table_offset = find_unused_space(ESP_PARTITION_TABLE_SIZE);
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ota_partition_table_offset, ESP_PARTITION_TABLE_SIZE, "OtaPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_OTA, &ota_partition_table));
|
||||
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(ota_partition_table, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_partition_table, true));
|
||||
download_new_image_from_partition(update_handle, primary_partition_table);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
TEST_ESP_OK(esp_partition_deregister_external(primary_partition_table));
|
||||
TEST_ESP_OK(esp_partition_deregister_external(ota_partition_table));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("OTA update of partition_table via temp partition", "[partition_table_ota][reset=SW_CPU_RESET]", start_partition_table_ota_update_via_ota_part_table, check_after_reboot);
|
||||
|
||||
static void start_partition_table_ota_update_via_primary_part_table(void)
|
||||
{
|
||||
const esp_partition_t *primary_partition_table;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
|
||||
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(primary_partition_table, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
download_new_image_from_partition(update_handle, primary_partition_table);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
TEST_ESP_OK(esp_partition_deregister_external(primary_partition_table));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("OTA update of partition_table via primary partition", "[partition_table_ota][reset=SW_CPU_RESET]", start_partition_table_ota_update_via_primary_part_table, check_after_reboot);
|
||||
|
||||
TEST_CASE("OTA update of NVS partition", "[nvs_ota]")
|
||||
{
|
||||
// intilaize "nvs" partition and define a var (magic_value).
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
nvs_handle_t my_handle;
|
||||
TEST_ESP_OK(nvs_open("namespace", NVS_READWRITE, &my_handle));
|
||||
uint32_t magic_value = 0x0729FEED;
|
||||
TEST_ESP_OK(nvs_set_u32(my_handle, "magic_value", magic_value));
|
||||
TEST_ESP_OK(nvs_commit(my_handle));
|
||||
magic_value = 0;
|
||||
TEST_ESP_OK(nvs_get_u32(my_handle, "magic_value", &magic_value));
|
||||
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
|
||||
nvs_close(my_handle);
|
||||
TEST_ESP_OK(nvs_flash_deinit());
|
||||
|
||||
// register a new "nvs2" partition
|
||||
const esp_partition_t *nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs");
|
||||
const esp_partition_t *nvs2_part;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, find_unused_space(nvs_part->size), nvs_part->size, "nvs2", ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, &nvs2_part));
|
||||
ESP_LOGI(TAG, "Use %s partition (0x%08" PRIx32 ") to load a new image", nvs2_part->label, nvs2_part->address);
|
||||
TEST_ESP_OK(nvs_flash_erase_partition("nvs2"));
|
||||
|
||||
// OTA update of the new "nvs2" partition, taking "nvs" partition as source.
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(nvs2_part, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
download_new_image_from_partition(update_handle, nvs_part);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
// init "nvs2" partition and check if the magic_value == 0x0729FEED
|
||||
TEST_ESP_OK(nvs_flash_init_partition("nvs2"));
|
||||
nvs_handle_t my_handle2;
|
||||
TEST_ESP_OK(nvs_open_from_partition("nvs2", "namespace", NVS_READWRITE, &my_handle2));
|
||||
magic_value = 0;
|
||||
TEST_ESP_OK(nvs_get_u32(my_handle2, "magic_value", &magic_value));
|
||||
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
|
||||
nvs_close(my_handle2);
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition("nvs2"));
|
||||
|
||||
// deregister "nvs2"
|
||||
TEST_ESP_OK(esp_partition_deregister_external(nvs2_part));
|
||||
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
}
|
||||
|
||||
static void start_bootloader_ota_update_via_app_part(void)
|
||||
{
|
||||
const esp_partition_t *primary_bootloader;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
|
||||
|
||||
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(free_app_ota_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_bootloader, true));
|
||||
download_new_image_from_partition(update_handle, primary_bootloader);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
TEST_ESP_OK(esp_partition_deregister_external(primary_bootloader));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("OTA update of bootloader via a free ota partition", "[bootloader_ota][reset=SW_CPU_RESET]", start_bootloader_ota_update_via_app_part, check_after_reboot);
|
||||
|
||||
static void start_partition_table_ota_update_via_app_part(void)
|
||||
{
|
||||
const esp_partition_t *primary_partition_table;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
|
||||
|
||||
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(free_app_ota_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_partition_table, true));
|
||||
download_new_image_from_partition(update_handle, primary_partition_table);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
TEST_ESP_OK(esp_partition_deregister_external(primary_partition_table));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("OTA update of partition_table via a free ota partition", "[partition_table_ota][reset=SW_CPU_RESET]", start_partition_table_ota_update_via_app_part, check_after_reboot);
|
||||
|
||||
TEST_CASE("OTA update of NVS partition via a free ota partition", "[nvs_ota]")
|
||||
{
|
||||
// intilaize "nvs" partition and define a var (magic_value).
|
||||
const esp_partition_t *nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs");
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
nvs_handle_t my_handle;
|
||||
TEST_ESP_OK(nvs_open("namespace", NVS_READWRITE, &my_handle));
|
||||
uint32_t magic_value = 0x0729FEED;
|
||||
TEST_ESP_OK(nvs_set_u32(my_handle, "magic_value", magic_value));
|
||||
TEST_ESP_OK(nvs_commit(my_handle));
|
||||
magic_value = 0;
|
||||
TEST_ESP_OK(nvs_get_u32(my_handle, "magic_value", &magic_value));
|
||||
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
|
||||
nvs_close(my_handle);
|
||||
TEST_ESP_OK(nvs_flash_deinit());
|
||||
|
||||
// 1. OTA update nvs partition into free_app_ota_partition
|
||||
// 2. copy free_app_ota_partition into the original nvs partition (which was erased before coping)
|
||||
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||
esp_ota_handle_t update_handle;
|
||||
TEST_ESP_OK(esp_ota_begin(free_app_ota_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, nvs_part, true));
|
||||
download_new_image_from_partition(update_handle, nvs_part);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
|
||||
// Check if the magic_value == 0x0729FEED
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open("namespace", NVS_READONLY, &my_handle));
|
||||
magic_value = 0;
|
||||
TEST_ESP_OK(nvs_get_u32(my_handle, "magic_value", &magic_value));
|
||||
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
|
||||
nvs_close(my_handle);
|
||||
TEST_ESP_OK(nvs_flash_deinit());
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
}
|
@@ -43,7 +43,12 @@ static const char *TAG = "ota_test";
|
||||
static void set_boot_count_in_nvs(uint8_t boot_count)
|
||||
{
|
||||
nvs_handle_t boot_count_handle;
|
||||
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
|
||||
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle);
|
||||
if (err != ESP_OK) {
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
|
||||
}
|
||||
TEST_ESP_OK(nvs_set_u8(boot_count_handle, "boot_count", boot_count));
|
||||
TEST_ESP_OK(nvs_commit(boot_count_handle));
|
||||
nvs_close(boot_count_handle);
|
||||
|
@@ -63,7 +63,20 @@ static void init_efuse_virtual(void)
|
||||
// esp_flash must be initialized in advance because here we read the efuse partition.
|
||||
const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL);
|
||||
if (efuse_partition) {
|
||||
/*
|
||||
* esp_partition_find_first triggers the reading of partitions from the partition table.
|
||||
* However, since the efuses have not yet been read from the 'efuse_em' partition,
|
||||
* the encryption flag for these partitions is set to false.
|
||||
*
|
||||
* Unloading all partitions ensures that the next time the esp_partition API is called,
|
||||
* the efuses will have been read, and the correct encryption flags will be applied.
|
||||
*/
|
||||
esp_efuse_init_virtual_mode_in_flash(efuse_partition->address, efuse_partition->size);
|
||||
esp_partition_unload_all();
|
||||
|
||||
// Use volatile to ensure this function call is not optimized out and the partition table will be loaded again.
|
||||
volatile const esp_partition_t *dummy_partition = esp_partition_find_first(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
(void) dummy_partition;
|
||||
}
|
||||
#else // !CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
// For efuse virtual mode we need to seed virtual efuses from efuse_regs.
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <esp_http_client.h>
|
||||
#include <bootloader_common.h>
|
||||
#include "esp_app_desc.h"
|
||||
#include "esp_bootloader_desc.h"
|
||||
#include <sdkconfig.h>
|
||||
|
||||
#include "esp_event.h"
|
||||
@@ -26,7 +27,7 @@ ESP_EVENT_DECLARE_BASE(ESP_HTTPS_OTA_EVENT);
|
||||
typedef enum {
|
||||
ESP_HTTPS_OTA_START, /*!< OTA started */
|
||||
ESP_HTTPS_OTA_CONNECTED, /*!< Connected to server */
|
||||
ESP_HTTPS_OTA_GET_IMG_DESC, /*!< Read app description from image header */
|
||||
ESP_HTTPS_OTA_GET_IMG_DESC, /*!< Read app/bootloader description from image header */
|
||||
ESP_HTTPS_OTA_VERIFY_CHIP_ID, /*!< Verify chip id of new image */
|
||||
ESP_HTTPS_OTA_DECRYPT_CB, /*!< Callback to decrypt function */
|
||||
ESP_HTTPS_OTA_WRITE_FLASH, /*!< Flash write operation */
|
||||
@@ -68,6 +69,11 @@ typedef struct {
|
||||
void *decrypt_user_ctx; /*!< User context for external decryption layer */
|
||||
uint16_t enc_img_header_size; /*!< Header size of pre-encrypted ota image header */
|
||||
#endif
|
||||
struct { /*!< Details of staging and final partitions for OTA update */
|
||||
const esp_partition_t *staging; /*!< New image will be downloaded in this staging partition. If NULL then a free app partition (passive app partition) is selected as the staging partition. */
|
||||
const esp_partition_t *final; /*!< Final destination partition. Its type/subtype will be used for verification. If set to NULL, staging partition shall be set as the final partition. */
|
||||
bool finalize_with_copy; /*!< Flag to copy the staging image to the final partition at the end of OTA update */
|
||||
} partition; /*!< Struct containing details about the staging and final partitions for OTA update. */
|
||||
} esp_https_ota_config_t;
|
||||
|
||||
#define ESP_ERR_HTTPS_OTA_BASE (0x9000)
|
||||
@@ -223,6 +229,23 @@ esp_err_t esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle);
|
||||
*/
|
||||
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info);
|
||||
|
||||
/**
|
||||
* @brief Reads bootloader description from image header. The bootloader description provides information
|
||||
* like the "Bootloader version" of the image.
|
||||
*
|
||||
* @note This API can be called only after esp_https_ota_begin() and before esp_https_ota_perform().
|
||||
* Calling this API is not mandatory.
|
||||
*
|
||||
* @param[in] https_ota_handle pointer to esp_https_ota_handle_t structure
|
||||
* @param[out] new_img_info pointer to an allocated esp_bootloader_desc_t structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state to call this API. esp_https_ota_begin() not called yet.
|
||||
* - ESP_FAIL: Failed to read image descriptor
|
||||
* - ESP_OK: Successfully read image descriptor
|
||||
*/
|
||||
esp_err_t esp_https_ota_get_bootloader_img_desc(esp_https_ota_handle_t https_ota_handle, esp_bootloader_desc_t *new_img_info);
|
||||
|
||||
/**
|
||||
* @brief This function returns OTA image data read so far.
|
||||
|
@@ -39,7 +39,11 @@ typedef enum {
|
||||
|
||||
struct esp_https_ota_handle {
|
||||
esp_ota_handle_t update_handle;
|
||||
const esp_partition_t *update_partition;
|
||||
struct { /*!< Details of staging and final partitions for OTA update */
|
||||
const esp_partition_t *staging; /*!< New image will be downloaded in this staging partition. If NULL then a free app partition (passive app partition) is selected as the staging partition. */
|
||||
const esp_partition_t *final; /*!< Final destination partition which is intended to be updated. Its type/subtype shall be used for verification. If NULL, staging partition is considered as the final partition. */
|
||||
bool finalize_with_copy; /*!< Flag to copy the staging image to the final at the end of OTA update */
|
||||
} partition;
|
||||
esp_http_client_handle_t http_client;
|
||||
char *ota_upgrade_buf;
|
||||
size_t ota_upgrade_buf_size;
|
||||
@@ -368,16 +372,35 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
|
||||
#endif
|
||||
}
|
||||
|
||||
https_ota_handle->update_partition = NULL;
|
||||
https_ota_handle->partition.staging = NULL;
|
||||
ESP_LOGI(TAG, "Starting OTA...");
|
||||
https_ota_handle->update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
if (https_ota_handle->update_partition == NULL) {
|
||||
ESP_LOGE(TAG, "Passive OTA partition not found");
|
||||
if (ota_config->partition.staging != NULL) {
|
||||
https_ota_handle->partition.staging = esp_partition_verify(ota_config->partition.staging);
|
||||
} else {
|
||||
https_ota_handle->partition.staging = esp_ota_get_next_update_partition(NULL);
|
||||
}
|
||||
if (https_ota_handle->partition.staging == NULL) {
|
||||
ESP_LOGE(TAG, "Given staging partition or another suitable Passive OTA partition could not be found");
|
||||
err = ESP_FAIL;
|
||||
goto http_cleanup;
|
||||
}
|
||||
ESP_LOGI(TAG, "Writing to <%s> partition at offset 0x%" PRIx32,
|
||||
https_ota_handle->update_partition->label, https_ota_handle->update_partition->address);
|
||||
https_ota_handle->partition.staging->label, https_ota_handle->partition.staging->address);
|
||||
|
||||
if (ota_config->partition.final == NULL) {
|
||||
https_ota_handle->partition.final = https_ota_handle->partition.staging;
|
||||
} else {
|
||||
if (ota_config->partition.staging != ota_config->partition.final) {
|
||||
const esp_partition_t *final = esp_partition_verify(ota_config->partition.final);
|
||||
if (final == NULL) {
|
||||
ESP_LOGE(TAG, "Given final partition not found");
|
||||
err = ESP_FAIL;
|
||||
goto http_cleanup;
|
||||
}
|
||||
https_ota_handle->partition.final = final;
|
||||
https_ota_handle->partition.finalize_with_copy = ota_config->partition.finalize_with_copy;
|
||||
}
|
||||
}
|
||||
|
||||
const int alloc_size = MAX(ota_config->http_config->buffer_size, DEFAULT_OTA_BUF_SIZE);
|
||||
if (ota_config->buffer_caps != 0) {
|
||||
@@ -449,7 +472,7 @@ static esp_err_t read_header(esp_https_ota_t *handle)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
|
||||
static esp_err_t get_description_from_image(esp_https_ota_handle_t https_ota_handle, void *new_img_info)
|
||||
{
|
||||
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_GET_IMG_DESC, NULL, 0);
|
||||
|
||||
@@ -460,7 +483,7 @@ esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, es
|
||||
#endif
|
||||
|
||||
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
||||
if (handle == NULL || new_app_info == NULL) {
|
||||
if (handle == NULL || new_img_info == NULL) {
|
||||
ESP_LOGE(TAG, "esp_https_ota_get_img_desc: Invalid argument");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -472,17 +495,41 @@ esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, es
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
const int app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t);
|
||||
esp_app_desc_t *app_info = (esp_app_desc_t *) &handle->ota_upgrade_buf[app_desc_offset];
|
||||
if (app_info->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
ESP_LOGE(TAG, "Incorrect app descriptor magic");
|
||||
void *img_info = (void *)&handle->ota_upgrade_buf[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)];
|
||||
unsigned img_info_len;
|
||||
if (handle->partition.final->type == ESP_PARTITION_TYPE_APP) {
|
||||
img_info_len = sizeof(esp_app_desc_t);
|
||||
esp_app_desc_t *app_info = (esp_app_desc_t *)img_info;
|
||||
if (app_info->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
ESP_LOGE(TAG, "Incorrect app descriptor magic");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else if (handle->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
img_info_len = sizeof(esp_bootloader_desc_t);
|
||||
esp_bootloader_desc_t *bootloader_info = (esp_bootloader_desc_t *)img_info;
|
||||
if (bootloader_info->magic_byte != ESP_BOOTLOADER_DESC_MAGIC_BYTE) {
|
||||
ESP_LOGE(TAG, "Incorrect bootloader descriptor magic");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "This partition type (%d) is not supported", handle->partition.final->type);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memcpy(new_app_info, app_info, sizeof(esp_app_desc_t));
|
||||
memcpy(new_img_info, img_info, img_info_len);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
|
||||
{
|
||||
return get_description_from_image(https_ota_handle, new_app_info);
|
||||
}
|
||||
|
||||
esp_err_t esp_https_ota_get_bootloader_img_desc(esp_https_ota_handle_t https_ota_handle, esp_bootloader_desc_t *new_img_info)
|
||||
{
|
||||
return get_description_from_image(https_ota_handle, new_img_info);
|
||||
}
|
||||
|
||||
static esp_err_t esp_ota_verify_chip_id(const void *arg)
|
||||
{
|
||||
esp_image_header_t *data = (esp_image_header_t *)(arg);
|
||||
@@ -512,11 +559,12 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
|
||||
const int erase_size = handle->bulk_flash_erase ? (handle->image_length > 0 ? handle->image_length : OTA_SIZE_UNKNOWN) : OTA_WITH_SEQUENTIAL_WRITES;
|
||||
switch (handle->state) {
|
||||
case ESP_HTTPS_OTA_BEGIN:
|
||||
err = esp_ota_begin(handle->update_partition, erase_size, &handle->update_handle);
|
||||
err = esp_ota_begin(handle->partition.staging, erase_size, &handle->update_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
esp_ota_set_final_partition(handle->update_handle, handle->partition.final, handle->partition.finalize_with_copy);
|
||||
handle->state = ESP_HTTPS_OTA_IN_PROGRESS;
|
||||
/* In case `esp_https_ota_get_img_desc` was invoked first,
|
||||
then the image data read there should be written to OTA partition
|
||||
@@ -550,9 +598,11 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
|
||||
err = esp_ota_verify_chip_id(data_buf);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
if (handle->partition.final->type == ESP_PARTITION_TYPE_APP || handle->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
|
||||
err = esp_ota_verify_chip_id(data_buf);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return _ota_write(handle, data_buf, binary_file_len);
|
||||
case ESP_HTTPS_OTA_IN_PROGRESS:
|
||||
@@ -674,12 +724,16 @@ esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
|
||||
err = esp_ota_set_boot_partition(handle->update_partition);
|
||||
if ((handle->partition.final->type == ESP_PARTITION_TYPE_APP) && (err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
|
||||
if (handle->partition.final->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0 && handle->partition.final->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
|
||||
// Do not allow the boot partition to be set as the Factory partition, because ota_data will be erased in this case.
|
||||
// The user can call it afterward if needed.
|
||||
err = esp_ota_set_boot_partition(handle->partition.staging);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
|
||||
} else {
|
||||
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_UPDATE_BOOT_PARTITION, (void *)(&handle->update_partition->subtype), sizeof(esp_partition_subtype_t));
|
||||
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_UPDATE_BOOT_PARTITION, (void *)(&handle->partition.final->subtype), sizeof(esp_partition_subtype_t));
|
||||
}
|
||||
}
|
||||
free(handle);
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_md5.h"
|
||||
#include "bootloader_util.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_LINUX
|
||||
#include "esp_private/partition_linux.h"
|
||||
@@ -92,6 +93,10 @@ static bool is_partition_encrypted(bool encryption_config, esp_partition_type_t
|
||||
are always encrypted */
|
||||
ret_encrypted = true;
|
||||
}
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
// FE can be enabled in virt eFuses but not in real eFuses.
|
||||
ret_encrypted &= efuse_hal_flash_encryption_enabled();
|
||||
#endif
|
||||
return ret_encrypted;
|
||||
#endif
|
||||
}
|
||||
|
@@ -150,6 +150,8 @@ Application Examples
|
||||
|
||||
- :example:`system/ota/advanced_https_ota` demonstrates how to use the Advanced HTTPS OTA update functionality on {IDF_TARGET_NAME} using the `esp_https_ota` component's APIs. For the applicable SoCs, please refer to :example_file:`system/ota/advanced_https_ota/README.md`.
|
||||
|
||||
- :example:`system/ota/partitions_ota` demonstrates how to perform OTA updates for various partitions (app, bootloader, partition table, storage) using the `esp_https_ota` component's APIs.
|
||||
|
||||
- :example:`system/ota/simple_ota_example` demonstrates how to use the `esp_https_ota` component's APIs to support firmware upgrades through specific networking interfaces such as Ethernet or Wi-Fi Station on {IDF_TARGET_NAME}. For the applicable SoCs, please refer to :example_file:`system/ota/simple_ota_example/README.md`.
|
||||
|
||||
API Reference
|
||||
|
@@ -8,9 +8,17 @@ OTA Process Overview
|
||||
|
||||
The OTA update mechanism allows a device to update itself based on data received while the normal firmware is running (for example, over Wi-Fi, Bluetooth or Ethernet).
|
||||
|
||||
OTA requires configuring the :doc:`../../api-guides/partition-tables` of the device with at least two OTA app slot partitions (i.e., ``ota_0`` and ``ota_1``) and an OTA Data Partition.
|
||||
The following modes support OTA updates for certain partitions:
|
||||
|
||||
The OTA operation functions write a new app firmware image to whichever OTA app slot that is currently not selected for booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the next boot.
|
||||
- **Safe update mode**. The update process for certain partitions is designed to be resilient, ensuring that even if the power is cut off during the update, the chip will remain operational and capable of booting the current application. The following partitions support this mode:
|
||||
|
||||
- Application. OTA requires configuring the :doc:`../../api-guides/partition-tables` of the device with at least two OTA app slot partitions (i.e., ``ota_0`` and ``ota_1``) and an OTA Data Partition. The OTA operation functions write a new app firmware image to whichever OTA app slot that is currently not selected for booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the next boot.
|
||||
|
||||
- **Unsafe update mode**. The update process is vulnerable, meaning that a power interruption during the update can cause issues that prevent the current application from loading, potentially leading to an unrecoverable state. The temporary partition receives the new image, and once it is fully downloaded, the image is copied to the final destination partition. If an interruption occurs during this final copying process, it can lead to issues. The following partitions support this mode:
|
||||
|
||||
- Bootloader.
|
||||
- Partition table.
|
||||
- other data partitions like nvs, fat, etc.
|
||||
|
||||
.. _ota_data_partition:
|
||||
|
||||
|
@@ -172,6 +172,25 @@ examples/system/ota/otatool:
|
||||
enable:
|
||||
- if: INCLUDE_DEFAULT == 1 or IDF_TARGET in ["esp32c5", "esp32c61"]
|
||||
|
||||
examples/system/ota/partitions_ota:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
||||
temporary: true
|
||||
reason: target esp32h2 is not supported yet
|
||||
disable_test:
|
||||
- if: IDF_TARGET not in ["esp32", "esp32c3", "esp32s3"]
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
depends_components:
|
||||
- app_update
|
||||
- esp_https_ota
|
||||
- esp_http_client
|
||||
# different configs need different components
|
||||
- esp_eth
|
||||
- esp_wifi
|
||||
- esp_phy
|
||||
- mbedtls
|
||||
|
||||
examples/system/ota/pre_encrypted_ota:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
||||
|
@@ -15,7 +15,15 @@ An application on "ESP-Dev-Board" may be upgraded at runtime by downloading a ne
|
||||
- Using the native APIs provided by the [`app_update`](../../../components/app_update) component.
|
||||
- Using simplified APIs provided by the [`esp_https_ota`](../../../components/esp_https_ota) component, which provides functionality to upgrade over HTTPS.
|
||||
|
||||
Use of the native API is demonstrated in the `native_ota_example` directory while the API provided by the `esp_https_ota` component is demonstrated under `simple_ota_example` and `advanced_https_ota`.
|
||||
Use of the native API is demonstrated in the `native_ota_example` directory while the API provided by the `esp_https_ota` component is demonstrated under `simple_ota_example`, `advanced_https_ota`, and `partitions_ota`.
|
||||
|
||||
The `partitions_ota` demonstrates the OTA update process for any partition type (other examples support only safe updates for application):
|
||||
- Application (safe update).
|
||||
- Bootloader (unsafe update).
|
||||
- Partition table (unsafe update).
|
||||
- other data partitions (unsafe update).
|
||||
|
||||
**Note:** **Safe updates** are designed to ensure that the device remains operational even if the update process is interrupted. This means that the device can still boot and function normally, minimizing the risk of failure. On the other hand, **unsafe updates** carry a significant risk. If the update is disrupted while copying to the destination partition, it can lead to critical failures, potentially making the device inoperable and unrecoverable. Since the final copying is performed on the user side, this risk can be minimized by ensuring stable power and error-free conditions during this time.
|
||||
|
||||
For information regarding the `esp_https_ota` component, please refer to [ESP HTTPS OTA](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_https_ota.html).
|
||||
|
||||
|
15
examples/system/ota/partitions_ota/CMakeLists.txt
Normal file
15
examples/system/ota/partitions_ota/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(partitions_ota)
|
||||
|
||||
# Copy storage.bin from test folder to build directory
|
||||
add_custom_target(copy_storage_bin ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_SOURCE_DIR}/test/storage.bin
|
||||
${CMAKE_BINARY_DIR}/storage.bin
|
||||
COMMENT "Copying test/storage.bin to build directory"
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/test/storage.bin
|
||||
)
|
633
examples/system/ota/partitions_ota/README.md
Normal file
633
examples/system/ota/partitions_ota/README.md
Normal file
@@ -0,0 +1,633 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
|
||||
|
||||
# Partition OTA Example
|
||||
|
||||
This example demonstrates how to perform OTA updates for various partitions using the `esp_https_ota` component's APIs. The following partitions can be updated:
|
||||
- Application (app)
|
||||
- Bootloader
|
||||
- Partition Table
|
||||
- Storage
|
||||
|
||||
This example can be easily modified to perform OTA updates for any partition type.
|
||||
|
||||
> ⚠️ **WARNING**: Updating the bootloader and partition table is not safe. If the final copying to the destination partition is interrupted, the chip may fail to boot. Ensure that the final copy occurs only when power is stable and there is a low risk of errors.
|
||||
|
||||
## OTA Update
|
||||
Currently, there is no rollback mechanism for non-application partitions. In case of failure, only the application partition can safely rollback.
|
||||
|
||||
### Application
|
||||
|
||||
Application OTA updates use one active and one passive partition. The new image is downloaded into the passive partition. Once the download is complete and verified, the device switches to the new image. This approach ensures that unexpected reboots during the update do not render the device unusable.
|
||||
|
||||
### Bootloader
|
||||
|
||||
Bootloader OTA updates are not inherently safe because the ROM bootloader does not support fallback to a recovery bootloader partition. Only the primary bootloader partition can be loaded by the ROM bootloader. Updating the bootloader is rarely necessary, and it is generally not recommended. However, if required, it can be done using the following approaches:
|
||||
|
||||
- Register the primary bootloader partition in the partition table, if not already present (see `test/partitions_efuse_emul_2.csv`).
|
||||
- Decide where to download the new bootloader image:
|
||||
- Use a passive app partition, if app rollback is not used at the same time.
|
||||
- Use a dedicated OTA bootloader partition (type=bootloader, subtype=ota). You can find unallocated flash space with `partition_utils_find_unallocated()`.
|
||||
- Download directly into the primary bootloader partition (this approach is highly unsafe).
|
||||
|
||||
After verification, if `finalize_with_copy` is set to `true`, the tool will automatically copy the new image to the primary bootloader partition. Set `finalize_with_copy` to `false` if you wish to control the final copy step manually.
|
||||
|
||||
Limitations for Bootloader OTA updates:
|
||||
- Secure Boot V1-enabled devices do not support bootloader updates.
|
||||
- There is always a risk of device bricking when updating the bootloader.
|
||||
|
||||
### Partition Table
|
||||
|
||||
Updating the partition table via OTA is similarly unsafe because the bootloader cannot use a backup partition table in case of failure. If the update fails, the device will be unable to boot. Partition table updates are rarely needed, and caution is strongly advised. The workflow for partition table updates is the same as for the bootloader.
|
||||
|
||||
### Storage
|
||||
|
||||
Updating storage partitions via OTA is also risky due to the potential for data loss in the partition. There is no fallback mechanism if an error occurs during the update. The workflow for Storage updates is the same as for the bootloader.
|
||||
|
||||
## Configuration
|
||||
|
||||
Refer to the README.md file in the parent directory for setup instructions.
|
||||
|
||||
This example supports binding to a specific network interface ("Ethernet" or "WiFi Station") for firmware updates. You can configure this in `idf.py menuconfig -> Example Configuration -> Support firmware upgrade bind specified interface -> Choose OTA data bind interface`.
|
||||
|
||||
The CSV partition table file may include these entries at the beginning (see `test/partitions_efuse_emul_2.csv`):
|
||||
```
|
||||
PrimaryBTLDR, bootloader, primary, N/A, N/A, encrypted
|
||||
PrimaryPrtTable, partition_table, primary, N/A, N/A, encrypted
|
||||
```
|
||||
|
||||
## Example output
|
||||
|
||||
Running the exapmple with sdkconfig.ci.on_update_no_sb_rsa settings:
|
||||
|
||||
```
|
||||
ESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce2820,len:0x15a0
|
||||
load:0x403c8700,len:0x4
|
||||
load:0x403c8704,len:0xd20
|
||||
load:0x403cb700,len:0x2f3c
|
||||
entry 0x403c8928
|
||||
I (27) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
|
||||
I (27) boot: compile time Oct 28 2024 15:26:41
|
||||
I (27) boot: Multicore bootloader
|
||||
I (27) boot: chip revision: v0.1
|
||||
I (30) boot: efuse block revision: v1.2
|
||||
I (34) boot.esp32s3: Boot SPI Speed : 80MHz
|
||||
I (37) boot.esp32s3: SPI Mode : DIO
|
||||
I (41) boot.esp32s3: SPI Flash Size : 4MB
|
||||
I (45) boot: Enabling RNG early entropy source...
|
||||
I (49) boot: Partition Table:
|
||||
I (52) boot: ## Label Usage Type ST Offset Length
|
||||
I (58) boot: 0 nvs WiFi data 01 02 0000d000 00006000
|
||||
I (65) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
|
||||
I (71) boot: 2 storage Unknown data 01 06 00014000 00001000
|
||||
I (78) boot: 3 otadata OTA data 01 00 00015000 00002000
|
||||
I (84) boot: 4 phy_init RF data 01 01 00017000 00001000
|
||||
I (91) boot: 5 emul_efuse efuse 01 05 00018000 00002000
|
||||
I (97) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
|
||||
I (104) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
|
||||
I (111) boot: End of partition table
|
||||
I (114) boot: No factory image, trying OTA 0
|
||||
I (118) esp_image: segment 0: paddr=00020020 vaddr=3c090020 size=24288h (148104) map
|
||||
I (152) esp_image: segment 1: paddr=000442b0 vaddr=3fc98900 size=04970h ( 18800) load
|
||||
I (156) esp_image: segment 2: paddr=00048c28 vaddr=40374000 size=073f0h ( 29680) load
|
||||
I (162) esp_image: segment 3: paddr=00050020 vaddr=42000020 size=8fc00h (588800) map
|
||||
I (267) esp_image: segment 4: paddr=000dfc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
|
||||
I (279) esp_image: segment 5: paddr=000ed0dc vaddr=600fe100 size=0001ch ( 28) load
|
||||
I (287) boot: Loaded app from partition at offset 0x20000
|
||||
I (429) boot: Set actual ota_seq=1 in otadata[0]
|
||||
I (430) boot: Disabling RNG early entropy source...
|
||||
I (439) cpu_start: Multicore app
|
||||
I (449) cpu_start: Pro cpu start user code
|
||||
I (449) cpu_start: cpu freq: 160000000 Hz
|
||||
I (449) app_init: Application information:
|
||||
I (449) app_init: Project name: partitions_ota
|
||||
I (453) app_init: App version: 95a1e4cd
|
||||
I (457) app_init: Compile time: Oct 28 2024 15:26:38
|
||||
I (462) app_init: ELF file SHA256: 0810d7fd3...
|
||||
I (467) app_init: ESP-IDF: 95a1e4cd
|
||||
I (471) efuse_init: Min chip rev: v0.0
|
||||
I (475) efuse_init: Max chip rev: v0.99
|
||||
I (479) efuse_init: Chip rev: v0.1
|
||||
I (482) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (489) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
|
||||
I (494) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
|
||||
I (499) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
|
||||
I (504) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
|
||||
I (511) spi_flash: detected chip: generic
|
||||
I (513) spi_flash: flash io: dio
|
||||
W (516) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
|
||||
I (530) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (535) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (542) main_task: Started on CPU0
|
||||
I (562) main_task: Calling app_main()
|
||||
I (562) ota_example: OTA example app_main start
|
||||
I (572) example_connect: Start example_connect.
|
||||
I (572) pp: pp rom version: e7ae62f
|
||||
I (572) net80211: net80211 rom version: e7ae62f
|
||||
I (592) wifi:wifi driver task: 3fcab44c, prio:23, stack:6656, core=0
|
||||
I (592) wifi:wifi firmware version: 2d9c351b0
|
||||
I (592) wifi:wifi certification version: v7.0
|
||||
I (592) wifi:config NVS flash: enabled
|
||||
I (592) wifi:config nano formatting: disabled
|
||||
I (602) wifi:Init data frame dynamic rx buffer num: 32
|
||||
I (602) wifi:Init static rx mgmt buffer num: 5
|
||||
I (612) wifi:Init management short buffer num: 32
|
||||
I (612) wifi:Init dynamic tx buffer num: 32
|
||||
I (612) wifi:Init static tx FG buffer num: 2
|
||||
I (622) wifi:Init static rx buffer size: 1600
|
||||
I (622) wifi:Init static rx buffer num: 10
|
||||
I (632) wifi:Init dynamic rx buffer num: 32
|
||||
I (632) wifi_init: rx ba win: 6
|
||||
I (632) wifi_init: accept mbox: 6
|
||||
I (642) wifi_init: tcpip mbox: 32
|
||||
I (642) wifi_init: udp mbox: 6
|
||||
I (642) wifi_init: tcp mbox: 6
|
||||
I (642) wifi_init: tcp tx win: 5760
|
||||
I (652) wifi_init: tcp rx win: 5760
|
||||
I (652) wifi_init: tcp mss: 1440
|
||||
I (652) wifi_init: WiFi IRAM OP enabled
|
||||
I (662) wifi_init: WiFi RX IRAM OP enabled
|
||||
I (662) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
|
||||
W (672) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
|
||||
W (702) phy_init: saving new calibration data because of checksum failure, mode(2)
|
||||
I (722) wifi:mode : sta (68:b6:b3:4d:91:08)
|
||||
I (722) wifi:enable tsf
|
||||
I (722) example_connect: Please input ssid password:
|
||||
I (752) example_connect: Connecting to myssid...
|
||||
W (752) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
|
||||
I (762) example_connect: Waiting for IP(s)
|
||||
I (3592) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (3592) wifi:state: init -> auth (0xb0)
|
||||
I (3592) wifi:state: auth -> assoc (0x0)
|
||||
I (3602) wifi:state: assoc -> run (0x10)
|
||||
I (3622) wifi:connected with myssid, aid = 3, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
|
||||
I (3622) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
|
||||
I (3622) wifi:pm start, type: 1
|
||||
|
||||
I (3632) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
|
||||
I (3632) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
|
||||
I (3722) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (4722) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (4722) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
|
||||
I (4732) example_common: Connected to example_netif_sta
|
||||
I (4732) example_common: - IPv4 address: 192.168.3.26,
|
||||
I (4742) wifi:Set ps type: 0, coexist: 0
|
||||
|
||||
I (4742) ota_example: Starting OTA example task
|
||||
I (4742) ota_example: Bind interface name is st1
|
||||
I (4752) main_task: Returned from app_main()
|
||||
I (4762) ota_example: Attempting to download update from https://192.168.3.9:8000/partitions_ota.bin
|
||||
I (4782) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
|
||||
I (4812) esp-x509-crt-bundle: Certificate validated
|
||||
I (5142) esp_https_ota: Starting OTA...
|
||||
I (5142) esp_https_ota: Writing to <ota_1> partition at offset 0x1d0000
|
||||
I (29702) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
|
||||
I (29722) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800)
|
||||
I (29732) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680)
|
||||
I (29732) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
|
||||
I (29822) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444)
|
||||
I (29832) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28)
|
||||
I (29832) esp_image: Verifying image signature...
|
||||
I (29842) secure_boot_v2: Take trusted digest key(s) from running app
|
||||
I (29852) secure_boot_v2: #0 app key digest == #0 trusted key digest
|
||||
I (29852) secure_boot_v2: Verifying with RSA-PSS...
|
||||
I (29912) secure_boot_v2_rsa: Signature verified successfully!
|
||||
I (29912) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
|
||||
I (29932) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800)
|
||||
I (29942) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680)
|
||||
I (29942) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
|
||||
I (30032) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444)
|
||||
I (30042) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28)
|
||||
I (30042) esp_image: Verifying image signature...
|
||||
I (30042) secure_boot_v2: Take trusted digest key(s) from running app
|
||||
I (30062) secure_boot_v2: #0 app key digest == #0 trusted key digest
|
||||
I (30062) secure_boot_v2: Verifying with RSA-PSS...
|
||||
I (30122) secure_boot_v2_rsa: Signature verified successfully!
|
||||
I (30292) ota_example: OTA Succeed, Rebooting...
|
||||
I (30292) wifi:state: run -> init (0x0)
|
||||
I (30292) wifi:pm stop, total sleep time: 737814 us / 26659208 us
|
||||
|
||||
I (30292) wifi:<ba-del>idx:0, tid:0
|
||||
I (30302) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (30352) wifi:flush txq
|
||||
I (30352) wifi:stop sw txq
|
||||
I (30352) wifi:lmac stop hw txq
|
||||
I (30352) wifi:Deinit lldesc rx mblock:10
|
||||
|
||||
ESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
Saved PC:0x40376c31
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce2820,len:0x15a0
|
||||
load:0x403c8700,len:0x4
|
||||
load:0x403c8704,len:0xd20
|
||||
load:0x403cb700,len:0x2f3c
|
||||
entry 0x403c8928
|
||||
I (31) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
|
||||
I (31) boot: compile time Oct 28 2024 15:26:41
|
||||
I (31) boot: Multicore bootloader
|
||||
I (32) boot: chip revision: v0.1
|
||||
I (34) boot: efuse block revision: v1.2
|
||||
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
|
||||
I (42) boot.esp32s3: SPI Mode : DIO
|
||||
I (46) boot.esp32s3: SPI Flash Size : 4MB
|
||||
I (49) boot: Enabling RNG early entropy source...
|
||||
I (54) boot: Partition Table:
|
||||
I (56) boot: ## Label Usage Type ST Offset Length
|
||||
I (63) boot: 0 nvs WiFi data 01 02 0000d000 00006000
|
||||
I (69) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
|
||||
I (76) boot: 2 storage Unknown data 01 06 00014000 00001000
|
||||
I (82) boot: 3 otadata OTA data 01 00 00015000 00002000
|
||||
I (89) boot: 4 phy_init RF data 01 01 00017000 00001000
|
||||
I (95) boot: 5 emul_efuse efuse 01 05 00018000 00002000
|
||||
I (102) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
|
||||
I (108) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
|
||||
I (115) boot: End of partition table
|
||||
I (118) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
|
||||
I (152) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800) load
|
||||
I (156) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680) load
|
||||
I (163) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
|
||||
I (267) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
|
||||
I (279) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28) load
|
||||
I (288) boot: Loaded app from partition at offset 0x1d0000
|
||||
I (288) boot: Disabling RNG early entropy source...
|
||||
I (298) cpu_start: Multicore app
|
||||
I (308) cpu_start: Pro cpu start user code
|
||||
I (308) cpu_start: cpu freq: 160000000 Hz
|
||||
I (308) app_init: Application information:
|
||||
I (308) app_init: Project name: partitions_ota
|
||||
I (312) app_init: App version: 95a1e4cd
|
||||
I (316) app_init: Compile time: Oct 28 2024 15:26:38
|
||||
I (321) app_init: ELF file SHA256: 0810d7fd3...
|
||||
I (326) app_init: ESP-IDF: 95a1e4cd
|
||||
I (330) efuse_init: Min chip rev: v0.0
|
||||
I (334) efuse_init: Max chip rev: v0.99
|
||||
I (338) efuse_init: Chip rev: v0.1
|
||||
I (341) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (348) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
|
||||
I (353) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
|
||||
I (358) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
|
||||
I (363) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
|
||||
I (370) spi_flash: detected chip: generic
|
||||
I (372) spi_flash: flash io: dio
|
||||
W (375) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
|
||||
I (389) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (394) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (401) main_task: Started on CPU0
|
||||
I (421) main_task: Calling app_main()
|
||||
I (421) ota_example: OTA example app_main start
|
||||
I (431) example_connect: Start example_connect.
|
||||
I (431) pp: pp rom version: e7ae62f
|
||||
I (431) net80211: net80211 rom version: e7ae62f
|
||||
I (441) wifi:wifi driver task: 3fcab48c, prio:23, stack:6656, core=0
|
||||
I (441) wifi:wifi firmware version: 2d9c351b0
|
||||
I (441) wifi:wifi certification version: v7.0
|
||||
I (451) wifi:config NVS flash: enabled
|
||||
I (451) wifi:config nano formatting: disabled
|
||||
I (451) wifi:Init data frame dynamic rx buffer num: 32
|
||||
I (461) wifi:Init static rx mgmt buffer num: 5
|
||||
I (461) wifi:Init management short buffer num: 32
|
||||
I (471) wifi:Init dynamic tx buffer num: 32
|
||||
I (471) wifi:Init static tx FG buffer num: 2
|
||||
I (471) wifi:Init static rx buffer size: 1600
|
||||
I (481) wifi:Init static rx buffer num: 10
|
||||
I (481) wifi:Init dynamic rx buffer num: 32
|
||||
I (491) wifi_init: rx ba win: 6
|
||||
I (491) wifi_init: accept mbox: 6
|
||||
I (491) wifi_init: tcpip mbox: 32
|
||||
I (501) wifi_init: udp mbox: 6
|
||||
I (501) wifi_init: tcp mbox: 6
|
||||
I (501) wifi_init: tcp tx win: 5760
|
||||
I (501) wifi_init: tcp rx win: 5760
|
||||
I (511) wifi_init: tcp mss: 1440
|
||||
I (511) wifi_init: WiFi IRAM OP enabled
|
||||
I (511) wifi_init: WiFi RX IRAM OP enabled
|
||||
I (521) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
|
||||
I (561) wifi:mode : sta (68:b6:b3:4d:91:08)
|
||||
I (561) wifi:enable tsf
|
||||
I (561) example_connect: Please input ssid password:
|
||||
I (611) example_connect: Connecting to myssid...
|
||||
W (611) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
|
||||
I (611) example_connect: Waiting for IP(s)
|
||||
I (3441) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (3441) wifi:state: init -> auth (0xb0)
|
||||
I (3451) wifi:state: auth -> assoc (0x0)
|
||||
I (3451) wifi:state: assoc -> run (0x10)
|
||||
I (3471) wifi:connected with myssid, aid = 3, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
|
||||
I (3471) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
|
||||
I (3471) wifi:pm start, type: 1
|
||||
|
||||
I (3491) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
|
||||
I (3491) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
|
||||
I (3571) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (4591) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (4591) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
|
||||
I (4601) example_common: Connected to example_netif_sta
|
||||
I (4601) example_common: - IPv4 address: 192.168.3.26,
|
||||
I (4611) wifi:Set ps type: 0, coexist: 0
|
||||
|
||||
I (4611) ota_example: Starting OTA example task
|
||||
I (4611) ota_example: Bind interface name is st1
|
||||
I (4621) main_task: Returned from app_main()
|
||||
I (4671) ota_example: Attempting to download update from https://192.168.3.9:8000/bootloader/bootloader.bin
|
||||
I (4671) ota_example: Use <PrimaryBTLDR> partition (0x00000000)
|
||||
I (4701) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
|
||||
I (4731) esp-x509-crt-bundle: Certificate validated
|
||||
I (5061) esp_https_ota: Starting OTA...
|
||||
I (5061) esp_https_ota: Writing to <ota_0> partition at offset 0x20000
|
||||
I (5061) esp_ota_ops: Staging partition - <ota_0>. Final partition - <PrimaryBTLDR>.
|
||||
I (5071) esp_image: Bootloader offsets for PRIMARY: 0x0, Secondary: 0x20000
|
||||
I (6121) esp_image: segment 0: paddr=00020020 vaddr=3fce2820 size=015a0h ( 5536)
|
||||
I (6121) esp_image: segment 1: paddr=000215c8 vaddr=403c8700 size=00004h ( 4)
|
||||
I (6131) esp_image: segment 2: paddr=000215d4 vaddr=403c8704 size=00d20h ( 3360)
|
||||
I (6131) esp_image: segment 3: paddr=000222fc vaddr=403cb700 size=02f3ch ( 12092)
|
||||
I (6151) esp_image: Bootloader offsets for PRIMARY: 0x0, Secondary: 0x0
|
||||
W (6151) ota_example: Ensure stable power supply! Loss of power at this stage leads to a chip bricking
|
||||
I (6151) ota_example: Copy from <ota_0> staging partition to <PrimaryBTLDR>...
|
||||
I (7801) ota_example: OTA Succeed, Rebooting...
|
||||
I (7801) wifi:state: run -> init (0x0)
|
||||
I (7801) wifi:pm stop, total sleep time: 742270 us / 4318054 us
|
||||
|
||||
I (7801) wifi:<ba-del>idx:0, tid:0
|
||||
I (7821) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (7831) wifi:flush txq
|
||||
I (7831) wifi:stop sw txq
|
||||
I (7831) wifi:lmac stop hw txq
|
||||
I (7831) wifi:Deinit lldesc rx mblock:10
|
||||
|
||||
ESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
Saved PC:0x40376c31
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce2820,len:0x15a0
|
||||
load:0x403c8700,len:0x4
|
||||
load:0x403c8704,len:0xd20
|
||||
load:0x403cb700,len:0x2f3c
|
||||
entry 0x403c8928
|
||||
I (31) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
|
||||
I (31) boot: compile time Oct 28 2024 15:26:41
|
||||
I (31) boot: Multicore bootloader
|
||||
I (32) boot: chip revision: v0.1
|
||||
I (34) boot: efuse block revision: v1.2
|
||||
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
|
||||
I (42) boot.esp32s3: SPI Mode : DIO
|
||||
I (46) boot.esp32s3: SPI Flash Size : 4MB
|
||||
I (49) boot: Enabling RNG early entropy source...
|
||||
I (54) boot: Partition Table:
|
||||
I (56) boot: ## Label Usage Type ST Offset Length
|
||||
I (63) boot: 0 nvs WiFi data 01 02 0000d000 00006000
|
||||
I (69) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
|
||||
I (76) boot: 2 storage Unknown data 01 06 00014000 00001000
|
||||
I (82) boot: 3 otadata OTA data 01 00 00015000 00002000
|
||||
I (89) boot: 4 phy_init RF data 01 01 00017000 00001000
|
||||
I (95) boot: 5 emul_efuse efuse 01 05 00018000 00002000
|
||||
I (102) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
|
||||
I (108) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
|
||||
I (115) boot: End of partition table
|
||||
I (118) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
|
||||
I (152) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800) load
|
||||
I (156) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680) load
|
||||
I (163) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
|
||||
I (267) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
|
||||
I (279) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28) load
|
||||
I (288) boot: Loaded app from partition at offset 0x1d0000
|
||||
I (288) boot: Disabling RNG early entropy source...
|
||||
I (298) cpu_start: Multicore app
|
||||
I (308) cpu_start: Pro cpu start user code
|
||||
I (308) cpu_start: cpu freq: 160000000 Hz
|
||||
I (308) app_init: Application information:
|
||||
I (308) app_init: Project name: partitions_ota
|
||||
I (312) app_init: App version: 95a1e4cd
|
||||
I (316) app_init: Compile time: Oct 28 2024 15:26:38
|
||||
I (321) app_init: ELF file SHA256: 0810d7fd3...
|
||||
I (326) app_init: ESP-IDF: 95a1e4cd
|
||||
I (330) efuse_init: Min chip rev: v0.0
|
||||
I (334) efuse_init: Max chip rev: v0.99
|
||||
I (338) efuse_init: Chip rev: v0.1
|
||||
I (341) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (348) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
|
||||
I (353) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
|
||||
I (358) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
|
||||
I (363) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
|
||||
I (370) spi_flash: detected chip: generic
|
||||
I (372) spi_flash: flash io: dio
|
||||
W (375) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
|
||||
I (389) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (394) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (401) main_task: Started on CPU0
|
||||
I (421) main_task: Calling app_main()
|
||||
I (421) ota_example: OTA example app_main start
|
||||
I (431) example_connect: Start example_connect.
|
||||
I (431) pp: pp rom version: e7ae62f
|
||||
I (431) net80211: net80211 rom version: e7ae62f
|
||||
I (441) wifi:wifi driver task: 3fcab48c, prio:23, stack:6656, core=0
|
||||
I (441) wifi:wifi firmware version: 2d9c351b0
|
||||
I (441) wifi:wifi certification version: v7.0
|
||||
I (451) wifi:config NVS flash: enabled
|
||||
I (451) wifi:config nano formatting: disabled
|
||||
I (451) wifi:Init data frame dynamic rx buffer num: 32
|
||||
I (461) wifi:Init static rx mgmt buffer num: 5
|
||||
I (461) wifi:Init management short buffer num: 32
|
||||
I (471) wifi:Init dynamic tx buffer num: 32
|
||||
I (471) wifi:Init static tx FG buffer num: 2
|
||||
I (471) wifi:Init static rx buffer size: 1600
|
||||
I (481) wifi:Init static rx buffer num: 10
|
||||
I (481) wifi:Init dynamic rx buffer num: 32
|
||||
I (491) wifi_init: rx ba win: 6
|
||||
I (491) wifi_init: accept mbox: 6
|
||||
I (491) wifi_init: tcpip mbox: 32
|
||||
I (501) wifi_init: udp mbox: 6
|
||||
I (501) wifi_init: tcp mbox: 6
|
||||
I (501) wifi_init: tcp tx win: 5760
|
||||
I (501) wifi_init: tcp rx win: 5760
|
||||
I (511) wifi_init: tcp mss: 1440
|
||||
I (511) wifi_init: WiFi IRAM OP enabled
|
||||
I (511) wifi_init: WiFi RX IRAM OP enabled
|
||||
I (521) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
|
||||
I (561) wifi:mode : sta (68:b6:b3:4d:91:08)
|
||||
I (561) wifi:enable tsf
|
||||
I (561) example_connect: Please input ssid password:
|
||||
I (601) example_connect: Connecting to myssid...
|
||||
W (601) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
|
||||
I (601) example_connect: Waiting for IP(s)
|
||||
I (3431) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (3431) wifi:state: init -> auth (0xb0)
|
||||
I (3431) wifi:state: auth -> assoc (0x0)
|
||||
I (3441) wifi:state: assoc -> run (0x10)
|
||||
I (3461) wifi:connected with myssid, aid = 1, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
|
||||
I (3461) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
|
||||
I (3461) wifi:pm start, type: 1
|
||||
|
||||
I (3471) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
|
||||
I (3471) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
|
||||
I (3511) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (4571) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (4571) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
|
||||
I (4581) example_common: Connected to example_netif_sta
|
||||
I (4581) example_common: - IPv4 address: 192.168.3.26,
|
||||
I (4591) wifi:Set ps type: 0, coexist: 0
|
||||
|
||||
I (4591) ota_example: Starting OTA example task
|
||||
I (4591) ota_example: Bind interface name is st1
|
||||
I (4601) main_task: Returned from app_main()
|
||||
I (4621) ota_example: Attempting to download update from https://192.168.3.9:8000/partition_table/partition-table.bin
|
||||
I (4631) ota_example: Use <PrimaryPrtTable> partition (0x0000c000)
|
||||
I (4651) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
|
||||
I (4681) esp-x509-crt-bundle: Certificate validated
|
||||
I (5021) esp_https_ota: Starting OTA...
|
||||
I (5021) esp_https_ota: Writing to <ota_0> partition at offset 0x20000
|
||||
I (5021) esp_ota_ops: Staging partition - <ota_0>. Final partition - <PrimaryPrtTable>.
|
||||
W (5181) ota_example: Ensure stable power supply! Loss of power at this stage leads to a chip bricking.
|
||||
I (5181) ota_example: Copy from <ota_0> staging partition to <PrimaryPrtTable>...
|
||||
I (5261) ota_example: OTA Succeed, Rebooting...
|
||||
I (5261) wifi:state: run -> init (0x0)
|
||||
I (5261) wifi:pm stop, total sleep time: 715566 us / 1792923 us
|
||||
|
||||
I (5261) wifi:<ba-del>idx:0, tid:0
|
||||
I (5281) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (5291) wifi:flush txq
|
||||
I (5291) wifi:stop sw txq
|
||||
I (5291) wifi:lmac stop hw txq
|
||||
I (5291) wifi:Deinit lldesc rx mblock:10
|
||||
|
||||
ESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
Saved PC:0x40376c31
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce2820,len:0x15a0
|
||||
load:0x403c8700,len:0x4
|
||||
load:0x403c8704,len:0xd20
|
||||
load:0x403cb700,len:0x2f3c
|
||||
entry 0x403c8928
|
||||
I (31) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
|
||||
I (31) boot: compile time Oct 28 2024 15:26:41
|
||||
I (31) boot: Multicore bootloader
|
||||
I (32) boot: chip revision: v0.1
|
||||
I (34) boot: efuse block revision: v1.2
|
||||
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
|
||||
I (42) boot.esp32s3: SPI Mode : DIO
|
||||
I (46) boot.esp32s3: SPI Flash Size : 4MB
|
||||
I (49) boot: Enabling RNG early entropy source...
|
||||
I (54) boot: Partition Table:
|
||||
I (56) boot: ## Label Usage Type ST Offset Length
|
||||
I (63) boot: 0 nvs WiFi data 01 02 0000d000 00006000
|
||||
I (69) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
|
||||
I (76) boot: 2 storage Unknown data 01 06 00014000 00001000
|
||||
I (82) boot: 3 otadata OTA data 01 00 00015000 00002000
|
||||
I (89) boot: 4 phy_init RF data 01 01 00017000 00001000
|
||||
I (95) boot: 5 emul_efuse efuse 01 05 00018000 00002000
|
||||
I (102) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
|
||||
I (108) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
|
||||
I (115) boot: End of partition table
|
||||
I (118) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
|
||||
I (152) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800) load
|
||||
I (156) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680) load
|
||||
I (163) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
|
||||
I (267) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
|
||||
I (279) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28) load
|
||||
I (288) boot: Loaded app from partition at offset 0x1d0000
|
||||
I (288) boot: Disabling RNG early entropy source...
|
||||
I (298) cpu_start: Multicore app
|
||||
I (308) cpu_start: Pro cpu start user code
|
||||
I (308) cpu_start: cpu freq: 160000000 Hz
|
||||
I (308) app_init: Application information:
|
||||
I (308) app_init: Project name: partitions_ota
|
||||
I (312) app_init: App version: 95a1e4cd
|
||||
I (316) app_init: Compile time: Oct 28 2024 15:26:38
|
||||
I (321) app_init: ELF file SHA256: 0810d7fd3...
|
||||
I (326) app_init: ESP-IDF: 95a1e4cd
|
||||
I (330) efuse_init: Min chip rev: v0.0
|
||||
I (334) efuse_init: Max chip rev: v0.99
|
||||
I (338) efuse_init: Chip rev: v0.1
|
||||
I (341) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (348) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
|
||||
I (353) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
|
||||
I (358) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
|
||||
I (363) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
|
||||
I (370) spi_flash: detected chip: generic
|
||||
I (372) spi_flash: flash io: dio
|
||||
W (375) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
|
||||
I (389) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (394) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (401) main_task: Started on CPU0
|
||||
I (421) main_task: Calling app_main()
|
||||
I (421) ota_example: OTA example app_main start
|
||||
I (431) example_connect: Start example_connect.
|
||||
I (431) pp: pp rom version: e7ae62f
|
||||
I (431) net80211: net80211 rom version: e7ae62f
|
||||
I (441) wifi:wifi driver task: 3fcab48c, prio:23, stack:6656, core=0
|
||||
I (441) wifi:wifi firmware version: 2d9c351b0
|
||||
I (441) wifi:wifi certification version: v7.0
|
||||
I (451) wifi:config NVS flash: enabled
|
||||
I (451) wifi:config nano formatting: disabled
|
||||
I (451) wifi:Init data frame dynamic rx buffer num: 32
|
||||
I (461) wifi:Init static rx mgmt buffer num: 5
|
||||
I (461) wifi:Init management short buffer num: 32
|
||||
I (471) wifi:Init dynamic tx buffer num: 32
|
||||
I (471) wifi:Init static tx FG buffer num: 2
|
||||
I (471) wifi:Init static rx buffer size: 1600
|
||||
I (481) wifi:Init static rx buffer num: 10
|
||||
I (481) wifi:Init dynamic rx buffer num: 32
|
||||
I (491) wifi_init: rx ba win: 6
|
||||
I (491) wifi_init: accept mbox: 6
|
||||
I (491) wifi_init: tcpip mbox: 32
|
||||
I (501) wifi_init: udp mbox: 6
|
||||
I (501) wifi_init: tcp mbox: 6
|
||||
I (501) wifi_init: tcp tx win: 5760
|
||||
I (501) wifi_init: tcp rx win: 5760
|
||||
I (511) wifi_init: tcp mss: 1440
|
||||
I (511) wifi_init: WiFi IRAM OP enabled
|
||||
I (511) wifi_init: WiFi RX IRAM OP enabled
|
||||
I (521) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
|
||||
I (561) wifi:mode : sta (68:b6:b3:4d:91:08)
|
||||
I (561) wifi:enable tsf
|
||||
I (561) example_connect: Please input ssid password:
|
||||
I (591) example_connect: Connecting to myssid...
|
||||
W (591) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
|
||||
I (591) example_connect: Waiting for IP(s)
|
||||
I (3421) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
I (3421) wifi:state: init -> auth (0xb0)
|
||||
I (3431) wifi:state: auth -> assoc (0x0)
|
||||
I (3431) wifi:state: assoc -> run (0x10)
|
||||
I (3451) wifi:connected with myssid, aid = 1, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
|
||||
I (3451) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
|
||||
I (3451) wifi:pm start, type: 1
|
||||
|
||||
I (3461) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
|
||||
I (3461) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
|
||||
I (3541) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (4551) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (4551) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
|
||||
I (4561) example_common: Connected to example_netif_sta
|
||||
I (4561) example_common: - IPv4 address: 192.168.3.26,
|
||||
I (4571) wifi:Set ps type: 0, coexist: 0
|
||||
|
||||
I (4571) ota_example: Starting OTA example task
|
||||
I (4571) ota_example: Bind interface name is st1
|
||||
I (4581) main_task: Returned from app_main()
|
||||
I (4601) ota_example: Attempting to download update from https://192.168.3.9:8000/storage.bin
|
||||
I (4621) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
|
||||
I (4641) esp-x509-crt-bundle: Certificate validated
|
||||
I (4981) esp_https_ota: Starting OTA...
|
||||
I (4981) esp_https_ota: Writing to <ota_0> partition at offset 0x20000
|
||||
I (4981) esp_ota_ops: Staging partition - <ota_0>. Final partition - <storage>.
|
||||
I (5161) esp_ota_ops: Copy from <ota_0> staging partition to <storage>...
|
||||
I (5351) ota_example: 7296406769363431
|
||||
I (5351) ota_example: OTA Succeed, Rebooting...
|
||||
I (5361) wifi:state: run -> init (0x0)
|
||||
I (5361) wifi:pm stop, total sleep time: 772888 us / 1893437 us
|
||||
|
||||
I (5371) wifi:<ba-del>idx:0, tid:0
|
||||
I (5371) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
|
||||
```
|
64
examples/system/ota/partitions_ota/conftest.py
Normal file
64
examples/system/ota/partitions_ota/conftest.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from pytest_embedded_idf.app import FlashFile
|
||||
from pytest_embedded_idf.serial import IdfSerial
|
||||
|
||||
|
||||
# This is a custom IdfSerial class to support custom functionality
|
||||
# which is required only for this test
|
||||
class EfuseFlashEncSerial(IdfSerial):
|
||||
|
||||
@IdfSerial.use_esptool()
|
||||
def write_flash_no_enc(self) -> None:
|
||||
self.app.flash_settings['encrypt'] = False
|
||||
flash_files = []
|
||||
for file in self.app.flash_files:
|
||||
# Set encrypted flag to false for each file.
|
||||
flash_files.append(file._replace(encrypted=False))
|
||||
# Replace the original tuple with modified tuple with all the files marked as unencrypted.
|
||||
self.app.flash_files = tuple(flash_files)
|
||||
# Now flash the files
|
||||
self.flash()
|
||||
|
||||
def bootloader_flash(self) -> None:
|
||||
"""
|
||||
Flash bootloader.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
logging.info('Flashing bootloader')
|
||||
bootloader_path = os.path.join(self.app.binary_path, 'bootloader', 'bootloader.bin')
|
||||
offs = int(self.app.sdkconfig.get('BOOTLOADER_OFFSET_IN_FLASH', 0))
|
||||
logging.info('bootloader offset is {0}'.format(hex(offs)))
|
||||
prev_flash_files = self.app.flash_files
|
||||
flash_files = []
|
||||
flash_files.append(
|
||||
FlashFile(
|
||||
offs,
|
||||
bootloader_path,
|
||||
False,
|
||||
)
|
||||
)
|
||||
self.app.flash_files = flash_files
|
||||
self.app.flash_settings['encrypt'] = False
|
||||
self.flash()
|
||||
# Restore self.app.flash files to original value
|
||||
self.app.flash_files = prev_flash_files
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch:
|
||||
mp = MonkeyPatch()
|
||||
request.addfinalizer(mp.undo)
|
||||
return mp
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', autouse=True)
|
||||
def replace_dut_class(monkeypatch_module: MonkeyPatch) -> None:
|
||||
monkeypatch_module.setattr('pytest_embedded_idf.IdfSerial', EfuseFlashEncSerial)
|
5
examples/system/ota/partitions_ota/main/CMakeLists.txt
Normal file
5
examples/system/ota/partitions_ota/main/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
# Embed the server root certificate into the final binary
|
||||
idf_build_get_property(project_dir PROJECT_DIR)
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem)
|
54
examples/system/ota/partitions_ota/main/Kconfig.projbuild
Normal file
54
examples/system/ota/partitions_ota/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,54 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_FIRMWARE_UPGRADE_URL
|
||||
string "firmware upgrade url endpoint"
|
||||
default "https://192.168.0.3:8070/partitions_ota.bin"
|
||||
help
|
||||
URL of server which hosts the firmware
|
||||
image.
|
||||
|
||||
config EXAMPLE_USE_CERT_BUNDLE
|
||||
bool "Enable certificate bundle"
|
||||
default y
|
||||
depends on MBEDTLS_CERTIFICATE_BUNDLE
|
||||
help
|
||||
Enable trusted root certificate bundle. This approach allows to have
|
||||
OTA updates functional with any public server without requirement
|
||||
to explicitly add its server certificate.
|
||||
|
||||
config EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
|
||||
bool
|
||||
default y if EXAMPLE_FIRMWARE_UPGRADE_URL = "FROM_STDIN"
|
||||
|
||||
config EXAMPLE_SKIP_COMMON_NAME_CHECK
|
||||
bool "Skip server certificate CN fieldcheck"
|
||||
default n
|
||||
help
|
||||
This allows you to skip the validation of OTA server certificate CN field.
|
||||
|
||||
config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
|
||||
bool "Support firmware upgrade bind specified interface"
|
||||
default n
|
||||
help
|
||||
This allows you to bind specified interface in OTA example.
|
||||
|
||||
choice EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_TYPE
|
||||
prompt "Choose OTA data bind interface"
|
||||
default EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA
|
||||
depends on EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
|
||||
help
|
||||
Select which interface type of OTA data go through.
|
||||
|
||||
config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA
|
||||
bool "Bind wifi station interface"
|
||||
depends on EXAMPLE_CONNECT_WIFI
|
||||
help
|
||||
Select wifi station interface to pass the OTA data.
|
||||
|
||||
config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_ETH
|
||||
bool "Bind ethernet interface"
|
||||
depends on EXAMPLE_CONNECT_ETHERNET
|
||||
help
|
||||
Select ethernet interface to pass the OTA data.
|
||||
endchoice
|
||||
endmenu
|
268
examples/system/ota/partitions_ota/main/app_main.c
Normal file
268
examples/system/ota/partitions_ota/main/app_main.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* OTA partitions example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_https_ota.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "string.h"
|
||||
#ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE
|
||||
#include "esp_crt_bundle.h"
|
||||
#endif
|
||||
#include "esp_flash.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_partition.h"
|
||||
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include <sys/socket.h>
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
#include "esp_wifi.h"
|
||||
#endif
|
||||
|
||||
#include "partition_utils.h"
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
|
||||
/* The interface name value can refer to if_desc in esp_netif_defaults.h */
|
||||
#if CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_ETH
|
||||
static const char *bind_interface_name = EXAMPLE_NETIF_DESC_ETH;
|
||||
#elif CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA
|
||||
static const char *bind_interface_name = EXAMPLE_NETIF_DESC_STA;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const char *TAG = "ota_example";
|
||||
extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
|
||||
extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
|
||||
|
||||
#define OTA_URL_SIZE 256
|
||||
|
||||
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
switch (evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
|
||||
break;
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_HEADER_SENT:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
|
||||
break;
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_REDIRECT:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t register_partition(size_t offset, size_t size, const char *label, esp_partition_type_t type, esp_partition_subtype_t subtype, const esp_partition_t **p_partition)
|
||||
{
|
||||
// If the partition table contains this partition, then use it, otherwise register it.
|
||||
*p_partition = esp_partition_find_first(type, subtype, NULL);
|
||||
if ((*p_partition) == NULL) {
|
||||
esp_err_t error = esp_partition_register_external(NULL, offset, size, label, type, subtype, p_partition);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register %s partition (err=0x%x)", "PrimaryBTLDR", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Use <%s> partition (0x%08" PRIx32 ")", (*p_partition)->label, (*p_partition)->address);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t ota_update_partitions(esp_https_ota_config_t *ota_config)
|
||||
{
|
||||
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
|
||||
if (strstr(ota_config->http_config->url, "partitions_ota.bin") != NULL) {
|
||||
ret = esp_https_ota(ota_config);
|
||||
|
||||
} else if (strstr(ota_config->http_config->url, "bootloader.bin") != NULL) {
|
||||
const esp_partition_t *primary_bootloader;
|
||||
ESP_ERROR_CHECK(register_partition(ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
|
||||
const esp_partition_t *ota_partition = esp_ota_get_next_update_partition(NULL); // free app ota partition will be used for downloading a new image
|
||||
#if CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
// Check if the passive OTA app partition is not needed for rollback before using it for other partitions.
|
||||
// The same can be done for partition table and storage updates.
|
||||
esp_ota_img_states_t ota_state;
|
||||
ESP_ERROR_CHECK(esp_ota_get_state_partition(ota_partition, &ota_state));
|
||||
if (ota_state == ESP_OTA_IMG_VALID) {
|
||||
ESP_LOGW(TAG, "Passive OTA app partition <%s> contains a valid app image eligible for rollback.", ota_partition->label);
|
||||
uint32_t ota_bootloader_offset;
|
||||
ESP_ERROR_CHECK(partition_utils_find_unallocated(NULL, ESP_BOOTLOADER_SIZE, ESP_PARTITION_TABLE_OFFSET + ESP_PARTITION_TABLE_SIZE, &ota_bootloader_offset, NULL));
|
||||
ESP_ERROR_CHECK(register_partition(ota_bootloader_offset, ESP_BOOTLOADER_SIZE, "OtaBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_OTA, &ota_partition));
|
||||
ESP_LOGW(TAG, "To avoid overwriting the passive app partition, using the unallocated space on the flash to create a temporary OTA bootloader partition <%s>", ota_partition->label);
|
||||
}
|
||||
#endif
|
||||
ota_config->partition.staging = ota_partition;
|
||||
ota_config->partition.final = primary_bootloader;
|
||||
ret = esp_https_ota(ota_config);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGW(TAG, "Ensure stable power supply! Loss of power at this stage leads to a chip bricking");
|
||||
ESP_LOGI(TAG, "Copy from <%s> staging partition to <%s>...", ota_partition->label, primary_bootloader->label);
|
||||
ret = esp_partition_copy(primary_bootloader, 0, ota_partition, 0, primary_bootloader->size);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to copy partition to Primary bootloader (err=0x%x). Bootloader likely corrupted. Device will not be able to boot again!", ret);
|
||||
}
|
||||
// If the primary_bootloader already exists in the partition table on flash, it will not be deregistered, and the function will return an error.
|
||||
esp_partition_deregister_external(primary_bootloader);
|
||||
}
|
||||
|
||||
} else if (strstr(ota_config->http_config->url, "partition-table.bin") != NULL) {
|
||||
const esp_partition_t *primary_partition_table;
|
||||
ESP_ERROR_CHECK(register_partition(ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
|
||||
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL); // free app ota partition will be used for downloading a new image
|
||||
ota_config->partition.staging = free_app_ota_partition;
|
||||
ota_config->partition.final = primary_partition_table;
|
||||
ota_config->partition.finalize_with_copy = false; // After the download is complete, do not copy the received image to the final partition automatically (it is false by default)
|
||||
ret = esp_https_ota(ota_config);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGW(TAG, "Ensure stable power supply! Loss of power at this stage leads to a chip bricking.");
|
||||
ESP_LOGI(TAG, "Copy from <%s> staging partition to <%s>...", free_app_ota_partition->label, primary_partition_table->label);
|
||||
ret = esp_partition_copy(primary_partition_table, 0, free_app_ota_partition, 0, primary_partition_table->size);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to copy partition to Primary partition table (err=0x%x). Partition table likely corrupted. Device will not be able to boot again!", ret);
|
||||
}
|
||||
// If the primary_partition_table already exists in the partition table on flash, it will not be deregistered, and the function will return an error.
|
||||
esp_partition_deregister_external(primary_partition_table);
|
||||
}
|
||||
|
||||
} else if (strstr(ota_config->http_config->url, "storage.bin") != NULL) {
|
||||
ota_config->partition.staging = NULL; // free app ota partition will be selected and used for downloading a new image
|
||||
ota_config->partition.final = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
||||
assert(ota_config->partition.final != NULL);
|
||||
ota_config->partition.finalize_with_copy = true; // After the download is complete, copy the received image to the final partition automatically
|
||||
ret = esp_https_ota(ota_config);
|
||||
char text[16];
|
||||
ESP_ERROR_CHECK(esp_partition_read(ota_config->partition.final, 0, text, sizeof(text)));
|
||||
ESP_LOG_BUFFER_CHAR(TAG, text, sizeof(text));
|
||||
assert(memcmp("7296406769363431", text, sizeof(text)) == 0);
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Unable to load this file (%s). The final partition is unknown.", ota_config->http_config->url);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ota_example_task(void *pvParameter)
|
||||
{
|
||||
ESP_LOGI(TAG, "Starting OTA example task");
|
||||
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
|
||||
esp_netif_t *netif = get_example_netif_from_desc(bind_interface_name);
|
||||
if (netif == NULL) {
|
||||
ESP_LOGE(TAG, "Can't find netif from interface description");
|
||||
abort();
|
||||
}
|
||||
struct ifreq ifr;
|
||||
esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
|
||||
ESP_LOGI(TAG, "Bind interface name is %s", ifr.ifr_name);
|
||||
#endif
|
||||
esp_http_client_config_t config = {
|
||||
.url = CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL,
|
||||
#ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE
|
||||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||
#else
|
||||
.cert_pem = (char *)server_cert_pem_start,
|
||||
#endif /* CONFIG_EXAMPLE_USE_CERT_BUNDLE */
|
||||
.event_handler = _http_event_handler,
|
||||
.keep_alive_enable = true,
|
||||
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
|
||||
.if_name = &ifr,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
|
||||
char url_buf[OTA_URL_SIZE];
|
||||
if (strcmp(config.url, "FROM_STDIN") == 0) {
|
||||
example_configure_stdin_stdout();
|
||||
fgets(url_buf, OTA_URL_SIZE, stdin);
|
||||
int len = strlen(url_buf);
|
||||
url_buf[len - 1] = '\0';
|
||||
config.url = url_buf;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url");
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK
|
||||
config.skip_cert_common_name_check = true;
|
||||
#endif
|
||||
|
||||
esp_https_ota_config_t ota_config = {
|
||||
.http_config = &config,
|
||||
};
|
||||
ESP_LOGI(TAG, "Attempting to download update from %s", config.url);
|
||||
esp_err_t ret = ota_update_partitions(&ota_config);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG, "OTA Succeed, Rebooting...");
|
||||
esp_restart();
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Firmware upgrade failed");
|
||||
}
|
||||
while (1) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "OTA example app_main start");
|
||||
// Initialize NVS.
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
// 1.OTA app partition table has a smaller NVS partition size than the non-OTA
|
||||
// partition table. This size mismatch may cause NVS initialization to fail.
|
||||
// 2.NVS partition contains data in new format and cannot be recognized by this version of code.
|
||||
// If this happens, we erase NVS partition and initialize NVS again.
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
/* Ensure to disable any WiFi power save mode, this allows best throughput
|
||||
* and hence timings for overall OTA operation.
|
||||
*/
|
||||
esp_wifi_set_ps(WIFI_PS_NONE);
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
|
||||
xTaskCreate(&ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
118
examples/system/ota/partitions_ota/main/partition_utils.c
Normal file
118
examples/system/ota/partitions_ota/main/partition_utils.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_flash_internal.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
// Returns the number of partitions belonging to the specified flash chip
|
||||
static unsigned int count_partitions(esp_flash_t *flash_chip)
|
||||
{
|
||||
unsigned int partition_count = 0;
|
||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
assert(it != NULL);
|
||||
for (; it != NULL; it = esp_partition_next(it)) {
|
||||
if (esp_partition_get(it)->flash_chip == flash_chip) {
|
||||
partition_count++;
|
||||
}
|
||||
}
|
||||
esp_partition_iterator_release(it);
|
||||
return partition_count;
|
||||
}
|
||||
|
||||
// Compare function for qsort to sort partitions by address
|
||||
static int compare_partitions(const void *a, const void *b) {
|
||||
const esp_partition_t *part_a = *(const esp_partition_t **)a;
|
||||
const esp_partition_t *part_b = *(const esp_partition_t **)b;
|
||||
return ((int32_t)part_a->address - (int32_t)part_b->address);
|
||||
}
|
||||
|
||||
static const esp_partition_t **get_sorted_partition_array(esp_flash_t *flash_chip, unsigned int *out_partition_count)
|
||||
{
|
||||
// Number of partitions on the flash chip
|
||||
unsigned int partition_count = count_partitions(flash_chip);
|
||||
assert(partition_count != 0);
|
||||
*out_partition_count = partition_count;
|
||||
|
||||
// Allocate an array for copying partitions
|
||||
const esp_partition_t **part_array = (const esp_partition_t **) calloc(partition_count, sizeof(esp_partition_t *));
|
||||
assert(part_array != NULL);
|
||||
|
||||
// Copy partitions to the array
|
||||
unsigned i = 0;
|
||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
assert(it != NULL);
|
||||
for (; it != NULL; it = esp_partition_next(it)) {
|
||||
const esp_partition_t *p = esp_partition_get(it);
|
||||
if (p->flash_chip == flash_chip) {
|
||||
part_array[i++] = p;
|
||||
}
|
||||
}
|
||||
esp_partition_iterator_release(it);
|
||||
assert(i == partition_count);
|
||||
|
||||
// Sort partitions by address using qsort
|
||||
qsort(part_array, partition_count, sizeof(esp_partition_t *), compare_partitions);
|
||||
return part_array;
|
||||
}
|
||||
|
||||
esp_err_t partition_utils_find_unallocated(esp_flash_t *flash_chip, size_t required_size, uint32_t start_offset, uint32_t *found_offset, size_t *found_size)
|
||||
{
|
||||
if (flash_chip == NULL) {
|
||||
flash_chip = esp_flash_default_chip;
|
||||
}
|
||||
|
||||
if (required_size == 0 || found_offset == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Get a sorted partition array for the given flash chip
|
||||
unsigned int partition_count;
|
||||
const esp_partition_t **sorted_partitions = get_sorted_partition_array(flash_chip, &partition_count);
|
||||
if (sorted_partitions == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// Scan for unallocated space between partitions, starting after the start_offset with unused space >= required_size
|
||||
uint32_t last_end_address = start_offset;
|
||||
for (size_t i = 0; i < partition_count; ++i) {
|
||||
if (sorted_partitions[i]->address > start_offset && sorted_partitions[i]->address > last_end_address) {
|
||||
size_t unallocated_size = sorted_partitions[i]->address - last_end_address;
|
||||
if (unallocated_size >= required_size) {
|
||||
*found_offset = last_end_address;
|
||||
if (found_size != NULL) {
|
||||
*found_size = unallocated_size;
|
||||
}
|
||||
free(sorted_partitions);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
last_end_address = sorted_partitions[i]->address + sorted_partitions[i]->size;
|
||||
}
|
||||
|
||||
// Check for unallocated space after the last partition
|
||||
last_end_address = MAX(last_end_address, start_offset);
|
||||
size_t unallocated_size = flash_chip->size - last_end_address;
|
||||
if (unallocated_size >= required_size) {
|
||||
*found_offset = last_end_address;
|
||||
if (found_size != NULL) {
|
||||
*found_size = unallocated_size;
|
||||
}
|
||||
free(sorted_partitions);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
free(sorted_partitions);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
39
examples/system/ota/partitions_ota/main/partition_utils.h
Normal file
39
examples/system/ota/partitions_ota/main/partition_utils.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_partition.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Find unallocated space in the partition table.
|
||||
*
|
||||
* This function searches for a contiguous space in the specified flash memory chip
|
||||
* that can accommodate a region of the given size and is not allocated to any partition.
|
||||
* It starts searching from the specifies start_offset and continues until the end of the flash memory.
|
||||
*
|
||||
* @param[in] flash_chip Pointer to the flash chip structure. If NULL, the default flash chip (internal) is used.
|
||||
* @param[in] required_size Size of the required unallocated space in bytes.
|
||||
* @param[in] start_offset Starting offset in the flash memory from where the search should begin.
|
||||
* @param[out] found_offset Pointer where the offset of the found unallocated space will be stored.
|
||||
* @param[out] found_size Pointer where the actual size of the found unallocated space will be stored (optional, if it is NULL).
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Unallocated space of the required size was found.
|
||||
* - ESP_ERR_INVALID_ARG: The found_offset parameter is NULL or the required_size is invalid (e.g., 0).
|
||||
* - ESP_ERR_NOT_FOUND: No suitable unallocated space was found.
|
||||
*/
|
||||
esp_err_t partition_utils_find_unallocated(esp_flash_t *flash_chip, size_t required_size, uint32_t start_offset, uint32_t *found_offset, size_t *found_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
186
examples/system/ota/partitions_ota/pytest_partitions_ota.py
Normal file
186
examples/system/ota/partitions_ota/pytest_partitions_ota.py
Normal file
@@ -0,0 +1,186 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import http.server
|
||||
import multiprocessing
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
from typing import Any
|
||||
from typing import Optional
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
try:
|
||||
from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip
|
||||
except ModuleNotFoundError:
|
||||
idf_path = os.environ['IDF_PATH']
|
||||
sys.path.insert(0, idf_path + '/tools/ci/python_packages')
|
||||
from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip
|
||||
|
||||
server_cert = '-----BEGIN CERTIFICATE-----\n' \
|
||||
'MIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ\n'\
|
||||
'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\
|
||||
'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\
|
||||
'b20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ\n'\
|
||||
'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\
|
||||
'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\
|
||||
'b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL\n'\
|
||||
'SwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W\n'\
|
||||
'ukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ\n'\
|
||||
'S5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz\n'\
|
||||
'YaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz\n'\
|
||||
'3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap\n'\
|
||||
'rFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud\n'\
|
||||
'IYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk\n'\
|
||||
'B5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32\n'\
|
||||
'3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9\n'\
|
||||
'RcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN\n'\
|
||||
'lFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=\n'\
|
||||
'-----END CERTIFICATE-----\n'
|
||||
|
||||
server_key = '-----BEGIN PRIVATE KEY-----\n'\
|
||||
'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhxF/y7bygndxP\n'\
|
||||
'wiWLSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQu\n'\
|
||||
'c32WukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2m\n'\
|
||||
'KRbQS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO\n'\
|
||||
'2fEzYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnv\n'\
|
||||
'L6Oz3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdO\n'\
|
||||
'AoaprFTRAgMBAAECggEAE0HCxV/N1Q1h+1OeDDGL5+74yjKSFKyb/vTVcaPCrmaH\n'\
|
||||
'fPvp0ddOvMZJ4FDMAsiQS6/n4gQ7EKKEnYmwTqj4eUYW8yxGUn3f0YbPHbZT+Mkj\n'\
|
||||
'z5woi3nMKi/MxCGDQZX4Ow3xUQlITUqibsfWcFHis8c4mTqdh4qj7xJzehD2PVYF\n'\
|
||||
'gNHZsvVj6MltjBDAVwV1IlGoHjuElm6vuzkfX7phxcA1B4ZqdYY17yCXUnvui46z\n'\
|
||||
'Xn2kUTOOUCEgfgvGa9E+l4OtdXi5IxjaSraU+dlg2KsE4TpCuN2MEVkeR5Ms3Y7Q\n'\
|
||||
'jgJl8vlNFJDQpbFukLcYwG7rO5N5dQ6WWfVia/5XgQKBgQD74at/bXAPrh9NxPmz\n'\
|
||||
'i1oqCHMDoM9sz8xIMZLF9YVu3Jf8ux4xVpRSnNy5RU1gl7ZXbpdgeIQ4v04zy5aw\n'\
|
||||
'8T4tu9K3XnR3UXOy25AK0q+cnnxZg3kFQm+PhtOCKEFjPHrgo2MUfnj+EDddod7N\n'\
|
||||
'JQr9q5rEFbqHupFPpWlqCa3QmQKBgQDldWUGokNaEpmgHDMnHxiibXV5LQhzf8Rq\n'\
|
||||
'gJIQXb7R9EsTSXEvsDyqTBb7PHp2Ko7rZ5YQfyf8OogGGjGElnPoU/a+Jij1gVFv\n'\
|
||||
'kZ064uXAAISBkwHdcuobqc5EbG3ceyH46F+FBFhqM8KcbxJxx08objmh58+83InN\n'\
|
||||
'P9Qr25Xw+QKBgEGXMHuMWgQbSZeM1aFFhoMvlBO7yogBTKb4Ecpu9wI5e3Kan3Al\n'\
|
||||
'pZYltuyf+VhP6XG3IMBEYdoNJyYhu+nzyEdMg8CwXg+8LC7FMis/Ve+o7aS5scgG\n'\
|
||||
'1to/N9DK/swCsdTRdzmc/ZDbVC+TuVsebFBGYZTyO5KgqLpezqaIQrTxAoGALFCU\n'\
|
||||
'10glO9MVyl9H3clap5v+MQ3qcOv/EhaMnw6L2N6WVT481tnxjW4ujgzrFcE4YuxZ\n'\
|
||||
'hgwYu9TOCmeqopGwBvGYWLbj+C4mfSahOAs0FfXDoYazuIIGBpuv03UhbpB1Si4O\n'\
|
||||
'rJDfRnuCnVWyOTkl54gKJ2OusinhjztBjcrV1XkCgYEA3qNi4uBsPdyz9BZGb/3G\n'\
|
||||
'rOMSw0CaT4pEMTLZqURmDP/0hxvTk1polP7O/FYwxVuJnBb6mzDa0xpLFPTpIAnJ\n'\
|
||||
'YXB8xpXU69QVh+EBbemdJWOd+zp5UCfXvb2shAeG3Tn/Dz4cBBMEUutbzP+or0nG\n'\
|
||||
'vSXnRLaxQhooWm+IuX9SuBQ=\n'\
|
||||
'-----END PRIVATE KEY-----\n'
|
||||
|
||||
|
||||
@pytest.mark.esp32 # This chip should be >= v3.0
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.wifi_high_traffic
|
||||
@pytest.mark.parametrize('config', [
|
||||
'on_update_no_sb_ecdsa',
|
||||
'on_update_no_sb_rsa',
|
||||
'virt_sb_v2_and_fe',
|
||||
'virt_sb_v2_and_fe_2'
|
||||
], indirect=True)
|
||||
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
|
||||
@pytest.mark.timeout(2400)
|
||||
def test_examples_partitions_ota(dut: Dut) -> None:
|
||||
print(' - Erase flash')
|
||||
dut.serial.erase_flash()
|
||||
print(' - Flash bootloader')
|
||||
dut.serial.bootloader_flash()
|
||||
print(' - Start app (flash partition_table and app)')
|
||||
dut.serial.write_flash_no_enc()
|
||||
update_partitions(dut, 'wifi_high_traffic')
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.flash_encryption_wifi_high_traffic
|
||||
@pytest.mark.nightly_run
|
||||
@pytest.mark.timeout(2400)
|
||||
@pytest.mark.parametrize('config', [
|
||||
'flash_enc_wifi',
|
||||
'flash_enc_wifi_2'
|
||||
], indirect=True)
|
||||
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
|
||||
def test_examples_partitions_ota_with_flash_encryption_wifi(dut: Dut) -> None:
|
||||
dut.serial.erase_flash()
|
||||
dut.serial.flash()
|
||||
update_partitions(dut, 'flash_encryption_wifi_high_traffic')
|
||||
|
||||
|
||||
def update_partitions(dut: Dut, env_name: Optional[str]) -> None:
|
||||
port = 8000
|
||||
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', port))
|
||||
thread1.daemon = True
|
||||
thread1.start()
|
||||
try:
|
||||
update(dut, port, 'partitions_ota.bin', env_name)
|
||||
update(dut, port, 'bootloader/bootloader.bin', env_name)
|
||||
update(dut, port, 'partition_table/partition-table.bin', env_name)
|
||||
update(dut, port, 'storage.bin', env_name)
|
||||
finally:
|
||||
thread1.terminate()
|
||||
|
||||
|
||||
def update(dut: Dut, port: int, path_to_image: str, env_name: Optional[str]) -> None:
|
||||
dut.expect('OTA example app_main start', timeout=90)
|
||||
host_ip = setting_connection(dut, env_name)
|
||||
dut.expect('Starting OTA example task', timeout=30)
|
||||
url = f'https://{host_ip}:{port}/{path_to_image}'
|
||||
print(f'Writing to device: {url}')
|
||||
dut.write(url)
|
||||
dut.expect('OTA Succeed, Rebooting...', timeout=90)
|
||||
|
||||
|
||||
def setting_connection(dut: Dut, env_name: Optional[str]) -> Any:
|
||||
if env_name is not None and dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||
dut.expect('Please input ssid password:')
|
||||
ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
|
||||
ap_password = get_env_config_variable(env_name, 'ap_password')
|
||||
dut.write(f'{ap_ssid} {ap_password}')
|
||||
try:
|
||||
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
|
||||
print(f'Connected to AP/Ethernet with IP: {ip_address}')
|
||||
except pexpect.exceptions.TIMEOUT:
|
||||
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
|
||||
return get_host_ip4_by_dest_ip(ip_address)
|
||||
|
||||
|
||||
def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, server_file: Optional[str] = None, key_file: Optional[str] = None) -> None:
|
||||
os.chdir(ota_image_dir)
|
||||
|
||||
if server_file is None:
|
||||
server_file = os.path.join(ota_image_dir, 'server_cert.pem')
|
||||
cert_file_handle = open(server_file, 'w+')
|
||||
cert_file_handle.write(server_cert)
|
||||
cert_file_handle.close()
|
||||
|
||||
if key_file is None:
|
||||
key_file = os.path.join(ota_image_dir, 'server_key.pem')
|
||||
key_file_handle = open('server_key.pem', 'w+')
|
||||
key_file_handle.write(server_key)
|
||||
key_file_handle.close()
|
||||
|
||||
httpd = http.server.HTTPServer((server_ip, server_port), http.server.SimpleHTTPRequestHandler)
|
||||
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file)
|
||||
|
||||
httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True)
|
||||
httpd.serve_forever()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[2:]: # if two or more arguments provided:
|
||||
# Usage: pytest_partition_ota.py <image_dir> <server_port> [cert_dir]
|
||||
image_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
bin_dir = os.path.join(image_dir, sys.argv[1])
|
||||
server_port = int(sys.argv[2])
|
||||
server_file = None
|
||||
key_file = None
|
||||
if sys.argv[3:]: # [cert_dir] - optional argument
|
||||
cert_dir = os.path.join(image_dir, sys.argv[3])
|
||||
server_file = os.path.join(cert_dir, 'ca_cert.pem')
|
||||
key_file = os.path.join(cert_dir, 'ca_key.pem')
|
||||
print(f'Starting HTTPS server at "https://0.0.0.0:{server_port}"')
|
||||
start_https_server(bin_dir, '0.0.0.0', server_port, server_file=server_file, key_file=key_file)
|
@@ -0,0 +1,21 @@
|
||||
# Common configs
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
|
||||
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
||||
|
||||
# This is required for nvs encryption (which is enabled by default with flash encryption)
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
@@ -0,0 +1,24 @@
|
||||
# Common configs
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
|
||||
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
||||
|
||||
# This is required for nvs encryption (which is enabled by default with flash encryption)
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul_2.csv"
|
@@ -0,0 +1,19 @@
|
||||
# Common configs
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
|
||||
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
|
||||
# ECDSA is available only in ESP32
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
||||
CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT=y
|
||||
CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT=y
|
||||
CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key_ecdsa.pem"
|
@@ -0,0 +1,17 @@
|
||||
# Common configs
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
|
||||
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
||||
|
||||
CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT=y
|
||||
CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT=y
|
||||
CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
|
||||
CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION=y
|
@@ -0,0 +1,3 @@
|
||||
# ESP32 supports SIGNED_APPS_RSA_SCHEME only in ECO3
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_ESP32_REV_MIN_3=y
|
@@ -0,0 +1,23 @@
|
||||
# Common configs
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
|
||||
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
|
||||
# FLASH_ENCRYPTION & SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xE000
|
||||
|
||||
CONFIG_SECURE_BOOT=y
|
||||
CONFIG_SECURE_BOOT_V2_ENABLED=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
|
||||
CONFIG_SECURE_DISABLE_ROM_DL_MODE=y
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
@@ -0,0 +1,3 @@
|
||||
# ESP32 supports SECURE_BOOT_V2 only in ECO3
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_ESP32_REV_MIN_3=y
|
@@ -0,0 +1,26 @@
|
||||
# Common configs
|
||||
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
|
||||
|
||||
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
|
||||
# FLASH_ENCRYPTION & SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
|
||||
CONFIG_EFUSE_VIRTUAL=y
|
||||
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xE000
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul_2.csv"
|
||||
|
||||
CONFIG_SECURE_BOOT=y
|
||||
CONFIG_SECURE_BOOT_V2_ENABLED=y
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
|
||||
CONFIG_SECURE_DISABLE_ROM_DL_MODE=y
|
||||
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
@@ -0,0 +1,3 @@
|
||||
# ESP32 supports SECURE_BOOT_V2 only in ECO3
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_ESP32_REV_MIN_3=y
|
11
examples/system/ota/partitions_ota/sdkconfig.defaults
Normal file
11
examples/system/ota/partitions_ota/sdkconfig.defaults
Normal file
@@ -0,0 +1,11 @@
|
||||
# Default sdkconfig parameters to use the OTA
|
||||
# partition table layout, with a 4MB flash size
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul_1.csv"
|
||||
|
||||
# Certificate bundle configuration
|
||||
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y
|
||||
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
|
||||
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="server_certs/ca_cert.pem"
|
20
examples/system/ota/partitions_ota/server_certs/ca_cert.pem
Normal file
20
examples/system/ota/partitions_ota/server_certs/ca_cert.pem
Normal file
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ
|
||||
TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD
|
||||
VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j
|
||||
b20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ
|
||||
TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD
|
||||
VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j
|
||||
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL
|
||||
SwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W
|
||||
ukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ
|
||||
S5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz
|
||||
YaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz
|
||||
3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap
|
||||
rFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud
|
||||
IYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk
|
||||
B5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32
|
||||
3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9
|
||||
RcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN
|
||||
lFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=
|
||||
-----END CERTIFICATE-----
|
@@ -0,0 +1,9 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, , 0x6000,
|
||||
nvs_key, data, nvs_keys, , 4K,
|
||||
storage, data, , , 0x1000, encrypted
|
||||
otadata, data, ota, , 0x2000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
emul_efuse, data, efuse, , 0x2000,
|
||||
ota_0, app, ota_0, , 0x1B0000,
|
||||
ota_1, app, ota_1, , 0x1B0000,
|
|
@@ -0,0 +1,11 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
PrimaryBTLDR, bootloader, primary, N/A, N/A,
|
||||
PrimaryPrtTable, partition_table, primary, N/A, N/A,
|
||||
nvs, data, nvs, , 0x6000,
|
||||
nvs_key, data, nvs_keys, , 4K,
|
||||
storage, data, , , 0x1000, encrypted
|
||||
otadata, data, ota, , 0x2000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
emul_efuse, data, efuse, , 0x2000,
|
||||
ota_0, app, ota_0, , 0x1B0000,
|
||||
ota_1, app, ota_1, , 0x1B0000,
|
|
@@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIG4wIBAAKCAYEAzJUktQ+7wpPDfDGterxiMRx5w9n7PFaUSK3wnE+05ALsEF8F
|
||||
rUOC7/q0GutYYdWopdRM1FUKX2XVaryMViC+DHof42fEbpWYnfrCkYrDn8MLuMyK
|
||||
4uGunl8LUTIAZk3I3SZKJZy5FW9eb1XtkwfN1lAd6lEEGQKyoR6Bk/Rkisj0LP7R
|
||||
dyV9NKbJhxavZ1ohZXiXU5FW873iGdPIsloZoUK3QGRE1KRIH2woUGHATfXBCf5a
|
||||
+e41wJzz7YHl5tjyxAbJ9PET52N14G73WoZKHu3QPShALrZVfjsk1oYdFvNdOBDL
|
||||
uU0vpyKl7mJHno11gM0UM0s9PrMxk9ffdAqMyS8YeLEk2Xl3AwPv7m9oeGIdSD/P
|
||||
okcISYcm4YAl5veqIG3RlkfpWjf5G15UYyLbgmn4GOkgr6ksB/dCFOMi9V1LjPah
|
||||
32A7gxqTlapQza+wNs30SYBIXrFde4bNnhFhj4Cbt34ADefWm26KLiZEHFHFN30Z
|
||||
IownitXz3rT7rmzBAgMBAAECggGBAK6bBA88dGWnM4rF42gDbFK6GPqdCp3+zuQR
|
||||
AHCIXrzT+aInV3L/Ubt730eyYWZusleGEGSQiB/PjAxjC+teWpXPjXPK1o4DQ5Rh
|
||||
trn9EuVB1LlOaaMmNqCYQdJ0uH6YGL0WtuXPEvBGcvTXA8MfQACPtFiN+M9XzBlT
|
||||
LgiW51DEHhJhEWl9J5VOXGXdaKru893kxFLgkrPI9jZQ2NPPrlxB0qE0csKBy8R1
|
||||
zRp9s2FWRAFBg2gYdOwFiPLGkO8rbM+jhXM+IUV1GgVYdxAC6zS9AiIAWuACDEwp
|
||||
Pzg3d3/5uyOFK1xTIPl/cG8CZyPQL1v/mUx0MZFaB1R1CVeDuMoFVz2YSbEaAVFv
|
||||
QIcJGDN/WlJbt0jwj7/RJKKTx0ipFlUdNbodzdaSl3Yg4N+evzR1nS8DvLJpwl/e
|
||||
ybu40IbavwYXWVzirH3wRg+P/NDsHLU5xASAyUwf1minsmObILayEZgfTA6TbrKL
|
||||
fZbJCvy2/IuCM6iqKZwSvYy0bJdaAQKBwQDzDVa/M4/sJV0GEbwegeN6Xf+XKkl3
|
||||
Gosjd+vQgv/0X1gbdMc0Ej9eYSU5/GYIHxDzDRkYIxtIfwaze1gGeNRHycMCmVkl
|
||||
09DMi48jLGE7wzObPu6MtBCSAGHaS9zMTVCYDYtRlykPzG2/1QNrRUDNACnpzneK
|
||||
MkWObzFYTIup1zh+JaD56vLIDdL7qM9apmEkq4O6y1BBPnCgRYJy5EU3BDZxz9fP
|
||||
47JtCZ47uVguoh/NVYY5uibdvI5iJ4SA/VECgcEA13srpwJppfTTFPRWgD+g7PdU
|
||||
Yg+ENBWygiJuwgGv6DyD4k73pxiyshNo7jxsdOLeGFA8hI3dvd/Ei6uUsGnWPy/a
|
||||
OwuBcOZrJZjyawNSiC+mrCSP0LGQrC5VjmuE8IU1d2hFWyV/NzkSLaXJ52Zkg3ee
|
||||
sSepBHtWEYpwH929u5FTKDKhL0qRH8E1EsULSjmkTa+cVDYgx8+2mb3vHRdJdvt3
|
||||
FZU9erKyDb4II5GJhyNQo/cxBosDzj4yIMKM/dxxAoHAE1r1lIZjqLeU/927sGZB
|
||||
mkYQC5a3gP+hIvLy2YkFHw3Us2MKVhA58ack0shRy8XFkMVzQSPSkWRkQTjKWsGW
|
||||
jhz4JaXWnpeOoite+7sWBy9VVcCeOKBCTY4wPLUb4T0q9ODnPlkeUP7Doqow+oLq
|
||||
VSj1LYReqqe0OFKMiG6YFK9p9UnD1wMp0FqheZ8I3DwxsjziYaa9PmTdjTXb3JBn
|
||||
Hql8OHYHxqtoUxyX+EObTSNmCvELnl8/pxrT7+cbuzXxAoHAfmNYb1US8qxvQtMu
|
||||
CXtIwLUxYXMIcCRp17qqjFDBBM657Hu09uWdqqWH3nTCiKyo6EnntTgg38XoWqQB
|
||||
SphJejZvIkLVYYtFPYBAcFQ6jHampEGtuRLtcJCczjRyfUEk4yzdwWB1BccLyop7
|
||||
qqZ8PkBjbDV/BYnyKcexjH9bUjEjPWi08jAifyWsI54/yQGWRZrDbwFwqMJEsFif
|
||||
b8jA5nEIoDgxH07A8R6NV499wy4LlqDeuJ/BU69XZ6+1UxGBAoHAXfb9t5ivdf9N
|
||||
ZbZj61GcrDLyYGDTotucy8HPNMr5P3ZmBR/5UzClpCbWVSaziK3CKzR0zURLw0W7
|
||||
rF4CySTjuD9FHOFFWjjlkS4KwOyYiy8fuMMLg1RmsCS8H+0L3Pm25PmRQ9TLjEf4
|
||||
0uFWf7fG4GQiciqGcvfaFH3w//d0Q7PSvIMNlM1Gc7JS1Qn4HoDF2Ux6drNb6nJL
|
||||
l6tdXNMkUFHBMtaQy0l9D/ex5NZlAniePT3xfMrQf6m0rVAAaAY0
|
||||
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIOvP45grF4dSM2fWbOAp4W8PgFm30HIZqtNEK13O5hVHoAoGCCqGSM49
|
||||
AwEHoUQDQgAE1IL73BARrNpkHj1jG50eHoF2LERCwz1BfbshuAeLcsED5aT92Xgu
|
||||
gJvq45LN9p6eBi62ZZwr6Z2ZfX3YB3/8KA==
|
||||
-----END EC PRIVATE KEY-----
|
68
examples/system/ota/partitions_ota/test/storage.bin
Normal file
68
examples/system/ota/partitions_ota/test/storage.bin
Normal file
@@ -0,0 +1,68 @@
|
||||
729640676936343167405726443197135657269157998
|
||||
933232050979719444751452267503063397819023382
|
||||
556506319597389776571009503699952437641061732
|
||||
002752455079598828837517200348560233202884961
|
||||
289477881250470899211041514323644847313434252
|
||||
730231884515472435547694444234642911818478157
|
||||
604144032495549544339412331088820122187613561
|
||||
037928985771855738051392892725939092474036895
|
||||
578049014383949960944604448487826864453409450
|
||||
296161831460741246018093614276144348092833874
|
||||
140428241649972439923475366687089049988769325
|
||||
628351145210907812434482037266152681719092912
|
||||
195052933351010873736343964178221498387487568
|
||||
880765493241408400507065714578908626300143903
|
||||
883991915607625769735210770743664311477574805
|
||||
803046247728563775122702680062751243196677727
|
||||
591992825319085180539338771922153143676093557
|
||||
878162825694361186599018123247178797942043904
|
||||
253513230477134391345104969412487168458933717
|
||||
879463603920957341514770185585897085439536061
|
||||
546050366983003480039672501169984474709911556
|
||||
432680670735296891758812059406730550421434400
|
||||
799748308597104378938356890827982866134014221
|
||||
535217212317851509531435779909442853259569048
|
||||
580409528656447379596945028254287449496748086
|
||||
321387039712708832937716833909605696109504066
|
||||
278470671408892520188316938495958536257526665
|
||||
660640085363653328064067701371831709621622531
|
||||
436530770318421608478245539795335337571927836
|
||||
848053923388780499943352551523532238273698176
|
||||
049362112819423888880054249487849648130087221
|
||||
687010509088780417528465152444332299326657281
|
||||
255338606197500772061483497687185654530379009
|
||||
809223233886931933248343109674340504152295885
|
||||
765334333996117982147891052573656099707681910
|
||||
057424651564819028940604517398495382795147311
|
||||
752675767253643761529415181834038113062154258
|
||||
694020157776375821024488585116268734923621487
|
||||
797603120028758119376826166666195814602885184
|
||||
256054926782662332557983780119850277271110264
|
||||
534729118343464049562614126424801063288960662
|
||||
418497776363476573070239863993771788850167929
|
||||
544623158969320919268138503435885988442279793
|
||||
367410227609285002234584503009426598103851672
|
||||
344936392655102339554247845914915561479550647
|
||||
291980804702566220358719744252448087492119608
|
||||
704318916097427876642053084788623400842338607
|
||||
771470900612011584595877155134205277401842505
|
||||
909521197008143210604801870018968664140327930
|
||||
324980994466472002076385074301506530901535978
|
||||
320185664126981369956414311892197871161156454
|
||||
378766138079997290959022342245831189632927648
|
||||
364825257659858363550270789813108372635022027
|
||||
738652557666400070994836903956811374712435567
|
||||
047611244061167695176168226753393440679656386
|
||||
185089811485754675632410309589122549282952655
|
||||
762982585738215953889178883392751359696199678
|
||||
466365406348114092011380838127323464485769393
|
||||
308459315194527893288390791240690970366091968
|
||||
418737882756335691688926129739468319284933735
|
||||
112439699935630133393004802185263769845456882
|
||||
716047319575852391012595513490467744266860105
|
||||
117800597394726582034935172600056709435421428
|
||||
760032386987855643579460268598949375417486418
|
||||
353173014844750264581499676629717396353130841
|
||||
051820655315640727727623322576821500963566535
|
||||
812443435910850388330357301683274331804203320
|
||||
356920660584480371919309487962624455455544515
|
Reference in New Issue
Block a user