diff --git a/mcu/include/SystemInformation.h b/mcu/include/SystemInformation.h index 64522ca..e1578c9 100644 --- a/mcu/include/SystemInformation.h +++ b/mcu/include/SystemInformation.h @@ -65,9 +65,9 @@ namespace TL struct TLInformation { - float rps; float fps; uint16_t ledCount; + uint16_t hiddenLedCount; }; static void begin(); diff --git a/mcu/include/TesLight.h b/mcu/include/TesLight.h index 267a7df..e697915 100644 --- a/mcu/include/TesLight.h +++ b/mcu/include/TesLight.h @@ -70,7 +70,6 @@ class TesLight static unsigned long lightSensorInterval; static unsigned long motionSensorInterval; static unsigned long audioUnitInterval; - static unsigned long renderTimer; static unsigned long frameTimer; static unsigned long lightSensorTimer; static unsigned long motionSensorTimer; @@ -81,7 +80,6 @@ class TesLight static unsigned long webServerTimer; // Counter - static uint16_t renderCounter; static uint16_t frameCounter; static float ledPowerCounter; diff --git a/mcu/include/configuration/SystemConfiguration.h b/mcu/include/configuration/SystemConfiguration.h index de80b2b..f483d5b 100644 --- a/mcu/include/configuration/SystemConfiguration.h +++ b/mcu/include/configuration/SystemConfiguration.h @@ -62,6 +62,7 @@ #endif #define LED_DEFAULT_COUNTS {2, 2, 2, 2, 2, 2, 2, 2} // Default number of LEDs for each channel #define LED_DEFAULT_CHANNEL_CURRENT 16 // Default current per LED channel in mA +#define LED_MAX_COUNT_PER_ZONE 250 // Maximum number of LEDs per channel #define ANIMATOR_NUM_ANIMATION_SETTINGS 25 // Number of custom fields in the LED configuration #define ANIMATOR_DEFAULT_TYPE 0 // Default animation type #define ANIMATOR_DEFAULT_DATA_SOURCE 0 // Default data source of the animation @@ -158,7 +159,6 @@ #define WEB_SERVER_STATIC_CONTENT "/ui/" // Static content location for the UI // Timer configuration -#define RENDER_INTERVAL 16666 // Interval for rendering the pixels in µs #define FRAME_INTERVAL 16666 // Interval for outputting to the LEDs in µs #define FAN_INTERVAL 500000 // Interval for running the fan controll in µs #define LIGHT_SENSOR_INTERVAL 40000 // Interval for the light sensor in µs diff --git a/mcu/include/led/LedManager.h b/mcu/include/led/LedManager.h index a1c0664..3104a85 100644 --- a/mcu/include/led/LedManager.h +++ b/mcu/include/led/LedManager.h @@ -29,9 +29,7 @@ #include "configuration/SystemConfiguration.h" #include "configuration/Configuration.h" -#include "util/FileUtil.h" -#include "FastLED.h" - +#include "led/driver/LedDriver.h" #include "led/animator/RainbowAnimator.h" #include "led/animator/GradientAnimator.h" #include "led/animator/StaticColorAnimator.h" @@ -41,6 +39,7 @@ #include "led/animator/GradientAnimatorMotion.h" #include "led/animator/SparkleAnimator.h" +#include "util/FileUtil.h" #include "sensor/MotionSensor.h" #include "hardware/AudioUnit.h" @@ -53,10 +52,11 @@ namespace TL { OK, // No error ERROR_CONFIG_UNAVAILABLE, // The configuration is not available - ERROR_CREATE_LED_DATA, // Failed to create LED pixel data + ERROR_INIT_LED_DRIVER, // Failed to initialize the LED driver + ERROR_DRIVER_NOT_READY, // The LED driver is not ready to send new LED data ERROR_UNKNOWN_ANIMATOR_TYPE, // The animator type is unknown - ERROR_INVALID_FSEQ, // When a custom animation was set but the fseq file is invalid ERROR_FILE_NOT_FOUND, // The animation file was not found + ERROR_INVALID_FSEQ, // When a custom animation was set but the fseq file is invalid ERROR_INVALID_LED_CONFIGURATION // The current LED configuration does not match the custom animation }; @@ -69,9 +69,6 @@ namespace TL static void setAmbientBrightness(const float ambientBrightness); - static void setRenderInterval(const uint32_t renderInterval); - static uint32_t getRenderInterval(); - static void setFrameInterval(const uint32_t frameInterval); static uint32_t getFrameInterval(); @@ -82,23 +79,24 @@ namespace TL static float getLedPowerDraw(); static size_t getLedCount(); + static size_t getHiddenLedCount(); static void render(); - static void show(); + static TL::LedManager::Error waitShow(const TickType_t timeout); + static TL::LedManager::Error show(const TickType_t timeout); private: LedManager(); static bool initialized; - static std::vector> ledData; + static std::unique_ptr ledBuffer; static std::vector> ledAnimator; static std::unique_ptr fseqLoader; - static uint32_t renderInterval; static uint32_t frameInterval; static float regulatorTemperature; - static TL::LedManager::Error createLedData(); + static TL::LedManager::Error initLedDriver(); static TL::LedManager::Error createAnimators(); static TL::LedManager::Error loadCalculatedAnimations(); static TL::LedManager::Error loadCustomAnimation(const String &fileName); @@ -106,7 +104,6 @@ namespace TL static void calculateRegulatorPowerDraw(float regulatorPower[REGULATOR_COUNT]); static void limitPowerConsumption(); static void limitRegulatorTemperature(); - static uint8_t getRegulatorIndexFromPin(const uint8_t pin); }; } diff --git a/mcu/include/led/animator/ColorBarAnimator.h b/mcu/include/led/animator/ColorBarAnimator.h index c9e6a07..f73e831 100644 --- a/mcu/include/led/animator/ColorBarAnimator.h +++ b/mcu/include/led/animator/ColorBarAnimator.h @@ -39,19 +39,19 @@ namespace TL }; ColorBarAnimator(); - ColorBarAnimator(const TL::ColorBarAnimator::ColorBarMode colorBarMode, const CRGB color1, const CRGB color2); + ColorBarAnimator(const TL::ColorBarAnimator::ColorBarMode colorBarMode, const TL::Pixel color1, const TL::Pixel color2); ~ColorBarAnimator(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); void setColorBarMode(const TL::ColorBarAnimator::ColorBarMode colorBarMode); - void setColor(const CRGB color1, const CRGB color2); + void setColor(const TL::Pixel color1, const TL::Pixel color2); private: float angle; TL::ColorBarAnimator::ColorBarMode colorBarMode; - CRGB color[2]; + TL::Pixel color[2]; }; } diff --git a/mcu/include/led/animator/FseqAnimator.h b/mcu/include/led/animator/FseqAnimator.h index 565a529..cc1d535 100644 --- a/mcu/include/led/animator/FseqAnimator.h +++ b/mcu/include/led/animator/FseqAnimator.h @@ -34,8 +34,8 @@ namespace TL FseqAnimator(TL::FseqLoader *fseqLoader, const bool loop = false); ~FseqAnimator(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: TL::FseqLoader *fseqLoader; diff --git a/mcu/include/led/animator/GradientAnimator.h b/mcu/include/led/animator/GradientAnimator.h index 59e9339..45791b9 100644 --- a/mcu/include/led/animator/GradientAnimator.h +++ b/mcu/include/led/animator/GradientAnimator.h @@ -36,15 +36,15 @@ namespace TL GRADIENT_CENTER = 1 }; - GradientAnimator(const TL::GradientAnimator::GradientMode gradientMode, const CRGB color1, const CRGB color2); + GradientAnimator(const TL::GradientAnimator::GradientMode gradientMode, const TL::Pixel color1, const TL::Pixel color2); ~GradientAnimator(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: TL::GradientAnimator::GradientMode gradientMode; - CRGB color[2]; + TL::Pixel color[2]; }; } diff --git a/mcu/include/led/animator/GradientAnimatorMotion.h b/mcu/include/led/animator/GradientAnimatorMotion.h index eb4636b..863407c 100644 --- a/mcu/include/led/animator/GradientAnimatorMotion.h +++ b/mcu/include/led/animator/GradientAnimatorMotion.h @@ -37,15 +37,15 @@ namespace TL GRADIENT_CENTER = 1 }; - GradientAnimatorMotion(const TL::GradientAnimatorMotion::GradientMode gradientMode, const CRGB color1, const CRGB color2); + GradientAnimatorMotion(const TL::GradientAnimatorMotion::GradientMode gradientMode, const TL::Pixel color1, const TL::Pixel color2); ~GradientAnimatorMotion(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: TL::GradientAnimatorMotion::GradientMode gradientMode; - CRGB color[2]; + TL::Pixel color[2]; float getMotionOffset(); }; diff --git a/mcu/include/led/animator/LedAnimator.h b/mcu/include/led/animator/LedAnimator.h index 994c145..cec2978 100644 --- a/mcu/include/led/animator/LedAnimator.h +++ b/mcu/include/led/animator/LedAnimator.h @@ -26,7 +26,7 @@ #include #include -#include "FastLED.h" +#include "led/driver/LedStrip.h" #include "sensor/MotionSensor.h" #include "hardware/AudioUnit.h" @@ -91,8 +91,8 @@ namespace TL void setAudioAnalysis(const TL::AudioUnit::AudioAnalysis &audioAnalysis); TL::AudioUnit::AudioAnalysis &getAudioAnalysis(); - virtual void init(std::vector &pixels) = 0; - virtual void render(std::vector &pixels) = 0; + virtual void init(TL::LedStrip &ledStrip) = 0; + virtual void render(TL::LedStrip &ledStrip) = 0; protected: TL::LedAnimator::DataSource dataSource; @@ -107,8 +107,8 @@ namespace TL TL::MotionSensor::MotionSensorData motionSensorData; TL::AudioUnit::AudioAnalysis audioAnalysis; - void reversePixels(std::vector &pixels); - void applyBrightness(std::vector &pixels); + void reversePixels(TL::LedStrip &ledStrip); + void applyBrightness(TL::LedStrip &ledStrip); static int32_t random(const int32_t min, const int32_t max); static float trapezoid(float angle); static float trapezoid2(float angle); diff --git a/mcu/include/led/animator/RainbowAnimator.h b/mcu/include/led/animator/RainbowAnimator.h index 76d9b02..27f5639 100644 --- a/mcu/include/led/animator/RainbowAnimator.h +++ b/mcu/include/led/animator/RainbowAnimator.h @@ -40,8 +40,8 @@ namespace TL RainbowAnimator(const TL::RainbowAnimator::RainbowMode rainbowMode); ~RainbowAnimator(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: float angle; diff --git a/mcu/include/led/animator/RainbowAnimatorMotion.h b/mcu/include/led/animator/RainbowAnimatorMotion.h index 5a06414..c49ddc0 100644 --- a/mcu/include/led/animator/RainbowAnimatorMotion.h +++ b/mcu/include/led/animator/RainbowAnimatorMotion.h @@ -41,8 +41,8 @@ namespace TL RainbowAnimatorMotion(const TL::RainbowAnimatorMotion::RainbowMode rainbowMode); ~RainbowAnimatorMotion(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: float angle; diff --git a/mcu/include/led/animator/SparkleAnimator.h b/mcu/include/led/animator/SparkleAnimator.h index 832d228..9f455fc 100644 --- a/mcu/include/led/animator/SparkleAnimator.h +++ b/mcu/include/led/animator/SparkleAnimator.h @@ -45,27 +45,27 @@ namespace TL float lastPosition; // Previous position of a spark float speed; // Speed of a spark float friction; // Friction of a spark - CRGB color; // Color of a spark + TL::Pixel color; // Color of a spark float brightness; // Brightness of a spark float fading; // Fafing speed of a spark }; - SparkleAnimator(const TL::SparkleAnimator::SpawnPosition spawnPosition, const uint8_t sparkCount, const CRGB color, + SparkleAnimator(const TL::SparkleAnimator::SpawnPosition spawnPosition, const uint8_t sparkCount, const TL::Pixel color, const float sparkFriction, const float sparkFading, const float sparkTail, const float birthRate, const float spawnVariance, const float speedVariance, const float brightnessVariance, const float frictionVariance, const float fadingVariance, const bool bounceAtCorner, const uint8_t frequencyBandMask); ~SparkleAnimator(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: - std::vector pixelBuffer; + std::vector pixelBuffer; std::vector pixelMask; std::vector sparks; TL::SparkleAnimator::SpawnPosition spawnPosition; - CRGB color; + TL::Pixel color; float sparkFriction; float sparkFading; float sparkTail; @@ -81,8 +81,8 @@ namespace TL float colorAngle; uint8_t audioSequence; - void spawnSparks(std::vector &pixels); - void runSparks(std::vector &pixels); + void spawnSparks(TL::LedStrip &ledStrip); + void runSparks(TL::LedStrip &ledStrip); template void limit(const T min, const T max, T &value) diff --git a/mcu/include/led/animator/StaticColorAnimator.h b/mcu/include/led/animator/StaticColorAnimator.h index 28fe675..51bfdc1 100644 --- a/mcu/include/led/animator/StaticColorAnimator.h +++ b/mcu/include/led/animator/StaticColorAnimator.h @@ -30,14 +30,14 @@ namespace TL class StaticColorAnimator : public LedAnimator { public: - StaticColorAnimator(const CRGB color); + StaticColorAnimator(const TL::Pixel color); ~StaticColorAnimator(); - void init(std::vector &pixels); - void render(std::vector &pixels); + void init(TL::LedStrip &ledStrip); + void render(TL::LedStrip &ledStrip); private: - CRGB color; + TL::Pixel color; }; } diff --git a/mcu/include/led/driver/LedBuffer.h b/mcu/include/led/driver/LedBuffer.h new file mode 100644 index 0000000..c93639a --- /dev/null +++ b/mcu/include/led/driver/LedBuffer.h @@ -0,0 +1,61 @@ +/** + * @file LedBuffer.h + * @author TheRealKasumi + * @brief Contains a class to manage the LED buffer for multiple LED strips. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#ifndef LED_BUFFER_H +#define LED_BUFFER_H + +#include +#include +#include + +#include "LedStrip.h" + +namespace TL +{ + class LedBuffer + { + public: + LedBuffer(const std::vector &ledStrips); + ~LedBuffer(); + + size_t getBufferSize(); + uint8_t *getBuffer(); + + size_t getTotalLedCount(); + size_t getMaxLedCount(); + + size_t getTotalHiddenLedCount(); + size_t getMaxHiddenLedCount(); + + size_t getLedStripCount(); + TL::LedStrip &getLedStrip(const size_t index); + + private: + std::vector ledStrips; + size_t totalLedCount; + size_t maxLedCount; + size_t totalHiddenLedCount; + size_t maxHiddenLedCount; + uint8_t *buffer; + }; +} + +#endif diff --git a/mcu/include/led/driver/LedDriver.h b/mcu/include/led/driver/LedDriver.h new file mode 100644 index 0000000..b8ef2fb --- /dev/null +++ b/mcu/include/led/driver/LedDriver.h @@ -0,0 +1,113 @@ +/** + * @file LedDriver.h + * @author TheRealKasumi + * @brief Contains a class with an LED driver for WS2812B LEDs. It support parallel output for up to 8 channels. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#ifndef LED_DRIVER_H +#define LED_DRIVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "led/driver/LedBuffer.h" + +namespace TL +{ + class LedDriver + { + public: + enum class Error + { + OK, // No error + ERROR_NO_LED_STRIPS, // No LED strips provided + ERROR_NOT_INITIALIZED, // Not initialized yet + ERROR_SET_PIN, // Failed to configure the output pin + ERROR_ALLOCATE_INTERRUPT, // Failed to allocate the interrupt + ERROR_ENABLE_INTERRUPT, // Failed to enable interrupt + ERROR_STILL_SENDING // When the driver is still sending LED data + }; + + enum class I2SDevice : uint8_t + { + I2S_DEV_0 = 0, // I2S device 0 + I2S_DEV_1 = 1 // I2S Device 1 + }; + + static TL::LedDriver::Error begin(TL::LedBuffer &ledBuffer, const TL::LedDriver::I2SDevice i2sDeviceIdentifier = TL::LedDriver::I2SDevice::I2S_DEV_0); + static bool isInitialized(); + static void end(); + + static TL::LedDriver::Error isReady(const TickType_t timeout = 0); + static TL::LedDriver::Error showPixels(const TickType_t timeout = 0); + + private: + LedDriver(); + + struct DMABuffer + { + lldesc_t descriptor; + uint8_t *buffer; + }; + + static bool initialized; + + static uint8_t *ledBuffer; + static volatile uint16_t ledIndex; + static volatile uint16_t ledStripCount; + static uint16_t ledStripLength[8]; + static volatile uint16_t ledStripMaxLength; + + static i2s_dev_t *i2sDevice; + static TL::LedDriver::I2SDevice i2sDeviceIdentifier; + + static TL::LedDriver::DMABuffer *dmaBuffer[4]; + static volatile uint8_t dmaBufferIndex; + + static intr_handle_t interruptHandle; + static volatile xSemaphoreHandle semaphore; + + static TL::LedDriver::Error initPin(const uint8_t outputPin, const uint8_t ledStripIndex); + static TL::LedDriver::Error initI2S(); + static TL::LedDriver::Error startI2S(const TL::LedDriver::DMABuffer *startBuffer); + static void IRAM_ATTR resetI2S(); + static void IRAM_ATTR stopI2S(); + static void resetDMA(); + static void resetFIFO(); + + static TL::LedDriver::DMABuffer *allocateDMABuffer(const uint32_t size); + static void freeDMABuffer(TL::LedDriver::DMABuffer *dmaBuffer); + static void initDMABuffers(); + + static void IRAM_ATTR interruptHandler(void *args); + static void IRAM_ATTR loadDMABuffer(uint8_t *ledBuffer, uint16_t *dmaBuffer, const uint16_t *ledStripLength, const uint16_t ledStripCount, const uint16_t ledIndex); + static void IRAM_ATTR transpose(uint8_t *pixelBuffer, uint16_t *dmaBuffer); + }; +}; + +#endif diff --git a/mcu/include/led/driver/LedStrip.h b/mcu/include/led/driver/LedStrip.h new file mode 100644 index 0000000..74952a1 --- /dev/null +++ b/mcu/include/led/driver/LedStrip.h @@ -0,0 +1,58 @@ +/** + * @file LedStrip.h + * @author TheRealKasumi + * @brief Contains a class that represents a single LED strip inside the {@link TL::LedBuffer}. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#ifndef LED_STRIP_H +#define LED_STRIP_H + +#include +#include +#include + +#include "Pixel.h" + +namespace TL +{ + class LedStrip + { + public: + LedStrip(const uint8_t ledPin, const size_t ledCount, const size_t hiddenLedCount = 8); + ~LedStrip(); + + uint8_t getLedPin(); + size_t getLedCount(); + size_t getHiddenLedCount(); + + TL::Pixel getPixel(const size_t index); + void setPixel(const TL::Pixel &pixel, const size_t index); + + uint8_t *getBuffer(); + void setBuffer(uint8_t *buffer); + + private: + uint8_t ledPin; + size_t ledCount; + size_t hiddenLedCount; + uint8_t *buffer; + bool initialized; + }; +} + +#endif diff --git a/mcu/include/led/driver/Pixel.h b/mcu/include/led/driver/Pixel.h new file mode 100644 index 0000000..edfc50c --- /dev/null +++ b/mcu/include/led/driver/Pixel.h @@ -0,0 +1,221 @@ +/** + * @file Pixel.h + * @author TheRealKasumi + * @brief Contains a class respresint a single WS2812B pixel. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#ifndef PIXEL_H +#define PIXEL_H + +#include "stdint.h" + +namespace TL +{ + class Pixel + { + public: + enum class ColorCode : uint32_t + { + AliceBlue = 0xF0F8FF, + Amethyst = 0x9966CC, + AntiqueWhite = 0xFAEBD7, + Aqua = 0x00FFFF, + Aquamarine = 0x7FFFD4, + Azure = 0xF0FFFF, + Beige = 0xF5F5DC, + Bisque = 0xFFE4C4, + Black = 0x000000, + BlanchedAlmond = 0xFFEBCD, + Blue = 0x0000FF, + BlueViolet = 0x8A2BE2, + Brown = 0xA52A2A, + BurlyWood = 0xDEB887, + CadetBlue = 0x5F9EA0, + Chartreuse = 0x7FFF00, + Chocolate = 0xD2691E, + Coral = 0xFF7F50, + CornflowerBlue = 0x6495ED, + Cornsilk = 0xFFF8DC, + Crimson = 0xDC143C, + Cyan = 0x00FFFF, + DarkBlue = 0x00008B, + DarkCyan = 0x008B8B, + DarkGoldenrod = 0xB8860B, + DarkGray = 0xA9A9A9, + DarkGrey = 0xA9A9A9, + DarkGreen = 0x006400, + DarkKhaki = 0xBDB76B, + DarkMagenta = 0x8B008B, + DarkOliveGreen = 0x556B2F, + DarkOrange = 0xFF8C00, + DarkOrchid = 0x9932CC, + DarkRed = 0x8B0000, + DarkSalmon = 0xE9967A, + DarkSeaGreen = 0x8FBC8F, + DarkSlateBlue = 0x483D8B, + DarkSlateGray = 0x2F4F4F, + DarkSlateGrey = 0x2F4F4F, + DarkTurquoise = 0x00CED1, + DarkViolet = 0x9400D3, + DeepPink = 0xFF1493, + DeepSkyBlue = 0x00BFFF, + DimGray = 0x696969, + DimGrey = 0x696969, + DodgerBlue = 0x1E90FF, + FireBrick = 0xB22222, + FloralWhite = 0xFFFAF0, + ForestGreen = 0x228B22, + Fuchsia = 0xFF00FF, + Gainsboro = 0xDCDCDC, + GhostWhite = 0xF8F8FF, + Gold = 0xFFD700, + Goldenrod = 0xDAA520, + Gray = 0x808080, + Grey = 0x808080, + Green = 0x008000, + GreenYellow = 0xADFF2F, + Honeydew = 0xF0FFF0, + HotPink = 0xFF69B4, + IndianRed = 0xCD5C5C, + Indigo = 0x4B0082, + Ivory = 0xFFFFF0, + Khaki = 0xF0E68C, + Lavender = 0xE6E6FA, + LavenderBlush = 0xFFF0F5, + LawnGreen = 0x7CFC00, + LemonChiffon = 0xFFFACD, + LightBlue = 0xADD8E6, + LightCoral = 0xF08080, + LightCyan = 0xE0FFFF, + LightGoldenrodYellow = 0xFAFAD2, + LightGreen = 0x90EE90, + LightGrey = 0xD3D3D3, + LightPink = 0xFFB6C1, + LightSalmon = 0xFFA07A, + LightSeaGreen = 0x20B2AA, + LightSkyBlue = 0x87CEFA, + LightSlateGray = 0x778899, + LightSlateGrey = 0x778899, + LightSteelBlue = 0xB0C4DE, + LightYellow = 0xFFFFE0, + Lime = 0x00FF00, + LimeGreen = 0x32CD32, + Linen = 0xFAF0E6, + Magenta = 0xFF00FF, + Maroon = 0x800000, + MediumAquamarine = 0x66CDAA, + MediumBlue = 0x0000CD, + MediumOrchid = 0xBA55D3, + MediumPurple = 0x9370DB, + MediumSeaGreen = 0x3CB371, + MediumSlateBlue = 0x7B68EE, + MediumSpringGreen = 0x00FA9A, + MediumTurquoise = 0x48D1CC, + MediumVioletRed = 0xC71585, + MidnightBlue = 0x191970, + MintCream = 0xF5FFFA, + MistyRose = 0xFFE4E1, + Moccasin = 0xFFE4B5, + NavajoWhite = 0xFFDEAD, + Navy = 0x000080, + OldLace = 0xFDF5E6, + Olive = 0x808000, + OliveDrab = 0x6B8E23, + Orange = 0xFFA500, + OrangeRed = 0xFF4500, + Orchid = 0xDA70D6, + PaleGoldenrod = 0xEEE8AA, + PaleGreen = 0x98FB98, + PaleTurquoise = 0xAFEEEE, + PaleVioletRed = 0xDB7093, + PapayaWhip = 0xFFEFD5, + PeachPuff = 0xFFDAB9, + Peru = 0xCD853F, + Pink = 0xFFC0CB, + Plaid = 0xCC5533, + Plum = 0xDDA0DD, + PowderBlue = 0xB0E0E6, + Purple = 0x800080, + Red = 0xFF0000, + RosyBrown = 0xBC8F8F, + RoyalBlue = 0x4169E1, + SaddleBrown = 0x8B4513, + Salmon = 0xFA8072, + SandyBrown = 0xF4A460, + SeaGreen = 0x2E8B57, + Seashell = 0xFFF5EE, + Sienna = 0xA0522D, + Silver = 0xC0C0C0, + SkyBlue = 0x87CEEB, + SlateBlue = 0x6A5ACD, + SlateGray = 0x708090, + SlateGrey = 0x708090, + Snow = 0xFFFAFA, + SpringGreen = 0x00FF7F, + SteelBlue = 0x4682B4, + Tan = 0xD2B48C, + Teal = 0x008080, + Thistle = 0xD8BFD8, + Tomato = 0xFF6347, + Turquoise = 0x40E0D0, + Violet = 0xEE82EE, + Wheat = 0xF5DEB3, + White = 0xFFFFFF, + WhiteSmoke = 0xF5F5F5, + Yellow = 0xFFFF00, + YellowGreen = 0x9ACD32, + }; + + union + { + struct + { + uint8_t green; + uint8_t red; + uint8_t blue; + }; + uint8_t raw[3]; + }; + + Pixel(); + Pixel(const uint32_t colorCode); + Pixel(const TL::Pixel::ColorCode colorCode); + Pixel(const uint8_t red, const uint8_t green, const uint8_t blue); + ~Pixel(); + + void setColor(const uint32_t colorCode); + void setColor(const TL::Pixel::ColorCode colorCode); + void setColor(const uint8_t red, const uint8_t green, const uint8_t blue); + + Pixel &operator=(const Pixel &pixel) + { + this->red = pixel.red; + this->green = pixel.green; + this->blue = pixel.blue; + return *this; + } + + Pixel &operator=(const Pixel::ColorCode &colorCode) + { + this->setColor(colorCode); + return *this; + } + }; +} + +#endif diff --git a/mcu/include/util/FseqLoader.h b/mcu/include/util/FseqLoader.h index 74b8b50..4f48254 100644 --- a/mcu/include/util/FseqLoader.h +++ b/mcu/include/util/FseqLoader.h @@ -25,7 +25,8 @@ #include #include #include -#include "FastLED.h" + +#include "led/driver/LedStrip.h" namespace TL { @@ -73,7 +74,7 @@ namespace TL void close(); FseqHeader getHeader(); - TL::FseqLoader::Error readPixelBuffer(std::vector &pixels); + TL::FseqLoader::Error readLedStrip(TL::LedStrip &ledStrip); void setFillerBytes(const uint8_t fillerBytes); uint8_t getFillerBytes(); diff --git a/mcu/platformio.ini b/mcu/platformio.ini index 7eeeef8..1a21268 100644 --- a/mcu/platformio.ini +++ b/mcu/platformio.ini @@ -14,7 +14,7 @@ board = az-delivery-devkit-v4 framework = arduino board_build.partitions = partition.csv build_type = release -build_flags = -O2 ; Better don't use O3, partially breaks code and even hits ICEs +build_flags = -O3 build_unflags = -Os check_tool = cppcheck, clangtidy upload_port = COM10 @@ -22,6 +22,5 @@ monitor_port = COM10 monitor_speed = 115200 monitor_filters = esp32_exception_decoder lib_deps = - https://github.com/TheRealKasumi/FastLED.git https://github.com/bblanchon/ArduinoJson.git https://github.com/PaulStoffregen/OneWire.git diff --git a/mcu/src/SystemInformation.cpp b/mcu/src/SystemInformation.cpp index ce0f0b8..9b40f17 100644 --- a/mcu/src/SystemInformation.cpp +++ b/mcu/src/SystemInformation.cpp @@ -58,7 +58,6 @@ void TL::SystemInformation::begin() TL::SystemInformation::hardwareInfo.audioUnit = 0; TL::SystemInformation::systemInfo.fps = 0; - TL::SystemInformation::systemInfo.rps = 0; TL::SystemInformation::systemInfo.ledCount = 0; TL::SystemInformation::updateSocInfo(false); diff --git a/mcu/src/TesLight.cpp b/mcu/src/TesLight.cpp index 2cda83f..e986641 100644 --- a/mcu/src/TesLight.cpp +++ b/mcu/src/TesLight.cpp @@ -24,7 +24,6 @@ unsigned long TesLight::lightSensorInterval = LIGHT_SENSOR_INTERVAL; unsigned long TesLight::motionSensorInterval = MOTION_SENSOR_INTERVAL; unsigned long TesLight::audioUnitInterval = AUDIO_UNIT_INTERVAL; -unsigned long TesLight::renderTimer = 0; unsigned long TesLight::frameTimer = 0; unsigned long TesLight::lightSensorTimer = 0; unsigned long TesLight::motionSensorTimer = 0; @@ -34,7 +33,6 @@ unsigned long TesLight::statusTimer = 0; unsigned long TesLight::statusPrintTimer = 0; unsigned long TesLight::webServerTimer = 0; -uint16_t TesLight::renderCounter = 0; uint16_t TesLight::frameCounter = 0; float TesLight::ledPowerCounter = 0.0f; @@ -63,6 +61,7 @@ void TesLight::begin() TesLight::initializeRestApi(); // Iniaialize the rest api TesLight::createtWiFiNetwork(); // Create the WiFi network for clients to connect to TesLight::initializeTimers(); // Initialize the timers + TL::WatchDog::initializeTaskWatchdog(); // Initialize the watchdog timer TL::Logger::log(TL::Logger::LogLevel::INFO, SOURCE_LOCATION, F("TesLight initialized successfully, going into work mode.")); } @@ -302,13 +301,9 @@ void TesLight::initializeLedManager() TL::Logger::log(TL::Logger::LogLevel::INFO, SOURCE_LOCATION, F("LED manager initialized. Loading animations.")); const TL::LedManager::Error ledManagerLoadError = TL::LedManager::reloadAnimations(); - if (ledManagerLoadError == TL::LedManager::Error::ERROR_CONFIG_UNAVAILABLE) + if (ledManagerLoadError == TL::LedManager::Error::ERROR_INIT_LED_DRIVER) { - TL::Logger::log(TL::Logger::LogLevel::WARN, SOURCE_LOCATION, F("Failed to load LED configuration. The TesLight configuration is not available. Continuing without LEDs.")); - } - else if (ledManagerLoadError == TL::LedManager::Error::ERROR_CREATE_LED_DATA) - { - TL::Logger::log(TL::Logger::LogLevel::WARN, SOURCE_LOCATION, F("Failed to load LED configuration. The pixel data could not be created. Continuing without LEDs.")); + TL::Logger::log(TL::Logger::LogLevel::WARN, SOURCE_LOCATION, F("Failed to load LED configuration. The LED driver could not be initialized for the LED configuration.")); } else if (ledManagerLoadError == TL::LedManager::Error::ERROR_UNKNOWN_ANIMATOR_TYPE) { @@ -511,7 +506,6 @@ void TesLight::initializeTimers() { TL::Logger::log(TL::Logger::LogLevel::INFO, SOURCE_LOCATION, F("Initialize/reset timers.")); unsigned long mic = micros(); - TesLight::renderTimer = mic; TesLight::frameTimer = mic; TesLight::lightSensorTimer = mic; TesLight::motionSensorTimer = mic; @@ -520,7 +514,6 @@ void TesLight::initializeTimers() TesLight::statusTimer = mic; TesLight::statusPrintTimer = mic; TesLight::webServerTimer = mic; - TesLight::renderCounter = 0; TesLight::frameCounter = 0; TL::Logger::log(TL::Logger::LogLevel::INFO, SOURCE_LOCATION, (String)F("Timers initialized to ") + mic + F(".")); } @@ -673,17 +666,12 @@ bool TesLight::checkTimer(unsigned long &timer, unsigned long cycleTime) */ void TesLight::run() { - // Handle the pixel rendering - if (TesLight::checkTimer(TesLight::renderTimer, TL::LedManager::getRenderInterval())) - { - TL::LedManager::render(); - TesLight::renderCounter++; - } - - // Handle the LEDs + // Handle the pixel rendering and LED output if (TesLight::checkTimer(TesLight::frameTimer, TL::LedManager::getFrameInterval())) { - TL::LedManager::show(); + TL::LedManager::render(); + TL::LedManager::show(portMAX_DELAY); + TL::LedManager::waitShow(portMAX_DELAY); TesLight::frameCounter++; TesLight::ledPowerCounter += TL::LedManager::getLedPowerDraw(); } @@ -745,7 +733,7 @@ void TesLight::run() const TL::Fan::Error fanError = TL::Fan::run(static_cast(TL::Configuration::getSystemConfig().fanMode)); if (fanError == TL::Fan::Error::ERROR_TEMP_UNAVAILABLE) { - TL::Logger::log(TL::Logger::LogLevel::ERROR, SOURCE_LOCATION, F("Failed to update cooling fan because the temperature could not be read. Using fallback.")); + TL::Logger::log(TL::Logger::LogLevel::DEBUG, SOURCE_LOCATION, F("Failed to update cooling fan because the temperature could not be read. Using fallback.")); } else if (fanError != TL::Fan::Error::OK) { @@ -765,9 +753,9 @@ void TesLight::run() // Update LED related information TL::SystemInformation::TLInformation tlInfo = TL::SystemInformation::getTesLightInfo(); - tlInfo.rps = renderCounter / (STATUS_INTERVAL / 1000000.0f); tlInfo.fps = frameCounter / (STATUS_INTERVAL / 1000000.0f); tlInfo.ledCount = TL::LedManager::getLedCount(); + tlInfo.hiddenLedCount = TL::LedManager::getHiddenLedCount(); TL::SystemInformation::setTesLightInfo(tlInfo); // Update regulator related information @@ -787,7 +775,6 @@ void TesLight::run() } TL::SystemInformation::setHardwareInfo(hwInfo); - TesLight::renderCounter = 0; TesLight::frameCounter = 0; TesLight::ledPowerCounter = 0.0f; } @@ -801,8 +788,7 @@ void TesLight::run() TL::Logger::log( TL::Logger::LogLevel::INFO, SOURCE_LOCATION, - (String)F("Renderer: ") + tlInfo.rps + F("RPS ") + - F("LED: ") + tlInfo.fps + F("FPS ") + + (String)F("LED Driver: ") + tlInfo.fps + F("FPS ") + F("Average Power: ") + hwInfo.regulatorPowerDraw + F("W ") + F("Average Current: ") + hwInfo.regulatorCurrentDraw + F("A ") + F("Temperature: ") + hwInfo.regulatorTemperature + F("°C ") + diff --git a/mcu/src/led/LedManager.cpp b/mcu/src/led/LedManager.cpp index fded047..0d27637 100644 --- a/mcu/src/led/LedManager.cpp +++ b/mcu/src/led/LedManager.cpp @@ -23,10 +23,9 @@ #include "led/LedManager.h" bool TL::LedManager::initialized = false; -std::vector> TL::LedManager::ledData; +std::unique_ptr TL::LedManager::ledBuffer; std::vector> TL::LedManager::ledAnimator; std::unique_ptr TL::LedManager::fseqLoader; -uint32_t TL::LedManager::renderInterval; uint32_t TL::LedManager::frameInterval; float TL::LedManager::regulatorTemperature; @@ -38,7 +37,6 @@ float TL::LedManager::regulatorTemperature; TL::LedManager::Error TL::LedManager::begin() { TL::LedManager::initialized = false; - TL::LedManager::renderInterval = RENDER_INTERVAL; TL::LedManager::frameInterval = FRAME_INTERVAL; TL::LedManager::regulatorTemperature = 0.0f; @@ -72,8 +70,7 @@ bool TL::LedManager::isInitialized() /** * @brief Clear and create new LED data and animators from the configuration. * @return OK when the animation were reloaded - * @return ERROR_CONFIG_UNAVAILABLE when the configuration was not initialized - * @return ERROR_CREATE_LED_DATA when the LED data could not be created + * @return ERROR_INIT_LED_DRIVER when the LED data could not be created * @return ERROR_UNKNOWN_ANIMATOR_TYPE when one of the animator types is unknown * @return ERROR_INVALID_FSEQ when a custom animation was set but the fseq file is invalid * @return ERROR_FILE_NOT_FOUND when the animation file was not found @@ -81,14 +78,9 @@ bool TL::LedManager::isInitialized() */ TL::LedManager::Error TL::LedManager::reloadAnimations() { - if (!TL::Configuration::isInitialized()) - { - return TL::LedManager::Error::ERROR_CONFIG_UNAVAILABLE; - } - TL::LedManager::clearAnimations(); - const TL::LedManager::Error ledDataError = TL::LedManager::createLedData(); + const TL::LedManager::Error ledDataError = TL::LedManager::initLedDriver(); if (ledDataError != TL::LedManager::Error::OK) { return ledDataError; @@ -108,8 +100,8 @@ TL::LedManager::Error TL::LedManager::reloadAnimations() */ void TL::LedManager::clearAnimations() { - FastLED.clear(); - TL::LedManager::ledData.clear(); + TL::LedDriver::end(); + TL::LedManager::ledBuffer.reset(); TL::LedManager::ledAnimator.clear(); TL::LedManager::fseqLoader.reset(); } @@ -126,25 +118,6 @@ void TL::LedManager::setAmbientBrightness(const float ambientBrightness) } } -/** - * @brief Set the interval for rendering the pixels in µs. - * The minimum frame time is currently limited to 10000µs. - * @param renderInterval target frame time in µs - */ -void TL::LedManager::setRenderInterval(const uint32_t renderInterval) -{ - TL::LedManager::renderInterval = renderInterval >= 10000 ? renderInterval : 10000; -} - -/** - * @brief Get the interval for rendering the pixels. - * @return interval in microseconds - */ -uint32_t TL::LedManager::getRenderInterval() -{ - return TL::LedManager::renderInterval; -} - /** * @brief Set the interval for outputting to the LEDs in µs. * The minimum frame time is currently limited to 10000µs. @@ -215,17 +188,29 @@ float TL::LedManager::getLedPowerDraw() } /** - * @brief Get the total number of LEDs. + * @brief Get the total number of visible LEDs. * @return total number of LEDs */ size_t TL::LedManager::getLedCount() { - size_t count = 0; - for (size_t i = 0; i < TL::LedManager::ledData.size(); i++) + if (TL::LedManager::ledBuffer != nullptr) { - count += TL::LedManager::ledData.at(i).size(); + return TL::LedManager::ledBuffer->getTotalLedCount(); } - return count; + return 0; +} + +/** + * @brief Get the total number of LEDs. + * @return total number of LEDs + */ +size_t TL::LedManager::getHiddenLedCount() +{ + if (TL::LedManager::ledBuffer != nullptr) + { + return TL::LedManager::ledBuffer->getTotalHiddenLedCount(); + } + return 0; } /** @@ -233,65 +218,85 @@ size_t TL::LedManager::getLedCount() */ void TL::LedManager::render() { - for (size_t i = 0; i < TL::LedManager::ledAnimator.size() && i < TL::LedManager::ledData.size(); i++) + if (TL::LedManager::ledBuffer == nullptr || !TL::LedDriver::isInitialized()) + { + return; + } + + for (size_t i = 0; i < TL::LedManager::ledBuffer->getLedStripCount(); i++) { - TL::LedManager::ledAnimator.at(i)->render(TL::LedManager::ledData.at(i)); + TL::LedManager::ledAnimator.at(i)->render(TL::LedManager::ledBuffer->getLedStrip(i)); } + TL::LedManager::limitPowerConsumption(); TL::LedManager::limitRegulatorTemperature(); } /** - * @brief Show the current LED data. + * @brief Wait for the LED driver until all data was sent out to the LEDs. + * @param timeout cpu cycles until a timeout will happen when data is still being send + * @return OK when the driver is done sending data + * @return ERROR_DRIVER_NOT_READY when the driver is not ready sending all the data + */ +TL::LedManager::Error TL::LedManager::waitShow(const TickType_t timeout) +{ + if (!TL::LedDriver::isInitialized()) + { + return TL::LedManager::Error::ERROR_DRIVER_NOT_READY; + } + + const TL::LedDriver::Error driverError = TL::LedDriver::isReady(timeout); + if (driverError != TL::LedDriver::Error::OK) + { + return TL::LedManager::Error::ERROR_DRIVER_NOT_READY; + } + + return TL::LedManager::Error::OK; +} + +/** + * @brief Async send out the current LED data via the LED driver. + * @param timeout cpu cycles until a timeout will happen when data is still being send + * @return OK when the data is being sent + * @return ERROR_DRIVER_NOT_READY when the driver is not ready to send new data */ -void TL::LedManager::show() +TL::LedManager::Error TL::LedManager::show(const TickType_t timeout) { - FastLED.show(); + if (TL::LedManager::ledBuffer == nullptr || !TL::LedDriver::isInitialized()) + { + return TL::LedManager::Error::ERROR_DRIVER_NOT_READY; + } + + const TL::LedDriver::Error driverError = TL::LedDriver::showPixels(timeout); + if (driverError != TL::LedDriver::Error::OK) + { + return TL::LedManager::Error::ERROR_DRIVER_NOT_READY; + } + + return TL::LedManager::Error::OK; } /** - * @brief Create the LED data and assign it to the FastLED library. + * @brief Initialize the LED driver, buffer and output channels. * @return OK when the LED data was created - * @return ERROR_CREATE_LED_DATA when the LED data could not be created because the data could not be linked to a pin + * @return ERROR_INIT_LED_DRIVER when the LED data could not be created */ -TL::LedManager::Error TL::LedManager::createLedData() +TL::LedManager::Error TL::LedManager::initLedDriver() { - TL::LedManager::ledData.assign(LED_NUM_ZONES, std::vector()); + std::vector ledStrips; for (size_t i = 0; i < LED_NUM_ZONES; i++) { const TL::Configuration::LedConfig ledConfig = TL::Configuration::getLedConfig(i); - TL::LedManager::ledData.at(i).assign(ledConfig.ledCount, CRGB::Black); + ledStrips.push_back(TL::LedStrip(ledConfig.ledPin, ledConfig.ledCount, LED_MAX_COUNT_PER_ZONE)); + } - switch (ledConfig.ledPin) - { - case 13: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 14: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 15: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 16: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 17: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 21: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 22: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - case 25: - FastLED.addLeds(&TL::LedManager::ledData.at(i).front(), ledConfig.ledCount); - break; - default: - return TL::LedManager::Error::ERROR_CREATE_LED_DATA; - } + TL::LedManager::ledBuffer.reset(new TL::LedBuffer(ledStrips)); + TL::LedDriver::Error driverError = TL::LedDriver::begin(*TL::LedManager::ledBuffer); + if (driverError != TL::LedDriver::Error::OK) + { + return TL::LedManager::Error::ERROR_INIT_LED_DRIVER; } + return TL::LedManager::Error::OK; } @@ -310,7 +315,7 @@ TL::LedManager::Error TL::LedManager::createAnimators() // Field 14 is reserved to store the previous, calculated animation type const bool customAnimation = TL::Configuration::getLedConfig(0).type == 255; uint32_t identifier = 0; - memcpy(&identifier, &TL::Configuration::getLedConfig(0).animationSettings[20], sizeof(identifier)); + std::memcpy(&identifier, &TL::Configuration::getLedConfig(0).animationSettings[20], sizeof(identifier)); if (!customAnimation) { return TL::LedManager::loadCalculatedAnimations(); @@ -336,26 +341,7 @@ TL::LedManager::Error TL::LedManager::createAnimators() */ TL::LedManager::Error TL::LedManager::loadCalculatedAnimations() { - const size_t ledCount = TL::LedManager::getLedCount(); - if (ledCount <= 850) - { - // 60 FPS - TL::LedManager::setRenderInterval(RENDER_INTERVAL); - TL::LedManager::setFrameInterval(FRAME_INTERVAL); - } - else if (ledCount > 850 && ledCount <= 1000) - { - // 40 FPS - TL::LedManager::setRenderInterval(RENDER_INTERVAL); - TL::LedManager::setFrameInterval(FRAME_INTERVAL * 1.5f); - } - else - { - // 30 FPS - TL::LedManager::setRenderInterval(RENDER_INTERVAL); - TL::LedManager::setFrameInterval(FRAME_INTERVAL * 2.0f); - } - + TL::LedManager::setFrameInterval(FRAME_INTERVAL); TL::LedManager::ledAnimator.resize(LED_NUM_ZONES); for (size_t i = 0; i < TL::LedManager::ledAnimator.size(); i++) { @@ -373,7 +359,7 @@ TL::LedManager::Error TL::LedManager::loadCalculatedAnimations() TL::LedManager::ledAnimator.at(i).reset(new TL::SparkleAnimator( static_cast(ledConfig.animationSettings[0]), ledConfig.animationSettings[7] / 2 + 1, - CRGB(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), + TL::Pixel(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), ledConfig.animationSettings[8] / 5120.0f, ledConfig.animationSettings[9] / 2560.0f, ledConfig.animationSettings[10] / 255.0f, @@ -392,14 +378,14 @@ TL::LedManager::Error TL::LedManager::loadCalculatedAnimations() { TL::LedManager::ledAnimator.at(i).reset(new TL::GradientAnimator( static_cast(ledConfig.animationSettings[0]), - CRGB(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), - CRGB(ledConfig.animationSettings[4], ledConfig.animationSettings[5], ledConfig.animationSettings[6]))); + TL::Pixel(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), + TL::Pixel(ledConfig.animationSettings[4], ledConfig.animationSettings[5], ledConfig.animationSettings[6]))); } // Static color type else if (ledConfig.type == 3) { - TL::LedManager::ledAnimator.at(i).reset(new TL::StaticColorAnimator(CRGB(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]))); + TL::LedManager::ledAnimator.at(i).reset(new TL::StaticColorAnimator(TL::Pixel(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]))); } // Color bar type @@ -407,8 +393,8 @@ TL::LedManager::Error TL::LedManager::loadCalculatedAnimations() { TL::LedManager::ledAnimator.at(i).reset(new TL::ColorBarAnimator( static_cast(ledConfig.animationSettings[0]), - CRGB(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), - CRGB(ledConfig.animationSettings[4], ledConfig.animationSettings[5], ledConfig.animationSettings[6]))); + TL::Pixel(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), + TL::Pixel(ledConfig.animationSettings[4], ledConfig.animationSettings[5], ledConfig.animationSettings[6]))); } // Rainbow motion type @@ -422,8 +408,8 @@ TL::LedManager::Error TL::LedManager::loadCalculatedAnimations() { TL::LedManager::ledAnimator.at(i).reset(new TL::GradientAnimatorMotion( static_cast(ledConfig.animationSettings[0]), - CRGB(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), - CRGB(ledConfig.animationSettings[4], ledConfig.animationSettings[5], ledConfig.animationSettings[6]))); + TL::Pixel(ledConfig.animationSettings[1], ledConfig.animationSettings[2], ledConfig.animationSettings[3]), + TL::Pixel(ledConfig.animationSettings[4], ledConfig.animationSettings[5], ledConfig.animationSettings[6]))); } // Unknown type @@ -438,7 +424,7 @@ TL::LedManager::Error TL::LedManager::loadCalculatedAnimations() TL::LedManager::ledAnimator.at(i)->setAnimationBrightness(ledConfig.brightness / 255.0f); TL::LedManager::ledAnimator.at(i)->setFadeSpeed(ledConfig.fadeSpeed / 4096.0f); TL::LedManager::ledAnimator.at(i)->setReverse(ledConfig.reverse); - TL::LedManager::ledAnimator.at(i)->init(TL::LedManager::ledData.at(i)); + TL::LedManager::ledAnimator.at(i)->init(TL::LedManager::ledBuffer->getLedStrip(i)); } return TL::LedManager::Error::OK; } @@ -470,7 +456,6 @@ TL::LedManager::Error TL::LedManager::loadCustomAnimation(const String &fileName TL::LedManager::fseqLoader->setFillerBytes(fillerBytes); TL::LedManager::fseqLoader->setZoneCount(LED_NUM_ZONES); - TL::LedManager::setRenderInterval(static_cast(TL::LedManager::fseqLoader->getHeader().stepTime) * 1000); TL::LedManager::setFrameInterval(static_cast(TL::LedManager::fseqLoader->getHeader().stepTime) * 1000); TL::LedManager::ledAnimator.resize(LED_NUM_ZONES); @@ -484,7 +469,7 @@ TL::LedManager::Error TL::LedManager::loadCustomAnimation(const String &fileName TL::LedManager::ledAnimator.at(i)->setAnimationBrightness(ledConfig.brightness / 255.0f); TL::LedManager::ledAnimator.at(i)->setFadeSpeed(ledConfig.fadeSpeed / 4096.0f); TL::LedManager::ledAnimator.at(i)->setReverse(ledConfig.reverse); - TL::LedManager::ledAnimator.at(i)->init(TL::LedManager::ledData.at(i)); + TL::LedManager::ledAnimator.at(i)->init(TL::LedManager::ledBuffer->getLedStrip(i)); } return TL::LedManager::Error::OK; } @@ -500,15 +485,17 @@ void TL::LedManager::calculateRegulatorPowerDraw(float regulatorPower[REGULATOR_ regulatorPower[i] = 0.0f; } - for (size_t i = 0; i < TL::LedManager::ledData.size(); i++) + for (size_t i = 0; i < TL::LedManager::ledBuffer->getLedStripCount(); i++) { - TL::Configuration::LedConfig ledConfig = TL::Configuration::getLedConfig(i); + TL::LedStrip ledStrip = TL::LedManager::ledBuffer->getLedStrip(i); + const TL::Configuration::LedConfig ledConfig = TL::Configuration::getLedConfig(i); + float zoneCurrent = 0.0f; - for (size_t j = 0; j < TL::LedManager::ledData.at(i).size(); j++) + for (size_t j = 0; j < ledStrip.getLedCount(); j++) { - zoneCurrent += ledConfig.ledChannelCurrent[0] * TL::LedManager::ledData.at(i).at(j).r / 255.0f; - zoneCurrent += ledConfig.ledChannelCurrent[1] * TL::LedManager::ledData.at(i).at(j).g / 255.0f; - zoneCurrent += ledConfig.ledChannelCurrent[2] * TL::LedManager::ledData.at(i).at(j).b / 255.0f; + zoneCurrent += ledConfig.ledChannelCurrent[0] * ledStrip.getPixel(j).red / 255.0f; + zoneCurrent += ledConfig.ledChannelCurrent[1] * ledStrip.getPixel(j).green / 255.0f; + zoneCurrent += ledConfig.ledChannelCurrent[2] * ledStrip.getPixel(j).blue / 255.0f; } const uint8_t regulatorIndex = TL::LedManager::getRegulatorIndexFromPin(ledConfig.ledPin); @@ -524,10 +511,12 @@ void TL::LedManager::limitPowerConsumption() float regulatorPower[REGULATOR_COUNT]; TL::LedManager::calculateRegulatorPowerDraw(regulatorPower); - TL::Configuration::SystemConfig systemConfig = TL::Configuration::getSystemConfig(); - for (size_t i = 0; i < TL::LedManager::ledData.size(); i++) + const TL::Configuration::SystemConfig systemConfig = TL::Configuration::getSystemConfig(); + for (size_t i = 0; i < TL::LedManager::ledBuffer->getLedStripCount(); i++) { - TL::Configuration::LedConfig ledConfig = TL::Configuration::getLedConfig(i); + TL::LedStrip ledStrip = TL::LedManager::ledBuffer->getLedStrip(i); + const TL::Configuration::LedConfig ledConfig = TL::Configuration::getLedConfig(i); + const uint8_t regulatorIndex = TL::LedManager::getRegulatorIndexFromPin(ledConfig.ledPin); float multiplicator = ((float)systemConfig.regulatorPowerLimit / REGULATOR_COUNT) / regulatorPower[regulatorIndex]; if (multiplicator < 0.0f) @@ -539,11 +528,13 @@ void TL::LedManager::limitPowerConsumption() multiplicator = 1.0f; } - for (size_t j = 0; j < TL::LedManager::ledData.at(i).size(); j++) + for (size_t j = 0; j < ledStrip.getLedCount(); j++) { - TL::LedManager::ledData.at(i).at(j).r *= multiplicator; - TL::LedManager::ledData.at(i).at(j).g *= multiplicator; - TL::LedManager::ledData.at(i).at(j).b *= multiplicator; + TL::Pixel pixel = ledStrip.getPixel(j); + pixel.red *= multiplicator; + pixel.green *= multiplicator; + pixel.blue *= multiplicator; + ledStrip.setPixel(pixel, j); } } } @@ -563,13 +554,16 @@ void TL::LedManager::limitRegulatorTemperature() multiplicator = 1.0f; } - for (size_t i = 0; i < TL::LedManager::ledData.size(); i++) + for (size_t i = 0; i < TL::LedManager::ledBuffer->getLedStripCount(); i++) { - for (size_t j = 0; j < TL::LedManager::ledData.at(i).size(); j++) + TL::LedStrip ledStrip = TL::LedManager::ledBuffer->getLedStrip(i); + for (size_t j = 0; j < ledStrip.getLedCount(); j++) { - TL::LedManager::ledData.at(i).at(j).r *= multiplicator; - TL::LedManager::ledData.at(i).at(j).g *= multiplicator; - TL::LedManager::ledData.at(i).at(j).b *= multiplicator; + TL::Pixel pixel = ledStrip.getPixel(j); + pixel.red *= multiplicator; + pixel.green *= multiplicator; + pixel.blue *= multiplicator; + ledStrip.setPixel(pixel, j); } } } diff --git a/mcu/src/led/animator/ColorBarAnimator.cpp b/mcu/src/led/animator/ColorBarAnimator.cpp index 81e2368..bdecc53 100644 --- a/mcu/src/led/animator/ColorBarAnimator.cpp +++ b/mcu/src/led/animator/ColorBarAnimator.cpp @@ -28,8 +28,8 @@ TL::ColorBarAnimator::ColorBarAnimator() { this->angle = 0.0f; this->colorBarMode = TL::ColorBarAnimator::ColorBarMode::COLOR_BAR_LINEAR_HARD; - this->color[0] = CRGB::Black; - this->color[1] = CRGB::Black; + this->color[0] = TL::Pixel::ColorCode::Black; + this->color[1] = TL::Pixel::ColorCode::Black; } /** @@ -39,7 +39,7 @@ TL::ColorBarAnimator::ColorBarAnimator() * @param color1 first color of the bars * @param color2 second color of the bars */ -TL::ColorBarAnimator::ColorBarAnimator(const TL::ColorBarAnimator::ColorBarMode colorBarMode, const CRGB color1, const CRGB color2) +TL::ColorBarAnimator::ColorBarAnimator(const TL::ColorBarAnimator::ColorBarMode colorBarMode, const TL::Pixel color1, const TL::Pixel color2) { this->colorBarMode = colorBarMode; this->color[0] = color1; @@ -55,22 +55,25 @@ TL::ColorBarAnimator::~ColorBarAnimator() /** * @brief Initialize the {@link TL::ColorBarAnimator}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::ColorBarAnimator::init(std::vector &pixels) +void TL::ColorBarAnimator::init(TL::LedStrip &ledStrip) { this->angle = 0.0f; - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render the color bars to the vector holding the LED pixel data - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::ColorBarAnimator::render(std::vector &pixels) +void TL::ColorBarAnimator::render(TL::LedStrip &ledStrip) { - const float middle = pixels.size() / 2; - for (size_t i = 0; i < pixels.size(); i++) + const float middle = ledStrip.getLedCount() / 2; + for (size_t i = 0; i < ledStrip.getLedCount(); i++) { float colorAngle1 = 0.0f; float colorAngle2 = 0.0f; @@ -84,8 +87,8 @@ void TL::ColorBarAnimator::render(std::vector &pixels) else if (this->colorBarMode == TL::ColorBarAnimator::ColorBarMode::COLOR_BAR_CENTER_HARD || this->colorBarMode == TL::ColorBarAnimator::ColorBarMode::COLOR_BAR_CENTER_SMOOTH) { - colorAngle1 = i < middle ? (this->angle + 0.0f) + i * offset : (this->angle + 0.0f) + (pixels.size() - i) * offset; - colorAngle2 = i < middle ? (this->angle + 180.0f) + i * offset : (this->angle + 180.0f) + (pixels.size() - i) * offset; + colorAngle1 = i < middle ? (this->angle + 0.0f) + i * offset : (this->angle + 0.0f) + (ledStrip.getLedCount() - i) * offset; + colorAngle2 = i < middle ? (this->angle + 180.0f) + i * offset : (this->angle + 180.0f) + (ledStrip.getLedCount() - i) * offset; } float trapezoidValue1 = this->trapezoid2(colorAngle1); @@ -97,10 +100,12 @@ void TL::ColorBarAnimator::render(std::vector &pixels) trapezoidValue2 = trapezoidValue2 < 0.5f ? 0.0f : 1.0f; } - pixels.at(i).setRGB( - trapezoidValue1 * this->color[0].r + trapezoidValue2 * this->color[1].r, - trapezoidValue1 * this->color[0].g + trapezoidValue2 * this->color[1].g, - trapezoidValue1 * this->color[0].b + trapezoidValue2 * this->color[1].b); + ledStrip.setPixel( + TL::Pixel( + trapezoidValue1 * this->color[0].red + trapezoidValue2 * this->color[1].red, + trapezoidValue1 * this->color[0].green + trapezoidValue2 * this->color[1].green, + trapezoidValue1 * this->color[0].blue + trapezoidValue2 * this->color[1].blue), + i); } if (this->reverse) @@ -121,7 +126,7 @@ void TL::ColorBarAnimator::render(std::vector &pixels) this->angle += 360.0f; } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); } /** @@ -138,7 +143,7 @@ void TL::ColorBarAnimator::setColorBarMode(const TL::ColorBarAnimator::ColorBarM * @param color1 first color of the bars * @param color2 second color of the bars */ -void TL::ColorBarAnimator::setColor(const CRGB color1, const CRGB color2) +void TL::ColorBarAnimator::setColor(const TL::Pixel color1, const TL::Pixel color2) { this->color[0] = color1; this->color[1] = color2; diff --git a/mcu/src/led/animator/FseqAnimator.cpp b/mcu/src/led/animator/FseqAnimator.cpp index cd9e526..ad6ee87 100644 --- a/mcu/src/led/animator/FseqAnimator.cpp +++ b/mcu/src/led/animator/FseqAnimator.cpp @@ -41,21 +41,24 @@ TL::FseqAnimator::~FseqAnimator() /** * @brief Initialize the {@link FseqAnimator}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::FseqAnimator::init(std::vector &pixels) +void TL::FseqAnimator::init(TL::LedStrip &ledStrip) { this->fseqLoader->moveToStart(); - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render the values from the fseq file to the vector holding the LED pixel data - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::FseqAnimator::render(std::vector &pixels) +void TL::FseqAnimator::render(TL::LedStrip &ledStrip) { - if (this->fseqLoader->available() < pixels.size()) + if (this->fseqLoader->available() < ledStrip.getLedCount()) { if (this->loop) { @@ -67,18 +70,18 @@ void TL::FseqAnimator::render(std::vector &pixels) } } - const TL::FseqLoader::Error fseqError = this->fseqLoader->readPixelBuffer(pixels); + const TL::FseqLoader::Error fseqError = this->fseqLoader->readLedStrip(ledStrip); if (fseqError != TL::FseqLoader::Error::OK) { - for (size_t i = 0; i < pixels.size(); i++) + for (size_t i = 0; i < ledStrip.getLedCount(); i++) { - pixels.at(i) = CRGB::Black; + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); } } if (this->reverse) { - this->reversePixels(pixels); + this->reversePixels(ledStrip); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); } diff --git a/mcu/src/led/animator/GradientAnimator.cpp b/mcu/src/led/animator/GradientAnimator.cpp index a46c1e7..886182a 100644 --- a/mcu/src/led/animator/GradientAnimator.cpp +++ b/mcu/src/led/animator/GradientAnimator.cpp @@ -27,7 +27,7 @@ * @param color1 first color value * @param color2 second color value */ -TL::GradientAnimator::GradientAnimator(const TL::GradientAnimator::GradientMode gradientMode, const CRGB color1, const CRGB color2) +TL::GradientAnimator::GradientAnimator(const TL::GradientAnimator::GradientMode gradientMode, const TL::Pixel color1, const TL::Pixel color2) { this->gradientMode = gradientMode; this->color[0] = color1; @@ -43,52 +43,59 @@ TL::GradientAnimator::~GradientAnimator() /** * @brief Initialize the {@link TL::GradientAnimator}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::GradientAnimator::init(std::vector &pixels) +void TL::GradientAnimator::init(TL::LedStrip &ledStrip) { - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render the gradient to the vector holding the LED pixel data - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::GradientAnimator::render(std::vector &pixels) +void TL::GradientAnimator::render(TL::LedStrip &ledStrip) { - if (pixels.size() == 2) + if (ledStrip.getLedCount() == 2) { const float middle = (this->offset / 255.0f - 0.5f) * 2.0f; if (middle < 0.0f) { - pixels.at(0).setRGB(this->color[1].r, this->color[1].g, this->color[1].b); - pixels.at(1).setRGB( - (-middle * this->color[1].r + (1 + middle) * this->color[0].r), - (-middle * this->color[1].g + (1 + middle) * this->color[0].g), - (-middle * this->color[1].b + (1 + middle) * this->color[0].b)); + ledStrip.setPixel(TL::Pixel(this->color[1].red, this->color[1].green, this->color[1].blue), 0); + ledStrip.setPixel( + TL::Pixel( + (-middle * this->color[1].red + (1 + middle) * this->color[0].red), + (-middle * this->color[1].green + (1 + middle) * this->color[0].green), + (-middle * this->color[1].blue + (1 + middle) * this->color[0].blue)), + 1); } else { - pixels.at(0).setRGB( - (middle * this->color[0].r + (1 - middle) * this->color[1].r), - (middle * this->color[0].g + (1 - middle) * this->color[1].g), - (middle * this->color[0].b + (1 - middle) * this->color[1].b)); - pixels.at(1).setRGB(this->color[0].r, this->color[0].g, this->color[0].b); + ledStrip.setPixel( + TL::Pixel( + (middle * this->color[0].red + (1 - middle) * this->color[1].red), + (middle * this->color[0].green + (1 - middle) * this->color[1].green), + (middle * this->color[0].blue + (1 - middle) * this->color[1].blue)), + 0); + ledStrip.setPixel(TL::Pixel(this->color[0].red, this->color[0].green, this->color[0].blue), 1); } } else { - float middle = (pixels.size() - 1) * this->offset / 255.0f; + float middle = (ledStrip.getLedCount() - 1) * this->offset / 255.0f; if (middle < 0.01f) { middle = 0.01f; } - else if (middle > pixels.size() - 1.01f) + else if (middle > ledStrip.getLedCount() - 1.01f) { - middle = pixels.size() - 1.01f; + middle = ledStrip.getLedCount() - 1.01f; } - for (size_t i = 0; i < pixels.size(); i++) + for (size_t i = 0; i < ledStrip.getLedCount(); i++) { float position = 0.0f; if (this->gradientMode == TL::GradientAnimator::GradientMode::GRADIENT_LINEAR) @@ -99,7 +106,7 @@ void TL::GradientAnimator::render(std::vector &pixels) } else { - position = 0.5f + ((float)i - middle) / ((pixels.size() - 1) - middle) * 0.5f; + position = 0.5f + ((float)i - middle) / ((ledStrip.getLedCount() - 1) - middle) * 0.5f; } } else if (this->gradientMode == TL::GradientAnimator::GradientMode::GRADIENT_CENTER) @@ -110,19 +117,21 @@ void TL::GradientAnimator::render(std::vector &pixels) } else { - position = 1.0f - ((float)i - middle) / ((pixels.size() - 1) - middle); + position = 1.0f - ((float)i - middle) / ((ledStrip.getLedCount() - 1) - middle); } } - pixels.at(i).setRGB( - (position * this->color[1].r + (1 - position) * this->color[0].r), - (position * this->color[1].g + (1 - position) * this->color[0].g), - (position * this->color[1].b + (1 - position) * this->color[0].b)); + ledStrip.setPixel( + TL::Pixel( + (position * this->color[1].red + (1 - position) * this->color[0].red), + (position * this->color[1].green + (1 - position) * this->color[0].green), + (position * this->color[1].blue + (1 - position) * this->color[0].blue)), + i); } } if (this->reverse) { - this->reversePixels(pixels); + this->reversePixels(ledStrip); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); } diff --git a/mcu/src/led/animator/GradientAnimatorMotion.cpp b/mcu/src/led/animator/GradientAnimatorMotion.cpp index 6e96d73..ad7d55f 100644 --- a/mcu/src/led/animator/GradientAnimatorMotion.cpp +++ b/mcu/src/led/animator/GradientAnimatorMotion.cpp @@ -27,7 +27,7 @@ * @param color1 first color value * @param color2 second color value */ -TL::GradientAnimatorMotion::GradientAnimatorMotion(const TL::GradientAnimatorMotion::GradientMode gradientMode, const CRGB color1, const CRGB color2) +TL::GradientAnimatorMotion::GradientAnimatorMotion(const TL::GradientAnimatorMotion::GradientMode gradientMode, const TL::Pixel color1, const TL::Pixel color2) { this->gradientMode = gradientMode; this->color[0] = color1; @@ -43,52 +43,59 @@ TL::GradientAnimatorMotion::~GradientAnimatorMotion() /** * @brief Initialize the {@link TL::GradientAnimatorMotion}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::GradientAnimatorMotion::init(std::vector &pixels) +void TL::GradientAnimatorMotion::init(TL::LedStrip &ledStrip) { - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render the gradient to the vector holding the LED pixel data - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::GradientAnimatorMotion::render(std::vector &pixels) +void TL::GradientAnimatorMotion::render(TL::LedStrip &ledStrip) { - if (pixels.size() == 2) + if (ledStrip.getLedCount() == 2) { const float motionOffset = (this->getMotionOffset() - 0.5f) * 2.0f; if (motionOffset < 0.0f) { - pixels.at(0).setRGB(this->color[0].r, this->color[0].g, this->color[0].b); - pixels.at(1).setRGB( - (-motionOffset * this->color[0].r + (1 + motionOffset) * this->color[1].r), - (-motionOffset * this->color[0].g + (1 + motionOffset) * this->color[1].g), - (-motionOffset * this->color[0].b + (1 + motionOffset) * this->color[1].b)); + ledStrip.setPixel(TL::Pixel(this->color[0].red, this->color[0].green, this->color[0].blue), 0); + ledStrip.setPixel( + TL::Pixel( + (-motionOffset * this->color[0].red + (1 + motionOffset) * this->color[1].red), + (-motionOffset * this->color[0].green + (1 + motionOffset) * this->color[1].green), + (-motionOffset * this->color[0].blue + (1 + motionOffset) * this->color[1].blue)), + 1); } else { - pixels.at(0).setRGB( - (motionOffset * this->color[1].r + (1 - motionOffset) * this->color[0].r), - (motionOffset * this->color[1].g + (1 - motionOffset) * this->color[0].g), - (motionOffset * this->color[1].b + (1 - motionOffset) * this->color[0].b)); - pixels.at(1).setRGB(this->color[1].r, this->color[1].g, this->color[1].b); + ledStrip.setPixel( + TL::Pixel( + (motionOffset * this->color[1].red + (1 - motionOffset) * this->color[0].red), + (motionOffset * this->color[1].green + (1 - motionOffset) * this->color[0].green), + (motionOffset * this->color[1].blue + (1 - motionOffset) * this->color[0].blue)), + 0); + ledStrip.setPixel(TL::Pixel(this->color[1].red, this->color[1].green, this->color[1].blue), 1); } } else { - float motionOffset = (pixels.size() - 1) * this->getMotionOffset(); + float motionOffset = (ledStrip.getLedCount() - 1) * this->getMotionOffset(); if (motionOffset < 0.01f) { motionOffset = 0.01f; } - else if (motionOffset > pixels.size() - 1.01f) + else if (motionOffset > ledStrip.getLedCount() - 1.01f) { - motionOffset = pixels.size() - 1.01f; + motionOffset = ledStrip.getLedCount() - 1.01f; } - for (uint16_t i = 0; i < pixels.size(); i++) + for (uint16_t i = 0; i < ledStrip.getLedCount(); i++) { float position = 0.0f; if (this->gradientMode == TL::GradientAnimatorMotion::GradientMode::GRADIENT_LINEAR) @@ -99,7 +106,7 @@ void TL::GradientAnimatorMotion::render(std::vector &pixels) } else { - position = 0.5f + ((float)i - motionOffset) / ((pixels.size() - 1) - motionOffset) * 0.5f; + position = 0.5f + ((float)i - motionOffset) / ((ledStrip.getLedCount() - 1) - motionOffset) * 0.5f; } } else if (this->gradientMode == TL::GradientAnimatorMotion::GradientMode::GRADIENT_CENTER) @@ -110,21 +117,23 @@ void TL::GradientAnimatorMotion::render(std::vector &pixels) } else { - position = 1.0f - ((float)i - motionOffset) / ((pixels.size() - 1) - motionOffset); + position = 1.0f - ((float)i - motionOffset) / ((ledStrip.getLedCount() - 1) - motionOffset); } } - pixels.at(i).setRGB( - (position * this->color[0].r + (1 - position) * this->color[1].r), - (position * this->color[0].g + (1 - position) * this->color[1].g), - (position * this->color[0].b + (1 - position) * this->color[1].b)); + ledStrip.setPixel( + TL::Pixel( + (position * this->color[0].red + (1 - position) * this->color[1].red), + (position * this->color[0].green + (1 - position) * this->color[1].green), + (position * this->color[0].blue + (1 - position) * this->color[1].blue)), + i); } } if (this->reverse) { - this->reversePixels(pixels); + this->reversePixels(ledStrip); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); } /** diff --git a/mcu/src/led/animator/LedAnimator.cpp b/mcu/src/led/animator/LedAnimator.cpp index 4377812..7903c09 100644 --- a/mcu/src/led/animator/LedAnimator.cpp +++ b/mcu/src/led/animator/LedAnimator.cpp @@ -245,18 +245,24 @@ TL::AudioUnit::AudioAnalysis &TL::LedAnimator::getAudioAnalysis() /** * @brief Reverse the order of all pixels to reverse the animation. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::LedAnimator::reversePixels(std::vector &pixels) +void TL::LedAnimator::reversePixels(TL::LedStrip &ledStrip) { - std::reverse(pixels.begin(), pixels.end()); + for (size_t i = 0; i < ledStrip.getLedCount() / 2; i++) + { + const TL::Pixel copy = ledStrip.getPixel(i); + const size_t inverseIndex = (ledStrip.getLedCount() - 1) - i; + ledStrip.setPixel(ledStrip.getPixel(inverseIndex), i); + ledStrip.setPixel(copy, inverseIndex); + } } /** * @brief Apply the brightness settings to all pixels. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::LedAnimator::applyBrightness(std::vector &pixels) +void TL::LedAnimator::applyBrightness(TL::LedStrip &ledStrip) { if (this->smoothedAmbBrightness < this->ambientBrightness) { @@ -276,9 +282,13 @@ void TL::LedAnimator::applyBrightness(std::vector &pixels) } const float totalBrightness = this->animationBrightness * this->smoothedAmbBrightness; - for (size_t i = 0; i < pixels.size(); i++) + for (size_t i = 0; i < ledStrip.getLedCount(); i++) { - pixels.at(i).setRGB(pixels.at(i).r * totalBrightness, pixels.at(i).g * totalBrightness, pixels.at(i).b * totalBrightness); + TL::Pixel pixel = ledStrip.getPixel(i); + pixel.red *= totalBrightness; + pixel.green *= totalBrightness; + pixel.blue *= totalBrightness; + ledStrip.setPixel(pixel, i); } } diff --git a/mcu/src/led/animator/RainbowAnimator.cpp b/mcu/src/led/animator/RainbowAnimator.cpp index bb8811f..18dbc8c 100644 --- a/mcu/src/led/animator/RainbowAnimator.cpp +++ b/mcu/src/led/animator/RainbowAnimator.cpp @@ -4,7 +4,7 @@ * @brief Implementation of the {@TL::RainbowAnimator}. * * @copyright Copyright (c) 2022-2023 TheRealKasumi - * + * * This project, including hardware and software, is provided "as is". There is no warranty * of any kind, express or implied, including but not limited to the warranties of fitness * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) @@ -43,20 +43,23 @@ TL::RainbowAnimator::~RainbowAnimator() * @brief Initialize the {@link TL::RainbowAnimator}. * @param pixels reference to the vector holding the LED pixel data */ -void TL::RainbowAnimator::init(std::vector &pixels) +void TL::RainbowAnimator::init(TL::LedStrip &ledStrip) { this->angle = 0.0f; - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render a rainbow to the vector holding the LED pixel data * @param pixels reference to the vector holding the LED pixel data */ -void TL::RainbowAnimator::render(std::vector &pixels) +void TL::RainbowAnimator::render(TL::LedStrip &ledStrip) { - const float middle = pixels.size() / 2; - for (size_t i = 0; i < pixels.size(); i++) + const float middle = ledStrip.getLedCount() / 2; + for (size_t i = 0; i < ledStrip.getLedCount(); i++) { float redAngle = 0.0f; float greenAngle = 0.0f; @@ -79,15 +82,15 @@ void TL::RainbowAnimator::render(std::vector &pixels) else if (this->rainbowMode == TL::RainbowAnimator::RainbowMode::RAINBOW_CENTER) { - redAngle = i < middle ? (this->angle + 0.0f) + i * offset : (this->angle + 0.0f) + (pixels.size() - i) * offset; - greenAngle = i < middle ? (this->angle + 120.0f) + i * offset : (this->angle + 120.0f) + (pixels.size() - i) * offset; - blueAngle = i < middle ? (this->angle + 240.0f) + i * offset : (this->angle + 240.0f) + (pixels.size() - i) * offset; + redAngle = i < middle ? (this->angle + 0.0f) + i * offset : (this->angle + 0.0f) + (ledStrip.getLedCount() - i) * offset; + greenAngle = i < middle ? (this->angle + 120.0f) + i * offset : (this->angle + 120.0f) + (ledStrip.getLedCount() - i) * offset; + blueAngle = i < middle ? (this->angle + 240.0f) + i * offset : (this->angle + 240.0f) + (ledStrip.getLedCount() - i) * offset; } - pixels.at(i).setRGB(this->trapezoid(redAngle) * 255.0f, this->trapezoid(greenAngle) * 255.0f, this->trapezoid(blueAngle) * 255.0f); + ledStrip.setPixel(TL::Pixel(this->trapezoid(redAngle) * 255.0f, this->trapezoid(greenAngle) * 255.0f, this->trapezoid(blueAngle) * 255.0f), i); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); if (this->reverse) { diff --git a/mcu/src/led/animator/RainbowAnimatorMotion.cpp b/mcu/src/led/animator/RainbowAnimatorMotion.cpp index ed2d4e5..7d9a4c5 100644 --- a/mcu/src/led/animator/RainbowAnimatorMotion.cpp +++ b/mcu/src/led/animator/RainbowAnimatorMotion.cpp @@ -40,22 +40,25 @@ TL::RainbowAnimatorMotion::~RainbowAnimatorMotion() /** * @brief Initialize the {@link TL::RainbowAnimatorMotion}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::RainbowAnimatorMotion::init(std::vector &pixels) +void TL::RainbowAnimatorMotion::init(TL::LedStrip &ledStrip) { this->angle = 0.0f; - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render a rainbow to the vector holding the LED pixel data - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::RainbowAnimatorMotion::render(std::vector &pixels) +void TL::RainbowAnimatorMotion::render(TL::LedStrip &ledStrip) { - const float middle = pixels.size() / 2; - for (uint16_t i = 0; i < pixels.size(); i++) + const float middle = ledStrip.getLedCount() / 2; + for (uint16_t i = 0; i < ledStrip.getLedCount(); i++) { float redAngle = 0.0f; float greenAngle = 0.0f; @@ -78,15 +81,15 @@ void TL::RainbowAnimatorMotion::render(std::vector &pixels) else if (this->rainbowMode == TL::RainbowAnimatorMotion::RainbowMode::RAINBOW_CENTER) { - redAngle = i < middle ? (this->angle + 0.0f) + i * offset : (this->angle + 0.0f) + (pixels.size() - i) * offset; - greenAngle = i < middle ? (this->angle + 120.0f) + i * offset : (this->angle + 120.0f) + (pixels.size() - i) * offset; - blueAngle = i < middle ? (this->angle + 240.0f) + i * offset : (this->angle + 240.0f) + (pixels.size() - i) * offset; + redAngle = i < middle ? (this->angle + 0.0f) + i * offset : (this->angle + 0.0f) + (ledStrip.getLedCount() - i) * offset; + greenAngle = i < middle ? (this->angle + 120.0f) + i * offset : (this->angle + 120.0f) + (ledStrip.getLedCount() - i) * offset; + blueAngle = i < middle ? (this->angle + 240.0f) + i * offset : (this->angle + 240.0f) + (ledStrip.getLedCount() - i) * offset; } - pixels.at(i).setRGB(this->trapezoid(redAngle) * 255.0f, this->trapezoid(greenAngle) * 255.0f, this->trapezoid(blueAngle) * 255.0f); + ledStrip.setPixel(TL::Pixel(this->trapezoid(redAngle) * 255.0f, this->trapezoid(greenAngle) * 255.0f, this->trapezoid(blueAngle) * 255.0f), i); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); const float speed = this->getMotionSpeed(); if (this->reverse) diff --git a/mcu/src/led/animator/SparkleAnimator.cpp b/mcu/src/led/animator/SparkleAnimator.cpp index bc5fc65..93a1d0c 100644 --- a/mcu/src/led/animator/SparkleAnimator.cpp +++ b/mcu/src/led/animator/SparkleAnimator.cpp @@ -38,7 +38,7 @@ * @param bounceAtCorner when set to true, the particles will bounce at the end of the LED strip * @param frequencyBandMask bit mask to mask frequency bands in audio mode */ -TL::SparkleAnimator::SparkleAnimator(const TL::SparkleAnimator::SpawnPosition spawnPosition, const uint8_t sparkCount, const CRGB color, +TL::SparkleAnimator::SparkleAnimator(const TL::SparkleAnimator::SpawnPosition spawnPosition, const uint8_t sparkCount, const TL::Pixel color, const float sparkFriction, const float sparkFading, const float sparkTail, const float birthRate, const float spawnVariance, const float speedVariance, const float brightnessVariance, const float frictionVariance, const float fadingVariance, const bool bounceAtCorner, const uint8_t frequencyBandMask) @@ -81,13 +81,16 @@ TL::SparkleAnimator::~SparkleAnimator() /** * @brief Initialize the {@link TL::SparkleAnimator}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::SparkleAnimator::init(std::vector &pixels) +void TL::SparkleAnimator::init(TL::LedStrip &ledStrip) { - this->pixelBuffer.assign(pixels.size(), CRGB::Black); - this->pixelMask.assign(pixels.size(), false); - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + this->pixelBuffer.assign(ledStrip.getLedCount(), TL::Pixel::ColorCode::Black); + this->pixelMask.assign(ledStrip.getLedCount(), false); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } this->colorAngle = 0.0f; this->audioSequence = 0; for (size_t i = 0; i < this->sparks.size(); i++) @@ -98,7 +101,7 @@ void TL::SparkleAnimator::init(std::vector &pixels) spark.lastPosition = 0.0f; spark.speed = 0.0f; spark.friction = 0.0f; - spark.color = CRGB::Black; + spark.color = TL::Pixel::ColorCode::Black; spark.brightness = 0.0f; spark.fading = 0.0f; this->sparks.at(i) = spark; @@ -107,9 +110,9 @@ void TL::SparkleAnimator::init(std::vector &pixels) /** * @brief Render the sparkle animator. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::SparkleAnimator::render(std::vector &pixels) +void TL::SparkleAnimator::render(TL::LedStrip &ledStrip) { // Check if new sparks should be spawned depending on the data source if (this->getDataSource() == TL::LedAnimator::DataSource::DS_AUDIO_FREQUENCY_TRIGGER) @@ -125,18 +128,18 @@ void TL::SparkleAnimator::render(std::vector &pixels) // Spawn new sparks depending on the band mask and the tigger status if (this->frequencyBandMask & (0B10000000 >> i) && audioAnalysis.frequencyBandTriggers.at(i).trigger == TL::AudioUnit::Trigger::TRIGGER_RISING) { - this->spawnSparks(pixels); + this->spawnSparks(ledStrip); } } } } else { - this->spawnSparks(pixels); + this->spawnSparks(ledStrip); } // Run the sparks - this->runSparks(pixels); + this->runSparks(ledStrip); // Clear the mask to store for which pixels a spark was rendere std::fill(this->pixelMask.begin(), this->pixelMask.end(), false); @@ -159,25 +162,25 @@ void TL::SparkleAnimator::render(std::vector &pixels) { break; } - else if (!isPositive && spark.position + j > pixels.size()) + else if (!isPositive && spark.position + j > ledStrip.getLedCount()) { break; } - const CRGB pixel = this->pixelBuffer.at(isPositive ? spark.position - j : spark.position + j); - int16_t red = pixel.r; - int16_t green = pixel.g; - int16_t blue = pixel.b; + const TL::Pixel pixel = this->pixelBuffer.at(isPositive ? spark.position - j : spark.position + j); + int16_t red = pixel.red; + int16_t green = pixel.green; + int16_t blue = pixel.blue; - red += spark.color.r * spark.brightness * exposure; - green += spark.color.g * spark.brightness * exposure; - blue += spark.color.b * spark.brightness * exposure; + red += spark.color.red * spark.brightness * exposure; + green += spark.color.green * spark.brightness * exposure; + blue += spark.color.blue * spark.brightness * exposure; red = red <= 255 ? red : 255; green = green <= 255 ? green : 255; blue = blue <= 255 ? blue : 255; - this->pixelBuffer.at(isPositive ? spark.position - j : spark.position + j).setRGB(red, green, blue); + this->pixelBuffer.at(isPositive ? spark.position - j : spark.position + j).setColor(red, green, blue); } this->pixelMask.at(spark.position) = true; } @@ -189,10 +192,10 @@ void TL::SparkleAnimator::render(std::vector &pixels) { if (!this->pixelMask.at(i)) { - const CRGB pixel = this->pixelBuffer.at(i); - int16_t red = pixel.r; - int16_t green = pixel.g; - int16_t blue = pixel.b; + const TL::Pixel pixel = this->pixelBuffer.at(i); + int16_t red = pixel.red; + int16_t green = pixel.green; + int16_t blue = pixel.blue; red -= red * (1.0f - this->sparkTail); green -= green * (1.0f - this->sparkTail); @@ -202,22 +205,28 @@ void TL::SparkleAnimator::render(std::vector &pixels) green = green >= 0 ? green : 0; blue = blue >= 0 ? blue : 0; - this->pixelBuffer.at(i).setRGB(red, green, blue); + this->pixelBuffer.at(i).setColor(red, green, blue); } } - pixels = this->pixelBuffer; + // Copy the internal pixel buffer into the LED strip + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(this->pixelBuffer.at(i), i); + } + if (this->reverse) { - this->reversePixels(pixels); + this->reversePixels(ledStrip); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); } /** * @brief Spawn new sparks from the set of currently invisible ones. + * @param ledStrip reference to the LED strip */ -void TL::SparkleAnimator::spawnSparks(std::vector &pixels) +void TL::SparkleAnimator::spawnSparks(TL::LedStrip &ledStrip) { size_t spawnCounter = 0; for (size_t i = 0; i < this->sparks.size(); i++) @@ -245,21 +254,21 @@ void TL::SparkleAnimator::spawnSparks(std::vector &pixels) switch (this->spawnPosition) { case TL::SparkleAnimator::SpawnPosition::SPAWN_SIDE: - spark.position = (this->offset / 255.0f) * (pixels.size() - 1.0f); - spark.position += this->random(0, pixels.size() - 1.0f) * this->spawnVariance; + spark.position = (this->offset / 255.0f) * (ledStrip.getLedCount() - 1.0f); + spark.position += this->random(0, ledStrip.getLedCount() - 1.0f) * this->spawnVariance; spark.position = spark.position >= 0 ? spark.position : 0; - spark.position = spark.position < pixels.size() ? spark.position : pixels.size() - 1; + spark.position = spark.position < ledStrip.getLedCount() ? spark.position : ledStrip.getLedCount() - 1; spark.lastPosition = spark.position; break; case TL::SparkleAnimator::SpawnPosition::SPAWN_CENTER: - spark.position = pixels.size() / 2.0f; + spark.position = ledStrip.getLedCount() / 2.0f; spark.position += this->random(-spark.position, spark.position) * this->spawnVariance; spark.position = spark.position >= 0 ? spark.position : 0; - spark.position = spark.position < pixels.size() ? spark.position : pixels.size() - 1; + spark.position = spark.position < ledStrip.getLedCount() ? spark.position : ledStrip.getLedCount() - 1; spark.lastPosition = spark.position; break; case TL::SparkleAnimator::SpawnPosition::SPAWN_RANDOM: - spark.position = this->random(0, pixels.size() - 1); + spark.position = this->random(0, ledStrip.getLedCount() - 1); spark.lastPosition = spark.position; break; } @@ -277,11 +286,11 @@ void TL::SparkleAnimator::spawnSparks(std::vector &pixels) spark.friction = spark.friction < 0.0f ? -spark.friction : spark.friction; spark.friction = spark.friction > 1.0f ? 1.0f : spark.friction; - if (this->color.r == 0 && this->color.g == 0 && this->color.b == 0) + if (this->color.red == 0 && this->color.green == 0 && this->color.blue == 0) { - spark.color.setRGB(this->trapezoid(this->colorAngle) * 255.0f, - this->trapezoid(this->colorAngle + 120.0f) * 255.0f, - this->trapezoid(this->colorAngle + 240.0f) * 255.0f); + spark.color.setColor(this->trapezoid(this->colorAngle) * 255.0f, + this->trapezoid(this->colorAngle + 120.0f) * 255.0f, + this->trapezoid(this->colorAngle + 240.0f) * 255.0f); this->colorAngle += 7.5f; if (this->colorAngle > 360.0f) { @@ -308,8 +317,9 @@ void TL::SparkleAnimator::spawnSparks(std::vector &pixels) /** * @brief Run the sparks :) . I know, thats a great explanation. + * @param ledStrip reference to the LED strip */ -void TL::SparkleAnimator::runSparks(std::vector &pixels) +void TL::SparkleAnimator::runSparks(TL::LedStrip &ledStrip) { for (size_t i = 0; i < this->sparks.size(); i++) { @@ -321,11 +331,11 @@ void TL::SparkleAnimator::runSparks(std::vector &pixels) spark.speed -= spark.speed * spark.friction; spark.brightness -= spark.brightness * spark.fading; - if (spark.position < 0.0f || spark.position >= pixels.size()) + if (spark.position < 0.0f || spark.position >= ledStrip.getLedCount()) { if (this->bounceAtCorner) { - spark.position = spark.position < 0.0f ? 0.0f : pixels.size() - 1; + spark.position = spark.position < 0.0f ? 0.0f : ledStrip.getLedCount() - 1; spark.lastPosition = spark.position; spark.speed = -spark.speed; } diff --git a/mcu/src/led/animator/StaticColorAnimator.cpp b/mcu/src/led/animator/StaticColorAnimator.cpp index 1b6da0e..307563e 100644 --- a/mcu/src/led/animator/StaticColorAnimator.cpp +++ b/mcu/src/led/animator/StaticColorAnimator.cpp @@ -4,7 +4,7 @@ * @brief Implementation of the {@link StaticColorAnimator}. * * @copyright Copyright (c) 2022-2023 TheRealKasumi - * + * * This project, including hardware and software, is provided "as is". There is no warranty * of any kind, express or implied, including but not limited to the warranties of fitness * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) @@ -25,7 +25,7 @@ * @brief Create a new instance of {@link TL::StaticColorAnimator}. * @param color color to display */ -TL::StaticColorAnimator::StaticColorAnimator(const CRGB color) +TL::StaticColorAnimator::StaticColorAnimator(const TL::Pixel color) { this->color = color; } @@ -39,23 +39,26 @@ TL::StaticColorAnimator::~StaticColorAnimator() /** * @brief Initialize the {@link StaticColorAnimator}. - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::StaticColorAnimator::init(std::vector &pixels) +void TL::StaticColorAnimator::init(TL::LedStrip &ledStrip) { - std::fill(pixels.begin(), pixels.end(), CRGB::Black); + for (size_t i = 0; i < ledStrip.getLedCount(); i++) + { + ledStrip.setPixel(TL::Pixel::ColorCode::Black, i); + } } /** * @brief Render the static color to the vector holding the LED pixel data - * @param pixels reference to the vector holding the LED pixel data + * @param ledStrip LED strip with the pixel data */ -void TL::StaticColorAnimator::render(std::vector &pixels) +void TL::StaticColorAnimator::render(TL::LedStrip &ledStrip) { - for (size_t i = 0; i < pixels.size(); i++) + for (size_t i = 0; i < ledStrip.getLedCount(); i++) { - pixels.at(i) = this->color; + ledStrip.setPixel(this->color, i); } - this->applyBrightness(pixels); + this->applyBrightness(ledStrip); } diff --git a/mcu/src/led/driver/LedBuffer.cpp b/mcu/src/led/driver/LedBuffer.cpp new file mode 100644 index 0000000..388a336 --- /dev/null +++ b/mcu/src/led/driver/LedBuffer.cpp @@ -0,0 +1,145 @@ +/** + * @file LedBuffer.cpp + * @author TheRealKasumi + * @brief Implementation of the {@link TL::LedBuffer}. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#include "led/driver/LedBuffer.h" + +/** + * @brief Create a new instance of {@link TL::LedBuffer}. + * @param ledStrips vector holding the LED strips + */ +TL::LedBuffer::LedBuffer(const std::vector &ledStrips) +{ + this->ledStrips = ledStrips; + this->totalLedCount = 0; + this->maxLedCount = 0; + this->totalHiddenLedCount = 0; + this->maxHiddenLedCount = 0; + + for (size_t i = 0; i < this->ledStrips.size(); i++) + { + const size_t ledCount = this->ledStrips.at(i).getLedCount(); + this->totalLedCount += ledCount; + this->maxLedCount = ledCount > this->maxLedCount ? ledCount : this->maxLedCount; + + const size_t hiddenLedCount = this->ledStrips.at(i).getHiddenLedCount(); + this->totalHiddenLedCount += hiddenLedCount; + this->maxHiddenLedCount = hiddenLedCount > this->maxHiddenLedCount ? hiddenLedCount : this->maxHiddenLedCount; + } + + const size_t bufferSize = this->totalHiddenLedCount * 3; + this->buffer = new uint8_t[bufferSize]; + for (size_t i = 0; i < bufferSize; i++) + { + this->buffer[i] = 0; + } + + uint8_t *ptr = this->buffer; + for (size_t i = 0; i < this->ledStrips.size(); i++) + { + this->ledStrips.at(i).setBuffer(ptr); + ptr += this->ledStrips.at(i).getHiddenLedCount() * 3; + } +} + +/** + * @brief Destroy the {@link TL::LedBuffer} instance and free memory. + */ +TL::LedBuffer::~LedBuffer() +{ + if (this->buffer != nullptr) + { + delete[] this->buffer; + this->buffer = nullptr; + } +} + +/** + * @brief Get the size of the LED buffer in bytes. + * @return size of the LED buffer in bytes. + */ +size_t TL::LedBuffer::getBufferSize() +{ + return this->totalLedCount * 3; +} + +/** + * @brief Get the base pointer to the LED buffer. + * @return pointer to the LED buffer + */ +uint8_t *TL::LedBuffer::getBuffer() +{ + return this->buffer; +} + +/** + * @brief Get the total number of visible LEDs. + * @return total number of LEDs + */ +size_t TL::LedBuffer::getTotalLedCount() +{ + return this->totalLedCount; +} + +/** + * @brief Get the highst number of visible LEDs from all strips. + * @return highest number of LED per strip + */ +size_t TL::LedBuffer::getMaxLedCount() +{ + return this->maxLedCount; +} + +/** + * @brief Get the total number of all LEDs. + * @return total number of LEDs + */ +size_t TL::LedBuffer::getTotalHiddenLedCount() +{ + return this->totalHiddenLedCount; +} + +/** + * @brief Get the highst number of LEDs from all strips. + * @return highest number of LED per strip + */ +size_t TL::LedBuffer::getMaxHiddenLedCount() +{ + return this->maxHiddenLedCount; +} + +/** + * @brief Get the number of LED strips. + * @return number of LED strips + */ +size_t TL::LedBuffer::getLedStripCount() +{ + return this->ledStrips.size(); +} + +/** + * @brief Get a single LED strip. + * @param index index of the LED strip + * @return reference to the LED strip + */ +TL::LedStrip &TL::LedBuffer::getLedStrip(const size_t index) +{ + return this->ledStrips.at(index); +} diff --git a/mcu/src/led/driver/LedDriver.cpp b/mcu/src/led/driver/LedDriver.cpp new file mode 100644 index 0000000..eeecf92 --- /dev/null +++ b/mcu/src/led/driver/LedDriver.cpp @@ -0,0 +1,464 @@ +#include "led/driver/LedDriver.h" + +bool TL::LedDriver::initialized = false; +uint8_t *TL::LedDriver::ledBuffer; +volatile uint16_t TL::LedDriver::ledIndex; +volatile uint16_t TL::LedDriver::ledStripCount; +uint16_t TL::LedDriver::ledStripLength[8]; +volatile uint16_t TL::LedDriver::ledStripMaxLength; +i2s_dev_t *TL::LedDriver::i2sDevice; +TL::LedDriver::I2SDevice TL::LedDriver::i2sDeviceIdentifier; +TL::LedDriver::DMABuffer *TL::LedDriver::dmaBuffer[4]; +volatile uint8_t TL::LedDriver::dmaBufferIndex; +intr_handle_t TL::LedDriver::interruptHandle; +volatile xSemaphoreHandle TL::LedDriver::semaphore; + +/** + * @brief Initialize and start the LED driver. + * @param ledBuffer reference to the LED buffer + * @param i2sDevice I2S device to use + * @return OK when the LED driver was initialized + * @return ERROR_NO_LED_STRIPS when no LED data was provided + * @return ERROR_SET_PIN when the pin could not be configured + * @return ERROR_ALLOCATE_INTERRUPT when the interrupt could not be allocated + */ +TL::LedDriver::Error TL::LedDriver::begin(TL::LedBuffer &ledBuffer, const TL::LedDriver::I2SDevice i2sDeviceIdentifier) +{ + if (ledBuffer.getLedStripCount() == 0 || ledBuffer.getMaxHiddenLedCount() < 8) + { + return TL::LedDriver::Error::ERROR_NO_LED_STRIPS; + } + + TL::LedDriver::initialized = false; + TL::LedDriver::ledBuffer = nullptr; + TL::LedDriver::ledIndex = 0; + TL::LedDriver::ledStripCount = 0; + std::memset(reinterpret_cast(TL::LedDriver::ledStripLength), 0, sizeof(ledStripLength)); + TL::LedDriver::ledStripMaxLength = 0; + TL::LedDriver::i2sDevice = nullptr; + TL::LedDriver::i2sDeviceIdentifier = TL::LedDriver::I2SDevice::I2S_DEV_0; + std::memset(reinterpret_cast(TL::LedDriver::dmaBuffer), 0, sizeof(TL::LedDriver::dmaBuffer)); + TL::LedDriver::dmaBufferIndex = 0; + TL::LedDriver::interruptHandle = nullptr; + TL::LedDriver::semaphore = NULL; + + for (size_t i = 0; i < ledBuffer.getLedStripCount(); i++) + { + const TL::LedDriver::Error pinError = TL::LedDriver::initPin(ledBuffer.getLedStrip(i).getLedPin(), i); + if (pinError != TL::LedDriver::Error::OK) + { + return pinError; + } + TL::LedDriver::ledStripLength[i] = ledBuffer.getLedStrip(i).getHiddenLedCount(); + } + + TL::LedDriver::ledBuffer = ledBuffer.getBuffer(); + TL::LedDriver::ledStripCount = ledBuffer.getLedStripCount(); + TL::LedDriver::ledStripMaxLength = ledBuffer.getMaxHiddenLedCount(); + TL::LedDriver::i2sDeviceIdentifier = i2sDeviceIdentifier; + TL::LedDriver::i2sDeviceIdentifier = i2sDeviceIdentifier; + TL::LedDriver::semaphore = xSemaphoreCreateBinary(); + xSemaphoreGive(TL::LedDriver::semaphore); + + const TL::LedDriver::Error i2sError = TL::LedDriver::initI2S(); + if (i2sError != TL::LedDriver::Error::OK) + { + return i2sError; + } + TL::LedDriver::initDMABuffers(); + + TL::LedDriver::initialized = true; + return TL::LedDriver::Error::OK; +} + +/** + * @brief Check if the LED driver was initialized. + * @return true when initialized + * @return false when not initialized + */ +bool TL::LedDriver::isInitialized() +{ + return TL::LedDriver::initialized; +} + +/** + * @brief Stop the LED driver and free resources. + */ +void TL::LedDriver::end() +{ + if (TL::LedDriver::initialized) + { + xSemaphoreTake(TL::LedDriver::semaphore, portMAX_DELAY); + xSemaphoreGive(TL::LedDriver::semaphore); + vSemaphoreDelete(semaphore); + esp_intr_free(interruptHandle); + + TL::LedDriver::initialized = false; + TL::LedDriver::freeDMABuffer(dmaBuffer[0]); + TL::LedDriver::freeDMABuffer(dmaBuffer[1]); + TL::LedDriver::freeDMABuffer(dmaBuffer[2]); + TL::LedDriver::freeDMABuffer(dmaBuffer[3]); + } +} + +/** + * @brief Check if the driver finished sending all data and is ready for new one. + * @param timeout cpu cycles until a timeout will occur when the output is not finished yet + * @return OK when the LED driver is ready + * @return ERROR_NOT_INITIALIZED when the LED driver was not properly initialized yet + * @return ERROR_STILL_SENDING when the output is still in progress and the driver is not ready yet + */ +TL::LedDriver::Error TL::LedDriver::isReady(const TickType_t timeout) +{ + if (!TL::LedDriver::initialized) + { + return TL::LedDriver::Error::ERROR_NOT_INITIALIZED; + } + + if (xSemaphoreTake(TL::LedDriver::semaphore, timeout) != pdTRUE) + { + return TL::LedDriver::Error::ERROR_STILL_SENDING; + } + + xSemaphoreGive(TL::LedDriver::semaphore); + return TL::LedDriver::Error::OK; +} + +/** + * @brief Prepare the DMA buffers and send the data to the LED strips (async). + * @param timeout cpu cycles until a timeout will occur when the output is not finished yet + * @return OK when the LED data is being processed + * @return ERROR_NOT_INITIALIZED when the LED driver was not properly initialized yet + * @return ERROR_STILL_SENDING when the output is still in progress and the driver is not ready yet + * @return ERROR_ENABLE_INTERRUPT when the interrupt could not be enabled + */ +TL::LedDriver::Error TL::LedDriver::showPixels(const TickType_t timeout) +{ + if (!TL::LedDriver::initialized) + { + return TL::LedDriver::Error::ERROR_NOT_INITIALIZED; + } + + if (xSemaphoreTake(TL::LedDriver::semaphore, timeout) != pdTRUE) + { + return TL::LedDriver::Error::ERROR_STILL_SENDING; + } + + TL::LedDriver::ledIndex = 0; + TL::LedDriver::dmaBufferIndex = 1; + TL::LedDriver::dmaBuffer[0]->descriptor.qe.stqe_next = &(dmaBuffer[1]->descriptor); + TL::LedDriver::dmaBuffer[1]->descriptor.qe.stqe_next = &(dmaBuffer[0]->descriptor); + TL::LedDriver::dmaBuffer[2]->descriptor.qe.stqe_next = &(dmaBuffer[0]->descriptor); + TL::LedDriver::dmaBuffer[3]->descriptor.qe.stqe_next = 0; + TL::LedDriver::loadDMABuffer(TL::LedDriver::ledBuffer, reinterpret_cast(TL::LedDriver::dmaBuffer[0]->buffer), TL::LedDriver::ledStripLength, TL::LedDriver::ledStripCount, TL::LedDriver::ledIndex); + + TL::LedDriver::Error startError = TL::LedDriver::startI2S(dmaBuffer[2]); + if (startError != TL::LedDriver::Error::OK) + { + return startError; + } + + return TL::LedDriver::Error::OK; +} + +/** + * @brief Initialize an output pin. + * @param outputPin pin number of the output pin + * @param ledStripIndex index of the assigned LED strip + * @return OK when the pin was configured + * @return ERROR_SET_PIN when the pin could not be configured + */ +TL::LedDriver::Error TL::LedDriver::initPin(const uint8_t outputPin, const uint8_t ledStripIndex) +{ + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[outputPin], PIN_FUNC_GPIO); + if (gpio_set_direction(static_cast(outputPin), (gpio_mode_t)GPIO_MODE_DEF_OUTPUT) != ESP_OK) + { + return TL::LedDriver::Error::ERROR_SET_PIN; + } + gpio_matrix_out(outputPin, (TL::LedDriver::i2sDeviceIdentifier == TL::LedDriver::I2SDevice::I2S_DEV_0 ? I2S0O_DATA_OUT0_IDX : I2S1O_DATA_OUT0_IDX) + ledStripIndex + 8, false, false); + return TL::LedDriver::Error::OK; +} + +/** + * @brief Initialize the I2S device and prepare DMA buffers. + * @return OK when the I2S device was initialized + * @return ERROR_ALLOCATE_INTERRUPT when the interrupt could not be allocated + */ +TL::LedDriver::Error TL::LedDriver::initI2S() +{ + uint8_t interruptSource; + if (TL::LedDriver::i2sDeviceIdentifier == TL::LedDriver::I2SDevice::I2S_DEV_0) + { + TL::LedDriver::i2sDevice = &I2S0; + periph_module_enable(PERIPH_I2S0_MODULE); + interruptSource = ETS_I2S0_INTR_SOURCE; + } + else + { + TL::LedDriver::i2sDevice = &I2S1; + periph_module_enable(PERIPH_I2S1_MODULE); + interruptSource = ETS_I2S1_INTR_SOURCE; + } + + TL::LedDriver::resetI2S(); + TL::LedDriver::resetDMA(); + TL::LedDriver::resetFIFO(); + + TL::LedDriver::i2sDevice->conf.tx_right_first = 0; + TL::LedDriver::i2sDevice->conf2.val = 0; + TL::LedDriver::i2sDevice->conf2.lcd_en = 1; + TL::LedDriver::i2sDevice->conf2.lcd_tx_wrx2_en = 1; + TL::LedDriver::i2sDevice->conf2.lcd_tx_sdx2_en = 0; + TL::LedDriver::i2sDevice->sample_rate_conf.val = 0; + TL::LedDriver::i2sDevice->sample_rate_conf.tx_bits_mod = 16; + TL::LedDriver::i2sDevice->clkm_conf.val = 0; + TL::LedDriver::i2sDevice->clkm_conf.clka_en = 0; + TL::LedDriver::i2sDevice->clkm_conf.clkm_div_a = 3; + TL::LedDriver::i2sDevice->clkm_conf.clkm_div_b = 1; + TL::LedDriver::i2sDevice->clkm_conf.clkm_div_num = 33; + TL::LedDriver::i2sDevice->fifo_conf.val = 0; + TL::LedDriver::i2sDevice->fifo_conf.tx_fifo_mod_force_en = 1; + TL::LedDriver::i2sDevice->fifo_conf.tx_fifo_mod = 1; + TL::LedDriver::i2sDevice->fifo_conf.tx_data_num = 32; + TL::LedDriver::i2sDevice->fifo_conf.dscr_en = 1; + TL::LedDriver::i2sDevice->sample_rate_conf.tx_bck_div_num = 1; + TL::LedDriver::i2sDevice->conf1.val = 0; + TL::LedDriver::i2sDevice->conf1.tx_stop_en = 0; + TL::LedDriver::i2sDevice->conf1.tx_pcm_bypass = 1; + TL::LedDriver::i2sDevice->conf_chan.val = 0; + TL::LedDriver::i2sDevice->conf_chan.tx_chan_mod = 1; + TL::LedDriver::i2sDevice->timing.val = 0; + TL::LedDriver::i2sDevice->int_ena.val = 0; + + if (esp_intr_alloc(interruptSource, ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL3 | ESP_INTR_FLAG_IRAM, &TL::LedDriver::interruptHandler, NULL, &TL::LedDriver::interruptHandle) != ESP_OK) + { + return TL::LedDriver::Error::ERROR_ALLOCATE_INTERRUPT; + } + + return TL::LedDriver::Error::OK; +} + +/** + * @brief Start the I2S device to send out the LED data. + * @param startBuffer first buffer to read the data from + * @return OK when the I2S device started to send out the LED data + * @return ERROR_ENABLE_INTERRUPT when the interrupt could not be enabled + */ +TL::LedDriver::Error TL::LedDriver::startI2S(const TL::LedDriver::DMABuffer *startBuffer) +{ + TL::LedDriver::resetI2S(); + + TL::LedDriver::i2sDevice->lc_conf.val = I2S_OUT_DATA_BURST_EN | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN; + TL::LedDriver::i2sDevice->out_link.addr = reinterpret_cast(&(startBuffer->descriptor)); + TL::LedDriver::i2sDevice->out_link.start = 1; + TL::LedDriver::i2sDevice->int_clr.val = TL::LedDriver::i2sDevice->int_raw.val; + TL::LedDriver::i2sDevice->int_clr.val = TL::LedDriver::i2sDevice->int_raw.val; + TL::LedDriver::i2sDevice->int_ena.val = 0; + TL::LedDriver::i2sDevice->int_ena.out_eof = 1; + TL::LedDriver::i2sDevice->int_ena.out_total_eof = 1; + + if (esp_intr_enable(TL::LedDriver::interruptHandle) != ESP_OK) + { + return TL::LedDriver::Error::ERROR_ENABLE_INTERRUPT; + } + + TL::LedDriver::i2sDevice->conf.tx_start = 1; + return TL::LedDriver::Error::OK; +} + +/** + * @brief Reset the I2S device. + */ +void IRAM_ATTR TL::LedDriver::resetI2S() +{ + const unsigned long lcConfigResetFlage = I2S_IN_RST_M | I2S_OUT_RST_M | I2S_AHBM_RST_M | I2S_AHBM_FIFO_RST_M; + TL::LedDriver::i2sDevice->lc_conf.val |= lcConfigResetFlage; + TL::LedDriver::i2sDevice->lc_conf.val &= ~lcConfigResetFlage; + const uint32_t configResetFlags = I2S_RX_RESET_M | I2S_RX_FIFO_RESET_M | I2S_TX_RESET_M | I2S_TX_FIFO_RESET_M; + TL::LedDriver::i2sDevice->conf.val |= configResetFlags; + TL::LedDriver::i2sDevice->conf.val &= ~configResetFlags; +} + +/** + * @brief Stop the I2S device after all data was sent to the LEDs. + */ +void IRAM_ATTR TL::LedDriver::stopI2S() +{ + if (esp_intr_disable(TL::LedDriver::interruptHandle) != ESP_OK) + { + // Idk... + } + + TL::LedDriver::i2sDevice->conf.tx_start = 0; + // while (TL::LedDriver::i2sDevice->conf.tx_start == 1); + resetI2S(); + ets_delay_us(30); +} + +/** + * @brief Reset the DMA of the I2S device. + */ +void TL::LedDriver::resetDMA() +{ + TL::LedDriver::i2sDevice->lc_conf.out_rst = 1; + TL::LedDriver::i2sDevice->lc_conf.out_rst = 0; +} + +/** + * @brief Reset the FIFO of the I2S device. + */ +void TL::LedDriver::resetFIFO() +{ + TL::LedDriver::i2sDevice->conf.tx_fifo_reset = 1; + TL::LedDriver::i2sDevice->conf.tx_fifo_reset = 0; +} + +/** + * @brief Allocate a DMA buffer with a given size. + * @param size number of elements to allocate + * @return allocated DMA buffer + */ +TL::LedDriver::DMABuffer *TL::LedDriver::allocateDMABuffer(const uint32_t size) +{ + DMABuffer *dmaBuffer = reinterpret_cast(heap_caps_malloc(sizeof(DMABuffer), MALLOC_CAP_DMA)); + dmaBuffer->buffer = reinterpret_cast(heap_caps_malloc(size, MALLOC_CAP_DMA)); + + std::memset(dmaBuffer->buffer, 0, size); + dmaBuffer->descriptor.length = size; + dmaBuffer->descriptor.size = size; + dmaBuffer->descriptor.owner = 1; + dmaBuffer->descriptor.sosf = 1; + dmaBuffer->descriptor.buf = dmaBuffer->buffer; + dmaBuffer->descriptor.offset = 0; + dmaBuffer->descriptor.empty = 0; + dmaBuffer->descriptor.eof = 1; + dmaBuffer->descriptor.qe.stqe_next = 0; + return dmaBuffer; +} + +/** + * @brief Free a given DMA buffer. + * @param dmaBuffer DMA buffer to free + */ +void TL::LedDriver::freeDMABuffer(TL::LedDriver::DMABuffer *dmaBuffer) +{ + heap_caps_free(dmaBuffer->buffer); + heap_caps_free(dmaBuffer); +} + +/** + * @brief Initialize the DMA buffers. + */ +void TL::LedDriver::initDMABuffers() +{ + TL::LedDriver::dmaBuffer[0] = TL::LedDriver::allocateDMABuffer(3 * 8 * 2 * 3); + TL::LedDriver::dmaBuffer[1] = TL::LedDriver::allocateDMABuffer(3 * 8 * 2 * 3); + TL::LedDriver::dmaBuffer[2] = TL::LedDriver::allocateDMABuffer(3 * 8 * 2 * 3); + TL::LedDriver::dmaBuffer[3] = TL::LedDriver::allocateDMABuffer(3 * 8 * 2 * 3 * 4); + + for (uint8_t i = 0; i < 2; i++) + { + for (uint8_t j = 0; j < 3 * 8 / 2; j++) + { + uint16_t *buffer = reinterpret_cast(TL::LedDriver::dmaBuffer[i]->buffer); + buffer[j * 6 + 1] = 0xffff; + buffer[j * 6 + 2] = 0xffff; + } + } +} + +/** + * @brief Interrupt handler is called once a buffer was sent. It will then preload the next buffer. + * @param args arguments, currently not used + */ +void IRAM_ATTR TL::LedDriver::interruptHandler(void *args) +{ + if (GET_PERI_REG_BITS(I2S_INT_ST_REG(static_cast(TL::LedDriver::i2sDeviceIdentifier)), I2S_OUT_EOF_INT_ST_V, I2S_OUT_EOF_INT_ST_S)) + { + TL::LedDriver::ledIndex++; + if (TL::LedDriver::ledIndex < TL::LedDriver::ledStripMaxLength) + { + loadDMABuffer(TL::LedDriver::ledBuffer, reinterpret_cast(TL::LedDriver::dmaBuffer[TL::LedDriver::dmaBufferIndex]->buffer), TL::LedDriver::ledStripLength, TL::LedDriver::ledStripCount, TL::LedDriver::ledIndex); + + if (TL::LedDriver::ledIndex == TL::LedDriver::ledStripMaxLength - 3) + { + TL::LedDriver::dmaBuffer[TL::LedDriver::dmaBufferIndex]->descriptor.qe.stqe_next = &(TL::LedDriver::dmaBuffer[3]->descriptor); + } + TL::LedDriver::dmaBufferIndex = (TL::LedDriver::dmaBufferIndex + 1) % 2; + } + } + + if (GET_PERI_REG_BITS(I2S_INT_ST_REG(static_cast(TL::LedDriver::i2sDeviceIdentifier)), I2S_OUT_TOTAL_EOF_INT_ST_V, I2S_OUT_TOTAL_EOF_INT_ST_S)) + { + TL::LedDriver::stopI2S(); + portBASE_TYPE hpTaskAwoken = pdFALSE; + xSemaphoreGiveFromISR(TL::LedDriver::semaphore, &hpTaskAwoken); + if (hpTaskAwoken == pdTRUE) + { + portYIELD_FROM_ISR(hpTaskAwoken); + } + } + REG_WRITE(I2S_INT_CLR_REG(0), (REG_READ(I2S_INT_RAW_REG(0)) & 0xffffffc0) | 0x3f); +} + +/** + * @brief Preload a DMA buffer from the LED pixel data. + * @param ledBuffer led buffer with the pixel data + * @param dmaBuffer DMA buffer to fill + * @param ledStripLength length of the individual LED strips + * @param ledStripCount number of LED strips + * @param ledIndex the current LED index + */ +void IRAM_ATTR TL::LedDriver::loadDMABuffer(uint8_t *ledBuffer, uint16_t *dmaBuffer, const uint16_t *ledStripLength, const uint16_t ledStripCount, const uint16_t ledIndex) +{ + uint8_t bytes[3][16] = {{0}}; + uint8_t *poli = ledBuffer + ledIndex * 3; + for (int i = 0; i < ledStripCount; i++) + { + if (ledIndex < ledStripLength[i]) + { + bytes[0][i] = *(poli + 1); + bytes[1][i] = *(poli + 0); + bytes[2][i] = *(poli + 2); + } + + poli += ledStripLength[i] * 3; + } + + transpose(bytes[0], reinterpret_cast(dmaBuffer)); + transpose(bytes[1], reinterpret_cast(dmaBuffer + 3 * 8)); + transpose(bytes[2], reinterpret_cast(dmaBuffer + 2 * 3 * 8)); +} + +/** + * @brief Transpose the LED data into the DMA buffers. + * Todo: clean and document this mess + */ +void IRAM_ATTR TL::LedDriver::transpose(uint8_t *pixelBuffer, uint16_t *dmaBuffer) +{ + uint32_t x, y, x1, y1, t; + y = *reinterpret_cast(pixelBuffer); + x = *reinterpret_cast(pixelBuffer + 4); + t = (x ^ (x >> 7)) & 0x00AA00AAL; + x = x ^ t ^ (t << 7); + t = (x ^ (x >> 14)) & 0x0000CCCCL; + x = x ^ t ^ (t << 14); + t = (y ^ (y >> 7)) & 0x00AA00AAL; + y = y ^ t ^ (t << 7); + t = (y ^ (y >> 14)) & 0x0000CCCCL; + y = y ^ t ^ (t << 14); + t = (x & 0xF0F0F0F0L) | ((y >> 4) & 0x0F0F0F0FL); + y = ((x << 4) & 0xF0F0F0F0L) | (y & 0x0F0F0F0FL); + x = t; + t = (x1 & 0xF0F0F0F0L) | ((y1 >> 4) & 0x0F0F0F0FL); + y1 = ((x1 << 4) & 0xF0F0F0F0L) | (y1 & 0x0F0F0F0FL); + x1 = t; + *(reinterpret_cast(dmaBuffer)) = static_cast(((x & 0xff000000) >> 8 | ((x1 & 0xff000000))) >> 16); + *(reinterpret_cast(dmaBuffer + 5)) = static_cast(((x & 0xff0000) >> 16 | ((x1 & 0xff0000) >> 8))); + *(reinterpret_cast(dmaBuffer + 6)) = static_cast(((x & 0xff00) | ((x1 & 0xff00) << 8)) >> 8); + *(reinterpret_cast(dmaBuffer + 11)) = static_cast((x & 0xff) | ((x1 & 0xff) << 8)); + *(reinterpret_cast(dmaBuffer + 12)) = static_cast(((y & 0xff000000) >> 8 | ((y1 & 0xff000000))) >> 16); + *(reinterpret_cast(dmaBuffer + 17)) = static_cast(((y & 0xff0000) | ((y1 & 0xff0000) << 8)) >> 16); + *(reinterpret_cast(dmaBuffer + 18)) = static_cast(((y & 0xff00) | ((y1 & 0xff00) << 8)) >> 8); + *(reinterpret_cast(dmaBuffer + 23)) = static_cast((y & 0xff) | ((y1 & 0xff) << 8)); +} diff --git a/mcu/src/led/driver/LedStrip.cpp b/mcu/src/led/driver/LedStrip.cpp new file mode 100644 index 0000000..5a5737b --- /dev/null +++ b/mcu/src/led/driver/LedStrip.cpp @@ -0,0 +1,135 @@ +/** + * @file LedStrip.cpp + * @author TheRealKasumi + * @brief Implementation of the {@link TL::LedStrip}. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#include "led/driver/LedStrip.h" + +/** + * @brief Create a new instance of {@link TL::LedStrip}. + * @param ledPin physical pin number for the data output + * @param ledCount number of visible LEDs + * @param hiddenLedCount total number of LEDs including invisible ones + */ +TL::LedStrip::LedStrip(const uint8_t ledPin, const size_t ledCount, const size_t hiddenLedCount) +{ + this->ledPin = ledPin; + this->ledCount = ledCount; + this->hiddenLedCount = hiddenLedCount; + this->buffer = nullptr; + this->initialized = false; + + if (this->hiddenLedCount < this->ledCount) + { + this->hiddenLedCount = ledCount; + } + else if (this->hiddenLedCount < 8) + { + this->hiddenLedCount = 8; + } +} + +/** + * @brief Destroy the {@link TL::LedStrip} instance. + */ +TL::LedStrip::~LedStrip() +{ +} + +/** + * @brief Get the LED output pin. + * @return pin number + */ +uint8_t TL::LedStrip::getLedPin() +{ + return this->ledPin; +} + +/** + * @brief Get the number of LEDs. + * @return number of LEDs + */ +size_t TL::LedStrip::getLedCount() +{ + return this->ledCount; +} + +/** + * @brief Get the number of hidden LEDs. This is the number of visible LEDs + the number of invisible LEDs. + * @return number of hidden LEDs + */ +size_t TL::LedStrip::getHiddenLedCount() +{ + return this->hiddenLedCount; +} + +/** + * @brief Get a single pixel from the buffer. + * @param index index of the pixel + * @return OK when the + */ +TL::Pixel TL::LedStrip::getPixel(const size_t index) +{ + if (!this->initialized || index >= this->ledCount) + { + std::abort(); + } + const size_t ind = index * 3; + return TL::Pixel(this->buffer[ind], this->buffer[ind + 1], this->buffer[ind + 2]); +} + +/** + * @brief Set a single pixel in the buffer. + * @param pixel updated pixel + * @param index index of the pixel + */ +void TL::LedStrip::setPixel(const TL::Pixel &pixel, const size_t index) +{ + if (!this->initialized || index >= this->ledCount) + { + std::abort(); + } + const size_t ind = index * 3; + this->buffer[ind] = pixel.red; + this->buffer[ind + 1] = pixel.green; + this->buffer[ind + 2] = pixel.blue; +} + +/** + * @brief Return the base pointer to the buffer. + * @return pointer to the buffer + */ +uint8_t *TL::LedStrip::getBuffer() +{ + if (!this->initialized) + { + std::abort(); + } + return this->buffer; +} + +/** + * @brief Set the base pointer to the buffer. + * @param buffer base pointer to the buffer + */ +void TL::LedStrip::setBuffer(uint8_t *buffer) +{ + this->initialized = true; + this->buffer = buffer; +} diff --git a/mcu/src/led/driver/Pixel.cpp b/mcu/src/led/driver/Pixel.cpp new file mode 100644 index 0000000..fc5341f --- /dev/null +++ b/mcu/src/led/driver/Pixel.cpp @@ -0,0 +1,101 @@ +/** + * @file Pixel.cpp + * @author TheRealKasumi + * @brief Implementation of the {@link TL::Pixel} class. + * + * @copyright Copyright (c) 2022-2023 TheRealKasumi + * + * This project, including hardware and software, is provided "as is". There is no warranty + * of any kind, express or implied, including but not limited to the warranties of fitness + * for a particular purpose and noninfringement. TheRealKasumi (https://github.com/TheRealKasumi) + * is holding ownership of this project. You are free to use, modify, distribute and contribute + * to this project for private, non-commercial purposes. It is granted to include this hardware + * and software into private, non-commercial projects. However, the source code of any project, + * software and hardware that is including this project must be public and free to use for private + * persons. Any commercial use is hereby strictly prohibited without agreement from the owner. + * By contributing to the project, you agree that the ownership of your work is transferred to + * the project owner and that you lose any claim to your contribute work. This copyright and + * license note applies to all files of this project and must not be removed without agreement + * from the owner. + * + */ +#include "led/driver/Pixel.h" + +/** + * @brief Create a new instance of {@link TL::Pixel}. + */ +TL::Pixel::Pixel() +{ + this->setColor(TL::Pixel::ColorCode::Black); +} + +/** + * @brief Create a new instance of {@link TL::Pixel}. + * @param colorCode 24 bit color code + */ +TL::Pixel::Pixel(const uint32_t colorCode) +{ + this->setColor(colorCode); +} + +/** + * @brief Create a new instance of {@link TL::Pixel}. + * @param colorCode one of the html color codes + */ +TL::Pixel::Pixel(const TL::Pixel::ColorCode colorCode) +{ + this->setColor(colorCode); +} + +/** + * @brief Create a new instance of {@link TL::Pixel}. + * @param red red value + * @param green green value + * @param blue blue value + */ +TL::Pixel::Pixel(const uint8_t red, const uint8_t green, const uint8_t blue) +{ + this->setColor(red, green, blue); +} + +/*** + * Destroy the {@link TL::Pixel} isntance. + */ +TL::Pixel::~Pixel() +{ +} + +/** + * @brief Set the pixel color. + * @param colorCode 24 bit color code + */ +void TL::Pixel::setColor(const uint32_t colorCode) +{ + this->red = colorCode & 0xff0000; + this->green = colorCode & 0x00ff00; + this->blue = colorCode & 0x0000ff; +} + +/** + * @brief Set the pixel color. + * @param colorCode one of the html color codes + */ +void TL::Pixel::setColor(const TL::Pixel::ColorCode colorCode) +{ + this->red = static_cast(colorCode) & 0xff0000; + this->green = static_cast(colorCode) & 0x00ff00; + this->blue = static_cast(colorCode) & 0x0000ff; +} + +/** + * @brief Set the pixel color. + * @param red red value + * @param green green value + * @param blue blue value + */ +void TL::Pixel::setColor(const uint8_t red, const uint8_t green, const uint8_t blue) +{ + this->red = red; + this->green = green; + this->blue = blue; +} diff --git a/mcu/src/server/LedConfigurationEndpoint.cpp b/mcu/src/server/LedConfigurationEndpoint.cpp index f45b592..4d961a1 100644 --- a/mcu/src/server/LedConfigurationEndpoint.cpp +++ b/mcu/src/server/LedConfigurationEndpoint.cpp @@ -194,16 +194,10 @@ void TL::LedConfigurationEndpoint::postLedConfig() } const TL::LedManager::Error ledManagerError = TL::LedManager::reloadAnimations(); - if (ledManagerError == TL::LedManager::Error::ERROR_CONFIG_UNAVAILABLE) + if (ledManagerError == TL::LedManager::Error::ERROR_INIT_LED_DRIVER) { - TL::Logger::log(TL::Logger::LogLevel::ERROR, SOURCE_LOCATION, F("Failed to apply LED configuration. The TesLight configuration is not available.")); - TL::LedConfigurationEndpoint::sendSimpleResponse(500, F("Failed to apply LED configuration. The TesLight configuration is not available.")); - return; - } - else if (ledManagerError == TL::LedManager::Error::ERROR_CREATE_LED_DATA) - { - TL::Logger::log(TL::Logger::LogLevel::ERROR, SOURCE_LOCATION, F("Failed to apply LED configuration. The pixel data could not be created.")); - TL::LedConfigurationEndpoint::sendSimpleResponse(500, F("Failed to apply LED configuration. The pixel data could not be created.")); + TL::Logger::log(TL::Logger::LogLevel::ERROR, SOURCE_LOCATION, F("Failed to initialized LED driver for the current configuration.")); + TL::LedConfigurationEndpoint::sendSimpleResponse(500, F("Failed to initialized LED driver for the current configuration.")); return; } else if (ledManagerError == TL::LedManager::Error::ERROR_UNKNOWN_ANIMATOR_TYPE) @@ -271,10 +265,10 @@ bool TL::LedConfigurationEndpoint::validateLedZone(const JsonObject &jsonObject, return false; } - if (!TL::LedConfigurationEndpoint::isInRange(jsonObject[F("ledCount")].as(), 2L, 250L)) + if (!TL::LedConfigurationEndpoint::isInRange(jsonObject[F("ledCount")].as(), 1L, LED_MAX_COUNT_PER_ZONE)) { - TL::Logger::log(TL::Logger::LogLevel::WARN, SOURCE_LOCATION, (String)F("The \"ledCount\" field at index ") + index + F(" must be between 2 and 250.")); - TL::LedConfigurationEndpoint::sendSimpleResponse(400, (String)F("The \"ledCount\" field at index ") + index + F(" must be between 2 and 250.")); + TL::Logger::log(TL::Logger::LogLevel::WARN, SOURCE_LOCATION, (String)F("The \"ledCount\" field at index ") + index + F(" must be between 1 and ") + LED_MAX_COUNT_PER_ZONE + F(".")); + TL::LedConfigurationEndpoint::sendSimpleResponse(400, (String)F("The \"ledCount\" field at index ") + index + F(" must be between 1 and ") + LED_MAX_COUNT_PER_ZONE + F(".")); return false; } diff --git a/mcu/src/server/SystemInformationEndpoint.cpp b/mcu/src/server/SystemInformationEndpoint.cpp index e8be482..e42072d 100644 --- a/mcu/src/server/SystemInformationEndpoint.cpp +++ b/mcu/src/server/SystemInformationEndpoint.cpp @@ -72,9 +72,9 @@ void TL::SystemInformationEndpoint::getSystemInformation() hardwareInfo[F("audioUnit")] = TL::SystemInformation::getHardwareInfo().audioUnit; const JsonObject tlSystemInfo = jsonDoc.createNestedObject(F("tlSystemInfo")); - tlSystemInfo[F("rps")] = TL::SystemInformation::getTesLightInfo().rps; tlSystemInfo[F("fps")] = TL::SystemInformation::getTesLightInfo().fps; tlSystemInfo[F("ledCount")] = TL::SystemInformation::getTesLightInfo().ledCount; + tlSystemInfo[F("hiddenLedCount")] = TL::SystemInformation::getTesLightInfo().hiddenLedCount; TL::Logger::log(TL::Logger::LogLevel::INFO, SOURCE_LOCATION, F("Sending the response.")); TL::SystemInformationEndpoint::sendJsonDocument(200, F("Here is my current status."), jsonDoc); diff --git a/mcu/src/util/FseqLoader.cpp b/mcu/src/util/FseqLoader.cpp index 57ea571..8d30afe 100644 --- a/mcu/src/util/FseqLoader.cpp +++ b/mcu/src/util/FseqLoader.cpp @@ -148,14 +148,14 @@ TL::FseqLoader::FseqHeader TL::FseqLoader::getHeader() } /** - * @brief Read a buffer of pixels from the stream. - * @param pixels reference to the vector holding the LED pixel data + * @brief Read a LED strip from the stream. + * @param ledStrip LED strip with the pixel data * @return OK when the pixel buffer was read * @return ERROR_END_OF_FILE when there is no more data to read */ -TL::FseqLoader::Error TL::FseqLoader::readPixelBuffer(std::vector &pixels) +TL::FseqLoader::Error TL::FseqLoader::readLedStrip(TL::LedStrip &ledStrip) { - if (this->file && this->available() >= pixels.size()) + if (this->file && this->available() >= ledStrip.getLedCount()) { this->zoneCounter++; if (this->zoneCounter >= this->zoneCount) @@ -167,7 +167,7 @@ TL::FseqLoader::Error TL::FseqLoader::readPixelBuffer(std::vector &pixels) } } - if (this->file.read((uint8_t *)&pixels.front(), pixels.size() * 3) == pixels.size() * 3) + if (this->file.read(ledStrip.getBuffer(), ledStrip.getLedCount() * 3) == ledStrip.getLedCount() * 3) { return TL::FseqLoader::Error::OK; }