Sensor3/lib/patrix/config.cpp

193 lines
4.5 KiB
C++

#include "config.h"
#include "log.h"
#include <EEPROM.h>
#include <ArduinoJson.h>
#define DIRTY_WRITE_DELAY (30 * 1000)
JsonDocument config;
unsigned long lastChangeMillis = 0;
bool configRead();
bool configWrite();
bool configWriteBytes(int *address, uint8_t *data, size_t size);
bool configReadBytes(int *address, uint8_t *data, size_t size);
void configSetup() {
configRead();
}
void configLoop() {
if (lastChangeMillis > 0 && millis() - lastChangeMillis > DIRTY_WRITE_DELAY) {
configWrite();
}
}
void configReset() {
config.clear();
configWrite();
}
String configGetString(const char *name, const char *fallback, bool allowEmpty) {
if (!config.containsKey(name)) {
return fallback;
}
String value = config[name];
if (!allowEmpty && value.isEmpty()) {
return fallback;
}
return value;
}
void configPutString(const char *name, const char *value) {
if (config[name] != value) {
config[name] = value;
lastChangeMillis = millis();
}
}
double configGetDouble(const char *name, double fallback) {
if (!config.containsKey(name)) {
return fallback;
}
return config[name];
}
void configPutDouble(const char *name, double value) {
if (config[name] != value) {
config[name] = value;
lastChangeMillis = millis();
}
}
uint64_t configGetUint64_t(const char *name, uint64_t fallback) {
if (!config.containsKey(name)) {
return fallback;
}
return config[name];
}
void configPutUint64_t(const char *name, uint64_t value) {
if (config[name] != value) {
config[name] = value;
lastChangeMillis = millis();
}
}
uint8_t configGetUint8_t(const char *name, uint8_t fallback) {
if (!config.containsKey(name)) {
return fallback;
}
return config[name];
}
void configPutUint8_t(const char *name, uint8_t value) {
if (config[name] != value) {
config[name] = value;
lastChangeMillis = millis();
}
}
void configPrint() {
info("Config (%s):", lastChangeMillis == 0 ? "PERSISTED" : "TRANSIENT");
for (JsonPair pair: config.as<JsonObject>()) {
const char *key = pair.key().c_str();
const JsonVariant &value = pair.value();
char valueStr[64];
if (strcmp(key, "WIFI_PKEY") == 0) {
snprintf(valueStr, sizeof valueStr, "[***]");
} else {
if (value.is<const char *>()) {
snprintf(valueStr, sizeof valueStr, "%s", value.as<const char *>());
} else if (value.is<double>()) {
snprintf(valueStr, sizeof valueStr, "%f", value.as<double>());
} else if (value.is<int>()) {
snprintf(valueStr, sizeof valueStr, "%d", value.as<int>());
} else if (value.is<bool>()) {
snprintf(valueStr, sizeof valueStr, "%s", value.as<bool>() ? "true" : "false");
} else {
snprintf(valueStr, sizeof valueStr, "[UNKNOWN TYPE]");
}
}
info(" %-15s = %s", key, valueStr);
}
}
bool configRead() {
size_t length;
char buffer[512];
bool ok = true;
int address = 0;
EEPROM.begin(512);
ok &= configReadBytes(&address, reinterpret_cast<uint8_t *>(&length), sizeof length);
ok &= configReadBytes(&address, reinterpret_cast<uint8_t *>(buffer), length);
ok &= EEPROM.end();
if (ok) {
JsonDocument tmp;
deserializeJson(tmp, buffer);
if (tmp.is<JsonObject>() && !tmp.isNull()) {
info("Config loaded");
config = tmp;
return true;
} else {
error("Failed to parse config JSON");
}
} else {
error("Failed to load config from EEPROM");
}
return false;
}
bool configWrite() {
lastChangeMillis = 0;
char buffer[512];
size_t length = serializeJson(config, buffer, sizeof buffer);
bool ok = true;
int address = 0;
EEPROM.begin(512);
ok &= configWriteBytes(&address, reinterpret_cast<uint8_t *>(&length), sizeof length);
ok &= configWriteBytes(&address, reinterpret_cast<uint8_t *>(buffer), length);
ok &= EEPROM.end();
if (ok) {
info("Successfully wrote config to EEPROM");
} else {
info("Failed to write config to EEPROM");
}
return ok;
}
bool configWriteBytes(int *address, uint8_t *data, size_t size) {
uint8_t *b = data;
for (; b < data + size; b++) {
EEPROM.write((*address)++, *b);
if ((size_t) *address >= EEPROM.length()) {
error("END OF EEPROM!!!");
break;
}
}
return (size_t) (b - data) == size;
}
bool configReadBytes(int *address, uint8_t *data, size_t size) {
uint8_t *b = data;
for (; b < data + size; b++) {
*b = EEPROM.read((*address)++);
if ((size_t) *address >= EEPROM.length()) {
error("END OF EEPROM!!!");
break;
}
}
return (size_t) (b - data) == size;
}