2016-12-17 23:43:07 +01:00
/*
WS2812FX . cpp - Library for WS2812 LED effects .
Harm Aldick - 2016
www . aldick . org
FEATURES
* A lot of blinken modes and counting
2018-09-04 15:51:38 +02:00
* WS2812FX can be used as drop - in replacement for Adafruit NeoPixel Library
2016-12-17 23:43:07 +01:00
NOTES
2018-09-04 15:51:38 +02:00
* Uses the Adafruit NeoPixel library . Get it here :
2016-12-17 23:43:07 +01:00
https : //github.com/adafruit/Adafruit_NeoPixel
LICENSE
The MIT License ( MIT )
2018-09-04 15:51:38 +02:00
Copyright ( c ) 2016 Harm Aldick
2016-12-17 23:43:07 +01:00
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 .
2019-02-02 15:31:43 +01:00
Modified heavily for WLED
2016-12-17 23:43:07 +01:00
*/
2018-09-28 23:53:51 +02:00
2016-12-17 23:43:07 +01:00
# include "WS2812FX.h"
2018-10-24 02:06:07 +02:00
# include "palettes.h"
2016-12-17 23:43:07 +01:00
2019-02-02 15:31:43 +01:00
# define IBN 5100
2019-01-31 23:42:48 +01:00
# define LED_SKIP_AMOUNT 24
2019-01-09 22:52:42 +01:00
2018-09-04 15:51:38 +02:00
void WS2812FX : : init ( bool supportWhite , uint16_t countPixels , bool skipFirst )
{
if ( supportWhite = = _rgbwMode & & countPixels = = _length & & _locked ! = NULL ) return ;
RESET_RUNTIME ;
_rgbwMode = supportWhite ;
_skipFirstMode = skipFirst ;
_length = countPixels ;
2019-01-09 22:52:42 +01:00
2018-09-04 15:51:38 +02:00
uint8_t ty = 1 ;
if ( supportWhite ) ty = 2 ;
2019-01-09 22:52:42 +01:00
uint16_t lengthRaw = _length ;
if ( _skipFirstMode ) lengthRaw + = LED_SKIP_AMOUNT ;
bus - > Begin ( ( NeoPixelType ) ty , lengthRaw ) ;
2018-09-04 15:51:38 +02:00
if ( _locked ! = NULL ) delete _locked ;
_locked = new byte [ _length ] ;
2019-01-09 22:52:42 +01:00
2018-09-04 15:51:38 +02:00
_segments [ 0 ] . start = 0 ;
_segments [ 0 ] . stop = _length - 1 ;
2019-01-09 22:52:42 +01:00
2018-09-04 15:51:38 +02:00
unlockAll ( ) ;
setBrightness ( _brightness ) ;
_running = true ;
2016-12-17 23:43:07 +01:00
}
void WS2812FX : : service ( ) {
2017-02-04 22:17:28 +01:00
if ( _running | | _triggered ) {
2018-09-04 15:51:38 +02:00
unsigned long now = millis ( ) ; // Be aware, millis() rolls over every 49 days
bool doShow = false ;
2018-11-09 17:00:36 +01:00
for ( uint8_t i = 0 ; i < _num_segments ; i + + )
{
2018-09-04 15:51:38 +02:00
_segment_index = i ;
2018-11-09 17:00:36 +01:00
if ( now > SEGMENT_RUNTIME . next_time | | _triggered )
{
2018-09-04 15:51:38 +02:00
doShow = true ;
2018-10-24 02:06:07 +02:00
handle_palette ( ) ;
2018-09-04 15:51:38 +02:00
uint16_t delay = ( this - > * _mode [ SEGMENT . mode ] ) ( ) ;
SEGMENT_RUNTIME . next_time = now + max ( delay , 5 ) ;
SEGMENT_RUNTIME . counter_mode_call + + ;
}
}
if ( doShow ) {
show ( ) ;
}
_triggered = false ;
}
}
2018-11-04 20:14:23 +01:00
bool WS2812FX : : modeUsesLock ( uint8_t m )
{
2019-01-31 23:42:48 +01:00
if ( m < FX_MODE_FIRE_2012 ) return false ;
if ( m = = FX_MODE_FIRE_2012 | | m = = FX_MODE_COLORTWINKLE | | m = = FX_MODE_METEOR | | m = = FX_MODE_METEOR_SMOOTH | | m = = FX_MODE_RIPPLE ) return true ;
2018-11-04 20:14:23 +01:00
return false ;
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setPixelColor ( uint16_t n , uint32_t c ) {
uint8_t w = ( c > > 24 ) & 0xFF ;
uint8_t r = ( c > > 16 ) & 0xFF ;
uint8_t g = ( c > > 8 ) & 0xFF ;
uint8_t b = c & 0xFF ;
setPixelColor ( n , r , g , b , w ) ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
void WS2812FX : : setPixelColor ( uint16_t i , byte r , byte g , byte b , byte w )
{
2018-11-04 20:14:23 +01:00
if ( _locked [ i ] & & ! modeUsesLock ( SEGMENT . mode ) ) return ;
2018-10-18 18:06:46 +02:00
if ( _reverseMode ) i = _length - 1 - i ;
2018-09-06 02:05:56 +02:00
if ( IS_REVERSE ) i = SEGMENT . stop - ( i - SEGMENT . start ) ; //reverse just individual segment
2018-11-24 11:52:23 +01:00
byte tmpg = g ;
switch ( colorOrder ) //0 = Grb, default
{
case 0 : break ; //0 = Grb, default
case 1 : g = r ; r = tmpg ; break ; //1 = Rgb, common for WS2811
case 2 : g = b ; b = tmpg ; break ; //2 = Brg
case 3 : g = b ; b = r ; r = tmpg ; //3 = Rbg
}
2018-09-04 15:51:38 +02:00
if ( ! _cronixieMode )
{
2019-01-09 22:52:42 +01:00
if ( _skipFirstMode )
{
if ( i < LED_SKIP_AMOUNT ) bus - > SetPixelColor ( i , RgbwColor ( 0 , 0 , 0 , 0 ) ) ;
i + = LED_SKIP_AMOUNT ;
}
2018-09-04 15:51:38 +02:00
bus - > SetPixelColor ( i , RgbwColor ( r , g , b , w ) ) ;
} else {
if ( i > 6 ) return ;
byte o = 10 * i ;
if ( _cronixieBacklightEnabled & & _cronixieDigits [ i ] < 11 )
{
2018-12-04 00:58:06 +01:00
byte r2 = ( _segments [ 0 ] . colors [ 1 ] > > 16 ) & 0xFF ;
byte g2 = ( _segments [ 0 ] . colors [ 1 ] > > 8 ) & 0xFF ;
byte b2 = ( _segments [ 0 ] . colors [ 1 ] ) & 0xFF ;
byte w2 = ( _segments [ 0 ] . colors [ 1 ] > > 24 ) & 0xFF ;
2018-09-04 15:51:38 +02:00
for ( int j = o ; j < o + 19 ; j + + )
{
2019-01-09 22:52:42 +01:00
bus - > SetPixelColor ( j , RgbwColor ( r2 , g2 , b2 , w2 ) ) ;
2018-09-04 15:51:38 +02:00
}
} else
{
for ( int j = o ; j < o + 19 ; j + + )
{
2019-01-09 22:52:42 +01:00
bus - > SetPixelColor ( j , RgbwColor ( 0 , 0 , 0 , 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
}
2019-01-09 22:52:42 +01:00
if ( _skipFirstMode ) o + = LED_SKIP_AMOUNT ;
2018-09-04 15:51:38 +02:00
switch ( _cronixieDigits [ i ] )
{
2019-01-09 22:52:42 +01:00
case 0 : bus - > SetPixelColor ( o + 5 , RgbwColor ( r , g , b , w ) ) ; break ;
case 1 : bus - > SetPixelColor ( o + 0 , RgbwColor ( r , g , b , w ) ) ; break ;
case 2 : bus - > SetPixelColor ( o + 6 , RgbwColor ( r , g , b , w ) ) ; break ;
case 3 : bus - > SetPixelColor ( o + 1 , RgbwColor ( r , g , b , w ) ) ; break ;
case 4 : bus - > SetPixelColor ( o + 7 , RgbwColor ( r , g , b , w ) ) ; break ;
case 5 : bus - > SetPixelColor ( o + 2 , RgbwColor ( r , g , b , w ) ) ; break ;
case 6 : bus - > SetPixelColor ( o + 8 , RgbwColor ( r , g , b , w ) ) ; break ;
case 7 : bus - > SetPixelColor ( o + 3 , RgbwColor ( r , g , b , w ) ) ; break ;
case 8 : bus - > SetPixelColor ( o + 9 , RgbwColor ( r , g , b , w ) ) ; break ;
case 9 : bus - > SetPixelColor ( o + 4 , RgbwColor ( r , g , b , w ) ) ; break ;
2016-12-17 23:43:07 +01:00
}
}
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setReverseMode ( bool b )
{
_reverseMode = b ;
}
void WS2812FX : : driverModeCronixie ( bool b )
{
_cronixieMode = b ;
2018-09-22 22:49:24 +02:00
_segments [ 0 ] . stop = ( b ) ? 5 : _length - 1 ;
2018-09-04 15:51:38 +02:00
}
void WS2812FX : : setCronixieBacklight ( bool b )
{
_cronixieBacklightEnabled = b ;
}
void WS2812FX : : setCronixieDigits ( byte d [ ] )
{
for ( int i = 0 ; i < 6 ; i + + )
{
_cronixieDigits [ i ] = d [ i ] ;
}
}
2018-12-04 00:58:06 +01:00
//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 PU_PER_MA 3600 //power units per milliamperere for accurate power estimation
//formula: 195075 divided by mA per fully lit LED, here ~54mA)
//lowering the value increases the estimated usage and therefore makes the ABL more aggressive
# 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
2018-09-04 15:51:38 +02:00
void WS2812FX : : show ( void ) {
2018-12-04 00:58:06 +01:00
//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)
if ( ablMilliampsMax > 149 & & ablMilliampsMax < 65000 ) //lower numbers and 65000 turn off calculation
{
uint32_t powerBudget = ( ablMilliampsMax - MA_FOR_ESP ) * PU_PER_MA ; //100mA for ESP power
if ( powerBudget > PU_PER_MA * _length ) //each LED uses about 1mA in standby, exclude that from power budget
{
powerBudget - = PU_PER_MA * _length ;
} else
{
powerBudget = 0 ;
}
uint32_t powerSum = 0 ;
for ( uint16_t i = 0 ; i < _length ; i + + ) //sum up the usage of each LED
{
RgbwColor c = bus - > GetPixelColorRgbw ( i ) ;
powerSum + = ( c . R + c . G + c . B + c . W ) ;
}
if ( _rgbwMode ) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
{
powerSum * = 3 ;
powerSum > > 2 ; //same as /= 4
}
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 ) ;
bus - > SetBrightness ( newBri ) ;
currentMilliamps = ( powerSum0 * newBri ) / PU_PER_MA ;
} else
{
currentMilliamps = powerSum / PU_PER_MA ;
bus - > SetBrightness ( _brightness ) ;
}
currentMilliamps + = MA_FOR_ESP ; //add power of ESP back to estimate
currentMilliamps + = _length ; //add standby power back to estimate
} else {
currentMilliamps = 0 ;
}
2018-09-04 15:51:38 +02:00
bus - > Show ( ) ;
}
2017-02-04 22:17:28 +01:00
void WS2812FX : : trigger ( ) {
_triggered = true ;
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setMode ( uint8_t m ) {
RESET_RUNTIME ;
2018-11-04 20:14:23 +01:00
bool ua = modeUsesLock ( _segments [ 0 ] . mode ) & & ! modeUsesLock ( m ) ;
2018-11-24 11:52:23 +01:00
if ( m > MODE_COUNT - 1 ) m = MODE_COUNT - 1 ;
_segments [ 0 ] . mode = m ;
2018-09-04 15:51:38 +02:00
if ( ua ) unlockAll ( ) ;
setBrightness ( _brightness ) ;
}
//TODO transitions
void WS2812FX : : setSpeed ( uint8_t s ) {
_segments [ 0 ] . speed = s ;
}
void WS2812FX : : setIntensity ( uint8_t in ) {
_segments [ 0 ] . intensity = in ;
}
2018-09-06 02:05:56 +02:00
void WS2812FX : : setPalette ( uint8_t p ) {
_segments [ 0 ] . palette = p ;
}
2018-11-24 11:52:23 +01:00
bool WS2812FX : : setEffectConfig ( uint8_t m , uint8_t s , uint8_t i , uint8_t p ) {
bool changed = false ;
m = constrain ( m , 0 , MODE_COUNT - 1 ) ;
if ( m ! = _segments [ 0 ] . mode ) { setMode ( m ) ; changed = true ; }
if ( s ! = _segments [ 0 ] . speed ) { setSpeed ( s ) ; changed = true ; }
if ( i ! = _segments [ 0 ] . intensity ) { setIntensity ( i ) ; changed = true ; }
if ( p ! = _segments [ 0 ] . palette ) { setPalette ( p ) ; changed = true ; }
return changed ;
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setColor ( uint8_t r , uint8_t g , uint8_t b , uint8_t w ) {
setColor ( ( ( uint32_t ) w < < 24 ) | ( ( uint32_t ) r < < 16 ) | ( ( uint32_t ) g < < 8 ) | b ) ;
}
void WS2812FX : : setSecondaryColor ( uint8_t r , uint8_t g , uint8_t b , uint8_t w ) {
setSecondaryColor ( ( ( uint32_t ) w < < 24 ) | ( ( uint32_t ) r < < 16 ) | ( ( uint32_t ) g < < 8 ) | b ) ;
}
void WS2812FX : : setColor ( uint32_t c ) {
_segments [ 0 ] . colors [ 0 ] = c ;
}
void WS2812FX : : setSecondaryColor ( uint32_t c ) {
_segments [ 0 ] . colors [ 1 ] = c ;
}
void WS2812FX : : setBrightness ( uint8_t b ) {
2018-11-28 12:24:32 +01:00
if ( _brightness = = b ) return ;
2018-09-04 15:51:38 +02:00
_brightness = b ;
bus - > SetBrightness ( _brightness ) ;
2018-04-11 23:50:35 +02:00
show ( ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint8_t WS2812FX : : getMode ( void ) {
return _segments [ 0 ] . mode ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint8_t WS2812FX : : getSpeed ( void ) {
return _segments [ 0 ] . speed ;
}
uint8_t WS2812FX : : getBrightness ( void ) {
return _brightness ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint8_t WS2812FX : : getNumSegments ( void ) {
return _num_segments ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setNumSegments ( uint8_t n ) {
_num_segments = n ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint32_t WS2812FX : : getColor ( void ) {
return _segments [ 0 ] . colors [ 0 ] ;
}
uint32_t WS2812FX : : getPixelColor ( uint16_t i )
{
if ( _reverseMode ) i = _length - 1 - i ;
2019-01-09 22:52:42 +01:00
if ( _skipFirstMode ) i + = LED_SKIP_AMOUNT ;
2018-09-04 15:51:38 +02:00
if ( _cronixieMode )
{
if ( i > 6 ) return 0 ;
byte o = 10 * i ;
switch ( _cronixieDigits [ i ] )
{
case 0 : i = o + 5 ; break ;
case 1 : i = o + 0 ; break ;
case 2 : i = o + 6 ; break ;
case 3 : i = o + 1 ; break ;
case 4 : i = o + 7 ; break ;
case 5 : i = o + 2 ; break ;
case 6 : i = o + 8 ; break ;
case 7 : i = o + 3 ; break ;
case 8 : i = o + 9 ; break ;
case 9 : i = o + 4 ; break ;
default : return 0 ;
}
}
RgbwColor lColor = bus - > GetPixelColorRgbw ( i ) ;
2018-11-28 12:24:32 +01:00
byte r = lColor . R , g = lColor . G , b = lColor . B ;
switch ( colorOrder )
{
case 0 : break ; //0 = Grb
case 1 : r = lColor . G ; g = lColor . R ; break ; //1 = Rgb, common for WS2811
case 2 : g = lColor . B ; b = lColor . G ; break ; //2 = Brg
case 3 : r = lColor . B ; g = lColor . R ; b = lColor . G ; //3 = Rbg
}
return ( ( lColor . W < < 24 ) | ( r < < 16 ) | ( g < < 8 ) | ( b ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
WS2812FX : : Segment WS2812FX : : getSegment ( void ) {
return SEGMENT ;
2018-01-27 23:28:20 +01:00
}
2018-09-04 15:51:38 +02:00
WS2812FX : : Segment_runtime WS2812FX : : getSegmentRuntime ( void ) {
return SEGMENT_RUNTIME ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
WS2812FX : : Segment * WS2812FX : : getSegments ( void ) {
return _segments ;
}
2017-09-27 21:45:58 +02:00
2018-09-04 15:51:38 +02:00
void WS2812FX : : setSegment ( uint8_t n , uint16_t start , uint16_t stop , uint8_t mode , uint32_t color , uint8_t speed , uint8_t intensity , bool reverse ) {
uint32_t colors [ ] = { color , 0 , 0 } ;
setSegment ( n , start , stop , mode , colors , speed , intensity , reverse ) ;
2017-09-27 21:45:58 +02:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setSegment ( uint8_t n , uint16_t start , uint16_t stop , uint8_t mode , const uint32_t colors [ ] , uint8_t speed , uint8_t intensity , bool reverse ) {
setSegment ( n , start , stop , mode , colors , speed , intensity , ( uint8_t ) ( reverse ? REVERSE : NO_OPTIONS ) ) ;
2017-11-28 15:09:58 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setSegment ( uint8_t n , uint16_t start , uint16_t stop , uint8_t mode , const uint32_t colors [ ] , uint8_t speed , uint8_t intensity , uint8_t options ) {
if ( n < ( sizeof ( _segments ) / sizeof ( _segments [ 0 ] ) ) ) {
if ( n + 1 > _num_segments ) _num_segments = n + 1 ;
_segments [ n ] . start = start ;
_segments [ n ] . stop = stop ;
_segments [ n ] . mode = mode ;
_segments [ n ] . speed = speed ;
_segments [ n ] . intensity = intensity ;
_segments [ n ] . options = options ;
2017-11-28 15:09:58 +01:00
2018-09-04 15:51:38 +02:00
for ( uint8_t i = 0 ; i < NUM_COLORS ; i + + ) {
_segments [ n ] . colors [ i ] = colors [ i ] ;
}
}
2017-11-28 15:09:58 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : resetSegments ( ) {
memset ( _segments , 0 , sizeof ( _segments ) ) ;
memset ( _segment_runtimes , 0 , sizeof ( _segment_runtimes ) ) ;
_segment_index = 0 ;
_num_segments = 1 ;
setSegment ( 0 , 0 , 7 , FX_MODE_STATIC , ( const uint32_t [ ] ) { DEFAULT_COLOR , 0 , 0 } , DEFAULT_SPEED , 128 , NO_OPTIONS ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setIndividual ( uint16_t i , uint32_t col )
{
2018-11-04 20:14:23 +01:00
if ( modeUsesLock ( SEGMENT . mode ) ) return ;
2018-09-04 15:51:38 +02:00
if ( i > = 0 & & i < _length )
{
_locked [ i ] = false ;
setPixelColor ( i , col ) ;
_locked [ i ] = true ;
}
2017-11-28 15:09:58 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : setRange ( uint16_t i , uint16_t i2 , uint32_t col )
{
if ( i2 > = i )
{
for ( uint16_t x = i ; x < = i2 ; x + + ) setIndividual ( x , col ) ;
} else
{
for ( uint16_t x = i2 ; x < = i ; x + + ) setIndividual ( x , col ) ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : lock ( uint16_t i )
{
2018-11-04 20:14:23 +01:00
if ( modeUsesLock ( SEGMENT . mode ) ) return ;
2018-09-04 15:51:38 +02:00
if ( i > = 0 & & i < _length ) _locked [ i ] = true ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : lockRange ( uint16_t i , uint16_t i2 )
{
2018-11-04 20:14:23 +01:00
if ( modeUsesLock ( SEGMENT . mode ) ) return ;
2018-09-04 15:51:38 +02:00
for ( uint16_t x = i ; x < = i2 ; x + + )
{
if ( i > = 0 & & i < _length ) _locked [ i ] = true ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : unlock ( uint16_t i )
{
2018-11-04 20:14:23 +01:00
if ( modeUsesLock ( SEGMENT . mode ) ) return ;
2018-09-04 15:51:38 +02:00
if ( i > = 0 & & i < _length ) _locked [ i ] = false ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : unlockRange ( uint16_t i , uint16_t i2 )
{
2018-11-04 20:14:23 +01:00
if ( modeUsesLock ( SEGMENT . mode ) ) return ;
2018-09-04 15:51:38 +02:00
for ( uint16_t x = i ; x < i2 ; x + + )
{
if ( x > = 0 & & x < _length ) _locked [ x ] = false ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
void WS2812FX : : unlockAll ( )
{
for ( int i = 0 ; i < _length ; i + + ) _locked [ i ] = false ;
2016-12-17 23:43:07 +01:00
}
2018-09-06 02:05:56 +02:00
void WS2812FX : : setTransitionMode ( bool t )
{
SEGMENT_RUNTIME . trans_act = ( t ) ? 1 : 2 ;
if ( ! t ) return ;
2018-11-04 20:14:23 +01:00
unsigned long waitMax = millis ( ) + 20 ; //refresh after 20 ms if transition enabled
2018-09-06 02:05:56 +02:00
if ( SEGMENT . mode = = FX_MODE_STATIC & & SEGMENT_RUNTIME . next_time > waitMax ) SEGMENT_RUNTIME . next_time = waitMax ;
}
2018-09-04 15:51:38 +02:00
/*
* color blend function
*/
uint32_t WS2812FX : : color_blend ( uint32_t color1 , uint32_t color2 , uint8_t blend ) {
if ( blend = = 0 ) return color1 ;
if ( blend = = 255 ) return color2 ;
int w1 = ( color1 > > 24 ) & 0xff ;
int r1 = ( color1 > > 16 ) & 0xff ;
int g1 = ( color1 > > 8 ) & 0xff ;
int b1 = color1 & 0xff ;
int w2 = ( color2 > > 24 ) & 0xff ;
int r2 = ( color2 > > 16 ) & 0xff ;
int g2 = ( color2 > > 8 ) & 0xff ;
int b2 = color2 & 0xff ;
2019-02-02 15:31:43 +01:00
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 ;
2018-09-04 15:51:38 +02:00
return ( ( w3 < < 24 ) | ( r3 < < 16 ) | ( g3 < < 8 ) | ( b3 ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-02-02 15:31:43 +01:00
/*
* Fills segment with color
*/
void WS2812FX : : fill ( uint32_t c ) {
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , c ) ;
}
}
2018-09-04 15:51:38 +02:00
2016-12-17 23:43:07 +01:00
/* #####################################################
#
# Color and Blinken Functions
#
# #################################################### * /
/*
* 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 .
*/
2018-09-04 15:51:38 +02:00
uint32_t WS2812FX : : color_wheel ( uint8_t pos ) {
2018-10-24 02:06:07 +02:00
if ( SEGMENT . palette ) return color_from_palette ( pos , false , true , 0 ) ;
2016-12-17 23:43:07 +01:00
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 .
*/
2018-09-04 15:51:38 +02:00
uint8_t WS2812FX : : get_random_wheel_index ( uint8_t pos ) {
2019-02-02 15:31:43 +01:00
uint8_t r = 0 , x = 0 , y = 0 , d = 0 ;
2016-12-17 23:43:07 +01:00
while ( d < 42 ) {
2018-09-04 15:51:38 +02:00
r = random8 ( ) ;
2016-12-17 23:43:07 +01:00
x = abs ( pos - r ) ;
y = 255 - x ;
2018-09-04 15:51:38 +02:00
d = min ( x , y ) ;
2016-12-17 23:43:07 +01:00
}
return r ;
}
/*
* No blinking . Just plain old static light .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_static ( void ) {
2019-02-02 15:31:43 +01:00
fill ( SEGMENT . colors [ 0 ] ) ;
2018-09-06 02:05:56 +02:00
return ( SEGMENT_RUNTIME . trans_act = = 1 ) ? 20 : 500 ;
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
# define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
2016-12-17 23:43:07 +01:00
/*
2018-09-04 15:51:38 +02:00
* Blink / strobe function
* Alternate between color1 and color2
* if ( strobe = = true ) then create a strobe effect
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : blink ( uint32_t color1 , uint32_t color2 , bool strobe , bool do_palette ) {
2018-09-04 15:51:38 +02:00
uint32_t color = ( ( SEGMENT_RUNTIME . counter_mode_call & 1 ) = = 0 ) ? color1 : color2 ;
2018-10-24 02:06:07 +02:00
if ( color = = color1 & & do_palette )
{
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
}
} else {
2019-02-02 15:31:43 +01:00
fill ( color ) ;
2018-09-04 15:51:38 +02:00
}
if ( ( SEGMENT_RUNTIME . counter_mode_call & 1 ) = = 0 ) {
return strobe ? 20 : ( 100 + ( ( 1986 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) ) * ( float ) ( SEGMENT . intensity / 128.0 ) ;
2016-12-17 23:43:07 +01:00
} else {
2018-09-04 15:51:38 +02:00
return strobe ? 50 + ( ( 1986 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) : ( 100 + ( ( 1986 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) ) * ( float ) ( 2.0 - ( SEGMENT . intensity / 128.0 ) ) ;
2016-12-17 23:43:07 +01:00
}
}
/*
2018-09-04 15:51:38 +02:00
* Normal blinking . 50 % on / off time .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_blink ( void ) {
2018-10-24 02:06:07 +02:00
return blink ( SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] , false , true ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Classic Blink effect . Cycling through the rainbow .
*/
uint16_t WS2812FX : : mode_blink_rainbow ( void ) {
2018-10-24 02:06:07 +02:00
return blink ( color_wheel ( SEGMENT_RUNTIME . counter_mode_call & 0xFF ) , SEGMENT . colors [ 1 ] , false , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Classic Strobe effect .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_strobe ( void ) {
2018-10-24 02:06:07 +02:00
return blink ( SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] , true , true ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Classic Strobe effect . Cycling through the rainbow .
*/
uint16_t WS2812FX : : mode_strobe_rainbow ( void ) {
2018-10-24 02:06:07 +02:00
return blink ( color_wheel ( SEGMENT_RUNTIME . counter_mode_call & 0xFF ) , SEGMENT . colors [ 1 ] , true , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Color wipe function
* LEDs are turned on ( color1 ) in sequence , then turned off ( color2 ) in sequence .
* if ( bool rev = = true ) then LEDs are turned off in reverse order
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : color_wipe ( uint32_t color1 , uint32_t color2 , bool rev , bool dopalette ) {
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step < SEGMENT_LENGTH ) {
uint32_t led_offset = SEGMENT_RUNTIME . counter_mode_step ;
2018-10-24 02:06:07 +02:00
uint16_t i = SEGMENT . start + led_offset ;
setPixelColor ( i , dopalette ? color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) : color1 ) ;
2018-09-04 15:51:38 +02:00
} else {
uint32_t led_offset = SEGMENT_RUNTIME . counter_mode_step - SEGMENT_LENGTH ;
if ( rev ) {
setPixelColor ( SEGMENT . stop - led_offset , color2 ) ;
} else {
setPixelColor ( SEGMENT . start + led_offset , color2 ) ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % ( SEGMENT_LENGTH * 2 ) ;
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Lights all LEDs one after another .
*/
uint16_t WS2812FX : : mode_color_wipe ( void ) {
2018-10-24 02:06:07 +02:00
return color_wipe ( SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] , false , true ) ;
2018-09-04 15:51:38 +02:00
}
/*
* Lights all LEDs one after another . Turns off opposite
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_color_sweep ( void ) {
2018-10-24 02:06:07 +02:00
return color_wipe ( SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] , true , true ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Turns all LEDs after each other to a random color .
* Then starts over with another color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_color_wipe_random ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_step % SEGMENT_LENGTH = = 0 ) { // aux_param will store our random color wheel index
SEGMENT_RUNTIME . aux_param = get_random_wheel_index ( SEGMENT_RUNTIME . aux_param ) ;
2018-04-01 00:08:50 +02:00
}
2018-09-04 15:51:38 +02:00
uint32_t color = color_wheel ( SEGMENT_RUNTIME . aux_param ) ;
2018-10-24 02:06:07 +02:00
return color_wipe ( color , color , false , false ) ;
2018-09-04 15:51:38 +02:00
}
/*
* Random color introduced alternating from start and end of strip .
*/
uint16_t WS2812FX : : mode_color_sweep_random ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_step % SEGMENT_LENGTH = = 0 ) { // aux_param will store our random color wheel index
SEGMENT_RUNTIME . aux_param = get_random_wheel_index ( SEGMENT_RUNTIME . aux_param ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint32_t color = color_wheel ( SEGMENT_RUNTIME . aux_param ) ;
2018-10-24 02:06:07 +02:00
return color_wipe ( color , color , true , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Lights all LEDs in one random color up . Then switches them
* to the next random color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_random_color ( void ) {
SEGMENT_RUNTIME . aux_param = get_random_wheel_index ( SEGMENT_RUNTIME . aux_param ) ; // aux_param will store our random color wheel index
uint32_t color = color_wheel ( SEGMENT_RUNTIME . aux_param ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , color ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return 50 + ( 20 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Lights every LED in a random color . Changes all LED at the same time
* to new random colors .
*/
uint16_t WS2812FX : : mode_dynamic ( void ) {
if ( SEGMENT . intensity > 127 | | SEGMENT_RUNTIME . counter_mode_call = = 0 ) {
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_wheel ( random8 ( ) ) ) ;
}
2016-12-17 23:43:07 +01:00
}
2019-01-31 23:42:48 +01:00
setPixelColor ( SEGMENT . start + random16 ( SEGMENT_LENGTH ) , color_wheel ( random8 ( ) ) ) ;
2018-09-04 15:51:38 +02:00
return 50 + ( 15 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Does the " standby-breathing " of well known i - Devices . Fixed Speed .
* Use mode " fade " if you like to have something similar with a different speed .
*/
uint16_t WS2812FX : : mode_breath ( void ) {
int lum = SEGMENT_RUNTIME . counter_mode_step ;
if ( lum > 255 ) lum = 511 - lum ; // lum = 15 -> 255 -> 15
uint16_t delay ;
2018-10-24 02:06:07 +02:00
if ( lum = = 15 ) delay = 465 ; // 970 pause before each breath
else if ( lum < = 25 ) delay = 19 ; // 19
else if ( lum < = 50 ) delay = 18 ; // 18
else if ( lum < = 75 ) delay = 14 ; // 14
else if ( lum < = 100 ) delay = 10 ; // 10
else if ( lum < = 125 ) delay = 7 ; // 7
else if ( lum < = 150 ) delay = 5 ; // 5
else delay = 4 ; // 4
if ( SEGMENT . palette = = 0 )
{
uint32_t color = SEGMENT . colors [ 0 ] ;
2019-02-02 15:31:43 +01:00
uint8_t w = ( ( color > > 24 & 0xFF ) * lum ) > > 8 ;
uint8_t r = ( ( color > > 16 & 0xFF ) * lum ) > > 8 ;
uint8_t g = ( ( color > > 8 & 0xFF ) * lum ) > > 8 ;
uint8_t b = ( ( color & 0xFF ) * lum ) > > 8 ;
2018-10-24 02:06:07 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , r , g , b , w ) ;
}
} else
{
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 , lum ) ) ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + = 2 ;
if ( SEGMENT_RUNTIME . counter_mode_step > ( 512 - 15 ) ) SEGMENT_RUNTIME . counter_mode_step = 15 ;
2018-10-24 02:06:07 +02:00
return delay * ( ( ( 256 - SEGMENT . speed ) / 64 ) + 1 ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Fades the LEDs between two colors
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fade ( void ) {
int lum = SEGMENT_RUNTIME . counter_mode_step ;
if ( lum > 255 ) lum = 511 - lum ; // lum = 0 -> 255 -> 0
2019-02-02 15:31:43 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_blend ( color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) , SEGMENT . colors [ 1 ] , lum ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + = 4 ;
if ( SEGMENT_RUNTIME . counter_mode_step > 511 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
return 5 + ( ( 15 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-10-24 02:06:07 +02:00
* Scan mode parent function
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : scan ( bool dual )
{
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step > ( SEGMENT_LENGTH * 2 ) - 3 ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
2016-12-17 23:43:07 +01:00
}
2019-02-02 15:31:43 +01:00
fill ( SEGMENT . colors [ 1 ] ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
int led_offset = SEGMENT_RUNTIME . counter_mode_step - ( SEGMENT_LENGTH - 1 ) ;
2018-10-24 02:06:07 +02:00
led_offset = abs ( led_offset ) ;
uint16_t i = SEGMENT . start + led_offset ;
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
if ( dual ) {
uint16_t i2 = SEGMENT . start + SEGMENT_LENGTH - led_offset - 1 ;
setPixelColor ( i2 , color_from_palette ( i2 , true , PALETTE_SOLID_WRAP , 0 ) ) ;
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + + ;
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
//TODO add intensity (more than 1 pixel lit)
2016-12-17 23:43:07 +01:00
/*
2018-10-24 02:06:07 +02:00
* Runs a single pixel back and forth .
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : mode_scan ( void ) {
return scan ( false ) ;
}
2018-09-04 15:51:38 +02:00
2018-10-24 02:06:07 +02:00
/*
* Runs two pixel back and forth in opposite directions .
*/
uint16_t WS2812FX : : mode_dual_scan ( void ) {
return scan ( true ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Cycles all LEDs at once through a rainbow .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_rainbow ( void ) {
uint32_t color = color_wheel ( SEGMENT_RUNTIME . counter_mode_step ) ;
2019-02-02 15:31:43 +01:00
fill ( color ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) & 0xFF ;
return 1 + ( ( ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 5 ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Cycles a rainbow over the entire string of LEDs .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_rainbow_cycle ( void ) {
for ( uint16_t i = 0 ; i < SEGMENT_LENGTH ; i + + ) {
uint32_t color = color_wheel ( ( ( i * 256 / ( ( uint16_t ) ( SEGMENT_LENGTH * ( float ) ( SEGMENT . intensity / 128.0 ) ) + 1 ) ) + SEGMENT_RUNTIME . counter_mode_step ) & 0xFF ) ;
setPixelColor ( SEGMENT . start + i , color ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) & 0xFF ;
return 1 + ( ( ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 5 ) ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* theater chase function
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : theater_chase ( uint32_t color1 , uint32_t color2 , bool dopalette ) {
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_call = SEGMENT_RUNTIME . counter_mode_call % 3 ;
for ( uint16_t i = 0 ; i < SEGMENT_LENGTH ; i + + ) {
if ( ( i % 3 ) = = SEGMENT_RUNTIME . counter_mode_call ) {
2018-10-24 02:06:07 +02:00
if ( dopalette )
{
setPixelColor ( SEGMENT . start + i , color_from_palette ( SEGMENT . start + i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else {
setPixelColor ( SEGMENT . start + i , color1 ) ;
}
2018-09-04 15:51:38 +02:00
} else {
setPixelColor ( SEGMENT . start + i , color2 ) ;
}
}
return 50 + ( 2 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Theatre - style crawling lights .
* Inspired by the Adafruit examples .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_theater_chase ( void ) {
2018-10-24 02:06:07 +02:00
return theater_chase ( SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] , true ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Theatre - style crawling lights with rainbow effect .
* Inspired by the Adafruit examples .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_theater_chase_rainbow ( void ) {
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) & 0xFF ;
2018-10-24 02:06:07 +02:00
return theater_chase ( color_wheel ( SEGMENT_RUNTIME . counter_mode_step ) , SEGMENT . colors [ 1 ] , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Running lights effect with smooth sine transition .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_lights ( void ) {
2019-01-31 23:42:48 +01:00
uint8_t x_scale = ( SEGMENT . intensity > > 3 ) + ( SEGMENT . intensity > > 4 ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = 0 ; i < SEGMENT_LENGTH ; i + + ) {
2019-01-31 23:42:48 +01:00
uint8_t s = sin8 ( i * x_scale + ( SEGMENT_RUNTIME . counter_mode_step > > 3 ) ) ;
setPixelColor ( SEGMENT . start + i , color_blend ( SEGMENT . colors [ 1 ] , color_from_palette ( SEGMENT . start + i , true , PALETTE_SOLID_WRAP , 0 ) , s ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-01-31 23:42:48 +01:00
SEGMENT_RUNTIME . counter_mode_step + = SEGMENT . speed ;
return 20 ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* twinkle function
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : twinkle ( uint32_t color ) {
if ( SEGMENT_RUNTIME . counter_mode_step = = 0 ) {
2019-02-02 15:31:43 +01:00
fill ( SEGMENT . colors [ 1 ] ) ;
2019-01-31 23:42:48 +01:00
SEGMENT_RUNTIME . counter_mode_step = map ( SEGMENT . intensity , 0 , 255 , 1 , SEGMENT_LENGTH ) ; // make sure, at least one LED is on
2016-12-17 23:43:07 +01:00
}
2019-01-31 23:42:48 +01:00
uint16_t i = SEGMENT . start + random16 ( SEGMENT_LENGTH ) ;
2018-10-24 02:06:07 +02:00
if ( color = = SEGMENT . colors [ 0 ] )
{
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else {
setPixelColor ( i , color ) ;
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step - - ;
2019-01-31 23:42:48 +01:00
return 20 + ( 5 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
/*
* Blink several LEDs on , reset , repeat .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
uint16_t WS2812FX : : mode_twinkle ( void ) {
return twinkle ( SEGMENT . colors [ 0 ] ) ;
}
2016-12-17 23:43:07 +01:00
/*
* Blink several LEDs in random colors on , reset , repeat .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_twinkle_random ( void ) {
return twinkle ( color_wheel ( random8 ( ) ) ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* fade out function
* fades out the current segment by dividing each pixel ' s intensity by 2
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
void WS2812FX : : fade_out ( uint8_t rate ) {
static const float rateMap [ ] = { 1.1 , 1.20 , 1.5 , 2.0 , 4.0 , 8.0 , 16.0 , 64.0 } ;
if ( rate > 7 ) rate = 7 ;
float mappedRate = rateMap [ rate ] ;
uint32_t color = SEGMENT . colors [ 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 = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
color = getPixelColor ( i ) ;
2019-02-02 15:31:43 +01:00
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 , w1 + wdelta ) ;
2018-09-04 15:51:38 +02:00
}
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
2019-01-31 23:42:48 +01:00
* Dissolve function
2018-09-04 15:51:38 +02:00
*/
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : dissolve ( uint32_t color ) {
bool wa = ( SEGMENT . colors [ 1 ] ! = 0 & & _brightness < 255 ) ; //workaround, can't compare getPixel to color if not full brightness
for ( uint16_t j = 0 ; j < = SEGMENT_LENGTH / 15 ; j + + )
{
if ( random8 ( ) < = SEGMENT . intensity ) {
for ( uint8_t times = 0 ; times < 10 ; times + + ) //attempt to spawn a new pixel 5 times
{
uint16_t i = SEGMENT . start + random16 ( SEGMENT_LENGTH ) ;
if ( SEGMENT_RUNTIME . aux_param ) { //dissolve to primary/palette
if ( getPixelColor ( i ) = = SEGMENT . colors [ 1 ] | | wa ) {
if ( color = = SEGMENT . colors [ 0 ] )
{
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else { setPixelColor ( i , color ) ; }
break ; //only spawn 1 new pixel per frame per 50 LEDs
}
} else { //dissolve to secondary
if ( getPixelColor ( i ) ! = SEGMENT . colors [ 1 ] ) { setPixelColor ( i , SEGMENT . colors [ 1 ] ) ; break ; }
}
}
2018-10-24 02:06:07 +02:00
}
2016-12-17 23:43:07 +01:00
}
2019-01-31 23:42:48 +01:00
if ( SEGMENT_RUNTIME . counter_mode_call > ( 255 - SEGMENT . speed ) + 15 )
{
SEGMENT_RUNTIME . aux_param = ! SEGMENT_RUNTIME . aux_param ;
SEGMENT_RUNTIME . counter_mode_call = 0 ;
}
2018-10-24 02:06:07 +02:00
2019-01-31 23:42:48 +01:00
return 20 ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
2019-01-31 23:42:48 +01:00
* Blink several LEDs on and then off
2018-09-04 15:51:38 +02:00
*/
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : mode_dissolve ( void ) {
return dissolve ( SEGMENT . colors [ 0 ] ) ;
2016-12-17 23:43:07 +01:00
}
/*
2019-01-31 23:42:48 +01:00
* Blink several LEDs on and then off in random colors
2016-12-17 23:43:07 +01:00
*/
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : mode_dissolve_random ( void ) {
return dissolve ( color_wheel ( random8 ( ) ) ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Blinks one LED at a time .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_sparkle ( void ) {
2018-10-24 02:06:07 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
}
2019-01-31 23:42:48 +01:00
SEGMENT_RUNTIME . aux_param = random16 ( SEGMENT_LENGTH ) ; // aux_param stores the random led index
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . aux_param , SEGMENT . colors [ 0 ] ) ;
return 10 + ( uint16_t ) ( 255 - SEGMENT . speed ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Lights all LEDs in the color . Flashes single white pixels randomly .
2016-12-17 23:43:07 +01:00
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_flash_sparkle ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_call = = 0 ) {
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
uint16_t i = SEGMENT . start + SEGMENT_RUNTIME . aux_param ;
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
if ( random8 ( 5 ) = = 0 ) {
2019-01-31 23:42:48 +01:00
SEGMENT_RUNTIME . aux_param = random16 ( SEGMENT_LENGTH ) ; // aux_param stores the random led index
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . aux_param , SEGMENT . colors [ 1 ] ) ;
return 20 ;
}
return 20 + ( uint16_t ) ( 255 - SEGMENT . speed ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Like flash sparkle . With more flash .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_hyper_sparkle ( void ) {
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
if ( random8 ( 5 ) < 2 ) {
for ( uint16_t i = 0 ; i < max ( 1 , SEGMENT_LENGTH / 3 ) ; i + + ) {
2019-01-31 23:42:48 +01:00
setPixelColor ( SEGMENT . start + random16 ( SEGMENT_LENGTH ) , SEGMENT . colors [ 1 ] ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 + ( uint16_t ) ( 255 - SEGMENT . speed ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Strobe effect with different strobe count and pause , controlled by speed .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_multi_strobe ( void ) {
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t delay = 50 + 20 * ( uint16_t ) ( 255 - SEGMENT . speed ) ;
uint16_t count = 2 * ( ( SEGMENT . speed / 10 ) + 1 ) ;
if ( SEGMENT_RUNTIME . counter_mode_step < count ) {
if ( ( SEGMENT_RUNTIME . counter_mode_step & 1 ) = = 0 ) {
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , SEGMENT . colors [ 0 ] ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
delay = 20 ;
2016-12-17 23:43:07 +01:00
} else {
2018-09-04 15:51:38 +02:00
delay = 50 ;
2017-11-28 15:09:58 +01:00
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % ( count + 1 ) ;
return delay ;
2016-12-17 23:43:07 +01:00
}
/*
2018-03-18 23:16:53 +01:00
* Android loading circle
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_android ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_call = = 0 )
{
SEGMENT_RUNTIME . aux_param = 0 ;
SEGMENT_RUNTIME . counter_mode_step = SEGMENT . start ;
}
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . aux_param2 > ( ( float ) SEGMENT . intensity / 255.0 ) * ( float ) SEGMENT_LENGTH )
2018-03-18 23:16:53 +01:00
{
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . aux_param = 1 ;
2018-03-18 23:16:53 +01:00
} else
{
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . aux_param2 < 2 ) SEGMENT_RUNTIME . aux_param = 0 ;
2018-03-18 23:16:53 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t a = SEGMENT_RUNTIME . counter_mode_step ;
2018-03-18 23:16:53 +01:00
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . aux_param = = 0 )
2018-03-18 23:16:53 +01:00
{
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_call % 3 = = 1 ) { a + + ; }
else { SEGMENT_RUNTIME . aux_param2 + + ; }
2018-03-18 23:16:53 +01:00
} else
{
a + + ;
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_call % 3 ! = 1 ) SEGMENT_RUNTIME . aux_param2 - - ;
2018-03-18 23:16:53 +01:00
}
2018-09-04 15:51:38 +02:00
if ( a > SEGMENT . stop ) a = SEGMENT . start ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
if ( a + SEGMENT_RUNTIME . aux_param2 < = SEGMENT . stop )
2018-03-18 23:16:53 +01:00
{
2018-09-04 15:51:38 +02:00
for ( int i = a ; i < a + SEGMENT_RUNTIME . aux_param2 ; i + + ) {
setPixelColor ( i , SEGMENT . colors [ 0 ] ) ;
2018-03-18 23:16:53 +01:00
}
} else
{
2018-09-04 15:51:38 +02:00
for ( int i = a ; i < = SEGMENT . stop ; i + + ) {
setPixelColor ( i , SEGMENT . colors [ 0 ] ) ;
2018-03-18 23:16:53 +01:00
}
2018-09-04 15:51:38 +02:00
for ( int i = SEGMENT . start ; i < SEGMENT_RUNTIME . aux_param2 - ( SEGMENT . stop + 1 - a ) ; i + + ) {
setPixelColor ( i , SEGMENT . colors [ 0 ] ) ;
2018-03-18 23:16:53 +01:00
}
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = a ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
return 3 + ( ( 8 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / SEGMENT_LENGTH ) ;
}
2016-12-17 23:43:07 +01:00
/*
2018-09-04 15:51:38 +02:00
* color chase function .
* color1 = background color
* color2 and color3 = colors of two adjacent leds
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : chase ( uint32_t color1 , uint32_t color2 , uint32_t color3 , uint8_t dopalette ) {
2018-09-04 15:51:38 +02:00
uint16_t a = SEGMENT_RUNTIME . counter_mode_step ;
uint16_t b = ( a + 1 ) % SEGMENT_LENGTH ;
uint16_t c = ( b + 1 ) % SEGMENT_LENGTH ;
2018-10-24 02:06:07 +02:00
switch ( dopalette )
{
case 0 : break ;
case 1 : color1 = color_from_palette ( SEGMENT . start + a , true , PALETTE_SOLID_WRAP , 1 ) ; break ;
case 2 : color2 = color_from_palette ( SEGMENT . start + b , true , PALETTE_SOLID_WRAP , 1 ) ; break ;
case 3 : color3 = color_from_palette ( SEGMENT . start + c , true , PALETTE_SOLID_WRAP , 1 ) ; break ;
}
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + a , color1 ) ;
setPixelColor ( SEGMENT . start + b , color2 ) ;
setPixelColor ( SEGMENT . start + c , color3 ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
return SPEED_FORMULA_L ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Bicolor chase , more primary color .
*/
uint16_t WS2812FX : : mode_chase_color ( void ) {
2018-10-24 02:06:07 +02:00
return chase ( SEGMENT . colors [ 1 ] , SEGMENT . colors [ 0 ] , SEGMENT . colors [ 0 ] , 1 ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-10-25 20:55:29 +02:00
2016-12-17 23:43:07 +01:00
/*
2018-09-04 15:51:38 +02:00
* Primary running followed by random color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_chase_random ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_step = = 0 ) {
SEGMENT_RUNTIME . aux_param = get_random_wheel_index ( SEGMENT_RUNTIME . aux_param ) ;
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
return chase ( color_wheel ( SEGMENT_RUNTIME . aux_param ) , SEGMENT . colors [ 0 ] , SEGMENT . colors [ 0 ] , 0 ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Primary running on rainbow .
*/
uint16_t WS2812FX : : mode_chase_rainbow_white ( void ) {
uint16_t n = SEGMENT_RUNTIME . counter_mode_step ;
uint16_t m = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
uint32_t color2 = color_wheel ( ( ( n * 256 / SEGMENT_LENGTH ) + ( SEGMENT_RUNTIME . counter_mode_call & 0xFF ) ) & 0xFF ) ;
uint32_t color3 = color_wheel ( ( ( m * 256 / SEGMENT_LENGTH ) + ( SEGMENT_RUNTIME . counter_mode_call & 0xFF ) ) & 0xFF ) ;
2018-10-24 02:06:07 +02:00
return chase ( SEGMENT . colors [ 0 ] , color2 , color3 , 0 ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Red - Amber - Green - Blue lights running
*/
uint16_t WS2812FX : : mode_colorful ( void ) {
uint32_t cols [ ] { 0x00FF0000 , 0x00EEBB00 , 0x0000EE00 , 0x000077CC , 0x00FF0000 , 0x00EEBB00 , 0x0000EE00 } ;
if ( SEGMENT . intensity < 127 ) //pastel (easter) colors
{
cols [ 0 ] = 0x00FF8040 ;
cols [ 1 ] = 0x00E5D241 ;
cols [ 2 ] = 0x0077FF77 ;
cols [ 3 ] = 0x0077F0F0 ;
for ( uint8_t i = 4 ; i < 7 ; i + + ) cols [ i ] = cols [ i - 4 ] ;
}
int i = SEGMENT . start ;
for ( i ; i < = SEGMENT . stop ; i + = 4 )
{
setPixelColor ( i , cols [ SEGMENT_RUNTIME . counter_mode_step ] ) ;
setPixelColor ( i + 1 , cols [ SEGMENT_RUNTIME . counter_mode_step + 1 ] ) ;
setPixelColor ( i + 2 , cols [ SEGMENT_RUNTIME . counter_mode_step + 2 ] ) ;
setPixelColor ( i + 3 , cols [ SEGMENT_RUNTIME . counter_mode_step + 3 ] ) ;
}
i + = 4 ;
if ( i < = SEGMENT . stop )
{
setPixelColor ( i , cols [ SEGMENT_RUNTIME . counter_mode_step ] ) ;
if ( i + 1 < = SEGMENT . stop )
{
setPixelColor ( i + 1 , cols [ SEGMENT_RUNTIME . counter_mode_step + 1 ] ) ;
if ( i + 2 < = SEGMENT . stop )
{
setPixelColor ( i + 2 , cols [ SEGMENT_RUNTIME . counter_mode_step + 2 ] ) ;
}
}
}
if ( SEGMENT . speed > 0 ) SEGMENT_RUNTIME . counter_mode_step + + ; //static if lowest speed
if ( SEGMENT_RUNTIME . counter_mode_step > 3 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
return 50 + ( 15 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Emulates a traffic light .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_traffic_light ( void ) {
2018-10-24 02:06:07 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + )
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
2018-09-04 15:51:38 +02:00
uint32_t mdelay = 500 ;
for ( int i = SEGMENT . start ; i < SEGMENT . stop - 1 ; i + = 3 )
{
switch ( SEGMENT_RUNTIME . counter_mode_step )
{
case 0 : setPixelColor ( i , 0x00FF0000 ) ; mdelay = 150 + ( 100 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; break ;
case 1 : setPixelColor ( i , 0x00FF0000 ) ; mdelay = 150 + ( 20 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; setPixelColor ( i + 1 , 0x00EECC00 ) ; break ;
case 2 : setPixelColor ( i + 2 , 0x0000FF00 ) ; mdelay = 150 + ( 100 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; break ;
case 3 : setPixelColor ( i + 1 , 0x00EECC00 ) ; mdelay = 150 + ( 20 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; break ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( SEGMENT_RUNTIME . counter_mode_step > 3 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
return mdelay ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Primary , secondary running on rainbow .
*/
uint16_t WS2812FX : : mode_chase_rainbow ( void ) {
uint8_t color_sep = 256 / SEGMENT_LENGTH ;
uint8_t color_index = SEGMENT_RUNTIME . counter_mode_call & 0xFF ;
uint32_t color = color_wheel ( ( ( SEGMENT_RUNTIME . counter_mode_step * color_sep ) + color_index ) & 0xFF ) ;
2018-10-24 02:06:07 +02:00
return chase ( color , SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] , 0 ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Sec flashes running on prim .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_chase_flash ( void ) {
const static uint8_t flash_count = 4 ;
uint8_t flash_step = SEGMENT_RUNTIME . counter_mode_call % ( ( flash_count * 2 ) + 1 ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t delay = 10 + ( ( 30 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) / SEGMENT_LENGTH ) ;
2016-12-17 23:43:07 +01:00
if ( flash_step < ( flash_count * 2 ) ) {
if ( flash_step % 2 = = 0 ) {
2018-09-04 15:51:38 +02:00
uint16_t n = SEGMENT_RUNTIME . counter_mode_step ;
uint16_t m = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
setPixelColor ( SEGMENT . start + n , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + m , SEGMENT . colors [ 1 ] ) ;
delay = 20 ;
2016-12-17 23:43:07 +01:00
} else {
2018-09-04 15:51:38 +02:00
delay = 30 ;
2016-12-17 23:43:07 +01:00
}
} else {
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return delay ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Prim flashes running , followed by random color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_chase_flash_random ( void ) {
const static uint8_t flash_count = 4 ;
uint8_t flash_step = SEGMENT_RUNTIME . counter_mode_call % ( ( flash_count * 2 ) + 1 ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = 0 ; i < SEGMENT_RUNTIME . counter_mode_step ; i + + ) {
setPixelColor ( SEGMENT . start + i , color_wheel ( SEGMENT_RUNTIME . aux_param ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t delay = 1 + ( ( 10 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) / SEGMENT_LENGTH ) ;
2016-12-17 23:43:07 +01:00
if ( flash_step < ( flash_count * 2 ) ) {
2018-09-04 15:51:38 +02:00
uint16_t n = SEGMENT_RUNTIME . counter_mode_step ;
uint16_t m = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
2016-12-17 23:43:07 +01:00
if ( flash_step % 2 = = 0 ) {
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + n , SEGMENT . colors [ 0 ] ) ;
setPixelColor ( SEGMENT . start + m , SEGMENT . colors [ 0 ] ) ;
delay = 20 ;
2016-12-17 23:43:07 +01:00
} else {
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + n , color_wheel ( SEGMENT_RUNTIME . aux_param ) ) ;
setPixelColor ( SEGMENT . start + m , SEGMENT . colors [ 1 ] ) ;
delay = 30 ;
2016-12-17 23:43:07 +01:00
}
} else {
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step = = 0 ) {
SEGMENT_RUNTIME . aux_param = get_random_wheel_index ( SEGMENT_RUNTIME . aux_param ) ;
2016-12-17 23:43:07 +01:00
}
}
2018-09-04 15:51:38 +02:00
return delay ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Alternating pixels running function .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : running ( uint32_t color1 , uint32_t color2 ) {
for ( uint16_t i = 0 ; i < SEGMENT_LENGTH ; i + + ) {
if ( ( i + SEGMENT_RUNTIME . counter_mode_step ) % 4 < 2 ) {
2018-10-24 02:06:07 +02:00
if ( color1 = = SEGMENT . colors [ 0 ] )
{
setPixelColor ( SEGMENT . stop - i , color_from_palette ( SEGMENT . stop - i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else
{
setPixelColor ( SEGMENT . stop - i , color1 ) ;
}
2018-09-04 15:51:38 +02:00
} else {
setPixelColor ( SEGMENT . stop - i , color2 ) ;
}
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
if ( SEGMENT . speed ! = 0 ) SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) & 0x3 ;
2018-09-04 15:51:38 +02:00
return 35 + ( ( 350 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-10-24 02:06:07 +02:00
* Alternating color / sec pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_color ( void ) {
2018-10-24 02:06:07 +02:00
return running ( SEGMENT . colors [ 0 ] , SEGMENT . colors [ 1 ] ) ;
2018-04-01 00:08:50 +02:00
}
2018-09-04 15:51:38 +02:00
2018-04-01 00:08:50 +02:00
/*
2018-09-04 15:51:38 +02:00
* Alternating red / blue pixels running .
2018-04-01 00:08:50 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_red_blue ( void ) {
return running ( RED , BLUE ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Alternating red / green pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_merry_christmas ( void ) {
return running ( RED , GREEN ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Alternating orange / purple pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_halloween ( void ) {
return running ( PURPLE , ORANGE ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Random colored pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_random ( void ) {
for ( uint16_t i = SEGMENT_LENGTH - 1 ; i > 0 ; i - - ) {
setPixelColor ( SEGMENT . start + i , getPixelColor ( SEGMENT . start + i - 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step = = 0 ) {
SEGMENT_RUNTIME . aux_param = get_random_wheel_index ( SEGMENT_RUNTIME . aux_param ) ;
setPixelColor ( SEGMENT . start , color_wheel ( SEGMENT_RUNTIME . aux_param ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step = = 0 ) ? 1 : 0 ;
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* K . I . T . T .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_larson_scanner ( void ) {
fade_out ( ( 255 - SEGMENT . intensity ) / 32 ) ;
2016-12-17 23:43:07 +01:00
2018-10-24 02:06:07 +02:00
uint16_t index = 0 ;
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step < SEGMENT_LENGTH ) {
2018-10-24 02:06:07 +02:00
index = SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step ;
2018-09-04 15:51:38 +02:00
} else {
2018-10-24 02:06:07 +02:00
index = SEGMENT . start + ( ( SEGMENT_LENGTH * 2 ) - SEGMENT_RUNTIME . counter_mode_step ) - 2 ;
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % ( ( SEGMENT_LENGTH * 2 ) - 2 ) ;
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Firing comets from one end .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_comet ( void ) {
fade_out ( ( 255 - SEGMENT . intensity ) / 32 ) ;
2016-12-17 23:43:07 +01:00
2018-10-24 02:06:07 +02:00
uint16_t index = SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step ;
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % SEGMENT_LENGTH ;
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Fireworks function .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : fireworks ( uint32_t color ) {
uint32_t prevLed , thisLed , nextLed ;
2016-12-17 23:43:07 +01:00
2018-10-24 02:06:07 +02:00
fade_out ( 3 ) ;
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
// set brightness(i) = ((brightness(i-1)/4 + brightness(i+1))/4) + brightness(i)
for ( uint16_t i = SEGMENT . start + 1 ; i < SEGMENT . stop ; i + + ) {
prevLed = ( getPixelColor ( i - 1 ) > > 2 ) & 0x3F3F3F3F ;
thisLed = getPixelColor ( i ) ;
nextLed = ( getPixelColor ( i + 1 ) > > 2 ) & 0x3F3F3F3F ;
setPixelColor ( i , prevLed + thisLed + nextLed ) ;
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
for ( uint16_t i = 0 ; i < max ( 1 , SEGMENT_LENGTH / 20 ) ; i + + ) {
if ( random8 ( ( 255 - SEGMENT . intensity ) / 8 ) = = 0 ) {
2019-01-31 23:42:48 +01:00
uint16_t index = SEGMENT . start + random16 ( SEGMENT_LENGTH ) ;
2018-10-24 02:06:07 +02:00
if ( color = = SEGMENT . colors [ 0 ] )
{
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else
{
setPixelColor ( index , color ) ;
2018-09-04 15:51:38 +02:00
}
}
}
2018-10-24 02:06:07 +02:00
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
* Firework sparks .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fireworks ( void ) {
uint32_t color = SEGMENT . colors [ 0 ] ;
return fireworks ( color ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Random colored firework sparks .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fireworks_random ( void ) {
uint32_t color = color_wheel ( random8 ( ) ) ;
return fireworks ( color ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Fire flicker function
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fire_flicker ( void ) {
byte w = ( SEGMENT . colors [ 0 ] > > 24 ) & 0xFF ;
byte r = ( SEGMENT . colors [ 0 ] > > 16 ) & 0xFF ;
byte g = ( SEGMENT . colors [ 0 ] > > 8 ) & 0xFF ;
byte b = ( SEGMENT . colors [ 0 ] & 0xFF ) ;
2018-10-24 02:06:07 +02:00
byte lum = ( SEGMENT . palette = = 0 ) ? max ( w , max ( r , max ( g , b ) ) ) : 255 ;
lum / = ( ( ( 256 - SEGMENT . intensity ) / 16 ) + 1 ) ;
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
byte flicker = random8 ( lum ) ;
if ( SEGMENT . palette = = 0 ) {
setPixelColor ( i , max ( r - flicker , 0 ) , max ( g - flicker , 0 ) , max ( b - flicker , 0 ) , max ( w - flicker , 0 ) ) ;
} else {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 , 255 - flicker ) ) ;
}
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return 10 + ( 2 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-03-18 23:16:53 +01:00
/*
* Gradient run
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_gradient ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_call = = 0 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
byte p_w = ( SEGMENT . colors [ 0 ] & 0xFF000000 ) > > 24 ;
2019-02-02 15:31:43 +01:00
byte p_r = ( SEGMENT . colors [ 0 ] & 0xFF0000 ) > > 16 ;
byte p_g = ( SEGMENT . colors [ 0 ] & 0xFF00 ) > > 8 ;
byte p_b = SEGMENT . colors [ 0 ] & 0xFF ;
2018-09-04 15:51:38 +02:00
byte p_w2 = ( SEGMENT . colors [ 1 ] & 0xFF000000 ) > > 24 ;
2019-02-02 15:31:43 +01:00
byte p_r2 = ( SEGMENT . colors [ 1 ] & 0xFF0000 ) > > 16 ;
byte p_g2 = ( SEGMENT . colors [ 1 ] & 0xFF00 ) > > 8 ;
byte p_b2 = SEGMENT . colors [ 1 ] & 0xFF ;
2018-03-18 23:16:53 +01:00
byte nw , nr , ng , nb ;
float per , val ; //0.0 = sec 1.0 = pri
2018-09-04 15:51:38 +02:00
float brd = SEGMENT . intensity / 2 ; if ( brd < 1.0 ) brd = 1.0 ;
int pp = SEGMENT_RUNTIME . counter_mode_step ;
int p1 = pp - SEGMENT_LENGTH ;
int p2 = pp + SEGMENT_LENGTH ;
2018-03-18 23:16:53 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + )
2018-03-18 23:16:53 +01:00
{
2018-09-04 15:51:38 +02:00
val = min ( abs ( pp - i ) , min ( abs ( p1 - i ) , abs ( p2 - i ) ) ) ;
2018-03-18 23:16:53 +01:00
per = val / brd ;
if ( per > 1.0 ) per = 1.0 ;
nw = p_w + ( ( p_w2 - p_w ) * per ) ;
nr = p_r + ( ( p_r2 - p_r ) * per ) ;
ng = p_g + ( ( p_g2 - p_g ) * per ) ;
nb = p_b + ( ( p_b2 - p_b ) * per ) ;
setPixelColor ( i , nr , ng , nb , nw ) ;
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( SEGMENT_RUNTIME . counter_mode_step > SEGMENT . stop ) SEGMENT_RUNTIME . counter_mode_step = SEGMENT . start ;
if ( SEGMENT . speed = = 0 ) SEGMENT_RUNTIME . counter_mode_step = SEGMENT . start + ( SEGMENT_LENGTH > > 1 ) ;
return SPEED_FORMULA_L ;
2018-03-18 23:16:53 +01:00
}
2016-12-31 17:36:07 +01:00
2018-09-04 15:51:38 +02:00
2018-03-18 23:16:53 +01:00
/*
* Gradient run with hard transition
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_loading ( void ) {
if ( SEGMENT_RUNTIME . counter_mode_call = = 0 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
byte p_w = ( SEGMENT . colors [ 0 ] & 0xFF000000 ) > > 24 ;
byte p_r = ( SEGMENT . colors [ 0 ] & 0x00FF0000 ) > > 16 ;
byte p_g = ( SEGMENT . colors [ 0 ] & 0x0000FF00 ) > > 8 ;
byte p_b = ( SEGMENT . colors [ 0 ] & 0x000000FF ) > > 0 ;
byte p_w2 = ( SEGMENT . colors [ 1 ] & 0xFF000000 ) > > 24 ;
byte p_r2 = ( SEGMENT . colors [ 1 ] & 0x00FF0000 ) > > 16 ;
byte p_g2 = ( SEGMENT . colors [ 1 ] & 0x0000FF00 ) > > 8 ;
byte p_b2 = ( SEGMENT . colors [ 1 ] & 0x000000FF ) > > 0 ;
2018-03-18 23:16:53 +01:00
byte nw , nr , ng , nb ;
float per , val ; //0.0 = sec 1.0 = pri
2018-09-04 15:51:38 +02:00
float brd = SEGMENT . intensity ; if ( brd < 1.0 ) brd = 1.0 ;
int pp = SEGMENT_RUNTIME . counter_mode_step ;
int p1 = pp + SEGMENT_LENGTH ;
2018-03-18 23:16:53 +01:00
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + )
2018-03-18 23:16:53 +01:00
{
2018-09-04 15:51:38 +02:00
pp = SEGMENT_RUNTIME . counter_mode_step ;
if ( i > pp ) pp + = SEGMENT_LENGTH ;
2018-03-18 23:16:53 +01:00
val = abs ( pp - i ) ;
per = val / brd ;
if ( per > 1.0 ) per = 1.0 ;
nw = p_w + ( ( p_w2 - p_w ) * per ) ;
nr = p_r + ( ( p_r2 - p_r ) * per ) ;
ng = p_g + ( ( p_g2 - p_g ) * per ) ;
nb = p_b + ( ( p_b2 - p_b ) * per ) ;
setPixelColor ( i , nr , ng , nb , nw ) ;
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( SEGMENT_RUNTIME . counter_mode_step > SEGMENT . stop ) SEGMENT_RUNTIME . counter_mode_step = SEGMENT . start ;
if ( SEGMENT . speed = = 0 ) SEGMENT_RUNTIME . counter_mode_step = SEGMENT . stop ;
return SPEED_FORMULA_L ;
}
/*
* Lights all LEDs after each other up starting from the outer edges and
* finishing in the middle . Then turns them in reverse order off . Repeat .
*/
uint16_t WS2812FX : : mode_dual_color_wipe_in_out ( void ) {
int end = SEGMENT_LENGTH - SEGMENT_RUNTIME . counter_mode_step - 1 ;
bool odd = ( SEGMENT_LENGTH % 2 ) = = 1 ;
int mid = odd ? ( ( SEGMENT_LENGTH / 2 ) + 1 ) : ( SEGMENT_LENGTH / 2 ) ;
2018-10-24 02:06:07 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step < mid ) {
byte pindex = map ( SEGMENT_RUNTIME . counter_mode_step , 0 , mid - 1 , 0 , 255 ) ;
uint32_t col = color_from_palette ( pindex , false , false , 0 ) ;
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step , col ) ;
setPixelColor ( SEGMENT . start + end , col ) ;
2018-09-04 15:51:38 +02:00
} else {
if ( odd ) {
// If odd, we need to 'double count' the center LED (once to turn it on,
// once to turn it off). So trail one behind after the middle LED.
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step - 1 , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + end + 1 , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
} else {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + end , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
}
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( odd ) {
if ( SEGMENT_RUNTIME . counter_mode_step > SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step > = SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
}
return SPEED_FORMULA_L ;
}
/*
* Lights all LEDs after each other up starting from the outer edges and
* finishing in the middle . Then turns them in that order off . Repeat .
*/
uint16_t WS2812FX : : mode_dual_color_wipe_in_in ( void ) {
bool odd = ( SEGMENT_LENGTH % 2 ) = = 1 ;
2018-10-24 02:06:07 +02:00
int mid = SEGMENT_LENGTH / 2 ;
byte pindex = 0 ;
uint32_t col = 0 ;
if ( SEGMENT_RUNTIME . counter_mode_step < = mid )
{
pindex = map ( SEGMENT_RUNTIME . counter_mode_step , 0 , mid , 0 , 255 ) ;
col = color_from_palette ( pindex , false , false , 0 ) ;
}
2018-09-04 15:51:38 +02:00
if ( odd ) {
if ( SEGMENT_RUNTIME . counter_mode_step < = mid ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step , col ) ;
setPixelColor ( SEGMENT . start + SEGMENT_LENGTH - SEGMENT_RUNTIME . counter_mode_step - 1 , col ) ;
2018-09-04 15:51:38 +02:00
} else {
int i = SEGMENT_RUNTIME . counter_mode_step - mid ;
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + i - 1 , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + SEGMENT_LENGTH - i , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step < mid ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step , col ) ;
setPixelColor ( SEGMENT . start + SEGMENT_LENGTH - SEGMENT_RUNTIME . counter_mode_step - 1 , col ) ;
2018-09-04 15:51:38 +02:00
} else {
int i = SEGMENT_RUNTIME . counter_mode_step - mid ;
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + i , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + SEGMENT_LENGTH - i - 1 , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
}
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( odd ) {
if ( SEGMENT_RUNTIME . counter_mode_step > SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step > = SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
}
return SPEED_FORMULA_L ;
}
/*
* Lights all LEDs after each other up starting from the middle and
* finishing at the edges . Then turns them off in that order . Repeat .
*/
uint16_t WS2812FX : : mode_dual_color_wipe_out_out ( void ) {
int end = SEGMENT_LENGTH - SEGMENT_RUNTIME . counter_mode_step - 1 ;
bool odd = ( SEGMENT_LENGTH % 2 ) = = 1 ;
2018-10-24 02:06:07 +02:00
int mid = SEGMENT_LENGTH / 2 ;
byte pindex = 0 ;
uint32_t col = 0 ;
if ( SEGMENT_RUNTIME . counter_mode_step < = mid )
{
pindex = map ( SEGMENT_RUNTIME . counter_mode_step , 0 , mid , 255 , 0 ) ;
col = color_from_palette ( pindex , false , false , 0 ) ;
}
if ( odd ) {
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step < = mid ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + mid + SEGMENT_RUNTIME . counter_mode_step , col ) ;
setPixelColor ( SEGMENT . start + mid - SEGMENT_RUNTIME . counter_mode_step , col ) ;
2018-09-04 15:51:38 +02:00
} else {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step - 1 , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + end + 1 , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step < mid ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + mid - SEGMENT_RUNTIME . counter_mode_step - 1 , col ) ;
setPixelColor ( SEGMENT . start + mid + SEGMENT_RUNTIME . counter_mode_step , col ) ;
2018-09-04 15:51:38 +02:00
} else {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + end , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
}
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( odd ) {
if ( SEGMENT_RUNTIME . counter_mode_step > SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step > = SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
}
return SPEED_FORMULA_L ;
}
/*
* Lights all LEDs after each other up starting from the middle and
* finishing at the edges . Then turns them off in reverse order . Repeat .
*/
uint16_t WS2812FX : : mode_dual_color_wipe_out_in ( void ) {
bool odd = ( SEGMENT_LENGTH % 2 ) = = 1 ;
2018-10-24 02:06:07 +02:00
int mid = SEGMENT_LENGTH / 2 ;
byte pindex = 0 ;
uint32_t col = 0 ;
if ( SEGMENT_RUNTIME . counter_mode_step < = mid )
{
pindex = map ( SEGMENT_RUNTIME . counter_mode_step , 0 , mid , 255 , 0 ) ;
col = color_from_palette ( pindex , false , false , 0 ) ;
}
2018-09-04 15:51:38 +02:00
if ( odd ) {
if ( SEGMENT_RUNTIME . counter_mode_step < = mid ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + mid + SEGMENT_RUNTIME . counter_mode_step , col ) ;
setPixelColor ( SEGMENT . start + mid - SEGMENT_RUNTIME . counter_mode_step , col ) ;
2018-09-04 15:51:38 +02:00
} else {
int i = SEGMENT_RUNTIME . counter_mode_step - mid ;
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + i - 1 , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + SEGMENT_LENGTH - i , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step < mid ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + mid - SEGMENT_RUNTIME . counter_mode_step - 1 , col ) ;
setPixelColor ( SEGMENT . start + mid + SEGMENT_RUNTIME . counter_mode_step , col ) ;
2018-09-04 15:51:38 +02:00
} else {
int i = SEGMENT_RUNTIME . counter_mode_step - mid ;
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + i , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + SEGMENT_LENGTH - i - 1 , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
}
}
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( odd ) {
if ( SEGMENT_RUNTIME . counter_mode_step > SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
} else {
if ( SEGMENT_RUNTIME . counter_mode_step > = SEGMENT_LENGTH ) {
SEGMENT_RUNTIME . counter_mode_step = 0 ;
}
}
return SPEED_FORMULA_L ;
}
2018-10-25 20:55:29 +02:00
/*
* Tricolor chase function
*/
uint16_t WS2812FX : : tricolor_chase ( uint32_t color1 , uint32_t color2 , uint32_t color3 ) {
uint16_t index = SEGMENT_RUNTIME . counter_mode_step % 6 ;
for ( uint16_t i = 0 ; i < SEGMENT_LENGTH ; i + + , index + + ) {
if ( index > 5 ) index = 0 ;
uint32_t color = color1 ;
if ( index > 3 ) color = color_from_palette ( i , true , PALETTE_SOLID_WRAP , 2 ) ;
else if ( index > 1 ) color = color2 ;
setPixelColor ( SEGMENT . stop - i , color ) ;
}
SEGMENT_RUNTIME . counter_mode_step + + ;
return 35 + ( ( 350 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) ;
}
2018-09-04 15:51:38 +02:00
/*
2018-10-24 02:06:07 +02:00
* Alternating white / red / black pixels running . PLACEHOLDER
2018-09-04 15:51:38 +02:00
*/
uint16_t WS2812FX : : mode_circus_combustus ( void ) {
2018-10-25 20:55:29 +02:00
return tricolor_chase ( RED , WHITE , BLACK ) ;
}
/*
* Tricolor chase mode
*/
uint16_t WS2812FX : : mode_tricolor_chase ( void ) {
return tricolor_chase ( SEGMENT . colors [ 1 ] , SEGMENT . colors [ 0 ] , SEGMENT . colors [ 2 ] ) ;
2018-09-04 15:51:38 +02:00
}
/*
* ICU mode
*/
uint16_t WS2812FX : : mode_icu ( void ) {
uint16_t dest = SEGMENT_RUNTIME . counter_mode_step & 0xFFFF ;
2018-09-08 16:21:44 +02:00
2019-02-02 15:31:43 +01:00
fill ( SEGMENT . colors [ 1 ] ) ;
2018-10-24 02:06:07 +02:00
byte pindex = map ( dest , 0 , SEGMENT_LENGTH / 2 , 0 , 255 ) ;
uint32_t col = color_from_palette ( pindex , false , false , 0 ) ;
2018-09-04 15:51:38 +02:00
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + dest , col ) ;
setPixelColor ( SEGMENT . start + dest + SEGMENT_LENGTH / 2 , col ) ;
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . aux_param = = dest ) { // pause between eye movements
if ( random8 ( 6 ) = = 0 ) { // blink once in a while
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + dest , SEGMENT . colors [ 1 ] ) ;
setPixelColor ( SEGMENT . start + dest + SEGMENT_LENGTH / 2 , SEGMENT . colors [ 1 ] ) ;
2018-09-04 15:51:38 +02:00
return 200 ;
2017-09-18 09:50:18 +02:00
}
2019-01-31 23:42:48 +01:00
SEGMENT_RUNTIME . aux_param = random16 ( SEGMENT_LENGTH / 2 ) ;
return 1000 + random16 ( 2000 ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
if ( SEGMENT_RUNTIME . aux_param > SEGMENT_RUNTIME . counter_mode_step ) {
SEGMENT_RUNTIME . counter_mode_step + + ;
dest + + ;
} else if ( SEGMENT_RUNTIME . aux_param < SEGMENT_RUNTIME . counter_mode_step ) {
SEGMENT_RUNTIME . counter_mode_step - - ;
dest - - ;
2017-09-18 09:50:18 +02:00
}
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + dest , col ) ;
setPixelColor ( SEGMENT . start + dest + SEGMENT_LENGTH / 2 , col ) ;
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Custom mode by Aircoookie . Color Wipe , but with 3 colors
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_tricolor_wipe ( void )
{
if ( SEGMENT_RUNTIME . counter_mode_step < SEGMENT_LENGTH ) {
uint32_t led_offset = SEGMENT_RUNTIME . counter_mode_step ;
setPixelColor ( SEGMENT . start + led_offset , SEGMENT . colors [ 0 ] ) ;
} else if ( SEGMENT_RUNTIME . counter_mode_step < SEGMENT_LENGTH * 2 ) {
uint32_t led_offset = SEGMENT_RUNTIME . counter_mode_step - SEGMENT_LENGTH ;
setPixelColor ( SEGMENT . start + led_offset , SEGMENT . colors [ 1 ] ) ;
} else
{
uint32_t led_offset = SEGMENT_RUNTIME . counter_mode_step - SEGMENT_LENGTH * 2 ;
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + led_offset , color_from_palette ( SEGMENT . start + led_offset , true , PALETTE_SOLID_WRAP , 2 ) ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % ( SEGMENT_LENGTH * 3 ) ;
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Fades between 3 colors
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/TriFade.h
* Modified by Aircoookie
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_tricolor_fade ( void )
{
2018-10-24 02:06:07 +02:00
uint32_t color1 = 0 , color2 = 0 ;
2018-10-25 20:55:29 +02:00
byte stage = 0 ;
2017-09-18 09:50:18 +02:00
2018-10-24 02:06:07 +02:00
if ( SEGMENT_RUNTIME . counter_mode_step < 256 ) {
2018-09-04 15:51:38 +02:00
color1 = SEGMENT . colors [ 0 ] ;
color2 = SEGMENT . colors [ 1 ] ;
2018-10-25 20:55:29 +02:00
stage = 0 ;
2018-10-24 02:06:07 +02:00
} else if ( SEGMENT_RUNTIME . counter_mode_step < 512 ) {
2018-09-04 15:51:38 +02:00
color1 = SEGMENT . colors [ 1 ] ;
color2 = SEGMENT . colors [ 2 ] ;
2018-10-25 20:55:29 +02:00
stage = 1 ;
2018-10-24 02:06:07 +02:00
} else {
2018-09-04 15:51:38 +02:00
color1 = SEGMENT . colors [ 2 ] ;
color2 = SEGMENT . colors [ 0 ] ;
2018-10-25 20:55:29 +02:00
stage = 2 ;
2017-09-18 09:50:18 +02:00
}
2018-10-24 02:06:07 +02:00
byte stp = SEGMENT_RUNTIME . counter_mode_step % 256 ;
uint32_t color = 0 ;
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-10-25 20:55:29 +02:00
if ( stage = = 2 ) {
2018-10-24 02:06:07 +02:00
color = color_blend ( color_from_palette ( i , true , PALETTE_SOLID_WRAP , 2 ) , color2 , stp ) ;
2018-10-25 20:55:29 +02:00
} else if ( stage = = 1 ) {
2018-10-24 02:06:07 +02:00
color = color_blend ( color1 , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 2 ) , stp ) ;
} else {
color = color_blend ( color1 , color2 , stp ) ;
}
2018-09-04 15:51:38 +02:00
setPixelColor ( i , color ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
SEGMENT_RUNTIME . counter_mode_step + = 4 ;
if ( SEGMENT_RUNTIME . counter_mode_step > = 768 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
return 5 + ( ( uint32_t ) ( 255 - SEGMENT . speed ) / 10 ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Creates random comets
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_multi_comet ( void )
{
fade_out ( ( 255 - SEGMENT . intensity ) / 32 ) ;
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
static uint16_t comets [ ] = { UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX } ;
for ( uint8_t i = 0 ; i < 6 ; i + + ) {
if ( comets [ i ] < SEGMENT_LENGTH ) {
2018-10-24 02:06:07 +02:00
uint16_t index = SEGMENT . start + comets [ i ] ;
if ( SEGMENT . colors [ 2 ] ! = 0 )
2018-09-04 15:51:38 +02:00
{
2018-10-24 02:06:07 +02:00
setPixelColor ( index , i % 2 ? color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) : SEGMENT . colors [ 2 ] ) ;
2018-09-04 15:51:38 +02:00
} else
{
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
comets [ i ] + + ;
2017-09-18 09:50:18 +02:00
} else {
2018-09-04 15:51:38 +02:00
if ( ! random ( SEGMENT_LENGTH ) ) {
comets [ i ] = 0 ;
}
2017-09-18 09:50:18 +02:00
}
}
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
}
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
/*
* Creates two Larson scanners moving in opposite directions
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/DualLarson.h
*/
uint16_t WS2812FX : : mode_dual_larson_scanner ( void ) {
if ( SEGMENT_RUNTIME . aux_param )
{
SEGMENT_RUNTIME . counter_mode_step - - ;
} else
{
SEGMENT_RUNTIME . counter_mode_step + + ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
fade_out ( ( 255 - SEGMENT . intensity ) / 32 ) ;
2017-09-18 09:50:18 +02:00
2018-10-24 02:06:07 +02:00
uint16_t index = SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step ;
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
index = SEGMENT . stop - SEGMENT_RUNTIME . counter_mode_step ;
if ( SEGMENT . colors [ 2 ] ! = 0 )
2018-09-04 15:51:38 +02:00
{
2018-10-24 02:06:07 +02:00
setPixelColor ( index , SEGMENT . colors [ 2 ] ) ;
2018-09-04 15:51:38 +02:00
} else
{
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
if ( SEGMENT_RUNTIME . counter_mode_step > = ( SEGMENT . stop - SEGMENT . start ) | | SEGMENT_RUNTIME . counter_mode_step < = 0 )
SEGMENT_RUNTIME . aux_param = ! SEGMENT_RUNTIME . aux_param ;
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Running random pixels
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/RandomChase.h
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_random_chase ( void )
{
for ( uint16_t i = SEGMENT . stop ; i > SEGMENT . start ; i - - ) {
setPixelColor ( i , getPixelColor ( i - 1 ) ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
uint32_t color = getPixelColor ( SEGMENT . start + 1 ) ;
2019-01-31 23:42:48 +01:00
int r = random8 ( 6 ) ! = 0 ? ( color > > 16 & 0xFF ) : random8 ( ) ;
int g = random8 ( 6 ) ! = 0 ? ( color > > 8 & 0xFF ) : random8 ( ) ;
int b = random8 ( 6 ) ! = 0 ? ( color & 0xFF ) : random8 ( ) ;
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start , r , g , b ) ;
2017-09-18 09:50:18 +02:00
2018-10-24 02:06:07 +02:00
return 10 + ( uint16_t ) ( 255 - SEGMENT . speed ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
typedef struct Oscillator {
int16_t pos ;
int8_t size ;
int8_t dir ;
int8_t speed ;
} oscillator ;
uint16_t WS2812FX : : mode_oscillate ( void )
2017-11-29 23:56:02 +01:00
{
2019-01-31 23:42:48 +01:00
static oscillator oscillators [ 2 ] = {
2018-09-04 15:51:38 +02:00
{ SEGMENT_LENGTH / 4 , SEGMENT_LENGTH / 8 , 1 , 1 } ,
2019-01-31 23:42:48 +01:00
{ SEGMENT_LENGTH / 4 * 2 , SEGMENT_LENGTH / 8 , - 1 , 1 }
//{SEGMENT_LENGTH/4*3, SEGMENT_LENGTH/8, 1, 2}
2018-09-04 15:51:38 +02:00
} ;
for ( int8_t i = 0 ; i < sizeof ( oscillators ) / sizeof ( oscillators [ 0 ] ) ; i + + ) {
oscillators [ i ] . pos + = oscillators [ i ] . dir * oscillators [ i ] . speed ;
if ( ( oscillators [ i ] . dir = = - 1 ) & & ( oscillators [ i ] . pos < = 0 ) ) {
oscillators [ i ] . pos = 0 ;
oscillators [ i ] . dir = 1 ;
2019-01-31 23:42:48 +01:00
oscillators [ i ] . speed = random8 ( 1 , 3 ) ;
2018-09-04 15:51:38 +02:00
}
if ( ( oscillators [ i ] . dir = = 1 ) & & ( oscillators [ i ] . pos > = ( SEGMENT_LENGTH - 1 ) ) ) {
oscillators [ i ] . pos = SEGMENT_LENGTH - 1 ;
oscillators [ i ] . dir = - 1 ;
2019-01-31 23:42:48 +01:00
oscillators [ i ] . speed = random8 ( 1 , 3 ) ;
2017-11-29 23:56:02 +01:00
}
}
2018-09-04 15:51:38 +02:00
for ( int16_t i = 0 ; i < SEGMENT_LENGTH ; i + + ) {
uint32_t color = BLACK ;
for ( int8_t j = 0 ; j < sizeof ( oscillators ) / sizeof ( oscillators [ 0 ] ) ; j + + ) {
if ( i > = oscillators [ j ] . pos - oscillators [ j ] . size & & i < = oscillators [ j ] . pos + oscillators [ j ] . size ) {
color = ( color = = BLACK ) ? SEGMENT . colors [ j ] : color_blend ( color , SEGMENT . colors [ j ] , 128 ) ;
}
}
setPixelColor ( SEGMENT . start + i , color ) ;
}
return 15 + ( uint32_t ) ( 255 - SEGMENT . speed ) ;
}
2018-09-06 02:05:56 +02:00
uint16_t WS2812FX : : mode_lightning ( void )
{
uint16_t ledstart = SEGMENT . start + random8 ( SEGMENT_LENGTH ) ; // Determine starting location of flash
uint16_t ledlen = random8 ( SEGMENT . stop - ledstart ) ; // Determine length of flash (not to go beyond NUM_LEDS-1)
uint8_t bri = 255 / random8 ( 1 , 3 ) ;
if ( SEGMENT_RUNTIME . counter_mode_step = = 0 )
{
SEGMENT_RUNTIME . aux_param = random8 ( 3 , 3 + SEGMENT . intensity / 20 ) ; //number of flashes
bri = 52 ;
SEGMENT_RUNTIME . aux_param2 = 1 ;
}
2019-02-02 15:31:43 +01:00
fill ( SEGMENT . colors [ 1 ] ) ;
2018-09-06 02:05:56 +02:00
if ( SEGMENT_RUNTIME . aux_param2 ) {
for ( int i = ledstart ; i < ledstart + ledlen ; i + + )
{
2018-10-24 02:06:07 +02:00
if ( SEGMENT . palette = = 0 )
{
setPixelColor ( i , bri , bri , bri , bri ) ;
} else {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 , bri ) ) ;
}
2018-09-06 02:05:56 +02:00
}
SEGMENT_RUNTIME . aux_param2 = 0 ;
SEGMENT_RUNTIME . counter_mode_step + + ;
return random8 ( 4 , 10 ) ; // each flash only lasts 4-10 milliseconds
}
SEGMENT_RUNTIME . aux_param2 = 1 ;
if ( SEGMENT_RUNTIME . counter_mode_step = = 1 ) return ( 200 ) ; // longer delay until next flash after the leader
if ( SEGMENT_RUNTIME . counter_mode_step < = SEGMENT_RUNTIME . aux_param ) return ( 50 + random8 ( 100 ) ) ; // shorter delay between strokes
SEGMENT_RUNTIME . counter_mode_step = 0 ;
return ( random8 ( 255 - SEGMENT . speed ) * 100 ) ; // delay between strikes
}
2018-11-04 20:14:23 +01:00
CRGB WS2812FX : : fastled_from_col ( 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 ;
}
2018-09-08 16:21:44 +02:00
// Pride2015
// Animated, ever-changing rainbows.
// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
uint16_t WS2812FX : : mode_pride_2015 ( void )
{
uint16_t duration = 10 + SEGMENT . speed ;
uint16_t sPseudotime = SEGMENT_RUNTIME . counter_mode_step ;
uint16_t sHue16 = SEGMENT_RUNTIME . aux_param ;
uint8_t sat8 = beatsin88 ( 87 , 220 , 250 ) ;
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 1 , 3000 ) ;
sPseudotime + = duration * msmultiplier ;
sHue16 + = duration * beatsin88 ( 400 , 5 , 9 ) ;
uint16_t brightnesstheta16 = sPseudotime ;
CRGB fastled_col ;
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
hue16 + = hueinc16 ;
uint8_t hue8 = hue16 > > 8 ;
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
CRGB newcolor = CHSV ( hue8 , sat8 , bri8 ) ;
2018-11-04 20:14:23 +01:00
fastled_col = fastled_from_col ( getPixelColor ( i ) ) ;
2018-09-08 16:21:44 +02:00
nblend ( fastled_col , newcolor , 64 ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
SEGMENT_RUNTIME . counter_mode_step = sPseudotime ;
SEGMENT_RUNTIME . aux_param = sHue16 ;
return 20 ;
}
// eight colored dots, weaving in and out of sync with each other
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_juggle ( void ) {
fade_out ( ( 255 - SEGMENT . intensity ) / 32 ) ;
CRGB fastled_col ;
byte dothue = 0 ;
for ( byte i = 0 ; i < 8 ; i + + ) {
2018-09-08 16:21:44 +02:00
uint16_t index = SEGMENT . start + beatsin16 ( i + 7 , 0 , SEGMENT_LENGTH - 1 ) ;
2018-11-04 20:14:23 +01:00
fastled_col = fastled_from_col ( getPixelColor ( index ) ) ;
2018-09-04 15:51:38 +02:00
fastled_col | = CHSV ( dothue , 220 , 255 ) ;
setPixelColor ( index , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
dothue + = 32 ;
2017-11-30 23:35:22 +01:00
}
2018-09-04 15:51:38 +02:00
return 10 + ( uint16_t ) ( 255 - SEGMENT . speed ) / 4 ;
2017-11-30 23:35:22 +01:00
}
2017-11-20 00:07:37 +01:00
2018-09-08 16:21:44 +02:00
2018-09-06 02:05:56 +02:00
/*
* FastLED palette modes helper function . Limitation : Due to memory reasons , multiple active segments with FastLED will disable the Palette transitions
*/
2018-09-04 15:51:38 +02:00
CRGBPalette16 currentPalette ( CRGB : : Black ) ;
CRGBPalette16 targetPalette ( CloudColors_p ) ;
2017-11-20 00:07:37 +01:00
2018-09-06 02:05:56 +02:00
void WS2812FX : : handle_palette ( void )
{
bool singleSegmentMode = ( _segment_index = = _segment_index_palette_last ) ;
_segment_index_palette_last = _segment_index ;
2018-11-28 12:24:32 +01:00
byte paletteIndex = SEGMENT . palette ;
2018-12-06 00:27:36 +01:00
if ( ( SEGMENT . mode > = FX_MODE_METEOR ) & & SEGMENT . palette = = 0 ) paletteIndex = 4 ;
2018-09-06 02:05:56 +02:00
2018-11-28 12:24:32 +01:00
switch ( paletteIndex )
2018-09-06 02:05:56 +02:00
{
2018-09-11 00:20:12 +02:00
case 0 : { //default palette. Differs depending on effect
switch ( SEGMENT . mode )
{
case FX_MODE_FIRE_2012 : targetPalette = gGradientPalettes [ 22 ] ; break ; //heat palette
case FX_MODE_COLORWAVES : targetPalette = gGradientPalettes [ 13 ] ; break ; //landscape 33
case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p ; break ;
case FX_MODE_NOISE16_1 : targetPalette = gGradientPalettes [ 17 ] ; break ; //Drywet
case FX_MODE_NOISE16_2 : targetPalette = gGradientPalettes [ 30 ] ; break ; //Blue cyan yellow
case FX_MODE_NOISE16_3 : targetPalette = gGradientPalettes [ 22 ] ; break ; //heat palette
case FX_MODE_NOISE16_4 : targetPalette = gGradientPalettes [ 13 ] ; break ; //landscape 33
default : targetPalette = PartyColors_p ; break ; //palette, bpm
}
break ; }
case 1 : { //periodically replace palette with a random one. Doesn't work with multiple FastLED segments
2018-09-06 02:05:56 +02:00
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 ; }
2018-09-11 00:20:12 +02:00
case 2 : { //primary color only
2018-11-04 20:14:23 +01:00
CRGB prim = fastled_from_col ( SEGMENT . colors [ 0 ] ) ;
2018-09-06 02:05:56 +02:00
targetPalette = CRGBPalette16 ( prim ) ; break ; }
2018-09-11 00:20:12 +02:00
case 3 : { //based on primary
2018-09-06 02:05:56 +02:00
//considering performance implications
2018-11-04 20:14:23 +01:00
CRGB prim = fastled_from_col ( SEGMENT . colors [ 0 ] ) ;
2018-09-06 02:05:56 +02:00
CHSV prim_hsv = rgb2hsv_approximate ( prim ) ;
targetPalette = CRGBPalette16 (
CHSV ( prim_hsv . h , prim_hsv . s , prim_hsv . v ) , //color itself
CHSV ( prim_hsv . h , max ( prim_hsv . s - 50 , 0 ) , prim_hsv . v ) , //less saturated
2018-09-11 00:20:12 +02:00
CHSV ( prim_hsv . h , prim_hsv . s , max ( prim_hsv . v - 50 , 0 ) ) , //darker
2018-09-06 02:05:56 +02:00
CHSV ( prim_hsv . h , prim_hsv . s , prim_hsv . v ) ) ; //color itself
break ; }
2018-09-11 00:20:12 +02:00
case 4 : { //primary + secondary
2018-11-04 20:14:23 +01:00
CRGB prim = fastled_from_col ( SEGMENT . colors [ 0 ] ) ;
CRGB sec = fastled_from_col ( SEGMENT . colors [ 1 ] ) ;
2018-09-11 00:20:12 +02:00
targetPalette = CRGBPalette16 ( sec , prim ) ; break ; }
case 5 : { //based on primary + secondary
2018-11-04 20:14:23 +01:00
CRGB prim = fastled_from_col ( SEGMENT . colors [ 0 ] ) ;
CRGB sec = fastled_from_col ( SEGMENT . colors [ 1 ] ) ;
2018-09-11 00:20:12 +02:00
targetPalette = CRGBPalette16 ( sec , prim , CRGB : : White ) ; break ; }
case 6 : //Party colors
2018-09-06 02:05:56 +02:00
targetPalette = PartyColors_p ; break ;
2018-09-11 00:20:12 +02:00
case 7 : //Cloud colors
2018-09-06 02:05:56 +02:00
targetPalette = CloudColors_p ; break ;
2018-09-11 00:20:12 +02:00
case 8 : //Lava colors
2018-09-06 02:05:56 +02:00
targetPalette = LavaColors_p ; break ;
2018-09-11 00:20:12 +02:00
case 9 : //Ocean colors
2018-09-06 02:05:56 +02:00
targetPalette = OceanColors_p ; break ;
2018-09-11 00:20:12 +02:00
case 10 : //Forest colors
2018-09-06 02:05:56 +02:00
targetPalette = ForestColors_p ; break ;
2018-09-11 00:20:12 +02:00
case 11 : //Rainbow colors
2018-09-06 02:05:56 +02:00
targetPalette = RainbowColors_p ; break ;
2018-09-11 00:20:12 +02:00
case 12 : //Rainbow stripe colors
2018-09-06 02:05:56 +02:00
targetPalette = RainbowStripeColors_p ; break ;
2018-09-08 20:26:04 +02:00
default : //progmem palettes
2018-09-11 00:20:12 +02:00
targetPalette = gGradientPalettes [ constrain ( SEGMENT . palette - 13 , 0 , gGradientPaletteCount - 1 ) ] ;
2018-09-06 02:05:56 +02:00
}
2018-09-08 16:21:44 +02:00
if ( singleSegmentMode & & paletteFade ) //only blend if just one segment uses FastLED mode
2018-09-06 02:05:56 +02:00
{
2018-09-11 00:20:12 +02:00
nblendPaletteTowardPalette ( currentPalette , targetPalette , 48 ) ;
2018-09-06 02:05:56 +02:00
} else
{
currentPalette = targetPalette ;
}
}
2018-10-24 02:06:07 +02:00
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 SEGMENT . colors [ mcol ] ; //WS2812FX default
uint8_t paletteIndex = i ;
if ( mapping ) paletteIndex = map ( i , SEGMENT . start , SEGMENT . stop , 0 , 255 ) ;
if ( ! wrap ) paletteIndex = map ( paletteIndex , 0 , 255 , 0 , 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 ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_palette ( void )
2016-12-17 23:43:07 +01:00
{
2018-09-11 00:20:12 +02:00
bool noWrap = ( paletteBlend = = 2 | | ( paletteBlend = = 0 & & SEGMENT . speed = = 0 ) ) ;
2018-09-04 15:51:38 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + )
2016-12-31 00:38:51 +01:00
{
2018-09-11 00:20:12 +02:00
uint8_t colorIndex = map ( i , SEGMENT . start , SEGMENT . stop , 0 , 255 ) - ( SEGMENT_RUNTIME . counter_mode_step > > 6 & 0xFF ) ;
if ( noWrap ) colorIndex = map ( colorIndex , 0 , 255 , 0 , 240 ) ; //cut off blend at palette "end"
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( colorIndex , false , true , 255 ) ) ;
2016-12-31 00:38:51 +01:00
}
2018-12-02 02:49:05 +01:00
SEGMENT_RUNTIME . counter_mode_step + = SEGMENT . speed ;
2018-09-06 02:05:56 +02:00
if ( SEGMENT . speed = = 0 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
return 20 ;
}
2018-09-11 00:20:12 +02:00
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
// at each point along the line. Every cycle through the simulation,
// four steps are performed:
// 1) All cells cool down a little bit, losing heat to the air
// 2) The heat from each cell drifts 'up' and diffuses a little
// 3) Sometimes randomly new 'sparks' of heat are added at the bottom
// 4) The heat from each cell is rendered as a color into the leds array
// The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
//
// Looks best on a high-density LED setup (60+ pixels/meter).
//
//
// There are two main parameters you can play with to control the look and
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
// in step 3 above) (Effect Intensity = Sparking).
//
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames. More cooling = shorter flames.
// Default 50, suggested range 20-100
# define COOLING 75
uint16_t WS2812FX : : mode_fire_2012 ( void )
{
// Step 1. Cool down every cell a little
for ( int i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
_locked [ i ] = qsub8 ( _locked [ i ] , random8 ( 0 , ( ( COOLING * 10 ) / SEGMENT_LENGTH ) + 2 ) ) ;
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for ( int k = SEGMENT . stop ; k > = SEGMENT . start + 2 ; k - - ) {
_locked [ k ] = ( _locked [ k - 1 ] + _locked [ k - 2 ] + _locked [ k - 2 ] ) / 3 ;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if ( random8 ( ) < = SEGMENT . intensity ) {
int y = SEGMENT . start + random8 ( 7 ) ;
if ( y < = SEGMENT . stop ) _locked [ y ] = qadd8 ( _locked [ y ] , random8 ( 160 , 255 ) ) ;
}
// Step 4. Map from heat cells to LED colors
for ( int j = SEGMENT . start ; j < = SEGMENT . stop ; j + + ) {
CRGB color = ColorFromPalette ( currentPalette , min ( _locked [ j ] , 240 ) , 255 , LINEARBLEND ) ;
setPixelColor ( j , color . red , color . green , color . blue ) ;
}
return 10 + ( uint16_t ) ( 255 - SEGMENT . speed ) / 6 ;
}
2018-09-08 16:21:44 +02:00
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
uint16_t WS2812FX : : mode_colorwaves ( void )
{
uint16_t duration = 10 + SEGMENT . speed ;
uint16_t sPseudotime = SEGMENT_RUNTIME . counter_mode_step ;
uint16_t sHue16 = SEGMENT_RUNTIME . aux_param ;
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 300 , 1500 ) ;
sPseudotime + = duration * msmultiplier ;
sHue16 + = duration * beatsin88 ( 400 , 5 , 9 ) ;
uint16_t brightnesstheta16 = sPseudotime ;
CRGB fastled_col ;
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
hue16 + = hueinc16 ;
2019-02-02 15:31:43 +01:00
uint8_t hue8 = hue16 > > 8 ;
2018-09-08 16:21:44 +02:00
uint16_t h16_128 = hue16 > > 7 ;
if ( h16_128 & 0x100 ) {
hue8 = 255 - ( h16_128 > > 1 ) ;
} else {
hue8 = h16_128 > > 1 ;
}
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
uint8_t index = hue8 ;
//index = triwave8( index);
index = scale8 ( index , 240 ) ;
CRGB newcolor = ColorFromPalette ( currentPalette , index , bri8 ) ;
2018-11-04 20:14:23 +01:00
fastled_col = fastled_from_col ( getPixelColor ( i ) ) ;
2018-09-08 16:21:44 +02:00
nblend ( fastled_col , newcolor , 128 ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
SEGMENT_RUNTIME . counter_mode_step = sPseudotime ;
SEGMENT_RUNTIME . aux_param = sHue16 ;
return 20 ;
}
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
2018-09-06 02:05:56 +02:00
uint16_t WS2812FX : : mode_bpm ( void )
{
CRGB fastled_col ;
uint8_t beat = beatsin8 ( SEGMENT . speed , 64 , 255 ) ;
2018-09-11 00:20:12 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , SEGMENT_RUNTIME . counter_mode_step + ( i * 2 ) , beat - SEGMENT_RUNTIME . counter_mode_step + ( i * 10 ) ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
SEGMENT_RUNTIME . counter_mode_step + + ;
if ( SEGMENT_RUNTIME . counter_mode_step > = 255 ) SEGMENT_RUNTIME . counter_mode_step = 0 ;
2018-09-04 15:51:38 +02:00
return 20 ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fillnoise8 ( void )
2016-12-31 00:38:51 +01:00
{
2019-01-31 23:42:48 +01:00
if ( SEGMENT_RUNTIME . counter_mode_call = = 0 ) SEGMENT_RUNTIME . counter_mode_step = random16 ( 12345 ) ;
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
2018-09-11 00:20:12 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-09-04 15:51:38 +02:00
uint8_t index = inoise8 ( i * SEGMENT_LENGTH , SEGMENT_RUNTIME . counter_mode_step + i * SEGMENT_LENGTH ) % 255 ;
fastled_col = ColorFromPalette ( currentPalette , index , 255 , LINEARBLEND ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2016-12-31 00:38:51 +01:00
}
2018-09-11 00:20:12 +02:00
SEGMENT_RUNTIME . counter_mode_step + = beatsin8 ( SEGMENT . speed , 1 , 6 ) ; //10,1,4
2016-12-31 00:38:51 +01:00
2018-09-06 02:05:56 +02:00
return 20 ;
2016-12-31 00:38:51 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_noise16_1 ( void )
2016-12-31 00:38:51 +01:00
{
2018-09-08 16:21:44 +02:00
uint16_t scale = 320 ; // the "zoom factor" for the noise
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
SEGMENT_RUNTIME . counter_mode_step + = ( 1 + SEGMENT . speed / 16 ) ;
2016-12-31 00:38:51 +01:00
2018-09-11 00:20:12 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2016-12-31 00:38:51 +01:00
2018-09-08 16:21:44 +02:00
uint16_t shift_x = beatsin8 ( 11 ) ; // the x position of the noise field swings @ 17 bpm
uint16_t shift_y = SEGMENT_RUNTIME . counter_mode_step / 42 ; // the y position becomes slowly incremented
2018-09-04 15:51:38 +02:00
uint16_t real_x = ( i + shift_x ) * scale ; // the x position of the noise field swings @ 17 bpm
uint16_t real_y = ( i + shift_y ) * scale ; // the y position becomes slowly incremented
2018-09-08 16:21:44 +02:00
uint32_t real_z = SEGMENT_RUNTIME . counter_mode_step ; // the z position becomes quickly incremented
2018-09-04 15:51:38 +02:00
uint8_t noise = inoise16 ( real_x , real_y , real_z ) > > 8 ; // get the noise data and scale it down
uint8_t index = sin8 ( noise * 3 ) ; // map LED color based on noise data
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , 255 , LINEARBLEND ) ; // With that value, look up the 8 bit colour palette value and assign it to the current LED.
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2016-12-31 00:38:51 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2016-12-31 00:38:51 +01:00
}
2017-11-19 15:31:17 +01:00
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_noise16_2 ( void )
2018-03-06 23:47:08 +01:00
{
2018-09-08 16:21:44 +02:00
uint16_t scale = 1000 ; // the "zoom factor" for the noise
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
SEGMENT_RUNTIME . counter_mode_step + = ( 1 + SEGMENT . speed ) ;
2018-03-06 23:47:08 +01:00
2018-09-11 00:20:12 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2017-12-14 00:12:02 +01:00
2018-09-08 16:21:44 +02:00
uint16_t shift_x = SEGMENT_RUNTIME . counter_mode_step > > 6 ; // x as a function of time
uint16_t shift_y = SEGMENT_RUNTIME . counter_mode_step / 42 ;
2017-12-19 16:12:51 +01:00
2018-09-04 15:51:38 +02:00
uint32_t real_x = ( i + shift_x ) * scale ; // calculate the coordinates within the noise field
2017-12-14 00:12:02 +01:00
2018-09-08 16:21:44 +02:00
uint8_t noise = inoise16 ( real_x , 0 , 4223 ) > > 8 ; // get the noise data and scale it down
2017-12-14 00:12:02 +01:00
2018-09-04 15:51:38 +02:00
uint8_t index = sin8 ( noise * 3 ) ; // map led color based on noise data
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , noise , LINEARBLEND ) ; // With that value, look up the 8 bit colour palette value and assign it to the current LED.
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2017-12-14 00:12:02 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2017-11-29 23:56:02 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_noise16_3 ( void )
2017-11-29 23:56:02 +01:00
{
2018-09-08 16:21:44 +02:00
uint16_t scale = 800 ; // the "zoom factor" for the noise
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
SEGMENT_RUNTIME . counter_mode_step + = ( 1 + SEGMENT . speed ) ;
2017-11-29 23:56:02 +01:00
2018-09-11 00:20:12 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2017-11-29 23:56:02 +01:00
2018-09-04 15:51:38 +02:00
uint16_t shift_x = 4223 ; // no movement along x and y
uint16_t shift_y = 1234 ;
2017-11-29 23:56:02 +01:00
2018-09-04 15:51:38 +02:00
uint32_t real_x = ( i + shift_x ) * scale ; // calculate the coordinates within the noise field
uint32_t real_y = ( i + shift_y ) * scale ; // based on the precalculated positions
2018-09-08 16:21:44 +02:00
uint32_t real_z = SEGMENT_RUNTIME . counter_mode_step * 8 ;
2017-11-29 23:56:02 +01:00
2018-09-08 16:21:44 +02:00
uint8_t noise = inoise16 ( real_x , real_y , real_z ) > > 8 ; // get the noise data and scale it down
2017-11-29 23:56:02 +01:00
2018-09-04 15:51:38 +02:00
uint8_t index = sin8 ( noise * 3 ) ; // map led color based on noise data
2017-11-29 23:56:02 +01:00
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , noise , LINEARBLEND ) ; // With that value, look up the 8 bit colour palette value and assign it to the current LED.
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2018-04-13 00:28:29 +02:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2017-09-18 12:24:31 +02:00
}
2018-09-04 15:51:38 +02:00
//https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino
uint16_t WS2812FX : : mode_noise16_4 ( void )
2017-09-27 21:45:58 +02:00
{
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
SEGMENT_RUNTIME . counter_mode_step + = SEGMENT . speed ;
2018-09-11 00:20:12 +02:00
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2018-09-04 15:51:38 +02:00
int16_t index = inoise16 ( uint32_t ( i - SEGMENT . start ) < < 12 , SEGMENT_RUNTIME . counter_mode_step / 8 ) ;
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index ) ;
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2017-12-14 00:12:02 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2017-09-27 21:45:58 +02:00
}
2018-11-04 20:14:23 +01:00
2018-11-07 20:22:05 +01:00
//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e
2018-11-04 20:14:23 +01:00
uint16_t WS2812FX : : mode_colortwinkle ( )
{
CRGB fastled_col , prev ;
fract8 fadeUpAmount = 8 + ( SEGMENT . speed / 4 ) , fadeDownAmount = 5 + ( SEGMENT . speed / 7 ) ;
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
fastled_col = fastled_from_col ( getPixelColor ( i ) ) ;
prev = fastled_col ;
if ( _locked [ i ] ) {
CRGB incrementalColor = fastled_col ;
incrementalColor . nscale8_video ( fadeUpAmount ) ;
fastled_col + = incrementalColor ;
if ( fastled_col . red = = 255 | | fastled_col . green = = 255 | | fastled_col . blue = = 255 ) {
_locked [ i ] = false ;
}
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
if ( fastled_from_col ( getPixelColor ( i ) ) = = prev ) //fix "stuck" pixels
{
fastled_col + = fastled_col ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
} else {
fastled_col . nscale8 ( 255 - fadeDownAmount ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
}
2018-12-16 20:38:00 +01:00
for ( uint16_t j = 0 ; j < = SEGMENT_LENGTH / 50 ; j + + )
{
if ( random8 ( ) < = SEGMENT . intensity ) {
for ( uint8_t times = 0 ; times < 5 ; times + + ) //attempt to spawn a new pixel 5 times
{
int i = SEGMENT . start + random16 ( SEGMENT_LENGTH ) ;
if ( getPixelColor ( i ) = = 0 ) {
fastled_col = ColorFromPalette ( currentPalette , random8 ( ) , 64 , NOBLEND ) ;
_locked [ i ] = true ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
break ; //only spawn 1 new pixel per frame per 50 LEDs
}
2018-11-04 20:14:23 +01:00
}
}
}
return 20 ;
}
2018-11-07 20:22:05 +01:00
//Calm effect, like a lake at night
uint16_t WS2812FX : : mode_lake ( ) {
uint8_t sp = SEGMENT . speed / 10 ;
int wave1 = beatsin8 ( sp + 2 , - 64 , 64 ) ;
int wave2 = beatsin8 ( sp + 1 , - 64 , 64 ) ;
uint8_t wave3 = beatsin8 ( sp + 2 , 0 , 80 ) ;
CRGB fastled_col ;
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + )
{
int index = cos8 ( ( i * 15 ) + wave1 ) / 2 + cubicwave8 ( ( i * 23 ) + wave2 ) / 2 ;
uint8_t lum = ( index > wave3 ) ? index - wave3 : 0 ;
fastled_col = ColorFromPalette ( currentPalette , map ( index , 0 , 255 , 0 , 240 ) , lum , LINEARBLEND ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
return 33 ;
}
2018-11-20 20:32:21 +01:00
2018-11-28 12:24:32 +01:00
2018-11-20 20:32:21 +01:00
// meteor effect
2018-11-28 12:24:32 +01:00
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
2018-11-20 20:32:21 +01:00
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX : : mode_meteor ( ) {
2018-11-28 12:24:32 +01:00
byte meteorSize = 1 + SEGMENT_LENGTH / 10 ;
uint16_t in = SEGMENT . start + SEGMENT_RUNTIME . counter_mode_step ;
2018-11-20 20:32:21 +01:00
// fade all leds to colors[1] in LEDs one step
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2019-02-02 15:31:43 +01:00
if ( random8 ( ) < = 255 - SEGMENT . intensity )
2018-11-28 12:24:32 +01:00
{
byte meteorTrailDecay = 128 + random8 ( 127 ) ;
_locked [ i ] = scale8 ( _locked [ i ] , meteorTrailDecay ) ;
setPixelColor ( i , color_from_palette ( _locked [ i ] , false , true , 255 ) ) ;
2018-11-20 20:32:21 +01:00
}
}
// draw meteor
2018-11-28 12:24:32 +01:00
for ( int j = 0 ; j < meteorSize ; j + + ) {
uint16_t index = in + j ;
if ( in + j > SEGMENT . stop ) {
index = SEGMENT . start + ( in + j - SEGMENT . stop ) - 1 ;
2018-11-20 20:32:21 +01:00
}
2018-11-28 12:24:32 +01:00
_locked [ index ] = 240 ;
setPixelColor ( index , color_from_palette ( _locked [ index ] , false , true , 255 ) ) ;
2018-11-20 20:32:21 +01:00
}
SEGMENT_RUNTIME . counter_mode_step = ( SEGMENT_RUNTIME . counter_mode_step + 1 ) % ( SEGMENT_LENGTH ) ;
return SPEED_FORMULA_L ;
}
2018-11-28 12:24:32 +01:00
2018-12-06 00:27:36 +01:00
2018-12-02 02:49:05 +01:00
// smooth meteor effect
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX : : mode_meteor_smooth ( ) {
byte meteorSize = 1 + SEGMENT_LENGTH / 10 ;
uint16_t in = map ( ( SEGMENT_RUNTIME . counter_mode_step > > 6 & 0xFF ) , 0 , 255 , SEGMENT . start , SEGMENT . stop ) ;
// fade all leds to colors[1] in LEDs one step
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + + ) {
2019-02-02 15:31:43 +01:00
if ( _locked [ i ] ! = 0 & & random8 ( ) < = 255 - SEGMENT . intensity )
2018-12-02 02:49:05 +01:00
{
int change = 3 - random8 ( 12 ) ; //change each time between -8 and +3
_locked [ i ] + = change ;
if ( _locked [ i ] > 245 ) _locked [ i ] = 0 ;
if ( _locked [ i ] > 240 ) _locked [ i ] = 240 ;
setPixelColor ( i , color_from_palette ( _locked [ i ] , false , true , 255 ) ) ;
}
}
// draw meteor
for ( int j = 0 ; j < meteorSize ; j + + ) {
uint16_t index = in + j ;
if ( in + j > SEGMENT . stop ) {
index = SEGMENT . start + ( in + j - SEGMENT . stop ) - 1 ;
}
setPixelColor ( index , color_blend ( getPixelColor ( index ) , color_from_palette ( 240 , false , true , 255 ) , 48 ) ) ;
2019-01-18 01:20:36 +01:00
_locked [ index ] = 240 ;
2018-12-02 02:49:05 +01:00
}
SEGMENT_RUNTIME . counter_mode_step + = SEGMENT . speed + 1 ;
return 20 ;
}
//Railway Crossing / Christmas Fairy lights
uint16_t WS2812FX : : mode_railway ( )
{
uint16_t dur = 40 + ( 255 - SEGMENT . speed ) * 10 ;
uint16_t rampdur = ( dur * SEGMENT . intensity ) > > 8 ;
if ( SEGMENT_RUNTIME . counter_mode_step > dur )
{
//reverse direction
SEGMENT_RUNTIME . counter_mode_step = 0 ;
SEGMENT_RUNTIME . aux_param = ! SEGMENT_RUNTIME . aux_param ;
}
uint8_t pos = 255 ;
if ( rampdur ! = 0 )
{
uint16_t p0 = ( SEGMENT_RUNTIME . counter_mode_step * 255 ) / rampdur ;
if ( p0 < 255 ) pos = p0 ;
}
if ( SEGMENT_RUNTIME . aux_param ) pos = 255 - pos ;
for ( uint16_t i = SEGMENT . start ; i < = SEGMENT . stop ; i + = 2 )
{
setPixelColor ( i , color_from_palette ( 255 - pos , false , false , 255 ) ) ;
if ( i ! = SEGMENT . stop )
{
setPixelColor ( i + 1 , color_from_palette ( pos , false , false , 255 ) ) ;
}
}
SEGMENT_RUNTIME . counter_mode_step + = 20 ;
return 20 ;
}
2019-01-31 23:42:48 +01:00
//Water ripple
//fade duration is random 2-5sec
//propagation velocity from speed
//drop rate from intensity
2019-02-02 15:31:43 +01:00
//? smooth sine instead of shifting +2
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : mode_ripple ( )
{
2019-02-02 15:31:43 +01:00
uint16_t maxripples = SEGMENT_LENGTH / 4 ;
2019-01-31 23:42:48 +01:00
if ( maxripples = = 0 ) return mode_static ( ) ;
2019-02-02 15:31:43 +01:00
fill ( SEGMENT . colors [ 1 ] ) ;
2019-01-31 23:42:48 +01:00
//draw wave
for ( uint16_t rippleI = 0 ; rippleI < maxripples ; rippleI + + )
{
2019-02-02 15:31:43 +01:00
uint16_t storeI = SEGMENT . start + 4 * rippleI ;
uint16_t ripplestate = _locked [ storeI ] ;
2019-01-31 23:42:48 +01:00
if ( ripplestate )
{
2019-02-02 15:31:43 +01:00
uint8_t rippledecay = ( SEGMENT . speed > > 4 ) + 1 ; //faster decay if faster propagation
uint16_t rippleorigin = ( _locked [ storeI + 1 ] < < 8 ) + _locked [ storeI + 2 ] ;
uint32_t col = color_from_palette ( _locked [ storeI + 3 ] , false , false , 255 ) ;
uint16_t propagation = ( ( ripplestate / rippledecay - 1 ) * SEGMENT . speed ) ;
int16_t propI = propagation > > 8 ;
uint8_t propF = propagation & 0xFF ;
int16_t left = rippleorigin - propI - 1 ;
uint8_t amp = ( ripplestate < 17 ) ? triwave8 ( ( ripplestate - 1 ) * 8 ) : map ( ripplestate , 17 , 255 , 255 , 2 ) ;
for ( int16_t v = left ; v < left + 4 ; v + + )
{
uint8_t mag = scale8 ( cubicwave8 ( ( propF > > 2 ) + ( v - left ) * 64 ) , amp ) ;
if ( v > = SEGMENT . start )
{
setPixelColor ( v , color_blend ( getPixelColor ( v ) , col , mag ) ) ;
}
int16_t w = left + propI * 2 + 3 - ( v - left ) ;
if ( w < = SEGMENT . stop & & w > = SEGMENT . start )
{
setPixelColor ( w , color_blend ( getPixelColor ( w ) , col , mag ) ) ;
}
}
ripplestate + = rippledecay ;
_locked [ storeI ] = ( ripplestate > 254 ) ? 0 : ripplestate ;
} else //randomly create new wave
2019-01-31 23:42:48 +01:00
{
2019-02-02 15:31:43 +01:00
if ( random16 ( IBN + 10000 ) < = SEGMENT . intensity )
2019-01-31 23:42:48 +01:00
{
2019-02-02 15:31:43 +01:00
_locked [ storeI ] = 1 ;
2019-01-31 23:42:48 +01:00
uint16_t origin = SEGMENT . start + random16 ( SEGMENT_LENGTH ) ;
2019-02-02 15:31:43 +01:00
_locked [ storeI + 1 ] = origin > > 8 ;
_locked [ storeI + 2 ] = origin & 0xFF ;
_locked [ storeI + 3 ] = random8 ( ) ;
2019-01-31 23:42:48 +01:00
}
}
}
return 20 ;
}