REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
base.cpp
Go to the documentation of this file.
1#include "entity/base.h"
2#include "utils/mac.h" // toString(eui64)
3
4FLASHMEM std::string entities::EntityClassifier::to_string() const {
5 return "(class = " + std::to_string(class_) + ", type = " + std::to_string(type) +
6 ", version = " + version.to_string() + ", variant = " + std::to_string(variant) + ")";
7}
8
9bool entities::EntityClassifier::operator==(const entities::EntityClassifier &rhs) const {
10 return class_ == rhs.class_ && class_enum == rhs.class_enum && type == rhs.type && version == rhs.version &&
11 variant == rhs.variant;
12}
13
14bool entities::EntityClassifier::operator!=(const entities::EntityClassifier &rhs) const {
15 return !(rhs == *this);
16}
17
18FLASHMEM
19entities::EntityClassifier entities::Entity::get_entity_classifier() const { return classifier; }
20
21FLASHMEM entities::EntityClass entities::Entity::get_entity_class() const { return classifier.class_enum; }
22
23FLASHMEM uint8_t entities::Entity::get_entity_type() const { return classifier.type; }
24
25FLASHMEM entities::Version entities::Entity::get_entity_version() const { return classifier.version; }
26
27FLASHMEM uint8_t entities::Entity::get_entity_variant() const { return classifier.variant; }
28
29FLASHMEM
31 auto resolved_entity = this;
32 for (size_t path_depth = 0; path_depth < len; path_depth++) {
33 resolved_entity = resolved_entity->get_child_entity(paths[path_depth]);
34 if (!resolved_entity) {
35 return nullptr;
36 }
37 }
38 return resolved_entity;
39}
40
41FLASHMEM
43 JsonArrayConstIterator end) {
44 auto resolved_entity = this;
45 for (auto sub_path = begin; sub_path != end; ++sub_path) {
46 std::string child_entity_id = (*sub_path).as<const char *>();
47 resolved_entity = resolved_entity->get_child_entity(child_entity_id);
48 if (!resolved_entity) {
49 return nullptr;
50 }
51 }
52 return resolved_entity;
53}
54
55FLASHMEM
57#ifdef ANABRID_DEBUG_ENTITY_CONFIG
58 Serial.println(__PRETTY_FUNCTION__);
59#endif
60 if (cfg.isNull())
61 return utils::status("Configuration is Null at entity %s", get_entity_id().c_str());
62 auto res = config_self_from_json(cfg);
63 if (!res)
64 return res;
65 res = config_children_from_json(cfg);
66 if (!res)
67 return res;
69}
70
71FLASHMEM
73 for (JsonPairConst keyval : cfg) {
74 if (keyval.key().c_str()[0] == '/' and keyval.key().size() > 1) {
75 std::string child_id(keyval.key().c_str() + 1);
76 auto child_entity = get_child_entity(child_id);
77 if (!child_entity)
78 return utils::status("Child entity '%s' does not exist at entity '%s'", child_id,
79 get_entity_id().c_str());
80 auto res = child_entity->config_from_json(keyval.value());
81 if (!res)
82 return res;
83 }
84 }
86}
87
88FLASHMEM
90 for (const auto &child : get_child_entities()) {
91 if (child) {
92 auto child_cfg = cfg.createNestedObject(std::string("/") + child->get_entity_id());
93 child->config_to_json(child_cfg, true);
94 }
95 }
96}
97
98FLASHMEM
99bool ArduinoJson::Converter<entities::EntityClassifier>::toJson(const entities::EntityClassifier &src,
100 JsonVariant dst) {
101 dst["class"] = src.class_;
102 dst["type"] = src.type;
103 dst["variant"] = src.variant;
104
105 auto versions_arr = dst.createNestedArray("version");
106 versions_arr.add(src.version.major);
107 versions_arr.add(src.version.minor);
108 versions_arr.add(src.version.patch);
109 return true;
110}
111
112FLASHMEM
113entities::EntityClassifier ArduinoJson::Converter<entities::EntityClassifier>::fromJson(JsonVariantConst src) {
114 return {src["class"].as<uint8_t>(), src["type"], src["version"][0],
115 src["version"][1], src["version"][2], src["variant"]};
116}
117
118FLASHMEM
119bool Converter<entities::EntityClassifier>::checkJson(JsonVariantConst src) {
120 return src["class"].is<uint8_t>() and src["type"].is<uint8_t>() and src["variant"].is<uint8_t>() and
121 src["version"].is<JsonArrayConst>() and src["version"].as<JsonArrayConst>().size() == 3;
122}
123
124FLASHMEM
125void entities::Entity::classifier_to_json(JsonObject &out) {
126 auto jsonvar = out["/" + get_entity_id()] = get_entity_classifier();
127 auto jsonobj = jsonvar.as<JsonObject>();
128 jsonobj["eui"] = utils::toString(get_entity_eui());
129
130 for (auto &child_ptr : get_child_entities()) {
131 if (child_ptr)
132 child_ptr->classifier_to_json(jsonobj);
133 }
134}
135
136FLASHMEM utils::status entities::Entity::user_set_config(JsonObjectConst msg_in, JsonObject &msg_out) {
137#ifdef ANABRID_DEBUG_COMMS
138 Serial.println(__PRETTY_FUNCTION__);
139#endif
140 auto self_entity_id = get_entity_id();
141 if (!msg_in.containsKey("entity") or !msg_in.containsKey("config")) {
142 return utils::status(1, "Malformed message.");
143 }
144
145 // Convert JSON array of possible anything to string array
146 auto path_json = msg_in["entity"].as<JsonArrayConst>();
147 auto path_depth = path_json.size();
148 std::string path[path_depth];
149 copyArray(path_json, path, path_depth);
150
151 // Sanity check path, which must at least be addressed to us
152 if (!path_depth) {
153 return utils::status(2, "Invalid entity path (depth)");
154 }
155 if (path[0] != self_entity_id) {
156 return utils::status(3, "Message intended for another entity (%s but I am %s)", path[0].c_str(),
157 self_entity_id.c_str());
158 }
159
160 // Path may be to one of our sub-entities
161 auto resolved_entity = resolve_child_entity(path + 1, path_depth - 1);
162 if (!resolved_entity) {
163 return utils::status(4, "Could not resolve child entity in given path");
164 }
165
166 utils::status res = resolved_entity->config_from_json(msg_in["config"]);
167 if (!res) {
168 // Could enrich with "could not apply configuration..."
169 return res;
170 }
171
172 // Actually write to hardware
173 utils::status hw_res = write_to_hardware();
174 if (!hw_res) {
175 return hw_res;
176 }
177
178 return utils::status::success();
179}
180
181FLASHMEM utils::status entities::Entity::user_get_config(JsonObjectConst msg_in, JsonObject &msg_out) {
182#ifdef ANABRID_DEBUG_COMMS
183 Serial.println(__PRETTY_FUNCTION__);
184#endif
185 auto recursive = true;
186 if (msg_in.containsKey("recursive"))
187 recursive = msg_in["recursive"].as<bool>();
188
189 // Message may contain path to sub-entity
190 entities::Entity *entity = nullptr;
191 if (!msg_in.containsKey("entity") or msg_in["entity"].isNull()) {
192 entity = this;
193 } else if (msg_in["entity"].is<JsonArrayConst>()) {
194 auto path = msg_in["entity"].as<JsonArrayConst>();
195 if (!path.size()) {
196 entity = this;
197 } else if (path[0].as<std::string>() != get_entity_id()) {
198 return utils::status(1, "Requested entity %s but I am %s", path[0].as<const char *>(),
199 get_entity_id().c_str());
200 } else {
201 auto path_begin = path.begin();
202 ++path_begin;
203 entity = resolve_child_entity(path_begin, path.end());
204 if (!entity) {
205 return utils::status(2, "Cannot resolve entity path");
206 }
207 }
208 } else {
209 return utils::status(3, "Entity path is not a list");
210 }
211
212 // Save entity path back into response
213 msg_out["entity"] = msg_in["entity"];
214 // Save config into response
215 auto cfg = msg_out.createNestedObject("config");
216 entity->config_to_json(cfg, recursive);
217 return utils::status::success();
218}
219
220FLASHMEM utils::status entities::Entity::user_reset_config(JsonObjectConst msg_in, JsonObject &msg_out) {
221 entities::ResetAction reset_request(0);
222
223 // msg_in["foo"] | default_value
224 // is a short way to write
225 // msg_in.contains("foo") ? msg_in["foo"].as<bool>() : default_value
226
227 bool keep_calibration = msg_in["keep_calibration"] | true;
228
229 if (!keep_calibration)
231
232 bool overload_reset = msg_in["overload_reset"] | true;
233
234 if (overload_reset)
236 // attention: Overload request always immediately writes to hardware
237
238 bool circuit_reset = msg_in["circuit_reset"] | true;
239
240 if (circuit_reset)
242
243 reset(reset_request);
244
245 if (msg_in["sync"] | true) {
246 auto status = write_to_hardware();
247 if (!status) {
248 return status;
249 }
250 }
251 return utils::status::success();
252}
EntityClassifier classifier
Definition base.h:217
utils::status config_children_from_json(JsonObjectConst &cfg)
Deserialize a new configuration for all child entities from a JsonObject.
Definition base.cpp:72
Version get_entity_version() const
Definition base.cpp:25
EntityClassifier get_entity_classifier() const
Definition base.cpp:19
void config_children_to_json(JsonObject &cfg)
Serialize the configuration of the child entities of this entity to a JsonObject.
Definition base.cpp:89
uint8_t get_entity_variant() const
Definition base.cpp:27
void config_to_json(JsonObject &cfg, bool recursive=true)
Serialize the configuration for this entity to a JsonObject.
Definition base.h:170
Entity * resolve_child_entity(std::string paths[], size_t len)
Definition base.cpp:30
uint8_t get_entity_type() const
Definition base.cpp:23
utils::status config_from_json(JsonObjectConst cfg)
Deserialize a new configuration for this entity and all its children from a JsonObject.
Definition base.cpp:56
EntityClass get_entity_class() const
Definition base.cpp:21
A recoverable error, inspired from https://abseil.io/docs/cpp/guides/status and https://github....
Definition error.h:35
static status success()
Syntactic sugar for success.
Definition error.h:104
utils::status status
Definition daq.h:28
uint32_t src
Definition flasher.cpp:63
uint32_t uint32_t size
Definition flasher.cpp:63
utils::status user_reset_config(JsonObjectConst msg_in, JsonObject &msg_out)
Definition base.cpp:220
utils::status user_set_config(JsonObjectConst msg_in, JsonObject &msg_out)
Definition base.cpp:136
utils::status user_get_config(JsonObjectConst msg_in, JsonObject &msg_out)
Definition base.cpp:181
EntityClass
Definition base.h:26
std::string toString(const MacAddress &mac, char sep='-')
EUI48/MAC Canonical Format AA-BB-CC-DD-EE-FF.
Definition mac.cpp:33
static constexpr uint8_t OVERLOAD_RESET
Definition base.h:104
static constexpr uint8_t CALIBRATION_RESET
Definition base.h:103
static constexpr uint8_t CIRCUIT_RESET
Definition base.h:102