ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
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 PC_ENABLE_PARTITION_MONITOR
16
18#include <string.h>
19
20// esp_partition type/subtype constants (mirrors esp_partition_type_t/subtype_t so
21// the classifier stays pure and host-testable without the IDF headers).
22#if defined(ARDUINO)
23#include <esp_ota_ops.h>
24#include <esp_partition.h>
25#endif
26const char *pc_partition_kind(uint8_t type, uint8_t subtype)
27{
28 if (type == 0) // ESP_PARTITION_TYPE_APP
29 {
30 if (subtype == 0x00)
31 {
32 return "factory";
33 }
34 if (subtype >= 0x10 && subtype <= 0x1F)
35 {
36 return "ota";
37 }
38 if (subtype == 0x20)
39 {
40 return "test";
41 }
42 return "app";
43 }
44 switch (subtype) // ESP_PARTITION_TYPE_DATA
45 {
46 case 0x00:
47 return "otadata";
48 case 0x01:
49 return "phy";
50 case 0x02:
51 return "nvs";
52 case 0x03:
53 return "coredump";
54 case 0x04:
55 return "nvs_keys";
56 case 0x81:
57 return "fat";
58 case 0x82:
59 return "spiffs";
60 case 0x83:
61 return "littlefs";
62 default:
63 return "data";
64 }
65}
66
67static const pc_field PART_OPEN[] = {{PC_FK_LIT, 0, 15, "{\"partitions\":["}, PC_END};
68static const pc_field PART_ENTRY[] = {
69 PC_STR, // "," from the second entry on
70 {PC_FK_LIT, 0, 9, "{\"label\":"}, //
71 PC_JSON, // label
72 {PC_FK_LIT, 0, 8, ",\"kind\":"}, //
73 PC_JSON, // kind name
74 {PC_FK_LIT, 0, 8, ",\"type\":"}, //
75 PC_U32, //
76 {PC_FK_LIT, 0, 11, ",\"subtype\":"}, //
77 PC_U32, //
78 {PC_FK_LIT, 0, 8, ",\"addr\":"}, //
79 PC_U32, //
80 {PC_FK_LIT, 0, 8, ",\"size\":"}, //
81 PC_U32, //
82 {PC_FK_LIT, 0, 11, ",\"running\":"}, //
83 PC_STR, // "true" / "false" - a JSON keyword, not a string
84 {PC_FK_LIT, 0, 1, "}"}, //
85 PC_END,
86};
87static const pc_field PART_CLOSE[] = {{PC_FK_LIT, 0, 2, "]}"}, PC_END};
88
89int32_t pc_partition_json(const pc_partition_info *parts, uint8_t count, char *out, uint32_t cap)
90{
91 if (!out || cap == 0)
92 {
93 return 0;
94 }
95 out[0] = '\0';
96 if (!parts)
97 {
98 return 0;
99 }
100 if (pc_frame_append(out, cap, PART_OPEN) == 0)
101 {
102 return 0;
103 }
104 for (uint8_t i = 0; i < count; i++)
105 {
106 const pc_partition_info *p = &parts[i];
107 if (pc_frame_append(out, cap, PART_ENTRY, i ? "," : "", p->label, pc_partition_kind(p->type, p->subtype),
108 (uint32_t)p->type, (uint32_t)p->subtype, (uint32_t)p->address, (uint32_t)p->size,
109 p->running ? "true" : "false") == 0)
110 {
111 return 0;
112 }
113 }
114 return (int32_t)pc_frame_append(out, cap, PART_CLOSE);
115}
116
117#ifdef ARDUINO
118
119uint8_t pc_partition_collect(pc_partition_info *out, uint8_t max)
120{
121 if (!out || max == 0)
122 {
123 return 0;
124 }
125 const esp_partition_t *running = esp_ota_get_running_partition();
126 uint8_t n = 0;
127 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
128 for (; it != NULL && n < max; it = esp_partition_next(it))
129 {
130 const esp_partition_t *p = esp_partition_get(it);
131 pc_partition_info *d = &out[n++];
132 strncpy(d->label, p->label, sizeof(d->label) - 1);
133 d->label[sizeof(d->label) - 1] = '\0';
134 d->type = (uint8_t)p->type;
135 d->subtype = (uint8_t)p->subtype;
136 d->address = p->address;
137 d->size = p->size;
138 d->running = (running != NULL && p->address == running->address);
139 }
140 esp_partition_iterator_release(it);
141 return n;
142}
143
144#else // host build - no flash
145
146uint8_t pc_partition_collect(pc_partition_info *, uint8_t)
147{
148 return 0;
149}
150
151#endif // ARDUINO
152
153#endif // PC_ENABLE_PARTITION_MONITOR
size_t pc_frame_append(char *out, size_t cap, const pc_field *spec,...)
Append spec to the NUL-terminated contents already in out.
Definition frame.cpp:109
Declarative frame builder: a frame is a static table of typed fields, built by one engine.
#define PC_END
Definition frame.h:110
#define PC_JSON
Definition frame.h:108
#define PC_U32
Definition frame.h:104
@ PC_FK_LIT
literal text from lit; takes no argument
Definition frame.h:56
#define PC_STR
Definition frame.h:103
Flash partition-map monitor (PC_ENABLE_PARTITION_MONITOR).
One field of a frame. Frames are static const pc_field[], so they live in rodata.
Definition frame.h:80