including light effects from different project
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @file color.hpp
|
||||
* @author Gustice
|
||||
* @brief
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
/// No Waveform definition
|
||||
extern uint8_t const *const noWave;
|
||||
|
||||
/**
|
||||
* @brief Color class
|
||||
*
|
||||
* @details Defines color data and common operations with color objects
|
||||
* \li Supports RGB with overlapping white channel (e.g. SK6812-LED)
|
||||
* \li Supports Operator overloading with '+' and '*' (Combined operation with MixWith)
|
||||
* \li Return formatted data stream that can be directly sent to an LED
|
||||
*/
|
||||
class Color {
|
||||
private:
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
uint8_t white;
|
||||
|
||||
public:
|
||||
struct Rgbw {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
uint8_t white;
|
||||
};
|
||||
|
||||
struct Rgb {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
|
||||
/// @brief Construct a new Color object
|
||||
/// @details Default color will be Black \ref _ctBlack
|
||||
Color(void) {
|
||||
set(0, 0, 0, 0);
|
||||
};
|
||||
|
||||
/// @brief Copy-Construct a new Color object
|
||||
Color(const Color & c) {
|
||||
red = c.red;
|
||||
green = c.green;
|
||||
blue = c.blue;
|
||||
white = c.white;
|
||||
};
|
||||
|
||||
/// @brief Construct a new Color object according to rgb color-channel-values
|
||||
/// @details This constructor also takes an overlapping white channel
|
||||
/// @param r Red channel
|
||||
/// @param g Green channel
|
||||
/// @param b Blue channel
|
||||
/// @param w White channel (zero by default if not assigned)
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { set(r, g, b, w); };
|
||||
|
||||
/// @brief Set the Color object according to rgb color-channel values
|
||||
/// @param r Red channel
|
||||
/// @param g Green channel
|
||||
/// @param b Blue channel
|
||||
/// @param w White channel (zero by default if not assigned)
|
||||
void set(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) {
|
||||
red = r;
|
||||
green = g;
|
||||
blue = b;
|
||||
white = w;
|
||||
}
|
||||
|
||||
/// @brief Returns Color as Color_t structure
|
||||
/// @return Color_t Color
|
||||
template <typename T>
|
||||
T getColor(void) const {
|
||||
if constexpr (std::is_same<T, Rgbw>::value) {
|
||||
return {red, green, blue, white};
|
||||
} else if constexpr (std::is_same<T, Rgb>::value) {
|
||||
return {red, green, blue};
|
||||
} else {
|
||||
throw "wrong type";
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getRed() { return red; };
|
||||
uint8_t getGreen() { return green; };
|
||||
uint8_t getBlue() { return blue; };
|
||||
uint8_t getWhite() { return white; };
|
||||
|
||||
/// @brief Scaling and overlaying with given color.
|
||||
/// @param c2 Color 2
|
||||
/// @param k scaling factor
|
||||
/// @return Overlayed Color
|
||||
Color mixWith(const Color c2, uint8_t k = 0x7F) {
|
||||
auto t(c2);
|
||||
*this = (*this * (UINT8_MAX - k)) + (t * k);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Writes Color as formatted byte stream to location
|
||||
/// @param color
|
||||
template <typename T>
|
||||
void writeByteStreamTo(uint8_t raw[sizeof(T)]) const {
|
||||
if constexpr (std::is_same<T, Rgbw>::value) {
|
||||
raw[0] = blue;
|
||||
raw[1] = green;
|
||||
raw[2] = red;
|
||||
raw[3] = white;
|
||||
} else if constexpr (std::is_same<T, Rgb>::value) {
|
||||
raw[0] = blue;
|
||||
raw[1] = green;
|
||||
raw[2] = red;
|
||||
} else {
|
||||
throw "wrong type";
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Assign overload
|
||||
Color operator=(const Color &c2) {
|
||||
red = c2.red;
|
||||
green = c2.green;
|
||||
blue = c2.blue;
|
||||
white = c2.white;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Checks if both color values are equal
|
||||
bool operator==(Color const &c2) const {
|
||||
return ((blue == c2.blue) && (green == c2.green) &&
|
||||
(red == c2.red) && (white == c2.white));
|
||||
}
|
||||
|
||||
/// @brief Checks if both color values are not equal
|
||||
bool operator!=(Color const &c2) const {
|
||||
return ((blue != c2.blue) || (green != c2.green) ||
|
||||
(red != c2.red) || (white != c2.white));
|
||||
}
|
||||
|
||||
/// @brief Scale color by scaling each color-channel by given factor
|
||||
/// @param c1 Color
|
||||
/// @param k Scale-factor uint8_t.Max is full-scale
|
||||
/// @return Scaled Color
|
||||
Color operator*(uint8_t k) {
|
||||
red = (uint8_t)((uint16_t)red * k / 0xFF);
|
||||
green = (uint8_t)((uint16_t)green * k / 0xFF);
|
||||
blue = (uint8_t)((uint16_t)blue * k / 0xFF);
|
||||
white = (uint8_t)((uint16_t)white * k / 0xFF);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Overlaying to colors my adding each color channel value
|
||||
/// @note Colors channels should not overlap since there is no automatic ratio correction.
|
||||
/// Use *-Operator first in order to scale each color value a a way that no overflow can occur
|
||||
/// @param c2 Color 2
|
||||
/// @return Overlayed Color
|
||||
Color operator+(Color c2) {
|
||||
red = red + c2.red;
|
||||
green = green + c2.green;
|
||||
blue = blue + c2.blue;
|
||||
white = white + c2.white;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(Color) == 4 && "Color Type is to big");
|
||||
|
||||
/// Null color object
|
||||
extern const Color *noColor;
|
||||
/// Used old color agreement (if no color pointer)
|
||||
extern const Color *oldColor;
|
||||
|
||||
/// Black color object constant
|
||||
extern const Color CBlack;
|
||||
/// Red color object constant
|
||||
extern const Color CRed;
|
||||
/// Green color object constant
|
||||
extern const Color CGreen;
|
||||
/// Blue color object constant
|
||||
extern const Color CBlue;
|
||||
/// Magenta color object constant
|
||||
extern const Color CMagenta;
|
||||
/// Cyan color object constant
|
||||
extern const Color CCyan;
|
||||
/// Yellow color object constant
|
||||
extern const Color CYellow;
|
||||
/// White color object constant
|
||||
extern const Color CWhite;
|
||||
/// Warm white color object constant (with higher red channel value)
|
||||
extern const Color CWarmWhite;
|
||||
/// Black color object constant (with higher green channel value)
|
||||
extern const Color CColdWhite;
|
||||
/// Black color object constant (with higher blue channel value)
|
||||
extern const Color CSpookyWhite;
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file ExactIndex.h
|
||||
* @author Gustice
|
||||
* @brief Index-Class with fix-point arithmetic
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief Index-Class with fix-point arithmetic for exact stepping though data-points
|
||||
* @details Allows stepping through data-points by quotient step-sizes
|
||||
*/
|
||||
class ExactIndex {
|
||||
public:
|
||||
/// @brief Construct Index-object according to number of data points and steps to be taken
|
||||
/// @param length
|
||||
/// @param steps
|
||||
ExactIndex(unsigned length, uint16_t steps) : Length(std::max(1u, length)), Steps(steps) {
|
||||
_delta = Length << 8;
|
||||
_delta = _delta / steps;
|
||||
_index = unsigned(0u - _delta);
|
||||
}
|
||||
|
||||
/// @brief Get current index-position as floor value to never pass upper bound
|
||||
uint16_t GetIdx(void) { return ((_index) >> 8); };
|
||||
|
||||
/// @brief Move index by quotient step forward
|
||||
ExactIndex &operator++() {
|
||||
_index = _index + _delta;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Move index by quotient step backward
|
||||
ExactIndex &operator--() {
|
||||
_index = _index - _delta;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Get current index-position as floor value to never pass upper bound
|
||||
operator int() const { return ((_index) >> 8); }
|
||||
|
||||
/// @brief Get size of data set (number of data points)
|
||||
unsigned GetLength() { return Length; }
|
||||
/// @brief Get number of steps that are to be taken though data set
|
||||
uint16_t GetSteps() { return Steps; }
|
||||
|
||||
private:
|
||||
/// @brief Number of data points
|
||||
unsigned Length;
|
||||
/// @brief Steps to be taken through data-set
|
||||
uint16_t Steps;
|
||||
|
||||
/// @brief Current index in fixed-point representation
|
||||
unsigned _index = 0;
|
||||
|
||||
/// @brief Step-with in fixed-point representation
|
||||
unsigned _delta;
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file Macro.h
|
||||
* @author Gustice
|
||||
* @brief Predefined effect macros
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "Waveform.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace Effect {
|
||||
|
||||
/// Collection of process values to maintain processing state machine
|
||||
struct StepProcessVars {
|
||||
/// @brief Reference of current color
|
||||
const Color &pCurentColor;
|
||||
/// @brief Number of color entries
|
||||
uint8_t ColorLen;
|
||||
/// @brief Idle value for intensity
|
||||
uint8_t IdleIntensity;
|
||||
/// @brief Full value for intensity
|
||||
uint8_t FullIntensity;
|
||||
/// @brief Dynamic range for effects
|
||||
uint8_t DynamicRange;
|
||||
/// @brief Index in current waveform
|
||||
uint16_t waveIdx;
|
||||
/// @brief Reference to processed waveform
|
||||
const WaveForm_t *const pWave;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Effect implementation for State-Machine
|
||||
* @details State-Machine invokes referred effect-implementation during processing
|
||||
*/
|
||||
typedef Color (*EffectImplementation)(StepProcessVars &pcsParam);
|
||||
|
||||
/**
|
||||
* @brief Definition of Effect-Macro
|
||||
*/
|
||||
struct Macro_t {
|
||||
/// @brief Effect type
|
||||
const EffectImplementation pImplementation;
|
||||
/// @brief Effect duration waveforms will be compressed / stretched to fit the duration
|
||||
const uint8_t Duration;
|
||||
/// @brief Next SubEffect
|
||||
const int8_t Next;
|
||||
/// @brief waveform reference
|
||||
const WaveForm_t *pWave = emptyWave;
|
||||
/// @brief Full-Scale-intensity
|
||||
const uint8_t FsIntensity;
|
||||
/// @brief Num of Repeats
|
||||
const int8_t Repeats;
|
||||
|
||||
Macro_t(uint8_t duration, int8_t next, EffectImplementation state, uint8_t intensity,
|
||||
int8_t repeats = 0)
|
||||
: pImplementation(state), Duration(duration), Next(next), FsIntensity(intensity),
|
||||
Repeats(repeats) {}
|
||||
|
||||
Macro_t(uint8_t duration, int8_t next, WaveForm_t const *wave, EffectImplementation state,
|
||||
uint8_t intensity, int8_t repeats = 0)
|
||||
: pImplementation(state), Duration(duration), Next(next), pWave(wave),
|
||||
FsIntensity(intensity), Repeats(repeats) {}
|
||||
|
||||
private:
|
||||
/// @brief Null-pointer to represent no change in color
|
||||
static constexpr Color *pOldColor = nullptr;
|
||||
|
||||
/// @brief Null-pointer to represent no actual waveform-representation
|
||||
static constexpr WaveForm_t *pNoWave = nullptr;
|
||||
|
||||
/// @brief Default implemented Waveform with no profile
|
||||
static const constexpr WaveForm_t *emptyWave = &EmptyWave;
|
||||
};
|
||||
using Macro = std::vector<Macro_t>;
|
||||
|
||||
/// @brief Dark - Nothing to see here
|
||||
extern const Macro macDark;
|
||||
/// @brief Continuous idle
|
||||
extern const Macro macIdle;
|
||||
/// @brief Continuous flicker
|
||||
extern const Macro macStartFlicker;
|
||||
/// @brief Smooth turn on and then remaining idle
|
||||
extern const Macro macStartIdle;
|
||||
/// @brief Smooth turn on to full color
|
||||
extern const Macro macStartFull;
|
||||
/// @brief Slow pulse starting from idle intensity. Appears like breathing
|
||||
extern const Macro macStdPulse;
|
||||
/// @brief Short pulses starting from idle intensity. Appears nervously.
|
||||
extern const Macro macNervousPulse;
|
||||
|
||||
} // namespace Effect
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file EffectProcessor.h
|
||||
* @author Gustice
|
||||
* @brief Effect-Processor-Class for processing effect scenarios and switching actions
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "Macro.hpp"
|
||||
#include "StateMachine.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Effect {
|
||||
|
||||
/**
|
||||
* @brief EffectProcessor Class
|
||||
* @details Maintains State-Machines, Processes effect-switching, and invokes generation
|
||||
* of raw data stream for LEDs.
|
||||
* \li If effect scenarios are changed a cross-fading is executed
|
||||
* \li Raw-data-stream for each Color object is generated
|
||||
*/
|
||||
class EffectProcessor {
|
||||
public:
|
||||
///@brief Constructor
|
||||
///@param fadeSteps Steps count for cross fade
|
||||
EffectProcessor(uint8_t const fadeSteps = 8);
|
||||
|
||||
/// @brief Set next effect sequence
|
||||
/// @param sequence reference to sequence that has to be processed next
|
||||
/// @param sColor Start color. Use noColor to start with default color
|
||||
/// @param intens Idle intensity for effect. Use NULL to start with default intensity
|
||||
void setEffect(const Macro &sequence, Color const *sColor = noColor, uint8_t delay = 0, uint8_t intens = gu8_idleIntensity);
|
||||
|
||||
/// @brief Execute step of effect processor
|
||||
/// @return Reference to color result
|
||||
Color tick(void);
|
||||
|
||||
private:
|
||||
StateMachine::Parameter _parameter;
|
||||
std::array<StateMachine, 2> _effectMachines;
|
||||
uint8_t _fadeSteps;
|
||||
uint8_t _fadingCnt;
|
||||
StateMachine *_EffPV;
|
||||
StateMachine *_EffPV_old;
|
||||
|
||||
Color crossFadeColors(Color &cNew, Color &cOld, uint8_t k);
|
||||
EffectProcessor();
|
||||
};
|
||||
|
||||
} // namespace Effect
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file EffectStateMachine.h
|
||||
* @author Gustice
|
||||
* @brief Effect-State-Machine-Class for processing Effect Macros
|
||||
* @version 0.6
|
||||
* @date 2019-10-01
|
||||
*
|
||||
* @copyright Copyright (c) 2019
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "Macro.hpp"
|
||||
#include <cstdint>
|
||||
#include "ExactIndex.hpp"
|
||||
|
||||
namespace Effect {
|
||||
|
||||
/**
|
||||
* @brief Effect State Machine Class
|
||||
* @details Processes Effect macro array Macro entry subsequently
|
||||
* Processing is executed in following manner:
|
||||
* \li Index-incrementing each Tick
|
||||
* \li ticks until duration \ref EffMacro is finished
|
||||
* \li each tick the index incremented by templateLength/duration
|
||||
* \li Repeats-processing
|
||||
* \li Each repeat the tick and the index are set back to start
|
||||
* \li Switches to next Macro enty
|
||||
* \li Next entry is given by 'next' index
|
||||
* \li Color changes can be executed optionally
|
||||
*/
|
||||
class StateMachine {
|
||||
public:
|
||||
/// @brief Collection of object configuration at startup
|
||||
struct Parameter {
|
||||
/// @brief Idle intensity as background color
|
||||
uint8_t idleIntens;
|
||||
/// @brief dynamic range as variation around background color
|
||||
uint8_t dynamicRange;
|
||||
/// @brief Fade steps for color changes
|
||||
uint8_t fadeSteps;
|
||||
/// @brief Count of target LEDs
|
||||
uint8_t targetCount;
|
||||
};
|
||||
|
||||
///@brief Construct a new Effect State Machine object
|
||||
///@param templateLength Length of waveforms that are used to display
|
||||
StateMachine(Parameter ¶meter);
|
||||
|
||||
///@brief Sets the effect state machine to process given effect macro
|
||||
///@param sequence reference to sequence
|
||||
///@param startColor Start color. Use noColor to invoke with default color
|
||||
///@param initialDelay Number of steps that are waited before effect is started
|
||||
void setEffect(const Macro &sequence, Color const *startColor = noColor, uint8_t initialDelay = 0);
|
||||
|
||||
/// @brief Sets the effect state machine to process given effect macro
|
||||
/// @param sequence reference to sequence
|
||||
/// @param startColor Start color. Use noColor to invoke with default color
|
||||
/// @param intens Idle intensity for effect. Use nullptr to start with default intensity
|
||||
/// @param delayedStart Number of steps that are waited before effect is started
|
||||
void setEffect(const Macro &sequence, Color const *startColor, const uint8_t *intens,
|
||||
const uint8_t delayedStart);
|
||||
|
||||
/// @brief Execute step of state machine
|
||||
/// @details Each tick the tick variable is decremented. After the limit is reached,
|
||||
/// the current macro line is either repeated or the next macro line is started (with
|
||||
/// an optional color change).\n
|
||||
/// @note Tick must be called regularly. For standard light applications all 40 ms seems to be
|
||||
/// a convenient values.
|
||||
/// @return Color const* Reference to color result
|
||||
virtual Color tick(void);
|
||||
|
||||
/// Black out lights
|
||||
static Color UpdateBlank(StepProcessVars &pcsParam);
|
||||
/// Continuous illumination in idle intensity
|
||||
static Color UpdateIdle(StepProcessVars &pcsParam);
|
||||
/// Keep latest state on hold
|
||||
static Color UpdateFreeze(StepProcessVars &pcsParam);
|
||||
/// Step through a defined waveform
|
||||
static Color UpdateWave(StepProcessVars &pcsParam);
|
||||
/// Step through a defined waveform backwards
|
||||
static Color UpdateRevWave(StepProcessVars &pcsParam);
|
||||
/// Show flicker effect with idle intensity as static part with dynamic flicker-range
|
||||
static Color UpdateFlicker(StepProcessVars &pcsParam);
|
||||
|
||||
protected:
|
||||
/// Collection of process values to maintain processing state machine
|
||||
struct ProcessValues {
|
||||
/// Decrementing tick, counting duration
|
||||
uint8_t tick;
|
||||
/// Decrementing repeats of current Effect-part
|
||||
uint8_t repeats;
|
||||
/// Index to macro element
|
||||
uint8_t macroIdx;
|
||||
/// Current index to waveform
|
||||
uint16_t waveIdx;
|
||||
/// Index step each tick according to duration and template length.
|
||||
uint16_t waveStep;
|
||||
};
|
||||
|
||||
/// @brief Concentrated parameter values of instance
|
||||
Parameter &_params;
|
||||
|
||||
Color const * _curentColor;
|
||||
ProcessValues _prcValues;
|
||||
void SetIndexes(void);
|
||||
|
||||
Macro const *_p_effSeq;
|
||||
Macro_t const *_p_effMac;
|
||||
ExactIndex _idx;
|
||||
|
||||
// Color& (*apF_Effects)(StateMachine * SM);
|
||||
typedef Color const *pEffPrc(StateMachine *);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Effect
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file WaveForm.h
|
||||
* @author Gustice
|
||||
* @brief C++ encapsulated waveform definition
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Waveforms.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace Effect {
|
||||
|
||||
/**
|
||||
* @brief Waveform definition based on c-definitions
|
||||
*/
|
||||
struct WaveForm_t {
|
||||
/// @brief Reference to waveform
|
||||
const uint8_t *const pWave;
|
||||
/// @brief Length of waveform
|
||||
const unsigned Length;
|
||||
};
|
||||
|
||||
/// @brief Empty waveform with defined pointer to meaningless data to avoid problems
|
||||
extern const WaveForm_t EmptyWave;
|
||||
|
||||
} // namespace Effect
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file EffectWaveforms.h
|
||||
* @author Gustice
|
||||
* @brief Predefined Waveforms that can be put together to a complex Waveform
|
||||
* @version 0.6
|
||||
* @date 2019-10-01
|
||||
*
|
||||
* @copyright Copyright (c) 2019
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Effect {
|
||||
|
||||
/// Length of all subsequent Template definitions
|
||||
extern const uint16_t cu16_TemplateLength;
|
||||
/// Idle intensity for Slopes and Pulses
|
||||
extern const uint8_t gu8_idleIntensity;
|
||||
/// Idle intensity for Slopes and Pulses
|
||||
extern const uint8_t gu8_fullIntensity;
|
||||
/// Headroom for Effects on top of idle brightness
|
||||
extern const uint8_t gu8_dynamicRange;
|
||||
/// Standard cross fade steps
|
||||
extern const uint8_t gu8_fadeSteps;
|
||||
|
||||
/// Starts from idle \ref gu8_idleIntensity and represents a gaussian impulse \ref gu8_fullIntensity
|
||||
extern const uint8_t gau8_offsetPulse[];
|
||||
/// Starts at zero and rises to idle intensity \ref gu8_idleIntensity
|
||||
extern const uint8_t gau8_initSlope[];
|
||||
/// Starts from idle \ref gu8_idleIntensity and rises up to full intensity \ref gu8_fullIntensity
|
||||
extern const uint8_t gau8_offsetSlope[];
|
||||
/// Starts at zero and rises to full intensity \ref gu8_fullIntensity
|
||||
extern const uint8_t gau8_fullSlope[];
|
||||
/// Starts at zero and represents a gaussian impulse to full intensity \ref gu8_fullIntensity
|
||||
extern const uint8_t gau8_fullPulse[];
|
||||
|
||||
} // namespace Effect
|
||||
Reference in New Issue
Block a user