Browse Source

Initial implementation of RTCMEM storage (#1420)

- store system crash counter and reset reason in rtcmem instead of eeprom
- store relay state mask in rtc in addition to the eeprom
- store relay state in eeprom only when boot mode requires it
- simplify relay state mask calculation / reading using std::bitset
- light state save and restore
- energy total save and restore
rules-rpn
Max Prokhorov 5 years ago
committed by GitHub
parent
commit
820d8c4be8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 365 additions and 144 deletions
  1. +5
    -0
      code/espurna/config/general.h
  2. +19
    -1
      code/espurna/config/prototypes.h
  3. +44
    -0
      code/espurna/config/rtcmem.h
  4. +3
    -0
      code/espurna/espurna.ino
  5. +51
    -5
      code/espurna/light.ino
  6. +1
    -43
      code/espurna/mqtt.ino
  7. +49
    -35
      code/espurna/relay.ino
  8. +63
    -0
      code/espurna/rtcmem.ino
  9. +38
    -20
      code/espurna/sensor.ino
  10. +1
    -1
      code/espurna/settings.ino
  11. +86
    -4
      code/espurna/system.ino
  12. +2
    -3
      code/espurna/terminal.ino
  13. +3
    -32
      code/espurna/utils.ino

+ 5
- 0
code/espurna/config/general.h View File

@ -399,6 +399,11 @@
#define RELAY_MQTT_OFF "0" #define RELAY_MQTT_OFF "0"
#endif #endif
// TODO Only single EEPROM address is used to store state, which is 1 byte
// Relay status is stored using bitfield.
// This means that, atm, we are only storing the status of the first 8 relays.
#define RELAY_SAVE_MASK_MAX 8
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// WIFI // WIFI
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 19
- 1
code/espurna/config/prototypes.h View File

@ -6,10 +6,19 @@
extern "C" { extern "C" {
#include "user_interface.h" #include "user_interface.h"
extern struct rst_info resetInfo;
} }
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
// -----------------------------------------------------------------------------
// System
// -----------------------------------------------------------------------------
uint32_t systemResetReason();
uint8_t systemStabilityCounter();
void systemStabilityCounter(uint8_t);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// API // API
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -134,6 +143,11 @@ typedef struct {
int16_t rssi; int16_t rssi;
} packet_t; } packet_t;
// -----------------------------------------------------------------------------
// Relay
// -----------------------------------------------------------------------------
#include <bitset>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Settings // Settings
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -214,7 +228,6 @@ typedef std::function<void(justwifi_messages_t code, char * parameter)> wifi_cal
void wifiRegister(wifi_callback_f callback); void wifiRegister(wifi_callback_f callback);
bool wifiConnected(); bool wifiConnected();
// -----------------------------------------------------------------------------
// THERMOSTAT // THERMOSTAT
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#if THERMOSTAT_SUPPORT #if THERMOSTAT_SUPPORT
@ -224,3 +237,8 @@ bool wifiConnected();
#define thermostat_callback_f void * #define thermostat_callback_f void *
#endif #endif
// -----------------------------------------------------------------------------
// RTC MEMORY
// -----------------------------------------------------------------------------
#include "rtcmem.h"

+ 44
- 0
code/espurna/config/rtcmem.h View File

@ -0,0 +1,44 @@
#pragma once
// Base address of USER RTC memory
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map#memmory-mapped-io-registers
#define RTCMEM_ADDR_BASE (0x60001200)
// RTC memory is accessed using blocks of 4 bytes.
// Blocks 0..63 are reserved by the SDK, 64..192 are available to the user.
// Blocks 64..96 are reserved by the eboot 'struct eboot_command' (128 -> (128 / 4) -> 32):
// https://github.com/esp8266/Arduino/blob/master/bootloaders/eboot/eboot_command.h
#define RTCMEM_OFFSET 32u
#define RTCMEM_ADDR (RTCMEM_ADDR_BASE + (RTCMEM_OFFSET * 4u))
#define RTCMEM_BLOCKS 96u
// Change this when modifying RtcmemData
#define RTCMEM_MAGIC 0x45535075
// XXX When using bitfields / inner structs / etc:
// ...
// uint32_t a : 8;
// uint32_t b : 8;
// uint32_t c : 8;
// uint32_t d : 8;
// ...
// mem->d = 4;
// At the same time writes 4 to the a, b and c
// TODO replace with custom memory segment in ldscript
struct RtcmemData {
uint32_t magic;
uint32_t sys;
uint32_t relay;
uint32_t mqtt;
uint64_t light;
double energy;
};
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
constexpr uint8_t RtcmemSize = (sizeof(RtcmemData) / 4u);
auto Rtcmem = reinterpret_cast<volatile RtcmemData*>(RTCMEM_ADDR);
bool rtcmemStatus();

+ 3
- 0
code/espurna/espurna.ino View File

@ -67,6 +67,9 @@ void setup() {
debugSetup(); debugSetup();
#endif #endif
// Init RTCMEM
rtcmemSetup();
// Init EEPROM // Init EEPROM
eepromSetup(); eepromSetup();


+ 51
- 5
code/espurna/light.ino View File

@ -470,7 +470,47 @@ void _lightProviderUpdate() {
// PERSISTANCE // PERSISTANCE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void _lightColorSave() {
union light_rtcmem_t {
struct {
uint8_t channels[5];
uint8_t brightness;
uint16_t mired;
} packed;
uint64_t value;
};
#define LIGHT_RTCMEM_CHANNELS_MAX sizeof(light_rtcmem_t().packed.channels)
void _lightSaveRtcmem() {
if (lightChannels() > LIGHT_RTCMEM_CHANNELS_MAX) return;
light_rtcmem_t light;
for (unsigned int i=0; i < lightChannels(); i++) {
light.packed.channels[i] = _light_channel[i].inputValue;
}
light.packed.brightness = _light_brightness;
light.packed.mired = _light_mireds;
Rtcmem->light = light.value;
}
void _lightRestoreRtcmem() {
if (lightChannels() > LIGHT_RTCMEM_CHANNELS_MAX) return;
light_rtcmem_t light;
light.value = Rtcmem->light;
for (unsigned int i=0; i < lightChannels(); i++) {
_light_channel[i].inputValue = light.packed.channels[i];
}
_light_brightness = light.packed.brightness;
_light_mireds = light.packed.mired;
}
void _lightSaveSettings() {
for (unsigned int i=0; i < _light_channel.size(); i++) { for (unsigned int i=0; i < _light_channel.size(); i++) {
setSetting("ch", i, _light_channel[i].inputValue); setSetting("ch", i, _light_channel[i].inputValue);
} }
@ -479,7 +519,7 @@ void _lightColorSave() {
saveSettings(); saveSettings();
} }
void _lightColorRestore() {
void _lightRestoreSettings() {
for (unsigned int i=0; i < _light_channel.size(); i++) { for (unsigned int i=0; i < _light_channel.size(); i++) {
_light_channel[i].inputValue = getSetting("ch", i, i==0 ? 255 : 0).toInt(); _light_channel[i].inputValue = getSetting("ch", i, i==0 ? 255 : 0).toInt();
} }
@ -699,9 +739,11 @@ void lightUpdate(bool save, bool forward, bool group_forward) {
if (group_forward) mask += 2; if (group_forward) mask += 2;
_light_comms_ticker.once_ms(LIGHT_COMMS_DELAY, _lightComms, mask); _light_comms_ticker.once_ms(LIGHT_COMMS_DELAY, _lightComms, mask);
_lightSaveRtcmem();
#if LIGHT_SAVE_ENABLED #if LIGHT_SAVE_ENABLED
// Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily
if (save) _light_save_ticker.once(LIGHT_SAVE_DELAY, _lightColorSave);
if (save) _light_save_ticker.once(LIGHT_SAVE_DELAY, _lightSaveSettings);
#endif #endif
}; };
@ -712,7 +754,7 @@ void lightUpdate(bool save, bool forward) {
#if LIGHT_SAVE_ENABLED == 0 #if LIGHT_SAVE_ENABLED == 0
void lightSave() { void lightSave() {
_lightColorSave();
_lightSaveSettings();
} }
#endif #endif
@ -1166,7 +1208,11 @@ void lightSetup() {
DEBUG_MSG_P(PSTR("[LIGHT] Number of channels: %d\n"), _light_channel.size()); DEBUG_MSG_P(PSTR("[LIGHT] Number of channels: %d\n"), _light_channel.size());
_lightConfigure(); _lightConfigure();
_lightColorRestore();
if (rtcmemStatus()) {
_lightRestoreRtcmem();
} else {
_lightRestoreSettings();
}
#if WEB_SUPPORT #if WEB_SUPPORT
wsOnSendRegister(_lightWebSocketOnSend); wsOnSendRegister(_lightWebSocketOnSend);


+ 1
- 43
code/espurna/mqtt.ino View File

@ -267,48 +267,6 @@ void _mqttBackwards() {
} }
} }
unsigned long _mqttNextMessageId() {
static unsigned long id = 0;
// just reboot, get last count from EEPROM
if (id == 0) {
// read id from EEPROM and shift it
id = EEPROMr.read(EEPROM_MESSAGE_ID);
if (id == 0xFF) {
// There was nothing in EEPROM,
// next message is first message
id = 0;
} else {
id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 1);
id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 2);
id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 3);
// Calculate next block and start from there
id = MQTT_MESSAGE_ID_SHIFT * (1 + (id / MQTT_MESSAGE_ID_SHIFT));
}
}
// Save to EEPROM every MQTT_MESSAGE_ID_SHIFT
if (id % MQTT_MESSAGE_ID_SHIFT == 0) {
EEPROMr.write(EEPROM_MESSAGE_ID + 0, (id >> 24) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 1, (id >> 16) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 2, (id >> 8) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 3, (id >> 0) & 0xFF);
eepromCommit();
}
id++;
return id;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// WEB // WEB
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -628,7 +586,7 @@ void mqttFlush() {
root[MQTT_TOPIC_IP] = getIP(); root[MQTT_TOPIC_IP] = getIP();
#endif #endif
#if MQTT_ENQUEUE_MESSAGE_ID #if MQTT_ENQUEUE_MESSAGE_ID
root[MQTT_TOPIC_MESSAGE_ID] = _mqttNextMessageId();
root[MQTT_TOPIC_MESSAGE_ID] = (Rtcmem->mqtt)++;
#endif #endif
// Send // Send


+ 49
- 35
code/espurna/relay.ino View File

@ -196,11 +196,11 @@ void _relayProcess(bool mode) {
relayPulse(id); relayPulse(id);
// We will trigger a commit only if
// We will trigger a eeprom save only if
// we care about current relay status on boot // we care about current relay status on boot
unsigned char boot_mode = getSetting("relayBoot", id, RELAY_BOOT_MODE).toInt(); unsigned char boot_mode = getSetting("relayBoot", id, RELAY_BOOT_MODE).toInt();
bool do_commit = ((RELAY_BOOT_SAME == boot_mode) || (RELAY_BOOT_TOGGLE == boot_mode));
_relaySaveTicker.once_ms(RELAY_SAVE_DELAY, relaySave, do_commit);
bool save_eeprom = ((RELAY_BOOT_SAME == boot_mode) || (RELAY_BOOT_TOGGLE == boot_mode));
_relaySaveTicker.once_ms(RELAY_SAVE_DELAY, relaySave, save_eeprom);
#if WEB_SUPPORT #if WEB_SUPPORT
wsSend(_relayWebSocketUpdate); wsSend(_relayWebSocketUpdate);
@ -247,6 +247,14 @@ void setSpeed(unsigned char speed) {
// RELAY // RELAY
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void _relayMaskRtcmem(uint32_t mask) {
Rtcmem->relay = mask;
}
uint32_t _relayMaskRtcmem() {
return Rtcmem->relay;
}
void relayPulse(unsigned char id) { void relayPulse(unsigned char id) {
_relays[id].pulseTicker.detach(); _relays[id].pulseTicker.detach();
@ -401,41 +409,41 @@ void relaySync(unsigned char id) {
} }
void relaySave(bool do_commit) {
// Relay status is stored in a single byte
// This means that, atm,
// we are only storing the status of the first 8 relays.
unsigned char bit = 1;
unsigned char mask = 0;
unsigned char count = _relays.size();
if (count > 8) count = 8;
for (unsigned int i=0; i < count; i++) {
if (relayStatus(i)) mask += bit;
bit += bit;
void relaySave(bool eeprom) {
auto mask = std::bitset<RELAY_SAVE_MASK_MAX>(0);
unsigned char count = relayCount();
if (count > RELAY_SAVE_MASK_MAX) count = RELAY_SAVE_MASK_MAX;
for (unsigned int i=0; i < count; ++i) {
mask.set(i, relayStatus(i));
} }
EEPROMr.write(EEPROM_RELAY_STATUS, mask);
DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %d\n"), mask);
const uint32_t mask_value = mask.to_ulong();
DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %u\n"), mask_value);
// Persist only to rtcmem, unless requested to save to the eeprom
_relayMaskRtcmem(mask_value);
// The 'do_commit' flag controls wether we are commiting this change or not.
// The 'eeprom' flag controls wether we are commiting this change or not.
// It is useful to set it to 'false' if the relay change triggering the // It is useful to set it to 'false' if the relay change triggering the
// save involves a relay whose boot mode is independent from current mode, // save involves a relay whose boot mode is independent from current mode,
// thus storing the last relay value is not absolutely necessary. // thus storing the last relay value is not absolutely necessary.
// Nevertheless, we store the value in the EEPROM buffer so it will be written // Nevertheless, we store the value in the EEPROM buffer so it will be written
// on the next commit. // on the next commit.
if (do_commit) {
if (eeprom) {
EEPROMr.write(EEPROM_RELAY_STATUS, mask_value);
// We are actually enqueuing the commit so it will be // We are actually enqueuing the commit so it will be
// executed on the main loop, in case this is called from a callback
// executed on the main loop, in case this is called from a system context callback
eepromCommit(); eepromCommit();
} }
} }
void relaySave() { void relaySave() {
relaySave(true);
relaySave(false);
} }
void relayToggle(unsigned char id, bool report, bool group_report) { void relayToggle(unsigned char id, bool report, bool group_report) {
@ -514,32 +522,37 @@ void _relayBackwards() {
void _relayBoot() { void _relayBoot() {
_relayRecursive = true; _relayRecursive = true;
unsigned char bit = 1;
bool trigger_save = false; bool trigger_save = false;
uint32_t stored_mask = 0;
// Get last statuses from EEPROM
unsigned char mask = EEPROMr.read(EEPROM_RELAY_STATUS);
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %d\n"), mask);
if (rtcmemStatus()) {
stored_mask = _relayMaskRtcmem();
} else {
stored_mask = EEPROMr.read(EEPROM_RELAY_STATUS);
}
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %u\n"), stored_mask);
auto mask = std::bitset<RELAY_SAVE_MASK_MAX>(stored_mask);
// Walk the relays // Walk the relays
bool status; bool status;
for (unsigned int i=0; i<_relays.size(); i++) {
for (unsigned char i=0; i<relayCount(); ++i) {
unsigned char boot_mode = getSetting("relayBoot", i, RELAY_BOOT_MODE).toInt(); unsigned char boot_mode = getSetting("relayBoot", i, RELAY_BOOT_MODE).toInt();
DEBUG_MSG_P(PSTR("[RELAY] Relay #%d boot mode %d\n"), i, boot_mode);
DEBUG_MSG_P(PSTR("[RELAY] Relay #%u boot mode %u\n"), i, boot_mode);
status = false; status = false;
switch (boot_mode) { switch (boot_mode) {
case RELAY_BOOT_SAME: case RELAY_BOOT_SAME:
if (i < 8) { if (i < 8) {
status = ((mask & bit) == bit);
status = mask.test(i);
} }
break; break;
case RELAY_BOOT_TOGGLE: case RELAY_BOOT_TOGGLE:
if (i < 8) { if (i < 8) {
status = ((mask & bit) != bit);
mask ^= bit;
status = !mask[i];
mask.flip(i);
trigger_save = true; trigger_save = true;
} }
break; break;
@ -558,12 +571,13 @@ void _relayBoot() {
#else #else
_relays[i].change_time = millis(); _relays[i].change_time = millis();
#endif #endif
bit <<= 1;
} }
// Save if there is any relay in the RELAY_BOOT_TOGGLE mode // Save if there is any relay in the RELAY_BOOT_TOGGLE mode
if (trigger_save) { if (trigger_save) {
EEPROMr.write(EEPROM_RELAY_STATUS, mask);
_relayMaskRtcmem(mask.to_ulong());
EEPROMr.write(EEPROM_RELAY_STATUS, mask.to_ulong());
eepromCommit(); eepromCommit();
} }


+ 63
- 0
code/espurna/rtcmem.ino View File

@ -0,0 +1,63 @@
bool _rtcmem_status = false;
void _rtcmemInit() {
memset((uint32_t*)RTCMEM_ADDR, 0, sizeof(uint32_t) * RTCMEM_BLOCKS);
Rtcmem->magic = RTCMEM_MAGIC;
}
// Treat memory as dirty on cold boot, hardware wdt reset and rst pin
bool _rtcmemStatus() {
bool readable;
switch (systemResetReason()) {
case REASON_EXT_SYS_RST:
case REASON_WDT_RST:
case REASON_DEFAULT_RST:
readable = false;
break;
default:
readable = true;
}
readable = readable and (RTCMEM_MAGIC == Rtcmem->magic);
return readable;
}
#if TERMINAL_SUPPORT
void _rtcmemInitCommands() {
terminalRegisterCommand(F("RTCMEM.REINIT"), [](Embedis* e) {
_rtcmemInit();
});
terminalRegisterCommand(F("RTCMEM.TEST"), [](Embedis* e) {
});
terminalRegisterCommand(F("RTCMEM.DUMP"), [](Embedis* e) {
DEBUG_MSG_P(PSTR("[RTCMEM] status:%u blocks:%u addr:0x%p\n"),
_rtcmemStatus(), RtcmemSize, Rtcmem);
for (uint8_t block=0; block<RtcmemSize; ++block) {
DEBUG_MSG_P(PSTR("[RTCMEM] %02u: %u\n"),
block, reinterpret_cast<volatile uint32_t*>(RTCMEM_ADDR)[block]);
}
});
}
#endif
bool rtcmemStatus() {
return _rtcmem_status;
}
void rtcmemSetup() {
_rtcmem_status = _rtcmemStatus();
if (!_rtcmem_status) {
_rtcmemInit();
}
#if TERMINAL_SUPPORT
_rtcmemInitCommands();
#endif
}

+ 38
- 20
code/espurna/sensor.ino View File

@ -423,6 +423,35 @@ void _sensorResetTS() {
#endif #endif
} }
double _sensorEnergyTotal() {
double value = 0;
if (rtcmemStatus()) {
value = Rtcmem->energy;
} else {
value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
}
return value;
}
void _sensorEnergyTotal(double value) {
static unsigned long save_count = 0;
// Save to EEPROM every '_sensor_save_every' readings
if (_sensor_save_every > 0) {
save_count = (save_count + 1) % _sensor_save_every;
if (0 == save_count) {
setSetting("eneTotal", value);
saveSettings();
}
}
// Always save to RTCMEM
Rtcmem->energy = value;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Sensor initialization // Sensor initialization
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -939,7 +968,9 @@ void _sensorInit() {
EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i]; EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i];
sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat()); sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat());
sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt());
double value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
double value = _sensorEnergyTotal();
if (value > 0) sensor->resetEnergy(0, value); if (value > 0) sensor->resetEnergy(0, value);
} }
@ -962,7 +993,7 @@ void _sensorInit() {
value = getSetting("pwrRatioP", HLW8012_POWER_RATIO).toFloat(); value = getSetting("pwrRatioP", HLW8012_POWER_RATIO).toFloat();
if (value > 0) sensor->setPowerRatio(value); if (value > 0) sensor->setPowerRatio(value);
value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
value = _sensorEnergyTotal();
if (value > 0) sensor->resetEnergy(value); if (value > 0) sensor->resetEnergy(value);
} }
@ -986,7 +1017,7 @@ void _sensorInit() {
value = getSetting("pwrRatioP", 0).toFloat(); value = getSetting("pwrRatioP", 0).toFloat();
if (value > 0) sensor->setPowerRatio(value); if (value > 0) sensor->setPowerRatio(value);
value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
value = _sensorEnergyTotal();
if (value > 0) sensor->resetEnergy(value); if (value > 0) sensor->resetEnergy(value);
} }
@ -1426,7 +1457,6 @@ void sensorLoop() {
// Check if we should read new data // Check if we should read new data
static unsigned long last_update = 0; static unsigned long last_update = 0;
static unsigned long report_count = 0; static unsigned long report_count = 0;
static unsigned long save_count = 0;
if (millis() - last_update > _sensor_read_interval) { if (millis() - last_update > _sensor_read_interval) {
last_update = millis(); last_update = millis();
@ -1532,23 +1562,11 @@ void sensorLoop() {
_sensorReport(i, value_filtered); _sensorReport(i, value_filtered);
} // if (fabs(value_filtered - magnitude.reported) >= magnitude.min_change) } // if (fabs(value_filtered - magnitude.reported) >= magnitude.min_change)
// -------------------------------------------------------------
// Saving to EEPROM
// (we do it every _sensor_save_every readings)
// -------------------------------------------------------------
if (_sensor_save_every > 0) {
save_count = (save_count + 1) % _sensor_save_every;
if (0 == save_count) {
if (MAGNITUDE_ENERGY == magnitude.type) {
setSetting("eneTotal", value_raw);
saveSettings();
}
} // if (0 == save_count)
} // if (_sensor_save_every > 0)
// Persist total energy value
if (MAGNITUDE_ENERGY == magnitude.type) {
_sensorEnergyTotal(value_raw);
}
} // if (report_count == 0) } // if (report_count == 0)


+ 1
- 1
code/espurna/settings.ino View File

@ -245,4 +245,4 @@ void settingsSetup() {
#endif #endif
); );
}
}

+ 86
- 4
code/espurna/system.ino View File

@ -6,6 +6,7 @@ Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
*/ */
#include <Ticker.h>
#include <EEPROM_Rotate.h> #include <EEPROM_Rotate.h>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -19,6 +20,41 @@ unsigned short int _load_average = 100;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
union system_rtcmem_t {
struct {
uint8_t stability_counter;
uint8_t reset_reason;
uint16_t _reserved_;
} parts;
uint32_t value;
};
uint8_t systemStabilityCounter() {
system_rtcmem_t data;
data.value = Rtcmem->sys;
return data.parts.stability_counter;
}
void systemStabilityCounter(uint8_t counter) {
system_rtcmem_t data;
data.value = Rtcmem->sys;
data.parts.stability_counter = counter;
Rtcmem->sys = data.value;
}
uint8_t _systemResetReason() {
system_rtcmem_t data;
data.value = Rtcmem->sys;
return data.parts.reset_reason;
}
void _systemResetReason(uint8_t reason) {
system_rtcmem_t data;
data.value = Rtcmem->sys;
data.parts.reset_reason = reason;
Rtcmem->sys = data.value;
}
#if SYSTEM_CHECK_ENABLED #if SYSTEM_CHECK_ENABLED
// Call this method on boot with start=true to increase the crash counter // Call this method on boot with start=true to increase the crash counter
@ -31,19 +67,27 @@ unsigned short int _load_average = 100;
bool _systemStable = true; bool _systemStable = true;
void systemCheck(bool stable) { void systemCheck(bool stable) {
unsigned char value = EEPROMr.read(EEPROM_CRASH_COUNTER);
uint8_t value = 0;
if (stable) { if (stable) {
value = 0; value = 0;
DEBUG_MSG_P(PSTR("[MAIN] System OK\n")); DEBUG_MSG_P(PSTR("[MAIN] System OK\n"));
} else { } else {
if (!rtcmemStatus()) {
systemStabilityCounter(1);
return;
}
value = systemStabilityCounter();
if (++value > SYSTEM_CHECK_MAX) { if (++value > SYSTEM_CHECK_MAX) {
_systemStable = false; _systemStable = false;
value = 0; value = 0;
DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n")); DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n"));
} }
} }
EEPROMr.write(EEPROM_CRASH_COUNTER, value);
eepromCommit();
systemStabilityCounter(value);
} }
bool systemCheck() { bool systemCheck() {
@ -53,7 +97,7 @@ bool systemCheck() {
void systemCheckLoop() { void systemCheckLoop() {
static bool checked = false; static bool checked = false;
if (!checked && (millis() > SYSTEM_CHECK_TIME)) { if (!checked && (millis() > SYSTEM_CHECK_TIME)) {
// Check system as stable
// Flag system as stable
systemCheck(true); systemCheck(true);
checked = true; checked = true;
} }
@ -61,6 +105,44 @@ void systemCheckLoop() {
#endif #endif
// -----------------------------------------------------------------------------
// Reset
// -----------------------------------------------------------------------------
Ticker _defer_reset;
uint8_t _reset_reason = 0;
// system_get_rst_info() result is cached by the Core init for internal use
uint32_t systemResetReason() {
return resetInfo.reason;
}
void customResetReason(unsigned char reason) {
_reset_reason = reason;
_systemResetReason(reason);
}
unsigned char customResetReason() {
static unsigned char status = 255;
if (status == 255) {
if (rtcmemStatus()) status = _systemResetReason();
if (status > 0) customResetReason(0);
if (status > CUSTOM_RESET_MAX) status = 0;
}
return status;
}
void reset() {
ESP.restart();
}
void deferredReset(unsigned long delay, unsigned char reason) {
_defer_reset.once_ms(delay, customResetReason, reason);
}
bool checkNeedsReset() {
return _reset_reason > 0;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void systemSendHeartbeat() { void systemSendHeartbeat() {


+ 2
- 3
code/espurna/terminal.ino View File

@ -95,8 +95,7 @@ void _terminalInitCommand() {
terminalRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) { terminalRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) {
terminalOK(); terminalOK();
resetReason(CUSTOM_RESET_TERMINAL);
_eepromCommit();
customResetReason(CUSTOM_RESET_TERMINAL);
eraseSDKConfig(); eraseSDKConfig();
*((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494 *((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494
}); });
@ -180,7 +179,7 @@ void _terminalInitCommand() {
}); });
terminalRegisterCommand(F("RESET.SAFE"), [](Embedis* e) { terminalRegisterCommand(F("RESET.SAFE"), [](Embedis* e) {
EEPROMr.write(EEPROM_CRASH_COUNTER, SYSTEM_CHECK_MAX);
systemStabilityCounter(SYSTEM_CHECK_MAX);
terminalOK(); terminalOK();
deferredReset(100, CUSTOM_RESET_TERMINAL); deferredReset(100, CUSTOM_RESET_TERMINAL);
}); });


+ 3
- 32
code/espurna/utils.ino View File

@ -7,9 +7,6 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
*/ */
#include <Ticker.h> #include <Ticker.h>
Ticker _defer_reset;
uint8_t _reset_reason = 0;
String getIdentifier() { String getIdentifier() {
char buffer[20]; char buffer[20];
@ -473,7 +470,7 @@ void info() {
DEBUG_MSG_P(PSTR("[MAIN] Boot version: %d\n"), ESP.getBootVersion()); DEBUG_MSG_P(PSTR("[MAIN] Boot version: %d\n"), ESP.getBootVersion());
DEBUG_MSG_P(PSTR("[MAIN] Boot mode: %d\n"), ESP.getBootMode()); DEBUG_MSG_P(PSTR("[MAIN] Boot mode: %d\n"), ESP.getBootMode());
unsigned char reason = resetReason();
unsigned char reason = customResetReason();
if (reason > 0) { if (reason > 0) {
char buffer[32]; char buffer[32];
strcpy_P(buffer, custom_reset_string[reason-1]); strcpy_P(buffer, custom_reset_string[reason-1]);
@ -571,34 +568,6 @@ bool sslFingerPrintChar(const char * fingerprint, char * destination) {
// Reset // Reset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
unsigned char resetReason() {
static unsigned char status = 255;
if (status == 255) {
status = EEPROMr.read(EEPROM_CUSTOM_RESET);
if (status > 0) resetReason(0);
if (status > CUSTOM_RESET_MAX) status = 0;
}
return status;
}
void resetReason(unsigned char reason) {
_reset_reason = reason;
EEPROMr.write(EEPROM_CUSTOM_RESET, reason);
eepromCommit();
}
void reset() {
ESP.restart();
}
void deferredReset(unsigned long delay, unsigned char reason) {
_defer_reset.once_ms(delay, resetReason, reason);
}
bool checkNeedsReset() {
return _reset_reason > 0;
}
// Use fixed method for Core 2.3.0, because it erases only 2 out of 4 SDK-reserved sectors // Use fixed method for Core 2.3.0, because it erases only 2 out of 4 SDK-reserved sectors
// Fixed since 2.4.0, see: esp8266/core/esp8266/Esp.cpp: ESP::eraseConfig() // Fixed since 2.4.0, see: esp8266/core/esp8266/Esp.cpp: ESP::eraseConfig()
bool eraseSDKConfig() { bool eraseSDKConfig() {
@ -618,6 +587,8 @@ bool eraseSDKConfig() {
#endif #endif
} }
// -----------------------------------------------------------------------------
// Helper functions
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
char * ltrim(char * s) { char * ltrim(char * s) {


Loading…
Cancel
Save