Skip to content

Commit

Permalink
Add save call stack in RTC memory in case of crash
Browse files Browse the repository at this point in the history
Add save call stack in RTC memory in case of crash, command ``Status 12`` to dump the stack (#7114, #5883)
  • Loading branch information
arendst committed Dec 7, 2019
1 parent 2686ccb commit f3a5b03
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 1 deletion.
1 change: 1 addition & 0 deletions tasmota/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### 7.1.2.2 20191206

- Add command ``SerialConfig 0..23`` or ``SerialConfig 8N1`` to select Serial Config (#7108)
- Add save call stack in RTC memory in case of crash, command ``Status 12`` to dump the stack

### 7.1.2.1 20191206

Expand Down
1 change: 1 addition & 0 deletions tasmota/i18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
#define D_STATUS9_MARGIN "PTH"
#define D_STATUS10_SENSOR "SNS"
#define D_STATUS11_STATUS "STS"
#define D_STATUS12_STATUS "STK"
#define D_CMND_STATE "State"
#define D_CMND_POWER "Power"
#define D_CMND_FANSPEED "FanSpeed"
Expand Down
10 changes: 10 additions & 0 deletions tasmota/support_command.ino
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,13 @@ void CmndStatus(void)
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "11"));
}

if ((0 == payload) || (12 == payload)) {
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS12_STATUS "\":"));
CrashDump();
ResponseJsonEnd();
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "12"));
}

#ifdef USE_SCRIPT_STATUS
if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">U",2,mqtt_data);
#endif
Expand Down Expand Up @@ -564,6 +571,9 @@ void CmndRestart(void)
restart_flag = 2;
ResponseCmndChar(D_JSON_RESTARTING);
break;
case -1:
CmndCrash(); // force a crash
break;
case 99:
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
EspRestart();
Expand Down
78 changes: 78 additions & 0 deletions tasmota/support_crash_recorder.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
support_crash_recorder.ino - record the call stack in RTC in cas of crash
Copyright (C) 2019 Stephan Hadinger, Theo Arends,
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

const uint32_t dump_max_len = 63; // dump only 64 call addresses

/**
* Save crash information in RTC memory
* This function is called automatically if ESP8266 suffers an exception
* 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, uint32_t stack_end ) {
uint32_t addr_written = 0; // how many addresses have we already written in RTC
uint32_t value; // 4 bytes buffer to write to RTC

for (uint32_t i = stack; i < stack_end; i += 4) {
value = *((uint32_t*) i); // load value from stack
if ((value >= 0x40000000) && (value < 0x40300000)) { // keep only addresses in code area
ESP.rtcUserMemoryWrite(addr_written, (uint32_t*)&value, sizeof(value));
addr_written++;
if (addr_written >= dump_max_len) { break; } // we store only 63 addresses
}
}
// fill the rest of RTC with the amount of addresses
value = addr_written;
while (addr_written < dump_max_len +1) {
ESP.rtcUserMemoryWrite(addr_written++, (uint32_t*)&value, sizeof(value));
}
}

// Generate a crash to test the crash recorder
void CmndCrash(void)
{
volatile uint32_t dummy;
dummy = *((uint32_t*) 0x00000000);
}

// Clear the RTC dump counter when we do a normal reboot, this avoids garbage data to stay in RTC
void CrashDumpClear(void) {
uint32_t value = 0;
ESP.rtcUserMemoryWrite(dump_max_len, (uint32_t*)&value, sizeof(value));
}

/*********************************************************************************************\
* CmndCrashDump - dump the crash history - called by `Status 12`
\*********************************************************************************************/
void CrashDump(void)
{
ResponseAppend_P(PSTR("{\"call_chain\":["));

uint32_t value;
ESP.rtcUserMemoryRead(dump_max_len, (uint32_t*)&value, sizeof(value));
uint32_t count = value & 0x3F;

for (uint32_t i = 0; i < count; i++) {
ESP.rtcUserMemoryRead(i, (uint32_t*)&value, sizeof(value));
if ((value >= 0x40000000) && (value < 0x40300000)) {
if (i > 0) { ResponseAppend_P(PSTR(",")); }
ResponseAppend_P(PSTR("\"%08x\""), value);
}
}
ResponseAppend_P(PSTR("]}"));
}
1 change: 1 addition & 0 deletions tasmota/support_wifi.ino
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ void WifiShutdown(void)
void EspRestart(void)
{
WifiShutdown();
CrashDumpClear(); // Clear the stack dump in RTC
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP.reset();
}
2 changes: 1 addition & 1 deletion tasmota/tasmota.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ const uint32_t SOFT_BAUDRATE = 9600; // Default software serial baudrate
const uint32_t APP_BAUDRATE = 115200; // Default serial baudrate
const uint32_t SERIAL_POLLING = 100; // Serial receive polling in ms
const uint32_t ZIGBEE_POLLING = 100; // Serial receive polling in ms
const uint8_t MAX_STATUS = 11; // Max number of status lines
const uint8_t MAX_STATUS = 12; // Max number of status lines

const uint32_t START_VALID_TIME = 1451602800; // Time is synced and after 2016-01-01

Expand Down

0 comments on commit f3a5b03

Please sign in to comment.