-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathparse_config_cbor.cpp
More file actions
185 lines (141 loc) · 6.05 KB
/
Copy pathparse_config_cbor.cpp
File metadata and controls
185 lines (141 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include <JsonFusion/parser.hpp>
#include <JsonFusion/cbor.hpp>
#include <JsonFusion/serializer.hpp>
#include <JsonFusion/validators.hpp>
#include <string_view>
using namespace JsonFusion;
using namespace JsonFusion::options;
using std::array;
using std::optional;
// Model matching typical embedded config needs:
// - Fixed-size arrays (static allocation)
// - Validation constraints
// - Nested structures
// - Optional fields
namespace {
using namespace JsonFusion::validators;
static constexpr std::size_t kMult = 2;
using SmallStr = array<char, 16 * kMult>;
using MediumStr = array<char, 32 * kMult>;
using LargeStr = array<char, 64 * kMult>;
using FPLike32 = float;
using FPLike64 = double;
// using FPLike32 = int32_t;
// using FPLike64 = int64_t;
struct EmbeddedConfig {
static constexpr std::size_t kMaxMotors = 16;
static constexpr std::size_t kMaxSensors = 16;
MediumStr app_name;
uint16_t version_major;
int version_minor;
struct Network {
SmallStr name;
SmallStr address; // e.g. "192.168.0.1/24"
uint16_t port;
bool enabled;
};
A<Network, indexes_as_keys> network;
A<optional<Network>, indexes_as_keys> fallback_network_conf;
struct Controller {
MediumStr name;
A<int, range<10, 10000>> loop_hz;
struct Motor {
int64_t id;
SmallStr name;
// Position [x,y,z] with validation
A<array<A<FPLike64, range<-1000, 1000>>, 3>, min_items<3>> position;
// Velocity limits [vx,vy,vz] with validation
A<array<A<FPLike32, range<-1000, 1000>>, 3>, min_items<3>> vel_limits;
bool inverted;
};
A<array<A<Motor, indexes_as_keys>, kMaxMotors>, min_items<1>> motors;
struct Sensor {
SmallStr type;
MediumStr model;
A<FPLike32, range<-100, 100000>> range_min;
A<FPLike64, range<-1000, 100000>> range_max;
bool active;
};
A<array<A<Sensor, indexes_as_keys>, kMaxSensors>, min_items<1>> sensors;
};
A<Controller, indexes_as_keys> controller;
struct Logging {
bool enabled;
LargeStr path;
uint32_t max_files;
};
A<Logging, indexes_as_keys> logging;
};
// RPC Command structure with validation and required/optional field specifications
struct RpcCommand_ {
static constexpr std::size_t kMaxParams = 8;
static constexpr std::size_t kMaxTargets = 4;
// Command identification
SmallStr command_id; // Required
uint64_t timestamp_us; // Required
uint16_t sequence; // Optional - server can auto-assign
A<uint8_t, range<0, 10>> priority; // Optional - has default
// Target specification
struct Target_ {
SmallStr device_id; // Required
SmallStr subsystem; // Optional - defaults to whole device
};
using Target = A<Target_, required<"device_id">, indexes_as_keys>;
A<array<Target, kMaxTargets>, min_items<1>> targets; // Required
// Command parameters
struct Parameter_ {
SmallStr key; // Required
// Union-like value storage (all optional by default)
optional<int64_t> int_value;
A<optional<FPLike64>, range<-1000000, 1000000>> float_value;
optional<bool> bool_value;
optional<SmallStr> string_value;
};
using Parameter = A<Parameter_, required<"key">, indexes_as_keys>;
A<array<Parameter, kMaxParams>, min_items<1>> params; // Required
// Execution constraints (entire section optional)
struct ExecutionOptions {
A<uint32_t, range<0, 300000>> timeout_ms; // Required if section present
bool retry_on_failure; // Optional - defaults to false
A<uint8_t, range<0, 5>> max_retries; // Optional - defaults to 0
};
A<optional<ExecutionOptions>, required<"timeout_ms">, indexes_as_keys> execution; // Optional section
// Callback/response configuration (entire section optional)
struct ResponseConfig {
SmallStr callback_url; // Optional - can use default endpoint
bool acknowledge; // Required if section present
bool send_result; // Required if section present
};
A<optional<ResponseConfig>, required<"acknowledge", "send_result">, indexes_as_keys> response_config; // Optional section
};
using RpcCommand = A<RpcCommand_, required<"command_id", "timestamp_us", "targets", "params">, indexes_as_keys>;
} // namespace
// Global config instance (will go in .bss section)
A<EmbeddedConfig, indexes_as_keys> g_config;
// Parse function - instantiates JsonFusion parser for this model
// This is what gets measured for code size
extern "C" __attribute__((used)) bool parse_serialize_config(const std::uint8_t* data, size_t size) {
auto result = JsonFusion::ParseWithReader(g_config, JsonFusion::CborReader(data, data + size));
std::uint8_t* d = const_cast<std::uint8_t*>(data);
auto result_s = JsonFusion::SerializeWithWriter(g_config, JsonFusion::CborWriter(d, d + size));
return !!result && !!result_s;
}
extern "C" __attribute__((used)) bool parse_serialize_rpc_command(const std::uint8_t* data, size_t size) {
RpcCommand cmd;
auto result_p = JsonFusion::ParseWithReader(cmd, JsonFusion::CborReader(data, data + size));
std::uint8_t* d = const_cast<std::uint8_t*>(data);
auto result_s = JsonFusion::SerializeWithWriter(cmd, JsonFusion::CborWriter(d, d + size));
return !!result_p && !!result_s;
}
// Entry point - ensures parse_config is not eliminated by linker
// In a real embedded system, this would be your main loop
int main() {
// Call parse_config to ensure it's included in binary
volatile bool result = parse_serialize_config(reinterpret_cast<const std::uint8_t*>(""), 0);
volatile bool rpc_result = parse_serialize_rpc_command(reinterpret_cast<const std::uint8_t*>(""), 0);
(void)result;
(void)rpc_result;
// Infinite loop (typical for embedded without OS)
while(1) {}
return 0;
}