added storing crash in eeprom so can analyze dump

This commit is contained in:
proddy
2019-03-10 22:19:51 +01:00
parent 18ee7cca84
commit 5b0dcc9b22
4 changed files with 203 additions and 24 deletions

View File

@@ -164,6 +164,8 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) {
if (_wifi_callback) {
_wifi_callback();
}
jw.enableAPFallback(false); // Disable AP mode after initial connect was succesfull. Thanks @JewelZB
}
if (code == MESSAGE_ACCESSPOINT_CREATED) {
@@ -289,10 +291,7 @@ void MyESP::_mqtt_setup() {
//mqttClient.onPublish([this](uint16_t packetId) { myDebug_P(PSTR("[MQTT] Publish ACK for PID %d"), packetId); });
mqttClient.onMessage(
[this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
_mqttOnMessage(topic, payload, len);
});
mqttClient.onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { _mqttOnMessage(topic, payload, len); });
}
// WiFI setup
@@ -414,7 +413,6 @@ void MyESP::_printBuildTime(unsigned long unix) {
unix /= 60; /* Go to hours */
uint8_t Hours = unix % 24; /* Get hours */
unix /= 24; /* Go to days */
uint8_t WeekDay = (unix + 3) % 7 + 1; /* Get week day, monday is first day */
uint16_t year = 1970; /* Process year */
while (1) {
@@ -470,10 +468,7 @@ void MyESP::_consoleShowHelp() {
#else
String hostname = WiFi.hostname();
#endif
SerialAndTelnet.printf("* Hostname: %s IP: %s MAC: %s",
hostname.c_str(),
WiFi.localIP().toString().c_str(),
WiFi.macAddress().c_str());
SerialAndTelnet.printf("* Hostname: %s IP: %s MAC: %s", hostname.c_str(), WiFi.localIP().toString().c_str(), WiFi.macAddress().c_str());
#ifdef ARDUINO_BOARD
SerialAndTelnet.printf(" Board: %s", ARDUINO_BOARD);
#endif
@@ -501,6 +496,7 @@ void MyESP::_consoleShowHelp() {
SerialAndTelnet.println(FPSTR("* Commands:"));
SerialAndTelnet.println(FPSTR("* ?=help, CTRL-D=quit"));
SerialAndTelnet.println(FPSTR("* reboot"));
SerialAndTelnet.println(FPSTR("* crash <dump | clear | test [n]>"));
SerialAndTelnet.println(FPSTR("* set"));
SerialAndTelnet.println(FPSTR("* set wifi [ssid] [password]"));
SerialAndTelnet.println(FPSTR("* set <mqtt_host | mqtt_username | mqtt_password> [value]"));
@@ -724,6 +720,20 @@ void MyESP::_telnetCommand(char * commandLine) {
resetESP();
}
// crash command
if ((strcmp(ptrToCommandName, "crash") == 0) && (wc >= 2)) {
char * cmd = _telnet_readWord();
if (strcmp(cmd, "dump") == 0) {
crashDump();
} else if (strcmp(cmd, "clear") == 0) {
crashClear();
} else if ((strcmp(cmd, "test") == 0) && (wc == 3) ) {
char * value = _telnet_readWord();
crashTest(atoi(value));
}
return;
}
// call callback function
(_telnetcommand_callback)(wc, commandLine);
}
@@ -854,17 +864,7 @@ void MyESP::setWIFI(const char * wifi_ssid, const char * wifi_password, wifi_cal
}
// init MQTT settings
void MyESP::setMQTT(const char * mqtt_host,
const char * mqtt_username,
const char * mqtt_password,
const char * mqtt_base,
unsigned long mqtt_keepalive,
unsigned char mqtt_qos,
bool mqtt_retain,
const char * mqtt_will_topic,
const char * mqtt_will_online_payload,
const char * mqtt_will_offline_payload,
mqtt_callback_f callback) {
void MyESP::setMQTT(const char * mqtt_host, const char * mqtt_username, const char * mqtt_password, const char * mqtt_base, unsigned long mqtt_keepalive, unsigned char mqtt_qos, bool mqtt_retain, const char * mqtt_will_topic, const char * mqtt_will_online_payload, const char * mqtt_will_offline_payload, mqtt_callback_f callback) {
// can be empty
if (!mqtt_host || *mqtt_host == 0x00) {
_mqtt_host = NULL;
@@ -1108,6 +1108,11 @@ void MyESP::_calculateLoad() {
}
}
// returns true is MQTT is alive
bool MyESP::isMQTTConnected() {
return mqttClient.connected();
}
// return true if wifi is connected
// WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
// WL_IDLE_STATUS = 0,
@@ -1143,7 +1148,155 @@ int MyESP::getWifiQuality() {
return 2 * (dBm + 100);
}
// register new instance
/**
* Save crash information in EEPROM
* 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_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);
// 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);
// 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);
// 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;
// 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);
}
EEPROM.commit();
}
void MyESP::crashTest(uint8_t t) {
if (t == 1) {
myDebug("Attempting to divide by zero ...");
int result, zero;
zero = 0;
result = 1 / zero;
myDebug("Result = %d", result);
}
if (t == 2) {
myDebug("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.println(*nullPointer);
}
if (t == 3) {
Serial.printf("Crashing with hardware WDT (%ld ms) ...\n", millis());
ESP.wdtDisable();
while (true) {
// stay in an infinite loop doing nothing
// this way other process can not be executed
//
// Note:
// Hardware wdt kicks in if software wdt is unable to perfrom
// Nothing will be saved in EEPROM for the hardware wdt
}
}
if (t == 4) {
Serial.printf("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
}
}
}
/**
* Clears crash info
*/
void MyESP::crashClear() {
EEPROM.begin(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EEPROM_SIZE);
uint32_t crash_time = 0xFFFFFFFF;
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
EEPROM.commit();
}
/**
* 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);
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));
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);
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);
myDebug_P(PSTR("[CRASH] sp=0x%08x end=0x%08x"), stack_start, stack_end);
int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE;
int16_t stack_len = stack_end - stack_start;
uint32_t stack_trace;
myDebug(">>>stack>>>");
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);
SerialAndTelnet.printf("%08x ", stack_trace);
current_address += 4;
}
SerialAndTelnet.println();
}
myDebug("<<<stack<<<");
}
// setup MyESP
void MyESP::begin(const char * app_hostname, const char * app_name, const char * app_version) {
_app_hostname = strdup(app_hostname);
_app_name = strdup(app_name);

View File

@@ -9,7 +9,7 @@
#ifndef MyEMS_h
#define MyEMS_h
#define MYESP_VERSION "1.1.5"
#define MYESP_VERSION "1.1.6b"
#include <ArduinoJson.h>
#include <ArduinoOTA.h>
@@ -19,6 +19,11 @@
#include <JustWifi.h> // https://github.com/xoseperez/justwifi
#include <TelnetSpy.h> // modified from https://github.com/yasheena/telnetspy
#include "EEPROM.h"
extern "C" {
void custom_crash_callback(struct rst_info*, uint32_t, uint32_t);
}
#if defined(ARDUINO_ARCH_ESP32)
//#include <ESPmDNS.h>
#include <SPIFFS.h> // added for ESP32
@@ -73,6 +78,21 @@
// SPIFFS
#define SPIFFS_MAXSIZE 500 // https://arduinojson.org/v5/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
typedef struct {
char key[40];
char description[100];
@@ -106,6 +126,7 @@ class MyESP {
bool isWifiConnected();
// mqtt
bool isMQTTConnected();
void mqttSubscribe(const char * topic);
void mqttUnsubscribe(const char * topic);
void mqttPublish(const char * topic, const char * payload);
@@ -134,6 +155,11 @@ class MyESP {
void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback);
bool fs_saveConfig();
// CRASH
void crashClear();
void crashDump();
void crashTest(uint8_t t);
// general
void end();
void loop();

View File

@@ -993,7 +993,7 @@ void initEMSESP() {
// call PublishValues without forcing, so using CRC to see if we really need to publish
void do_publishValues() {
// don't publish if we're not connected to the EMS bus
if ((ems_getBusConnected()) && (!myESP.getUseSerial())) {
if ((ems_getBusConnected()) && (!myESP.getUseSerial()) && myESP.isMQTTConnected() ) {
publishValues(false);
}
}

View File

@@ -1508,7 +1508,7 @@ void ems_printAllTypes() {
*/
void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh) {
// if not a valid type of boiler is not accessible then quits
if (type == EMS_ID_NONE) {
if ( (type == EMS_ID_NONE) || (dest == EMS_ID_NONE) ) {
return;
}