Multiple updates:
- additional debug timings - removed local leds[] buffer - async segment bounds change (crashes seen otherwise) - added isActive() check to Segment drawing methods - ABL simplification - palette option for Black hole (FX) - (possible) crash mitigation is Segment handling (rapid preset changes)
This commit is contained in:
		| @@ -606,7 +606,6 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0"; | ||||
| uint16_t dissolve(uint32_t color) { | ||||
|   //bool wa = (SEGCOLOR(1) != 0 && strip.getBrightness() < 255); //workaround, can't compare getPixel to color if not full brightness | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds();  //lossless getPixelColor() | ||||
|     SEGMENT.fill(SEGCOLOR(1)); | ||||
|   } | ||||
|  | ||||
| @@ -1205,7 +1204,6 @@ uint16_t mode_fireworks() { | ||||
|   const uint16_t height = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds();  //lossless getPixelColor() | ||||
|     SEGMENT.fill(SEGCOLOR(1)); | ||||
|     SEGENV.aux0 = UINT16_MAX; | ||||
|     SEGENV.aux1 = UINT16_MAX; | ||||
| @@ -1904,7 +1902,6 @@ static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; | ||||
| uint16_t mode_juggle(void) { | ||||
|   if (SEGLEN == 1) return mode_static(); | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds();  //lossless getPixelColor() | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4585,7 +4582,6 @@ uint16_t mode_2DBlackHole(void) {            // By: Stepko https://editor.soulma | ||||
|  | ||||
|   // initialize on first call | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4595,22 +4591,22 @@ uint16_t mode_2DBlackHole(void) {            // By: Stepko https://editor.soulma | ||||
|   for (size_t i = 0; i < 8; i++) { | ||||
|     x = beatsin8(SEGMENT.custom1>>3,   0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); | ||||
|     y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); | ||||
|     SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255)); | ||||
|     SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(i*32, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); | ||||
|   } | ||||
|   // inner stars | ||||
|   for (size_t i = 0; i < 4; i++) { | ||||
|     x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); | ||||
|     y = beatsin8(SEGMENT.custom3   , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); | ||||
|     SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255)); | ||||
|     SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(255-i*64, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); | ||||
|   } | ||||
|   // central white dot | ||||
|   SEGMENT.setPixelColorXY(cols/2, rows/2, CHSV(0, 0, 255)); | ||||
|   SEGMENT.setPixelColorXY(cols/2, rows/2, WHITE); | ||||
|   // blur everything a bit | ||||
|   SEGMENT.blur(16); | ||||
|  | ||||
|   return FRAMETIME; | ||||
| } // mode_2DBlackHole() | ||||
| static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.;;;2"; | ||||
| static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid;!;!;2;pal=11"; | ||||
|  | ||||
|  | ||||
| //////////////////////////// | ||||
| @@ -4623,7 +4619,6 @@ uint16_t mode_2DColoredBursts() {              // By: ldirko   https://editor.so | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|     SEGENV.aux0 = 0; // start with red hue | ||||
|   } | ||||
| @@ -4677,7 +4672,6 @@ uint16_t mode_2Ddna(void) {         // dna originally by by ldirko at https://pa | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4704,7 +4698,6 @@ uint16_t mode_2DDNASpiral() {               // By: ldirko  https://editor.soulma | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4750,7 +4743,6 @@ uint16_t mode_2DDrift() {              // By: Stepko   https://editor.soulmateli | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4781,7 +4773,6 @@ uint16_t mode_2Dfirenoise(void) {               // firenoise2d. By Andrew Tuline | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4816,7 +4807,6 @@ uint16_t mode_2DFrizzles(void) {                 // By: Stepko https://editor.so | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -4855,8 +4845,6 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: | ||||
|  | ||||
|   CRGB backgroundColor = SEGCOLOR(1); | ||||
|  | ||||
|   if (SEGENV.call == 0) SEGMENT.setUpLeds(); | ||||
|  | ||||
|   if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) { | ||||
|     SEGENV.step = strip.now; | ||||
|     SEGENV.aux0 = 0; | ||||
| @@ -5122,7 +5110,6 @@ uint16_t mode_2Dmatrix(void) {                  // Matrix2D. By Jeremy Williams. | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5267,7 +5254,6 @@ uint16_t mode_2DPlasmaball(void) {                   // By: Stepko https://edito | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5315,7 +5301,6 @@ uint16_t mode_2DPolarLights(void) {        // By: Kostyantyn Matviyevskyy  https | ||||
|   CRGBPalette16 auroraPalette  = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000}; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|     SEGENV.step = 0; | ||||
|   } | ||||
| @@ -5365,7 +5350,6 @@ uint16_t mode_2DPulser(void) {                       // By: ldirko   https://edi | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5393,7 +5377,6 @@ uint16_t mode_2DSindots(void) {                             // By: ldirko   http | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5425,7 +5408,6 @@ uint16_t mode_2Dsquaredswirl(void) {            // By: Mark Kriegsman. https://g | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5468,7 +5450,6 @@ uint16_t mode_2DSunradiation(void) {                   // By: ldirko https://edi | ||||
|   byte *bump = reinterpret_cast<byte*>(SEGENV.data); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5516,7 +5497,6 @@ uint16_t mode_2Dtartan(void) {          // By: Elliott Kember  https://editor.so | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5556,7 +5536,6 @@ uint16_t mode_2Dspaceships(void) {    //// Space ships by stepko (c)05.02.21 [ht | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -5625,7 +5604,6 @@ uint16_t mode_2Dcrazybees(void) { | ||||
|   bee_t *bee = reinterpret_cast<bee_t*>(SEGENV.data); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|     for (size_t i = 0; i < n; i++) { | ||||
|       bee[i].posX = random8(0, cols); | ||||
| @@ -5695,7 +5673,6 @@ uint16_t mode_2Dghostrider(void) { | ||||
|  | ||||
|   const size_t maxLighters = min(cols + rows, LIGHTERS_AM); | ||||
|  | ||||
|   if (SEGENV.call == 0) SEGMENT.setUpLeds(); | ||||
|   if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { | ||||
|     SEGENV.aux0 = cols; | ||||
|     SEGENV.aux1 = rows; | ||||
| @@ -5780,7 +5757,6 @@ uint16_t mode_2Dfloatingblobs(void) { | ||||
|   if (!SEGENV.allocateData(sizeof(blob_t))) return mode_static(); //allocation failed | ||||
|   blob_t *blob = reinterpret_cast<blob_t*>(SEGENV.data); | ||||
|  | ||||
|   if (SEGENV.call == 0) SEGMENT.setUpLeds(); | ||||
|   if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { | ||||
|     SEGENV.aux0 = cols; // re-initialise if virtual size changes | ||||
|     SEGENV.aux1 = rows; | ||||
| @@ -5946,7 +5922,6 @@ uint16_t mode_2Ddriftrose(void) { | ||||
|   const float L = min(cols, rows) / 2.f; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6101,7 +6076,6 @@ uint16_t mode_2DSwirl(void) { | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6148,7 +6122,6 @@ uint16_t mode_2DWaverly(void) { | ||||
|   const uint16_t rows = SEGMENT.virtualHeight(); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6377,7 +6350,6 @@ uint16_t mode_matripix(void) {                  // Matripix. By Andrew Tuline. | ||||
|   int16_t volumeRaw    = *(int16_t*)um_data->u_data[1]; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6505,7 +6477,6 @@ uint16_t mode_pixelwave(void) {                 // Pixelwave. By Andrew Tuline. | ||||
|   // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6731,7 +6702,6 @@ uint16_t mode_DJLight(void) {                   // Written by ??? Adapted by Wil | ||||
|   uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6800,7 +6770,6 @@ uint16_t mode_freqmatrix(void) {                // Freqmatrix. By Andreas Plesch | ||||
|   float volumeSmth    = *(float*)um_data->u_data[0]; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -6902,7 +6871,6 @@ uint16_t mode_freqwave(void) {                  // Freqwave. By Andreas Pleschun | ||||
|   float volumeSmth    = *(float*)um_data->u_data[0]; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -7087,7 +7055,6 @@ uint16_t mode_waterfall(void) {                   // Waterfall. By: Andrew Tulin | ||||
|   if (FFT_MajorPeak < 1) FFT_MajorPeak = 1;                                         // log10(0) is "forbidden" (throws exception) | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|     SEGENV.aux0 = 255; | ||||
|     SEGMENT.custom1 = *binNum; | ||||
| @@ -7204,7 +7171,6 @@ uint16_t mode_2DFunkyPlank(void) {              // Written by ??? Adapted by Wil | ||||
|   uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     SEGMENT.fill(BLACK); | ||||
|   } | ||||
|  | ||||
| @@ -7417,7 +7383,6 @@ uint16_t mode_2Dsoap() { | ||||
|  | ||||
|   // init | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.setUpLeds(); | ||||
|     *noise32_x = random16(); | ||||
|     *noise32_y = random16(); | ||||
|     *noise32_z = random16(); | ||||
| @@ -7535,12 +7500,12 @@ uint16_t mode_2Doctopus() { | ||||
|     SEGENV.aux1 = rows; | ||||
|     *offsX = SEGMENT.custom1; | ||||
|     *offsY = SEGMENT.custom2; | ||||
|     const uint8_t C_X = cols / 2 + (SEGMENT.custom1 - 128)*cols/255; | ||||
|     const uint8_t C_Y = rows / 2 + (SEGMENT.custom2 - 128)*rows/255; | ||||
|     const int C_X = (cols / 2) + ((SEGMENT.custom1 - 128)*cols)/255; | ||||
|     const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; | ||||
|     for (int x = 0; x < cols; x++) { | ||||
|       for (int y = 0; y < rows; y++) { | ||||
|         rMap[XY(x, y)].angle = 40.7436f * atan2f(y - C_Y, x - C_X); // avoid 128*atan2()/PI | ||||
|         rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu | ||||
|         rMap[XY(x, y)].angle  = 40.7436f * atan2f((y - C_Y), (x - C_X));  // avoid 128*atan2()/PI | ||||
|         rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp;      //thanks Sutaburosu | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
							
								
								
									
										36
									
								
								wled00/FX.h
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								wled00/FX.h
									
									
									
									
									
								
							| @@ -329,7 +329,7 @@ typedef enum mapping1D2D { | ||||
|   M12_pCorner = 3 | ||||
| } mapping1D2D_t; | ||||
|  | ||||
| // segment, 72 bytes | ||||
| // segment, 80 bytes | ||||
| typedef struct Segment { | ||||
|   public: | ||||
|     uint16_t start; // start index / start X coordinate 2D (left) | ||||
| @@ -370,7 +370,7 @@ typedef struct Segment { | ||||
|     }; | ||||
|     uint8_t startY;  // start Y coodrinate 2D (top); there should be no more than 255 rows | ||||
|     uint8_t stopY;   // stop Y coordinate 2D (bottom); there should be no more than 255 rows | ||||
|     char *name; | ||||
|     char    *name; | ||||
|  | ||||
|     // runtime data | ||||
|     unsigned long next_time;  // millis() of next update | ||||
| @@ -378,8 +378,7 @@ typedef struct Segment { | ||||
|     uint32_t call;  // call counter | ||||
|     uint16_t aux0;  // custom var | ||||
|     uint16_t aux1;  // custom var | ||||
|     byte* data;     // effect data pointer | ||||
|     uint32_t* leds; // local leds[] array (may be a pointer to global) | ||||
|     byte     *data; // effect data pointer | ||||
|     static uint16_t maxWidth, maxHeight;  // these define matrix width & height (max. segment dimensions) | ||||
|  | ||||
|   private: | ||||
| @@ -393,10 +392,13 @@ typedef struct Segment { | ||||
|         uint8_t _reserved : 4; | ||||
|       }; | ||||
|     }; | ||||
|     uint16_t _dataLen; | ||||
|     uint16_t        _dataLen; | ||||
|     static uint16_t _usedSegmentData; | ||||
|  | ||||
|     // transition data, valid only if transitional==true, holds values during transition | ||||
|     uint16_t _qStart, _qStop, _qStartY, _qStopY; | ||||
|     bool     _queuedChanges; | ||||
|  | ||||
|     // transition data, valid only if transitional==true, holds values during transition (72 bytes) | ||||
|     struct Transition { | ||||
|       uint32_t      _colorT[NUM_COLORS]; | ||||
|       uint8_t       _briT;        // temporary brightness | ||||
| @@ -407,7 +409,7 @@ typedef struct Segment { | ||||
|       //uint16_t      _aux0, _aux1; // previous mode/effect runtime data | ||||
|       //uint32_t      _step, _call; // previous mode/effect runtime data | ||||
|       //byte         *_data;        // previous mode/effect runtime data | ||||
|       uint32_t      _start; | ||||
|       unsigned long _start;         // must accommodate millis() | ||||
|       uint16_t      _dur; | ||||
|       Transition(uint16_t dur=750) | ||||
|         : _briT(255) | ||||
| @@ -462,9 +464,9 @@ typedef struct Segment { | ||||
|       aux0(0), | ||||
|       aux1(0), | ||||
|       data(nullptr), | ||||
|       leds(nullptr), | ||||
|       _capabilities(0), | ||||
|       _dataLen(0), | ||||
|       _queuedChanges(false), | ||||
|       _t(nullptr) | ||||
|     { | ||||
|       //refreshLightCapabilities(); | ||||
| @@ -485,9 +487,8 @@ typedef struct Segment { | ||||
|       //if (data) Serial.printf(" %d (%p)", (int)_dataLen, data); | ||||
|       //Serial.println(); | ||||
|       //#endif | ||||
|       if (name) delete[] name; | ||||
|       if (_t) delete _t; | ||||
|       if (leds) free(leds); | ||||
|       if (name) { delete[] name; name = nullptr; } | ||||
|       if (_t)   { transitional = false; delete _t; _t = nullptr; } | ||||
|       deallocateData(); | ||||
|     } | ||||
|  | ||||
| @@ -495,7 +496,7 @@ typedef struct Segment { | ||||
|     Segment& operator= (Segment &&orig) noexcept; // move assignment | ||||
|  | ||||
| #ifdef WLED_DEBUG | ||||
|     size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0) + (leds?sizeof(CRGB)*length():0); } | ||||
|     size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0); } | ||||
| #endif | ||||
|  | ||||
|     inline bool     getOption(uint8_t n) const { return ((options >> n) & 0x01); } | ||||
| @@ -505,16 +506,16 @@ typedef struct Segment { | ||||
|     inline bool     hasRGB(void)         const { return _isRGB; } | ||||
|     inline bool     hasWhite(void)       const { return _hasW; } | ||||
|     inline bool     isCCT(void)          const { return _isCCT; } | ||||
|     inline uint16_t width(void)          const { return (stop > start)   ? (stop - start)   : 0; } // segment width in physical pixels (length if 1D) | ||||
|     inline uint16_t height(void)         const { return (stopY > startY) ? (stopY - startY) : 0; } // segment height (if 2D) in physical pixels // softhack007: make sure its always > 0 | ||||
|     inline uint16_t length(void)         const { return width() * height(); }                      // segment length (count) in physical pixels | ||||
|     inline uint16_t width(void)          const { return isActive() ? (stop - start) : 0; }  // segment width in physical pixels (length if 1D) | ||||
|     inline uint16_t height(void)         const { return stopY - startY; }                   // segment height (if 2D) in physical pixels (it *is* always >=1) | ||||
|     inline uint16_t length(void)         const { return width() * height(); }               // segment length (count) in physical pixels | ||||
|     inline uint16_t groupLength(void)    const { return grouping + spacing; } | ||||
|     inline uint8_t  getLightCapabilities(void) const { return _capabilities; } | ||||
|  | ||||
|     static uint16_t getUsedSegmentData(void)    { return _usedSegmentData; } | ||||
|     static void     addUsedSegmentData(int len) { _usedSegmentData += len; } | ||||
|  | ||||
|     void    setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); | ||||
|     void    setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, bool immediate=false); | ||||
|     bool    setColor(uint8_t slot, uint32_t c); //returns true if changed | ||||
|     void    setCCT(uint16_t k); | ||||
|     void    setOpacity(uint8_t o); | ||||
| @@ -536,7 +537,6 @@ typedef struct Segment { | ||||
|       * Safe to call from interrupts and network requests. | ||||
|       */ | ||||
|     inline void markForReset(void) { reset = true; }  // setOption(SEG_OPTION_RESET, true) | ||||
|     void setUpLeds(void); // local double buffer/lossless getPixelColor() | ||||
|  | ||||
|     // transition functions | ||||
|     void     startTransition(uint16_t dur); // transition has to start before actual segment values change | ||||
| @@ -896,7 +896,7 @@ class WS2812FX {  // 96 bytes | ||||
|     uint16_t* customMappingTable; | ||||
|     uint16_t  customMappingSize; | ||||
|  | ||||
|     uint32_t _lastShow; | ||||
|     unsigned long _lastShow; | ||||
|  | ||||
|     uint8_t _segment_index; | ||||
|     uint8_t _mainSegment; | ||||
|   | ||||
| @@ -189,20 +189,16 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) { | ||||
|  | ||||
| // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) | ||||
| uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) { | ||||
|   uint16_t width  = virtualWidth();   // segment width in logical pixels | ||||
|   uint16_t height = virtualHeight();  // segment height in logical pixels | ||||
|   if (width == 0) return 0;           // softhack007 avoid div/0 | ||||
|   if (height == 0) return (x%width);  // softhack007 avoid div/0 | ||||
|   return (x%width) + (y%height) * width; | ||||
|   uint16_t width  = virtualWidth();   // segment width in logical pixels (can be 0 if segment is inactive) | ||||
|   uint16_t height = virtualHeight();  // segment height in logical pixels (is always >= 1) | ||||
|   return isActive() ? (x%width) + (y%height) * width : 0; | ||||
| } | ||||
|  | ||||
| void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col) | ||||
| { | ||||
|   if (Segment::maxHeight==1) return; // not a matrix set-up | ||||
|   if (!isActive()) return; // not active | ||||
|   if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return;  // if pixel would fall out of virtual segment just exit | ||||
|  | ||||
|   if (leds) leds[XY(x,y)] = col; | ||||
|  | ||||
|   uint8_t _bri_t = currentBri(on ? opacity : 0); | ||||
|   if (_bri_t < 255) { | ||||
|     byte r = scale8(R(col), _bri_t); | ||||
| @@ -245,7 +241,7 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col) | ||||
| // anti-aliased version of setPixelColorXY() | ||||
| void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) | ||||
| { | ||||
|   if (Segment::maxHeight==1) return; // not a matrix set-up | ||||
|   if (!isActive()) return; // not active | ||||
|   if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized | ||||
|  | ||||
|   const uint16_t cols = virtualWidth(); | ||||
| @@ -288,7 +284,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) | ||||
|  | ||||
| // returns RGBW values of pixel | ||||
| uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) { | ||||
|   if (leds) return leds[XY(x,y)]; | ||||
|   if (!isActive()) return 0; // not active | ||||
|   if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0;  // if pixel would fall out of virtual segment just exit | ||||
|   if (reverse  ) x = virtualWidth()  - x - 1; | ||||
|   if (reverse_y) y = virtualHeight() - y - 1; | ||||
|   if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed | ||||
| @@ -305,6 +302,7 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t | ||||
|  | ||||
| // Adds the specified color with the existing pixel color perserving color balance. | ||||
| void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) { | ||||
|   if (!isActive()) return; // not active | ||||
|   if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return;  // if pixel would fall out of virtual segment just exit | ||||
|   uint32_t col = getPixelColorXY(x,y); | ||||
|   uint8_t r = R(col); | ||||
| @@ -324,12 +322,14 @@ void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) { | ||||
| } | ||||
|  | ||||
| void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { | ||||
|   if (!isActive()) return; // not active | ||||
|   CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade); | ||||
|   setPixelColorXY(x, y, pix); | ||||
| } | ||||
|  | ||||
| // blurRow: perform a blur on a row of a rectangular matrix | ||||
| void Segment::blurRow(uint16_t row, fract8 blur_amount) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint_fast16_t cols = virtualWidth(); | ||||
|   const uint_fast16_t rows = virtualHeight(); | ||||
|  | ||||
| @@ -357,6 +357,7 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) { | ||||
|  | ||||
| // blurCol: perform a blur on a column of a rectangular matrix | ||||
| void Segment::blurCol(uint16_t col, fract8 blur_amount) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint_fast16_t cols = virtualWidth(); | ||||
|   const uint_fast16_t rows = virtualHeight(); | ||||
|  | ||||
| @@ -384,6 +385,7 @@ void Segment::blurCol(uint16_t col, fract8 blur_amount) { | ||||
|  | ||||
| // 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur]) | ||||
| void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = virtualWidth(); | ||||
|   const uint16_t rows = virtualHeight(); | ||||
|   const uint16_t dim1 = vertical ? rows : cols; | ||||
| @@ -436,6 +438,7 @@ void Segment::blur1d(fract8 blur_amount) { | ||||
| } | ||||
|  | ||||
| void Segment::moveX(int8_t delta, bool wrap) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = virtualWidth(); | ||||
|   const uint16_t rows = virtualHeight(); | ||||
|   if (!delta || abs(delta) >= cols) return; | ||||
| @@ -453,6 +456,7 @@ void Segment::moveX(int8_t delta, bool wrap) { | ||||
| } | ||||
|  | ||||
| void Segment::moveY(int8_t delta, bool wrap) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = virtualWidth(); | ||||
|   const uint16_t rows = virtualHeight(); | ||||
|   if (!delta || abs(delta) >= rows) return; | ||||
| @@ -488,6 +492,7 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { | ||||
| } | ||||
|  | ||||
| void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { | ||||
|   if (!isActive()) return; // not active | ||||
|   // Bresenham’s Algorithm | ||||
|   int d = 3 - (2*radius); | ||||
|   int y = radius, x = 0; | ||||
| @@ -512,6 +517,7 @@ void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { | ||||
|  | ||||
| // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs | ||||
| void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = virtualWidth(); | ||||
|   const uint16_t rows = virtualHeight(); | ||||
|   for (int16_t y = -radius; y <= radius; y++) { | ||||
| @@ -525,6 +531,7 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { | ||||
| } | ||||
|  | ||||
| void Segment::nscale8(uint8_t scale) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = virtualWidth(); | ||||
|   const uint16_t rows = virtualHeight(); | ||||
|   for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) { | ||||
| @@ -534,6 +541,7 @@ void Segment::nscale8(uint8_t scale) { | ||||
|  | ||||
| //line function | ||||
| void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = virtualWidth(); | ||||
|   const uint16_t rows = virtualHeight(); | ||||
|   if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; | ||||
| @@ -558,6 +566,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 | ||||
| // draws a raster font character on canvas | ||||
| // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM | ||||
| void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) { | ||||
|   if (!isActive()) return; // not active | ||||
|   if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported | ||||
|   chr -= 32; // align with font table entries | ||||
|   const uint16_t cols = virtualWidth(); | ||||
| @@ -593,6 +602,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, | ||||
|  | ||||
| #define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8)) | ||||
| void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) {      //awesome wu_pixel procedure by reddit u/sutaburosu | ||||
|   if (!isActive()) return; // not active | ||||
|   // extract the fractional parts and derive their inverses | ||||
|   uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy; | ||||
|   // calculate the intensities for each affected pixel | ||||
|   | ||||
| @@ -81,22 +81,21 @@ uint16_t Segment::maxHeight = 1; | ||||
| Segment::Segment(const Segment &orig) { | ||||
|   //DEBUG_PRINTLN(F("-- Copy segment constructor --")); | ||||
|   memcpy((void*)this, (void*)&orig, sizeof(Segment)); | ||||
|   transitional = false; // copied segment cannot be in transition | ||||
|   name = nullptr; | ||||
|   data = nullptr; | ||||
|   _dataLen = 0; | ||||
|   _t = nullptr; | ||||
|   leds = nullptr; | ||||
|   if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } | ||||
|   if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } | ||||
|   if (orig._t)   { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } | ||||
|   if (orig.leds) { leds = (uint32_t*)malloc(sizeof(uint32_t)*length()); if (leds) memcpy(leds, orig.leds, sizeof(uint32_t)*length()); } | ||||
|   //if (orig._t)   { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } | ||||
| } | ||||
|  | ||||
| // move constructor | ||||
| Segment::Segment(Segment &&orig) noexcept { | ||||
|   //DEBUG_PRINTLN(F("-- Move segment constructor --")); | ||||
|   memcpy((void*)this, (void*)&orig, sizeof(Segment)); | ||||
|   orig.leds = nullptr; | ||||
|   orig.transitional = false; // old segment cannot be in transition any more | ||||
|   orig.name = nullptr; | ||||
|   orig.data = nullptr; | ||||
|   orig._dataLen = 0; | ||||
| @@ -108,23 +107,22 @@ Segment& Segment::operator= (const Segment &orig) { | ||||
|   //DEBUG_PRINTLN(F("-- Copying segment --")); | ||||
|   if (this != &orig) { | ||||
|     // clean destination | ||||
|     transitional = false; // copied segment cannot be in transition | ||||
|     if (name) delete[] name; | ||||
|     if (_t)   delete _t; | ||||
|     if (leds) free(leds); | ||||
|     deallocateData(); | ||||
|     // copy source | ||||
|     memcpy((void*)this, (void*)&orig, sizeof(Segment)); | ||||
|     transitional = false; | ||||
|     // erase pointers to allocated data | ||||
|     name = nullptr; | ||||
|     data = nullptr; | ||||
|     _dataLen = 0; | ||||
|     _t = nullptr; | ||||
|     leds = nullptr; | ||||
|     // copy source data | ||||
|     if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } | ||||
|     if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } | ||||
|     if (orig._t)   { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } | ||||
|     if (orig.leds) { leds = (uint32_t*)malloc(sizeof(uint32_t)*length()); if (leds) memcpy(leds, orig.leds, sizeof(uint32_t)*length()); } | ||||
|     //if (orig._t)   { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } | ||||
|   } | ||||
|   return *this; | ||||
| } | ||||
| @@ -133,16 +131,16 @@ Segment& Segment::operator= (const Segment &orig) { | ||||
| Segment& Segment::operator= (Segment &&orig) noexcept { | ||||
|   //DEBUG_PRINTLN(F("-- Moving segment --")); | ||||
|   if (this != &orig) { | ||||
|     if (name) delete[] name; // free old name | ||||
|     if (leds) free(leds); | ||||
|     transitional = false; // just temporary | ||||
|     if (name) { delete[] name; name = nullptr; } // free old name | ||||
|     deallocateData(); // free old runtime data | ||||
|     if (_t) delete _t; | ||||
|     if (_t) { delete _t; _t = nullptr; } | ||||
|     memcpy((void*)this, (void*)&orig, sizeof(Segment)); | ||||
|     orig.transitional = false; // old segment cannot be in transition | ||||
|     orig.name = nullptr; | ||||
|     orig.data = nullptr; | ||||
|     orig._dataLen = 0; | ||||
|     orig._t   = nullptr; | ||||
|     orig.leds = nullptr; | ||||
|   } | ||||
|   return *this; | ||||
| } | ||||
| @@ -152,12 +150,7 @@ bool Segment::allocateData(size_t len) { | ||||
|   deallocateData(); | ||||
|   if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory | ||||
|   // do not use SPI RAM on ESP32 since it is slow | ||||
|   //#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM) | ||||
|   //if (psramFound()) | ||||
|   //  data = (byte*) ps_malloc(len); | ||||
|   //else | ||||
|   //#endif | ||||
|     data = (byte*) malloc(len); | ||||
|   data = (byte*) malloc(len); | ||||
|   if (!data) return false; //allocation failed | ||||
|   Segment::addUsedSegmentData(len); | ||||
|   _dataLen = len; | ||||
| @@ -182,28 +175,13 @@ void Segment::deallocateData() { | ||||
|   */ | ||||
| void Segment::resetIfRequired() { | ||||
|   if (reset) { | ||||
|     if (leds) { free(leds); leds = nullptr; } | ||||
|     deallocateData(); | ||||
|     next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; | ||||
|     if (_queuedChanges) setUp(_qStart, _qStop, grouping, spacing, offset, _qStartY, _qStopY, true); | ||||
|     reset = false; // setOption(SEG_OPTION_RESET, false); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Segment::setUpLeds() { | ||||
|   // deallocation happens in resetIfRequired() as it is called when segment changes or in destructor | ||||
|   if (useGlobalLedBuffer) return; // TODO optional seg buffer for FX without lossy restore due to opacity | ||||
|  | ||||
|   // no global buffer | ||||
|   if (leds == nullptr && length() > 0) { //softhack007 quickfix - avoid malloc(0) which is undefined behaviour (should not happen, but i've seen it) | ||||
|     //#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) | ||||
|     //if (psramFound()) | ||||
|     //  leds = (CRGB*)ps_malloc(sizeof(CRGB)*length());   // softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards | ||||
|     //else | ||||
|     //#endif | ||||
|     leds = (uint32_t *)calloc(length(), sizeof(uint32_t)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { | ||||
|   static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment | ||||
|   static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR); | ||||
| @@ -326,7 +304,7 @@ void Segment::startTransition(uint16_t dur) { | ||||
| // transition progression between 0-65535 | ||||
| uint16_t Segment::progress() { | ||||
|   if (!transitional || !_t) return 0xFFFFU; | ||||
|   uint32_t timeNow = millis(); | ||||
|   unsigned long timeNow = millis(); | ||||
|   if (timeNow - _t->_start > _t->_dur || _t->_dur == 0) return 0xFFFFU; | ||||
|   return (timeNow - _t->_start) * 0xFFFFU / _t->_dur; | ||||
| } | ||||
| @@ -355,7 +333,7 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal | ||||
|     // blend palettes | ||||
|     // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) | ||||
|     // minimum blend time is 100ms maximum is 65535ms | ||||
|     uint32_t timeMS = millis() - _t->_start; | ||||
|     unsigned long timeMS = millis() - _t->_start; | ||||
|     uint16_t noOfBlends = (255U * timeMS / _t->_dur) - _t->_prevPaletteBlends; | ||||
|     for (int i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48); | ||||
|     targetPalette = _t->_palT; // copy transitioning/temporary palette | ||||
| @@ -376,8 +354,9 @@ void Segment::handleTransition() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) { | ||||
|   //return if neither bounds nor grouping have changed | ||||
| void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, bool immediate) { | ||||
|   _queuedChanges = false; // cancel anything queued | ||||
|   // return if neither bounds nor grouping have changed | ||||
|   bool boundsUnchanged = (start == i1 && stop == i2); | ||||
|   #ifndef WLED_DISABLE_2D | ||||
|   if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D | ||||
| @@ -386,29 +365,47 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t | ||||
|       && (!grp || (grouping == grp && spacing == spc)) | ||||
|       && (ofs == UINT16_MAX || ofs == offset)) return; | ||||
|  | ||||
|   if (stop) fill(BLACK); //turn old segment range off | ||||
|   if (i2 <= i1) { //disable segment | ||||
|     stop = 0; | ||||
|     markForReset(); | ||||
|     return; | ||||
|   } | ||||
|   if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D | ||||
|   stop = i2 > Segment::maxWidth*Segment::maxHeight ? MIN(i2,strip.getLengthTotal()) : (i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2)); | ||||
|   startY = 0; | ||||
|   stopY  = 1; | ||||
|   #ifndef WLED_DISABLE_2D | ||||
|   if (Segment::maxHeight>1) { // 2D | ||||
|     if (i1Y < Segment::maxHeight) startY = i1Y; | ||||
|     stopY = i2Y > Segment::maxHeight ? Segment::maxHeight : MAX(1,i2Y); | ||||
|   } | ||||
|   #endif | ||||
|   if (grp) { | ||||
|   if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing) | ||||
|   if (grp) { // prevent assignment of 0 | ||||
|     grouping = grp; | ||||
|     spacing = spc; | ||||
|   } else { | ||||
|     grouping = 1; | ||||
|     spacing = 0; | ||||
|   } | ||||
|   if (ofs < UINT16_MAX) offset = ofs; | ||||
|  | ||||
|   markForReset(); | ||||
|   if (!boundsUnchanged) refreshLightCapabilities(); | ||||
|   if (!boundsUnchanged) { | ||||
|     if (immediate) { | ||||
|       if (i2 <= i1) { //disable segment | ||||
|         stop = 0; | ||||
|         return; | ||||
|       } | ||||
|       if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D | ||||
|       stop = i2 > Segment::maxWidth*Segment::maxHeight ? MIN(i2,strip.getLengthTotal()) : (i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2)); | ||||
|       startY = 0; | ||||
|       stopY  = 1; | ||||
|       #ifndef WLED_DISABLE_2D | ||||
|       if (Segment::maxHeight>1) { // 2D | ||||
|         if (i1Y < Segment::maxHeight) startY = i1Y; | ||||
|         stopY = i2Y > Segment::maxHeight ? Segment::maxHeight : MAX(1,i2Y); | ||||
|       } | ||||
|       #endif | ||||
|       // safety check | ||||
|       if (start >= stop || startY >= stopY) { | ||||
|         stop = 0; | ||||
|         return; | ||||
|       } | ||||
|       if (!boundsUnchanged) refreshLightCapabilities(); | ||||
|     } else { | ||||
|       _qStart  = i1; | ||||
|       _qStop   = i2; | ||||
|       _qStartY = i1Y; | ||||
|       _qStopY  = i2Y; | ||||
|       _queuedChanges = true; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -455,8 +452,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) { | ||||
|   // if we have a valid mode & is not reserved | ||||
|   if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) { | ||||
|     if (fx != mode) { | ||||
|       startTransition(strip.getTransition()); // set effect transitions | ||||
|       //markForReset(); // transition will handle this | ||||
|       if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions | ||||
|       mode = fx; | ||||
|  | ||||
|       // load default values from effect string | ||||
| @@ -541,8 +537,7 @@ uint16_t Segment::virtualLength() const { | ||||
|     return vLen; | ||||
|   } | ||||
| #endif | ||||
|   uint16_t groupLen = groupLength(); | ||||
|   if (groupLen < 1) groupLen = 1;          // prevent division by zero - better safe than sorry ... | ||||
|   uint16_t groupLen = groupLength(); // is always >= 1 | ||||
|   uint16_t vLength = (length() + groupLen - 1) / groupLen; | ||||
|   if (mirror) vLength = (vLength + 1) /2;  // divide by 2 if mirror, leave at least a single LED | ||||
|   return vLength; | ||||
| @@ -550,6 +545,7 @@ uint16_t Segment::virtualLength() const { | ||||
|  | ||||
| void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) | ||||
| { | ||||
|   if (!isActive()) return; // not active | ||||
| #ifndef WLED_DISABLE_2D | ||||
|   int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) | ||||
| #endif | ||||
| @@ -617,8 +613,6 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   if (leds) leds[i] = col; | ||||
|  | ||||
|   uint16_t len = length(); | ||||
|   uint8_t _bri_t = currentBri(on ? opacity : 0); | ||||
|   if (_bri_t < 255) { | ||||
| @@ -660,6 +654,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) | ||||
| // anti-aliased normalized version of setPixelColor() | ||||
| void Segment::setPixelColor(float i, uint32_t col, bool aa) | ||||
| { | ||||
|   if (!isActive()) return; // not active | ||||
|   int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows) | ||||
|   i -= int(i); | ||||
|  | ||||
| @@ -691,6 +686,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) | ||||
|  | ||||
| uint32_t Segment::getPixelColor(int i) | ||||
| { | ||||
|   if (!isActive()) return 0; // not active | ||||
| #ifndef WLED_DISABLE_2D | ||||
|   int vStrip = i>>16; | ||||
| #endif | ||||
| @@ -718,8 +714,6 @@ uint32_t Segment::getPixelColor(int i) | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   if (leds) return leds[i]; | ||||
|  | ||||
|   if (reverse) i = virtualLength() - i - 1; | ||||
|   i *= groupLength(); | ||||
|   i += start; | ||||
| @@ -760,6 +754,11 @@ void Segment::refreshLightCapabilities() { | ||||
|   uint16_t segStartIdx = 0xFFFFU; | ||||
|   uint16_t segStopIdx  = 0; | ||||
|  | ||||
|   if (!isActive()) { | ||||
|     _capabilities = 0; | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (start < Segment::maxWidth * Segment::maxHeight) { | ||||
|     // we are withing 2D matrix (includes 1D segments) | ||||
|     for (int y = startY; y < stopY; y++) for (int x = start; x < stop; x++) { | ||||
| @@ -804,6 +803,7 @@ void Segment::refreshLightCapabilities() { | ||||
|  * Fills segment with color | ||||
|  */ | ||||
| void Segment::fill(uint32_t c) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = is2D() ? virtualWidth() : virtualLength(); | ||||
|   const uint16_t rows = virtualHeight(); // will be 1 for 1D | ||||
|   for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) { | ||||
| @@ -819,6 +819,7 @@ void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) { | ||||
|  | ||||
| // Adds the specified color with the existing pixel color perserving color balance. | ||||
| void Segment::addPixelColor(int n, uint32_t color, bool fast) { | ||||
|   if (!isActive()) return; // not active | ||||
|   uint32_t col = getPixelColor(n); | ||||
|   uint8_t r = R(col); | ||||
|   uint8_t g = G(col); | ||||
| @@ -837,6 +838,7 @@ void Segment::addPixelColor(int n, uint32_t color, bool fast) { | ||||
| } | ||||
|  | ||||
| void Segment::fadePixelColor(uint16_t n, uint8_t fade) { | ||||
|   if (!isActive()) return; // not active | ||||
|   CRGB pix = CRGB(getPixelColor(n)).nscale8_video(fade); | ||||
|   setPixelColor(n, pix); | ||||
| } | ||||
| @@ -845,6 +847,7 @@ void Segment::fadePixelColor(uint16_t n, uint8_t fade) { | ||||
|  * fade out function, higher rate = quicker fade | ||||
|  */ | ||||
| void Segment::fade_out(uint8_t rate) { | ||||
|   if (!isActive()) return; // not active | ||||
|   const uint16_t cols = is2D() ? virtualWidth() : virtualLength(); | ||||
|   const uint16_t rows = virtualHeight(); // will be 1 for 1D | ||||
|  | ||||
| @@ -882,7 +885,7 @@ void Segment::fade_out(uint8_t rate) { | ||||
|  | ||||
| // fades all pixels to black using nscale8() | ||||
| void Segment::fadeToBlackBy(uint8_t fadeBy) { | ||||
|   if (fadeBy == 0) return;   // optimization - no scaling to apply | ||||
|   if (!isActive() || fadeBy == 0) return;   // optimization - no scaling to apply | ||||
|   const uint16_t cols = is2D() ? virtualWidth() : virtualLength(); | ||||
|   const uint16_t rows = virtualHeight(); // will be 1 for 1D | ||||
|  | ||||
| @@ -897,7 +900,7 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { | ||||
|  */ | ||||
| void Segment::blur(uint8_t blur_amount) | ||||
| { | ||||
|   if (blur_amount == 0) return; // optimization: 0 means "don't blur" | ||||
|   if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur" | ||||
| #ifndef WLED_DISABLE_2D | ||||
|   if (is2D()) { | ||||
|     // compatibility with 2D | ||||
| @@ -1071,7 +1074,7 @@ void WS2812FX::finalizeInit(void) | ||||
| } | ||||
|  | ||||
| void WS2812FX::service() { | ||||
|   uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days | ||||
|   unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days | ||||
|   now = nowUp + timebase; | ||||
|   if (nowUp - _lastShow < MIN_SHOW_DELAY) return; | ||||
|   bool doShow = false; | ||||
| @@ -1089,7 +1092,6 @@ void WS2812FX::service() { | ||||
|     // last condition ensures all solid segments are updated at the same time | ||||
|     if(nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) | ||||
|     { | ||||
|       if (seg.grouping == 0) seg.grouping = 1; // sanity check | ||||
|       doShow = true; | ||||
|       uint16_t delay = FRAMETIME; | ||||
|  | ||||
| @@ -1117,12 +1119,19 @@ void WS2812FX::service() { | ||||
|   } | ||||
|   _virtualSegmentLength = 0; | ||||
|   busses.setSegmentCCT(-1); | ||||
|   if(doShow) { | ||||
|   _isServicing = false; | ||||
|   _triggered = false; | ||||
|  | ||||
|   #ifdef WLED_DEBUG | ||||
|   if (millis() - nowUp > _frametime) DEBUG_PRINTLN(F("Slow effects.")); | ||||
|   #endif | ||||
|   if (doShow) { | ||||
|     yield(); | ||||
|     show(); | ||||
|   } | ||||
|   _triggered = false; | ||||
|   _isServicing = false; | ||||
|   #ifdef WLED_DEBUG | ||||
|   if (millis() - nowUp > _frametime) DEBUG_PRINTLN(F("Slow strip.")); | ||||
|   #endif | ||||
| } | ||||
|  | ||||
| void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col) | ||||
| @@ -1159,31 +1168,25 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() { | ||||
|   bool useWackyWS2815PowerModel = false; | ||||
|   byte actualMilliampsPerLed = milliampsPerLed; | ||||
|  | ||||
|   if(milliampsPerLed == 255) { | ||||
|     useWackyWS2815PowerModel = true; | ||||
|     actualMilliampsPerLed = 12; // from testing an actual strip | ||||
|   } | ||||
|  | ||||
|   if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation | ||||
|     currentMilliamps = 0; | ||||
|     return _brightness; | ||||
|   } | ||||
|  | ||||
|   uint16_t pLen = getLengthPhysical(); | ||||
|   uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed; | ||||
|   uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power | ||||
|   if (powerBudget > puPerMilliamp * pLen) { //each LED uses about 1mA in standby, exclude that from power budget | ||||
|     powerBudget -= puPerMilliamp * pLen; | ||||
|   } else { | ||||
|     powerBudget = 0; | ||||
|   if (milliampsPerLed == 255) { | ||||
|     useWackyWS2815PowerModel = true; | ||||
|     actualMilliampsPerLed = 12; // from testing an actual strip | ||||
|   } | ||||
|  | ||||
|   uint32_t powerSum = 0; // could overflow if more than 22K LEDs (uint32_t MAX / 195075 PU per LED) | ||||
|   size_t powerBudget = (ablMilliampsMax - MA_FOR_ESP); //100mA for ESP power | ||||
|  | ||||
|   size_t pLen = 0; //getLengthPhysical(); | ||||
|   size_t powerSum = 0; | ||||
|   for (uint_fast8_t bNum = 0; bNum < busses.getNumBusses(); bNum++) { | ||||
|     Bus *bus = busses.getBus(bNum); | ||||
|     if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses | ||||
|     if (!IS_DIGITAL(bus->getType())) continue; //exclude non-digital network busses | ||||
|     uint16_t len = bus->getLength(); | ||||
|     pLen += len; | ||||
|     uint32_t busPowerSum = 0; | ||||
|     for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED | ||||
|       uint32_t c = bus->getPixelColor(i); // always returns original or restored color without brightness scaling | ||||
| @@ -1198,38 +1201,44 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() { | ||||
|  | ||||
|     if (bus->hasWhite()) { //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less | ||||
|       busPowerSum *= 3; | ||||
|       busPowerSum = busPowerSum >> 2; //same as /= 4 | ||||
|       busPowerSum >>= 2; //same as /= 4 | ||||
|     } | ||||
|     powerSum += busPowerSum; | ||||
|   } | ||||
|  | ||||
|   uint8_t newBri = _brightness; | ||||
|   uint32_t powerSumUnscaled = powerSum; | ||||
|   powerSum *= _brightness; | ||||
|   if (powerBudget > pLen) { //each LED uses about 1mA in standby, exclude that from power budget | ||||
|     powerBudget -= pLen; | ||||
|   } else { | ||||
|     powerBudget = 0; | ||||
|   } | ||||
|  | ||||
|   if (powerSum > powerBudget) { //scale brightness down to stay in current limit | ||||
|   // powerSum has all the values of channels summed (max would be pLen*765 as white is excluded) so convert to milliAmps | ||||
|   powerSum = (powerSum * actualMilliampsPerLed) / 765; | ||||
|  | ||||
|   uint8_t newBri = _brightness; | ||||
|   if (powerSum * _brightness / 255 > powerBudget) { //scale brightness down to stay in current limit | ||||
|     float scale = (float)powerBudget / (float)powerSum; | ||||
|     uint16_t scaleI = scale * 255; | ||||
|     uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; | ||||
|     newBri = scale8(_brightness, scaleB); | ||||
|   } | ||||
|   currentMilliamps = (powerSumUnscaled * newBri) / puPerMilliamp; | ||||
|   currentMilliamps = (powerSum * newBri) / 255; | ||||
|   currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate | ||||
|   currentMilliamps += pLen; //add standby power back to estimate | ||||
|   currentMilliamps += pLen; //add standby power (1mA/LED) back to estimate | ||||
|   return newBri; | ||||
| } | ||||
|  | ||||
| void WS2812FX::show(void) { | ||||
|   // avoid race condition, caputre _callback value | ||||
|   show_callback callback = _callback; | ||||
|   if (callback) callback(); | ||||
|  | ||||
|   #ifdef WLED_DEBUG | ||||
|   static unsigned long sumMicros = 0, sumCurrent = 0; | ||||
|   static size_t calls = 0; | ||||
|   unsigned long microsStart = micros(); | ||||
|   #endif | ||||
|  | ||||
|   // avoid race condition, caputre _callback value | ||||
|   show_callback callback = _callback; | ||||
|   if (callback) callback(); | ||||
|  | ||||
|   uint8_t busBrightness = estimateCurrentAndLimitBri(); | ||||
|   busses.setBrightness(busBrightness); | ||||
|   #ifdef WLED_DEBUG | ||||
| @@ -1240,21 +1249,22 @@ void WS2812FX::show(void) { | ||||
|   // all of the data has been sent. | ||||
|   // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods | ||||
|   busses.show(); | ||||
|   unsigned long now = millis(); | ||||
|   unsigned long diff = now - _lastShow; | ||||
|   uint16_t fpsCurr = 200; | ||||
|   if (diff > 0) fpsCurr = 1000 / diff; | ||||
|   _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2; | ||||
|   _lastShow = now; | ||||
|  | ||||
|   #ifdef WLED_DEBUG | ||||
|   sumMicros += micros() - microsStart; | ||||
|   if (++calls == 100) { | ||||
|     DEBUG_PRINTF("show calls: %d micros: %lu avg: %lu (current: %lu avg: %lu)\n", calls, sumMicros, sumMicros/calls, sumCurrent, sumCurrent/calls); | ||||
|     DEBUG_PRINTF("%d show calls: %lu[us] avg: %lu[us] (current: %lu[us] avg: %lu[us])\n", calls, sumMicros, sumMicros/calls, sumCurrent, sumCurrent/calls); | ||||
|     sumMicros = sumCurrent = 0; | ||||
|     calls = 0; | ||||
|   } | ||||
|   #endif | ||||
|  | ||||
|   unsigned long now = millis(); | ||||
|   size_t diff = now - _lastShow; | ||||
|   size_t fpsCurr = 200; | ||||
|   if (diff > 0) fpsCurr = 1000 / diff; | ||||
|   _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2; | ||||
|   _lastShow = now; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -1431,6 +1441,7 @@ Segment& WS2812FX::getSegment(uint8_t id) { | ||||
|   return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors | ||||
| } | ||||
|  | ||||
| // compatibility method (deprecated) | ||||
| void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) { | ||||
|   if (n >= _segments.size()) return; | ||||
|   _segments[n].setUp(i1, i2, grouping, spacing, offset, startY, stopY); | ||||
|   | ||||
| @@ -128,11 +128,6 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) | ||||
|  | ||||
| void BusDigital::show() { | ||||
|   if (!_valid) return; | ||||
|   #ifdef WLED_DEBUG | ||||
|   static unsigned long sumMicros = 0; | ||||
|   static size_t calls = 0; | ||||
|   unsigned long microsStart = micros(); | ||||
|   #endif | ||||
|   PolyBus::setBrightness(_busPtr, _iType, _bri); | ||||
|   if (buffering) { // should be _data != nullptr, but that causes ~20% FPS drop | ||||
|     size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type); | ||||
| @@ -159,14 +154,6 @@ void BusDigital::show() { | ||||
|   } | ||||
|   PolyBus::show(_busPtr, _iType); | ||||
|   PolyBus::setBrightness(_busPtr, _iType, 255); // restore full brightness at bus level (setting unscaled pixel color) | ||||
|   #ifdef WLED_DEBUG | ||||
|   sumMicros += micros() - microsStart; | ||||
|   if (++calls == 100) { | ||||
|     DEBUG_PRINTF("Bus calls: %d micros: %lu avg: %lu\n", calls, sumMicros, sumMicros/calls); | ||||
|     sumMicros = 0; | ||||
|     calls = 0; | ||||
|   } | ||||
|   #endif | ||||
| } | ||||
|  | ||||
| bool BusDigital::canShow() { | ||||
|   | ||||
| @@ -22,7 +22,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) | ||||
|  | ||||
|   int stop = elem["stop"] | -1; | ||||
|  | ||||
|   // if using vectors use this code to append segment | ||||
|   // append segment | ||||
|   if (id >= strip.getSegmentsNum()) { | ||||
|     if (stop <= 0) return false; // ignore empty/inactive segments | ||||
|     strip.appendSegment(Segment(0, strip.getLengthTotal())); | ||||
| @@ -110,7 +110,10 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) | ||||
|     of = offsetAbs; | ||||
|   } | ||||
|   if (stop > start && of > len -1) of = len -1; | ||||
|   seg.setUp(start, stop, grp, spc, of, startY, stopY); | ||||
|  | ||||
|   // update segment (delete if necessary) | ||||
|   // we must not change segment dimensions during drawing of effects as that may produce undesired behaviour (crash) | ||||
|   seg.setUp(start, stop, grp, spc, of, startY, stopY, !strip.isServicing()); | ||||
|  | ||||
|   if (seg.reset && seg.stop == 0) return true; // segment was deleted & is marked for reset, no need to change anything else | ||||
|  | ||||
| @@ -468,12 +471,14 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b | ||||
|   if (segmentBounds) { | ||||
|     root["start"] = seg.start; | ||||
|     root["stop"] = seg.stop; | ||||
|     #ifndef WLED_DISABLE_2D | ||||
|     if (strip.isMatrix) { | ||||
|       root[F("startY")] = seg.startY; | ||||
|       root[F("stopY")]  = seg.stopY; | ||||
|     } | ||||
|     #endif | ||||
|   } | ||||
|   if (!forPreset) root["len"] = (seg.stop >= seg.start) ? (seg.stop - seg.start) : 0; | ||||
|   if (!forPreset) root["len"] = seg.stop - seg.start; | ||||
|   root["grp"]    = seg.grouping; | ||||
|   root[F("spc")] = seg.spacing; | ||||
|   root[F("of")]  = seg.offset; | ||||
|   | ||||
| @@ -23,7 +23,7 @@ void WLED::reset() | ||||
|   #ifdef WLED_ENABLE_WEBSOCKETS | ||||
|   ws.closeAll(1012); | ||||
|   #endif | ||||
|   long dly = millis(); | ||||
|   unsigned long dly = millis(); | ||||
|   while (millis() - dly < 450) { | ||||
|     yield();        // enough time to send response to client | ||||
|   } | ||||
| @@ -36,13 +36,17 @@ void WLED::loop() | ||||
| { | ||||
|   #ifdef WLED_DEBUG | ||||
|   static unsigned long lastRun = 0; | ||||
|   size_t loopDelay = (millis() - lastRun); | ||||
|   unsigned long        loopMillis = millis(); | ||||
|   size_t               loopDelay = loopMillis - lastRun; | ||||
|   if (lastRun == 0) loopDelay=0; // startup - don't have valid data from last run. | ||||
|   if (loopDelay > 2) DEBUG_PRINTF("Loop delayed more than %dms.\n", loopDelay); | ||||
|   if (loopDelay > 2) DEBUG_PRINTF("Loop delayed more than %ums.\n", loopDelay); | ||||
|   static unsigned long maxLoopMillis = 0; | ||||
|   static size_t        avgLoopMillis = 0; | ||||
|   static unsigned long maxUsermodMillis = 0; | ||||
|   static size_t        avgUsermodMillis = 0; | ||||
|   static unsigned long maxStripMillis = 0; | ||||
|   static size_t        avgStripMillis = 0; | ||||
|   unsigned long        stripMillis; | ||||
|   #endif | ||||
|  | ||||
|   handleTime(); | ||||
| @@ -84,6 +88,9 @@ void WLED::loop() | ||||
|     yield(); | ||||
|   } | ||||
|  | ||||
|   #ifdef WLED_DEBUG | ||||
|   stripMillis = millis(); | ||||
|   #endif | ||||
|   if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly))  // block stuff if WARLS/Adalight is enabled | ||||
|   { | ||||
|     if (apActive) dnsServer.processNextRequest(); | ||||
| @@ -102,22 +109,18 @@ void WLED::loop() | ||||
|     handlePresets(); | ||||
|     yield(); | ||||
|  | ||||
|     #ifdef WLED_DEBUG | ||||
|     unsigned long stripMillis = millis(); | ||||
|     #endif | ||||
|     if (!offMode || strip.isOffRefreshRequired()) | ||||
|       strip.service(); | ||||
|     #ifdef ESP8266 | ||||
|     else if (!noWifiSleep) | ||||
|       delay(1); //required to make sure ESP enters modem sleep (see #1184) | ||||
|     #endif | ||||
|     #ifdef WLED_DEBUG | ||||
|     stripMillis = millis() - stripMillis; | ||||
|     if (stripMillis > 50) DEBUG_PRINTLN("Slow strip."); | ||||
|     avgStripMillis += stripMillis; | ||||
|     if (stripMillis > maxStripMillis) maxStripMillis = stripMillis; | ||||
|     #endif | ||||
|   } | ||||
|   #ifdef WLED_DEBUG | ||||
|   stripMillis = millis() - stripMillis; | ||||
|   avgStripMillis += stripMillis; | ||||
|   if (stripMillis > maxStripMillis) maxStripMillis = stripMillis; | ||||
|   #endif | ||||
|  | ||||
|   yield(); | ||||
| #ifdef ESP8266 | ||||
| @@ -186,8 +189,31 @@ void WLED::loop() | ||||
|   handleWs(); | ||||
|   handleStatusLED(); | ||||
|  | ||||
|   toki.resetTick(); | ||||
|  | ||||
| #if WLED_WATCHDOG_TIMEOUT > 0 | ||||
|   // we finished our mainloop, reset the watchdog timer | ||||
|   if (!strip.isUpdating()) | ||||
|   #ifdef ARDUINO_ARCH_ESP32 | ||||
|     esp_task_wdt_reset(); | ||||
|   #else | ||||
|     ESP.wdtFeed(); | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
|   if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration | ||||
|     reset(); | ||||
|  | ||||
| // DEBUG serial logging (every 30s) | ||||
| #ifdef WLED_DEBUG | ||||
|   loopMillis = millis() - loopMillis; | ||||
|   if (loopMillis > 30) { | ||||
|     DEBUG_PRINTF("Loop took %lums.\n", loopMillis); | ||||
|     DEBUG_PRINTF("Usermods took %lums.\n", usermodMillis); | ||||
|     DEBUG_PRINTF("Strip took %lums.\n", stripMillis); | ||||
|   } | ||||
|   avgLoopMillis += loopMillis; | ||||
|   if (loopMillis > maxLoopMillis) maxLoopMillis = loopMillis; | ||||
|   if (millis() - debugTime > 29999) { | ||||
|     DEBUG_PRINTLN(F("---DEBUG INFO---")); | ||||
|     DEBUG_PRINT(F("Runtime: "));       DEBUG_PRINTLN(millis()); | ||||
| @@ -210,11 +236,13 @@ void WLED::loop() | ||||
|     DEBUG_PRINT(F("Client IP: "));       DEBUG_PRINTLN(Network.localIP()); | ||||
|     if (loops > 0) { // avoid division by zero | ||||
|       DEBUG_PRINT(F("Loops/sec: "));       DEBUG_PRINTLN(loops / 30); | ||||
|       DEBUG_PRINT(F("Loop time[ms]: "));   DEBUG_PRINT(avgLoopMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxLoopMillis); | ||||
|       DEBUG_PRINT(F("UM time[ms]: "));     DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis); | ||||
|       DEBUG_PRINT(F("Strip time[ms]: "));  DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis); | ||||
|     } | ||||
|     strip.printSize(); | ||||
|     loops = 0; | ||||
|     maxLoopMillis = 0; | ||||
|     maxUsermodMillis = 0; | ||||
|     maxStripMillis = 0; | ||||
|     avgUsermodMillis = 0; | ||||
| @@ -224,20 +252,6 @@ void WLED::loop() | ||||
|   loops++; | ||||
|   lastRun = millis(); | ||||
| #endif        // WLED_DEBUG | ||||
|   toki.resetTick(); | ||||
|  | ||||
| #if WLED_WATCHDOG_TIMEOUT > 0 | ||||
|   // we finished our mainloop, reset the watchdog timer | ||||
|   if (!strip.isUpdating()) | ||||
|   #ifdef ARDUINO_ARCH_ESP32 | ||||
|     esp_task_wdt_reset(); | ||||
|   #else | ||||
|     ESP.wdtFeed(); | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
|   if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration | ||||
|     reset(); | ||||
| } | ||||
|  | ||||
| void WLED::enableWatchdog() { | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  */ | ||||
|  | ||||
| // version code in format yymmddb (b = daily build) | ||||
| #define VERSION 2307090 | ||||
| #define VERSION 2307120 | ||||
|  | ||||
| //uncomment this if you have a "my_config.h" file you'd like to use | ||||
| //#define WLED_USE_MY_CONFIG | ||||
| @@ -513,7 +513,7 @@ WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use i | ||||
| // wifi | ||||
| WLED_GLOBAL bool apActive _INIT(false); | ||||
| WLED_GLOBAL bool forceReconnect _INIT(false); | ||||
| WLED_GLOBAL uint32_t lastReconnectAttempt _INIT(0); | ||||
| WLED_GLOBAL unsigned long lastReconnectAttempt _INIT(0); | ||||
| WLED_GLOBAL bool interfacesInited _INIT(false); | ||||
| WLED_GLOBAL bool wasConnected _INIT(false); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Blaz Kristan
					Blaz Kristan