DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
partition_monitor.cpp
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 partition_monitor.cpp
6 * @brief Partition-map kind classifier, JSON serializer, and flash walk.
7 *
8 * The classifier and serializer are pure (host-tested); the walk uses
9 * esp_partition / esp_ota_ops on ESP32 and is a no-op on host builds. No server
10 * dependency lives here - the route is in partition_monitor_routes.cpp.
11 */
12
14
15#if DETWS_ENABLE_PARTITION_MONITOR
16
17#include <stdarg.h>
18#include <stdio.h>
19#include <string.h>
20
21// esp_partition type/subtype constants (mirrors esp_partition_type_t/subtype_t so
22// the classifier stays pure and host-testable without the IDF headers).
23const char *detws_partition_kind(uint8_t type, uint8_t subtype)
24{
25 if (type == 0) // ESP_PARTITION_TYPE_APP
26 {
27 if (subtype == 0x00)
28 return "factory";
29 if (subtype >= 0x10 && subtype <= 0x1F)
30 return "ota";
31 if (subtype == 0x20)
32 return "test";
33 return "app";
34 }
35 switch (subtype) // ESP_PARTITION_TYPE_DATA
36 {
37 case 0x00:
38 return "otadata";
39 case 0x01:
40 return "phy";
41 case 0x02:
42 return "nvs";
43 case 0x03:
44 return "coredump";
45 case 0x04:
46 return "nvs_keys";
47 case 0x81:
48 return "fat";
49 case 0x82:
50 return "spiffs";
51 case 0x83:
52 return "littlefs";
53 default:
54 return "data";
55 }
56}
57
58static int json_append(char *out, size_t cap, size_t *pos, const char *fmt, ...)
59{
60 if (*pos >= cap)
61 return -1;
62 va_list ap;
63 va_start(ap, fmt);
64 int w = vsnprintf(out + *pos, cap - *pos, fmt, ap);
65 va_end(ap);
66 if (w < 0 || (size_t)w >= cap - *pos)
67 return -1;
68 *pos += (size_t)w;
69 return 0;
70}
71
72int detws_partition_json(const DetwsPartitionInfo *parts, uint8_t count, char *out, size_t cap)
73{
74 if (!out || cap == 0)
75 return 0;
76 out[0] = '\0';
77 if (!parts)
78 return 0;
79 size_t pos = 0;
80 if (json_append(out, cap, &pos, "{\"partitions\":[") != 0)
81 return 0;
82 for (uint8_t i = 0; i < count; i++)
83 {
84 const DetwsPartitionInfo *p = &parts[i];
85 if (json_append(out, cap, &pos,
86 "%s{\"label\":\"%s\",\"kind\":\"%s\",\"type\":%u,\"subtype\":%u,\"addr\":%u,\"size\":%u,"
87 "\"running\":%s}",
88 i ? "," : "", p->label, detws_partition_kind(p->type, p->subtype), (unsigned)p->type,
89 (unsigned)p->subtype, (unsigned)p->address, (unsigned)p->size,
90 p->running ? "true" : "false") != 0)
91 return 0;
92 }
93 if (json_append(out, cap, &pos, "]}") != 0)
94 return 0;
95 return (int)pos;
96}
97
98#ifdef ARDUINO
99
100#include <esp_ota_ops.h>
101#include <esp_partition.h>
102
103uint8_t detws_partition_collect(DetwsPartitionInfo *out, uint8_t max)
104{
105 if (!out || max == 0)
106 return 0;
107 const esp_partition_t *running = esp_ota_get_running_partition();
108 uint8_t n = 0;
109 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
110 for (; it != NULL && n < max; it = esp_partition_next(it))
111 {
112 const esp_partition_t *p = esp_partition_get(it);
113 DetwsPartitionInfo *d = &out[n++];
114 strncpy(d->label, p->label, sizeof(d->label) - 1);
115 d->label[sizeof(d->label) - 1] = '\0';
116 d->type = (uint8_t)p->type;
117 d->subtype = (uint8_t)p->subtype;
118 d->address = p->address;
119 d->size = p->size;
120 d->running = (running != NULL && p->address == running->address);
121 }
122 esp_partition_iterator_release(it);
123 return n;
124}
125
126#else // host build - no flash
127
128uint8_t detws_partition_collect(DetwsPartitionInfo *, uint8_t)
129{
130 return 0;
131}
132
133#endif // ARDUINO
134
135#endif // DETWS_ENABLE_PARTITION_MONITOR
Flash partition-map monitor (DETWS_ENABLE_PARTITION_MONITOR).