mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-28 12:30:58 +00:00
health record support
This commit is contained in:
1 parent
6814b44b03
commit
1e99974b83
17 files changed
+748
-17
No files matched your search
@@ -133,7 +133,7 @@ int main(void)
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
(void) MX_ETH_Init; // Don't use that stuff, Mongoose handle Ethernet
|
||||
MX_ETH_Init();
|
||||
MX_RNG_Init();
|
||||
MX_USART3_UART_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
# Copyright (c) 2026 Cesanta Software Limited
|
||||
# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/
|
||||
|
||||
MGDIR = ../../../..
|
||||
|
||||
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
|
||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
|
||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include -Imongoose
|
||||
CFLAGS += -I. -I$(MGDIR) -Icmsis_core/CMSIS/Core/Include -Icmsis_h7/Include
|
||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
||||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nosys.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
SOURCES = main.c hal.c
|
||||
SOURCES += cmsis_h7/Source/Templates/gcc/startup_stm32h723xx.s
|
||||
SOURCES += mongoose/mongoose.c
|
||||
|
||||
SOURCES += $(MGDIR)/mongoose.c
|
||||
|
||||
all build example: firmware.bin
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
cp ../../../../mongoose.[ch] mongoose/
|
||||
|
||||
firmware.elf: cmsis_core cmsis_h7 hal.h link.ld Makefile $(SOURCES) mongoose/mongoose.h
|
||||
firmware.elf: cmsis_core cmsis_h7 hal.h link.ld Makefile $(SOURCES) $(MGDIR)/mongoose.h mongoose_config.h
|
||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
|
||||
|
||||
firmware.bin: firmware.elf
|
||||
@@ -36,7 +34,7 @@ cmsis_h7:
|
||||
git clone -q -c advice.detachedHead=false --depth 1 -b v1.10.6 https://github.com/STMicroelectronics/cmsis_device_h7 $@
|
||||
|
||||
clean:
|
||||
rm -rf firmware.* cmsis_* mongoose/mongoose.*
|
||||
rm -rf firmware.* cmsis_*
|
||||
|
||||
|
||||
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
|
||||
|
||||
@@ -23,6 +23,10 @@ SECTIONS {
|
||||
|
||||
.eth_ram : { *(.eth_ram .eth_ram*) } > ram_d1 AT > flash
|
||||
|
||||
/* Health record. NOLOAD and in unused DTCM, so startup code neither copies
|
||||
nor zeroes it and the contents survive a warm reset */
|
||||
.mg_health (NOLOAD) : { KEEP(*(.mg_health .mg_health*)) } > dtcmram
|
||||
|
||||
. = ALIGN(8);
|
||||
_end = .;
|
||||
}
|
||||
@@ -24,10 +24,54 @@ static void log_fn(char ch, void *param) {
|
||||
static void blink_task(void) {
|
||||
static uint64_t blink_timer = 0;
|
||||
if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) {
|
||||
hal_gpio_toggle(LED1);
|
||||
hal_gpio_toggle(LED2);
|
||||
}
|
||||
}
|
||||
|
||||
// Fault handler body. Runs in exception context: no printf, no malloc, no
|
||||
// blocking calls. Records the crash reason and a backtrace into the health
|
||||
// record, then resets.
|
||||
// "used" keeps the linker from garbage-collecting this section: the only
|
||||
// reference is the "b fault_c" branch in the naked handler below
|
||||
__attribute__((used, noinline)) static void fault_c(uint32_t *sp) {
|
||||
extern uint8_t _estack; // End of the main RAM region, defined in link.ld
|
||||
size_t n = 0;
|
||||
mg_health_record.reset_reason = MG_HEALTH_RESET_FAULT;
|
||||
// Frame 0 is the faulting PC, frame 1 the caller's LR. Deeper frames come
|
||||
// from a heuristic stack walk: BL pushes an odd return address that lives
|
||||
// in flash. A stack word that merely looks like an address shows up as a
|
||||
// bogus frame when symbolised, which is easy to filter by eye
|
||||
mg_health_record.backtrace[n++] = sp[6] & ~1U; // Stacked PC
|
||||
mg_health_record.backtrace[n++] = sp[5] & ~1U; // Stacked LR
|
||||
for (uint32_t *p = sp + 8;
|
||||
n < MG_HEALTH_BACKTRACE &&
|
||||
(uintptr_t) p < (uintptr_t) sp + 4096U && // Bound the scan
|
||||
(uintptr_t) p < (uintptr_t) &_estack; // Stay in RAM
|
||||
p++) {
|
||||
uint32_t v = *p;
|
||||
if ((v & 1U) && v >= 0x08000000U && v < 0x08000000U + 1024U * 1024U) {
|
||||
mg_health_record.backtrace[n++] = v & ~1U;
|
||||
}
|
||||
}
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
// Common fault entry. EXC_RETURN bit 2 tells which stack was in use:
|
||||
// 0 = MSP, 1 = PSP. Load the faulting SP into r0 and hand it to fault_c()
|
||||
__attribute__((naked)) void HardFault_Handler(void) {
|
||||
__asm volatile(
|
||||
"tst lr, #4\n\t" // Test EXC_RETURN bit 2
|
||||
"ite eq\n\t" // If zero, use MSP; else PSP
|
||||
"mrseq r0, msp\n\t"
|
||||
"mrsne r0, psp\n\t"
|
||||
"b fault_c\n\t");
|
||||
}
|
||||
|
||||
// Route the other fault types through the same entry point
|
||||
void MemManage_Handler(void) __attribute__((alias("HardFault_Handler")));
|
||||
void BusFault_Handler(void) __attribute__((alias("HardFault_Handler")));
|
||||
void UsageFault_Handler(void) __attribute__((alias("HardFault_Handler")));
|
||||
|
||||
uint64_t mg_millis(void) {
|
||||
return hal_get_tick();
|
||||
}
|
||||
@@ -70,6 +114,15 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
|
||||
int main(void) {
|
||||
hal_clock_init();
|
||||
|
||||
// Enable MemManage, BusFault and UsageFault so faults are precise and
|
||||
// routed to their own handlers instead of escalating to HardFault
|
||||
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk |
|
||||
SCB_SHCSR_USGFAULTENA_Msk;
|
||||
|
||||
MG_OTA_BOOT_CHECK(); // Must be called after clock init
|
||||
MG_HEALTH_INIT(); // Must be called after clock init
|
||||
|
||||
hal_uart_init(UART_DEBUG, UART_DEBUG_TX_PIN, UART_DEBUG_RX_PIN, 115200);
|
||||
mg_log_set_fn(log_fn, UART_DEBUG);
|
||||
hal_rng_init();
|
||||
@@ -79,8 +132,17 @@ int main(void) {
|
||||
hal_gpio_output(LED3);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
|
||||
MG_OTA_BOOT_CHECK(); // Must be called after clock init
|
||||
// Report the previous boot's crash backtrace, if any
|
||||
if (mg_health_reason() == MG_HEALTH_RESET_FAULT) {
|
||||
MG_INFO(("Previous boot faulted. Backtrace:"));
|
||||
for (int i = 0; i < MG_HEALTH_BACKTRACE; i++) {
|
||||
if (mg_health_record.backtrace[i] == 0) break;
|
||||
MG_INFO((" #%d 0x%08lx", i,
|
||||
(unsigned long) mg_health_record.backtrace[i]));
|
||||
}
|
||||
// * (volatile uint32_t *) 0 = 123; // Deliberate fault: write to unmapped memory
|
||||
}
|
||||
// for (;;) (void) 0;
|
||||
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
|
||||
+10
@@ -44,6 +44,16 @@
|
||||
#define MG_OTA_STATE_GET() (RTC->BKP0R)
|
||||
#define MG_OTA_STATE_SET(v) (RTC->BKP0R = (uint32_t) (v))
|
||||
|
||||
// Health record lives in the .mg_health region, see link.ld
|
||||
#define MG_HEALTH_RAM __attribute__((section(".mg_health")))
|
||||
|
||||
// mdash device token
|
||||
#define MG_ENABLE_MDASH 1
|
||||
|
||||
#ifndef MG_MDASH_KEY
|
||||
#define MG_MDASH_KEY "" // Set this
|
||||
#endif
|
||||
|
||||
// Construct MAC address from the MCU unique ID
|
||||
#define MGUID ((uint32_t *) UID_BASE)
|
||||
#define MG_SET_MAC_ADDRESS(mac) \
|
||||
Reference in new issue
Block a user