DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
wearlevel.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 wearlevel.h
6 * @brief Flash wear-leveling slot selector (DETWS_ENABLE_WEARLEVEL).
7 *
8 * Flash/NVS cells wear out after a bounded number of erase cycles, so a device that repeatedly writes a
9 * record (a log line, a config snapshot, a counter) to the *same* location burns that block out early.
10 * This is the pure core of wear leveling: given a per-slot erase/write count, `detws_wearlevel_pick`
11 * returns the least-worn slot to write next, so writes spread evenly and the whole region ages together.
12 *
13 * The app owns the actual slots (NVS keys, flash sectors, VFS files) and the persisted counts; this core
14 * just decides *where* the next write goes and reports the wear imbalance. Pure, zero heap, no stdlib,
15 * so it is fully host-testable. It composes with services/vfs (the storage medium) and services/logbuf
16 * (whose sink can offload to a wear-leveled store).
17 */
18
19#ifndef DETERMINISTICESPASYNCWEBSERVER_WEARLEVEL_H
20#define DETERMINISTICESPASYNCWEBSERVER_WEARLEVEL_H
21
22#include "ServerConfig.h"
23#include <stddef.h>
24#include <stdint.h>
25
26#if DETWS_ENABLE_WEARLEVEL
27
28/**
29 * @brief Pick the least-worn slot to write next.
30 * @param counts per-slot write/erase counts (length @p n); the app persists these across boots.
31 * @param n number of slots.
32 * @return the index of the slot with the lowest count (ties resolve to the lowest index), or 0 if
33 * @p counts is null or @p n is 0.
34 *
35 * Round-robins naturally: after writing to the chosen slot the app bumps its count (detws_wearlevel_mark),
36 * so the next pick moves on, and the region wears uniformly.
37 */
38size_t detws_wearlevel_pick(const uint32_t *counts, size_t n);
39
40/** @brief Record a write to slot @p idx (saturating increment, so a count never wraps to 0). */
41void detws_wearlevel_mark(uint32_t *counts, size_t n, size_t idx);
42
43/**
44 * @brief Wear imbalance = max count - min count across the slots (0 = perfectly level).
45 *
46 * A monotone health metric for a /health-style endpoint: it stays small under `pick`+`mark` and grows
47 * if the app writes off-policy.
48 */
49uint32_t detws_wearlevel_spread(const uint32_t *counts, size_t n);
50
51#endif // DETWS_ENABLE_WEARLEVEL
52#endif // DETERMINISTICESPASYNCWEBSERVER_WEARLEVEL_H
User-facing configuration for DeterministicESPAsyncWebServer.