mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-02 13:20:51 +00:00
Add generic mg_health report for mdash
This commit is contained in:
1 parent
60c75a22b8
commit
4e7c664455
16 files changed
+1225
-230
No files matched your search
+117
-72
@@ -4945,44 +4945,25 @@ void mg_ota_device_id(char *buf, size_t len);
|
||||
void mg_ota_poll(struct mg_mgr *);
|
||||
// Device health monitoring
|
||||
//
|
||||
// Keeps a small record in a RAM region that survives a warm reset, so a device
|
||||
// can tell why it restarted. The record holds a boot counter, the uptime this
|
||||
// boot has reached, and the reset reason reported by the hardware. A crash
|
||||
// loop, a hang loop and a marginal power supply each leave a different mark.
|
||||
//
|
||||
// Put MG_HEALTH_INIT() in main(), right after clock and memory init:
|
||||
//
|
||||
// ```c
|
||||
// int main(void) {
|
||||
// hal_clock_init();
|
||||
// MG_HEALTH_INIT();
|
||||
// ...
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The record must live in RAM that startup code neither copies nor zeroes.
|
||||
// See tutorials/stm32/nucleo-h723zg/minimal/link.ld for the .mg_health region,
|
||||
// and tutorials/stm32/nucleo-h723zg/minimal/mongoose_config.h for the
|
||||
// reset-reason hooks.
|
||||
//
|
||||
// On Cortex-M, a fault handler can record the crash: it sets reset_reason to
|
||||
// MG_HEALTH_RESET_FAULT and walks the stack into backtrace[]. See
|
||||
// tutorials/stm32/nucleo-h723zg/minimal/main.c for a sample HardFault_Handler.
|
||||
// A health provider owns the report format and returns it as an opaque blob.
|
||||
// Applications and transports use mg_health_get_blob() without knowing how the
|
||||
// report was collected or encoded.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define MG_HEALTH_NONE 0
|
||||
#define MG_HEALTH_CORTEX 1
|
||||
|
||||
#ifndef MG_HEALTH
|
||||
#define MG_HEALTH MG_HEALTH_NONE
|
||||
#endif
|
||||
|
||||
#ifndef MG_HEALTH_MAGIC
|
||||
#define MG_HEALTH_MAGIC {'M', 'G', 'H', '3'} // '3' is the layout version
|
||||
#endif
|
||||
|
||||
// Places the record in RAM that survives a reset. Define in mongoose_config.h
|
||||
// to match the linker script, e.g. __attribute__((section(".mg_health")))
|
||||
#ifndef MG_HEALTH_RAM
|
||||
#define MG_HEALTH_RAM
|
||||
#endif
|
||||
|
||||
// Why the device restarted. Hardware usually reports several flags at once,
|
||||
// so these are ordered by how much they tell you: the most specific cause a
|
||||
// device reports wins
|
||||
@@ -4997,15 +4978,16 @@ enum mg_health_reason {
|
||||
MG_HEALTH_RESET_FAULT // Fault handler ran, see regs[] and saved_stack
|
||||
};
|
||||
|
||||
#define MG_HEALTH_BACKTRACE 20 // Return addresses in mg_health::backtrace
|
||||
typedef struct mg_str mg_health_blob;
|
||||
|
||||
struct mg_health {
|
||||
char magic[4]; // MG_HEALTH_MAGIC when the record holds valid data
|
||||
uint32_t reset_reason; // enum mg_health_reason that started this boot
|
||||
uint32_t backtrace[MG_HEALTH_BACKTRACE]; // Crash backtrace, frame 0 first
|
||||
char magic[4];
|
||||
mg_health_blob (*get_blob)(void *);
|
||||
void *fn_data;
|
||||
uint32_t reset_reason;
|
||||
};
|
||||
|
||||
extern struct mg_health mg_health_record; // Defined in health.c
|
||||
extern struct mg_health mg_health_record;
|
||||
|
||||
// Return true if the record holds valid data, i.e. it survived the reset and
|
||||
// was written by this firmware layout
|
||||
@@ -5015,6 +4997,14 @@ static inline bool mg_health_valid(void) {
|
||||
sizeof(mg_health_record.magic)) == 0;
|
||||
}
|
||||
|
||||
// Select and initialise the configured health provider. Call after
|
||||
// initializing the board-specific persistent-storage
|
||||
void mg_health_init(void);
|
||||
|
||||
// Return the provider's opaque report. The returned memory is provider-owned
|
||||
// and remains valid until the next call to this function
|
||||
struct mg_str mg_health_get_blob(void);
|
||||
|
||||
static inline int mg_health_reason(void) {
|
||||
return mg_health_valid() ? (int) mg_health_record.reset_reason
|
||||
: MG_HEALTH_RESET_UNKNOWN;
|
||||
@@ -5022,48 +5012,103 @@ static inline int mg_health_reason(void) {
|
||||
|
||||
static inline const char *mg_health_reason_str(int reason) {
|
||||
switch (reason) {
|
||||
case MG_HEALTH_RESET_POWER: return "power";
|
||||
case MG_HEALTH_RESET_BROWNOUT: return "brownout";
|
||||
case MG_HEALTH_RESET_PIN: return "pin";
|
||||
case MG_HEALTH_RESET_SOFTWARE: return "software";
|
||||
case MG_HEALTH_RESET_LOWPOWER: return "lowpower";
|
||||
case MG_HEALTH_RESET_WATCHDOG: return "watchdog";
|
||||
case MG_HEALTH_RESET_FAULT: return "fault";
|
||||
default: return "unknown";
|
||||
case MG_HEALTH_RESET_POWER:
|
||||
return "power";
|
||||
case MG_HEALTH_RESET_BROWNOUT:
|
||||
return "brownout";
|
||||
case MG_HEALTH_RESET_PIN:
|
||||
return "pin";
|
||||
case MG_HEALTH_RESET_SOFTWARE:
|
||||
return "software";
|
||||
case MG_HEALTH_RESET_LOWPOWER:
|
||||
return "lowpower";
|
||||
case MG_HEALTH_RESET_WATCHDOG:
|
||||
return "watchdog";
|
||||
case MG_HEALTH_RESET_FAULT:
|
||||
return "fault";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Start a new boot: validate the record, count the boot, store the reset
|
||||
// reason. The current boot moves to prev_* slots first, so the previous
|
||||
// boot's uptime and reason stay readable. Called by MG_HEALTH_INIT()
|
||||
static inline void mg_health_init(void) {
|
||||
char magic[] = MG_HEALTH_MAGIC;
|
||||
// struct mg_health *h = mg_health_get();
|
||||
if (!mg_health_valid()) { // First boot, or RAM lost its contents
|
||||
memset(&mg_health_record, 0, sizeof(mg_health_record));
|
||||
memcpy(mg_health_record.magic, magic, sizeof(mg_health_record.magic));
|
||||
}
|
||||
// h->prev_uptime = h->uptime;
|
||||
// h->prev_reason = h->reason;
|
||||
// h->counter++;
|
||||
// h->uptime = 0;
|
||||
// h->reason = mg_health_decode_reason();
|
||||
// MG_HEALTH_RESET_CLEAR();
|
||||
}
|
||||
|
||||
// // Record that the main loop is still alive. Called from mg_mgr_poll(), so a
|
||||
// // hung application leaves uptime frozen at the hang
|
||||
// extern uint64_t mg_health_next_ms; // Defined in health.c
|
||||
|
||||
// static inline void mg_health_uptime(uint64_t now_ms) {
|
||||
// struct mg_health *h = mg_health_get();
|
||||
// if (now_ms >= mg_health_next_ms && mg_health_valid()) {
|
||||
// mg_health_next_ms = now_ms + 1000;
|
||||
// h->uptime++;
|
||||
// }
|
||||
// }
|
||||
|
||||
#define MG_HEALTH_INIT() mg_health_init()
|
||||
|
||||
|
||||
|
||||
|
||||
#define MG_HEALTH_CORTEX_VERSION 1U
|
||||
|
||||
#ifndef MG_HEALTH_CORTEX_STORAGE
|
||||
#define MG_HEALTH_CORTEX_STORAGE NULL
|
||||
#endif
|
||||
|
||||
#ifndef MG_HEALTH_CORTEX_STORAGE_SIZE
|
||||
#define MG_HEALTH_CORTEX_STORAGE_SIZE 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_HEALTH_CORTEX_STACK_WORDS
|
||||
#define MG_HEALTH_CORTEX_STACK_WORDS 980U
|
||||
#endif
|
||||
|
||||
#ifndef MG_HEALTH_CORTEX_REPORT_SIZE
|
||||
#define MG_HEALTH_CORTEX_REPORT_SIZE 16384U
|
||||
#endif
|
||||
|
||||
// Storage operations are deliberately format-agnostic. H723 uses the default
|
||||
// direct-memory implementation; boards with different retained storage can
|
||||
// replace these callbacks before calling MG_HEALTH_INIT()
|
||||
struct mg_health_cortex {
|
||||
void *storage;
|
||||
size_t storage_size;
|
||||
bool (*init)(void *, size_t);
|
||||
bool (*read)(const void *, size_t, void *, size_t);
|
||||
bool (*write)(void *, size_t, const void *, size_t);
|
||||
};
|
||||
|
||||
struct mg_health_cortex_record {
|
||||
char magic[4];
|
||||
uint32_t version;
|
||||
|
||||
uint32_t cpuid;
|
||||
uint32_t exception_sp;
|
||||
uint32_t sp;
|
||||
uint32_t exc_return;
|
||||
int32_t exception_valid;
|
||||
int32_t stack_valid;
|
||||
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
uint32_t r2;
|
||||
uint32_t r3;
|
||||
uint32_t r4;
|
||||
uint32_t r5;
|
||||
uint32_t r6;
|
||||
uint32_t r7;
|
||||
uint32_t r8;
|
||||
uint32_t r9;
|
||||
uint32_t r10;
|
||||
uint32_t r11;
|
||||
uint32_t r12;
|
||||
uint32_t lr;
|
||||
uint32_t pc;
|
||||
uint32_t psr;
|
||||
|
||||
uint32_t cfsr;
|
||||
uint32_t hfsr;
|
||||
uint32_t dfsr;
|
||||
uint32_t afsr;
|
||||
uint32_t bfar;
|
||||
uint32_t mmfar;
|
||||
uint32_t abfsr;
|
||||
|
||||
uint32_t stack_word_count;
|
||||
uint32_t stack_words[MG_HEALTH_CORTEX_STACK_WORDS];
|
||||
};
|
||||
|
||||
extern struct mg_health_cortex mg_health_cortex;
|
||||
|
||||
void mg_health_cortex_init(struct mg_health_cortex *);
|
||||
struct mg_str mg_health_cortex_get_blob(void *);
|
||||
// Cloud connector API to https://mdash.net - device management cloud
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user