Refactor bootloader upload to buffer entire file in RAM before flash operations
Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
This commit is contained in:
@@ -561,25 +561,42 @@ void initServer()
|
|||||||
}
|
}
|
||||||
if (!correctPIN || otaLock) return;
|
if (!correctPIN || otaLock) return;
|
||||||
|
|
||||||
static size_t bootloaderBytesWritten = 0;
|
static uint8_t* bootloaderBuffer = nullptr;
|
||||||
static bool bootloaderErased = false;
|
static size_t bootloaderBytesBuffered = 0;
|
||||||
const uint32_t bootloaderOffset = 0x1000;
|
const uint32_t bootloaderOffset = 0x1000;
|
||||||
const uint32_t maxBootloaderSize = 0x8000; // 32KB max
|
const uint32_t maxBootloaderSize = 0x8000; // 32KB max
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
DEBUG_PRINTLN(F("Bootloader Update Start"));
|
DEBUG_PRINTLN(F("Bootloader Update Start - buffering data"));
|
||||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||||
WLED::instance().disableWatchdog();
|
WLED::instance().disableWatchdog();
|
||||||
#endif
|
#endif
|
||||||
lastEditTime = millis(); // make sure PIN does not lock during update
|
lastEditTime = millis(); // make sure PIN does not lock during update
|
||||||
strip.suspend();
|
strip.suspend();
|
||||||
strip.resetSegments();
|
strip.resetSegments();
|
||||||
bootloaderBytesWritten = 0;
|
|
||||||
bootloaderErased = false;
|
// Allocate buffer for entire bootloader
|
||||||
|
if (bootloaderBuffer) {
|
||||||
|
free(bootloaderBuffer);
|
||||||
|
bootloaderBuffer = nullptr;
|
||||||
|
}
|
||||||
|
bootloaderBuffer = (uint8_t*)malloc(maxBootloaderSize);
|
||||||
|
if (!bootloaderBuffer) {
|
||||||
|
DEBUG_PRINTLN(F("Failed to allocate bootloader buffer!"));
|
||||||
|
strip.resume();
|
||||||
|
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||||
|
WLED::instance().enableWatchdog();
|
||||||
|
#endif
|
||||||
|
Update.abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bootloaderBytesBuffered = 0;
|
||||||
|
|
||||||
// Verify bootloader magic on first chunk
|
// Verify bootloader magic on first chunk
|
||||||
if (!isValidBootloader(data, len)) {
|
if (!isValidBootloader(data, len)) {
|
||||||
DEBUG_PRINTLN(F("Invalid bootloader file!"));
|
DEBUG_PRINTLN(F("Invalid bootloader file!"));
|
||||||
|
free(bootloaderBuffer);
|
||||||
|
bootloaderBuffer = nullptr;
|
||||||
strip.resume();
|
strip.resume();
|
||||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||||
WLED::instance().enableWatchdog();
|
WLED::instance().enableWatchdog();
|
||||||
@@ -587,44 +604,56 @@ void initServer()
|
|||||||
Update.abort();
|
Update.abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erase bootloader region (32KB)
|
|
||||||
DEBUG_PRINTLN(F("Erasing bootloader region..."));
|
|
||||||
esp_err_t err = esp_flash_erase_region(NULL, bootloaderOffset, maxBootloaderSize);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
DEBUG_PRINTF_P(PSTR("Bootloader erase error: %d\n"), err);
|
|
||||||
strip.resume();
|
|
||||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
|
||||||
WLED::instance().enableWatchdog();
|
|
||||||
#endif
|
|
||||||
Update.abort();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bootloaderErased = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write data to flash at bootloader offset
|
// Buffer the incoming data
|
||||||
if (bootloaderErased && bootloaderBytesWritten + len <= maxBootloaderSize) {
|
if (bootloaderBuffer && bootloaderBytesBuffered + len <= maxBootloaderSize) {
|
||||||
esp_err_t err = esp_flash_write(NULL, data, bootloaderOffset + bootloaderBytesWritten, len);
|
memcpy(bootloaderBuffer + bootloaderBytesBuffered, data, len);
|
||||||
if (err != ESP_OK) {
|
bootloaderBytesBuffered += len;
|
||||||
DEBUG_PRINTF_P(PSTR("Bootloader flash write error: %d\n"), err);
|
} else if (!bootloaderBuffer) {
|
||||||
Update.abort();
|
DEBUG_PRINTLN(F("Bootloader buffer not allocated!"));
|
||||||
} else {
|
|
||||||
bootloaderBytesWritten += len;
|
|
||||||
}
|
|
||||||
} else if (!bootloaderErased) {
|
|
||||||
DEBUG_PRINTLN(F("Bootloader region not erased!"));
|
|
||||||
Update.abort();
|
Update.abort();
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F("Bootloader size exceeds maximum!"));
|
DEBUG_PRINTLN(F("Bootloader size exceeds maximum!"));
|
||||||
|
if (bootloaderBuffer) {
|
||||||
|
free(bootloaderBuffer);
|
||||||
|
bootloaderBuffer = nullptr;
|
||||||
|
}
|
||||||
Update.abort();
|
Update.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only write to flash when upload is complete
|
||||||
if (isFinal) {
|
if (isFinal) {
|
||||||
if (!Update.hasError() && bootloaderBytesWritten > 0) {
|
bool success = false;
|
||||||
DEBUG_PRINTF_P(PSTR("Bootloader Update Success - %d bytes written\n"), bootloaderBytesWritten);
|
if (!Update.hasError() && bootloaderBuffer && bootloaderBytesBuffered > 0) {
|
||||||
bootloaderSHA256Cached = false; // Invalidate cached bootloader hash
|
DEBUG_PRINTF_P(PSTR("Bootloader buffered (%d bytes) - writing to flash\n"), bootloaderBytesBuffered);
|
||||||
} else {
|
|
||||||
|
// Erase bootloader region
|
||||||
|
DEBUG_PRINTLN(F("Erasing bootloader region..."));
|
||||||
|
esp_err_t err = esp_flash_erase_region(NULL, bootloaderOffset, maxBootloaderSize);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
DEBUG_PRINTF_P(PSTR("Bootloader erase error: %d\n"), err);
|
||||||
|
} else {
|
||||||
|
// Write buffered data to flash
|
||||||
|
err = esp_flash_write(NULL, bootloaderBuffer, bootloaderOffset, bootloaderBytesBuffered);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
DEBUG_PRINTF_P(PSTR("Bootloader flash write error: %d\n"), err);
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTF_P(PSTR("Bootloader Update Success - %d bytes written\n"), bootloaderBytesBuffered);
|
||||||
|
bootloaderSHA256Cached = false; // Invalidate cached bootloader hash
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
if (bootloaderBuffer) {
|
||||||
|
free(bootloaderBuffer);
|
||||||
|
bootloaderBuffer = nullptr;
|
||||||
|
}
|
||||||
|
bootloaderBytesBuffered = 0;
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
DEBUG_PRINTLN(F("Bootloader Update Failed"));
|
DEBUG_PRINTLN(F("Bootloader Update Failed"));
|
||||||
strip.resume();
|
strip.resume();
|
||||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||||
|
|||||||
Reference in New Issue
Block a user