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:
copilot-swe-agent[bot]
2025-11-08 18:00:24 +00:00
parent d79b02379e
commit 62c78fc5ac

View File

@@ -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