## Summary Follow-up https://github.com/crosspoint-reader/crosspoint-reader/pull/1145 - Fix log not being record without USB connected - Bump release log to INFO for more logging details --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
141 lines
3.7 KiB
C++
141 lines
3.7 KiB
C++
#include "HalSystem.h"
|
|
|
|
#include <string>
|
|
|
|
#include "Arduino.h"
|
|
#include "HalStorage.h"
|
|
#include "Logging.h"
|
|
#include "esp_debug_helpers.h"
|
|
#include "esp_private/esp_cpu_internal.h"
|
|
#include "esp_private/esp_system_attr.h"
|
|
#include "esp_private/panic_internal.h"
|
|
|
|
#define MAX_PANIC_STACK_DEPTH 32
|
|
|
|
RTC_NOINIT_ATTR char panicMessage[256];
|
|
RTC_NOINIT_ATTR HalSystem::StackFrame panicStack[MAX_PANIC_STACK_DEPTH];
|
|
|
|
extern "C" {
|
|
|
|
void __real_panic_abort(const char* message);
|
|
void __real_panic_print_backtrace(const void* frame, int core);
|
|
|
|
static DRAM_ATTR const char PANIC_REASON_UNKNOWN[] = "(unknown panic reason)";
|
|
void IRAM_ATTR __wrap_panic_abort(const char* message) {
|
|
if (!message) message = PANIC_REASON_UNKNOWN;
|
|
// IRAM-safe bounded copy (strncpy is not IRAM-safe in panic context)
|
|
int i = 0;
|
|
for (; i < (int)sizeof(panicMessage) - 1 && message[i]; i++) {
|
|
panicMessage[i] = message[i];
|
|
}
|
|
panicMessage[i] = '\0';
|
|
|
|
__real_panic_abort(message);
|
|
}
|
|
|
|
void IRAM_ATTR __wrap_panic_print_backtrace(const void* frame, int core) {
|
|
if (!frame) {
|
|
__real_panic_print_backtrace(frame, core);
|
|
return;
|
|
}
|
|
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
|
|
panicStack[i].sp = 0;
|
|
}
|
|
|
|
// Copied from components/esp_system/port/arch/riscv/panic_arch.c
|
|
uint32_t sp = (uint32_t)((RvExcFrame*)frame)->sp;
|
|
const int per_line = 8;
|
|
int depth = 0;
|
|
for (int x = 0; x < 1024; x += per_line * sizeof(uint32_t)) {
|
|
uint32_t* spp = (uint32_t*)(sp + x);
|
|
// panic_print_hex(sp + x);
|
|
// panic_print_str(": ");
|
|
panicStack[depth].sp = sp + x;
|
|
for (int y = 0; y < per_line; y++) {
|
|
// panic_print_str("0x");
|
|
// panic_print_hex(spp[y]);
|
|
// panic_print_str(y == per_line - 1 ? "\r\n" : " ");
|
|
panicStack[depth].spp[y] = spp[y];
|
|
}
|
|
|
|
depth++;
|
|
if (depth >= MAX_PANIC_STACK_DEPTH) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
__real_panic_print_backtrace(frame, core);
|
|
}
|
|
}
|
|
|
|
namespace HalSystem {
|
|
|
|
void begin() {
|
|
// This is mostly for the first boot, we need to initialize the panic info and logs to empty state
|
|
// If we reboot from a panic state, we want to keep the panic info until we successfully dump it to the SD card, use
|
|
// `clearPanic()` to clear it after dumping
|
|
if (!isRebootFromPanic()) {
|
|
clearPanic();
|
|
}
|
|
}
|
|
|
|
void checkPanic() {
|
|
if (isRebootFromPanic()) {
|
|
auto panicInfo = getPanicInfo(true);
|
|
auto file = Storage.open("/crash_report.txt", O_WRITE | O_CREAT | O_TRUNC);
|
|
if (file) {
|
|
file.write(panicInfo.c_str(), panicInfo.size());
|
|
file.close();
|
|
LOG_INF("SYS", "Dumped panic info to SD card");
|
|
} else {
|
|
LOG_ERR("SYS", "Failed to open crash_report.txt for writing");
|
|
}
|
|
}
|
|
}
|
|
|
|
void clearPanic() {
|
|
panicMessage[0] = '\0';
|
|
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
|
|
panicStack[i].sp = 0;
|
|
}
|
|
clearLastLogs();
|
|
}
|
|
|
|
std::string getPanicInfo(bool full) {
|
|
if (!full) {
|
|
return panicMessage;
|
|
} else {
|
|
std::string info;
|
|
|
|
info += "CrossPoint version: " CROSSPOINT_VERSION;
|
|
info += "\n\nPanic reason: " + std::string(panicMessage);
|
|
info += "\n\nLast logs:\n" + getLastLogs();
|
|
info += "\n\nStack memory:\n";
|
|
|
|
auto toHex = [](uint32_t value) {
|
|
char buffer[9];
|
|
snprintf(buffer, sizeof(buffer), "%08X", value);
|
|
return std::string(buffer);
|
|
};
|
|
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
|
|
if (panicStack[i].sp == 0) {
|
|
break;
|
|
}
|
|
info += "0x" + toHex(panicStack[i].sp) + ": ";
|
|
for (size_t j = 0; j < 8; j++) {
|
|
info += "0x" + toHex(panicStack[i].spp[j]) + " ";
|
|
}
|
|
info += "\n";
|
|
}
|
|
|
|
return info;
|
|
}
|
|
}
|
|
|
|
bool isRebootFromPanic() {
|
|
const auto resetReason = esp_reset_reason();
|
|
return resetReason == ESP_RST_PANIC || resetReason == ESP_RST_CPU_LOCKUP;
|
|
}
|
|
|
|
} // namespace HalSystem
|