diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 534fbb110..ceb6a7052 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -413,6 +413,34 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition) } } +static const esp_partition_t *find_default_boot_partition(void) +{ + // This logic matches the logic of bootloader get_selected_boot_partition() & load_boot_image(). + + // Default to factory if present + const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); + if (result != NULL) { + return result; + } + + // Try first OTA slot if no factory partition + for (esp_partition_subtype_t s = ESP_PARTITION_SUBTYPE_APP_OTA_MIN; s != ESP_PARTITION_SUBTYPE_APP_OTA_MAX; s++) { + result = esp_partition_find_first(ESP_PARTITION_TYPE_APP, s, NULL); + if (result != NULL) { + return result; + } + } + + // Test app slot if present + result = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEST, NULL); + if (result != NULL) { + return result; + } + + ESP_LOGE(TAG, "invalid partition table, no app partitions"); + return NULL; +} + const esp_partition_t *esp_ota_get_boot_partition(void) { esp_err_t ret; @@ -443,8 +471,7 @@ const esp_partition_t *esp_ota_get_boot_partition(void) if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) { ESP_LOGD(TAG, "finding factory app......"); - - return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); + return find_default_boot_partition(); } else if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) { ESP_LOGD(TAG, "finding ota_%d app......", \ ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count)); @@ -467,7 +494,7 @@ const esp_partition_t *esp_ota_get_boot_partition(void) } else { ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory"); - return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); + return find_default_boot_partition(); } } diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index 9bc8798e4..a089a92be 100755 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -126,13 +126,17 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition); * * If esp_ota_set_boot_partition() has been called, the partition which was set by that function will be returned. * - * If esp_ota_set_boot_partition() has not been called, the result is - * equivalent to esp_ota_get_running_partition(). + * If esp_ota_set_boot_partition() has not been called, the result is usually the same as esp_ota_get_running_partition(). + * The two results are not equal if the configured boot partition does not contain a valid app (meaning that the running partition + * will be an app that the bootloader chose via fallback). + * + * If the OTA data partition is not present or not valid then the result is the first app partition found in the + * partition table. In priority order, this means: the factory app, the first OTA app slot, or the test app partition. * * Note that there is no guarantee the returned partition is a valid app. Use esp_image_load(ESP_IMAGE_VERIFY, ...) to verify if the - * partition contains a bootable image. + * returned partition contains a bootable image. * - * @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application. + * @return Pointer to info for partition structure, or NULL if partition table is invalid or a flash read operation failed. Any returned pointer is valid for the lifetime of the application. */ const esp_partition_t* esp_ota_get_boot_partition(void);