Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
krzychb committed Aug 14, 2016
0 parents commit 06f6c93
Show file tree
Hide file tree
Showing 9 changed files with 901 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
_input
Thumbs.db
502 changes: 502 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

51 changes: 51 additions & 0 deletions examples/SimpleCrash/SimpleCrash.ino
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;
}
}
}

16 changes: 16 additions & 0 deletions keywords.txt
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
15 changes: 15 additions & 0 deletions library.json
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",
]
}
9 changes: 9 additions & 0 deletions library.properties
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
81 changes: 81 additions & 0 deletions readme.md
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)
161 changes: 161 additions & 0 deletions src/EspSaveCrash.cpp
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;
Loading

0 comments on commit 06f6c93

Please sign in to comment.