diff --git a/debug.py b/debug.py index 5c8a66030..c54d05902 100644 --- a/debug.py +++ b/debug.py @@ -2,9 +2,6 @@ from subprocess import call import os -# python decoder.py -p ESP8266 -t C:\Users\Paul\.platformio\packages\toolchain-xtensa -e .pioenvs/nodemcuv2/firmware.elf stackdmp.txt -# java -jar .\EspStackTraceDecoder.jar C:\Users\Paul\.platformio\packages\toolchain-xtensa\bin\xtensa-lx106-elf-addr2line.exe .pioenvs/nodemcuv2/firmware.elf stackdmp.txt - # example stackdmp.txt would contain text like below copied & pasted from a 'crash dump' command # >>>stack>>> # 3fffff20: 3fff32f0 00000003 3fff3028 402101b2 @@ -19,4 +16,7 @@ import os # 3fffffb0: feefeffe feefeffe 3ffe8558 40100b01 # <<")); + SerialAndTelnet.println(FPSTR("* crash ")); SerialAndTelnet.println(FPSTR("* set")); SerialAndTelnet.println(FPSTR("* set wifi [ssid] [password]")); SerialAndTelnet.println(FPSTR("* set [value]")); @@ -736,8 +771,10 @@ void MyESP::_telnetCommand(char * commandLine) { } else if ((strcmp(cmd, "test") == 0) && (wc == 3)) { char * value = _telnet_readWord(); crashTest(atoi(value)); + } else if (strcmp(cmd, "info") == 0) { + crashInfo(); } - return; + return; // don't call custom command line callback } // call callback function @@ -1171,47 +1208,38 @@ int MyESP::getWifiQuality() { * It should be kept quick / consise to be able to execute before hardware wdt may kick in */ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack_start, uint32_t stack_end) { - // Note that 'EEPROM.begin' method is reserving a RAM buffer - // The buffer size is SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_SPACE_SIZE - EEPROM.begin(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EEPROM_SIZE); - // write crash time to EEPROM uint32_t crash_time = millis(); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); // write reset info to EEPROM - EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON, rst_info->reason); - EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause); + EEPROMr.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON, rst_info->reason); + EEPROMr.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause); // write epc1, epc2, epc3, excvaddr and depc to EEPROM - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, rst_info->epc1); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, rst_info->epc2); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, rst_info->epc3); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, rst_info->excvaddr); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, rst_info->depc); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, rst_info->epc1); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, rst_info->epc2); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, rst_info->epc3); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, rst_info->excvaddr); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, rst_info->depc); // write stack start and end address to EEPROM - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); - - // starting address - const uint16_t settings_start = SPI_FLASH_SEC_SIZE - SAVE_CRASH_EEPROM_SIZE - 0x10; + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); // write stack trace to EEPROM and avoid overwriting settings int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE; for (uint32_t i = stack_start; i < stack_end; i++) { - if (current_address >= settings_start) - break; byte * byteValue = (byte *)i; - EEPROM.write(current_address++, *byteValue); + EEPROMr.write(current_address++, *byteValue); } - EEPROM.commit(); + EEPROMr.commit(); } void MyESP::crashTest(uint8_t t) { if (t == 1) { - myDebug("Attempting to divide by zero ..."); + myDebug("[CRASH] Attempting to divide by zero ..."); int result, zero; zero = 0; result = 1 / zero; @@ -1219,7 +1247,7 @@ void MyESP::crashTest(uint8_t t) { } if (t == 2) { - myDebug("Attempting to read through a pointer to no object ..."); + myDebug("[CRASH] Attempting to read through a pointer to no object ..."); int * nullPointer; nullPointer = NULL; // null pointer dereference - read @@ -1228,7 +1256,7 @@ void MyESP::crashTest(uint8_t t) { } if (t == 3) { - Serial.printf("Crashing with hardware WDT (%ld ms) ...\n", millis()); + Serial.printf("[CRASH] Crashing with hardware WDT (%ld ms) ...\n", millis()); ESP.wdtDisable(); while (true) { // stay in an infinite loop doing nothing @@ -1241,7 +1269,7 @@ void MyESP::crashTest(uint8_t t) { } if (t == 4) { - Serial.printf("Crashing with software WDT (%ld ms) ...\n", millis()); + Serial.printf("[CRASH] Crashing with software WDT (%ld ms) ...\n", millis()); while (true) { // stay in an infinite loop doing nothing // this way other process can not be executed @@ -1253,43 +1281,49 @@ void MyESP::crashTest(uint8_t t) { * Clears crash info */ void MyESP::crashClear() { - EEPROM.begin(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EEPROM_SIZE); - + myDebug_P(PSTR("[CRASH] Clearing crash dump")); uint32_t crash_time = 0xFFFFFFFF; - EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); - EEPROM.commit(); + EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); + EEPROMr.commit(); +} + +/* Crash info */ +void MyESP::crashInfo() { + myDebug_P(PSTR("[EEPROM] Sector pool size: %u"), EEPROMr.size()); + myDebug_P(PSTR("[EEPROM] Sectors in use : ")); + for (uint32_t i = 0; i < EEPROMr.size(); i++) { + myDebug_P(PSTR("%d"), EEPROMr.base() - i); + } } /** * Print out crash information that has been previously saved in EEPROM */ void MyESP::crashDump() { - EEPROM.begin(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EEPROM_SIZE); - uint32_t crash_time; - EEPROM.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)) { myDebug_P(PSTR("[CRASH] No crash info")); return; } myDebug_P(PSTR("[CRASH] Latest crash was at %lu ms after boot"), crash_time); - myDebug_P(PSTR("[CRASH] Reason of restart: %u"), EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON)); - myDebug_P(PSTR("[CRASH] Exception cause: %u"), EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE)); + myDebug_P(PSTR("[CRASH] Reason of restart: %u"), EEPROMr.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON)); + myDebug_P(PSTR("[CRASH] Exception cause: %u"), EEPROMr.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE)); uint32_t epc1, epc2, epc3, excvaddr, depc; - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, epc1); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, epc2); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, epc1); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, epc2); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc); myDebug_P(PSTR("[CRASH] epc1=0x%08x epc2=0x%08x epc3=0x%08x"), epc1, epc2, epc3); myDebug_P(PSTR("[CRASH] excvaddr=0x%08x depc=0x%08x"), excvaddr, depc); uint32_t stack_start, stack_end; - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); - EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start); + EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end); myDebug_P(PSTR("[CRASH] sp=0x%08x end=0x%08x"), stack_start, stack_end); @@ -1303,7 +1337,7 @@ void MyESP::crashDump() { for (int16_t i = 0; i < stack_len; i += 0x10) { SerialAndTelnet.printf("%08x: ", stack_start + i); for (byte j = 0; j < 4; j++) { - EEPROM.get(current_address, stack_trace); + EEPROMr.get(current_address, stack_trace); SerialAndTelnet.printf("%08x ", stack_trace); current_address += 4; } @@ -1313,13 +1347,16 @@ void MyESP::crashDump() { } #else void MyESP::crashTest(uint8_t t) { - myDebug("[CRASH] disabled or not supported"); + myDebug("[CRASH] disabled or not supported. Compile with -DCRASH"); } void MyESP::crashClear() { - myDebug("[CRASH] disabled or not supported"); + myDebug("[CRASH] disabled or not supported. Compile with -DCRASH"); } void MyESP::crashDump() { - myDebug("[CRASH] disabled or not supported"); + myDebug("[CRASH] disabled or not supported. Compile with -DCRASH"); +} +void MyESP::crashInfo() { + myDebug("[CRASH] disabled or not supported. Compile with -DCRASH"); } #endif @@ -1329,7 +1366,8 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _app_name = strdup(app_name); _app_version = strdup(app_version); - _telnet_setup(); // Telnet setup + _telnet_setup(); // Telnet setup, does first to set Serial + _eeprom_setup(); // set up eeprom for storing crash data _fs_setup(); // SPIFFS setup, do this first to get values _wifi_setup(); // WIFI setup _ota_setup(); diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 19d6ec709..2ac6ff4b2 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.6b" +#define MYESP_VERSION "1.1.6c" #include #include @@ -20,9 +20,9 @@ #include // modified from https://github.com/yasheena/telnetspy #ifdef CRASH -#include "EEPROM.h" +#include extern "C" { - void custom_crash_callback(struct rst_info*, uint32_t, uint32_t); +void custom_crash_callback(struct rst_info *, uint32_t, uint32_t); } #endif @@ -81,19 +81,36 @@ extern "C" { #define SPIFFS_MAXSIZE 500 // https://arduinojson.org/v6/assistant/ // CRASH -#define SAVE_CRASH_EEPROM_OFFSET 0x0100 // initial address for crash data -#define SAVE_CRASH_EEPROM_SIZE 0x0200 // size -#define SAVE_CRASH_CRASH_TIME 0x00 // 4 bytes -#define SAVE_CRASH_RESTART_REASON 0x04 // 1 byte -#define SAVE_CRASH_EXCEPTION_CAUSE 0x05 // 1 byte -#define SAVE_CRASH_EPC1 0x06 // 4 bytes -#define SAVE_CRASH_EPC2 0x0A // 4 bytes -#define SAVE_CRASH_EPC3 0x0E // 4 bytes -#define SAVE_CRASH_EXCVADDR 0x12 // 4 bytes -#define SAVE_CRASH_DEPC 0x16 // 4 bytes -#define SAVE_CRASH_STACK_START 0x1A // 4 bytes -#define SAVE_CRASH_STACK_END 0x1E // 4 bytes -#define SAVE_CRASH_STACK_TRACE 0x22 // variable +#define EEPROM_ROTATE_DATA 11 // Reserved for the EEPROM_ROTATE library (3 bytes) +/** + * Structure of the single crash data set + * + * 1. Crash time + * 2. Restart reason + * 3. Exception cause + * 4. epc1 + * 5. epc2 + * 6. epc3 + * 7. excvaddr + * 8. depc + * 9. adress of stack start + * 10. adress of stack end + * 11. stack trace bytes + * ... + */ +#define SAVE_CRASH_EEPROM_OFFSET 0x0100 // initial address for crash data +#define SAVE_CRASH_CRASH_TIME 0x00 // 4 bytes +#define SAVE_CRASH_RESTART_REASON 0x04 // 1 byte +#define SAVE_CRASH_EXCEPTION_CAUSE 0x05 // 1 byte +#define SAVE_CRASH_EPC1 0x06 // 4 bytes +#define SAVE_CRASH_EPC2 0x0A // 4 bytes +#define SAVE_CRASH_EPC3 0x0E // 4 bytes +#define SAVE_CRASH_EXCVADDR 0x12 // 4 bytes +#define SAVE_CRASH_DEPC 0x16 // 4 bytes +#define SAVE_CRASH_STACK_START 0x1A // 4 bytes +#define SAVE_CRASH_STACK_END 0x1E // 4 bytes +#define SAVE_CRASH_STACK_TRACE 0x22 // variable + typedef struct { char key[40]; @@ -161,6 +178,7 @@ class MyESP { void crashClear(); void crashDump(); void crashTest(uint8_t t); + void crashInfo(); // general void end(); @@ -211,6 +229,9 @@ class MyESP { void _ota_setup(); void _OTACallback(); + // crash + void _eeprom_setup(); + // telnet & debug TelnetSpy SerialAndTelnet; void _telnetConnected();