kopia lustrzana https://github.com/Aircoookie/WLED
				
				
				
			
						commit
						93853613bd
					
				| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
 | 
			
		||||
# CI binaries
 | 
			
		||||
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
 | 
			
		||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
 | 
			
		||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi
 | 
			
		||||
 | 
			
		||||
# Release binaries
 | 
			
		||||
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +175,7 @@ upload_speed = 115200
 | 
			
		|||
# ------------------------------------------------------------------------------
 | 
			
		||||
lib_compat_mode = strict
 | 
			
		||||
lib_deps =
 | 
			
		||||
    fastled/FastLED @ 3.5.0
 | 
			
		||||
    fastled/FastLED @ 3.6.0
 | 
			
		||||
    IRremoteESP8266 @ 2.8.2
 | 
			
		||||
    makuna/NeoPixelBus @ 2.7.5
 | 
			
		||||
    https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
 | 
			
		||||
| 
						 | 
				
			
			@ -201,7 +201,7 @@ build_flags =
 | 
			
		|||
  -DESP8266
 | 
			
		||||
  -DFP_IN_IROM
 | 
			
		||||
  ;-Wno-deprecated-declarations
 | 
			
		||||
  -Wno-register  ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C
 | 
			
		||||
  ;-Wno-register  ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C
 | 
			
		||||
  ;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this can be dangerous
 | 
			
		||||
  -Wno-misleading-indentation
 | 
			
		||||
  ; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
 | 
			
		||||
| 
						 | 
				
			
			@ -249,9 +249,8 @@ lib_deps =
 | 
			
		|||
;;
 | 
			
		||||
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
 | 
			
		||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
 | 
			
		||||
platform = espressif32@5.2.0
 | 
			
		||||
platform = espressif32@5.3.0
 | 
			
		||||
platform_packages =
 | 
			
		||||
  toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
 | 
			
		||||
build_flags = -g
 | 
			
		||||
  -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
 | 
			
		||||
  -DARDUINO_ARCH_ESP32 -DESP32
 | 
			
		||||
| 
						 | 
				
			
			@ -265,9 +264,8 @@ lib_deps =
 | 
			
		|||
 | 
			
		||||
[esp32s2]
 | 
			
		||||
;; generic definitions for all ESP32-S2 boards
 | 
			
		||||
platform = espressif32@5.2.0
 | 
			
		||||
platform = espressif32@5.3.0
 | 
			
		||||
platform_packages =
 | 
			
		||||
  toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
 | 
			
		||||
build_flags = -g
 | 
			
		||||
  -DARDUINO_ARCH_ESP32
 | 
			
		||||
  -DARDUINO_ARCH_ESP32S2
 | 
			
		||||
| 
						 | 
				
			
			@ -285,9 +283,8 @@ lib_deps =
 | 
			
		|||
 | 
			
		||||
[esp32c3]
 | 
			
		||||
;; generic definitions for all ESP32-C3 boards
 | 
			
		||||
platform = espressif32@5.2.0
 | 
			
		||||
platform = espressif32@5.3.0
 | 
			
		||||
platform_packages =
 | 
			
		||||
  toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
 | 
			
		||||
build_flags = -g
 | 
			
		||||
  -DARDUINO_ARCH_ESP32
 | 
			
		||||
  -DARDUINO_ARCH_ESP32C3
 | 
			
		||||
| 
						 | 
				
			
			@ -304,9 +301,8 @@ lib_deps =
 | 
			
		|||
 | 
			
		||||
[esp32s3]
 | 
			
		||||
;; generic definitions for all ESP32-S3 boards
 | 
			
		||||
platform = espressif32@5.2.0
 | 
			
		||||
platform = espressif32@5.3.0
 | 
			
		||||
platform_packages =
 | 
			
		||||
  toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
 | 
			
		||||
build_flags = -g
 | 
			
		||||
  -DESP32
 | 
			
		||||
  -DARDUINO_ARCH_ESP32
 | 
			
		||||
| 
						 | 
				
			
			@ -450,6 +446,7 @@ board_build.flash_mode = qio
 | 
			
		|||
upload_speed = 460800
 | 
			
		||||
build_unflags = ${common.build_unflags}
 | 
			
		||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=S2_saola
 | 
			
		||||
  ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work
 | 
			
		||||
  -DARDUINO_USB_CDC_ON_BOOT=1
 | 
			
		||||
lib_deps = ${esp32s2.lib_deps}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -462,6 +459,7 @@ board = esp32-c3-devkitm-1
 | 
			
		|||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
 | 
			
		||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3
 | 
			
		||||
  -D WLED_WATCHDOG_TIMEOUT=0
 | 
			
		||||
  -DLOLIN_WIFI_FIX ; seems to work much better with this
 | 
			
		||||
  -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
 | 
			
		||||
  ;-DARDUINO_USB_CDC_ON_BOOT=0   ;; for serial-to-USB chip
 | 
			
		||||
upload_speed = 460800
 | 
			
		||||
| 
						 | 
				
			
			@ -478,7 +476,7 @@ build_unflags = ${common.build_unflags}
 | 
			
		|||
build_flags = ${common.build_flags} ${esp32s3.build_flags}
 | 
			
		||||
  -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
 | 
			
		||||
  -D ARDUINO_USB_CDC_ON_BOOT=0  ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
 | 
			
		||||
  ;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=0 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
 | 
			
		||||
  ;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
 | 
			
		||||
  ;-D WLED_DEBUG
 | 
			
		||||
lib_deps = ${esp32s3.lib_deps}
 | 
			
		||||
board_build.partitions = tools/WLED_ESP32_8MB.csv
 | 
			
		||||
| 
						 | 
				
			
			@ -487,19 +485,18 @@ board_build.flash_mode = qio
 | 
			
		|||
; board_build.flash_mode = dio   ;; try this if you have problems at startup
 | 
			
		||||
monitor_filters = esp32_exception_decoder
 | 
			
		||||
 | 
			
		||||
[env:esp32s3dev_8MB_PSRAM]
 | 
			
		||||
;; ESP32-TinyS3 development board, with 8MB FLASH and 8MB PSRAM (memory_type: qio_opi, qio_qspi, or opi_opi)
 | 
			
		||||
;board = um_tinys3 ;    -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860
 | 
			
		||||
;board = esp32s3box   ; -> error: 'esp32_adc2gpio' was not declared in this scope
 | 
			
		||||
board = esp32-s3-devkitc-1 ; -> compiles, but does not support PSRAM
 | 
			
		||||
[env:esp32s3dev_8MB_PSRAM_opi]
 | 
			
		||||
;; ESP32-S3 development board, with 8MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
 | 
			
		||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
 | 
			
		||||
board_build.arduino.memory_type = qio_opi     ;; use with PSRAM: 8MB or 16MB
 | 
			
		||||
platform = ${esp32s3.platform}
 | 
			
		||||
platform_packages = ${esp32s3.platform_packages}
 | 
			
		||||
upload_speed = 921600
 | 
			
		||||
build_unflags = ${common.build_unflags}
 | 
			
		||||
build_flags = ${common.build_flags} ${esp32s3.build_flags}
 | 
			
		||||
  -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
 | 
			
		||||
  ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
 | 
			
		||||
  -D ARDUINO_USB_CDC_ON_BOOT=1  ;; -D ARDUINO_USB_MODE=0 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
 | 
			
		||||
  ;-D ARDUINO_USB_CDC_ON_BOOT=0  ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
 | 
			
		||||
  -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1      ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
 | 
			
		||||
  ; -D WLED_RELEASE_NAME=ESP32-S3_PSRAM
 | 
			
		||||
  -D WLED_USE_PSRAM -DBOARD_HAS_PSRAM ; tells WLED that PSRAM shall be used
 | 
			
		||||
lib_deps = ${esp32s3.lib_deps}
 | 
			
		||||
| 
						 | 
				
			
			@ -508,6 +505,13 @@ board_build.f_flash = 80000000L
 | 
			
		|||
board_build.flash_mode = qio
 | 
			
		||||
monitor_filters = esp32_exception_decoder
 | 
			
		||||
 | 
			
		||||
[env:esp32s3dev_8MB_PSRAM_qspi]
 | 
			
		||||
;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi)
 | 
			
		||||
extends = env:esp32s3dev_8MB_PSRAM_opi
 | 
			
		||||
;board = um_tinys3 ;    -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860
 | 
			
		||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
 | 
			
		||||
board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or  4MB
 | 
			
		||||
 | 
			
		||||
[env:esp8285_4CH_MagicHome]
 | 
			
		||||
board = esp8285
 | 
			
		||||
platform = ${common.platform_wled_default}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
# Name,   Type, SubType, Offset,  Size, Flags
 | 
			
		||||
nvs,      data, nvs,     0x9000,  0x5000,
 | 
			
		||||
otadata,  data, ota,     0xe000,  0x2000,
 | 
			
		||||
app0,     app,  ota_0,   0x10000, 0x300000,
 | 
			
		||||
app1,     app,  ota_1,   0x310000,0x300000,
 | 
			
		||||
spiffs,   data, spiffs,  0x610000,0x9E0000,
 | 
			
		||||
coredump, data, coredump,,64K
 | 
			
		||||
# to create/use ffat, see https://github.com/marcmerlin/esp32_fatfsimage
 | 
			
		||||
		
		
			
  | 
| 
						 | 
				
			
			@ -3,4 +3,5 @@ nvs,      data, nvs,     0x9000,  0x5000,
 | 
			
		|||
otadata,  data, ota,     0xe000,  0x2000,
 | 
			
		||||
app0,     app,  ota_0,   0x10000, 0x200000,
 | 
			
		||||
app1,     app,  ota_1,   0x210000,0x200000,
 | 
			
		||||
spiffs,   data, spiffs,  0x410000,0x3F0000,
 | 
			
		||||
spiffs,   data, spiffs,  0x410000,0x3E0000,
 | 
			
		||||
coredump, data, coredump,,64K
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		
		
			
  | 
| 
						 | 
				
			
			@ -289,7 +289,6 @@ uint16_t mode_dynamic(void) {
 | 
			
		|||
  if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
 | 
			
		||||
 | 
			
		||||
  if(SEGENV.call == 0) {
 | 
			
		||||
    //SEGMENT.setUpLeds();  //lossless getPixelColor()
 | 
			
		||||
    //SEGMENT.fill(BLACK);
 | 
			
		||||
    for (int i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8();
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -607,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));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1206,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1215,19 +1212,21 @@ uint16_t mode_fireworks() {
 | 
			
		|||
 | 
			
		||||
  bool valid1 = (SEGENV.aux0 < width*height);
 | 
			
		||||
  bool valid2 = (SEGENV.aux1 < width*height);
 | 
			
		||||
  uint8_t x = SEGENV.aux0%width, y = SEGENV.aux0/width; // 2D coordinates stored in upper and lower byte
 | 
			
		||||
  uint32_t sv1 = 0, sv2 = 0;
 | 
			
		||||
  if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
 | 
			
		||||
  if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width) : SEGMENT.getPixelColor(SEGENV.aux1);
 | 
			
		||||
  if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
 | 
			
		||||
  if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1);
 | 
			
		||||
  if (!SEGENV.step) SEGMENT.blur(16);
 | 
			
		||||
  if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
 | 
			
		||||
  if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
 | 
			
		||||
  if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
 | 
			
		||||
  if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
 | 
			
		||||
 | 
			
		||||
  for (int i=0; i<MAX(1, width/20); i++) {
 | 
			
		||||
    if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
 | 
			
		||||
      uint16_t index = random16(width*height);
 | 
			
		||||
      uint16_t j = index % width, k = index / width;
 | 
			
		||||
      x = index % width;
 | 
			
		||||
      y = index / width;
 | 
			
		||||
      uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0);
 | 
			
		||||
      if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(j, k, col);
 | 
			
		||||
      if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col);
 | 
			
		||||
      else                SEGMENT.setPixelColor(index, col);
 | 
			
		||||
      SEGENV.aux1 = SEGENV.aux0;  // old spark
 | 
			
		||||
      SEGENV.aux0 = index;        // remember where spark occured
 | 
			
		||||
| 
						 | 
				
			
			@ -1905,7 +1904,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4586,7 +4584,6 @@ uint16_t mode_2DBlackHole(void) {            // By: Stepko https://editor.soulma
 | 
			
		|||
 | 
			
		||||
  // initialize on first call
 | 
			
		||||
  if (SEGENV.call == 0) {
 | 
			
		||||
    SEGMENT.setUpLeds();
 | 
			
		||||
    SEGMENT.fill(BLACK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4596,22 +4593,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";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -4624,7 +4621,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
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -4678,7 +4674,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4705,7 +4700,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4751,7 +4745,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4783,7 +4776,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4818,7 +4810,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4857,8 +4848,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -4915,7 +4904,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
 | 
			
		|||
    } // i,j
 | 
			
		||||
 | 
			
		||||
    // Rules of Life
 | 
			
		||||
    uint32_t col = prevLeds[XY(x,y)];
 | 
			
		||||
    uint32_t col = uint32_t(prevLeds[XY(x,y)]) & 0x00FFFFFF;  // uint32_t operator returns RGBA, we want RGBW -> cut off "alpha" byte
 | 
			
		||||
    uint32_t bgc = RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0);
 | 
			
		||||
    if      ((col != bgc) && (neighbors <  2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness
 | 
			
		||||
    else if ((col != bgc) && (neighbors >  3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation
 | 
			
		||||
| 
						 | 
				
			
			@ -5124,7 +5113,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5269,7 +5257,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5317,7 +5304,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;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -5367,7 +5353,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5395,7 +5380,6 @@ uint16_t mode_2DSindots(void) {                             // By: ldirko   http
 | 
			
		|||
  const uint16_t rows = SEGMENT.virtualHeight();
 | 
			
		||||
 | 
			
		||||
  if (SEGENV.call == 0) {
 | 
			
		||||
    SEGMENT.setUpLeds();
 | 
			
		||||
    SEGMENT.fill(BLACK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5427,7 +5411,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5470,7 +5453,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5518,7 +5500,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5558,7 +5539,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5627,7 +5607,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -5697,7 +5676,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -5782,7 +5760,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -5948,7 +5925,6 @@ uint16_t mode_2Ddriftrose(void) {
 | 
			
		|||
  const float L = min(cols, rows) / 2.f;
 | 
			
		||||
 | 
			
		||||
  if (SEGENV.call == 0) {
 | 
			
		||||
    SEGMENT.setUpLeds();
 | 
			
		||||
    SEGMENT.fill(BLACK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6103,7 +6079,6 @@ uint16_t mode_2DSwirl(void) {
 | 
			
		|||
  const uint16_t rows = SEGMENT.virtualHeight();
 | 
			
		||||
 | 
			
		||||
  if (SEGENV.call == 0) {
 | 
			
		||||
    SEGMENT.setUpLeds();
 | 
			
		||||
    SEGMENT.fill(BLACK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6150,7 +6125,6 @@ uint16_t mode_2DWaverly(void) {
 | 
			
		|||
  const uint16_t rows = SEGMENT.virtualHeight();
 | 
			
		||||
 | 
			
		||||
  if (SEGENV.call == 0) {
 | 
			
		||||
    SEGMENT.setUpLeds();
 | 
			
		||||
    SEGMENT.fill(BLACK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6379,7 +6353,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6507,7 +6480,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6733,7 +6705,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6802,7 +6773,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6904,7 +6874,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7089,7 +7058,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -7206,7 +7174,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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7419,7 +7386,6 @@ uint16_t mode_2Dsoap() {
 | 
			
		|||
 | 
			
		||||
  // init
 | 
			
		||||
  if (SEGENV.call == 0) {
 | 
			
		||||
    SEGMENT.setUpLeds();
 | 
			
		||||
    *noise32_x = random16();
 | 
			
		||||
    *noise32_y = random16();
 | 
			
		||||
    *noise32_z = random16();
 | 
			
		||||
| 
						 | 
				
			
			@ -7537,12 +7503,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
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										61
									
								
								wled00/FX.h
								
								
								
								
							
							
						
						
									
										61
									
								
								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,9 +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
 | 
			
		||||
    CRGB* leds;     // local leds[] array (may be a pointer to global)
 | 
			
		||||
    static CRGB *_globalLeds;             // global leds[] array
 | 
			
		||||
    byte     *data; // effect data pointer
 | 
			
		||||
    static uint16_t maxWidth, maxHeight;  // these define matrix width & height (max. segment dimensions)
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
| 
						 | 
				
			
			@ -394,10 +392,10 @@ 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
 | 
			
		||||
    // 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
 | 
			
		||||
| 
						 | 
				
			
			@ -408,7 +406,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)
 | 
			
		||||
| 
						 | 
				
			
			@ -463,7 +461,6 @@ typedef struct Segment {
 | 
			
		|||
      aux0(0),
 | 
			
		||||
      aux1(0),
 | 
			
		||||
      data(nullptr),
 | 
			
		||||
      leds(nullptr),
 | 
			
		||||
      _capabilities(0),
 | 
			
		||||
      _dataLen(0),
 | 
			
		||||
      _t(nullptr)
 | 
			
		||||
| 
						 | 
				
			
			@ -484,12 +481,10 @@ typedef struct Segment {
 | 
			
		|||
      //Serial.print(F("Destroying segment:"));
 | 
			
		||||
      //if (name) Serial.printf(" %s (%p)", name, name);
 | 
			
		||||
      //if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
 | 
			
		||||
      //if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
 | 
			
		||||
      //Serial.println();
 | 
			
		||||
      //#endif
 | 
			
		||||
      if (!Segment::_globalLeds && leds) { free(leds); leds = nullptr;} // reset to nullptr, to avoid race conditions
 | 
			
		||||
      if (name) delete[] name;
 | 
			
		||||
      if (_t) delete _t;
 | 
			
		||||
      if (name) { delete[] name; name = nullptr; }
 | 
			
		||||
      if (_t)   { transitional = false; delete _t; _t = nullptr; }
 | 
			
		||||
      deallocateData();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -497,7 +492,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) + (!Segment::_globalLeds && 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); }
 | 
			
		||||
| 
						 | 
				
			
			@ -507,16 +502,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, uint8_t segId = 255);
 | 
			
		||||
    bool    setColor(uint8_t slot, uint32_t c); //returns true if changed
 | 
			
		||||
    void    setCCT(uint16_t k);
 | 
			
		||||
    void    setOpacity(uint8_t o);
 | 
			
		||||
| 
						 | 
				
			
			@ -538,7 +533,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);   // set up leds[] array for loseless getPixelColor()
 | 
			
		||||
 | 
			
		||||
    // transition functions
 | 
			
		||||
    void     startTransition(uint16_t dur); // transition has to start before actual segment values change
 | 
			
		||||
| 
						 | 
				
			
			@ -579,7 +573,7 @@ typedef struct Segment {
 | 
			
		|||
    uint16_t virtualHeight(void) const;
 | 
			
		||||
    uint16_t nrOfVStrips(void) const;
 | 
			
		||||
  #ifndef WLED_DISABLE_2D
 | 
			
		||||
    uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[])
 | 
			
		||||
    uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment
 | 
			
		||||
    void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
 | 
			
		||||
    void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
 | 
			
		||||
    void setPixelColorXY(int x, int y, CRGB c)                             { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
 | 
			
		||||
| 
						 | 
				
			
			@ -692,7 +686,15 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
      customMappingSize(0),
 | 
			
		||||
      _lastShow(0),
 | 
			
		||||
      _segment_index(0),
 | 
			
		||||
      _mainSegment(0)
 | 
			
		||||
      _mainSegment(0),
 | 
			
		||||
      _queuedChangesSegId(255),
 | 
			
		||||
      _qStart(0),
 | 
			
		||||
      _qStop(0),
 | 
			
		||||
      _qStartY(0),
 | 
			
		||||
      _qStopY(0),
 | 
			
		||||
      _qGrouping(0),
 | 
			
		||||
      _qSpacing(0),
 | 
			
		||||
      _qOffset(0)
 | 
			
		||||
    {
 | 
			
		||||
      WS2812FX::instance = this;
 | 
			
		||||
      _mode.reserve(_modeCount);     // allocate memory to prevent initial fragmentation (does not increase size())
 | 
			
		||||
| 
						 | 
				
			
			@ -710,7 +712,6 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
      panel.clear();
 | 
			
		||||
#endif
 | 
			
		||||
      customPalettes.clear();
 | 
			
		||||
      if (useLedsArray && Segment::_globalLeds) {free(Segment::_globalLeds); Segment::_globalLeds = nullptr;} // reset to nullptr, to avoid race conditions
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static WS2812FX* getInstance(void) { return instance; }
 | 
			
		||||
| 
						 | 
				
			
			@ -749,7 +750,7 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
    inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
 | 
			
		||||
    inline void setShowCallback(show_callback cb) { _callback = cb; }
 | 
			
		||||
    inline void setTransition(uint16_t t) { _transitionDur = t; }
 | 
			
		||||
    inline void appendSegment(const Segment &seg = Segment()) { _segments.push_back(seg); }
 | 
			
		||||
    inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
      checkSegmentAlignment(void),
 | 
			
		||||
| 
						 | 
				
			
			@ -757,8 +758,7 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
      hasCCTBus(void),
 | 
			
		||||
      // return true if the strip is being sent pixel updates
 | 
			
		||||
      isUpdating(void),
 | 
			
		||||
      deserializeMap(uint8_t n=0),
 | 
			
		||||
      useLedsArray = false;
 | 
			
		||||
      deserializeMap(uint8_t n=0);
 | 
			
		||||
 | 
			
		||||
    inline bool isServicing(void) { return _isServicing; }
 | 
			
		||||
    inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
 | 
			
		||||
| 
						 | 
				
			
			@ -900,13 +900,20 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
    uint16_t* customMappingTable;
 | 
			
		||||
    uint16_t  customMappingSize;
 | 
			
		||||
 | 
			
		||||
    uint32_t _lastShow;
 | 
			
		||||
    unsigned long _lastShow;
 | 
			
		||||
 | 
			
		||||
    uint8_t _segment_index;
 | 
			
		||||
    uint8_t _mainSegment;
 | 
			
		||||
    uint8_t _queuedChangesSegId;
 | 
			
		||||
    uint16_t _qStart, _qStop, _qStartY, _qStopY;
 | 
			
		||||
    uint8_t _qGrouping, _qSpacing;
 | 
			
		||||
    uint16_t _qOffset;
 | 
			
		||||
 | 
			
		||||
    uint8_t
 | 
			
		||||
      estimateCurrentAndLimitBri(void);
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
      estimateCurrentAndLimitBri(void);
 | 
			
		||||
      setUpSegmentFromQueuedChanges(void);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const char JSON_mode_names[];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,8 +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) {
 | 
			
		||||
  int i = XY(x,y);
 | 
			
		||||
  if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0);
 | 
			
		||||
  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
 | 
			
		||||
| 
						 | 
				
			
			@ -306,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -325,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();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -358,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();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -385,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -437,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -454,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -489,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -513,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++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -526,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++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -535,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -559,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();
 | 
			
		||||
| 
						 | 
				
			
			@ -594,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,6 @@
 | 
			
		|||
// Segment class implementation
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
 | 
			
		||||
CRGB    *Segment::_globalLeds = nullptr;
 | 
			
		||||
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
 | 
			
		||||
uint16_t Segment::maxHeight = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,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;
 | 
			
		||||
  if (leds && !Segment::_globalLeds) 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 && !Segment::_globalLeds && length() > 0) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*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;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,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 && !Segment::_globalLeds) {free(leds); leds=nullptr;} 
 | 
			
		||||
    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;
 | 
			
		||||
    if (!Segment::_globalLeds) 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 && !Segment::_globalLeds && length() > 0) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
 | 
			
		||||
    //if (orig._t)   { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
 | 
			
		||||
  }
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -134,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
 | 
			
		||||
    transitional = false; // just temporary
 | 
			
		||||
    if (name) { delete[] name; name = nullptr; } // free old name
 | 
			
		||||
    deallocateData(); // free old runtime data
 | 
			
		||||
    if (_t) delete _t;
 | 
			
		||||
    if (leds && !Segment::_globalLeds) {free(leds); leds=nullptr;}
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -153,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,31 +174,11 @@ void Segment::deallocateData() {
 | 
			
		|||
  * may free that data buffer.
 | 
			
		||||
  */
 | 
			
		||||
void Segment::resetIfRequired() {
 | 
			
		||||
  if (reset) {
 | 
			
		||||
    if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
 | 
			
		||||
    //if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
 | 
			
		||||
    deallocateData();
 | 
			
		||||
    next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
 | 
			
		||||
    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 (Segment::_globalLeds)
 | 
			
		||||
    #ifndef WLED_DISABLE_2D
 | 
			
		||||
    leds = &Segment::_globalLeds[start + startY*Segment::maxWidth];
 | 
			
		||||
    #else
 | 
			
		||||
    leds = &Segment::_globalLeds[start];
 | 
			
		||||
    #endif
 | 
			
		||||
  else 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 = (CRGB*)malloc(sizeof(CRGB)*length());
 | 
			
		||||
  }
 | 
			
		||||
  if (!reset) return;
 | 
			
		||||
  
 | 
			
		||||
  deallocateData();
 | 
			
		||||
  next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
 | 
			
		||||
  reset = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
 | 
			
		||||
| 
						 | 
				
			
			@ -331,7 +303,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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -360,7 +332,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
 | 
			
		||||
| 
						 | 
				
			
			@ -381,8 +353,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
 | 
			
		||||
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
 | 
			
		||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t segId) {
 | 
			
		||||
  // 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
 | 
			
		||||
| 
						 | 
				
			
			@ -391,10 +364,22 @@ 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 (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) return;
 | 
			
		||||
 | 
			
		||||
  // apply change immediately
 | 
			
		||||
  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
 | 
			
		||||
| 
						 | 
				
			
			@ -407,13 +392,12 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
 | 
			
		|||
    stopY = i2Y > Segment::maxHeight ? Segment::maxHeight : MAX(1,i2Y);
 | 
			
		||||
  }
 | 
			
		||||
  #endif
 | 
			
		||||
  if (grp) {
 | 
			
		||||
    grouping = grp;
 | 
			
		||||
    spacing = spc;
 | 
			
		||||
  // safety check
 | 
			
		||||
  if (start >= stop || startY >= stopY) {
 | 
			
		||||
    stop = 0;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (ofs < UINT16_MAX) offset = ofs;
 | 
			
		||||
  markForReset();
 | 
			
		||||
  if (!boundsUnchanged) refreshLightCapabilities();
 | 
			
		||||
  refreshLightCapabilities();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -460,8 +444,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
 | 
			
		||||
| 
						 | 
				
			
			@ -546,8 +529,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -555,6 +537,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
 | 
			
		||||
| 
						 | 
				
			
			@ -622,8 +605,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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -665,6 +646,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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -696,6 +678,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
 | 
			
		||||
| 
						 | 
				
			
			@ -723,8 +706,6 @@ uint32_t Segment::getPixelColor(int i)
 | 
			
		|||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0);
 | 
			
		||||
 | 
			
		||||
  if (reverse) i = virtualLength() - i - 1;
 | 
			
		||||
  i *= groupLength();
 | 
			
		||||
  i += start;
 | 
			
		||||
| 
						 | 
				
			
			@ -765,6 +746,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++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -809,6 +795,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++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -824,6 +811,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -842,6 +830,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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -850,6 +839,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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -887,7 +877,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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -902,7 +892,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
 | 
			
		||||
| 
						 | 
				
			
			@ -1068,24 +1058,6 @@ void WS2812FX::finalizeInit(void)
 | 
			
		|||
    Segment::maxHeight = 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //initialize leds array. TBD: realloc if nr of leds change
 | 
			
		||||
  if (Segment::_globalLeds) {
 | 
			
		||||
    purgeSegments(true);
 | 
			
		||||
    free(Segment::_globalLeds);
 | 
			
		||||
    Segment::_globalLeds = nullptr;
 | 
			
		||||
  }
 | 
			
		||||
  if (useLedsArray) {
 | 
			
		||||
    size_t arrSize = sizeof(CRGB) * getLengthTotal();
 | 
			
		||||
    // softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards (see setUpLeds())
 | 
			
		||||
    //#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
 | 
			
		||||
    //if (psramFound())
 | 
			
		||||
    //  Segment::_globalLeds = (CRGB*) ps_malloc(arrSize);
 | 
			
		||||
    //else
 | 
			
		||||
    //#endif
 | 
			
		||||
      Segment::_globalLeds = (CRGB*) malloc(arrSize);
 | 
			
		||||
    if (Segment::_globalLeds && (arrSize > 0)) memset(Segment::_globalLeds, 0, arrSize);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //segments are created in makeAutoSegments();
 | 
			
		||||
  DEBUG_PRINTLN(F("Loading custom palettes"));
 | 
			
		||||
  loadCustomPalettes(); // (re)load all custom palettes
 | 
			
		||||
| 
						 | 
				
			
			@ -1094,7 +1066,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1107,12 +1079,9 @@ void WS2812FX::service() {
 | 
			
		|||
    // reset the segment runtime data if needed
 | 
			
		||||
    seg.resetIfRequired();
 | 
			
		||||
 | 
			
		||||
    if (!seg.isActive()) continue;
 | 
			
		||||
 | 
			
		||||
    // 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.isActive() && (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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1136,16 +1105,24 @@ void WS2812FX::service() {
 | 
			
		|||
 | 
			
		||||
      seg.next_time = nowUp + delay;
 | 
			
		||||
    }
 | 
			
		||||
    if (_segment_index == _queuedChangesSegId) setUpSegmentFromQueuedChanges();
 | 
			
		||||
    _segment_index++;
 | 
			
		||||
  }
 | 
			
		||||
  _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)
 | 
			
		||||
| 
						 | 
				
			
			@ -1174,7 +1151,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
 | 
			
		|||
#define MA_FOR_ESP        100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
 | 
			
		||||
                              //you can set it to 0 if the ESP is powered by USB and the LEDs by external
 | 
			
		||||
 | 
			
		||||
void WS2812FX::estimateCurrentAndLimitBri() {
 | 
			
		||||
uint8_t WS2812FX::estimateCurrentAndLimitBri() {
 | 
			
		||||
  //power limit calculation
 | 
			
		||||
  //each LED can draw up 195075 "power units" (approx. 53mA)
 | 
			
		||||
  //one PU is the power it takes to have 1 channel 1 step brighter per brightness step
 | 
			
		||||
| 
						 | 
				
			
			@ -1182,35 +1159,28 @@ void WS2812FX::estimateCurrentAndLimitBri() {
 | 
			
		|||
  bool useWackyWS2815PowerModel = false;
 | 
			
		||||
  byte actualMilliampsPerLed = milliampsPerLed;
 | 
			
		||||
 | 
			
		||||
  if(milliampsPerLed == 255) {
 | 
			
		||||
  if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
 | 
			
		||||
    currentMilliamps = 0;
 | 
			
		||||
    return _brightness;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
    busses.setBrightness(_brightness);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint32_t powerSum = 0;
 | 
			
		||||
  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);
 | 
			
		||||
      uint32_t c = bus->getPixelColor(i); // always returns original or restored color without brightness scaling
 | 
			
		||||
      byte r = R(c), g = G(c), b = B(c), w = W(c);
 | 
			
		||||
 | 
			
		||||
      if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation
 | 
			
		||||
| 
						 | 
				
			
			@ -1222,51 +1192,75 @@ void 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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint32_t powerSum0 = powerSum;
 | 
			
		||||
  //powerSum *= _brightness; // for NPBrightnessBus
 | 
			
		||||
  powerSum *= 255;           // no need to scale down powerSum - NPB-LG getPixelColor returns colors scaled down by 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
 | 
			
		||||
  {
 | 
			
		||||
    float scale = (float)powerBudget / (float)powerSum;
 | 
			
		||||
  // 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 * 255) / (float)(powerSum * _brightness);
 | 
			
		||||
    uint16_t scaleI = scale * 255;
 | 
			
		||||
    uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
 | 
			
		||||
    uint8_t newBri = scale8(_brightness, scaleB);
 | 
			
		||||
    // to keep brightness uniform, sets virtual busses too - softhack007: apply reductions immediately
 | 
			
		||||
    if (scaleB < 255) busses.setBrightness(scaleB, true); // NPB-LG has already applied brightness, so its suffifient to post-apply scaling ==> use scaleB instead of newBri
 | 
			
		||||
    busses.setBrightness(newBri, false);                  // set new brightness for next frame
 | 
			
		||||
    //currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; // for NPBrightnessBus
 | 
			
		||||
    currentMilliamps = (powerSum0 * scaleB) / puPerMilliamp;   // for NPBus-LG
 | 
			
		||||
  } else {
 | 
			
		||||
    currentMilliamps = powerSum / puPerMilliamp;
 | 
			
		||||
    busses.setBrightness(_brightness, false);            // set new brightness for next frame
 | 
			
		||||
    newBri = scale8(_brightness, scaleB) + 1;
 | 
			
		||||
  }
 | 
			
		||||
  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();
 | 
			
		||||
 | 
			
		||||
  estimateCurrentAndLimitBri();
 | 
			
		||||
  #ifdef WLED_DEBUG
 | 
			
		||||
  static unsigned long sumMicros = 0, sumCurrent = 0;
 | 
			
		||||
  static size_t calls = 0;
 | 
			
		||||
  unsigned long microsStart = micros();
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  uint8_t newBri = estimateCurrentAndLimitBri();
 | 
			
		||||
  busses.setBrightness(newBri); // "repaints" all pixels if brightness changed
 | 
			
		||||
 | 
			
		||||
  #ifdef WLED_DEBUG
 | 
			
		||||
  sumCurrent += micros() - microsStart;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  // some buses send asynchronously and this method will return before
 | 
			
		||||
  // all of the data has been sent.
 | 
			
		||||
  // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
 | 
			
		||||
  busses.show();
 | 
			
		||||
 | 
			
		||||
  // restore bus brightness to its original value
 | 
			
		||||
  // this is done right after show, so this is only OK if LED updates are completed before show() returns
 | 
			
		||||
  // or async show has a separate buffer (ESP32 RMT and I2S are ok)
 | 
			
		||||
  if (newBri < _brightness) busses.setBrightness(_brightness);
 | 
			
		||||
 | 
			
		||||
  #ifdef WLED_DEBUG
 | 
			
		||||
  sumMicros += micros() - microsStart;
 | 
			
		||||
  if (++calls == 100) {
 | 
			
		||||
    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();
 | 
			
		||||
  unsigned long diff = now - _lastShow;
 | 
			
		||||
  uint16_t fpsCurr = 200;
 | 
			
		||||
  size_t diff = now - _lastShow;
 | 
			
		||||
  size_t fpsCurr = 200;
 | 
			
		||||
  if (diff > 0) fpsCurr = 1000 / diff;
 | 
			
		||||
  _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2;
 | 
			
		||||
  _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2;   // "+2" for proper rounding (2/4 = 0.5)
 | 
			
		||||
  _lastShow = now;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1323,6 +1317,8 @@ void WS2812FX::setCCT(uint16_t k) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// direct=true either expects the caller to call show() themselves (realtime modes) or be ok waiting for the next frame for the change to apply
 | 
			
		||||
// direct=false immediately triggers an effect redraw
 | 
			
		||||
void WS2812FX::setBrightness(uint8_t b, bool direct) {
 | 
			
		||||
  if (gammaCorrectBri) b = gamma8(b);
 | 
			
		||||
  if (_brightness == b) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1332,12 +1328,12 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
 | 
			
		|||
      seg.freeze = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (direct) {
 | 
			
		||||
    // would be dangerous if applied immediately (could exceed ABL), but will not output until the next show()
 | 
			
		||||
    busses.setBrightness(b);
 | 
			
		||||
  } else {
 | 
			
		||||
  // setting brightness with NeoPixelBusLg has no effect on already painted pixels,
 | 
			
		||||
  // so we need to force an update to existing buffer
 | 
			
		||||
  busses.setBrightness(b);
 | 
			
		||||
  if (!direct) {
 | 
			
		||||
    unsigned long t = millis();
 | 
			
		||||
    if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
 | 
			
		||||
    if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1444,9 +1440,32 @@ Segment& WS2812FX::getSegment(uint8_t id) {
 | 
			
		|||
  return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
// sets new segment bounds, queues if that segment is currently running
 | 
			
		||||
void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
 | 
			
		||||
  if (segId >= getSegmentsNum()) {
 | 
			
		||||
    if (i2 <= i1) return; // do not append empty/inactive segments
 | 
			
		||||
    appendSegment(Segment(0, strip.getLengthTotal()));
 | 
			
		||||
    segId = getSegmentsNum()-1; // segments are added at the end of list
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (_queuedChangesSegId == segId) _queuedChangesSegId = 255; // cancel queued change if already queued for this segment
 | 
			
		||||
 | 
			
		||||
  if (segId < getMaxSegments() && segId == getCurrSegmentId() && isServicing()) { // queue change to prevent concurrent access
 | 
			
		||||
    // queuing a change for a second segment will lead to the loss of the first change if not yet applied
 | 
			
		||||
    // however this is not a problem as the queued change is applied immediately after the effect function in that segment returns
 | 
			
		||||
    _qStart  = i1; _qStop   = i2; _qStartY = startY; _qStopY  = stopY;
 | 
			
		||||
    _qGrouping = grouping; _qSpacing  = spacing; _qOffset   = offset;
 | 
			
		||||
    _queuedChangesSegId = segId;
 | 
			
		||||
    return; // queued changes are applied immediately after effect function returns
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  _segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WS2812FX::setUpSegmentFromQueuedChanges() {
 | 
			
		||||
  if (_queuedChangesSegId >= getSegmentsNum()) return;
 | 
			
		||||
  getSegment(_queuedChangesSegId).setUp(_qStart, _qStop, _qGrouping, _qSpacing, _qOffset, _qStartY, _qStopY);
 | 
			
		||||
  _queuedChangesSegId = 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WS2812FX::restartRuntime() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1614,7 +1633,7 @@ void WS2812FX::printSize() {
 | 
			
		|||
  DEBUG_PRINTF("Data: %d*%d=%uB\n", sizeof(const char *), _modeData.size(), (_modeData.capacity()*sizeof(const char *)));
 | 
			
		||||
  DEBUG_PRINTF("Map: %d*%d=%uB\n", sizeof(uint16_t), (int)customMappingSize, customMappingSize*sizeof(uint16_t));
 | 
			
		||||
  size = getLengthTotal();
 | 
			
		||||
  if (useLedsArray) DEBUG_PRINTF("Buffer: %d*%u=%uB\n", sizeof(CRGB), size, size*sizeof(CRGB));
 | 
			
		||||
  if (useGlobalLedBuffer) DEBUG_PRINTF("Buffer: %d*%u=%uB\n", sizeof(CRGB), size, size*sizeof(CRGB));
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,96 +91,168 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) {
 | 
			
		|||
  return RGBW32(r, g, b, w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t *Bus::allocData(size_t size) {
 | 
			
		||||
  if (_data) free(_data); // should not happen, but for safety
 | 
			
		||||
  return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _colorOrderMap(com) {
 | 
			
		||||
 | 
			
		||||
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
 | 
			
		||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
 | 
			
		||||
, _skip(bc.skipAmount) //sacrificial pixels
 | 
			
		||||
, _colorOrder(bc.colorOrder)
 | 
			
		||||
, _colorOrderMap(com)
 | 
			
		||||
{
 | 
			
		||||
  if (!IS_DIGITAL(bc.type) || !bc.count) return;
 | 
			
		||||
  if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
 | 
			
		||||
  _frequencykHz = 0U;
 | 
			
		||||
  _pins[0] = bc.pins[0];
 | 
			
		||||
  if (IS_2PIN(bc.type)) {
 | 
			
		||||
    if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
 | 
			
		||||
    cleanup(); return;
 | 
			
		||||
      cleanup();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    _pins[1] = bc.pins[1];
 | 
			
		||||
    _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined
 | 
			
		||||
  }
 | 
			
		||||
  reversed = bc.reversed;
 | 
			
		||||
  _needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
 | 
			
		||||
  _skip = bc.skipAmount;    //sacrificial pixels
 | 
			
		||||
  _len = bc.count + _skip;
 | 
			
		||||
  _iType = PolyBus::getI(bc.type, _pins, nr);
 | 
			
		||||
  if (_iType == I_NONE) return;
 | 
			
		||||
  uint16_t lenToCreate = _len;
 | 
			
		||||
  if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus 
 | 
			
		||||
  _busPtr = PolyBus::create(_iType, _pins, lenToCreate, nr, _frequencykHz);
 | 
			
		||||
  if (bc.doubleBuffer && !allocData(bc.count * (Bus::hasWhite(_type) + 3*Bus::hasRGB(_type)))) return; //warning: hardcoded channel count
 | 
			
		||||
  _buffering = bc.doubleBuffer;
 | 
			
		||||
  uint16_t lenToCreate = bc.count;
 | 
			
		||||
  if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
 | 
			
		||||
  _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz);
 | 
			
		||||
  _valid = (_busPtr != nullptr);
 | 
			
		||||
  _colorOrder = bc.colorOrder;
 | 
			
		||||
  DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, _len, bc.type, _pins[0],_pins[1],_iType);
 | 
			
		||||
  DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], _pins[1], _iType);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BusDigital::show() {
 | 
			
		||||
  PolyBus::show(_busPtr, _iType);
 | 
			
		||||
  if (!_valid) return;
 | 
			
		||||
  if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop
 | 
			
		||||
    size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
 | 
			
		||||
    for (size_t i=0; i<_len; i++) {
 | 
			
		||||
      size_t offset = i*channels;
 | 
			
		||||
      uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder);
 | 
			
		||||
      uint32_t c;
 | 
			
		||||
      if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs (_len is always a multiple of 3)
 | 
			
		||||
        switch (i%3) {
 | 
			
		||||
          case 0: c = RGBW32(_data[offset]  , _data[offset+1], _data[offset+2], 0); break;
 | 
			
		||||
          case 1: c = RGBW32(_data[offset-1], _data[offset]  , _data[offset+1], 0); break;
 | 
			
		||||
          case 2: c = RGBW32(_data[offset-2], _data[offset-1], _data[offset]  , 0); break;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        c = RGBW32(_data[offset],_data[offset+1],_data[offset+2],(Bus::hasWhite(_type)?_data[offset+3]:0));
 | 
			
		||||
      }
 | 
			
		||||
      uint16_t pix = i;
 | 
			
		||||
      if (_reversed) pix  = _len - pix -1;
 | 
			
		||||
      else           pix += _skip;
 | 
			
		||||
      PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BusDigital::canShow() {
 | 
			
		||||
  if (!_valid) return true;
 | 
			
		||||
  return PolyBus::canShow(_busPtr, _iType);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BusDigital::setBrightness(uint8_t b, bool immediate) {
 | 
			
		||||
void BusDigital::setBrightness(uint8_t b) {
 | 
			
		||||
  if (_bri == b) return;
 | 
			
		||||
  //Fix for turning off onboard LED breaking bus
 | 
			
		||||
  #ifdef LED_BUILTIN
 | 
			
		||||
  if (_bri == 0 && b > 0) {
 | 
			
		||||
    if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
 | 
			
		||||
  if (_bri == 0) { // && b > 0, covered by guard if above
 | 
			
		||||
    if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) reinit();
 | 
			
		||||
  }
 | 
			
		||||
  #endif
 | 
			
		||||
  Bus::setBrightness(b, immediate);
 | 
			
		||||
  PolyBus::setBrightness(_busPtr, _iType, b, immediate);
 | 
			
		||||
  uint8_t prevBri = _bri;
 | 
			
		||||
  Bus::setBrightness(b);
 | 
			
		||||
  PolyBus::setBrightness(_busPtr, _iType, b);
 | 
			
		||||
 | 
			
		||||
  if (_buffering) return;
 | 
			
		||||
 | 
			
		||||
  // must update/repaint every LED in the NeoPixelBus buffer to the new brightness
 | 
			
		||||
  // the only case where repainting is unnecessary is when all pixels are set after the brightness change but before the next show
 | 
			
		||||
  // (which we can't rely on)
 | 
			
		||||
  uint16_t hwLen = _len;
 | 
			
		||||
  if (_type == TYPE_WS2812_1CH_X3) hwLen = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
 | 
			
		||||
  for (uint_fast16_t i = 0; i < hwLen; i++) {
 | 
			
		||||
    // use 0 as color order, actual order does not matter here as we just update the channel values as-is
 | 
			
		||||
    uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, i, 0),prevBri);
 | 
			
		||||
    PolyBus::setPixelColor(_busPtr, _iType, i, c, 0);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//If LEDs are skipped, it is possible to use the first as a status LED.
 | 
			
		||||
//TODO only show if no new show due in the next 50ms
 | 
			
		||||
void BusDigital::setStatusPixel(uint32_t c) {
 | 
			
		||||
  if (_skip && canShow()) {
 | 
			
		||||
  if (_valid && _skip) {
 | 
			
		||||
    PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
 | 
			
		||||
    PolyBus::show(_busPtr, _iType);
 | 
			
		||||
    if (canShow()) PolyBus::show(_busPtr, _iType);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
 | 
			
		||||
  if (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814 || _type == TYPE_WS2812_1CH_X3) c = autoWhiteCalc(c);
 | 
			
		||||
  if (!_valid) return;
 | 
			
		||||
  if (Bus::hasWhite(_type)) c = autoWhiteCalc(c);
 | 
			
		||||
  if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
 | 
			
		||||
  if (reversed) pix = _len - pix -1;
 | 
			
		||||
  else pix += _skip;
 | 
			
		||||
  uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
 | 
			
		||||
  if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
 | 
			
		||||
    uint16_t pOld = pix;
 | 
			
		||||
    pix = IC_INDEX_WS2812_1CH_3X(pix);
 | 
			
		||||
    uint32_t cOld = PolyBus::getPixelColor(_busPtr, _iType, pix, co);
 | 
			
		||||
    switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set)
 | 
			
		||||
      case 0: c = RGBW32(R(cOld), W(c)   , B(cOld), 0); break;
 | 
			
		||||
      case 1: c = RGBW32(W(c)   , G(cOld), B(cOld), 0); break;
 | 
			
		||||
      case 2: c = RGBW32(R(cOld), G(cOld), W(c)   , 0); break;
 | 
			
		||||
  if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop
 | 
			
		||||
    size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
 | 
			
		||||
    size_t offset = pix*channels;
 | 
			
		||||
    if (Bus::hasRGB(_type)) {
 | 
			
		||||
      _data[offset++] = R(c);
 | 
			
		||||
      _data[offset++] = G(c);
 | 
			
		||||
      _data[offset++] = B(c);
 | 
			
		||||
    }
 | 
			
		||||
    if (Bus::hasWhite(_type)) _data[offset] = W(c);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (_reversed) pix  = _len - pix -1;
 | 
			
		||||
    else           pix += _skip;
 | 
			
		||||
    uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
 | 
			
		||||
    if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
 | 
			
		||||
      uint16_t pOld = pix;
 | 
			
		||||
      pix = IC_INDEX_WS2812_1CH_3X(pix);
 | 
			
		||||
      uint32_t cOld = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co),_bri);
 | 
			
		||||
      switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set)
 | 
			
		||||
        case 0: c = RGBW32(R(cOld), W(c)   , B(cOld), 0); break;
 | 
			
		||||
        case 1: c = RGBW32(W(c)   , G(cOld), B(cOld), 0); break;
 | 
			
		||||
        case 2: c = RGBW32(R(cOld), G(cOld), W(c)   , 0); break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
 | 
			
		||||
  }
 | 
			
		||||
  PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns original color if global buffering is enabled, else returns lossly restored color from bus
 | 
			
		||||
uint32_t BusDigital::getPixelColor(uint16_t pix) {
 | 
			
		||||
  if (reversed) pix = _len - pix -1;
 | 
			
		||||
  else pix += _skip;
 | 
			
		||||
  uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
 | 
			
		||||
  if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
 | 
			
		||||
    uint16_t pOld = pix;
 | 
			
		||||
    pix = IC_INDEX_WS2812_1CH_3X(pix);
 | 
			
		||||
    uint32_t c = PolyBus::getPixelColor(_busPtr, _iType, pix, co);
 | 
			
		||||
    switch (pOld % 3) { // get only the single channel
 | 
			
		||||
      case 0: c = RGBW32(G(c), G(c), G(c), G(c)); break;
 | 
			
		||||
      case 1: c = RGBW32(R(c), R(c), R(c), R(c)); break;
 | 
			
		||||
      case 2: c = RGBW32(B(c), B(c), B(c), B(c)); break;
 | 
			
		||||
  if (!_valid) return 0;
 | 
			
		||||
  if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop
 | 
			
		||||
    size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
 | 
			
		||||
    size_t offset = pix*channels;
 | 
			
		||||
    uint32_t c;
 | 
			
		||||
    if (!Bus::hasRGB(_type)) {
 | 
			
		||||
      c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]);
 | 
			
		||||
    } else {
 | 
			
		||||
      c = RGBW32(_data[offset], _data[offset+1], _data[offset+2], Bus::hasWhite(_type) ? _data[offset+3] : 0);
 | 
			
		||||
    }
 | 
			
		||||
    return c;
 | 
			
		||||
  } else {
 | 
			
		||||
    if (_reversed) pix  = _len - pix -1;
 | 
			
		||||
    else           pix += _skip;
 | 
			
		||||
    uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
 | 
			
		||||
    uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
 | 
			
		||||
    if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
 | 
			
		||||
      uint8_t r = R(c);
 | 
			
		||||
      uint8_t g = _reversed ? B(c) : G(c); // should G and B be switched if _reversed?
 | 
			
		||||
      uint8_t b = _reversed ? G(c) : B(c);
 | 
			
		||||
      switch (pix % 3) { // get only the single channel
 | 
			
		||||
        case 0: c = RGBW32(g, g, g, g); break;
 | 
			
		||||
        case 1: c = RGBW32(r, r, r, r); break;
 | 
			
		||||
        case 2: c = RGBW32(b, b, b, b); break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return c;
 | 
			
		||||
  }
 | 
			
		||||
  return PolyBus::getPixelColor(_busPtr, _iType, pix, co);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t BusDigital::getPins(uint8_t* pinArray) {
 | 
			
		||||
| 
						 | 
				
			
			@ -196,6 +268,7 @@ void BusDigital::setColorOrder(uint8_t colorOrder) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void BusDigital::reinit() {
 | 
			
		||||
  if (!_valid) return;
 | 
			
		||||
  PolyBus::begin(_busPtr, _iType, _pins);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -205,13 +278,15 @@ void BusDigital::cleanup() {
 | 
			
		|||
  _iType = I_NONE;
 | 
			
		||||
  _valid = false;
 | 
			
		||||
  _busPtr = nullptr;
 | 
			
		||||
  if (_data != nullptr) freeData();
 | 
			
		||||
  pinManager.deallocatePin(_pins[1], PinOwner::BusDigital);
 | 
			
		||||
  pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		||||
  _valid = false;
 | 
			
		||||
BusPwm::BusPwm(BusConfig &bc)
 | 
			
		||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
 | 
			
		||||
{
 | 
			
		||||
  if (!IS_PWM(bc.type)) return;
 | 
			
		||||
  uint8_t numPins = NUM_PWM_PINS(bc.type);
 | 
			
		||||
  _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ;
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +304,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		|||
  for (uint8_t i = 0; i < numPins; i++) {
 | 
			
		||||
    uint8_t currentPin = bc.pins[i];
 | 
			
		||||
    if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) {
 | 
			
		||||
    deallocatePins(); return;
 | 
			
		||||
      deallocatePins(); return;
 | 
			
		||||
    }
 | 
			
		||||
    _pins[i] = currentPin; //store only after allocatePin() succeeds
 | 
			
		||||
    #ifdef ESP8266
 | 
			
		||||
| 
						 | 
				
			
			@ -239,7 +314,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		|||
    ledcAttachPin(_pins[i], _ledcStart + i);
 | 
			
		||||
    #endif
 | 
			
		||||
  }
 | 
			
		||||
  reversed = bc.reversed;
 | 
			
		||||
  _data = _pwmdata; // avoid malloc() and use stack
 | 
			
		||||
  _valid = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -307,7 +382,7 @@ void BusPwm::show() {
 | 
			
		|||
  uint8_t numPins = NUM_PWM_PINS(_type);
 | 
			
		||||
  for (uint8_t i = 0; i < numPins; i++) {
 | 
			
		||||
    uint8_t scaled = (_data[i] * _bri) / 255;
 | 
			
		||||
    if (reversed) scaled = 255 - scaled;
 | 
			
		||||
    if (_reversed) scaled = 255 - scaled;
 | 
			
		||||
    #ifdef ESP8266
 | 
			
		||||
    analogWrite(_pins[i], scaled);
 | 
			
		||||
    #else
 | 
			
		||||
| 
						 | 
				
			
			@ -342,8 +417,10 @@ void BusPwm::deallocatePins() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		||||
  _valid = false;
 | 
			
		||||
BusOnOff::BusOnOff(BusConfig &bc)
 | 
			
		||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
 | 
			
		||||
, _onoffdata(0)
 | 
			
		||||
{
 | 
			
		||||
  if (bc.type != TYPE_ONOFF) return;
 | 
			
		||||
 | 
			
		||||
  uint8_t currentPin = bc.pins[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +429,7 @@ BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		|||
  }
 | 
			
		||||
  _pin = currentPin; //store only after allocatePin() succeeds
 | 
			
		||||
  pinMode(_pin, OUTPUT);
 | 
			
		||||
  reversed = bc.reversed;
 | 
			
		||||
  _data = &_onoffdata; // avoid malloc() and use stack
 | 
			
		||||
  _valid = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -363,18 +440,17 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
 | 
			
		|||
  uint8_t g = G(c);
 | 
			
		||||
  uint8_t b = B(c);
 | 
			
		||||
  uint8_t w = W(c);
 | 
			
		||||
 | 
			
		||||
  _data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
 | 
			
		||||
  _data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) {
 | 
			
		||||
  if (!_valid) return 0;
 | 
			
		||||
  return RGBW32(_data, _data, _data, _data);
 | 
			
		||||
  return RGBW32(_data[0], _data[0], _data[0], _data[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BusOnOff::show() {
 | 
			
		||||
  if (!_valid) return;
 | 
			
		||||
  digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data);
 | 
			
		||||
  digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t BusOnOff::getPins(uint8_t* pinArray) {
 | 
			
		||||
| 
						 | 
				
			
			@ -384,8 +460,10 @@ uint8_t BusOnOff::getPins(uint8_t* pinArray) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		||||
  _valid = false;
 | 
			
		||||
BusNetwork::BusNetwork(BusConfig &bc)
 | 
			
		||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
 | 
			
		||||
, _broadcastLock(false)
 | 
			
		||||
{
 | 
			
		||||
  switch (bc.type) {
 | 
			
		||||
    case TYPE_NET_ARTNET_RGB:
 | 
			
		||||
      _rgbw = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -401,18 +479,13 @@ BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
 | 
			
		|||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  _UDPchannels = _rgbw ? 4 : 3;
 | 
			
		||||
  _data = (byte *)malloc(bc.count * _UDPchannels);
 | 
			
		||||
  if (_data == nullptr) return;
 | 
			
		||||
  memset(_data, 0, bc.count * _UDPchannels);
 | 
			
		||||
  _len = bc.count;
 | 
			
		||||
  _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
 | 
			
		||||
  _broadcastLock = false;
 | 
			
		||||
  _valid = true;
 | 
			
		||||
  _valid = (allocData(_len * _UDPchannels) != nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
 | 
			
		||||
  if (!_valid || pix >= _len) return;
 | 
			
		||||
  if (hasWhite()) c = autoWhiteCalc(c);
 | 
			
		||||
  if (_rgbw) c = autoWhiteCalc(c);
 | 
			
		||||
  if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
 | 
			
		||||
  uint16_t offset = pix * _UDPchannels;
 | 
			
		||||
  _data[offset]   = R(c);
 | 
			
		||||
| 
						 | 
				
			
			@ -424,7 +497,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
 | 
			
		|||
uint32_t BusNetwork::getPixelColor(uint16_t pix) {
 | 
			
		||||
  if (!_valid || pix >= _len) return 0;
 | 
			
		||||
  uint16_t offset = pix * _UDPchannels;
 | 
			
		||||
  return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0);
 | 
			
		||||
  return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (_rgbw ? _data[offset+3] : 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BusNetwork::show() {
 | 
			
		||||
| 
						 | 
				
			
			@ -444,8 +517,7 @@ uint8_t BusNetwork::getPins(uint8_t* pinArray) {
 | 
			
		|||
void BusNetwork::cleanup() {
 | 
			
		||||
  _type = I_NONE;
 | 
			
		||||
  _valid = false;
 | 
			
		||||
  if (_data != nullptr) free(_data);
 | 
			
		||||
  _data = nullptr;
 | 
			
		||||
  freeData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -506,7 +578,7 @@ void BusManager::setStatusPixel(uint32_t c) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {
 | 
			
		||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) {
 | 
			
		||||
  for (uint8_t i = 0; i < numBusses; i++) {
 | 
			
		||||
    Bus* b = busses[i];
 | 
			
		||||
    uint16_t bstart = b->getStart();
 | 
			
		||||
| 
						 | 
				
			
			@ -515,9 +587,9 @@ void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct)
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BusManager::setBrightness(uint8_t b, bool immediate) {
 | 
			
		||||
void BusManager::setBrightness(uint8_t b) {
 | 
			
		||||
  for (uint8_t i = 0; i < numBusses; i++) {
 | 
			
		||||
    busses[i]->setBrightness(b, immediate);
 | 
			
		||||
    busses[i]->setBrightness(b);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,10 @@
 | 
			
		|||
#define IC_INDEX_WS2812_2CH_3X(i)  ((i)*2/3)
 | 
			
		||||
#define WS2812_2CH_3X_SPANS_2_ICS(i) ((i)&0x01)    // every other LED zone is on two different ICs
 | 
			
		||||
 | 
			
		||||
// flag for using double buffering in BusDigital
 | 
			
		||||
extern bool useGlobalLedBuffer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//temporary struct for passing bus configuration to bus
 | 
			
		||||
struct BusConfig {
 | 
			
		||||
  uint8_t type;
 | 
			
		||||
| 
						 | 
				
			
			@ -30,15 +34,25 @@ struct BusConfig {
 | 
			
		|||
  uint8_t autoWhite;
 | 
			
		||||
  uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
 | 
			
		||||
  uint16_t frequency;
 | 
			
		||||
  BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U) {
 | 
			
		||||
  bool doubleBuffer;
 | 
			
		||||
 | 
			
		||||
  BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U, bool dblBfr=false)
 | 
			
		||||
  : count(len)
 | 
			
		||||
  , start(pstart)
 | 
			
		||||
  , colorOrder(pcolorOrder)
 | 
			
		||||
  , reversed(rev)
 | 
			
		||||
  , skipAmount(skip)
 | 
			
		||||
  , autoWhite(aw)
 | 
			
		||||
  , frequency(clock_kHz)
 | 
			
		||||
  , doubleBuffer(dblBfr)
 | 
			
		||||
  {
 | 
			
		||||
    refreshReq = (bool) GET_BIT(busType,7);
 | 
			
		||||
    type = busType & 0x7F;  // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
 | 
			
		||||
    count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw; frequency = clock_kHz;
 | 
			
		||||
    uint8_t nPins = 1;
 | 
			
		||||
    size_t nPins = 1;
 | 
			
		||||
    if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
 | 
			
		||||
    else if (type > 47) nPins = 2;
 | 
			
		||||
    else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
 | 
			
		||||
    for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
 | 
			
		||||
    for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //validates start and length and extends total if needed
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +68,7 @@ struct BusConfig {
 | 
			
		|||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Defines an LED Strip and its color ordering.
 | 
			
		||||
struct ColorOrderMapEntry {
 | 
			
		||||
  uint16_t start;
 | 
			
		||||
| 
						 | 
				
			
			@ -64,9 +79,7 @@ struct ColorOrderMapEntry {
 | 
			
		|||
struct ColorOrderMap {
 | 
			
		||||
    void add(uint16_t start, uint16_t len, uint8_t colorOrder);
 | 
			
		||||
 | 
			
		||||
    uint8_t count() const {
 | 
			
		||||
      return _count;
 | 
			
		||||
    }
 | 
			
		||||
    uint8_t count() const { return _count; }
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
      _count = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -87,56 +100,63 @@ struct ColorOrderMap {
 | 
			
		|||
    ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//parent class of BusDigital, BusPwm, and BusNetwork
 | 
			
		||||
class Bus {
 | 
			
		||||
  public:
 | 
			
		||||
    Bus(uint8_t type, uint16_t start, uint8_t aw)
 | 
			
		||||
    : _bri(255)
 | 
			
		||||
    , _len(1)
 | 
			
		||||
    Bus(uint8_t type, uint16_t start, uint8_t aw, uint16_t len = 1, bool reversed = false, bool refresh = false)
 | 
			
		||||
    : _type(type)
 | 
			
		||||
    , _bri(255)
 | 
			
		||||
    , _start(start)
 | 
			
		||||
    , _len(len)
 | 
			
		||||
    , _reversed(reversed)
 | 
			
		||||
    , _valid(false)
 | 
			
		||||
    , _needsRefresh(false)
 | 
			
		||||
    , _needsRefresh(refresh)
 | 
			
		||||
    , _data(nullptr) // keep data access consistent across all types of buses
 | 
			
		||||
    {
 | 
			
		||||
      _type = type;
 | 
			
		||||
      _start = start;
 | 
			
		||||
      _autoWhiteMode = Bus::hasWhite(_type) ? aw : RGBW_MODE_MANUAL_ONLY;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    virtual ~Bus() {} //throw the bus under the bus
 | 
			
		||||
 | 
			
		||||
    virtual void     show() = 0;
 | 
			
		||||
    virtual bool     canShow() { return true; }
 | 
			
		||||
    virtual void     setStatusPixel(uint32_t c) {}
 | 
			
		||||
    virtual bool     canShow()                   { return true; }
 | 
			
		||||
    virtual void     setStatusPixel(uint32_t c)  {}
 | 
			
		||||
    virtual void     setPixelColor(uint16_t pix, uint32_t c) = 0;
 | 
			
		||||
    virtual uint32_t getPixelColor(uint16_t pix) { return 0; }
 | 
			
		||||
    virtual void     setBrightness(uint8_t b, bool immediate=false) { _bri = b; };
 | 
			
		||||
    virtual void     setBrightness(uint8_t b)    { _bri = b; };
 | 
			
		||||
    virtual void     cleanup() = 0;
 | 
			
		||||
    virtual uint8_t  getPins(uint8_t* pinArray) { return 0; }
 | 
			
		||||
    virtual uint16_t getLength() { return _len; }
 | 
			
		||||
    virtual void     setColorOrder() {}
 | 
			
		||||
    virtual uint8_t  getColorOrder() { return COL_ORDER_RGB; }
 | 
			
		||||
    virtual uint8_t  skippedLeds() { return 0; }
 | 
			
		||||
    virtual uint16_t getFrequency() { return 0U; }
 | 
			
		||||
    inline  uint16_t getStart() { return _start; }
 | 
			
		||||
    inline  void     setStart(uint16_t start) { _start = start; }
 | 
			
		||||
    inline  uint8_t  getType() { return _type; }
 | 
			
		||||
    inline  bool     isOk() { return _valid; }
 | 
			
		||||
    inline  bool     isOffRefreshRequired() { return _needsRefresh; }
 | 
			
		||||
    virtual uint8_t  getPins(uint8_t* pinArray)  { return 0; }
 | 
			
		||||
    virtual uint16_t getLength()                 { return _len; }
 | 
			
		||||
    virtual void     setColorOrder()             {}
 | 
			
		||||
    virtual uint8_t  getColorOrder()             { return COL_ORDER_RGB; }
 | 
			
		||||
    virtual uint8_t  skippedLeds()               { return 0; }
 | 
			
		||||
    virtual uint16_t getFrequency()              { return 0U; }
 | 
			
		||||
    inline  void     setReversed(bool reversed)  { _reversed = reversed; }
 | 
			
		||||
    inline  uint16_t getStart()                  { return _start; }
 | 
			
		||||
    inline  void     setStart(uint16_t start)    { _start = start; }
 | 
			
		||||
    inline  uint8_t  getType()                   { return _type; }
 | 
			
		||||
    inline  bool     isOk()                      { return _valid; }
 | 
			
		||||
    inline  bool     isReversed()                { return _reversed; }
 | 
			
		||||
    inline  bool     isOffRefreshRequired()      { return _needsRefresh; }
 | 
			
		||||
            bool     containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; }
 | 
			
		||||
 | 
			
		||||
    virtual bool hasRGB() {
 | 
			
		||||
      if ((_type >= TYPE_WS2812_1CH && _type <= TYPE_WS2812_WWA) || _type == TYPE_ANALOG_1CH || _type == TYPE_ANALOG_2CH || _type == TYPE_ONOFF) return false;
 | 
			
		||||
    virtual bool hasRGB(void) { return Bus::hasRGB(_type); }
 | 
			
		||||
    static  bool hasRGB(uint8_t type) {
 | 
			
		||||
      if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF) return false;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    virtual bool hasWhite() { return Bus::hasWhite(_type); }
 | 
			
		||||
    virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
 | 
			
		||||
    static  bool hasWhite(uint8_t type) {
 | 
			
		||||
      if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; // digital types with white channel
 | 
			
		||||
      if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
 | 
			
		||||
      if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    virtual bool hasCCT() {
 | 
			
		||||
      if (_type == TYPE_WS2812_2CH_X3 || _type == TYPE_WS2812_WWA ||
 | 
			
		||||
          _type == TYPE_ANALOG_2CH    || _type == TYPE_ANALOG_5CH) return true;
 | 
			
		||||
    virtual bool hasCCT(void) { return Bus::hasCCT(_type); }
 | 
			
		||||
    static  bool hasCCT(uint8_t type) {
 | 
			
		||||
      if (type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA ||
 | 
			
		||||
          type == TYPE_ANALOG_2CH    || type == TYPE_ANALOG_5CH) return true;
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    static void setCCT(uint16_t cct) {
 | 
			
		||||
| 
						 | 
				
			
			@ -155,107 +175,87 @@ class Bus {
 | 
			
		|||
    inline static void    setGlobalAWMode(uint8_t m)  { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
 | 
			
		||||
    inline static uint8_t getGlobalAWMode()           { return _gAWM; }
 | 
			
		||||
 | 
			
		||||
    bool reversed = false;
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
    uint8_t  _type;
 | 
			
		||||
    uint8_t  _bri;
 | 
			
		||||
    uint16_t _start;
 | 
			
		||||
    uint16_t _len;
 | 
			
		||||
    bool     _reversed;
 | 
			
		||||
    bool     _valid;
 | 
			
		||||
    bool     _needsRefresh;
 | 
			
		||||
    uint8_t  _autoWhiteMode;
 | 
			
		||||
    uint8_t  *_data;
 | 
			
		||||
    static uint8_t _gAWM;
 | 
			
		||||
    static int16_t _cct;
 | 
			
		||||
    static uint8_t _cctBlend;
 | 
			
		||||
 | 
			
		||||
    uint32_t autoWhiteCalc(uint32_t c);
 | 
			
		||||
    uint8_t *allocData(size_t size = 1);
 | 
			
		||||
    void     freeData() { if (_data != nullptr) free(_data); _data = nullptr; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BusDigital : public Bus {
 | 
			
		||||
  public:
 | 
			
		||||
    BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
 | 
			
		||||
    ~BusDigital() { cleanup(); }
 | 
			
		||||
 | 
			
		||||
    inline void show();
 | 
			
		||||
 | 
			
		||||
    void show();
 | 
			
		||||
    bool canShow();
 | 
			
		||||
 | 
			
		||||
    void setBrightness(uint8_t b, bool immediate);
 | 
			
		||||
 | 
			
		||||
    void setBrightness(uint8_t b);
 | 
			
		||||
    void setStatusPixel(uint32_t c);
 | 
			
		||||
 | 
			
		||||
    void setPixelColor(uint16_t pix, uint32_t c);
 | 
			
		||||
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
 | 
			
		||||
    uint8_t getColorOrder() {
 | 
			
		||||
      return _colorOrder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t getLength() {
 | 
			
		||||
      return _len - _skip;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t getPins(uint8_t* pinArray);
 | 
			
		||||
 | 
			
		||||
    void setColorOrder(uint8_t colorOrder);
 | 
			
		||||
 | 
			
		||||
    uint8_t skippedLeds() {
 | 
			
		||||
      return _skip;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t getFrequency() { return _frequencykHz; }
 | 
			
		||||
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
    uint8_t  getColorOrder() { return _colorOrder; }
 | 
			
		||||
    uint8_t  getPins(uint8_t* pinArray);
 | 
			
		||||
    uint8_t  skippedLeds()   { return _skip; }
 | 
			
		||||
    uint16_t getFrequency()  { return _frequencykHz; }
 | 
			
		||||
    void reinit();
 | 
			
		||||
 | 
			
		||||
    void cleanup();
 | 
			
		||||
 | 
			
		||||
    ~BusDigital() {
 | 
			
		||||
      cleanup();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    uint8_t _colorOrder = COL_ORDER_GRB;
 | 
			
		||||
    uint8_t _pins[2] = {255, 255};
 | 
			
		||||
    uint8_t _iType = 0; //I_NONE;
 | 
			
		||||
    uint8_t _skip = 0;
 | 
			
		||||
    uint16_t _frequencykHz = 0U;
 | 
			
		||||
    void * _busPtr = nullptr;
 | 
			
		||||
    uint8_t _skip;
 | 
			
		||||
    uint8_t _colorOrder;
 | 
			
		||||
    uint8_t _pins[2];
 | 
			
		||||
    uint8_t _iType;
 | 
			
		||||
    uint16_t _frequencykHz;
 | 
			
		||||
    void * _busPtr;
 | 
			
		||||
    const ColorOrderMap &_colorOrderMap;
 | 
			
		||||
    bool _buffering; // temporary until we figure out why comparison "_data != nullptr" causes severe FPS drop
 | 
			
		||||
 | 
			
		||||
    inline uint32_t restoreColorLossy(uint32_t c, uint8_t restoreBri) {
 | 
			
		||||
      if (restoreBri < 255) {
 | 
			
		||||
        uint8_t* chan = (uint8_t*) &c;
 | 
			
		||||
        for (uint_fast8_t i=0; i<4; i++) {
 | 
			
		||||
          uint_fast16_t val = chan[i];
 | 
			
		||||
          chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slighly improves recovery / stops degradation on re-scale
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BusPwm : public Bus {
 | 
			
		||||
  public:
 | 
			
		||||
    BusPwm(BusConfig &bc);
 | 
			
		||||
    ~BusPwm() { cleanup(); }
 | 
			
		||||
 | 
			
		||||
    void setPixelColor(uint16_t pix, uint32_t c);
 | 
			
		||||
 | 
			
		||||
    //does no index check
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
 | 
			
		||||
    void show();
 | 
			
		||||
 | 
			
		||||
    uint8_t getPins(uint8_t* pinArray);
 | 
			
		||||
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix); //does no index check
 | 
			
		||||
    uint8_t  getPins(uint8_t* pinArray);
 | 
			
		||||
    uint16_t getFrequency() { return _frequency; }
 | 
			
		||||
 | 
			
		||||
    void cleanup() {
 | 
			
		||||
      deallocatePins();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~BusPwm() {
 | 
			
		||||
      cleanup();
 | 
			
		||||
    }
 | 
			
		||||
    void show();
 | 
			
		||||
    void cleanup() { deallocatePins(); }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    uint8_t _pins[5] = {255, 255, 255, 255, 255};
 | 
			
		||||
    uint8_t _data[5] = {0};
 | 
			
		||||
    uint8_t _pins[5];
 | 
			
		||||
    uint8_t _pwmdata[5];
 | 
			
		||||
    #ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
    uint8_t _ledcStart = 255;
 | 
			
		||||
    uint8_t _ledcStart;
 | 
			
		||||
    #endif
 | 
			
		||||
    uint16_t _frequency = 0U;
 | 
			
		||||
    uint16_t _frequency;
 | 
			
		||||
 | 
			
		||||
    void deallocatePins();
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -264,72 +264,46 @@ class BusPwm : public Bus {
 | 
			
		|||
class BusOnOff : public Bus {
 | 
			
		||||
  public:
 | 
			
		||||
    BusOnOff(BusConfig &bc);
 | 
			
		||||
    ~BusOnOff() { cleanup(); }
 | 
			
		||||
 | 
			
		||||
    void setPixelColor(uint16_t pix, uint32_t c);
 | 
			
		||||
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
 | 
			
		||||
    uint8_t  getPins(uint8_t* pinArray);
 | 
			
		||||
    void show();
 | 
			
		||||
 | 
			
		||||
    uint8_t getPins(uint8_t* pinArray);
 | 
			
		||||
 | 
			
		||||
    void cleanup() {
 | 
			
		||||
      pinManager.deallocatePin(_pin, PinOwner::BusOnOff);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~BusOnOff() {
 | 
			
		||||
      cleanup();
 | 
			
		||||
    }
 | 
			
		||||
    void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    uint8_t _pin = 255;
 | 
			
		||||
    uint8_t _data = 0;
 | 
			
		||||
    uint8_t _pin;
 | 
			
		||||
    uint8_t _onoffdata;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BusNetwork : public Bus {
 | 
			
		||||
  public:
 | 
			
		||||
    BusNetwork(BusConfig &bc);
 | 
			
		||||
    ~BusNetwork() { cleanup(); }
 | 
			
		||||
 | 
			
		||||
    bool hasRGB() { return true; }
 | 
			
		||||
    bool hasRGB()   { return true; }
 | 
			
		||||
    bool hasWhite() { return _rgbw; }
 | 
			
		||||
 | 
			
		||||
    bool canShow()  { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
 | 
			
		||||
    void setPixelColor(uint16_t pix, uint32_t c);
 | 
			
		||||
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
 | 
			
		||||
    uint8_t  getPins(uint8_t* pinArray);
 | 
			
		||||
    void show();
 | 
			
		||||
 | 
			
		||||
    bool canShow() {
 | 
			
		||||
      // this should be a return value from UDP routine if it is still sending data out
 | 
			
		||||
      return !_broadcastLock;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t getPins(uint8_t* pinArray);
 | 
			
		||||
 | 
			
		||||
    uint16_t getLength() {
 | 
			
		||||
      return _len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void cleanup();
 | 
			
		||||
 | 
			
		||||
    ~BusNetwork() {
 | 
			
		||||
      cleanup();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    IPAddress _client;
 | 
			
		||||
    uint8_t   _UDPtype;
 | 
			
		||||
    uint8_t   _UDPchannels;
 | 
			
		||||
    bool      _rgbw;
 | 
			
		||||
    bool      _broadcastLock;
 | 
			
		||||
    byte     *_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BusManager {
 | 
			
		||||
  public:
 | 
			
		||||
    BusManager() {};
 | 
			
		||||
    BusManager() : numBusses(0) {};
 | 
			
		||||
 | 
			
		||||
    //utility to get the approx. memory usage of a given BusConfig
 | 
			
		||||
    static uint32_t memUsage(BusConfig &bc);
 | 
			
		||||
| 
						 | 
				
			
			@ -340,38 +314,24 @@ class BusManager {
 | 
			
		|||
    void removeAll();
 | 
			
		||||
 | 
			
		||||
    void show();
 | 
			
		||||
 | 
			
		||||
    void setStatusPixel(uint32_t c);
 | 
			
		||||
 | 
			
		||||
    void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
 | 
			
		||||
 | 
			
		||||
    void setBrightness(uint8_t b, bool immediate=false);          // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient)
 | 
			
		||||
 | 
			
		||||
    void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
 | 
			
		||||
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
 | 
			
		||||
    bool canAllShow();
 | 
			
		||||
    void setStatusPixel(uint32_t c);
 | 
			
		||||
    void setPixelColor(uint16_t pix, uint32_t c);
 | 
			
		||||
    void setBrightness(uint8_t b);
 | 
			
		||||
    void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
 | 
			
		||||
    uint32_t getPixelColor(uint16_t pix);
 | 
			
		||||
 | 
			
		||||
    Bus* getBus(uint8_t busNr);
 | 
			
		||||
 | 
			
		||||
    //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
 | 
			
		||||
    uint16_t getTotalLength();
 | 
			
		||||
    inline uint8_t getNumBusses() const { return numBusses; }
 | 
			
		||||
 | 
			
		||||
    inline void updateColorOrderMap(const ColorOrderMap &com) {
 | 
			
		||||
      memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline const ColorOrderMap& getColorOrderMap() const {
 | 
			
		||||
      return colorOrderMap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline uint8_t getNumBusses() {
 | 
			
		||||
      return numBusses;
 | 
			
		||||
    }
 | 
			
		||||
    inline void                 updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); }
 | 
			
		||||
    inline const ColorOrderMap& getColorOrderMap() const { return colorOrderMap; }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    uint8_t numBusses = 0;
 | 
			
		||||
    uint8_t numBusses;
 | 
			
		||||
    Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
 | 
			
		||||
    ColorOrderMap colorOrderMap;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -381,4 +341,4 @@ class BusManager {
 | 
			
		|||
      return j;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -280,6 +280,7 @@ class PolyBus {
 | 
			
		|||
    #endif
 | 
			
		||||
    if (clock_kHz) dotStar_strip->SetMethodSettings(NeoSpiSettings((uint32_t)clock_kHz*1000));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Begin & initialize the PixelSettings for TM1814 strips.
 | 
			
		||||
  template <class T>
 | 
			
		||||
  static void beginTM1814(void* busPtr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -288,6 +289,7 @@ class PolyBus {
 | 
			
		|||
    // Max current for each LED (22.5 mA).
 | 
			
		||||
    tm1814_strip->SetPixelSettings(NeoTm1814Settings(/*R*/225, /*G*/225, /*B*/225, /*W*/225));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) {
 | 
			
		||||
    switch (busType) {
 | 
			
		||||
      case I_NONE: break;
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +392,8 @@ class PolyBus {
 | 
			
		|||
      case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
 | 
			
		||||
      case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) {
 | 
			
		||||
    void* busPtr = nullptr;
 | 
			
		||||
    switch (busType) {
 | 
			
		||||
| 
						 | 
				
			
			@ -491,104 +494,106 @@ class PolyBus {
 | 
			
		|||
    }
 | 
			
		||||
    begin(busPtr, busType, pins, clock_kHz);
 | 
			
		||||
    return busPtr;
 | 
			
		||||
  };
 | 
			
		||||
  static void show(void* busPtr, uint8_t busType) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static void show(void* busPtr, uint8_t busType, bool consistent = true) {
 | 
			
		||||
    switch (busType) {
 | 
			
		||||
      case I_NONE: break;
 | 
			
		||||
    #ifdef ESP8266
 | 
			
		||||
      case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
    #endif
 | 
			
		||||
    #ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
      case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
//      case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
//      case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->Show(); break;
 | 
			
		||||
//      case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_UCS_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
//      case I_32_BB_UCS_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(); break;
 | 
			
		||||
//      case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(consistent); break;
 | 
			
		||||
    #endif
 | 
			
		||||
      case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(); break;
 | 
			
		||||
      case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
      case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(consistent); break;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static bool canShow(void* busPtr, uint8_t busType) {
 | 
			
		||||
    switch (busType) {
 | 
			
		||||
      case I_NONE: return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -685,7 +690,8 @@ class PolyBus {
 | 
			
		|||
      case I_SS_P98_3: return (static_cast<B_SS_P98_3*>(busPtr))->CanShow(); break;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) {
 | 
			
		||||
    uint8_t r = c >> 16;
 | 
			
		||||
    uint8_t g = c >> 8;
 | 
			
		||||
| 
						 | 
				
			
			@ -805,104 +811,106 @@ class PolyBus {
 | 
			
		|||
      case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
 | 
			
		||||
      case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  static void setBrightness(void* busPtr, uint8_t busType, uint8_t b, bool immediate) { // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) {
 | 
			
		||||
    switch (busType) {
 | 
			
		||||
      case I_NONE: break;
 | 
			
		||||
    #ifdef ESP8266
 | 
			
		||||
      case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
    #endif
 | 
			
		||||
    #ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
      case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
//      case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
//      case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
//      case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
//      case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #ifndef WLED_NO_I2S0_PIXELBUS
 | 
			
		||||
      case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
      #ifndef WLED_NO_I2S1_PIXELBUS
 | 
			
		||||
      case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      #endif
 | 
			
		||||
//      case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
//      case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
    #endif
 | 
			
		||||
      case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
 | 
			
		||||
      case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
      case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); break;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
 | 
			
		||||
    RgbwColor col(0,0,0,0);
 | 
			
		||||
    switch (busType) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1209,4 +1217,4 @@ class PolyBus {
 | 
			
		|||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
 | 
			
		|||
  CJSON(strip.cctBlending, hw_led[F("cb")]);
 | 
			
		||||
  Bus::setCCTBlend(strip.cctBlending);
 | 
			
		||||
  strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
 | 
			
		||||
  CJSON(strip.useLedsArray, hw_led[F("ld")]);
 | 
			
		||||
  CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
 | 
			
		||||
 | 
			
		||||
  #ifndef WLED_DISABLE_2D
 | 
			
		||||
  // 2D Matrix Settings
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +134,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
 | 
			
		|||
  if (fromFS || !ins.isNull()) {
 | 
			
		||||
    uint8_t s = 0;  // bus iterator
 | 
			
		||||
    if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback
 | 
			
		||||
    uint32_t mem = 0;
 | 
			
		||||
    uint32_t mem = 0, globalBufMem = 0;
 | 
			
		||||
    uint16_t maxlen = 0;
 | 
			
		||||
    bool busesChanged = false;
 | 
			
		||||
    for (JsonObject elm : ins) {
 | 
			
		||||
      if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
 | 
			
		||||
| 
						 | 
				
			
			@ -160,12 +161,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
 | 
			
		|||
      ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
 | 
			
		||||
      uint8_t AWmode = elm[F("rgbwm")] | autoWhiteMode;
 | 
			
		||||
      if (fromFS) {
 | 
			
		||||
        BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz);
 | 
			
		||||
        BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer);
 | 
			
		||||
        mem += BusManager::memUsage(bc);
 | 
			
		||||
        if (mem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break;  // finalization will be done in WLED::beginStrip()
 | 
			
		||||
        if (useGlobalLedBuffer && start + length > maxlen) {
 | 
			
		||||
          maxlen = start + length;
 | 
			
		||||
          globalBufMem = maxlen * 4;
 | 
			
		||||
        }
 | 
			
		||||
        if (mem + globalBufMem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break;  // finalization will be done in WLED::beginStrip()
 | 
			
		||||
      } else {
 | 
			
		||||
        if (busConfigs[s] != nullptr) delete busConfigs[s];
 | 
			
		||||
        busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
 | 
			
		||||
        busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer);
 | 
			
		||||
        busesChanged = true;
 | 
			
		||||
      }
 | 
			
		||||
      s++;
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +178,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
 | 
			
		|||
    doInitBusses = busesChanged;
 | 
			
		||||
    // finalization done in beginStrip()
 | 
			
		||||
  }
 | 
			
		||||
  if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
 | 
			
		||||
  if (hw_led["rev"]) busses.getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
 | 
			
		||||
 | 
			
		||||
  // read color order map configuration
 | 
			
		||||
  JsonArray hw_com = hw[F("com")];
 | 
			
		||||
| 
						 | 
				
			
			@ -711,7 +716,7 @@ void serializeConfig() {
 | 
			
		|||
  hw_led[F("cb")] = strip.cctBlending;
 | 
			
		||||
  hw_led["fps"] = strip.getTargetFps();
 | 
			
		||||
  hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
 | 
			
		||||
  hw_led[F("ld")] = strip.useLedsArray;
 | 
			
		||||
  hw_led[F("ld")] = useGlobalLedBuffer;
 | 
			
		||||
 | 
			
		||||
  #ifndef WLED_DISABLE_2D
 | 
			
		||||
  // 2D Matrix Settings
 | 
			
		||||
| 
						 | 
				
			
			@ -746,7 +751,7 @@ void serializeConfig() {
 | 
			
		|||
    uint8_t nPins = bus->getPins(pins);
 | 
			
		||||
    for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
 | 
			
		||||
    ins[F("order")] = bus->getColorOrder();
 | 
			
		||||
    ins["rev"] = bus->reversed;
 | 
			
		||||
    ins["rev"] = bus->isReversed();
 | 
			
		||||
    ins[F("skip")] = bus->skippedLeds();
 | 
			
		||||
    ins["type"] = bus->getType() & 0x7F;
 | 
			
		||||
    ins["ref"] = bus->isOffRefreshRequired();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,7 +141,7 @@
 | 
			
		|||
			let len = parseInt(d.getElementsByName("LC"+n)[0].value);
 | 
			
		||||
			len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
 | 
			
		||||
			let dbl = 0;
 | 
			
		||||
			if (d.Sf.LD.checked) dbl = len * 3;	// double buffering
 | 
			
		||||
			if (d.Sf.LD.checked) dbl = len * 4;	// double buffering
 | 
			
		||||
			if (t < 32) {
 | 
			
		||||
				if (t==26 || t==29) len *= 2; // 16 bit LEDs
 | 
			
		||||
				if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,11 @@ 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)
 | 
			
		||||
  // do not call seg.setUp() here, as it may cause a crash due to concurrent access if the segment is currently drawing effects
 | 
			
		||||
  // WS2812FX handles queueing of the change
 | 
			
		||||
  strip.setSegment(id, start, stop, grp, spc, of, startY, stopY);
 | 
			
		||||
 | 
			
		||||
  if (seg.reset && seg.stop == 0) return true; // segment was deleted & is marked for reset, no need to change anything else
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -468,12 +472,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1060,7 +1066,10 @@ void serveJson(AsyncWebServerRequest* request)
 | 
			
		|||
 | 
			
		||||
  DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", lDoc.memoryUsage(), subJson);
 | 
			
		||||
 | 
			
		||||
  size_t len = response->setLength();
 | 
			
		||||
  #ifdef WLED_DEBUG
 | 
			
		||||
  size_t len =
 | 
			
		||||
  #endif
 | 
			
		||||
  response->setLength();
 | 
			
		||||
  DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len);
 | 
			
		||||
 | 
			
		||||
  request->send(response);
 | 
			
		||||
| 
						 | 
				
			
			@ -1090,9 +1099,13 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
 | 
			
		|||
  for (size_t i= 0; i < used; i += n)
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t c = strip.getPixelColor(i);
 | 
			
		||||
    uint8_t r = qadd8(W(c), R(c)); //add white channel to RGB channels as a simple RGBW -> RGB map
 | 
			
		||||
    uint8_t g = qadd8(W(c), G(c));
 | 
			
		||||
    uint8_t b = qadd8(W(c), B(c));
 | 
			
		||||
    uint8_t r = R(c);
 | 
			
		||||
    uint8_t g = G(c);
 | 
			
		||||
    uint8_t b = B(c);
 | 
			
		||||
    uint8_t w = W(c);
 | 
			
		||||
    r = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map
 | 
			
		||||
    g = scale8(qadd8(w, g), strip.getBrightness()); //G
 | 
			
		||||
    b = scale8(qadd8(w, b), strip.getBrightness()); //B
 | 
			
		||||
    olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
 | 
			
		||||
  }
 | 
			
		||||
  olen -= 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ void handleTransitions()
 | 
			
		|||
      applyFinalBri();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (tper - tperLast < 0.004) return;
 | 
			
		||||
    if (tper - tperLast < 0.004f) return;
 | 
			
		||||
    tperLast = tper;
 | 
			
		||||
    briT = briOld + ((bri - briOld) * tper);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -205,7 +205,7 @@ void handleTransitions()
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
// legacy method, applies values from col, effectCurrent, ... to selected segments
 | 
			
		||||
void colorUpdated(byte callMode){
 | 
			
		||||
void colorUpdated(byte callMode) {
 | 
			
		||||
  applyValuesToSelectedSegs();
 | 
			
		||||
  stateUpdated(callMode);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,7 +91,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
 | 
			
		|||
    Bus::setCCTBlend(strip.cctBlending);
 | 
			
		||||
    Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
 | 
			
		||||
    strip.setTargetFps(request->arg(F("FR")).toInt());
 | 
			
		||||
    strip.useLedsArray = request->hasArg(F("LD"));
 | 
			
		||||
    useGlobalLedBuffer = request->hasArg(F("LD"));
 | 
			
		||||
 | 
			
		||||
    bool busesChanged = false;
 | 
			
		||||
    for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +153,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
 | 
			
		|||
      // actual finalization is done in WLED::loop() (removing old busses and adding new)
 | 
			
		||||
      // this may happen even before this loop is finished so we do "doInitBusses" after the loop
 | 
			
		||||
      if (busConfigs[s] != nullptr) delete busConfigs[s];
 | 
			
		||||
      busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freqHz);
 | 
			
		||||
      busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freqHz, useGlobalLedBuffer);
 | 
			
		||||
      busesChanged = true;
 | 
			
		||||
    }
 | 
			
		||||
    //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
 | 
			
		||||
| 
						 | 
				
			
			@ -797,7 +797,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
 | 
			
		|||
  if (pos > 0) {
 | 
			
		||||
    spcI = getNumVal(&req, pos);
 | 
			
		||||
  }
 | 
			
		||||
  selseg.setUp(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
 | 
			
		||||
  strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
 | 
			
		||||
 | 
			
		||||
  pos = req.indexOf(F("RV=")); //Segment reverse
 | 
			
		||||
  if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -35,10 +35,18 @@ void WLED::reset()
 | 
			
		|||
void WLED::loop()
 | 
			
		||||
{
 | 
			
		||||
  #ifdef WLED_DEBUG
 | 
			
		||||
  static unsigned long lastRun = 0;
 | 
			
		||||
  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 %ums.\n", loopDelay);
 | 
			
		||||
  static unsigned long maxLoopMillis = 0;
 | 
			
		||||
  static size_t        avgLoopMillis = 0;
 | 
			
		||||
  static unsigned long maxUsermodMillis = 0;
 | 
			
		||||
  static uint16_t avgUsermodMillis = 0;
 | 
			
		||||
  static size_t        avgUsermodMillis = 0;
 | 
			
		||||
  static unsigned long maxStripMillis = 0;
 | 
			
		||||
  static uint16_t avgStripMillis = 0;
 | 
			
		||||
  static size_t        avgStripMillis = 0;
 | 
			
		||||
  unsigned long        stripMillis;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  handleTime();
 | 
			
		||||
| 
						 | 
				
			
			@ -80,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();
 | 
			
		||||
| 
						 | 
				
			
			@ -98,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
 | 
			
		||||
| 
						 | 
				
			
			@ -152,11 +159,16 @@ void WLED::loop()
 | 
			
		|||
    DEBUG_PRINTLN(F("Re-init busses."));
 | 
			
		||||
    bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
 | 
			
		||||
    busses.removeAll();
 | 
			
		||||
    uint32_t mem = 0;
 | 
			
		||||
    uint32_t mem = 0, globalBufMem = 0;
 | 
			
		||||
    uint16_t maxlen = 0;
 | 
			
		||||
    for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
 | 
			
		||||
      if (busConfigs[i] == nullptr) break;
 | 
			
		||||
      mem += BusManager::memUsage(*busConfigs[i]);
 | 
			
		||||
      if (mem <= MAX_LED_MEMORY) {
 | 
			
		||||
      if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) {
 | 
			
		||||
          maxlen = busConfigs[i]->start + busConfigs[i]->count;
 | 
			
		||||
          globalBufMem = maxlen * 4;
 | 
			
		||||
      }
 | 
			
		||||
      if (mem + globalBufMem <= MAX_LED_MEMORY) {
 | 
			
		||||
        busses.add(*busConfigs[i]);
 | 
			
		||||
      }
 | 
			
		||||
      delete busConfigs[i]; busConfigs[i] = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -177,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());
 | 
			
		||||
| 
						 | 
				
			
			@ -201,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -213,21 +250,8 @@ void WLED::loop()
 | 
			
		|||
    debugTime = millis();
 | 
			
		||||
  }
 | 
			
		||||
  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() {
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +536,7 @@ void WLED::initAP(bool resetAP)
 | 
			
		|||
  DEBUG_PRINTLN(apSSID);
 | 
			
		||||
  WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0));
 | 
			
		||||
  WiFi.softAP(apSSID, apPass, apChannel, apHide);
 | 
			
		||||
  #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2))
 | 
			
		||||
  #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
 | 
			
		||||
  WiFi.setTxPower(WIFI_POWER_8_5dBm);
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -690,7 +714,7 @@ void WLED::initConnection()
 | 
			
		|||
 | 
			
		||||
  WiFi.begin(clientSSID, clientPass);
 | 
			
		||||
#ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
  #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2))
 | 
			
		||||
  #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
 | 
			
		||||
  WiFi.setTxPower(WIFI_POWER_8_5dBm);
 | 
			
		||||
  #endif
 | 
			
		||||
  WiFi.setSleep(!noWifiSleep);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
// version code in format yymmddb (b = daily build)
 | 
			
		||||
#define VERSION 2307130
 | 
			
		||||
#define VERSION 2307180
 | 
			
		||||
 | 
			
		||||
//uncomment this if you have a "my_config.h" file you'd like to use
 | 
			
		||||
//#define WLED_USE_MY_CONFIG
 | 
			
		||||
| 
						 | 
				
			
			@ -331,12 +331,17 @@ WLED_GLOBAL byte bootPreset   _INIT(0);                   // save preset to load
 | 
			
		|||
//if true, a segment per bus will be created on boot and LED settings save
 | 
			
		||||
//if false, only one segment spanning the total LEDs is created,
 | 
			
		||||
//but not on LED settings save if there is more than one segment currently
 | 
			
		||||
WLED_GLOBAL bool autoSegments    _INIT(false);
 | 
			
		||||
WLED_GLOBAL bool correctWB       _INIT(false); // CCT color correction of RGB color
 | 
			
		||||
WLED_GLOBAL bool cctFromRgb      _INIT(false); // CCT is calculated from RGB instead of using seg.cct
 | 
			
		||||
WLED_GLOBAL bool gammaCorrectCol _INIT(true ); // use gamma correction on colors
 | 
			
		||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
 | 
			
		||||
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
 | 
			
		||||
WLED_GLOBAL bool autoSegments       _INIT(false);
 | 
			
		||||
#ifdef ESP8266
 | 
			
		||||
WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266
 | 
			
		||||
#else
 | 
			
		||||
WLED_GLOBAL bool useGlobalLedBuffer _INIT(true);  // double buffering enabled on ESP32
 | 
			
		||||
#endif
 | 
			
		||||
WLED_GLOBAL bool correctWB          _INIT(false); // CCT color correction of RGB color
 | 
			
		||||
WLED_GLOBAL bool cctFromRgb         _INIT(false); // CCT is calculated from RGB instead of using seg.cct
 | 
			
		||||
WLED_GLOBAL bool gammaCorrectCol    _INIT(true);  // use gamma correction on colors
 | 
			
		||||
WLED_GLOBAL bool gammaCorrectBri    _INIT(false); // use gamma correction on brightness
 | 
			
		||||
WLED_GLOBAL float gammaCorrectVal   _INIT(2.8f);  // gamma correction value
 | 
			
		||||
 | 
			
		||||
WLED_GLOBAL byte col[]    _INIT_N(({ 255, 160, 0, 0 }));  // current RGB(W) primary color. col[] should be updated if you want to change the color.
 | 
			
		||||
WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 }));      // current RGB(W) secondary color
 | 
			
		||||
| 
						 | 
				
			
			@ -508,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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -166,23 +166,24 @@ bool sendLiveLedsWs(uint32_t wsClient)
 | 
			
		|||
  size_t n = ((used -1)/MAX_LIVE_LEDS_WS) +1; //only serve every n'th LED if count over MAX_LIVE_LEDS_WS
 | 
			
		||||
  size_t pos = (strip.isMatrix ? 4 : 2);  // start of data
 | 
			
		||||
  size_t bufSize = pos + (used/n)*3;
 | 
			
		||||
  size_t skipLines = 0;
 | 
			
		||||
 | 
			
		||||
  AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize);
 | 
			
		||||
  if (!wsBuf) return false; //out of memory
 | 
			
		||||
  uint8_t* buffer = wsBuf->get();
 | 
			
		||||
  buffer[0] = 'L';
 | 
			
		||||
  buffer[1] = 1; //version
 | 
			
		||||
 | 
			
		||||
#ifndef WLED_DISABLE_2D
 | 
			
		||||
  size_t skipLines = 0;
 | 
			
		||||
  if (strip.isMatrix) {
 | 
			
		||||
    buffer[1] = 2; //version
 | 
			
		||||
    buffer[2] = Segment::maxWidth;
 | 
			
		||||
    buffer[3] = Segment::maxHeight;
 | 
			
		||||
    if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS*4) {
 | 
			
		||||
    if (used > MAX_LIVE_LEDS_WS*4) {
 | 
			
		||||
      buffer[2] = Segment::maxWidth/4;
 | 
			
		||||
      buffer[3] = Segment::maxHeight/4;
 | 
			
		||||
      skipLines = 3;
 | 
			
		||||
    } else if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS) {
 | 
			
		||||
    } else if (used > MAX_LIVE_LEDS_WS) {
 | 
			
		||||
      buffer[2] = Segment::maxWidth/2;
 | 
			
		||||
      buffer[3] = Segment::maxHeight/2;
 | 
			
		||||
      skipLines = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -198,9 +199,13 @@ bool sendLiveLedsWs(uint32_t wsClient)
 | 
			
		|||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    uint32_t c = strip.getPixelColor(i);
 | 
			
		||||
    buffer[pos++] = qadd8(W(c), R(c)); //R, add white channel to RGB channels as a simple RGBW -> RGB map
 | 
			
		||||
    buffer[pos++] = qadd8(W(c), G(c)); //G
 | 
			
		||||
    buffer[pos++] = qadd8(W(c), B(c)); //B
 | 
			
		||||
    uint8_t r = R(c);
 | 
			
		||||
    uint8_t g = G(c);
 | 
			
		||||
    uint8_t b = B(c);
 | 
			
		||||
    uint8_t w = W(c);
 | 
			
		||||
    buffer[pos++] = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map
 | 
			
		||||
    buffer[pos++] = scale8(qadd8(w, g), strip.getBrightness()); //G
 | 
			
		||||
    buffer[pos++] = scale8(qadd8(w, b), strip.getBrightness()); //B
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  wsc->binary(wsBuf);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -355,7 +355,7 @@ void getSettingsJS(byte subPage, char* dest)
 | 
			
		|||
    sappend('v',SET_F("CB"),strip.cctBlending);
 | 
			
		||||
    sappend('v',SET_F("FR"),strip.getTargetFps());
 | 
			
		||||
    sappend('v',SET_F("AW"),Bus::getGlobalAWMode());
 | 
			
		||||
    sappend('c',SET_F("LD"),strip.useLedsArray);
 | 
			
		||||
    sappend('c',SET_F("LD"),useGlobalLedBuffer);
 | 
			
		||||
 | 
			
		||||
    for (uint8_t s=0; s < busses.getNumBusses(); s++) {
 | 
			
		||||
      Bus* bus = busses.getBus(s);
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +382,7 @@ void getSettingsJS(byte subPage, char* dest)
 | 
			
		|||
      sappend('v',lt,bus->getType());
 | 
			
		||||
      sappend('v',co,bus->getColorOrder() & 0x0F);
 | 
			
		||||
      sappend('v',ls,bus->getStart());
 | 
			
		||||
      sappend('c',cv,bus->reversed);
 | 
			
		||||
      sappend('c',cv,bus->isReversed());
 | 
			
		||||
      sappend('v',sl,bus->skippedLeds());
 | 
			
		||||
      sappend('c',rf,bus->isOffRefreshRequired());
 | 
			
		||||
      sappend('v',aw,bus->getAutoWhiteMode());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue