crashmode

This commit is contained in:
proddy
2026-10-07 23:00:14 +02:00
parent 6411b6ffbd
commit 965d93661a
19 changed files with 600 additions and 273 deletions
+79 -25
View File
@@ -3,6 +3,10 @@
#include <Update.h>
#include <esp_app_format.h>
#include <esp_image_format.h>
#ifdef OTA_UPDATER_ANY_PARTITION
#include <esp_heap_caps.h>
#include <esp_partition.h>
#endif
#include <cstddef>
@@ -19,8 +23,14 @@ OtaUpdater::FileType OtaUpdater::classify(const String & filename, size_t filesi
if (extension == "bin" && filename.endsWith("littlefs.bin")) {
return FileType::FILESYSTEM;
}
if (extension == "bin" && filesize >= min_firmware_size) {
return FileType::FIRMWARE;
if (extension == "bin") {
String lower = filename;
lower.toLowerCase();
const size_t min_size =
lower.indexOf("recovery") >= 0 ? MIN_RECOVERY_FIRMWARE_SIZE : min_firmware_size;
if (filesize >= min_size) {
return FileType::FIRMWARE;
}
}
if (extension == "json") {
return FileType::JSON;
@@ -114,6 +124,19 @@ bool OtaUpdater::hasMd5() const {
return strlen(_md5.data()) == _md5.size() - 1;
}
#ifdef OTA_UPDATER_ANY_PARTITION
void OtaUpdater::setError(esp_err_t err) {
snprintf(_error_buf, sizeof(_error_buf), "%s (0x%x)", esp_err_to_name(err), static_cast<unsigned>(err));
_error = _error_buf;
}
void OtaUpdater::releaseTarget() {
_target = nullptr;
heap_caps_free(_dram);
_dram = nullptr;
}
#endif
bool OtaUpdater::beginFirmware(size_t filesize, const esp_partition_t * target, bool set_boot) {
_md5_applied = false;
_error = "";
@@ -126,13 +149,14 @@ bool OtaUpdater::beginFirmware(size_t filesize, const esp_partition_t * target,
_error = "Firmware does not fit in the partition";
return false;
}
const esp_err_t err = esp_ota_begin(target, OTA_WITH_SEQUENTIAL_WRITES, &_handle);
if (err != ESP_OK) {
_error = esp_err_to_name(err);
_dram = static_cast<uint8_t *>(heap_caps_malloc(DRAM_CHUNK, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
if (_dram == nullptr) {
_error = "No internal RAM for OTA buffer";
return false;
}
_target = target;
_written = 0;
_erased = 0;
_set_boot = set_boot;
if (hasMd5()) {
_md5Builder.begin();
@@ -166,15 +190,39 @@ bool OtaUpdater::beginFilesystem() {
bool OtaUpdater::write(const uint8_t * data, size_t len) {
#ifdef OTA_UPDATER_ANY_PARTITION
if (_target != nullptr) {
const esp_err_t err = esp_ota_write(_handle, data, len);
if (err != ESP_OK) {
_error = esp_err_to_name(err);
return false;
while (len) {
const size_t n = len < DRAM_CHUNK ? len : DRAM_CHUNK;
memcpy(_dram, data, n);
const size_t need = _written + n;
if (need > _erased) {
size_t erase_to = (need + FLASH_SECTOR - 1) / FLASH_SECTOR * FLASH_SECTOR;
if (erase_to > _target->size) {
erase_to = _target->size;
}
const size_t erase_len = erase_to - _erased;
if (erase_len > 0) {
const esp_err_t err = esp_partition_erase_range(_target, _erased, erase_len);
if (err != ESP_OK) {
setError(err);
return false;
}
_erased = erase_to;
}
}
const esp_err_t err = esp_partition_write(_target, _written, _dram, n);
if (err != ESP_OK) {
setError(err);
return false;
}
if (_md5_applied) {
_md5Builder.add(_dram, n);
}
_written += n;
data += n;
len -= n;
}
if (_md5_applied) {
_md5Builder.add(data, len);
}
_written += len;
return true;
}
#endif
@@ -184,27 +232,32 @@ bool OtaUpdater::write(const uint8_t * data, size_t len) {
bool OtaUpdater::end() {
#ifdef OTA_UPDATER_ANY_PARTITION
if (_target != nullptr) {
const esp_partition_t * target = _target;
_target = nullptr;
const esp_partition_t * target = _target;
const bool set_boot = _set_boot;
releaseTarget();
if (_md5_applied) {
_md5Builder.calculate();
if (strcmp(_md5Builder.toString().c_str(), _md5.data()) != 0) {
esp_ota_abort(_handle);
_error = "MD5 check failed";
return false;
}
}
// esp_ota_end() validates the image
esp_err_t err = esp_ota_end(_handle);
if (err == ESP_OK && _set_boot) {
err = esp_ota_set_boot_partition(target);
}
esp_image_metadata_t meta = {};
esp_partition_pos_t part_pos = {.offset = target->address, .size = target->size};
esp_err_t err = esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &part_pos, &meta);
if (err != ESP_OK) {
_error = esp_err_to_name(err);
setError(err);
return false;
}
if (set_boot) {
err = esp_ota_set_boot_partition(target);
if (err != ESP_OK) {
setError(err);
return false;
}
}
return true;
}
#endif
@@ -214,12 +267,13 @@ bool OtaUpdater::end() {
void OtaUpdater::abort() {
#ifdef OTA_UPDATER_ANY_PARTITION
if (_target != nullptr) {
esp_ota_abort(_handle);
_target = nullptr;
releaseTarget();
return;
}
#endif
Update.abort();
if (Update.isRunning()) {
Update.abort();
}
}
size_t OtaUpdater::progress() const {
+16 -2
View File
@@ -16,11 +16,16 @@ class OtaUpdater {
public:
enum class FileType : uint8_t { UNSUPPORTED, FIRMWARE, FILESYSTEM, JSON, MD5 };
// min_firmware_size is for the main EMS-ESP image. Filenames containing "recovery"
// (case-insensitive) use MIN_RECOVERY_FIRMWARE_SIZE instead.
static FileType classify(const String & filename, size_t filesize, size_t min_firmware_size);
// project name in the app description of the recovery firmware, set by custom_fw_name in platformio.ini
static constexpr char RECOVERY_PROJECT_NAME[] = "EMS-ESP-Recovery";
// recovery firmware is much smaller than the main image (~512 KB–1 MB)
static constexpr size_t MIN_RECOVERY_FIRMWARE_SIZE = 512 * 1024;
// checks the ESP image magic byte and that the chip id matches the chip we're running on
static bool isCompatibleFirmware(const uint8_t * data, size_t len);
@@ -64,12 +69,21 @@ class OtaUpdater {
const char * _error = "";
#ifdef OTA_UPDATER_ANY_PARTITION
// set when writing to an explicit target partition with the IDF OTA API instead of Update
// explicit target (factory/boot or an OTA slot) is written with the partition API;
// esp_ota_begin() returns ESP_ERR_INVALID_STATE (0x102) on the factory partition
const esp_partition_t * _target = nullptr;
esp_ota_handle_t _handle = 0;
size_t _written = 0;
size_t _erased = 0;
bool _set_boot = true;
MD5Builder _md5Builder;
// AsyncTCP may hand us PSRAM pointers; ESP32 flash DMA needs internal RAM
uint8_t * _dram = nullptr;
static constexpr size_t DRAM_CHUNK = 1024;
static constexpr size_t FLASH_SECTOR = 4096;
char _error_buf[48]{};
void setError(esp_err_t err);
void releaseTarget();
#endif
};