config: fix crashes, implement fallback profiles
This commit is contained in:
		| @@ -9,7 +9,7 @@ | |||||||
| #include <LittleFS.h> | #include <LittleFS.h> | ||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| StaticJsonDocument<256> jsonConfig; | StaticJsonDocument<1024> jsonConfig; | ||||||
|  |  | ||||||
| constexpr uint16_t HardwareConfig::MAX_LED_NUM; | constexpr uint16_t HardwareConfig::MAX_LED_NUM; | ||||||
|  |  | ||||||
| @@ -77,14 +77,20 @@ ConfigService::onStart() | |||||||
|         m_config = HardwareConfig{}; |         m_config = HardwareConfig{}; | ||||||
|         m_config.save(); |         m_config.save(); | ||||||
|     } |     } | ||||||
|     if (strlen(m_config.data.loadedProfile) == 0) { |  | ||||||
|       strcpy(m_config.data.loadedProfile, "default"); |     bool loaded = false; | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (m_overrideProfile != nullptr) { |     if (m_overrideProfile != nullptr) { | ||||||
|       loadProfile(m_overrideProfile); |       loaded = loadProfile(m_overrideProfile); | ||||||
|     } else { |     } | ||||||
|       loadProfile(m_config.data.loadedProfile); |  | ||||||
|  |     if (!loaded && strlen(m_config.data.loadedProfile) > 0) { | ||||||
|  |       loaded = loadProfile(m_config.data.loadedProfile); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!loaded && !loadProfile("default")) { | ||||||
|  |       Log.fatal("Could not load default fallback profile! No tasks will be started."); | ||||||
|  |       m_jsonMap.loadDefault(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -94,24 +100,24 @@ ConfigService::overrideProfile(const char* profileName) | |||||||
|     m_overrideProfile = profileName; |     m_overrideProfile = profileName; | ||||||
| } | } | ||||||
|  |  | ||||||
| void | bool | ||||||
| ConfigService::loadMap(const String& mapName) | ConfigService::loadMap(const String& mapName) | ||||||
| { | { | ||||||
|   String fname = String("/maps/") + mapName + ".json"; |   String fname = String("/maps/") + mapName + ".json"; | ||||||
|   if (LittleFS.exists(fname)) { |   if (LittleFS.exists(fname)) { | ||||||
|     File configFile = LittleFS.open(fname, "r"); |     File configFile = LittleFS.open(fname, "r"); | ||||||
|     Log.notice("config: Loading coordinate map %s", mapName.c_str()); |     Log.notice("config: Loading coordinate map from %s", fname.c_str()); | ||||||
|     deserializeJson(jsonConfig, configFile); |     deserializeJson(jsonConfig, configFile); | ||||||
|     configFile.close(); |     configFile.close(); | ||||||
|     JsonArray strideList = jsonConfig["strides"]; |     JsonArray strideList = jsonConfig["strides"]; | ||||||
|     m_jsonMap.load(strideList); |     m_jsonMap.load(strideList); | ||||||
|  |     return true; | ||||||
|   } else { |   } else { | ||||||
|       Log.warning("config: Couldn't load coordinate map %s!!! Defaulting to linear mapping.", mapName.c_str()); |     return false; | ||||||
|       m_jsonMap.loadDefault(); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void | bool | ||||||
| ConfigService::loadProfile(const char* profileName) | ConfigService::loadProfile(const char* profileName) | ||||||
| { | { | ||||||
|     Log.notice("config: Loading profile %s...", profileName); |     Log.notice("config: Loading profile %s...", profileName); | ||||||
| @@ -119,11 +125,16 @@ ConfigService::loadProfile(const char* profileName) | |||||||
|  |  | ||||||
|     LittleFS.begin(); |     LittleFS.begin(); | ||||||
|     if (LittleFS.exists(fname)) { |     if (LittleFS.exists(fname)) { | ||||||
|  |       strncpy(m_config.data.loadedProfile, fname.c_str(), sizeof(m_config.data.loadedProfile)); | ||||||
|       File configFile = LittleFS.open(fname, "r"); |       File configFile = LittleFS.open(fname, "r"); | ||||||
|       jsonConfig.clear(); |       jsonConfig.clear(); | ||||||
|       deserializeJson(jsonConfig, configFile); |       deserializeJson(jsonConfig, configFile); | ||||||
|       configFile.close(); |       configFile.close(); | ||||||
|  |  | ||||||
|  |       //int profileLogLevel = max(0, min(6, jsonConfig["logLevel"])); | ||||||
|  |       //Log.setLevel(profileLogLevel); | ||||||
|  |       //Log.trace("config: \t %d logging level"); | ||||||
|  |  | ||||||
|       JsonObject sceneList = jsonConfig["scenes"]; |       JsonObject sceneList = jsonConfig["scenes"]; | ||||||
|       std::vector<Sequencer::Scene> scenes; |       std::vector<Sequencer::Scene> scenes; | ||||||
|       for(JsonPair pair : sceneList) { |       for(JsonPair pair : sceneList) { | ||||||
| @@ -139,25 +150,37 @@ ConfigService::loadProfile(const char* profileName) | |||||||
|       JsonArray taskList = jsonConfig["tasks"]; |       JsonArray taskList = jsonConfig["tasks"]; | ||||||
|       Log.notice("config: Starting %d tasks", taskList.size()); |       Log.notice("config: Starting %d tasks", taskList.size()); | ||||||
|       for(int i = 0; i < taskList.size();i++) { |       for(int i = 0; i < taskList.size();i++) { | ||||||
|         MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, taskList[i].as<const char*>()}); |         MainLoop::instance()->dispatchSync(InputEvent{InputEvent::StartThing, taskList[i].as<const char*>()}); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       JsonObject defaults = jsonConfig["defaults"]; | ||||||
|  |       Log.notice("config: Loading %d app configurations", defaults.size()); | ||||||
|  |       MainLoop::instance()->dispatchSync(InputEvent{InputEvent::ConfigurationChanged, &defaults}); | ||||||
|  |  | ||||||
|  |       String mapName = jsonConfig["surfaceMap"]; | ||||||
|  |  | ||||||
|  |       jsonConfig.clear(); | ||||||
|  |  | ||||||
|  |       if (mapName.isEmpty()) { | ||||||
|  |         Log.warning("config: No coordinate map defined! Defaulting to linear mapping.", mapName.c_str()); | ||||||
|  |         m_jsonMap.loadDefault(); | ||||||
|  |       } else if (!loadMap(mapName)) { | ||||||
|  |         Log.warning("config: Couldn't load coordinate map %s!!! Defaulting to linear mapping.", mapName.c_str()); | ||||||
|  |         m_jsonMap.loadDefault(); | ||||||
|       } |       } | ||||||
|       Log.notice("config: Loaded!"); |       Log.notice("config: Loaded!"); | ||||||
|     } else { |     } else { | ||||||
|       Log.warning("config: Could not load profile %s!", profileName); |       Log.warning("config: Could not load profile %s!", profileName); | ||||||
|  |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     JsonObject defaults = jsonConfig["defaults"]; |  | ||||||
|     MainLoop::instance()->dispatch(InputEvent{InputEvent::ConfigurationChanged, &defaults}); |  | ||||||
|  |  | ||||||
|     String configName = jsonConfig["surfaceMap"]; |  | ||||||
|     jsonConfig.clear(); |  | ||||||
|     loadMap(configName); |  | ||||||
|     LittleFS.end(); |     LittleFS.end(); | ||||||
|     Log.notice("config: Configured to use %d pixels", m_jsonMap.physicalPixelCount()); |     Log.notice("config: Configured to use %d pixels", m_jsonMap.physicalPixelCount()); | ||||||
|     PhysicalCoordinates topLeft = m_jsonMap.virtualToPhysicalCoords({0, 0}); |     PhysicalCoordinates topLeft = m_jsonMap.virtualToPhysicalCoords({0, 0}); | ||||||
|     PhysicalCoordinates bottomRight = m_jsonMap.virtualToPhysicalCoords({255, 255}); |     PhysicalCoordinates bottomRight = m_jsonMap.virtualToPhysicalCoords({255, 255}); | ||||||
|     Log.verbose("  (0,0) -> (%d, %d) -> %d", topLeft.x, topLeft.y, m_jsonMap.physicalCoordsToIndex(topLeft)); |     Log.verbose("  (0,0) -> (%d, %d) -> %d", topLeft.x, topLeft.y, m_jsonMap.physicalCoordsToIndex(topLeft)); | ||||||
|     Log.verbose("  (255,255) -> (%d, %d) -> %d", bottomRight.x, bottomRight.y, m_jsonMap.physicalCoordsToIndex(bottomRight)); |     Log.verbose("  (255,255) -> (%d, %d) -> %d", bottomRight.x, bottomRight.y, m_jsonMap.physicalCoordsToIndex(bottomRight)); | ||||||
|  |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| @@ -177,7 +200,6 @@ ConfigService::handleEvent(const InputEvent &evt) | |||||||
|     switch(evt.intent) { |     switch(evt.intent) { | ||||||
|         case InputEvent::LoadConfigurationByName: |         case InputEvent::LoadConfigurationByName: | ||||||
|             Log.notice("Reloading configuration %s", evt.asString()); |             Log.notice("Reloading configuration %s", evt.asString()); | ||||||
|             strcpy(m_config.data.loadedProfile, evt.asString()); |  | ||||||
|             loadProfile(evt.asString()); |             loadProfile(evt.asString()); | ||||||
|         case InputEvent::SaveConfigurationRequest: |         case InputEvent::SaveConfigurationRequest: | ||||||
|             Log.notice("Saving configuration"); |             Log.notice("Saving configuration"); | ||||||
|   | |||||||
| @@ -44,6 +44,6 @@ private: | |||||||
|     JsonCoordinateMapping m_jsonMap; |     JsonCoordinateMapping m_jsonMap; | ||||||
|     const char* m_overrideProfile = nullptr; |     const char* m_overrideProfile = nullptr; | ||||||
|  |  | ||||||
|     void loadProfile(const char* name); |     bool loadProfile(const char* name); | ||||||
|     void loadMap(const String&  mapName); |     bool loadMap(const String&  mapName); | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user