diff --git a/wled00/FX.cpp b/wled00/FX.cpp index bbca1c973..718c1f3c6 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -388,41 +388,12 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) { } -/* - * theater chase function - */ -uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2, bool do_palette) { - byte gap = 2 + ((255 - SEGMENT.intensity) >> 5); - uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2; - uint32_t it = now / cycleTime; - if (it != SEGENV.step) //new color - { - SEGENV.aux0 = (SEGENV.aux0 +1) % gap; - SEGENV.step = it; - } - - for(uint16_t i = 0; i < SEGLEN; i++) { - if((i % gap) == SEGENV.aux0) { - if (do_palette) - { - setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); - } else { - setPixelColor(i, color1); - } - } else { - setPixelColor(i, color2); - } - } - return FRAMETIME; -} - - /* * Theatre-style crawling lights. * Inspired by the Adafruit examples. */ uint16_t WS2812FX::mode_theater_chase(void) { - return theater_chase(SEGCOLOR(0), SEGCOLOR(1), true); + return running(SEGCOLOR(0), SEGCOLOR(1), true); } @@ -431,7 +402,7 @@ uint16_t WS2812FX::mode_theater_chase(void) { * Inspired by the Adafruit examples. */ uint16_t WS2812FX::mode_theater_chase_rainbow(void) { - return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false); + return running(color_wheel(SEGENV.step), SEGCOLOR(1), true); } @@ -976,29 +947,27 @@ uint16_t WS2812FX::mode_chase_flash_random(void) { /* * Alternating pixels running function. */ -uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) { - uint8_t pxw = 1 + (SEGMENT.intensity >> 5); - uint32_t cycleTime = 35 + (255 - SEGMENT.speed); +uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) { + uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window + uint32_t cycleTime = 50 + (255 - SEGMENT.speed); uint32_t it = now / cycleTime; - if (SEGMENT.speed == 0) it = 0; - + bool usePalette = color1 == SEGCOLOR(0); + for(uint16_t i = 0; i < SEGLEN; i++) { - if((i + SEGENV.aux0) % (pxw*2) < pxw) { - if (color1 == SEGCOLOR(0)) - { - setPixelColor(SEGLEN -i -1, color_from_palette(SEGLEN -i -1, true, PALETTE_SOLID_WRAP, 0)); - } else - { - setPixelColor(SEGLEN -i -1, color1); - } + uint32_t col = color2; + if (usePalette) color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0); + if (theatre) { + if ((i % width) == SEGENV.aux0) col = color1; } else { - setPixelColor(SEGLEN -i -1, color2); + int8_t pos = (i % (width<<1)); + if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1; } + setPixelColor(i,col); } if (it != SEGENV.step ) { - SEGENV.aux0 = (SEGENV.aux0 +1) % (pxw*2); + SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1)); SEGENV.step = it; } return FRAMETIME; @@ -1247,44 +1216,19 @@ uint16_t WS2812FX::mode_loading(void) { //American Police Light with all LEDs Red and Blue -uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all) +uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, uint16_t width) { - uint16_t counter = now * ((SEGMENT.speed >> 2) +1); - uint16_t idexR = (counter * SEGLEN) >> 16; - if (idexR >= SEGLEN) idexR = 0; - - uint16_t topindex = SEGLEN >> 1; - uint16_t idexB = (idexR > topindex) ? idexR - topindex : idexR + topindex; - if (SEGENV.call == 0) SEGENV.aux0 = idexR; - if (idexB >= SEGLEN) idexB = 0; //otherwise overflow on odd number of LEDs - - if (all) { //different algo, ensuring immediate fill - if (idexB > idexR) { - fill(color2); - for (uint16_t i = idexR; i < idexB; i++) setPixelColor(i, color1); - } else { - fill(color1); - for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2); - } - } else { //regular dot-only mode - uint8_t size = 1 + (SEGMENT.intensity >> 3); - if (size > SEGLEN/2) size = 1+ SEGLEN/2; - for (uint8_t i=0; i <= size; i++) { - setPixelColor(idexR+i, color1); - setPixelColor(idexB+i, color2); - } - if (SEGENV.aux0 != idexR) { - uint8_t gap = (SEGENV.aux0 < idexR)? idexR - SEGENV.aux0:SEGLEN - SEGENV.aux0 + idexR; - for (uint8_t i = 0; i <= gap ; i++) { - if ((idexR - i) < 0) idexR = SEGLEN-1 + i; - if ((idexB - i) < 0) idexB = SEGLEN-1 + i; - setPixelColor(idexR-i, color1); - setPixelColor(idexB-i, color2); - } - SEGENV.aux0 = idexR; - } - } + uint16_t delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster + uint32_t it = now / map(SEGMENT.speed, 0, 255, delay<<4, delay); + uint16_t offset = it % SEGLEN; + if (!width) width = 1; + for (uint16_t i = 0; i < width; i++) { + uint16_t indexR = (offset + i) % SEGLEN; + uint16_t indexB = (offset + i + (SEGLEN>>1)) % SEGLEN; + setPixelColor(indexR, color1); + setPixelColor(indexB, color2); + } return FRAMETIME; } @@ -1292,7 +1236,7 @@ uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all) //American Police Light with all LEDs Red and Blue uint16_t WS2812FX::mode_police_all() { - return police_base(RED, BLUE, true); + return police_base(RED, BLUE, (SEGLEN>>1)); } @@ -1300,15 +1244,15 @@ uint16_t WS2812FX::mode_police_all() uint16_t WS2812FX::mode_police() { fill(SEGCOLOR(1)); - - return police_base(RED, BLUE, false); + return police_base(RED, BLUE, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip } //Police All with custom colors uint16_t WS2812FX::mode_two_areas() { - return police_base(SEGCOLOR(0), SEGCOLOR(1), true); + fill(SEGCOLOR(2)); + return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip } @@ -1318,7 +1262,7 @@ uint16_t WS2812FX::mode_two_dots() fill(SEGCOLOR(2)); uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1); - return police_base(SEGCOLOR(0), color2, false); + return police_base(SEGCOLOR(0), color2, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip } @@ -1326,21 +1270,20 @@ uint16_t WS2812FX::mode_two_dots() * Tricolor chase function */ uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) { - uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2; - uint32_t it = now / cycleTime; - uint8_t width = (1 + SEGMENT.intensity/32) * 3; //value of 1-8 for each colour - uint8_t index = it % width; + uint32_t cycleTime = 50 + ((255 - SEGMENT.speed)<<1); + uint32_t it = now / cycleTime; // iterator + uint8_t width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour + uint8_t index = it % (width*3); - for(uint16_t i = 0; i < SEGLEN; i++, index++) { - if(index > width-1) index = 0; + for (uint16_t i = 0; i < SEGLEN; i++, index++) { + if (index > (width*3)-1) index = 0; uint32_t color = color1; - if(index > width*2/3-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1); - else if(index > width/3-1) color = color2; + if (index > (width<<1)-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1); + else if (index > width-1) color = color2; setPixelColor(SEGLEN - i -1, color); } - return FRAMETIME; } @@ -1548,7 +1491,7 @@ uint16_t WS2812FX::mode_random_chase(void) return FRAMETIME; } - +//7 bytes typedef struct Oscillator { int16_t pos; int8_t size; @@ -1780,7 +1723,7 @@ uint16_t WS2812FX::mode_fire_2012() // Step 1. Cool down every cell a little for (uint16_t i = 0; i < SEGLEN; i++) { uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2)); - heat[i] = (temp==0 && i> 3; uint8_t bitNum = i & 0x07; @@ -2170,10 +2110,14 @@ typedef struct Ripple { uint16_t pos; } ripple; +#ifdef ESP8266 + #define MAX_RIPPLES 56 +#else + #define MAX_RIPPLES 100 +#endif uint16_t WS2812FX::ripple_base(bool rainbow) { - uint16_t maxRipples = 1 + (SEGLEN >> 2); - if (maxRipples > 100) maxRipples = 100; + uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 18 segment ESP8266 uint16_t dataSize = sizeof(ripple) * maxRipples; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2241,6 +2185,7 @@ uint16_t WS2812FX::ripple_base(bool rainbow) } return FRAMETIME; } +#undef MAX_RIPPLES uint16_t WS2812FX::mode_ripple(void) { return ripple_base(false); @@ -2541,7 +2486,6 @@ uint16_t WS2812FX::mode_spots_fade() //each needs 12 bytes -//Spark type is used for popcorn and 1D fireworks typedef struct Ball { unsigned long lastBounceTime; float impactVelocity; @@ -2651,7 +2595,7 @@ uint16_t WS2812FX::mode_sinelon_dual(void) { } uint16_t WS2812FX::mode_sinelon_rainbow(void) { - return sinelon_base(true, true); + return sinelon_base(false, true); } @@ -2670,7 +2614,7 @@ uint16_t WS2812FX::mode_glitter() -//each needs 12 bytes +//each needs 11 bytes //Spark type is used for popcorn, 1D fireworks, and drip typedef struct Spark { float pos; @@ -2685,7 +2629,7 @@ typedef struct Spark { */ uint16_t WS2812FX::mode_popcorn(void) { //allocate segment data - uint16_t maxNumPopcorn = 24; + uint16_t maxNumPopcorn = 22; // max 22 on 18 segment ESP8266 uint16_t dataSize = sizeof(spark) * maxNumPopcorn; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2744,7 +2688,7 @@ uint16_t WS2812FX::candle(bool multi) if (multi) { //allocate segment data - uint16_t dataSize = (SEGLEN -1) *3; + uint16_t dataSize = (SEGLEN -1) *3; // max length of segment on 18 segment ESP8266 is 75 pixels if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed } @@ -2831,9 +2775,14 @@ uint16_t WS2812FX::mode_candle_multi() / 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 +#ifdef ESP8266 + #define STARBURST_MAX_FRAG 4 + #define STARBURST_MAX_STARS 6 +#else + #define STARBURST_MAX_FRAG 10 + #define STARBURST_MAX_STARS 11 +#endif +//each needs 18+STARBURST_MAX_FRAG*4 bytes typedef struct particle { CRGB color; uint32_t birth =0; @@ -2845,7 +2794,7 @@ typedef struct particle { uint16_t WS2812FX::mode_starburst(void) { uint8_t numStars = 1 + (SEGLEN >> 3); - if (numStars > 15) numStars = 15; + if (numStars > STARBURST_MAX_STARS) numStars = STARBURST_MAX_STARS; // 11 * 58 * 32 = 19k (ESP32), 6 * 34 * 18 = 4k (ESP8266) uint16_t dataSize = sizeof(star) * numStars; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2946,18 +2895,22 @@ uint16_t WS2812FX::mode_starburst(void) { } return FRAMETIME; } - +#undef STARBURST_MAX_FRAG +#undef STARBURST_MAX_STARS /* * Exploding fireworks effect * adapted from: http://www.anirama.com/1000leds/1d-fireworks/ */ - +#ifdef ESP8266 + #define MAX_SPARKS 20 // number of fragments +#else + #define MAX_SPARKS 58 // number of fragments +#endif uint16_t WS2812FX::mode_exploding_fireworks(void) { //allocate segment data - uint16_t numSparks = 2 + (SEGLEN >> 1); - if (numSparks > 80) numSparks = 80; + uint16_t numSparks = min(2 + (SEGLEN >> 1), MAX_SPARKS); // max 58 for 32 segment ESP32, 20 for 18 segment ESP8266 uint16_t dataSize = sizeof(spark) * numSparks; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -3052,7 +3005,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) SEGENV.aux0--; if (SEGENV.aux0 < 4) { SEGENV.aux0 = 0; //back to flare - SEGENV.step = (SEGMENT.intensity > random8()); //decide firing side + SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side } } @@ -3060,6 +3013,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) return FRAMETIME; } +#undef MAX_SPARKS /* @@ -3069,7 +3023,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) uint16_t WS2812FX::mode_drip(void) { //allocate segment data - uint16_t numDrops = 4; + uint8_t numDrops = 4; uint16_t dataSize = sizeof(spark) * numDrops; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -3077,7 +3031,7 @@ uint16_t WS2812FX::mode_drip(void) Spark* drops = reinterpret_cast(SEGENV.data); - numDrops = 1 + (SEGMENT.intensity >> 6); + numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3 float gravity = -0.0005 - (SEGMENT.speed/50000.0); gravity *= SEGLEN; @@ -3107,13 +3061,13 @@ uint16_t WS2812FX::mode_drip(void) if (drops[j].pos > 0) { // fall until end of segment drops[j].pos += drops[j].vel; if (drops[j].pos < 0) drops[j].pos = 0; - drops[j].vel += gravity; + drops[j].vel += gravity; // gravity is negative for (uint16_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally setPixelColor(pos,color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling } - + if (drops[j].colIndex > 2) { // during bounce, some water is on the floor setPixelColor(0,color_blend(SEGCOLOR(0),BLACK,drops[j].col)); } @@ -3142,6 +3096,7 @@ uint16_t WS2812FX::mode_drip(void) * Tetris or Stacking (falling bricks) Effect * by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home) */ +//12 bytes typedef struct Tetris { float pos; float speed; @@ -3163,8 +3118,8 @@ uint16_t WS2812FX::mode_tetrix(void) { } if (SEGENV.step == 0) { //init - drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>3)+1 : random8(6,40)); // set speed - drop->pos = SEGLEN-1; // start at end of segment + drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>2)+1 : random8(6,64)); // set speed + drop->pos = SEGLEN; // start at end of segment (no need to subtract 1) drop->col = color_from_palette(random8(0,15)<<4,false,false,0); // limit color choices so there is enough HUE gap SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling) SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick @@ -3196,13 +3151,17 @@ uint16_t WS2812FX::mode_tetrix(void) { / adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino */ uint16_t WS2812FX::mode_plasma(void) { - uint8_t thisPhase = beatsin8(6,-64,64); // Setting phase change for a couple of waves. - uint8_t thatPhase = beatsin8(7,-64,64); + // initialize phases on start + if (SEGENV.call == 0) { + SEGENV.aux0 = random8(0,2); // add a bit of randomness + } + uint8_t thisPhase = beatsin8(6+SEGENV.aux0,-64,64); + uint8_t thatPhase = beatsin8(7+SEGENV.aux0,-64,64); for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: - uint8_t colorIndex = cubicwave8(((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase)) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. - + cos8(((i*(1+ 2*(SEGMENT.speed >> 5)))+(thatPhase)) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. - uint8_t thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 )); + uint8_t colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. + + cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. + uint8_t thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1)))); CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND); setPixelColor(i, color.red, color.green, color.blue); } @@ -3531,7 +3490,7 @@ uint16_t WS2812FX::mode_noisepal(void) { // S uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30 //#define scale 30 - uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes + uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes) if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed CRGBPalette16* palettes = reinterpret_cast(SEGENV.data); @@ -3644,7 +3603,7 @@ uint16_t WS2812FX::mode_chunchun(void) return FRAMETIME; } - +//13 bytes typedef struct Spotlight { float speed; uint8_t colorIdx; @@ -3661,6 +3620,11 @@ typedef struct Spotlight { #define SPOT_TYPE_3X_DOT 4 #define SPOT_TYPE_4X_DOT 5 #define SPOT_TYPES_COUNT 6 +#ifdef ESP8266 + #define SPOT_MAX_COUNT 17 //Number of simultaneous waves +#else + #define SPOT_MAX_COUNT 49 //Number of simultaneous waves +#endif /* * Spotlights moving back and forth that cast dancing shadows. @@ -3671,7 +3635,7 @@ typedef struct Spotlight { */ uint16_t WS2812FX::mode_dancing_shadows(void) { - uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, 50); + uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 18 segment ESP8266 bool initialize = SEGENV.aux0 != numSpotlights; SEGENV.aux0 = numSpotlights; @@ -3810,7 +3774,7 @@ uint16_t WS2812FX::mode_washing_machine(void) { Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e */ uint16_t WS2812FX::mode_blends(void) { - uint16_t dataSize = sizeof(uint32_t) * SEGLEN; + uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 18 segment ESP8266 if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed uint32_t* pixels = reinterpret_cast(SEGENV.data); uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128); @@ -3825,6 +3789,11 @@ uint16_t WS2812FX::mode_blends(void) { return FRAMETIME; } +/* + TV Simulator + Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch +*/ +//43 bytes typedef struct TvSim { uint32_t totalTime = 0; uint32_t fadeTime = 0; @@ -3845,11 +3814,6 @@ typedef struct TvSim { uint16_t pb = 0; } tvSim; - -/* - TV Simulator - Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch -*/ uint16_t WS2812FX::mode_tv_simulator(void) { uint16_t nr, ng, nb, r, g, b, i, hue; uint8_t sat, bri, j; @@ -3957,10 +3921,15 @@ uint16_t WS2812FX::mode_tv_simulator(void) { */ //CONFIG -#define W_MAX_COUNT 20 //Number of simultaneous waves +#ifdef ESP8266 + #define W_MAX_COUNT 9 //Number of simultaneous waves +#else + #define W_MAX_COUNT 20 //Number of simultaneous waves +#endif #define W_MAX_SPEED 6 //Higher number, higher speed #define W_WIDTH_FACTOR 6 //Higher number, smaller waves +//24 bytes class AuroraWave { private: uint16_t ttl; @@ -4055,10 +4024,10 @@ uint16_t WS2812FX::mode_aurora(void) { if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) { //Intensity slider changed or first call - SEGENV.aux1 = ((float)SEGMENT.intensity / 255) * W_MAX_COUNT; + SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT); SEGENV.aux0 = SEGMENT.intensity; - if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { + if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 18 segment ESP8266 return mode_static(); //allocation failed } diff --git a/wled00/FX.h b/wled00/FX.h index ba4ee858e..836321504 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -24,8 +24,6 @@ Modified for WLED */ -#include "wled.h" - #ifndef WS2812FX_h #define WS2812FX_h @@ -55,17 +53,17 @@ /* each segment uses 52 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ #ifdef ESP8266 - #define MAX_NUM_SEGMENTS 12 + #define MAX_NUM_SEGMENTS 16 /* How many color transitions can run at once */ #define MAX_NUM_TRANSITIONS 8 /* How much data bytes all segments combined may allocate */ - #define MAX_SEGMENT_DATA 2048 + #define MAX_SEGMENT_DATA 4096 #else -#ifndef MAX_NUM_SEGMENTS - #define MAX_NUM_SEGMENTS 16 -#endif - #define MAX_NUM_TRANSITIONS 16 - #define MAX_SEGMENT_DATA 8192 + #ifndef MAX_NUM_SEGMENTS + #define MAX_NUM_SEGMENTS 32 + #endif + #define MAX_NUM_TRANSITIONS 24 + #define MAX_SEGMENT_DATA 20480 #endif #define LED_SKIP_AMOUNT 1 @@ -245,7 +243,7 @@ class WS2812FX { // segment parameters public: - typedef struct Segment { // 25 (28 in memory?) bytes + typedef struct Segment { // 29 (32 in memory?) bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 uint16_t offset; @@ -257,6 +255,7 @@ class WS2812FX { uint8_t grouping, spacing; uint8_t opacity; uint32_t colors[NUM_COLORS]; + char *name; bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false; if (c == colors[slot]) return false; @@ -296,19 +295,19 @@ class WS2812FX { { return ((options >> n) & 0x01); } - bool isSelected() + inline bool isSelected() { return getOption(0); } - bool isActive() + inline bool isActive() { return stop > start; } - uint16_t length() + inline uint16_t length() { return stop - start; } - uint16_t groupLength() + inline uint16_t groupLength() { return grouping + spacing; } @@ -345,17 +344,23 @@ class WS2812FX { // segment runtime parameters typedef struct Segment_runtime { // 28 bytes - unsigned long next_time; - uint32_t step; - uint32_t call; - uint16_t aux0; - uint16_t aux1; + unsigned long next_time; // millis() of next update + uint32_t step; // custom "step" var + uint32_t call; // call counter + uint16_t aux0; // custom var + uint16_t aux1; // custom var byte* data = nullptr; bool allocateData(uint16_t len){ if (data && _dataLen == len) return true; //already allocated deallocateData(); if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory - data = new (std::nothrow) byte[len]; + // if possible use SPI RAM on ESP32 + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) + if (psramFound()) + data = (byte*) ps_malloc(len); + else + #endif + data = (byte*) malloc(len); if (!data) return false; //allocation failed WS2812FX::instance->_usedSegmentData += len; _dataLen = len; @@ -363,7 +368,7 @@ class WS2812FX { return true; } void deallocateData(){ - delete[] data; + free(data); data = nullptr; WS2812FX::instance->_usedSegmentData -= _dataLen; _dataLen = 0; @@ -389,7 +394,7 @@ class WS2812FX { * the internal segment state should be reset. * Call resetIfRequired before calling the next effect function. */ - void reset() { _requiresReset = true; } + inline void reset() { _requiresReset = true; } private: uint16_t _dataLen = 0; bool _requiresReset = false; @@ -622,11 +627,12 @@ class WS2812FX { trigger(void), setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0), resetSegments(), + populateDefaultSegments(), setPixelColor(uint16_t n, uint32_t c), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), show(void), - setColorOrder(uint8_t co), - setPixelSegment(uint8_t n); + setPixelSegment(uint8_t n), + deserializeMap(uint8_t n=0); bool isRgbw = false, @@ -644,8 +650,6 @@ class WS2812FX { paletteFade = 0, paletteBlend = 0, milliampsPerLed = 55, -// getStripType(uint8_t strip=0), -// setStripType(uint8_t type, uint8_t strip=0), getBrightness(void), getMode(void), getSpeed(void), @@ -654,24 +658,17 @@ class WS2812FX { getMaxSegments(void), //getFirstSelectedSegment(void), getMainSegmentId(void), - getColorOrder(void), gamma8(uint8_t), gamma8_cal(uint8_t, float), sin_gap(uint16_t), get_random_wheel_index(uint8_t); int8_t -// setStripPin(uint8_t strip, int8_t pin), -// getStripPin(uint8_t strip=0), -// setStripPinClk(uint8_t strip, int8_t pin), -// getStripPinClk(uint8_t strip=0), tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec); uint16_t ablMilliampsMax, currentMilliamps, -// setStripLen(uint8_t strip, uint16_t len), -// getStripLen(uint8_t strip=0), triwave16(uint16_t), getFps(); @@ -849,7 +846,6 @@ class WS2812FX { color_wipe(bool, bool), dynamic(bool), scan(bool), - theater_chase(uint32_t, uint32_t, bool), running_base(bool,bool), larson_scanner(bool), sinelon_base(bool,bool), @@ -857,8 +853,8 @@ class WS2812FX { chase(uint32_t, uint32_t, uint32_t, bool), gradient_base(bool), ripple_base(bool), - police_base(uint32_t, uint32_t, bool), - running(uint32_t, uint32_t), + police_base(uint32_t, uint32_t, uint16_t), + running(uint32_t, uint32_t, bool theatre=false), tricolor_chase(uint32_t, uint32_t), twinklefox_base(bool), spots_base(uint16_t), @@ -869,8 +865,7 @@ class WS2812FX { void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend), - startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot), - deserializeMap(void); + startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot); uint16_t* customMappingTable = nullptr; uint16_t customMappingSize = 0; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 43cb48466..68595c452 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -23,7 +23,7 @@ Modified heavily for WLED */ - +#include "wled.h" #include "FX.h" #include "palettes.h" @@ -40,7 +40,7 @@ another example. Switches direction every 5 LEDs. {"map":[ 0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14, - 19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25] + 19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]} */ //factory defaults LED setup @@ -218,14 +218,13 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) { int16_t realIndex = iGroup; if (IS_REVERSE) { if (IS_MIRROR) { - realIndex = (SEGMENT.length() -1) / 2 - iGroup; //only need to index half the pixels + realIndex = (SEGMENT.length() - 1) / 2 - iGroup; //only need to index half the pixels } else { - realIndex = SEGMENT.length() - iGroup - 1; + realIndex = (SEGMENT.length() - 1) - iGroup; } } realIndex += SEGMENT.start; - return realIndex; } @@ -246,7 +245,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } if (SEGLEN) {//from segment - //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments) if (_bri_t < 255) { r = scale8(r, _bri_t); @@ -256,12 +254,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b)); - bool reversed = IS_REVERSE; + /* Set all the pixels in the group */ uint16_t realIndex = realPixelIndex(i); uint16_t len = SEGMENT.length(); for (uint16_t j = 0; j < SEGMENT.grouping; j++) { - int indexSet = realIndex + (reversed ? -j : j); + uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j); if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { if (IS_MIRROR) { //set the corresponding mirrored pixel uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1; @@ -273,8 +271,8 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) busses.setPixelColor(indexMir, col); } /* offset/phase */ - indexSet += SEGMENT.offset; - if (indexSet >= SEGMENT.stop) indexSet -= len; + indexSet += SEGMENT.offset; + if (indexSet >= SEGMENT.stop) indexSet -= len; if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; busses.setPixelColor(indexSet, col); @@ -282,7 +280,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } } else { //live data, etc. if (i < customMappingSize) i = customMappingTable[i]; - uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b)); busses.setPixelColor(i, col); } @@ -563,6 +560,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i) } if (i < customMappingSize) i = customMappingTable[i]; + if (i >= _length) return 0; return busses.getPixelColor(i); } @@ -584,15 +582,6 @@ uint32_t WS2812FX::getLastShow(void) { return _lastShow; } -//TODO these need to be on a per-strip basis -uint8_t WS2812FX::getColorOrder(void) { - return COL_ORDER_GRB; -} - -void WS2812FX::setColorOrder(uint8_t co) { - //bus->SetColorOrder(co); -} - void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { if (n >= MAX_NUM_SEGMENTS) return; Segment& seg = _segments[n]; @@ -603,7 +592,11 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off if (i2 <= i1) //disable segment { - seg.stop = 0; + seg.stop = 0; + if (seg.name) { + delete[] seg.name; + seg.name = nullptr; + } if (n == mainSegment) //if main segment is deleted, set first active as main segment { for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) @@ -628,6 +621,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, } void WS2812FX::resetSegments() { + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete _segments[i].name; mainSegment = 0; memset(_segments, 0, sizeof(_segments)); //memset(_segment_runtimes, 0, sizeof(_segment_runtimes)); @@ -656,6 +650,25 @@ void WS2812FX::resetSegments() { _segment_runtimes[0].reset(); } +void WS2812FX::populateDefaultSegments() { + uint16_t length = 0; + for (uint8_t i=0; igetStart(); + length += bus->getLength(); + _segments[i].stop = _segments[i].start + bus->getLength(); + _segments[i].mode = DEFAULT_MODE; + _segments[i].colors[0] = DEFAULT_COLOR; + _segments[i].speed = DEFAULT_SPEED; + _segments[i].intensity = DEFAULT_INTENSITY; + _segments[i].grouping = 1; + _segments[i].setOption(SEG_OPTION_SELECTED, 1); + _segments[i].setOption(SEG_OPTION_ON, 1); + _segments[i].opacity = 255; + } +} + //After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) void WS2812FX::setPixelSegment(uint8_t n) { @@ -1033,18 +1046,34 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8 //load custom mapping table from JSON file -void WS2812FX::deserializeMap(void) { - if (!WLED_FS.exists("/ledmap.json")) return; +void WS2812FX::deserializeMap(uint8_t n) { + char fileName[32]; + strcpy_P(fileName, PSTR("/ledmap")); + if (n) sprintf(fileName +7, "%d", n); + strcat(fileName, ".json"); + bool isFile = WLED_FS.exists(fileName); + + if (!isFile) { + // erase custom mapping if selecting nonexistent ledmap.json (n==0) + if (!n && customMappingTable != nullptr) { + customMappingSize = 0; + delete[] customMappingTable; + customMappingTable = nullptr; + } + return; + } + DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps + DEBUG_PRINT(F("Reading LED map from ")); + DEBUG_PRINTLN(fileName); - DEBUG_PRINTLN(F("Reading LED map from /ledmap.json...")); - - if (!readObjectFromFile("/ledmap.json", nullptr, &doc)) return; //if file does not exist just exit + if (!readObjectFromFile(fileName, nullptr, &doc)) return; //if file does not exist just exit + // erase old custom ledmap if (customMappingTable != nullptr) { + customMappingSize = 0; delete[] customMappingTable; customMappingTable = nullptr; - customMappingSize = 0; } JsonArray map = doc[F("map")]; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 7f938688f..8adaac2fe 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -106,7 +106,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { uint16_t length = elm[F("len")] | 1; uint8_t colorOrder = (int)elm[F("order")]; uint8_t skipFirst = elm[F("skip")]; - uint16_t start = elm[F("start")] | 0; + uint16_t start = elm["start"] | 0; uint8_t ledType = elm["type"] | TYPE_WS2812_RGB; bool reversed = elm["rev"]; @@ -398,7 +398,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject dmx = doc["dmx"]; CJSON(DMXChannels, dmx[F("chan")]); CJSON(DMXGap,dmx[F("gap")]); - CJSON(DMXStart, dmx[F("start")]); + CJSON(DMXStart, dmx["start"]); CJSON(DMXStartLED,dmx[F("start-led")]); JsonArray dmx_fixmap = dmx[F("fixmap")]; @@ -516,7 +516,7 @@ void serializeConfig() { Bus *bus = busses.getBus(s); if (!bus || bus->getLength()==0) break; JsonObject ins = hw_led_ins.createNestedObject(); - ins[F("start")] = bus->getStart(); + ins["start"] = bus->getStart(); ins[F("len")] = bus->getLength(); JsonArray ins_pin = ins.createNestedArray("pin"); uint8_t pins[5]; @@ -719,7 +719,7 @@ void serializeConfig() { JsonObject dmx = doc.createNestedObject("dmx"); dmx[F("chan")] = DMXChannels; dmx[F("gap")] = DMXGap; - dmx[F("start")] = DMXStart; + dmx["start"] = DMXStart; dmx[F("start-led")] = DMXStartLED; JsonArray dmx_fixmap = dmx.createNestedArray(F("fixmap")); diff --git a/wled00/data/index.css b/wled00/data/index.css index 8439e0a9a..f27024ac8 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -1,6 +1,6 @@ @font-face { font-family: "WIcons"; - src: url(data:application/x-font-woff;charset=utf-8;base64,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) format('woff'); + src: url(data:font/woff2;charset=utf-8;base64,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) format('woff'); } :root { @@ -166,6 +166,20 @@ button { color: var(--c-d); } +.edit-icon { + position: absolute; + right: -26px; + top: 10px; + display: none; +} + +.search-icon { + position: absolute; + left: 8px; + top: 10px; + pointer-events: none; +} + .search-cancel-icon { position: absolute; right: 8px; @@ -695,6 +709,11 @@ input[type=text] { } .stxt { + display: none; + margin-top: 6px !important; +} + +.qltxt { width: 50px !important; } @@ -738,6 +757,12 @@ input[type=number]::-webkit-outer-spin-button { cursor: pointer; } +.segntxt { + max-width: 160px; + overflow: hidden; + text-overflow: clip; +} + .pname { width: 208px; padding: 8px 0; @@ -787,7 +812,7 @@ input[type=number]::-webkit-outer-spin-button { .cnf-s { position: absolute; - top: 173px; + bottom: 100px; right: 23px; padding: 7px 22px; } @@ -804,7 +829,7 @@ input[type=number]::-webkit-outer-spin-button { .half { padding: 7.5px; - top: 64px; + bottom: 35px; } .del { @@ -1022,9 +1047,6 @@ input[type="text"].search { padding: 8px 8px 9px 38px; margin: 6px auto 0 auto; text-align: left; - background: url("data:image/svg+xml;utf8,") - no-repeat 10px 10px; - background-size: 20px; background-color: var(--c-3); } diff --git a/wled00/data/index.js b/wled00/data/index.js index 2c788f2da..c2467b6fe 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -578,11 +578,13 @@ function populateSegments(s) -
- Segment ${i} +
+
${inst.n ? inst.n : "Segment "+i}
+
+
@@ -649,7 +651,7 @@ function populateSegments(s) function populateEffects(effects) { var html = ``; +
`; effects.shift(); //remove solid for (let i = 0; i < effects.length; i++) { @@ -695,7 +697,7 @@ function populatePalettes(palettes) }); var html = ``; +
`; for (let i = 0; i < palettes.length; i++) { html += generateListItemHtml( 'palette', @@ -1258,9 +1260,11 @@ function makeSeg() { var cn = `
New segment ${lowestUnused} +

+ @@ -1405,7 +1409,7 @@ function makeP(i,pl) { return `
-
Quick load label:
+
Quick load label:
(leave empty for no Quick load button)
Start LED