FastLED 3.10.6
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 255 of file screenmap.cpp.hpp.

256 {
257
258#if FASTLED_NO_JSON
259 FL_UNUSED(jsonStrScreenMap);
260 FL_UNUSED(segmentMaps);
261 FL_UNUSED(err);
262 FL_WARN("ScreenMap::ParseJson called with FASTLED_NO_JSON");
263 if (err) {
264 *err = "JSON is not supported in this build";
265 }
266 return false;
267#else
268 //FL_WARN_SCREENMAP("ParseJson called with JSON: " << jsonStrScreenMap);
269
270 string _err;
271 if (!err) {
272 err = &_err;
273 }
274
275 auto jsonDoc = fl::json::parse(jsonStrScreenMap);
276 if (!jsonDoc.has_value()) {
277 *err = "Failed to parse JSON";
278 FL_WARN("Failed to parse JSON");
279 return false;
280 }
281
282 if (!jsonDoc.is_object()) {
283 *err = "JSON root is not an object";
284 FL_WARN("JSON root is not an object");
285 return false;
286 }
287
288 // ── v2 dispatch ──────────────────────────────────────────────────────
289 // v2 if: explicit "version": 2 OR has top-level "segments" array.
290 // v1 if: explicit "version": 1 OR has top-level "map" object.
291 bool explicitV2 = false;
292 bool explicitV1 = false;
293 if (jsonDoc.contains("version") && jsonDoc["version"].has_value()) {
294 auto versionOpt = jsonDoc["version"].as_int();
295 if (versionOpt) {
296 int v = static_cast<int>(*versionOpt);
297 if (v == 2) explicitV2 = true;
298 else if (v == 1) explicitV1 = true;
299 }
300 }
301 bool hasSegments = jsonDoc.contains("segments") && jsonDoc["segments"].has_value()
302 && jsonDoc["segments"].is_array();
303 bool hasMap = jsonDoc.contains("map") && jsonDoc["map"].has_value()
304 && jsonDoc["map"].is_object();
305
306 if (explicitV2 || (!explicitV1 && hasSegments && !hasMap)) {
307 return parseV2SegmentArray(jsonDoc["segments"], segmentMaps, err);
308 }
309
310 // Fall through to v1 path.
311 // Check if "map" key exists and is an object
312 if (!jsonDoc.contains("map")) {
313 *err = "Missing 'map' key in JSON";
314 FL_WARN("Missing 'map' key in JSON");
315 return false;
316 }
317
318 // Get the map object
319 auto mapObj = jsonDoc["map"];
320 if (!mapObj.has_value() || !mapObj.is_object()) {
321 *err = "Invalid 'map' object in JSON";
322 FL_WARN("Invalid 'map' object in JSON");
323 return false;
324 }
325
326 auto jsonMapPtr = mapObj.as_object();
327 if (!jsonMapPtr || jsonMapPtr->empty()) {
328 *err = "Failed to parse map from JSON or map is empty";
329 FL_WARN("Failed to parse map from JSON or map is empty");
330 return false;
331 }
332
333 auto& jsonMap = *jsonMapPtr;
334
335
336 for (const auto& kv : jsonMap) {
337 auto name = kv.first;
338
339
340 // Check that the value is not null before creating json object
341 if (!kv.second) {
342 *err = "Null value for segment " + name;
343 return false;
344 }
345
346 // Create json object directly from shared_ptr
347 fl::json val(kv.second);
348 if (!val.has_value()) {
349 *err = "Invalid value for segment " + name;
350 return false;
351 }
352
353 if (!val.is_object()) {
354 *err = "Segment value for " + name + " is not an object";
355 return false;
356 }
357
358 // Check if x array exists and is actually an array
359 if (!val.contains("x")) {
360 *err = "Missing x array for " + name;
361 return false;
362 }
363
364 if (!val["x"].has_value() || !val["x"].is_array()) {
365 *err = "Invalid x array for " + name;
366 return false;
367 }
368
369 // Extract x array using our helper function
370 fl::vector<float> x_array = jsonArrayToFloatVector(val["x"]);
371
372 // Check if y array exists and is actually an array
373 if (!val.contains("y")) {
374 *err = "Missing y array for " + name;
375 return false;
376 }
377
378 if (!val["y"].has_value() || !val["y"].is_array()) {
379 *err = "Invalid y array for " + name;
380 return false;
381 }
382
383 // Extract y array using our helper function
384 fl::vector<float> y_array = jsonArrayToFloatVector(val["y"]);
385
386 // Get diameter (optional) with default value
387 float diameter = -1.0f; // default value
388 if (val.contains("diameter") && val["diameter"].has_value()) {
389 auto diameterOpt = val["diameter"].as_float();
390 if (diameterOpt) {
391 diameter = static_cast<float>(*diameterOpt);
392 }
393 }
394
395 auto n = fl::min(x_array.size(), y_array.size());
396 if (n != x_array.size() || n != y_array.size()) {
397 if (n != x_array.size()) {
398 }
399 if (n != y_array.size()) {
400 }
401 }
402
403 ScreenMap segment_map(n, diameter);
404 for (size_t i = 0; i < n; i++) {
405 segment_map.set(i, vec2f{x_array[i], y_array[i]});
406 }
407 (*segmentMaps)[name] = fl::move(segment_map);
408 }
409 return true;
410#endif
411}
ScreenMap() FL_NO_EXCEPT
static json parse(const fl::string &txt) FL_NO_EXCEPT
Definition json.h:842
fl::size size() const FL_NO_EXCEPT
#define FL_UNUSED(x)
#define FL_WARN(...)
Definition log.h:440
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:28
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NO_EXCEPT
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_NO_EXCEPT

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::move(), fl::json::parse(), fl::parseV2SegmentArray(), set(), and fl::vector_basic::size().

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

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