main: move more tiny objects out of main.cpp
This commit is contained in:
		| @@ -80,7 +80,18 @@ ConfigService::onStart() | ||||
|     if (strlen(m_config.data.loadedProfile) == 0) { | ||||
|       strcpy(m_config.data.loadedProfile, "default"); | ||||
|     } | ||||
|  | ||||
|     if (m_overrideProfile != nullptr) { | ||||
|       loadProfile(m_overrideProfile); | ||||
|     } else { | ||||
|       loadProfile(m_config.data.loadedProfile); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| ConfigService::overrideProfile(const char* profileName) | ||||
| { | ||||
|     m_overrideProfile = profileName; | ||||
| } | ||||
|  | ||||
| void | ||||
|   | ||||
| @@ -36,10 +36,12 @@ struct ConfigService: public Task { | ||||
|     void handleEvent(const InputEvent &evt) override; | ||||
|     const CoordinateMapping* coordMap() const { return &m_jsonMap; } | ||||
|     const char* loadedProfile() const; | ||||
|     void overrideProfile(const char* profileName); | ||||
|  | ||||
| private: | ||||
|     HardwareConfig m_config; | ||||
|     JsonCoordinateMapping m_jsonMap; | ||||
|     const char* m_overrideProfile = nullptr; | ||||
|  | ||||
|     void loadProfile(const char* name); | ||||
|     void loadMap(const String&  mapName); | ||||
|   | ||||
							
								
								
									
										56
									
								
								src/SafeMode.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/SafeMode.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #include "./SafeMode.h" | ||||
| #include "./LogService.h" | ||||
| #include "./Platform.h" | ||||
| #include "./Static.h" | ||||
| #include "./Config.h" | ||||
|  | ||||
| TaskFunc safeModeNag([]{  | ||||
|     static uint8_t frame = 0; | ||||
|     static CRGB* leds = FastLED.leds(); | ||||
|     EVERY_N_SECONDS(30) { | ||||
|       Log.fatal("I am running in safe mode!"); | ||||
|     } | ||||
|     EVERY_N_MILLISECONDS(16) { | ||||
|       frame++; | ||||
|       for(int i = 0; i < HardwareConfig::MAX_LED_NUM; i++) { | ||||
|         leds[i] = CRGB(0, 0, 0); | ||||
|       } | ||||
|       for(int idx = 0; idx < 3; idx++) { | ||||
|         uint8_t length = beatsin8(5, 3, HardwareConfig::MAX_LED_NUM, 0, idx * 5); | ||||
|         for(int i = 0; i < length; i++) { | ||||
|             leds[i] += CRGB(scale8(5, beatsin8(5 + i * 7, 0, 255, 0, i*3)), 0, 0); | ||||
|         } | ||||
|       } | ||||
|       FastLED.show(); | ||||
|     } | ||||
| }); | ||||
|  | ||||
| #ifdef CONFIG_WIFI | ||||
| #include "platform/arduino/WiFiTask.h" | ||||
| #endif // CONFIG_WIFI | ||||
| #ifdef CONFIG_OTA | ||||
| #include "platform/arduino/OTA.h" | ||||
| #endif // CONFIG_OTA | ||||
| #ifdef CONFIG_MQTT | ||||
| #include "platform/arduino/MQTTTelemetry.h" | ||||
| #endif // CONFIG_MQTT | ||||
|  | ||||
| MainLoop | ||||
| SafeMode::safeModeApp{{ | ||||
|     Static<Platform>::instance(), | ||||
|     // System logging | ||||
|     Static<LogService>::instance(), | ||||
|     &safeModeNag, | ||||
| #ifdef CONFIG_WIFI | ||||
|     // ESP Wifi | ||||
|     Static<WiFiTask>::instance(), | ||||
| #endif // CONFIG_WIFI | ||||
| #ifdef CONFIG_MQTT | ||||
|     // MQTT | ||||
|     Static<MQTTTelemetry>::instance(), | ||||
| #endif // CONFIG_MQTT | ||||
| #ifdef CONFIG_OTA | ||||
|     // OTA Updates | ||||
|     Static<ArduinoOTAUpdater>::instance(), | ||||
| #endif // CONFIG_OTA | ||||
| }}; | ||||
							
								
								
									
										7
									
								
								src/SafeMode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/SafeMode.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #pragma once | ||||
| #include <Figments.h> | ||||
|  | ||||
| class SafeMode { | ||||
|   public: | ||||
|     static MainLoop safeModeApp; | ||||
| }; | ||||
							
								
								
									
										5
									
								
								src/inputs/BPM.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/inputs/BPM.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #include "./BPM.h" | ||||
| #include "../Static.h" | ||||
|  | ||||
| STATIC_ALLOC(BPM); | ||||
| STATIC_TASK(BPM); | ||||
							
								
								
									
										52
									
								
								src/inputs/BPM.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/inputs/BPM.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| #pragma once | ||||
| #include <Figments.h> | ||||
|  | ||||
| class BPM : public InputSource { | ||||
| public: | ||||
|   BPM() : InputSource("BPM") {} | ||||
|   void handleEvent(const InputEvent& evt) override { | ||||
|       if (evt.intent == InputEvent::BeatDetect) { | ||||
|         m_nextBpm = millis(); | ||||
|         m_timings.insert(millis()); | ||||
|         Log.notice("%d timings", m_timings.size()); | ||||
|         if (m_timings.size() >= 5) { | ||||
|           updateBPM(); | ||||
|         } | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   InputEvent read() override { | ||||
|     if (m_bpm > 0) { | ||||
|       uint16_t now = millis(); | ||||
|       if (now >= m_nextBpm) { | ||||
|         m_nextBpm += m_bpm; | ||||
|         return InputEvent{InputEvent::Beat, m_bpm}; | ||||
|       } | ||||
|       if (now >= m_nextLearn && m_nextLearn != 0) { | ||||
|         m_timings.clear(); | ||||
|         m_nextLearn = 0; | ||||
|       } | ||||
|     } | ||||
|     return InputEvent{}; | ||||
|   } | ||||
|  | ||||
| private: | ||||
|   uint16_t m_bpm = 0; | ||||
|   uint16_t m_nextBpm = 0; | ||||
|   uint16_t m_nextLearn = 0; | ||||
|   Ringbuf<uint16_t, 7> m_timings; | ||||
|  | ||||
|   void updateBPM() { | ||||
|     uint16_t avgDelta = 0; | ||||
|     for(uint8_t i = 0; i < m_timings.size() - 1; i++) { | ||||
|       uint16_t delta = m_timings.peek(i+1) - m_timings.peek(i); | ||||
|       Log.notice("Timing %d Delta %d", m_timings.peek(i), delta); | ||||
|       avgDelta += delta; | ||||
|     } | ||||
|     m_bpm = avgDelta / 4; | ||||
|     m_nextLearn = m_bpm * 5 + millis(); | ||||
|     Log.notice("BPM is now %d", m_bpm); | ||||
|     uint16_t trash; | ||||
|     m_timings.take(trash); | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										5
									
								
								src/inputs/CircadianRhythm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/inputs/CircadianRhythm.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #include "./CircadianRhythm.h" | ||||
| #include "../Static.h" | ||||
|  | ||||
| STATIC_ALLOC(CircadianRhythm); | ||||
| STATIC_TASK(CircadianRhythm); | ||||
							
								
								
									
										90
									
								
								src/inputs/CircadianRhythm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/inputs/CircadianRhythm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| #pragma once | ||||
| #include <Figments.h> | ||||
|  | ||||
| struct ScheduleEntry { | ||||
|   uint8_t hour; | ||||
|   uint8_t brightness; | ||||
| }; | ||||
|  | ||||
| std::array<ScheduleEntry, 10> schedule{{ | ||||
|   {0, 0}, | ||||
|   {5, 0}, | ||||
|   {6, 0}, | ||||
|   {7, 10}, | ||||
|   {8, 80}, | ||||
|   {11, 120}, | ||||
|   {18, 200}, | ||||
|   {19, 255}, | ||||
|   {22, 120}, | ||||
|   {23, 20} | ||||
| }}; | ||||
|  | ||||
| class CircadianRhythm : public InputSource { | ||||
|   private: | ||||
|     bool needsUpdate = true; | ||||
|   public: | ||||
|     CircadianRhythm() : InputSource("CircadianRhythm") {} | ||||
|  | ||||
|     void onStart() { | ||||
|       needsUpdate = true; | ||||
|     } | ||||
|  | ||||
|     uint8_t brightnessForTime(uint8_t hour, uint8_t minute) const { | ||||
|       ScheduleEntry start = schedule.back(); | ||||
|       ScheduleEntry end = schedule.front(); | ||||
|       for(ScheduleEntry cur : schedule) { | ||||
|         // Find the last hour that is prior to or equal to now | ||||
|         if (cur.hour <= hour) { | ||||
|           start = cur; | ||||
|         } else { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       for(ScheduleEntry cur : schedule) { | ||||
|         // Find the first hour that is after now | ||||
|         // If no such hour exists, we should automatically wrap back to hour 0 | ||||
|         if (cur.hour > hour) { | ||||
|           end = cur; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       if (start.hour > end.hour) { | ||||
|         end.hour += 24; | ||||
|       } | ||||
|  | ||||
|       uint16_t startTime = start.hour * 60; | ||||
|       uint16_t endTime = end.hour * 60; | ||||
|       uint16_t nowTime = hour * 60 + minute; | ||||
|  | ||||
|       uint16_t duration = endTime - startTime; | ||||
|       uint16_t curDuration = nowTime - startTime; | ||||
|  | ||||
|       uint8_t frac = map8(curDuration, 0, duration); | ||||
|  | ||||
|       return lerp8by8(start.brightness, end.brightness, frac); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     InputEvent read() { | ||||
|       EVERY_N_SECONDS(60) { | ||||
|         needsUpdate = true; | ||||
|       } | ||||
|       if (needsUpdate) { | ||||
|         uint8_t hour = 0; | ||||
|         uint8_t minute = 0; | ||||
|         needsUpdate = false; | ||||
|         struct tm timeinfo; | ||||
|         if (Platform::getLocalTime(&timeinfo)) { | ||||
|           hour = timeinfo.tm_hour; | ||||
|           minute = timeinfo.tm_min; | ||||
|         } else { | ||||
|           hour = 0; | ||||
|           minute = 0; | ||||
|         } | ||||
|         Log.notice("Current time: %d:%d", hour, minute); | ||||
|         return InputEvent{InputEvent::SetBrightness, brightnessForTime(hour, minute)}; | ||||
|       } | ||||
|       return InputEvent{}; | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										5
									
								
								src/inputs/ConfigInput.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/inputs/ConfigInput.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #include "./ConfigInput.h" | ||||
| #include "./Static.h" | ||||
|  | ||||
| STATIC_ALLOC(ConfigInput); | ||||
| STATIC_TASK(ConfigInput); | ||||
							
								
								
									
										77
									
								
								src/inputs/ConfigInput.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/inputs/ConfigInput.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| #pragma once | ||||
| #include <Figments.h> | ||||
|  | ||||
| class ConfigInputTask : public BufferedInputSource { | ||||
|   public: | ||||
|     ConfigInputTask() : BufferedInputSource("ConfigInput") {} | ||||
|  | ||||
|     void handleEvent(const InputEvent& evt) override { | ||||
|         if (evt.intent == InputEvent::UserInput) { | ||||
|             Buttons::Chord chord = (Buttons::Chord) evt.asInt(); | ||||
|             switch (chord) { | ||||
|                 case Buttons::Circle: | ||||
|                     m_currentIntent = nextIntent(); | ||||
|                     //Log.info("Next setting... (%d)", m_currentIntent); | ||||
|                     break; | ||||
|                 case Buttons::CircleTriangle: | ||||
|                     //Log.info("Increment..."); | ||||
|                     increment(); | ||||
|                     break; | ||||
|                 case Buttons::CircleCross: | ||||
|                     //Log.info("Decrement..."); | ||||
|                     decrement(); | ||||
|                     break; | ||||
|                 case Buttons::Triangle: | ||||
|                     //Log.info("Save..."); | ||||
|                     setEvent(InputEvent::SaveConfigurationRequest); | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     InputEvent::Intent m_currentIntent = InputEvent::SetDisplayLength; | ||||
|  | ||||
|     void decrement() { | ||||
|         int current = 0; | ||||
|         switch (m_currentIntent) { | ||||
|             case InputEvent::SetDisplayLength: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->pixelCount; | ||||
|               break; | ||||
|             case InputEvent::SetDisplayOffset: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->startPixel; | ||||
|               break; | ||||
|             default: | ||||
|               break; | ||||
|         } | ||||
|         setEvent(InputEvent{m_currentIntent, current - 1}); | ||||
|     } | ||||
|  | ||||
|     void increment() { | ||||
|         int current = 0; | ||||
|         switch (m_currentIntent) { | ||||
|             case InputEvent::SetDisplayLength: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->pixelCount; | ||||
|               break; | ||||
|             case InputEvent::SetDisplayOffset: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->startPixel; | ||||
|               break; | ||||
|             default: | ||||
|               break; | ||||
|         } | ||||
|         setEvent(InputEvent{m_currentIntent, current + 1}); | ||||
|     } | ||||
|  | ||||
|     InputEvent::Intent nextIntent() { | ||||
|         switch (m_currentIntent) { | ||||
|             case InputEvent::SetDisplayLength: | ||||
|               return InputEvent::SetDisplayOffset; | ||||
|             case InputEvent::SetDisplayOffset: | ||||
|               return InputEvent::SetDisplayLength; | ||||
|             default: | ||||
|               return InputEvent::None; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										319
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										319
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -14,11 +14,10 @@ | ||||
| #include <time.h> | ||||
|  | ||||
| #include "animations/Power.h" | ||||
| #include "animations/Drain.h" | ||||
| #include "animations/InputBlip.h" | ||||
|  | ||||
| #include "inputs/ColorCycle.h" | ||||
| #include "inputs/Buttons.h" | ||||
| #include "SafeMode.h" | ||||
|  | ||||
| #define MAX_BRIGHTNESS 255 | ||||
| //#define PSU_MILLIAMPS 4800 | ||||
| @@ -36,9 +35,9 @@ Display dpy(leds, HardwareConfig::MAX_LED_NUM, Static<ConfigService>::instance() | ||||
|  | ||||
| // Setup power management | ||||
| Power<MAX_BRIGHTNESS, PSU_MILLIAMPS> power; | ||||
|  | ||||
| REGISTER_TASK(power); | ||||
|  | ||||
| // FIXME: rewrite as static task | ||||
| /*FigmentFunc configDisplay([](Display* dpy) { | ||||
|     uint8_t brightness = brighten8_video(beatsin8(60)); | ||||
|     auto coords = Static<ConfigService>::instance()->coordMap(); | ||||
| @@ -91,63 +90,6 @@ InputMapper keyMap([](const InputEvent& evt) { | ||||
|  | ||||
| REGISTER_TASK(keyMap); | ||||
|  | ||||
| class BPM : public InputSource { | ||||
| public: | ||||
|   BPM() : InputSource("BPM") {} | ||||
|   void handleEvent(const InputEvent& evt) override { | ||||
|       if (evt.intent == InputEvent::BeatDetect) { | ||||
|         m_nextBpm = millis(); | ||||
|         m_timings.insert(millis()); | ||||
|         Log.notice("%d timings", m_timings.size()); | ||||
|         if (m_timings.size() >= 5) { | ||||
|           updateBPM(); | ||||
|         } | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   InputEvent read() override { | ||||
|     if (m_bpm > 0) { | ||||
|       uint16_t now = millis(); | ||||
|       if (now >= m_nextBpm) { | ||||
|         m_nextBpm += m_bpm; | ||||
|         return InputEvent{InputEvent::Beat, m_bpm}; | ||||
|       } | ||||
|       if (now >= m_nextLearn && m_nextLearn != 0) { | ||||
|         m_timings.clear(); | ||||
|         m_nextLearn = 0; | ||||
|       } | ||||
|     } | ||||
|     return InputEvent{}; | ||||
|   } | ||||
|  | ||||
| private: | ||||
|   uint16_t m_bpm = 0; | ||||
|   uint16_t m_nextBpm = 0; | ||||
|   uint16_t m_nextLearn = 0; | ||||
|   Ringbuf<uint16_t, 7> m_timings; | ||||
|  | ||||
|   void updateBPM() { | ||||
|     uint16_t avgDelta = 0; | ||||
|     for(uint8_t i = 0; i < m_timings.size() - 1; i++) { | ||||
|       uint16_t delta = m_timings.peek(i+1) - m_timings.peek(i); | ||||
|       Log.notice("Timing %d Delta %d", m_timings.peek(i), delta); | ||||
|       avgDelta += delta; | ||||
|     } | ||||
|     m_bpm = avgDelta / 4; | ||||
|     m_nextLearn = m_bpm * 5 + millis(); | ||||
|     Log.notice("BPM is now %d", m_bpm); | ||||
|     uint16_t trash; | ||||
|     m_timings.take(trash); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| STATIC_ALLOC(BPM); | ||||
| STATIC_TASK(BPM); | ||||
|  | ||||
| Renderer configRenderer{ | ||||
|     {&dpy}, | ||||
|     {Static<DrainAnimation>::instance(), /*&configDisplay,*/ Static<InputBlip>::instance(), &power} | ||||
| }; | ||||
|  | ||||
| // Cycle some random colors | ||||
| ColorSequenceInput<9> idleCycle{{ | ||||
| @@ -171,249 +113,7 @@ ColorSequenceInput<7> rainbowCycle{{ | ||||
|  | ||||
| REGISTER_TASK(rainbowCycle); | ||||
|  | ||||
| /*struct ConfigInputTask: public BufferedInputSource { | ||||
| public: | ||||
|     ConfigInputTask() : BufferedInputSource("ConfigInput") {} | ||||
|  | ||||
|     void handleEvent(const InputEvent& evt) override { | ||||
|         if (evt.intent == InputEvent::UserInput) { | ||||
|             Buttons::Chord chord = (Buttons::Chord) evt.asInt(); | ||||
|             switch (chord) { | ||||
|                 case Buttons::Circle: | ||||
|                     m_currentIntent = nextIntent(); | ||||
|                     //Log.info("Next setting... (%d)", m_currentIntent); | ||||
|                     break; | ||||
|                 case Buttons::CircleTriangle: | ||||
|                     //Log.info("Increment..."); | ||||
|                     increment(); | ||||
|                     break; | ||||
|                 case Buttons::CircleCross: | ||||
|                     //Log.info("Decrement..."); | ||||
|                     decrement(); | ||||
|                     break; | ||||
|                 case Buttons::Triangle: | ||||
|                     //Log.info("Save..."); | ||||
|                     setEvent(InputEvent::SaveConfigurationRequest); | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     InputEvent::Intent m_currentIntent = InputEvent::SetDisplayLength; | ||||
|  | ||||
|     void decrement() { | ||||
|         int current = 0; | ||||
|         switch (m_currentIntent) { | ||||
|             case InputEvent::SetDisplayLength: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->pixelCount; | ||||
|               break; | ||||
|             case InputEvent::SetDisplayOffset: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->startPixel; | ||||
|               break; | ||||
|             default: | ||||
|               break; | ||||
|         } | ||||
|         setEvent(InputEvent{m_currentIntent, current - 1}); | ||||
|     } | ||||
|  | ||||
|     void increment() { | ||||
|         int current = 0; | ||||
|         switch (m_currentIntent) { | ||||
|             case InputEvent::SetDisplayLength: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->pixelCount; | ||||
|               break; | ||||
|             case InputEvent::SetDisplayOffset: | ||||
|               current = Static<ConfigService>::instance()->coordMap()->startPixel; | ||||
|               break; | ||||
|             default: | ||||
|               break; | ||||
|         } | ||||
|         setEvent(InputEvent{m_currentIntent, current + 1}); | ||||
|     } | ||||
|  | ||||
|     InputEvent::Intent nextIntent() { | ||||
|         switch (m_currentIntent) { | ||||
|             case InputEvent::SetDisplayLength: | ||||
|               return InputEvent::SetDisplayOffset; | ||||
|             case InputEvent::SetDisplayOffset: | ||||
|               return InputEvent::SetDisplayLength; | ||||
|             default: | ||||
|               return InputEvent::None; | ||||
|         } | ||||
|     } | ||||
| };*/ | ||||
|  | ||||
| struct ScheduleEntry { | ||||
|   uint8_t hour; | ||||
|   uint8_t brightness; | ||||
| }; | ||||
|  | ||||
| std::array<ScheduleEntry, 10> schedule{{ | ||||
|   {0, 0}, | ||||
|   {5, 0}, | ||||
|   {6, 0}, | ||||
|   {7, 10}, | ||||
|   {8, 80}, | ||||
|   {11, 120}, | ||||
|   {18, 200}, | ||||
|   {19, 255}, | ||||
|   {22, 120}, | ||||
|   {23, 20} | ||||
| }}; | ||||
|  | ||||
| class CircadianRhythm : public InputSource { | ||||
|   private: | ||||
|     bool needsUpdate = true; | ||||
|   public: | ||||
|     CircadianRhythm() : InputSource("CircadianRhythm") {} | ||||
|  | ||||
|     void onStart() { | ||||
|       needsUpdate = true; | ||||
|     } | ||||
|  | ||||
|     uint8_t brightnessForTime(uint8_t hour, uint8_t minute) const { | ||||
|       ScheduleEntry start = schedule.back(); | ||||
|       ScheduleEntry end = schedule.front(); | ||||
|       for(ScheduleEntry cur : schedule) { | ||||
|         // Find the last hour that is prior to or equal to now | ||||
|         if (cur.hour <= hour) { | ||||
|           start = cur; | ||||
|         } else { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       for(ScheduleEntry cur : schedule) { | ||||
|         // Find the first hour that is after now | ||||
|         // If no such hour exists, we should automatically wrap back to hour 0 | ||||
|         if (cur.hour > hour) { | ||||
|           end = cur; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       if (start.hour > end.hour) { | ||||
|         end.hour += 24; | ||||
|       } | ||||
|  | ||||
|       uint16_t startTime = start.hour * 60; | ||||
|       uint16_t endTime = end.hour * 60; | ||||
|       uint16_t nowTime = hour * 60 + minute; | ||||
|  | ||||
|       uint16_t duration = endTime - startTime; | ||||
|       uint16_t curDuration = nowTime - startTime; | ||||
|  | ||||
|       uint8_t frac = map8(curDuration, 0, duration); | ||||
|  | ||||
|       return lerp8by8(start.brightness, end.brightness, frac); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     InputEvent read() { | ||||
|       EVERY_N_SECONDS(60) { | ||||
|         needsUpdate = true; | ||||
|       } | ||||
|       if (needsUpdate) { | ||||
|         uint8_t hour = 0; | ||||
|         uint8_t minute = 0; | ||||
|         needsUpdate = false; | ||||
|         struct tm timeinfo; | ||||
|         if (Platform::getLocalTime(&timeinfo)) { | ||||
|           hour = timeinfo.tm_hour; | ||||
|           minute = timeinfo.tm_min; | ||||
|         } else { | ||||
|           hour = 0; | ||||
|           minute = 0; | ||||
|         } | ||||
|         Log.notice("Current time: %d:%d", hour, minute); | ||||
|         return InputEvent{InputEvent::SetBrightness, brightnessForTime(hour, minute)}; | ||||
|       } | ||||
|       return InputEvent{}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| STATIC_ALLOC(CircadianRhythm); | ||||
| STATIC_TASK(CircadianRhythm); | ||||
|  | ||||
| // A special mainloop app for configuring hardware settings that reboots the | ||||
| // device when the user is finished. | ||||
| /*MainLoop configApp{{ | ||||
|     Static<Platform>::instance(), | ||||
|  | ||||
|     // Manage read/write of configuration data | ||||
|     Static<ConfigService>::instance(), | ||||
|  | ||||
|     // Read hardware inputs | ||||
|     Static<Buttons>::instance(), | ||||
|  | ||||
|     // Map input buttons to configuration commands | ||||
|     new ConfigInputTask(), | ||||
|  | ||||
|     // System logging | ||||
|     Static<LogService>::instance(), | ||||
|  | ||||
|     // Fill the entire display with a color, to see size | ||||
|     &configDisplay, | ||||
|     // Render some basic input feedback | ||||
|     &inputBlip, | ||||
|     // Render it all | ||||
|     &configRenderer, | ||||
| }};*/ | ||||
|  | ||||
| MainLoop configApp{std::vector<Task*>()}; | ||||
|  | ||||
| TaskFunc safeModeNag([]{  | ||||
|     static uint8_t frame = 0; | ||||
|     EVERY_N_SECONDS(30) { | ||||
|       Log.fatal("I am running in safe mode!"); | ||||
|     } | ||||
|     EVERY_N_MILLISECONDS(16) { | ||||
|       frame++; | ||||
|       for(int i = 0; i < HardwareConfig::MAX_LED_NUM; i++) { | ||||
|         leds[i] = CRGB(0, 0, 0); | ||||
|       } | ||||
|       for(int idx = 0; idx < 3; idx++) { | ||||
|         uint8_t length = beatsin8(5, 3, HardwareConfig::MAX_LED_NUM, 0, idx * 5); | ||||
|         for(int i = 0; i < length; i++) { | ||||
|             leds[i] += CRGB(scale8(5, beatsin8(5 + i * 7, 0, 255, 0, i*3)), 0, 0); | ||||
|         } | ||||
|       } | ||||
|       FastLED.show(); | ||||
|     } | ||||
| }); | ||||
|  | ||||
| #ifdef CONFIG_WIFI | ||||
| #include "platform/arduino/WiFiTask.h" | ||||
| #endif // CONFIG_WIFI | ||||
| #ifdef CONFIG_OTA | ||||
| #include "platform/arduino/OTA.h" | ||||
| #endif // CONFIG_OTA | ||||
| #ifdef CONFIG_MQTT | ||||
| #include "platform/arduino/MQTTTelemetry.h" | ||||
| #endif // CONFIG_MQTT | ||||
|  | ||||
| MainLoop safeModeApp{{ | ||||
|     Static<Platform>::instance(), | ||||
|     // System logging | ||||
|     Static<LogService>::instance(), | ||||
|     &safeModeNag, | ||||
| #ifdef CONFIG_WIFI | ||||
|     // ESP Wifi | ||||
|     Static<WiFiTask>::instance(), | ||||
| #endif // CONFIG_WIFI | ||||
| #ifdef CONFIG_MQTT | ||||
|     // MQTT | ||||
|     Static<MQTTTelemetry>::instance(), | ||||
| #endif // CONFIG_MQTT | ||||
| #ifdef CONFIG_OTA | ||||
|     // OTA Updates | ||||
|     Static<ArduinoOTAUpdater>::instance(), | ||||
| #endif // CONFIG_OTA | ||||
| }}; | ||||
|  | ||||
| MainLoop* runner = &safeModeApp; | ||||
| MainLoop* runner = &SafeMode::safeModeApp; | ||||
|  | ||||
| void setup() { | ||||
|   // Turn on, | ||||
| @@ -436,18 +136,19 @@ void setup() { | ||||
|   // Tune in, | ||||
|   if (Platform::bootopts.isSafeMode) { | ||||
|     Log.notice(u8"⚠️ Starting Figment in safe mode!!!"); | ||||
|     runner = &safeModeApp; | ||||
|     runner = &SafeMode::safeModeApp; | ||||
|     FastLED.showColor(CRGB(5, 0, 0)); | ||||
|     FastLED.show(); | ||||
|   } else if (Platform::bootopts.isSetup) { | ||||
|     Log.notice(u8"🔧 Starting Figment in configuration mode..."); | ||||
|     FastLED.showColor(CRGB(0, 5, 0)); | ||||
|     //runner = &configApp; | ||||
|   } else { | ||||
|     Log.notice(u8"🌌 Starting Figment..."); | ||||
|  | ||||
|     if (Platform::bootopts.isSetup) { | ||||
|         Log.notice(u8"🔧 Booting up into setup profile!!!"); | ||||
|         Static<ConfigService>::instance()->overrideProfile("setup"); | ||||
|     } | ||||
|  | ||||
|     // Render all layers to the displays | ||||
|     Renderer* renderer = new Renderer({&dpy}, std::vector<Figment*>{Platform::beginFigments(), Platform::endFigments()}); | ||||
|  | ||||
|     std::vector<Task*> defaultTasks{Platform::beginTasks(), Platform::endTasks()}; | ||||
|     defaultTasks.push_back(renderer); | ||||
|     runner = new MainLoop{std::vector<Task*>{defaultTasks.begin(), defaultTasks.end()}}; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user