diff --git a/include/FSMGlobals.h b/include/FSMGlobals.h index eb1d0d8..f35fc71 100644 --- a/include/FSMGlobals.h +++ b/include/FSMGlobals.h @@ -45,6 +45,7 @@ typedef struct { uint8_t animSnakeIdx = 0; //!< AnimateSnake: Mode selector uint8_t animHeartbeatHue = 0; //!< AnimateHeartbeat: Hue selector uint8_t animHeartbeatSpeed = 1; //!< AnimateHeartbeat: Speed selector + uint8_t animPerlinSpeed = 1; //!< AnimatePerlin: Speed selector } FSMGlobals; #endif /* FSMGLOBALS_H_ */ diff --git a/include/FSMState.h b/include/FSMState.h index f4ad10c..b69c9f1 100644 --- a/include/FSMState.h +++ b/include/FSMState.h @@ -233,6 +233,23 @@ struct AnimateHeartbeat : public FSMState { virtual std::unique_ptr touchEventNoseShortpress() override; }; +/** + * @brief Displays perlin-noise pattern + */ +struct AnimatePerlin : public FSMState { + uint32_t tick = 0; + + virtual const char* getName() override; + virtual bool shouldBeRemembered() override; + virtual const unsigned int getTickRateMs() override; + + virtual void entry() override; + virtual void run() override; + + virtual std::unique_ptr touchEventFingerprintShortpress() override; + virtual std::unique_ptr touchEventNoseShortpress() override; +}; + /** * @brief Accept and handle OTA updates */ diff --git a/src/FSM.cpp b/src/FSM.cpp index 74365d4..8c14a64 100644 --- a/src/FSM.cpp +++ b/src/FSM.cpp @@ -56,6 +56,7 @@ void FSM::resume() { case 2: this->transition(std::make_unique()); break; case 3: this->transition(std::make_unique()); break; case 4: this->transition(std::make_unique()); break; + case 5: this->transition(std::make_unique()); break; default: LOGF_WARNING("(FSM) Failed to resume to unknown state: %d\r\n", this->globals->resumeStateIdx); this->transition(std::make_unique()); diff --git a/src/states/AnimatePerlin.cpp b/src/states/AnimatePerlin.cpp new file mode 100644 index 0000000..3b3d327 --- /dev/null +++ b/src/states/AnimatePerlin.cpp @@ -0,0 +1,97 @@ +// MIT License +// +// Copyright 2024 Eurofurence e.V. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the “Software”), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include +#include +#include + +#include "FSMState.h" + +const char *AnimatePerlin::getName() { + return "AnimatePerlin"; +} + +bool AnimatePerlin::shouldBeRemembered() { + return true; +} + +const unsigned int AnimatePerlin::getTickRateMs() { + return 60; +} + +void AnimatePerlin::entry() { + this->tick = random(500); +} + +void AnimatePerlin::run() { + CRGB data[EFLED_TOTAL_NUM]; + fill_solid(data, EFLED_TOTAL_NUM, CRGB::Black); + + constexpr uint8_t hueScaleX = 2; + constexpr uint8_t hueScaleY = 2; + constexpr uint8_t valScaleX = 10; + constexpr uint8_t valScaleY = 10; + + for (uint8_t i = 0; i < EFLED_TOTAL_NUM; i++) { + + uint8_t hueF = inoise8(EFLedClass::getLEDPosition(i).x * hueScaleX, EFLedClass::getLEDPosition(i).y * hueScaleY, tick * 2 * (this->globals->animPerlinSpeed + 1)); + uint16_t valueF = inoise8(EFLedClass::getLEDPosition(i).x * valScaleX, EFLedClass::getLEDPosition(i).y * valScaleY, tick * 2 * (this->globals->animPerlinSpeed + 1)); + + // inoise is +-64 somehow + //int n = inoise16(x << 8, y << 8) >> 8; + valueF = valueF + 50; + if (valueF > 255) { + valueF = 255; + } + data[i] = CHSV((hueF * 2) % 255, 255, static_cast(valueF)); + } + + EFLed.setAll(data); + + // Prepare next tick + this->tick = this->tick + 1; +} + +std::unique_ptr AnimatePerlin::touchEventFingerprintShortpress() { + return std::make_unique(); +} + +std::unique_ptr AnimatePerlin::touchEventNoseShortpress() { + this->globals->animPerlinSpeed = (this->globals->animPerlinSpeed + 1) % 3; + this->is_globals_dirty = true; + + CRGB data[EFLED_EFBAR_NUM]; + fill_solid(data, EFLED_EFBAR_NUM, CRGB::Black); + EFLed.setEFBar(data); + delay(100); + fill_solid(data, this->globals->animPerlinSpeed + 1, CRGB::Red); + EFLed.setEFBar(data); + delay(300); + fill_solid(data, this->globals->animPerlinSpeed + 1, CRGB::Black); + EFLed.setEFBar(data); + delay(200); + fill_solid(data, this->globals->animPerlinSpeed + 1, CRGB::Red); + EFLed.setEFBar(data); + delay(400); + + return nullptr; +} diff --git a/src/states/MenuMain.cpp b/src/states/MenuMain.cpp index 140e2a0..18ec35c 100644 --- a/src/states/MenuMain.cpp +++ b/src/states/MenuMain.cpp @@ -32,7 +32,7 @@ /** * @brief Number of registered menu items */ -#define MENUMAIN_NUM_MENU_ITEMS 6 +#define MENUMAIN_NUM_MENU_ITEMS 7 const char *MenuMain::getName() { @@ -64,7 +64,8 @@ std::unique_ptr MenuMain::touchEventFingerprintShortpress() { case 2: return std::make_unique(); case 3: return std::make_unique(); case 4: return std::make_unique(); - case 5: return std::make_unique(); + case 5: return std::make_unique(); + case 6: return std::make_unique(); default: return nullptr; } }