Compare commits
	
		
			65 Commits
		
	
	
		
			copilot/fi
			...
			v0.15.1.be
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6572efbf9f | ||
|   | dbe76479a2 | ||
|   | dc3d463925 | ||
|   | f593d404cb | ||
|   | b75a2de485 | ||
|   | 642a9e3652 | ||
|   | 85d3f6f11c | ||
|   | f490908278 | ||
|   | 1fc3cc83bd | ||
|   | e96fd8ae58 | ||
|   | c46e328b59 | ||
|   | fa2f831044 | ||
|   | 1bf13ea525 | ||
|   | edc6022441 | ||
|   | 2ac4d03160 | ||
|   | cc4a4c4ae1 | ||
|   | 4e11ecda4b | ||
|   | 473700e4c0 | ||
|   | 0d5a0fb830 | ||
|   | 012143bd7b | ||
|   | 700a7076fd | ||
|   | 5fc2175dd4 | ||
|   | c9b95e22d3 | ||
|   | a265318037 | ||
|   | 866a4c8ab6 | ||
|   | 9dc1022010 | ||
|   | faadb67eb0 | ||
|   | a111a2e7a1 | ||
|   | 32864d8986 | ||
|   | d7bebc2659 | ||
|   | af410ae2d0 | ||
|   | 1891cc816f | ||
|   | 9a4073e606 | ||
|   | b78229d1e2 | ||
|   | 71b242874f | ||
|   | 9328e6faca | ||
|   | bbacc2daae | ||
|   | 3e22f9cabb | ||
|   | 685ad83d4b | ||
|   | 62ddb18a1a | ||
|   | 6a12378475 | ||
|   | d26b3108da | ||
|   | c89e4576b4 | ||
|   | bc79f44a26 | ||
|   | 7ece14ff3f | ||
|   | 0b3643132b | ||
|   | a5693fbf8d | ||
|   | 5c5b70f52b | ||
|   | ae97e388a6 | ||
|   | 37cddcaacc | ||
|   | a1b332fc78 | ||
|   | 86d7c24513 | ||
|   | b28add3b8b | ||
|   | 5fd3a513a4 | ||
|   | b98a8a10b0 | ||
|   | 2bee2793ef | ||
|   | 2f6fa66f4d | ||
|   | 5d38acd787 | ||
|   | e607fcb5c5 | ||
|   | 8a18555ae4 | ||
|   | beb709dc8f | ||
|   | 7a58c69a80 | ||
|   | 1082c85789 | ||
|   | 568d2edd96 | ||
|   | d2d56ebbd2 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -15,6 +15,7 @@ wled-update.sh | ||||
|  | ||||
| /build_output/ | ||||
| /node_modules/ | ||||
| /logs/ | ||||
|  | ||||
| /wled00/extLibs | ||||
| /wled00/LittleFS | ||||
|   | ||||
							
								
								
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,5 +1,23 @@ | ||||
| ## WLED changelog | ||||
|  | ||||
| #### Build 2412100 | ||||
| -   WLED 0.15.0 release | ||||
| -   Usermod BME280: Fix "Unit of Measurement" for temperature | ||||
| -   WiFi reconnect bugfix (@blazoncek) | ||||
|  | ||||
| #### Build 2411250 | ||||
| -   WLED 0.15.0-rc1 release | ||||
| -   Add support for esp32S3_wroom2 (#4243 by @softhack007) | ||||
| -   Fix mixed LED SK6812 and ws2812b booloop (#4301 by @willmmiles) | ||||
| -   Improved FPS calculation (by DedeHai) | ||||
| -   Fix crashes when using HTTP API within MQTT (#4269 by @willmmiles) | ||||
| -   Fix array overflow in exploding_fireworks (#4120 by @willmmiles) | ||||
| -   Fix MQTT topic buffer length (#4293 by @WouterGritter) | ||||
| -   Fix SparkFunDMX fix for possible array bounds violation in DMX.write (by @softhack007) | ||||
| -   Allow TV Simulator on single LED segments (by @softhack007) | ||||
| -   Fix WLED_RELEASE_NAME (by @netmindz) | ||||
|  | ||||
|  | ||||
| #### Build 2410270 | ||||
| -   WLED 0.15.0-b7 release | ||||
| -   Re-license the WLED project from MIT to EUPL (#4194 by @Aircoookie) | ||||
|   | ||||
							
								
								
									
										9
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,18 +1,21 @@ | ||||
| { | ||||
|   "name": "wled", | ||||
|   "version": "0.15.0-b7", | ||||
|   "version": "0.15.1.beta1", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "wled", | ||||
|       "version": "0.15.0-b7", | ||||
|       "version": "0.15.1.beta1", | ||||
|       "license": "ISC", | ||||
|       "dependencies": { | ||||
|         "clean-css": "^5.3.3", | ||||
|         "html-minifier-terser": "^7.2.0", | ||||
|         "inliner": "^1.13.1", | ||||
|         "nodemon": "^3.0.2" | ||||
|         "nodemon": "^3.1.7" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=20.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@jridgewell/gen-mapping": { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "wled", | ||||
|   "version": "0.15.0-b7", | ||||
|   "version": "0.15.1.beta2", | ||||
|   "description": "Tools for WLED project", | ||||
|   "main": "tools/cdata.js", | ||||
|   "directories": { | ||||
|   | ||||
| @@ -1,3 +1,21 @@ | ||||
| Import('env') | ||||
| Import("env") | ||||
| import shutil | ||||
|  | ||||
| env.Execute("npm run build") | ||||
| node_ex = shutil.which("node") | ||||
| # Check if Node.js is installed and present in PATH if it failed, abort the build | ||||
| if node_ex is None: | ||||
|     print('\x1b[0;31;43m' + 'Node.js is not installed or missing from PATH html css js will not be processed check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m') | ||||
|     exitCode = env.Execute("null") | ||||
|     exit(exitCode) | ||||
| else: | ||||
|     # Install the necessary node packages for the pre-build asset bundling script | ||||
|     print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m') | ||||
|     env.Execute("npm install") | ||||
|  | ||||
|     # Call the bundling script | ||||
|     exitCode = env.Execute("npm run build") | ||||
|  | ||||
|     # If it failed, abort the build | ||||
|     if (exitCode): | ||||
|       print('\x1b[0;31;43m' + 'npm run build fails check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m') | ||||
|       exit(exitCode) | ||||
| @@ -138,7 +138,7 @@ lib_compat_mode = strict | ||||
| lib_deps = | ||||
|     fastled/FastLED @ 3.6.0 | ||||
|     IRremoteESP8266 @ 2.8.2 | ||||
|     makuna/NeoPixelBus @ 2.8.0 | ||||
|     makuna/NeoPixelBus @ 2.8.3 | ||||
|     #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta | ||||
|     https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 | ||||
|   # for I2C interface | ||||
| @@ -176,6 +176,7 @@ lib_deps = | ||||
| extra_scripts = ${scripts_defaults.extra_scripts} | ||||
|  | ||||
| [esp8266] | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = | ||||
|   -DESP8266 | ||||
|   -DFP_IN_IROM | ||||
| @@ -242,6 +243,7 @@ lib_deps_compat = | ||||
| #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip | ||||
| platform = espressif32@3.5.0 | ||||
| platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4 | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = -g | ||||
|   -DARDUINO_ARCH_ESP32 | ||||
|   #-DCONFIG_LITTLEFS_FOR_IDF_3_2 | ||||
| @@ -263,6 +265,7 @@ lib_deps = | ||||
| AR_build_flags = -D USERMOD_AUDIOREACTIVE  | ||||
|   -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) | ||||
| AR_lib_deps = kosme/arduinoFFT @ 2.0.1 | ||||
| board_build.partitions = ${esp32.default_partitions}   ;; default partioning for 4MB Flash - can be overridden in build envs | ||||
|  | ||||
| [esp32_idf_V4] | ||||
| ;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5 | ||||
| @@ -272,6 +275,7 @@ AR_lib_deps = kosme/arduinoFFT @ 2.0.1 | ||||
| ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. | ||||
| platform = espressif32@ ~6.3.2 | ||||
| platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0    ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = -g | ||||
|   -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one | ||||
|   -DARDUINO_ARCH_ESP32 -DESP32 | ||||
| @@ -280,11 +284,13 @@ build_flags = -g | ||||
| lib_deps = | ||||
|   https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 | ||||
|   ${env.lib_deps} | ||||
| board_build.partitions = ${esp32.default_partitions}   ;; default partioning for 4MB Flash - can be overridden in build envs | ||||
|  | ||||
| [esp32s2] | ||||
| ;; generic definitions for all ESP32-S2 boards | ||||
| platform = espressif32@ ~6.3.2 | ||||
| platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0    ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = -g | ||||
|   -DARDUINO_ARCH_ESP32 | ||||
|   -DARDUINO_ARCH_ESP32S2 | ||||
| @@ -298,11 +304,13 @@ build_flags = -g | ||||
| lib_deps = | ||||
|   https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 | ||||
|   ${env.lib_deps} | ||||
| board_build.partitions = ${esp32.default_partitions}   ;; default partioning for 4MB Flash - can be overridden in build envs | ||||
|  | ||||
| [esp32c3] | ||||
| ;; generic definitions for all ESP32-C3 boards | ||||
| platform = espressif32@ ~6.3.2 | ||||
| platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0    ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = -g | ||||
|   -DARDUINO_ARCH_ESP32 | ||||
|   -DARDUINO_ARCH_ESP32C3 | ||||
| @@ -315,11 +323,13 @@ build_flags = -g | ||||
| lib_deps = | ||||
|   https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 | ||||
|   ${env.lib_deps} | ||||
| board_build.partitions = ${esp32.default_partitions}   ;; default partioning for 4MB Flash - can be overridden in build envs | ||||
|  | ||||
| [esp32s3] | ||||
| ;; generic definitions for all ESP32-S3 boards | ||||
| platform = espressif32@ ~6.3.2 | ||||
| platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0    ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = -g | ||||
|   -DESP32 | ||||
|   -DARDUINO_ARCH_ESP32 | ||||
| @@ -333,6 +343,7 @@ build_flags = -g | ||||
| lib_deps = | ||||
|   https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 | ||||
|   ${env.lib_deps} | ||||
| board_build.partitions = ${esp32.large_partitions}   ;; default partioning for 8MB flash - can be overridden in build envs | ||||
|  | ||||
|  | ||||
| # ------------------------------------------------------------------------------ | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| # Please visit documentation: https://docs.platformio.org/page/projectconf.html | ||||
|  | ||||
| [platformio] | ||||
| default_envs = WLED_tasmota_1M  # define as many as you need | ||||
| default_envs = WLED_generic8266_1M, esp32dev_V4_dio80  # put the name(s) of your own build environment here. You can define as many as you need | ||||
|  | ||||
| #---------- | ||||
| # SAMPLE | ||||
| @@ -28,8 +28,8 @@ lib_deps = ${esp8266.lib_deps} | ||||
| ;  robtillaart/SHT85@~0.3.3 | ||||
| ;  ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug | ||||
| ;  https://github.com/blazoncek/QuickESPNow.git#optional-debug  ;; exludes debug library | ||||
| ;  ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE | ||||
| ;  bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following | ||||
| ;  ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE | ||||
|  | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp8266.build_flags} | ||||
| @@ -141,7 +141,8 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} | ||||
| ;   -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering) | ||||
| ; | ||||
| ; Use Audioreactive usermod and configure I2S microphone | ||||
| ;   -D USERMOD_AUDIOREACTIVE | ||||
| ;   ${esp32.AR_build_flags} ;; default flags required to properly configure ArduinoFFT | ||||
| ;   ;; don't forget to add ArduinoFFT to your libs_deps: ${esp32.AR_lib_deps} | ||||
| ;   -D AUDIOPIN=-1 | ||||
| ;   -D DMTYPE=1     # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM | ||||
| ;   -D I2S_SDPIN=36 | ||||
| @@ -157,17 +158,22 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} | ||||
| ;   -D USERMOD_POV_DISPLAY | ||||
| ; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16) | ||||
| ;   -D STATUSLED=16 | ||||
| ;    | ||||
| ; | ||||
| ; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name | ||||
| ;   -D SERVERNAME="\"WLED\"" | ||||
| ;    | ||||
| ; | ||||
| ; set the number of LEDs | ||||
| ;   -D DEFAULT_LED_COUNT=30 | ||||
| ;   -D PIXEL_COUNTS=30 | ||||
| ; or this for multiple outputs | ||||
| ;   -D PIXEL_COUNTS=30,30 | ||||
| ; | ||||
| ; set the default LED type | ||||
| ;   -D DEFAULT_LED_TYPE=22    # see const.h (TYPE_xxxx) | ||||
| ;   -D LED_TYPES=22    # see const.h (TYPE_xxxx) | ||||
| ; or this for multiple outputs | ||||
| ;   -D LED_TYPES=TYPE_SK6812_RGBW,TYPE_WS2812_RGB | ||||
| ; | ||||
| ; set default color order of your led strip | ||||
| ;   -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB | ||||
| ; | ||||
| ; set milliampere limit when using ESP power pin (or inadequate PSU) to power LEDs | ||||
| ;   -D ABL_MILLIAMPS_DEFAULT=850 | ||||
| @@ -176,9 +182,6 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} | ||||
| ; enable IR by setting remote type | ||||
| ;   -D IRTYPE=0   # 0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote | ||||
| ;    | ||||
| ; set default color order of your led strip | ||||
| ;   -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB | ||||
| ; | ||||
| ; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues) | ||||
| ;   -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue   # needed only for classic ESP32 rev.1 | ||||
| ; | ||||
| @@ -236,14 +239,13 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLE | ||||
| lib_deps = ${esp8266.lib_deps} | ||||
|  | ||||
| [env:esp32dev_qio80] | ||||
| extends = env:esp32dev  # we want to extend the existing esp32dev environment (and define only updated options) | ||||
| board = esp32dev | ||||
| platform = ${esp32.platform} | ||||
| platform_packages = ${esp32.platform_packages} | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET | ||||
|   ${esp32.AR_build_flags} ;; optional - includes USERMOD_AUDIOREACTIVE | ||||
| lib_deps = ${esp32.lib_deps} | ||||
|   ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE | ||||
| monitor_filters = esp32_exception_decoder | ||||
| board_build.partitions = ${esp32.default_partitions} | ||||
| board_build.f_flash = 80000000L | ||||
| board_build.flash_mode = qio | ||||
|  | ||||
| @@ -251,26 +253,25 @@ board_build.flash_mode = qio | ||||
| ;; experimental ESP32 env using ESP-IDF V4.4.x | ||||
| ;; Warning: this build environment is not stable!! | ||||
| ;; please erase your device before installing. | ||||
| extends = esp32_idf_V4  # based on newer "esp-idf V4" platform environment | ||||
| board = esp32dev | ||||
| platform = ${esp32_idf_V4.platform} | ||||
| platform_packages = ${esp32_idf_V4.platform_packages} | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags}  ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET | ||||
|   ${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE | ||||
| lib_deps = ${esp32_idf_V4.lib_deps} | ||||
|   ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE | ||||
| monitor_filters = esp32_exception_decoder | ||||
| board_build.partitions = ${esp32_idf_V4.default_partitions} | ||||
| board_build.partitions = ${esp32.default_partitions}  ;; if you get errors about "out of program space", change this to ${esp32.extended_partitions} or even ${esp32.big_partitions} | ||||
| board_build.f_flash = 80000000L | ||||
| board_build.flash_mode = dio | ||||
|  | ||||
| [env:esp32s2_saola] | ||||
| extends = esp32s2 | ||||
| board = esp32-s2-saola-1 | ||||
| platform = ${esp32s2.platform} | ||||
| platform_packages = ${esp32s2.platform_packages} | ||||
| framework = arduino | ||||
| board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv | ||||
| board_build.flash_mode = qio | ||||
| upload_speed = 460800 | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp32s2.build_flags} | ||||
|   ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work | ||||
|   -DARDUINO_USB_CDC_ON_BOOT=1 | ||||
| @@ -307,7 +308,7 @@ platform = ${common.platform_wled_default} | ||||
| platform_packages = ${common.platform_packages} | ||||
| board_build.ldscript = ${common.ldscript_4m1m} | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB | ||||
| build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB ;; NB: WLED_USE_SHOJO_PCB is not used anywhere in the source code. Not sure why its needed. | ||||
| lib_deps = ${esp8266.lib_deps} | ||||
|  | ||||
| [env:d1_mini_debug] | ||||
| @@ -362,35 +363,48 @@ board_upload.flash_size = 2MB | ||||
| board_upload.maximum_size = 2097152 | ||||
|  | ||||
| [env:wemos_shield_esp32] | ||||
| extends = esp32              ;; use default esp32 platform | ||||
| board = esp32dev | ||||
| platform = ${esp32.platform} | ||||
| platform_packages = ${esp32.platform_packages} | ||||
| upload_speed = 460800 | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp32.build_flags} | ||||
|   -D WLED_RELEASE_NAME=\"ESP32_wemos_shield\" | ||||
|   -D DATA_PINS=16 | ||||
|   -D RLYPIN=19 | ||||
|   -D BTNPIN=17 | ||||
|   -D IRPIN=18 | ||||
|   -D UWLED_USE_MY_CONFIG | ||||
|   -UWLED_USE_MY_CONFIG | ||||
|   -D USERMOD_DALLASTEMPERATURE | ||||
|   -D USERMOD_FOUR_LINE_DISPLAY | ||||
|   -D TEMPERATURE_PIN=23 | ||||
|   -D USERMOD_AUDIOREACTIVE | ||||
|   ${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE | ||||
| lib_deps = ${esp32.lib_deps} | ||||
|   OneWire@~2.3.5 | ||||
|   olikraus/U8g2 @ ^2.28.8 | ||||
|   https://github.com/blazoncek/arduinoFFT.git | ||||
|   OneWire@~2.3.5          ;; needed for USERMOD_DALLASTEMPERATURE | ||||
|   olikraus/U8g2 @ ^2.28.8 ;; needed for USERMOD_FOUR_LINE_DISPLAY | ||||
|   ${esp32.AR_lib_deps}    ;; needed for USERMOD_AUDIOREACTIVE | ||||
| board_build.partitions = ${esp32.default_partitions} | ||||
|  | ||||
| [env:m5atom] | ||||
| board = esp32dev | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39 | ||||
| [env:esp32_pico-D4] | ||||
| extends = esp32              ;; use default esp32 platform | ||||
| board = pico32               ;; pico32-D4 is different from the standard esp32dev | ||||
|                              ;; hardware details from https://github.com/srg74/WLED-ESP32-pico | ||||
| build_flags = ${common.build_flags} ${esp32.build_flags} | ||||
|   -D WLED_RELEASE_NAME=\"pico32-D4\" -D SERVERNAME='"WLED-pico32"' | ||||
|   -D WLED_DISABLE_ADALIGHT   ;; no serial-to-USB chip on this board - better to disable serial protocols | ||||
|   -D DATA_PINS=2,18          ;; LED pins | ||||
|   -D RLYPIN=19 -D BTNPIN=0 -D IRPIN=-1 ;; no default pin for IR | ||||
|   ${esp32.AR_build_flags}    ;; include USERMOD_AUDIOREACTIVE | ||||
|   -D UM_AUDIOREACTIVE_ENABLE ;; enable AR by default | ||||
|   ;; Audioreactive settings for on-board microphone (ICS-43432) | ||||
|   -D SR_DMTYPE=1 -D I2S_SDPIN=25 -D I2S_WSPIN=15 -D I2S_CKPIN=14 | ||||
|   -D SR_SQUELCH=5 -D SR_GAIN=30 | ||||
| lib_deps = ${esp32.lib_deps} | ||||
| platform = ${esp32.platform} | ||||
| platform_packages = ${esp32.platform_packages} | ||||
|   ${esp32.AR_lib_deps}       ;; needed for USERMOD_AUDIOREACTIVE | ||||
| board_build.partitions = ${esp32.default_partitions} | ||||
| board_build.f_flash = 80000000L | ||||
|  | ||||
| [env:m5atom] | ||||
| extends = env:esp32dev  # we want to extend the existing esp32dev environment (and define only updated options) | ||||
| build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39 | ||||
|  | ||||
| [env:sp501e] | ||||
| board = esp_wroom_02 | ||||
| @@ -413,7 +427,7 @@ platform_packages = ${common.platform_packages} | ||||
| board_build.ldscript = ${common.ldscript_2m512k} | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5 | ||||
|                                             -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 | ||||
|                                             -D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 | ||||
| lib_deps = ${esp8266.lib_deps} | ||||
|  | ||||
| [env:Athom_15w_RGBCW]        ;15w bulb | ||||
| @@ -423,7 +437,7 @@ platform_packages = ${common.platform_packages} | ||||
| board_build.ldscript = ${common.ldscript_2m512k} | ||||
| build_unflags = ${common.build_unflags} | ||||
| build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13 | ||||
|                                             -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT | ||||
|                                             -D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT | ||||
| lib_deps = ${esp8266.lib_deps} | ||||
|  | ||||
| [env:Athom_3Pin_Controller]        ;small controller with only data | ||||
| @@ -489,9 +503,8 @@ lib_deps = ${esp8266.lib_deps} | ||||
| # EleksTube-IPS | ||||
| # ------------------------------------------------------------------------------ | ||||
| [env:elekstube_ips] | ||||
| extends = esp32              ;; use default esp32 platform | ||||
| board = esp32dev | ||||
| platform = ${esp32.platform} | ||||
| platform_packages = ${esp32.platform_packages} | ||||
| upload_speed = 921600 | ||||
| build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED | ||||
|   -D USERMOD_RTC | ||||
| @@ -499,7 +512,7 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU | ||||
|   -D DATA_PINS=12 | ||||
|   -D RLYPIN=27 | ||||
|   -D BTNPIN=34 | ||||
|   -D DEFAULT_LED_COUNT=6 | ||||
|   -D PIXEL_COUNTS=6 | ||||
|   # Display config | ||||
|   -D ST7789_DRIVER | ||||
|   -D TFT_WIDTH=135 | ||||
| @@ -515,5 +528,4 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU | ||||
| monitor_filters = esp32_exception_decoder | ||||
| lib_deps = | ||||
|   ${esp32.lib_deps} | ||||
|   TFT_eSPI @ ^2.3.70 | ||||
| board_build.partitions = ${esp32.default_partitions} | ||||
|   TFT_eSPI @ 2.5.33  ;; this is the last version that compiles with the WLED default framework - newer versions require platform = espressif32 @ ^6.3.2 | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								tools/AutoCubeMap.xlsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tools/AutoCubeMap.xlsx
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -444,6 +444,7 @@ public: | ||||
|     configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false); | ||||
|     configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true); | ||||
|     configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false); | ||||
|     tempScale = UseCelsius ? "°C" : "°F"; | ||||
|  | ||||
|     DEBUG_PRINT(FPSTR(_name)); | ||||
|     if (!initDone) { | ||||
|   | ||||
| @@ -75,7 +75,7 @@ static uint8_t  soundAgc = 0;                   // Automagic gain control: 0 - n | ||||
| //static float    volumeSmth = 0.0f;              // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample | ||||
| static float FFT_MajorPeak = 1.0f;              // FFT: strongest (peak) frequency | ||||
| static float FFT_Magnitude = 0.0f;              // FFT: volume (magnitude) of peak frequency | ||||
| static bool samplePeak = false;      // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay() | ||||
| static bool samplePeak = false;      // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getFrameTime() | ||||
| static bool udpSamplePeak = false;   // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData | ||||
| static unsigned long timeOfPeak = 0; // time of last sample peak detection. | ||||
| static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects | ||||
| @@ -536,8 +536,8 @@ static void detectSamplePeak(void) { | ||||
| #endif | ||||
|  | ||||
| static void autoResetPeak(void) { | ||||
|   uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay());  // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC | ||||
|   if (millis() - timeOfPeak > MinShowDelay) {          // Auto-reset of samplePeak after a complete frame has passed. | ||||
|   uint16_t peakDelay = max(uint16_t(50), strip.getFrameTime()); | ||||
|   if (millis() - timeOfPeak > peakDelay) {          // Auto-reset of samplePeak after at least one complete frame has passed. | ||||
|     samplePeak = false; | ||||
|     if (audioSyncEnabled == 0) udpSamplePeak = false;  // this is normally reset by transmitAudioData | ||||
|   } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ The actual / original code that controls the LED modes is from Adam Zeloof. I ta | ||||
| It was quite a bit more work than I hoped, but I got there eventually :) | ||||
|  | ||||
| ## Requirements | ||||
| * "ESP Rotary" by Lennart Hennigs, v1.5.0 or higher: https://github.com/LennartHennigs/ESPRotary | ||||
| * "ESP Rotary" by Lennart Hennigs, v2.1.1 or higher: https://github.com/LennartHennigs/ESPRotary | ||||
|  | ||||
| ## Usermod installation | ||||
| Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one and add the buildflag `-D RGB_ROTARY_ENCODER`. | ||||
| @@ -20,7 +20,7 @@ ESP32: | ||||
| extends = env:esp32dev | ||||
| build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER | ||||
| lib_deps = ${esp32.lib_deps} | ||||
|     lennarthennigs/ESP Rotary@^1.5.0 | ||||
|     lennarthennigs/ESP Rotary@^2.1.1 | ||||
| ``` | ||||
|  | ||||
| ESP8266 / D1 Mini: | ||||
| @@ -29,7 +29,7 @@ ESP8266 / D1 Mini: | ||||
| extends = env:d1_mini | ||||
| build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER | ||||
| lib_deps = ${esp8266.lib_deps} | ||||
|     lennarthennigs/ESP Rotary@^1.5.0 | ||||
|     lennarthennigs/ESP Rotary@^2.1.1 | ||||
| ``` | ||||
|  | ||||
| ## How to connect the board to your ESP | ||||
|   | ||||
| @@ -600,11 +600,12 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0"; | ||||
|  * Dissolve function | ||||
|  */ | ||||
| uint16_t dissolve(uint32_t color) { | ||||
|   unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED | ||||
|   unsigned dataSize = sizeof(uint32_t) * SEGLEN; | ||||
|   if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed | ||||
|   uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     memset(SEGMENT.data, 0xFF, dataSize); // start by fading pixels up | ||||
|     for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = SEGCOLOR(1); | ||||
|     SEGENV.aux0 = 1; | ||||
|   } | ||||
|  | ||||
| @@ -612,33 +613,26 @@ uint16_t dissolve(uint32_t color) { | ||||
|     if (random8() <= SEGMENT.intensity) { | ||||
|       for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times | ||||
|         unsigned i = random16(SEGLEN); | ||||
|         unsigned index = i >> 3; | ||||
|         unsigned bitNum = i & 0x07; | ||||
|         bool fadeUp = bitRead(SEGENV.data[index], bitNum); | ||||
|         if (SEGENV.aux0) { //dissolve to primary/palette | ||||
|           if (fadeUp) { | ||||
|             if (color == SEGCOLOR(0)) { | ||||
|               SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); | ||||
|             } else { | ||||
|               SEGMENT.setPixelColor(i, color); | ||||
|             } | ||||
|             bitWrite(SEGENV.data[index], bitNum, false); | ||||
|           if (pixels[i] == SEGCOLOR(1)) { | ||||
|             pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color; | ||||
|             break; //only spawn 1 new pixel per frame per 50 LEDs | ||||
|           } | ||||
|         } else { //dissolve to secondary | ||||
|           if (!fadeUp) { | ||||
|             SEGMENT.setPixelColor(i, SEGCOLOR(1)); break; | ||||
|             bitWrite(SEGENV.data[index], bitNum, true); | ||||
|           if (pixels[i] != SEGCOLOR(1)) { | ||||
|             pixels[i] = SEGCOLOR(1); | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   // fix for #4401 | ||||
|   for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]); | ||||
|  | ||||
|   if (SEGENV.step > (255 - SEGMENT.speed) + 15U) { | ||||
|     SEGENV.aux0 = !SEGENV.aux0; | ||||
|     SEGENV.step = 0; | ||||
|     memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading | ||||
|   } else { | ||||
|     SEGENV.step++; | ||||
|   } | ||||
| @@ -1097,7 +1091,7 @@ uint16_t mode_running_random(void) { | ||||
|  | ||||
|   unsigned z = it % zoneSize; | ||||
|   bool nzone = (!z && it != SEGENV.aux1); | ||||
|   for (unsigned i=SEGLEN-1; i > 0; i--) { | ||||
|   for (int i=SEGLEN-1; i >= 0; i--) { | ||||
|     if (nzone || z >= zoneSize) { | ||||
|       unsigned lastrand = PRNG16 >> 8; | ||||
|       int16_t diff = 0; | ||||
| @@ -1441,7 +1435,7 @@ uint16_t mode_fairy() { | ||||
|     if (z == zones-1) flashersInZone = numFlashers-(flashersInZone*(zones-1)); | ||||
|  | ||||
|     for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) { | ||||
|       unsigned stateTime = now16 - flashers[f].stateStart; | ||||
|       unsigned stateTime = uint16_t(now16 - flashers[f].stateStart); | ||||
|       //random on/off time reached, switch state | ||||
|       if (stateTime > flashers[f].stateDur * 10) { | ||||
|         flashers[f].stateOn = !flashers[f].stateOn; | ||||
| @@ -1500,7 +1494,7 @@ uint16_t mode_fairytwinkle() { | ||||
|   unsigned maxDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + 13 + ((255 - SEGMENT.intensity) >> 1); | ||||
|  | ||||
|   for (int f = 0; f < SEGLEN; f++) { | ||||
|     unsigned stateTime = now16 - flashers[f].stateStart; | ||||
|     uint16_t stateTime = now16 - flashers[f].stateStart; | ||||
|     //random on/off time reached, switch state | ||||
|     if (stateTime > flashers[f].stateDur * 100) { | ||||
|       flashers[f].stateOn = !flashers[f].stateOn; | ||||
| @@ -1745,7 +1739,7 @@ uint16_t mode_random_chase(void) { | ||||
|   uint32_t color = SEGENV.step; | ||||
|   random16_set_seed(SEGENV.aux0); | ||||
|  | ||||
|   for (unsigned i = SEGLEN -1; i > 0; i--) { | ||||
|   for (int i = SEGLEN -1; i >= 0; i--) { | ||||
|     uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8(); | ||||
|     uint8_t g = random8(6) != 0 ? (color >> 8  & 0xFF) : random8(); | ||||
|     uint8_t b = random8(6) != 0 ? (color       & 0xFF) : random8(); | ||||
| @@ -1798,7 +1792,7 @@ uint16_t mode_oscillate(void) { | ||||
|     // if the counter has increased, move the oscillator by the random step | ||||
|     if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed; | ||||
|     oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8); | ||||
|     if((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) { | ||||
|     if((oscillators[i].dir == -1) && (oscillators[i].pos > SEGLEN << 1)) { // use integer overflow | ||||
|       oscillators[i].pos = 0; | ||||
|       oscillators[i].dir = 1; | ||||
|       // make bigger steps for faster speeds | ||||
| @@ -1814,8 +1808,8 @@ uint16_t mode_oscillate(void) { | ||||
|   for (unsigned i = 0; i < SEGLEN; i++) { | ||||
|     uint32_t color = BLACK; | ||||
|     for (unsigned j = 0; j < numOscillators; j++) { | ||||
|       if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { | ||||
|         color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128); | ||||
|       if((int)i >= (int)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { | ||||
|         color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128)); | ||||
|       } | ||||
|     } | ||||
|     SEGMENT.setPixelColor(i, color); | ||||
| @@ -2003,7 +1997,7 @@ uint16_t mode_palette() { | ||||
|       const mathType sourceX = xtSinTheta + ytCosTheta + centerX; | ||||
|       // The computation was scaled just right so that the result should always be in range [0, maxXOut], but enforce this anyway | ||||
|       // to account for imprecision. Then scale it so that the range is [0, 255], which we can use with the palette. | ||||
|       int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * 255) / (sInt16Scale * maxXOut); | ||||
|       int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * wideMathType(255)) / (sInt16Scale * maxXOut); | ||||
|       // inputSize determines by how much we want to scale the palette: | ||||
|       // values < 128 display a fraction of a palette, | ||||
|       // values > 128 display multiple palettes. | ||||
| @@ -2565,11 +2559,11 @@ static CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) | ||||
| { | ||||
|   // Overall twinkle speed (changed) | ||||
|   unsigned ticks = ms / SEGENV.aux0; | ||||
|   unsigned fastcycle8 = ticks; | ||||
|   unsigned slowcycle16 = (ticks >> 8) + salt; | ||||
|   unsigned fastcycle8 = uint8_t(ticks); | ||||
|   uint16_t slowcycle16 = (ticks >> 8) + salt; | ||||
|   slowcycle16 += sin8_t(slowcycle16); | ||||
|   slowcycle16 = (slowcycle16 * 2053) + 1384; | ||||
|   unsigned slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); | ||||
|   uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); | ||||
|  | ||||
|   // Overall twinkle density. | ||||
|   // 0 (NONE lit) to 8 (ALL lit at once). | ||||
| @@ -5170,7 +5164,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: | ||||
|         neighbors++; | ||||
|         bool colorFound = false; | ||||
|         int k; | ||||
|         for (k=0; k<9 && colorsCount[i].count != 0; k++) | ||||
|         for (k=0; k<9 && colorsCount[k].count != 0; k++) | ||||
|           if (colorsCount[k].color == prevLeds[xy]) { | ||||
|             colorsCount[k].count++; | ||||
|             colorFound = true; | ||||
| @@ -6639,14 +6633,16 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!; | ||||
| //   * MATRIPIX     // | ||||
| ////////////////////// | ||||
| uint16_t mode_matripix(void) {                  // Matripix. By Andrew Tuline. | ||||
|   if (SEGLEN == 1) return mode_static(); | ||||
|   // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment | ||||
|   // effect can work on single pixels, we just lose the shifting effect | ||||
|   unsigned dataSize = sizeof(uint32_t) * SEGLEN; | ||||
|   if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed | ||||
|   uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | ||||
|  | ||||
|   um_data_t *um_data = getAudioData(); | ||||
|   int volumeRaw    = *(int16_t*)um_data->u_data[1]; | ||||
|  | ||||
|   if (SEGENV.call == 0) { | ||||
|     SEGMENT.fill(BLACK); | ||||
|     for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK;   // may not be needed as resetIfRequired() clears buffer | ||||
|   } | ||||
|  | ||||
|   uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; | ||||
| @@ -6654,8 +6650,14 @@ uint16_t mode_matripix(void) {                  // Matripix. By Andrew Tuline. | ||||
|     SEGENV.aux0 = secondHand; | ||||
|  | ||||
|     int pixBri = volumeRaw * SEGMENT.intensity / 64; | ||||
|     for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left | ||||
|     SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri)); | ||||
|     unsigned k = SEGLEN-1; | ||||
|     // loop will not execute if SEGLEN equals 1 | ||||
|     for (unsigned i = 0; i < k; i++) { | ||||
|       pixels[i] = pixels[i+1]; // shift left | ||||
|       SEGMENT.setPixelColor(i, pixels[i]); | ||||
|     } | ||||
|     pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri); | ||||
|     SEGMENT.setPixelColor(k, pixels[k]); | ||||
|   } | ||||
|  | ||||
|   return FRAMETIME; | ||||
| @@ -7283,8 +7285,11 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12= | ||||
| // Combines peak detection with FFT_MajorPeak and FFT_Magnitude. | ||||
| uint16_t mode_waterfall(void) {                   // Waterfall. By: Andrew Tuline | ||||
|   // effect can work on single pixels, we just lose the shifting effect | ||||
|    | ||||
|   um_data_t *um_data = getAudioData(); | ||||
|   unsigned dataSize = sizeof(uint32_t) * SEGLEN; | ||||
|   if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed | ||||
|   uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | ||||
|  | ||||
|   um_data_t *um_data    = getAudioData(); | ||||
|   uint8_t samplePeak    = *(uint8_t*)um_data->u_data[3]; | ||||
|   float   FFT_MajorPeak = *(float*)  um_data->u_data[4]; | ||||
|   uint8_t *maxVol       =  (uint8_t*)um_data->u_data[6]; | ||||
| @@ -7294,7 +7299,7 @@ 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.fill(BLACK); | ||||
|     for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK;   // may not be needed as resetIfRequired() clears buffer | ||||
|     SEGENV.aux0 = 255; | ||||
|     SEGMENT.custom1 = *binNum; | ||||
|     SEGMENT.custom2 = *maxVol * 2; | ||||
| @@ -7311,13 +7316,18 @@ uint16_t mode_waterfall(void) {                   // Waterfall. By: Andrew Tulin | ||||
|     uint8_t pixCol = (log10f(FFT_MajorPeak) - 2.26f) * 150;           // 22Khz sampling - log10 frequency range is from 2.26 (182hz) to 3.967 (9260hz). Let's scale accordingly. | ||||
|     if (FFT_MajorPeak < 182.0f) pixCol = 0;                           // handle underflow | ||||
|  | ||||
|     unsigned k = SEGLEN-1; | ||||
|     if (samplePeak) { | ||||
|       SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92)); | ||||
|       pixels[k] = (uint32_t)CRGB(CHSV(92,92,92)); | ||||
|     } else { | ||||
|       SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); | ||||
|       pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude); | ||||
|     } | ||||
|     SEGMENT.setPixelColor(k, pixels[k]); | ||||
|     // loop will not execute if SEGLEN equals 1 | ||||
|     for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left | ||||
|     for (unsigned i = 0; i < k; i++) { | ||||
|       pixels[i] = pixels[i+1]; // shift left | ||||
|       SEGMENT.setPixelColor(i, pixels[i]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return FRAMETIME; | ||||
|   | ||||
							
								
								
									
										41
									
								
								wled00/FX.h
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								wled00/FX.h
									
									
									
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| #pragma once | ||||
| /* | ||||
|   WS2812FX.h - Library for WS2812 LED effects. | ||||
|   Harm Aldick - 2016 | ||||
| @@ -8,12 +9,15 @@ | ||||
|   Adapted from code originally licensed under the MIT license | ||||
|  | ||||
|   Modified for WLED | ||||
|  | ||||
|   Segment class/struct (c) 2022 Blaz Kristan (@blazoncek) | ||||
| */ | ||||
|  | ||||
| #ifndef WS2812FX_h | ||||
| #define WS2812FX_h | ||||
|  | ||||
| #include <vector> | ||||
| #include "wled.h" | ||||
|  | ||||
| #include "const.h" | ||||
|  | ||||
| @@ -46,6 +50,14 @@ | ||||
| #define WLED_FPS         42 | ||||
| #define FRAMETIME_FIXED  (1000/WLED_FPS) | ||||
| #define FRAMETIME        strip.getFrameTime() | ||||
| #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
|   #define MIN_FRAME_DELAY  2                                              // minimum wait between repaints, to keep other functions like WiFi alive  | ||||
| #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|   #define MIN_FRAME_DELAY  3                                              // S2/C3 are slower than normal esp32, and only have one core | ||||
| #else | ||||
|   #define MIN_FRAME_DELAY  8                                              // 8266 legacy MIN_SHOW_DELAY | ||||
| #endif | ||||
| #define FPS_UNLIMITED    0 | ||||
|  | ||||
| // FPS calculation (can be defined as compile flag for debugging) | ||||
| #ifndef FPS_CALC_AVG | ||||
| @@ -59,26 +71,21 @@ | ||||
| /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of | ||||
|   insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ | ||||
| #ifdef ESP8266 | ||||
|   #define MAX_NUM_SEGMENTS    16 | ||||
|   #define MAX_NUM_SEGMENTS  16 | ||||
|   /* How much data bytes all segments combined may allocate */ | ||||
|   #define MAX_SEGMENT_DATA  5120 | ||||
| #elif defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
|   #define MAX_NUM_SEGMENTS  20 | ||||
|   #define MAX_SEGMENT_DATA  (MAX_NUM_SEGMENTS*512)  // 10k by default (S2 is short on free RAM) | ||||
| #else | ||||
|   #ifndef MAX_NUM_SEGMENTS | ||||
|     #define MAX_NUM_SEGMENTS  32 | ||||
|   #endif | ||||
|   #if defined(ARDUINO_ARCH_ESP32S2) | ||||
|     #define MAX_SEGMENT_DATA  MAX_NUM_SEGMENTS*768 // 24k by default (S2 is short on free RAM) | ||||
|   #else | ||||
|     #define MAX_SEGMENT_DATA  MAX_NUM_SEGMENTS*1280 // 40k by default | ||||
|   #endif | ||||
|   #define MAX_NUM_SEGMENTS  32  // warning: going beyond 32 may consume too much RAM for stable operation | ||||
|   #define MAX_SEGMENT_DATA  (MAX_NUM_SEGMENTS*1280) // 40k by default | ||||
| #endif | ||||
|  | ||||
| /* How much data bytes each segment should max allocate to leave enough space for other segments, | ||||
|   assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ | ||||
| #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip.getMaxSegments()) | ||||
|  | ||||
| #define MIN_SHOW_DELAY   (_frametime < 16 ? 8 : 15) | ||||
|  | ||||
| #define NUM_COLORS       3 /* number of colors per segment */ | ||||
| #define SEGMENT          strip._segments[strip.getCurrSegmentId()] | ||||
| #define SEGENV           strip._segments[strip.getCurrSegmentId()] | ||||
| @@ -524,6 +531,9 @@ typedef struct Segment { | ||||
|     inline uint16_t length()             const { return width() * height(); }               // segment length (count) in physical pixels | ||||
|     inline uint16_t groupLength()        const { return grouping + spacing; } | ||||
|     inline uint8_t  getLightCapabilities() const { return _capabilities; } | ||||
|     inline void     deactivate()               { setGeometry(0,0); } | ||||
|     inline Segment &clearName()                { if (name) free(name); name = nullptr; return *this; } | ||||
|     inline Segment &setName(const String &name) { return setName(name.c_str()); } | ||||
|  | ||||
|     inline static uint16_t getUsedSegmentData()    { return _usedSegmentData; } | ||||
|     inline static void addUsedSegmentData(int len) { _usedSegmentData += len; } | ||||
| @@ -533,14 +543,15 @@ typedef struct Segment { | ||||
|     static void     handleRandomPalette(); | ||||
|     inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } | ||||
|  | ||||
|     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    setGeometry(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); | ||||
|     Segment &setColor(uint8_t slot, uint32_t c); | ||||
|     Segment &setCCT(uint16_t k); | ||||
|     Segment &setOpacity(uint8_t o); | ||||
|     Segment &setOption(uint8_t n, bool val); | ||||
|     Segment &setMode(uint8_t fx, bool loadDefaults = false); | ||||
|     Segment &setPalette(uint8_t pal); | ||||
|     uint8_t differs(Segment& b) const; | ||||
|     Segment &setName(const char* name); | ||||
|     uint8_t differs(const Segment& b) const; | ||||
|     void    refreshLightCapabilities(); | ||||
|  | ||||
|     // runtime data functions | ||||
| @@ -748,6 +759,7 @@ class WS2812FX {  // 96 bytes | ||||
|       customMappingTable(nullptr), | ||||
|       customMappingSize(0), | ||||
|       _lastShow(0), | ||||
|       _lastServiceShow(0), | ||||
|       _segment_index(0), | ||||
|       _mainSegment(0) | ||||
|     { | ||||
| @@ -846,7 +858,7 @@ class WS2812FX {  // 96 bytes | ||||
|       getMappedPixelIndex(uint16_t index) const; | ||||
|  | ||||
|     inline uint16_t getFrameTime() const    { return _frametime; }        // returns amount of time a frame should take (in ms) | ||||
|     inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; }    // returns minimum amount of time strip.service() can be delayed (constant) | ||||
|     inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; }   // returns minimum amount of time strip.service() can be delayed (constant) | ||||
|     inline uint16_t getLength() const       { return _length; }           // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) | ||||
|     inline uint16_t getTransition() const   { return _transitionDur; }    // returns currently set transition time (in ms) | ||||
|  | ||||
| @@ -958,6 +970,7 @@ class WS2812FX {  // 96 bytes | ||||
|     uint16_t  customMappingSize; | ||||
|  | ||||
|     unsigned long _lastShow; | ||||
|     unsigned long _lastServiceShow; | ||||
|  | ||||
|     uint8_t _segment_index; | ||||
|     uint8_t _mainSegment; | ||||
|   | ||||
| @@ -456,7 +456,7 @@ void Segment::handleRandomPalette() { | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| void Segment::setGeometry(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 | ||||
|   bool boundsUnchanged = (start == i1 && stop == i2); | ||||
|   #ifndef WLED_DISABLE_2D | ||||
| @@ -601,6 +601,20 @@ Segment &Segment::setPalette(uint8_t pal) { | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| Segment &Segment::setName(const char *newName) { | ||||
|   if (newName) { | ||||
|     const int newLen = min(strlen(newName), (size_t)WLED_MAX_SEGNAME_LEN); | ||||
|     if (newLen) { | ||||
|       if (name) name = static_cast<char*>(realloc(name, newLen+1)); | ||||
|       else      name = static_cast<char*>(malloc(newLen+1)); | ||||
|       if (name) strlcpy(name, newName, newLen+1); | ||||
|       name[newLen] = 0; | ||||
|       return *this; | ||||
|     } | ||||
|   } | ||||
|   return clearName(); | ||||
| } | ||||
|  | ||||
| // 2D matrix | ||||
| unsigned IRAM_ATTR Segment::virtualWidth() const { | ||||
|   unsigned groupLen = groupLength(); | ||||
| @@ -951,7 +965,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const | ||||
|   return strip.getPixelColor(i); | ||||
| } | ||||
|  | ||||
| uint8_t Segment::differs(Segment& b) const { | ||||
| uint8_t Segment::differs(const Segment& b) const { | ||||
|   uint8_t d = 0; | ||||
|   if (start != b.start)         d |= SEG_DIFFERS_BOUNDS; | ||||
|   if (stop != b.stop)           d |= SEG_DIFFERS_BOUNDS; | ||||
| @@ -1192,6 +1206,34 @@ void WS2812FX::finalizeInit() { | ||||
|  | ||||
|   _hasWhiteChannel = _isOffRefreshRequired = false; | ||||
|  | ||||
|   unsigned digitalCount = 0; | ||||
|   #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|   // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) | ||||
|   unsigned maxLedsOnBus = 0; | ||||
|   for (const auto &bus : busConfigs) { | ||||
|     if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) { | ||||
|       digitalCount++; | ||||
|       if (bus.count > maxLedsOnBus) maxLedsOnBus = bus.count; | ||||
|     } | ||||
|   } | ||||
|   DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); | ||||
|   // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 | ||||
|   if (maxLedsOnBus <= 300 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses | ||||
|   else useParallelI2S = false; // enforce single I2S | ||||
|   #endif | ||||
|  | ||||
|   // create buses/outputs | ||||
|   unsigned mem = 0; | ||||
|   digitalCount = 0; | ||||
|   for (const auto &bus : busConfigs) { | ||||
|     mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // includes global buffer | ||||
|     if (mem <= MAX_LED_MEMORY) { | ||||
|       if (BusManager::add(bus) == -1) break; | ||||
|     } else DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus %d (%d) #%u not created."), (int)bus.type, (int)bus.count, digitalCount); | ||||
|   } | ||||
|   busConfigs.clear(); | ||||
|   busConfigs.shrink_to_fit(); | ||||
|  | ||||
|   //if busses failed to load, add default (fresh install, FS issue, ...) | ||||
|   if (BusManager::getNumBusses() == 0) { | ||||
|     DEBUG_PRINTLN(F("No busses, init default")); | ||||
| @@ -1207,6 +1249,7 @@ void WS2812FX::finalizeInit() { | ||||
|      | ||||
|     unsigned prevLen = 0; | ||||
|     unsigned pinsIndex = 0; | ||||
|     digitalCount = 0; | ||||
|     for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { | ||||
|       uint8_t defPin[OUTPUT_MAX_PINS]; | ||||
|       // if we have less types than requested outputs and they do not align, use last known type to set current type | ||||
| @@ -1271,9 +1314,11 @@ void WS2812FX::finalizeInit() { | ||||
|       if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1; | ||||
|       prevLen += count; | ||||
|       BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); | ||||
|       mem += defCfg.memUsage(Bus::isDigital(dataType) && !Bus::is2Pin(dataType) ? digitalCount++ : 0); | ||||
|       if (BusManager::add(defCfg) == -1) break; | ||||
|     } | ||||
|   } | ||||
|   DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::memUsage()); | ||||
|  | ||||
|   _length = 0; | ||||
|   for (int i=0; i<BusManager::getNumBusses(); i++) { | ||||
| @@ -1290,6 +1335,7 @@ void WS2812FX::finalizeInit() { | ||||
|     // This must be done after all buses have been created, as some kinds (parallel I2S) interact | ||||
|     bus->begin(); | ||||
|   } | ||||
|   DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); | ||||
|  | ||||
|   Segment::maxWidth  = _length; | ||||
|   Segment::maxHeight = 1; | ||||
| @@ -1304,7 +1350,14 @@ void WS2812FX::finalizeInit() { | ||||
| void WS2812FX::service() { | ||||
|   unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days | ||||
|   now = nowUp + timebase; | ||||
|   if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return; | ||||
|   if (_suspend) return; | ||||
|   unsigned long elapsed = nowUp - _lastServiceShow; | ||||
|  | ||||
|   if (elapsed <= MIN_FRAME_DELAY) return;                                        // keep wifi alive - no matter if triggered or unlimited | ||||
|   if ( !_triggered && (_targetFps != FPS_UNLIMITED)) {                           // unlimited mode = no frametime | ||||
|     if (elapsed < _frametime) return;                                            // too early for service | ||||
|   } | ||||
|  | ||||
|   bool doShow = false; | ||||
|  | ||||
|   _isServicing = true; | ||||
| @@ -1321,7 +1374,7 @@ void WS2812FX::service() { | ||||
|     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 (nowUp >= seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) | ||||
|     { | ||||
|       doShow = true; | ||||
|       unsigned frameDelay = FRAMETIME; | ||||
| @@ -1371,15 +1424,16 @@ void WS2812FX::service() { | ||||
|   _triggered = false; | ||||
|  | ||||
|   #ifdef WLED_DEBUG | ||||
|   if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); | ||||
|   if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); | ||||
|   #endif | ||||
|   if (doShow) { | ||||
|     yield(); | ||||
|     Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette | ||||
|     show(); | ||||
|     _lastServiceShow = nowUp; // update timestamp, for precise FPS control | ||||
|   } | ||||
|   #ifdef WLED_DEBUG | ||||
|   if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); | ||||
|   if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); | ||||
|   #endif | ||||
| } | ||||
|  | ||||
| @@ -1399,13 +1453,13 @@ void WS2812FX::show() { | ||||
|   // avoid race condition, capture _callback value | ||||
|   show_callback callback = _callback; | ||||
|   if (callback) callback(); | ||||
|   unsigned long showNow = millis(); | ||||
|  | ||||
|   // 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 | ||||
|   BusManager::show(); | ||||
|  | ||||
|   unsigned long showNow = millis(); | ||||
|   size_t diff = showNow - _lastShow; | ||||
|  | ||||
|   if (diff > 0) { // skip calculation if no time has passed | ||||
| @@ -1433,8 +1487,9 @@ uint16_t WS2812FX::getFps() const { | ||||
| } | ||||
|  | ||||
| void WS2812FX::setTargetFps(uint8_t fps) { | ||||
|   if (fps > 0 && fps <= 120) _targetFps = fps; | ||||
|   _frametime = 1000 / _targetFps; | ||||
|   if (fps <= 250) _targetFps = fps; | ||||
|   if (_targetFps > 0) _frametime = 1000 / _targetFps; | ||||
|   else _frametime = MIN_FRAME_DELAY;     // unlimited mode | ||||
| } | ||||
|  | ||||
| void WS2812FX::setMode(uint8_t segid, uint8_t m) { | ||||
| @@ -1482,7 +1537,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { | ||||
|   BusManager::setBrightness(b); | ||||
|   if (!direct) { | ||||
|     unsigned long t = millis(); | ||||
|     if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon | ||||
|     if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_FRAME_DELAY) trigger(); //apply brightness change immediately if no refresh soon | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -1592,7 +1647,7 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group | ||||
|     segId = getSegmentsNum()-1; // segments are added at the end of list | ||||
|   } | ||||
|   suspend(); | ||||
|   _segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY); | ||||
|   _segments[segId].setGeometry(i1, i2, grouping, spacing, offset, startY, stopY); | ||||
|   resume(); | ||||
|   if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector | ||||
| } | ||||
|   | ||||
| @@ -18,10 +18,12 @@ | ||||
| #endif | ||||
| #include "const.h" | ||||
| #include "pin_manager.h" | ||||
| #include "bus_wrapper.h" | ||||
| #include "bus_manager.h" | ||||
| #include "bus_wrapper.h" | ||||
| #include <bits/unique_ptr.h> | ||||
|  | ||||
| extern bool cctICused; | ||||
| extern bool useParallelI2S; | ||||
|  | ||||
| //colors.cpp | ||||
| uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); | ||||
| @@ -29,28 +31,6 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); | ||||
| //udp.cpp | ||||
| uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false); | ||||
|  | ||||
| // enable additional debug output | ||||
| #if defined(WLED_DEBUG_HOST) | ||||
|   #include "net_debug.h" | ||||
|   #define DEBUGOUT NetDebug | ||||
| #else | ||||
|   #define DEBUGOUT Serial | ||||
| #endif | ||||
|  | ||||
| #ifdef WLED_DEBUG | ||||
|   #ifndef ESP8266 | ||||
|   #include <rom/rtc.h> | ||||
|   #endif | ||||
|   #define DEBUG_PRINT(x) DEBUGOUT.print(x) | ||||
|   #define DEBUG_PRINTLN(x) DEBUGOUT.println(x) | ||||
|   #define DEBUG_PRINTF(x...) DEBUGOUT.printf(x) | ||||
|   #define DEBUG_PRINTF_P(x...) DEBUGOUT.printf_P(x) | ||||
| #else | ||||
|   #define DEBUG_PRINT(x) | ||||
|   #define DEBUG_PRINTLN(x) | ||||
|   #define DEBUG_PRINTF(x...) | ||||
|   #define DEBUG_PRINTF_P(x...) | ||||
| #endif | ||||
|  | ||||
| //color mangling macros | ||||
| #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) | ||||
| @@ -63,6 +43,7 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte | ||||
| bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { | ||||
|   if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information | ||||
|   _mappings.push_back({start,len,colorOrder}); | ||||
|   DEBUGBUS_PRINTF_P(PSTR("Bus: Add COM (%d,%d,%d)\n"), (int)start, (int)len, (int)colorOrder); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| @@ -116,12 +97,16 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) const { | ||||
| } | ||||
|  | ||||
| uint8_t *Bus::allocateData(size_t size) { | ||||
|   if (_data) free(_data); // should not happen, but for safety | ||||
|   freeData(); // should not happen, but for safety | ||||
|   return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr); | ||||
| } | ||||
|  | ||||
| void Bus::freeData() { | ||||
|   if (_data) free(_data); | ||||
|   _data = nullptr; | ||||
| } | ||||
|  | ||||
| BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) | ||||
| BusDigital::BusDigital(const 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) | ||||
| @@ -129,42 +114,43 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) | ||||
| , _milliAmpsMax(bc.milliAmpsMax) | ||||
| , _colorOrderMap(com) | ||||
| { | ||||
|   if (!isDigital(bc.type) || !bc.count) return; | ||||
|   if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; | ||||
|   DEBUGBUS_PRINTLN(F("Bus: Creating digital bus.")); | ||||
|   if (!isDigital(bc.type) || !bc.count) { DEBUGBUS_PRINTLN(F("Not digial or empty bus!")); return; } | ||||
|   if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUGBUS_PRINTLN(F("Pin 0 allocated!")); return; } | ||||
|   _frequencykHz = 0U; | ||||
|   _pins[0] = bc.pins[0]; | ||||
|   if (is2Pin(bc.type)) { | ||||
|     if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) { | ||||
|       cleanup(); | ||||
|       DEBUGBUS_PRINTLN(F("Pin 1 allocated!")); | ||||
|       return; | ||||
|     } | ||||
|     _pins[1] = bc.pins[1]; | ||||
|     _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined | ||||
|   } | ||||
|   _iType = PolyBus::getI(bc.type, _pins, nr); | ||||
|   if (_iType == I_NONE) return; | ||||
|   if (_iType == I_NONE) { DEBUGBUS_PRINTLN(F("Incorrect iType!")); return; } | ||||
|   _hasRgb = hasRGB(bc.type); | ||||
|   _hasWhite = hasWhite(bc.type); | ||||
|   _hasCCT = hasCCT(bc.type); | ||||
|   if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) return; | ||||
|   if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUGBUS_PRINTLN(F("Buffer allocation failed!")); return; } | ||||
|   //_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); | ||||
|   _valid = (_busPtr != nullptr); | ||||
|   DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); | ||||
|   DEBUGBUS_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"), | ||||
|     _valid?"S":"Uns", | ||||
|     (int)nr, | ||||
|     (int)bc.count, | ||||
|     (int)bc.type, | ||||
|     (int)_hasRgb, (int)_hasWhite, (int)_hasCCT, | ||||
|     (unsigned)_pins[0], is2Pin(bc.type)?(unsigned)_pins[1]:255U, | ||||
|     (unsigned)_iType, | ||||
|     (int)_milliAmpsPerLed, (int)_milliAmpsMax | ||||
|   ); | ||||
| } | ||||
|  | ||||
| //fine tune power estimation constants for your setup | ||||
| //you can set it to 0 if the ESP is powered by USB and the LEDs by external | ||||
| #ifndef MA_FOR_ESP | ||||
|   #ifdef ESP8266 | ||||
|     #define MA_FOR_ESP         80 //how much mA does the ESP use (Wemos D1 about 80mA) | ||||
|   #else | ||||
|     #define MA_FOR_ESP        120 //how much mA does the ESP use (ESP32 about 120mA) | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
| //DISCLAIMER | ||||
| //The following function attemps to calculate the current LED power usage, | ||||
| //and will limit the brightness to stay below a set amperage threshold. | ||||
| @@ -173,7 +159,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) | ||||
| //I am NOT to be held liable for burned down garages or houses! | ||||
|  | ||||
| // To disable brightness limiter we either set output max current to 0 or single LED current to 0 | ||||
| uint8_t BusDigital::estimateCurrentAndLimitBri() { | ||||
| uint8_t BusDigital::estimateCurrentAndLimitBri() const { | ||||
|   bool useWackyWS2815PowerModel = false; | ||||
|   byte actualMilliampsPerLed = _milliAmpsPerLed; | ||||
|  | ||||
| @@ -186,7 +172,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() { | ||||
|     actualMilliampsPerLed = 12; // from testing an actual strip | ||||
|   } | ||||
|  | ||||
|   size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power | ||||
|   unsigned powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power | ||||
|   if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget | ||||
|     powerBudget -= getLength(); | ||||
|   } else { | ||||
| @@ -211,26 +197,25 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() { | ||||
|   } | ||||
|  | ||||
|   // powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps | ||||
|   busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765; | ||||
|   _milliAmpsTotal = busPowerSum * _bri / 255; | ||||
|   BusDigital::_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * _bri) / (765*255); | ||||
|  | ||||
|   uint8_t newBri = _bri; | ||||
|   if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit | ||||
|     float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri); | ||||
|     if (scale >= 1.0f) return _bri; | ||||
|     _milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale); | ||||
|     uint8_t scaleB = min((int)(scale * 255), 255); | ||||
|     newBri = unsigned(_bri * scaleB) / 256 + 1; | ||||
|   if (BusDigital::_milliAmpsTotal > powerBudget) { | ||||
|     //scale brightness down to stay in current limit | ||||
|     unsigned scaleB = powerBudget * 255 / BusDigital::_milliAmpsTotal; | ||||
|     newBri = (_bri * scaleB) / 256 + 1; | ||||
|     BusDigital::_milliAmpsTotal = powerBudget; | ||||
|     //_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * newBri) / (765*255); | ||||
|   } | ||||
|   return newBri; | ||||
| } | ||||
|  | ||||
| void BusDigital::show() { | ||||
|   _milliAmpsTotal = 0; | ||||
|   BusDigital::_milliAmpsTotal = 0; | ||||
|   if (!_valid) return; | ||||
|  | ||||
|   uint8_t cctWW = 0, cctCW = 0; | ||||
|   unsigned newBri = estimateCurrentAndLimitBri();  // will fill _milliAmpsTotal | ||||
|   unsigned newBri = estimateCurrentAndLimitBri();  // will fill _milliAmpsTotal (TODO: could use PolyBus::CalcTotalMilliAmpere()) | ||||
|   if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits | ||||
|  | ||||
|   if (_data) { | ||||
| @@ -256,6 +241,7 @@ void BusDigital::show() { | ||||
|         // TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer | ||||
|         Bus::_cct = _data[offset+channels-1]; | ||||
|         Bus::calculateCCT(c, cctWW, cctCW); | ||||
|         if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping | ||||
|       } | ||||
|       unsigned pix = i; | ||||
|       if (_reversed) pix = _len - pix -1; | ||||
| @@ -306,9 +292,8 @@ void BusDigital::setStatusPixel(uint32_t c) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { | ||||
| void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { | ||||
|   if (!_valid) return; | ||||
|   uint8_t cctWW = 0, cctCW = 0; | ||||
|   if (hasWhite()) c = autoWhiteCalc(c); | ||||
|   if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT | ||||
|   if (_data) { | ||||
| @@ -336,13 +321,19 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { | ||||
|         case 2: c = RGBW32(R(cOld), G(cOld), W(c)   , 0); break; | ||||
|       } | ||||
|     } | ||||
|     if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW); | ||||
|     PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW); | ||||
|     uint16_t wwcw = 0; | ||||
|     if (hasCCT()) { | ||||
|       uint8_t cctWW = 0, cctCW = 0; | ||||
|       Bus::calculateCCT(c, cctWW, cctCW); | ||||
|       wwcw = (cctCW<<8) | cctWW; | ||||
|       if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping | ||||
|     } | ||||
|     PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // returns original color if global buffering is enabled, else returns lossly restored color from bus | ||||
| uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const { | ||||
| uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { | ||||
|   if (!_valid) return 0; | ||||
|   if (_data) { | ||||
|     size_t offset = pix * getNumberOfChannels(); | ||||
| @@ -368,16 +359,24 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const { | ||||
|         case 2: c = RGBW32(b, b, b, b); break; | ||||
|       } | ||||
|     } | ||||
|     if (_type == TYPE_WS2812_WWA) { | ||||
|       uint8_t w = R(c) | G(c); | ||||
|       c = RGBW32(w, w, 0, w); | ||||
|     } | ||||
|     return c; | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t BusDigital::getPins(uint8_t* pinArray) const { | ||||
| unsigned BusDigital::getPins(uint8_t* pinArray) const { | ||||
|   unsigned numPins = is2Pin(_type) + 1; | ||||
|   if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; | ||||
|   return numPins; | ||||
| } | ||||
|  | ||||
| unsigned BusDigital::getBusSize() const { | ||||
|   return sizeof(BusDigital) + (isOk() ? PolyBus::getDataSize(_busPtr, _iType) + (_data ? _len * getNumberOfChannels() : 0) : 0); | ||||
| } | ||||
|  | ||||
| void BusDigital::setColorOrder(uint8_t colorOrder) { | ||||
|   // upper nibble contains W swap information | ||||
|   if ((colorOrder & 0x0F) > 5) return; | ||||
| @@ -400,8 +399,8 @@ std::vector<LEDType> BusDigital::getLEDTypes() { | ||||
|     {TYPE_WS2805,        "D",  PSTR("WS2805 RGBCW")}, | ||||
|     {TYPE_SM16825,       "D",  PSTR("SM16825 RGBCW")}, | ||||
|     {TYPE_WS2812_1CH_X3, "D",  PSTR("WS2811 White")}, | ||||
|     //{TYPE_WS2812_2CH_X3, "D",  PSTR("WS2811 CCT")}, // not implemented | ||||
|     //{TYPE_WS2812_WWA,    "D",  PSTR("WS2811 WWA")}, // not implemented | ||||
|     //{TYPE_WS2812_2CH_X3, "D",  PSTR("WS281x CCT")}, // not implemented | ||||
|     {TYPE_WS2812_WWA,    "D",  PSTR("WS281x WWA")}, // amber ignored | ||||
|     {TYPE_WS2801,        "2P", PSTR("WS2801")}, | ||||
|     {TYPE_APA102,        "2P", PSTR("APA102")}, | ||||
|     {TYPE_LPD8806,       "2P", PSTR("LPD8806")}, | ||||
| @@ -416,12 +415,13 @@ void BusDigital::begin() { | ||||
| } | ||||
|  | ||||
| void BusDigital::cleanup() { | ||||
|   DEBUG_PRINTLN(F("Digital Cleanup.")); | ||||
|   DEBUGBUS_PRINTLN(F("Digital Cleanup.")); | ||||
|   PolyBus::cleanup(_busPtr, _iType); | ||||
|   _iType = I_NONE; | ||||
|   _valid = false; | ||||
|   _busPtr = nullptr; | ||||
|   if (_data != nullptr) freeData(); | ||||
|   freeData(); | ||||
|   //PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital); | ||||
|   PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); | ||||
|   PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); | ||||
| } | ||||
| @@ -452,7 +452,7 @@ void BusDigital::cleanup() { | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
| BusPwm::BusPwm(BusConfig &bc) | ||||
| BusPwm::BusPwm(const BusConfig &bc) | ||||
| : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed, bc.refreshReq) // hijack Off refresh flag to indicate usage of dithering | ||||
| { | ||||
|   if (!isPWM(bc.type)) return; | ||||
| @@ -496,12 +496,12 @@ BusPwm::BusPwm(BusConfig &bc) | ||||
|   _hasRgb = hasRGB(bc.type); | ||||
|   _hasWhite = hasWhite(bc.type); | ||||
|   _hasCCT = hasCCT(bc.type); | ||||
|   _data = _pwmdata; // avoid malloc() and use stack | ||||
|   _data = _pwmdata; // avoid malloc() and use already allocated memory | ||||
|   _valid = true; | ||||
|   DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); | ||||
|   DEBUGBUS_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); | ||||
| } | ||||
|  | ||||
| void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { | ||||
| void BusPwm::setPixelColor(unsigned pix, uint32_t c) { | ||||
|   if (pix != 0 || !_valid) return; //only react to first pixel | ||||
|   if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c); | ||||
|   if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) { | ||||
| @@ -538,7 +538,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { | ||||
| } | ||||
|  | ||||
| //does no index check | ||||
| uint32_t BusPwm::getPixelColor(uint16_t pix) const { | ||||
| uint32_t BusPwm::getPixelColor(unsigned pix) const { | ||||
|   if (!_valid) return 0; | ||||
|   // TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented) | ||||
|   switch (_type) { | ||||
| @@ -567,19 +567,15 @@ void BusPwm::show() { | ||||
|   const unsigned maxBri = (1<<_depth);      // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8)  | ||||
|   [[maybe_unused]] const unsigned bitShift = dithering * 4;  // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) | ||||
|  | ||||
|   // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness | ||||
|   // the formula is based on 12 bit resolution as there is no need for greater precision | ||||
|   // use CIE brightness formula (linear + cubic) to approximate human eye perceived brightness | ||||
|   // see: https://en.wikipedia.org/wiki/Lightness | ||||
|   unsigned pwmBri = (unsigned)_bri * 100;  // enlarge to use integer math for linear response | ||||
|   if (pwmBri < 2040) { | ||||
|     // linear response for values [0-20] | ||||
|     pwmBri = ((pwmBri << 12) + 115043) / 230087; //adding '0.5' before division for correct rounding | ||||
|   } else { | ||||
|     // cubic response for values [21-255] | ||||
|     pwmBri += 4080; | ||||
|     float temp = (float)pwmBri / 29580.0f; | ||||
|     temp = temp * temp * temp * (float)maxBri;  | ||||
|     pwmBri = (unsigned)temp;  // pwmBri is in range [0-maxBri]  | ||||
|   unsigned pwmBri = _bri; | ||||
|   if (pwmBri < 21) {                                   // linear response for values [0-20] | ||||
|     pwmBri = (pwmBri * maxBri + 2300 / 2) / 2300 ;     // adding '0.5' before division for correct rounding, 2300 gives a good match to CIE curve | ||||
|   } else {                                             // cubic response for values [21-255] | ||||
|     float temp = float(pwmBri + 41) / float(255 + 41); // 41 is to match offset & slope to linear part | ||||
|     temp = temp * temp * temp * (float)maxBri; | ||||
|     pwmBri = (unsigned)temp;                           // pwmBri is in range [0-maxBri] C | ||||
|   } | ||||
|  | ||||
|   [[maybe_unused]] unsigned hPoint = 0;  // phase shift (0 - maxBri) | ||||
| @@ -618,7 +614,7 @@ void BusPwm::show() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t BusPwm::getPins(uint8_t* pinArray) const { | ||||
| unsigned BusPwm::getPins(uint8_t* pinArray) const { | ||||
|   if (!_valid) return 0; | ||||
|   unsigned numPins = numPWMPins(_type); | ||||
|   if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; | ||||
| @@ -654,7 +650,7 @@ void BusPwm::deallocatePins() { | ||||
| } | ||||
|  | ||||
|  | ||||
| BusOnOff::BusOnOff(BusConfig &bc) | ||||
| BusOnOff::BusOnOff(const BusConfig &bc) | ||||
| : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) | ||||
| , _onoffdata(0) | ||||
| { | ||||
| @@ -671,10 +667,10 @@ BusOnOff::BusOnOff(BusConfig &bc) | ||||
|   _hasCCT = false; | ||||
|   _data = &_onoffdata; // avoid malloc() and use stack | ||||
|   _valid = true; | ||||
|   DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); | ||||
|   DEBUGBUS_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); | ||||
| } | ||||
|  | ||||
| void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { | ||||
| void BusOnOff::setPixelColor(unsigned pix, uint32_t c) { | ||||
|   if (pix != 0 || !_valid) return; //only react to first pixel | ||||
|   c = autoWhiteCalc(c); | ||||
|   uint8_t r = R(c); | ||||
| @@ -684,7 +680,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { | ||||
|   _data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; | ||||
| } | ||||
|  | ||||
| uint32_t BusOnOff::getPixelColor(uint16_t pix) const { | ||||
| uint32_t BusOnOff::getPixelColor(unsigned pix) const { | ||||
|   if (!_valid) return 0; | ||||
|   return RGBW32(_data[0], _data[0], _data[0], _data[0]); | ||||
| } | ||||
| @@ -694,7 +690,7 @@ void BusOnOff::show() { | ||||
|   digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]); | ||||
| } | ||||
|  | ||||
| uint8_t BusOnOff::getPins(uint8_t* pinArray) const { | ||||
| unsigned BusOnOff::getPins(uint8_t* pinArray) const { | ||||
|   if (!_valid) return 0; | ||||
|   if (pinArray) pinArray[0] = _pin; | ||||
|   return 1; | ||||
| @@ -707,7 +703,7 @@ std::vector<LEDType> BusOnOff::getLEDTypes() { | ||||
|   }; | ||||
| } | ||||
|  | ||||
| BusNetwork::BusNetwork(BusConfig &bc) | ||||
| BusNetwork::BusNetwork(const BusConfig &bc) | ||||
| : Bus(bc.type, bc.start, bc.autoWhite, bc.count) | ||||
| , _broadcastLock(false) | ||||
| { | ||||
| @@ -731,10 +727,10 @@ BusNetwork::BusNetwork(BusConfig &bc) | ||||
|   _UDPchannels = _hasWhite + 3; | ||||
|   _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); | ||||
|   _valid = (allocateData(_len * _UDPchannels) != nullptr); | ||||
|   DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); | ||||
|   DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); | ||||
| } | ||||
|  | ||||
| void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { | ||||
| void BusNetwork::setPixelColor(unsigned pix, uint32_t c) { | ||||
|   if (!_valid || pix >= _len) return; | ||||
|   if (_hasWhite) c = autoWhiteCalc(c); | ||||
|   if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT | ||||
| @@ -745,7 +741,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { | ||||
|   if (_hasWhite) _data[offset+3] = W(c); | ||||
| } | ||||
|  | ||||
| uint32_t BusNetwork::getPixelColor(uint16_t pix) const { | ||||
| uint32_t BusNetwork::getPixelColor(unsigned pix) const { | ||||
|   if (!_valid || pix >= _len) return 0; | ||||
|   unsigned offset = pix * _UDPchannels; | ||||
|   return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0)); | ||||
| @@ -758,7 +754,7 @@ void BusNetwork::show() { | ||||
|   _broadcastLock = false; | ||||
| } | ||||
|  | ||||
| uint8_t BusNetwork::getPins(uint8_t* pinArray) const { | ||||
| unsigned BusNetwork::getPins(uint8_t* pinArray) const { | ||||
|   if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i]; | ||||
|   return 4; | ||||
| } | ||||
| @@ -779,6 +775,7 @@ std::vector<LEDType> BusNetwork::getLEDTypes() { | ||||
| } | ||||
|  | ||||
| void BusNetwork::cleanup() { | ||||
|   DEBUGBUS_PRINTLN(F("Virtual Cleanup.")); | ||||
|   _type = I_NONE; | ||||
|   _valid = false; | ||||
|   freeData(); | ||||
| @@ -786,43 +783,66 @@ void BusNetwork::cleanup() { | ||||
|  | ||||
|  | ||||
| //utility to get the approx. memory usage of a given BusConfig | ||||
| uint32_t BusManager::memUsage(BusConfig &bc) { | ||||
|   if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; | ||||
|  | ||||
|   unsigned len = bc.count + bc.skipAmount; | ||||
|   unsigned channels = Bus::getNumberOfChannels(bc.type); | ||||
|   unsigned multiplier = 1; | ||||
|   if (Bus::isDigital(bc.type)) { // digital types | ||||
|     if (Bus::is16bit(bc.type)) len *= 2; // 16-bit LEDs | ||||
|     #ifdef ESP8266 | ||||
|       if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem | ||||
|         multiplier = 5; | ||||
|       } | ||||
|     #else //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) | ||||
|       multiplier = PolyBus::isParallelI2S1Output() ? 24 : 2; | ||||
|     #endif | ||||
|   } | ||||
|   return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels; | ||||
| } | ||||
|  | ||||
| uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned minBuses) { | ||||
|   //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) | ||||
|   unsigned multiplier = PolyBus::isParallelI2S1Output() ? 3 : 2; | ||||
|   return (maxChannels * maxCount * minBuses * multiplier); | ||||
| } | ||||
|  | ||||
| int BusManager::add(BusConfig &bc) { | ||||
|   if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; | ||||
|   if (Bus::isVirtual(bc.type)) { | ||||
|     busses[numBusses] = new BusNetwork(bc); | ||||
|   } else if (Bus::isDigital(bc.type)) { | ||||
|     busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); | ||||
|   } else if (Bus::isOnOff(bc.type)) { | ||||
|     busses[numBusses] = new BusOnOff(bc); | ||||
| unsigned BusConfig::memUsage(unsigned nr) const { | ||||
|   if (Bus::isVirtual(type)) { | ||||
|     return sizeof(BusNetwork) + (count * Bus::getNumberOfChannels(type)); | ||||
|   } else if (Bus::isDigital(type)) { | ||||
|     return sizeof(BusDigital) + PolyBus::memUsage(count + skipAmount, PolyBus::getI(type, pins, nr)) + doubleBuffer * (count + skipAmount) * Bus::getNumberOfChannels(type); | ||||
|   } else if (Bus::isOnOff(type)) { | ||||
|     return sizeof(BusOnOff); | ||||
|   } else { | ||||
|     busses[numBusses] = new BusPwm(bc); | ||||
|     return sizeof(BusPwm); | ||||
|   } | ||||
|   return numBusses++; | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned BusManager::memUsage() { | ||||
|   // when ESP32, S2 & S3 use parallel I2S only the largest bus determines the total memory requirements for back buffers | ||||
|   // front buffers are always allocated per bus | ||||
|   unsigned size = 0; | ||||
|   unsigned maxI2S = 0; | ||||
|   #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266) | ||||
|   unsigned digitalCount = 0; | ||||
|     #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) | ||||
|       #define MAX_RMT 4 | ||||
|     #else | ||||
|       #define MAX_RMT 8 | ||||
|     #endif | ||||
|   #endif | ||||
|   for (const auto &bus : busses) { | ||||
|     unsigned busSize = bus->getBusSize(); | ||||
|     #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266) | ||||
|     if (bus->isDigital() && !bus->is2Pin()) digitalCount++; | ||||
|     if (PolyBus::isParallelI2S1Output() && digitalCount > MAX_RMT) { | ||||
|       unsigned i2sCommonSize = 3 * bus->getLength() * bus->getNumberOfChannels() * (bus->is16bit()+1); | ||||
|       if (i2sCommonSize > maxI2S) maxI2S = i2sCommonSize; | ||||
|       busSize -= i2sCommonSize; | ||||
|     } | ||||
|     #endif | ||||
|     size += busSize; | ||||
|   } | ||||
|   return size + maxI2S; | ||||
| } | ||||
|  | ||||
| int BusManager::add(const BusConfig &bc) { | ||||
|   DEBUGBUS_PRINTF_P(PSTR("Bus: Adding bus (%d - %d >= %d)\n"), getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES); | ||||
|   if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; | ||||
|   unsigned numDigital = 0; | ||||
|   for (const auto &bus : busses) if (bus->isDigital() && !bus->is2Pin()) numDigital++; | ||||
|   if (Bus::isVirtual(bc.type)) { | ||||
|     //busses.push_back(std::make_unique<BusNetwork>(bc)); // when C++ >11 | ||||
|     busses.push_back(new BusNetwork(bc)); | ||||
|   } else if (Bus::isDigital(bc.type)) { | ||||
|     //busses.push_back(std::make_unique<BusDigital>(bc, numDigital, colorOrderMap)); | ||||
|     busses.push_back(new BusDigital(bc, numDigital, colorOrderMap)); | ||||
|   } else if (Bus::isOnOff(bc.type)) { | ||||
|     //busses.push_back(std::make_unique<BusOnOff>(bc)); | ||||
|     busses.push_back(new BusOnOff(bc)); | ||||
|   } else { | ||||
|     //busses.push_back(std::make_unique<BusPwm>(bc)); | ||||
|     busses.push_back(new BusPwm(bc)); | ||||
|   } | ||||
|   return busses.size(); | ||||
| } | ||||
|  | ||||
| // credit @willmmiles | ||||
| @@ -851,18 +871,21 @@ String BusManager::getLEDTypesJSONString() { | ||||
| } | ||||
|  | ||||
| void BusManager::useParallelOutput() { | ||||
|   _parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods | ||||
|   DEBUGBUS_PRINTLN(F("Bus: Enabling parallel I2S.")); | ||||
|   PolyBus::setParallelI2S1Output(); | ||||
| } | ||||
|  | ||||
| bool BusManager::hasParallelOutput() { | ||||
|   return PolyBus::isParallelI2S1Output(); | ||||
| } | ||||
|  | ||||
| //do not call this method from system context (network callback) | ||||
| void BusManager::removeAll() { | ||||
|   DEBUG_PRINTLN(F("Removing all.")); | ||||
|   DEBUGBUS_PRINTLN(F("Removing all.")); | ||||
|   //prevents crashes due to deleting busses while in use. | ||||
|   while (!canAllShow()) yield(); | ||||
|   for (unsigned i = 0; i < numBusses; i++) delete busses[i]; | ||||
|   numBusses = 0; | ||||
|   _parallelOutputs = 1; | ||||
|   for (auto &bus : busses) delete bus; // needed when not using std::unique_ptr C++ >11 | ||||
|   busses.clear(); | ||||
|   PolyBus::setParallelI2S1Output(false); | ||||
| } | ||||
|  | ||||
| @@ -873,7 +896,9 @@ void BusManager::removeAll() { | ||||
| void BusManager::esp32RMTInvertIdle() { | ||||
|   bool idle_out; | ||||
|   unsigned rmt = 0; | ||||
|   for (unsigned u = 0; u < numBusses(); u++) { | ||||
|   unsigned u = 0; | ||||
|   for (auto &bus : busses) { | ||||
|     if (bus->getLength()==0 || !bus->isDigital() || bus->is2Pin()) continue; | ||||
|     #if defined(CONFIG_IDF_TARGET_ESP32C3)    // 2 RMT, only has 1 I2S but NPB does not support it ATM | ||||
|       if (u > 1) return; | ||||
|       rmt = u; | ||||
| @@ -884,11 +909,11 @@ void BusManager::esp32RMTInvertIdle() { | ||||
|       if (u > 3) return; | ||||
|       rmt = u; | ||||
|     #else | ||||
|       if (u < _parallelOutputs) continue; | ||||
|       if (u >= _parallelOutputs + 8) return; // only 8 RMT channels | ||||
|       rmt = u - _parallelOutputs; | ||||
|       unsigned numI2S = !PolyBus::isParallelI2S1Output(); // if using parallel I2S, RMT is used 1st | ||||
|       if (numI2S > u) continue; | ||||
|       if (u > 7 + numI2S) return; | ||||
|       rmt = u - numI2S; | ||||
|     #endif | ||||
|     if (busses[u]->getLength()==0 || !busses[u]->isDigital() || busses[u]->is2Pin()) continue; | ||||
|     //assumes that bus number to rmt channel mapping stays 1:1 | ||||
|     rmt_channel_t ch = static_cast<rmt_channel_t>(rmt); | ||||
|     rmt_idle_level_t lvl; | ||||
| @@ -897,6 +922,7 @@ void BusManager::esp32RMTInvertIdle() { | ||||
|     else if (lvl == RMT_IDLE_LEVEL_LOW) lvl = RMT_IDLE_LEVEL_HIGH; | ||||
|     else continue; | ||||
|     rmt_set_idle_level(ch, idle_out, lvl); | ||||
|     u++ | ||||
|   } | ||||
| } | ||||
| #endif | ||||
| @@ -905,12 +931,12 @@ void BusManager::on() { | ||||
|   #ifdef ESP8266 | ||||
|   //Fix for turning off onboard LED breaking bus | ||||
|   if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { | ||||
|     for (unsigned i = 0; i < numBusses; i++) { | ||||
|     for (auto &bus : busses) { | ||||
|       uint8_t pins[2] = {255,255}; | ||||
|       if (busses[i]->isDigital() && busses[i]->getPins(pins)) { | ||||
|       if (bus->isDigital() && bus->getPins(pins)) { | ||||
|         if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) { | ||||
|           BusDigital *bus = static_cast<BusDigital*>(busses[i]); | ||||
|           bus->begin(); | ||||
|           BusDigital *b = static_cast<BusDigital*>(bus); | ||||
|           b->begin(); | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
| @@ -927,7 +953,7 @@ void BusManager::off() { | ||||
|   // turn off built-in LED if strip is turned off | ||||
|   // this will break digital bus so will need to be re-initialised on On | ||||
|   if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { | ||||
|     for (unsigned i = 0; i < numBusses; i++) if (busses[i]->isOffRefreshRequired()) return; | ||||
|     for (const auto &bus : busses) if (bus->isOffRefreshRequired()) return; | ||||
|     pinMode(LED_BUILTIN, OUTPUT); | ||||
|     digitalWrite(LED_BUILTIN, HIGH); | ||||
|   } | ||||
| @@ -939,31 +965,26 @@ void BusManager::off() { | ||||
|  | ||||
| void BusManager::show() { | ||||
|   _milliAmpsUsed = 0; | ||||
|   for (unsigned i = 0; i < numBusses; i++) { | ||||
|     busses[i]->show(); | ||||
|     _milliAmpsUsed += busses[i]->getUsedCurrent(); | ||||
|   for (auto &bus : busses) { | ||||
|     bus->show(); | ||||
|     _milliAmpsUsed += bus->getUsedCurrent(); | ||||
|   } | ||||
|   if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP; | ||||
| } | ||||
|  | ||||
| void BusManager::setStatusPixel(uint32_t c) { | ||||
|   for (unsigned i = 0; i < numBusses; i++) { | ||||
|     busses[i]->setStatusPixel(c); | ||||
|   } | ||||
|   for (auto &bus : busses) bus->setStatusPixel(c); | ||||
| } | ||||
|  | ||||
| void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) { | ||||
|   for (unsigned i = 0; i < numBusses; i++) { | ||||
|     unsigned bstart = busses[i]->getStart(); | ||||
|     if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue; | ||||
|     busses[i]->setPixelColor(pix - bstart, c); | ||||
| void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) { | ||||
|   for (auto &bus : busses) { | ||||
|     unsigned bstart = bus->getStart(); | ||||
|     if (pix < bstart || pix >= bstart + bus->getLength()) continue; | ||||
|     bus->setPixelColor(pix - bstart, c); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BusManager::setBrightness(uint8_t b) { | ||||
|   for (unsigned i = 0; i < numBusses; i++) { | ||||
|     busses[i]->setBrightness(b); | ||||
|   } | ||||
|   for (auto &bus : busses) bus->setBrightness(b); | ||||
| } | ||||
|  | ||||
| void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { | ||||
| @@ -975,35 +996,33 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { | ||||
|   Bus::setCCT(cct); | ||||
| } | ||||
|  | ||||
| uint32_t BusManager::getPixelColor(uint16_t pix) { | ||||
|   for (unsigned i = 0; i < numBusses; i++) { | ||||
|     unsigned bstart = busses[i]->getStart(); | ||||
|     if (!busses[i]->containsPixel(pix)) continue; | ||||
|     return busses[i]->getPixelColor(pix - bstart); | ||||
| uint32_t BusManager::getPixelColor(unsigned pix) { | ||||
|   for (auto &bus : busses) { | ||||
|     unsigned bstart = bus->getStart(); | ||||
|     if (!bus->containsPixel(pix)) continue; | ||||
|     return bus->getPixelColor(pix - bstart); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| bool BusManager::canAllShow() { | ||||
|   for (unsigned i = 0; i < numBusses; i++) { | ||||
|     if (!busses[i]->canShow()) return false; | ||||
|   } | ||||
|   for (const auto &bus : busses) if (!bus->canShow()) return false; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| Bus* BusManager::getBus(uint8_t busNr) { | ||||
|   if (busNr >= numBusses) return nullptr; | ||||
|   if (busNr >= busses.size()) return nullptr; | ||||
|   return busses[busNr]; | ||||
| } | ||||
|  | ||||
| //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) | ||||
| uint16_t BusManager::getTotalLength() { | ||||
|   unsigned len = 0; | ||||
|   for (unsigned i=0; i<numBusses; i++) len += busses[i]->getLength(); | ||||
|   for (const auto &bus : busses) len += bus->getLength(); | ||||
|   return len; | ||||
| } | ||||
|  | ||||
| bool PolyBus::useParallelI2S = false; | ||||
| bool PolyBus::_useParallelI2S = false; | ||||
|  | ||||
| // Bus static member definition | ||||
| int16_t Bus::_cct = -1; | ||||
| @@ -1012,9 +1031,8 @@ uint8_t Bus::_gAWM = 255; | ||||
|  | ||||
| uint16_t BusDigital::_milliAmpsTotal = 0; | ||||
|  | ||||
| uint8_t       BusManager::numBusses = 0; | ||||
| Bus*          BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; | ||||
| //std::vector<std::unique_ptr<Bus>> BusManager::busses; | ||||
| std::vector<Bus*> BusManager::busses; | ||||
| ColorOrderMap BusManager::colorOrderMap = {}; | ||||
| uint16_t      BusManager::_milliAmpsUsed = 0; | ||||
| uint16_t      BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; | ||||
| uint8_t       BusManager::_parallelOutputs = 1; | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| #pragma once | ||||
| #ifndef BusManager_h | ||||
| #define BusManager_h | ||||
|  | ||||
| @@ -7,6 +8,30 @@ | ||||
|  | ||||
| #include "const.h" | ||||
| #include <vector> | ||||
| #include <memory> | ||||
|  | ||||
| // enable additional debug output | ||||
| #if defined(WLED_DEBUG_HOST) | ||||
|   #include "net_debug.h" | ||||
|   #define DEBUGOUT NetDebug | ||||
| #else | ||||
|   #define DEBUGOUT Serial | ||||
| #endif | ||||
|  | ||||
| #ifdef WLED_DEBUG_BUS | ||||
|   #ifndef ESP8266 | ||||
|   #include <rom/rtc.h> | ||||
|   #endif | ||||
|   #define DEBUGBUS_PRINT(x) DEBUGOUT.print(x) | ||||
|   #define DEBUGBUS_PRINTLN(x) DEBUGOUT.println(x) | ||||
|   #define DEBUGBUS_PRINTF(x...) DEBUGOUT.printf(x) | ||||
|   #define DEBUGBUS_PRINTF_P(x...) DEBUGOUT.printf_P(x) | ||||
| #else | ||||
|   #define DEBUGBUS_PRINT(x) | ||||
|   #define DEBUGBUS_PRINTLN(x) | ||||
|   #define DEBUGBUS_PRINTF(x...) | ||||
|   #define DEBUGBUS_PRINTF_P(x...) | ||||
| #endif | ||||
|  | ||||
| //colors.cpp | ||||
| uint16_t approximateKelvinFromRGB(uint32_t rgb); | ||||
| @@ -77,50 +102,51 @@ class Bus { | ||||
|       _autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY; | ||||
|     }; | ||||
|  | ||||
|     virtual ~Bus() {} //throw the bus under the bus | ||||
|     virtual ~Bus() {} //throw the bus under the bus (derived class needs to freeData()) | ||||
|  | ||||
|     virtual void     begin() {}; | ||||
|     virtual void     begin()                                    {}; | ||||
|     virtual void     show() = 0; | ||||
|     virtual bool     canShow() const                          { return true; } | ||||
|     virtual void     setStatusPixel(uint32_t c)                {} | ||||
|     virtual void     setPixelColor(uint16_t pix, uint32_t c) = 0; | ||||
|     virtual void     setBrightness(uint8_t b)                  { _bri = b; }; | ||||
|     virtual void     setColorOrder(uint8_t co)                 {} | ||||
|     virtual uint32_t getPixelColor(uint16_t pix) const         { return 0; } | ||||
|     virtual uint8_t  getPins(uint8_t* pinArray = nullptr) const { return 0; } | ||||
|     virtual uint16_t getLength() const                         { return isOk() ? _len : 0; } | ||||
|     virtual uint8_t  getColorOrder() const                     { return COL_ORDER_RGB; } | ||||
|     virtual uint8_t  skippedLeds() const                       { return 0; } | ||||
|     virtual uint16_t getFrequency() const                      { return 0U; } | ||||
|     virtual uint16_t getLEDCurrent() const                     { return 0; } | ||||
|     virtual uint16_t getUsedCurrent() const                    { return 0; } | ||||
|     virtual uint16_t getMaxCurrent() const                     { return 0; } | ||||
|     virtual bool     canShow() const                            { return true; } | ||||
|     virtual void     setStatusPixel(uint32_t c)                 {} | ||||
|     virtual void     setPixelColor(unsigned pix, uint32_t c) = 0; | ||||
|     virtual void     setBrightness(uint8_t b)                   { _bri = b; }; | ||||
|     virtual void     setColorOrder(uint8_t co)                  {} | ||||
|     virtual uint32_t getPixelColor(unsigned pix) const          { return 0; } | ||||
|     virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; } | ||||
|     virtual uint16_t getLength() const                          { return isOk() ? _len : 0; } | ||||
|     virtual uint8_t  getColorOrder() const                      { return COL_ORDER_RGB; } | ||||
|     virtual unsigned skippedLeds() const                        { return 0; } | ||||
|     virtual uint16_t getFrequency() const                       { return 0U; } | ||||
|     virtual uint16_t getLEDCurrent() const                      { return 0; } | ||||
|     virtual uint16_t getUsedCurrent() const                     { return 0; } | ||||
|     virtual uint16_t getMaxCurrent() const                      { return 0; } | ||||
|     virtual unsigned getBusSize() const                         { return sizeof(Bus); } | ||||
|  | ||||
|     inline  bool     hasRGB() const                            { return _hasRgb; } | ||||
|     inline  bool     hasWhite() const                          { return _hasWhite; } | ||||
|     inline  bool     hasCCT() const                            { return _hasCCT; } | ||||
|     inline  bool     isDigital() const                         { return isDigital(_type); } | ||||
|     inline  bool     is2Pin() const                            { return is2Pin(_type); } | ||||
|     inline  bool     isOnOff() const                           { return isOnOff(_type); } | ||||
|     inline  bool     isPWM() const                             { return isPWM(_type); } | ||||
|     inline  bool     isVirtual() const                         { return isVirtual(_type); } | ||||
|     inline  bool     is16bit() const                           { return is16bit(_type); } | ||||
|     inline  bool     mustRefresh() const                       { return mustRefresh(_type); } | ||||
|     inline  void     setReversed(bool reversed)                { _reversed = reversed; } | ||||
|     inline  void     setStart(uint16_t start)                  { _start = start; } | ||||
|     inline  void     setAutoWhiteMode(uint8_t m)               { if (m < 5) _autoWhiteMode = m; } | ||||
|     inline  uint8_t  getAutoWhiteMode() const                  { return _autoWhiteMode; } | ||||
|     inline  uint8_t  getNumberOfChannels() const               { return hasWhite() + 3*hasRGB() + hasCCT(); } | ||||
|     inline  uint16_t getStart() const                          { return _start; } | ||||
|     inline  uint8_t  getType() const                           { return _type; } | ||||
|     inline  bool     isOk() const                              { return _valid; } | ||||
|     inline  bool     isReversed() const                        { return _reversed; } | ||||
|     inline  bool     isOffRefreshRequired() const              { return _needsRefresh; } | ||||
|     inline  bool     containsPixel(uint16_t pix) const         { return pix >= _start && pix < _start + _len; } | ||||
|     inline  bool     hasRGB() const                             { return _hasRgb; } | ||||
|     inline  bool     hasWhite() const                           { return _hasWhite; } | ||||
|     inline  bool     hasCCT() const                             { return _hasCCT; } | ||||
|     inline  bool     isDigital() const                          { return isDigital(_type); } | ||||
|     inline  bool     is2Pin() const                             { return is2Pin(_type); } | ||||
|     inline  bool     isOnOff() const                            { return isOnOff(_type); } | ||||
|     inline  bool     isPWM() const                              { return isPWM(_type); } | ||||
|     inline  bool     isVirtual() const                          { return isVirtual(_type); } | ||||
|     inline  bool     is16bit() const                            { return is16bit(_type); } | ||||
|     inline  bool     mustRefresh() const                        { return mustRefresh(_type); } | ||||
|     inline  void     setReversed(bool reversed)                 { _reversed = reversed; } | ||||
|     inline  void     setStart(uint16_t start)                   { _start = start; } | ||||
|     inline  void     setAutoWhiteMode(uint8_t m)                { if (m < 5) _autoWhiteMode = m; } | ||||
|     inline  uint8_t  getAutoWhiteMode() const                   { return _autoWhiteMode; } | ||||
|     inline  unsigned getNumberOfChannels() const                { return hasWhite() + 3*hasRGB() + hasCCT(); } | ||||
|     inline  uint16_t getStart() const                           { return _start; } | ||||
|     inline  uint8_t  getType() const                            { return _type; } | ||||
|     inline  bool     isOk() const                               { return _valid; } | ||||
|     inline  bool     isReversed() const                         { return _reversed; } | ||||
|     inline  bool     isOffRefreshRequired() const               { return _needsRefresh; } | ||||
|     inline  bool     containsPixel(uint16_t pix) const          { return pix >= _start && pix < _start + _len; } | ||||
|  | ||||
|     static inline std::vector<LEDType> getLEDTypes()           { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes | ||||
|     static constexpr uint8_t getNumberOfPins(uint8_t type)     { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK | ||||
|     static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } | ||||
|     static inline std::vector<LEDType> getLEDTypes()            { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes | ||||
|     static constexpr unsigned getNumberOfPins(uint8_t type)     { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK | ||||
|     static constexpr unsigned getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } | ||||
|     static constexpr bool hasRGB(uint8_t type) { | ||||
|       return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); | ||||
|     } | ||||
| @@ -152,7 +178,7 @@ class Bus { | ||||
|     static inline uint8_t  getGlobalAWMode()          { return _gAWM; } | ||||
|     static inline void     setCCT(int16_t cct)        { _cct = cct; } | ||||
|     static inline uint8_t  getCCTBlend()              { return _cctBlend; } | ||||
|     static inline void setCCTBlend(uint8_t b) { | ||||
|     static inline void     setCCTBlend(uint8_t b) { | ||||
|       _cctBlend = (std::min((int)b,100) * 127) / 100; | ||||
|       //compile-time limiter for hardware that can't power both white channels at max | ||||
|       #ifdef WLED_MAX_CCT_BLEND | ||||
| @@ -191,29 +217,30 @@ class Bus { | ||||
|  | ||||
|     uint32_t autoWhiteCalc(uint32_t c) const; | ||||
|     uint8_t *allocateData(size_t size = 1); | ||||
|     void     freeData() { if (_data != nullptr) free(_data); _data = nullptr; } | ||||
|     void     freeData(); | ||||
| }; | ||||
|  | ||||
|  | ||||
| class BusDigital : public Bus { | ||||
|   public: | ||||
|     BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com); | ||||
|     BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com); | ||||
|     ~BusDigital() { cleanup(); } | ||||
|  | ||||
|     void show() override; | ||||
|     bool canShow() const override; | ||||
|     void setBrightness(uint8_t b) override; | ||||
|     void setStatusPixel(uint32_t c) override; | ||||
|     [[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override; | ||||
|     [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override; | ||||
|     void setColorOrder(uint8_t colorOrder) override; | ||||
|     [[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override; | ||||
|     [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; | ||||
|     uint8_t  getColorOrder() const override  { return _colorOrder; } | ||||
|     uint8_t  getPins(uint8_t* pinArray = nullptr) const override; | ||||
|     uint8_t  skippedLeds() const override    { return _skip; } | ||||
|     unsigned getPins(uint8_t* pinArray = nullptr) const override; | ||||
|     unsigned skippedLeds() const override    { return _skip; } | ||||
|     uint16_t getFrequency() const override   { return _frequencykHz; } | ||||
|     uint16_t getLEDCurrent() const override  { return _milliAmpsPerLed; } | ||||
|     uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } | ||||
|     uint16_t getMaxCurrent() const override  { return _milliAmpsMax; } | ||||
|     unsigned getBusSize() const override; | ||||
|     void begin() override; | ||||
|     void cleanup(); | ||||
|  | ||||
| @@ -243,21 +270,22 @@ class BusDigital : public Bus { | ||||
|       return c; | ||||
|     } | ||||
|  | ||||
|     uint8_t  estimateCurrentAndLimitBri(); | ||||
|     uint8_t  estimateCurrentAndLimitBri() const; | ||||
| }; | ||||
|  | ||||
|  | ||||
| class BusPwm : public Bus { | ||||
|   public: | ||||
|     BusPwm(BusConfig &bc); | ||||
|     BusPwm(const BusConfig &bc); | ||||
|     ~BusPwm() { cleanup(); } | ||||
|  | ||||
|     void setPixelColor(uint16_t pix, uint32_t c) override; | ||||
|     uint32_t getPixelColor(uint16_t pix) const override; //does no index check | ||||
|     uint8_t  getPins(uint8_t* pinArray = nullptr) const override; | ||||
|     void setPixelColor(unsigned pix, uint32_t c) override; | ||||
|     uint32_t getPixelColor(unsigned pix) const override; //does no index check | ||||
|     unsigned getPins(uint8_t* pinArray = nullptr) const override; | ||||
|     uint16_t getFrequency() const override { return _frequency; } | ||||
|     unsigned getBusSize() const override   { return sizeof(BusPwm); } | ||||
|     void show() override; | ||||
|     void cleanup() { deallocatePins(); } | ||||
|     inline void cleanup() { deallocatePins(); _data = nullptr; } | ||||
|  | ||||
|     static std::vector<LEDType> getLEDTypes(); | ||||
|  | ||||
| @@ -276,14 +304,15 @@ class BusPwm : public Bus { | ||||
|  | ||||
| class BusOnOff : public Bus { | ||||
|   public: | ||||
|     BusOnOff(BusConfig &bc); | ||||
|     BusOnOff(const BusConfig &bc); | ||||
|     ~BusOnOff() { cleanup(); } | ||||
|  | ||||
|     void setPixelColor(uint16_t pix, uint32_t c) override; | ||||
|     uint32_t getPixelColor(uint16_t pix) const override; | ||||
|     uint8_t  getPins(uint8_t* pinArray) const override; | ||||
|     void setPixelColor(unsigned pix, uint32_t c) override; | ||||
|     uint32_t getPixelColor(unsigned pix) const override; | ||||
|     unsigned getPins(uint8_t* pinArray) const override; | ||||
|     unsigned getBusSize() const override { return sizeof(BusOnOff); } | ||||
|     void show() override; | ||||
|     void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } | ||||
|     inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; } | ||||
|  | ||||
|     static std::vector<LEDType> getLEDTypes(); | ||||
|  | ||||
| @@ -295,13 +324,14 @@ class BusOnOff : public Bus { | ||||
|  | ||||
| class BusNetwork : public Bus { | ||||
|   public: | ||||
|     BusNetwork(BusConfig &bc); | ||||
|     BusNetwork(const BusConfig &bc); | ||||
|     ~BusNetwork() { cleanup(); } | ||||
|  | ||||
|     bool canShow() const override  { 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) override; | ||||
|     uint32_t getPixelColor(uint16_t pix) const override; | ||||
|     uint8_t  getPins(uint8_t* pinArray = nullptr) const override; | ||||
|     [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override; | ||||
|     [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; | ||||
|     unsigned getPins(uint8_t* pinArray = nullptr) const override; | ||||
|     unsigned getBusSize() const override  { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); } | ||||
|     void show() override; | ||||
|     void cleanup(); | ||||
|  | ||||
| @@ -347,6 +377,16 @@ struct BusConfig { | ||||
|     type = busType & 0x7F;  // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh) | ||||
|     size_t nPins = Bus::getNumberOfPins(type); | ||||
|     for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i]; | ||||
|     DEBUGBUS_PRINTF_P(PSTR("Bus: Config (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), | ||||
|       (int)start, (int)(start+len), | ||||
|       (int)type, | ||||
|       (int)colorOrder, | ||||
|       (int)reversed, | ||||
|       (int)skipAmount, | ||||
|       (int)autoWhite, | ||||
|       (int)frequency, | ||||
|       (int)milliAmpsPerLed, (int)milliAmpsMax | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   //validates start and length and extends total if needed | ||||
| @@ -360,21 +400,32 @@ struct BusConfig { | ||||
|     if (start + count > total) total = start + count; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   unsigned memUsage(unsigned nr = 0) const; | ||||
| }; | ||||
|  | ||||
|  | ||||
| //fine tune power estimation constants for your setup | ||||
| //you can set it to 0 if the ESP is powered by USB and the LEDs by external | ||||
| #ifndef MA_FOR_ESP | ||||
|   #ifdef ESP8266 | ||||
|     #define MA_FOR_ESP         80 //how much mA does the ESP use (Wemos D1 about 80mA) | ||||
|   #else | ||||
|     #define MA_FOR_ESP        120 //how much mA does the ESP use (ESP32 about 120mA) | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
| class BusManager { | ||||
|   public: | ||||
|     BusManager() {}; | ||||
|  | ||||
|     //utility to get the approx. memory usage of a given BusConfig | ||||
|     static uint32_t memUsage(BusConfig &bc); | ||||
|     static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); | ||||
|     static uint16_t currentMilliamps() { return _milliAmpsUsed; } | ||||
|     static unsigned memUsage(); | ||||
|     static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } | ||||
|     static uint16_t ablMilliampsMax()  { return _milliAmpsMax; } | ||||
|  | ||||
|     static int add(BusConfig &bc); | ||||
|     static int add(const BusConfig &bc); | ||||
|     static void useParallelOutput(); // workaround for inaccessible PolyBus | ||||
|     static bool hasParallelOutput(); // workaround for inaccessible PolyBus | ||||
|  | ||||
|     //do not call this method from system context (network callback) | ||||
|     static void removeAll(); | ||||
| @@ -385,38 +436,37 @@ class BusManager { | ||||
|     static void show(); | ||||
|     static bool canAllShow(); | ||||
|     static void setStatusPixel(uint32_t c); | ||||
|     [[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c); | ||||
|     [[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c); | ||||
|     static void setBrightness(uint8_t b); | ||||
|     // for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K | ||||
|     // WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT() | ||||
|     static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); | ||||
|     static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;} | ||||
|     static uint32_t getPixelColor(uint16_t pix); | ||||
|     static uint32_t getPixelColor(unsigned pix); | ||||
|     static inline int16_t getSegmentCCT() { return Bus::getCCT(); } | ||||
|  | ||||
|     static Bus* getBus(uint8_t busNr); | ||||
|  | ||||
|     //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) | ||||
|     static uint16_t getTotalLength(); | ||||
|     static inline uint8_t getNumBusses() { return numBusses; } | ||||
|     static inline uint8_t getNumBusses() { return busses.size(); } | ||||
|     static String getLEDTypesJSONString(); | ||||
|  | ||||
|     static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; } | ||||
|  | ||||
|   private: | ||||
|     static uint8_t numBusses; | ||||
|     static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; | ||||
|     //static std::vector<std::unique_ptr<Bus>> busses; // we'd need C++ >11 | ||||
|     static std::vector<Bus*> busses; | ||||
|     static ColorOrderMap colorOrderMap; | ||||
|     static uint16_t _milliAmpsUsed; | ||||
|     static uint16_t _milliAmpsMax; | ||||
|     static uint8_t _parallelOutputs; | ||||
|  | ||||
|     #ifdef ESP32_DATA_IDLE_HIGH | ||||
|     static void    esp32RMTInvertIdle() ; | ||||
|     #endif | ||||
|     static uint8_t getNumVirtualBusses() { | ||||
|       int j = 0; | ||||
|       for (int i=0; i<numBusses; i++) if (busses[i]->isVirtual()) j++; | ||||
|       for (const auto &bus : busses) j += bus->isVirtual(); | ||||
|       return j; | ||||
|     } | ||||
| }; | ||||
|   | ||||
| @@ -1,23 +1,9 @@ | ||||
| #pragma once | ||||
| #ifndef BusWrapper_h | ||||
| #define BusWrapper_h | ||||
|  | ||||
| //#define NPB_CONF_4STEP_CADENCE | ||||
| #include "NeoPixelBusLg.h" | ||||
| #include "bus_manager.h" | ||||
|  | ||||
| // temporary - these defines should actually be set in platformio.ini | ||||
| // C3: I2S0 and I2S1 methods not supported (has one I2S bus) | ||||
| // S2: I2S1 methods not supported (has one I2S bus) | ||||
| // S3: I2S0 and I2S1 methods not supported yet (has two I2S buses) | ||||
| // https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4 | ||||
| // https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857 | ||||
|  | ||||
| #if !defined(WLED_NO_I2S0_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) | ||||
| #define WLED_NO_I2S0_PIXELBUS | ||||
| #endif | ||||
| #if !defined(WLED_NO_I2S1_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)) | ||||
| #define WLED_NO_I2S1_PIXELBUS | ||||
| #endif | ||||
| // temporary end | ||||
|  | ||||
| //Hardware SPI Pins | ||||
| #define P_8266_HS_MOSI 13 | ||||
| @@ -55,110 +41,98 @@ | ||||
| #define I_8266_DM_TM2_3 19 | ||||
| #define I_8266_BB_TM2_3 20 | ||||
| //UCS8903 (RGB) | ||||
| #define I_8266_U0_UCS_3 49 | ||||
| #define I_8266_U1_UCS_3 50 | ||||
| #define I_8266_DM_UCS_3 51 | ||||
| #define I_8266_BB_UCS_3 52 | ||||
| #define I_8266_U0_UCS_3 21 | ||||
| #define I_8266_U1_UCS_3 22 | ||||
| #define I_8266_DM_UCS_3 23 | ||||
| #define I_8266_BB_UCS_3 24 | ||||
| //UCS8904 (RGBW) | ||||
| #define I_8266_U0_UCS_4 53 | ||||
| #define I_8266_U1_UCS_4 54 | ||||
| #define I_8266_DM_UCS_4 55 | ||||
| #define I_8266_BB_UCS_4 56 | ||||
| #define I_8266_U0_UCS_4 25 | ||||
| #define I_8266_U1_UCS_4 26 | ||||
| #define I_8266_DM_UCS_4 27 | ||||
| #define I_8266_BB_UCS_4 28 | ||||
| //FW1906 GRBCW | ||||
| #define I_8266_U0_FW6_5 66 | ||||
| #define I_8266_U1_FW6_5 67 | ||||
| #define I_8266_DM_FW6_5 68 | ||||
| #define I_8266_BB_FW6_5 69 | ||||
| #define I_8266_U0_FW6_5 29 | ||||
| #define I_8266_U1_FW6_5 30 | ||||
| #define I_8266_DM_FW6_5 31 | ||||
| #define I_8266_BB_FW6_5 32 | ||||
| //ESP8266 APA106 | ||||
| #define I_8266_U0_APA106_3 81 | ||||
| #define I_8266_U1_APA106_3 82 | ||||
| #define I_8266_DM_APA106_3 83 | ||||
| #define I_8266_BB_APA106_3 84 | ||||
| #define I_8266_U0_APA106_3 33 | ||||
| #define I_8266_U1_APA106_3 34 | ||||
| #define I_8266_DM_APA106_3 35 | ||||
| #define I_8266_BB_APA106_3 36 | ||||
| //WS2805 (RGBCW) | ||||
| #define I_8266_U0_2805_5 89 | ||||
| #define I_8266_U1_2805_5 90 | ||||
| #define I_8266_DM_2805_5 91 | ||||
| #define I_8266_BB_2805_5 92 | ||||
| #define I_8266_U0_2805_5 37 | ||||
| #define I_8266_U1_2805_5 38 | ||||
| #define I_8266_DM_2805_5 39 | ||||
| #define I_8266_BB_2805_5 40 | ||||
| //TM1914 (RGB) | ||||
| #define I_8266_U0_TM1914_3 99 | ||||
| #define I_8266_U1_TM1914_3 100 | ||||
| #define I_8266_DM_TM1914_3 101 | ||||
| #define I_8266_BB_TM1914_3 102 | ||||
| #define I_8266_U0_TM1914_3 41 | ||||
| #define I_8266_U1_TM1914_3 42 | ||||
| #define I_8266_DM_TM1914_3 43 | ||||
| #define I_8266_BB_TM1914_3 44 | ||||
| //SM16825 (RGBCW) | ||||
| #define I_8266_U0_SM16825_5 103 | ||||
| #define I_8266_U1_SM16825_5 104 | ||||
| #define I_8266_DM_SM16825_5 105 | ||||
| #define I_8266_BB_SM16825_5 106 | ||||
| #define I_8266_U0_SM16825_5 45 | ||||
| #define I_8266_U1_SM16825_5 46 | ||||
| #define I_8266_DM_SM16825_5 47 | ||||
| #define I_8266_BB_SM16825_5 48 | ||||
|  | ||||
| /*** ESP32 Neopixel methods ***/ | ||||
| //RGB | ||||
| #define I_32_RN_NEO_3 21 | ||||
| #define I_32_I0_NEO_3 22 | ||||
| #define I_32_I1_NEO_3 23 | ||||
| #define I_32_RN_NEO_3 1 | ||||
| #define I_32_I2_NEO_3 2 | ||||
| //RGBW | ||||
| #define I_32_RN_NEO_4 25 | ||||
| #define I_32_I0_NEO_4 26 | ||||
| #define I_32_I1_NEO_4 27 | ||||
| #define I_32_RN_NEO_4 5 | ||||
| #define I_32_I2_NEO_4 6 | ||||
| //400Kbps | ||||
| #define I_32_RN_400_3 29 | ||||
| #define I_32_I0_400_3 30 | ||||
| #define I_32_I1_400_3 31 | ||||
| #define I_32_RN_400_3 9 | ||||
| #define I_32_I2_400_3 10 | ||||
| //TM1814 (RGBW) | ||||
| #define I_32_RN_TM1_4 33 | ||||
| #define I_32_I0_TM1_4 34 | ||||
| #define I_32_I1_TM1_4 35 | ||||
| #define I_32_RN_TM1_4 13 | ||||
| #define I_32_I2_TM1_4 14 | ||||
| //TM1829 (RGB) | ||||
| #define I_32_RN_TM2_3 36 | ||||
| #define I_32_I0_TM2_3 37 | ||||
| #define I_32_I1_TM2_3 38 | ||||
| #define I_32_RN_TM2_3 17 | ||||
| #define I_32_I2_TM2_3 18 | ||||
| //UCS8903 (RGB) | ||||
| #define I_32_RN_UCS_3 57 | ||||
| #define I_32_I0_UCS_3 58 | ||||
| #define I_32_I1_UCS_3 59 | ||||
| #define I_32_RN_UCS_3 21 | ||||
| #define I_32_I2_UCS_3 22 | ||||
| //UCS8904 (RGBW) | ||||
| #define I_32_RN_UCS_4 60 | ||||
| #define I_32_I0_UCS_4 61 | ||||
| #define I_32_I1_UCS_4 62 | ||||
| #define I_32_RN_UCS_4 25 | ||||
| #define I_32_I2_UCS_4 26 | ||||
| //FW1906 GRBCW | ||||
| #define I_32_RN_FW6_5 63 | ||||
| #define I_32_I0_FW6_5 64 | ||||
| #define I_32_I1_FW6_5 65 | ||||
| #define I_32_RN_FW6_5 29 | ||||
| #define I_32_I2_FW6_5 30 | ||||
| //APA106 | ||||
| #define I_32_RN_APA106_3 85 | ||||
| #define I_32_I0_APA106_3 86 | ||||
| #define I_32_I1_APA106_3 87 | ||||
| #define I_32_RN_APA106_3 33 | ||||
| #define I_32_I2_APA106_3 34 | ||||
| //WS2805 (RGBCW) | ||||
| #define I_32_RN_2805_5 93 | ||||
| #define I_32_I0_2805_5 94 | ||||
| #define I_32_I1_2805_5 95 | ||||
| #define I_32_RN_2805_5 37 | ||||
| #define I_32_I2_2805_5 38 | ||||
| //TM1914 (RGB) | ||||
| #define I_32_RN_TM1914_3 96 | ||||
| #define I_32_I0_TM1914_3 97 | ||||
| #define I_32_I1_TM1914_3 98 | ||||
| #define I_32_RN_TM1914_3 41 | ||||
| #define I_32_I2_TM1914_3 42 | ||||
| //SM16825 (RGBCW) | ||||
| #define I_32_RN_SM16825_5 107 | ||||
| #define I_32_I0_SM16825_5 108 | ||||
| #define I_32_I1_SM16825_5 109 | ||||
| #define I_32_RN_SM16825_5 45 | ||||
| #define I_32_I2_SM16825_5 46 | ||||
|  | ||||
| //APA102 | ||||
| #define I_HS_DOT_3 39 //hardware SPI | ||||
| #define I_SS_DOT_3 40 //soft SPI | ||||
| #define I_HS_DOT_3 101 //hardware SPI | ||||
| #define I_SS_DOT_3 102 //soft SPI | ||||
|  | ||||
| //LPD8806 | ||||
| #define I_HS_LPD_3 41 | ||||
| #define I_SS_LPD_3 42 | ||||
| #define I_HS_LPD_3 103 | ||||
| #define I_SS_LPD_3 104 | ||||
|  | ||||
| //WS2801 | ||||
| #define I_HS_WS1_3 43 | ||||
| #define I_SS_WS1_3 44 | ||||
| #define I_HS_WS1_3 105 | ||||
| #define I_SS_WS1_3 106 | ||||
|  | ||||
| //P9813 | ||||
| #define I_HS_P98_3 45 | ||||
| #define I_SS_P98_3 46 | ||||
| #define I_HS_P98_3 107 | ||||
| #define I_SS_P98_3 108 | ||||
|  | ||||
| //LPD6803 | ||||
| #define I_HS_LPO_3 47 | ||||
| #define I_SS_LPO_3 48 | ||||
| #define I_HS_LPO_3 109 | ||||
| #define I_SS_LPO_3 110 | ||||
|  | ||||
|  | ||||
| // In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly | ||||
| @@ -230,66 +204,95 @@ | ||||
|  | ||||
| /*** ESP32 Neopixel methods ***/ | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
| // C3: I2S0 and I2S1 methods not supported (has one I2S bus) | ||||
| // S2: I2S0 methods supported (single & parallel), I2S1 methods not supported (has one I2S bus) | ||||
| // S3: I2S0 methods not supported, I2S1 supports LCD parallel methods (has two I2S buses) | ||||
| // https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4 | ||||
| // https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857 | ||||
| #if defined(CONFIG_IDF_TARGET_ESP32S3) | ||||
|   // S3 will always use LCD parallel output | ||||
|   typedef X8Ws2812xMethod X1Ws2812xMethod; | ||||
|   typedef X8Sk6812Method X1Sk6812Method; | ||||
|   typedef X8400KbpsMethod X1400KbpsMethod; | ||||
|   typedef X8800KbpsMethod X1800KbpsMethod; | ||||
|   typedef X8Tm1814Method X1Tm1814Method; | ||||
|   typedef X8Tm1829Method X1Tm1829Method; | ||||
|   typedef X8Apa106Method X1Apa106Method; | ||||
|   typedef X8Ws2805Method X1Ws2805Method; | ||||
|   typedef X8Tm1914Method X1Tm1914Method; | ||||
| #elif defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
|   // S2 will use I2S0 | ||||
|   typedef NeoEsp32I2s0Ws2812xMethod X1Ws2812xMethod; | ||||
|   typedef NeoEsp32I2s0Sk6812Method X1Sk6812Method; | ||||
|   typedef NeoEsp32I2s0400KbpsMethod X1400KbpsMethod; | ||||
|   typedef NeoEsp32I2s0800KbpsMethod X1800KbpsMethod; | ||||
|   typedef NeoEsp32I2s0Tm1814Method X1Tm1814Method; | ||||
|   typedef NeoEsp32I2s0Tm1829Method X1Tm1829Method; | ||||
|   typedef NeoEsp32I2s0Apa106Method X1Apa106Method; | ||||
|   typedef NeoEsp32I2s0Ws2805Method X1Ws2805Method; | ||||
|   typedef NeoEsp32I2s0Tm1914Method X1Tm1914Method; | ||||
| #elif !defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|   // regular ESP32 will use I2S1 | ||||
|   typedef NeoEsp32I2s1Ws2812xMethod X1Ws2812xMethod; | ||||
|   typedef NeoEsp32I2s1Sk6812Method X1Sk6812Method; | ||||
|   typedef NeoEsp32I2s1400KbpsMethod X1400KbpsMethod; | ||||
|   typedef NeoEsp32I2s1800KbpsMethod X1800KbpsMethod; | ||||
|   typedef NeoEsp32I2s1Tm1814Method X1Tm1814Method; | ||||
|   typedef NeoEsp32I2s1Tm1829Method X1Tm1829Method; | ||||
|   typedef NeoEsp32I2s1Apa106Method X1Apa106Method; | ||||
|   typedef NeoEsp32I2s1Ws2805Method X1Ws2805Method; | ||||
|   typedef NeoEsp32I2s1Tm1914Method X1Tm1914Method; | ||||
| #endif | ||||
|  | ||||
| //RGB | ||||
| #define B_32_RN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I0_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0Ws2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Ws2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_NEO_3P NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_RN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> // ESP32, S2, S3, C3 | ||||
| //#define B_32_IN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2sNWs2812xMethod, NeoGammaNullMethod> // ESP32 (dynamic I2S selection) | ||||
| #define B_32_I2_NEO_3 NeoPixelBusLg<NeoGrbFeature, X1Ws2812xMethod, NeoGammaNullMethod> // ESP32, S2, S3 (automatic I2S selection, see typedef above) | ||||
| #define B_32_IP_NEO_3 NeoPixelBusLg<NeoGrbFeature, X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S (ESP32, S2, S3) | ||||
| //RGBW | ||||
| #define B_32_RN_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32RmtNSk6812Method, NeoGammaNullMethod> | ||||
| #define B_32_I0_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s0Sk6812Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1Sk6812Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_NEO_4P NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1X8Sk6812Method, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_NEO_4 NeoPixelBusLg<NeoGrbwFeature, X1Sk6812Method, NeoGammaNullMethod> | ||||
| #define B_32_IP_NEO_4 NeoPixelBusLg<NeoGrbwFeature, X8Sk6812Method, NeoGammaNullMethod> // parallel I2S | ||||
| //400Kbps | ||||
| #define B_32_RN_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtN400KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I0_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0400KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_400_3P NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_400_3 NeoPixelBusLg<NeoGrbFeature, X1400KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_IP_400_3 NeoPixelBusLg<NeoGrbFeature, X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| //TM1814 (RGBW) | ||||
| #define B_32_RN_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32RmtNTm1814Method, NeoGammaNullMethod> | ||||
| #define B_32_I0_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s0Tm1814Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_TM1_4P NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1X8Tm1814Method, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, X1Tm1814Method, NeoGammaNullMethod> | ||||
| #define B_32_IP_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, X8Tm1814Method, NeoGammaNullMethod> // parallel I2S | ||||
| //TM1829 (RGB) | ||||
| #define B_32_RN_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32RmtNTm1829Method, NeoGammaNullMethod> | ||||
| #define B_32_I0_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s0Tm1829Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1Tm1829Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_TM2_3P NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1X8Tm1829Method, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_TM2_3 NeoPixelBusLg<NeoBrgFeature, X1Tm1829Method, NeoGammaNullMethod> | ||||
| #define B_32_IP_TM2_3 NeoPixelBusLg<NeoBrgFeature, X8Tm1829Method, NeoGammaNullMethod> // parallel I2S | ||||
| //UCS8903 | ||||
| #define B_32_RN_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I0_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_UCS_3P NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, X1800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_IP_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| //UCS8904 | ||||
| #define B_32_RN_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I0_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_UCS_4P NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S | ||||
| #define B_32_I2_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, X1800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_IP_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S | ||||
| //APA106 | ||||
| #define B_32_RN_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNApa106Method, NeoGammaNullMethod> | ||||
| #define B_32_I0_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0Apa106Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Apa106Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_APA106_3P NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Apa106Method, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_APA106_3 NeoPixelBusLg<NeoGrbFeature, X1Apa106Method, NeoGammaNullMethod> | ||||
| #define B_32_IP_APA106_3 NeoPixelBusLg<NeoGrbFeature, X8Apa106Method, NeoGammaNullMethod> // parallel I2S | ||||
| //FW1906 GRBCW | ||||
| #define B_32_RN_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I0_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_FW6_5P NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, X1800KbpsMethod, NeoGammaNullMethod> | ||||
| #define B_32_IP_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S | ||||
| //WS2805 RGBWC | ||||
| #define B_32_RN_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32RmtNWs2805Method, NeoGammaNullMethod> | ||||
| #define B_32_I0_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s0Ws2805Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1Ws2805Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_2805_5P NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1X8Ws2805Method, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_2805_5 NeoPixelBusLg<NeoGrbwwFeature, X1Ws2805Method, NeoGammaNullMethod> | ||||
| #define B_32_IP_2805_5 NeoPixelBusLg<NeoGrbwwFeature, X8Ws2805Method, NeoGammaNullMethod> // parallel I2S | ||||
| //TM1914 (RGB) | ||||
| #define B_32_RN_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32RmtNTm1914Method, NeoGammaNullMethod> | ||||
| #define B_32_I0_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s0Tm1914Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1Tm1914Method, NeoGammaNullMethod> | ||||
| #define B_32_I1_TM1914_3P NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1X8Tm1914Method, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, X1Tm1914Method, NeoGammaNullMethod> | ||||
| #define B_32_IP_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, X8Tm1914Method, NeoGammaNullMethod> // parallel I2S | ||||
| //Sm16825 (RGBWC) | ||||
| #define B_32_RN_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I0_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32I2s0Ws2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32I2s1Ws2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_I1_SM16825_5P NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #define B_32_I2_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, X1Ws2812xMethod, NeoGammaNullMethod> | ||||
| #define B_32_IP_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S | ||||
| #endif | ||||
|  | ||||
| //APA102 | ||||
| @@ -328,11 +331,11 @@ | ||||
| //handles pointer type conversion for all possible bus types | ||||
| class PolyBus { | ||||
|   private: | ||||
|     static bool useParallelI2S; | ||||
|     static bool _useParallelI2S; | ||||
|  | ||||
|   public: | ||||
|     static inline void setParallelI2S1Output(bool b = true) { useParallelI2S = b; } | ||||
|     static inline bool isParallelI2S1Output(void) { return useParallelI2S; } | ||||
|     static inline void setParallelI2S1Output(bool b = true) { _useParallelI2S = b; } | ||||
|     static inline bool isParallelI2S1Output(void) { return _useParallelI2S; } | ||||
|  | ||||
|   // initialize SPI bus speed for DotStar methods | ||||
|   template <class T> | ||||
| @@ -436,34 +439,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: beginTM1914<B_32_RN_TM1914_3*>(busPtr); break; | ||||
|       case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->Begin(); break; | ||||
|       // I2S1 bus or parellel buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_NEO_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->Begin(); else (static_cast<B_32_I1_NEO_4*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_400_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) beginTM1814<B_32_I1_TM1_4P*>(busPtr); else beginTM1814<B_32_I1_TM1_4*>(busPtr); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_TM2_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_UCS_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->Begin(); else (static_cast<B_32_I1_UCS_4*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->Begin(); else (static_cast<B_32_I1_FW6_5*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_APA106_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->Begin(); else (static_cast<B_32_I1_2805_5*>(busPtr))->Begin(); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) beginTM1914<B_32_I1_TM1914_3P*>(busPtr); else beginTM1914<B_32_I1_TM1914_3*>(busPtr); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->Begin(); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->Begin(); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_TM1_4: beginTM1814<B_32_I0_TM1_4*>(busPtr); break; | ||||
|       case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->Begin(); break; | ||||
|       case I_32_I0_TM1914_3: beginTM1914<B_32_I0_TM1914_3*>(busPtr); break; | ||||
|       case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->Begin(); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_NEO_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->Begin(); else (static_cast<B_32_I2_NEO_4*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_400_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) beginTM1814<B_32_IP_TM1_4*>(busPtr); else beginTM1814<B_32_I2_TM1_4*>(busPtr); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_TM2_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_UCS_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->Begin(); else (static_cast<B_32_I2_UCS_4*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->Begin(); else (static_cast<B_32_I2_FW6_5*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_APA106_3*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->Begin(); else (static_cast<B_32_I2_2805_5*>(busPtr))->Begin(); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) beginTM1914<B_32_IP_TM1914_3*>(busPtr); else beginTM1914<B_32_I2_TM1914_3*>(busPtr); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->Begin(); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->Begin(); break; | ||||
|       #endif | ||||
|       // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() | ||||
|       case I_HS_DOT_3: beginDotStar<B_HS_DOT_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; | ||||
| @@ -484,8 +472,8 @@ class PolyBus { | ||||
|     #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) | ||||
|     // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation | ||||
|     // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation | ||||
|     if (useParallelI2S && channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 | ||||
|     else if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 | ||||
|     if (!_useParallelI2S && channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 | ||||
|     // if user selected parallel I2S, RMT is used 1st (8 channels) followed by parallel I2S (8 channels) | ||||
|     #endif | ||||
|     void* busPtr = nullptr; | ||||
|     switch (busType) { | ||||
| @@ -555,34 +543,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: busPtr = new B_32_RN_TM1914_3(len, pins[0], (NeoBusChannel)channel); break; | ||||
|       case I_32_RN_SM16825_5: busPtr = new B_32_RN_SM16825_5(len, pins[0], (NeoBusChannel)channel); break; | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) busPtr = new B_32_I1_NEO_3P(len, pins[0]); else busPtr = new B_32_I1_NEO_3(len, pins[0]); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) busPtr = new B_32_I1_NEO_4P(len, pins[0]); else busPtr = new B_32_I1_NEO_4(len, pins[0]); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) busPtr = new B_32_I1_400_3P(len, pins[0]); else busPtr = new B_32_I1_400_3(len, pins[0]); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) busPtr = new B_32_I1_TM1_4P(len, pins[0]); else busPtr = new B_32_I1_TM1_4(len, pins[0]); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) busPtr = new B_32_I1_TM2_3P(len, pins[0]); else busPtr = new B_32_I1_TM2_3(len, pins[0]); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) busPtr = new B_32_I1_UCS_3P(len, pins[0]); else busPtr = new B_32_I1_UCS_3(len, pins[0]); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) busPtr = new B_32_I1_UCS_4P(len, pins[0]); else busPtr = new B_32_I1_UCS_4(len, pins[0]); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) busPtr = new B_32_I1_APA106_3P(len, pins[0]); else busPtr = new B_32_I1_APA106_3(len, pins[0]); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) busPtr = new B_32_I1_FW6_5P(len, pins[0]); else busPtr = new B_32_I1_FW6_5(len, pins[0]); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) busPtr = new B_32_I1_2805_5P(len, pins[0]); else busPtr = new B_32_I1_2805_5(len, pins[0]); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) busPtr = new B_32_I1_TM1914_3P(len, pins[0]); else busPtr = new B_32_I1_TM1914_3(len, pins[0]); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) busPtr = new B_32_I1_SM16825_5P(len, pins[0]); else busPtr = new B_32_I1_SM16825_5(len, pins[0]); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break; | ||||
|       case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break; | ||||
|       case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break; | ||||
|       case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break; | ||||
|       case I_32_I0_TM2_3: busPtr = new B_32_I0_TM2_3(len, pins[0]); break; | ||||
|       case I_32_I0_UCS_3: busPtr = new B_32_I0_UCS_3(len, pins[0]); break; | ||||
|       case I_32_I0_UCS_4: busPtr = new B_32_I0_UCS_4(len, pins[0]); break; | ||||
|       case I_32_I0_APA106_3: busPtr = new B_32_I0_APA106_3(len, pins[0]); break; | ||||
|       case I_32_I0_FW6_5: busPtr = new B_32_I0_FW6_5(len, pins[0]); break; | ||||
|       case I_32_I0_2805_5: busPtr = new B_32_I0_2805_5(len, pins[0]); break; | ||||
|       case I_32_I0_TM1914_3: busPtr = new B_32_I0_TM1914_3(len, pins[0]); break; | ||||
|       case I_32_I0_SM16825_5: busPtr = new B_32_I0_SM16825_5(len, pins[0]); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) busPtr = new B_32_IP_NEO_3(len, pins[0]); else busPtr = new B_32_I2_NEO_3(len, pins[0]); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) busPtr = new B_32_IP_NEO_4(len, pins[0]); else busPtr = new B_32_I2_NEO_4(len, pins[0]); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) busPtr = new B_32_IP_400_3(len, pins[0]); else busPtr = new B_32_I2_400_3(len, pins[0]); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) busPtr = new B_32_IP_TM1_4(len, pins[0]); else busPtr = new B_32_I2_TM1_4(len, pins[0]); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) busPtr = new B_32_IP_TM2_3(len, pins[0]); else busPtr = new B_32_I2_TM2_3(len, pins[0]); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) busPtr = new B_32_IP_UCS_3(len, pins[0]); else busPtr = new B_32_I2_UCS_3(len, pins[0]); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) busPtr = new B_32_IP_UCS_4(len, pins[0]); else busPtr = new B_32_I2_UCS_4(len, pins[0]); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) busPtr = new B_32_IP_APA106_3(len, pins[0]); else busPtr = new B_32_I2_APA106_3(len, pins[0]); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) busPtr = new B_32_IP_FW6_5(len, pins[0]); else busPtr = new B_32_I2_FW6_5(len, pins[0]); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) busPtr = new B_32_IP_2805_5(len, pins[0]); else busPtr = new B_32_I2_2805_5(len, pins[0]); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) busPtr = new B_32_IP_TM1914_3(len, pins[0]); else busPtr = new B_32_I2_TM1914_3(len, pins[0]); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) busPtr = new B_32_IP_SM16825_5(len, pins[0]); else busPtr = new B_32_I2_SM16825_5(len, pins[0]); break; | ||||
|       #endif | ||||
|     #endif | ||||
|       // for 2-wire: pins[1] is clk, pins[0] is dat.  begin expects (len, clk, dat) | ||||
| @@ -669,34 +642,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->Show(consistent); break; | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_400_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) (static_cast<B_32_I1_TM1_4P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_TM2_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_APA106_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_FW6_5*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_2805_5*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast<B_32_I1_TM1914_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_TM1914_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->Show(consistent); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(consistent); 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; | ||||
|       case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_TM1914_3: (static_cast<B_32_I0_TM1914_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->Show(consistent); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_NEO_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_NEO_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_400_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast<B_32_IP_TM1_4*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_TM1_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_TM2_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_UCS_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_UCS_4*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_APA106_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_FW6_5*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_2805_5*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast<B_32_IP_TM1914_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_TM1914_3*>(busPtr))->Show(consistent); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->Show(consistent); break; | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(consistent); break; | ||||
| @@ -743,6 +701,7 @@ class PolyBus { | ||||
|       case I_8266_U0_UCS_4: return (static_cast<B_8266_U0_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_8266_U1_UCS_4: return (static_cast<B_8266_U1_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_8266_DM_UCS_4: return (static_cast<B_8266_DM_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_8266_BB_UCS_4: return (static_cast<B_8266_BB_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_8266_U0_APA106_3: return (static_cast<B_8266_U0_APA106_3*>(busPtr))->CanShow(); break; | ||||
|       case I_8266_U1_APA106_3: return (static_cast<B_8266_U1_APA106_3*>(busPtr))->CanShow(); break; | ||||
|       case I_8266_DM_APA106_3: return (static_cast<B_8266_DM_APA106_3*>(busPtr))->CanShow(); break; | ||||
| @@ -779,34 +738,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: return (static_cast<B_32_RN_TM1914_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_RN_SM16825_5: return (static_cast<B_32_RN_SM16825_5*>(busPtr))->CanShow(); break; | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) return (static_cast<B_32_I1_NEO_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_NEO_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) return (static_cast<B_32_I1_NEO_4P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_NEO_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) return (static_cast<B_32_I1_400_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_400_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) return (static_cast<B_32_I1_TM1_4P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_TM1_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) return (static_cast<B_32_I1_TM2_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_TM2_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) return (static_cast<B_32_I1_UCS_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_UCS_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) return (static_cast<B_32_I1_UCS_4P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) return (static_cast<B_32_I1_APA106_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_APA106_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) return (static_cast<B_32_I1_FW6_5P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_FW6_5*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) return (static_cast<B_32_I1_2805_5P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_2805_5*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) return (static_cast<B_32_I1_TM1914_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_TM1914_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) return (static_cast<B_32_I1_SM16825_5P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_SM16825_5*>(busPtr))->CanShow(); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: return (static_cast<B_32_I0_NEO_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_NEO_4: return (static_cast<B_32_I0_NEO_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_400_3: return (static_cast<B_32_I0_400_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_TM1_4: return (static_cast<B_32_I0_TM1_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_TM2_3: return (static_cast<B_32_I0_TM2_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_UCS_3: return (static_cast<B_32_I0_UCS_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_UCS_4: return (static_cast<B_32_I0_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_APA106_3: return (static_cast<B_32_I0_APA106_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_FW6_5: return (static_cast<B_32_I0_FW6_5*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_2805_5: return (static_cast<B_32_I0_2805_5*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_TM1914_3: return (static_cast<B_32_I0_TM1914_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I0_SM16825_5: return (static_cast<B_32_I0_SM16825_5*>(busPtr))->CanShow(); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) return (static_cast<B_32_IP_NEO_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_NEO_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) return (static_cast<B_32_IP_NEO_4*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_NEO_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) return (static_cast<B_32_IP_400_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_400_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) return (static_cast<B_32_IP_TM1_4*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_TM1_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) return (static_cast<B_32_IP_TM2_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_TM2_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) return (static_cast<B_32_IP_UCS_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_UCS_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) return (static_cast<B_32_IP_UCS_4*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_UCS_4*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) return (static_cast<B_32_IP_APA106_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_APA106_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) return (static_cast<B_32_IP_FW6_5*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_FW6_5*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) return (static_cast<B_32_IP_2805_5*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_2805_5*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) return (static_cast<B_32_IP_TM1914_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_TM1914_3*>(busPtr))->CanShow(); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) return (static_cast<B_32_IP_SM16825_5*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_SM16825_5*>(busPtr))->CanShow(); break; | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break; | ||||
| @@ -823,7 +767,7 @@ class PolyBus { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) { | ||||
|   [[gnu::hot]] static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) { | ||||
|     uint8_t r = c >> 16; | ||||
|     uint8_t g = c >> 8; | ||||
|     uint8_t b = c >> 0; | ||||
| @@ -916,34 +860,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) (static_cast<B_32_I1_TM1_4P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I1_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I1_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast<B_32_I1_TM1914_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break; | ||||
|       case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break; | ||||
|       case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; | ||||
|       case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; | ||||
|       case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; | ||||
|       case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; | ||||
|       case I_32_I0_TM1914_3: (static_cast<B_32_I0_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_NEO_4*>(busPtr))->SetPixelColor(pix, col); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast<B_32_IP_TM1_4*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_TM1_4*>(busPtr))->SetPixelColor(pix, col); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I2_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I2_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast<B_32_IP_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; | ||||
| @@ -1027,34 +956,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->SetLuminance(b); break; | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) (static_cast<B_32_I1_TM1_4P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_APA106_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_FW6_5*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_2805_5*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast<B_32_I1_TM1914_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_TM1914_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->SetLuminance(b); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); 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; | ||||
|       case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_TM1914_3: (static_cast<B_32_I0_TM1914_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->SetLuminance(b); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_NEO_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_NEO_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_400_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast<B_32_IP_TM1_4*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_TM1_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_TM2_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_UCS_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_UCS_4*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_APA106_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_FW6_5*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_2805_5*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast<B_32_IP_TM1914_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_TM1914_3*>(busPtr))->SetLuminance(b); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->SetLuminance(b); break; | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break; | ||||
| @@ -1070,7 +984,7 @@ class PolyBus { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { | ||||
|   [[gnu::hot]] static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { | ||||
|     RgbwColor col(0,0,0,0); | ||||
|     switch (busType) { | ||||
|       case I_NONE: break; | ||||
| @@ -1139,34 +1053,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: col = (static_cast<B_32_RN_TM1914_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_RN_SM16825_5: { Rgbww80Color c = (static_cast<B_32_RN_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: col = (useParallelI2S) ? (static_cast<B_32_I1_NEO_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_NEO_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_NEO_4: col = (useParallelI2S) ? (static_cast<B_32_I1_NEO_4P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_NEO_4*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_400_3: col = (useParallelI2S) ? (static_cast<B_32_I1_400_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_400_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_TM1_4: col = (useParallelI2S) ? (static_cast<B_32_I1_TM1_4P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_TM1_4*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_TM2_3: col = (useParallelI2S) ? (static_cast<B_32_I1_TM2_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_TM2_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_UCS_3: { Rgb48Color c = (useParallelI2S) ? (static_cast<B_32_I1_UCS_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; | ||||
|       case I_32_I1_UCS_4: { Rgbw64Color c = (useParallelI2S) ? (static_cast<B_32_I1_UCS_4P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; | ||||
|       case I_32_I1_APA106_3: col = (useParallelI2S) ? (static_cast<B_32_I1_APA106_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_APA106_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_FW6_5: { RgbwwColor c = (useParallelI2S) ? (static_cast<B_32_I1_FW6_5P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W | ||||
|       case I_32_I1_2805_5: { RgbwwColor c = (useParallelI2S) ? (static_cast<B_32_I1_2805_5P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W | ||||
|       case I_32_I1_TM1914_3: col = (useParallelI2S) ? (static_cast<B_32_I1_TM1914_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_TM1914_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I1_SM16825_5: { Rgbww80Color c = (useParallelI2S) ? (static_cast<B_32_I1_SM16825_5P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: col = (static_cast<B_32_I0_NEO_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_NEO_4: col = (static_cast<B_32_I0_NEO_4*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_400_3: col = (static_cast<B_32_I0_400_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_TM1_4: col = (static_cast<B_32_I0_TM1_4*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_TM2_3: col = (static_cast<B_32_I0_TM2_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_UCS_3: { Rgb48Color c = (static_cast<B_32_I0_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; | ||||
|       case I_32_I0_UCS_4: { Rgbw64Color c = (static_cast<B_32_I0_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; | ||||
|       case I_32_I0_APA106_3: col = (static_cast<B_32_I0_APA106_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_FW6_5: { RgbwwColor c = (static_cast<B_32_I0_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W | ||||
|       case I_32_I0_2805_5: { RgbwwColor c = (static_cast<B_32_I0_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W | ||||
|       case I_32_I0_TM1914_3: col = (static_cast<B_32_I0_TM1914_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I0_SM16825_5: { Rgbww80Color c = (static_cast<B_32_I0_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_NEO_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_NEO_4: col = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_4*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_NEO_4*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_400_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_400_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_400_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_TM1_4: col = (_useParallelI2S) ? (static_cast<B_32_IP_TM1_4*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_TM1_4*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_TM2_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_TM2_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_TM2_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_UCS_3: { Rgb48Color c = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; | ||||
|       case I_32_I2_UCS_4: { Rgbw64Color c = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_4*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; | ||||
|       case I_32_I2_APA106_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_APA106_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_APA106_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_FW6_5: { RgbwwColor c = (_useParallelI2S) ? (static_cast<B_32_IP_FW6_5*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W | ||||
|       case I_32_I2_2805_5: { RgbwwColor c = (_useParallelI2S) ? (static_cast<B_32_IP_2805_5*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W | ||||
|       case I_32_I2_TM1914_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_TM1914_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_TM1914_3*>(busPtr))->GetPixelColor(pix); break; | ||||
|       case I_32_I2_SM16825_5: { Rgbww80Color c = (_useParallelI2S) ? (static_cast<B_32_IP_SM16825_5*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break; | ||||
| @@ -1269,34 +1168,19 @@ class PolyBus { | ||||
|       case I_32_RN_TM1914_3: delete (static_cast<B_32_RN_TM1914_3*>(busPtr)); break; | ||||
|       case I_32_RN_SM16825_5: delete (static_cast<B_32_RN_SM16825_5*>(busPtr)); break; | ||||
|       // I2S1 bus or paralell buses | ||||
|       #ifndef WLED_NO_I2S1_PIXELBUS | ||||
|       case I_32_I1_NEO_3: if (useParallelI2S) delete (static_cast<B_32_I1_NEO_3P*>(busPtr)); else delete (static_cast<B_32_I1_NEO_3*>(busPtr)); break; | ||||
|       case I_32_I1_NEO_4: if (useParallelI2S) delete (static_cast<B_32_I1_NEO_4P*>(busPtr)); else delete (static_cast<B_32_I1_NEO_4*>(busPtr)); break; | ||||
|       case I_32_I1_400_3: if (useParallelI2S) delete (static_cast<B_32_I1_400_3P*>(busPtr)); else delete (static_cast<B_32_I1_400_3*>(busPtr)); break; | ||||
|       case I_32_I1_TM1_4: if (useParallelI2S) delete (static_cast<B_32_I1_TM1_4P*>(busPtr)); else delete (static_cast<B_32_I1_TM1_4*>(busPtr)); break; | ||||
|       case I_32_I1_TM2_3: if (useParallelI2S) delete (static_cast<B_32_I1_TM2_3P*>(busPtr)); else delete (static_cast<B_32_I1_TM2_3*>(busPtr)); break; | ||||
|       case I_32_I1_UCS_3: if (useParallelI2S) delete (static_cast<B_32_I1_UCS_3P*>(busPtr)); else delete (static_cast<B_32_I1_UCS_3*>(busPtr)); break; | ||||
|       case I_32_I1_UCS_4: if (useParallelI2S) delete (static_cast<B_32_I1_UCS_4P*>(busPtr)); else delete (static_cast<B_32_I1_UCS_4*>(busPtr)); break; | ||||
|       case I_32_I1_APA106_3: if (useParallelI2S) delete (static_cast<B_32_I1_APA106_3P*>(busPtr)); else delete (static_cast<B_32_I1_APA106_3*>(busPtr)); break; | ||||
|       case I_32_I1_FW6_5: if (useParallelI2S) delete (static_cast<B_32_I1_FW6_5P*>(busPtr)); else delete (static_cast<B_32_I1_FW6_5*>(busPtr)); break; | ||||
|       case I_32_I1_2805_5: if (useParallelI2S) delete (static_cast<B_32_I1_2805_5P*>(busPtr)); else delete (static_cast<B_32_I1_2805_5*>(busPtr)); break; | ||||
|       case I_32_I1_TM1914_3: if (useParallelI2S) delete (static_cast<B_32_I1_TM1914_3P*>(busPtr)); else delete (static_cast<B_32_I1_TM1914_3*>(busPtr)); break; | ||||
|       case I_32_I1_SM16825_5: if (useParallelI2S) delete (static_cast<B_32_I1_SM16825_5P*>(busPtr)); else delete (static_cast<B_32_I1_SM16825_5*>(busPtr)); break; | ||||
|       #endif | ||||
|       // I2S0 bus | ||||
|       #ifndef WLED_NO_I2S0_PIXELBUS | ||||
|       case I_32_I0_NEO_3: delete (static_cast<B_32_I0_NEO_3*>(busPtr)); break; | ||||
|       case I_32_I0_NEO_4: delete (static_cast<B_32_I0_NEO_4*>(busPtr)); break; | ||||
|       case I_32_I0_400_3: delete (static_cast<B_32_I0_400_3*>(busPtr)); break; | ||||
|       case I_32_I0_TM1_4: delete (static_cast<B_32_I0_TM1_4*>(busPtr)); break; | ||||
|       case I_32_I0_TM2_3: delete (static_cast<B_32_I0_TM2_3*>(busPtr)); break; | ||||
|       case I_32_I0_UCS_3: delete (static_cast<B_32_I0_UCS_3*>(busPtr)); break; | ||||
|       case I_32_I0_UCS_4: delete (static_cast<B_32_I0_UCS_4*>(busPtr)); break; | ||||
|       case I_32_I0_APA106_3: delete (static_cast<B_32_I0_APA106_3*>(busPtr)); break; | ||||
|       case I_32_I0_FW6_5: delete (static_cast<B_32_I0_FW6_5*>(busPtr)); break; | ||||
|       case I_32_I0_2805_5: delete (static_cast<B_32_I0_2805_5*>(busPtr)); break; | ||||
|       case I_32_I0_TM1914_3: delete (static_cast<B_32_I0_TM1914_3*>(busPtr)); break; | ||||
|       case I_32_I0_SM16825_5: delete (static_cast<B_32_I0_SM16825_5*>(busPtr)); break; | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: if (_useParallelI2S) delete (static_cast<B_32_IP_NEO_3*>(busPtr)); else delete (static_cast<B_32_I2_NEO_3*>(busPtr)); break; | ||||
|       case I_32_I2_NEO_4: if (_useParallelI2S) delete (static_cast<B_32_IP_NEO_4*>(busPtr)); else delete (static_cast<B_32_I2_NEO_4*>(busPtr)); break; | ||||
|       case I_32_I2_400_3: if (_useParallelI2S) delete (static_cast<B_32_IP_400_3*>(busPtr)); else delete (static_cast<B_32_I2_400_3*>(busPtr)); break; | ||||
|       case I_32_I2_TM1_4: if (_useParallelI2S) delete (static_cast<B_32_IP_TM1_4*>(busPtr)); else delete (static_cast<B_32_I2_TM1_4*>(busPtr)); break; | ||||
|       case I_32_I2_TM2_3: if (_useParallelI2S) delete (static_cast<B_32_IP_TM2_3*>(busPtr)); else delete (static_cast<B_32_I2_TM2_3*>(busPtr)); break; | ||||
|       case I_32_I2_UCS_3: if (_useParallelI2S) delete (static_cast<B_32_IP_UCS_3*>(busPtr)); else delete (static_cast<B_32_I2_UCS_3*>(busPtr)); break; | ||||
|       case I_32_I2_UCS_4: if (_useParallelI2S) delete (static_cast<B_32_IP_UCS_4*>(busPtr)); else delete (static_cast<B_32_I2_UCS_4*>(busPtr)); break; | ||||
|       case I_32_I2_APA106_3: if (_useParallelI2S) delete (static_cast<B_32_IP_APA106_3*>(busPtr)); else delete (static_cast<B_32_I2_APA106_3*>(busPtr)); break; | ||||
|       case I_32_I2_FW6_5: if (_useParallelI2S) delete (static_cast<B_32_IP_FW6_5*>(busPtr)); else delete (static_cast<B_32_I2_FW6_5*>(busPtr)); break; | ||||
|       case I_32_I2_2805_5: if (_useParallelI2S) delete (static_cast<B_32_IP_2805_5*>(busPtr)); else delete (static_cast<B_32_I2_2805_5*>(busPtr)); break; | ||||
|       case I_32_I2_TM1914_3: if (_useParallelI2S) delete (static_cast<B_32_IP_TM1914_3*>(busPtr)); else delete (static_cast<B_32_I2_TM1914_3*>(busPtr)); break; | ||||
|       case I_32_I2_SM16825_5: if (_useParallelI2S) delete (static_cast<B_32_IP_SM16825_5*>(busPtr)); else delete (static_cast<B_32_I2_SM16825_5*>(busPtr)); break; | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break; | ||||
| @@ -1312,8 +1196,178 @@ class PolyBus { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static unsigned getDataSize(void* busPtr, uint8_t busType) { | ||||
|     unsigned size = 0; | ||||
|     switch (busType) { | ||||
|       case I_NONE: break; | ||||
|     #ifdef ESP8266 | ||||
|       case I_8266_U0_NEO_3: size = (static_cast<B_8266_U0_NEO_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_NEO_3: size = (static_cast<B_8266_U1_NEO_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_NEO_3: size = (static_cast<B_8266_DM_NEO_3*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_NEO_3: size = (static_cast<B_8266_BB_NEO_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_NEO_4: size = (static_cast<B_8266_U0_NEO_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_NEO_4: size = (static_cast<B_8266_U1_NEO_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_NEO_4: size = (static_cast<B_8266_DM_NEO_4*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_NEO_4: size = (static_cast<B_8266_BB_NEO_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_400_3: size = (static_cast<B_8266_U0_400_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_400_3: size = (static_cast<B_8266_U1_400_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_400_3: size = (static_cast<B_8266_DM_400_3*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_400_3: size = (static_cast<B_8266_BB_400_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_TM1_4: size = (static_cast<B_8266_U0_TM1_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_TM1_4: size = (static_cast<B_8266_U1_TM1_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_TM1_4: size = (static_cast<B_8266_DM_TM1_4*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_TM1_4: size = (static_cast<B_8266_BB_TM1_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_TM2_3: size = (static_cast<B_8266_U0_TM2_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_TM2_3: size = (static_cast<B_8266_U1_TM2_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_TM2_3: size = (static_cast<B_8266_DM_TM2_3*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_TM2_3: size = (static_cast<B_8266_BB_TM2_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_UCS_3: size = (static_cast<B_8266_U0_UCS_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_UCS_3: size = (static_cast<B_8266_U1_UCS_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_UCS_3: size = (static_cast<B_8266_DM_UCS_3*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_UCS_3: size = (static_cast<B_8266_BB_UCS_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_UCS_4: size = (static_cast<B_8266_U0_UCS_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_UCS_4: size = (static_cast<B_8266_U1_UCS_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_UCS_4: size = (static_cast<B_8266_DM_UCS_4*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_UCS_4: size = (static_cast<B_8266_BB_UCS_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_APA106_3: size = (static_cast<B_8266_U0_APA106_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_APA106_3: size = (static_cast<B_8266_U1_APA106_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_APA106_3: size = (static_cast<B_8266_DM_APA106_3*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_APA106_3: size = (static_cast<B_8266_BB_APA106_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_FW6_5: size = (static_cast<B_8266_U0_FW6_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_FW6_5: size = (static_cast<B_8266_U1_FW6_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_FW6_5: size = (static_cast<B_8266_DM_FW6_5*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_FW6_5: size = (static_cast<B_8266_BB_FW6_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_2805_5: size = (static_cast<B_8266_U0_2805_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_2805_5: size = (static_cast<B_8266_U1_2805_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_2805_5: size = (static_cast<B_8266_DM_2805_5*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_2805_5: size = (static_cast<B_8266_BB_2805_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_TM1914_3: size = (static_cast<B_8266_U0_TM1914_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_TM1914_3: size = (static_cast<B_8266_U1_TM1914_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_TM1914_3: size = (static_cast<B_8266_DM_TM1914_3*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_TM1914_3: size = (static_cast<B_8266_BB_TM1914_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U0_SM16825_5: size = (static_cast<B_8266_U0_SM16825_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_U1_SM16825_5: size = (static_cast<B_8266_U1_SM16825_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_8266_DM_SM16825_5: size = (static_cast<B_8266_DM_SM16825_5*>(busPtr))->PixelsSize()*5; break; | ||||
|       case I_8266_BB_SM16825_5: size = (static_cast<B_8266_BB_SM16825_5*>(busPtr))->PixelsSize()*2; break; | ||||
|     #endif | ||||
|     #ifdef ARDUINO_ARCH_ESP32 | ||||
|       // RMT buses (front + back + small system managed RMT) | ||||
|       case I_32_RN_NEO_3: size = (static_cast<B_32_RN_NEO_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_NEO_4: size = (static_cast<B_32_RN_NEO_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_400_3: size = (static_cast<B_32_RN_400_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_TM1_4: size = (static_cast<B_32_RN_TM1_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_TM2_3: size = (static_cast<B_32_RN_TM2_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_UCS_3: size = (static_cast<B_32_RN_UCS_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_UCS_4: size = (static_cast<B_32_RN_UCS_4*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_APA106_3: size = (static_cast<B_32_RN_APA106_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_FW6_5: size = (static_cast<B_32_RN_FW6_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_2805_5: size = (static_cast<B_32_RN_2805_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_TM1914_3: size = (static_cast<B_32_RN_TM1914_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_32_RN_SM16825_5: size = (static_cast<B_32_RN_SM16825_5*>(busPtr))->PixelsSize()*2; break; | ||||
|       // I2S1 bus or paralell buses (front + DMA; DMA = front * cadence, aligned to 4 bytes) | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_NEO_3*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_NEO_4: size = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_4*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_NEO_4*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_400_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_400_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_400_3*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_TM1_4: size = (_useParallelI2S) ? (static_cast<B_32_IP_TM1_4*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_TM1_4*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_TM2_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_TM2_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_TM2_3*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_UCS_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_UCS_3*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_UCS_4: size = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_4*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_UCS_4*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_APA106_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_APA106_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_APA106_3*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_FW6_5: size = (_useParallelI2S) ? (static_cast<B_32_IP_FW6_5*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_FW6_5*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_2805_5: size = (_useParallelI2S) ? (static_cast<B_32_IP_2805_5*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_2805_5*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_TM1914_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_TM1914_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_TM1914_3*>(busPtr))->PixelsSize()*4; break; | ||||
|       case I_32_I2_SM16825_5: size = (_useParallelI2S) ? (static_cast<B_32_IP_SM16825_5*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_SM16825_5*>(busPtr))->PixelsSize()*4; break; | ||||
|       #endif | ||||
|     #endif | ||||
|       case I_HS_DOT_3: size = (static_cast<B_HS_DOT_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_SS_DOT_3: size = (static_cast<B_SS_DOT_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_HS_LPD_3: size = (static_cast<B_HS_LPD_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_SS_LPD_3: size = (static_cast<B_SS_LPD_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_HS_LPO_3: size = (static_cast<B_HS_LPO_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_SS_LPO_3: size = (static_cast<B_SS_LPO_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_HS_WS1_3: size = (static_cast<B_HS_WS1_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_SS_WS1_3: size = (static_cast<B_SS_WS1_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_HS_P98_3: size = (static_cast<B_HS_P98_3*>(busPtr))->PixelsSize()*2; break; | ||||
|       case I_SS_P98_3: size = (static_cast<B_SS_P98_3*>(busPtr))->PixelsSize()*2; break; | ||||
|     } | ||||
|     return size; | ||||
|   } | ||||
|  | ||||
|   static unsigned memUsage(unsigned count, unsigned busType) { | ||||
|     unsigned size = count*3;  // let's assume 3 channels, we will add count or 2*count below for 4 channels or 5 channels | ||||
|     switch (busType) { | ||||
|       case I_NONE: size = 0; break; | ||||
|     #ifdef ESP8266 | ||||
|       // UART methods have front + back buffers + small UART | ||||
|       case I_8266_U0_NEO_4: size = (size + count)*2; break; // 4 channels | ||||
|       case I_8266_U1_NEO_4: size = (size + count)*2; break; // 4 channels | ||||
|       case I_8266_BB_NEO_4: size = (size + count)*2; break; // 4 channels | ||||
|       case I_8266_U0_TM1_4: size = (size + count)*2; break; // 4 channels | ||||
|       case I_8266_U1_TM1_4: size = (size + count)*2; break; // 4 channels | ||||
|       case I_8266_BB_TM1_4: size = (size + count)*2; break; // 4 channels | ||||
|       case I_8266_U0_UCS_3: size *= 4; break; // 16 bit | ||||
|       case I_8266_U1_UCS_3: size *= 4; break; // 16 bit | ||||
|       case I_8266_BB_UCS_3: size *= 4; break; // 16 bit | ||||
|       case I_8266_U0_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels | ||||
|       case I_8266_U1_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels | ||||
|       case I_8266_BB_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels | ||||
|       case I_8266_U0_FW6_5: size = (size + 2*count)*2; break; // 5 channels | ||||
|       case I_8266_U1_FW6_5: size = (size + 2*count)*2; break; // 5channels | ||||
|       case I_8266_BB_FW6_5: size = (size + 2*count)*2; break; // 5 channels | ||||
|       case I_8266_U0_2805_5: size = (size + 2*count)*2; break; // 5 channels | ||||
|       case I_8266_U1_2805_5: size = (size + 2*count)*2; break; // 5 channels | ||||
|       case I_8266_BB_2805_5: size = (size + 2*count)*2; break; // 5 channels | ||||
|       case I_8266_U0_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels | ||||
|       case I_8266_U1_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels | ||||
|       case I_8266_BB_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels | ||||
|       // DMA methods have front + DMA buffer = ((1+(3+1)) * channels) | ||||
|       case I_8266_DM_NEO_3: size *= 5; break; | ||||
|       case I_8266_DM_NEO_4: size = (size + count)*5; break; | ||||
|       case I_8266_DM_400_3: size *= 5; break; | ||||
|       case I_8266_DM_TM1_4: size = (size + count)*5; break; | ||||
|       case I_8266_DM_TM2_3: size *= 5; break; | ||||
|       case I_8266_DM_UCS_3: size *= 2*5; break; | ||||
|       case I_8266_DM_UCS_4: size = (size + count)*2*5; break; | ||||
|       case I_8266_DM_APA106_3: size *= 5; break; | ||||
|       case I_8266_DM_FW6_5: size = (size + 2*count)*5; break; | ||||
|       case I_8266_DM_2805_5: size = (size + 2*count)*5; break; | ||||
|       case I_8266_DM_TM1914_3: size *= 5; break; | ||||
|       case I_8266_DM_SM16825_5: size = (size + 2*count)*2*5; break; | ||||
|     #endif | ||||
|     #ifdef ARDUINO_ARCH_ESP32 | ||||
|       // RMT buses (1x front and 1x back buffer) | ||||
|       case I_32_RN_NEO_4: size = (size + count)*2; break; | ||||
|       case I_32_RN_TM1_4: size = (size + count)*2; break; | ||||
|       case I_32_RN_UCS_3: size *= 2*2; break; | ||||
|       case I_32_RN_UCS_4: size = (size + count)*2*2; break; | ||||
|       case I_32_RN_FW6_5: size = (size + 2*count)*2; break; | ||||
|       case I_32_RN_2805_5: size = (size + 2*count)*2; break; | ||||
|       case I_32_RN_SM16825_5: size = (size + 2*count)*2*2; break; | ||||
|       // I2S1 bus or paralell buses (individual 1x front and 1 DMA (3x or 4x pixel count) or common back DMA buffers) | ||||
|       #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
|       case I_32_I2_NEO_3: size *= 4; break; | ||||
|       case I_32_I2_NEO_4: size = (size + count)*4; break; | ||||
|       case I_32_I2_400_3: size *= 4; break; | ||||
|       case I_32_I2_TM1_4: size = (size + count)*4; break; | ||||
|       case I_32_I2_TM2_3: size *= 4; break; | ||||
|       case I_32_I2_UCS_3: size *= 2*4; break; | ||||
|       case I_32_I2_UCS_4: size = (size + count)*2*4; break; | ||||
|       case I_32_I2_APA106_3: size *= 4; break; | ||||
|       case I_32_I2_FW6_5: size = (size + 2*count)*4; break; | ||||
|       case I_32_I2_2805_5: size = (size + 2*count)*4; break; | ||||
|       case I_32_I2_TM1914_3: size *= 4; break; | ||||
|       case I_32_I2_SM16825_5: size = (size + 2*count)*2*4; break; | ||||
|       #endif | ||||
|     #endif | ||||
|       // everything else uses 2 buffers | ||||
|       default:         size *= 2; break; | ||||
|     } | ||||
|     return size; | ||||
|   } | ||||
|  | ||||
|   //gives back the internal type index (I_XX_XXX_X above) for the input | ||||
|   static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) { | ||||
|   static uint8_t getI(uint8_t busType, const uint8_t* pins, uint8_t num = 0) { | ||||
|     if (!Bus::isDigital(busType)) return I_NONE; | ||||
|     if (Bus::is2Pin(busType)) { //SPI LED chips | ||||
|       bool isHSPI = false; | ||||
| @@ -1372,26 +1426,33 @@ class PolyBus { | ||||
|       uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 | ||||
|       #if defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
|       // ESP32-S2 only has 4 RMT channels | ||||
|       if (num > 4) return I_NONE; | ||||
|       if (num > 3) offset = 1;  // only one I2S (use last to allow Audioreactive) | ||||
|       if (_useParallelI2S) { | ||||
|         if (num > 11) return I_NONE; | ||||
|         if (num > 3) offset = 1;    // use x8 parallel I2S0 channels (use last to allow Audioreactive) | ||||
|       } else { | ||||
|         if (num > 4) return I_NONE; | ||||
|         if (num > 3) offset = 1;  // only one I2S0 (use last to allow Audioreactive) | ||||
|       } | ||||
|       #elif defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|       // On ESP32-C3 only the first 2 RMT channels are usable for transmitting | ||||
|       if (num > 1) return I_NONE; | ||||
|       //if (num > 1) offset = 1; // I2S not supported yet (only 1 I2S) | ||||
|       #elif defined(CONFIG_IDF_TARGET_ESP32S3) | ||||
|       // On ESP32-S3 only the first 4 RMT channels are usable for transmitting | ||||
|       if (num > 3) return I_NONE; | ||||
|       //if (num > 3) offset = num -4; // I2S not supported yet | ||||
|       if (_useParallelI2S) { | ||||
|         if (num > 11) return I_NONE; | ||||
|         if (num > 3) offset = 1;    // use x8 parallel I2S LCD channels | ||||
|       } else { | ||||
|         if (num > 3) return I_NONE; // do not use single I2S (as it is not supported) | ||||
|       } | ||||
|       #else | ||||
|       // standard ESP32 has 8 RMT and 2 I2S channels | ||||
|       if (useParallelI2S) { | ||||
|         if (num > 16) return I_NONE; | ||||
|         if (num < 8) offset = 2;  // prefer 8 parallel I2S1 channels | ||||
|         if (num == 16) offset = 1; | ||||
|       // standard ESP32 has 8 RMT and x1/x8 I2S1 channels | ||||
|       if (_useParallelI2S) { | ||||
|         if (num > 15) return I_NONE; | ||||
|         if (num > 7) offset = 1;  // 8 RMT followed by 8 I2S | ||||
|       } else { | ||||
|         if (num > 9) return I_NONE; | ||||
|         if (num > 8) offset = 1; | ||||
|         if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed) | ||||
|         if (num == 0) offset = 1; // prefer I2S1 for 1st bus (less flickering but more RAM needed) | ||||
|       } | ||||
|       #endif | ||||
|       switch (busType) { | ||||
|   | ||||
| @@ -375,6 +375,7 @@ void handleIO() | ||||
|       if (rlyPin>=0) { | ||||
|         pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT); | ||||
|         digitalWrite(rlyPin, rlyMde); | ||||
|         delay(50); // wait for relay to switch and power to stabilize | ||||
|       } | ||||
|       offMode = false; | ||||
|     } | ||||
|   | ||||
| @@ -118,6 +118,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { | ||||
|   Bus::setCCTBlend(strip.cctBlending); | ||||
|   strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS | ||||
|   CJSON(useGlobalLedBuffer, hw_led[F("ld")]); | ||||
|   #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|   CJSON(useParallelI2S, hw_led[F("prl")]); | ||||
|   #endif | ||||
|  | ||||
|   #ifndef WLED_DISABLE_2D | ||||
|   // 2D Matrix Settings | ||||
| @@ -162,34 +165,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { | ||||
|     DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap()); | ||||
|     int s = 0;  // bus iterator | ||||
|     if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback | ||||
|     unsigned mem = 0; | ||||
|  | ||||
|     // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) | ||||
|     bool useParallel = false; | ||||
|     #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) | ||||
|     unsigned digitalCount = 0; | ||||
|     unsigned maxLedsOnBus = 0; | ||||
|     unsigned maxChannels = 0; | ||||
|     for (JsonObject elm : ins) { | ||||
|       unsigned type = elm["type"] | TYPE_WS2812_RGB; | ||||
|       unsigned len = elm["len"] | DEFAULT_LED_COUNT; | ||||
|       if (!Bus::isDigital(type)) continue; | ||||
|       if (!Bus::is2Pin(type)) { | ||||
|         digitalCount++; | ||||
|         unsigned channels = Bus::getNumberOfChannels(type); | ||||
|         if (len > maxLedsOnBus)     maxLedsOnBus = len; | ||||
|         if (channels > maxChannels) maxChannels  = channels; | ||||
|       } | ||||
|     } | ||||
|     DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); | ||||
|     // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 | ||||
|     if (maxLedsOnBus <= 300 && digitalCount > 5) { | ||||
|       DEBUG_PRINTLN(F("Switching to parallel I2S.")); | ||||
|       useParallel = true; | ||||
|       BusManager::useParallelOutput(); | ||||
|       mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation | ||||
|     } | ||||
|     #endif | ||||
|  | ||||
|     for (JsonObject elm : ins) { | ||||
|       if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; | ||||
| @@ -220,24 +195,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { | ||||
|         maMax = 0; | ||||
|       } | ||||
|       ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh | ||||
|       if (fromFS) { | ||||
|         BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); | ||||
|         if (useParallel && s < 8) { | ||||
|           // if for some unexplained reason the above pre-calculation was wrong, update | ||||
|           unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S | ||||
|           if (memT > mem) mem = memT; // if we have unequal LED count use the largest | ||||
|         } else | ||||
|           mem += BusManager::memUsage(bc); // includes global buffer | ||||
|         if (mem <= MAX_LED_MEMORY) if (BusManager::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, freqkHz, useGlobalLedBuffer, maPerLed, maMax); | ||||
|         doInitBusses = true;  // finalization done in beginStrip() | ||||
|       } | ||||
|  | ||||
|       busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax))); | ||||
|       doInitBusses = true;  // finalization done in beginStrip() | ||||
|       s++; | ||||
|     } | ||||
|     DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); | ||||
|     DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); | ||||
|   } | ||||
|   if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus | ||||
|  | ||||
| @@ -824,6 +786,9 @@ void serializeConfig() { | ||||
|   hw_led["fps"] = strip.getTargetFps(); | ||||
|   hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override | ||||
|   hw_led[F("ld")] = useGlobalLedBuffer; | ||||
|   #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|   hw_led[F("prl")] = BusManager::hasParallelOutput(); | ||||
|   #endif | ||||
|  | ||||
|   #ifndef WLED_DISABLE_2D | ||||
|   // 2D Matrix Settings | ||||
| @@ -848,8 +813,19 @@ void serializeConfig() { | ||||
|   JsonArray hw_led_ins = hw_led.createNestedArray("ins"); | ||||
|  | ||||
|   for (size_t s = 0; s < BusManager::getNumBusses(); s++) { | ||||
|     DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s); | ||||
|     Bus *bus = BusManager::getBus(s); | ||||
|     if (!bus || bus->getLength()==0) break; | ||||
|     DEBUG_PRINTF_P(PSTR("  (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), | ||||
|       (int)bus->getStart(), (int)(bus->getStart()+bus->getLength()), | ||||
|       (int)(bus->getType() & 0x7F), | ||||
|       (int)bus->getColorOrder(), | ||||
|       (int)bus->isReversed(), | ||||
|       (int)bus->skippedLeds(), | ||||
|       (int)bus->getAutoWhiteMode(), | ||||
|       (int)bus->getFrequency(), | ||||
|       (int)bus->getLEDCurrent(), (int)bus->getMaxCurrent() | ||||
|     ); | ||||
|     JsonObject ins = hw_led_ins.createNestedObject(); | ||||
|     ins["start"] = bus->getStart(); | ||||
|     ins["len"] = bus->getLength(); | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
| #endif | ||||
|  | ||||
| #ifndef WLED_MAX_USERMODS | ||||
|   #ifdef ESP8266 | ||||
|   #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
|     #define WLED_MAX_USERMODS 4 | ||||
|   #else | ||||
|     #define WLED_MAX_USERMODS 6 | ||||
| @@ -49,31 +49,31 @@ | ||||
|     #define WLED_MAX_DIGITAL_CHANNELS 3 | ||||
|     #define WLED_MAX_ANALOG_CHANNELS 5 | ||||
|     #define WLED_MAX_BUSSES 4                 // will allow 3 digital & 1 analog RGB | ||||
|     #define WLED_MIN_VIRTUAL_BUSSES 2 | ||||
|     #define WLED_MIN_VIRTUAL_BUSSES 3 | ||||
|   #else | ||||
|     #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) | ||||
|     #if defined(CONFIG_IDF_TARGET_ESP32C3)    // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM | ||||
|       #define WLED_MAX_BUSSES 6               // will allow 2 digital & 2 analog RGB or 6 PWM white | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 2 | ||||
|       //#define WLED_MAX_ANALOG_CHANNELS 6 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 3 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 4 | ||||
|     #elif defined(CONFIG_IDF_TARGET_ESP32S2)  // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB | ||||
|       // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) | ||||
|       #define WLED_MAX_BUSSES 7               // will allow 5 digital & 2 analog RGB | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 5 | ||||
|       //#define WLED_MAX_ANALOG_CHANNELS 8 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 3 | ||||
|     #elif defined(CONFIG_IDF_TARGET_ESP32S3)  // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM | ||||
|       #define WLED_MAX_BUSSES 6               // will allow 4 digital & 2 analog RGB | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 4 | ||||
|       #define WLED_MAX_BUSSES 14              // will allow 12 digital & 2 analog RGB | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 12    // x4 RMT + x1/x8 I2S0 | ||||
|       //#define WLED_MAX_ANALOG_CHANNELS 8 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 4 | ||||
|     #elif defined(CONFIG_IDF_TARGET_ESP32S3)  // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1 | ||||
|       #define WLED_MAX_BUSSES 14              // will allow 12 digital & 2 analog RGB | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 12    // x4 RMT + x8 I2S-LCD | ||||
|       //#define WLED_MAX_ANALOG_CHANNELS 8 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 6 | ||||
|     #else | ||||
|       // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning | ||||
|       #define WLED_MAX_BUSSES 20              // will allow 17 digital & 3 analog RGB | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 17 | ||||
|       #define WLED_MAX_BUSSES 19              // will allow 16 digital & 3 analog RGB | ||||
|       #define WLED_MAX_DIGITAL_CHANNELS 16    // x1/x8 I2S1 + x8 RMT | ||||
|       //#define WLED_MAX_ANALOG_CHANNELS 16 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 4 | ||||
|       #define WLED_MIN_VIRTUAL_BUSSES 6 | ||||
|     #endif | ||||
|   #endif | ||||
| #else | ||||
| @@ -115,7 +115,7 @@ | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef ESP8266 | ||||
| #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
| #define WLED_MAX_COLOR_ORDER_MAPPINGS 5 | ||||
| #else | ||||
| #define WLED_MAX_COLOR_ORDER_MAPPINGS 10 | ||||
| @@ -125,7 +125,7 @@ | ||||
|   #undef WLED_MAX_LEDMAPS | ||||
| #endif | ||||
| #ifndef WLED_MAX_LEDMAPS | ||||
|   #ifdef ESP8266 | ||||
|   #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
|     #define WLED_MAX_LEDMAPS 10 | ||||
|   #else | ||||
|     #define WLED_MAX_LEDMAPS 16 | ||||
| @@ -473,6 +473,8 @@ | ||||
| #ifndef MAX_LEDS | ||||
| #ifdef ESP8266 | ||||
| #define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs | ||||
| #elif defined(CONFIG_IDF_TARGET_ESP32S2) | ||||
| #define MAX_LEDS 2048 //due to memory constraints | ||||
| #else | ||||
| #define MAX_LEDS 8192 | ||||
| #endif | ||||
| @@ -482,7 +484,9 @@ | ||||
|   #ifdef ESP8266 | ||||
|     #define MAX_LED_MEMORY 4000 | ||||
|   #else | ||||
|     #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) | ||||
|     #if defined(ARDUINO_ARCH_ESP32S2) | ||||
|       #define MAX_LED_MEMORY 16000 | ||||
|     #elif defined(ARDUINO_ARCH_ESP32C3) | ||||
|       #define MAX_LED_MEMORY 32000 | ||||
|     #else | ||||
|       #define MAX_LED_MEMORY 64000 | ||||
|   | ||||
| @@ -16,7 +16,7 @@ function isI(n)     { return n === +n && n === (n|0); } // isInteger | ||||
| function toggle(el) { gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide"); } | ||||
| function tooltip(cont=null) { | ||||
| 	d.querySelectorAll((cont?cont+" ":"")+"[title]").forEach((element)=>{ | ||||
| 		element.addEventListener("mouseover", ()=>{ | ||||
| 		element.addEventListener("pointerover", ()=>{ | ||||
| 			// save title | ||||
| 			element.setAttribute("data-title", element.getAttribute("title")); | ||||
| 			const tooltip = d.createElement("span"); | ||||
| @@ -41,7 +41,7 @@ function tooltip(cont=null) { | ||||
| 			tooltip.classList.add("visible"); | ||||
| 		}); | ||||
|  | ||||
| 		element.addEventListener("mouseout", ()=>{ | ||||
| 		element.addEventListener("pointerout", ()=>{ | ||||
| 			d.querySelectorAll('.tooltip').forEach((tooltip)=>{ | ||||
| 				tooltip.classList.remove("visible"); | ||||
| 				d.body.removeChild(tooltip); | ||||
|   | ||||
| @@ -3114,10 +3114,9 @@ function mergeDeep(target, ...sources) | ||||
| 	return mergeDeep(target, ...sources); | ||||
| } | ||||
|  | ||||
| function tooltip(cont=null) | ||||
| { | ||||
| function tooltip(cont=null) { | ||||
| 	d.querySelectorAll((cont?cont+" ":"")+"[title]").forEach((element)=>{ | ||||
| 		element.addEventListener("mouseover", ()=>{ | ||||
| 		element.addEventListener("pointerover", ()=>{ | ||||
| 			// save title | ||||
| 			element.setAttribute("data-title", element.getAttribute("title")); | ||||
| 			const tooltip = d.createElement("span"); | ||||
| @@ -3142,7 +3141,7 @@ function tooltip(cont=null) | ||||
| 			tooltip.classList.add("visible"); | ||||
| 		}); | ||||
|  | ||||
| 		element.addEventListener("mouseout", ()=>{ | ||||
| 		element.addEventListener("pointerout", ()=>{ | ||||
| 			d.querySelectorAll('.tooltip').forEach((tooltip)=>{ | ||||
| 				tooltip.classList.remove("visible"); | ||||
| 				d.body.removeChild(tooltip); | ||||
|   | ||||
| @@ -42,10 +42,10 @@ | ||||
| 			if (loc) d.Sf.action = getURL('/settings/leds'); | ||||
| 		} | ||||
| 		function bLimits(b,v,p,m,l,o=5,d=2,a=6) { | ||||
| 			oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) | ||||
| 			maxD  = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) | ||||
| 			maxA  = a; // maxA - max analog channels | ||||
| 			maxV  = v; // maxV - min virtual buses | ||||
| 			oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 19 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266 | ||||
| 			maxD  = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 16 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266 | ||||
| 			maxA  = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266 | ||||
| 			maxV  = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266 | ||||
| 			maxPB = p; // maxPB - max LEDs per bus | ||||
| 			maxM  = m; // maxM - max LED memory | ||||
| 			maxL  = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) | ||||
| @@ -250,6 +250,7 @@ | ||||
| 			} | ||||
|  | ||||
| 			// enable/disable LED fields | ||||
| 			let dC = 0; // count of digital buses (for parallel I2S) | ||||
| 			let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]"); | ||||
| 			LTs.forEach((s,i)=>{ | ||||
| 				if (i < LTs.length-1) s.disabled = true; // prevent changing type (as we can't update options) | ||||
| @@ -257,6 +258,7 @@ | ||||
| 				var n = s.name.substring(2); | ||||
| 				var t = parseInt(s.value); | ||||
| 				memu += getMem(t, n); // calc memory | ||||
| 				dC += (isDig(t) && !isD2P(t)); | ||||
| 				setPinConfig(n,t); | ||||
| 				gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings | ||||
| 				if (change) { // did we change LED type? | ||||
| @@ -295,8 +297,7 @@ | ||||
| 				// do we have a led count field | ||||
| 				if (nm=="LC") { | ||||
| 					let c = parseInt(LC.value,10); //get LED count | ||||
| 					if (c > 300 && i < 8) maxB = oMaxB - Math.max(maxD-7,0); //TODO: hard limit for buses when using ESP32 parallel I2S | ||||
| 					if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value | ||||
| 					if (!customStarts || !startsDirty[n]) gId("ls"+n).value = sLC; //update start value | ||||
| 					gId("ls"+n).disabled = !customStarts; //enable/disable field editing | ||||
| 					if (c) { | ||||
| 						let s = parseInt(gId("ls"+n).value); //start value | ||||
| @@ -350,6 +351,17 @@ | ||||
| 						else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; | ||||
| 					} | ||||
| 			}); | ||||
| 			const S2 = (oMaxB == 14) && (maxV == 4); | ||||
| 			const S3 = (oMaxB == 14) && (maxV == 6); | ||||
| 			if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection | ||||
| 				if (maxLC > 300 || dC <= 2) { | ||||
| 					d.Sf["PR"].checked = false; | ||||
| 					gId("prl").classList.add("hide"); | ||||
| 				} else | ||||
| 					gId("prl").classList.remove("hide"); | ||||
| 				maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1 | ||||
| 				maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==3) does support single I2S | ||||
| 			} | ||||
| 			// distribute ABL current if not using PPL | ||||
| 			enPPL(sDI); | ||||
|  | ||||
| @@ -379,6 +391,11 @@ | ||||
| 			gId('psu').innerHTML = s; | ||||
| 			gId('psu2').innerHTML = s2; | ||||
| 			gId("json").style.display = d.Sf.IT.value==8 ? "" : "none"; | ||||
|  | ||||
| 			// show/hide FPS warning messages | ||||
| 			gId('fpsNone').style.display = (d.Sf.FR.value == 0) ? 'block':'none'; | ||||
| 			gId('fpsWarn').style.display = (d.Sf.FR.value == 0) || (d.Sf.FR.value >= 80) ? 'block':'none'; | ||||
| 			gId('fpsHigh').style.display = (d.Sf.FR.value >= 80) ? 'block':'none'; | ||||
| 		} | ||||
| 		function lastEnd(i) { | ||||
| 			if (i-- < 1) return 0; | ||||
| @@ -465,6 +482,7 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();"> | ||||
| 						} | ||||
| 					} | ||||
| 				}); | ||||
| 				enLA(d.Sf["LAsel"+s],s); // update LED mA | ||||
| 				// disable inappropriate LED types | ||||
| 				let sel = d.getElementsByName("LT"+s)[0] | ||||
| 				if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]'); // NOTE: see isDig() | ||||
| @@ -782,6 +800,7 @@ Swap: <select id="xw${s}" name="XW${s}"> | ||||
| 			Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br> | ||||
| 		</div> | ||||
| 		<hr class="sml"> | ||||
| 		<div id="prl" class="hide">Use parallel I2S: <input type="checkbox" name="PR"><br></div> | ||||
| 		Make a segment for each output: <input type="checkbox" name="MS"><br> | ||||
| 		Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br> | ||||
| 		Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br> | ||||
| @@ -869,7 +888,10 @@ Swap: <select id="xw${s}" name="XW${s}"> | ||||
| 			<option value="2">Linear (never wrap)</option> | ||||
| 			<option value="3">None (not recommended)</option> | ||||
| 		</select><br> | ||||
| 		Target refresh rate: <input type="number" class="s" min="1" max="120" name="FR" required> FPS | ||||
| 		Target refresh rate: <input type="number" class="s" min="0" max="250" name="FR" oninput="UI()" required> FPS | ||||
| 		<div id="fpsNone" class="warn" style="display: none;">⚠ Unlimited FPS Mode  is experimental ⚠<br></div> | ||||
| 		<div id="fpsHigh" class="warn" style="display: none;">⚠ High FPS Mode is experimental.<br></div> | ||||
| 		<div id="fpsWarn" class="warn" style="display: none;">Please <a class="lnk" href="sec#backup">backup</a> WLED configuration and presets first!<br></div> | ||||
| 		<hr class="sml"> | ||||
| 		<div id="cfg">Config template: <input type="file" name="data2" accept=".json"><button type="button" class="sml" onclick="loadCfg(d.Sf.data2)">Apply</button><br></div> | ||||
| 		<hr> | ||||
|   | ||||
| @@ -57,7 +57,7 @@ | ||||
| 		<h3>Software Update</h3> | ||||
| 		<button type="button" onclick="U()">Manual OTA Update</button><br> | ||||
| 		Enable ArduinoOTA: <input type="checkbox" name="AO"> | ||||
| 		<hr> | ||||
| 		<hr id="backup"> | ||||
| 		<h3>Backup & Restore</h3> | ||||
| 		<div class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br> | ||||
| 		Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.<br> | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| #pragma once | ||||
| #ifndef WLED_FCN_DECLARE_H | ||||
| #define WLED_FCN_DECLARE_H | ||||
|  | ||||
| @@ -230,7 +231,8 @@ void deletePreset(byte index); | ||||
| bool getPresetName(byte index, String& name); | ||||
|  | ||||
| //remote.cpp | ||||
| void handleRemote(uint8_t *data, size_t len); | ||||
| void handleWiZdata(uint8_t *incomingData, size_t len); | ||||
| void handleRemote(); | ||||
|  | ||||
| //set.cpp | ||||
| bool isAsterisksOnly(const char* str, byte maxLen); | ||||
| @@ -372,7 +374,7 @@ void userLoop(); | ||||
| //util.cpp | ||||
| int getNumVal(const String* req, uint16_t pos); | ||||
| void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); | ||||
| bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); | ||||
| bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) | ||||
| bool getBoolVal(JsonVariant elem, bool dflt); | ||||
| bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); | ||||
| size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val); | ||||
|   | ||||
| @@ -117,7 +117,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) | ||||
|   if (stop > start && of > len -1) of = len -1; | ||||
|  | ||||
|   // update segment (delete if necessary) | ||||
|   seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues | ||||
|   seg.setGeometry(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues | ||||
|  | ||||
|   if (newSeg) seg.refreshLightCapabilities(); // fix for #3403 | ||||
|  | ||||
| @@ -223,30 +223,17 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) | ||||
|   #endif | ||||
|  | ||||
|   byte fx = seg.mode; | ||||
|   byte last = strip.getModeCount(); | ||||
|   // partial fix for #3605 | ||||
|   if (!elem["fx"].isNull() && elem["fx"].is<const char*>()) { | ||||
|     const char *tmp = elem["fx"].as<const char *>(); | ||||
|     if (strlen(tmp) > 3 && (strchr(tmp,'r') || strchr(tmp,'~') != strrchr(tmp,'~'))) last = 0; // we have "X~Y(r|[w]~[-])" form | ||||
|   } | ||||
|   // end fix | ||||
|   if (getVal(elem["fx"], &fx, 0, last)) { //load effect ('r' random, '~' inc/dec, 0-255 exact value, 5~10r pick random between 5 & 10) | ||||
|   if (getVal(elem["fx"], &fx, 0, strip.getModeCount())) { | ||||
|     if (!presetId && currentPlaylist>=0) unloadPlaylist(); | ||||
|     if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]); | ||||
|   } | ||||
|  | ||||
|   //getVal also supports inc/decrementing and random | ||||
|   getVal(elem["sx"], &seg.speed); | ||||
|   getVal(elem["ix"], &seg.intensity); | ||||
|  | ||||
|   uint8_t pal = seg.palette; | ||||
|   last = strip.getPaletteCount(); | ||||
|   if (!elem["pal"].isNull() && elem["pal"].is<const char*>()) { | ||||
|     const char *tmp = elem["pal"].as<const char *>(); | ||||
|     if (strlen(tmp) > 3 && (strchr(tmp,'r') || strchr(tmp,'~') != strrchr(tmp,'~'))) last = 0; // we have "X~Y(r|[w]~[-])" form | ||||
|   } | ||||
|   if (seg.getLightCapabilities() & 1) {  // ignore palette for White and On/Off segments | ||||
|     if (getVal(elem["pal"], &pal, 0, last)) seg.setPalette(pal); | ||||
|     if (getVal(elem["pal"], &pal, 0, strip.getPaletteCount())) seg.setPalette(pal); | ||||
|   } | ||||
|  | ||||
|   getVal(elem["c1"], &seg.custom1); | ||||
| @@ -467,7 +454,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) | ||||
|     DEBUG_PRINTF_P(PSTR("Preset direct: %d\n"), currentPreset); | ||||
|   } else if (!root["ps"].isNull()) { | ||||
|     // we have "ps" call (i.e. from button or external API call) or "pd" that includes "ps" (i.e. from UI call) | ||||
|     if (root["win"].isNull() && getVal(root["ps"], &presetCycCurr, 0, 0) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) { | ||||
|     if (root["win"].isNull() && getVal(root["ps"], &presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) { | ||||
|       DEBUG_PRINTF_P(PSTR("Preset select: %d\n"), presetCycCurr); | ||||
|       // b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal()) | ||||
|       applyPreset(presetCycCurr, callMode); // async load from file system (only preset ID was specified) | ||||
|   | ||||
| @@ -73,8 +73,8 @@ byte scaledBri(byte in) | ||||
|  | ||||
| //applies global brightness | ||||
| void applyBri() { | ||||
|   if (!realtimeMode || !arlsForceMaxBri) | ||||
|   { | ||||
|   if (!(realtimeMode && arlsForceMaxBri)) { | ||||
|     //DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld); | ||||
|     strip.setBrightness(scaledBri(briT)); | ||||
|   } | ||||
| } | ||||
| @@ -85,6 +85,7 @@ void applyFinalBri() { | ||||
|   briOld = bri; | ||||
|   briT = bri; | ||||
|   applyBri(); | ||||
|   strip.trigger(); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -146,7 +147,6 @@ void stateUpdated(byte callMode) { | ||||
|     transitionStartTime = millis(); | ||||
|   } else { | ||||
|     applyFinalBri(); | ||||
|     strip.trigger(); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -207,6 +207,7 @@ void WiFiEvent(WiFiEvent_t event) | ||||
|       break; | ||||
| #endif | ||||
|     default: | ||||
|       DEBUG_PRINTF_P(PSTR("Network event: %d\n"), (int)event); | ||||
|       break; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -214,8 +214,20 @@ bool PinManager::isPinOk(byte gpio, bool output) | ||||
|     // JTAG: GPIO39-42 are usually used for inline debugging | ||||
|     // GPIO46 is input only and pulled down | ||||
|   #else | ||||
|     if (gpio > 5 && gpio < 12) return false;      //SPI flash pins | ||||
|     if (strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0 && (gpio == 16 || gpio == 17)) return false; // PICO-D4: gpio16+17 are in use for onboard SPI FLASH | ||||
|  | ||||
|     if ((strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) ||    // this is the correct identifier, but.... | ||||
|         (strncmp_P(PSTR("ESP32-PICO-D2"), ESP.getChipModel(), 13) == 0)) {  // https://github.com/espressif/arduino-esp32/issues/10683 | ||||
|       // this chip has 4 MB of internal Flash and different packaging, so available pins are different! | ||||
|       if (((gpio > 5) && (gpio < 9)) || (gpio == 11)) | ||||
|         return false; | ||||
|     } else { | ||||
|       // for classic ESP32 (non-mini) modules, these are the SPI flash pins | ||||
|       if (gpio > 5 && gpio < 12) return false;      //SPI flash pins | ||||
|     } | ||||
|  | ||||
|     if (((strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0) || | ||||
|          (strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0)) | ||||
|         && (gpio == 16 || gpio == 17)) return false; // PICO-D4/U4WDH: gpio16+17 are in use for onboard SPI FLASH | ||||
|     if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO) | ||||
|   #endif | ||||
|     if (output) return digitalPinCanOutput(gpio); | ||||
|   | ||||
| @@ -164,6 +164,11 @@ void handlePresets() | ||||
|  | ||||
|   DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset); | ||||
|  | ||||
|   #if defined(ARDUINO_ARCH_ESP32S3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) | ||||
|   unsigned long start = millis(); | ||||
|   while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches | ||||
|   #endif | ||||
|  | ||||
|   #ifdef ARDUINO_ARCH_ESP32 | ||||
|   if (tmpPreset==255 && tmpRAMbuffer!=nullptr) { | ||||
|     deserializeJson(*pDoc,tmpRAMbuffer); | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| #include "wled.h" | ||||
| #ifndef WLED_DISABLE_ESPNOW | ||||
|  | ||||
| #define ESPNOW_BUSWAIT_TIMEOUT 24 // one frame timeout to wait for bus to finish updating | ||||
|  | ||||
| #define NIGHT_MODE_DEACTIVATED     -1 | ||||
| #define NIGHT_MODE_BRIGHTNESS      5 | ||||
|  | ||||
| @@ -38,6 +40,7 @@ typedef struct WizMoteMessageStructure { | ||||
|  | ||||
| static uint32_t last_seq = UINT32_MAX; | ||||
| static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED; | ||||
| static int16_t ESPNowButton = -1; // set in callback if new button value is received | ||||
|  | ||||
| // Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3 | ||||
| static const byte brightnessSteps[] = { | ||||
| @@ -121,6 +124,9 @@ static bool remoteJson(int button) | ||||
|  | ||||
|   sprintf_P(objKey, PSTR("\"%d\":"), button); | ||||
|  | ||||
|   unsigned long start = millis(); | ||||
|   while (strip.isUpdating() && millis()-start < ESPNOW_BUSWAIT_TIMEOUT) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches | ||||
|  | ||||
|   // attempt to read command from remote.json | ||||
|   readObjectFromFile(PSTR("/remote.json"), objKey, pDoc); | ||||
|   JsonObject fdo = pDoc->as<JsonObject>(); | ||||
| @@ -176,7 +182,7 @@ static bool remoteJson(int button) | ||||
| } | ||||
|  | ||||
| // Callback function that will be executed when data is received | ||||
| void handleRemote(uint8_t *incomingData, size_t len) { | ||||
| void handleWiZdata(uint8_t *incomingData, size_t len) { | ||||
|   message_structure_t *incoming = reinterpret_cast<message_structure_t *>(incomingData); | ||||
|  | ||||
|   if (strcmp(last_signal_src, linked_remote) != 0) { | ||||
| @@ -202,8 +208,15 @@ void handleRemote(uint8_t *incomingData, size_t len) { | ||||
|   DEBUG_PRINT(F("] button: ")); | ||||
|   DEBUG_PRINTLN(incoming->button); | ||||
|  | ||||
|   if (!remoteJson(incoming->button)) | ||||
|     switch (incoming->button) { | ||||
|   ESPNowButton = incoming->button; // save state, do not process in callback (can cause glitches) | ||||
|   last_seq = cur_seq; | ||||
| } | ||||
|  | ||||
| // process ESPNow button data (acesses FS, should not be called while update to avoid glitches) | ||||
| void handleRemote() { | ||||
|   if(ESPNowButton >= 0) { | ||||
|   if (!remoteJson(ESPNowButton)) | ||||
|     switch (ESPNowButton) { | ||||
|       case WIZMOTE_BUTTON_ON             : setOn();                                         break; | ||||
|       case WIZMOTE_BUTTON_OFF            : setOff();                                        break; | ||||
|       case WIZMOTE_BUTTON_ONE            : presetWithFallback(1, FX_MODE_STATIC,        0); break; | ||||
| @@ -219,9 +232,10 @@ void handleRemote(uint8_t *incomingData, size_t len) { | ||||
|       case WIZ_SMART_BUTTON_BRIGHT_DOWN  : brightnessDown();                                break; | ||||
|       default: break; | ||||
|     } | ||||
|   last_seq = cur_seq; | ||||
|   } | ||||
|   ESPNowButton = -1; | ||||
| } | ||||
|  | ||||
| #else | ||||
| void handleRemote(uint8_t *incomingData, size_t len) {} | ||||
| void handleRemote() {} | ||||
| #endif | ||||
|   | ||||
| @@ -134,11 +134,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) | ||||
|     strip.correctWB = request->hasArg(F("CCT")); | ||||
|     strip.cctFromRgb = request->hasArg(F("CR")); | ||||
|     cctICused = request->hasArg(F("IC")); | ||||
|     strip.cctBlending = request->arg(F("CB")).toInt(); | ||||
|     Bus::setCCTBlend(strip.cctBlending); | ||||
|     Bus::setCCTBlend(request->arg(F("CB")).toInt()); | ||||
|     Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); | ||||
|     strip.setTargetFps(request->arg(F("FR")).toInt()); | ||||
|     useGlobalLedBuffer = request->hasArg(F("LD")); | ||||
|     #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) | ||||
|     useParallelI2S = request->hasArg(F("PR")); | ||||
|     #endif | ||||
|  | ||||
|     bool busesChanged = false; | ||||
|     for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { | ||||
| @@ -208,8 +210,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) | ||||
|       type |= request->hasArg(rf) << 7; // off refresh override | ||||
|       // 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, freq, useGlobalLedBuffer, maPerLed, maMax); | ||||
|       busConfigs.push_back(std::move(BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax))); | ||||
|       busesChanged = true; | ||||
|     } | ||||
|     //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed | ||||
|   | ||||
| @@ -300,7 +300,7 @@ void parseNotifyPacket(uint8_t *udpIn) { | ||||
|       if (!receiveSegmentOptions) { | ||||
|         DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY); | ||||
|         strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" | ||||
|         selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY); | ||||
|         selseg.setGeometry(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY); | ||||
|         strip.resume(); | ||||
|         continue; // we do receive bounds, but not options | ||||
|       } | ||||
| @@ -342,12 +342,12 @@ void parseNotifyPacket(uint8_t *udpIn) { | ||||
|       if (receiveSegmentBounds) { | ||||
|         DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY); | ||||
|         strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" | ||||
|         selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY); | ||||
|         selseg.setGeometry(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY); | ||||
|         strip.resume(); | ||||
|       } else { | ||||
|         DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]); | ||||
|         strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" | ||||
|         selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY); | ||||
|         selseg.setGeometry(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY); | ||||
|         strip.resume(); | ||||
|       } | ||||
|     } | ||||
| @@ -979,7 +979,7 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs | ||||
|  | ||||
|   // handle WiZ Mote data | ||||
|   if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) { | ||||
|     handleRemote(data, len); | ||||
|     handleWiZdata(data, len); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv) | ||||
|   *val = atoi(str); | ||||
| } | ||||
|  | ||||
|  | ||||
| //getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) | ||||
| bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) { | ||||
|   if (elem.is<int>()) { | ||||
| 		if (elem < 0) return false; //ignore e.g. {"ps":-1} | ||||
| @@ -60,8 +60,12 @@ bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) { | ||||
|     return true; | ||||
|   } else if (elem.is<const char*>()) { | ||||
|     const char* str = elem; | ||||
|     size_t len = strnlen(str, 12); | ||||
|     if (len == 0 || len > 10) return false; | ||||
|     size_t len = strnlen(str, 14); | ||||
|     if (len == 0 || len > 12) return false; | ||||
|     // fix for #3605 & #4346 | ||||
|     // ignore vmin and vmax and use as specified in API | ||||
|     if (len > 3 && (strchr(str,'r') || strchr(str,'~') != strrchr(str,'~'))) vmax = vmin = 0; // we have "X~Y(r|~[w][-][Z])" form | ||||
|     // end fix | ||||
|     parseNumber(str, val, vmin, vmax); | ||||
|     return true; | ||||
|   } | ||||
|   | ||||
| @@ -84,6 +84,9 @@ void WLED::loop() | ||||
|   #ifndef WLED_DISABLE_INFRARED | ||||
|   handleIR(); | ||||
|   #endif | ||||
|   #ifndef WLED_DISABLE_ESPNOW | ||||
|   handleRemote(); | ||||
|   #endif | ||||
|   #ifndef WLED_DISABLE_ALEXA | ||||
|   handleAlexa(); | ||||
|   #endif | ||||
| @@ -179,46 +182,7 @@ void WLED::loop() | ||||
|     DEBUG_PRINTLN(F("Re-init busses.")); | ||||
|     bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) | ||||
|     BusManager::removeAll(); | ||||
|     unsigned mem = 0; | ||||
|     // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) | ||||
|     bool useParallel = false; | ||||
|     #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) | ||||
|     unsigned digitalCount = 0; | ||||
|     unsigned maxLedsOnBus = 0; | ||||
|     unsigned maxChannels = 0; | ||||
|     for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { | ||||
|       if (busConfigs[i] == nullptr) break; | ||||
|       if (!Bus::isDigital(busConfigs[i]->type)) continue; | ||||
|       if (!Bus::is2Pin(busConfigs[i]->type)) { | ||||
|         digitalCount++; | ||||
|         unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type); | ||||
|         if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count; | ||||
|         if (channels > maxChannels) maxChannels  = channels; | ||||
|       } | ||||
|     } | ||||
|     DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); | ||||
|     // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 | ||||
|     if (maxLedsOnBus <= 300 && digitalCount > 5) { | ||||
|       DEBUG_PRINTF_P(PSTR("Switching to parallel I2S.")); | ||||
|       useParallel = true; | ||||
|       BusManager::useParallelOutput(); | ||||
|       mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation (hse to be used *after* useParallelOutput()) | ||||
|     } | ||||
|     #endif | ||||
|     // create buses/outputs | ||||
|     for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { | ||||
|       if (busConfigs[i] == nullptr || (!useParallel && i > 10)) break; | ||||
|       if (useParallel && i < 8) { | ||||
|         // if for some unexplained reason the above pre-calculation was wrong, update | ||||
|         unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S | ||||
|         if (memT > mem) mem = memT; // if we have unequal LED count use the largest | ||||
|       } else | ||||
|         mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer | ||||
|       if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]); | ||||
|       delete busConfigs[i]; | ||||
|       busConfigs[i] = nullptr; | ||||
|     } | ||||
|     strip.finalizeInit(); // also loads default ledmap if present | ||||
|     strip.finalizeInit(); // will create buses and also load default ledmap if present | ||||
|     BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005 | ||||
|     if (aligned) strip.makeAutoSegments(); | ||||
|     else strip.fixInvalidSegments(); | ||||
| @@ -478,10 +442,7 @@ void WLED::setup() | ||||
|   if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0) | ||||
|     showWelcomePage = true; | ||||
|   WiFi.persistent(false); | ||||
|   #ifdef WLED_USE_ETHERNET | ||||
|   WiFi.onEvent(WiFiEvent); | ||||
|   #endif | ||||
|  | ||||
|   WiFi.mode(WIFI_STA); // enable scanning | ||||
|   findWiFi(true);      // start scanning for available WiFi-s | ||||
|  | ||||
| @@ -571,6 +532,7 @@ void WLED::beginStrip() | ||||
|   strip.makeAutoSegments(); | ||||
|   strip.setBrightness(0); | ||||
|   strip.setShowCallback(handleOverlayDraw); | ||||
|   doInitBusses = false; | ||||
|  | ||||
|   if (turnOnAtBoot) { | ||||
|     if (briS > 0) bri = briS; | ||||
| @@ -781,7 +743,7 @@ int8_t WLED::findWiFi(bool doScan) { | ||||
|  | ||||
| void WLED::initConnection() | ||||
| { | ||||
|   DEBUG_PRINTLN(F("initConnection() called.")); | ||||
|   DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000); | ||||
|  | ||||
|   #ifdef WLED_ENABLE_WEBSOCKETS | ||||
|   ws.onEvent(wsEvent); | ||||
| @@ -796,6 +758,7 @@ void WLED::initConnection() | ||||
| #endif | ||||
|  | ||||
|   WiFi.disconnect(true); // close old connections | ||||
|   delay(5);              // wait for hardware to be ready | ||||
| #ifdef ESP8266 | ||||
|   WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N); | ||||
| #endif | ||||
| @@ -825,9 +788,7 @@ void WLED::initConnection() | ||||
|   if (WLED_WIFI_CONFIGURED) { | ||||
|     showWelcomePage = false; | ||||
|      | ||||
|     DEBUG_PRINT(F("Connecting to ")); | ||||
|     DEBUG_PRINT(multiWiFi[selectedWiFi].clientSSID); | ||||
|     DEBUG_PRINTLN(F("...")); | ||||
|     DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID); | ||||
|  | ||||
|     // convert the "serverDescription" into a valid DNS hostname (alphanumeric) | ||||
|     char hostname[25]; | ||||
| @@ -926,7 +887,8 @@ void WLED::handleConnection() | ||||
| { | ||||
|   static bool scanDone = true; | ||||
|   static byte stacO = 0; | ||||
|   unsigned long now = millis(); | ||||
|   const unsigned long now = millis(); | ||||
|   const unsigned long nowS = now/1000; | ||||
|   const bool wifiConfigured = WLED_WIFI_CONFIGURED; | ||||
|  | ||||
|   // ignore connection handling if WiFi is configured and scan still running | ||||
| @@ -935,7 +897,7 @@ void WLED::handleConnection() | ||||
|     return; | ||||
|  | ||||
|   if (lastReconnectAttempt == 0 || forceReconnect) { | ||||
|     DEBUG_PRINTLN(F("Initial connect or forced reconnect.")); | ||||
|     DEBUG_PRINTF_P(PSTR("Initial connect or forced reconnect (@ %lus).\n"), nowS); | ||||
|     selectedWiFi = findWiFi(); // find strongest WiFi | ||||
|     initConnection(); | ||||
|     interfacesInited = false; | ||||
| @@ -955,8 +917,7 @@ void WLED::handleConnection() | ||||
| #endif | ||||
|     if (stac != stacO) { | ||||
|       stacO = stac; | ||||
|       DEBUG_PRINT(F("Connected AP clients: ")); | ||||
|       DEBUG_PRINTLN(stac); | ||||
|       DEBUG_PRINTF_P(PSTR("Connected AP clients: %d\n"), (int)stac); | ||||
|       if (!WLED_CONNECTED && wifiConfigured) {        // trying to connect, but not connected | ||||
|         if (stac) | ||||
|           WiFi.disconnect();        // disable search so that AP can work | ||||
| @@ -979,6 +940,7 @@ void WLED::handleConnection() | ||||
|       initConnection(); | ||||
|       interfacesInited = false; | ||||
|       scanDone = true; | ||||
|       return; | ||||
|     } | ||||
|     //send improv failed 6 seconds after second init attempt (24 sec. after provisioning) | ||||
|     if (improvActive > 2 && now - lastReconnectAttempt > 6000) { | ||||
| @@ -987,13 +949,13 @@ void WLED::handleConnection() | ||||
|     } | ||||
|     if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && wifiConfigured) { | ||||
|       if (improvActive == 2) improvActive = 3; | ||||
|       DEBUG_PRINTLN(F("Last reconnect too old.")); | ||||
|       DEBUG_PRINTF_P(PSTR("Last reconnect (%lus) too old (@ %lus).\n"), lastReconnectAttempt/1000, nowS); | ||||
|       if (++selectedWiFi >= multiWiFi.size()) selectedWiFi = 0; // we couldn't connect, try with another network from the list | ||||
|       initConnection(); | ||||
|     } | ||||
|     if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) { | ||||
|       if (!(apBehavior == AP_BEHAVIOR_TEMPORARY && now > WLED_AP_TIMEOUT)) { | ||||
|         DEBUG_PRINTLN(F("Not connected AP.")); | ||||
|         DEBUG_PRINTF_P(PSTR("Not connected AP (@ %lus).\n"), nowS); | ||||
|         initAP();  // start AP only within first 5min | ||||
|       } | ||||
|     } | ||||
| @@ -1003,7 +965,7 @@ void WLED::handleConnection() | ||||
|         dnsServer.stop(); | ||||
|         WiFi.softAPdisconnect(true); | ||||
|         apActive = false; | ||||
|         DEBUG_PRINTLN(F("Temporary AP disabled.")); | ||||
|         DEBUG_PRINTF_P(PSTR("Temporary AP disabled (@ %lus).\n"), nowS); | ||||
|       } | ||||
|     } | ||||
|   } else if (!interfacesInited) { //newly connected | ||||
|   | ||||
| @@ -3,12 +3,11 @@ | ||||
| /* | ||||
|    Main sketch, global variable declarations | ||||
|    @title WLED project sketch | ||||
|    @version 0.15.0-b7 | ||||
|    @author Christian Schwinne | ||||
|  */ | ||||
|  | ||||
| // version code in format yymmddb (b = daily build) | ||||
| #define VERSION 2410270 | ||||
| #define VERSION 2502220 | ||||
|  | ||||
| //uncomment this if you have a "my_config.h" file you'd like to use | ||||
| //#define WLED_USE_MY_CONFIG | ||||
| @@ -368,7 +367,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(false); | ||||
| WLED_GLOBAL bool force802_3g _INIT(false); | ||||
| #endif // WLED_SAVE_RAM | ||||
| #ifdef ARDUINO_ARCH_ESP32 | ||||
|   #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) | ||||
|   #if defined(LOLIN_WIFI_FIX) && (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)) | ||||
| WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); | ||||
|   #else | ||||
| WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); | ||||
| @@ -395,6 +394,9 @@ WLED_GLOBAL byte bootPreset   _INIT(0);                   // save preset to load | ||||
| WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 | ||||
| #else | ||||
| WLED_GLOBAL bool useGlobalLedBuffer _INIT(true);  // double buffering enabled on ESP32 | ||||
|   #ifndef CONFIG_IDF_TARGET_ESP32C3 | ||||
| WLED_GLOBAL bool useParallelI2S     _INIT(false); // parallel I2S for ESP32 | ||||
|   #endif | ||||
| #endif | ||||
| #ifdef WLED_USE_IC_CCT | ||||
| WLED_GLOBAL bool cctICused          _INIT(true);  // CCT IC used (Athom 15W bulbs) | ||||
| @@ -884,7 +886,7 @@ WLED_GLOBAL bool e131NewData _INIT(false); | ||||
| // led fx library object | ||||
| WLED_GLOBAL BusManager busses _INIT(BusManager()); | ||||
| WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); | ||||
| WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after | ||||
| WLED_GLOBAL std::vector<BusConfig> busConfigs; //temporary, to remember values from network callback until after | ||||
| WLED_GLOBAL bool doInitBusses _INIT(false); | ||||
| WLED_GLOBAL int8_t loadLedmap _INIT(-1); | ||||
| WLED_GLOBAL uint8_t currentLedmap _INIT(0); | ||||
|   | ||||
| @@ -289,6 +289,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) | ||||
|     printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); | ||||
|     printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); | ||||
|     printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); | ||||
|     printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput());  // get it from bus manager not global variable | ||||
|  | ||||
|     unsigned sumMa = 0; | ||||
|     for (int s = 0; s < BusManager::getNumBusses(); s++) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user