Merge branch 'master' into master
This commit is contained in:
commit
4af7ccd84c
@ -41,6 +41,8 @@ lib_deps_external =
|
|||||||
IRremoteESP8266@2.5.5
|
IRremoteESP8266@2.5.5
|
||||||
#Time@1.5
|
#Time@1.5
|
||||||
#Timezone@1.2.1
|
#Timezone@1.2.1
|
||||||
|
#For use SSD1306 0.91" OLED display uncomment following
|
||||||
|
#U8g2@~2.27.2
|
||||||
|
|
||||||
[common:esp8266]
|
[common:esp8266]
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -4,5 +4,5 @@ This code uses Aircookie's WLED software. It has a premade file for user modific
|
|||||||
|
|
||||||
To install:
|
To install:
|
||||||
|
|
||||||
Add the enties in the WLED00 file to the top of the same file from Aircoookies WLED.
|
Add the entries in the WLED00 file to the top of the same file from Aircoookies WLED.
|
||||||
Replace the WLED06_usermod.ino file in Aircoookies WLED folder.
|
Replace the WLED06_usermod.ino file in Aircoookies WLED folder.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||||
|
|
||||||
//The SCL and SDA pins are defined here.
|
//The SCL and SDA pins are defined here.
|
||||||
//Lolin32 boards use SCL=4 SDA=5
|
//Lolin32 boards use SCL=5 SDA=4
|
||||||
#define U8X8_PIN_SCL 5
|
#define U8X8_PIN_SCL 5
|
||||||
#define U8X8_PIN_SDA 4
|
#define U8X8_PIN_SDA 4
|
||||||
|
|
||||||
|
458
wled00/FX.cpp
458
wled00/FX.cpp
@ -236,22 +236,24 @@ uint16_t WS2812FX::mode_random_color(void) {
|
|||||||
// * to new random colors.
|
// * to new random colors.
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_dynamic(void) {
|
uint16_t WS2812FX::mode_dynamic(void) {
|
||||||
|
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
if(SEGENV.call == 0) {
|
if(SEGENV.call == 0) {
|
||||||
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) _locked[i] = random8();
|
for (uint16_t i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15;
|
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15;
|
||||||
uint32_t it = now / cycleTime;
|
uint32_t it = now / cycleTime;
|
||||||
if (it != SEGENV.step) //new color
|
if (it != SEGENV.step && SEGMENT.speed != 0) //new color
|
||||||
{
|
{
|
||||||
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) {
|
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
if (random8() <= SEGMENT.intensity) _locked[i] = random8();
|
if (random8() <= SEGMENT.intensity) SEGENV.data[i] = random8();
|
||||||
}
|
}
|
||||||
SEGENV.step = it;
|
SEGENV.step = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) {
|
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
setPixelColor(i, color_wheel(_locked[i]));
|
setPixelColor(SEGMENT.start + i, color_wheel(SEGENV.data[i]));
|
||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
@ -414,7 +416,6 @@ uint16_t WS2812FX::mode_theater_chase(void) {
|
|||||||
* Inspired by the Adafruit examples.
|
* Inspired by the Adafruit examples.
|
||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
||||||
SEGENV.step = (SEGENV.step + 1) & 0xFF;
|
|
||||||
return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false);
|
return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1294,20 +1295,38 @@ uint16_t WS2812FX::mode_icu(void) {
|
|||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_tricolor_wipe(void)
|
uint16_t WS2812FX::mode_tricolor_wipe(void)
|
||||||
{
|
{
|
||||||
if(SEGENV.step < SEGLEN) {
|
uint32_t cycleTime = 1000 + (255 - SEGMENT.speed)*200;
|
||||||
uint32_t led_offset = SEGENV.step;
|
uint32_t perc = now % cycleTime;
|
||||||
setPixelColor(SEGMENT.start + led_offset, SEGCOLOR(0));
|
uint16_t prog = (perc * 65535) / cycleTime;
|
||||||
} else if (SEGENV.step < SEGLEN*2) {
|
uint16_t ledIndex = (prog * SEGLEN * 3) >> 16;
|
||||||
uint32_t led_offset = SEGENV.step - SEGLEN;
|
uint16_t ledOffset = ledIndex;
|
||||||
setPixelColor(SEGMENT.start + led_offset, SEGCOLOR(1));
|
|
||||||
} else
|
for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++)
|
||||||
{
|
{
|
||||||
uint32_t led_offset = SEGENV.step - SEGLEN*2;
|
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2));
|
||||||
setPixelColor(SEGMENT.start + led_offset, color_from_palette(SEGMENT.start + led_offset, true, PALETTE_SOLID_WRAP, 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGENV.step = (SEGENV.step + 1) % (SEGLEN * 3);
|
if(ledIndex < SEGLEN) { //wipe from 0 to 1
|
||||||
return SPEED_FORMULA_L;
|
for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++)
|
||||||
|
{
|
||||||
|
setPixelColor(i, (i - SEGMENT.start > ledOffset)? SEGCOLOR(0) : SEGCOLOR(1));
|
||||||
|
}
|
||||||
|
} else if (ledIndex < SEGLEN*2) { //wipe from 1 to 2
|
||||||
|
ledOffset = ledIndex - SEGLEN;
|
||||||
|
for (uint16_t i = SEGMENT.start +ledOffset +1; i < SEGMENT.stop; i++)
|
||||||
|
{
|
||||||
|
setPixelColor(i, SEGCOLOR(1));
|
||||||
|
}
|
||||||
|
} else //wipe from 2 to 0
|
||||||
|
{
|
||||||
|
ledOffset = ledIndex - SEGLEN*2;
|
||||||
|
for (uint16_t i = SEGMENT.start; i <= SEGMENT.start +ledOffset; i++)
|
||||||
|
{
|
||||||
|
setPixelColor(i, SEGCOLOR(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1318,14 +1337,17 @@ uint16_t WS2812FX::mode_tricolor_wipe(void)
|
|||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_tricolor_fade(void)
|
uint16_t WS2812FX::mode_tricolor_fade(void)
|
||||||
{
|
{
|
||||||
|
uint16_t counter = now * ((SEGMENT.speed >> 3) +1);
|
||||||
|
uint32_t prog = (counter * 768) >> 16;
|
||||||
|
|
||||||
uint32_t color1 = 0, color2 = 0;
|
uint32_t color1 = 0, color2 = 0;
|
||||||
byte stage = 0;
|
byte stage = 0;
|
||||||
|
|
||||||
if(SEGENV.step < 256) {
|
if(prog < 256) {
|
||||||
color1 = SEGCOLOR(0);
|
color1 = SEGCOLOR(0);
|
||||||
color2 = SEGCOLOR(1);
|
color2 = SEGCOLOR(1);
|
||||||
stage = 0;
|
stage = 0;
|
||||||
} else if(SEGENV.step < 512) {
|
} else if(prog < 512) {
|
||||||
color1 = SEGCOLOR(1);
|
color1 = SEGCOLOR(1);
|
||||||
color2 = SEGCOLOR(2);
|
color2 = SEGCOLOR(2);
|
||||||
stage = 1;
|
stage = 1;
|
||||||
@ -1335,7 +1357,7 @@ uint16_t WS2812FX::mode_tricolor_fade(void)
|
|||||||
stage = 2;
|
stage = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte stp = SEGENV.step % 256;
|
byte stp = prog; // % 256
|
||||||
uint32_t color = 0;
|
uint32_t color = 0;
|
||||||
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) {
|
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) {
|
||||||
if (stage == 2) {
|
if (stage == 2) {
|
||||||
@ -1432,17 +1454,24 @@ typedef struct Oscillator {
|
|||||||
*/
|
*/
|
||||||
uint16_t WS2812FX::mode_oscillate(void)
|
uint16_t WS2812FX::mode_oscillate(void)
|
||||||
{
|
{
|
||||||
static oscillator oscillators[NUM_COLORS] = {
|
uint8_t numOscillators = 3;
|
||||||
{SEGLEN/4, SEGLEN/8, 1, 1},
|
uint16_t dataSize = sizeof(oscillator) * numOscillators;
|
||||||
{SEGLEN/4*3, SEGLEN/8, 1, 2},
|
|
||||||
{SEGLEN/4*2, SEGLEN/8, -1, 1}
|
|
||||||
|
|
||||||
};
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
Oscillator* oscillators = reinterpret_cast<Oscillator*>(SEGENV.data);
|
||||||
|
|
||||||
|
if (SEGENV.call == 0)
|
||||||
|
{
|
||||||
|
oscillators[0] = {SEGLEN/4, SEGLEN/8, 1, 1};
|
||||||
|
oscillators[1] = {SEGLEN/4*3, SEGLEN/8, 1, 2};
|
||||||
|
oscillators[2] = {SEGLEN/4*2, SEGLEN/8, -1, 1};
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
|
uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
|
||||||
uint32_t it = now / cycleTime;
|
uint32_t it = now / cycleTime;
|
||||||
|
|
||||||
for(int8_t i=0; i < sizeof(oscillators)/sizeof(oscillators[0]); i++) {
|
for(uint8_t i=0; i < numOscillators; i++) {
|
||||||
// if the counter has increased, move the oscillator by the random step
|
// if the counter has increased, move the oscillator by the random step
|
||||||
if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
|
if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
|
||||||
oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8);
|
oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8);
|
||||||
@ -1459,9 +1488,9 @@ uint16_t WS2812FX::mode_oscillate(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int16_t i=0; i < SEGLEN; i++) {
|
for(uint16_t i=0; i < SEGLEN; i++) {
|
||||||
uint32_t color = BLACK;
|
uint32_t color = BLACK;
|
||||||
for(int8_t j=0; j < sizeof(oscillators)/sizeof(oscillators[0]); j++) {
|
for(uint8_t j=0; j < numOscillators; j++) {
|
||||||
if(i >= oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
|
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);
|
color = (color == BLACK) ? SEGMENT.colors[j] : color_blend(color, SEGMENT.colors[j], 128);
|
||||||
}
|
}
|
||||||
@ -1631,30 +1660,34 @@ uint16_t WS2812FX::mode_fire_2012()
|
|||||||
{
|
{
|
||||||
uint32_t it = now >> 5; //div 32
|
uint32_t it = now >> 5; //div 32
|
||||||
|
|
||||||
|
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
byte* heat = SEGENV.data;
|
||||||
|
|
||||||
if (it != SEGENV.step)
|
if (it != SEGENV.step)
|
||||||
{
|
{
|
||||||
// Step 1. Cool down every cell a little
|
// Step 1. Cool down every cell a little
|
||||||
for( int i = SEGMENT.start; i < SEGMENT.stop; i++) {
|
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
_locked[i] = qsub8(_locked[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
SEGENV.data[i] = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||||
for( int k= SEGMENT.stop -1; k >= SEGMENT.start + 2; k--) {
|
for (uint16_t k= SEGLEN -1; k > 1; k--) {
|
||||||
_locked[k] = (_locked[k - 1] + _locked[k - 2] + _locked[k - 2] ) / 3;
|
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
|
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
|
||||||
if( random8() <= SEGMENT.intensity ) {
|
if (random8() <= SEGMENT.intensity) {
|
||||||
int y = SEGMENT.start + random8(7);
|
uint8_t y = random8(7);
|
||||||
if (y < SEGMENT.stop) _locked[y] = qadd8(_locked[y], random8(160,255) );
|
if (y < SEGLEN) heat[y] = qadd8(heat[y], random8(160,255));
|
||||||
}
|
}
|
||||||
SEGENV.step = it;
|
SEGENV.step = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4. Map from heat cells to LED colors
|
// Step 4. Map from heat cells to LED colors
|
||||||
for( int j = SEGMENT.start; j < SEGMENT.stop; j++) {
|
for (uint16_t j = 0; j < SEGLEN; j++) {
|
||||||
CRGB color = ColorFromPalette( currentPalette, min(_locked[j],240), 255, LINEARBLEND);
|
CRGB color = ColorFromPalette(currentPalette, min(heat[j],240), 255, LINEARBLEND);
|
||||||
setPixelColor(j, color.red, color.green, color.blue);
|
setPixelColor(SEGMENT.start + j, color.red, color.green, color.blue);
|
||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
@ -1835,18 +1868,25 @@ uint16_t WS2812FX::mode_noise16_4()
|
|||||||
//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e
|
//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e
|
||||||
uint16_t WS2812FX::mode_colortwinkle()
|
uint16_t WS2812FX::mode_colortwinkle()
|
||||||
{
|
{
|
||||||
|
uint16_t dataSize = (SEGLEN+7) >> 3; //1 bit per LED
|
||||||
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
CRGB fastled_col, prev;
|
CRGB fastled_col, prev;
|
||||||
fract8 fadeUpAmount = 8 + (SEGMENT.speed/4), fadeDownAmount = 5 + (SEGMENT.speed/7);
|
fract8 fadeUpAmount = 8 + (SEGMENT.speed/4), fadeDownAmount = 5 + (SEGMENT.speed/7);
|
||||||
for( uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) {
|
for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) {
|
||||||
fastled_col = col_to_crgb(getPixelColor(i));
|
fastled_col = col_to_crgb(getPixelColor(i));
|
||||||
prev = fastled_col;
|
prev = fastled_col;
|
||||||
if(_locked[i]) {
|
uint16_t index = (i - SEGMENT.start) >> 3;
|
||||||
|
uint8_t bitNum = (i - SEGMENT.start) & 0x07;
|
||||||
|
bool fadeUp = bitRead(SEGENV.data[index], bitNum);
|
||||||
|
|
||||||
|
if (fadeUp) {
|
||||||
CRGB incrementalColor = fastled_col;
|
CRGB incrementalColor = fastled_col;
|
||||||
incrementalColor.nscale8_video( fadeUpAmount);
|
incrementalColor.nscale8_video( fadeUpAmount);
|
||||||
fastled_col += incrementalColor;
|
fastled_col += incrementalColor;
|
||||||
|
|
||||||
if( fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
||||||
_locked[i] = false;
|
bitWrite(SEGENV.data[index], bitNum, false);
|
||||||
}
|
}
|
||||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||||
|
|
||||||
@ -1863,13 +1903,15 @@ uint16_t WS2812FX::mode_colortwinkle()
|
|||||||
|
|
||||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++)
|
for (uint16_t j = 0; j <= SEGLEN / 50; j++)
|
||||||
{
|
{
|
||||||
if ( random8() <= SEGMENT.intensity ) {
|
if (random8() <= SEGMENT.intensity) {
|
||||||
for (uint8_t times = 0; times < 5; times++) //attempt to spawn a new pixel 5 times
|
for (uint8_t times = 0; times < 5; times++) //attempt to spawn a new pixel 5 times
|
||||||
{
|
{
|
||||||
int i = SEGMENT.start + random16(SEGLEN);
|
int i = SEGMENT.start + random16(SEGLEN);
|
||||||
if(getPixelColor(i) == 0) {
|
if(getPixelColor(i) == 0) {
|
||||||
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
||||||
_locked[i] = true;
|
uint16_t index = (i - SEGMENT.start) >> 3;
|
||||||
|
uint8_t bitNum = (i - SEGMENT.start) & 0x07;
|
||||||
|
bitWrite(SEGENV.data[index], bitNum, true);
|
||||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||||
break; //only spawn 1 new pixel per frame per 50 LEDs
|
break; //only spawn 1 new pixel per frame per 50 LEDs
|
||||||
}
|
}
|
||||||
@ -1903,29 +1945,33 @@ uint16_t WS2812FX::mode_lake() {
|
|||||||
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
|
// 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
|
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
||||||
uint16_t WS2812FX::mode_meteor() {
|
uint16_t WS2812FX::mode_meteor() {
|
||||||
|
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
byte* trail = SEGENV.data;
|
||||||
|
|
||||||
byte meteorSize= 1+ SEGLEN / 10;
|
byte meteorSize= 1+ SEGLEN / 10;
|
||||||
uint16_t counter = now * ((SEGMENT.speed >> 2) +8);
|
uint16_t counter = now * ((SEGMENT.speed >> 2) +8);
|
||||||
uint16_t in = counter * SEGLEN >> 16;
|
uint16_t in = counter * SEGLEN >> 16;
|
||||||
|
|
||||||
// fade all leds to colors[1] in LEDs one step
|
// fade all leds to colors[1] in LEDs one step
|
||||||
for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) {
|
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
if (random8() <= 255 - SEGMENT.intensity)
|
if (random8() <= 255 - SEGMENT.intensity)
|
||||||
{
|
{
|
||||||
byte meteorTrailDecay = 128 + random8(127);
|
byte meteorTrailDecay = 128 + random8(127);
|
||||||
_locked[i] = scale8(_locked[i], meteorTrailDecay);
|
trail[i] = scale8(trail[i], meteorTrailDecay);
|
||||||
setPixelColor(i, color_from_palette(_locked[i], false, true, 255));
|
setPixelColor(SEGMENT.start + i, color_from_palette(trail[i], false, true, 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw meteor
|
// draw meteor
|
||||||
for(int j = 0; j < meteorSize; j++) {
|
for(int j = 0; j < meteorSize; j++) {
|
||||||
uint16_t index = in + j;
|
uint16_t index = in + j;
|
||||||
if(in + j >= SEGMENT.stop) {
|
if(index >= SEGLEN) {
|
||||||
index = SEGMENT.start + (in + j - SEGMENT.stop);
|
index = (in + j - SEGLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
_locked[index] = 240;
|
trail[index] = 240;
|
||||||
setPixelColor(index, color_from_palette(_locked[index], false, true, 255));
|
setPixelColor(SEGMENT.start + index, color_from_palette(trail[index], false, true, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
@ -1936,29 +1982,33 @@ uint16_t WS2812FX::mode_meteor() {
|
|||||||
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
|
// 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
|
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
||||||
uint16_t WS2812FX::mode_meteor_smooth() {
|
uint16_t WS2812FX::mode_meteor_smooth() {
|
||||||
|
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
byte* trail = SEGENV.data;
|
||||||
|
|
||||||
byte meteorSize= 1+ SEGLEN / 10;
|
byte meteorSize= 1+ SEGLEN / 10;
|
||||||
uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, SEGMENT.start, SEGMENT.stop -1);
|
uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1);
|
||||||
|
|
||||||
// fade all leds to colors[1] in LEDs one step
|
// fade all leds to colors[1] in LEDs one step
|
||||||
for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) {
|
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
if (_locked[i] != 0 && random8() <= 255 - SEGMENT.intensity)
|
if (trail[i] != 0 && random8() <= 255 - SEGMENT.intensity)
|
||||||
{
|
{
|
||||||
int change = 3 - random8(12); //change each time between -8 and +3
|
int change = 3 - random8(12); //change each time between -8 and +3
|
||||||
_locked[i] += change;
|
trail[i] += change;
|
||||||
if (_locked[i] > 245) _locked[i] = 0;
|
if (trail[i] > 245) trail[i] = 0;
|
||||||
if (_locked[i] > 240) _locked[i] = 240;
|
if (trail[i] > 240) trail[i] = 240;
|
||||||
setPixelColor(i, color_from_palette(_locked[i], false, true, 255));
|
setPixelColor(SEGMENT.start + i, color_from_palette(trail[i], false, true, 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw meteor
|
// draw meteor
|
||||||
for(int j = 0; j < meteorSize; j++) {
|
for(int j = 0; j < meteorSize; j++) {
|
||||||
uint16_t index = in + j;
|
uint16_t index = in + j;
|
||||||
if(in + j >= SEGMENT.stop) {
|
if(in + j >= SEGLEN) {
|
||||||
index = SEGMENT.start + (in + j - SEGMENT.stop);
|
index = (in + j - SEGLEN);
|
||||||
}
|
}
|
||||||
setPixelColor(index, color_blend(getPixelColor(index), color_from_palette(240, false, true, 255), 48));
|
setPixelColor(SEGMENT.start + index, color_blend(getPixelColor(SEGMENT.start + index), color_from_palette(240, false, true, 255), 48));
|
||||||
_locked[index] = 240;
|
trail[index] = 240;
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGENV.step += SEGMENT.speed +1;
|
SEGENV.step += SEGMENT.speed +1;
|
||||||
@ -2000,23 +2050,35 @@ uint16_t WS2812FX::mode_railway()
|
|||||||
//Water ripple
|
//Water ripple
|
||||||
//propagation velocity from speed
|
//propagation velocity from speed
|
||||||
//drop rate from intensity
|
//drop rate from intensity
|
||||||
|
|
||||||
|
//4 bytes
|
||||||
|
typedef struct Ripple {
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t color;
|
||||||
|
uint16_t pos;
|
||||||
|
} ripple;
|
||||||
|
|
||||||
uint16_t WS2812FX::mode_ripple()
|
uint16_t WS2812FX::mode_ripple()
|
||||||
{
|
{
|
||||||
uint16_t maxripples = SEGLEN / 4;
|
uint16_t maxRipples = 1 + (SEGLEN >> 2);
|
||||||
if (maxripples == 0) return mode_static();
|
if (maxRipples > 100) maxRipples = 100;
|
||||||
|
uint16_t dataSize = sizeof(ripple) * maxRipples;
|
||||||
|
|
||||||
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
|
||||||
|
|
||||||
fill(SEGCOLOR(1));
|
fill(SEGCOLOR(1));
|
||||||
|
|
||||||
//draw wave
|
//draw wave
|
||||||
for (uint16_t rippleI = 0; rippleI < maxripples; rippleI++)
|
for (uint16_t i = 0; i < maxRipples; i++)
|
||||||
{
|
{
|
||||||
uint16_t storeI = SEGMENT.start + 4*rippleI;
|
uint16_t ripplestate = ripples[i].state;
|
||||||
uint16_t ripplestate = _locked[storeI];
|
|
||||||
if (ripplestate)
|
if (ripplestate)
|
||||||
{
|
{
|
||||||
uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation
|
uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation
|
||||||
uint16_t rippleorigin = (_locked[storeI+1] << 8) + _locked[storeI+2];
|
uint16_t rippleorigin = ripples[i].pos;
|
||||||
uint32_t col = color_from_palette(_locked[storeI+3], false, false, 255);
|
uint32_t col = color_from_palette(ripples[i].color, false, false, 255);
|
||||||
uint16_t propagation = ((ripplestate/rippledecay -1) * SEGMENT.speed);
|
uint16_t propagation = ((ripplestate/rippledecay -1) * SEGMENT.speed);
|
||||||
int16_t propI = propagation >> 8;
|
int16_t propI = propagation >> 8;
|
||||||
uint8_t propF = propagation & 0xFF;
|
uint8_t propF = propagation & 0xFF;
|
||||||
@ -2026,7 +2088,7 @@ uint16_t WS2812FX::mode_ripple()
|
|||||||
for (int16_t v = left; v < left +4; v++)
|
for (int16_t v = left; v < left +4; v++)
|
||||||
{
|
{
|
||||||
uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
|
uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
|
||||||
if (v >= SEGMENT.start)
|
if (v < SEGMENT.stop && v >= SEGMENT.start)
|
||||||
{
|
{
|
||||||
setPixelColor(v, color_blend(getPixelColor(v), col, mag));
|
setPixelColor(v, color_blend(getPixelColor(v), col, mag));
|
||||||
}
|
}
|
||||||
@ -2037,16 +2099,14 @@ uint16_t WS2812FX::mode_ripple()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ripplestate += rippledecay;
|
ripplestate += rippledecay;
|
||||||
_locked[storeI] = (ripplestate > 254) ? 0 : ripplestate;
|
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
|
||||||
} else //randomly create new wave
|
} else //randomly create new wave
|
||||||
{
|
{
|
||||||
if (random16(IBN + 10000) <= SEGMENT.intensity)
|
if (random16(IBN + 10000) <= SEGMENT.intensity)
|
||||||
{
|
{
|
||||||
_locked[storeI] = 1;
|
ripples[i].state = 1;
|
||||||
uint16_t origin = SEGMENT.start + random16(SEGLEN);
|
ripples[i].pos = SEGMENT.start + random16(SEGLEN);
|
||||||
_locked[storeI+1] = origin >> 8;
|
ripples[i].color = random8(); //color
|
||||||
_locked[storeI+2] = origin & 0xFF;
|
|
||||||
_locked[storeI+3] = random8(); //color
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2567,3 +2627,247 @@ uint16_t WS2812FX::mode_candle()
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
/ Fireworks in starburst effect
|
||||||
|
/ based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/
|
||||||
|
/ Speed sets frequency of new starbursts, intensity is the intensity of the burst
|
||||||
|
*/
|
||||||
|
#define STARBURST_MAX_FRAG 12
|
||||||
|
|
||||||
|
//each needs 64 byte
|
||||||
|
typedef struct particle {
|
||||||
|
CRGB color;
|
||||||
|
uint32_t birth =0;
|
||||||
|
uint32_t last =0;
|
||||||
|
float vel =0;
|
||||||
|
uint16_t pos =-1;
|
||||||
|
float fragment[STARBURST_MAX_FRAG];
|
||||||
|
} star;
|
||||||
|
|
||||||
|
uint16_t WS2812FX::mode_starburst(void) {
|
||||||
|
uint8_t numStars = 1 + (SEGLEN >> 3);
|
||||||
|
if (numStars > 15) numStars = 15;
|
||||||
|
uint16_t dataSize = sizeof(star) * numStars;
|
||||||
|
|
||||||
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
uint32_t it = millis();
|
||||||
|
|
||||||
|
star* stars = reinterpret_cast<star*>(SEGENV.data);
|
||||||
|
|
||||||
|
float maxSpeed = 375.0f; // Max velocity
|
||||||
|
float particleIgnition = 250.0f; // How long to "flash"
|
||||||
|
float particleFadeTime = 1500.0f; // Fade out time
|
||||||
|
|
||||||
|
for (int j = 0; j < numStars; j++)
|
||||||
|
{
|
||||||
|
// speed to adjust chance of a burst, max is nearly always.
|
||||||
|
if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0)
|
||||||
|
{
|
||||||
|
// Pick a random color and location.
|
||||||
|
uint16_t startPos = random16(SEGLEN-1);
|
||||||
|
float multiplier = (float)(random8())/255.0 * 1.0;
|
||||||
|
|
||||||
|
stars[j].color = col_to_crgb(color_wheel(random8()));
|
||||||
|
stars[j].pos = startPos;
|
||||||
|
stars[j].vel = maxSpeed * (float)(random8())/255.0 * multiplier;
|
||||||
|
stars[j].birth = it;
|
||||||
|
stars[j].last = it;
|
||||||
|
// more fragments means larger burst effect
|
||||||
|
int num = random8(3,6 + (SEGMENT.intensity >> 5));
|
||||||
|
|
||||||
|
for (int i=0; i < STARBURST_MAX_FRAG; i++) {
|
||||||
|
if (i < num) stars[j].fragment[i] = startPos;
|
||||||
|
else stars[j].fragment[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fill(SEGCOLOR(1));
|
||||||
|
|
||||||
|
for (int j=0; j<numStars; j++)
|
||||||
|
{
|
||||||
|
if (stars[j].birth != 0) {
|
||||||
|
float dt = (it-stars[j].last)/1000.0;
|
||||||
|
|
||||||
|
for (int i=0; i < STARBURST_MAX_FRAG; i++) {
|
||||||
|
int var = i >> 1;
|
||||||
|
|
||||||
|
if (stars[j].fragment[i] > 0) {
|
||||||
|
//all fragments travel right, will be mirrored on other side
|
||||||
|
stars[j].fragment[i] += stars[j].vel * dt * (float)var/3.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stars[j].last = it;
|
||||||
|
stars[j].vel -= 3*stars[j].vel*dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRGB c = stars[j].color;
|
||||||
|
|
||||||
|
// If the star is brand new, it flashes white briefly.
|
||||||
|
// Otherwise it just fades over time.
|
||||||
|
float fade = 0.0f;
|
||||||
|
float age = it-stars[j].birth;
|
||||||
|
|
||||||
|
if (age < particleIgnition) {
|
||||||
|
c = col_to_crgb(color_blend(WHITE, crgb_to_col(c), 254.5f*((age / particleIgnition))));
|
||||||
|
} else {
|
||||||
|
// Figure out how much to fade and shrink the star based on
|
||||||
|
// its age relative to its lifetime
|
||||||
|
if (age > particleIgnition + particleFadeTime) {
|
||||||
|
fade = 1.0f; // Black hole, all faded out
|
||||||
|
stars[j].birth = 0;
|
||||||
|
c = col_to_crgb(SEGCOLOR(1));
|
||||||
|
} else {
|
||||||
|
age -= particleIgnition;
|
||||||
|
fade = (age / particleFadeTime); // Fading star
|
||||||
|
byte f = 254.5f*fade;
|
||||||
|
c = col_to_crgb(color_blend(crgb_to_col(c), SEGCOLOR(1), f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float particleSize = (1.0 - fade) * 2;
|
||||||
|
|
||||||
|
for (uint8_t index=0; index < STARBURST_MAX_FRAG*2; index++) {
|
||||||
|
bool mirrored = index & 0x1;
|
||||||
|
uint8_t i = index >> 1;
|
||||||
|
if (stars[j].fragment[i] > 0) {
|
||||||
|
float loc = stars[j].fragment[i];
|
||||||
|
if (mirrored) loc -= (loc-stars[j].pos)*2;
|
||||||
|
int start = loc - particleSize;
|
||||||
|
int end = loc + particleSize;
|
||||||
|
if (start < 0) start = 0;
|
||||||
|
if (start == end) end++;
|
||||||
|
if (end > SEGLEN) end = SEGLEN;
|
||||||
|
for (int p = start; p < end; p++) {
|
||||||
|
setPixelColor(SEGMENT.start+p, c.r, c.g, c.b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FRAMETIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exploding fireworks effect
|
||||||
|
* adapted from: http://www.anirama.com/1000leds/1d-fireworks/
|
||||||
|
*/
|
||||||
|
|
||||||
|
//each needs 12 byte
|
||||||
|
typedef struct Spark {
|
||||||
|
float pos;
|
||||||
|
float vel;
|
||||||
|
uint16_t col;
|
||||||
|
uint8_t colIndex;
|
||||||
|
} spark;
|
||||||
|
|
||||||
|
uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||||
|
{
|
||||||
|
//allocate segment data
|
||||||
|
uint16_t numSparks = 2 + (SEGLEN >> 1);
|
||||||
|
if (numSparks > 80) numSparks = 80;
|
||||||
|
uint16_t dataSize = sizeof(spark) * numSparks;
|
||||||
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
|
fill(BLACK);
|
||||||
|
|
||||||
|
bool actuallyReverse = SEGMENT.getOption(1);
|
||||||
|
//have fireworks start in either direction based on intensity
|
||||||
|
SEGMENT.setOption(1, SEGENV.step);
|
||||||
|
|
||||||
|
Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data);
|
||||||
|
Spark* flare = sparks; //first spark is flare data
|
||||||
|
|
||||||
|
float gravity = -0.0004 - (SEGMENT.speed/800000.0); // m/s/s
|
||||||
|
gravity *= SEGLEN;
|
||||||
|
|
||||||
|
if (SEGENV.aux0 < 2) { //FLARE
|
||||||
|
if (SEGENV.aux0 == 0) { //init flare
|
||||||
|
flare->pos = 0;
|
||||||
|
uint16_t peakHeight = 75 + random8(180); //0-255
|
||||||
|
peakHeight = (peakHeight * (SEGLEN -1)) >> 8;
|
||||||
|
flare->vel = sqrt(-2.0 * gravity * peakHeight);
|
||||||
|
flare->col = 255; //brightness
|
||||||
|
|
||||||
|
SEGENV.aux0 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// launch
|
||||||
|
if (flare->vel > 12 * gravity) {
|
||||||
|
// flare
|
||||||
|
setPixelColor(SEGMENT.start + int(flare->pos),flare->col,flare->col,flare->col);
|
||||||
|
|
||||||
|
flare->pos += flare->vel;
|
||||||
|
flare->pos = constrain(flare->pos, 0, SEGLEN-1);
|
||||||
|
flare->vel += gravity;
|
||||||
|
flare->col -= 2;
|
||||||
|
} else {
|
||||||
|
SEGENV.aux0 = 2; // ready to explode
|
||||||
|
}
|
||||||
|
} else if (SEGENV.aux0 < 4) {
|
||||||
|
/*
|
||||||
|
* Explode!
|
||||||
|
*
|
||||||
|
* Explosion happens where the flare ended.
|
||||||
|
* Size is proportional to the height.
|
||||||
|
*/
|
||||||
|
int nSparks = flare->pos;
|
||||||
|
nSparks = constrain(nSparks, 0, numSparks);
|
||||||
|
static float dying_gravity;
|
||||||
|
|
||||||
|
// initialize sparks
|
||||||
|
if (SEGENV.aux0 == 2) {
|
||||||
|
for (int i = 1; i < nSparks; i++) {
|
||||||
|
sparks[i].pos = flare->pos;
|
||||||
|
sparks[i].vel = (float(random16(0, 20000)) / 10000.0) - 0.9; // from -0.9 to 1.1
|
||||||
|
sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
|
||||||
|
//sparks[i].col = constrain(sparks[i].col, 0, 345);
|
||||||
|
sparks[i].colIndex = random8();
|
||||||
|
sparks[i].vel *= flare->pos/SEGLEN; // proportional to height
|
||||||
|
sparks[i].vel *= -gravity *50;
|
||||||
|
}
|
||||||
|
//sparks[1].col = 345; // this will be our known spark
|
||||||
|
dying_gravity = gravity/2;
|
||||||
|
SEGENV.aux0 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sparks[1].col > 4) {//&& sparks[1].pos > 0) { // as long as our known spark is lit, work with all the sparks
|
||||||
|
for (int i = 1; i < nSparks; i++) {
|
||||||
|
sparks[i].pos += sparks[i].vel;
|
||||||
|
sparks[i].vel += dying_gravity;
|
||||||
|
if (sparks[i].col > 3) sparks[i].col -= 4;
|
||||||
|
|
||||||
|
if (sparks[i].pos > 0 && sparks[i].pos < SEGLEN) {
|
||||||
|
uint16_t prog = sparks[i].col;
|
||||||
|
uint32_t spColor = (SEGMENT.palette) ? color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
|
||||||
|
CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
|
||||||
|
if (prog > 300) { //fade from white to spark color
|
||||||
|
c = col_to_crgb(color_blend(spColor, WHITE, (prog - 300)*5));
|
||||||
|
} else if (prog > 45) { //fade from spark color to black
|
||||||
|
c = col_to_crgb(color_blend(BLACK, spColor, prog - 45));
|
||||||
|
uint8_t cooling = (300 - prog) >> 5;
|
||||||
|
c.g = qsub8(c.g, cooling);
|
||||||
|
c.b = qsub8(c.b, cooling * 2);
|
||||||
|
}
|
||||||
|
setPixelColor(SEGMENT.start + int(sparks[i].pos), c.red, c.green, c.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dying_gravity *= .99; // as sparks burn out they fall slower
|
||||||
|
} else {
|
||||||
|
SEGENV.aux0 = 6 + random8(10); //wait for this many frames
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SEGENV.aux0--;
|
||||||
|
if (SEGENV.aux0 < 4) {
|
||||||
|
SEGENV.aux0 = 0; //back to flare
|
||||||
|
SEGENV.step = (SEGMENT.intensity > random8()); //decide firing side
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SEGMENT.setOption(1, actuallyReverse);
|
||||||
|
|
||||||
|
return FRAMETIME;
|
||||||
|
}
|
||||||
|
88
wled00/FX.h
88
wled00/FX.h
@ -44,10 +44,17 @@
|
|||||||
#define WLED_FPS 42
|
#define WLED_FPS 42
|
||||||
#define FRAMETIME (1000/WLED_FPS)
|
#define FRAMETIME (1000/WLED_FPS)
|
||||||
|
|
||||||
/* each segment uses 37 bytes of SRAM memory, so if you're application fails because of
|
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||||
#define MAX_NUM_SEGMENTS 10
|
#define MAX_NUM_SEGMENTS 10
|
||||||
|
|
||||||
|
/* How much data bytes all segments combined may allocate */
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define MAX_SEGMENT_DATA 2048
|
||||||
|
#else
|
||||||
|
#define MAX_SEGMENT_DATA 8192
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NUM_COLORS 3 /* number of colors per segment */
|
#define NUM_COLORS 3 /* number of colors per segment */
|
||||||
#define SEGMENT _segments[_segment_index]
|
#define SEGMENT _segments[_segment_index]
|
||||||
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
|
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
|
||||||
@ -84,7 +91,7 @@
|
|||||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||||
#define IS_SELECTED ((SEGMENT.options & SELECTED) == SELECTED )
|
#define IS_SELECTED ((SEGMENT.options & SELECTED) == SELECTED )
|
||||||
|
|
||||||
#define MODE_COUNT 94
|
#define MODE_COUNT 96
|
||||||
|
|
||||||
#define FX_MODE_STATIC 0
|
#define FX_MODE_STATIC 0
|
||||||
#define FX_MODE_BLINK 1
|
#define FX_MODE_BLINK 1
|
||||||
@ -175,16 +182,21 @@
|
|||||||
#define FX_MODE_SPOTS_FADE 86
|
#define FX_MODE_SPOTS_FADE 86
|
||||||
#define FX_MODE_GLITTER 87
|
#define FX_MODE_GLITTER 87
|
||||||
#define FX_MODE_CANDLE 88
|
#define FX_MODE_CANDLE 88
|
||||||
#define FX_MODE_BOUNCINGBALLS 89
|
#define FX_MODE_STARBURST 89
|
||||||
#define FX_MODE_SINELON 90
|
#define FX_MODE_EXPLODING_FIREWORKS 90
|
||||||
#define FX_MODE_SINELON_DUAL 91
|
#define FX_MODE_BOUNCINGBALLS 91
|
||||||
#define FX_MODE_SINELON_RAINBOW 92
|
#define FX_MODE_SINELON 92
|
||||||
#define FX_MODE_POPCORN 93
|
#define FX_MODE_SINELON_DUAL 93
|
||||||
|
#define FX_MODE_SINELON_RAINBOW 94
|
||||||
|
#define FX_MODE_POPCORN 95
|
||||||
|
|
||||||
|
|
||||||
class WS2812FX {
|
class WS2812FX {
|
||||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||||
|
|
||||||
|
// pre show callback
|
||||||
|
typedef void (*show_callback) (void);
|
||||||
|
|
||||||
// segment parameters
|
// segment parameters
|
||||||
public:
|
public:
|
||||||
typedef struct Segment { // 24 bytes
|
typedef struct Segment { // 24 bytes
|
||||||
@ -226,13 +238,33 @@ class WS2812FX {
|
|||||||
} segment;
|
} segment;
|
||||||
|
|
||||||
// segment runtime parameters
|
// segment runtime parameters
|
||||||
typedef struct Segment_runtime { // 16 bytes
|
typedef struct Segment_runtime { // 28 bytes
|
||||||
unsigned long next_time;
|
unsigned long next_time;
|
||||||
uint32_t step;
|
uint32_t step;
|
||||||
uint32_t call;
|
uint32_t call;
|
||||||
uint16_t aux0;
|
uint16_t aux0;
|
||||||
uint16_t aux1;
|
uint16_t aux1;
|
||||||
void reset(){next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;};
|
byte* data = nullptr;
|
||||||
|
bool allocateData(uint16_t len){
|
||||||
|
if (data && _dataLen == len) return true; //already allocated
|
||||||
|
deallocateData();
|
||||||
|
if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||||
|
data = new (std::nothrow) byte[len];
|
||||||
|
if (!data) return false; //allocation failed
|
||||||
|
WS2812FX::_usedSegmentData += len;
|
||||||
|
_dataLen = len;
|
||||||
|
memset(data, 0, len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void deallocateData(){
|
||||||
|
delete[] data;
|
||||||
|
data = nullptr;
|
||||||
|
WS2812FX::_usedSegmentData -= _dataLen;
|
||||||
|
_dataLen = 0;
|
||||||
|
}
|
||||||
|
void reset(){next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; deallocateData();}
|
||||||
|
private:
|
||||||
|
uint16_t _dataLen = 0;
|
||||||
} segment_runtime;
|
} segment_runtime;
|
||||||
|
|
||||||
WS2812FX() {
|
WS2812FX() {
|
||||||
@ -324,13 +356,15 @@ class WS2812FX {
|
|||||||
_mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern;
|
_mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern;
|
||||||
_mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots;
|
_mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots;
|
||||||
_mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade;
|
_mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade;
|
||||||
|
_mode[FX_MODE_GLITTER] = &WS2812FX::mode_glitter;
|
||||||
|
_mode[FX_MODE_CANDLE] = &WS2812FX::mode_candle;
|
||||||
|
_mode[FX_MODE_STARBURST] = &WS2812FX::mode_starburst;
|
||||||
|
_mode[FX_MODE_EXPLODING_FIREWORKS] = &WS2812FX::mode_exploding_fireworks;
|
||||||
_mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_BouncingBalls;
|
_mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_BouncingBalls;
|
||||||
_mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon;
|
_mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon;
|
||||||
_mode[FX_MODE_SINELON_DUAL] = &WS2812FX::mode_sinelon_dual;
|
_mode[FX_MODE_SINELON_DUAL] = &WS2812FX::mode_sinelon_dual;
|
||||||
_mode[FX_MODE_SINELON_RAINBOW] = &WS2812FX::mode_sinelon_rainbow;
|
_mode[FX_MODE_SINELON_RAINBOW] = &WS2812FX::mode_sinelon_rainbow;
|
||||||
_mode[FX_MODE_POPCORN] = &WS2812FX::mode_popcorn;
|
_mode[FX_MODE_POPCORN] = &WS2812FX::mode_popcorn;
|
||||||
_mode[FX_MODE_GLITTER] = &WS2812FX::mode_glitter;
|
|
||||||
_mode[FX_MODE_CANDLE] = &WS2812FX::mode_candle;
|
|
||||||
|
|
||||||
_brightness = DEFAULT_BRIGHTNESS;
|
_brightness = DEFAULT_BRIGHTNESS;
|
||||||
currentPalette = CRGBPalette16(CRGB::Black);
|
currentPalette = CRGBPalette16(CRGB::Black);
|
||||||
@ -338,8 +372,6 @@ class WS2812FX {
|
|||||||
ablMilliampsMax = 850;
|
ablMilliampsMax = 850;
|
||||||
currentMilliamps = 0;
|
currentMilliamps = 0;
|
||||||
timebase = 0;
|
timebase = 0;
|
||||||
_locked = nullptr;
|
|
||||||
_modeUsesLock = false;
|
|
||||||
bus = new NeoPixelWrapper();
|
bus = new NeoPixelWrapper();
|
||||||
resetSegments();
|
resetSegments();
|
||||||
}
|
}
|
||||||
@ -356,13 +388,8 @@ class WS2812FX {
|
|||||||
driverModeCronixie(bool b),
|
driverModeCronixie(bool b),
|
||||||
setCronixieDigits(byte* d),
|
setCronixieDigits(byte* d),
|
||||||
setCronixieBacklight(bool b),
|
setCronixieBacklight(bool b),
|
||||||
setIndividual(uint16_t i, uint32_t col),
|
|
||||||
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
||||||
lock(uint16_t i),
|
setShowCallback(show_callback cb),
|
||||||
lockRange(uint16_t i, uint16_t i2),
|
|
||||||
unlock(uint16_t i),
|
|
||||||
unlockRange(uint16_t i, uint16_t i2),
|
|
||||||
unlockAll(void),
|
|
||||||
setTransitionMode(bool t),
|
setTransitionMode(bool t),
|
||||||
trigger(void),
|
trigger(void),
|
||||||
setSegment(uint8_t n, uint16_t start, uint16_t stop),
|
setSegment(uint8_t n, uint16_t start, uint16_t stop),
|
||||||
@ -512,13 +539,15 @@ class WS2812FX {
|
|||||||
mode_tri_static_pattern(void),
|
mode_tri_static_pattern(void),
|
||||||
mode_spots(void),
|
mode_spots(void),
|
||||||
mode_spots_fade(void),
|
mode_spots_fade(void),
|
||||||
|
mode_glitter(void),
|
||||||
|
mode_candle(void),
|
||||||
|
mode_starburst(void),
|
||||||
|
mode_exploding_fireworks(void),
|
||||||
mode_BouncingBalls(void),
|
mode_BouncingBalls(void),
|
||||||
mode_sinelon(void),
|
mode_sinelon(void),
|
||||||
mode_sinelon_dual(void),
|
mode_sinelon_dual(void),
|
||||||
mode_sinelon_rainbow(void),
|
mode_sinelon_rainbow(void),
|
||||||
mode_popcorn(void),
|
mode_popcorn(void);
|
||||||
mode_glitter(void),
|
|
||||||
mode_candle(void);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -533,24 +562,24 @@ class WS2812FX {
|
|||||||
uint16_t _length, _lengthRaw, _usableCount;
|
uint16_t _length, _lengthRaw, _usableCount;
|
||||||
uint16_t _rand16seed;
|
uint16_t _rand16seed;
|
||||||
uint8_t _brightness;
|
uint8_t _brightness;
|
||||||
|
static uint16_t _usedSegmentData;
|
||||||
|
|
||||||
void handle_palette(void);
|
void handle_palette(void);
|
||||||
void fill(uint32_t);
|
void fill(uint32_t);
|
||||||
bool modeUsesLock(uint8_t);
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
_modeUsesLock,
|
|
||||||
_rgbwMode,
|
_rgbwMode,
|
||||||
_cronixieMode,
|
_cronixieMode,
|
||||||
_cronixieBacklightEnabled,
|
_cronixieBacklightEnabled,
|
||||||
_skipFirstMode,
|
_skipFirstMode,
|
||||||
_triggered;
|
_triggered;
|
||||||
|
|
||||||
byte* _locked;
|
|
||||||
byte _cronixieDigits[6];
|
byte _cronixieDigits[6];
|
||||||
|
|
||||||
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
|
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
|
||||||
|
|
||||||
|
show_callback _callback = nullptr;
|
||||||
|
|
||||||
// mode helper functions
|
// mode helper functions
|
||||||
uint16_t
|
uint16_t
|
||||||
blink(uint32_t, uint32_t, bool strobe, bool),
|
blink(uint32_t, uint32_t, bool strobe, bool),
|
||||||
@ -580,7 +609,8 @@ class WS2812FX {
|
|||||||
// start, stop, speed, intensity, palette, mode, options, 3 unused bytes (group, spacing, opacity), color[]
|
// start, stop, speed, intensity, palette, mode, options, 3 unused bytes (group, spacing, opacity), color[]
|
||||||
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
|
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
|
||||||
};
|
};
|
||||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 16 bytes per element
|
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
||||||
|
friend class Segment_runtime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -592,10 +622,10 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
|||||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
|
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
|
||||||
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
|
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||||
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
||||||
"Scanner Dual ","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
|
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
|
||||||
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
||||||
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Bouncing Balls",
|
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
||||||
"Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn"
|
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn"
|
||||||
])=====";
|
])=====";
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst, uint8_t disableNLeds)
|
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst, uint8_t disableNLeds)
|
||||||
{
|
{
|
||||||
if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL && disableNLeds == _disableNLeds) return;
|
if (supportWhite == _rgbwMode && countPixels == _length && disableNLeds == _disableNLeds) return;
|
||||||
RESET_RUNTIME;
|
RESET_RUNTIME;
|
||||||
_rgbwMode = supportWhite;
|
_rgbwMode = supportWhite;
|
||||||
_skipFirstMode = skipFirst;
|
_skipFirstMode = skipFirst;
|
||||||
@ -59,13 +59,9 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst, uin
|
|||||||
|
|
||||||
bus->Begin((NeoPixelType)ty, _lengthRaw);
|
bus->Begin((NeoPixelType)ty, _lengthRaw);
|
||||||
|
|
||||||
delete[] _locked;
|
|
||||||
_locked = new byte[_length];
|
|
||||||
|
|
||||||
_segments[0].start = 0;
|
_segments[0].start = 0;
|
||||||
_segments[0].stop = _usableCount;
|
_segments[0].stop = _usableCount;
|
||||||
|
|
||||||
unlockAll();
|
|
||||||
setBrightness(_brightness);
|
setBrightness(_brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,14 +92,6 @@ void WS2812FX::service() {
|
|||||||
_triggered = false;
|
_triggered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WS2812FX::modeUsesLock(uint8_t m)
|
|
||||||
{
|
|
||||||
if (m == FX_MODE_FIRE_2012 || m == FX_MODE_COLORTWINKLE ||
|
|
||||||
m == FX_MODE_METEOR || m == FX_MODE_METEOR_SMOOTH ||
|
|
||||||
m == FX_MODE_RIPPLE || m == FX_MODE_DYNAMIC ) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||||
uint8_t w = (c >> 24);
|
uint8_t w = (c >> 24);
|
||||||
uint8_t r = (c >> 16);
|
uint8_t r = (c >> 16);
|
||||||
@ -115,7 +103,6 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
|||||||
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||||
{
|
{
|
||||||
i = i * (_disableNLeds+1);
|
i = i * (_disableNLeds+1);
|
||||||
if (_locked[i] && !_modeUsesLock) return;
|
|
||||||
if (IS_REVERSE) i = SEGMENT.stop -1 -i + SEGMENT.start; //reverse just individual segment
|
if (IS_REVERSE) i = SEGMENT.stop -1 -i + SEGMENT.start; //reverse just individual segment
|
||||||
byte tmpg = g;
|
byte tmpg = g;
|
||||||
switch (colorOrder) //0 = Grb, default
|
switch (colorOrder) //0 = Grb, default
|
||||||
@ -208,6 +195,8 @@ void WS2812FX::setCronixieDigits(byte d[])
|
|||||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||||
|
|
||||||
void WS2812FX::show(void) {
|
void WS2812FX::show(void) {
|
||||||
|
if (_callback) _callback();
|
||||||
|
|
||||||
//power limit calculation
|
//power limit calculation
|
||||||
//each LED can draw up 195075 "power units" (approx. 53mA)
|
//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
|
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
|
||||||
@ -273,7 +262,6 @@ void WS2812FX::trigger() {
|
|||||||
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||||
if (segid >= MAX_NUM_SEGMENTS) return;
|
if (segid >= MAX_NUM_SEGMENTS) return;
|
||||||
|
|
||||||
bool anyUsedLock = _modeUsesLock, anyUseLock = false;
|
|
||||||
if (m >= MODE_COUNT) m = MODE_COUNT - 1;
|
if (m >= MODE_COUNT) m = MODE_COUNT - 1;
|
||||||
|
|
||||||
if (_segments[segid].mode != m)
|
if (_segments[segid].mode != m)
|
||||||
@ -281,13 +269,6 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
|||||||
_segment_runtimes[segid].reset();
|
_segment_runtimes[segid].reset();
|
||||||
_segments[segid].mode = m;
|
_segments[segid].mode = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
|
||||||
{
|
|
||||||
if (modeUsesLock(_segments[i].mode)) anyUseLock = true;
|
|
||||||
}
|
|
||||||
if (anyUsedLock && !anyUseLock) unlockAll();
|
|
||||||
_modeUsesLock = anyUseLock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t WS2812FX::getModeCount()
|
uint8_t WS2812FX::getModeCount()
|
||||||
@ -454,12 +435,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2) {
|
|||||||
if (n >= MAX_NUM_SEGMENTS) return;
|
if (n >= MAX_NUM_SEGMENTS) return;
|
||||||
Segment& seg = _segments[n];
|
Segment& seg = _segments[n];
|
||||||
if (seg.start == i1 && seg.stop == i2) return;
|
if (seg.start == i1 && seg.stop == i2) return;
|
||||||
if (seg.isActive() && modeUsesLock(seg.mode))
|
|
||||||
{
|
|
||||||
_modeUsesLock = false;
|
|
||||||
unlockRange(seg.start, seg.stop);
|
|
||||||
_modeUsesLock = true;
|
|
||||||
}
|
|
||||||
_segment_index = n; fill(0); //turn old segment range off
|
_segment_index = n; fill(0); //turn old segment range off
|
||||||
if (i2 <= i1) //disable segment
|
if (i2 <= i1) //disable segment
|
||||||
{
|
{
|
||||||
@ -473,7 +449,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2) {
|
|||||||
|
|
||||||
void WS2812FX::resetSegments() {
|
void WS2812FX::resetSegments() {
|
||||||
memset(_segments, 0, sizeof(_segments));
|
memset(_segments, 0, sizeof(_segments));
|
||||||
memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
||||||
_segment_index = 0;
|
_segment_index = 0;
|
||||||
_segments[0].mode = DEFAULT_MODE;
|
_segments[0].mode = DEFAULT_MODE;
|
||||||
_segments[0].colors[0] = DEFAULT_COLOR;
|
_segments[0].colors[0] = DEFAULT_COLOR;
|
||||||
@ -484,64 +460,25 @@ void WS2812FX::resetSegments() {
|
|||||||
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++)
|
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++)
|
||||||
{
|
{
|
||||||
_segments[i].colors[0] = color_wheel(i*51);
|
_segments[i].colors[0] = color_wheel(i*51);
|
||||||
|
_segment_runtimes[i].reset();
|
||||||
}
|
}
|
||||||
}
|
_segment_runtimes[0].reset();
|
||||||
|
|
||||||
void WS2812FX::setIndividual(uint16_t i, uint32_t col)
|
|
||||||
{
|
|
||||||
if (modeUsesLock(SEGMENT.mode)) return;
|
|
||||||
if (i >= 0 && i < _length)
|
|
||||||
{
|
|
||||||
_locked[i] = false;
|
|
||||||
setPixelColor(i, col);
|
|
||||||
_locked[i] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
||||||
{
|
{
|
||||||
if (i2 >= i)
|
if (i2 >= i)
|
||||||
{
|
{
|
||||||
for (uint16_t x = i; x <= i2; x++) setIndividual(x,col);
|
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
for (uint16_t x = i2; x <= i; x++) setIndividual(x,col);
|
for (uint16_t x = i2; x <= i; x++) setPixelColor(x, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::lock(uint16_t i)
|
void WS2812FX::setShowCallback(show_callback cb)
|
||||||
{
|
{
|
||||||
if (_modeUsesLock) return;
|
_callback = cb;
|
||||||
if (i < _length) _locked[i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::lockRange(uint16_t i, uint16_t i2)
|
|
||||||
{
|
|
||||||
if (_modeUsesLock) return;
|
|
||||||
for (uint16_t x = i; x < i2; x++)
|
|
||||||
{
|
|
||||||
if (x < _length) _locked[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::unlock(uint16_t i)
|
|
||||||
{
|
|
||||||
if (_modeUsesLock) return;
|
|
||||||
if (i < _length) _locked[i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::unlockRange(uint16_t i, uint16_t i2)
|
|
||||||
{
|
|
||||||
if (_modeUsesLock) return;
|
|
||||||
for (uint16_t x = i; x < i2; x++)
|
|
||||||
{
|
|
||||||
if (x < _length) _locked[x] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WS2812FX::unlockAll()
|
|
||||||
{
|
|
||||||
for (int i=0; i < _length; i++) _locked[i] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::setTransitionMode(bool t)
|
void WS2812FX::setTransitionMode(bool t)
|
||||||
@ -862,3 +799,5 @@ uint32_t WS2812FX::gamma32(uint32_t color)
|
|||||||
b = gammaT[b];
|
b = gammaT[b];
|
||||||
return ((w << 24) | (r << 16) | (g << 8) | (b));
|
return ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t WS2812FX::_usedSegmentData = 0;
|
||||||
|
@ -130,26 +130,25 @@ public:
|
|||||||
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, LEDPIN);
|
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, LEDPIN);
|
||||||
#endif
|
#endif
|
||||||
_pGrbw->Begin();
|
_pGrbw->Begin();
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef WLED_USE_ANALOG_LEDS
|
#ifdef WLED_USE_ANALOG_LEDS
|
||||||
//init PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
pinMode(WPIN, OUTPUT);
|
||||||
pinMode(RPIN, OUTPUT);
|
#ifdef WLED_USE_5CH_LEDS
|
||||||
pinMode(GPIN, OUTPUT);
|
pinMode(W2PIN, OUTPUT);
|
||||||
pinMode(BPIN, OUTPUT);
|
|
||||||
switch (_type) {
|
|
||||||
case NeoPixelType_Grb: break;
|
|
||||||
#ifdef WLED_USE_5CH_LEDS
|
|
||||||
case NeoPixelType_Grbw: pinMode(WPIN, OUTPUT); pinMode(W2PIN, OUTPUT); break;
|
|
||||||
#else
|
|
||||||
case NeoPixelType_Grbw: pinMode(WPIN, OUTPUT); break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
analogWriteRange(255); //same range as one RGB channel
|
|
||||||
analogWriteFreq(880); //PWM frequency proven as good for LEDs
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WLED_USE_ANALOG_LEDS
|
||||||
|
//init PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
||||||
|
pinMode(RPIN, OUTPUT);
|
||||||
|
pinMode(GPIN, OUTPUT);
|
||||||
|
pinMode(BPIN, OUTPUT);
|
||||||
|
analogWriteRange(255); //same range as one RGB channel
|
||||||
|
analogWriteFreq(880); //PWM frequency proven as good for LEDs
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_USE_ANALOG_LEDS
|
#ifdef WLED_USE_ANALOG_LEDS
|
||||||
|
@ -368,10 +368,10 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
|
|||||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||||
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
||||||
<h3>About</h3>
|
<h3>About</h3>
|
||||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.9.0-b1<br><br>
|
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.9.0-b2<br><br>
|
||||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
|
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||||
(c) 2016-2019 Christian Schwinne <br>
|
(c) 2016-2020 Christian Schwinne <br>
|
||||||
<i>Licensed under the MIT license</i><br><br>
|
<i>Licensed under the MIT license</i><br><br>
|
||||||
Server message: <span class="msg"> Response error! </span><hr>
|
Server message: <span class="msg"> Response error! </span><hr>
|
||||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
|
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
|
||||||
|
@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
|
|
||||||
//version code in format yymmddb (b = daily build)
|
//version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 1912232
|
#define VERSION 2001031
|
||||||
char versionString[] = "0.9.0-b2";
|
char versionString[] = "0.9.0-b2";
|
||||||
|
|
||||||
|
|
||||||
@ -424,6 +424,7 @@ AsyncMqttClient* mqtt = NULL;
|
|||||||
void colorFromUint32(uint32_t,bool=false);
|
void colorFromUint32(uint32_t,bool=false);
|
||||||
void serveMessage(AsyncWebServerRequest*,uint16_t,String,String,byte);
|
void serveMessage(AsyncWebServerRequest*,uint16_t,String,String,byte);
|
||||||
void handleE131Packet(e131_packet_t*, IPAddress);
|
void handleE131Packet(e131_packet_t*, IPAddress);
|
||||||
|
void handleOverlayDraw();
|
||||||
|
|
||||||
#define E131_MAX_UNIVERSE_COUNT 9
|
#define E131_MAX_UNIVERSE_COUNT 9
|
||||||
|
|
||||||
|
@ -200,7 +200,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
|
|
||||||
if (request->hasArg("OL")){
|
if (request->hasArg("OL")){
|
||||||
overlayDefault = request->arg("OL").toInt();
|
overlayDefault = request->arg("OL").toInt();
|
||||||
if (overlayCurrent != overlayDefault) strip.unlockAll();
|
|
||||||
overlayCurrent = overlayDefault;
|
overlayCurrent = overlayDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,29 +458,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
pos = req.indexOf("OL=");
|
pos = req.indexOf("OL=");
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
overlayCurrent = getNumVal(&req, pos);
|
overlayCurrent = getNumVal(&req, pos);
|
||||||
strip.unlockAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
//(un)lock pixel (ranges)
|
|
||||||
pos = req.indexOf("&L=");
|
|
||||||
if (pos > 0) {
|
|
||||||
uint16_t index = getNumVal(&req, pos);
|
|
||||||
pos = req.indexOf("L2=");
|
|
||||||
bool unlock = req.indexOf("UL") > 0;
|
|
||||||
if (pos > 0) {
|
|
||||||
uint16_t index2 = getNumVal(&req, pos);
|
|
||||||
if (unlock) {
|
|
||||||
strip.unlockRange(index, index2);
|
|
||||||
} else {
|
|
||||||
strip.lockRange(index, index2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (unlock) {
|
|
||||||
strip.unlock(index);
|
|
||||||
} else {
|
|
||||||
strip.lock(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//apply macro
|
//apply macro
|
||||||
@ -622,6 +598,10 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
|
|
||||||
//cronixie
|
//cronixie
|
||||||
#ifndef WLED_DISABLE_CRONIXIE
|
#ifndef WLED_DISABLE_CRONIXIE
|
||||||
|
//mode, 1 countdown
|
||||||
|
pos = req.indexOf("NM=");
|
||||||
|
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
|
||||||
|
|
||||||
pos = req.indexOf("NX="); //sets digits to code
|
pos = req.indexOf("NX="); //sets digits to code
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
strlcpy(cronixieDisplay, req.substring(pos + 3, pos + 9).c_str(), 6);
|
strlcpy(cronixieDisplay, req.substring(pos + 3, pos + 9).c_str(), 6);
|
||||||
@ -636,9 +616,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
overlayRefreshedTime = 0;
|
overlayRefreshedTime = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//mode, 1 countdown
|
|
||||||
pos = req.indexOf("NM=");
|
|
||||||
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
|
|
||||||
|
|
||||||
pos = req.indexOf("U0="); //user var 0
|
pos = req.indexOf("U0="); //user var 0
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
|
@ -96,6 +96,7 @@ void wledInit()
|
|||||||
void beginStrip()
|
void beginStrip()
|
||||||
{
|
{
|
||||||
// Initialize NeoPixel Strip and button
|
// Initialize NeoPixel Strip and button
|
||||||
|
strip.setShowCallback(handleOverlayDraw);
|
||||||
|
|
||||||
#ifdef BTNPIN
|
#ifdef BTNPIN
|
||||||
pinMode(BTNPIN, INPUT_PULLUP);
|
pinMode(BTNPIN, INPUT_PULLUP);
|
||||||
|
@ -79,7 +79,6 @@ void arlsLock(uint32_t timeoutMs)
|
|||||||
{
|
{
|
||||||
strip.setPixelColor(i,0,0,0,0);
|
strip.setPixelColor(i,0,0,0,0);
|
||||||
}
|
}
|
||||||
strip.unlockAll();
|
|
||||||
realtimeActive = true;
|
realtimeActive = true;
|
||||||
}
|
}
|
||||||
realtimeTimeout = millis() + timeoutMs;
|
realtimeTimeout = millis() + timeoutMs;
|
||||||
@ -127,7 +126,6 @@ void handleNotifications()
|
|||||||
//unlock strip when realtime UDP times out
|
//unlock strip when realtime UDP times out
|
||||||
if (realtimeActive && millis() > realtimeTimeout)
|
if (realtimeActive && millis() > realtimeTimeout)
|
||||||
{
|
{
|
||||||
//strip.unlockAll();
|
|
||||||
strip.setBrightness(bri);
|
strip.setBrightness(bri);
|
||||||
realtimeActive = false;
|
realtimeActive = false;
|
||||||
//strip.setMode(effectCurrent);
|
//strip.setMode(effectCurrent);
|
||||||
|
@ -163,13 +163,16 @@ void setCountdown()
|
|||||||
//returns true if countdown just over
|
//returns true if countdown just over
|
||||||
bool checkCountdown()
|
bool checkCountdown()
|
||||||
{
|
{
|
||||||
long diff = countdownTime - now();
|
unsigned long n = now();
|
||||||
local = abs(diff);
|
local = countdownTime - n;
|
||||||
if (diff <0 && !countdownOverTriggered)
|
if (n > countdownTime) {
|
||||||
{
|
local = n - countdownTime;
|
||||||
if (macroCountdown != 0) applyMacro(macroCountdown);
|
if (!countdownOverTriggered)
|
||||||
countdownOverTriggered = true;
|
{
|
||||||
return true;
|
if (macroCountdown != 0) applyMacro(macroCountdown);
|
||||||
|
countdownOverTriggered = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Used to draw clock overlays over the strip
|
* Used to draw clock overlays over the strip
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void initCronixie()
|
void initCronixie()
|
||||||
{
|
{
|
||||||
if (overlayCurrent == 3 && !cronixieInit)
|
if (overlayCurrent == 3 && !cronixieInit)
|
||||||
@ -24,14 +25,8 @@ void handleOverlays()
|
|||||||
initCronixie();
|
initCronixie();
|
||||||
updateLocalTime();
|
updateLocalTime();
|
||||||
checkTimers();
|
checkTimers();
|
||||||
switch (overlayCurrent)
|
checkCountdown();
|
||||||
{
|
if (overlayCurrent == 3) _overlayCronixie();//Diamex cronixie clock kit
|
||||||
case 0: break;//no overlay
|
|
||||||
case 1: _overlayAnalogClock(); break;//2 analog clock
|
|
||||||
case 2: break;//nixie 1-digit, removed
|
|
||||||
case 3: _overlayCronixie();//Diamex cronixie clock kit
|
|
||||||
}
|
|
||||||
if (!countdownMode || overlayCurrent < 3) checkCountdown(); //countdown macro activation must work
|
|
||||||
overlayRefreshedTime = millis();
|
overlayRefreshedTime = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +35,6 @@ void handleOverlays()
|
|||||||
void _overlayAnalogClock()
|
void _overlayAnalogClock()
|
||||||
{
|
{
|
||||||
int overlaySize = overlayMax - overlayMin +1;
|
int overlaySize = overlayMax - overlayMin +1;
|
||||||
strip.unlockAll();
|
|
||||||
if (countdownMode)
|
if (countdownMode)
|
||||||
{
|
{
|
||||||
_overlayAnalogCountdown(); return;
|
_overlayAnalogCountdown(); return;
|
||||||
@ -73,23 +67,19 @@ void _overlayAnalogClock()
|
|||||||
{
|
{
|
||||||
pix = analogClock12pixel + round((overlaySize / 12.0) *i);
|
pix = analogClock12pixel + round((overlaySize / 12.0) *i);
|
||||||
if (pix > overlayMax) pix -= overlaySize;
|
if (pix > overlayMax) pix -= overlaySize;
|
||||||
strip.setIndividual(pix, 0x00FFAA);
|
strip.setPixelColor(pix, 0x00FFAA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!analogClockSecondsTrail) strip.setIndividual(secondPixel, 0xFF0000);
|
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000);
|
||||||
strip.setIndividual(minutePixel, 0x00FF00);
|
strip.setPixelColor(minutePixel, 0x00FF00);
|
||||||
strip.setIndividual(hourPixel, 0x0000FF);
|
strip.setPixelColor(hourPixel, 0x0000FF);
|
||||||
overlayRefreshMs = 998;
|
overlayRefreshMs = 998;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _overlayAnalogCountdown()
|
void _overlayAnalogCountdown()
|
||||||
{
|
{
|
||||||
strip.unlockAll();
|
if (now() < countdownTime)
|
||||||
if (now() >= countdownTime)
|
|
||||||
{
|
|
||||||
checkCountdown();
|
|
||||||
} else
|
|
||||||
{
|
{
|
||||||
long diff = countdownTime - now();
|
long diff = countdownTime - now();
|
||||||
double pval = 60;
|
double pval = 60;
|
||||||
@ -127,3 +117,9 @@ void _overlayAnalogCountdown()
|
|||||||
}
|
}
|
||||||
overlayRefreshMs = 998;
|
overlayRefreshMs = 998;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handleOverlayDraw() {
|
||||||
|
if (overlayCurrent != 1) return; //only analog clock
|
||||||
|
_overlayAnalogClock();
|
||||||
|
}
|
||||||
|
@ -145,9 +145,7 @@ void setCronixie()
|
|||||||
|
|
||||||
void _overlayCronixie()
|
void _overlayCronixie()
|
||||||
{
|
{
|
||||||
if (countdownMode) checkCountdown();
|
|
||||||
#ifndef WLED_DISABLE_CRONIXIE
|
#ifndef WLED_DISABLE_CRONIXIE
|
||||||
|
|
||||||
byte h = hour(local);
|
byte h = hour(local);
|
||||||
byte h0 = h;
|
byte h0 = h;
|
||||||
byte m = minute(local);
|
byte m = minute(local);
|
||||||
|
@ -243,7 +243,7 @@ void serializeInfo(JsonObject root)
|
|||||||
leds_pin.add(LEDPIN);
|
leds_pin.add(LEDPIN);
|
||||||
|
|
||||||
leds["pwr"] = strip.currentMilliamps;
|
leds["pwr"] = strip.currentMilliamps;
|
||||||
leds["maxpwr"] = strip.ablMilliampsMax;
|
leds["maxpwr"] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||||
leds["maxseg"] = strip.getMaxSegments();
|
leds["maxseg"] = strip.getMaxSegments();
|
||||||
leds["seglock"] = false; //will be used in the future to prevent modifications to segment config
|
leds["seglock"] = false; //will be used in the future to prevent modifications to segment config
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user