mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
improved crash detection
This commit is contained in:
@@ -8,9 +8,19 @@
|
|||||||
|
|
||||||
#include "MyESP.h"
|
#include "MyESP.h"
|
||||||
|
|
||||||
#ifdef CRASH
|
|
||||||
EEPROM_Rotate EEPROMr;
|
EEPROM_Rotate EEPROMr;
|
||||||
#endif
|
|
||||||
|
union system_rtcmem_t {
|
||||||
|
struct {
|
||||||
|
uint8_t stability_counter;
|
||||||
|
uint8_t reset_reason;
|
||||||
|
uint16_t _reserved_;
|
||||||
|
} parts;
|
||||||
|
uint32_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t RtcmemSize = (sizeof(RtcmemData) / 4u);
|
||||||
|
auto Rtcmem = reinterpret_cast<volatile RtcmemData *>(RTCMEM_ADDR);
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
MyESP::MyESP() {
|
MyESP::MyESP() {
|
||||||
@@ -57,6 +67,9 @@ MyESP::MyESP() {
|
|||||||
_ota_post_callback = NULL;
|
_ota_post_callback = NULL;
|
||||||
|
|
||||||
_suspendOutput = false;
|
_suspendOutput = false;
|
||||||
|
|
||||||
|
_rtcmem_status = false;
|
||||||
|
_systemStable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyESP::~MyESP() {
|
MyESP::~MyESP() {
|
||||||
@@ -361,7 +374,6 @@ void MyESP::setOTA(ota_callback_f OTACallback_pre, ota_callback_f OTACallback_po
|
|||||||
void MyESP::_OTACallback() {
|
void MyESP::_OTACallback() {
|
||||||
myDebug_P(PSTR("[OTA] Start"));
|
myDebug_P(PSTR("[OTA] Start"));
|
||||||
|
|
||||||
#ifdef CRASH
|
|
||||||
// If we are not specifically reserving the sectors we are using as
|
// If we are not specifically reserving the sectors we are using as
|
||||||
// EEPROM in the memory layout then any OTA upgrade will overwrite
|
// EEPROM in the memory layout then any OTA upgrade will overwrite
|
||||||
// all but the last one.
|
// all but the last one.
|
||||||
@@ -374,7 +386,6 @@ void MyESP::_OTACallback() {
|
|||||||
// See onError callback below.
|
// See onError callback below.
|
||||||
EEPROMr.rotate(false);
|
EEPROMr.rotate(false);
|
||||||
EEPROMr.commit();
|
EEPROMr.commit();
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_ota_pre_callback) {
|
if (_ota_pre_callback) {
|
||||||
(_ota_pre_callback)(); // call custom function
|
(_ota_pre_callback)(); // call custom function
|
||||||
@@ -391,7 +402,11 @@ void MyESP::_ota_setup() {
|
|||||||
ArduinoOTA.setHostname(_app_hostname);
|
ArduinoOTA.setHostname(_app_hostname);
|
||||||
|
|
||||||
ArduinoOTA.onStart([this]() { _OTACallback(); });
|
ArduinoOTA.onStart([this]() { _OTACallback(); });
|
||||||
ArduinoOTA.onEnd([this]() { myDebug_P(PSTR("[OTA] Done, restarting...")); });
|
ArduinoOTA.onEnd([this]() {
|
||||||
|
myDebug_P(PSTR("[OTA] Done, restarting..."));
|
||||||
|
_deferredReset(100, CUSTOM_RESET_OTA);
|
||||||
|
});
|
||||||
|
|
||||||
ArduinoOTA.onProgress([this](unsigned int progress, unsigned int total) {
|
ArduinoOTA.onProgress([this](unsigned int progress, unsigned int total) {
|
||||||
static unsigned int _progOld;
|
static unsigned int _progOld;
|
||||||
unsigned int _prog = (progress / (total / 100));
|
unsigned int _prog = (progress / (total / 100));
|
||||||
@@ -413,10 +428,8 @@ void MyESP::_ota_setup() {
|
|||||||
else if (error == OTA_END_ERROR)
|
else if (error == OTA_END_ERROR)
|
||||||
myDebug_P(PSTR("[OTA] End Failed"));
|
myDebug_P(PSTR("[OTA] End Failed"));
|
||||||
|
|
||||||
#ifdef CRASH
|
|
||||||
// There's been an error, reenable rotation
|
// There's been an error, reenable rotation
|
||||||
EEPROMr.rotate(true);
|
EEPROMr.rotate(true);
|
||||||
#endif
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,10 +443,8 @@ void MyESP::setBoottime(const char * boottime) {
|
|||||||
|
|
||||||
// eeprom
|
// eeprom
|
||||||
void MyESP::_eeprom_setup() {
|
void MyESP::_eeprom_setup() {
|
||||||
#ifdef CRASH
|
|
||||||
EEPROMr.size(4);
|
EEPROMr.size(4);
|
||||||
EEPROMr.begin(SPI_FLASH_SEC_SIZE);
|
EEPROMr.begin(SPI_FLASH_SEC_SIZE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set callback of sketch function to process project messages
|
// Set callback of sketch function to process project messages
|
||||||
@@ -449,7 +460,6 @@ void MyESP::_telnetConnected() {
|
|||||||
_consoleShowHelp(); // Show the initial message
|
_consoleShowHelp(); // Show the initial message
|
||||||
|
|
||||||
// show crash dump if just restarted after a fatal crash
|
// show crash dump if just restarted after a fatal crash
|
||||||
#ifdef CRASH
|
|
||||||
uint32_t crash_time;
|
uint32_t crash_time;
|
||||||
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
|
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
|
||||||
if ((crash_time != 0) && (crash_time != 0xFFFFFFFF)) {
|
if ((crash_time != 0) && (crash_time != 0xFFFFFFFF)) {
|
||||||
@@ -461,7 +471,6 @@ void MyESP::_telnetConnected() {
|
|||||||
EEPROMr.commit();
|
EEPROMr.commit();
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// call callback
|
// call callback
|
||||||
if (_telnet_callback) {
|
if (_telnet_callback) {
|
||||||
@@ -505,9 +514,7 @@ void MyESP::_consoleShowHelp() {
|
|||||||
myDebug_P(PSTR("* Commands:"));
|
myDebug_P(PSTR("* Commands:"));
|
||||||
myDebug_P(PSTR("* ?=help, CTRL-D/quit=exit telnet session"));
|
myDebug_P(PSTR("* ?=help, CTRL-D/quit=exit telnet session"));
|
||||||
myDebug_P(PSTR("* set, system, reboot"));
|
myDebug_P(PSTR("* set, system, reboot"));
|
||||||
#ifdef CRASH
|
|
||||||
myDebug_P(PSTR("* crash <dump | clear>"));
|
myDebug_P(PSTR("* crash <dump | clear>"));
|
||||||
#endif
|
|
||||||
|
|
||||||
// print custom commands if available. Taken from progmem
|
// print custom commands if available. Taken from progmem
|
||||||
if (_telnetcommand_callback) {
|
if (_telnetcommand_callback) {
|
||||||
@@ -601,6 +608,7 @@ void MyESP::_printSetCommands() {
|
|||||||
// reset / restart
|
// reset / restart
|
||||||
void MyESP::resetESP() {
|
void MyESP::resetESP() {
|
||||||
myDebug_P(PSTR("* Reboot ESP..."));
|
myDebug_P(PSTR("* Reboot ESP..."));
|
||||||
|
_deferredReset(100, CUSTOM_RESET_TERMINAL);
|
||||||
end();
|
end();
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
@@ -792,8 +800,7 @@ void MyESP::_telnetCommand(char * commandLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// crash command
|
// crash command
|
||||||
#ifdef CRASH
|
|
||||||
if ((strcmp(ptrToCommandName, "crash") == 0) && (wc == 2)) {
|
if ((strcmp(ptrToCommandName, "crash") == 0) && (wc == 2)) {
|
||||||
char * cmd = _telnet_readWord(false);
|
char * cmd = _telnet_readWord(false);
|
||||||
if (strcmp(cmd, "dump") == 0) {
|
if (strcmp(cmd, "dump") == 0) {
|
||||||
@@ -805,7 +812,6 @@ void MyESP::_telnetCommand(char * commandLine) {
|
|||||||
}
|
}
|
||||||
return; // don't call custom command line callback
|
return; // don't call custom command line callback
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// call callback function
|
// call callback function
|
||||||
(_telnetcommand_callback)(wc, commandLine);
|
(_telnetcommand_callback)(wc, commandLine);
|
||||||
@@ -864,6 +870,137 @@ unsigned long MyESP::_getUptime() {
|
|||||||
return uptime_seconds;
|
return uptime_seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reason code
|
||||||
|
void MyESP::_rtcmemInit() {
|
||||||
|
memset((uint32_t *)RTCMEM_ADDR, 0, sizeof(uint32_t) * RTCMEM_BLOCKS);
|
||||||
|
Rtcmem->magic = RTCMEM_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MyESP::_getSystemStabilityCounter() {
|
||||||
|
system_rtcmem_t data;
|
||||||
|
data.value = Rtcmem->sys;
|
||||||
|
return data.parts.stability_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyESP::_setSystemStabilityCounter(uint8_t counter) {
|
||||||
|
system_rtcmem_t data;
|
||||||
|
data.value = Rtcmem->sys;
|
||||||
|
data.parts.stability_counter = counter;
|
||||||
|
Rtcmem->sys = data.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MyESP::_getSystemResetReason() {
|
||||||
|
system_rtcmem_t data;
|
||||||
|
data.value = Rtcmem->sys;
|
||||||
|
return data.parts.reset_reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyESP::_setSystemResetReason(uint8_t reason) {
|
||||||
|
system_rtcmem_t data;
|
||||||
|
data.value = Rtcmem->sys;
|
||||||
|
data.parts.reset_reason = reason;
|
||||||
|
Rtcmem->sys = data.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t MyESP::getSystemResetReason() {
|
||||||
|
return resetInfo.reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyESP::_rtcmemSetup() {
|
||||||
|
_rtcmem_status = _rtcmemStatus();
|
||||||
|
if (!_rtcmem_status) {
|
||||||
|
_rtcmemInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyESP::_setCustomResetReason(uint8_t reason) {
|
||||||
|
_setSystemResetReason(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat memory as dirty on cold boot, hardware wdt reset and rst pin
|
||||||
|
bool MyESP::_rtcmemStatus() {
|
||||||
|
bool readable;
|
||||||
|
|
||||||
|
switch (getSystemResetReason()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyESP::rtcmemStatus() {
|
||||||
|
return _rtcmem_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char MyESP::_getCustomResetReason() {
|
||||||
|
static unsigned char status = 255;
|
||||||
|
if (status == 255) {
|
||||||
|
if (_rtcmemStatus())
|
||||||
|
status = _getSystemResetReason();
|
||||||
|
if (status > 0)
|
||||||
|
_setCustomResetReason(0);
|
||||||
|
if (status > CUSTOM_RESET_MAX)
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyESP::_deferredReset(unsigned long delaytime, unsigned char reason) {
|
||||||
|
delay(delaytime);
|
||||||
|
_setCustomResetReason(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call this method on boot with start=true to increase the crash counter
|
||||||
|
// Call it again once the system is stable to decrease the counter
|
||||||
|
// If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable
|
||||||
|
// setting _systemOK = false;
|
||||||
|
//
|
||||||
|
// An unstable system will only have serial access, WiFi in AP mode and OTA
|
||||||
|
void MyESP::_setSystemCheck(bool stable) {
|
||||||
|
uint8_t value = 0;
|
||||||
|
|
||||||
|
if (stable) {
|
||||||
|
value = 0; // system is ok
|
||||||
|
// myDebug_P(PSTR("[SYSTEM] System OK\n"));
|
||||||
|
} else {
|
||||||
|
if (!rtcmemStatus()) {
|
||||||
|
_setSystemStabilityCounter(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = _getSystemStabilityCounter();
|
||||||
|
|
||||||
|
if (++value > SYSTEM_CHECK_MAX) {
|
||||||
|
_systemStable = false;
|
||||||
|
value = 0; // system is unstable
|
||||||
|
myDebug_P(PSTR("[SYSTEM] Warning, system UNSTABLE\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setSystemStabilityCounter(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyESP::getSystemCheck() {
|
||||||
|
return _systemStable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyESP::_systemCheckLoop() {
|
||||||
|
static bool checked = false;
|
||||||
|
if (!checked && (millis() > SYSTEM_CHECK_TIME)) {
|
||||||
|
_setSystemCheck(true); // Flag system as stable
|
||||||
|
checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// print out ESP system stats
|
// print out ESP system stats
|
||||||
// for battery power is ESP.getVcc()
|
// for battery power is ESP.getVcc()
|
||||||
void MyESP::showSystemStats() {
|
void MyESP::showSystemStats() {
|
||||||
@@ -892,6 +1029,10 @@ void MyESP::showSystemStats() {
|
|||||||
|
|
||||||
myDebug_P(PSTR(" [APP] System Load: %d%%"), getSystemLoadAverage());
|
myDebug_P(PSTR(" [APP] System Load: %d%%"), getSystemLoadAverage());
|
||||||
|
|
||||||
|
if (!getSystemCheck()) {
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] Device is in SAFE MODE"));
|
||||||
|
}
|
||||||
|
|
||||||
if (isAPmode()) {
|
if (isAPmode()) {
|
||||||
myDebug_P(PSTR(" [WIFI] Device is in AP mode with SSID %s"), jw.getAPSSID().c_str());
|
myDebug_P(PSTR(" [WIFI] Device is in AP mode with SSID %s"), jw.getAPSSID().c_str());
|
||||||
} else {
|
} else {
|
||||||
@@ -902,7 +1043,6 @@ void MyESP::showSystemStats() {
|
|||||||
|
|
||||||
myDebug_P(PSTR(" [WIFI] WiFi MAC: %s"), WiFi.macAddress().c_str());
|
myDebug_P(PSTR(" [WIFI] WiFi MAC: %s"), WiFi.macAddress().c_str());
|
||||||
|
|
||||||
#ifdef CRASH
|
|
||||||
char output_str[80] = {0};
|
char output_str[80] = {0};
|
||||||
char buffer[16] = {0};
|
char buffer[16] = {0};
|
||||||
myDebug_P(PSTR(" [EEPROM] EEPROM size: %u"), EEPROMr.reserved() * SPI_FLASH_SEC_SIZE);
|
myDebug_P(PSTR(" [EEPROM] EEPROM size: %u"), EEPROMr.reserved() * SPI_FLASH_SEC_SIZE);
|
||||||
@@ -914,7 +1054,6 @@ void MyESP::showSystemStats() {
|
|||||||
strlcat(output_str, " ", sizeof(output_str));
|
strlcat(output_str, " ", sizeof(output_str));
|
||||||
}
|
}
|
||||||
myDebug(output_str);
|
myDebug(output_str);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARDUINO_BOARD
|
#ifdef ARDUINO_BOARD
|
||||||
myDebug_P(PSTR(" [SYSTEM] Board: %s"), ARDUINO_BOARD);
|
myDebug_P(PSTR(" [SYSTEM] Board: %s"), ARDUINO_BOARD);
|
||||||
@@ -929,6 +1068,21 @@ void MyESP::showSystemStats() {
|
|||||||
myDebug_P(PSTR(" [SYSTEM] Boot version: %d"), ESP.getBootVersion());
|
myDebug_P(PSTR(" [SYSTEM] Boot version: %d"), ESP.getBootVersion());
|
||||||
myDebug_P(PSTR(" [SYSTEM] Boot mode: %d"), ESP.getBootMode());
|
myDebug_P(PSTR(" [SYSTEM] Boot mode: %d"), ESP.getBootMode());
|
||||||
//myDebug_P(PSTR("[SYSTEM] Firmware MD5: %s"), (char *)ESP.getSketchMD5().c_str());
|
//myDebug_P(PSTR("[SYSTEM] Firmware MD5: %s"), (char *)ESP.getSketchMD5().c_str());
|
||||||
|
unsigned char reason = _getCustomResetReason();
|
||||||
|
if (reason > 0) {
|
||||||
|
char buffer[32];
|
||||||
|
strcpy_P(buffer, custom_reset_string[reason - 1]);
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] Last reset reason: %s"), buffer);
|
||||||
|
} else {
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] Last reset reason: %s"), (char *)ESP.getResetReason().c_str());
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] Last reset info: %s"), (char *)ESP.getResetInfo().c_str());
|
||||||
|
}
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] Restart count: %d"), _getSystemStabilityCounter());
|
||||||
|
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] rtcmem status:%u blocks:%u addr:0x%p"), _rtcmemStatus(), RtcmemSize, Rtcmem);
|
||||||
|
for (uint8_t block = 0; block < RtcmemSize; ++block) {
|
||||||
|
myDebug_P(PSTR(" [SYSTEM] rtcmem %02u: %u"), block, reinterpret_cast<volatile uint32_t *>(RTCMEM_ADDR)[block]);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FlashMode_t mode = ESP.getFlashChipMode();
|
FlashMode_t mode = ESP.getFlashChipMode();
|
||||||
@@ -942,10 +1096,10 @@ void MyESP::showSystemStats() {
|
|||||||
#endif
|
#endif
|
||||||
myDebug_P(PSTR(" [FLASH] Flash size (SDK): %d"), ESP.getFlashChipSize());
|
myDebug_P(PSTR(" [FLASH] Flash size (SDK): %d"), ESP.getFlashChipSize());
|
||||||
myDebug_P(PSTR(" [FLASH] Flash Reserved: %d"), 1 * SPI_FLASH_SEC_SIZE);
|
myDebug_P(PSTR(" [FLASH] Flash Reserved: %d"), 1 * SPI_FLASH_SEC_SIZE);
|
||||||
myDebug_P(PSTR(" [MEM] Firmware size: %d"), ESP.getSketchSize());
|
//myDebug_P(PSTR(" [MEM] Firmware size: %d"), ESP.getSketchSize()); // TODO: commented out because it causes a crash with 2.5.2
|
||||||
myDebug_P(PSTR(" [MEM] Max OTA size: %d"), (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
myDebug_P(PSTR(" [MEM] Max OTA size: %d"), (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
||||||
myDebug_P(PSTR(" [MEM] OTA Reserved: %d"), 4 * SPI_FLASH_SEC_SIZE);
|
myDebug_P(PSTR(" [MEM] OTA Reserved: %d"), 4 * SPI_FLASH_SEC_SIZE);
|
||||||
//myDebug_P(PSTR(" [MEM] Free Heap: %d"), ESP.getFreeHeap());
|
myDebug_P(PSTR(" [MEM] Free Heap: %d"), ESP.getFreeHeap());
|
||||||
myDebug_P(PSTR(""));
|
myDebug_P(PSTR(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1385,7 +1539,6 @@ int MyESP::getWifiQuality() {
|
|||||||
return 2 * (dBm + 100);
|
return 2 * (dBm + 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CRASH
|
|
||||||
/**
|
/**
|
||||||
* Save crash information in EEPROM
|
* Save crash information in EEPROM
|
||||||
* This function is called automatically if ESP8266 suffers an exception
|
* This function is called automatically if ESP8266 suffers an exception
|
||||||
@@ -1534,14 +1687,6 @@ void MyESP::crashDump() {
|
|||||||
myDebug_P(PSTR("<<<stack<<<"));
|
myDebug_P(PSTR("<<<stack<<<"));
|
||||||
myDebug_P(PSTR("\nTo clean this dump use the command: %scrash clear%s\n"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
myDebug_P(PSTR("\nTo clean this dump use the command: %scrash clear%s\n"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void MyESP::crashClear() {
|
|
||||||
}
|
|
||||||
void MyESP::crashDump() {
|
|
||||||
}
|
|
||||||
void MyESP::crashInfo() {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// setup MyESP
|
// setup MyESP
|
||||||
void MyESP::begin(const char * app_hostname, const char * app_name, const char * app_version) {
|
void MyESP::begin(const char * app_hostname, const char * app_name, const char * app_version) {
|
||||||
@@ -1549,6 +1694,7 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
|
|||||||
_app_name = strdup(app_name);
|
_app_name = strdup(app_name);
|
||||||
_app_version = strdup(app_version);
|
_app_version = strdup(app_version);
|
||||||
|
|
||||||
|
_rtcmemSetup();
|
||||||
_telnet_setup(); // Telnet setup, called first to set Serial
|
_telnet_setup(); // Telnet setup, called first to set Serial
|
||||||
_eeprom_setup(); // set up eeprom for storing crash data, if compiled with -DCRASH
|
_eeprom_setup(); // set up eeprom for storing crash data, if compiled with -DCRASH
|
||||||
_fs_setup(); // SPIFFS setup, do this first to get values
|
_fs_setup(); // SPIFFS setup, do this first to get values
|
||||||
@@ -1558,6 +1704,8 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
|
|||||||
// print a welcome message
|
// print a welcome message
|
||||||
myDebug_P(PSTR("\n* %s version %s"), _app_name, _app_version);
|
myDebug_P(PSTR("\n* %s version %s"), _app_name, _app_version);
|
||||||
SerialAndTelnet.flush();
|
SerialAndTelnet.flush();
|
||||||
|
|
||||||
|
_setSystemCheck(false); // reset system check
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1565,17 +1713,12 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
|
|||||||
*/
|
*/
|
||||||
void MyESP::loop() {
|
void MyESP::loop() {
|
||||||
_calculateLoad();
|
_calculateLoad();
|
||||||
|
_systemCheckLoop();
|
||||||
|
|
||||||
_telnetHandle();
|
_telnetHandle();
|
||||||
|
|
||||||
jw.loop(); // WiFi
|
jw.loop(); // WiFi
|
||||||
|
|
||||||
/*
|
|
||||||
// do nothing else until we've got a wifi connection
|
|
||||||
if (WiFi.getMode() & WIFI_AP) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
ArduinoOTA.handle(); // OTA
|
ArduinoOTA.handle(); // OTA
|
||||||
_mqttConnect(); // MQTT
|
_mqttConnect(); // MQTT
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#ifndef MyEMS_h
|
#ifndef MyEMS_h
|
||||||
#define MyEMS_h
|
#define MyEMS_h
|
||||||
|
|
||||||
#define MYESP_VERSION "1.1.13"
|
#define MYESP_VERSION "1.1.14"
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
@@ -18,13 +18,14 @@
|
|||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <JustWifi.h> // https://github.com/xoseperez/justwifi
|
#include <JustWifi.h> // https://github.com/xoseperez/justwifi
|
||||||
#include <TelnetSpy.h> // modified from https://github.com/yasheena/telnetspy
|
#include <TelnetSpy.h> // modified from https://github.com/yasheena/telnetspy
|
||||||
|
#include <Ticker.h>
|
||||||
|
|
||||||
#ifdef CRASH
|
|
||||||
#include <EEPROM_Rotate.h>
|
#include <EEPROM_Rotate.h>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void custom_crash_callback(struct rst_info *, uint32_t, uint32_t);
|
#include "user_interface.h"
|
||||||
|
void custom_crash_callback(struct rst_info *, uint32_t, uint32_t);
|
||||||
|
extern struct rst_info resetInfo;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
//#include <ESPmDNS.h>
|
//#include <ESPmDNS.h>
|
||||||
@@ -86,6 +87,18 @@ void custom_crash_callback(struct rst_info *, uint32_t, uint32_t);
|
|||||||
#define COLOR_BRIGHT_CYAN "\x1B[0;96m"
|
#define COLOR_BRIGHT_CYAN "\x1B[0;96m"
|
||||||
#define COLOR_BRIGHT_WHITE "\x1B[0;97m"
|
#define COLOR_BRIGHT_WHITE "\x1B[0;97m"
|
||||||
|
|
||||||
|
// reset reason codes
|
||||||
|
PROGMEM const char custom_reset_hardware[] = "Hardware button";
|
||||||
|
PROGMEM const char custom_reset_terminal[] = "Reboot from terminal";
|
||||||
|
PROGMEM const char custom_reset_mqtt[] = "Reboot from MQTT";
|
||||||
|
PROGMEM const char custom_reset_ota[] = "Reboot after successful OTA update";
|
||||||
|
PROGMEM const char * const custom_reset_string[] = {custom_reset_hardware, custom_reset_terminal, custom_reset_mqtt, custom_reset_ota};
|
||||||
|
#define CUSTOM_RESET_HARDWARE 1 // Reset from hardware button
|
||||||
|
#define CUSTOM_RESET_TERMINAL 2 // Reset from terminal
|
||||||
|
#define CUSTOM_RESET_MQTT 3 // Reset via MQTT
|
||||||
|
#define CUSTOM_RESET_OTA 4 // Reset after successful OTA update
|
||||||
|
#define CUSTOM_RESET_MAX 4
|
||||||
|
|
||||||
// SPIFFS
|
// SPIFFS
|
||||||
#define SPIFFS_MAXSIZE 800 // https://arduinojson.org/v6/assistant/
|
#define SPIFFS_MAXSIZE 800 // https://arduinojson.org/v6/assistant/
|
||||||
|
|
||||||
@@ -119,6 +132,30 @@ void custom_crash_callback(struct rst_info *, uint32_t, uint32_t);
|
|||||||
#define SAVE_CRASH_STACK_END 0x1E // 4 bytes
|
#define SAVE_CRASH_STACK_END 0x1E // 4 bytes
|
||||||
#define SAVE_CRASH_STACK_TRACE 0x22 // variable
|
#define SAVE_CRASH_STACK_TRACE 0x22 // variable
|
||||||
|
|
||||||
|
// 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
|
||||||
|
#define RTCMEM_MAGIC 0x45535075
|
||||||
|
|
||||||
|
struct RtcmemData {
|
||||||
|
uint32_t magic; // RTCMEM_MAGIC
|
||||||
|
uint32_t sys; // system reset reason (1-4)
|
||||||
|
uint32_t energy; // store energy count
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
||||||
|
|
||||||
|
#define SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis
|
||||||
|
#define SYSTEM_CHECK_MAX 5 // After this many crashes on boot
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool set; // is it a set command
|
bool set; // is it a set command
|
||||||
char key[50];
|
char key[50];
|
||||||
@@ -202,6 +239,10 @@ class MyESP {
|
|||||||
int getWifiQuality();
|
int getWifiQuality();
|
||||||
void showSystemStats();
|
void showSystemStats();
|
||||||
|
|
||||||
|
// rtcmem and reset reason
|
||||||
|
bool rtcmemStatus();
|
||||||
|
uint32_t getSystemResetReason();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// mqtt
|
// mqtt
|
||||||
AsyncMqttClient mqttClient;
|
AsyncMqttClient mqttClient;
|
||||||
@@ -226,6 +267,7 @@ class MyESP {
|
|||||||
char * _mqtt_topic;
|
char * _mqtt_topic;
|
||||||
unsigned long _mqtt_last_connection;
|
unsigned long _mqtt_last_connection;
|
||||||
bool _mqtt_connecting;
|
bool _mqtt_connecting;
|
||||||
|
bool _rtcmem_status;
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
DNSServer dnsServer; // For Access Point (AP) support
|
DNSServer dnsServer; // For Access Point (AP) support
|
||||||
@@ -283,6 +325,29 @@ class MyESP {
|
|||||||
unsigned long _getUptime();
|
unsigned long _getUptime();
|
||||||
String _buildTime();
|
String _buildTime();
|
||||||
|
|
||||||
|
// reset reason and rtcmem
|
||||||
|
bool _rtcmemStatus();
|
||||||
|
void _rtcmemInit();
|
||||||
|
void _rtcmemSetup();
|
||||||
|
|
||||||
|
void _deferredReset(unsigned long delay, uint8_t reason);
|
||||||
|
|
||||||
|
uint8_t _getSystemStabilityCounter();
|
||||||
|
void _setSystemStabilityCounter(uint8_t counter);
|
||||||
|
|
||||||
|
uint8_t _getSystemResetReason();
|
||||||
|
void _setSystemResetReason(uint8_t reason);
|
||||||
|
|
||||||
|
unsigned char _getCustomResetReason();
|
||||||
|
void _setCustomResetReason(unsigned char reason);
|
||||||
|
|
||||||
|
bool _systemStable;
|
||||||
|
|
||||||
|
bool getSystemCheck();
|
||||||
|
void _systemCheckLoop();
|
||||||
|
void _setSystemCheck(bool stable);
|
||||||
|
|
||||||
|
|
||||||
// load average (0..100)
|
// load average (0..100)
|
||||||
void _calculateLoad();
|
void _calculateLoad();
|
||||||
unsigned short int _load_average;
|
unsigned short int _load_average;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ upload_protocol = espota
|
|||||||
upload_port = ems-esp.local
|
upload_port = ems-esp.local
|
||||||
|
|
||||||
[env:debug]
|
[env:debug]
|
||||||
build_flags = -g -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DCRASH -DTESTS ${common.wifi_settings}
|
build_flags = -g -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DTESTS -DNO_GLOBAL_EEPROM ${common.wifi_settings}
|
||||||
|
|
||||||
[env:clean]
|
[env:clean]
|
||||||
extra_scripts = pre:scripts/clean_fw.py
|
extra_scripts = pre:scripts/clean_fw.py
|
||||||
@@ -42,5 +42,5 @@ build_flags = -g -w
|
|||||||
extra_scripts = pre:scripts/rename_fw.py
|
extra_scripts = pre:scripts/rename_fw.py
|
||||||
|
|
||||||
[env:checkcode]
|
[env:checkcode]
|
||||||
build_flags = -g -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DCRASH -DTESTS
|
build_flags = -g -w
|
||||||
extra_scripts = scripts/checkcode.py
|
extra_scripts = scripts/checkcode.py
|
||||||
|
|||||||
@@ -1,33 +1,43 @@
|
|||||||
>>>stack>>>
|
>>>stack>>>
|
||||||
3ffffdd0: 3ffffe30 3fff43c8 3fff89bc 40211340
|
3ffffd30: 40105346 00000030 0000001e ffffffff
|
||||||
3ffffde0: 3fff89bc 3fff43c8 3fff461c 4022cd7a
|
3ffffd40: 40105928 00000000 60000200 04000002
|
||||||
3ffffdf0: 3ffffe70 402096cb 3fff461c 4022cd68
|
3ffffd50: 3feffe00 fffffeff 00000000 00000000
|
||||||
3ffffe00: 3ffffe30 3fff43c8 3fff89bc 402096dc
|
3ffffd60: 00000003 00000000 0000002d 3ffffe50
|
||||||
3ffffe10: 454d5b20 4f205d4d 52204154 72657365
|
3ffffd70: 00000008 00001008 00000000 00000030
|
||||||
3ffffe20: 00000000 00642520 4025ce70 40209684
|
3ffffd80: 34303936 34343139 3ffe3131 40223f98
|
||||||
3ffffe30: 3ffffe70 3ffffe40 00000008 00000001
|
3ffffd90: 3fff46dc 00000001 3ffec7b9 40223f98
|
||||||
3ffffe40: 00000002 3fff4770 3fff43c8 40246b28
|
3ffffda0: 3fff46dc 0000001c 3fff8b18 3ffffe20
|
||||||
3ffffe50: 3fff89b8 ff000000 00068d0c 4020f650
|
3ffffdb0: 3fff4a0c 0000073d 0000073d 40211340
|
||||||
3ffffe60: 0000001b 00003340 400205e9 4024f545
|
3ffffdc0: 3ffffe20 3fff4488 3fff8afc 40211768
|
||||||
3ffffe70: 4020cd64 3fff4770 3fff43c8 00000001
|
3ffffdd0: 3fff8afc 3fff4488 3fff46dc 4022d182
|
||||||
3ffffe80: 00000002 3fff4770 3fff43c8 4020a640
|
3ffffde0: 3ffffe60 402097ff 3fff46dc 4022d170
|
||||||
3ffffe90: 45455b20 4d4f5250 4545205d 4d4f5250
|
3ffffdf0: 3ffffe20 3fff4488 3fff8afc 40209810
|
||||||
3ffffea0: 63655320 20726f74 6c6f6f70 7a697320
|
3ffffe00: 00000000 400042db 616c4620 52206873
|
||||||
3ffffeb0: 73692065 202c3420 20646e61 75206e69
|
3ffffe10: 40004b31 3ffffe58 00000008 00001000
|
||||||
3ffffec0: 61206573 203a6572 39313031 31303120
|
3ffffe20: 40105934 3ffffe30 00000008 00000000
|
||||||
3ffffed0: 30312038 31203731 20363130 00000000
|
3ffffe30: 40100289 3ffffe50 00000000 3fff482c
|
||||||
3ffffee0: 36313031 00000000 00000000 00000000
|
3ffffe40: 3fff8c18 ff000000 00001008 4020d3cc
|
||||||
3ffffef0: 00000000 00000000 ff000007 4020f5ae
|
3ffffe50: 00000000 00000000 400205e9 40100250
|
||||||
3fffff00: 00000000 00000007 3ffe8304 402274e7
|
3ffffe60: 400201e9 001640ef 3fff4488 00000003
|
||||||
3fffff10: 0000000d 00000001 3fff43c8 3fff46a0
|
3ffffe70: 00000002 3fff4834 3fff4488 4020a9b9
|
||||||
3fffff20: 3fff8c4c 00000001 3fff43c8 4020c5b9
|
3ffffe80: 45455b20 4d4f5250 4545205d 4d4f5250
|
||||||
3fffff30: 3fffdad0 3fff4630 0000000d 40217c8e
|
3ffffe90: 63655320 20726f74 6c6f6f70 7a697320
|
||||||
3fffff40: 3fffdad0 3fff4630 3fff461c 3fff46a0
|
3ffffea0: 73692065 202c3420 20646e61 75206e69
|
||||||
3fffff50: 0000000d 3fff461c 3fff43c8 4020cb89
|
3ffffeb0: 61206573 203a6572 39313031 31303120
|
||||||
3fffff60: 0000000d 3fff4908 3ffe97ac 3fff48ac
|
3ffffec0: 30312038 31203731 20363130 00000000
|
||||||
3fffff70: 3fff43c8 3fff29cc 3fff43b8 3fff48ac
|
3ffffed0: 6f626552 6620746f 206d6f72 6d726574
|
||||||
3fffff80: 3fffdad0 3fff29cc 3fff43c8 4020cc58
|
3ffffee0: 6c616e69 4020f900 00000007 40211584
|
||||||
3fffff90: 3fffdad0 00000000 3fff29cc 40205ccc
|
3ffffef0: 36313031 00000000 00000000 00000000
|
||||||
3fffffa0: 3fffdad0 00000000 3fff487c 4020ebd4
|
3fffff00: 00000000 00000007 3ffe8304 402278ef
|
||||||
3fffffb0: feefeffe feefeffe 3ffe97ac 401006f1
|
3fffff10: 0000000d 00000001 3fff4488 3fff4760
|
||||||
|
3fffff20: 3fff800c 00000001 3fff4488 4020c95d
|
||||||
|
3fffff30: 0000006d 3fff46f0 0000000d 402180b6
|
||||||
|
3fffff40: 0000006d 3fff46f0 3fff46dc 3fff4760
|
||||||
|
3fffff50: 0000000d 3fff46dc 3fff4488 4020cf39
|
||||||
|
3fffff60: 0000000d 3fff49cc 3ffe97b8 3fff4970
|
||||||
|
3fffff70: 3fff4488 3fff2a8c 3fff4478 3fff4970
|
||||||
|
3fffff80: 3fffdad0 3fff2a8c 3fff4488 4020d008
|
||||||
|
3fffff90: 3fffdad0 00000000 3fff2a8c 40205cd4
|
||||||
|
3fffffa0: 3fffdad0 00000000 3fff4940 4020f000
|
||||||
|
3fffffb0: feefeffe feefeffe 3ffe97b8 401006f1
|
||||||
<<<stack<<<
|
<<<stack<<<
|
||||||
@@ -183,7 +183,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() {
|
|||||||
tmp = (1 << UCBRK);
|
tmp = (1 << UCBRK);
|
||||||
USC0(EMSUART_UART) |= (tmp); // set bit
|
USC0(EMSUART_UART) |= (tmp); // set bit
|
||||||
|
|
||||||
if (EMS_Sys_Status.emsTxMode <= 2) { // classic mode
|
if (EMS_Sys_Status.emsTxMode <= 1) { // classic mode and ems+ (0, 1)
|
||||||
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
||||||
} else if (EMS_Sys_Status.emsTxMode == 3) { // junkers mode
|
} else if (EMS_Sys_Status.emsTxMode == 3) { // junkers mode
|
||||||
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
|
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
|
||||||
@@ -238,10 +238,9 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
|||||||
* - <BRK> is detected
|
* - <BRK> is detected
|
||||||
* At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode.
|
* At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ETS_UART_INTR_DISABLE(); // disable rx interrupt
|
ETS_UART_INTR_DISABLE(); // disable rx interrupt
|
||||||
|
|
||||||
// clear Rx status register - https://github.com/proddy/EMS-ESP/issues/103#issuecomment-495605798
|
// clear Rx status register
|
||||||
USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo
|
USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo
|
||||||
emsuart_flush_fifos();
|
emsuart_flush_fifos();
|
||||||
|
|
||||||
@@ -254,9 +253,9 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we got the whole telegram in Rx buffer
|
// we got the whole telegram in the Rx buffer
|
||||||
// on Rx-BRK (bus collision), we simply enable Rx and leave
|
// on Rx-BRK (bus collision), we simply enable Rx and leave it
|
||||||
// otherwise, we send the final Tx-BRK in loopback and enable Rx-INT.
|
// otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT.
|
||||||
// worst case, we'll see an additional Rx-BRK...
|
// worst case, we'll see an additional Rx-BRK...
|
||||||
if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
|
if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
|
||||||
phantomBrk = 1; // tell Rx to expect a phantom BRK
|
phantomBrk = 1; // tell Rx to expect a phantom BRK
|
||||||
@@ -276,7 +275,6 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// w/o flushing the Rx FIFO we will get a trailing \0 from our loopback BRK
|
// w/o flushing the Rx FIFO we will get a trailing \0 from our loopback BRK
|
||||||
// emsuart_flush_fifos(); // flush Rx buffer to be sure
|
|
||||||
ETS_UART_INTR_ENABLE(); // receive anything from FIFO...
|
ETS_UART_INTR_ENABLE(); // receive anything from FIFO...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define APP_NAME "EMS-ESP"
|
#define APP_NAME "EMS-ESP"
|
||||||
#define APP_VERSION "1.8.0b11"
|
#define APP_VERSION "1.8.0b12"
|
||||||
#define APP_HOSTNAME "ems-esp"
|
#define APP_HOSTNAME "ems-esp"
|
||||||
|
|||||||
Reference in New Issue
Block a user