configmanager: enhancements for version migration
This commit is contained in:
parent
1cbf0d7124
commit
414bc41404
@ -1,11 +1,12 @@
|
|||||||
#ifndef _CONFIGMANAGER_H
|
#ifndef _CONFIGMANAGER_H
|
||||||
#define _CONFIGMANAGER_H
|
#define _CONFIGMANAGER_H
|
||||||
|
|
||||||
#include <Preferences.h>
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
void saveConfig(bool erase = false);
|
void saveConfig(bool erase = false);
|
||||||
bool loadConfig(void);
|
bool loadConfig(void);
|
||||||
void eraseConfig(void);
|
void eraseConfig(void);
|
||||||
|
int version_compare(const String v1, const String v2);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -60,8 +60,10 @@ enum runmode_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Struct holding devices's runtime configuration
|
// Struct holding devices's runtime configuration
|
||||||
// using packed to avoid compiler padding, because struct will be memcpy'd to byte array
|
// using packed to avoid compiler padding, because struct will be memcpy'd to
|
||||||
|
// byte array
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
|
char version[10]; // Firmware version
|
||||||
uint8_t loradr; // 0-15, lora datarate
|
uint8_t loradr; // 0-15, lora datarate
|
||||||
uint8_t txpower; // 2-15, lora tx power
|
uint8_t txpower; // 2-15, lora tx power
|
||||||
uint8_t adrmode; // 0=disabled, 1=enabled
|
uint8_t adrmode; // 0=disabled, 1=enabled
|
||||||
@ -80,7 +82,6 @@ typedef struct __attribute__((packed)) {
|
|||||||
uint8_t monitormode; // 0=disabled, 1=enabled
|
uint8_t monitormode; // 0=disabled, 1=enabled
|
||||||
uint8_t runmode; // 0=normal, 1=update
|
uint8_t runmode; // 0=normal, 1=update
|
||||||
uint8_t payloadmask; // bitswitches for payload data
|
uint8_t payloadmask; // bitswitches for payload data
|
||||||
char version[10]; // Firmware version
|
|
||||||
#ifdef HAS_BME680
|
#ifdef HAS_BME680
|
||||||
uint8_t
|
uint8_t
|
||||||
bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]; // BSEC state for BME680 sensor
|
bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]; // BSEC state for BME680 sensor
|
||||||
|
@ -6,17 +6,15 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "configmanager.h"
|
||||||
|
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFiClientSecure.h>
|
||||||
#include <BintrayClient.h>
|
#include <BintrayClient.h>
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
int do_ota_update();
|
int do_ota_update();
|
||||||
void start_ota_update();
|
void start_ota_update();
|
||||||
int version_compare(const String v1, const String v2);
|
|
||||||
void ota_display(const uint8_t row, const std::string status,
|
void ota_display(const uint8_t row, const std::string status,
|
||||||
const std::string msg);
|
const std::string msg);
|
||||||
void show_progress(unsigned long current, unsigned long size);
|
void show_progress(unsigned long current, unsigned long size);
|
||||||
|
@ -16,16 +16,20 @@ static const char TAG[] = __FILE__;
|
|||||||
|
|
||||||
Preferences nvram;
|
Preferences nvram;
|
||||||
|
|
||||||
static const char cfgMagicBytes[] = {0x21, 0x76, 0x87, 0x32, 0xf3};
|
static const uint8_t cfgMagicBytes[] = {0x21, 0x76, 0x87, 0x32, 0xf4};
|
||||||
static const size_t cfgLen = sizeof(cfg), cfgLen2 = sizeof(cfgMagicBytes);
|
static const size_t cfgLen = sizeof(cfg), cfgLen2 = sizeof(cfgMagicBytes);
|
||||||
static char buffer[cfgLen + cfgLen2];
|
static uint8_t buffer[cfgLen + cfgLen2];
|
||||||
|
|
||||||
// populate runtime config with factory settings
|
// populate runtime config with device factory settings
|
||||||
static void defaultConfig(configData_t *myconfig) {
|
static void defaultConfig(configData_t *myconfig) {
|
||||||
char version[10];
|
// char version[10];
|
||||||
snprintf(version, 10, "%-10s", PROGVERSION);
|
// snprintf(version, 10, "%-10s", PROGVERSION);
|
||||||
|
// memcpy(myconfig->version, version, 10); // Firmware version [exactly 10
|
||||||
|
// chars]
|
||||||
|
memcpy(myconfig->version, &PROGVERSION,
|
||||||
|
10); // Firmware version [exactly 10 chars]
|
||||||
|
|
||||||
// factory settings
|
// device factory settings
|
||||||
myconfig->loradr = LORADRDEFAULT; // 0-15, lora datarate, see paxcounter.conf
|
myconfig->loradr = LORADRDEFAULT; // 0-15, lora datarate, see paxcounter.conf
|
||||||
myconfig->txpower = LORATXPOWDEFAULT; // 0-15, lora tx power
|
myconfig->txpower = LORATXPOWDEFAULT; // 0-15, lora tx power
|
||||||
myconfig->adrmode = 1; // 0=disabled, 1=enabled
|
myconfig->adrmode = 1; // 0=disabled, 1=enabled
|
||||||
@ -47,7 +51,6 @@ static void defaultConfig(configData_t *myconfig) {
|
|||||||
myconfig->rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
myconfig->rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
||||||
myconfig->monitormode = 0; // 0=disabled, 1=enabled
|
myconfig->monitormode = 0; // 0=disabled, 1=enabled
|
||||||
myconfig->payloadmask = PAYLOADMASK; // all payload switched on
|
myconfig->payloadmask = PAYLOADMASK; // all payload switched on
|
||||||
memcpy(myconfig->version, version, 10); // Firmware version [exactly 10 chars]
|
|
||||||
|
|
||||||
#ifdef HAS_BME680
|
#ifdef HAS_BME680
|
||||||
// initial BSEC state for BME680 sensor
|
// initial BSEC state for BME680 sensor
|
||||||
@ -55,6 +58,15 @@ static void defaultConfig(configData_t *myconfig) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// migrate runtime config from earlier version to current
|
||||||
|
static void migrateConfig(void) {
|
||||||
|
// currently no migration rules are implemented, we just reset config to
|
||||||
|
// factory settings
|
||||||
|
ESP_LOGI(TAG, "Migrating device configuration from %s to %s", cfg.version,
|
||||||
|
PROGVERSION);
|
||||||
|
eraseConfig();
|
||||||
|
}
|
||||||
|
|
||||||
// save current configuration from RAM to NVRAM
|
// save current configuration from RAM to NVRAM
|
||||||
void saveConfig(bool erase) {
|
void saveConfig(bool erase) {
|
||||||
ESP_LOGI(TAG, "Storing settings to NVRAM...");
|
ESP_LOGI(TAG, "Storing settings to NVRAM...");
|
||||||
@ -89,30 +101,58 @@ bool loadConfig() {
|
|||||||
ESP_LOGW(TAG, "NVRAM initialized, device starts with factory settings");
|
ESP_LOGW(TAG, "NVRAM initialized, device starts with factory settings");
|
||||||
eraseConfig();
|
eraseConfig();
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// simple check that runtime config data matches
|
// simple check that runtime config data matches
|
||||||
if (nvram.getBytesLength(DEVCONFIG) != (cfgLen + cfgLen2)) {
|
if (nvram.getBytesLength(DEVCONFIG) != (cfgLen + cfgLen2)) {
|
||||||
ESP_LOGE(TAG, "configuration invalid");
|
ESP_LOGE(TAG, "Configuration invalid");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// load device runtime config from nvram and copy it to byte array
|
// load device runtime config from nvram and copy it to byte array
|
||||||
nvram.getBytes(DEVCONFIG, buffer, cfgLen + cfgLen2);
|
nvram.getBytes(DEVCONFIG, buffer, cfgLen + cfgLen2);
|
||||||
nvram.end();
|
nvram.end();
|
||||||
// validate configuration by checking magic bytes at end of array
|
|
||||||
|
// validate loaded configuration by checking magic bytes at end of array
|
||||||
if (memcmp(buffer + cfgLen, &cfgMagicBytes, cfgLen2) != 0) {
|
if (memcmp(buffer + cfgLen, &cfgMagicBytes, cfgLen2) != 0) {
|
||||||
ESP_LOGW(TAG, "No configuration found");
|
ESP_LOGW(TAG, "No configuration found");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
// copy loaded configuration into runtime cfg struct
|
||||||
// copy byte array into runtime cfg struct
|
|
||||||
memcpy(&cfg, buffer, cfgLen);
|
memcpy(&cfg, buffer, cfgLen);
|
||||||
ESP_LOGI(TAG, "Runtime configuration loaded");
|
ESP_LOGI(TAG, "Runtime configuration v%s loaded", cfg.version);
|
||||||
|
|
||||||
|
// check if config version matches current firmware version
|
||||||
|
switch (version_compare(PROGVERSION, cfg.version)) {
|
||||||
|
case -1: // device configuration belongs to newer than current firmware
|
||||||
|
ESP_LOGE(TAG, "Incompatible device configuration, aborting");
|
||||||
|
return false;
|
||||||
|
case 1: // device configuration belongs to older than current firmware
|
||||||
|
ESP_LOGW(TAG, "Device was updated, migrating device configuration");
|
||||||
|
migrateConfig();
|
||||||
|
return true;
|
||||||
|
default: // device configuration version matches current firmware version
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper function to convert strings into lower case
|
||||||
|
bool comp(char s1, char s2) { return (tolower(s1) < tolower(s2)); }
|
||||||
|
|
||||||
|
// helper function to lexicographically compare two versions. Returns 1 if v2
|
||||||
|
// is smaller, -1 if v1 is smaller, 0 if equal
|
||||||
|
int version_compare(const String v1, const String v2) {
|
||||||
|
|
||||||
|
if (v1 == v2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const char *a1 = v1.c_str(), *a2 = v2.c_str();
|
||||||
|
|
||||||
|
if (std::lexicographical_compare(a1, a1 + strlen(a1), a2, a2 + strlen(a2), comp))
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void eraseConfig(void) { saveConfig(true); }
|
void eraseConfig(void) { saveConfig(true); }
|
18
src/ota.cpp
18
src/ota.cpp
@ -328,22 +328,4 @@ void show_progress(unsigned long current, unsigned long size) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to convert strings into lower case
|
|
||||||
bool comp(char s1, char s2) { return tolower(s1) < tolower(s2); }
|
|
||||||
|
|
||||||
// helper function to lexicographically compare two versions. Returns 1 if v2 is
|
|
||||||
// smaller, -1 if v1 is smaller, 0 if equal
|
|
||||||
int version_compare(const String v1, const String v2) {
|
|
||||||
|
|
||||||
if (v1 == v2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const char *a1 = v1.c_str(), *a2 = v2.c_str();
|
|
||||||
|
|
||||||
if (lexicographical_compare(a1, a1 + strlen(a1), a2, a2 + strlen(a2), comp))
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // USE_OTA
|
#endif // USE_OTA
|
Loading…
Reference in New Issue
Block a user