From 3d11d13631ed293705efcf34d1c336c0cedb6036 Mon Sep 17 00:00:00 2001 From: Yurii Date: Thu, 24 Oct 2024 04:01:14 +0300 Subject: [PATCH] feat: added crash recorder and ability to save dump --- lib/BufferedWebServer/BufferedWebServer.h | 10 +- platformio.ini | 14 +++ secrets.default.ini | 2 + src/CrashRecorder.h | 132 ++++++++++++++++++++ src/PortalTask.h | 142 +++++++++++++++++----- src/main.cpp | 2 + src/utils.h | 16 +++ src_data/locales/en.json | 9 +- src_data/locales/ru.json | 9 +- src_data/pages/index.html | 69 ++++++----- 10 files changed, 338 insertions(+), 67 deletions(-) create mode 100644 src/CrashRecorder.h diff --git a/lib/BufferedWebServer/BufferedWebServer.h b/lib/BufferedWebServer/BufferedWebServer.h index 56f23c9..8c04c14 100644 --- a/lib/BufferedWebServer/BufferedWebServer.h +++ b/lib/BufferedWebServer/BufferedWebServer.h @@ -10,7 +10,7 @@ public: 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 if (!this->webServer->chunkedResponseModeStart(code, contentType)) { this->webServer->send(505, F("text/html"), F("HTTP1.1 required")); @@ -24,7 +24,13 @@ public: this->webServer->send(code, contentType, emptyString); #endif - serializeJson(content, *this); + if (pretty) { + serializeJsonPretty(content, *this); + + } else { + serializeJson(content, *this); + } + this->flush(); #ifdef ARDUINO_ARCH_ESP8266 diff --git a/platformio.ini b/platformio.ini index fc4a10d..759b3cd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,6 +26,7 @@ lib_deps = gyverlibs/GyverBlinker@^1.1.1 https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg laxilef/TinyLogger@^1.1.1 +build_type = ${secrets.build_type} build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY ;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH @@ -67,6 +68,7 @@ lib_deps = lib_ignore = extra_scripts = post:tools/build.py +build_type = ${env.build_type} build_flags = ${env.build_flags} board_build.ldscript = eagle.flash.4m1m.ld @@ -87,9 +89,11 @@ lib_ignore = extra_scripts = post:tools/esp32.py post:tools/build.py +build_type = ${env.build_type} build_flags = ${env.build_flags} -D CORE_DEBUG_LEVEL=0 + -Wl,--wrap=esp_panic_handler ; Boards @@ -100,6 +104,7 @@ lib_deps = ${esp8266_defaults.lib_deps} lib_ignore = ${esp8266_defaults.lib_ignore} extra_scripts = ${esp8266_defaults.extra_scripts} board_build.ldscript = ${esp8266_defaults.board_build.ldscript} +build_type = ${esp8266_defaults.build_type} build_flags = ${esp8266_defaults.build_flags} -D DEFAULT_OT_IN_GPIO=4 @@ -116,6 +121,7 @@ lib_deps = ${esp8266_defaults.lib_deps} lib_ignore = ${esp8266_defaults.lib_ignore} extra_scripts = ${esp8266_defaults.extra_scripts} board_build.ldscript = ${esp8266_defaults.board_build.ldscript} +build_type = ${esp8266_defaults.build_type} build_flags = ${esp8266_defaults.build_flags} -D DEFAULT_OT_IN_GPIO=4 @@ -132,6 +138,7 @@ lib_deps = ${esp8266_defaults.lib_deps} lib_ignore = ${esp8266_defaults.lib_ignore} extra_scripts = ${esp8266_defaults.extra_scripts} board_build.ldscript = ${esp8266_defaults.board_build.ldscript} +build_type = ${esp8266_defaults.build_type} build_flags = ${esp8266_defaults.build_flags} -D DEFAULT_OT_IN_GPIO=4 @@ -148,6 +155,7 @@ lib_deps = ${esp8266_defaults.lib_deps} lib_ignore = ${esp8266_defaults.lib_ignore} extra_scripts = ${esp8266_defaults.extra_scripts} board_build.ldscript = ${esp8266_defaults.board_build.ldscript} +build_type = ${esp8266_defaults.build_type} build_flags = ${esp8266_defaults.build_flags} -D DEFAULT_OT_IN_GPIO=13 @@ -167,6 +175,7 @@ lib_ignore = ${esp32_defaults.lib_ignore} extra_scripts = ${esp32_defaults.extra_scripts} build_unflags = -DARDUINO_USB_MODE=1 +build_type = ${esp32_defaults.build_type} build_flags = ${esp32_defaults.build_flags} -D ARDUINO_USB_MODE=0 @@ -190,6 +199,7 @@ lib_ignore = ${esp32_defaults.lib_ignore} extra_scripts = ${esp32_defaults.extra_scripts} build_unflags = -DARDUINO_USB_MODE=1 +build_type = ${esp32_defaults.build_type} build_flags = ${esp32_defaults.build_flags} -D ARDUINO_USB_MODE=0 @@ -214,6 +224,7 @@ lib_ignore = ${esp32_defaults.lib_ignore} extra_scripts = ${esp32_defaults.extra_scripts} build_unflags = -mtext-section-literals +build_type = ${esp32_defaults.build_type} build_flags = ${esp32_defaults.build_flags} -D USE_BLE=1 @@ -234,6 +245,7 @@ lib_deps = ${esp32_defaults.nimble_lib} lib_ignore = ${esp32_defaults.lib_ignore} extra_scripts = ${esp32_defaults.extra_scripts} +build_type = ${esp32_defaults.build_type} build_flags = ${esp32_defaults.build_flags} -D USE_BLE=1 @@ -254,6 +266,7 @@ lib_deps = ${esp32_defaults.nimble_lib} lib_ignore = ${esp32_defaults.lib_ignore} extra_scripts = ${esp32_defaults.extra_scripts} +build_type = ${esp32_defaults.build_type} build_flags = ${esp32_defaults.build_flags} -D USE_BLE=1 @@ -276,6 +289,7 @@ lib_ignore = ${esp32_defaults.lib_ignore} extra_scripts = ${esp32_defaults.extra_scripts} build_unflags = -mtext-section-literals +build_type = ${esp32_defaults.build_type} build_flags = ${esp32_defaults.build_flags} ; Currently the NimBLE library is incompatible with ESP32 C6 diff --git a/secrets.default.ini b/secrets.default.ini index 4ba0b64..e19d0a4 100644 --- a/secrets.default.ini +++ b/secrets.default.ini @@ -1,4 +1,6 @@ [secrets] +build_type = release + serial_enable = true serial_baud = 115200 telnet_enable = true diff --git a/src/CrashRecorder.h b/src/CrashRecorder.h new file mode 100644 index 0000000..e795b2a --- /dev/null +++ b/src/CrashRecorder.h @@ -0,0 +1,132 @@ +#pragma once +#include + +#ifdef ARDUINO_ARCH_ESP32 + #include "esp_err.h" +#endif + +#ifdef ARDUINO_ARCH_ESP8266 + extern "C" { + #include + } + + // 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 \ No newline at end of file diff --git a/src/PortalTask.h b/src/PortalTask.h index 1490d49..b4265ef 100644 --- a/src/PortalTask.h +++ b/src/PortalTask.h @@ -504,6 +504,9 @@ protected: bool isConnected = network->isConnected(); JsonDocument doc; + doc["system"]["resetReason"] = getResetReason(); + doc["system"]["uptime"] = millis() / 1000ul; + doc["network"]["hostname"] = networkSettings.hostname; doc["network"]["mac"] = network->getStaMac(); doc["network"]["connected"] = isConnected; @@ -515,49 +518,124 @@ protected: doc["network"]["gateway"] = isConnected ? network->getStaGateway().toString() : ""; doc["network"]["dns"] = isConnected ? network->getStaDns().toString() : ""; - doc["system"]["buildVersion"] = BUILD_VERSION; - doc["system"]["buildDate"] = __DATE__ " " __TIME__; - doc["system"]["buildEnv"] = BUILD_ENV; - doc["system"]["uptime"] = millis() / 1000ul; - doc["system"]["totalHeap"] = getTotalHeap(); - doc["system"]["freeHeap"] = getFreeHeap(); - doc["system"]["minFreeHeap"] = getFreeHeap(true); - doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap(); - doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true); - doc["system"]["resetReason"] = getResetReason(); + 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); #ifdef ARDUINO_ARCH_ESP8266 - doc["system"]["chipModel"] = esp_is_8285() ? "ESP8285" : "ESP8266"; - doc["system"]["chipRevision"] = 0; - doc["system"]["chipCores"] = 1; - doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz(); - doc["system"]["coreVersion"] = ESP.getCoreVersion(); - doc["system"]["flashSize"] = ESP.getFlashChipSize(); - doc["system"]["flashRealSize"] = ESP.getFlashChipRealSize(); + 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["system"]["chipModel"] = ESP.getChipModel(); - doc["system"]["chipRevision"] = ESP.getChipRevision(); - doc["system"]["chipCores"] = ESP.getChipCores(); - doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz(); - doc["system"]["coreVersion"] = ESP.getSdkVersion(); - doc["system"]["flashSize"] = ESP.getFlashChipSize(); - doc["system"]["flashRealSize"] = doc["system"]["flashSize"]; + 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["system"]["chipModel"] = 0; - doc["system"]["chipRevision"] = 0; - doc["system"]["chipCores"] = 0; - doc["system"]["cpuFreq"] = 0; - doc["system"]["coreVersion"] = 0; - doc["system"]["flashSize"] = 0; - doc["system"]["flashRealSize"] = 0; + 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->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 this->webServer->onNotFound([this]() { diff --git a/src/main.cpp b/src/main.cpp index 583eb32..c5c2f94 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include #include "defines.h" #include "strings.h" +#include "CrashRecorder.h" #include #include #include @@ -45,6 +46,7 @@ MainTask* tMain; void setup() { + CrashRecorder::init(); LittleFS.begin(); Log.setLevel(TinyLogger::Level::VERBOSE); diff --git a/src/utils.h b/src/utils.h index 1c23f73..8f4d2d5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -188,6 +188,22 @@ String getResetReason() { return value; } +template +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) { dst["hostname"] = src.hostname; diff --git a/src_data/locales/en.json b/src_data/locales/en.json index 39f7adf..25ecf7c 100644 --- a/src_data/locales/en.json +++ b/src_data/locales/en.json @@ -10,6 +10,12 @@ }, "dbm": "dBm", "kw": "kW", + "time": { + "days": "d.", + "hours": "h.", + "min": "min.", + "sec": "sec." + }, "button": { "upgrade": "Upgrade", @@ -39,7 +45,8 @@ "title": "Build", "version": "Version", "date": "Date", - "sdk": "Core/SDK" + "core": "Core", + "sdk": "SDK" }, "uptime": "Uptime", "memory": { diff --git a/src_data/locales/ru.json b/src_data/locales/ru.json index 09e9621..797cf30 100644 --- a/src_data/locales/ru.json +++ b/src_data/locales/ru.json @@ -10,6 +10,12 @@ }, "dbm": "дБм", "kw": "кВт", + "time": { + "days": "д.", + "hours": "ч.", + "min": "мин.", + "sec": "сек." + }, "button": { "upgrade": "Обновить", @@ -39,7 +45,8 @@ "title": "Билд", "version": "Версия", "date": "Дата", - "sdk": "Ядро/SDK" + "core": "Ядро", + "sdk": "SDK" }, "uptime": "Аптайм", "memory": { diff --git a/src_data/pages/index.html b/src_data/pages/index.html index 0cbbafc..f23ba8e 100644 --- a/src_data/pages/index.html +++ b/src_data/pages/index.html @@ -101,36 +101,40 @@ Env:
index.system.build.date:
- index.system.build.sdk: + index.system.build.core:
+ index.system.build.sdk: index.system.uptime - days, - hours, - min., - sec. + time.days, + time.hours, + time.min, + time.sec index.system.memory.title - of bytes (index.system.memory.min: bytes)
- index.system.memory.maxFreeBlock: bytes (index.system.memory.min: bytes) + of bytes (index.system.memory.min: bytes)
+ index.system.memory.maxFreeBlock: bytes (index.system.memory.min: bytes) index.system.board - index.system.chip.model: (rev. )
- index.system.chip.cores: , index.system.chip.freq: mHz
+ index.system.chip.model: (rev. )
+ index.system.chip.cores: , index.system.chip.freq: mHz
index.system.flash.size: MB (index.system.flash.realSize: MB) index.system.lastResetReason - + +
+ Save debug data + @@ -170,6 +174,13 @@ } 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-mac', result.network.mac); setState('#network-connected', result.network.connected); @@ -181,28 +192,24 @@ setValue('#network-dns', result.network.dns); setBusy('#main-busy', '#main-table', false); - setValue('#build-version', result.system.buildVersion); - setValue('#build-date', result.system.buildDate); - setValue('#build-env', result.system.buildEnv); - 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('#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('#build-version', result.build.version); + setValue('#build-date', result.build.date); + setValue('#build-env', result.build.env); + setValue('#build-core', result.build.core); + setValue('#build-sdk', result.build.sdk); - setValue('#chip-model', result.system.chipModel); - setValue('#chip-revision', result.system.chipRevision); - setValue('#chip-cores', result.system.chipCores); - setValue('#cpu-freq', result.system.cpuFreq); - setValue('#core-version', result.system.coreVersion); - setValue('#flash-size', result.system.flashSize / 1024 / 1024); - setValue('#flash-real-size', result.system.flashRealSize / 1024 / 1024); + setValue('#heap-total', result.heap.total); + setValue('#heap-free', result.heap.free); + setValue('#heap-min-free', result.heap.minFree); + setValue('#heap-max-free-block', result.heap.maxFreeBlock); + setValue('#heap-min-max-free-block', result.heap.minMaxFreeBlock); + + 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);