FastLED 3.9.15
Loading...
Searching...
No Matches

◆ ParseJson() [2/2]

bool fl::ScreenMap::ParseJson ( const char * jsonStrScreenMap,
fl::flat_map< string, ScreenMap > * segmentMaps,
string * err = nullptr )
static
Examples
Chromancer.ino.

Definition at line 186 of file screenmap.cpp.hpp.

187 {
188
189#if FASTLED_NO_JSON
190 FL_UNUSED(jsonStrScreenMap);
191 FL_UNUSED(segmentMaps);
192 FL_UNUSED(err);
193 FL_WARN("ScreenMap::ParseJson called with FASTLED_NO_JSON");
194 if (err) {
195 *err = "JSON is not supported in this build";
196 }
197 return false;
198#else
199 //FL_WARN_SCREENMAP("ParseJson called with JSON: " << jsonStrScreenMap);
200
201 string _err;
202 if (!err) {
203 err = &_err;
204 }
205
206 auto jsonDoc = fl::json::parse(jsonStrScreenMap);
207 if (!jsonDoc.has_value()) {
208 *err = "Failed to parse JSON";
209 FL_WARN("Failed to parse JSON");
210 return false;
211 }
212
213 if (!jsonDoc.is_object()) {
214 *err = "JSON root is not an object";
215 FL_WARN("JSON root is not an object");
216 return false;
217 }
218
219 // ── v2 dispatch ──────────────────────────────────────────────────────
220 // v2 if: explicit "version": 2 OR has top-level "segments" array.
221 // v1 if: explicit "version": 1 OR has top-level "map" object.
222 bool explicitV2 = false;
223 bool explicitV1 = false;
224 if (jsonDoc.contains("version") && jsonDoc["version"].has_value()) {
225 auto versionOpt = jsonDoc["version"].as_int();
226 if (versionOpt) {
227 int v = static_cast<int>(*versionOpt);
228 if (v == 2) explicitV2 = true;
229 else if (v == 1) explicitV1 = true;
230 }
231 }
232 bool hasSegments = jsonDoc.contains("segments") && jsonDoc["segments"].has_value()
233 && jsonDoc["segments"].is_array();
234 bool hasMap = jsonDoc.contains("map") && jsonDoc["map"].has_value()
235 && jsonDoc["map"].is_object();
236
237 if (explicitV2 || (!explicitV1 && hasSegments && !hasMap)) {
238 return parseV2SegmentArray(jsonDoc["segments"], segmentMaps, err);
239 }
240
241 // Fall through to v1 path.
242 // Check if "map" key exists and is an object
243 if (!jsonDoc.contains("map")) {
244 *err = "Missing 'map' key in JSON";
245 FL_WARN("Missing 'map' key in JSON");
246 return false;
247 }
248
249 // Get the map object
250 auto mapObj = jsonDoc["map"];
251 if (!mapObj.has_value() || !mapObj.is_object()) {
252 *err = "Invalid 'map' object in JSON";
253 FL_WARN("Invalid 'map' object in JSON");
254 return false;
255 }
256
257 auto jsonMapPtr = mapObj.as_object();
258 if (!jsonMapPtr || jsonMapPtr->empty()) {
259 *err = "Failed to parse map from JSON or map is empty";
260 FL_WARN("Failed to parse map from JSON or map is empty");
261 return false;
262 }
263
264 auto& jsonMap = *jsonMapPtr;
265
266
267 for (const auto& kv : jsonMap) {
268 auto name = kv.first;
269
270
271 // Check that the value is not null before creating json object
272 if (!kv.second) {
273 *err = "Null value for segment " + name;
274 return false;
275 }
276
277 // Create json object directly from shared_ptr
278 fl::json val(kv.second);
279 if (!val.has_value()) {
280 *err = "Invalid value for segment " + name;
281 return false;
282 }
283
284 if (!val.is_object()) {
285 *err = "Segment value for " + name + " is not an object";
286 return false;
287 }
288
289 // Check if x array exists and is actually an array
290 if (!val.contains("x")) {
291 *err = "Missing x array for " + name;
292 return false;
293 }
294
295 if (!val["x"].has_value() || !val["x"].is_array()) {
296 *err = "Invalid x array for " + name;
297 return false;
298 }
299
300 // Extract x array using our helper function
301 fl::vector<float> x_array = jsonArrayToFloatVector(val["x"]);
302
303 // Check if y array exists and is actually an array
304 if (!val.contains("y")) {
305 *err = "Missing y array for " + name;
306 return false;
307 }
308
309 if (!val["y"].has_value() || !val["y"].is_array()) {
310 *err = "Invalid y array for " + name;
311 return false;
312 }
313
314 // Extract y array using our helper function
315 fl::vector<float> y_array = jsonArrayToFloatVector(val["y"]);
316
317 // Get diameter (optional) with default value
318 float diameter = -1.0f; // default value
319 if (val.contains("diameter") && val["diameter"].has_value()) {
320 auto diameterOpt = val["diameter"].as_float();
321 if (diameterOpt) {
322 diameter = static_cast<float>(*diameterOpt);
323 }
324 }
325
326 auto n = fl::min(x_array.size(), y_array.size());
327 if (n != x_array.size() || n != y_array.size()) {
328 if (n != x_array.size()) {
329 }
330 if (n != y_array.size()) {
331 }
332 }
333
334 ScreenMap segment_map(n, diameter);
335 for (size_t i = 0; i < n; i++) {
336 segment_map.set(i, vec2f{x_array[i], y_array[i]});
337 }
338 (*segmentMaps)[name] = fl::move(segment_map);
339 }
340 return true;
341#endif
342}
ScreenMap() FL_NOEXCEPT
static json parse(const fl::string &txt) FL_NOEXCEPT
Definition json.h:677
fl::size size() const FL_NOEXCEPT
#define FL_WARN(X)
Definition log.h:276
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
Definition math.h:71
vec2< float > vec2f
Definition geometry.h:333
fl::vector< float > jsonArrayToFloatVector(const fl::json &jsonArray)
static bool parseV2SegmentArray(const fl::json &segmentsArr, fl::flat_map< string, ScreenMap > *segmentMaps, string *err) FL_NOEXCEPT
#define FL_UNUSED(x)

References ScreenMap(), fl::json::as_float(), fl::json::contains(), FL_UNUSED, FL_WARN, fl::json::has_value(), fl::json::is_object(), fl::jsonArrayToFloatVector(), fl::min(), fl::fl::move(), fl::json::parse(), fl::parseV2SegmentArray(), set(), and fl::vector_basic::size().

Referenced by openVideoEitherFormat(), ParseJson(), fl::FileSystem::readScreenMap(), fl::FileSystem::readScreenMaps(), and setup().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: