mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-02-27 01:10:31 +00:00
New firmware upload
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user