15#if PC_ENABLE_GUARDRAILS
20#include "esp_heap_caps.h"
21#include "esp_system.h"
22#include "freertos/FreeRTOS.h"
23#include "freertos/task.h"
25uint8_t pc_guardrail_eval(
const pc_health *h, uint32_t heap_min, uint32_t frag_min_block, uint32_t stack_min)
27 uint8_t b = pc_breach::PC_BREACH_NONE;
32 if (h->free_heap < heap_min)
34 b |= pc_breach::PC_BREACH_HEAP;
36 if (h->largest_free_block < frag_min_block)
38 b |= pc_breach::PC_BREACH_FRAG;
40 if (h->stack_free < stack_min)
42 b |= pc_breach::PC_BREACH_STACK;
47int pc_health_json(
const pc_health *h,
char *out,
size_t cap)
58 pc_sb sb_out = {out, cap, 0,
true};
60 pc_sb_u32(&sb_out, (uint32_t)((
unsigned)h->free_heap));
61 pc_sb_put(&sb_out,
",\"min_free_heap\":");
62 pc_sb_u32(&sb_out, (uint32_t)((
unsigned)h->min_free_heap));
63 pc_sb_put(&sb_out,
",\"largest_free_block\":");
64 pc_sb_u32(&sb_out, (uint32_t)((
unsigned)h->largest_free_block));
66 pc_sb_u32(&sb_out, (uint32_t)((
unsigned)h->stack_free));
87 pc_breach_fn cb =
nullptr;
92void pc_guardrails_sample(pc_health *h)
98 h->free_heap = esp_get_free_heap_size();
99 h->min_free_heap = esp_get_minimum_free_heap_size();
100 h->largest_free_block = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT);
101 h->stack_free = (uint32_t)uxTaskGetStackHighWaterMark(
nullptr) *
sizeof(StackType_t);
104void pc_guardrails_begin(pc_breach_fn cb)
109uint8_t pc_guardrails_check(
void)
112 pc_guardrails_sample(&h);
114 if (b != pc_breach::PC_BREACH_NONE && s_gr.cb)
123void pc_guardrails_sample(pc_health *h)
130void pc_guardrails_begin(pc_breach_fn)
133uint8_t pc_guardrails_check(
void)
135 return pc_breach::PC_BREACH_NONE;
Runtime heap/stack guardrails (PC_ENABLE_GUARDRAILS).
#define PC_GUARDRAIL_HEAP_MIN
Free-heap floor (bytes); below this trips the heap guardrail.
#define PC_GUARDRAIL_FRAG_MIN_BLOCK
Largest-free-block floor (bytes); below this trips the fragmentation guardrail.
#define PC_GUARDRAIL_STACK_MIN
Task remaining-stack floor (bytes); below this trips the stack guardrail.
Bounded no-heap string builder that fails closed on overflow (one shared copy).
size_t pc_sb_finish(pc_sb *b)
NUL-terminate and return the built length, or 0 if the build overflowed.
void pc_sb_put(pc_sb *b, const char *s)
Append NUL-terminated s; leaves the buffer untouched and clears ok if it would not fit.
void pc_sb_u32(pc_sb *b, uint32_t v)
Append v as decimal (no leading zeros; "0" for zero).
Bump-append target; ok latches false once an append would overflow cap.