DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
hw_health.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file hw_health.h
6 * @brief Hardware-health diagnostics: rail droop, SPI CRC backoff, GPIO short, cap leakage
7 * (DETWS_ENABLE_HW_HEALTH).
8 *
9 * Four pure decision cores an app feeds with samples it reads from the hardware (ADC millivolts, a SPI
10 * CRC pass/fail, a driven-vs-readback GPIO level, a capacitor decay time). Each turns raw measurements
11 * into an actionable verdict for a "/health" panel or a fail-safe hook, without touching a peripheral
12 * itself:
13 *
14 * - **Power-rail voltage-drop logger**: track a rail's worst droop and count sag / brownout crossings.
15 * - **SPI-bus CRC audit + clock backoff**: a hysteretic state machine that halves the SPI clock after a
16 * run of CRC failures and steps it back up after a run of good transfers.
17 * - **GPIO short-circuit test**: compare a driven level to its readback to spot a short to ground / Vcc.
18 * - **Capacitor-leakage diag**: compare a measured RC decay time to the expected one to spot a leaky
19 * cap (too fast) or a high-ESR / open path (too slow).
20 *
21 * Pure, zero heap, no stdlib, host-testable.
22 */
23
24#ifndef DETERMINISTICESPASYNCWEBSERVER_HW_HEALTH_H
25#define DETERMINISTICESPASYNCWEBSERVER_HW_HEALTH_H
26
27#include "ServerConfig.h"
28#include <stddef.h>
29#include <stdint.h>
30
31#if DETWS_ENABLE_HW_HEALTH
32
33/** @brief Rail sample verdict (the sole return of detws_hwhealth_rail_sample). */
34enum class HwRailVerdict : uint8_t
35{
36 HW_RAIL_OK = 0, ///< at or above the warn threshold.
37 HW_RAIL_SAG = 1, ///< below warn, at or above crit.
38 HW_RAIL_BROWNOUT = 2 ///< below the crit threshold.
39};
40
41/** @brief GPIO short-circuit verdict (the sole return of detws_hwhealth_gpio_short). */
42enum class HwGpioVerdict : uint8_t
43{
44 HW_GPIO_OK = 0, ///< readback matches the driven level.
45 HW_GPIO_SHORT_GND = 1, ///< drove high, read low: shorted to ground.
46 HW_GPIO_SHORT_VCC = 2 ///< drove low, read high: shorted to Vcc.
47};
48
49/** @brief Capacitor-leakage verdict (the sole return of detws_hwhealth_cap_leak). */
50enum class HwCapVerdict : uint8_t
51{
52 HW_CAP_OK = 0, ///< decay time within tolerance of expected.
53 HW_CAP_LEAK = 1, ///< decays too fast: leaky capacitor.
54 HW_CAP_HIGH_ESR = 2 ///< decays too slow: high-ESR / open charge path.
55};
56
57/** @brief Rolling monitor for one power rail (in millivolts). */
58struct HwRailMonitor
59{
60 uint32_t nominal_mv;
61 uint32_t warn_mv; ///< below this -> SAG.
62 uint32_t crit_mv; ///< below this -> BROWNOUT.
63 uint32_t min_mv; ///< lowest sample seen (worst droop).
64 uint32_t sag_events;
65 uint32_t brownout_events;
66};
67
68/** @brief Hysteretic SPI clock backoff state. */
69struct HwSpiBackoff
70{
71 uint32_t hz; ///< current clock.
72 uint32_t min_hz; ///< floor.
73 uint32_t max_hz; ///< ceiling.
74 uint16_t fail_streak;
75 uint16_t ok_streak;
76 uint16_t fail_trip; ///< consecutive failures that halve the clock.
77 uint16_t ok_trip; ///< consecutive successes that double the clock.
78};
79
80/** @brief Initialize a rail monitor. @p min_mv starts at @p nominal_mv. */
81void detws_hwhealth_rail_init(HwRailMonitor *m, uint32_t nominal_mv, uint32_t warn_mv, uint32_t crit_mv);
82
83/** @brief Record one rail sample; updates the worst-droop min + counters. @return HW_RAIL_*. */
84HwRailVerdict detws_hwhealth_rail_sample(HwRailMonitor *m, uint32_t mv);
85
86/** @brief Serialize a rail monitor: `{"nominal_mv":..,"min_mv":..,"sag":..,"brownout":..}`. */
87size_t detws_hwhealth_rail_json(const HwRailMonitor *m, char *out, size_t cap);
88
89/** @brief Initialize a SPI backoff state machine. */
90void detws_hwhealth_spi_init(HwSpiBackoff *s, uint32_t start_hz, uint32_t min_hz, uint32_t max_hz, uint16_t fail_trip,
91 uint16_t ok_trip);
92
93/** @brief Feed one transfer's CRC result; adjusts the clock with hysteresis. @return the new clock (hz). */
94uint32_t detws_hwhealth_spi_result(HwSpiBackoff *s, bool crc_ok);
95
96/** @brief Short-circuit test from a driven level and its readback. @return HW_GPIO_*. */
97HwGpioVerdict detws_hwhealth_gpio_short(bool driven_high, bool read_high);
98
99/**
100 * @brief Leakage test comparing a measured RC decay time to the expected one.
101 * @param measured_ms observed decay time.
102 * @param expected_ms nominal decay time for a healthy cap.
103 * @param tol_pct tolerance band (percent) around expected.
104 * @return HW_CAP_OK / HW_CAP_LEAK (too fast) / HW_CAP_HIGH_ESR (too slow).
105 */
106HwCapVerdict detws_hwhealth_cap_leak(uint32_t measured_ms, uint32_t expected_ms, uint8_t tol_pct);
107
108#endif // DETWS_ENABLE_HW_HEALTH
109#endif // DETERMINISTICESPASYNCWEBSERVER_HW_HEALTH_H
User-facing configuration for DeterministicESPAsyncWebServer.