Compare commits

...

65 Commits

Author SHA1 Message Date
Will Tatam
6572efbf9f Update version to 0.15.1.beta2 2025-02-22 18:02:31 +00:00
Blaž Kristan
dbe76479a2 Merge pull request #4484 from blazoncek/parallel-I2S
WWA strip support & parallel I2S for S2/S3 (bumping outputs from 5/4 to 12)
2025-02-22 18:44:10 +01:00
netmindz
dc3d463925 Merge pull request #4428 from blazoncek/waterfall-fix
FX: Waterfall, Matripix & Dissolve fix
2025-02-22 17:49:10 +01:00
netmindz
f593d404cb Merge pull request #4244 from MoonModules/framerate_ac015
Improved framerate control code - strip.show(), strip.service()
2025-02-22 11:21:27 +00:00
netmindz
b75a2de485 Merge pull request #4356 from blazoncek/json-cycle
Proper fix for #3605 & #4346
2025-02-22 11:21:09 +00:00
Blaž Kristan
642a9e3652 Idle current bugfix (#4402) 2025-02-22 11:20:34 +00:00
Frank
85d3f6f11c Merge pull request #4398 from Aircoookie/4395-platformio_override
update platformio override example file (solves #4395)
2025-02-22 11:19:48 +00:00
Frank
f490908278 Merge pull request #4439 from dosipod/Upstream_PRs
Update readme.md for rgb-rotary-encoder usermod
2025-02-22 11:17:29 +00:00
Frank
1fc3cc83bd Merge pull request #4450 from adafruit/main
Add correct pin availability for ESP32 Mini modules
2025-02-22 11:16:06 +00:00
Will Miles
e96fd8ae58 Merge pull request #4511 from mlichvar/main
fix reproduction in game of life
2025-02-22 11:06:54 +00:00
netmindz
c46e328b59 Merge pull request #4556 from spiro-c/npm-check
Fix for: Build should stop if npm fails #4513
2025-02-22 11:02:32 +00:00
Damian Schneider
fa2f831044 fix for incorrect hardware timing 2025-02-16 10:36:03 +00:00
Damian Schneider
1bf13ea525 BUGFIX in oscillate FX (#4494)
effect was changed from int to uint but it relied on negative numbers. fixed by checking overflow and a cast.
2025-02-16 10:35:40 +00:00
maxi4329
edc6022441 Fix for #4153 (#4253)
* fix for #4153

* only load touch/mouse events for touch/mouse devices

* undid formating changes

* undid more formating changes

* undid all formating changes

* use pointerover and pointerout eventlisteners
2025-02-15 15:16:43 +01:00
Damian Schneider
2ac4d03160 Fixes first pixel not being set in Stream FX (#4542)
* Fixes first pixel not being set
* added fix to Stream 2 as well
2025-02-10 20:34:24 +01:00
netmindz
cc4a4c4ae1 Merge pull request #4428 from blazoncek/waterfall-fix
FX: Waterfall, Matripix & Dissolve fix
2025-01-16 15:55:33 +00:00
Will Tatam
4e11ecda4b Set version to 0.15.1.beta1 2025-01-16 13:18:50 +00:00
netmindz
473700e4c0 Merge pull request #4018 from Brandon502/main
Added Cube Mapping Tool
2025-01-16 13:03:47 +00:00
netmindz
0d5a0fb830 Merge pull request #4386 from DedeHai/ESPNow_glitchfix
Fix for ESPNow remote causing output glitches
2025-01-16 13:01:40 +00:00
Damian Schneider
012143bd7b BUGFIX in oscillate FX
effect was changed from int to uint but it relied on negative numbers. fixed by checking overflow and a cast.
2025-01-14 18:46:47 +01:00
Damian Schneider
700a7076fd added a delay after switching relay (#4474)
- helps to stabilize power on the LEDs before sending data
2025-01-12 15:20:27 +01:00
Damian Schneider
5fc2175dd4 Playlist output glitchfix update: found it also happens on S3 (#4462)
* Fix output glitches when playlist changes preset update: glitches also happen on S3
2025-01-12 15:20:27 +01:00
Damian Schneider
c9b95e22d3 Fix output glitches when playlist changes preset (#4442)
same issue as with https://github.com/Aircoookie/WLED/pull/4386
waiting on bus to finish updating before file access fixes the glitches.
this issue is only present on S2 and C3, not on ESP8266 or dual-core ESPs, the fix is only applied for these two.
2025-01-12 15:20:27 +01:00
Damian Schneider
a265318037 fixed CIE brightness calculation for PWM outputs 2025-01-12 15:20:27 +01:00
Damian Schneider
866a4c8ab6 fix for repeating glitch
glitch appeared every 65s due to missing uint16_t overflow.
2025-01-12 15:20:26 +01:00
TripleWhy
9dc1022010 palette effect overflow fix 2025-01-10 17:41:12 +00:00
Will Tatam
faadb67eb0 update changelog for 2412100 2024-12-10 20:20:28 +00:00
Will Tatam
a111a2e7a1 update version to 0.15.0 2024-12-10 20:13:12 +00:00
netmindz
32864d8986
update version to 0.15.0 2024-12-10 18:54:39 +00:00
netmindz
d7bebc2659
Merge pull request #4360 from euphi/patch-1
Usermod BME280: Fix "Unit of Measurement" for temperature
2024-12-10 08:07:24 +00:00
Blaž Kristan
af410ae2d0 WiFi reconnect bugfix
- additional debug info
2024-12-09 23:06:21 +00:00
Will Tatam
1891cc816f Merge branch '0_15_0' of https://github.com/Aircoookie/WLED into 0_15_0 2024-12-09 09:33:33 +00:00
Ian Hubbertz
9a4073e606
Fix "Unit of Measurement" for BME280 temperature
The Unit of Measurement ("tempScale") of the MQTT message is set for each published measurement - but not for the homeassistant discovery.

Thus, openhab (and mabye other systems?) don't recognize the value as "Number" - so it uses String instead. This is somehow annoying when trying to configure the sensor channel to be linked to an existing item in OpenHAB.
(Items that are created automatically or with "Add point to model" can be configured in a way that the String is transformed to Number or Number:Temperature, but existing Items cannot be linked).

When a "Unit of Measurement" is set in HomeAssistant discovery, the HA binding of OpenHAB notices that the MQTT String is a number and automatically converts it.
2024-12-07 21:33:46 +01:00
Damian Schneider
b78229d1e2 Fix update for #4193 (twinkle fox & cat)
- previous fix worked but there was still an overflow after some time passed. there were still missing roll-overs apparently: reverting these two variables back to 16bit/8bit should fix it for good.
2024-12-05 06:49:17 +01:00
Damian Schneider
71b242874f Fix for #4193 (twinkle fox & cat) 2024-12-04 20:39:19 +01:00
Will Tatam
9328e6faca Merge branch '0_15_0' of https://github.com/Aircoookie/WLED into 0_15_0 2024-11-30 12:07:46 +00:00
netmindz
bbacc2daae
Merge pull request #4287 from netmindz/v0.15.0-rcX
0.15.0-rc1
2024-11-30 11:42:46 +00:00
Will Tatam
3e22f9cabb Merge branch '0_15' into 0_15_0 2024-11-30 11:39:13 +00:00
Will Miles
685ad83d4b PolyBus: Clarify use of clock_kHz
While not used by most bus types, it's not an optional parameter.
2024-11-27 19:36:16 +00:00
Will Miles
62ddb18a1a BusDigital::begin: Pass clock rate argument
Fixes bug introduced by #4312.
2024-11-27 19:36:01 +00:00
Blaž Kristan
6a12378475 Fix for #4321 2024-11-27 19:33:29 +00:00
Blaž Kristan
d26b3108da Fix for #4300 2024-11-27 11:04:52 +00:00
Will Tatam
c89e4576b4 Dedicated release workflow 2024-11-27 10:42:38 +00:00
Will Tatam
bc79f44a26 workflow refactor to used shared build file 2024-11-27 10:42:29 +00:00
Will Tatam
7ece14ff3f rename workflow ready for workflow refactor 2024-11-27 10:42:19 +00:00
Will Tatam
0b3643132b Update to 2411250 2024-11-25 23:47:41 +00:00
Will Tatam
a5693fbf8d Merge branch '0_15_0' into v0.15.0-rcX 2024-11-25 23:45:34 +00:00
maxi4329
5c5b70f52b version changed to 20 2024-11-25 23:34:27 +00:00
maxi4329
ae97e388a6 indened formating 2024-11-25 23:34:20 +00:00
maxi4329
37cddcaacc specified required nodejs ver 2024-11-25 23:34:13 +00:00
Will Miles
a1b332fc78 handleSet: Fix incorrect response generation
Don't generate a response if there's no HTTP request.

Fixes #4269
2024-11-25 23:33:53 +00:00
Frank
86d7c24513 rename delay -> frameDelay
Avoiding name collisions with the 'delay' function.
2024-11-25 23:32:27 +00:00
Damian Schneider
b28add3b8b Added define for bitshift, removed dithering
dithering is not really needed, the FPS_MULTIPLIER is a much better option.
2024-11-25 23:31:17 +00:00
Damian Schneider
5fd3a513a4 bugfix
bitshift was still set from testing, forgot to update
2024-11-25 23:31:08 +00:00
Damian Schneider
b98a8a10b0 improved FPS calc resolution, added averaging & multiplier compileflags
Fixed point calculation for improved accuracy, dithering in debug builds only.
Averaging and optional multiplier can be set as compile flags, example for speed testing with long averaging and a 10x multiplier:

-D FPS_CALC_AVG=200
-D FPS_MULTIPLIER=10

The calculation resolution is limited (9.7bit fixed point) so values larger than 200 can hit resolution limit and get stuck before reaching the final value.

If WLED_DEBUG is defined, dithering is added to the returned value so sub-frame accuracy is possible in post-processingwithout enabling the multiplier.
2024-11-25 23:30:59 +00:00
netmindz
2bee2793ef Merge pull request #4309 from netmindz/release-name-fix
Fix release name macro expansion
2024-11-25 23:12:04 +00:00
netmindz
2f6fa66f4d Merge pull request #4309 from netmindz/release-name-fix
Fix release name macro expansion
2024-11-25 23:04:22 +00:00
Will Tatam
5d38acd787 Update CHANGELOG 2024-11-24 21:04:50 +00:00
Will Tatam
e607fcb5c5 Merge branch '0_15_0' into v0.15.0-rcX 2024-11-24 21:04:08 +00:00
Frank
8a18555ae4 Merge pull request #4243 from MoonModules/AC_0_15_S3-WROOM2
Add support for ESP32-S3 WROOM-2 (solves #4099)
2024-11-24 20:49:49 +00:00
netmindz
beb709dc8f Merge pull request #4312 from willmmiles/mixed-led-crash
Defer calling begin() on buses
2024-11-24 20:46:45 +00:00
Will Tatam
7a58c69a80 Stip \" from WLED_RELEASE_NAME 2024-11-23 16:50:34 +00:00
Will Tatam
1082c85789 Fix WLED_RELEASE_NAME=ESP32-S3_WROOM-2 2024-11-23 16:37:54 +00:00
Will Tatam
568d2edd96 Remove TOSTRING for releaseString and add quotes to WLED_RELEASE_NAME 2024-11-23 16:37:03 +00:00
Will Tatam
d2d56ebbd2 0.15.0-rc1 2024-11-15 20:27:30 +00:00
37 changed files with 1168 additions and 904 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ wled-update.sh
/build_output/
/node_modules/
/logs/
/wled00/extLibs
/wled00/LittleFS

View File

@ -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
View File

@ -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": {

View File

@ -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": {

View File

@ -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)

View File

@ -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
# ------------------------------------------------------------------------------

View File

@ -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

Binary file not shown.

View File

@ -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) {

View File

@ -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
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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
}

View File

@ -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;

View File

@ -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;
}
};

View File

@ -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) {

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;">&#9888; Unlimited FPS Mode is experimental &#9888;<br></div>
<div id="fpsHigh" class="warn" style="display: none;">&#9888; 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>

View File

@ -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">&#9888; 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>

View File

@ -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);

View File

@ -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)

View File

@ -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();
}
}

View File

@ -207,6 +207,7 @@ void WiFiEvent(WiFiEvent_t event)
break;
#endif
default:
DEBUG_PRINTF_P(PSTR("Network event: %d\n"), (int)event);
break;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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++) {