2024-09-20 11:07:08 +03:00
|
|
|
|
#include "DebugTrace.h"
|
|
|
|
|
|
#if defined(RESTART_DEBUG_INFO) && defined(ESP32) && !defined(esp32c3m_4mb)
|
|
|
|
|
|
//#ifdef RESTART_DEBUG_INFO
|
|
|
|
|
|
__NOINIT_ATTR static re_restart_debug_t _debug_info;
|
|
|
|
|
|
|
|
|
|
|
|
#include "esp_debug_helpers.h"
|
|
|
|
|
|
#include "esp_types.h"
|
|
|
|
|
|
#include "esp_attr.h"
|
|
|
|
|
|
#include "esp_err.h"
|
|
|
|
|
|
#include "soc/soc_memory_layout.h"
|
|
|
|
|
|
#include "soc/cpu.h"
|
2024-09-21 11:28:46 +03:00
|
|
|
|
#include "esp_ota_ops.h"
|
2024-09-20 11:07:08 +03:00
|
|
|
|
|
|
|
|
|
|
// RU: Размер буфера для конвертации даты и времeни в строку
|
|
|
|
|
|
#define CONFIG_FORMAT_STRFTIME_BUFFER_SIZE 32
|
|
|
|
|
|
#define CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE 20 // YYYY.MM.DD HH:NN:SS + \n
|
|
|
|
|
|
|
|
|
|
|
|
// RU: Форматы даты и времени
|
|
|
|
|
|
#define CONFIG_FORMAT_DTS "%d.%m.%Y %H:%M:%S"
|
|
|
|
|
|
|
|
|
|
|
|
void IRAM_ATTR debugHeapUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
_debug_info.heap_total = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
|
|
|
|
|
|
_debug_info.heap_free = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
|
|
|
|
|
|
size_t _new_free_min = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
|
|
|
|
|
|
if ((_debug_info.heap_free_min == 0) || (_new_free_min < _debug_info.heap_free_min))
|
|
|
|
|
|
{
|
|
|
|
|
|
_debug_info.heap_free_min = _new_free_min;
|
|
|
|
|
|
_debug_info.heap_min_time = time(nullptr);
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IRAM_ATTR debugBacktraceUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
esp_backtrace_frame_t stk_frame;
|
|
|
|
|
|
esp_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc));
|
|
|
|
|
|
_debug_info.backtrace[0] = esp_cpu_process_stack_pc(stk_frame.pc);
|
|
|
|
|
|
|
|
|
|
|
|
bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) &&
|
|
|
|
|
|
esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)))
|
|
|
|
|
|
? false
|
|
|
|
|
|
: true;
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t i = CONFIG_RESTART_DEBUG_STACK_DEPTH;
|
|
|
|
|
|
while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!esp_backtrace_get_next_frame(&stk_frame))
|
|
|
|
|
|
{
|
|
|
|
|
|
corrupted = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
_debug_info.backtrace[CONFIG_RESTART_DEBUG_STACK_DEPTH - i] = esp_cpu_process_stack_pc(stk_frame.pc);
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IRAM_ATTR debugUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
debugHeapUpdate();
|
|
|
|
|
|
debugBacktraceUpdate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" void __wrap_esp_panic_handler(void *info)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
debugHeapUpdate();
|
|
|
|
|
|
debugBacktraceUpdate();
|
2024-09-20 12:05:34 +03:00
|
|
|
|
bootloop_panic_count += 1;
|
2024-09-20 11:07:08 +03:00
|
|
|
|
// Call the original panic handler function to finish processing this error (creating a core dump for example...)
|
|
|
|
|
|
__real_esp_panic_handler(info);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
re_restart_debug_t debugGet()
|
|
|
|
|
|
{
|
|
|
|
|
|
re_restart_debug_t ret;
|
|
|
|
|
|
memset(&ret, 0, sizeof(re_restart_debug_t));
|
|
|
|
|
|
esp_reset_reason_t esp_reason = esp_reset_reason();
|
|
|
|
|
|
if ((esp_reason != ESP_RST_UNKNOWN) && (esp_reason != ESP_RST_POWERON))
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t i = CONFIG_RESTART_DEBUG_STACK_DEPTH;
|
|
|
|
|
|
ret = _debug_info;
|
|
|
|
|
|
if (_debug_info.heap_total > heap_caps_get_total_size(MALLOC_CAP_DEFAULT))
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(&ret, 0, sizeof(re_restart_debug_t));
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
memset(&_debug_info, 0, sizeof(re_restart_debug_t));
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define CONFIG_MESSAGE_TG_VERSION_DEF "! Устройство запущено\n\nИмя устройства: %s\nПричина перезапуска: %s\nCPU0: %s\nCPU1: %s"
|
|
|
|
|
|
#define CONFIG_MESSAGE_TG_VERSION_HEAP "! Устройство аварийно перезапущено !\n\nИмя устройства: %s\nПричина перезапуска: %s\nCPU0: %s\nCPU1: %s\nHEAP: %s"
|
|
|
|
|
|
#define CONFIG_MESSAGE_TG_VERSION_TRACE "! Устройство аварийно перезапущено !\n\nИмя устройства: %s\nПричина перезапуска: %s\nCPU0: %s\nCPU1: %s\nHEAP: %s\nTRACE: %s"
|
|
|
|
|
|
|
2024-09-20 13:22:49 +03:00
|
|
|
|
#define INFO_MESSAGE_DEBUG "By used -> USERPROFILE/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin xtensa-esp32-elf-addr2line.exe -pfiaC -e .pio/build/esp32_4mb3f/firmware.elf Стэк_адресов"
|
|
|
|
|
|
|
2024-09-20 11:07:08 +03:00
|
|
|
|
char *malloc_stringf(const char *format, ...)
|
|
|
|
|
|
{
|
|
|
|
|
|
char *ret = nullptr;
|
|
|
|
|
|
if (format != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
// get the list of arguments
|
|
|
|
|
|
va_list args1, args2;
|
|
|
|
|
|
va_start(args1, format);
|
|
|
|
|
|
va_copy(args2, args1);
|
|
|
|
|
|
// calculate length of resulting string
|
|
|
|
|
|
int len = vsnprintf(nullptr, 0, format, args1);
|
|
|
|
|
|
va_end(args1);
|
|
|
|
|
|
// allocate memory for string
|
|
|
|
|
|
if (len > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
#if USE_ESP_MALLOC
|
|
|
|
|
|
ret = (char *)esp_malloc(len + 1);
|
|
|
|
|
|
#else
|
|
|
|
|
|
ret = (char *)malloc(len + 1);
|
|
|
|
|
|
#endif
|
|
|
|
|
|
if (ret != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(ret, 0, len + 1);
|
|
|
|
|
|
vsnprintf(ret, len + 1, format, args2);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// rlog_e(tagHEAP, "Failed to format string: out of memory!");
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
va_end(args2);
|
|
|
|
|
|
};
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *statesGetDebugHeap(re_restart_debug_t *debug)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((debug->heap_total > 0) && (debug->heap_total > debug->heap_free))
|
|
|
|
|
|
{
|
|
|
|
|
|
struct tm timeinfo;
|
|
|
|
|
|
localtime_r(&debug->heap_min_time, &timeinfo);
|
|
|
|
|
|
char time_buffer[CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE];
|
|
|
|
|
|
memset(&time_buffer, 0, CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE);
|
|
|
|
|
|
strftime(time_buffer, CONFIG_FORMAT_STRFTIME_DTS_BUFFER_SIZE, CONFIG_FORMAT_DTS, &timeinfo);
|
|
|
|
|
|
|
|
|
|
|
|
double heapTotal = (double)debug->heap_total / 1024;
|
|
|
|
|
|
double heapFree = (double)debug->heap_free / 1024;
|
|
|
|
|
|
double heapFreeMin = (double)debug->heap_free_min / 1024;
|
|
|
|
|
|
|
|
|
|
|
|
return malloc_stringf("Total %.1fkB ; Free %.1fkB (%.1f%%) ; FreeMin %.1fkB (%.1f%%) %s",
|
|
|
|
|
|
heapTotal,
|
|
|
|
|
|
heapFree, 100.0 * (heapFree / heapTotal),
|
|
|
|
|
|
heapFreeMin, 100.0 * (heapFreeMin / heapTotal), time_buffer);
|
|
|
|
|
|
};
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *statesGetDebugTrace(re_restart_debug_t *debug)
|
|
|
|
|
|
{
|
|
|
|
|
|
char *backtrace = nullptr;
|
|
|
|
|
|
char *item = nullptr;
|
|
|
|
|
|
char *temp = nullptr;
|
|
|
|
|
|
for (uint8_t i = 0; i < CONFIG_RESTART_DEBUG_STACK_DEPTH; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (debug->backtrace[i] != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
item = malloc_stringf("0x%08x", debug->backtrace[i]);
|
|
|
|
|
|
if (item)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (backtrace)
|
|
|
|
|
|
{
|
|
|
|
|
|
temp = backtrace;
|
|
|
|
|
|
backtrace = malloc_stringf("%s %s", temp, item);
|
|
|
|
|
|
free(item);
|
|
|
|
|
|
free(temp);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
backtrace = item;
|
|
|
|
|
|
};
|
|
|
|
|
|
item = nullptr;
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
return backtrace;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void printDebugTrace()
|
|
|
|
|
|
{
|
|
|
|
|
|
// esp_register_shutdown_handler(debugUpdate);
|
|
|
|
|
|
re_restart_debug_t debug = debugGet();
|
|
|
|
|
|
char *debug_heap = statesGetDebugHeap(&debug);
|
|
|
|
|
|
char *debug_trace = nullptr;
|
|
|
|
|
|
if (debug_heap)
|
|
|
|
|
|
{
|
|
|
|
|
|
debug_trace = statesGetDebugTrace(&debug);
|
|
|
|
|
|
if (debug_trace)
|
|
|
|
|
|
{
|
|
|
|
|
|
Serial.printf(CONFIG_MESSAGE_TG_VERSION_TRACE,
|
|
|
|
|
|
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
|
|
|
|
|
debug_heap, debug_trace);
|
|
|
|
|
|
// free(debug_trace);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Serial.printf(CONFIG_MESSAGE_TG_VERSION_HEAP,
|
|
|
|
|
|
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
|
|
|
|
|
debug_heap);
|
|
|
|
|
|
};
|
|
|
|
|
|
// free(debug_heap);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Serial.println("DEVICE START");
|
|
|
|
|
|
Serial.printf(CONFIG_MESSAGE_TG_VERSION_DEF,
|
|
|
|
|
|
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-20 13:22:49 +03:00
|
|
|
|
Serial.println(INFO_MESSAGE_DEBUG);
|
|
|
|
|
|
|
2024-09-20 11:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void sendDebugTraceAndFreeMemory( bool postMsg)
|
|
|
|
|
|
{
|
|
|
|
|
|
// esp_register_shutdown_handler(debugUpdate);
|
|
|
|
|
|
re_restart_debug_t debug = debugGet();
|
|
|
|
|
|
char *debug_heap = statesGetDebugHeap(&debug);
|
|
|
|
|
|
char *debug_trace = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
if (debug_heap)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isNetworkActive() && postMsg)
|
|
|
|
|
|
{
|
|
|
|
|
|
debug_trace = statesGetDebugTrace(&debug);
|
|
|
|
|
|
if (debug_trace)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tlgrmItem)
|
|
|
|
|
|
{
|
|
|
|
|
|
char *msg;
|
|
|
|
|
|
msg = malloc_stringf(CONFIG_MESSAGE_TG_VERSION_TRACE,
|
|
|
|
|
|
jsonReadStr(settingsFlashJson, F("name")).c_str(), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
|
|
|
|
|
debug_heap, debug_trace);
|
|
|
|
|
|
tlgrmItem->sendTelegramMsg(false, String(msg));
|
|
|
|
|
|
tlgrmItem->sendTelegramMsg(false, String("Подробности /helpDebug в Telegram_v2"));
|
|
|
|
|
|
free(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
free(debug_trace);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
/*
|
|
|
|
|
|
Serial.printf(CONFIG_MESSAGE_TG_VERSION_HEAP,
|
|
|
|
|
|
jsonReadStr(settingsFlashJson, F("name")), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
|
|
|
|
|
debug_heap);
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (tlgrmItem)
|
|
|
|
|
|
{
|
|
|
|
|
|
char *msg;
|
|
|
|
|
|
msg = malloc_stringf(CONFIG_MESSAGE_TG_VERSION_HEAP,
|
|
|
|
|
|
jsonReadStr(settingsFlashJson, F("name")).c_str(), ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str(),
|
|
|
|
|
|
debug_heap);
|
|
|
|
|
|
tlgrmItem->sendTelegramMsg(false, String(msg));
|
|
|
|
|
|
tlgrmItem->sendTelegramMsg(false, String("Подробности /helpDebug в Telegram_v2"));
|
|
|
|
|
|
free(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
free(debug_heap);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Serial.println("DEVICE START");
|
|
|
|
|
|
// Serial.printf(CONFIG_MESSAGE_TG_VERSION_DEF,
|
|
|
|
|
|
// FIRMWARE_VERSION, ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str());
|
|
|
|
|
|
if (tlgrmItem && isNetworkActive())
|
|
|
|
|
|
{
|
|
|
|
|
|
char *msg;
|
|
|
|
|
|
msg = malloc_stringf(CONFIG_MESSAGE_TG_VERSION_DEF,
|
|
|
|
|
|
WiFi.localIP().toString(), FIRMWARE_VERSION, ESP_getResetReason().c_str(), ESP32GetResetReason(0).c_str(), ESP32GetResetReason(1).c_str());
|
|
|
|
|
|
tlgrmItem->sendTelegramMsg(false, String(msg));
|
|
|
|
|
|
free(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
};*/
|
2024-09-20 12:05:34 +03:00
|
|
|
|
|
2024-09-20 11:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
void printDebugTrace() {}
|
|
|
|
|
|
void sendDebugTraceAndFreeMemory(bool) {}
|
|
|
|
|
|
void IRAM_ATTR debugUpdate() {}
|
|
|
|
|
|
extern "C" void __wrap_esp_panic_handler(void *info)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Call the original panic handler function to finish processing this error (creating a core dump for example...)
|
|
|
|
|
|
__real_esp_panic_handler(info);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif // RESTART_DEBUG_INFO
|
2024-09-20 12:05:34 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" bool verifyRollbackLater(){
|
|
|
|
|
|
Serial.printf("verifyRollbackLater OVERRIDDEN FUNCTION!");
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void verifyFirmware(){
|
|
|
|
|
|
Serial.printf("[SYSTEM] - Checking firmware...\n");
|
|
|
|
|
|
const esp_partition_t *running = esp_ota_get_running_partition();
|
|
|
|
|
|
esp_ota_img_states_t ota_state;
|
|
|
|
|
|
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
|
|
|
|
|
const char* otaState = ota_state == ESP_OTA_IMG_NEW ? "ESP_OTA_IMG_NEW"
|
|
|
|
|
|
: ota_state == ESP_OTA_IMG_PENDING_VERIFY ? "ESP_OTA_IMG_PENDING_VERIFY"
|
|
|
|
|
|
: ota_state == ESP_OTA_IMG_VALID ? "ESP_OTA_IMG_VALID"
|
|
|
|
|
|
: ota_state == ESP_OTA_IMG_INVALID ? "ESP_OTA_IMG_INVALID"
|
|
|
|
|
|
: ota_state == ESP_OTA_IMG_ABORTED ? "ESP_OTA_IMG_ABORTED"
|
|
|
|
|
|
: "ESP_OTA_IMG_UNDEFINED";
|
|
|
|
|
|
Serial.printf( "[System] - Ota state: %s\n",otaState);
|
|
|
|
|
|
|
|
|
|
|
|
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
|
|
|
|
|
if (esp_ota_mark_app_valid_cancel_rollback() == ESP_OK) {
|
|
|
|
|
|
Serial.printf( "[System] - App is valid, rollback cancelled successfully\n");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Serial.printf("[System] - Failed to cancel rollback\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
Serial.printf("[System] - OTA partition has no record in OTA data\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|