New firmware upload

This commit is contained in:
Gunnar Skjold
2024-12-05 13:40:30 +01:00
parent bf3059ba04
commit a5fc1f0cbe
3 changed files with 214 additions and 49 deletions

View File

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

View File

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

View File

@@ -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("<html><body><h1>Upload already in progress!</h1></body></html>"));
} else if (!LittleFS.begin()) {
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::ERROR))
#endif
debugger->printf_P(PSTR("An Error has occurred while mounting LittleFS\n"));
if (debugger->isActive(RemoteDebug::ERROR))
#endif
debugger->printf_P(PSTR("An Error has occurred while mounting LittleFS\n"));
server.send_P(500, MIME_HTML, PSTR("<html><body><h1>Unable to mount LittleFS!</h1></body></html>"));
} else {
uploading = true;
@@ -1830,9 +1884,9 @@ debugger->printf_P(PSTR("An Error has occurred while mounting LittleFS\n"));
LittleFS.remove(path);
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::ERROR))
#endif
debugger->printf_P(PSTR("An Error has occurred while writing file\n"));
if (debugger->isActive(RemoteDebug::ERROR))
#endif
debugger->printf_P(PSTR("An Error has occurred while writing file\n"));
snprintf_P(buf, BufferSize, RESPONSE_JSON,
"false",
"File size does not match",
@@ -2254,6 +2308,58 @@ void AmsWebServer::configFileDownload() {
if(strlen(price.entsoeToken) == 36 && includeSecrets) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("priceEntsoeToken %s\n"), price.entsoeToken));
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("priceArea %s\n"), price.area));
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("priceCurrency %s\n"), price.currency));
if(ps != NULL) {
uint8_t i = 0;
std::vector<PriceConfig> pc = ps->getPriceConfig();
if(pc.size() > 0) {
for(uint8_t i = 0; i < pc.size(); i++) {
PriceConfig& p = pc.at(i);
char direction[6] = "";
switch(p.direction) {
case PRICE_DIRECTION_IMPORT:
strcpy_P(direction, PSTR("import"));
break;
case PRICE_DIRECTION_EXPORT:
strcpy_P(direction, PSTR("export"));
break;
case PRICE_DIRECTION_BOTH:
strcpy_P(direction, PSTR("both"));
break;
}
char type[9] = "";
switch(p.type) {
case PRICE_TYPE_FIXED:
strcpy_P(type, PSTR("fixed"));
break;
case PRICE_TYPE_ADD:
strcpy_P(type, PSTR("add"));
break;
case PRICE_TYPE_PCT:
strcpy_P(type, PSTR("percent"));
break;
case PRICE_TYPE_SUBTRACT:
strcpy_P(type, PSTR("subtract"));
break;
}
char days[12] = "";
char hours[12] = "";
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("priceModifier %i %s %s %s %.4f %s %s %02d-%02d %02d-%02d\n"),
i,
p.name,
direction,
type,
p.value / 10000.0,
days,
hours,
p.start_dayofmonth,
p.start_month,
p.end_dayofmonth,
p.end_month
));
}
}
}
}
if(includeThresholds) {