Add the WS2812FX pattern library.

This commit is contained in:
Brian Bulkowski
2020-09-11 17:59:14 -07:00
parent 09f76c33c6
commit 62e078bbed
11 changed files with 6164 additions and 22 deletions

View File

@ -1,4 +1,4 @@
# FastLED-idf
# FastLED-idf & Patterns
# TL;DR
@ -8,6 +8,8 @@ MASSIVE UPDATE Sept 4, 2020. Even after porting Sam Guyer's branch in July, I st
had a huge amount of visual artifacts. I've done a huge analysis and have licked the issue to my
satisfaction, and can say the system simply doesn't glitch.
UPDATE 2 Sept 11, 2020. Added the WS2812FX pattern library, see below.
There are some new tunables, and if you're also fighting glitches, you need to read `components/FastLED-idf/ESP-IDF.md`.
Note you must use the ESP-IDF environment, and the ESP-IDF build system. That's how the paths and whatnot are created.
@ -45,6 +47,12 @@ changing the duty cycle and brightness, it doesn't control color-controlled LEDs
Thus, we need FastLED
# WS8212FX
Playing around, there are "a lot of nice libraries on FastLED", but each and every one of them
requires porting. At least, now there's a single one to start with. See the underlying component,
and use it or not. If you don't want it, just don't bring that component over into your project.
# TL;DR about this repo
As with any ESP-IDF project, there is a sdkconfig file. It contains things that might
@ -57,9 +65,9 @@ contradictory, the one in this repo matches "current" master, with a 4.0, 4.1, a
If you'd like to test my starting point, copy the correct one over to sdkconfig and
give it a try.
I've read scary stuff about Rev0 and GPIO. You have to insert a number of NOP statements
between bangs of the pins. If you're using that version, you might want to look carefully
into the issue.
For master, either use the standard `sdkconfig` or build your own. Remove this one,
and `idf.py menuconfig`, and set whatever paramenters you need. There is
nothing in this library that's specific to any particular version.
# a note about level shifting
@ -117,7 +125,7 @@ and the RMT interface doesn't do that. What does do that is the SPI
interface, and I don't think I've wired that up.
There are two hardware SPI ports in the system, so that should be
able to be enabled. I haven't tried that.
able to be enabled. Work to do.
Since hardware banging is used ( that's the big ugly warning ),
these LEDs are very likely far slower, and probably do not respond to parallelism
@ -226,12 +234,13 @@ In their forums, they said they don't intend to do anything like that.
According to a reddit post, someone named Sam Guyer fixed the issues with FastLED. There are
a number of fundamental problems that Sam has been gnawing on, notably the access to flash
that happens when you 'read files'.
that happens when you 'read files'. His fork was my starting point.
However, Sam found the truely important thing: that the built-in interrupt handler
wasn't working, because the use of templates obscured the IRAM_ATTR attribute. Which
means the "fast interrupt routing" to shovel bits into RMT was running out of executable
flash, not out of RAM, so of course it wouldn't keep up.
However, I found that the primarily issue with visual artifacts in RMT had to do with
the amount of ESP-IDF jitter.
Kudos to Sam for getting the code to a better point, where it was amenable to the optimizations
I did.
https://github.com/samguyer/FastLED

View File

@ -1,6 +1,11 @@
#ifndef __INC_LIB8TION_H
#define __INC_LIB8TION_H
/* defines get_millis() */
#include "freertos/FreeRTOS.h"
#include "esp_timer.h"
#include "FastLED.h"
#ifndef __INC_LED_SYSDEFS_H
@ -915,16 +920,13 @@ typedef q<uint16_t, 12,4> q124;
// need to provide a function with this signature:
// uint32_t get_millisecond_timer();
// that provides similar functionality.
// You can also force use of the get_millisecond_timer function
// by #defining USE_GET_MILLISECOND_TIMER.
#if (defined(ARDUINO) || defined(SPARK) || defined(FASTLED_HAS_MILLIS)) && !defined(USE_GET_MILLISECOND_TIMER)
// Forward declaration of Arduino function 'millis'.
//uint32_t millis();
#define GET_MILLIS millis
#else
uint32_t get_millisecond_timer();
#define GET_MILLIS get_millisecond_timer
#endif
//
// On ESP-IDF we have esp_timer_get_time which has microseconds.
// It's a little expensive to get micros and divide, but.... good for now and later we'll
// fix that uses it
#define GET_MILLIS() (get_millisecond_timer())
static inline uint32_t get_millisecond_timer() { return( esp_timer_get_time() / 1000); }
// beat16 generates a 16-bit 'sawtooth' wave at a given BPM,
/// with BPM specified in Q8.8 fixed-point format; e.g.

View File

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.5)
set(srcs
"FX.cpp"
"FX_fcn.cpp"
)
# everything needs the ESP32 flag, not sure why this won't work
# going to hack by adding the ESP32 define in the h file
#`target_compile_options(${COMPONENT_LIB} PRIVATE "-DESP32")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "."
REQUIRES FastLED-idf )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,746 @@
/*
WS2812FX.h - Library for WS2812 LED effects.
Harm Aldick - 2016
www.aldick.org
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to dealf
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Modified for WLED
*/
#ifndef WS2812FX_h
#define WS2812FX_h
#define USE_GET_MILLISECOND_TIMER
#include "FastLED.h"
// byte exists as std::byte, but that's not included here
typedef uint8_t byte;
#define DEFAULT_BRIGHTNESS (uint8_t)127
#define DEFAULT_MODE (uint8_t)0
#define DEFAULT_SPEED (uint8_t)128
#define DEFAULT_COLOR (uint32_t)0xFFAA00
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
// the arduino 'map' has nothing to do with std::map :-/
#define ArduinoMap(v, s1, e1, s2, e2) \
( s2 + (e2 - s2) * ((v - s1) / (e1 - s1) ) )
#define ArduinoConstrain(amt,low,high) \
((amt) < (low) ? (low) : ( (amt)>(high) ? (high) : (amt) ) )
#define ArduinoBitRead(value, bit) \
(((value) >> (bit)) & 0x01)
#define ArduinoBitSet(value, bit) \
((value) |= (1UL << (bit)))
#define ArduinoBitClear(value, bit) \
((value) &= ~(1UL << (bit)))
#define ArduinoBitWrite(value, bit, bitvalue) \
( bitvalue ? ArduinoBitSet(value, bit) : ArduinoBitClear(value, bit) )
uint32_t getColorCode(const CRGB &c);
/* Not used in all effects yet */
#define FX_FPS 42
#define FRAMETIME (1000/FX_FPS)
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#define MAX_NUM_SEGMENTS 10
/* How much data bytes all segments combined may allocate */
#ifdef ESP8266
#define MAX_SEGMENT_DATA 2048
#else
#define MAX_SEGMENT_DATA 8192
#endif
#define LED_SKIP_AMOUNT 1
#define MIN_SHOW_DELAY 15
#define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT _segments[_segment_index]
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
#define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength
#define SEGACT SEGMENT.stop
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
// some common colors
#define RED (uint32_t)0xFF0000
#define GREEN (uint32_t)0x00FF00
#define BLUE (uint32_t)0x0000FF
#define WHITE (uint32_t)0xFFFFFF
#define BLACK (uint32_t)0x000000
#define YELLOW (uint32_t)0xFFFF00
#define CYAN (uint32_t)0x00FFFF
#define MAGENTA (uint32_t)0xFF00FF
#define PURPLE (uint32_t)0x400080
#define ORANGE (uint32_t)0xFF3000
#define PINK (uint32_t)0xFF1493
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
// options
// bit 7: segment is in transition mode
// bits 4-6: TBD
// bit 3: mirror effect within segment
// bit 2: segment is on
// bit 1: reverse segment
// bit 0: segment is selected
#define NO_OPTIONS (uint8_t)0x00
#define TRANSITIONAL (uint8_t)0x80
#define MIRROR (uint8_t)0x08
#define SEGMENT_ON (uint8_t)0x04
#define REVERSE (uint8_t)0x02
#define SELECTED (uint8_t)0x01
#define IS_TRANSITIONAL ((SEGMENT.options & TRANSITIONAL) == TRANSITIONAL)
#define IS_MIRROR ((SEGMENT.options & MIRROR ) == MIRROR )
#define IS_SEGMENT_ON ((SEGMENT.options & SEGMENT_ON ) == SEGMENT_ON )
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
#define MODE_COUNT 113
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
#define FX_MODE_BREATH 2
#define FX_MODE_COLOR_WIPE 3
#define FX_MODE_COLOR_WIPE_RANDOM 4
#define FX_MODE_RANDOM_COLOR 5
#define FX_MODE_COLOR_SWEEP 6
#define FX_MODE_DYNAMIC 7
#define FX_MODE_RAINBOW 8
#define FX_MODE_RAINBOW_CYCLE 9
#define FX_MODE_SCAN 10
#define FX_MODE_DUAL_SCAN 11
#define FX_MODE_FADE 12
#define FX_MODE_THEATER_CHASE 13
#define FX_MODE_THEATER_CHASE_RAINBOW 14
#define FX_MODE_RUNNING_LIGHTS 15
#define FX_MODE_SAW 16
#define FX_MODE_TWINKLE 17
#define FX_MODE_DISSOLVE 18
#define FX_MODE_DISSOLVE_RANDOM 19
#define FX_MODE_SPARKLE 20
#define FX_MODE_FLASH_SPARKLE 21
#define FX_MODE_HYPER_SPARKLE 22
#define FX_MODE_STROBE 23
#define FX_MODE_STROBE_RAINBOW 24
#define FX_MODE_MULTI_STROBE 25
#define FX_MODE_BLINK_RAINBOW 26
#define FX_MODE_ANDROID 27
#define FX_MODE_CHASE_COLOR 28
#define FX_MODE_CHASE_RANDOM 29
#define FX_MODE_CHASE_RAINBOW 30
#define FX_MODE_CHASE_FLASH 31
#define FX_MODE_CHASE_FLASH_RANDOM 32
#define FX_MODE_CHASE_RAINBOW_WHITE 33
#define FX_MODE_COLORFUL 34
#define FX_MODE_TRAFFIC_LIGHT 35
#define FX_MODE_COLOR_SWEEP_RANDOM 36
#define FX_MODE_RUNNING_COLOR 37
#define FX_MODE_RUNNING_RED_BLUE 38
#define FX_MODE_RUNNING_RANDOM 39
#define FX_MODE_LARSON_SCANNER 40
#define FX_MODE_COMET 41
#define FX_MODE_FIREWORKS 42
#define FX_MODE_RAIN 43
#define FX_MODE_MERRY_CHRISTMAS 44
#define FX_MODE_FIRE_FLICKER 45
#define FX_MODE_GRADIENT 46
#define FX_MODE_LOADING 47
#define FX_MODE_POLICE 48
#define FX_MODE_POLICE_ALL 49
#define FX_MODE_TWO_DOTS 50
#define FX_MODE_TWO_AREAS 51
#define FX_MODE_CIRCUS_COMBUSTUS 52
#define FX_MODE_HALLOWEEN 53
#define FX_MODE_TRICOLOR_CHASE 54
#define FX_MODE_TRICOLOR_WIPE 55
#define FX_MODE_TRICOLOR_FADE 56
#define FX_MODE_LIGHTNING 57
#define FX_MODE_ICU 58
#define FX_MODE_MULTI_COMET 59
#define FX_MODE_DUAL_LARSON_SCANNER 60
#define FX_MODE_RANDOM_CHASE 61
#define FX_MODE_OSCILLATE 62
#define FX_MODE_PRIDE_2015 63
#define FX_MODE_JUGGLE 64
#define FX_MODE_PALETTE 65
#define FX_MODE_FIRE_2012 66
#define FX_MODE_COLORWAVES 67
#define FX_MODE_BPM 68
#define FX_MODE_FILLNOISE8 69
#define FX_MODE_NOISE16_1 70
#define FX_MODE_NOISE16_2 71
#define FX_MODE_NOISE16_3 72
#define FX_MODE_NOISE16_4 73
#define FX_MODE_COLORTWINKLE 74
#define FX_MODE_LAKE 75
#define FX_MODE_METEOR 76
#define FX_MODE_METEOR_SMOOTH 77
#define FX_MODE_RAILWAY 78
#define FX_MODE_RIPPLE 79
#define FX_MODE_TWINKLEFOX 80
#define FX_MODE_TWINKLECAT 81
#define FX_MODE_HALLOWEEN_EYES 82
#define FX_MODE_STATIC_PATTERN 83
#define FX_MODE_TRI_STATIC_PATTERN 84
#define FX_MODE_SPOTS 85
#define FX_MODE_SPOTS_FADE 86
#define FX_MODE_GLITTER 87
#define FX_MODE_CANDLE 88
#define FX_MODE_STARBURST 89
#define FX_MODE_EXPLODING_FIREWORKS 90
#define FX_MODE_BOUNCINGBALLS 91
#define FX_MODE_SINELON 92
#define FX_MODE_SINELON_DUAL 93
#define FX_MODE_SINELON_RAINBOW 94
#define FX_MODE_POPCORN 95
#define FX_MODE_DRIP 96
#define FX_MODE_PLASMA 97
#define FX_MODE_PERCENT 98
#define FX_MODE_RIPPLE_RAINBOW 99
#define FX_MODE_HEARTBEAT 100
#define FX_MODE_PACIFICA 101
#define FX_MODE_CANDLE_MULTI 102
#define FX_MODE_SOLID_GLITTER 103
#define FX_MODE_SUNRISE 104
#define FX_MODE_PHASED 105
#define FX_MODE_TWINKLEUP 106
#define FX_MODE_NOISEPAL 107
#define FX_MODE_SINEWAVE 108
#define FX_MODE_PHASEDNOISE 109
#define FX_MODE_FLOW 110
#define FX_MODE_CHUNCHUN 111
#define FX_MODE_DANCING_SHADOWS 112
class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
// pre show callback
typedef void (*show_callback) (void);
// segment parameters
public:
typedef struct Segment { // 24 bytes
uint16_t start;
uint16_t stop; //segment invalid if stop == 0
uint8_t speed;
uint8_t intensity;
uint8_t palette;
uint8_t mode;
uint8_t options; //bit pattern: msb first: transitional needspixelstate tbd tbd (paused) on reverse selected
uint8_t grouping, spacing;
uint8_t opacity;
uint32_t colors[NUM_COLORS];
void setOption(uint8_t n, bool val)
{
if (val) {
options |= 0x01 << n;
} else
{
options &= ~(0x01 << n);
}
}
bool getOption(uint8_t n)
{
return ((options >> n) & 0x01);
}
bool isSelected()
{
return getOption(0);
}
bool isActive()
{
return stop > start;
}
uint16_t length()
{
return stop - start;
}
uint16_t groupLength()
{
return grouping + spacing;
}
uint16_t virtualLength()
{
uint16_t groupLen = groupLength();
uint16_t vLength = (length() + groupLen - 1) / groupLen;
if (options & MIRROR)
vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vLength;
}
} segment;
// segment runtime parameters
typedef struct Segment_runtime { // 28 bytes
unsigned long next_time;
uint32_t step;
uint32_t call;
uint16_t aux0;
uint16_t aux1;
// what is data? patterns often want a byte of per-pixel data, although they don't need it
uint8_t * data = nullptr;
bool allocateData(uint16_t len){
if (data && _dataLen == len) return true; //already allocated
deallocateData();
if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
data = (uint8_t *) malloc((size_t)len); // don't need nothrow, really
if (!data) return false; //allocation failed
WS2812FX::_usedSegmentData += len;
_dataLen = len;
memset(data, 0, len);
return true;
}
void deallocateData(){
delete[] data;
data = nullptr;
WS2812FX::_usedSegmentData -= _dataLen;
_dataLen = 0;
}
void reset(){next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; deallocateData();}
private:
uint16_t _dataLen = 0;
} segment_runtime;
WS2812FX() {
//assign each member of the _mode[] array to its respective function reference
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
_mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe;
_mode[FX_MODE_COLOR_WIPE_RANDOM] = &WS2812FX::mode_color_wipe_random;
_mode[FX_MODE_RANDOM_COLOR] = &WS2812FX::mode_random_color;
_mode[FX_MODE_COLOR_SWEEP] = &WS2812FX::mode_color_sweep;
_mode[FX_MODE_DYNAMIC] = &WS2812FX::mode_dynamic;
_mode[FX_MODE_RAINBOW] = &WS2812FX::mode_rainbow;
_mode[FX_MODE_RAINBOW_CYCLE] = &WS2812FX::mode_rainbow_cycle;
_mode[FX_MODE_SCAN] = &WS2812FX::mode_scan;
_mode[FX_MODE_DUAL_SCAN] = &WS2812FX::mode_dual_scan;
_mode[FX_MODE_FADE] = &WS2812FX::mode_fade;
_mode[FX_MODE_THEATER_CHASE] = &WS2812FX::mode_theater_chase;
_mode[FX_MODE_THEATER_CHASE_RAINBOW] = &WS2812FX::mode_theater_chase_rainbow;
_mode[FX_MODE_SAW] = &WS2812FX::mode_saw;
_mode[FX_MODE_TWINKLE] = &WS2812FX::mode_twinkle;
_mode[FX_MODE_DISSOLVE] = &WS2812FX::mode_dissolve;
_mode[FX_MODE_DISSOLVE_RANDOM] = &WS2812FX::mode_dissolve_random;
_mode[FX_MODE_SPARKLE] = &WS2812FX::mode_sparkle;
_mode[FX_MODE_FLASH_SPARKLE] = &WS2812FX::mode_flash_sparkle;
_mode[FX_MODE_HYPER_SPARKLE] = &WS2812FX::mode_hyper_sparkle;
_mode[FX_MODE_STROBE] = &WS2812FX::mode_strobe;
_mode[FX_MODE_STROBE_RAINBOW] = &WS2812FX::mode_strobe_rainbow;
_mode[FX_MODE_MULTI_STROBE] = &WS2812FX::mode_multi_strobe;
_mode[FX_MODE_BLINK_RAINBOW] = &WS2812FX::mode_blink_rainbow;
_mode[FX_MODE_ANDROID] = &WS2812FX::mode_android;
_mode[FX_MODE_CHASE_COLOR] = &WS2812FX::mode_chase_color;
_mode[FX_MODE_CHASE_RANDOM] = &WS2812FX::mode_chase_random;
_mode[FX_MODE_CHASE_RAINBOW] = &WS2812FX::mode_chase_rainbow;
_mode[FX_MODE_CHASE_FLASH] = &WS2812FX::mode_chase_flash;
_mode[FX_MODE_CHASE_FLASH_RANDOM] = &WS2812FX::mode_chase_flash_random;
_mode[FX_MODE_CHASE_RAINBOW_WHITE] = &WS2812FX::mode_chase_rainbow_white;
_mode[FX_MODE_COLORFUL] = &WS2812FX::mode_colorful;
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
_mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue;
_mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
_mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks;
_mode[FX_MODE_RAIN] = &WS2812FX::mode_rain;
_mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas;
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
_mode[FX_MODE_LOADING] = &WS2812FX::mode_loading;
_mode[FX_MODE_POLICE] = &WS2812FX::mode_police;
_mode[FX_MODE_POLICE_ALL] = &WS2812FX::mode_police_all;
_mode[FX_MODE_TWO_DOTS] = &WS2812FX::mode_two_dots;
_mode[FX_MODE_TWO_AREAS] = &WS2812FX::mode_two_areas;
_mode[FX_MODE_CIRCUS_COMBUSTUS] = &WS2812FX::mode_circus_combustus;
_mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween;
_mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase;
_mode[FX_MODE_TRICOLOR_WIPE] = &WS2812FX::mode_tricolor_wipe;
_mode[FX_MODE_TRICOLOR_FADE] = &WS2812FX::mode_tricolor_fade;
_mode[FX_MODE_BREATH] = &WS2812FX::mode_breath;
_mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_running_lights;
_mode[FX_MODE_LIGHTNING] = &WS2812FX::mode_lightning;
_mode[FX_MODE_ICU] = &WS2812FX::mode_icu;
_mode[FX_MODE_MULTI_COMET] = &WS2812FX::mode_multi_comet;
_mode[FX_MODE_DUAL_LARSON_SCANNER] = &WS2812FX::mode_dual_larson_scanner;
_mode[FX_MODE_RANDOM_CHASE] = &WS2812FX::mode_random_chase;
_mode[FX_MODE_OSCILLATE] = &WS2812FX::mode_oscillate;
_mode[FX_MODE_FIRE_2012] = &WS2812FX::mode_fire_2012;
_mode[FX_MODE_PRIDE_2015] = &WS2812FX::mode_pride_2015;
_mode[FX_MODE_BPM] = &WS2812FX::mode_bpm;
_mode[FX_MODE_JUGGLE] = &WS2812FX::mode_juggle;
_mode[FX_MODE_PALETTE] = &WS2812FX::mode_palette;
_mode[FX_MODE_COLORWAVES] = &WS2812FX::mode_colorwaves;
_mode[FX_MODE_FILLNOISE8] = &WS2812FX::mode_fillnoise8;
_mode[FX_MODE_NOISE16_1] = &WS2812FX::mode_noise16_1;
_mode[FX_MODE_NOISE16_2] = &WS2812FX::mode_noise16_2;
_mode[FX_MODE_NOISE16_3] = &WS2812FX::mode_noise16_3;
_mode[FX_MODE_NOISE16_4] = &WS2812FX::mode_noise16_4;
_mode[FX_MODE_COLORTWINKLE] = &WS2812FX::mode_colortwinkle;
_mode[FX_MODE_LAKE] = &WS2812FX::mode_lake;
_mode[FX_MODE_METEOR] = &WS2812FX::mode_meteor;
_mode[FX_MODE_METEOR_SMOOTH] = &WS2812FX::mode_meteor_smooth;
_mode[FX_MODE_RAILWAY] = &WS2812FX::mode_railway;
_mode[FX_MODE_RIPPLE] = &WS2812FX::mode_ripple;
_mode[FX_MODE_TWINKLEFOX] = &WS2812FX::mode_twinklefox;
_mode[FX_MODE_TWINKLECAT] = &WS2812FX::mode_twinklecat;
_mode[FX_MODE_HALLOWEEN_EYES] = &WS2812FX::mode_halloween_eyes;
_mode[FX_MODE_STATIC_PATTERN] = &WS2812FX::mode_static_pattern;
_mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern;
_mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots;
_mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade;
_mode[FX_MODE_GLITTER] = &WS2812FX::mode_glitter;
_mode[FX_MODE_CANDLE] = &WS2812FX::mode_candle;
_mode[FX_MODE_STARBURST] = &WS2812FX::mode_starburst;
_mode[FX_MODE_EXPLODING_FIREWORKS] = &WS2812FX::mode_exploding_fireworks;
_mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_bouncing_balls;
_mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon;
_mode[FX_MODE_SINELON_DUAL] = &WS2812FX::mode_sinelon_dual;
_mode[FX_MODE_SINELON_RAINBOW] = &WS2812FX::mode_sinelon_rainbow;
_mode[FX_MODE_POPCORN] = &WS2812FX::mode_popcorn;
_mode[FX_MODE_DRIP] = &WS2812FX::mode_drip;
_mode[FX_MODE_PLASMA] = &WS2812FX::mode_plasma;
_mode[FX_MODE_PERCENT] = &WS2812FX::mode_percent;
_mode[FX_MODE_RIPPLE_RAINBOW] = &WS2812FX::mode_ripple_rainbow;
_mode[FX_MODE_HEARTBEAT] = &WS2812FX::mode_heartbeat;
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
_mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter;
_mode[FX_MODE_SUNRISE] = &WS2812FX::mode_sunrise;
_mode[FX_MODE_PHASED] = &WS2812FX::mode_phased;
_mode[FX_MODE_TWINKLEUP] = &WS2812FX::mode_twinkleup;
_mode[FX_MODE_NOISEPAL] = &WS2812FX::mode_noisepal;
_mode[FX_MODE_SINEWAVE] = &WS2812FX::mode_sinewave;
_mode[FX_MODE_PHASEDNOISE] = &WS2812FX::mode_phased_noise;
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
_mode[FX_MODE_DANCING_SHADOWS] = &WS2812FX::mode_dancing_shadows;
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
targetPalette = CloudColors_p;
ablMilliampsMax = 850;
currentMilliamps = 0;
timebase = 0;
resetSegments();
}
void
init(uint16_t countPixels, CRGB *leds, bool skipFirst),
service(void),
blur(uint8_t),
fill(uint32_t),
fade_out(uint8_t r),
setMode(uint8_t segid, uint8_t m),
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b),
setColor(uint8_t slot, uint32_t c),
setBrightness(uint8_t b),
setRange(uint16_t i, uint16_t i2, uint32_t col),
setShowCallback(show_callback cb),
setTransitionMode(bool t),
trigger(void),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
resetSegments(),
setPixelColor(uint16_t n, uint32_t c),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
show(void),
setRgbwPwm(void),
setPixelSegment(uint8_t n);
bool
reverseMode = false, //is the entire LED strip reversed?
gammaCorrectBri = false,
gammaCorrectCol = true,
applyToAllSelected = true,
segmentsAreIdentical(Segment* a, Segment* b),
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p);
uint8_t
mainSegment = 0,
paletteFade = 0,
paletteBlend = 0,
colorOrder = 0,
milliampsPerLed = 55,
getBrightness(void),
getMode(void),
getSpeed(void),
getModeCount(void),
getPaletteCount(void),
getMaxSegments(void),
getFirstSelectedSegment(void),
getMainSegmentId(void),
gamma8(uint8_t),
get_random_wheel_index(uint8_t);
uint16_t
ablMilliampsMax,
currentMilliamps,
triwave16(uint16_t);
uint32_t
now,
timebase,
color_wheel(uint8_t),
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
color_blend(uint32_t,uint32_t,uint8_t),
gamma32(uint32_t),
getLastShow(void),
getPixelColor(uint16_t),
getColor(void);
WS2812FX::Segment&
getSegment(uint8_t n);
WS2812FX::Segment_runtime
getSegmentRuntime(void);
WS2812FX::Segment*
getSegments(void);
// builtin modes
uint16_t
mode_static(void),
mode_blink(void),
mode_blink_rainbow(void),
mode_strobe(void),
mode_strobe_rainbow(void),
mode_color_wipe(void),
mode_color_sweep(void),
mode_color_wipe_random(void),
mode_color_sweep_random(void),
mode_random_color(void),
mode_dynamic(void),
mode_breath(void),
mode_fade(void),
mode_scan(void),
mode_dual_scan(void),
mode_theater_chase(void),
mode_theater_chase_rainbow(void),
mode_rainbow(void),
mode_rainbow_cycle(void),
mode_running_lights(void),
mode_saw(void),
mode_twinkle(void),
mode_dissolve(void),
mode_dissolve_random(void),
mode_sparkle(void),
mode_flash_sparkle(void),
mode_hyper_sparkle(void),
mode_multi_strobe(void),
mode_android(void),
mode_chase_color(void),
mode_chase_random(void),
mode_chase_rainbow(void),
mode_chase_flash(void),
mode_chase_flash_random(void),
mode_chase_rainbow_white(void),
mode_colorful(void),
mode_traffic_light(void),
mode_running_color(void),
mode_running_red_blue(void),
mode_running_random(void),
mode_larson_scanner(void),
mode_comet(void),
mode_fireworks(void),
mode_rain(void),
mode_merry_christmas(void),
mode_halloween(void),
mode_fire_flicker(void),
mode_gradient(void),
mode_loading(void),
mode_police(void),
mode_police_all(void),
mode_two_dots(void),
mode_two_areas(void),
mode_circus_combustus(void),
mode_bicolor_chase(void),
mode_tricolor_chase(void),
mode_tricolor_wipe(void),
mode_tricolor_fade(void),
mode_lightning(void),
mode_icu(void),
mode_multi_comet(void),
mode_dual_larson_scanner(void),
mode_random_chase(void),
mode_oscillate(void),
mode_fire_2012(void),
mode_pride_2015(void),
mode_bpm(void),
mode_juggle(void),
mode_palette(void),
mode_colorwaves(void),
mode_fillnoise8(void),
mode_noise16_1(void),
mode_noise16_2(void),
mode_noise16_3(void),
mode_noise16_4(void),
mode_colortwinkle(void),
mode_lake(void),
mode_meteor(void),
mode_meteor_smooth(void),
mode_railway(void),
mode_ripple(void),
mode_twinklefox(void),
mode_twinklecat(void),
mode_halloween_eyes(void),
mode_static_pattern(void),
mode_tri_static_pattern(void),
mode_spots(void),
mode_spots_fade(void),
mode_glitter(void),
mode_candle(void),
mode_starburst(void),
mode_exploding_fireworks(void),
mode_bouncing_balls(void),
mode_sinelon(void),
mode_sinelon_dual(void),
mode_sinelon_rainbow(void),
mode_popcorn(void),
mode_drip(void),
mode_plasma(void),
mode_percent(void),
mode_ripple_rainbow(void),
mode_heartbeat(void),
mode_pacifica(void),
mode_candle_multi(void),
mode_solid_glitter(void),
mode_sunrise(void),
mode_phased(void),
mode_twinkleup(void),
mode_noisepal(void),
mode_sinewave(void),
mode_phased_noise(void),
mode_flow(void),
mode_chunchun(void),
mode_dancing_shadows(void);
private:
uint32_t crgb_to_col(CRGB fastled);
CRGB col_to_crgb(uint32_t);
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
CRGB *_leds;
uint16_t _length, _lengthRaw, _virtualSegmentLength;
uint16_t _rand16seed;
uint8_t _brightness;
static uint16_t _usedSegmentData;
void load_gradient_palette(uint8_t);
void handle_palette(void);
bool
_skipFirstMode,
_triggered;
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
show_callback _callback = nullptr;
// mode helper functions
uint16_t
blink(uint32_t, uint32_t, bool strobe, bool),
candle(bool),
color_wipe(bool, bool),
scan(bool),
theater_chase(uint32_t, uint32_t, bool),
running_base(bool),
larson_scanner(bool),
sinelon_base(bool,bool),
dissolve(uint32_t),
chase(uint32_t, uint32_t, uint32_t, bool),
gradient_base(bool),
ripple_base(bool),
police_base(uint32_t, uint32_t, bool),
running(uint32_t, uint32_t),
tricolor_chase(uint32_t, uint32_t),
twinklefox_base(bool),
spots_base(uint16_t),
phased_base(uint8_t);
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend);
uint32_t _lastPaletteChange = 0;
uint32_t _lastShow = 0;
uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99;
segment _segments[MAX_NUM_SEGMENTS] = {
// SRAM footprint: 24 bytes per element
// start, stop, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
};
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
friend class Segment_runtime;
uint16_t realPixelIndex(uint16_t i);
};
//10 names per line
const char JSON_mode_names[] = R"=====([
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
"Flow","Chunchun","Dancing Shadows"
])=====";
const char JSON_palette_names[] = R"=====([
"Default","* Random Cycle","* Color 1","* Colors 1&2","* Color Gradient","* Colors Only","Party","Cloud","Lava","Ocean",
"Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash",
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
"Aurora","Atlantica"
])=====";
//Segment option byte bits
#define SEG_OPTION_SELECTED 0
#define SEG_OPTION_REVERSED 1
#define SEG_OPTION_ON 2
#define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
#define SEG_OPTION_TRANSITIONAL 7
#endif

View File

@ -0,0 +1,899 @@
/*
WS2812FX_fcn.cpp contains all utility functions
Harm Aldick - 2016
www.aldick.org
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Modified heavily for WLED
*/
#include "FX.h"
#include "palettes.h"
//enable custom per-LED mapping. This can allow for better effects on matrices or special displays
//#define WLED_CUSTOM_LED_MAPPING
#ifdef WLED_CUSTOM_LED_MAPPING
//this is just an example (30 LEDs). It will first set all even, then all uneven LEDs.
const uint16_t customMappingTable[] = {
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29};
//another example. Switches direction every 5 LEDs.
/*const uint16_t customMappingTable[] = {
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25};*/
const uint16_t customMappingSize = sizeof(customMappingTable)/sizeof(uint16_t); //30 in example
#endif
void WS2812FX::init( uint16_t countPixels, CRGB *leds, bool skipFirst)
{
if ( countPixels == _length && _skipFirstMode == skipFirst) return;
RESET_RUNTIME;
_length = countPixels;
_leds = leds;
_skipFirstMode = skipFirst;
_lengthRaw = _length;
if (_skipFirstMode) {
_lengthRaw += LED_SKIP_AMOUNT;
}
_segments[0].start = 0;
_segments[0].stop = _length;
setBrightness(_brightness);
}
void WS2812FX::service() {
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
now = nowUp + timebase;
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
bool doShow = false;
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
if (SEGMENT.isActive())
{
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
{
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
doShow = true;
uint16_t delay = FRAMETIME;
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
_virtualSegmentLength = SEGMENT.virtualLength();
handle_palette();
delay = (this->*_mode[SEGMENT.mode])(); //effect function
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
}
SEGENV.next_time = nowUp + delay;
}
}
}
_virtualSegmentLength = 0;
if(doShow) {
yield();
show();
}
_triggered = false;
}
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
uint8_t r = (c >> 16);
uint8_t g = (c >> 8);
uint8_t b = c ;
setPixelColor(n, r, g, b);
}
#define REV(i) (_length - 1 - (i))
//used to map from segment index to physical pixel, taking into account grouping, offsets, reverse and mirroring
uint16_t WS2812FX::realPixelIndex(uint16_t i) {
int16_t iGroup = i * SEGMENT.groupLength();
/* reverse just an individual segment */
int16_t realIndex = iGroup;
if (IS_REVERSE) {
if (IS_MIRROR) {
realIndex = (SEGMENT.length() -1) / 2 - iGroup; //only need to index half the pixels
} else {
realIndex = SEGMENT.length() - iGroup - 1;
}
}
realIndex += SEGMENT.start;
/* Reverse the whole string */
if (reverseMode) realIndex = REV(realIndex);
return realIndex;
}
void WS2812FX::setPixelColor(uint16_t i, uint8_t r, uint8_t g, uint8_t b)
{
// create a color
CRGB col(r, g, b);
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
if (SEGLEN) {//from segment
//color_blend(getpixel, col, SEGMENT.opacity); (pseudocode for future blending of segments)
if (IS_SEGMENT_ON)
{
// fixme: there's a specific multiply operator we should use
if (SEGMENT.opacity < 255) {
col.r = scale8(col.r, SEGMENT.opacity);
col.g = scale8(col.g, SEGMENT.opacity);
col.b = scale8(col.b, SEGMENT.opacity);
}
} else {
col = BLACK;
}
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
bool reversed = reverseMode ^ IS_REVERSE;
uint16_t realIndex = realPixelIndex(i);
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
int16_t indexSet = realIndex + (reversed ? -j : j);
int16_t indexSetRev = indexSet;
if (reverseMode) indexSetRev = REV(indexSet);
#ifdef WLED_CUSTOM_LED_MAPPING
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
#endif
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) {
_leds[indexSet+skip] = col;
if (IS_MIRROR) { //set the corresponding mirrored pixel
if (reverseMode) {
_leds[REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1] = col;
} else {
_leds[SEGMENT.stop - indexSet + skip + SEGMENT.start - 1] = col;
}
}
}
}
} else { //live data, etc.
if (reverseMode) i = REV(i);
#ifdef WLED_CUSTOM_LED_MAPPING
if (i < customMappingSize) i = customMappingTable[i];
#endif
_leds[i + skip] = col;
}
if (skip && i == 0) {
for (uint16_t j = 0; j < skip; j++) {
_leds[j].r = 0; _leds[j].g = 0; _leds[j].b = 0;
}
}
}
//DISCLAIMER
//The following function attemps to calculate the current LED power usage,
//and will limit the brightness to stay below a set amperage threshold.
//It is NOT a measurement and NOT guaranteed to stay within the ablMilliampsMax margin.
//Stay safe with high amperage and have a reasonable safety margin!
//I am NOT to be held liable for burned down garages!
//fine tune power estimation constants for your setup
#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
void WS2812FX::show(void) {
if (_callback) _callback();
//power limit calculation
//each LED can draw up 195075 "power units" (approx. 53mA)
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
//so A=2,R=255,G=0,B=0 would use 510 PU per LED (1mA is about 3700 PU)
bool useWackyWS2815PowerModel = false;
uint8_t actualMilliampsPerLed = milliampsPerLed;
if(milliampsPerLed == 255) {
useWackyWS2815PowerModel = true;
actualMilliampsPerLed = 12; // from testing an actual strip
}
if (ablMilliampsMax > 149 && actualMilliampsPerLed > 0) //0 mA per LED and too low numbers turn off calculation
{
uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed;
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power
if (powerBudget > puPerMilliamp * _length) //each LED uses about 1mA in standby, exclude that from power budget
{
powerBudget -= puPerMilliamp * _length;
} else
{
powerBudget = 0;
}
uint32_t powerSum = 0;
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
{
CRGB c = _leds[i];
if(useWackyWS2815PowerModel)
{
// ignore white component on WS2815 power calculation
powerSum += (MAX(MAX(c.r,c.g),c.b)) * 3;
}
else
{
powerSum += (c.r + c.g + c.b) ;
}
}
uint32_t powerSum0 = powerSum;
powerSum *= _brightness;
if (powerSum > powerBudget) //scale brightness down to stay in current limit
{
float scale = (float)powerBudget / (float)powerSum;
uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
uint8_t newBri = scale8(_brightness, scaleB);
FastLED.setBrightness(newBri);
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
} else
{
currentMilliamps = powerSum / puPerMilliamp;
FastLED.setBrightness(_brightness);
}
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += _length; //add standby power back to estimate
} else {
currentMilliamps = 0;
FastLED.setBrightness(_brightness);
}
FastLED.show();
_lastShow = millis();
}
void WS2812FX::trigger() {
_triggered = true;
}
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
if (segid >= MAX_NUM_SEGMENTS) return;
if (m >= MODE_COUNT) m = MODE_COUNT - 1;
if (_segments[segid].mode != m)
{
_segment_runtimes[segid].reset();
_segments[segid].mode = m;
}
}
uint8_t WS2812FX::getModeCount()
{
return MODE_COUNT;
}
uint8_t WS2812FX::getPaletteCount()
{
return 13 + GRADIENT_PALETTE_COUNT;
}
//TODO transitions
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
uint8_t mainSeg = getMainSegmentId();
Segment& seg = _segments[getMainSegmentId()];
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
bool applied = false;
if (applyToAllSelected)
{
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected())
{
_segments[i].speed = s;
_segments[i].intensity = in;
_segments[i].palette = p;
setMode(i, m);
applied = true;
}
}
}
if (!applyToAllSelected || !applied) {
seg.speed = s;
seg.intensity = in;
seg.palette = p;
setMode(mainSegment, m);
}
if (seg.mode != modePrev || seg.speed != speedPrev || seg.intensity != intensityPrev || seg.palette != palettePrev) return true;
return false;
}
void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b) {
setColor(slot, ((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
}
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
if (slot >= NUM_COLORS) return;
bool applied = false;
if (applyToAllSelected) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected()) _segments[i].colors[slot] = c;
}
}
if (!applyToAllSelected || !applied) {
_segments[getMainSegmentId()].colors[slot] = c;
}
}
void WS2812FX::setBrightness(uint8_t b) {
if (_brightness == b) return;
_brightness = (gammaCorrectBri) ? gamma8(b) : b;
_segment_index = 0;
if (b == 0) { //unfreeze all segments on power off
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
_segments[i].setOption(SEG_OPTION_FREEZE, false);
}
}
if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon
}
uint8_t WS2812FX::getMode(void) {
return _segments[getMainSegmentId()].mode;
}
uint8_t WS2812FX::getSpeed(void) {
return _segments[getMainSegmentId()].speed;
}
uint8_t WS2812FX::getBrightness(void) {
return _brightness;
}
uint8_t WS2812FX::getMaxSegments(void) {
return MAX_NUM_SEGMENTS;
}
/*uint8_t WS2812FX::getFirstSelectedSegment(void)
{
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isActive() && _segments[i].isSelected()) return i;
}
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //if none selected, get first active
{
if (_segments[i].isActive()) return i;
}
return 0;
}*/
uint8_t WS2812FX::getMainSegmentId(void) {
if (mainSegment >= MAX_NUM_SEGMENTS) return 0;
if (_segments[mainSegment].isActive()) return mainSegment;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //get first active
{
if (_segments[i].isActive()) return i;
}
return 0;
}
uint32_t WS2812FX::getColor(void) {
return _segments[getMainSegmentId()].colors[0];
}
uint32_t WS2812FX::getPixelColor(uint16_t i)
{
i = realPixelIndex(i);
#ifdef WLED_CUSTOM_LED_MAPPING
if (i < customMappingSize) i = customMappingTable[i];
#endif
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
if (i >= _lengthRaw) return 0;
return( (_leds[i].r << 24) | (_leds[i].g << 16) | _leds[i].b );
}
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
if (id >= MAX_NUM_SEGMENTS) return _segments[0];
return _segments[id];
}
WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) {
return SEGENV;
}
WS2812FX::Segment* WS2812FX::getSegments(void) {
return _segments;
}
uint32_t WS2812FX::getLastShow(void) {
return _lastShow;
}
/*
** n: which segment
** CRGB - beginning of the RGB array
** --- wtf: what exactly do i1 and i2 mean, if start and stop are already set?
*/
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
if (n >= MAX_NUM_SEGMENTS) return;
Segment& seg = _segments[n];
//return if neither bounds nor grouping have changed
if (seg.start == i1 && seg.stop == i2 && (!grouping || (seg.grouping == grouping && seg.spacing == spacing))) return;
if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off
if (i2 <= i1) //disable segment
{
seg.stop = 0;
if (n == mainSegment) //if main segment is deleted, set first active as main segment
{
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isActive()) {
mainSegment = i;
return;
}
}
mainSegment = 0; //should not happen (always at least one active segment)
}
return;
}
if (i1 < _length) seg.start = i1;
seg.stop = i2;
if (i2 > _length) seg.stop = _length;
if (grouping) {
seg.grouping = grouping;
seg.spacing = spacing;
}
_segment_runtimes[n].reset();
}
void WS2812FX::resetSegments() {
mainSegment = 0;
memset(_segments, 0, sizeof(_segments));
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
_segment_index = 0;
_segments[0].mode = DEFAULT_MODE;
_segments[0].colors[0] = DEFAULT_COLOR;
_segments[0].start = 0;
_segments[0].speed = DEFAULT_SPEED;
_segments[0].stop = _length;
_segments[0].grouping = 1;
_segments[0].setOption(SEG_OPTION_SELECTED, 1);
_segments[0].setOption(SEG_OPTION_ON, 1);
_segments[0].opacity = 255;
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++)
{
_segments[i].colors[0] = color_wheel(i*51);
_segments[i].grouping = 1;
_segments[i].setOption(SEG_OPTION_ON, 1);
_segments[i].opacity = 255;
_segment_runtimes[i].reset();
}
_segment_runtimes[0].reset();
}
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
void WS2812FX::setPixelSegment(uint8_t n)
{
if (n < MAX_NUM_SEGMENTS) {
_segment_index = n;
_virtualSegmentLength = SEGMENT.length();
} else {
_segment_index = 0;
_virtualSegmentLength = 0;
}
}
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
{
if (i2 >= i)
{
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
} else
{
for (uint16_t x = i2; x <= i; x++) setPixelColor(x, col);
}
}
void WS2812FX::setShowCallback(show_callback cb)
{
_callback = cb;
}
void WS2812FX::setTransitionMode(bool t)
{
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
for (uint16_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
SEGMENT.setOption(SEG_OPTION_TRANSITIONAL, t);
if (t && SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
}
}
/*
* color blend function - returns color code
*/
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
if(blend == 0) return color1;
if(blend == 255) return color2;
uint32_t w1 = (color1 >> 24) & 0xff;
uint32_t r1 = (color1 >> 16) & 0xff;
uint32_t g1 = (color1 >> 8) & 0xff;
uint32_t b1 = color1 & 0xff;
uint32_t w2 = (color2 >> 24) & 0xff;
uint32_t r2 = (color2 >> 16) & 0xff;
uint32_t g2 = (color2 >> 8) & 0xff;
uint32_t b2 = color2 & 0xff;
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8;
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8;
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
}
/*
* Fills segment with color
*/
void WS2812FX::fill(uint32_t c) {
for(uint16_t i = 0; i < SEGLEN; i++) {
setPixelColor(i, c);
}
}
/*
* Blends the specified color with the existing pixel color.
*/
void WS2812FX::blendPixelColor(uint16_t n, uint32_t color, uint8_t blend)
{
setPixelColor(n, color_blend(getPixelColor(n), color, blend));
}
/*
* fade out function, higher rate = quicker fade
*/
void WS2812FX::fade_out(uint8_t rate) {
rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1;
uint32_t color = SEGCOLOR(1); // target color
int w2 = (color >> 24) & 0xff;
int r2 = (color >> 16) & 0xff;
int g2 = (color >> 8) & 0xff;
int b2 = color & 0xff;
for(uint16_t i = 0; i < SEGLEN; i++) {
color = getPixelColor(i);
int w1 = (color >> 24) & 0xff;
int r1 = (color >> 16) & 0xff;
int g1 = (color >> 8) & 0xff;
int b1 = color & 0xff;
int wdelta = (w2 - w1) / mappedRate;
int rdelta = (r2 - r1) / mappedRate;
int gdelta = (g2 - g1) / mappedRate;
int bdelta = (b2 - b1) / mappedRate;
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
setPixelColor(i, r1 + rdelta, g1 + gdelta, b1 + bdelta);
}
}
/*
* blurs segment content, source: FastLED colorutils.cpp
*/
void WS2812FX::blur(uint8_t blur_amount)
{
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for(uint16_t i = 0; i < SEGLEN; i++)
{
CRGB cur = col_to_crgb(getPixelColor(i));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if(i > 0) {
uint32_t c = getPixelColor(i-1);
uint8_t r = (c >> 16 & 0xFF);
uint8_t g = (c >> 8 & 0xFF);
uint8_t b = (c & 0xFF);
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
}
setPixelColor(i,cur.red, cur.green, cur.blue);
carryover = part;
}
}
uint16_t WS2812FX::triwave16(uint16_t in)
{
if (in < 0x8000) return in *2;
return 0xFFFF - (in - 0x8000)*2;
}
/*
* Put a value 0 to 255 in to get a color value.
* The colours are a transition r -> g -> b -> back to r
* Inspired by the Adafruit examples.
* In FastLED terms, the return value is a 'colorCode' and can be used with 'setColorCode'
*/
uint32_t WS2812FX::color_wheel(uint8_t pos) {
if (SEGMENT.palette) return color_from_palette(pos, false, true, 0);
pos = 255 - pos;
if(pos < 85) {
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
} else if(pos < 170) {
pos -= 85;
return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
} else {
pos -= 170;
return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
}
}
/*
* Returns a new, random wheel index with a minimum distance of 42 from pos.
*/
uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
uint8_t r = 0, x = 0, y = 0, d = 0;
while(d < 42) {
r = random8();
x = abs(pos - r);
y = 255 - x;
d = MIN(x, y);
}
return r;
}
uint32_t WS2812FX::crgb_to_col(CRGB fastled)
{
return (((uint32_t)fastled.red << 16) | ((uint32_t)fastled.green << 8) | fastled.blue);
}
CRGB WS2812FX::col_to_crgb(uint32_t color)
{
CRGB fastled_col;
fastled_col.red = (color >> 16 & 0xFF);
fastled_col.green = (color >> 8 & 0xFF);
fastled_col.blue = (color & 0xFF);
return fastled_col;
}
void WS2812FX::load_gradient_palette(uint8_t index)
{
uint8_t i = ArduinoConstrain(index, 0, GRADIENT_PALETTE_COUNT -1);
uint8_t tcp[72]; //support gradient palettes with up to 18 entries
memcpy(tcp, &(gGradientPalettes[i]), 72);
targetPalette.loadDynamicGradientPalette(tcp);
}
/*
* FastLED palette modes helper function. Limitation: Due to memory reasons, multiple active segments with FastLED will disable the Palette transitions
*/
void WS2812FX::handle_palette(void)
{
bool singleSegmentMode = (_segment_index == _segment_index_palette_last);
_segment_index_palette_last = _segment_index;
uint8_t paletteIndex = SEGMENT.palette;
if (paletteIndex == 0) //default palette. Differs depending on effect
{
switch (SEGMENT.mode)
{
case FX_MODE_FIRE_2012 : paletteIndex = 35; break; //heat palette
case FX_MODE_COLORWAVES : paletteIndex = 26; break; //landscape 33
case FX_MODE_FILLNOISE8 : paletteIndex = 9; break; //ocean colors
case FX_MODE_NOISE16_1 : paletteIndex = 20; break; //Drywet
case FX_MODE_NOISE16_2 : paletteIndex = 43; break; //Blue cyan yellow
case FX_MODE_NOISE16_3 : paletteIndex = 35; break; //heat palette
case FX_MODE_NOISE16_4 : paletteIndex = 26; break; //landscape 33
case FX_MODE_GLITTER : paletteIndex = 11; break; //rainbow colors
case FX_MODE_SUNRISE : paletteIndex = 35; break; //heat palette
case FX_MODE_FLOW : paletteIndex = 6; break; //party
}
}
if (SEGMENT.mode >= FX_MODE_METEOR && paletteIndex == 0) paletteIndex = 4;
switch (paletteIndex)
{
case 0: //default palette. Exceptions for specific effects above
targetPalette = PartyColors_p; break;
case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments
if (!singleSegmentMode)
{
targetPalette = PartyColors_p; break; //fallback
}
if (millis() - _lastPaletteChange > 1000 + ((uint32_t)(255-SEGMENT.intensity))*100)
{
targetPalette = CRGBPalette16(
CHSV(random8(), 255, random8(128, 255)),
CHSV(random8(), 255, random8(128, 255)),
CHSV(random8(), 192, random8(128, 255)),
CHSV(random8(), 255, random8(128, 255)));
_lastPaletteChange = millis();
} break;}
case 2: {//primary color only
CRGB prim = col_to_crgb(SEGCOLOR(0));
targetPalette = CRGBPalette16(prim); break;}
case 3: {//primary + secondary
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
targetPalette = CRGBPalette16(prim,prim,sec,sec); break;}
case 4: {//primary + secondary + tertiary
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
CRGB ter = col_to_crgb(SEGCOLOR(2));
targetPalette = CRGBPalette16(ter,sec,prim); break;}
case 5: {//primary + secondary (+tert if not off), more distinct
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
if (SEGCOLOR(2)) {
CRGB ter = col_to_crgb(SEGCOLOR(2));
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,ter,ter,ter,ter,ter,prim);
} else {
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec);
}
break;}
case 6: //Party colors
targetPalette = PartyColors_p; break;
case 7: //Cloud colors
targetPalette = CloudColors_p; break;
case 8: //Lava colors
targetPalette = LavaColors_p; break;
case 9: //Ocean colors
targetPalette = OceanColors_p; break;
case 10: //Forest colors
targetPalette = ForestColors_p; break;
case 11: //Rainbow colors
targetPalette = RainbowColors_p; break;
case 12: //Rainbow stripe colors
targetPalette = RainbowStripeColors_p; break;
default: //progmem palettes
load_gradient_palette(paletteIndex -13);
}
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
{
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
} else
{
currentPalette = targetPalette;
}
}
/*
* Gets a single color from the currently selected palette.
* @param i Palette Index (if mapping is true, the full palette will be SEGLEN long, if false, 255). Will wrap around automatically.
* @param mapping if true, LED position in segment is considered for color
* @param wrap FastLED palettes will usally wrap back to the start smoothly. Set false to get a hard edge
* @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
* @returns Single color from palette
*/
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
{
if (SEGMENT.palette == 0 && mcol < 3) return SEGCOLOR(mcol); //WS2812FX default
uint8_t paletteIndex = i;
if (mapping) paletteIndex = (i*255)/(SEGLEN -1);
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGB fastled_col;
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
}
//@returns `true` if color, mode, speed, intensity and palette match
bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
{
//if (a->start != b->start) return false;
//if (a->stop != b->stop) return false;
for (uint8_t i = 0; i < NUM_COLORS; i++)
{
if (a->colors[i] != b->colors[i]) return false;
}
if (a->mode != b->mode) return false;
if (a->speed != b->speed) return false;
if (a->intensity != b->intensity) return false;
if (a->palette != b->palette) return false;
//if (a->getOption(SEG_OPTION_REVERSED) != b->getOption(SEG_OPTION_REVERSED)) return false;
return true;
}
//gamma 2.4 lookup table used for color correction
const byte gammaT[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
uint8_t WS2812FX::gamma8(uint8_t b)
{
return gammaT[b];
}
uint32_t WS2812FX::gamma32(uint32_t color)
{
if (!gammaCorrectCol) return color;
uint8_t r = (color >> 16);
uint8_t g = (color >> 8);
uint8_t b = color;
r = gammaT[r];
g = gammaT[g];
b = gammaT[b];
return ((r << 16) | (g << 8) | (b));
}
uint16_t WS2812FX::_usedSegmentData = 0;

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 FastLED
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,55 @@
# WS2812FX pattern library
There are a few different pattern libraries scattered throughout the internet. One of the better
and more interesting started here:
https://github.com/kitesurfer1404/WS2812FX
and it uses NeoPixel, and Arduino.
This is a port to FastLED, and to ESP-IDF.
This version started from the WLED source code, for no really good reason, as of 9/11/2020.
https://github.com/Aircoookie/WLED
# differences
This port doesn't have RGBW support, nor for analog LEDs, simply because FastLED doesn't support them, so
it was easier to rip them out.
# using
See `main.cpp` for an example.
There is one interesting bit about the port, which is instead of subclassing the LEDs,
you init it by passing the CRGB LED array in.
This means you can support a lot of LEDs on a lot of pins. In order to code for that, make sure the CRGB LED array
you create is contiguous, like this:
```
#define NUM_LEDS1
#define NUM_LEDS2
CRGB leds[NUM_LEDS1 + NUM_LEDS2];
FastLED.addLeds<LED_TYPE, DATA_PIN1>(&leds[0], NUM_LEDS1);
FastLED.addLeds<LED_TYPE, DATA_PIN1>(&leds[1], NUM_LEDS2);
```
Then you can pass all of the leds array with the entire size.
Then, another benefit of this interface is the segments system. You can have a completly different mapping of
segments, arbitrarily so.
# porting and notes
Annoyingly, the old code used Arduino calls. They got urned into `#define`s.
Arduino code likes milliseconds, but ESP-IDF code likes microseconds. There should probably be some re-coding.
A benefit of the WLED version is you can reuse the WS2812FX object. Interestingly, some patterns
allocate per-pixel memory.
Probably some of the code should be made more FastLED specific, and use more of the 8-bit code.
It should also probably be integrated together with 'show' and double-buffer or similar.

View File

@ -0,0 +1,3 @@
COMPONENT_SRCDIRS := .
COMPONENT_ADD_INCLUDEDIRS := .

View File

@ -0,0 +1,634 @@
/*
* Color palettes for FastLED effects (65-73).
*/
// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
// Unfortunaltely, these are stored in RAM!
// Gradient palette "ib_jul01_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 16 uint8_ts each.
// BB: removed PROGMEM because that's an arduino thing
#ifndef PalettesWLED_h
#define PalettesWLED_h
#define GRADIENT_PALETTE_COUNT 39
const uint8_t ib_jul01_gp[] = {
0, 194, 1, 1,
94, 1, 29, 18,
132, 57,131, 28,
255, 113, 1, 1};
// Gradient palette "es_vintage_57_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_57.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t es_vintage_57_gp[] = {
0, 2, 1, 1,
53, 18, 1, 0,
104, 69, 29, 1,
153, 167,135, 10,
255, 46, 56, 4};
// Gradient palette "es_vintage_01_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_01.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 32 uint8_ts of program space.
const uint8_t es_vintage_01_gp[] = {
0, 4, 1, 1,
51, 16, 0, 1,
76, 97,104, 3,
101, 255,131, 19,
127, 67, 9, 4,
153, 16, 0, 1,
229, 4, 1, 1,
255, 4, 1, 1};
// Gradient palette "es_rivendell_15_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/rivendell/tn/es_rivendell_15.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t es_rivendell_15_gp[] = {
0, 1, 14, 5,
101, 16, 36, 14,
165, 56, 68, 30,
242, 150,156, 99,
255, 150,156, 99};
// Gradient palette "rgi_15_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/ds/rgi/tn/rgi_15.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 36 uint8_ts of program space.
// Edited to be brighter
const uint8_t rgi_15_gp[] = {
0, 4, 1, 70,
31, 55, 1, 30,
63, 255, 4, 7,
95, 59, 2, 29,
127, 11, 3, 50,
159, 39, 8, 60,
191, 112, 19, 40,
223, 78, 11, 39,
255, 29, 8, 59};
// Gradient palette "retro2_16_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/ma/retro2/tn/retro2_16.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 8 uint8_ts of program space.
const uint8_t retro2_16_gp[] = {
0, 188,135, 1,
255, 46, 7, 1};
// Gradient palette "Analogous_1_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/red/tn/Analogous_1.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t Analogous_1_gp[] = {
0, 3, 0,255,
63, 23, 0,255,
127, 67, 0,255,
191, 142, 0, 45,
255, 255, 0, 0};
// Gradient palette "es_pinksplash_08_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_08.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t es_pinksplash_08_gp[] = {
0, 126, 11,255,
127, 197, 1, 22,
175, 210,157,172,
221, 157, 3,112,
255, 157, 3,112};
// Gradient palette "es_ocean_breeze_036_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_036.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 16 uint8_ts of program space.
const uint8_t es_ocean_breeze_036_gp[] = {
0, 1, 6, 7,
89, 1, 99,111,
153, 144,209,255,
255, 0, 73, 82};
// Gradient palette "departure_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/mjf/tn/departure.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 88 uint8_ts of program space.
const uint8_t departure_gp[] = {
0, 8, 3, 0,
42, 23, 7, 0,
63, 75, 38, 6,
84, 169, 99, 38,
106, 213,169,119,
116, 255,255,255,
138, 135,255,138,
148, 22,255, 24,
170, 0,255, 0,
191, 0,136, 0,
212, 0, 55, 0,
255, 0, 55, 0};
// Gradient palette "es_landscape_64_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_64.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 36 uint8_ts of program space.
const uint8_t es_landscape_64_gp[] = {
0, 0, 0, 0,
37, 2, 25, 1,
76, 15,115, 5,
127, 79,213, 1,
128, 126,211, 47,
130, 188,209,247,
153, 144,182,205,
204, 59,117,250,
255, 1, 37,192};
// Gradient palette "es_landscape_33_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_33.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 24 uint8_ts of program space.
const uint8_t es_landscape_33_gp[] = {
0, 1, 5, 0,
19, 32, 23, 1,
38, 161, 55, 1,
63, 229,144, 1,
66, 39,142, 74,
255, 1, 4, 1};
// Gradient palette "rainbowsherbet_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/ma/icecream/tn/rainbowsherbet.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 uint8_ts of program space.
const uint8_t rainbowsherbet_gp[] = {
0, 255, 33, 4,
43, 255, 68, 25,
86, 255, 7, 25,
127, 255, 82,103,
170, 255,255,242,
209, 42,255, 22,
255, 87,255, 65};
// Gradient palette "gr65_hult_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/hult/tn/gr65_hult.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 24 uint8_ts of program space.
const uint8_t gr65_hult_gp[] = {
0, 247,176,247,
48, 255,136,255,
89, 220, 29,226,
160, 7, 82,178,
216, 1,124,109,
255, 1,124,109};
// Gradient palette "gr64_hult_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/hult/tn/gr64_hult.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 32 uint8_ts of program space.
const uint8_t gr64_hult_gp[] = {
0, 1,124,109,
66, 1, 93, 79,
104, 52, 65, 1,
130, 115,127, 1,
150, 52, 65, 1,
201, 1, 86, 72,
239, 0, 55, 45,
255, 0, 55, 45};
// Gradient palette "GMT_drywet_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/gmt/tn/GMT_drywet.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 uint8_ts of program space.
const uint8_t GMT_drywet_gp[] = {
0, 47, 30, 2,
42, 213,147, 24,
84, 103,219, 52,
127, 3,219,207,
170, 1, 48,214,
212, 1, 1,111,
255, 1, 7, 33};
// Gradient palette "ib15_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/ing/general/tn/ib15.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 24 uint8_ts of program space.
const uint8_t ib15_gp[] = {
0, 113, 91,147,
72, 157, 88, 78,
89, 208, 85, 33,
107, 255, 29, 11,
141, 137, 31, 39,
255, 59, 33, 89};
// Gradient palette "Tertiary_01_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/vermillion/tn/Tertiary_01.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t Tertiary_01_gp[] = {
0, 0, 1,255,
63, 3, 68, 45,
127, 23,255, 0,
191, 100, 68, 1,
255, 255, 1, 4};
// Gradient palette "lava_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/neota/elem/tn/lava.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 52 uint8_ts of program space.
const uint8_t lava_gp[] = {
0, 0, 0, 0,
46, 18, 0, 0,
96, 113, 0, 0,
108, 142, 3, 1,
119, 175, 17, 1,
146, 213, 44, 2,
174, 255, 82, 4,
188, 255,115, 4,
202, 255,156, 4,
218, 255,203, 4,
234, 255,255, 4,
244, 255,255, 71,
255, 255,255,255};
// Gradient palette "fierce_ice_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/neota/elem/tn/fierce-ice.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 uint8_ts of program space.
const uint8_t fierce_ice_gp[] = {
0, 0, 0, 0,
59, 0, 9, 45,
119, 0, 38,255,
149, 3,100,255,
180, 23,199,255,
217, 100,235,255,
255, 255,255,255};
// Gradient palette "Colorfull_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/atmospheric/tn/Colorfull.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 44 uint8_ts of program space.
const uint8_t Colorfull_gp[] = {
0, 10, 85, 5,
25, 29,109, 18,
60, 59,138, 42,
93, 83, 99, 52,
106, 110, 66, 64,
109, 123, 49, 65,
113, 139, 35, 66,
116, 192,117, 98,
124, 255,255,137,
168, 100,180,155,
255, 22,121,174};
// Gradient palette "Pink_Purple_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/atmospheric/tn/Pink_Purple.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 44 uint8_ts of program space.
const uint8_t Pink_Purple_gp[] = {
0, 19, 2, 39,
25, 26, 4, 45,
51, 33, 6, 52,
76, 68, 62,125,
102, 118,187,240,
109, 163,215,247,
114, 217,244,255,
122, 159,149,221,
149, 113, 78,188,
183, 128, 57,155,
255, 146, 40,123};
// Gradient palette "Sunset_Real_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 uint8_ts of program space.
const uint8_t Sunset_Real_gp[] = {
0, 120, 0, 0,
22, 179, 22, 0,
51, 255,104, 0,
85, 167, 22, 18,
135, 100, 0,103,
198, 16, 0,130,
255, 0, 0,160};
// Gradient palette "Sunset_Yellow_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Yellow.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 44 uint8_ts of program space.
const uint8_t Sunset_Yellow_gp[] = {
0, 10, 62,123,
36, 56,130,103,
87, 153,225, 85,
100, 199,217, 68,
107, 255,207, 54,
115, 247,152, 57,
120, 239,107, 61,
128, 247,152, 57,
180, 255,207, 54,
223, 255,227, 48,
255, 255,248, 42};
// Gradient palette "Beech_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/atmospheric/tn/Beech.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 60 uint8_ts of program space.
const uint8_t Beech_gp[] = {
0, 255,252,214,
12, 255,252,214,
22, 255,252,214,
26, 190,191,115,
28, 137,141, 52,
28, 112,255,205,
50, 51,246,214,
71, 17,235,226,
93, 2,193,199,
120, 0,156,174,
133, 1,101,115,
136, 1, 59, 71,
136, 7,131,170,
208, 1, 90,151,
255, 0, 56,133};
// Gradient palette "Another_Sunset_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/atmospheric/tn/Another_Sunset.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 32 uint8_ts of program space.
const uint8_t Another_Sunset_gp[] = {
0, 110, 49, 11,
29, 55, 34, 10,
68, 22, 22, 9,
68, 239,124, 8,
97, 220,156, 27,
124, 203,193, 61,
178, 33, 53, 56,
255, 0, 1, 52};
// Gradient palette "es_autumn_19_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/es/autumn/tn/es_autumn_19.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 52 uint8_ts of program space.
const uint8_t es_autumn_19_gp[] = {
0, 26, 1, 1,
51, 67, 4, 1,
84, 118, 14, 1,
104, 137,152, 52,
112, 113, 65, 1,
122, 133,149, 59,
124, 137,152, 52,
135, 113, 65, 1,
142, 139,154, 46,
163, 113, 13, 1,
204, 55, 3, 1,
249, 17, 1, 1,
255, 17, 1, 1};
// Gradient palette "BlacK_Blue_Magenta_White_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Blue_Magenta_White.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 uint8_ts of program space.
const uint8_t BlacK_Blue_Magenta_White_gp[] = {
0, 0, 0, 0,
42, 0, 0, 45,
84, 0, 0,255,
127, 42, 0,255,
170, 255, 0,255,
212, 255, 55,255,
255, 255,255,255};
// Gradient palette "BlacK_Magenta_Red_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Magenta_Red.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t BlacK_Magenta_Red_gp[] = {
0, 0, 0, 0,
63, 42, 0, 45,
127, 255, 0,255,
191, 255, 0, 45,
255, 255, 0, 0};
// Gradient palette "BlacK_Red_Magenta_Yellow_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Red_Magenta_Yellow.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 uint8_ts of program space.
const uint8_t BlacK_Red_Magenta_Yellow_gp[] = {
0, 0, 0, 0,
42, 42, 0, 0,
84, 255, 0, 0,
127, 255, 0, 45,
170, 255, 0,255,
212, 255, 55, 45,
255, 255,255, 0};
// Gradient palette "Blue_Cyan_Yellow_gp", originally from
// http://soliton.vm.uint8_tmark.co.uk/pub/cpt-city/nd/basic/tn/Blue_Cyan_Yellow.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 20 uint8_ts of program space.
const uint8_t Blue_Cyan_Yellow_gp[] = {
0, 0, 0,255,
63, 0, 55,255,
127, 0,255,255,
191, 42,255, 45,
255, 255,255, 0};
//Custom palette by Aircoookie
const uint8_t Orange_Teal_gp[] = {
0, 0,150, 92,
55, 0,150, 92,
200, 255, 72, 0,
255, 255, 72, 0};
//Custom palette by Aircoookie
const uint8_t Tiamat_gp[] = {
0, 1, 2, 14, //gc
33, 2, 5, 35, //gc from 47, 61,126
100, 13,135, 92, //gc from 88,242,247
120, 43,255,193, //gc from 135,255,253
140, 247, 7,249, //gc from 252, 69,253
160, 193, 17,208, //gc from 231, 96,237
180, 39,255,154, //gc from 130, 77,213
200, 4,213,236, //gc from 57,122,248
220, 39,252,135, //gc from 177,254,255
240, 193,213,253, //gc from 203,239,253
255, 255,249,255};
//Custom palette by Aircoookie
const uint8_t April_Night_gp[] = {
0, 1, 5, 45, //deep blue
10, 1, 5, 45,
25, 5,169,175, //light blue
40, 1, 5, 45,
61, 1, 5, 45,
76, 45,175, 31, //green
91, 1, 5, 45,
112, 1, 5, 45,
127, 249,150, 5, //yellow
143, 1, 5, 45,
162, 1, 5, 45,
178, 255, 92, 0, //pastel orange
193, 1, 5, 45,
214, 1, 5, 45,
229, 223, 45, 72, //pink
244, 1, 5, 45,
255, 1, 5, 45};
const uint8_t Orangery_gp[] = {
0, 255, 95, 23,
30, 255, 82, 0,
60, 223, 13, 8,
90, 144, 44, 2,
120, 255,110, 17,
150, 255, 69, 0,
180, 158, 13, 11,
210, 241, 82, 17,
255, 213, 37, 4};
//inspired by Mark Kriegsman https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
const uint8_t C9_gp[] = {
0, 184, 4, 0, //red
60, 184, 4, 0,
65, 144, 44, 2, //amber
125, 144, 44, 2,
130, 4, 96, 2, //green
190, 4, 96, 2,
195, 7, 7, 88, //blue
255, 7, 7, 88};
const uint8_t Sakura_gp[] = {
0, 196, 19, 10,
65, 255, 69, 45,
130, 223, 45, 72,
195, 255, 82,103,
255, 223, 13, 17};
const uint8_t Aurora_gp[] = {
0, 1, 5, 45, //deep blue
64, 0,200, 23,
128, 0,255, 0, //green
170, 0,243, 45,
200, 0,135, 7,
255, 1, 5, 45};//deep blue
const uint8_t Atlantica_gp[] = {
0, 0, 28,112, //#001C70
50, 32, 96,255, //#2060FF
100, 0,243, 45,
150, 12, 95, 82, //#0C5F52
200, 25,190, 95, //#19BE5F
255, 40,170, 80};//#28AA50
// Single array of defined cpt-city color palettes.
// This will let us programmatically choose one based on
// a number, rather than having to activate each explicitly
// by name every time.
const uint8_t* const gGradientPalettes[] = {
Sunset_Real_gp, //13-00 Sunset
es_rivendell_15_gp, //14-01 Rivendell
es_ocean_breeze_036_gp, //15-02 Breeze
rgi_15_gp, //16-03 Red & Blue
retro2_16_gp, //17-04 Yellowout
Analogous_1_gp, //18-05 Analogous
es_pinksplash_08_gp, //19-06 Splash
Sunset_Yellow_gp, //20-07 Pastel
Another_Sunset_gp, //21-08 Sunset2
Beech_gp, //22-09 Beech
es_vintage_01_gp, //23-10 Vintage
departure_gp, //24-11 Departure
es_landscape_64_gp, //25-12 Landscape
es_landscape_33_gp, //26-13 Beach
rainbowsherbet_gp, //27-14 Sherbet
gr65_hult_gp, //28-15 Hult
gr64_hult_gp, //29-16 Hult64
GMT_drywet_gp, //30-17 Drywet
ib_jul01_gp, //31-18 Jul
es_vintage_57_gp, //32-19 Grintage
ib15_gp, //33-20 Rewhi
Tertiary_01_gp, //34-21 Tertiary
lava_gp, //35-22 Fire
fierce_ice_gp, //36-23 Icefire
Colorfull_gp, //37-24 Cyane
Pink_Purple_gp, //38-25 Light Pink
es_autumn_19_gp, //39-26 Autumn
BlacK_Blue_Magenta_White_gp, //40-27 Magenta
BlacK_Magenta_Red_gp, //41-28 Magred
BlacK_Red_Magenta_Yellow_gp, //42-29 Yelmag
Blue_Cyan_Yellow_gp, //43-30 Yelblu
Orange_Teal_gp, //44-31 Orange & Teal
Tiamat_gp, //45-32 Tiamat
April_Night_gp, //46-33 April Night
Orangery_gp, //47-34 Orangery
C9_gp, //48-35 C9
Sakura_gp, //49-36 Sakura
Aurora_gp, //50-37 Aurora
Atlantica_gp, //51-38 Atlantica
};
#endif

View File

@ -14,6 +14,8 @@
#include "esp_spi_flash.h"
#include "FastLED.h"
#include "FX.h"
CRGBPalette16 currentPalette;
TBlendType currentBlending;
@ -27,6 +29,7 @@ extern const TProgmemPalette16 IRAM_ATTR myRedWhiteBluePalette_p;
#define BRIGHTNESS 80
#define LED_TYPE WS2811
#define COLOR_ORDER RGB
CRGB leds[NUM_LEDS];
@ -34,6 +37,40 @@ extern "C" {
void app_main();
}
/* test using the FX unit
**
*/
static void blinkWithFx(void *pvParameters) {
uint16_t mode = FX_MODE_STATIC;
WS2812FX ws2812fx;
ws2812fx.init(NUM_LEDS, leds, false); // type was configured before
ws2812fx.setBrightness(255);
ws2812fx.setMode(0 /*segid*/, mode);
// microseconds
uint64_t mode_change_time = esp_timer_get_time();
while (true) {
if ((mode_change_time + 10000000L) < esp_timer_get_time() ) {
mode += 1;
mode %= MODE_COUNT;
mode_change_time = esp_timer_get_time();
ws2812fx.setMode(0 /*segid*/, mode);
printf(" changed mode to %d\n", mode);
}
ws2812fx.service();
vTaskDelay(10 / portTICK_PERIOD_MS); /*10ms*/
}
};
void ChangePalettePeriodically(){
@ -223,7 +260,8 @@ void app_main() {
// change the task below to one of the functions above to try different patterns
printf("create task for led blinking\n");
//xTaskCreatePinnedToCore(&blinkLeds_simple, "blinkLeds", 4000, NULL, 5, NULL, 0);
xTaskCreatePinnedToCore(&fastfade, "blinkLeds", 4000, NULL, 5, NULL, 0);
//xTaskCreatePinnedToCore(&blinkLeds_simple, "blinkLeds", 4000, NULL, 5, NULL, 0);
//xTaskCreatePinnedToCore(&fastfade, "blinkLeds", 4000, NULL, 5, NULL, 0);
xTaskCreatePinnedToCore(&blinkWithFx, "blinkLeds", 4000, NULL, 5, NULL, 0);
}