9#include <esp_ota_ops.h>
10#include <esp_task_wdt.h>
11#include <spi_flash_mmap.h>
12#ifdef USE_OTA_DOWNGRADE_PROTECTION
13#include <esp_app_desc.h>
18static const char *
const TAG =
"ota.idf";
20std::unique_ptr<IDFOTABackend>
make_ota_backend() {
return make_unique<IDFOTABackend>(); }
23#ifdef USE_OTA_PARTITIONS
24 this->ota_type_ = ota_type;
27 if (image_size != ESP_PARTITION_TABLE_MAX_LEN) {
28 ESP_LOGE(TAG,
"Wrong partition table size: expected %u bytes, got %zu", ESP_PARTITION_TABLE_MAX_LEN, image_size);
31 memset(this->buf_, 0xFF,
sizeof this->buf_);
32 this->buf_written_ = 0;
33 this->image_size_ = image_size;
51#ifdef USE_OTA_ROLLBACK
55 esp_ota_mark_app_valid_cancel_rollback();
58 this->partition_ = esp_ota_get_next_update_partition(
nullptr);
59 if (this->partition_ ==
nullptr) {
69 size_t erase_size = image_size;
70 if (erase_size == 0 || erase_size > this->partition_->size) {
71 erase_size = this->partition_->size;
73 const uint32_t erase_budget_ms = 15000 + (erase_size >> 10) * 10;
75 esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_);
78 ESP_LOGE(TAG,
"esp_ota_begin failed (err=0x%X)", err);
79 esp_ota_abort(this->update_handle_);
80 this->update_handle_ = 0;
81 if (err == ESP_ERR_INVALID_SIZE) {
83 }
else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) {
85 }
else if (err == ESP_ERR_OTA_PARTITION_CONFLICT) {
91#ifdef USE_OTA_PARTITIONS
104 memcpy(this->expected_bin_md5_, expected_md5, 32);
105 this->md5_set_ =
true;
109#ifdef USE_OTA_PARTITIONS
111 if (
len > PARTITION_TABLE_BUFFER_SIZE - this->buf_written_) {
112 ESP_LOGE(TAG,
"Wrong partition table size");
115 memcpy(this->buf_ + this->buf_written_, data,
len);
116 this->buf_written_ +=
len;
117 this->md5_.
add(data,
len);
124 esp_err_t err = esp_ota_write(this->update_handle_, data,
len);
125 this->md5_.
add(data,
len);
127 ESP_LOGE(TAG,
"esp_ota_write failed (err=0x%X)", err);
128 if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
130 }
else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) {
139 if (this->md5_set_) {
141 if (!this->md5_.
equals_hex(this->expected_bin_md5_)) {
146#ifdef USE_OTA_PARTITIONS
154 esp_err_t err = esp_ota_end(this->update_handle_);
155 this->update_handle_ = 0;
157 ESP_LOGE(TAG,
"esp_ota_end failed (err=0x%X)", err);
159#ifdef USE_OTA_PARTITIONS
165#ifdef USE_OTA_DOWNGRADE_PROTECTION
170 esp_app_desc_t incoming;
171 esp_err_t desc_err = esp_ota_get_partition_description(this->partition_, &incoming);
172 if (desc_err != ESP_OK) {
175 ESP_LOGW(TAG,
"Downgrade protection: could not read image version (err=0x%X); allowing update", desc_err);
177 ESP_LOGE(TAG,
"Rejecting downgrade: image version '%s' is older than running version '%s'", incoming.version,
178 ESPHOME_PROJECT_VERSION);
182 err = esp_ota_set_boot_partition(this->partition_);
187 if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
188#ifdef USE_OTA_SIGNED_VERIFICATION
189 ESP_LOGE(TAG,
"OTA validation failed (err=0x%X) - possible signature verification failure", err);
195 if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) {
202#ifdef USE_OTA_PARTITIONS
203 if (this->partition_table_part_ !=
nullptr) {
204 esp_partition_deregister_external(this->partition_table_part_);
205 this->partition_table_part_ =
nullptr;
207 if (this->bootloader_part_ !=
nullptr) {
208 esp_partition_deregister_external(this->bootloader_part_);
209 this->bootloader_part_ =
nullptr;
214 esp_ota_abort(this->update_handle_);
215 this->update_handle_ = 0;
bool equals_hex(const char *expected)
Compare the hash against a provided hex-encoded hash.
void calculate() override
Compute the digest, based on the provided data.
void add(const uint8_t *data, size_t len) override
Add bytes of data for the digest.
void init() override
Initialize a new MD5 digest computation.
OTAResponseTypes setup_bootloader_staging_()
void set_update_md5(const char *md5)
OTAResponseTypes finalize_bootloader_update_(esp_err_t ota_end_err)
OTAResponseTypes begin(size_t image_size, ota::OTAType ota_type=ota::OTA_TYPE_UPDATE_APP)
OTAResponseTypes prepare_bootloader_update_(size_t image_size)
OTAResponseTypes write(uint8_t *data, size_t len)
OTAResponseTypes update_partition_table()
bool is_app_or_bootloader_update_() const
@ OTA_TYPE_UPDATE_BOOTLOADER
@ OTA_TYPE_UPDATE_PARTITION_TABLE
bool version_is_older(const char *candidate, const char *reference)
Compare two dotted-numeric version strings (such as "1.2.3").
@ OTA_RESPONSE_ERROR_MD5_MISMATCH
@ OTA_RESPONSE_ERROR_VERSION_DOWNGRADE
@ OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE
@ OTA_RESPONSE_ERROR_WRITING_FLASH
@ OTA_RESPONSE_ERROR_UNSUPPORTED_OTA_TYPE
@ OTA_RESPONSE_ERROR_UPDATE_END
@ OTA_RESPONSE_ERROR_SIGNATURE_INVALID
@ OTA_RESPONSE_ERROR_UNKNOWN
@ OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION
@ OTA_RESPONSE_ERROR_MAGIC
@ OTA_RESPONSE_ERROR_PARTITION_TABLE_VERIFY
std::unique_ptr< ArduinoLibreTinyOTABackend > make_ota_backend()