mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-11 02:34:29 +05:00
feat: added crash recorder and ability to save dump
This commit is contained in:
@@ -10,7 +10,7 @@ public:
|
|||||||
free(this->buffer);
|
free(this->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send(int code, const char* contentType, JsonDocument& content) {
|
void send(int code, const char* contentType, JsonDocument& content, bool pretty = false) {
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
if (!this->webServer->chunkedResponseModeStart(code, contentType)) {
|
if (!this->webServer->chunkedResponseModeStart(code, contentType)) {
|
||||||
this->webServer->send(505, F("text/html"), F("HTTP1.1 required"));
|
this->webServer->send(505, F("text/html"), F("HTTP1.1 required"));
|
||||||
@@ -24,7 +24,13 @@ public:
|
|||||||
this->webServer->send(code, contentType, emptyString);
|
this->webServer->send(code, contentType, emptyString);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
serializeJson(content, *this);
|
if (pretty) {
|
||||||
|
serializeJsonPretty(content, *this);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
serializeJson(content, *this);
|
||||||
|
}
|
||||||
|
|
||||||
this->flush();
|
this->flush();
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ lib_deps =
|
|||||||
gyverlibs/GyverBlinker@^1.1.1
|
gyverlibs/GyverBlinker@^1.1.1
|
||||||
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg
|
||||||
laxilef/TinyLogger@^1.1.1
|
laxilef/TinyLogger@^1.1.1
|
||||||
|
build_type = ${secrets.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||||
;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||||
@@ -67,6 +68,7 @@ lib_deps =
|
|||||||
lib_ignore =
|
lib_ignore =
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
post:tools/build.py
|
post:tools/build.py
|
||||||
|
build_type = ${env.build_type}
|
||||||
build_flags = ${env.build_flags}
|
build_flags = ${env.build_flags}
|
||||||
board_build.ldscript = eagle.flash.4m1m.ld
|
board_build.ldscript = eagle.flash.4m1m.ld
|
||||||
|
|
||||||
@@ -87,9 +89,11 @@ lib_ignore =
|
|||||||
extra_scripts =
|
extra_scripts =
|
||||||
post:tools/esp32.py
|
post:tools/esp32.py
|
||||||
post:tools/build.py
|
post:tools/build.py
|
||||||
|
build_type = ${env.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D CORE_DEBUG_LEVEL=0
|
-D CORE_DEBUG_LEVEL=0
|
||||||
|
-Wl,--wrap=esp_panic_handler
|
||||||
|
|
||||||
|
|
||||||
; Boards
|
; Boards
|
||||||
@@ -100,6 +104,7 @@ lib_deps = ${esp8266_defaults.lib_deps}
|
|||||||
lib_ignore = ${esp8266_defaults.lib_ignore}
|
lib_ignore = ${esp8266_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp8266_defaults.extra_scripts}
|
extra_scripts = ${esp8266_defaults.extra_scripts}
|
||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
|
build_type = ${esp8266_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D DEFAULT_OT_IN_GPIO=4
|
-D DEFAULT_OT_IN_GPIO=4
|
||||||
@@ -116,6 +121,7 @@ lib_deps = ${esp8266_defaults.lib_deps}
|
|||||||
lib_ignore = ${esp8266_defaults.lib_ignore}
|
lib_ignore = ${esp8266_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp8266_defaults.extra_scripts}
|
extra_scripts = ${esp8266_defaults.extra_scripts}
|
||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
|
build_type = ${esp8266_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D DEFAULT_OT_IN_GPIO=4
|
-D DEFAULT_OT_IN_GPIO=4
|
||||||
@@ -132,6 +138,7 @@ lib_deps = ${esp8266_defaults.lib_deps}
|
|||||||
lib_ignore = ${esp8266_defaults.lib_ignore}
|
lib_ignore = ${esp8266_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp8266_defaults.extra_scripts}
|
extra_scripts = ${esp8266_defaults.extra_scripts}
|
||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
|
build_type = ${esp8266_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D DEFAULT_OT_IN_GPIO=4
|
-D DEFAULT_OT_IN_GPIO=4
|
||||||
@@ -148,6 +155,7 @@ lib_deps = ${esp8266_defaults.lib_deps}
|
|||||||
lib_ignore = ${esp8266_defaults.lib_ignore}
|
lib_ignore = ${esp8266_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp8266_defaults.extra_scripts}
|
extra_scripts = ${esp8266_defaults.extra_scripts}
|
||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
|
build_type = ${esp8266_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D DEFAULT_OT_IN_GPIO=13
|
-D DEFAULT_OT_IN_GPIO=13
|
||||||
@@ -167,6 +175,7 @@ lib_ignore = ${esp32_defaults.lib_ignore}
|
|||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-DARDUINO_USB_MODE=1
|
-DARDUINO_USB_MODE=1
|
||||||
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D ARDUINO_USB_MODE=0
|
-D ARDUINO_USB_MODE=0
|
||||||
@@ -190,6 +199,7 @@ lib_ignore = ${esp32_defaults.lib_ignore}
|
|||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-DARDUINO_USB_MODE=1
|
-DARDUINO_USB_MODE=1
|
||||||
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D ARDUINO_USB_MODE=0
|
-D ARDUINO_USB_MODE=0
|
||||||
@@ -214,6 +224,7 @@ lib_ignore = ${esp32_defaults.lib_ignore}
|
|||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-mtext-section-literals
|
-mtext-section-literals
|
||||||
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
@@ -234,6 +245,7 @@ lib_deps =
|
|||||||
${esp32_defaults.nimble_lib}
|
${esp32_defaults.nimble_lib}
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
lib_ignore = ${esp32_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
@@ -254,6 +266,7 @@ lib_deps =
|
|||||||
${esp32_defaults.nimble_lib}
|
${esp32_defaults.nimble_lib}
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
lib_ignore = ${esp32_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
@@ -276,6 +289,7 @@ lib_ignore = ${esp32_defaults.lib_ignore}
|
|||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-mtext-section-literals
|
-mtext-section-literals
|
||||||
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
; Currently the NimBLE library is incompatible with ESP32 C6
|
; Currently the NimBLE library is incompatible with ESP32 C6
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
[secrets]
|
[secrets]
|
||||||
|
build_type = release
|
||||||
|
|
||||||
serial_enable = true
|
serial_enable = true
|
||||||
serial_baud = 115200
|
serial_baud = 115200
|
||||||
telnet_enable = true
|
telnet_enable = true
|
||||||
|
|||||||
132
src/CrashRecorder.h
Normal file
132
src/CrashRecorder.h
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#include "esp_err.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
extern "C" {
|
||||||
|
#include <user_interface.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/espressif/ESP8266_RTOS_SDK/blob/master/components/esp8266/include/esp_attr.h
|
||||||
|
#define _COUNTER_STRINGIFY(COUNTER) #COUNTER
|
||||||
|
#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION "." _COUNTER_STRINGIFY(COUNTER))))
|
||||||
|
#define __NOINIT_ATTR _SECTION_ATTR_IMPL(".noinit", __COUNTER__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace CrashRecorder {
|
||||||
|
typedef struct {
|
||||||
|
unsigned int data[32];
|
||||||
|
uint8_t length;
|
||||||
|
bool continues;
|
||||||
|
} backtrace_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int data[4];
|
||||||
|
uint8_t length;
|
||||||
|
} epc_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t core;
|
||||||
|
size_t heap;
|
||||||
|
unsigned long uptime;
|
||||||
|
} ext_t;
|
||||||
|
|
||||||
|
|
||||||
|
__NOINIT_ATTR volatile static backtrace_t backtrace;
|
||||||
|
__NOINIT_ATTR volatile static epc_t epc;
|
||||||
|
__NOINIT_ATTR volatile static ext_t ext;
|
||||||
|
|
||||||
|
uint8_t backtraceMaxLength = sizeof(backtrace.data) / sizeof(*backtrace.data);
|
||||||
|
uint8_t epcMaxLength = sizeof(epc.data) / sizeof(*epc.data);
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
void IRAM_ATTR panicHandler(arduino_panic_info_t *info, void *arg) {;
|
||||||
|
ext.core = info->core;
|
||||||
|
ext.heap = ESP.getFreeHeap();
|
||||||
|
ext.uptime = millis() / 1000u;
|
||||||
|
|
||||||
|
// Backtrace
|
||||||
|
backtrace.length = info->backtrace_len < backtraceMaxLength ? info->backtrace_len : backtraceMaxLength;
|
||||||
|
backtrace.continues = false;
|
||||||
|
for (unsigned int i = 0; i < info->backtrace_len; i++) {
|
||||||
|
if (i >= backtraceMaxLength) {
|
||||||
|
backtrace.continues = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
backtrace.data[i] = info->backtrace[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// EPC
|
||||||
|
if (info->pc) {
|
||||||
|
epc.data[0] = (unsigned int) info->pc;
|
||||||
|
epc.length = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
epc.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
if (backtrace.length > backtraceMaxLength) {
|
||||||
|
backtrace.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (epc.length > epcMaxLength) {
|
||||||
|
epc.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
set_arduino_panic_handler(panicHandler, nullptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
extern "C" void custom_crash_callback(struct rst_info *info, uint32_t stack, uint32_t stack_end) {
|
||||||
|
uint8_t _length = 0;
|
||||||
|
|
||||||
|
CrashRecorder::ext.core = 0;
|
||||||
|
CrashRecorder::ext.heap = ESP.getFreeHeap();
|
||||||
|
CrashRecorder::ext.uptime = millis() / 1000u;
|
||||||
|
|
||||||
|
// Backtrace
|
||||||
|
CrashRecorder::backtrace.continues = false;
|
||||||
|
uint32_t value;
|
||||||
|
for (uint32_t i = stack; i < stack_end; i += 4) {
|
||||||
|
value = *((uint32_t*) i);
|
||||||
|
|
||||||
|
// keep only addresses in code area
|
||||||
|
if ((value >= 0x40000000) && (value < 0x40300000)) {
|
||||||
|
if (_length >= CrashRecorder::backtraceMaxLength) {
|
||||||
|
CrashRecorder::backtrace.continues = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashRecorder::backtrace.data[_length++] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashRecorder::backtrace.length = _length;
|
||||||
|
|
||||||
|
// EPC
|
||||||
|
_length = 0;
|
||||||
|
if (info->epc1 > 0) {
|
||||||
|
CrashRecorder::epc.data[_length++] = info->epc1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->epc2 > 0) {
|
||||||
|
CrashRecorder::epc.data[_length++] = info->epc2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->epc3 > 0) {
|
||||||
|
CrashRecorder::epc.data[_length++] = info->epc3;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashRecorder::epc.length = _length;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
142
src/PortalTask.h
142
src/PortalTask.h
@@ -504,6 +504,9 @@ protected:
|
|||||||
bool isConnected = network->isConnected();
|
bool isConnected = network->isConnected();
|
||||||
|
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
|
doc["system"]["resetReason"] = getResetReason();
|
||||||
|
doc["system"]["uptime"] = millis() / 1000ul;
|
||||||
|
|
||||||
doc["network"]["hostname"] = networkSettings.hostname;
|
doc["network"]["hostname"] = networkSettings.hostname;
|
||||||
doc["network"]["mac"] = network->getStaMac();
|
doc["network"]["mac"] = network->getStaMac();
|
||||||
doc["network"]["connected"] = isConnected;
|
doc["network"]["connected"] = isConnected;
|
||||||
@@ -515,49 +518,124 @@ protected:
|
|||||||
doc["network"]["gateway"] = isConnected ? network->getStaGateway().toString() : "";
|
doc["network"]["gateway"] = isConnected ? network->getStaGateway().toString() : "";
|
||||||
doc["network"]["dns"] = isConnected ? network->getStaDns().toString() : "";
|
doc["network"]["dns"] = isConnected ? network->getStaDns().toString() : "";
|
||||||
|
|
||||||
doc["system"]["buildVersion"] = BUILD_VERSION;
|
doc["build"]["version"] = BUILD_VERSION;
|
||||||
doc["system"]["buildDate"] = __DATE__ " " __TIME__;
|
doc["build"]["date"] = __DATE__ " " __TIME__;
|
||||||
doc["system"]["buildEnv"] = BUILD_ENV;
|
doc["build"]["env"] = BUILD_ENV;
|
||||||
doc["system"]["uptime"] = millis() / 1000ul;
|
|
||||||
doc["system"]["totalHeap"] = getTotalHeap();
|
doc["heap"]["total"] = getTotalHeap();
|
||||||
doc["system"]["freeHeap"] = getFreeHeap();
|
doc["heap"]["free"] = getFreeHeap();
|
||||||
doc["system"]["minFreeHeap"] = getFreeHeap(true);
|
doc["heap"]["minFree"] = getFreeHeap(true);
|
||||||
doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap();
|
doc["heap"]["maxFreeBlock"] = getMaxFreeBlockHeap();
|
||||||
doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true);
|
doc["heap"]["minMaxFreeBlock"] = getMaxFreeBlockHeap(true);
|
||||||
doc["system"]["resetReason"] = getResetReason();
|
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
doc["system"]["chipModel"] = esp_is_8285() ? "ESP8285" : "ESP8266";
|
doc["build"]["core"] = ESP.getCoreVersion();
|
||||||
doc["system"]["chipRevision"] = 0;
|
doc["build"]["sdk"] = ESP.getSdkVersion();
|
||||||
doc["system"]["chipCores"] = 1;
|
doc["chip"]["model"] = esp_is_8285() ? "ESP8285" : "ESP8266";
|
||||||
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
doc["chip"]["rev"] = 0;
|
||||||
doc["system"]["coreVersion"] = ESP.getCoreVersion();
|
doc["chip"]["cores"] = 1;
|
||||||
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
doc["chip"]["freq"] = ESP.getCpuFreqMHz();
|
||||||
doc["system"]["flashRealSize"] = ESP.getFlashChipRealSize();
|
doc["flash"]["size"] = ESP.getFlashChipSize();
|
||||||
|
doc["flash"]["realSize"] = ESP.getFlashChipRealSize();
|
||||||
#elif ARDUINO_ARCH_ESP32
|
#elif ARDUINO_ARCH_ESP32
|
||||||
doc["system"]["chipModel"] = ESP.getChipModel();
|
doc["build"]["core"] = ESP.getCoreVersion();
|
||||||
doc["system"]["chipRevision"] = ESP.getChipRevision();
|
doc["build"]["sdk"] = ESP.getSdkVersion();
|
||||||
doc["system"]["chipCores"] = ESP.getChipCores();
|
doc["chip"]["model"] = ESP.getChipModel();
|
||||||
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
doc["chip"]["rev"] = ESP.getChipRevision();
|
||||||
doc["system"]["coreVersion"] = ESP.getSdkVersion();
|
doc["chip"]["cores"] = ESP.getChipCores();
|
||||||
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
doc["chip"]["freq"] = ESP.getCpuFreqMHz();
|
||||||
doc["system"]["flashRealSize"] = doc["system"]["flashSize"];
|
doc["flash"]["size"] = ESP.getFlashChipSize();
|
||||||
|
doc["flash"]["realSize"] = doc["flash"]["size"];
|
||||||
#else
|
#else
|
||||||
doc["system"]["chipModel"] = 0;
|
doc["build"]["core"] = 0;
|
||||||
doc["system"]["chipRevision"] = 0;
|
doc["build"]["sdk"] = 0;
|
||||||
doc["system"]["chipCores"] = 0;
|
doc["chip"]["model"] = 0;
|
||||||
doc["system"]["cpuFreq"] = 0;
|
doc["chip"]["rev"] = 0;
|
||||||
doc["system"]["coreVersion"] = 0;
|
doc["chip"]["cores"] = 0;
|
||||||
doc["system"]["flashSize"] = 0;
|
doc["chip"]["freq"] = 0;
|
||||||
doc["system"]["flashRealSize"] = 0;
|
doc["flash"]["size"] = 0;
|
||||||
|
doc["flash"]["realSize"] = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
this->bufferedWebServer->send(200, "application/json", doc);
|
this->bufferedWebServer->send(200, "application/json", doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this->webServer->on("/api/debug", HTTP_GET, [this]() {
|
||||||
|
JsonDocument doc;
|
||||||
|
doc["build"]["version"] = BUILD_VERSION;
|
||||||
|
doc["build"]["date"] = __DATE__ " " __TIME__;
|
||||||
|
doc["build"]["env"] = BUILD_ENV;
|
||||||
|
doc["heap"]["total"] = getTotalHeap();
|
||||||
|
doc["heap"]["free"] = getFreeHeap();
|
||||||
|
doc["heap"]["minFree"] = getFreeHeap(true);
|
||||||
|
doc["heap"]["maxFreeBlock"] = getMaxFreeBlockHeap();
|
||||||
|
doc["heap"]["minMaxFreeBlock"] = getMaxFreeBlockHeap(true);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
auto reason = esp_reset_reason();
|
||||||
|
if (reason != ESP_RST_UNKNOWN && reason != ESP_RST_POWERON && reason != ESP_RST_SW) {
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
auto reason = ESP.getResetInfoPtr()->reason;
|
||||||
|
if (reason != REASON_DEFAULT_RST && reason != REASON_SOFT_RESTART && reason != REASON_EXT_SYS_RST) {
|
||||||
|
#else
|
||||||
|
if (false) {
|
||||||
|
#endif
|
||||||
|
doc["crash"]["reason"] = getResetReason();
|
||||||
|
doc["crash"]["core"] = CrashRecorder::ext.core;
|
||||||
|
doc["crash"]["heap"] = CrashRecorder::ext.heap;
|
||||||
|
doc["crash"]["uptime"] = CrashRecorder::ext.uptime;
|
||||||
|
|
||||||
|
if (CrashRecorder::backtrace.length > 0 && CrashRecorder::backtrace.length <= CrashRecorder::backtraceMaxLength) {
|
||||||
|
String backtraceStr;
|
||||||
|
arr2str(backtraceStr, CrashRecorder::backtrace.data, CrashRecorder::backtrace.length);
|
||||||
|
doc["crash"]["backtrace"]["data"] = backtraceStr;
|
||||||
|
doc["crash"]["backtrace"]["continues"] = CrashRecorder::backtrace.continues;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CrashRecorder::epc.length > 0 && CrashRecorder::epc.length <= CrashRecorder::epcMaxLength) {
|
||||||
|
String epcStr;
|
||||||
|
arr2str(epcStr, CrashRecorder::epc.data, CrashRecorder::epc.length);
|
||||||
|
doc["crash"]["epc"] = epcStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
doc["build"]["core"] = ESP.getCoreVersion();
|
||||||
|
doc["build"]["sdk"] = ESP.getSdkVersion();
|
||||||
|
doc["chip"]["model"] = esp_is_8285() ? "ESP8285" : "ESP8266";
|
||||||
|
doc["chip"]["rev"] = 0;
|
||||||
|
doc["chip"]["cores"] = 1;
|
||||||
|
doc["chip"]["freq"] = ESP.getCpuFreqMHz();
|
||||||
|
doc["flash"]["size"] = ESP.getFlashChipSize();
|
||||||
|
doc["flash"]["realSize"] = ESP.getFlashChipRealSize();
|
||||||
|
#elif ARDUINO_ARCH_ESP32
|
||||||
|
doc["build"]["core"] = ESP.getCoreVersion();
|
||||||
|
doc["build"]["sdk"] = ESP.getSdkVersion();
|
||||||
|
doc["chip"]["model"] = ESP.getChipModel();
|
||||||
|
doc["chip"]["rev"] = ESP.getChipRevision();
|
||||||
|
doc["chip"]["cores"] = ESP.getChipCores();
|
||||||
|
doc["chip"]["freq"] = ESP.getCpuFreqMHz();
|
||||||
|
doc["flash"]["size"] = ESP.getFlashChipSize();
|
||||||
|
doc["flash"]["realSize"] = doc["flash"]["size"];
|
||||||
|
#else
|
||||||
|
doc["build"]["core"] = 0;
|
||||||
|
doc["build"]["sdk"] = 0;
|
||||||
|
doc["chip"]["model"] = 0;
|
||||||
|
doc["chip"]["rev"] = 0;
|
||||||
|
doc["chip"]["cores"] = 0;
|
||||||
|
doc["chip"]["freq"] = 0;
|
||||||
|
doc["flash"]["size"] = 0;
|
||||||
|
doc["flash"]["realSize"] = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
this->webServer->sendHeader(F("Content-Disposition"), F("attachment; filename=\"debug.json\""));
|
||||||
|
this->bufferedWebServer->send(200, "application/json", doc, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// not found
|
// not found
|
||||||
this->webServer->onNotFound([this]() {
|
this->webServer->onNotFound([this]() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
|
#include "CrashRecorder.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <FileData.h>
|
#include <FileData.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
@@ -45,6 +46,7 @@ MainTask* tMain;
|
|||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
CrashRecorder::init();
|
||||||
LittleFS.begin();
|
LittleFS.begin();
|
||||||
|
|
||||||
Log.setLevel(TinyLogger::Level::VERBOSE);
|
Log.setLevel(TinyLogger::Level::VERBOSE);
|
||||||
|
|||||||
16
src/utils.h
16
src/utils.h
@@ -188,6 +188,22 @@ String getResetReason() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void arr2str(String &str, T arr[], size_t length) {
|
||||||
|
char buffer[12];
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
auto addr = arr[i];
|
||||||
|
if (!addr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(buffer, "0x%08X ", addr);
|
||||||
|
str.concat(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
str.trim();
|
||||||
|
}
|
||||||
|
|
||||||
void networkSettingsToJson(const NetworkSettings& src, JsonVariant dst) {
|
void networkSettingsToJson(const NetworkSettings& src, JsonVariant dst) {
|
||||||
dst["hostname"] = src.hostname;
|
dst["hostname"] = src.hostname;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
},
|
},
|
||||||
"dbm": "dBm",
|
"dbm": "dBm",
|
||||||
"kw": "kW",
|
"kw": "kW",
|
||||||
|
"time": {
|
||||||
|
"days": "d.",
|
||||||
|
"hours": "h.",
|
||||||
|
"min": "min.",
|
||||||
|
"sec": "sec."
|
||||||
|
},
|
||||||
|
|
||||||
"button": {
|
"button": {
|
||||||
"upgrade": "Upgrade",
|
"upgrade": "Upgrade",
|
||||||
@@ -39,7 +45,8 @@
|
|||||||
"title": "Build",
|
"title": "Build",
|
||||||
"version": "Version",
|
"version": "Version",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"sdk": "Core/SDK"
|
"core": "Core",
|
||||||
|
"sdk": "SDK"
|
||||||
},
|
},
|
||||||
"uptime": "Uptime",
|
"uptime": "Uptime",
|
||||||
"memory": {
|
"memory": {
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
},
|
},
|
||||||
"dbm": "дБм",
|
"dbm": "дБм",
|
||||||
"kw": "кВт",
|
"kw": "кВт",
|
||||||
|
"time": {
|
||||||
|
"days": "д.",
|
||||||
|
"hours": "ч.",
|
||||||
|
"min": "мин.",
|
||||||
|
"sec": "сек."
|
||||||
|
},
|
||||||
|
|
||||||
"button": {
|
"button": {
|
||||||
"upgrade": "Обновить",
|
"upgrade": "Обновить",
|
||||||
@@ -39,7 +45,8 @@
|
|||||||
"title": "Билд",
|
"title": "Билд",
|
||||||
"version": "Версия",
|
"version": "Версия",
|
||||||
"date": "Дата",
|
"date": "Дата",
|
||||||
"sdk": "Ядро/SDK"
|
"core": "Ядро",
|
||||||
|
"sdk": "SDK"
|
||||||
},
|
},
|
||||||
"uptime": "Аптайм",
|
"uptime": "Аптайм",
|
||||||
"memory": {
|
"memory": {
|
||||||
|
|||||||
@@ -101,36 +101,40 @@
|
|||||||
<td>
|
<td>
|
||||||
Env: <b id="build-env"></b><br />
|
Env: <b id="build-env"></b><br />
|
||||||
<span data-i18n>index.system.build.date</span>: <b id="build-date"></b><br />
|
<span data-i18n>index.system.build.date</span>: <b id="build-date"></b><br />
|
||||||
<span data-i18n>index.system.build.sdk</span>: <b id="core-version"></b>
|
<span data-i18n>index.system.build.core</span>: <b id="build-core"></b><br />
|
||||||
|
<span data-i18n>index.system.build.sdk</span>: <b id="build-sdk"></b>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" data-i18n>index.system.uptime</th>
|
<th scope="row" data-i18n>index.system.uptime</th>
|
||||||
<td>
|
<td>
|
||||||
<b id="uptime-days"></b> days,
|
<b id="uptime-days"></b> <span data-i18n>time.days</span>,
|
||||||
<b id="uptime-hours"></b> hours,
|
<b id="uptime-hours"></b> <span data-i18n>time.hours</span>,
|
||||||
<b id="uptime-min"></b> min.,
|
<b id="uptime-min"></b> <span data-i18n>time.min</span>,
|
||||||
<b id="uptime-sec"></b> sec.
|
<b id="uptime-sec"></b> <span data-i18n>time.sec</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" data-i18n>index.system.memory.title</th>
|
<th scope="row" data-i18n>index.system.memory.title</th>
|
||||||
<td>
|
<td>
|
||||||
<b id="free-heap"></b> of <b id="total-heap"></b> bytes (<span data-i18n>index.system.memory.min</span>: <b id="min-free-heap"></b> bytes)<br />
|
<b id="heap-free"></b> of <b id="heap-total"></b> bytes (<span data-i18n>index.system.memory.min</span>: <b id="heap-min-free"></b> bytes)<br />
|
||||||
<span data-i18n>index.system.memory.maxFreeBlock</span>: <b id="max-free-block-heap"></b> bytes (<span data-i18n>index.system.memory.min</span>: <b id="min-max-free-block-heap"></b> bytes)
|
<span data-i18n>index.system.memory.maxFreeBlock</span>: <b id="heap-max-free-block"></b> bytes (<span data-i18n>index.system.memory.min</span>: <b id="heap-min-max-free-block"></b> bytes)
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" data-i18n>index.system.board</th>
|
<th scope="row" data-i18n>index.system.board</th>
|
||||||
<td>
|
<td>
|
||||||
<span data-i18n>index.system.chip.model</span>: <b id="chip-model"></b> (rev. <span id="chip-revision"></span>)<br />
|
<span data-i18n>index.system.chip.model</span>: <b id="chip-model"></b> (rev. <span id="chip-rev"></span>)<br />
|
||||||
<span data-i18n>index.system.chip.cores</span>: <b id="chip-cores"></b>, <span data-i18n>index.system.chip.freq</span>: <b id="cpu-freq"></b> mHz<br />
|
<span data-i18n>index.system.chip.cores</span>: <b id="chip-cores"></b>, <span data-i18n>index.system.chip.freq</span>: <b id="chip-freq"></b> mHz<br />
|
||||||
<span data-i18n>index.system.flash.size</span>: <b id="flash-size"></b> MB (<span data-i18n>index.system.flash.realSize</span>: <b id="flash-real-size"></b> MB)
|
<span data-i18n>index.system.flash.size</span>: <b id="flash-size"></b> MB (<span data-i18n>index.system.flash.realSize</span>: <b id="flash-real-size"></b> MB)
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" data-i18n>index.system.lastResetReason</th>
|
<th scope="row" data-i18n>index.system.lastResetReason</th>
|
||||||
<td><b id="reset-reason"></b></td>
|
<td>
|
||||||
|
<b id="reset-reason"></b><br />
|
||||||
|
<a href="/api/debug" target="_blank"><small>Save debug data</small></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -170,6 +174,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
setValue('#reset-reason', result.system.resetReason);
|
||||||
|
setValue('#uptime', result.system.uptime);
|
||||||
|
setValue('#uptime-days', Math.floor(result.system.uptime / 86400));
|
||||||
|
setValue('#uptime-hours', Math.floor(result.system.uptime % 86400 / 3600));
|
||||||
|
setValue('#uptime-min', Math.floor(result.system.uptime % 3600 / 60));
|
||||||
|
setValue('#uptime-sec', Math.floor(result.system.uptime % 60));
|
||||||
|
|
||||||
setValue('#network-hostname', result.network.hostname);
|
setValue('#network-hostname', result.network.hostname);
|
||||||
setValue('#network-mac', result.network.mac);
|
setValue('#network-mac', result.network.mac);
|
||||||
setState('#network-connected', result.network.connected);
|
setState('#network-connected', result.network.connected);
|
||||||
@@ -181,28 +192,24 @@
|
|||||||
setValue('#network-dns', result.network.dns);
|
setValue('#network-dns', result.network.dns);
|
||||||
setBusy('#main-busy', '#main-table', false);
|
setBusy('#main-busy', '#main-table', false);
|
||||||
|
|
||||||
setValue('#build-version', result.system.buildVersion);
|
setValue('#build-version', result.build.version);
|
||||||
setValue('#build-date', result.system.buildDate);
|
setValue('#build-date', result.build.date);
|
||||||
setValue('#build-env', result.system.buildEnv);
|
setValue('#build-env', result.build.env);
|
||||||
setValue('#uptime', result.system.uptime);
|
setValue('#build-core', result.build.core);
|
||||||
setValue('#uptime-days', Math.floor(result.system.uptime / 86400));
|
setValue('#build-sdk', result.build.sdk);
|
||||||
setValue('#uptime-hours', Math.floor(result.system.uptime % 86400 / 3600));
|
|
||||||
setValue('#uptime-min', Math.floor(result.system.uptime % 3600 / 60));
|
|
||||||
setValue('#uptime-sec', Math.floor(result.system.uptime % 60));
|
|
||||||
setValue('#total-heap', result.system.totalHeap);
|
|
||||||
setValue('#free-heap', result.system.freeHeap);
|
|
||||||
setValue('#min-free-heap', result.system.minFreeHeap);
|
|
||||||
setValue('#max-free-block-heap', result.system.maxFreeBlockHeap);
|
|
||||||
setValue('#min-max-free-block-heap', result.system.minMaxFreeBlockHeap);
|
|
||||||
setValue('#reset-reason', result.system.resetReason);
|
|
||||||
|
|
||||||
setValue('#chip-model', result.system.chipModel);
|
setValue('#heap-total', result.heap.total);
|
||||||
setValue('#chip-revision', result.system.chipRevision);
|
setValue('#heap-free', result.heap.free);
|
||||||
setValue('#chip-cores', result.system.chipCores);
|
setValue('#heap-min-free', result.heap.minFree);
|
||||||
setValue('#cpu-freq', result.system.cpuFreq);
|
setValue('#heap-max-free-block', result.heap.maxFreeBlock);
|
||||||
setValue('#core-version', result.system.coreVersion);
|
setValue('#heap-min-max-free-block', result.heap.minMaxFreeBlock);
|
||||||
setValue('#flash-size', result.system.flashSize / 1024 / 1024);
|
|
||||||
setValue('#flash-real-size', result.system.flashRealSize / 1024 / 1024);
|
setValue('#chip-model', result.chip.model);
|
||||||
|
setValue('#chip-rev', result.chip.rev);
|
||||||
|
setValue('#chip-cores', result.chip.cores);
|
||||||
|
setValue('#chip-freq', result.chip.freq);
|
||||||
|
setValue('#flash-size', result.flash.size / 1024 / 1024);
|
||||||
|
setValue('#flash-real-size', result.flash.realSize / 1024 / 1024);
|
||||||
|
|
||||||
setBusy('#system-busy', '#system-table', false);
|
setBusy('#system-busy', '#system-table', false);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user