-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 06f6c93
Showing
9 changed files
with
901 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
_input | ||
Thumbs.db |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#include "EspSaveCrash.h" | ||
|
||
void setup(void) | ||
{ | ||
Serial.begin(115200); | ||
Serial.println(); | ||
Serial.println("SimpleCrash.ino"); | ||
SaveCrash.print(); | ||
|
||
Serial.println(); | ||
Serial.println("Type a letter + <enter>"); | ||
Serial.println("0 : attempt to divide by zero"); | ||
Serial.println("e : attempt to read through a pointer to no object"); | ||
Serial.println("c : clear crash information"); | ||
} | ||
|
||
|
||
void loop(void) | ||
{ | ||
if (Serial.available() > 0) | ||
{ | ||
char inChar = Serial.read(); | ||
switch (inChar) | ||
{ | ||
case '0': | ||
Serial.println("Attempting to divide one by zero ..."); | ||
Serial.println(millis()); | ||
int result; | ||
result = 1 / 0; | ||
Serial.print("Result = "); | ||
Serial.println(result); | ||
break; | ||
case 'e': | ||
Serial.println("Attempting to read through a pointer to no object ..."); | ||
int* nullPointer; | ||
nullPointer = NULL; | ||
// null pointer dereference - read | ||
// attempt to read a value through a null pointer | ||
Serial.print(*nullPointer); | ||
break; | ||
case 'c': | ||
SaveCrash.clear(); | ||
Serial.println("Crash information cleared"); | ||
break; | ||
default: | ||
Serial.printf("%c typed\n", inChar); | ||
break; | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
########################################### | ||
# Syntax Coloring Map For EspSaveCrash | ||
########################################### | ||
|
||
########################################### | ||
# Datatypes (KEYWORD1) | ||
########################################### | ||
|
||
SaveCrash KEYWORD1 | ||
|
||
########################################### | ||
# Methods and Functions (KEYWORD2) | ||
########################################### | ||
|
||
print KEYWORD2 | ||
clear KEYWORD2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "EspSaveCrash", | ||
"keywords": "crash, exception, restart, software WDT, diagnostics", | ||
"description": "Automatically saves exception details and stack trace to flash in case of ESP8266 crash.", | ||
"repository": | ||
{ | ||
"type": "git", | ||
"url": "https://github.com/krzychb/EspSaveCrash.git" | ||
}, | ||
"exclude": "extras", | ||
"frameworks": "arduino", | ||
"platforms": [ | ||
"espressif", | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name=EspSaveCrash | ||
version=1.0.0 | ||
author=Krzysztof Budzynski <[email protected]> | ||
maintainer=Krzysztof Budzynski <[email protected]> | ||
sentence=Automatically saves exception details and stack trace to flash in case of ESP8266 crash. | ||
paragraph=EspSaveCrash is a handy little library that will keep catching and saving crash information to ESP8266 flash in case it fails due to exception or software WDT. For more details please visit https://github.com/krzychb/ESPSaveCrash. | ||
category=Other | ||
url=https://github.com/krzychb/EspSaveCrash | ||
architectures=esp8266 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# EspSaveCrash | ||
|
||
Save exception details and stack trace anytime and anywhere the ESP8266 crashes. Implement it in your sketch in two simple steps. | ||
|
||
|
||
## Overview | ||
|
||
Do you face random crashes of ESP8266? Is it difficult to capture diagnostic information because module is in some remote location? Or maybe module crashes after several hours of operation and it is inconvenient to keep serial monitor open until it fails? | ||
|
||
EspSaveCrash is a handy little library that will keep automatically catching and saving crash information to ESP8266 flash in case it fails due to exception or software WDT. You will then be able to analyze the crash log and decode the stack trace using [ESP Exception Decoder](https://github.com/me-no-dev/EspExceptionDecoder). | ||
|
||
You will implement it in your sketch in two simple steps. | ||
|
||
1. Include the library | ||
```cpp | ||
#include "EspSaveCrash.h" | ||
``` | ||
|
||
2. Print out saved crash details | ||
```cpp | ||
SaveCrash.print(); | ||
``` | ||
|
||
|
||
## Use it With | ||
|
||
* Any ESP8266 module programmed using [esp8266 / Arduino](https://github.com/esp8266/Arduino) core. | ||
|
||
|
||
## Functions | ||
|
||
* Registers callback to automatically capture and save crash details | ||
* Captures several crashes to save them to ESP8266's flash | ||
* Captures exceptions and software WDT restarts (not hardware WDT) | ||
* The following information is saved: | ||
* Time of crash using the ESP's milliseconds counter | ||
* Reason of restart - see [rst cause](https://github.com/esp8266/Arduino/blob/master/doc/boards.md#rst-cause) | ||
* Exception cause - see [EXCCAUSE](https://github.com/esp8266/Arduino/blob/master/doc/exception_causes.md#exception-causes-exccause) | ||
* `epc1`, `epc2`, `epc3`, `excvaddr` and `depc` | ||
* Stack trace in format you can analyze with [ESP Exception Decoder](https://github.com/me-no-dev/EspExceptionDecoder) | ||
* Automatically arms itself to operate after each restart of power up of module | ||
* Saves crash details within defined flash space and then stops | ||
|
||
|
||
## Tested With | ||
|
||
### Arduino Core | ||
|
||
* [Esp8266 / Arduino](https://github.com/esp8266/Arduino) core [2.3.0](https://github.com/esp8266/Arduino/releases/tag/2.3.0) for Arduino IDE and Visual Micro | ||
* [framework-arduinoespressif](http://platformio.org/platforms/espressif) version 13 for PlatformIO | ||
|
||
|
||
### Programming Environment | ||
|
||
* [Arduino IDE](https://www.arduino.cc/en/Main/Software) 1.6.9 portable version running on Windows 7 x64 | ||
* [PlatformIO IDE](http://platformio.org/platformio-ide) 1.3.0 CLI 2.11.0 running on Windows 7 x64 | ||
* [Visual Micro](http://www.visualmicro.com/) 1606.17.10 with Visual Studio Community 2015 running on Windows 7 x64 | ||
|
||
|
||
## Contribute | ||
|
||
Feel free to contribute to the project in any way you like! | ||
|
||
If you find any issues with code or descriptions please report them using *Issues* tab above. | ||
|
||
|
||
## Author | ||
|
||
krzychb | ||
|
||
|
||
## Credits | ||
|
||
* Preparation of this library has been inspired by issue [#1152](https://github.com/esp8266/Arduino/issues/1152) in [esp8266 / Arduono](https://github.com/esp8266/Arduino) repository. | ||
* Development was possible thanks to [Ivan Grokhotkov](https://twitter.com/i_grr), who clarified how to register a crash callback and suggested to save crash information on flash. | ||
* Actual implementation of library has been done thanks to [djoele](https://github.com/djoele) who provided first working code and suggested to convert it into general functionality. | ||
|
||
|
||
## License | ||
|
||
[GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999](LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
#include "EspSaveCrash.h" | ||
|
||
|
||
extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, 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_SPACE_SIZE); | ||
|
||
byte crashCounter = EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_COUNTER); | ||
int16_t writeFrom; | ||
if(crashCounter == 0) | ||
{ | ||
writeFrom = SAVE_CRASH_DATA_SETS; | ||
} | ||
else | ||
{ | ||
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_WRITE_FROM, writeFrom); | ||
} | ||
|
||
// is there free EEPROM space avialable to save data for this crash? | ||
if (writeFrom + SAVE_CRASH_STACK_TRACE > SAVE_CRASH_SPACE_SIZE) | ||
{ | ||
return; | ||
} | ||
|
||
// increment crash counter and write it to EEPROM | ||
EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_COUNTER, ++crashCounter); | ||
|
||
// now address EEPROM contents including SAVE_CRASH_EEPROM_OFFSET | ||
writeFrom += SAVE_CRASH_EEPROM_OFFSET; | ||
|
||
// write crash time to EEPROM | ||
uint32_t crashTime = millis(); | ||
EEPROM.put(writeFrom + SAVE_CRASH_CRASH_TIME, crashTime); | ||
|
||
// write reset info to EEPROM | ||
EEPROM.write(writeFrom + SAVE_CRASH_RESTART_REASON, rst_info->reason); | ||
EEPROM.write(writeFrom + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause); | ||
|
||
// write epc1, epc2, epc3, excvaddr and depc to EEPROM | ||
EEPROM.put(writeFrom + SAVE_CRASH_EPC1, rst_info->epc1); | ||
EEPROM.put(writeFrom + SAVE_CRASH_EPC2, rst_info->epc2); | ||
EEPROM.put(writeFrom + SAVE_CRASH_EPC3, rst_info->epc3); | ||
EEPROM.put(writeFrom + SAVE_CRASH_EXCVADDR, rst_info->excvaddr); | ||
EEPROM.put(writeFrom + SAVE_CRASH_DEPC, rst_info->depc); | ||
|
||
// write stack start and end address to EEPROM | ||
EEPROM.put(writeFrom + SAVE_CRASH_STACK_START, stack); | ||
EEPROM.put(writeFrom + SAVE_CRASH_STACK_END, stack_end); | ||
|
||
// write stack trace to EEPROM | ||
int16_t currentAddress = writeFrom + SAVE_CRASH_STACK_TRACE; | ||
for (uint32_t iAddress = stack; iAddress < stack_end; iAddress++) | ||
{ | ||
byte* byteValue = (byte*) iAddress; | ||
EEPROM.write(currentAddress++, *byteValue); | ||
if (currentAddress - SAVE_CRASH_EEPROM_OFFSET > SAVE_CRASH_SPACE_SIZE) | ||
{ | ||
// ToDo: flag an incomplete stack trace written to EEPROM! | ||
break; | ||
} | ||
} | ||
// now exclude SAVE_CRASH_EEPROM_OFFSET from address written to EEPROM | ||
currentAddress -= SAVE_CRASH_EEPROM_OFFSET; | ||
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_WRITE_FROM, currentAddress); | ||
|
||
EEPROM.commit(); | ||
} | ||
|
||
|
||
EspSaveCrash::EspSaveCrash(void) {} | ||
|
||
|
||
void EspSaveCrash::clear(void) | ||
{ | ||
// 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_SPACE_SIZE); | ||
// clear the crash counter | ||
EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_COUNTER, 0); | ||
EEPROM.end(); | ||
} | ||
|
||
|
||
void EspSaveCrash::print(void) | ||
{ | ||
// 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_SPACE_SIZE); | ||
|
||
byte crashCounter = EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_COUNTER); | ||
if (crashCounter == 0) | ||
{ | ||
Serial.println("No any crashes saved"); | ||
return; | ||
} | ||
|
||
Serial.println("Crash information recovered from EEPROM"); | ||
int16_t readFrom = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DATA_SETS; | ||
for (byte k = 0; k < crashCounter; k++) | ||
{ | ||
uint32_t crashTime; | ||
EEPROM.get(readFrom + SAVE_CRASH_CRASH_TIME, crashTime); | ||
Serial.printf("Crash # %d at %d ms\n", k + 1, crashTime); | ||
|
||
Serial.printf("Reason of restart: %d\n", EEPROM.read(readFrom + SAVE_CRASH_RESTART_REASON)); | ||
Serial.printf("Exception cause: %d\n", EEPROM.read(readFrom + SAVE_CRASH_EXCEPTION_CAUSE)); | ||
|
||
uint32_t epc1, epc2, epc3, excvaddr, depc; | ||
EEPROM.get(readFrom + SAVE_CRASH_EPC1, epc1); | ||
EEPROM.get(readFrom + SAVE_CRASH_EPC2, epc2); | ||
EEPROM.get(readFrom + SAVE_CRASH_EPC3, epc3); | ||
EEPROM.get(readFrom + SAVE_CRASH_EXCVADDR, excvaddr); | ||
EEPROM.get(readFrom + SAVE_CRASH_DEPC, depc); | ||
Serial.printf("epc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n", epc1, epc2, epc3, excvaddr, depc); | ||
|
||
uint32_t stackStart, stackEnd; | ||
EEPROM.get(readFrom + SAVE_CRASH_STACK_START, stackStart); | ||
EEPROM.get(readFrom + SAVE_CRASH_STACK_END, stackEnd); | ||
Serial.println(">>>stack>>>"); | ||
int16_t currentAddress = readFrom + SAVE_CRASH_STACK_TRACE; | ||
int16_t stackLength = stackEnd - stackStart; | ||
uint32_t stackTrace; | ||
for (int16_t i = 0; i < stackLength; i += 0x10) | ||
{ | ||
Serial.printf("%08x: ", stackStart + i); | ||
for (byte j = 0; j < 4; j++) | ||
{ | ||
EEPROM.get(currentAddress, stackTrace); | ||
Serial.printf("%08x ", stackTrace); | ||
currentAddress += 4; | ||
if (currentAddress - SAVE_CRASH_EEPROM_OFFSET > SAVE_CRASH_SPACE_SIZE) | ||
{ | ||
Serial.println("\nIncomplete stack trace saved!"); | ||
break; | ||
} | ||
} | ||
Serial.println(); | ||
} | ||
Serial.println("<<<stack<<<"); | ||
readFrom = readFrom + SAVE_CRASH_STACK_TRACE + stackLength; | ||
} | ||
int16_t writeFrom; | ||
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_WRITE_FROM, writeFrom); | ||
EEPROM.end(); | ||
|
||
// is there free EEPROM space avialable to save data for next crash? | ||
if (writeFrom + SAVE_CRASH_STACK_TRACE > SAVE_CRASH_SPACE_SIZE) | ||
{ | ||
Serial.println("No more EEPROM space available to save crash information!"); | ||
} | ||
else | ||
{ | ||
Serial.printf("EEPROM space available: 0x%04x bytes\n", SAVE_CRASH_SPACE_SIZE - writeFrom); | ||
} | ||
} | ||
|
||
|
||
EspSaveCrash SaveCrash; |
Oops, something went wrong.