diff --git a/include/Animation/AnimationController.h b/include/Animation/AnimationController.h index 0f481fb..6a24c7e 100644 --- a/include/Animation/AnimationController.h +++ b/include/Animation/AnimationController.h @@ -22,6 +22,12 @@ class AnimationController NUM_DEFAULT_ANIMATIONS }; + enum AnimationInitiator { + NONE, + INTERNAL, + USER + }; + static const constexpr std::array AnimationNames{ "Hot Fire", "Cold Fire", @@ -33,8 +39,8 @@ class AnimationController AnimationController(Fader *fader); - void changeAnimation(std::unique_ptr anim, bool transition = true); - void changeAnimation(DefaultAnimation animation_id, bool transition = true); + void changeAnimation(std::unique_ptr anim, bool transition = true, AnimationInitiator animInitiator = INTERNAL); + void changeAnimation(DefaultAnimation animation_id, bool transition = true, AnimationInitiator animInitiator = INTERNAL); void loop(void); @@ -46,6 +52,10 @@ class AnimationController return !m_animation || (m_animation->finished() && !m_nextAnimation); } + uint32_t currentFrame(void) { return m_frame; } + AnimationInitiator animationInitiator(void) { return m_animationInitiator; } + DefaultAnimation lastDefaultAnimation(void) { return m_lastDefaultAnimation; } + private: Fader *m_fader; std::unique_ptr m_animation; @@ -54,4 +64,7 @@ class AnimationController SemaphoreHandle_t m_updateMutex; uint64_t m_frame; + + AnimationInitiator m_animationInitiator; + DefaultAnimation m_lastDefaultAnimation; }; diff --git a/src/Animation/AnimationController.cpp b/src/Animation/AnimationController.cpp index 21831e1..f305bd6 100644 --- a/src/Animation/AnimationController.cpp +++ b/src/Animation/AnimationController.cpp @@ -10,12 +10,13 @@ const constexpr AnimationController::AnimationController(Fader *fader) - : m_fader(fader), m_animation(nullptr), m_frame(0) + : m_fader(fader), m_animation(nullptr), m_frame(0), m_animationInitiator(NONE), m_lastDefaultAnimation(FIRE_HOT) { m_updateMutex = xSemaphoreCreateMutex(); } -void AnimationController::changeAnimation(std::unique_ptr anim, bool transition) +void AnimationController::changeAnimation(std::unique_ptr anim, bool transition, + AnimationController::AnimationInitiator animInitiator) { xSemaphoreTake(m_updateMutex, portMAX_DELAY); @@ -32,29 +33,30 @@ void AnimationController::changeAnimation(std::unique_ptr anim, bool xSemaphoreGive(m_updateMutex); } -void AnimationController::changeAnimation(AnimationController::DefaultAnimation animation_id, bool transition) +void AnimationController::changeAnimation(AnimationController::DefaultAnimation animation_id, bool transition, + AnimationController::AnimationInitiator animInitiator) { std::unique_ptr anim(nullptr); switch(animation_id) { case FIRE_HOT: - changeAnimation(std::unique_ptr(new FireAnimation(m_fader, false)), transition); + anim.reset(new FireAnimation(m_fader, false)); break; case FIRE_COLD: - changeAnimation(std::unique_ptr(new FireAnimation(m_fader, true)), transition); + anim.reset(new FireAnimation(m_fader, true)); break; case SNOWFALL: - changeAnimation(std::unique_ptr(new SnowfallAnimation(m_fader)), transition); + anim.reset(new SnowfallAnimation(m_fader)); break; case MATRIX_CODE: - changeAnimation(std::unique_ptr(new MatrixCodeAnimation(m_fader)), transition); + anim.reset(new MatrixCodeAnimation(m_fader)); break; case FIREWORK: - changeAnimation(std::unique_ptr(new FireworkAnimation(m_fader, 64, 1)), transition); + anim.reset(new FireworkAnimation(m_fader, 64, 1)); break; case FONT_TEST: @@ -69,6 +71,12 @@ void AnimationController::changeAnimation(AnimationController::DefaultAnimation default: return; // unknown id, do nothing } + + m_lastDefaultAnimation = animation_id; + + if(anim) { + changeAnimation(std::move(anim), transition, animInitiator); + } } void AnimationController::loop(void) diff --git a/src/WebServer.cpp b/src/WebServer.cpp index 3dbb75e..fe9ed61 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -172,7 +172,8 @@ void WebServer::handleSetAnim(httpsserver::HTTPRequest *req, httpsserver::HTTPRe WebServer::instance().m_animController->changeAnimation( static_cast(anim_id), - true); + true, + AnimationController::USER); } void WebServer::handleListAnim(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) diff --git a/src/main.cpp b/src/main.cpp index 99fe014..320f936 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,6 +105,56 @@ enum LEDState { TRANSITION_FADE2BLACK }; +static AnimationController::DefaultAnimation loadSavedAnimation(void) +{ + size_t ret; + + File f = SPIFFS.open("/dyn/last_anim"); + if(!f) { + // error, but return something useful + goto readErr; + } + + AnimationController::DefaultAnimation anim; + + ret = f.readBytes(reinterpret_cast(&anim), sizeof(anim)); + + if(ret != sizeof(anim)) { + goto readErr; + } + + f.close(); + + return anim; + +readErr: + return AnimationController::FIRE_COLD; +} + +static void updateSavedAnimation(AnimationController::DefaultAnimation newSavedAnim) +{ + AnimationController::DefaultAnimation oldSavedAnim = loadSavedAnimation(); + + if(oldSavedAnim == newSavedAnim) { + return; + } + + SPIFFS.mkdir("/dyn/"); + File f = SPIFFS.open("/dyn/last_anim", "w"); + + if(!f) { + return; + } + + size_t ret = f.write(reinterpret_cast(&newSavedAnim), sizeof(newSavedAnim)); + + if(ret != sizeof(newSavedAnim)) { + // failed + } + + f.close(); +} + static void ledFSM(void) { static bool stateEntered = true; @@ -147,7 +197,8 @@ static void ledFSM(void) // change to last used animation after some time if((millis() - stateEnteredTime) > 60000) { - animController.changeAnimation(std::unique_ptr(new FireAnimation(&ledFader, false)), true); + // FIXME: does not work with transition because of restart() call in ANIMATION state + animController.changeAnimation(loadSavedAnimation(), false); ledState = ANIMATION; } break; @@ -165,6 +216,11 @@ static void ledFSM(void) nextState = UDP; ledState = TRANSITION; } + + if((animController.animationInitiator() == AnimationController::USER) && + (animController.currentFrame() == 60*60)) { // FIXME: #define FPS and use everywhere + updateSavedAnimation(animController.lastDefaultAnimation()); + } break; case UDP: