12#include <esp8266_peri.h>
18#include <eboot_command.h>
21#include <user_interface.h>
27static constexpr uint8_t FLASH_MODE_OFFSET = 2;
30static constexpr uint8_t FIRMWARE_MAGIC = 0xE9;
31static constexpr uint8_t GZIP_MAGIC_1 = 0x1F;
32static constexpr uint8_t GZIP_MAGIC_2 = 0x8B;
35static constexpr uint32_t FLASH_BASE_ADDRESS = 0x40200000;
38static constexpr int BOOT_MODE_SHIFT = 16;
39static constexpr int BOOT_MODE_MASK = 0xf;
42static constexpr int BOOT_MODE_UART_DOWNLOAD = 1;
45static constexpr size_t MIN_BUFFER_SIZE = 256;
49static const char *
const TAG =
"ota.esp8266";
51std::unique_ptr<ota::OTABackend>
make_ota_backend() {
return make_unique<ota::ESP8266OTABackend>(); }
55 if (image_size == 0) {
58 image_size = (ESP.getFreeSketchSpace() - FLASH_SECTOR_SIZE) & ~(FLASH_SECTOR_SIZE - 1);
63 int boot_mode = (GPI >> BOOT_MODE_SHIFT) & BOOT_MODE_MASK;
64 if (boot_mode == BOOT_MODE_UART_DOWNLOAD) {
70 if (!ESP.checkFlashConfig(
false)) {
76 uint32_t sketch_size = ESP.getSketchSize();
79 uint32_t current_sketch_size = (sketch_size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
82 uint32_t rounded_size = (image_size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
85 uint32_t update_end_address = FS_start - FLASH_BASE_ADDRESS;
88 this->
start_address_ = (update_end_address > rounded_size) ? (update_end_address - rounded_size) : 0;
97 this->
buffer_size_ = (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) ? FLASH_SECTOR_SIZE : MIN_BUFFER_SIZE;
112 wifi_set_sleep_type(NONE_SLEEP_T);
120 ESP_LOGD(TAG,
"OTA begin: start=0x%08" PRIX32
", size=%zu", this->
start_address_, image_size);
138 while (written <
len) {
141 memcpy(this->
buffer_.get() + this->buffer_len_, data + written, to_buffer);
143 written += to_buffer;
160 if (spi_flash_erase_sector(this->
current_address_ / FLASH_SECTOR_SIZE) != SPI_FLASH_RESULT_OK) {
161 ESP_LOGE(TAG,
"Flash erase failed at 0x%08" PRIX32, this->
current_address_);
169 if (spi_flash_write(this->
current_address_,
reinterpret_cast<uint32_t *
>(this->
buffer_.get()), this->buffer_len_) !=
170 SPI_FLASH_RESULT_OK) {
171 ESP_LOGE(TAG,
"Flash write failed at 0x%08" PRIX32, this->
current_address_);
189 uint8_t original_flash_mode = 0;
190 bool patched_flash_mode =
false;
193 if (is_first_sector && this->
buffer_len_ > FLASH_MODE_OFFSET && this->
buffer_[0] != GZIP_MAGIC_1) {
196 uint8_t buffer_flash_mode = this->
buffer_[FLASH_MODE_OFFSET];
198 if (buffer_flash_mode != current_flash_mode) {
199 original_flash_mode = buffer_flash_mode;
200 this->
buffer_[FLASH_MODE_OFFSET] = current_flash_mode;
201 patched_flash_mode =
true;
210 if (patched_flash_mode) {
211 this->
buffer_[FLASH_MODE_OFFSET] = original_flash_mode;
259 if (actual_size == 0) {
260 ESP_LOGE(TAG,
"No data written");
270 ESP_LOGE(TAG,
"MD5 mismatch");
288 ebcmd.action = ACTION_COPY_RAW;
290 ebcmd.args[1] = 0x00000;
292 eboot_command_write(&ebcmd);
294 ESP_LOGI(TAG,
"OTA update staged: 0x%08" PRIX32
" -> 0x00000, size=%zu", this->start_address_, this->
image_size_);
312 if (spi_flash_read(this->
start_address_, &buf, 4) != SPI_FLASH_RESULT_OK) {
313 ESP_LOGE(TAG,
"Failed to read firmware header");
317 uint8_t *bytes =
reinterpret_cast<uint8_t *
>(&buf);
320 if (bytes[0] == GZIP_MAGIC_1 && bytes[1] == GZIP_MAGIC_2) {
326 if (bytes[0] != FIRMWARE_MAGIC) {
327 ESP_LOGE(TAG,
"Invalid firmware magic: 0x%02X (expected 0x%02X)", bytes[0], FIRMWARE_MAGIC);
331#if !FLASH_MAP_SUPPORT
335 uint32_t bin_flash_size = ESP.magicFlashChipSize((bytes[3] & 0xf0) >> 4);
337 if (bin_flash_size > ESP.getFlashChipRealSize()) {
338 ESP_LOGE(TAG,
"Firmware flash size (%" PRIu32
") exceeds chip size (%" PRIu32
")", bin_flash_size,
339 ESP.getFlashChipRealSize());
349 if (spi_flash_read(0x0000, &data, 4) != SPI_FLASH_RESULT_OK) {
352 return (
reinterpret_cast<uint8_t *
>(&data))[FLASH_MODE_OFFSET];
void feed_wdt(uint32_t time=0)
bool equals_bytes(const uint8_t *expected)
Compare the hash against a provided byte-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.
bool write_buffer_final_()
Write buffered data to flash without MD5 update (for final padded write)
std::unique_ptr< uint8_t[]> buffer_
OTAResponseTypes write(uint8_t *data, size_t len) override
bool erase_sector_if_needed_()
Erase flash sector if current address is at sector boundary.
bool write_buffer_()
Write buffered data to flash and update MD5.
uint32_t current_address_
OTAResponseTypes begin(size_t image_size) override
uint8_t expected_md5_[16]
bool verify_end_()
Verify the firmware header is valid.
bool flash_write_()
Write buffer to flash (does not update address or clear buffer)
OTAResponseTypes end() override
void set_update_md5(const char *md5) override
uint8_t get_flash_chip_mode_()
Get current flash chip mode from flash header.
void preferences_prevent_write(bool prevent)
std::unique_ptr< ota::OTABackend > make_ota_backend()
@ OTA_RESPONSE_ERROR_MD5_MISMATCH
@ OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG
@ OTA_RESPONSE_ERROR_WRITING_FLASH
@ OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE
@ OTA_RESPONSE_ERROR_UPDATE_END
@ OTA_RESPONSE_ERROR_UNKNOWN
@ OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING
size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count)
Parse bytes from a hex-encoded string into a byte array.
Application App
Global storage of Application pointer - only one Application can exist.