diff --git a/lib/AmsFirmwareUpdater/include/AmsFirmwareUpdater.h b/lib/AmsFirmwareUpdater/include/AmsFirmwareUpdater.h index f4d9ebe6..c00b2a0b 100644 --- a/lib/AmsFirmwareUpdater/include/AmsFirmwareUpdater.h +++ b/lib/AmsFirmwareUpdater/include/AmsFirmwareUpdater.h @@ -17,7 +17,7 @@ #define AMS_PARTITION_TABLE_OFFSET 0x8000 #define AMS_PARTITION_APP0_OFFSET 0x10000 #define AMS_PARTITION_APP_SIZE 0x1D0000 -#define AMS_PARTITION_SPIFFS_SIZE 0x40000 +#define AMS_PARTITION_MIN_SPIFFS_SIZE 0x20000 #endif #define AMS_UPDATE_ERR_OK 0 @@ -54,6 +54,10 @@ public: bool isUpgradeInformationChanged(); void ackUpgradeInformationChanged(); + bool startFirmwareUpload(uint32_t size, const char* version); + bool addFirmwareUploadChunk(uint8_t* buf, size_t length); + bool completeFirmwareUpload(); + private: #if defined(ESP8266) char chipType[10] = "esp8266"; @@ -100,8 +104,8 @@ private: uint32_t sketchSize(sketchSize_t response); #if defined(ESP32) - uint32_t updateHandle = 0; char* buf = NULL; + uint16_t bufPos = 0; bool readPartition(uint8_t num, const esp_partition_info_t* info); bool writePartition(uint8_t num, const esp_partition_info_t* info); diff --git a/lib/AmsFirmwareUpdater/src/AmsFirmwareUpdater.cpp b/lib/AmsFirmwareUpdater/src/AmsFirmwareUpdater.cpp index 556fb2e3..7ea7c22c 100644 --- a/lib/AmsFirmwareUpdater/src/AmsFirmwareUpdater.cpp +++ b/lib/AmsFirmwareUpdater/src/AmsFirmwareUpdater.cpp @@ -45,6 +45,9 @@ bool AmsFirmwareUpdater::setTargetVersion(const char* version) { updateStatus.errorCode = AMS_UPDATE_ERR_OK; updateStatus.reboot_count = 0; + bufPos = 0; + memset(buf, 0, UPDATE_BUF_SIZE); + #if defined(AMS_REMOTE_DEBUG) if (debugger->isActive(RemoteDebug::INFO)) #endif @@ -185,21 +188,7 @@ void AmsFirmwareUpdater::loop() { #endif debugger->printf_P(PSTR("http end took %lums\n"), end-start); } else if(updateStatus.block_position * UPDATE_BUF_SIZE >= updateStatus.size) { - #if defined(AMS_REMOTE_DEBUG) - if (debugger->isActive(RemoteDebug::INFO)) - #endif - debugger->printf_P(PSTR("Firmware download complete\n")); - - if(!verifyChecksum()) { - updateStatus.errorCode = AMS_UPDATE_ERR_MD5; - updateStatusChanged = true; - return; - } - if(!activateNewFirmware()) { - updateStatus.errorCode = AMS_UPDATE_ERR_ACTIVATE; - updateStatusChanged = true; - return; - } + if(!completeFirmwareUpload()) return; updateStatus.errorCode = AMS_UPDATE_ERR_SUCCESS_SIGNAL; updateStatusChanged = true; } @@ -602,6 +591,7 @@ bool AmsFirmwareUpdater::hasLargeEnoughAppPartitions() { } bool AmsFirmwareUpdater::canMigratePartitionTable() { + size_t appAndSpiffs = 0; esp_partition_info_t part; readPartition(0, &part); if(part.magic != ESP_PARTITION_MAGIC || part.type != ESP_PARTITION_TYPE_DATA, part.subtype != ESP_PARTITION_SUBTYPE_DATA_NVS) @@ -614,19 +604,25 @@ bool AmsFirmwareUpdater::canMigratePartitionTable() { readPartition(2, &part); if(part.magic != ESP_PARTITION_MAGIC || part.type != ESP_PARTITION_TYPE_APP, part.subtype != ESP_PARTITION_SUBTYPE_APP_OTA_0) return false; + appAndSpiffs += part.pos.size; readPartition(3, &part); if(part.magic != ESP_PARTITION_MAGIC || part.type != ESP_PARTITION_TYPE_APP, part.subtype != ESP_PARTITION_SUBTYPE_APP_OTA_1) return false; + appAndSpiffs += part.pos.size; readPartition(4, &part); if(part.magic != ESP_PARTITION_MAGIC || part.type != ESP_PARTITION_TYPE_DATA, part.subtype != ESP_PARTITION_SUBTYPE_DATA_SPIFFS) return false; + appAndSpiffs += part.pos.size; readPartition(5, &part); if(part.magic != ESP_PARTITION_MAGIC || part.type != ESP_PARTITION_TYPE_DATA, part.subtype != ESP_PARTITION_SUBTYPE_DATA_COREDUMP) return false; + if(appAndSpiffs < (AMS_PARTITION_APP_SIZE * 2) + AMS_PARTITION_MIN_SPIFFS_SIZE) + return false; + return true; } @@ -785,7 +781,7 @@ bool AmsFirmwareUpdater::writePartitionTableWithSpiffsAtOldAndApp1() { if(!writePartition(3, &p_app1)) return false; if(!writePartition(4, &p_spiffs)) return false; if(!writePartition(5, &p_coredump)) return false; - bool ret = writeNewPartitionChecksum(6); + if(!writeNewPartitionChecksum(6)) return false; // Clearing app1 partition if(esp_flash_erase_region(NULL, p_app1.pos.offset, p_app1.pos.size) != ESP_OK) { @@ -795,7 +791,7 @@ bool AmsFirmwareUpdater::writePartitionTableWithSpiffsAtOldAndApp1() { debugger->printf_P(PSTR("Unable to erase app1\n")); } - return ret; + return true; } bool AmsFirmwareUpdater::writePartitionTableWithSpiffsAtApp1AndNew() { @@ -834,7 +830,7 @@ bool AmsFirmwareUpdater::writePartitionTableWithSpiffsAtApp1AndNew() { if(!writePartition(4, &p_dummy)) return false; if(!writePartition(5, &p_spiffs)) return false; if(!writePartition(6, &p_coredump)) return false; - bool ret = writeNewPartitionChecksum(7); + if(!writeNewPartitionChecksum(7)) return false; // Clearing dummy partition if(esp_flash_erase_region(NULL, p_dummy.pos.offset, p_dummy.pos.size) != ESP_OK) { @@ -852,7 +848,7 @@ bool AmsFirmwareUpdater::writePartitionTableWithSpiffsAtApp1AndNew() { debugger->printf_P(PSTR("Unable to erase spiffs partition\n")); } - return ret; + return true; } bool AmsFirmwareUpdater::writePartitionTableFinal() { @@ -904,7 +900,7 @@ bool AmsFirmwareUpdater::writePartitionTableFinal() { if(!writePartition(3, &p_app1)) return false; if(!writePartition(4, &p_spiffs)) return false; if(!writePartition(5, &p_coredump)) return false; - bool ret = writeNewPartitionChecksum(6); + if(!writeNewPartitionChecksum(6)) return false; // Clearing app1 partition if(esp_flash_erase_region(NULL, p_app1.pos.offset, p_app1.pos.size) != ESP_OK) { @@ -930,7 +926,7 @@ bool AmsFirmwareUpdater::writePartitionTableFinal() { debugger->printf_P(PSTR("Unable to read header from app0\n")); } - return ret; + return true; } bool AmsFirmwareUpdater::moveLittleFsFromOldToApp1() { @@ -1015,4 +1011,63 @@ bool AmsFirmwareUpdater::moveLittleFsFromApp1ToNew() { copyFile(&tmpFs, &newFs, FILE_PRICE_CONF); return true; } +bool AmsFirmwareUpdater::startFirmwareUpload(uint32_t size, const char* version) { + const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL); + if(partition == NULL) { + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("No eligable partition was found for upgrade\n")); + return false; + } + + if(!setTargetVersion(version)) { + return false; + } + updateStatus.size = size; + return true; +} + +bool AmsFirmwareUpdater::addFirmwareUploadChunk(uint8_t* buf, size_t length) { + for(size_t i = 0; i < length; i++) { + this->buf[bufPos++] = buf[i]; + if(bufPos == UPDATE_BUF_SIZE) { + if(!writeBufferToFlash()) { + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("Unable to write to flash\n")); + return false; + } + bufPos = 0; + memset(buf, 0, UPDATE_BUF_SIZE); + } + } + return true; +} + +bool AmsFirmwareUpdater::completeFirmwareUpload() { + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::INFO)) + #endif + debugger->printf_P(PSTR("Firmware write complete\n")); + + if(bufPos > 0) { + writeBufferToFlash(); + bufPos = 0; + } + if(!verifyChecksum()) { + updateStatus.errorCode = AMS_UPDATE_ERR_MD5; + updateStatusChanged = true; + return false; + } + if(!activateNewFirmware()) { + updateStatus.errorCode = AMS_UPDATE_ERR_ACTIVATE; + updateStatusChanged = true; + return false; + } + updateStatus.errorCode = AMS_UPDATE_ERR_SUCCESS_CONFIRMED; + updateStatusChanged = true; + return true; +} #endif diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index a3c116b8..b1469e43 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -1773,28 +1773,82 @@ void AmsWebServer::firmwareUpload() { String filename = upload.filename; if(filename.isEmpty()) { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("No file, falling back to post\n")); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("No file, falling back to post\n")); return; } if(!filename.endsWith(F(".bin"))) { - server.send_P(500, MIME_PLAIN, PSTR("500: couldn't create file")); - } else { - #if defined(ESP32) - esp_task_wdt_delete(NULL); - esp_task_wdt_deinit(); - #elif defined(ESP8266) - ESP.wdtDisable(); + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::ERROR)) #endif + debugger->printf_P(PSTR("Invalid file extension\n")); + snprintf_P(buf, BufferSize, RESPONSE_JSON, + "false", + "Invalid file extension", + "false" + ); + server.setContentLength(strlen(buf)); + server.send(500, MIME_JSON, buf); + return; } - } - // TODO: uploadFile(FILE_FIRMWARE); - if(upload.status == UPLOAD_FILE_END) { - rebootForUpgrade = true; - server.sendHeader(HEADER_LOCATION,F("/")); - server.send(302); - } + if(!updater->startFirmwareUpload(upload.totalSize, "upload")) { + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("An error has occurred while starting firmware upload\n")); + snprintf_P(buf, BufferSize, RESPONSE_JSON, + "false", + "Unable to start firmware upgrade", + "false" + ); + server.setContentLength(strlen(buf)); + server.send(500, MIME_JSON, buf); + return; + } + #if defined(ESP32) + esp_task_wdt_delete(NULL); + esp_task_wdt_deinit(); + #elif defined(ESP8266) + ESP.wdtDisable(); + #endif + } + + if(upload.status == UPLOAD_FILE_START || upload.status == UPLOAD_FILE_WRITE) { + if(!updater->addFirmwareUploadChunk(upload.buf, upload.currentSize)) { + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("An error has occurred while writing firmware to flash\n")); + snprintf_P(buf, BufferSize, RESPONSE_JSON, + "false", + "Unable to write to flash", + "false" + ); + server.setContentLength(strlen(buf)); + server.send(500, MIME_JSON, buf); + return; + } + } else if(upload.status == UPLOAD_FILE_END) { + if(updater->completeFirmwareUpload()) { + rebootForUpgrade = true; + server.sendHeader(HEADER_LOCATION,F("/")); + server.send(302); + } else { + #if defined(AMS_REMOTE_DEBUG) + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("An error has occurred while activating new firmware\n")); + snprintf_P(buf, BufferSize, RESPONSE_JSON, + "false", + "Unable to activate new firmware", + "false" + ); + server.setContentLength(strlen(buf)); + server.send(500, MIME_JSON, buf); + return; + } + } } HTTPUpload& AmsWebServer::uploadFile(const char* path) { @@ -1802,15 +1856,15 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) { if(upload.status == UPLOAD_FILE_START) { if(uploading) { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("Upload already in progress\n")); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("Upload already in progress\n")); server.send_P(500, MIME_HTML, PSTR("