mirror of
https://github.com/wled/WLED.git
synced 2025-07-14 14:26:33 +00:00
Merge branch 'main' into use-bssid
This commit is contained in:
commit
3debaf0f41
@ -2,12 +2,7 @@
|
|||||||
|
|
||||||
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
|
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
|
||||||
ARG VARIANT="3"
|
ARG VARIANT="3"
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
|
FROM mcr.microsoft.com/devcontainers/python:0-${VARIANT}
|
||||||
|
|
||||||
# [Option] Install Node.js
|
|
||||||
ARG INSTALL_NODE="true"
|
|
||||||
ARG NODE_VERSION="lts/*"
|
|
||||||
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
|
||||||
|
|
||||||
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
||||||
# COPY requirements.txt /tmp/pip-tmp/
|
# COPY requirements.txt /tmp/pip-tmp/
|
||||||
|
@ -5,10 +5,7 @@
|
|||||||
"context": "..",
|
"context": "..",
|
||||||
"args": {
|
"args": {
|
||||||
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
|
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
|
||||||
"VARIANT": "3",
|
"VARIANT": "3"
|
||||||
// Options
|
|
||||||
"INSTALL_NODE": "true",
|
|
||||||
"NODE_VERSION": "lts/*"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -54,7 +51,7 @@
|
|||||||
// "forwardPorts": [],
|
// "forwardPorts": [],
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
"postCreateCommand": "npm install",
|
"postCreateCommand": "bash -i -c 'nvm install && npm ci'",
|
||||||
|
|
||||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||||
"remoteUser": "vscode"
|
"remoteUser": "vscode"
|
||||||
|
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -38,6 +38,7 @@ jobs:
|
|||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- name: Cache PlatformIO
|
- name: Cache PlatformIO
|
||||||
@ -74,7 +75,7 @@ jobs:
|
|||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
40
.github/workflows/nightly.yml
vendored
Normal file
40
.github/workflows/nightly.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
name: Deploy Nightly
|
||||||
|
on:
|
||||||
|
# This can be used to automatically publish nightlies at UTC nighttime
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * *' # run at 2 AM UTC
|
||||||
|
# This can be used to allow manually triggering nightlies from the web interface
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
wled_build:
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
nightly:
|
||||||
|
name: Deploy nightly
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: wled_build
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Show Files
|
||||||
|
run: ls -la
|
||||||
|
- name: "✏️ Generate release changelog"
|
||||||
|
id: changelog
|
||||||
|
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
sinceTag: v0.15.0
|
||||||
|
- name: Update Nightly Release
|
||||||
|
uses: andelf/nightly-release@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: nightly
|
||||||
|
name: 'Nightly Release $$'
|
||||||
|
prerelease: true
|
||||||
|
body: ${{ steps.changelog.outputs.changelog }}
|
||||||
|
files: |
|
||||||
|
./*.bin
|
@ -173,7 +173,7 @@
|
|||||||
- v0.15.0-b2
|
- v0.15.0-b2
|
||||||
- WS2805 support (RGB + WW + CW, 600kbps)
|
- WS2805 support (RGB + WW + CW, 600kbps)
|
||||||
- Unified PSRAM use
|
- Unified PSRAM use
|
||||||
- NeoPixelBus v2.7.9
|
- NeoPixelBus v2.7.9 (for future WS2805 support)
|
||||||
- Ubiquitous PSRAM mode for all variants of ESP32
|
- Ubiquitous PSRAM mode for all variants of ESP32
|
||||||
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
|
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
|
||||||
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
|
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
|
||||||
|
47
boards/lolin_s3_mini.json
Normal file
47
boards/lolin_s3_mini.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"memory_type": "qio_qspi"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_LOLIN_S3_MINI",
|
||||||
|
"-DARDUINO_USB_MODE=1"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [
|
||||||
|
[
|
||||||
|
"0x303A",
|
||||||
|
"0x8167"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "lolin_s3_mini"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"bluetooth",
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"espidf"
|
||||||
|
],
|
||||||
|
"name": "WEMOS LOLIN S3 Mini",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "4MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 4194304,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 460800
|
||||||
|
},
|
||||||
|
"url": "https://www.wemos.cc/en/latest/s3/index.html",
|
||||||
|
"vendor": "WEMOS"
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.16.0-dev",
|
"version": "0.16.0-alpha",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
# CI/release binaries
|
# CI/release binaries
|
||||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
|
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
|
||||||
|
|
||||||
src_dir = ./wled00
|
src_dir = ./wled00
|
||||||
data_dir = ./wled00/data
|
data_dir = ./wled00/data
|
||||||
@ -273,23 +273,25 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for
|
|||||||
;;
|
;;
|
||||||
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
|
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
|
||||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
|
;; 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)
|
;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||||
|
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = -g
|
build_flags = -g
|
||||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||||
-DARDUINO_ARCH_ESP32 -DESP32
|
-DARDUINO_ARCH_ESP32 -DESP32
|
||||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||||
|
-D WLED_ENABLE_DMX_INPUT
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||||
|
https://github.com/someweisguy/esp_dmx.git#47db25d
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||||
|
|
||||||
[esp32s2]
|
[esp32s2]
|
||||||
;; generic definitions for all ESP32-S2 boards
|
;; generic definitions for all ESP32-S2 boards
|
||||||
platform = espressif32@ ~6.3.2
|
platform = ${esp32_idf_V4.platform}
|
||||||
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_unflags = ${common.build_unflags}
|
||||||
build_flags = -g
|
build_flags = -g
|
||||||
-DARDUINO_ARCH_ESP32
|
-DARDUINO_ARCH_ESP32
|
||||||
@ -308,8 +310,7 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for
|
|||||||
|
|
||||||
[esp32c3]
|
[esp32c3]
|
||||||
;; generic definitions for all ESP32-C3 boards
|
;; generic definitions for all ESP32-C3 boards
|
||||||
platform = espressif32@ ~6.3.2
|
platform = ${esp32_idf_V4.platform}
|
||||||
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_unflags = ${common.build_unflags}
|
||||||
build_flags = -g
|
build_flags = -g
|
||||||
-DARDUINO_ARCH_ESP32
|
-DARDUINO_ARCH_ESP32
|
||||||
@ -324,11 +325,11 @@ lib_deps =
|
|||||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||||
|
board_build.flash_mode = qio
|
||||||
|
|
||||||
[esp32s3]
|
[esp32s3]
|
||||||
;; generic definitions for all ESP32-S3 boards
|
;; generic definitions for all ESP32-S3 boards
|
||||||
platform = espressif32@ ~6.3.2
|
platform = ${esp32_idf_V4.platform}
|
||||||
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_unflags = ${common.build_unflags}
|
||||||
build_flags = -g
|
build_flags = -g
|
||||||
-DESP32
|
-DESP32
|
||||||
@ -432,10 +433,21 @@ lib_deps = ${esp32.lib_deps}
|
|||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
board_build.partitions = ${esp32.default_partitions}
|
board_build.partitions = ${esp32.default_partitions}
|
||||||
|
|
||||||
|
[env:esp32dev_V4]
|
||||||
|
board = esp32dev
|
||||||
|
platform = ${esp32_idf_V4.platform}
|
||||||
|
build_unflags = ${common.build_unflags}
|
||||||
|
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||||
|
${esp32.AR_build_flags}
|
||||||
|
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||||
|
${esp32.AR_lib_deps}
|
||||||
|
monitor_filters = esp32_exception_decoder
|
||||||
|
board_build.partitions = ${esp32.default_partitions}
|
||||||
|
board_build.flash_mode = dio
|
||||||
|
|
||||||
[env:esp32dev_8M]
|
[env:esp32dev_8M]
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
platform = ${esp32_idf_V4.platform}
|
platform = ${esp32_idf_V4.platform}
|
||||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
|
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||||
${esp32.AR_build_flags}
|
${esp32.AR_build_flags}
|
||||||
@ -451,7 +463,6 @@ board_upload.maximum_size = 8388608
|
|||||||
[env:esp32dev_16M]
|
[env:esp32dev_16M]
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
platform = ${esp32_idf_V4.platform}
|
platform = ${esp32_idf_V4.platform}
|
||||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
|
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||||
${esp32.AR_build_flags}
|
${esp32.AR_build_flags}
|
||||||
@ -494,7 +505,6 @@ board_build.partitions = ${esp32.default_partitions}
|
|||||||
[env:esp32_wrover]
|
[env:esp32_wrover]
|
||||||
extends = esp32_idf_V4
|
extends = esp32_idf_V4
|
||||||
platform = ${esp32_idf_V4.platform}
|
platform = ${esp32_idf_V4.platform}
|
||||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
|
||||||
board = ttgo-t7-v14-mini32
|
board = ttgo-t7-v14-mini32
|
||||||
board_build.f_flash = 80000000L
|
board_build.f_flash = 80000000L
|
||||||
board_build.flash_mode = qio
|
board_build.flash_mode = qio
|
||||||
@ -510,7 +520,6 @@ lib_deps = ${esp32_idf_V4.lib_deps}
|
|||||||
[env:esp32c3dev]
|
[env:esp32c3dev]
|
||||||
extends = esp32c3
|
extends = esp32c3
|
||||||
platform = ${esp32c3.platform}
|
platform = ${esp32c3.platform}
|
||||||
platform_packages = ${esp32c3.platform_packages}
|
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp32-c3-devkitm-1
|
board = esp32-c3-devkitm-1
|
||||||
board_build.partitions = ${esp32.default_partitions}
|
board_build.partitions = ${esp32.default_partitions}
|
||||||
@ -528,7 +537,6 @@ lib_deps = ${esp32c3.lib_deps}
|
|||||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||||
platform = ${esp32s3.platform}
|
platform = ${esp32s3.platform}
|
||||||
platform_packages = ${esp32s3.platform_packages}
|
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
|
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
|
||||||
@ -551,7 +559,6 @@ monitor_filters = esp32_exception_decoder
|
|||||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||||
platform = ${esp32s3.platform}
|
platform = ${esp32s3.platform}
|
||||||
platform_packages = ${esp32s3.platform_packages}
|
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
|
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
|
||||||
@ -571,7 +578,6 @@ monitor_filters = esp32_exception_decoder
|
|||||||
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
|
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
|
||||||
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
|
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
|
||||||
platform = ${esp32s3.platform}
|
platform = ${esp32s3.platform}
|
||||||
platform_packages = ${esp32s3.platform_packages}
|
|
||||||
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
|
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
|
||||||
board_build.arduino.memory_type = opi_opi
|
board_build.arduino.memory_type = opi_opi
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
@ -598,7 +604,6 @@ monitor_filters = esp32_exception_decoder
|
|||||||
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
|
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
|
||||||
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
|
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
|
||||||
platform = ${esp32s3.platform}
|
platform = ${esp32s3.platform}
|
||||||
platform_packages = ${esp32s3.platform_packages}
|
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
||||||
@ -616,7 +621,6 @@ monitor_filters = esp32_exception_decoder
|
|||||||
|
|
||||||
[env:lolin_s2_mini]
|
[env:lolin_s2_mini]
|
||||||
platform = ${esp32s2.platform}
|
platform = ${esp32s2.platform}
|
||||||
platform_packages = ${esp32s2.platform_packages}
|
|
||||||
board = lolin_s2_mini
|
board = lolin_s2_mini
|
||||||
board_build.partitions = ${esp32.default_partitions}
|
board_build.partitions = ${esp32.default_partitions}
|
||||||
board_build.flash_mode = qio
|
board_build.flash_mode = qio
|
||||||
|
@ -529,3 +529,14 @@ monitor_filters = esp32_exception_decoder
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32.lib_deps}
|
${esp32.lib_deps}
|
||||||
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
|
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
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Usermod examples
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 433MHz RF remote example for esp32dev
|
||||||
|
[env:esp32dev_usermod_RF433]
|
||||||
|
extends = env:esp32dev
|
||||||
|
build_flags = ${env:esp32dev.build_flags} -D USERMOD_RF433
|
||||||
|
lib_deps = ${env:esp32dev.lib_deps}
|
||||||
|
sui77/rc-switch @ 2.6.4
|
||||||
|
BIN
tools/AutoCubeMap.xlsx
Normal file
BIN
tools/AutoCubeMap.xlsx
Normal file
Binary file not shown.
84
usermods/deep_sleep/readme.md
Normal file
84
usermods/deep_sleep/readme.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# Deep Sleep usermod
|
||||||
|
|
||||||
|
This usermod unleashes the low power capabilities of th ESP: when you power off your LEDs (using the UI power button or a macro) the ESP will be put into deep sleep mode, reducing power consumption to a minimum.
|
||||||
|
During deep sleep the ESP is shut down completely: no WiFi, no CPU, no outputs. The only way to wake it up is to use an external signal or a button. Once it wakes from deep sleep it reboots so ***make sure to use a boot-up preset.***
|
||||||
|
|
||||||
|
# A word of warning
|
||||||
|
|
||||||
|
When you disable the WLED option 'Turn LEDs on after power up/reset' and 'DelaySleep' is set to zero the ESP will go into deep sleep directly after power-up and only start WLED after it has been woken up.
|
||||||
|
If the ESP can not be awoken from deep sleep due to a wrong configuration it has to be factory reset, disabling sleep at power-up. There is no other way to wake it up.
|
||||||
|
|
||||||
|
# Power Consumption in deep sleep
|
||||||
|
|
||||||
|
The current drawn by the ESP in deep sleep mode depends on the type and is in the range of 5uA-20uA (as in micro Amperes):
|
||||||
|
- ESP32: 10uA
|
||||||
|
- ESP32 S3: 8uA
|
||||||
|
- ESP32 S2: 20uA
|
||||||
|
- ESP32 C3: 5uA
|
||||||
|
- ESP8266: 20uA (not supported in this usermod)
|
||||||
|
|
||||||
|
However, there is usually additional components on a controller that increase the value:
|
||||||
|
- Power LED: the power LED on a ESP board draws 500uA - 1mA
|
||||||
|
- LDO: the voltage regulator also draws idle current. Depending on the type used this can be around 50uA up to 10mA (LM1117). Special low power LDOs with very low idle currents do exist
|
||||||
|
- Digital LEDs: WS2812 for example draw a current of about 1mA per LED. To make good use of this usermod it is required to power them off using MOSFETs or a Relay
|
||||||
|
|
||||||
|
For lowest power consumption, remove the Power LED and make sure your board does not use an LM1117. On a ESP32 C3 Supermini with the power LED removed (no other modifications) powered through the 5V pin I measured a current draw of 50uA in deep sleep.
|
||||||
|
|
||||||
|
# Useable GPIOs
|
||||||
|
|
||||||
|
The GPIOs that can be used to wake the ESP from deep sleep are limited. Only pins connected to the internal RTC unit can be used:
|
||||||
|
|
||||||
|
- ESP32: GPIO 0, 2, 4, 12-15, 25-39
|
||||||
|
- ESP32 S3: GPIO 0-21
|
||||||
|
- ESP32 S2: GPIO 0-21
|
||||||
|
- ESP32 C3: GPIO 0-5
|
||||||
|
- ESP8266 is not supported in this usermod
|
||||||
|
|
||||||
|
You can however use the selected wake-up pin normally in WLED, it only gets activated as a wake-up pin when your LEDs are powered down.
|
||||||
|
|
||||||
|
# Limitations
|
||||||
|
|
||||||
|
To keep this usermod simple and easy to use, it is a very basic implementation of the low-power capabilities provided by the ESP. If you need more advanced control you are welcome to implement your own version based on this usermod.
|
||||||
|
|
||||||
|
## Usermod installation
|
||||||
|
|
||||||
|
Use `#define USERMOD_DEEP_SLEEP` in wled.h or `-D USERMOD_DEEP_SLEEP` in your platformio.ini. Settings can be changed in the usermod config UI.
|
||||||
|
|
||||||
|
### Define Settings
|
||||||
|
|
||||||
|
There are five parameters you can set:
|
||||||
|
|
||||||
|
- GPIO: the pin to use for wake-up
|
||||||
|
- WakeWhen High/Low: the pin state that triggers the wake-up
|
||||||
|
- Pull-up/down disable: enable or disable the internal pullup resistors during sleep (does not affect normal use while running)
|
||||||
|
- Wake after: if set larger than 0, ESP will automatically wake-up after this many seconds (Turn LEDs on after power up/reset is overriden, it will always turn on)
|
||||||
|
- Delay sleep: if set larger than 0, ESP will not go to sleep for this many seconds after you power it off. Timer is reset when switched back on during this time.
|
||||||
|
|
||||||
|
To override the default settings, place the `#define` in wled.h or add `-D DEEPSLEEP_xxx` to your platformio_override.ini build flags
|
||||||
|
|
||||||
|
* `DEEPSLEEP_WAKEUPPIN x` - define the pin to be used for wake-up, see list of useable pins above. The pin can be used normally as a button pin in WLED.
|
||||||
|
* `DEEPSLEEP_WAKEWHENHIGH` - if defined, wakes up when pin goes high (default is low)
|
||||||
|
* `DEEPSLEEP_DISABLEPULL` - if defined, internal pullup/pulldown is disabled in deep sleep (default is ebnabled)
|
||||||
|
* `DEEPSLEEP_WAKEUPINTERVAL` - number of seconds after which a wake-up happens automatically, sooner if button is pressed. 0 = never. accuracy is about 2%
|
||||||
|
* `DEEPSLEEP_DELAY` - delay between power-off and sleep
|
||||||
|
|
||||||
|
example for env build flags:
|
||||||
|
`-D USERMOD_DEEP_SLEEP`
|
||||||
|
`-D DEEPSLEEP_WAKEUPPIN=4`
|
||||||
|
`-D DEEPSLEEP_DISABLEPULL=0` ;enable pull-up/down resistors by default
|
||||||
|
`-D DEEPSLEEP_WAKEUPINTERVAL=43200` ;wake up after 12 hours (or when button is pressed)
|
||||||
|
|
||||||
|
### Hardware Setup
|
||||||
|
|
||||||
|
To wake from deep-sleep an external trigger signal on the configured GPIO is required. When using timed-only wake-up, use a GPIO that has an on-board pull-up resistor (GPIO0 on most boards). When using push-buttons it is highly recommended to use an external pull-up resistor: not all IO's on all devices have properly working internal resistors.
|
||||||
|
|
||||||
|
Using sensors like PIR, IR, touch sensors or any other sensor with a digital output can be used instead of a button.
|
||||||
|
|
||||||
|
now go on and save some power
|
||||||
|
@dedehai
|
||||||
|
|
||||||
|
## Change log
|
||||||
|
2024-09
|
||||||
|
* Initial version
|
||||||
|
2024-10
|
||||||
|
* Changed from #define configuration to UI configuration
|
227
usermods/deep_sleep/usermod_deep_sleep.h
Normal file
227
usermods/deep_sleep/usermod_deep_sleep.h
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
#include "driver/rtc_io.h"
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#error The "Deep Sleep" usermod does not support ESP8266
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEEPSLEEP_WAKEUPPIN
|
||||||
|
#define DEEPSLEEP_WAKEUPPIN 0
|
||||||
|
#endif
|
||||||
|
#ifndef DEEPSLEEP_WAKEWHENHIGH
|
||||||
|
#define DEEPSLEEP_WAKEWHENHIGH 0
|
||||||
|
#endif
|
||||||
|
#ifndef DEEPSLEEP_DISABLEPULL
|
||||||
|
#define DEEPSLEEP_DISABLEPULL 1
|
||||||
|
#endif
|
||||||
|
#ifndef DEEPSLEEP_WAKEUPINTERVAL
|
||||||
|
#define DEEPSLEEP_WAKEUPINTERVAL 0
|
||||||
|
#endif
|
||||||
|
#ifndef DEEPSLEEP_DELAY
|
||||||
|
#define DEEPSLEEP_DELAY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RTC_DATA_ATTR bool powerup = true; // variable in RTC data persists on a reboot
|
||||||
|
|
||||||
|
class DeepSleepUsermod : public Usermod {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool enabled = true;
|
||||||
|
bool initDone = false;
|
||||||
|
uint8_t wakeupPin = DEEPSLEEP_WAKEUPPIN;
|
||||||
|
uint8_t wakeWhenHigh = DEEPSLEEP_WAKEWHENHIGH; // wake up when pin goes high if 1, triggers on low if 0
|
||||||
|
bool noPull = true; // use pullup/pulldown resistor
|
||||||
|
int wakeupAfter = DEEPSLEEP_WAKEUPINTERVAL; // in seconds, <=0: button only
|
||||||
|
int sleepDelay = DEEPSLEEP_DELAY; // in seconds, 0 = immediate
|
||||||
|
int delaycounter = 5; // delay deep sleep at bootup until preset settings are applied
|
||||||
|
uint32_t lastLoopTime = 0;
|
||||||
|
// string that are used multiple time (this will save some flash memory)
|
||||||
|
static const char _name[];
|
||||||
|
static const char _enabled[];
|
||||||
|
|
||||||
|
bool pin_is_valid(uint8_t wakePin) {
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32 //ESP32: GPIOs 0,2,4, 12-15, 25-39 can be used for wake-up
|
||||||
|
if (wakePin == 0 || wakePin == 2 || wakePin == 4 || (wakePin >= 12 && wakePin <= 15) || (wakePin >= 25 && wakePin <= 27) || (wakePin >= 32 && wakePin <= 39)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2) //ESP32 S3 & S3: GPIOs 0-21 can be used for wake-up
|
||||||
|
if (wakePin <= 21) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C3 // ESP32 C3: GPIOs 0-5 can be used for wake-up
|
||||||
|
if (wakePin <= 5) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
DEBUG_PRINTLN(F("Error: unsupported deep sleep wake-up pin"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline void enable(bool enable) { enabled = enable; } // Enable/Disable the usermod
|
||||||
|
inline bool isEnabled() { return enabled; } //Get usermod enabled/disabled state
|
||||||
|
|
||||||
|
// setup is called at boot (or in this case after every exit of sleep mode)
|
||||||
|
void setup() {
|
||||||
|
//TODO: if the de-init of RTC pins is required to do it could be done here
|
||||||
|
//rtc_gpio_deinit(wakeupPin);
|
||||||
|
initDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (!enabled || !offMode) { // disabled or LEDs are on
|
||||||
|
lastLoopTime = 0; // reset timer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sleepDelay > 0) {
|
||||||
|
if(lastLoopTime == 0) lastLoopTime = millis(); // initialize
|
||||||
|
if (millis() - lastLoopTime < sleepDelay * 1000) {
|
||||||
|
return; // wait until delay is over
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(powerup == false && delaycounter) { // delay sleep in case a preset is being loaded and turnOnAtBoot is disabled (handleIO() does enable offMode temporarily in this case)
|
||||||
|
delaycounter--;
|
||||||
|
if(delaycounter == 2 && offMode) { // force turn on, no matter the settings (device is bricked if user set sleepDelay=0, no bootup preset and turnOnAtBoot=false)
|
||||||
|
if (briS == 0) bri = 10; // turn on at low brightness
|
||||||
|
else bri = briS;
|
||||||
|
strip.setBrightness(bri); // needed to make handleIO() not turn off LEDs (really? does not help in bootup preset)
|
||||||
|
offMode = false;
|
||||||
|
applyPresetWithFallback(0, CALL_MODE_INIT, FX_MODE_STATIC, 0); // try to apply preset 0, fallback to static
|
||||||
|
if (rlyPin >= 0) {
|
||||||
|
digitalWrite(rlyPin, (rlyMde ? HIGH : LOW)); // turn relay on TODO: this should be done by wled, what function to call?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINTLN(F("DeepSleep UM: entering deep sleep..."));
|
||||||
|
powerup = false; // turn leds on in all subsequent bootups (overrides Turn LEDs on after power up/reset' at reboot)
|
||||||
|
if(!pin_is_valid(wakeupPin)) return;
|
||||||
|
esp_err_t halerror = ESP_OK;
|
||||||
|
pinMode(wakeupPin, INPUT); // make sure GPIO is input with pullup/pulldown disabled
|
||||||
|
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); //disable all wake-up sources (just in case)
|
||||||
|
|
||||||
|
if(wakeupAfter)
|
||||||
|
esp_sleep_enable_timer_wakeup((uint64_t)wakeupAfter * (uint64_t)1e6); //sleep for x seconds
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32C3) // ESP32 C3
|
||||||
|
if(noPull)
|
||||||
|
gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_FLOATING);
|
||||||
|
else { // enable pullup/pulldown resistor
|
||||||
|
if(wakeWhenHigh)
|
||||||
|
gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLDOWN_ONLY);
|
||||||
|
else
|
||||||
|
gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLUP_ONLY);
|
||||||
|
}
|
||||||
|
if(wakeWhenHigh)
|
||||||
|
halerror = esp_deep_sleep_enable_gpio_wakeup(1<<wakeupPin, ESP_GPIO_WAKEUP_GPIO_HIGH);
|
||||||
|
else
|
||||||
|
halerror = esp_deep_sleep_enable_gpio_wakeup(1<<wakeupPin, ESP_GPIO_WAKEUP_GPIO_LOW);
|
||||||
|
#else // ESP32, S2, S3
|
||||||
|
gpio_pulldown_dis((gpio_num_t)wakeupPin); // disable internal pull resistors for GPIO use
|
||||||
|
gpio_pullup_dis((gpio_num_t)wakeupPin);
|
||||||
|
if(noPull) {
|
||||||
|
rtc_gpio_pullup_dis((gpio_num_t)wakeupPin);
|
||||||
|
rtc_gpio_pulldown_dis((gpio_num_t)wakeupPin);
|
||||||
|
}
|
||||||
|
else { // enable pullup/pulldown resistor for RTC use
|
||||||
|
if(wakeWhenHigh)
|
||||||
|
rtc_gpio_pulldown_en((gpio_num_t)wakeupPin);
|
||||||
|
else
|
||||||
|
rtc_gpio_pullup_en((gpio_num_t)wakeupPin);
|
||||||
|
}
|
||||||
|
if(wakeWhenHigh)
|
||||||
|
halerror = esp_sleep_enable_ext0_wakeup((gpio_num_t)wakeupPin, HIGH); // only RTC pins can be used
|
||||||
|
else
|
||||||
|
halerror = esp_sleep_enable_ext0_wakeup((gpio_num_t)wakeupPin, LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
delay(1); // wait for pin to be ready
|
||||||
|
if(halerror == ESP_OK) esp_deep_sleep_start(); // go into deep sleep
|
||||||
|
else DEBUG_PRINTLN(F("sleep failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//void connected() {} //unused, this is called every time the WiFi is (re)connected
|
||||||
|
|
||||||
|
void addToConfig(JsonObject& root) override
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
|
top[FPSTR(_enabled)] = enabled;
|
||||||
|
//save these vars persistently whenever settings are saved
|
||||||
|
top["gpio"] = wakeupPin;
|
||||||
|
top["wakeWhen"] = wakeWhenHigh;
|
||||||
|
top["pull"] = noPull;
|
||||||
|
top["wakeAfter"] = wakeupAfter;
|
||||||
|
top["delaySleep"] = sleepDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readFromConfig(JsonObject& root) override
|
||||||
|
{
|
||||||
|
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||||
|
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||||
|
JsonObject top = root[FPSTR(_name)];
|
||||||
|
bool configComplete = !top.isNull();
|
||||||
|
|
||||||
|
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
|
||||||
|
configComplete &= getJsonValue(top["gpio"], wakeupPin, DEEPSLEEP_WAKEUPPIN);
|
||||||
|
if (!pin_is_valid(wakeupPin)) {
|
||||||
|
wakeupPin = 0; // set to 0 if invalid
|
||||||
|
configComplete = false; // Mark config as incomplete if pin is invalid
|
||||||
|
}
|
||||||
|
configComplete &= getJsonValue(top["wakeWhen"], wakeWhenHigh, DEEPSLEEP_WAKEWHENHIGH); // default to wake on low
|
||||||
|
configComplete &= getJsonValue(top["pull"], noPull, DEEPSLEEP_DISABLEPULL); // default to no pullup/pulldown
|
||||||
|
configComplete &= getJsonValue(top["wakeAfter"], wakeupAfter, DEEPSLEEP_WAKEUPINTERVAL);
|
||||||
|
configComplete &= getJsonValue(top["delaySleep"], sleepDelay, DEEPSLEEP_DELAY);
|
||||||
|
|
||||||
|
return configComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* appendConfigData() is called when user enters usermod settings page
|
||||||
|
* it may add additional metadata for certain entry fields (adding drop down is possible)
|
||||||
|
* be careful not to add too much as oappend() buffer is limited to 3k
|
||||||
|
*/
|
||||||
|
void appendConfigData() override
|
||||||
|
{
|
||||||
|
// dropdown for wakeupPin
|
||||||
|
oappend(SET_F("dd=addDropdown('DeepSleep','gpio');"));
|
||||||
|
for (int pin = 0; pin < 40; pin++) { // possible pins are in range 0-39
|
||||||
|
if (pin_is_valid(pin)) {
|
||||||
|
oappend(SET_F("addOption(dd,'"));
|
||||||
|
oappend(String(pin).c_str());
|
||||||
|
oappend(SET_F("',"));
|
||||||
|
oappend(String(pin).c_str());
|
||||||
|
oappend(SET_F(");"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oappend(SET_F("dd=addDropdown('DeepSleep','wakeWhen');"));
|
||||||
|
oappend(SET_F("addOption(dd,'Low',0);"));
|
||||||
|
oappend(SET_F("addOption(dd,'High',1);"));
|
||||||
|
|
||||||
|
oappend(SET_F("addInfo('DeepSleep:pull',1,'','-up/down disable: ');")); // first string is suffix, second string is prefix
|
||||||
|
oappend(SET_F("addInfo('DeepSleep:wakeAfter',1,'seconds <i>(0 = never)<i>');"));
|
||||||
|
oappend(SET_F("addInfo('DeepSleep:delaySleep',1,'seconds <i>(0 = sleep at powerup)<i>');")); // first string is suffix, second string is prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||||
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
|
*/
|
||||||
|
uint16_t getId() {
|
||||||
|
return USERMOD_ID_DEEP_SLEEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// add more strings here to reduce flash memory usage
|
||||||
|
const char DeepSleepUsermod::_name[] PROGMEM = "DeepSleep";
|
||||||
|
const char DeepSleepUsermod::_enabled[] PROGMEM = "enabled";
|
@ -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 :)
|
It was quite a bit more work than I hoped, but I got there eventually :)
|
||||||
|
|
||||||
## Requirements
|
## 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
|
## 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`.
|
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
|
extends = env:esp32dev
|
||||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER
|
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER
|
||||||
lib_deps = ${esp32.lib_deps}
|
lib_deps = ${esp32.lib_deps}
|
||||||
lennarthennigs/ESP Rotary@^1.5.0
|
lennarthennigs/ESP Rotary@^2.1.1
|
||||||
```
|
```
|
||||||
|
|
||||||
ESP8266 / D1 Mini:
|
ESP8266 / D1 Mini:
|
||||||
@ -29,7 +29,7 @@ ESP8266 / D1 Mini:
|
|||||||
extends = env:d1_mini
|
extends = env:d1_mini
|
||||||
build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER
|
build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER
|
||||||
lib_deps = ${esp8266.lib_deps}
|
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
|
## How to connect the board to your ESP
|
||||||
|
@ -9,7 +9,7 @@ Very loosely based on the existing usermod "seven segment display".
|
|||||||
|
|
||||||
Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`.
|
Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`.
|
||||||
|
|
||||||
For the auto brightness option, the usermod SN_Photoresistor has to be installed as well. See SN_Photoresistor/readme.md for instructions.
|
For the auto brightness option, the usermod SN_Photoresistor or BH1750_V2 has to be installed as well. See SN_Photoresistor/readme.md or BH1750_V2/readme.md for instructions.
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
All settings can be controlled via the usermod settings page.
|
All settings can be controlled via the usermod settings page.
|
||||||
@ -28,10 +28,10 @@ Enables the blinking colon(s) if they are defined
|
|||||||
Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`)
|
Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`)
|
||||||
|
|
||||||
### enable-auto-brightness
|
### enable-auto-brightness
|
||||||
Enables the auto brightness feature. Can be used only when the usermod SN_Photoresistor is installed.
|
Enables the auto brightness feature. Can be used only when the usermods SN_Photoresistor or BH1750_V2 are installed.
|
||||||
|
|
||||||
### auto-brightness-min / auto-brightness-max
|
### auto-brightness-min / auto-brightness-max
|
||||||
The lux value calculated from usermod SN_Photoresistor will be mapped to the values defined here.
|
The lux value calculated from usermod SN_Photoresistor or BH1750_V2 will be mapped to the values defined here.
|
||||||
The mapping, 0 - 1000 lux, will be mapped to auto-brightness-min and auto-brightness-max
|
The mapping, 0 - 1000 lux, will be mapped to auto-brightness-min and auto-brightness-max
|
||||||
|
|
||||||
WLED current protection will override the calculated value if it is too high.
|
WLED current protection will override the calculated value if it is too high.
|
||||||
|
@ -97,6 +97,11 @@ private:
|
|||||||
#else
|
#else
|
||||||
void* ptr = nullptr;
|
void* ptr = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USERMOD_BH1750
|
||||||
|
Usermod_BH1750* bh1750 = nullptr;
|
||||||
|
#else
|
||||||
|
void* bh1750 = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
void _overlaySevenSegmentDraw() {
|
void _overlaySevenSegmentDraw() {
|
||||||
int displayMaskLen = static_cast<int>(umSSDRDisplayMask.length());
|
int displayMaskLen = static_cast<int>(umSSDRDisplayMask.length());
|
||||||
@ -387,6 +392,9 @@ public:
|
|||||||
#ifdef USERMOD_SN_PHOTORESISTOR
|
#ifdef USERMOD_SN_PHOTORESISTOR
|
||||||
ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR);
|
ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USERMOD_BH1750
|
||||||
|
bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750);
|
||||||
|
#endif
|
||||||
DEBUG_PRINTLN(F("Setup done"));
|
DEBUG_PRINTLN(F("Setup done"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,6 +418,20 @@ public:
|
|||||||
umSSDRLastRefresh = millis();
|
umSSDRLastRefresh = millis();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USERMOD_BH1750
|
||||||
|
if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime)) {
|
||||||
|
if (bh1750 != nullptr) {
|
||||||
|
float lux = bh1750->getIlluminance();
|
||||||
|
uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax);
|
||||||
|
if (bri != brightness) {
|
||||||
|
DEBUG_PRINTF("Adjusting brightness based on lux value: %.2f lx, new brightness: %d\n", lux, brightness);
|
||||||
|
bri = brightness;
|
||||||
|
stateUpdated(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
umSSDRLastRefresh = millis();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleOverlayDraw() {
|
void handleOverlayDraw() {
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file allows you to add own functionality to WLED more easily
|
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
|
||||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in wled_eeprom.h)
|
|
||||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
|
||||||
|
|
||||||
byte wipeState = 0; //0: inactive 1: wiping 2: solid
|
|
||||||
unsigned long timeStaticStart = 0;
|
|
||||||
uint16_t previousUserVar0 = 0;
|
|
||||||
|
|
||||||
//comment this out if you want the turn off effect to be just fading out instead of reverse wipe
|
|
||||||
#define STAIRCASE_WIPE_OFF
|
|
||||||
|
|
||||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
|
||||||
void userSetup()
|
|
||||||
{
|
|
||||||
//setup PIR sensor here, if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
|
||||||
void userConnected()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
|
||||||
void userLoop()
|
|
||||||
{
|
|
||||||
//userVar0 (U0 in HTTP API):
|
|
||||||
//has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266
|
|
||||||
//has to be set to 2 if movement is detected on the PIR that is the opposite side
|
|
||||||
//can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds)
|
|
||||||
|
|
||||||
if (userVar0 > 0)
|
|
||||||
{
|
|
||||||
if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered
|
|
||||||
previousUserVar0 = userVar0;
|
|
||||||
|
|
||||||
if (wipeState == 0) {
|
|
||||||
startWipe();
|
|
||||||
wipeState = 1;
|
|
||||||
} else if (wipeState == 1) { //wiping
|
|
||||||
uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time)
|
|
||||||
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
|
|
||||||
effectCurrent = FX_MODE_STATIC;
|
|
||||||
timeStaticStart = millis();
|
|
||||||
colorUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
wipeState = 2;
|
|
||||||
}
|
|
||||||
} else if (wipeState == 2) { //static
|
|
||||||
if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered
|
|
||||||
{
|
|
||||||
if (millis() - timeStaticStart > userVar1*1000) wipeState = 3;
|
|
||||||
}
|
|
||||||
} else if (wipeState == 3) { //switch to wipe off
|
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
|
||||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
|
||||||
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
|
|
||||||
colorUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
wipeState = 4;
|
|
||||||
#else
|
|
||||||
turnOff();
|
|
||||||
#endif
|
|
||||||
} else { //wiping off
|
|
||||||
if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wipeState = 0; //reset for next time
|
|
||||||
if (previousUserVar0) {
|
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
|
||||||
userVar0 = previousUserVar0;
|
|
||||||
wipeState = 3;
|
|
||||||
#else
|
|
||||||
turnOff();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
previousUserVar0 = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void startWipe()
|
|
||||||
{
|
|
||||||
bri = briLast; //turn on
|
|
||||||
transitionDelayTemp = 0; //no transition
|
|
||||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
|
||||||
strip.resetTimebase(); //make sure wipe starts from beginning
|
|
||||||
|
|
||||||
//set wipe direction
|
|
||||||
Segment& seg = strip.getSegment(0);
|
|
||||||
bool doReverse = (userVar0 == 2);
|
|
||||||
seg.setOption(1, doReverse);
|
|
||||||
|
|
||||||
colorUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void turnOff()
|
|
||||||
{
|
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
|
||||||
transitionDelayTemp = 0; //turn off immediately after wipe completed
|
|
||||||
#else
|
|
||||||
transitionDelayTemp = 4000; //fade out slowly
|
|
||||||
#endif
|
|
||||||
bri = 0;
|
|
||||||
stateUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
wipeState = 0;
|
|
||||||
userVar0 = 0;
|
|
||||||
previousUserVar0 = 0;
|
|
||||||
}
|
|
18
usermods/usermod_v2_RF433/readme.md
Normal file
18
usermods/usermod_v2_RF433/readme.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# RF433 remote usermod
|
||||||
|
|
||||||
|
Usermod for controlling WLED using a generic 433 / 315MHz remote and simple 3-pin receiver
|
||||||
|
See <https://github.com/sui77/rc-switch/> for compatibility details
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
- Create a `platformio_override.ini` file at the root of the wled source directory if not already present
|
||||||
|
- Copy the `433MHz RF remote example for esp32dev` section from `platformio_override.sample.ini` into it
|
||||||
|
- Duplicate/adjust for other boards
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- Connect receiver to a free pin
|
||||||
|
- Set pin in Config->Usermods
|
||||||
|
- Info pane will show the last received button code
|
||||||
|
- Upload the remote433.json sample file in this folder to the ESP with the file editor at [http://\[wled-ip\]/edit](http://ip/edit)
|
||||||
|
- Edit as necessary, the key is the button number retrieved from the info pane, and the "cmd" can be either an [HTTP API](https://kno.wled.ge/interfaces/http-api/) or a [JSON API](https://kno.wled.ge/interfaces/json-api/) command.
|
34
usermods/usermod_v2_RF433/remote433.json
Normal file
34
usermods/usermod_v2_RF433/remote433.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"13985576": {
|
||||||
|
"cmnt": "Toggle Power using HTTP API",
|
||||||
|
"cmd": "T=2"
|
||||||
|
},
|
||||||
|
"3670817": {
|
||||||
|
"cmnt": "Force Power ON using HTTP API",
|
||||||
|
"cmd": "T=1"
|
||||||
|
},
|
||||||
|
"13985572": {
|
||||||
|
"cmnt": "Set brightness to 200 using JSON API",
|
||||||
|
"cmd": {"bri":200}
|
||||||
|
},
|
||||||
|
"3670818": {
|
||||||
|
"cmnt": "Run Preset 1 using JSON API",
|
||||||
|
"cmd": {"ps":1}
|
||||||
|
},
|
||||||
|
"13985570": {
|
||||||
|
"cmnt": "Increase brightness by 40 using HTTP API",
|
||||||
|
"cmd": "A=~40"
|
||||||
|
},
|
||||||
|
"13985569": {
|
||||||
|
"cmnt": "Decrease brightness by 40 using HTTP API",
|
||||||
|
"cmd": "A=~-40"
|
||||||
|
},
|
||||||
|
"7608836": {
|
||||||
|
"cmnt": "Start 1min timer using JSON API",
|
||||||
|
"cmd": {"nl":{"on":true,"dur":1,"mode":0}}
|
||||||
|
},
|
||||||
|
"7608840": {
|
||||||
|
"cmnt": "Select random effect on all segments using JSON API",
|
||||||
|
"cmd": {"seg":{"fx":"r"}}
|
||||||
|
}
|
||||||
|
}
|
183
usermods/usermod_v2_RF433/usermod_v2_RF433.h
Normal file
183
usermods/usermod_v2_RF433/usermod_v2_RF433.h
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
#define RF433_BUSWAIT_TIMEOUT 24
|
||||||
|
|
||||||
|
class RF433Usermod : public Usermod
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
unsigned long lastCommand = 0;
|
||||||
|
unsigned long lastTime = 0;
|
||||||
|
|
||||||
|
bool modEnabled = true;
|
||||||
|
int8_t receivePin = -1;
|
||||||
|
|
||||||
|
static const char _modName[];
|
||||||
|
static const char _modEnabled[];
|
||||||
|
static const char _receivePin[];
|
||||||
|
|
||||||
|
bool initDone = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
mySwitch.disableReceive();
|
||||||
|
if (modEnabled)
|
||||||
|
{
|
||||||
|
mySwitch.enableReceive(receivePin);
|
||||||
|
}
|
||||||
|
initDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
void connected()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if (!modEnabled || strip.isUpdating())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mySwitch.available())
|
||||||
|
{
|
||||||
|
unsigned long receivedCommand = mySwitch.getReceivedValue();
|
||||||
|
mySwitch.resetAvailable();
|
||||||
|
|
||||||
|
// Discard duplicates, limit long press repeat
|
||||||
|
if (lastCommand == receivedCommand && millis() - lastTime < 800)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastCommand = receivedCommand;
|
||||||
|
lastTime = millis();
|
||||||
|
|
||||||
|
DEBUG_PRINT(F("RF433 Receive: "));
|
||||||
|
DEBUG_PRINTLN(receivedCommand);
|
||||||
|
|
||||||
|
if(!remoteJson433(receivedCommand))
|
||||||
|
DEBUG_PRINTLN(F("RF433: unknown button"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add last received button to info pane
|
||||||
|
void addToJsonInfo(JsonObject &root)
|
||||||
|
{
|
||||||
|
if (!initDone)
|
||||||
|
return; // prevent crash on boot applyPreset()
|
||||||
|
JsonObject user = root["u"];
|
||||||
|
if (user.isNull())
|
||||||
|
user = root.createNestedObject("u");
|
||||||
|
|
||||||
|
JsonArray switchArr = user.createNestedArray("RF433 Last Received"); // name
|
||||||
|
switchArr.add(lastCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject(FPSTR(_modName)); // usermodname
|
||||||
|
top[FPSTR(_modEnabled)] = modEnabled;
|
||||||
|
JsonArray pinArray = top.createNestedArray("pin");
|
||||||
|
pinArray.add(receivePin);
|
||||||
|
|
||||||
|
DEBUG_PRINTLN(F(" config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readFromConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root[FPSTR(_modName)];
|
||||||
|
if (top.isNull())
|
||||||
|
{
|
||||||
|
DEBUG_PRINT(FPSTR(_modName));
|
||||||
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
getJsonValue(top[FPSTR(_modEnabled)], modEnabled);
|
||||||
|
getJsonValue(top["pin"][0], receivePin);
|
||||||
|
|
||||||
|
DEBUG_PRINTLN(F("config (re)loaded."));
|
||||||
|
|
||||||
|
// Redo init on update
|
||||||
|
if(initDone)
|
||||||
|
setup();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||||
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
|
*/
|
||||||
|
uint16_t getId()
|
||||||
|
{
|
||||||
|
return USERMOD_ID_RF433;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function follows the same principle as decodeIRJson() / remoteJson()
|
||||||
|
bool remoteJson433(int button)
|
||||||
|
{
|
||||||
|
char objKey[14];
|
||||||
|
bool parsed = false;
|
||||||
|
|
||||||
|
if (!requestJSONBufferLock(22)) return false;
|
||||||
|
|
||||||
|
sprintf_P(objKey, PSTR("\"%d\":"), button);
|
||||||
|
|
||||||
|
unsigned long start = millis();
|
||||||
|
while (strip.isUpdating() && millis()-start < RF433_BUSWAIT_TIMEOUT) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches
|
||||||
|
|
||||||
|
// attempt to read command from remote.json
|
||||||
|
readObjectFromFile(PSTR("/remote433.json"), objKey, pDoc);
|
||||||
|
JsonObject fdo = pDoc->as<JsonObject>();
|
||||||
|
if (fdo.isNull()) {
|
||||||
|
// the received button does not exist
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
String cmdStr = fdo["cmd"].as<String>();
|
||||||
|
JsonObject jsonCmdObj = fdo["cmd"]; //object
|
||||||
|
|
||||||
|
if (jsonCmdObj.isNull()) // we could also use: fdo["cmd"].is<String>()
|
||||||
|
{
|
||||||
|
// HTTP API command
|
||||||
|
String apireq = "win"; apireq += '&'; // reduce flash string usage
|
||||||
|
if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix
|
||||||
|
if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) {
|
||||||
|
char tmp[10];
|
||||||
|
sprintf_P(tmp, PSTR("&SS=%d"), strip.getMainSegmentId());
|
||||||
|
cmdStr += tmp;
|
||||||
|
}
|
||||||
|
fdo.clear(); // clear JSON buffer (it is no longer needed)
|
||||||
|
handleSet(nullptr, cmdStr, false); // no stateUpdated() call here
|
||||||
|
stateUpdated(CALL_MODE_BUTTON);
|
||||||
|
parsed = true;
|
||||||
|
} else {
|
||||||
|
// command is JSON object
|
||||||
|
if (jsonCmdObj[F("psave")].isNull())
|
||||||
|
deserializeState(jsonCmdObj, CALL_MODE_BUTTON_PRESET);
|
||||||
|
else {
|
||||||
|
uint8_t psave = jsonCmdObj[F("psave")].as<int>();
|
||||||
|
char pname[33];
|
||||||
|
sprintf_P(pname, PSTR("IR Preset %d"), psave);
|
||||||
|
fdo.clear();
|
||||||
|
if (psave > 0 && psave < 251) savePreset(psave, pname, fdo);
|
||||||
|
}
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char RF433Usermod::_modName[] PROGMEM = "RF433 Remote";
|
||||||
|
const char RF433Usermod::_modEnabled[] PROGMEM = "Enabled";
|
||||||
|
const char RF433Usermod::_receivePin[] PROGMEM = "RX Pin";
|
||||||
|
|
273
wled00/FX.cpp
273
wled00/FX.cpp
@ -197,7 +197,7 @@ static const char _data_FX_MODE_STROBE_RAINBOW[] PROGMEM = "Strobe Rainbow@!;,!;
|
|||||||
* if (bool rev == true) then LEDs are turned off in reverse order
|
* if (bool rev == true) then LEDs are turned off in reverse order
|
||||||
*/
|
*/
|
||||||
uint16_t color_wipe(bool rev, bool useRandomColors) {
|
uint16_t color_wipe(bool rev, bool useRandomColors) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150;
|
uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150;
|
||||||
uint32_t perc = strip.now % cycleTime;
|
uint32_t perc = strip.now % cycleTime;
|
||||||
unsigned prog = (perc * 65535) / cycleTime;
|
unsigned prog = (perc * 65535) / cycleTime;
|
||||||
@ -410,7 +410,7 @@ static const char _data_FX_MODE_FADE[] PROGMEM = "Fade@!;!,!;!;01";
|
|||||||
* Scan mode parent function
|
* Scan mode parent function
|
||||||
*/
|
*/
|
||||||
uint16_t scan(bool dual) {
|
uint16_t scan(bool dual) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150;
|
uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150;
|
||||||
uint32_t perc = strip.now % cycleTime;
|
uint32_t perc = strip.now % cycleTime;
|
||||||
int prog = (perc * 65535) / cycleTime;
|
int prog = (perc * 65535) / cycleTime;
|
||||||
@ -642,11 +642,12 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
|
|||||||
* Dissolve function
|
* Dissolve function
|
||||||
*/
|
*/
|
||||||
uint16_t dissolve(uint32_t color) {
|
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
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||||
|
|
||||||
if (SEGENV.call == 0) {
|
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;
|
SEGENV.aux0 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,33 +655,26 @@ uint16_t dissolve(uint32_t color) {
|
|||||||
if (hw_random8() <= SEGMENT.intensity) {
|
if (hw_random8() <= SEGMENT.intensity) {
|
||||||
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
|
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
|
||||||
unsigned i = hw_random16(SEGLEN);
|
unsigned i = hw_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 (SEGENV.aux0) { //dissolve to primary/palette
|
||||||
if (fadeUp) {
|
if (pixels[i] == SEGCOLOR(1)) {
|
||||||
if (color == SEGCOLOR(0)) {
|
pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color;
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
|
||||||
} else {
|
|
||||||
SEGMENT.setPixelColor(i, color);
|
|
||||||
}
|
|
||||||
bitWrite(SEGENV.data[index], bitNum, false);
|
|
||||||
break; //only spawn 1 new pixel per frame per 50 LEDs
|
break; //only spawn 1 new pixel per frame per 50 LEDs
|
||||||
}
|
}
|
||||||
} else { //dissolve to secondary
|
} else { //dissolve to secondary
|
||||||
if (!fadeUp) {
|
if (pixels[i] != SEGCOLOR(1)) {
|
||||||
SEGMENT.setPixelColor(i, SEGCOLOR(1)); break;
|
pixels[i] = SEGCOLOR(1);
|
||||||
bitWrite(SEGENV.data[index], bitNum, true);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// fix for #4401
|
||||||
|
for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]);
|
||||||
|
|
||||||
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
|
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
|
||||||
SEGENV.aux0 = !SEGENV.aux0;
|
SEGENV.aux0 = !SEGENV.aux0;
|
||||||
SEGENV.step = 0;
|
SEGENV.step = 0;
|
||||||
memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading
|
|
||||||
} else {
|
} else {
|
||||||
SEGENV.step++;
|
SEGENV.step++;
|
||||||
}
|
}
|
||||||
@ -1023,7 +1017,7 @@ static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2,
|
|||||||
* Emulates a traffic light.
|
* Emulates a traffic light.
|
||||||
*/
|
*/
|
||||||
uint16_t mode_traffic_light(void) {
|
uint16_t mode_traffic_light(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
for (unsigned i=0; i < SEGLEN; i++)
|
for (unsigned i=0; i < SEGLEN; i++)
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
||||||
uint32_t mdelay = 500;
|
uint32_t mdelay = 500;
|
||||||
@ -1056,7 +1050,7 @@ static const char _data_FX_MODE_TRAFFIC_LIGHT[] PROGMEM = "Traffic Light@!,US st
|
|||||||
*/
|
*/
|
||||||
#define FLASH_COUNT 4
|
#define FLASH_COUNT 4
|
||||||
uint16_t mode_chase_flash(void) {
|
uint16_t mode_chase_flash(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
|
unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
|
||||||
|
|
||||||
for (unsigned i = 0; i < SEGLEN; i++) {
|
for (unsigned i = 0; i < SEGLEN; i++) {
|
||||||
@ -1086,7 +1080,7 @@ static const char _data_FX_MODE_CHASE_FLASH[] PROGMEM = "Chase Flash@!;Bg,Fx;!";
|
|||||||
* Prim flashes running, followed by random color.
|
* Prim flashes running, followed by random color.
|
||||||
*/
|
*/
|
||||||
uint16_t mode_chase_flash_random(void) {
|
uint16_t mode_chase_flash_random(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
|
unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
|
||||||
|
|
||||||
for (int i = 0; i < SEGENV.aux1; i++) {
|
for (int i = 0; i < SEGENV.aux1; i++) {
|
||||||
@ -1168,7 +1162,7 @@ static const char _data_FX_MODE_RUNNING_RANDOM[] PROGMEM = "Stream@!,Zone size;;
|
|||||||
* K.I.T.T.
|
* K.I.T.T.
|
||||||
*/
|
*/
|
||||||
uint16_t mode_larson_scanner(void) {
|
uint16_t mode_larson_scanner(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
|
|
||||||
const unsigned speed = FRAMETIME * map(SEGMENT.speed, 0, 255, 96, 2); // map into useful range
|
const unsigned speed = FRAMETIME * map(SEGMENT.speed, 0, 255, 96, 2); // map into useful range
|
||||||
const unsigned pixels = SEGLEN / speed; // how many pixels to advance per frame
|
const unsigned pixels = SEGLEN / speed; // how many pixels to advance per frame
|
||||||
@ -1226,7 +1220,7 @@ static const char _data_FX_MODE_DUAL_LARSON_SCANNER[] PROGMEM = "Scanner Dual@!,
|
|||||||
* Firing comets from one end. "Lighthouse"
|
* Firing comets from one end. "Lighthouse"
|
||||||
*/
|
*/
|
||||||
uint16_t mode_comet(void) {
|
uint16_t mode_comet(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned counter = (strip.now * ((SEGMENT.speed >>2) +1)) & 0xFFFF;
|
unsigned counter = (strip.now * ((SEGMENT.speed >>2) +1)) & 0xFFFF;
|
||||||
unsigned index = (counter * SEGLEN) >> 16;
|
unsigned index = (counter * SEGLEN) >> 16;
|
||||||
if (SEGENV.call == 0) SEGENV.aux0 = index;
|
if (SEGENV.call == 0) SEGENV.aux0 = index;
|
||||||
@ -1254,7 +1248,7 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!"
|
|||||||
* Fireworks function.
|
* Fireworks function.
|
||||||
*/
|
*/
|
||||||
uint16_t mode_fireworks() {
|
uint16_t mode_fireworks() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
const uint16_t width = SEGMENT.is2D() ? SEG_W : SEGLEN;
|
const uint16_t width = SEGMENT.is2D() ? SEG_W : SEGLEN;
|
||||||
const uint16_t height = SEG_H;
|
const uint16_t height = SEG_H;
|
||||||
|
|
||||||
@ -1296,7 +1290,7 @@ static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!;
|
|||||||
|
|
||||||
//Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h
|
//Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h
|
||||||
uint16_t mode_rain() {
|
uint16_t mode_rain() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
const unsigned width = SEG_W;
|
const unsigned width = SEG_W;
|
||||||
const unsigned height = SEG_H;
|
const unsigned height = SEG_H;
|
||||||
SEGENV.step += FRAMETIME;
|
SEGENV.step += FRAMETIME;
|
||||||
@ -1362,7 +1356,7 @@ static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!;0
|
|||||||
* Gradient run base function
|
* Gradient run base function
|
||||||
*/
|
*/
|
||||||
uint16_t gradient_base(bool loading) {
|
uint16_t gradient_base(bool loading) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1);
|
uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1);
|
||||||
uint16_t pp = (counter * SEGLEN) >> 16;
|
uint16_t pp = (counter * SEGLEN) >> 16;
|
||||||
if (SEGENV.call == 0) pp = 0;
|
if (SEGENV.call == 0) pp = 0;
|
||||||
@ -1407,7 +1401,7 @@ static const char _data_FX_MODE_LOADING[] PROGMEM = "Loading@!,Fade;!,!;!;;ix=16
|
|||||||
* Two dots running
|
* Two dots running
|
||||||
*/
|
*/
|
||||||
uint16_t mode_two_dots() {
|
uint16_t mode_two_dots() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster
|
unsigned delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster
|
||||||
uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
|
uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
|
||||||
unsigned offset = it % SEGLEN;
|
unsigned offset = it % SEGLEN;
|
||||||
@ -1827,7 +1821,7 @@ uint16_t mode_oscillate(void) {
|
|||||||
// if the counter has increased, move the oscillator by the random step
|
// 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;
|
if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
|
||||||
oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8);
|
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].pos = 0;
|
||||||
oscillators[i].dir = 1;
|
oscillators[i].dir = 1;
|
||||||
// make bigger steps for faster speeds
|
// make bigger steps for faster speeds
|
||||||
@ -1843,7 +1837,7 @@ uint16_t mode_oscillate(void) {
|
|||||||
for (unsigned i = 0; i < SEGLEN; i++) {
|
for (unsigned i = 0; i < SEGLEN; i++) {
|
||||||
uint32_t color = BLACK;
|
uint32_t color = BLACK;
|
||||||
for (unsigned j = 0; j < numOscillators; j++) {
|
for (unsigned j = 0; j < numOscillators; j++) {
|
||||||
if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
|
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));
|
color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1858,7 +1852,7 @@ static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate";
|
|||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
uint16_t mode_lightning(void) {
|
uint16_t mode_lightning(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash
|
unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash
|
||||||
unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
|
unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
|
||||||
uint8_t bri = 255/hw_random8(1, 3);
|
uint8_t bri = 255/hw_random8(1, 3);
|
||||||
@ -1899,52 +1893,76 @@ uint16_t mode_lightning(void) {
|
|||||||
}
|
}
|
||||||
static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!";
|
static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!";
|
||||||
|
|
||||||
|
// combined function from original pride and colorwaves
|
||||||
// Pride2015
|
uint16_t mode_colorwaves_pride_base(bool isPride2015) {
|
||||||
// Animated, ever-changing rainbows.
|
|
||||||
// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
|
|
||||||
uint16_t mode_pride_2015(void) {
|
|
||||||
unsigned duration = 10 + SEGMENT.speed;
|
unsigned duration = 10 + SEGMENT.speed;
|
||||||
unsigned sPseudotime = SEGENV.step;
|
unsigned sPseudotime = SEGENV.step;
|
||||||
unsigned sHue16 = SEGENV.aux0;
|
unsigned sHue16 = SEGENV.aux0;
|
||||||
|
|
||||||
uint8_t sat8 = beatsin88_t( 87, 220, 250);
|
uint8_t sat8 = isPride2015 ? beatsin88_t(87, 220, 250) : 255;
|
||||||
uint8_t brightdepth = beatsin88_t( 341, 96, 224);
|
unsigned brightdepth = beatsin88_t(341, 96, 224);
|
||||||
unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256));
|
unsigned brightnessthetainc16 = beatsin88_t(203, (25 * 256), (40 * 256));
|
||||||
unsigned msmultiplier = beatsin88_t(147, 23, 60);
|
unsigned msmultiplier = beatsin88_t(147, 23, 60);
|
||||||
|
|
||||||
unsigned hue16 = sHue16;//gHue * 256;
|
unsigned hue16 = sHue16;
|
||||||
unsigned hueinc16 = beatsin88_t(113, 1, 3000);
|
unsigned hueinc16 = isPride2015 ? beatsin88_t(113, 1, 3000) :
|
||||||
|
beatsin88_t(113, 60, 300) * SEGMENT.intensity * 10 / 255;
|
||||||
|
|
||||||
sPseudotime += duration * msmultiplier;
|
sPseudotime += duration * msmultiplier;
|
||||||
sHue16 += duration * beatsin88_t( 400, 5,9);
|
sHue16 += duration * beatsin88_t(400, 5, 9);
|
||||||
unsigned brightnesstheta16 = sPseudotime;
|
unsigned brightnesstheta16 = sPseudotime;
|
||||||
|
|
||||||
for (unsigned i = 0 ; i < SEGLEN; i++) {
|
for (unsigned i = 0; i < SEGLEN; i++) {
|
||||||
hue16 += hueinc16;
|
hue16 += hueinc16;
|
||||||
uint8_t hue8 = hue16 >> 8;
|
uint8_t hue8;
|
||||||
|
|
||||||
brightnesstheta16 += brightnessthetainc16;
|
if (isPride2015) {
|
||||||
unsigned b16 = sin16_t( brightnesstheta16 ) + 32768;
|
hue8 = hue16 >> 8;
|
||||||
|
} else {
|
||||||
|
unsigned h16_128 = hue16 >> 7;
|
||||||
|
hue8 = (h16_128 & 0x100) ? (255 - (h16_128 >> 1)) : (h16_128 >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
brightnesstheta16 += brightnessthetainc16;
|
||||||
|
unsigned b16 = sin16_t(brightnesstheta16) + 32768;
|
||||||
unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
|
unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
|
||||||
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
|
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
|
||||||
bri8 += (255 - brightdepth);
|
bri8 += (255 - brightdepth);
|
||||||
|
|
||||||
CRGB newcolor = CHSV(hue8, sat8, bri8);
|
if (isPride2015) {
|
||||||
SEGMENT.blendPixelColor(i, newcolor, 64);
|
CRGB newcolor = CHSV(hue8, sat8, bri8);
|
||||||
|
SEGMENT.blendPixelColor(i, newcolor, 64);
|
||||||
|
} else {
|
||||||
|
SEGMENT.blendPixelColor(i, SEGMENT.color_from_palette(hue8, false, PALETTE_SOLID_WRAP, 0, bri8), 128);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGENV.step = sPseudotime;
|
SEGENV.step = sPseudotime;
|
||||||
SEGENV.aux0 = sHue16;
|
SEGENV.aux0 = sHue16;
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pride2015
|
||||||
|
// Animated, ever-changing rainbows.
|
||||||
|
// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
|
||||||
|
uint16_t mode_pride_2015(void) {
|
||||||
|
return mode_colorwaves_pride_base(true);
|
||||||
|
}
|
||||||
static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
|
static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
|
||||||
|
|
||||||
|
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
||||||
|
// This function draws color waves with an ever-changing,
|
||||||
|
// widely-varying set of parameters, using a color palette.
|
||||||
|
uint16_t mode_colorwaves() {
|
||||||
|
return mode_colorwaves_pride_base(false);
|
||||||
|
}
|
||||||
|
static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!;;pal=26";
|
||||||
|
|
||||||
|
|
||||||
//eight colored dots, weaving in and out of sync with each other
|
//eight colored dots, weaving in and out of sync with each other
|
||||||
uint16_t mode_juggle(void) {
|
uint16_t mode_juggle(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
|
|
||||||
SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4));
|
SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4));
|
||||||
CRGB fastled_col;
|
CRGB fastled_col;
|
||||||
@ -2032,7 +2050,7 @@ uint16_t mode_palette() {
|
|||||||
const mathType sourceX = xtSinTheta + ytCosTheta + centerX;
|
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
|
// 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.
|
// 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:
|
// inputSize determines by how much we want to scale the palette:
|
||||||
// values < 128 display a fraction of a palette,
|
// values < 128 display a fraction of a palette,
|
||||||
// values > 128 display multiple palettes.
|
// values > 128 display multiple palettes.
|
||||||
@ -2089,7 +2107,7 @@ static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation
|
|||||||
// feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used
|
// feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used
|
||||||
// in step 3 above) (Effect Intensity = Sparking).
|
// in step 3 above) (Effect Intensity = Sparking).
|
||||||
uint16_t mode_fire_2012() {
|
uint16_t mode_fire_2012() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
const unsigned strips = SEGMENT.nrOfVStrips();
|
const unsigned strips = SEGMENT.nrOfVStrips();
|
||||||
if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed
|
||||||
byte* heat = SEGENV.data;
|
byte* heat = SEGENV.data;
|
||||||
@ -2147,53 +2165,6 @@ uint16_t mode_fire_2012() {
|
|||||||
}
|
}
|
||||||
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;pal=35,sx=64,ix=160,m12=1,c2=128"; // bars
|
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;pal=35,sx=64,ix=160,m12=1,c2=128"; // bars
|
||||||
|
|
||||||
|
|
||||||
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
|
||||||
// This function draws color waves with an ever-changing,
|
|
||||||
// widely-varying set of parameters, using a color palette.
|
|
||||||
uint16_t mode_colorwaves() {
|
|
||||||
unsigned duration = 10 + SEGMENT.speed;
|
|
||||||
unsigned sPseudotime = SEGENV.step;
|
|
||||||
unsigned sHue16 = SEGENV.aux0;
|
|
||||||
|
|
||||||
unsigned brightdepth = beatsin88_t(341, 96, 224);
|
|
||||||
unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256));
|
|
||||||
unsigned msmultiplier = beatsin88_t(147, 23, 60);
|
|
||||||
|
|
||||||
unsigned hue16 = sHue16;//gHue * 256;
|
|
||||||
unsigned hueinc16 = beatsin88_t(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues
|
|
||||||
|
|
||||||
sPseudotime += duration * msmultiplier;
|
|
||||||
sHue16 += duration * beatsin88_t(400, 5, 9);
|
|
||||||
unsigned brightnesstheta16 = sPseudotime;
|
|
||||||
|
|
||||||
for (unsigned i = 0 ; i < SEGLEN; i++) {
|
|
||||||
hue16 += hueinc16;
|
|
||||||
uint8_t hue8 = hue16 >> 8;
|
|
||||||
unsigned h16_128 = hue16 >> 7;
|
|
||||||
if ( h16_128 & 0x100) {
|
|
||||||
hue8 = 255 - (h16_128 >> 1);
|
|
||||||
} else {
|
|
||||||
hue8 = h16_128 >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
brightnesstheta16 += brightnessthetainc16;
|
|
||||||
unsigned b16 = sin16_t(brightnesstheta16) + 32768;
|
|
||||||
|
|
||||||
unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
|
|
||||||
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
|
|
||||||
bri8 += (255 - brightdepth);
|
|
||||||
|
|
||||||
SEGMENT.blendPixelColor(i, SEGMENT.color_from_palette(hue8, false, PALETTE_SOLID_WRAP, 0, bri8), 128); // 50/50 mix
|
|
||||||
}
|
|
||||||
SEGENV.step = sPseudotime;
|
|
||||||
SEGENV.aux0 = sHue16;
|
|
||||||
|
|
||||||
return FRAMETIME;
|
|
||||||
}
|
|
||||||
static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!;;pal=26";
|
|
||||||
|
|
||||||
|
|
||||||
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
|
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
|
||||||
uint16_t mode_bpm() {
|
uint16_t mode_bpm() {
|
||||||
uint32_t stp = (strip.now / 20) & 0xFF;
|
uint32_t stp = (strip.now / 20) & 0xFF;
|
||||||
@ -2369,7 +2340,7 @@ static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!";
|
|||||||
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
|
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
|
||||||
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
||||||
uint16_t mode_meteor() {
|
uint16_t mode_meteor() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||||
const bool meteorSmooth = SEGMENT.check3;
|
const bool meteorSmooth = SEGMENT.check3;
|
||||||
byte* trail = SEGENV.data;
|
byte* trail = SEGENV.data;
|
||||||
@ -2436,7 +2407,7 @@ static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient,,
|
|||||||
|
|
||||||
//Railway Crossing / Christmas Fairy lights
|
//Railway Crossing / Christmas Fairy lights
|
||||||
uint16_t mode_railway() {
|
uint16_t mode_railway() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned dur = (256 - SEGMENT.speed) * 40;
|
unsigned dur = (256 - SEGMENT.speed) * 40;
|
||||||
uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
|
uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
|
||||||
if (SEGENV.step > dur)
|
if (SEGENV.step > dur)
|
||||||
@ -2537,7 +2508,7 @@ static uint16_t ripple_base(uint8_t blurAmount = 0) {
|
|||||||
|
|
||||||
|
|
||||||
uint16_t mode_ripple(void) {
|
uint16_t mode_ripple(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
if(SEGMENT.custom1 || SEGMENT.check2) // blur or overlay
|
if(SEGMENT.custom1 || SEGMENT.check2) // blur or overlay
|
||||||
SEGMENT.fade_out(250);
|
SEGMENT.fade_out(250);
|
||||||
else
|
else
|
||||||
@ -2549,7 +2520,7 @@ static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Over
|
|||||||
|
|
||||||
|
|
||||||
uint16_t mode_ripple_rainbow(void) {
|
uint16_t mode_ripple_rainbow(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
if (SEGENV.call ==0) {
|
if (SEGENV.call ==0) {
|
||||||
SEGENV.aux0 = hw_random8();
|
SEGENV.aux0 = hw_random8();
|
||||||
SEGENV.aux1 = hw_random8();
|
SEGENV.aux1 = hw_random8();
|
||||||
@ -2727,7 +2698,7 @@ uint16_t mode_halloween_eyes()
|
|||||||
uint32_t blinkEndTime;
|
uint32_t blinkEndTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
const unsigned maxWidth = strip.isMatrix ? SEG_W : SEGLEN;
|
const unsigned maxWidth = strip.isMatrix ? SEG_W : SEGLEN;
|
||||||
const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEG_W>>4: SEGLEN>>5);
|
const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEG_W>>4: SEGLEN>>5);
|
||||||
const unsigned HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2;
|
const unsigned HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2;
|
||||||
@ -2912,7 +2883,7 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr
|
|||||||
|
|
||||||
static uint16_t spots_base(uint16_t threshold)
|
static uint16_t spots_base(uint16_t threshold)
|
||||||
{
|
{
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
unsigned maxZones = SEGLEN >> 2;
|
unsigned maxZones = SEGLEN >> 2;
|
||||||
@ -2968,7 +2939,7 @@ typedef struct Ball {
|
|||||||
* Bouncing Balls Effect
|
* Bouncing Balls Effect
|
||||||
*/
|
*/
|
||||||
uint16_t mode_bouncing_balls(void) {
|
uint16_t mode_bouncing_balls(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
const unsigned strips = SEGMENT.nrOfVStrips(); // adapt for 2D
|
const unsigned strips = SEGMENT.nrOfVStrips(); // adapt for 2D
|
||||||
const size_t maxNumBalls = 16;
|
const size_t maxNumBalls = 16;
|
||||||
@ -3146,7 +3117,7 @@ static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of b
|
|||||||
* Sinelon stolen from FASTLED examples
|
* Sinelon stolen from FASTLED examples
|
||||||
*/
|
*/
|
||||||
static uint16_t sinelon_base(bool dual, bool rainbow=false) {
|
static uint16_t sinelon_base(bool dual, bool rainbow=false) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
SEGMENT.fade_out(SEGMENT.intensity);
|
SEGMENT.fade_out(SEGMENT.intensity);
|
||||||
unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1);
|
unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1);
|
||||||
if (SEGENV.call == 0) SEGENV.aux0 = pos;
|
if (SEGENV.call == 0) SEGENV.aux0 = pos;
|
||||||
@ -3251,7 +3222,7 @@ typedef struct Spark {
|
|||||||
* modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h
|
* modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h
|
||||||
*/
|
*/
|
||||||
uint16_t mode_popcorn(void) {
|
uint16_t mode_popcorn(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
unsigned strips = SEGMENT.nrOfVStrips();
|
unsigned strips = SEGMENT.nrOfVStrips();
|
||||||
unsigned usablePopcorns = maxNumPopcorn;
|
unsigned usablePopcorns = maxNumPopcorn;
|
||||||
@ -3426,7 +3397,7 @@ typedef struct particle {
|
|||||||
} star;
|
} star;
|
||||||
|
|
||||||
uint16_t mode_starburst(void) {
|
uint16_t mode_starburst(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
|
unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
|
||||||
unsigned segs = strip.getActiveSegmentsNum();
|
unsigned segs = strip.getActiveSegmentsNum();
|
||||||
if (segs <= (strip.getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
|
if (segs <= (strip.getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
|
||||||
@ -3545,7 +3516,7 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc
|
|||||||
*/
|
*/
|
||||||
uint16_t mode_exploding_fireworks(void)
|
uint16_t mode_exploding_fireworks(void)
|
||||||
{
|
{
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
const int cols = SEGMENT.is2D() ? SEG_W : 1;
|
const int cols = SEGMENT.is2D() ? SEG_W : 1;
|
||||||
const int rows = SEGMENT.is2D() ? SEG_H : SEGLEN;
|
const int rows = SEGMENT.is2D() ? SEG_H : SEGLEN;
|
||||||
|
|
||||||
@ -3683,7 +3654,7 @@ static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gr
|
|||||||
*/
|
*/
|
||||||
uint16_t mode_drip(void)
|
uint16_t mode_drip(void)
|
||||||
{
|
{
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
//allocate segment data
|
//allocate segment data
|
||||||
unsigned strips = SEGMENT.nrOfVStrips();
|
unsigned strips = SEGMENT.nrOfVStrips();
|
||||||
const int maxNumDrops = 4;
|
const int maxNumDrops = 4;
|
||||||
@ -3779,7 +3750,7 @@ typedef struct Tetris {
|
|||||||
} tetris;
|
} tetris;
|
||||||
|
|
||||||
uint16_t mode_tetrix(void) {
|
uint16_t mode_tetrix(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned strips = SEGMENT.nrOfVStrips(); // allow running on virtual strips (columns in 2D segment)
|
unsigned strips = SEGMENT.nrOfVStrips(); // allow running on virtual strips (columns in 2D segment)
|
||||||
unsigned dataSize = sizeof(tetris);
|
unsigned dataSize = sizeof(tetris);
|
||||||
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
||||||
@ -3990,7 +3961,7 @@ static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;01;m1
|
|||||||
// Modified for WLED, based on https://github.com/FastLED/FastLED/blob/master/examples/Pacifica/Pacifica.ino
|
// Modified for WLED, based on https://github.com/FastLED/FastLED/blob/master/examples/Pacifica/Pacifica.ino
|
||||||
//
|
//
|
||||||
// Add one layer of waves into the led array
|
// Add one layer of waves into the led array
|
||||||
static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
|
static CRGB pacifica_one_layer(uint16_t i, const CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
|
||||||
{
|
{
|
||||||
unsigned ci = cistart;
|
unsigned ci = cistart;
|
||||||
unsigned waveangle = ioff;
|
unsigned waveangle = ioff;
|
||||||
@ -4086,7 +4057,7 @@ static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=5
|
|||||||
* Mode simulates a gradual sunrise
|
* Mode simulates a gradual sunrise
|
||||||
*/
|
*/
|
||||||
uint16_t mode_sunrise() {
|
uint16_t mode_sunrise() {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
//speed 0 - static sun
|
//speed 0 - static sun
|
||||||
//speed 1 - 60: sunrise time in minutes
|
//speed 1 - 60: sunrise time in minutes
|
||||||
//speed 60 - 120 : sunset time in minutes - 60;
|
//speed 60 - 120 : sunset time in minutes - 60;
|
||||||
@ -4293,7 +4264,7 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver
|
|||||||
*/
|
*/
|
||||||
uint16_t mode_chunchun(void)
|
uint16_t mode_chunchun(void)
|
||||||
{
|
{
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
SEGMENT.fade_out(254); // add a bit of trail
|
SEGMENT.fade_out(254); // add a bit of trail
|
||||||
unsigned counter = strip.now * (6 + (SEGMENT.speed >> 4));
|
unsigned counter = strip.now * (6 + (SEGMENT.speed >> 4));
|
||||||
unsigned numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
unsigned numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
||||||
@ -4344,7 +4315,7 @@ typedef struct Spotlight {
|
|||||||
*/
|
*/
|
||||||
uint16_t mode_dancing_shadows(void)
|
uint16_t mode_dancing_shadows(void)
|
||||||
{
|
{
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266
|
unsigned numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266
|
||||||
bool initialize = SEGENV.aux0 != numSpotlights;
|
bool initialize = SEGENV.aux0 != numSpotlights;
|
||||||
SEGENV.aux0 = numSpotlights;
|
SEGENV.aux0 = numSpotlights;
|
||||||
@ -4806,7 +4777,7 @@ static const char _data_FX_MODE_AURORA[] PROGMEM = "Aurora@!,!;1,2,3;!;;sx=24,pa
|
|||||||
// 16 bit perlinmove. Use Perlin Noise instead of sinewaves for movement. By Andrew Tuline.
|
// 16 bit perlinmove. Use Perlin Noise instead of sinewaves for movement. By Andrew Tuline.
|
||||||
// Controls are speed, # of pixels, faderate.
|
// Controls are speed, # of pixels, faderate.
|
||||||
uint16_t mode_perlinmove(void) {
|
uint16_t mode_perlinmove(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
SEGMENT.fade_out(255-SEGMENT.custom1);
|
SEGMENT.fade_out(255-SEGMENT.custom1);
|
||||||
for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) {
|
for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) {
|
||||||
unsigned locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise.
|
unsigned locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise.
|
||||||
@ -4842,7 +4813,7 @@ static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness vari
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
// By: ldirko https://editor.soulmatelights.com/gallery/392-flow-led-stripe , modifed by: Andrew Tuline
|
// By: ldirko https://editor.soulmatelights.com/gallery/392-flow-led-stripe , modifed by: Andrew Tuline
|
||||||
uint16_t mode_FlowStripe(void) {
|
uint16_t mode_FlowStripe(void) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
const int hl = SEGLEN * 10 / 13;
|
const int hl = SEGLEN * 10 / 13;
|
||||||
uint8_t hue = strip.now / (SEGMENT.speed+1);
|
uint8_t hue = strip.now / (SEGMENT.speed+1);
|
||||||
uint32_t t = strip.now / (SEGMENT.intensity/8+1);
|
uint32_t t = strip.now / (SEGMENT.intensity/8+1);
|
||||||
@ -5475,15 +5446,15 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have
|
|||||||
// and add them together with weightening
|
// and add them together with weightening
|
||||||
unsigned dx = abs(x - x1);
|
unsigned dx = abs(x - x1);
|
||||||
unsigned dy = abs(y - y1);
|
unsigned dy = abs(y - y1);
|
||||||
unsigned dist = 2 * sqrt16((dx * dx) + (dy * dy));
|
unsigned dist = 2 * sqrt32_bw((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
dx = abs(x - x2);
|
dx = abs(x - x2);
|
||||||
dy = abs(y - y2);
|
dy = abs(y - y2);
|
||||||
dist += sqrt16((dx * dx) + (dy * dy));
|
dist += sqrt32_bw((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
dx = abs(x - x3);
|
dx = abs(x - x3);
|
||||||
dy = abs(y - y3);
|
dy = abs(y - y3);
|
||||||
dist += sqrt16((dx * dx) + (dy * dy));
|
dist += sqrt32_bw((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
// inverse result
|
// inverse result
|
||||||
int color = dist ? 1000 / dist : 255;
|
int color = dist ? 1000 / dist : 255;
|
||||||
@ -6123,13 +6094,23 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
if (!strlen(text)) { // fallback if empty segment name: display date and time
|
if (!strlen(text)) { // fallback if empty segment name: display date and time
|
||||||
sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||||
} else {
|
} else {
|
||||||
|
if (text[0] == '#') for (auto &c : text) c = std::toupper(c);
|
||||||
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime));
|
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
|
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
||||||
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
|
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), AmPmHour);
|
else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf (text, zero? ("%02d") : ("%d"), AmPmHour);
|
||||||
else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), minute(localTime));
|
else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf (text, zero? ("%02d") : ("%d"), minute(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#SS"),3)) sprintf (text, ("%02d") , second(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DD"),3)) sprintf (text, zero? ("%02d") : ("%d"), day(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DAY"),4)) sprintf (text, ("%s") , dayShortStr(day(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DDDD"),5)) sprintf (text, ("%s") , dayStr(day(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MO"),3)) sprintf (text, zero? ("%02d") : ("%d"), month(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MON"),4)) sprintf (text, ("%s") , monthShortStr(month(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MMMM"),5)) sprintf (text, ("%s") , monthStr(month(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#YY"),3)) sprintf (text, ("%02d") , year(localTime)%100);
|
||||||
|
else if (!strncmp_P(text,PSTR("#YYYY"),5)) sprintf_P(text, zero?PSTR("%04d") : ("%d"), year(localTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
const int numberOfLetters = strlen(text);
|
const int numberOfLetters = strlen(text);
|
||||||
@ -6568,23 +6549,31 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!;
|
|||||||
// * MATRIPIX //
|
// * MATRIPIX //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
|
uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
|
||||||
if (SEGLEN == 1) return mode_static();
|
// effect can work on single pixels, we just lose the shifting effect
|
||||||
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
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();
|
um_data_t *um_data = getAudioData();
|
||||||
int volumeRaw = *(int16_t*)um_data->u_data[1];
|
int volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||||
|
|
||||||
if (SEGENV.call == 0) {
|
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;
|
uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16;
|
||||||
if(SEGENV.aux0 != secondHand) {
|
if(SEGENV.aux0 != secondHand) {
|
||||||
SEGENV.aux0 = secondHand;
|
SEGENV.aux0 = secondHand;
|
||||||
|
|
||||||
uint8_t pixBri = volumeRaw * SEGMENT.intensity / 64;
|
int pixBri = volumeRaw * SEGMENT.intensity / 64;
|
||||||
for (unsigned i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
|
unsigned k = SEGLEN-1;
|
||||||
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri));
|
// 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;
|
return FRAMETIME;
|
||||||
@ -6596,7 +6585,7 @@ static const char _data_FX_MODE_MATRIPIX[] PROGMEM = "Matripix@!,Brightness;!,!;
|
|||||||
// * MIDNOISE //
|
// * MIDNOISE //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
|
uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
// Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1.
|
// Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1.
|
||||||
|
|
||||||
um_data_t *um_data = getAudioData();
|
um_data_t *um_data = getAudioData();
|
||||||
@ -6687,7 +6676,7 @@ static const char _data_FX_MODE_NOISEMETER[] PROGMEM = "Noisemeter@Fade rate,Wid
|
|||||||
// * PIXELWAVE //
|
// * PIXELWAVE //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
|
uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
|
||||||
if (SEGLEN == 1) return mode_static();
|
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
|
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||||
|
|
||||||
if (SEGENV.call == 0) {
|
if (SEGENV.call == 0) {
|
||||||
@ -6755,7 +6744,7 @@ static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels
|
|||||||
//////////////////////
|
//////////////////////
|
||||||
// Puddles/Puddlepeak By Andrew Tuline. Merged by @dedehai
|
// Puddles/Puddlepeak By Andrew Tuline. Merged by @dedehai
|
||||||
uint16_t mode_puddles_base(bool peakdetect) {
|
uint16_t mode_puddles_base(bool peakdetect) {
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
|
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
|
||||||
unsigned pos = hw_random16(SEGLEN); // Set a random starting position.
|
unsigned pos = hw_random16(SEGLEN); // Set a random starting position.
|
||||||
@ -6805,7 +6794,7 @@ static const char _data_FX_MODE_PUDDLES[] PROGMEM = "Puddles@Fade rate,Puddle si
|
|||||||
// * PIXELS //
|
// * PIXELS //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
|
uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
|
|
||||||
if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed
|
||||||
uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low.
|
uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low.
|
||||||
@ -6833,7 +6822,7 @@ static const char _data_FX_MODE_PIXELS[] PROGMEM = "Pixels@Fade rate,# of pixels
|
|||||||
// ** Blurz //
|
// ** Blurz //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
|
uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
|
||||||
if (SEGLEN == 1) return mode_static();
|
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
|
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||||
|
|
||||||
um_data_t *um_data = getAudioData();
|
um_data_t *um_data = getAudioData();
|
||||||
@ -6897,7 +6886,7 @@ static const char _data_FX_MODE_DJLIGHT[] PROGMEM = "DJ Light@Speed;;;01f;m12=2,
|
|||||||
// ** Freqmap //
|
// ** Freqmap //
|
||||||
////////////////////
|
////////////////////
|
||||||
uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. Would be better if a higher framerate.
|
uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. Would be better if a higher framerate.
|
||||||
if (SEGLEN == 1) return mode_static();
|
if (SEGLEN <= 1) return mode_static();
|
||||||
// Start frequency = 60 Hz and log10(60) = 1.78
|
// Start frequency = 60 Hz and log10(60) = 1.78
|
||||||
// End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10
|
// End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10
|
||||||
|
|
||||||
@ -7139,8 +7128,11 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12=
|
|||||||
// Combines peak detection with FFT_MajorPeak and FFT_Magnitude.
|
// Combines peak detection with FFT_MajorPeak and FFT_Magnitude.
|
||||||
uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline
|
uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline
|
||||||
// effect can work on single pixels, we just lose the shifting effect
|
// 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();
|
um_data_t *um_data = getAudioData();
|
||||||
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
||||||
float FFT_MajorPeak = *(float*) um_data->u_data[4];
|
float FFT_MajorPeak = *(float*) um_data->u_data[4];
|
||||||
uint8_t *maxVol = (uint8_t*)um_data->u_data[6];
|
uint8_t *maxVol = (uint8_t*)um_data->u_data[6];
|
||||||
@ -7150,7 +7142,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
|
|||||||
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
|
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
|
||||||
|
|
||||||
if (SEGENV.call == 0) {
|
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;
|
SEGENV.aux0 = 255;
|
||||||
SEGMENT.custom1 = *binNum;
|
SEGMENT.custom1 = *binNum;
|
||||||
SEGMENT.custom2 = *maxVol * 2;
|
SEGMENT.custom2 = *maxVol * 2;
|
||||||
@ -7167,13 +7159,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.
|
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
|
if (FFT_MajorPeak < 182.0f) pixCol = 0; // handle underflow
|
||||||
|
|
||||||
|
unsigned k = SEGLEN-1;
|
||||||
if (samplePeak) {
|
if (samplePeak) {
|
||||||
SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92));
|
pixels[k] = (uint32_t)CRGB(CHSV(92,92,92));
|
||||||
} else {
|
} else {
|
||||||
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (uint8_t)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
|
// loop will not execute if SEGLEN equals 1
|
||||||
for (unsigned 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;
|
return FRAMETIME;
|
||||||
|
113
wled00/FX.h
113
wled00/FX.h
@ -79,9 +79,9 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
|
|||||||
#define MAX_NUM_SEGMENTS 32
|
#define MAX_NUM_SEGMENTS 32
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default (S2 is short on free RAM)
|
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM)
|
||||||
#else
|
#else
|
||||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default
|
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -325,6 +325,30 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
|
|||||||
|
|
||||||
#define MODE_COUNT 187
|
#define MODE_COUNT 187
|
||||||
|
|
||||||
|
|
||||||
|
#define BLEND_STYLE_FADE 0x00 // universal
|
||||||
|
#define BLEND_STYLE_FAIRY_DUST 0x01 // universal
|
||||||
|
#define BLEND_STYLE_SWIPE_RIGHT 0x02 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_SWIPE_LEFT 0x03 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_PINCH_OUT 0x04 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_INSIDE_OUT 0x05 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_SWIPE_UP 0x06 // 2D
|
||||||
|
#define BLEND_STYLE_SWIPE_DOWN 0x07 // 2D
|
||||||
|
#define BLEND_STYLE_OPEN_H 0x08 // 2D
|
||||||
|
#define BLEND_STYLE_OPEN_V 0x09 // 2D
|
||||||
|
// as there are many push variants to optimise if statements they are groupped together
|
||||||
|
#define BLEND_STYLE_PUSH_RIGHT 0x10 // 1D or 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_LEFT 0x11 // 1D or 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_UP 0x12 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_DOWN 0x13 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_TL 0x14 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_TR 0x15 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_BR 0x16 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_BL 0x17 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_MASK 0x10
|
||||||
|
#define BLEND_STYLE_COUNT 18
|
||||||
|
|
||||||
|
|
||||||
typedef enum mapping1D2D {
|
typedef enum mapping1D2D {
|
||||||
M12_Pixels = 0,
|
M12_Pixels = 0,
|
||||||
M12_pBar = 1,
|
M12_pBar = 1,
|
||||||
@ -333,7 +357,7 @@ typedef enum mapping1D2D {
|
|||||||
M12_sPinwheel = 4
|
M12_sPinwheel = 4
|
||||||
} mapping1D2D_t;
|
} mapping1D2D_t;
|
||||||
|
|
||||||
// segment, 80 bytes
|
// segment, 68 bytes
|
||||||
typedef struct Segment {
|
typedef struct Segment {
|
||||||
public:
|
public:
|
||||||
uint16_t start; // start index / start X coordinate 2D (left)
|
uint16_t start; // start index / start X coordinate 2D (left)
|
||||||
@ -436,6 +460,9 @@ typedef struct Segment {
|
|||||||
static uint16_t _transitionprogress; // current transition progress 0 - 0xFFFF
|
static uint16_t _transitionprogress; // current transition progress 0 - 0xFFFF
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
static bool _modeBlend; // mode/effect blending semaphore
|
static bool _modeBlend; // mode/effect blending semaphore
|
||||||
|
// clipping
|
||||||
|
static uint16_t _clipStart, _clipStop;
|
||||||
|
static uint8_t _clipStartY, _clipStopY;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
|
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
|
||||||
@ -446,6 +473,7 @@ typedef struct Segment {
|
|||||||
#else
|
#else
|
||||||
uint32_t _colorT[NUM_COLORS];
|
uint32_t _colorT[NUM_COLORS];
|
||||||
#endif
|
#endif
|
||||||
|
uint8_t _palTid; // previous palette
|
||||||
uint8_t _briT; // temporary brightness
|
uint8_t _briT; // temporary brightness
|
||||||
uint8_t _cctT; // temporary CCT
|
uint8_t _cctT; // temporary CCT
|
||||||
CRGBPalette16 _palT; // temporary palette
|
CRGBPalette16 _palT; // temporary palette
|
||||||
@ -460,7 +488,7 @@ typedef struct Segment {
|
|||||||
{}
|
{}
|
||||||
} *_t;
|
} *_t;
|
||||||
|
|
||||||
[[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col); // set pixel without mapping (internal use only)
|
[[gnu::hot]] void _setPixelColorXY_raw(const int& x, const int& y, uint32_t& col) const; // set pixel without mapping (internal use only)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -518,7 +546,7 @@ typedef struct Segment {
|
|||||||
//if (data) Serial.printf(" %d->(%p)", (int)_dataLen, data);
|
//if (data) Serial.printf(" %d->(%p)", (int)_dataLen, data);
|
||||||
//Serial.println();
|
//Serial.println();
|
||||||
#endif
|
#endif
|
||||||
if (name) { delete[] name; name = nullptr; }
|
if (name) { free(name); name = nullptr; }
|
||||||
stopTransition();
|
stopTransition();
|
||||||
deallocateData();
|
deallocateData();
|
||||||
}
|
}
|
||||||
@ -534,7 +562,6 @@ typedef struct Segment {
|
|||||||
inline bool isSelected() const { return selected; }
|
inline bool isSelected() const { return selected; }
|
||||||
inline bool isInTransition() const { return _t != nullptr; }
|
inline bool isInTransition() const { return _t != nullptr; }
|
||||||
inline bool isActive() const { return stop > start; }
|
inline bool isActive() const { return stop > start; }
|
||||||
inline bool is2D() const { return (width()>1 && height()>1); }
|
|
||||||
inline bool hasRGB() const { return _isRGB; }
|
inline bool hasRGB() const { return _isRGB; }
|
||||||
inline bool hasWhite() const { return _hasW; }
|
inline bool hasWhite() const { return _hasW; }
|
||||||
inline bool isCCT() const { return _isCCT; }
|
inline bool isCCT() const { return _isCCT; }
|
||||||
@ -588,10 +615,10 @@ typedef struct Segment {
|
|||||||
inline void handleTransition() { updateTransitionProgress(); if (progress() == 0xFFFFU) stopTransition(); }
|
inline void handleTransition() { updateTransitionProgress(); if (progress() == 0xFFFFU) stopTransition(); }
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer
|
void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer
|
||||||
void restoreSegenv(tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer
|
void restoreSegenv(const tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer
|
||||||
#endif
|
#endif
|
||||||
[[gnu::hot]] void updateTransitionProgress(); // set current progression of transition
|
[[gnu::hot]] void updateTransitionProgress(); // set current progression of transition
|
||||||
inline uint16_t progress() const { return _transitionprogress; }; // transition progression between 0-65535
|
inline uint16_t progress() const { return Segment::_transitionprogress; } // transition progression between 0-65535
|
||||||
[[gnu::hot]] uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition)
|
[[gnu::hot]] uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition)
|
||||||
uint8_t currentMode() const; // currently active effect/mode (while in transition)
|
uint8_t currentMode() const; // currently active effect/mode (while in transition)
|
||||||
[[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
|
[[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
|
||||||
@ -599,15 +626,19 @@ typedef struct Segment {
|
|||||||
|
|
||||||
// 1D strip
|
// 1D strip
|
||||||
[[gnu::hot]] uint16_t virtualLength() const;
|
[[gnu::hot]] uint16_t virtualLength() const;
|
||||||
[[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
|
[[gnu::hot]] void setPixelColor(int i, uint32_t c) const; // set relative pixel within segment with color
|
||||||
inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); }
|
inline void setPixelColor(unsigned n, uint32_t c) const { setPixelColor(int(n), c); }
|
||||||
inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||||
inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); }
|
inline void setPixelColor(int n, CRGB c) const { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); }
|
||||||
#ifdef WLED_USE_AA_PIXELS
|
#ifdef WLED_USE_AA_PIXELS
|
||||||
void setPixelColor(float i, uint32_t c, bool aa = true);
|
void setPixelColor(float i, uint32_t c, bool aa = true) const;
|
||||||
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) const { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
||||||
inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
static inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; };
|
||||||
|
#endif
|
||||||
|
bool isPixelClipped(int i) const;
|
||||||
[[gnu::hot]] uint32_t getPixelColor(int i) const;
|
[[gnu::hot]] uint32_t getPixelColor(int i) const;
|
||||||
// 1D support functions (some implement 2D as well)
|
// 1D support functions (some implement 2D as well)
|
||||||
void blur(uint8_t, bool smear = false);
|
void blur(uint8_t, bool smear = false);
|
||||||
@ -642,17 +673,19 @@ typedef struct Segment {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
[[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment
|
inline bool is2D() const { return (width()>1 && height()>1); }
|
||||||
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
[[gnu::hot]] int XY(int x, int y) const; // support function to get relative index within segment
|
||||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); }
|
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c) const; // set relative pixel within segment with color
|
||||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) const { setPixelColorXY(int(x), int(y), c); }
|
||||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||||
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); }
|
inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||||
|
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) const { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); }
|
||||||
#ifdef WLED_USE_AA_PIXELS
|
#ifdef WLED_USE_AA_PIXELS
|
||||||
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true);
|
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) const;
|
||||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
|
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
|
||||||
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
|
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||||
#endif
|
#endif
|
||||||
|
[[gnu::hot]] bool isPixelXYClipped(int x, int y) const;
|
||||||
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
|
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
|
||||||
// 2D support functions
|
// 2D support functions
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
||||||
@ -678,7 +711,8 @@ typedef struct Segment {
|
|||||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||||
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
||||||
#else
|
#else
|
||||||
inline uint16_t XY(int x, int y) { return x; }
|
inline constexpr bool is2D() const { return false; }
|
||||||
|
inline int XY(int x, int y) const { return x; }
|
||||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
|
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
|
||||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
|
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
|
||||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
|
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
|
||||||
@ -689,6 +723,7 @@ typedef struct Segment {
|
|||||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
|
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
|
||||||
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
|
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||||
#endif
|
#endif
|
||||||
|
inline bool isPixelXYClipped(int x, int y) { return isPixelClipped(x); }
|
||||||
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||||
@ -733,9 +768,7 @@ class WS2812FX { // 96 bytes
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
WS2812FX() :
|
WS2812FX() :
|
||||||
paletteFade(0),
|
|
||||||
paletteBlend(0),
|
paletteBlend(0),
|
||||||
cctBlending(0),
|
|
||||||
now(millis()),
|
now(millis()),
|
||||||
timebase(0),
|
timebase(0),
|
||||||
isMatrix(false),
|
isMatrix(false),
|
||||||
@ -778,7 +811,7 @@ class WS2812FX { // 96 bytes
|
|||||||
}
|
}
|
||||||
|
|
||||||
~WS2812FX() {
|
~WS2812FX() {
|
||||||
if (customMappingTable) delete[] customMappingTable;
|
if (customMappingTable) free(customMappingTable);
|
||||||
_mode.clear();
|
_mode.clear();
|
||||||
_modeData.clear();
|
_modeData.clear();
|
||||||
_segments.clear();
|
_segments.clear();
|
||||||
@ -804,7 +837,7 @@ class WS2812FX { // 96 bytes
|
|||||||
resetSegments(), // marks all segments for reset
|
resetSegments(), // marks all segments for reset
|
||||||
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
||||||
fixInvalidSegments(), // fixes incorrect segment configuration
|
fixInvalidSegments(), // fixes incorrect segment configuration
|
||||||
setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c
|
setPixelColor(unsigned i, uint32_t c) const, // paints absolute strip pixel with index n and color c
|
||||||
show(), // initiates LED output
|
show(), // initiates LED output
|
||||||
setTargetFps(unsigned fps),
|
setTargetFps(unsigned fps),
|
||||||
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
||||||
@ -812,9 +845,9 @@ class WS2812FX { // 96 bytes
|
|||||||
inline void resetTimebase() { timebase = 0UL - millis(); }
|
inline void resetTimebase() { timebase = 0UL - millis(); }
|
||||||
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
|
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
|
||||||
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
||||||
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||||
inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
|
inline void setPixelColor(unsigned n, CRGB c) const { setPixelColor(n, c.red, c.green, c.blue); }
|
||||||
inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
inline void fill(uint32_t c) const { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||||
inline void trigger() { _triggered = true; } // Forces the next frame to be computed on all active segments.
|
inline void trigger() { _triggered = true; } // Forces the next frame to be computed on all active segments.
|
||||||
inline void setShowCallback(show_callback cb) { _callback = cb; }
|
inline void setShowCallback(show_callback cb) { _callback = cb; }
|
||||||
inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
|
inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
|
||||||
@ -823,8 +856,7 @@ class WS2812FX { // 96 bytes
|
|||||||
inline void resume() { _suspend = false; } // will resume strip.service() execution
|
inline void resume() { _suspend = false; } // will resume strip.service() execution
|
||||||
|
|
||||||
bool
|
bool
|
||||||
paletteFade,
|
checkSegmentAlignment() const,
|
||||||
checkSegmentAlignment(),
|
|
||||||
hasRGBWBus() const,
|
hasRGBWBus() const,
|
||||||
hasCCTBus() const,
|
hasCCTBus() const,
|
||||||
deserializeMap(unsigned n = 0);
|
deserializeMap(unsigned n = 0);
|
||||||
@ -838,7 +870,6 @@ class WS2812FX { // 96 bytes
|
|||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
paletteBlend,
|
paletteBlend,
|
||||||
cctBlending,
|
|
||||||
getActiveSegmentsNum() const,
|
getActiveSegmentsNum() const,
|
||||||
getFirstSelectedSegId() const,
|
getFirstSelectedSegId() const,
|
||||||
getLastActiveSegmentId() const,
|
getLastActiveSegmentId() const,
|
||||||
@ -869,7 +900,7 @@ class WS2812FX { // 96 bytes
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned long now, timebase;
|
unsigned long now, timebase;
|
||||||
uint32_t getPixelColor(unsigned) const;
|
uint32_t getPixelColor(unsigned i) const;
|
||||||
|
|
||||||
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||||
|
|
||||||
@ -918,11 +949,11 @@ class WS2812FX { // 96 bytes
|
|||||||
void setUpMatrix(); // sets up automatic matrix ledmap from panel configuration
|
void setUpMatrix(); // sets up automatic matrix ledmap from panel configuration
|
||||||
|
|
||||||
// outsmart the compiler :) by correctly overloading
|
// outsmart the compiler :) by correctly overloading
|
||||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor((unsigned)(y * Segment::maxWidth + x), c); }
|
inline void setPixelColorXY(int x, int y, uint32_t c) const { setPixelColor((unsigned)(y * Segment::maxWidth + x), c); }
|
||||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||||
|
|
||||||
inline uint32_t getPixelColorXY(int x, int y) const { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x); }
|
inline uint32_t getPixelColorXY(int x, int y) const { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x); }
|
||||||
|
|
||||||
// end 2D support
|
// end 2D support
|
||||||
|
|
||||||
@ -936,7 +967,7 @@ class WS2812FX { // 96 bytes
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<segment> _segments;
|
std::vector<segment> _segments;
|
||||||
friend class Segment;
|
friend struct Segment;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
volatile bool _suspend;
|
volatile bool _suspend;
|
||||||
|
@ -50,8 +50,8 @@ void WS2812FX::setUpMatrix() {
|
|||||||
|
|
||||||
customMappingSize = 0; // prevent use of mapping if anything goes wrong
|
customMappingSize = 0; // prevent use of mapping if anything goes wrong
|
||||||
|
|
||||||
if (customMappingTable) delete[] customMappingTable;
|
if (customMappingTable) free(customMappingTable);
|
||||||
customMappingTable = new uint16_t[getLengthTotal()];
|
customMappingTable = static_cast<uint16_t*>(malloc(sizeof(uint16_t)*getLengthTotal()));
|
||||||
|
|
||||||
if (customMappingTable) {
|
if (customMappingTable) {
|
||||||
customMappingSize = getLengthTotal();
|
customMappingSize = getLengthTotal();
|
||||||
@ -68,7 +68,7 @@ void WS2812FX::setUpMatrix() {
|
|||||||
// content of the file is just raw JSON array in the form of [val1,val2,val3,...]
|
// content of the file is just raw JSON array in the form of [val1,val2,val3,...]
|
||||||
// there are no other "key":"value" pairs in it
|
// there are no other "key":"value" pairs in it
|
||||||
// allowed values are: -1 (missing pixel/no LED attached), 0 (inactive/unused pixel), 1 (active/used pixel)
|
// allowed values are: -1 (missing pixel/no LED attached), 0 (inactive/unused pixel), 1 (active/used pixel)
|
||||||
char fileName[32]; strcpy_P(fileName, PSTR("/2d-gaps.json")); // reduce flash footprint
|
char fileName[32]; strcpy_P(fileName, PSTR("/2d-gaps.json"));
|
||||||
bool isFile = WLED_FS.exists(fileName);
|
bool isFile = WLED_FS.exists(fileName);
|
||||||
size_t gapSize = 0;
|
size_t gapSize = 0;
|
||||||
int8_t *gapTable = nullptr;
|
int8_t *gapTable = nullptr;
|
||||||
@ -85,7 +85,7 @@ void WS2812FX::setUpMatrix() {
|
|||||||
JsonArray map = pDoc->as<JsonArray>();
|
JsonArray map = pDoc->as<JsonArray>();
|
||||||
gapSize = map.size();
|
gapSize = map.size();
|
||||||
if (!map.isNull() && gapSize >= matrixSize) { // not an empty map
|
if (!map.isNull() && gapSize >= matrixSize) { // not an empty map
|
||||||
gapTable = new int8_t[gapSize];
|
gapTable = static_cast<int8_t*>(malloc(gapSize));
|
||||||
if (gapTable) for (size_t i = 0; i < gapSize; i++) {
|
if (gapTable) for (size_t i = 0; i < gapSize; i++) {
|
||||||
gapTable[i] = constrain(map[i], -1, 1);
|
gapTable[i] = constrain(map[i], -1, 1);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ void WS2812FX::setUpMatrix() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete gap array as we no longer need it
|
// delete gap array as we no longer need it
|
||||||
if (gapTable) delete[] gapTable;
|
if (gapTable) free(gapTable);
|
||||||
|
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("Matrix ledmap:"));
|
DEBUG_PRINT(F("Matrix ledmap:"));
|
||||||
@ -146,7 +146,7 @@ void WS2812FX::setUpMatrix() {
|
|||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
|
|
||||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||||
uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
int IRAM_ATTR_YN Segment::XY(int x, int y) const
|
||||||
{
|
{
|
||||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
@ -154,13 +154,13 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// raw setColor function without checks (checks are done in setPixelColorXY())
|
// raw setColor function without checks (checks are done in setPixelColorXY())
|
||||||
void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col)
|
void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint32_t& col) const
|
||||||
{
|
{
|
||||||
const int baseX = start + x;
|
const int baseX = start + x;
|
||||||
const int baseY = startY + y;
|
const int baseY = startY + y;
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
// if blending modes, blend with underlying pixel
|
// if blending modes, blend with underlying pixel
|
||||||
if (_modeBlend) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
|
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColorXY(baseX, baseY, col);
|
strip.setPixelColorXY(baseX, baseY, col);
|
||||||
|
|
||||||
@ -179,14 +179,57 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false)
|
||||||
|
// if clipping start > stop the clipping range is inverted
|
||||||
|
// _modeBlend==true -> old effect during transition
|
||||||
|
// _modeBlend==false -> new effect during transition
|
||||||
|
bool IRAM_ATTR_YN Segment::isPixelXYClipped(int x, int y) const {
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
if (_clipStart != _clipStop && blendingStyle != BLEND_STYLE_FADE) {
|
||||||
|
const bool invertX = _clipStart > _clipStop;
|
||||||
|
const bool invertY = _clipStartY > _clipStopY;
|
||||||
|
const int startX = invertX ? _clipStop : _clipStart;
|
||||||
|
const int stopX = invertX ? _clipStart : _clipStop;
|
||||||
|
const int startY = invertY ? _clipStopY : _clipStartY;
|
||||||
|
const int stopY = invertY ? _clipStartY : _clipStopY;
|
||||||
|
if (blendingStyle == BLEND_STYLE_FAIRY_DUST) {
|
||||||
|
const unsigned width = stopX - startX; // assumes full segment width (faster than virtualWidth())
|
||||||
|
const unsigned len = width * (stopY - startY); // assumes full segment height (faster than virtualHeight())
|
||||||
|
if (len < 2) return false;
|
||||||
|
const unsigned shuffled = hashInt(x + y * width) % len;
|
||||||
|
const unsigned pos = (shuffled * 0xFFFFU) / len;
|
||||||
|
return progress() > pos;
|
||||||
|
}
|
||||||
|
bool xInside = (x >= startX && x < stopX); if (invertX) xInside = !xInside;
|
||||||
|
bool yInside = (y >= startY && y < stopY); if (invertY) yInside = !yInside;
|
||||||
|
const bool clip = (invertX && invertY) ? !_modeBlend : _modeBlend;
|
||||||
|
if (xInside && yInside) return clip; // covers window & corners (inverted)
|
||||||
|
return !clip;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const
|
||||||
{
|
{
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
|
|
||||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
// negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH
|
|
||||||
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
if (!prog && !_modeBlend && (blendingStyle & BLEND_STYLE_PUSH_MASK)) {
|
||||||
|
unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF;
|
||||||
|
unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x += dX;
|
||||||
|
else x -= dX;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY;
|
||||||
|
else y += dY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (x >= vW || y >= vH || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit
|
||||||
|
|
||||||
// if color is unscaled
|
// if color is unscaled
|
||||||
if (!_colorScaled) col = color_fade(col, _segBri);
|
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||||
@ -215,7 +258,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
|||||||
|
|
||||||
#ifdef WLED_USE_AA_PIXELS
|
#ifdef WLED_USE_AA_PIXELS
|
||||||
// anti-aliased version of setPixelColorXY()
|
// anti-aliased version of setPixelColorXY()
|
||||||
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) const
|
||||||
{
|
{
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||||
@ -259,9 +302,24 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
|||||||
// returns RGBW values of pixel
|
// returns RGBW values of pixel
|
||||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||||
if (!isActive()) return 0; // not active
|
if (!isActive()) return 0; // not active
|
||||||
|
|
||||||
const int vW = vWidth();
|
const int vW = vWidth();
|
||||||
const int vH = vHeight();
|
const int vH = vHeight();
|
||||||
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit
|
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
if (!prog && !_modeBlend && (blendingStyle & BLEND_STYLE_PUSH_MASK)) {
|
||||||
|
unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF;
|
||||||
|
unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x -= dX;
|
||||||
|
else x += dX;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY;
|
||||||
|
else y += dY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (x >= vW || y >= vH || x<0 || y<0 || isPixelXYClipped(x,y)) return 0; // if pixel would fall out of virtual segment just exit
|
||||||
|
|
||||||
if (reverse ) x = vW - x - 1;
|
if (reverse ) x = vW - x - 1;
|
||||||
if (reverse_y) y = vH - y - 1;
|
if (reverse_y) y = vH - y - 1;
|
||||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||||
@ -276,7 +334,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) {
|
|||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
const unsigned cols = vWidth();
|
const unsigned cols = vWidth();
|
||||||
const unsigned rows = vHeight();
|
const unsigned rows = vHeight();
|
||||||
uint32_t lastnew;
|
uint32_t lastnew; // not necessary to initialize lastnew and last, as both will be initialized by the first loop iteration
|
||||||
uint32_t last;
|
uint32_t last;
|
||||||
if (blur_x) {
|
if (blur_x) {
|
||||||
const uint8_t keepx = smear ? 255 : 255 - blur_x;
|
const uint8_t keepx = smear ? 255 : 255 - blur_x;
|
||||||
|
@ -84,6 +84,10 @@ uint16_t Segment::_transitionprogress = 0xFFFF;
|
|||||||
|
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
bool Segment::_modeBlend = false;
|
bool Segment::_modeBlend = false;
|
||||||
|
uint16_t Segment::_clipStart = 0;
|
||||||
|
uint16_t Segment::_clipStop = 0;
|
||||||
|
uint8_t Segment::_clipStartY = 0;
|
||||||
|
uint8_t Segment::_clipStopY = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// copy constructor
|
// copy constructor
|
||||||
@ -94,7 +98,7 @@ Segment::Segment(const Segment &orig) {
|
|||||||
name = nullptr;
|
name = nullptr;
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
_dataLen = 0;
|
_dataLen = 0;
|
||||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
if (orig.name) { name = static_cast<char*>(malloc(strlen(orig.name)+1)); if (name) strcpy(name, orig.name); }
|
||||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +117,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
|||||||
//DEBUG_PRINTF_P(PSTR("-- Copying segment: %p -> %p\n"), &orig, this);
|
//DEBUG_PRINTF_P(PSTR("-- Copying segment: %p -> %p\n"), &orig, this);
|
||||||
if (this != &orig) {
|
if (this != &orig) {
|
||||||
// clean destination
|
// clean destination
|
||||||
if (name) { delete[] name; name = nullptr; }
|
if (name) { free(name); name = nullptr; }
|
||||||
stopTransition();
|
stopTransition();
|
||||||
deallocateData();
|
deallocateData();
|
||||||
// copy source
|
// copy source
|
||||||
@ -122,7 +126,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
|||||||
data = nullptr;
|
data = nullptr;
|
||||||
_dataLen = 0;
|
_dataLen = 0;
|
||||||
// copy source data
|
// copy source data
|
||||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
if (orig.name) { name = static_cast<char*>(malloc(strlen(orig.name)+1)); if (name) strcpy(name, orig.name); }
|
||||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@ -132,7 +136,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
|||||||
Segment& Segment::operator= (Segment &&orig) noexcept {
|
Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Moving segment: %p -> %p\n"), &orig, this);
|
//DEBUG_PRINTF_P(PSTR("-- Moving segment: %p -> %p\n"), &orig, this);
|
||||||
if (this != &orig) {
|
if (this != &orig) {
|
||||||
if (name) { delete[] name; name = nullptr; } // free old name
|
if (name) { free(name); name = nullptr; } // free old name
|
||||||
stopTransition();
|
stopTransition();
|
||||||
deallocateData(); // free old runtime data
|
deallocateData(); // free old runtime data
|
||||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||||
@ -253,29 +257,26 @@ void Segment::startTransition(uint16_t dur) {
|
|||||||
if (isInTransition()) return; // already in transition no need to store anything
|
if (isInTransition()) return; // already in transition no need to store anything
|
||||||
|
|
||||||
// starting a transition has to occur before change so we get current values 1st
|
// starting a transition has to occur before change so we get current values 1st
|
||||||
_t = new Transition(dur); // no previous transition running
|
_t = new(std::nothrow) Transition(dur); // no previous transition running
|
||||||
if (!_t) return; // failed to allocate data
|
if (!_t) return; // failed to allocate data
|
||||||
|
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t);
|
//DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t);
|
||||||
loadPalette(_t->_palT, palette);
|
loadPalette(_t->_palT, palette);
|
||||||
|
_t->_palTid = palette;
|
||||||
_t->_briT = on ? opacity : 0;
|
_t->_briT = on ? opacity : 0;
|
||||||
_t->_cctT = cct;
|
_t->_cctT = cct;
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending) {
|
swapSegenv(_t->_segT);
|
||||||
swapSegenv(_t->_segT);
|
_t->_modeT = mode;
|
||||||
_t->_modeT = mode;
|
_t->_segT._dataLenT = 0;
|
||||||
_t->_segT._dataLenT = 0;
|
_t->_segT._dataT = nullptr;
|
||||||
_t->_segT._dataT = nullptr;
|
if (_dataLen > 0 && data) {
|
||||||
if (_dataLen > 0 && data) {
|
_t->_segT._dataT = (byte *)malloc(_dataLen);
|
||||||
_t->_segT._dataT = (byte *)malloc(_dataLen);
|
if (_t->_segT._dataT) {
|
||||||
if (_t->_segT._dataT) {
|
//DEBUG_PRINTF_P(PSTR("-- Allocated duplicate data (%d) for %p: %p\n"), _dataLen, this, _t->_segT._dataT);
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Allocated duplicate data (%d) for %p: %p\n"), _dataLen, this, _t->_segT._dataT);
|
memcpy(_t->_segT._dataT, data, _dataLen);
|
||||||
memcpy(_t->_segT._dataT, data, _dataLen);
|
_t->_segT._dataLenT = _dataLen;
|
||||||
_t->_segT._dataLenT = _dataLen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_segT._colorT[i] = colors[i];
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
||||||
@ -296,6 +297,7 @@ void Segment::stopTransition() {
|
|||||||
delete _t;
|
delete _t;
|
||||||
_t = nullptr;
|
_t = nullptr;
|
||||||
}
|
}
|
||||||
|
_transitionprogress = 0xFFFFU; // stop means stop - transition has ended
|
||||||
}
|
}
|
||||||
|
|
||||||
// transition progression between 0-65535
|
// transition progression between 0-65535
|
||||||
@ -326,7 +328,7 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
|
|||||||
tmpSeg._callT = call;
|
tmpSeg._callT = call;
|
||||||
tmpSeg._dataT = data;
|
tmpSeg._dataT = data;
|
||||||
tmpSeg._dataLenT = _dataLen;
|
tmpSeg._dataLenT = _dataLen;
|
||||||
if (_t && &tmpSeg != &(_t->_segT)) {
|
if (isInTransition() && &tmpSeg != &(_t->_segT)) {
|
||||||
// swap SEGENV with transitional data
|
// swap SEGENV with transitional data
|
||||||
options = _t->_segT._optionsT;
|
options = _t->_segT._optionsT;
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = _t->_segT._colorT[i];
|
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = _t->_segT._colorT[i];
|
||||||
@ -347,9 +349,9 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) {
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Restoring temp seg: %p->(%p) [%d->%p]\n"), &tmpSeg, this, _dataLen, data);
|
//DEBUG_PRINTF_P(PSTR("-- Restoring temp seg: %p->(%p) [%d->%p]\n"), &tmpSeg, this, _dataLen, data);
|
||||||
if (_t && &(_t->_segT) != &tmpSeg) {
|
if (isInTransition() && &(_t->_segT) != &tmpSeg) {
|
||||||
// update possibly changed variables to keep old effect running correctly
|
// update possibly changed variables to keep old effect running correctly
|
||||||
_t->_segT._aux0T = aux0;
|
_t->_segT._aux0T = aux0;
|
||||||
_t->_segT._aux1T = aux1;
|
_t->_segT._aux1T = aux1;
|
||||||
@ -379,29 +381,53 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t Segment::currentBri(bool useCct) const {
|
uint8_t Segment::currentBri(bool useCct) const {
|
||||||
unsigned prog = progress();
|
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
||||||
|
uint32_t curBri = useCct ? cct : (on ? opacity : 0);
|
||||||
if (prog < 0xFFFFU) {
|
if (prog < 0xFFFFU) {
|
||||||
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog);
|
uint8_t tmpBri = useCct ? _t->_cctT : (_t->_segT._optionsT & 0x0004 ? _t->_briT : 0);
|
||||||
|
// _modeBlend==true -> old effect
|
||||||
|
if (blendingStyle != BLEND_STYLE_FADE) return _modeBlend ? tmpBri : curBri; // not fade/blend transition, each effect uses its brightness
|
||||||
|
#else
|
||||||
|
uint8_t tmpBri = useCct ? _t->_cctT : _t->_briT;
|
||||||
|
#endif
|
||||||
|
curBri *= prog;
|
||||||
|
curBri += tmpBri * (0xFFFFU - prog);
|
||||||
return curBri / 0xFFFFU;
|
return curBri / 0xFFFFU;
|
||||||
}
|
}
|
||||||
return (useCct ? cct : (on ? opacity : 0));
|
return curBri;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Segment::currentMode() const {
|
uint8_t Segment::currentMode() const {
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
unsigned prog = progress();
|
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
||||||
if (modeBlending && prog < 0xFFFFU) return _t->_modeT;
|
if (prog == 0xFFFFU) return mode;
|
||||||
#endif
|
if (blendingStyle != BLEND_STYLE_FADE) {
|
||||||
|
// workaround for on/off transition to respect blending style
|
||||||
|
uint8_t modeT = (bri != briT) && bri ? FX_MODE_STATIC : _t->_modeT; // On/Off transition active (bri!=briT) and final bri>0 : old mode is STATIC
|
||||||
|
uint8_t modeS = (bri != briT) && !bri ? FX_MODE_STATIC : mode; // On/Off transition active (bri!=briT) and final bri==0 : new mode is STATIC
|
||||||
|
return _modeBlend ? modeT : modeS; // _modeBlend==true -> old effect
|
||||||
|
}
|
||||||
|
return _modeBlend ? _t->_modeT : mode; // _modeBlend==true -> old effect
|
||||||
|
#else
|
||||||
return mode;
|
return mode;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Segment::currentColor(uint8_t slot) const {
|
uint32_t Segment::currentColor(uint8_t slot) const {
|
||||||
if (slot >= NUM_COLORS) slot = 0;
|
if (slot >= NUM_COLORS) slot = 0;
|
||||||
|
unsigned prog = progress();
|
||||||
|
if (prog == 0xFFFFU) return colors[slot];
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
return isInTransition() ? color_blend16(_t->_segT._colorT[slot], colors[slot], progress()) : colors[slot];
|
if (blendingStyle != BLEND_STYLE_FADE) {
|
||||||
|
// workaround for on/off transition to respect blending style
|
||||||
|
uint32_t colT = (bri != briT) && bri ? BLACK : _t->_segT._colorT[slot]; // On/Off transition active (bri!=briT) and final bri>0 : old color is BLACK
|
||||||
|
uint32_t colS = (bri != briT) && !bri ? BLACK : colors[slot]; // On/Off transition active (bri!=briT) and final bri==0 : new color is BLACK
|
||||||
|
return _modeBlend ? colT : colS; // _modeBlend==true -> old effect
|
||||||
|
}
|
||||||
|
return color_blend16(_t->_segT._colorT[slot], colors[slot], prog);
|
||||||
#else
|
#else
|
||||||
return isInTransition() ? color_blend16(_t->_colorT[slot], colors[slot], progress()) : colors[slot];
|
return color_blend16(_t->_colorT[slot], colors[slot], prog);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,44 +437,49 @@ void Segment::beginDraw() {
|
|||||||
_vHeight = virtualHeight();
|
_vHeight = virtualHeight();
|
||||||
_vLength = virtualLength();
|
_vLength = virtualLength();
|
||||||
_segBri = currentBri();
|
_segBri = currentBri();
|
||||||
|
unsigned prog = isInTransition() ? progress() : 0xFFFFU; // transition progress; 0xFFFFU = no transition active
|
||||||
// adjust gamma for effects
|
// adjust gamma for effects
|
||||||
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], progress()) : colors[i];
|
uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], prog) : colors[i];
|
||||||
#else
|
#else
|
||||||
uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], progress()) : colors[i];
|
uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], prog) : colors[i];
|
||||||
#endif
|
#endif
|
||||||
_currentColors[i] = gamma32(col);
|
_currentColors[i] = gamma32(col);
|
||||||
}
|
}
|
||||||
// load palette into _currentPalette
|
// load palette into _currentPalette
|
||||||
loadPalette(_currentPalette, palette);
|
loadPalette(_currentPalette, palette);
|
||||||
unsigned prog = progress();
|
if (prog < 0xFFFFU) {
|
||||||
if (strip.paletteFade && prog < 0xFFFFU) {
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
// blend palettes
|
if (blendingStyle > BLEND_STYLE_FADE) {
|
||||||
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
|
//if (_modeBlend) loadPalette(_currentPalette, _t->_palTid); // not fade/blend transition, each effect uses its palette
|
||||||
// minimum blend time is 100ms maximum is 65535ms
|
if (_modeBlend) _currentPalette = _t->_palT; // not fade/blend transition, each effect uses its palette
|
||||||
unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
|
} else
|
||||||
for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48);
|
#endif
|
||||||
_currentPalette = _t->_palT; // copy transitioning/temporary palette
|
{
|
||||||
|
// blend palettes
|
||||||
|
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
|
||||||
|
// minimum blend time is 100ms maximum is 65535ms
|
||||||
|
unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
|
||||||
|
for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48);
|
||||||
|
_currentPalette = _t->_palT; // copy transitioning/temporary palette
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// relies on WS2812FX::service() to call it for each frame
|
// relies on WS2812FX::service() to call it for each frame
|
||||||
void Segment::handleRandomPalette() {
|
void Segment::handleRandomPalette() {
|
||||||
// is it time to generate a new palette?
|
// is it time to generate a new palette?
|
||||||
if ((uint16_t)((uint16_t)(millis() / 1000U) - _lastPaletteChange) > randomPaletteChangeTime){
|
if ((uint16_t)(millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) {
|
||||||
_newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
|
_newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
|
||||||
_lastPaletteChange = (uint16_t)(millis() / 1000U);
|
_lastPaletteChange = (uint16_t)(millis()/1000U);
|
||||||
_lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately
|
_lastPaletteBlend = (uint16_t)(millis())-512; // starts blending immediately
|
||||||
}
|
}
|
||||||
|
|
||||||
// if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls)
|
// assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
|
||||||
if (strip.paletteFade) {
|
// in reality there need to be 255 blends to fully blend two entirely different palettes
|
||||||
// assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
|
if ((uint16_t)millis() - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
|
||||||
// in reality there need to be 255 blends to fully blend two entirely different palettes
|
_lastPaletteBlend = (uint16_t)millis();
|
||||||
if ((uint16_t)((uint16_t)millis() - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
|
|
||||||
_lastPaletteBlend = (uint16_t)millis();
|
|
||||||
}
|
|
||||||
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +554,8 @@ Segment &Segment::setColor(uint8_t slot, uint32_t c) {
|
|||||||
if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black
|
if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black
|
||||||
if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black
|
if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black
|
||||||
}
|
}
|
||||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
//DEBUG_PRINTF_P(PSTR("- Starting color transition: %d [0x%X]\n"), slot, c);
|
||||||
|
startTransition(strip.getTransition()); // start transition prior to change
|
||||||
colors[slot] = c;
|
colors[slot] = c;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
return *this;
|
return *this;
|
||||||
@ -536,7 +568,7 @@ Segment &Segment::setCCT(uint16_t k) {
|
|||||||
k = (k - 1900) >> 5;
|
k = (k - 1900) >> 5;
|
||||||
}
|
}
|
||||||
if (cct != k) {
|
if (cct != k) {
|
||||||
//DEBUGFX_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k);
|
//DEBUG_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k);
|
||||||
startTransition(strip.getTransition()); // start transition prior to change
|
startTransition(strip.getTransition()); // start transition prior to change
|
||||||
cct = k;
|
cct = k;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
@ -546,7 +578,7 @@ Segment &Segment::setCCT(uint16_t k) {
|
|||||||
|
|
||||||
Segment &Segment::setOpacity(uint8_t o) {
|
Segment &Segment::setOpacity(uint8_t o) {
|
||||||
if (opacity != o) {
|
if (opacity != o) {
|
||||||
//DEBUGFX_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o);
|
//DEBUG_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o);
|
||||||
startTransition(strip.getTransition()); // start transition prior to change
|
startTransition(strip.getTransition()); // start transition prior to change
|
||||||
opacity = o;
|
opacity = o;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
@ -556,7 +588,7 @@ Segment &Segment::setOpacity(uint8_t o) {
|
|||||||
|
|
||||||
Segment &Segment::setOption(uint8_t n, bool val) {
|
Segment &Segment::setOption(uint8_t n, bool val) {
|
||||||
bool prevOn = on;
|
bool prevOn = on;
|
||||||
if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
|
if (n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
|
||||||
if (val) options |= 0x01 << n;
|
if (val) options |= 0x01 << n;
|
||||||
else options &= ~(0x01 << n);
|
else options &= ~(0x01 << n);
|
||||||
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
|
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
|
||||||
@ -570,7 +602,8 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
// if we have a valid mode & is not reserved
|
// if we have a valid mode & is not reserved
|
||||||
if (fx != mode) {
|
if (fx != mode) {
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
//DEBUG_PRINTF_P(PSTR("- Starting effect transition: %d\n"), fx);
|
||||||
|
startTransition(strip.getTransition()); // set effect transitions
|
||||||
#endif
|
#endif
|
||||||
mode = fx;
|
mode = fx;
|
||||||
int sOpt;
|
int sOpt;
|
||||||
@ -605,7 +638,8 @@ Segment &Segment::setPalette(uint8_t pal) {
|
|||||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes
|
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes
|
||||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes
|
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes
|
||||||
if (pal != palette) {
|
if (pal != palette) {
|
||||||
if (strip.paletteFade) startTransition(strip.getTransition());
|
//DEBUG_PRINTF_P(PSTR("- Starting palette transition: %d\n"), pal);
|
||||||
|
startTransition(strip.getTransition());
|
||||||
palette = pal;
|
palette = pal;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
}
|
}
|
||||||
@ -678,7 +712,7 @@ uint16_t Segment::virtualLength() const {
|
|||||||
vLen = max(vW,vH); // get the longest dimension
|
vLen = max(vW,vH); // get the longest dimension
|
||||||
break;
|
break;
|
||||||
case M12_pArc:
|
case M12_pArc:
|
||||||
vLen = sqrt16(vH*vH + vW*vW); // use diagonal
|
vLen = sqrt32_bw(vH*vH + vW*vW); // use diagonal
|
||||||
break;
|
break;
|
||||||
case M12_sPinwheel:
|
case M12_sPinwheel:
|
||||||
vLen = getPinwheelLength(vW, vH);
|
vLen = getPinwheelLength(vW, vH);
|
||||||
@ -696,7 +730,34 @@ uint16_t Segment::virtualLength() const {
|
|||||||
return vLength;
|
return vLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false)
|
||||||
|
// if clipping start > stop the clipping range is inverted
|
||||||
|
// _modeBlend==true -> old effect during transition
|
||||||
|
// _modeBlend==false -> new effect during transition
|
||||||
|
bool IRAM_ATTR_YN Segment::isPixelClipped(int i) const {
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) {
|
||||||
|
bool invert = _clipStart > _clipStop; // ineverted start & stop
|
||||||
|
int start = invert ? _clipStop : _clipStart;
|
||||||
|
int stop = invert ? _clipStart : _clipStop;
|
||||||
|
if (blendingStyle == BLEND_STYLE_FAIRY_DUST) {
|
||||||
|
unsigned len = stop - start;
|
||||||
|
if (len < 2) return false;
|
||||||
|
unsigned shuffled = hashInt(i) % len;
|
||||||
|
unsigned pos = (shuffled * 0xFFFFU) / len;
|
||||||
|
return (progress() <= pos) ^ _modeBlend;
|
||||||
|
}
|
||||||
|
const bool iInside = (i >= start && i < stop);
|
||||||
|
//if (!invert && iInside) return _modeBlend;
|
||||||
|
//if ( invert && !iInside) return _modeBlend;
|
||||||
|
//return !_modeBlend;
|
||||||
|
return !iInside ^ invert ^ _modeBlend; // thanks @willmmiles (https://github.com/Aircoookie/WLED/pull/3877#discussion_r1554633876)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
|
||||||
{
|
{
|
||||||
if (!isActive() || i < 0) return; // not active or invalid index
|
if (!isActive() || i < 0) return; // not active or invalid index
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
@ -828,6 +889,18 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
// if we blend using "push" style we need to "shift" new mode to left or right
|
||||||
|
if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) {
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
unsigned dI = prog * vL / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI;
|
||||||
|
else i += dI;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (i >= vL || i < 0 || isPixelClipped(i)) return; // handle clipping on 1D
|
||||||
|
|
||||||
unsigned len = length();
|
unsigned len = length();
|
||||||
// if color is unscaled
|
// if color is unscaled
|
||||||
if (!_colorScaled) col = color_fade(col, _segBri);
|
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||||
@ -853,14 +926,16 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
indexMir += offset; // offset/phase
|
indexMir += offset; // offset/phase
|
||||||
if (indexMir >= stop) indexMir -= len; // wrap
|
if (indexMir >= stop) indexMir -= len; // wrap
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, uint16_t(0xFFFFU - progress()));
|
// _modeBlend==true -> old effect
|
||||||
|
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, 0xFFFFU - progress());
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColor(indexMir, tmpCol);
|
strip.setPixelColor(indexMir, tmpCol);
|
||||||
}
|
}
|
||||||
indexSet += offset; // offset/phase
|
indexSet += offset; // offset/phase
|
||||||
if (indexSet >= stop) indexSet -= len; // wrap
|
if (indexSet >= stop) indexSet -= len; // wrap
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, uint16_t(0xFFFFU - progress()));
|
// _modeBlend==true -> old effect
|
||||||
|
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, 0xFFFFU - progress());
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColor(indexSet, tmpCol);
|
strip.setPixelColor(indexSet, tmpCol);
|
||||||
}
|
}
|
||||||
@ -869,7 +944,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
|||||||
|
|
||||||
#ifdef WLED_USE_AA_PIXELS
|
#ifdef WLED_USE_AA_PIXELS
|
||||||
// anti-aliased normalized version of setPixelColor()
|
// anti-aliased normalized version of setPixelColor()
|
||||||
void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
void Segment::setPixelColor(float i, uint32_t col, bool aa) const
|
||||||
{
|
{
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows)
|
int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows)
|
||||||
@ -906,6 +981,9 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
{
|
{
|
||||||
if (!isActive()) return 0; // not active
|
if (!isActive()) return 0; // not active
|
||||||
|
|
||||||
|
int vL = vLength();
|
||||||
|
if (i >= vL || i < 0) return 0;
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
@ -921,7 +999,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
break; }
|
break; }
|
||||||
case M12_pArc:
|
case M12_pArc:
|
||||||
if (i >= vW && i >= vH) {
|
if (i >= vW && i >= vH) {
|
||||||
unsigned vI = sqrt16(i*i/2);
|
unsigned vI = sqrt32_bw(i*i/2);
|
||||||
return getPixelColorXY(vI,vI); // use diagonal
|
return getPixelColorXY(vI,vI); // use diagonal
|
||||||
}
|
}
|
||||||
case M12_pCorner:
|
case M12_pCorner:
|
||||||
@ -962,7 +1040,18 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (reverse) i = vLength() - i - 1;
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) {
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
unsigned dI = prog * vL / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI;
|
||||||
|
else i += dI;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (i >= vL || i < 0 || isPixelClipped(i)) return 0; // handle clipping on 1D
|
||||||
|
|
||||||
|
if (reverse) i = vL - i - 1;
|
||||||
i *= groupLength();
|
i *= groupLength();
|
||||||
i += start;
|
i += start;
|
||||||
// offset/phase
|
// offset/phase
|
||||||
@ -1134,7 +1223,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
|||||||
uint8_t seep = blur_amount >> 1;
|
uint8_t seep = blur_amount >> 1;
|
||||||
unsigned vlength = vLength();
|
unsigned vlength = vLength();
|
||||||
uint32_t carryover = BLACK;
|
uint32_t carryover = BLACK;
|
||||||
uint32_t lastnew;
|
uint32_t lastnew; // not necessary to initialize lastnew and last, as both will be initialized by the first loop iteration
|
||||||
uint32_t last;
|
uint32_t last;
|
||||||
uint32_t curnew = BLACK;
|
uint32_t curnew = BLACK;
|
||||||
for (unsigned i = 0; i < vlength; i++) {
|
for (unsigned i = 0; i < vlength; i++) {
|
||||||
@ -1195,7 +1284,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
|
|||||||
if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
|
if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
|
||||||
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
||||||
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||||
CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
CRGBW palcol = ColorFromPaletteWLED(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||||
palcol.w = W(color);
|
palcol.w = W(color);
|
||||||
|
|
||||||
return palcol.color32;
|
return palcol.color32;
|
||||||
@ -1372,21 +1461,78 @@ void WS2812FX::service() {
|
|||||||
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
||||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||||
// would need to be allocated for each effect and then blended together for each pixel.
|
// would need to be allocated for each effect and then blended together for each pixel.
|
||||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
|
||||||
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending && seg.mode != tmpMode) {
|
Segment::setClippingRect(0, 0); // disable clipping (just in case)
|
||||||
|
if (seg.isInTransition()) {
|
||||||
|
// set clipping rectangle
|
||||||
|
// new mode is run inside clipping area and old mode outside clipping area
|
||||||
|
unsigned p = seg.progress();
|
||||||
|
unsigned w = seg.is2D() ? Segment::vWidth() : Segment::vLength();
|
||||||
|
unsigned h = Segment::vHeight();
|
||||||
|
unsigned dw = p * w / 0xFFFFU + 1;
|
||||||
|
unsigned dh = p * h / 0xFFFFU + 1;
|
||||||
|
unsigned orgBS = blendingStyle;
|
||||||
|
if (w*h == 1) blendingStyle = BLEND_STYLE_FADE; // disable belending for single pixel segments (use fade instead)
|
||||||
|
switch (blendingStyle) {
|
||||||
|
case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped())
|
||||||
|
Segment::setClippingRect(0, w, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_RIGHT: // left-to-right
|
||||||
|
case BLEND_STYLE_PUSH_RIGHT: // left-to-right
|
||||||
|
Segment::setClippingRect(0, dw, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_LEFT: // right-to-left
|
||||||
|
case BLEND_STYLE_PUSH_LEFT: // right-to-left
|
||||||
|
Segment::setClippingRect(w - dw, w, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PINCH_OUT: // corners
|
||||||
|
Segment::setClippingRect((w + dw)/2, (w - dw)/2, (h + dh)/2, (h - dh)/2); // inverted!!
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_INSIDE_OUT: // outward
|
||||||
|
Segment::setClippingRect((w - dw)/2, (w + dw)/2, (h - dh)/2, (h + dh)/2);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_DOWN: // top-to-bottom (2D)
|
||||||
|
case BLEND_STYLE_PUSH_DOWN: // top-to-bottom (2D)
|
||||||
|
Segment::setClippingRect(0, w, 0, dh);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_UP: // bottom-to-top (2D)
|
||||||
|
case BLEND_STYLE_PUSH_UP: // bottom-to-top (2D)
|
||||||
|
Segment::setClippingRect(0, w, h - dh, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_OPEN_H: // horizontal-outward (2D) same look as INSIDE_OUT on 1D
|
||||||
|
Segment::setClippingRect((w - dw)/2, (w + dw)/2, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_OPEN_V: // vertical-outward (2D)
|
||||||
|
Segment::setClippingRect(0, w, (h - dh)/2, (h + dh)/2);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_TL: // TL-to-BR (2D)
|
||||||
|
Segment::setClippingRect(0, dw, 0, dh);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_TR: // TR-to-BL (2D)
|
||||||
|
Segment::setClippingRect(w - dw, w, 0, dh);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_BR: // BR-to-TL (2D)
|
||||||
|
Segment::setClippingRect(w - dw, w, h - dh, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_BL: // BL-to-TR (2D)
|
||||||
|
Segment::setClippingRect(0, dw, h - dh, h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
frameDelay = (*_mode[seg.currentMode()])(); // run new/current mode
|
||||||
|
// now run old/previous mode
|
||||||
Segment::tmpsegd_t _tmpSegData;
|
Segment::tmpsegd_t _tmpSegData;
|
||||||
Segment::modeBlend(true); // set semaphore
|
Segment::modeBlend(true); // set semaphore
|
||||||
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
||||||
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
unsigned d2 = (*_mode[tmpMode])(); // run old mode
|
frameDelay = min(frameDelay, (unsigned)(*_mode[seg.currentMode()])()); // run old mode
|
||||||
|
seg.call++; // increment old mode run counter
|
||||||
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
||||||
frameDelay = min(frameDelay,d2); // use shortest delay
|
|
||||||
Segment::modeBlend(false); // unset semaphore
|
Segment::modeBlend(false); // unset semaphore
|
||||||
}
|
blendingStyle = orgBS; // restore blending style if it was modified for single pixel segment
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
frameDelay = (*_mode[seg.mode])(); // run effect mode (not in transition)
|
||||||
seg.call++;
|
seg.call++;
|
||||||
if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition
|
if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition
|
||||||
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
|
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
|
||||||
@ -1396,6 +1542,7 @@ void WS2812FX::service() {
|
|||||||
}
|
}
|
||||||
_segment_index++;
|
_segment_index++;
|
||||||
}
|
}
|
||||||
|
Segment::setClippingRect(0, 0); // disable clipping for overlays
|
||||||
_isServicing = false;
|
_isServicing = false;
|
||||||
_triggered = false;
|
_triggered = false;
|
||||||
|
|
||||||
@ -1413,7 +1560,7 @@ void WS2812FX::service() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) {
|
void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) const {
|
||||||
i = getMappedPixelIndex(i);
|
i = getMappedPixelIndex(i);
|
||||||
if (i >= _length) return;
|
if (i >= _length) return;
|
||||||
BusManager::setPixelColor(i, col);
|
BusManager::setPixelColor(i, col);
|
||||||
@ -1694,9 +1841,9 @@ void WS2812FX::fixInvalidSegments() {
|
|||||||
|
|
||||||
//true if all segments align with a bus, or if a segment covers the total length
|
//true if all segments align with a bus, or if a segment covers the total length
|
||||||
//irrelevant in 2D set-up
|
//irrelevant in 2D set-up
|
||||||
bool WS2812FX::checkSegmentAlignment() {
|
bool WS2812FX::checkSegmentAlignment() const {
|
||||||
bool aligned = false;
|
bool aligned = false;
|
||||||
for (segment &seg : _segments) {
|
for (const segment &seg : _segments) {
|
||||||
for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
|
for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
|
||||||
Bus *bus = BusManager::getBus(b);
|
Bus *bus = BusManager::getBus(b);
|
||||||
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
||||||
@ -1808,8 +1955,8 @@ bool WS2812FX::deserializeMap(unsigned n) {
|
|||||||
Segment::maxHeight = min(max(root[F("height")].as<int>(), 1), 128);
|
Segment::maxHeight = min(max(root[F("height")].as<int>(), 1), 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customMappingTable) delete[] customMappingTable;
|
if (customMappingTable) free(customMappingTable);
|
||||||
customMappingTable = new uint16_t[getLengthTotal()];
|
customMappingTable = static_cast<uint16_t*>(malloc(sizeof(uint16_t)*getLengthTotal()));
|
||||||
|
|
||||||
if (customMappingTable) {
|
if (customMappingTable) {
|
||||||
DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName);
|
DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName);
|
||||||
|
@ -27,7 +27,7 @@ extern bool cctICused;
|
|||||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||||
|
|
||||||
//udp.cpp
|
//udp.cpp
|
||||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
|
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false);
|
||||||
|
|
||||||
// enable additional debug output
|
// enable additional debug output
|
||||||
#if defined(WLED_DEBUG_HOST)
|
#if defined(WLED_DEBUG_HOST)
|
||||||
@ -121,7 +121,7 @@ uint8_t *Bus::allocateData(size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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))
|
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
|
||||||
, _skip(bc.skipAmount) //sacrificial pixels
|
, _skip(bc.skipAmount) //sacrificial pixels
|
||||||
, _colorOrder(bc.colorOrder)
|
, _colorOrder(bc.colorOrder)
|
||||||
@ -448,7 +448,7 @@ void BusDigital::cleanup() {
|
|||||||
#endif
|
#endif
|
||||||
#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
|
: 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;
|
if (!isPWM(bc.type)) return;
|
||||||
@ -646,7 +646,7 @@ void BusPwm::deallocatePins() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BusOnOff::BusOnOff(BusConfig &bc)
|
BusOnOff::BusOnOff(const BusConfig &bc)
|
||||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
||||||
, _onoffdata(0)
|
, _onoffdata(0)
|
||||||
{
|
{
|
||||||
@ -699,7 +699,7 @@ std::vector<LEDType> BusOnOff::getLEDTypes() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
BusNetwork::BusNetwork(BusConfig &bc)
|
BusNetwork::BusNetwork(const BusConfig &bc)
|
||||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
|
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
|
||||||
, _broadcastLock(false)
|
, _broadcastLock(false)
|
||||||
{
|
{
|
||||||
@ -778,7 +778,7 @@ void BusNetwork::cleanup() {
|
|||||||
|
|
||||||
|
|
||||||
//utility to get the approx. memory usage of a given BusConfig
|
//utility to get the approx. memory usage of a given BusConfig
|
||||||
uint32_t BusManager::memUsage(BusConfig &bc) {
|
uint32_t BusManager::memUsage(const BusConfig &bc) {
|
||||||
if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS;
|
if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS;
|
||||||
|
|
||||||
unsigned len = bc.count + bc.skipAmount;
|
unsigned len = bc.count + bc.skipAmount;
|
||||||
@ -803,7 +803,7 @@ uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned
|
|||||||
return (maxChannels * maxCount * minBuses * multiplier);
|
return (maxChannels * maxCount * minBuses * multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BusManager::add(BusConfig &bc) {
|
int BusManager::add(const BusConfig &bc) {
|
||||||
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
|
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
|
||||||
if (Bus::isVirtual(bc.type)) {
|
if (Bus::isVirtual(bc.type)) {
|
||||||
busses[numBusses] = new BusNetwork(bc);
|
busses[numBusses] = new BusNetwork(bc);
|
||||||
|
@ -198,7 +198,7 @@ class Bus {
|
|||||||
|
|
||||||
class BusDigital : public Bus {
|
class BusDigital : public Bus {
|
||||||
public:
|
public:
|
||||||
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
||||||
~BusDigital() { cleanup(); }
|
~BusDigital() { cleanup(); }
|
||||||
|
|
||||||
void show() override;
|
void show() override;
|
||||||
@ -250,7 +250,7 @@ class BusDigital : public Bus {
|
|||||||
|
|
||||||
class BusPwm : public Bus {
|
class BusPwm : public Bus {
|
||||||
public:
|
public:
|
||||||
BusPwm(BusConfig &bc);
|
BusPwm(const BusConfig &bc);
|
||||||
~BusPwm() { cleanup(); }
|
~BusPwm() { cleanup(); }
|
||||||
|
|
||||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||||
@ -277,7 +277,7 @@ class BusPwm : public Bus {
|
|||||||
|
|
||||||
class BusOnOff : public Bus {
|
class BusOnOff : public Bus {
|
||||||
public:
|
public:
|
||||||
BusOnOff(BusConfig &bc);
|
BusOnOff(const BusConfig &bc);
|
||||||
~BusOnOff() { cleanup(); }
|
~BusOnOff() { cleanup(); }
|
||||||
|
|
||||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||||
@ -296,7 +296,7 @@ class BusOnOff : public Bus {
|
|||||||
|
|
||||||
class BusNetwork : public Bus {
|
class BusNetwork : public Bus {
|
||||||
public:
|
public:
|
||||||
BusNetwork(BusConfig &bc);
|
BusNetwork(const BusConfig &bc);
|
||||||
~BusNetwork() { cleanup(); }
|
~BusNetwork() { cleanup(); }
|
||||||
|
|
||||||
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
||||||
@ -379,12 +379,12 @@ class BusManager {
|
|||||||
BusManager() {};
|
BusManager() {};
|
||||||
|
|
||||||
//utility to get the approx. memory usage of a given BusConfig
|
//utility to get the approx. memory usage of a given BusConfig
|
||||||
static uint32_t memUsage(BusConfig &bc);
|
static uint32_t memUsage(const BusConfig &bc);
|
||||||
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
||||||
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
||||||
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
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 void useParallelOutput(); // workaround for inaccessible PolyBus
|
||||||
|
|
||||||
//do not call this method from system context (network callback)
|
//do not call this method from system context (network callback)
|
||||||
|
@ -29,7 +29,7 @@ void shortPressAction(uint8_t b)
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
// publish MQTT message
|
// publish MQTT message
|
||||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||||
char subuf[64];
|
char subuf[MQTT_MAX_TOPIC_LEN + 32];
|
||||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||||
mqtt->publish(subuf, 0, false, "short");
|
mqtt->publish(subuf, 0, false, "short");
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ void longPressAction(uint8_t b)
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
// publish MQTT message
|
// publish MQTT message
|
||||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||||
char subuf[64];
|
char subuf[MQTT_MAX_TOPIC_LEN + 32];
|
||||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||||
mqtt->publish(subuf, 0, false, "long");
|
mqtt->publish(subuf, 0, false, "long");
|
||||||
}
|
}
|
||||||
@ -83,19 +83,19 @@ void doublePressAction(uint8_t b)
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
// publish MQTT message
|
// publish MQTT message
|
||||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||||
char subuf[64];
|
char subuf[MQTT_MAX_TOPIC_LEN + 32];
|
||||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||||
mqtt->publish(subuf, 0, false, "double");
|
mqtt->publish(subuf, 0, false, "double");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isButtonPressed(uint8_t i)
|
bool isButtonPressed(uint8_t b)
|
||||||
{
|
{
|
||||||
if (btnPin[i]<0) return false;
|
if (btnPin[b]<0) return false;
|
||||||
unsigned pin = btnPin[i];
|
unsigned pin = btnPin[b];
|
||||||
|
|
||||||
switch (buttonType[i]) {
|
switch (buttonType[b]) {
|
||||||
case BTN_TYPE_NONE:
|
case BTN_TYPE_NONE:
|
||||||
case BTN_TYPE_RESERVED:
|
case BTN_TYPE_RESERVED:
|
||||||
break;
|
break;
|
||||||
@ -113,7 +113,7 @@ bool isButtonPressed(uint8_t i)
|
|||||||
#ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt)
|
#ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt)
|
||||||
if (touchInterruptGetLastStatus(pin)) return true;
|
if (touchInterruptGetLastStatus(pin)) return true;
|
||||||
#else
|
#else
|
||||||
if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) return true;
|
if (digitalPinToTouchChannel(btnPin[b]) >= 0 && touchRead(pin) <= touchThreshold) return true;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@ -151,7 +151,7 @@ void handleSwitch(uint8_t b)
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
// publish MQTT message
|
// publish MQTT message
|
||||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||||
char subuf[64];
|
char subuf[MQTT_MAX_TOPIC_LEN + 32];
|
||||||
if (buttonType[b] == BTN_TYPE_PIR_SENSOR) sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)b);
|
if (buttonType[b] == BTN_TYPE_PIR_SENSOR) sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)b);
|
||||||
else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||||
mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on");
|
mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on");
|
||||||
@ -375,6 +375,7 @@ void handleIO()
|
|||||||
if (rlyPin>=0) {
|
if (rlyPin>=0) {
|
||||||
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
|
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
|
||||||
digitalWrite(rlyPin, rlyMde);
|
digitalWrite(rlyPin, rlyMde);
|
||||||
|
delay(50); // wait for relay to switch and power to stabilize
|
||||||
}
|
}
|
||||||
offMode = false;
|
offMode = false;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
CJSON(strip.correctWB, hw_led["cct"]);
|
CJSON(strip.correctWB, hw_led["cct"]);
|
||||||
CJSON(strip.cctFromRgb, hw_led[F("cr")]);
|
CJSON(strip.cctFromRgb, hw_led[F("cr")]);
|
||||||
CJSON(cctICused, hw_led[F("ic")]);
|
CJSON(cctICused, hw_led[F("ic")]);
|
||||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
uint8_t cctBlending = hw_led[F("cb")] | Bus::getCCTBlend();
|
||||||
Bus::setCCTBlend(strip.cctBlending);
|
Bus::setCCTBlend(cctBlending);
|
||||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||||
CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
|
CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
|
||||||
|
|
||||||
@ -447,12 +447,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||||
|
|
||||||
JsonObject light_tr = light["tr"];
|
JsonObject light_tr = light["tr"];
|
||||||
CJSON(fadeTransition, light_tr["mode"]);
|
|
||||||
CJSON(modeBlending, light_tr["fx"]);
|
|
||||||
int tdd = light_tr["dur"] | -1;
|
int tdd = light_tr["dur"] | -1;
|
||||||
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
||||||
strip.setTransition(fadeTransition ? transitionDelayDefault : 0);
|
strip.setTransition(transitionDelayDefault);
|
||||||
CJSON(strip.paletteFade, light_tr["pal"]);
|
|
||||||
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
|
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
|
||||||
CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]);
|
CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]);
|
||||||
|
|
||||||
@ -525,6 +522,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
|
|
||||||
tdd = if_live[F("timeout")] | -1;
|
tdd = if_live[F("timeout")] | -1;
|
||||||
if (tdd >= 0) realtimeTimeoutMs = tdd * 100;
|
if (tdd >= 0) realtimeTimeoutMs = tdd * 100;
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
CJSON(dmxInputTransmitPin, if_live_dmx[F("inputRxPin")]);
|
||||||
|
CJSON(dmxInputReceivePin, if_live_dmx[F("inputTxPin")]);
|
||||||
|
CJSON(dmxInputEnablePin, if_live_dmx[F("inputEnablePin")]);
|
||||||
|
CJSON(dmxInputPort, if_live_dmx[F("dmxInputPort")]);
|
||||||
|
#endif
|
||||||
|
|
||||||
CJSON(arlsForceMaxBri, if_live[F("maxbri")]);
|
CJSON(arlsForceMaxBri, if_live[F("maxbri")]);
|
||||||
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
||||||
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
||||||
@ -825,7 +830,7 @@ void serializeConfig() {
|
|||||||
hw_led["cct"] = strip.correctWB;
|
hw_led["cct"] = strip.correctWB;
|
||||||
hw_led[F("cr")] = strip.cctFromRgb;
|
hw_led[F("cr")] = strip.cctFromRgb;
|
||||||
hw_led[F("ic")] = cctICused;
|
hw_led[F("ic")] = cctICused;
|
||||||
hw_led[F("cb")] = strip.cctBlending;
|
hw_led[F("cb")] = Bus::getCCTBlend();
|
||||||
hw_led["fps"] = strip.getTargetFps();
|
hw_led["fps"] = strip.getTargetFps();
|
||||||
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
|
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
|
||||||
hw_led[F("ld")] = useGlobalLedBuffer;
|
hw_led[F("ld")] = useGlobalLedBuffer;
|
||||||
@ -943,10 +948,7 @@ void serializeConfig() {
|
|||||||
light_gc["val"] = gammaCorrectVal;
|
light_gc["val"] = gammaCorrectVal;
|
||||||
|
|
||||||
JsonObject light_tr = light.createNestedObject("tr");
|
JsonObject light_tr = light.createNestedObject("tr");
|
||||||
light_tr["mode"] = fadeTransition;
|
|
||||||
light_tr["fx"] = modeBlending;
|
|
||||||
light_tr["dur"] = transitionDelayDefault / 100;
|
light_tr["dur"] = transitionDelayDefault / 100;
|
||||||
light_tr["pal"] = strip.paletteFade;
|
|
||||||
light_tr[F("rpc")] = randomPaletteChangeTime;
|
light_tr[F("rpc")] = randomPaletteChangeTime;
|
||||||
light_tr[F("hrp")] = useHarmonicRandomPalette;
|
light_tr[F("hrp")] = useHarmonicRandomPalette;
|
||||||
|
|
||||||
@ -1007,6 +1009,12 @@ void serializeConfig() {
|
|||||||
if_live_dmx[F("addr")] = DMXAddress;
|
if_live_dmx[F("addr")] = DMXAddress;
|
||||||
if_live_dmx[F("dss")] = DMXSegmentSpacing;
|
if_live_dmx[F("dss")] = DMXSegmentSpacing;
|
||||||
if_live_dmx["mode"] = DMXMode;
|
if_live_dmx["mode"] = DMXMode;
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
if_live_dmx[F("inputRxPin")] = dmxInputTransmitPin;
|
||||||
|
if_live_dmx[F("inputTxPin")] = dmxInputReceivePin;
|
||||||
|
if_live_dmx[F("inputEnablePin")] = dmxInputEnablePin;
|
||||||
|
if_live_dmx[F("dmxInputPort")] = dmxInputPort;
|
||||||
|
#endif
|
||||||
|
|
||||||
if_live[F("timeout")] = realtimeTimeoutMs / 100;
|
if_live[F("timeout")] = realtimeTimeoutMs / 100;
|
||||||
if_live[F("maxbri")] = arlsForceMaxBri;
|
if_live[F("maxbri")] = arlsForceMaxBri;
|
||||||
|
@ -122,7 +122,7 @@ void setRandomColor(byte* rgb)
|
|||||||
* generates a random palette based on harmonic color theory
|
* generates a random palette based on harmonic color theory
|
||||||
* takes a base palette as the input, it will choose one color of the base palette and keep it
|
* takes a base palette as the input, it will choose one color of the base palette and keep it
|
||||||
*/
|
*/
|
||||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette)
|
||||||
{
|
{
|
||||||
CHSV palettecolors[4]; // array of colors for the new palette
|
CHSV palettecolors[4]; // array of colors for the new palette
|
||||||
uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep
|
uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep
|
||||||
@ -391,7 +391,7 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
|
|||||||
rgb[2] = byte(255.0f*b);
|
rgb[2] = byte(255.0f*b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
|
void colorRGBtoXY(const byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
|
||||||
{
|
{
|
||||||
float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f;
|
float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f;
|
||||||
float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f;
|
float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f;
|
||||||
@ -402,7 +402,7 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo
|
|||||||
#endif // WLED_DISABLE_HUESYNC
|
#endif // WLED_DISABLE_HUESYNC
|
||||||
|
|
||||||
//RRGGBB / WWRRGGBB order for hex
|
//RRGGBB / WWRRGGBB order for hex
|
||||||
void colorFromDecOrHexString(byte* rgb, char* in)
|
void colorFromDecOrHexString(byte* rgb, const char* in)
|
||||||
{
|
{
|
||||||
if (in[0] == 0) return;
|
if (in[0] == 0) return;
|
||||||
char first = in[0];
|
char first = in[0];
|
||||||
|
@ -203,6 +203,8 @@
|
|||||||
#define USERMOD_ID_LD2410 52 //Usermod "usermod_ld2410.h"
|
#define USERMOD_ID_LD2410 52 //Usermod "usermod_ld2410.h"
|
||||||
#define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h"
|
#define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h"
|
||||||
#define USERMOD_ID_PIXELS_DICE_TRAY 54 //Usermod "pixels_dice_tray.h"
|
#define USERMOD_ID_PIXELS_DICE_TRAY 54 //Usermod "pixels_dice_tray.h"
|
||||||
|
#define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h"
|
||||||
|
#define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h"
|
||||||
|
|
||||||
//Access point behavior
|
//Access point behavior
|
||||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||||
@ -248,6 +250,7 @@
|
|||||||
#define REALTIME_MODE_ARTNET 6
|
#define REALTIME_MODE_ARTNET 6
|
||||||
#define REALTIME_MODE_TPM2NET 7
|
#define REALTIME_MODE_TPM2NET 7
|
||||||
#define REALTIME_MODE_DDP 8
|
#define REALTIME_MODE_DDP 8
|
||||||
|
#define REALTIME_MODE_DMX 9
|
||||||
|
|
||||||
//realtime override modes
|
//realtime override modes
|
||||||
#define REALTIME_OVERRIDE_NONE 0
|
#define REALTIME_OVERRIDE_NONE 0
|
||||||
|
@ -266,7 +266,29 @@
|
|||||||
<div id="segutil2">
|
<div id="segutil2">
|
||||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||||
</div>
|
</div>
|
||||||
<p>Transition: <input id="tt" type="number" min="0" max="65.5" step="0.1" value="0.7"> s</p>
|
<p>Transition: <input id="tt" type="number" min="0" max="65.5" step="0.1" value="0.7" onchange="parseFloat(this.value)===0?gId('bsp').classList.add('hide'):gId('bsp').classList.remove('hide');"> s</p>
|
||||||
|
<p id="bsp">Blend:
|
||||||
|
<select id="bs" class="sel-sg" onchange="requestJson({'bs':parseInt(this.value)})">
|
||||||
|
<option value="0">Fade</option>
|
||||||
|
<option value="1">Fairy Dust</option>
|
||||||
|
<option value="2">Swipe right</option>
|
||||||
|
<option value="3">Swipe left</option>
|
||||||
|
<option value="4">Push right</option>
|
||||||
|
<option value="5">Push left</option>
|
||||||
|
<option value="6">Pinch-out</option>
|
||||||
|
<option value="7">Inside-out</option>
|
||||||
|
<option value="8" data-type="2D">Swipe up</option>
|
||||||
|
<option value="9" data-type="2D">Swipe down</option>
|
||||||
|
<option value="10" data-type="2D">Open V</option>
|
||||||
|
<option value="11" data-type="2D">Open H</option>
|
||||||
|
<option value="12" data-type="2D">Push up</option>
|
||||||
|
<option value="13" data-type="2D">Push down</option>
|
||||||
|
<option value="14" data-type="2D">Push TL</option>
|
||||||
|
<option value="15" data-type="2D">Push TR</option>
|
||||||
|
<option value="16" data-type="2D">Push BR</option>
|
||||||
|
<option value="17" data-type="2D">Push BL</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
<p id="ledmap" class="hide"></p>
|
<p id="ledmap" class="hide"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -677,8 +677,10 @@ function parseInfo(i) {
|
|||||||
isM = mw>0 && mh>0;
|
isM = mw>0 && mh>0;
|
||||||
if (!isM) {
|
if (!isM) {
|
||||||
gId("filter2D").classList.add('hide');
|
gId("filter2D").classList.add('hide');
|
||||||
|
gId('bs').querySelectorAll('option[data-type="2D"]').forEach((o,i)=>{o.style.display='none';});
|
||||||
} else {
|
} else {
|
||||||
gId("filter2D").classList.remove('hide');
|
gId("filter2D").classList.remove('hide');
|
||||||
|
gId('bs').querySelectorAll('option[data-type="2D"]').forEach((o,i)=>{o.style.display='';});
|
||||||
}
|
}
|
||||||
// if (i.noaudio) {
|
// if (i.noaudio) {
|
||||||
// gId("filterVol").classList.add("hide");
|
// gId("filterVol").classList.add("hide");
|
||||||
@ -1437,6 +1439,9 @@ function readState(s,command=false)
|
|||||||
|
|
||||||
tr = s.transition;
|
tr = s.transition;
|
||||||
gId('tt').value = tr/10;
|
gId('tt').value = tr/10;
|
||||||
|
gId('bs').value = s.bs || 0;
|
||||||
|
if (tr===0) gId('bsp').classList.add('hide')
|
||||||
|
else gId('bsp').classList.remove('hide')
|
||||||
|
|
||||||
populateSegments(s);
|
populateSegments(s);
|
||||||
var selc=0;
|
var selc=0;
|
||||||
@ -1698,6 +1703,7 @@ function requestJson(command=null)
|
|||||||
var tn = parseInt(t.value*10);
|
var tn = parseInt(t.value*10);
|
||||||
if (tn != tr) command.transition = tn;
|
if (tn != tr) command.transition = tn;
|
||||||
}
|
}
|
||||||
|
//command.bs = parseInt(gId('bs').value);
|
||||||
req = JSON.stringify(command);
|
req = JSON.stringify(command);
|
||||||
if (req.length > 1340) useWs = false; // do not send very long requests over websocket
|
if (req.length > 1340) useWs = false; // do not send very long requests over websocket
|
||||||
if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes
|
if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes
|
||||||
|
@ -832,12 +832,7 @@ Swap: <select id="xw${s}" name="XW${s}">
|
|||||||
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
||||||
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||||
<h3>Transitions</h3>
|
<h3>Transitions</h3>
|
||||||
Enable transitions: <input type="checkbox" name="TF" onchange="gId('tran').style.display=this.checked?'inline':'none';"><br>
|
Default transition time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
||||||
<span id="tran">
|
|
||||||
Effect blending: <input type="checkbox" name="EB"><br>
|
|
||||||
Default transition time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
|
||||||
Palette transitions: <input type="checkbox" name="PF"><br>
|
|
||||||
</span>
|
|
||||||
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
||||||
Use harmonic <i>Random Cycle</i> Palette: <input type="checkbox" name="TH"><br>
|
Use harmonic <i>Random Cycle</i> Palette: <input type="checkbox" name="TH"><br>
|
||||||
<h3>Timed light</h3>
|
<h3>Timed light</h3>
|
||||||
|
@ -151,6 +151,19 @@ Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
|
|||||||
Force max brightness: <input type="checkbox" name="FB"><br>
|
Force max brightness: <input type="checkbox" name="FB"><br>
|
||||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||||
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
|
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
|
||||||
|
<div id="dmxInput">
|
||||||
|
<h4>Wired DMX Input Pins</h4>
|
||||||
|
DMX RX: <input name="IDMR" type="number" min="-1" max="99">RO<br/>
|
||||||
|
DMX TX: <input name="IDMT" type="number" min="-1" max="99">DI<br/>
|
||||||
|
DMX Enable: <input name="IDME" type="number" min="-1" max="99">RE+DE<br/>
|
||||||
|
DMX Port: <input name="IDMP" type="number" min="1" max="2"><br/>
|
||||||
|
</div>
|
||||||
|
<div id="dmxInputOff">
|
||||||
|
<br><em style="color:darkorange">This firmware build does not include DMX Input support. <br></em>
|
||||||
|
</div>
|
||||||
|
<div id="dmxOnOff2">
|
||||||
|
<br><em style="color:darkorange">This firmware build does not include DMX output support. <br></em>
|
||||||
|
</div>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<h3>Alexa Voice Assistant</h3>
|
<h3>Alexa Voice Assistant</h3>
|
||||||
<div id="NoAlexa" class="hide">
|
<div id="NoAlexa" class="hide">
|
||||||
|
280
wled00/dmx_input.cpp
Normal file
280
wled00/dmx_input.cpp
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
#include "wled.h"
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#error DMX input is only supported on ESP32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dmx_input.h"
|
||||||
|
#include <rdm/responder.h>
|
||||||
|
|
||||||
|
void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
DMXInput *dmx = static_cast<DMXInput *>(context);
|
||||||
|
|
||||||
|
if (!dmx) {
|
||||||
|
DEBUG_PRINTLN("DMX: Error: no context in rdmPersonalityChangedCb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) {
|
||||||
|
const uint8_t personality = dmx_get_current_personality(dmx->inputPortNum);
|
||||||
|
DMXMode = std::min(DMX_MODE_PRESET, std::max(DMX_MODE_SINGLE_RGB, int(personality)));
|
||||||
|
doSerializeConfig = true;
|
||||||
|
DEBUG_PRINTF("DMX personality changed to to: %d\n", DMXMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
DMXInput *dmx = static_cast<DMXInput *>(context);
|
||||||
|
|
||||||
|
if (!dmx) {
|
||||||
|
DEBUG_PRINTLN("DMX: Error: no context in rdmAddressChangedCb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) {
|
||||||
|
const uint16_t addr = dmx_get_start_address(dmx->inputPortNum);
|
||||||
|
DMXAddress = std::min(512, int(addr));
|
||||||
|
doSerializeConfig = true;
|
||||||
|
DEBUG_PRINTF("DMX start addr changed to: %d\n", DMXAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static dmx_config_t createConfig()
|
||||||
|
{
|
||||||
|
dmx_config_t config;
|
||||||
|
config.pd_size = 255;
|
||||||
|
config.dmx_start_address = DMXAddress;
|
||||||
|
config.model_id = 0;
|
||||||
|
config.product_category = RDM_PRODUCT_CATEGORY_FIXTURE;
|
||||||
|
config.software_version_id = VERSION;
|
||||||
|
strcpy(config.device_label, "WLED_MM");
|
||||||
|
|
||||||
|
const std::string versionString = "WLED_V" + std::to_string(VERSION);
|
||||||
|
strncpy(config.software_version_label, versionString.c_str(), 32);
|
||||||
|
config.software_version_label[32] = '\0'; // zero termination in case versionString string was longer than 32 chars
|
||||||
|
|
||||||
|
config.personalities[0].description = "SINGLE_RGB";
|
||||||
|
config.personalities[0].footprint = 3;
|
||||||
|
config.personalities[1].description = "SINGLE_DRGB";
|
||||||
|
config.personalities[1].footprint = 4;
|
||||||
|
config.personalities[2].description = "EFFECT";
|
||||||
|
config.personalities[2].footprint = 15;
|
||||||
|
config.personalities[3].description = "MULTIPLE_RGB";
|
||||||
|
config.personalities[3].footprint = std::min(512, int(strip.getLengthTotal()) * 3);
|
||||||
|
config.personalities[4].description = "MULTIPLE_DRGB";
|
||||||
|
config.personalities[4].footprint = std::min(512, int(strip.getLengthTotal()) * 3 + 1);
|
||||||
|
config.personalities[5].description = "MULTIPLE_RGBW";
|
||||||
|
config.personalities[5].footprint = std::min(512, int(strip.getLengthTotal()) * 4);
|
||||||
|
config.personalities[6].description = "EFFECT_W";
|
||||||
|
config.personalities[6].footprint = 18;
|
||||||
|
config.personalities[7].description = "EFFECT_SEGMENT";
|
||||||
|
config.personalities[7].footprint = std::min(512, strip.getSegmentsNum() * 15);
|
||||||
|
config.personalities[8].description = "EFFECT_SEGMENT_W";
|
||||||
|
config.personalities[8].footprint = std::min(512, strip.getSegmentsNum() * 18);
|
||||||
|
config.personalities[9].description = "PRESET";
|
||||||
|
config.personalities[9].footprint = 1;
|
||||||
|
|
||||||
|
config.personality_count = 10;
|
||||||
|
// rdm personalities are numbered from 1, thus we can just set the DMXMode directly.
|
||||||
|
config.current_personality = DMXMode;
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmxReceiverTask(void *context)
|
||||||
|
{
|
||||||
|
DMXInput *instance = static_cast<DMXInput *>(context);
|
||||||
|
if (instance == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->installDriver()) {
|
||||||
|
while (true) {
|
||||||
|
instance->updateInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DMXInput::installDriver()
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto config = createConfig();
|
||||||
|
DEBUG_PRINTF("DMX port: %u\n", inputPortNum);
|
||||||
|
if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) {
|
||||||
|
DEBUG_PRINTF("Error: Failed to install dmx driver\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINTF("Listening for DMX on pin %u\n", rxPin);
|
||||||
|
DEBUG_PRINTF("Sending DMX on pin %u\n", txPin);
|
||||||
|
DEBUG_PRINTF("DMX enable pin is: %u\n", enPin);
|
||||||
|
dmx_set_pin(inputPortNum, txPin, rxPin, enPin);
|
||||||
|
|
||||||
|
rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this);
|
||||||
|
rdm_register_dmx_personality(inputPortNum, rdmPersonalityChangedCb, this);
|
||||||
|
initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_DMX_OUTPUT
|
||||||
|
//TODO add again once dmx output has been merged
|
||||||
|
// if(inputPortNum == dmxOutputPort)
|
||||||
|
// {
|
||||||
|
// DEBUG_PRINTF("DMXInput: Error: Input port == output port");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (inputPortNum <= (SOC_UART_NUM - 1) && inputPortNum > 0) {
|
||||||
|
this->inputPortNum = inputPortNum;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG_PRINTF("DMXInput: Error: invalid inputPortNum: %d\n", inputPortNum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rxPin > 0 && enPin > 0 && txPin > 0) {
|
||||||
|
|
||||||
|
const managed_pin_type pins[] = {
|
||||||
|
{(int8_t)txPin, false}, // these are not used as gpio pins, thus isOutput is always false.
|
||||||
|
{(int8_t)rxPin, false},
|
||||||
|
{(int8_t)enPin, false}};
|
||||||
|
const bool pinsAllocated = PinManager::allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT);
|
||||||
|
if (!pinsAllocated) {
|
||||||
|
DEBUG_PRINTF("DMXInput: Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n");
|
||||||
|
DEBUG_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(rxPin).c_str());
|
||||||
|
DEBUG_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(txPin).c_str());
|
||||||
|
DEBUG_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(enPin).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->rxPin = rxPin;
|
||||||
|
this->txPin = txPin;
|
||||||
|
this->enPin = enPin;
|
||||||
|
|
||||||
|
// put dmx receiver into seperate task because it should not be blocked
|
||||||
|
// pin to core 0 because wled is running on core 1
|
||||||
|
xTaskCreatePinnedToCore(dmxReceiverTask, "DMX_RCV_TASK", 10240, this, 2, &task, 0);
|
||||||
|
if (!task) {
|
||||||
|
DEBUG_PRINTF("Error: Failed to create dmx rcv task");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG_PRINTLN("DMX input disabled due to rxPin, enPin or txPin not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMXInput::updateInternal()
|
||||||
|
{
|
||||||
|
if (!initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAndUpdateConfig();
|
||||||
|
|
||||||
|
dmx_packet_t packet;
|
||||||
|
unsigned long now = millis();
|
||||||
|
if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) {
|
||||||
|
if (!packet.err) {
|
||||||
|
if(!connected) {
|
||||||
|
DEBUG_PRINTLN("DMX Input - connected");
|
||||||
|
}
|
||||||
|
connected = true;
|
||||||
|
identify = isIdentifyOn();
|
||||||
|
if (!packet.is_rdm) {
|
||||||
|
const std::lock_guard<std::mutex> lock(dmxDataLock);
|
||||||
|
dmx_read(inputPortNum, dmxdata, packet.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(connected) {
|
||||||
|
DEBUG_PRINTLN("DMX Input - disconnected");
|
||||||
|
}
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DMXInput::update()
|
||||||
|
{
|
||||||
|
if (identify) {
|
||||||
|
turnOnAllLeds();
|
||||||
|
}
|
||||||
|
else if (connected) {
|
||||||
|
const std::lock_guard<std::mutex> lock(dmxDataLock);
|
||||||
|
handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMXInput::turnOnAllLeds()
|
||||||
|
{
|
||||||
|
// TODO not sure if this is the correct way?
|
||||||
|
const uint16_t numPixels = strip.getLengthTotal();
|
||||||
|
for (uint16_t i = 0; i < numPixels; ++i)
|
||||||
|
{
|
||||||
|
strip.setPixelColor(i, 255, 255, 255, 255);
|
||||||
|
}
|
||||||
|
strip.setBrightness(255, true);
|
||||||
|
strip.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMXInput::disable()
|
||||||
|
{
|
||||||
|
if (initialized) {
|
||||||
|
dmx_driver_disable(inputPortNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DMXInput::enable()
|
||||||
|
{
|
||||||
|
if (initialized) {
|
||||||
|
dmx_driver_enable(inputPortNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DMXInput::isIdentifyOn() const
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t identify = 0;
|
||||||
|
const bool gotIdentify = rdm_get_identify_device(inputPortNum, &identify);
|
||||||
|
// gotIdentify should never be false because it is a default parameter in rdm
|
||||||
|
// but just in case we check for it anyway
|
||||||
|
return bool(identify) && gotIdentify;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMXInput::checkAndUpdateConfig()
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The global configuration variables are modified by the web interface.
|
||||||
|
* If they differ from the driver configuration, we have to update the driver
|
||||||
|
* configuration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t currentPersonality = dmx_get_current_personality(inputPortNum);
|
||||||
|
if (currentPersonality != DMXMode) {
|
||||||
|
DEBUG_PRINTF("DMX personality has changed from %d to %d\n", currentPersonality, DMXMode);
|
||||||
|
dmx_set_current_personality(inputPortNum, DMXMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t currentAddr = dmx_get_start_address(inputPortNum);
|
||||||
|
if (currentAddr != DMXAddress) {
|
||||||
|
DEBUG_PRINTF("DMX address has changed from %d to %d\n", currentAddr, DMXAddress);
|
||||||
|
dmx_set_start_address(inputPortNum, DMXAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
73
wled00/dmx_input.h
Normal file
73
wled00/dmx_input.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <esp_dmx.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for DMX/RDM input via serial (e.g. max485) on ESP32
|
||||||
|
* ESP32 Library from:
|
||||||
|
* https://github.com/someweisguy/esp_dmx
|
||||||
|
*/
|
||||||
|
class DMXInput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum);
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/**disable dmx receiver (do this before disabling the cache)*/
|
||||||
|
void disable();
|
||||||
|
void enable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @return true if rdm identify is active
|
||||||
|
bool isIdentifyOn() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the global dmx config has changed and updates the changes in rdm
|
||||||
|
*/
|
||||||
|
void checkAndUpdateConfig();
|
||||||
|
|
||||||
|
/// overrides everything and turns on all leds
|
||||||
|
void turnOnAllLeds();
|
||||||
|
|
||||||
|
/// installs the dmx driver
|
||||||
|
/// @return false on fail
|
||||||
|
bool installDriver();
|
||||||
|
|
||||||
|
/// is called by the dmx receive task regularly to receive new dmx data
|
||||||
|
void updateInternal();
|
||||||
|
|
||||||
|
// is invoked whenver the dmx start address is changed via rdm
|
||||||
|
friend void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
|
||||||
|
void *context);
|
||||||
|
|
||||||
|
// is invoked whenever the personality is changed via rdm
|
||||||
|
friend void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
|
||||||
|
void *context);
|
||||||
|
|
||||||
|
/// The internal dmx task.
|
||||||
|
/// This is the main loop of the dmx receiver. It never returns.
|
||||||
|
friend void dmxReceiverTask(void * context);
|
||||||
|
|
||||||
|
uint8_t inputPortNum = 255;
|
||||||
|
uint8_t rxPin = 255;
|
||||||
|
uint8_t txPin = 255;
|
||||||
|
uint8_t enPin = 255;
|
||||||
|
|
||||||
|
/// is written to by the dmx receive task.
|
||||||
|
byte dmxdata[DMX_PACKET_SIZE];
|
||||||
|
/// True once the dmx input has been initialized successfully
|
||||||
|
bool initialized = false; // true once init finished successfully
|
||||||
|
/// True if dmx is currently connected
|
||||||
|
std::atomic<bool> connected{false};
|
||||||
|
std::atomic<bool> identify{false};
|
||||||
|
/// Timestamp of the last time a dmx frame was received
|
||||||
|
unsigned long lastUpdate = 0;
|
||||||
|
|
||||||
|
/// Taskhandle of the dmx task that is running in the background
|
||||||
|
TaskHandle_t task;
|
||||||
|
/// Guards access to dmxData
|
||||||
|
std::mutex dmxDataLock;
|
||||||
|
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Support for DMX Output via MAX485.
|
* Support for DMX output via serial (e.g. MAX485).
|
||||||
* Change the output pin in src/dependencies/ESPDMX.cpp, if needed (ESP8266)
|
* Change the output pin in src/dependencies/ESPDMX.cpp, if needed (ESP8266)
|
||||||
* Change the output pin in src/dependencies/SparkFunDMX.cpp, if needed (ESP32)
|
* Change the output pin in src/dependencies/SparkFunDMX.cpp, if needed (ESP32)
|
||||||
* ESP8266 Library from:
|
* ESP8266 Library from:
|
||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
|
|
||||||
void handleDMX()
|
void handleDMXOutput()
|
||||||
{
|
{
|
||||||
// don't act, when in DMX Proxy mode
|
// don't act, when in DMX Proxy mode
|
||||||
if (e131ProxyUniverse != 0) return;
|
if (e131ProxyUniverse != 0) return;
|
||||||
@ -68,11 +68,14 @@ void handleDMX()
|
|||||||
dmx.update(); // update the DMX bus
|
dmx.update(); // update the DMX bus
|
||||||
}
|
}
|
||||||
|
|
||||||
void initDMX() {
|
void initDMXOutput() {
|
||||||
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
dmx.init(512); // initialize with bus length
|
dmx.init(512); // initialize with bus length
|
||||||
#else
|
#else
|
||||||
dmx.initWrite(512); // initialize with bus length
|
dmx.initWrite(512); // initialize with bus length
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void initDMXOutput(){}
|
||||||
|
void handleDMXOutput() {}
|
||||||
#endif
|
#endif
|
@ -116,6 +116,11 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
|
|
||||||
// update status info
|
// update status info
|
||||||
realtimeIP = clientIP;
|
realtimeIP = clientIP;
|
||||||
|
|
||||||
|
handleDMXData(uni, dmxChannels, e131_data, mde, previousUniverses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8_t mde, uint8_t previousUniverses) {
|
||||||
byte wChannel = 0;
|
byte wChannel = 0;
|
||||||
unsigned totalLen = strip.getLengthTotal();
|
unsigned totalLen = strip.getLengthTotal();
|
||||||
unsigned availDMXLen = 0;
|
unsigned availDMXLen = 0;
|
||||||
@ -130,7 +135,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DMX data in Art-Net packet starts at index 0, for E1.31 at index 1
|
// DMX data in Art-Net packet starts at index 0, for E1.31 at index 1
|
||||||
if (protocol == P_ARTNET && dataOffset > 0) {
|
if (mde == REALTIME_MODE_ARTNET && dataOffset > 0) {
|
||||||
dataOffset--;
|
dataOffset--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +216,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
else
|
else
|
||||||
dataOffset = DMXAddress;
|
dataOffset = DMXAddress;
|
||||||
// Modify address for Art-Net data
|
// Modify address for Art-Net data
|
||||||
if (protocol == P_ARTNET && dataOffset > 0)
|
if (mde == REALTIME_MODE_ARTNET && dataOffset > 0)
|
||||||
dataOffset--;
|
dataOffset--;
|
||||||
// Skip out of universe addresses
|
// Skip out of universe addresses
|
||||||
if (dataOffset > dmxChannels - dmxEffectChannels + 1)
|
if (dataOffset > dmxChannels - dmxEffectChannels + 1)
|
||||||
@ -285,7 +290,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// All subsequent universes start at the first channel.
|
// All subsequent universes start at the first channel.
|
||||||
dmxOffset = (protocol == P_ARTNET) ? 0 : 1;
|
dmxOffset = (mde == REALTIME_MODE_ARTNET) ? 0 : 1;
|
||||||
const unsigned dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0;
|
const unsigned dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0;
|
||||||
unsigned ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed;
|
unsigned ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed;
|
||||||
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * ledsPerUniverse;
|
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * ledsPerUniverse;
|
||||||
|
@ -163,12 +163,12 @@ class NeoGammaWLEDMethod {
|
|||||||
};
|
};
|
||||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||||
[[gnu::hot]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
|
[[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
|
||||||
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
|
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
|
||||||
[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
||||||
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
[[gnu::hot, gnu::pure]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
||||||
[[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
|
[[gnu::hot, gnu::pure]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
|
||||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
|
CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette);
|
||||||
CRGBPalette16 generateRandomPalette();
|
CRGBPalette16 generateRandomPalette();
|
||||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||||
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb);
|
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb);
|
||||||
@ -178,33 +178,38 @@ inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) <<
|
|||||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||||
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
||||||
void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO
|
void colorRGBtoXY(const byte* rgb, float* xy); // only defined if huesync disabled TODO
|
||||||
void colorFromDecOrHexString(byte* rgb, char* in);
|
void colorFromDecOrHexString(byte* rgb, const char* in);
|
||||||
bool colorFromHexString(byte* rgb, const char* in);
|
bool colorFromHexString(byte* rgb, const char* in);
|
||||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||||
void setRandomColor(byte* rgb);
|
void setRandomColor(byte* rgb);
|
||||||
|
|
||||||
//dmx.cpp
|
//dmx_output.cpp
|
||||||
void initDMX();
|
void initDMXOutput();
|
||||||
void handleDMX();
|
void handleDMXOutput();
|
||||||
|
|
||||||
|
//dmx_input.cpp
|
||||||
|
void initDMXInput();
|
||||||
|
void handleDMXInput();
|
||||||
|
|
||||||
//e131.cpp
|
//e131.cpp
|
||||||
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol);
|
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol);
|
||||||
|
void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8_t mde, uint8_t previousUniverses);
|
||||||
void handleArtnetPollReply(IPAddress ipAddress);
|
void handleArtnetPollReply(IPAddress ipAddress);
|
||||||
void prepareArtnetPollReply(ArtPollReply* reply);
|
void prepareArtnetPollReply(ArtPollReply* reply);
|
||||||
void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t portAddress);
|
void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t portAddress);
|
||||||
|
|
||||||
//file.cpp
|
//file.cpp
|
||||||
bool handleFileRead(AsyncWebServerRequest*, String path);
|
bool handleFileRead(AsyncWebServerRequest*, String path);
|
||||||
bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content);
|
bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content);
|
||||||
bool writeObjectToFile(const char* file, const char* key, JsonDocument* content);
|
bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content);
|
||||||
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest);
|
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest);
|
||||||
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest);
|
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest);
|
||||||
void updateFSInfo();
|
void updateFSInfo();
|
||||||
void closeFile();
|
void closeFile();
|
||||||
inline bool writeObjectToFileUsingId(const String &file, uint16_t id, JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); };
|
inline bool writeObjectToFileUsingId(const String &file, uint16_t id, const JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); };
|
||||||
inline bool writeObjectToFile(const String &file, const char* key, JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); };
|
inline bool writeObjectToFile(const String &file, const char* key, const JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); };
|
||||||
inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest) { return readObjectFromFileUsingId(file.c_str(), id, dest); };
|
inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest) { return readObjectFromFileUsingId(file.c_str(), id, dest); };
|
||||||
inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest) { return readObjectFromFile(file.c_str(), key, dest); };
|
inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest) { return readObjectFromFile(file.c_str(), key, dest); };
|
||||||
|
|
||||||
@ -245,11 +250,11 @@ void handleIR();
|
|||||||
|
|
||||||
bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
|
bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
|
||||||
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
|
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
|
||||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
||||||
void serializeInfo(JsonObject root);
|
void serializeInfo(JsonObject root);
|
||||||
void serializeModeNames(JsonArray root);
|
void serializeModeNames(JsonArray arr);
|
||||||
void serializeModeData(JsonArray root);
|
void serializeModeData(JsonArray fxdata);
|
||||||
void serveJson(AsyncWebServerRequest* request);
|
void serveJson(AsyncWebServerRequest* request);
|
||||||
#ifdef WLED_ENABLE_JSONLIVE
|
#ifdef WLED_ENABLE_JSONLIVE
|
||||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||||
@ -320,7 +325,8 @@ void deletePreset(byte index);
|
|||||||
bool getPresetName(byte index, String& name);
|
bool getPresetName(byte index, String& name);
|
||||||
|
|
||||||
//remote.cpp
|
//remote.cpp
|
||||||
void handleRemote(uint8_t *data, size_t len);
|
void handleWiZdata(uint8_t *incomingData, size_t len);
|
||||||
|
void handleRemote();
|
||||||
|
|
||||||
//set.cpp
|
//set.cpp
|
||||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||||
@ -329,7 +335,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=tru
|
|||||||
|
|
||||||
//udp.cpp
|
//udp.cpp
|
||||||
void notify(byte callMode, bool followUp=false);
|
void notify(byte callMode, bool followUp=false);
|
||||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false);
|
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false);
|
||||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||||
void exitRealtime();
|
void exitRealtime();
|
||||||
void handleNotifications();
|
void handleNotifications();
|
||||||
@ -424,36 +430,33 @@ class Usermod {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class UsermodManager {
|
namespace UsermodManager {
|
||||||
private:
|
extern byte numMods;
|
||||||
static Usermod* ums[WLED_MAX_USERMODS];
|
|
||||||
static byte numMods;
|
|
||||||
|
|
||||||
public:
|
void loop();
|
||||||
static void loop();
|
void handleOverlayDraw();
|
||||||
static void handleOverlayDraw();
|
bool handleButton(uint8_t b);
|
||||||
static bool handleButton(uint8_t b);
|
bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods
|
||||||
static bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods
|
void setup();
|
||||||
static void setup();
|
void connected();
|
||||||
static void connected();
|
void appendConfigData(Print&);
|
||||||
static void appendConfigData(Print&);
|
void addToJsonState(JsonObject& obj);
|
||||||
static void addToJsonState(JsonObject& obj);
|
void addToJsonInfo(JsonObject& obj);
|
||||||
static void addToJsonInfo(JsonObject& obj);
|
void readFromJsonState(JsonObject& obj);
|
||||||
static void readFromJsonState(JsonObject& obj);
|
void addToConfig(JsonObject& obj);
|
||||||
static void addToConfig(JsonObject& obj);
|
bool readFromConfig(JsonObject& obj);
|
||||||
static bool readFromConfig(JsonObject& obj);
|
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
static void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
static bool onMqttMessage(char* topic, char* payload);
|
bool onMqttMessage(char* topic, char* payload);
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_DISABLE_ESPNOW
|
#ifndef WLED_DISABLE_ESPNOW
|
||||||
static bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
|
bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
|
||||||
#endif
|
#endif
|
||||||
static void onUpdateBegin(bool);
|
void onUpdateBegin(bool);
|
||||||
static void onStateChange(uint8_t);
|
void onStateChange(uint8_t);
|
||||||
static bool add(Usermod* um);
|
bool add(Usermod* um);
|
||||||
static Usermod* lookup(uint16_t mod_id);
|
Usermod* lookup(uint16_t mod_id);
|
||||||
static inline byte getModCount() {return numMods;};
|
inline byte getModCount() {return numMods;};
|
||||||
};
|
};
|
||||||
|
|
||||||
//usermods_list.cpp
|
//usermods_list.cpp
|
||||||
@ -472,10 +475,10 @@ void userLoop();
|
|||||||
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
||||||
#endif
|
#endif
|
||||||
#define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0)
|
#define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0)
|
||||||
int getNumVal(const String* req, uint16_t pos);
|
[[gnu::pure]] int getNumVal(const String* req, uint16_t pos);
|
||||||
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
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); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form)
|
||||||
bool getBoolVal(JsonVariant elem, bool dflt);
|
[[gnu::pure]] bool getBoolVal(const JsonVariant &elem, bool dflt);
|
||||||
bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255);
|
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);
|
size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val);
|
||||||
size_t printSetFormValue(Print& settingsScript, const char* key, int val);
|
size_t printSetFormValue(Print& settingsScript, const char* key, int val);
|
||||||
@ -483,8 +486,8 @@ size_t printSetFormValue(Print& settingsScript, const char* key, const char* val
|
|||||||
size_t printSetFormIndex(Print& settingsScript, const char* key, int index);
|
size_t printSetFormIndex(Print& settingsScript, const char* key, int index);
|
||||||
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val);
|
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val);
|
||||||
void prepareHostname(char* hostname);
|
void prepareHostname(char* hostname);
|
||||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
[[gnu::pure]] bool isAsterisksOnly(const char* str, byte maxLen);
|
||||||
bool requestJSONBufferLock(uint8_t module=255);
|
bool requestJSONBufferLock(uint8_t moduleID=255);
|
||||||
void releaseJSONBufferLock();
|
void releaseJSONBufferLock();
|
||||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
||||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
|
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
|
||||||
@ -496,8 +499,9 @@ uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest = 0, uint16_t hig
|
|||||||
uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0);
|
uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0);
|
||||||
um_data_t* simulateSound(uint8_t simulationId);
|
um_data_t* simulateSound(uint8_t simulationId);
|
||||||
void enumerateLedmaps();
|
void enumerateLedmaps();
|
||||||
uint8_t get_random_wheel_index(uint8_t pos);
|
[[gnu::hot]] uint8_t get_random_wheel_index(uint8_t pos);
|
||||||
float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
[[gnu::hot, gnu::pure]] float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
||||||
|
uint32_t hashInt(uint32_t s);
|
||||||
|
|
||||||
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
||||||
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
||||||
@ -557,6 +561,7 @@ float asin_t(float x);
|
|||||||
template <typename T> T atan_t(T x);
|
template <typename T> T atan_t(T x);
|
||||||
float floor_t(float x);
|
float floor_t(float x);
|
||||||
float fmod_t(float num, float denom);
|
float fmod_t(float num, float denom);
|
||||||
|
uint32_t sqrt32_bw(uint32_t x);
|
||||||
#define sin_t sin_approx
|
#define sin_t sin_approx
|
||||||
#define cos_t cos_approx
|
#define cos_t cos_approx
|
||||||
#define tan_t tan_approx
|
#define tan_t tan_approx
|
||||||
|
@ -176,7 +176,7 @@ static void writeSpace(size_t l)
|
|||||||
if (knownLargestSpace < l) knownLargestSpace = l;
|
if (knownLargestSpace < l) knownLargestSpace = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint32_t contentLen = 0)
|
static bool appendObjectToFile(const char* key, const JsonDocument* content, uint32_t s, uint32_t contentLen = 0)
|
||||||
{
|
{
|
||||||
#ifdef WLED_DEBUG_FS
|
#ifdef WLED_DEBUG_FS
|
||||||
DEBUGFS_PRINTLN(F("Append"));
|
DEBUGFS_PRINTLN(F("Append"));
|
||||||
@ -255,14 +255,14 @@ bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content)
|
bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content)
|
||||||
{
|
{
|
||||||
char objKey[10];
|
char objKey[10];
|
||||||
sprintf(objKey, "\"%d\":", id);
|
sprintf(objKey, "\"%d\":", id);
|
||||||
return writeObjectToFile(file, objKey, content);
|
return writeObjectToFile(file, objKey, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeObjectToFile(const char* file, const char* key, JsonDocument* content)
|
bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content)
|
||||||
{
|
{
|
||||||
uint32_t s = 0; //timing
|
uint32_t s = 0; //timing
|
||||||
#ifdef WLED_DEBUG_FS
|
#ifdef WLED_DEBUG_FS
|
||||||
|
@ -68,7 +68,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
if (elem["n"]) {
|
if (elem["n"]) {
|
||||||
// name field exists
|
// name field exists
|
||||||
if (seg.name) { //clear old name
|
if (seg.name) { //clear old name
|
||||||
delete[] seg.name;
|
free(seg.name);
|
||||||
seg.name = nullptr;
|
seg.name = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
if (name != nullptr) len = strlen(name);
|
if (name != nullptr) len = strlen(name);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
|
if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
|
||||||
seg.name = new char[len+1];
|
seg.name = static_cast<char*>(malloc(len+1));
|
||||||
if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
|
if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
|
||||||
} else {
|
} else {
|
||||||
// but is empty (already deleted above)
|
// but is empty (already deleted above)
|
||||||
@ -86,7 +86,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
} else if (start != seg.start || stop != seg.stop) {
|
} else if (start != seg.start || stop != seg.stop) {
|
||||||
// clearing or setting segment without name field
|
// clearing or setting segment without name field
|
||||||
if (seg.name) {
|
if (seg.name) {
|
||||||
delete[] seg.name;
|
free(seg.name);
|
||||||
seg.name = nullptr;
|
seg.name = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,15 +332,20 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
tr = root[F("transition")] | -1;
|
tr = root[F("transition")] | -1;
|
||||||
if (tr >= 0) {
|
if (tr >= 0) {
|
||||||
transitionDelay = tr * 100;
|
transitionDelay = tr * 100;
|
||||||
if (fadeTransition) strip.setTransition(transitionDelay);
|
strip.setTransition(transitionDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
blendingStyle = root[F("bs")] | blendingStyle;
|
||||||
|
blendingStyle = constrain(blendingStyle, 0, BLEND_STYLE_COUNT-1);
|
||||||
|
#endif
|
||||||
|
|
||||||
// temporary transition (applies only once)
|
// temporary transition (applies only once)
|
||||||
tr = root[F("tt")] | -1;
|
tr = root[F("tt")] | -1;
|
||||||
if (tr >= 0) {
|
if (tr >= 0) {
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
if (fadeTransition) strip.setTransition(tr * 100);
|
strip.setTransition(tr * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr = root[F("tb")] | -1;
|
tr = root[F("tb")] | -1;
|
||||||
@ -493,7 +498,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
return stateResponse;
|
return stateResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||||
{
|
{
|
||||||
root["id"] = id;
|
root["id"] = id;
|
||||||
if (segmentBounds) {
|
if (segmentBounds) {
|
||||||
@ -568,6 +573,9 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
root["on"] = (bri > 0);
|
root["on"] = (bri > 0);
|
||||||
root["bri"] = briLast;
|
root["bri"] = briLast;
|
||||||
root[F("transition")] = transitionDelay/100; //in 100ms
|
root[F("transition")] = transitionDelay/100; //in 100ms
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
root[F("bs")] = blendingStyle;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forPreset) {
|
if (!forPreset) {
|
||||||
@ -761,7 +769,7 @@ void serializeInfo(JsonObject root)
|
|||||||
|
|
||||||
root[F("freeheap")] = ESP.getFreeHeap();
|
root[F("freeheap")] = ESP.getFreeHeap();
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
if (psramSafe && psramFound()) root[F("psram")] = ESP.getFreePsram();
|
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||||
#endif
|
#endif
|
||||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||||
|
|
||||||
|
@ -71,10 +71,9 @@ byte scaledBri(byte in)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//applies global brightness
|
//applies global temporary brightness (briT) to strip
|
||||||
void applyBri() {
|
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);
|
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
||||||
strip.setBrightness(scaledBri(briT));
|
strip.setBrightness(scaledBri(briT));
|
||||||
}
|
}
|
||||||
@ -86,6 +85,7 @@ void applyFinalBri() {
|
|||||||
briOld = bri;
|
briOld = bri;
|
||||||
briT = bri;
|
briT = bri;
|
||||||
applyBri();
|
applyBri();
|
||||||
|
strip.trigger(); // force one last update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,30 +129,23 @@ void stateUpdated(byte callMode) {
|
|||||||
// notify usermods of state change
|
// notify usermods of state change
|
||||||
UsermodManager::onStateChange(callMode);
|
UsermodManager::onStateChange(callMode);
|
||||||
|
|
||||||
if (fadeTransition) {
|
if (strip.getTransition() == 0) {
|
||||||
if (strip.getTransition() == 0) {
|
jsonTransitionOnce = false;
|
||||||
jsonTransitionOnce = false;
|
transitionActive = false;
|
||||||
transitionActive = false;
|
|
||||||
applyFinalBri();
|
|
||||||
strip.trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transitionActive) {
|
|
||||||
briOld = briT;
|
|
||||||
} else
|
|
||||||
strip.setTransitionMode(true); // force all segments to transition mode
|
|
||||||
transitionActive = true;
|
|
||||||
transitionStartTime = millis();
|
|
||||||
} else {
|
|
||||||
applyFinalBri();
|
applyFinalBri();
|
||||||
strip.trigger();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (transitionActive) {
|
||||||
|
briOld = briT;
|
||||||
|
} else
|
||||||
|
strip.setTransitionMode(true); // force all segments to transition mode
|
||||||
|
transitionActive = true;
|
||||||
|
transitionStartTime = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void updateInterfaces(uint8_t callMode)
|
void updateInterfaces(uint8_t callMode) {
|
||||||
{
|
|
||||||
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
|
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
|
||||||
|
|
||||||
sendDataWs();
|
sendDataWs();
|
||||||
@ -173,8 +166,7 @@ void updateInterfaces(uint8_t callMode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleTransitions()
|
void handleTransitions() {
|
||||||
{
|
|
||||||
//handle still pending interface update
|
//handle still pending interface update
|
||||||
updateInterfaces(interfaceUpdateCallMode);
|
updateInterfaces(interfaceUpdateCallMode);
|
||||||
|
|
||||||
@ -205,8 +197,7 @@ void colorUpdated(byte callMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleNightlight()
|
void handleNightlight() {
|
||||||
{
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; // take care of millis() rollover
|
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; // take care of millis() rollover
|
||||||
if (now - lastNlUpdate < 100) return; // allow only 10 NL updates per second
|
if (now - lastNlUpdate < 100) return; // allow only 10 NL updates per second
|
||||||
@ -286,7 +277,6 @@ void handleNightlight()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//utility for FastLED to use our custom timer
|
//utility for FastLED to use our custom timer
|
||||||
uint32_t get_millisecond_timer()
|
uint32_t get_millisecond_timer() {
|
||||||
{
|
|
||||||
return strip.now;
|
return strip.now;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ bool parseLx(int lxValue, byte* rgbw)
|
|||||||
} else if ((lxValue >= 200000000) && (lxValue <= 201006500)) {
|
} else if ((lxValue >= 200000000) && (lxValue <= 201006500)) {
|
||||||
// Loxone Lumitech
|
// Loxone Lumitech
|
||||||
ok = true;
|
ok = true;
|
||||||
float tmpBri = floor((lxValue - 200000000) / 10000); ;
|
float tmpBri = floor((lxValue - 200000000) / 10000);
|
||||||
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
|
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
|
||||||
|
|
||||||
tmpBri *= 2.55f;
|
tmpBri *= 2.55f;
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
|
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
|
||||||
|
|
||||||
|
#if MQTT_MAX_TOPIC_LEN > 32
|
||||||
|
#warning "MQTT topics length > 32 is not recommended for compatibility with usermods!"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void parseMQTTBriPayload(char* payload)
|
static void parseMQTTBriPayload(char* payload)
|
||||||
{
|
{
|
||||||
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||||
@ -23,24 +27,24 @@ static void parseMQTTBriPayload(char* payload)
|
|||||||
static void onMqttConnect(bool sessionPresent)
|
static void onMqttConnect(bool sessionPresent)
|
||||||
{
|
{
|
||||||
//(re)subscribe to required topics
|
//(re)subscribe to required topics
|
||||||
char subuf[38];
|
char subuf[MQTT_MAX_TOPIC_LEN + 6];
|
||||||
|
|
||||||
if (mqttDeviceTopic[0] != 0) {
|
if (mqttDeviceTopic[0] != 0) {
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
mqtt->subscribe(subuf, 0);
|
mqtt->subscribe(subuf, 0);
|
||||||
strcat_P(subuf, PSTR("/col"));
|
strcat_P(subuf, PSTR("/col"));
|
||||||
mqtt->subscribe(subuf, 0);
|
mqtt->subscribe(subuf, 0);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(subuf, PSTR("/api"));
|
strcat_P(subuf, PSTR("/api"));
|
||||||
mqtt->subscribe(subuf, 0);
|
mqtt->subscribe(subuf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mqttGroupTopic[0] != 0) {
|
if (mqttGroupTopic[0] != 0) {
|
||||||
strlcpy(subuf, mqttGroupTopic, 33);
|
strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
mqtt->subscribe(subuf, 0);
|
mqtt->subscribe(subuf, 0);
|
||||||
strcat_P(subuf, PSTR("/col"));
|
strcat_P(subuf, PSTR("/col"));
|
||||||
mqtt->subscribe(subuf, 0);
|
mqtt->subscribe(subuf, 0);
|
||||||
strlcpy(subuf, mqttGroupTopic, 33);
|
strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(subuf, PSTR("/api"));
|
strcat_P(subuf, PSTR("/api"));
|
||||||
mqtt->subscribe(subuf, 0);
|
mqtt->subscribe(subuf, 0);
|
||||||
}
|
}
|
||||||
@ -64,8 +68,8 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (index == 0) { // start (1st partial packet or the only packet)
|
if (index == 0) { // start (1st partial packet or the only packet)
|
||||||
if (payloadStr) delete[] payloadStr; // fail-safe: release buffer
|
if (payloadStr) free(payloadStr); // fail-safe: release buffer
|
||||||
payloadStr = new char[total+1]; // allocate new buffer
|
payloadStr = static_cast<char*>(malloc(total+1)); // allocate new buffer
|
||||||
}
|
}
|
||||||
if (payloadStr == nullptr) return; // buffer not allocated
|
if (payloadStr == nullptr) return; // buffer not allocated
|
||||||
|
|
||||||
@ -90,7 +94,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
|||||||
} else {
|
} else {
|
||||||
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
|
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
|
||||||
UsermodManager::onMqttMessage(topic, payloadStr);
|
UsermodManager::onMqttMessage(topic, payloadStr);
|
||||||
delete[] payloadStr;
|
free(payloadStr);
|
||||||
payloadStr = nullptr;
|
payloadStr = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -120,7 +124,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
|||||||
// topmost topic (just wled/MAC)
|
// topmost topic (just wled/MAC)
|
||||||
parseMQTTBriPayload(payloadStr);
|
parseMQTTBriPayload(payloadStr);
|
||||||
}
|
}
|
||||||
delete[] payloadStr;
|
free(payloadStr);
|
||||||
payloadStr = nullptr;
|
payloadStr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,19 +162,19 @@ void publishMqtt()
|
|||||||
|
|
||||||
#ifndef USERMOD_SMARTNEST
|
#ifndef USERMOD_SMARTNEST
|
||||||
char s[10];
|
char s[10];
|
||||||
char subuf[48];
|
char subuf[MQTT_MAX_TOPIC_LEN + 16];
|
||||||
|
|
||||||
sprintf_P(s, PSTR("%u"), bri);
|
sprintf_P(s, PSTR("%u"), bri);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(subuf, PSTR("/g"));
|
strcat_P(subuf, PSTR("/g"));
|
||||||
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||||
|
|
||||||
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(subuf, PSTR("/c"));
|
strcat_P(subuf, PSTR("/c"));
|
||||||
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||||
|
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(subuf, PSTR("/status"));
|
strcat_P(subuf, PSTR("/status"));
|
||||||
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
|
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
|
||||||
|
|
||||||
@ -178,7 +182,7 @@ void publishMqtt()
|
|||||||
DynamicBuffer buf(1024);
|
DynamicBuffer buf(1024);
|
||||||
bufferPrint pbuf(buf.data(), buf.size());
|
bufferPrint pbuf(buf.data(), buf.size());
|
||||||
XML_response(pbuf);
|
XML_response(pbuf);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(subuf, PSTR("/v"));
|
strcat_P(subuf, PSTR("/v"));
|
||||||
mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263)
|
mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263)
|
||||||
#endif
|
#endif
|
||||||
@ -211,7 +215,7 @@ bool initMqtt()
|
|||||||
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
||||||
|
|
||||||
#ifndef USERMOD_SMARTNEST
|
#ifndef USERMOD_SMARTNEST
|
||||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
strlcpy(mqttStatusTopic, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
|
||||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||||
#endif
|
#endif
|
||||||
|
@ -224,7 +224,7 @@ void sendNTPPacket()
|
|||||||
ntpUdp.endPacket();
|
ntpUdp.endPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isValidNtpResponse(byte * ntpPacket) {
|
static bool isValidNtpResponse(const byte* ntpPacket) {
|
||||||
// Perform a few validity checks on the packet
|
// Perform a few validity checks on the packet
|
||||||
// based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp
|
// based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp
|
||||||
if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC
|
if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC
|
||||||
|
@ -13,6 +13,16 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Pin management state variables
|
||||||
|
#ifdef ESP8266
|
||||||
|
static uint32_t pinAlloc = 0UL; // 1 bit per pin, we use first 17bits
|
||||||
|
#else
|
||||||
|
static uint64_t pinAlloc = 0ULL; // 1 bit per pin, we use 50 bits on ESP32-S3
|
||||||
|
static uint16_t ledcAlloc = 0; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS)
|
||||||
|
#endif
|
||||||
|
static uint8_t i2cAllocCount = 0; // allow multiple allocation of I2C bus pins but keep track of allocations
|
||||||
|
static uint8_t spiAllocCount = 0; // allow multiple allocation of SPI bus pins but keep track of allocations
|
||||||
|
static PinOwner ownerTag[WLED_NUM_PINS] = { PinOwner::None };
|
||||||
|
|
||||||
/// Actual allocation/deallocation routines
|
/// Actual allocation/deallocation routines
|
||||||
bool PinManager::deallocatePin(byte gpio, PinOwner tag)
|
bool PinManager::deallocatePin(byte gpio, PinOwner tag)
|
||||||
@ -131,7 +141,9 @@ bool PinManager::allocateMultiplePins(const managed_pin_type * mptArray, byte ar
|
|||||||
bool PinManager::allocatePin(byte gpio, bool output, PinOwner tag)
|
bool PinManager::allocatePin(byte gpio, bool output, PinOwner tag)
|
||||||
{
|
{
|
||||||
// HW I2C & SPI pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair
|
// HW I2C & SPI pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair
|
||||||
if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) {
|
// DMX_INPUT pins have to be allocated using allocateMultiplePins variant since there is always RX/TX/EN triple
|
||||||
|
if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI
|
||||||
|
|| tag==PinOwner::DMX_INPUT) {
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
if (gpio < 255) { // 255 (-1) is the "not defined GPIO"
|
if (gpio < 255) { // 255 (-1) is the "not defined GPIO"
|
||||||
if (!isPinOk(gpio, output)) {
|
if (!isPinOk(gpio, output)) {
|
||||||
@ -214,8 +226,20 @@ bool PinManager::isPinOk(byte gpio, bool output)
|
|||||||
// JTAG: GPIO39-42 are usually used for inline debugging
|
// JTAG: GPIO39-42 are usually used for inline debugging
|
||||||
// GPIO46 is input only and pulled down
|
// GPIO46 is input only and pulled down
|
||||||
#else
|
#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)
|
if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO)
|
||||||
#endif
|
#endif
|
||||||
if (output) return digitalPinCanOutput(gpio);
|
if (output) return digitalPinCanOutput(gpio);
|
||||||
@ -278,13 +302,3 @@ void PinManager::deallocateLedc(byte pos, byte channels)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
uint32_t PinManager::pinAlloc = 0UL;
|
|
||||||
#else
|
|
||||||
uint64_t PinManager::pinAlloc = 0ULL;
|
|
||||||
uint16_t PinManager::ledcAlloc = 0;
|
|
||||||
#endif
|
|
||||||
uint8_t PinManager::i2cAllocCount = 0;
|
|
||||||
uint8_t PinManager::spiAllocCount = 0;
|
|
||||||
PinOwner PinManager::ownerTag[WLED_NUM_PINS] = { PinOwner::None };
|
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "const.h" // for USERMOD_* values
|
#include "const.h" // for USERMOD_* values
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17)
|
||||||
|
#else
|
||||||
|
#define WLED_NUM_PINS (GPIO_PIN_COUNT)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct PinManagerPinType {
|
typedef struct PinManagerPinType {
|
||||||
int8_t pin;
|
int8_t pin;
|
||||||
bool isOutput;
|
bool isOutput;
|
||||||
@ -29,15 +35,16 @@ enum struct PinOwner : uint8_t {
|
|||||||
Ethernet = 0x81,
|
Ethernet = 0x81,
|
||||||
BusDigital = 0x82,
|
BusDigital = 0x82,
|
||||||
BusOnOff = 0x83,
|
BusOnOff = 0x83,
|
||||||
BusPwm = 0x84, // 'BusP' == PWM output using BusPwm
|
BusPwm = 0x84, // 'BusP' == PWM output using BusPwm
|
||||||
Button = 0x85, // 'Butn' == button from configuration
|
Button = 0x85, // 'Butn' == button from configuration
|
||||||
IR = 0x86, // 'IR' == IR receiver pin from configuration
|
IR = 0x86, // 'IR' == IR receiver pin from configuration
|
||||||
Relay = 0x87, // 'Rly' == Relay pin from configuration
|
Relay = 0x87, // 'Rly' == Relay pin from configuration
|
||||||
SPI_RAM = 0x88, // 'SpiR' == SPI RAM
|
SPI_RAM = 0x88, // 'SpiR' == SPI RAM
|
||||||
DebugOut = 0x89, // 'Dbg' == debug output always IO1
|
DebugOut = 0x89, // 'Dbg' == debug output always IO1
|
||||||
DMX = 0x8A, // 'DMX' == hard-coded to IO2
|
DMX = 0x8A, // 'DMX' == hard-coded to IO2
|
||||||
HW_I2C = 0x8B, // 'I2C' == hardware I2C pins (4&5 on ESP8266, 21&22 on ESP32)
|
HW_I2C = 0x8B, // 'I2C' == hardware I2C pins (4&5 on ESP8266, 21&22 on ESP32)
|
||||||
HW_SPI = 0x8C, // 'SPI' == hardware (V)SPI pins (13,14&15 on ESP8266, 5,18&23 on ESP32)
|
HW_SPI = 0x8C, // 'SPI' == hardware (V)SPI pins (13,14&15 on ESP8266, 5,18&23 on ESP32)
|
||||||
|
DMX_INPUT = 0x8D, // 'DMX_INPUT' == DMX input via serial
|
||||||
// Use UserMod IDs from const.h here
|
// Use UserMod IDs from const.h here
|
||||||
UM_Unspecified = USERMOD_ID_UNSPECIFIED, // 0x01
|
UM_Unspecified = USERMOD_ID_UNSPECIFIED, // 0x01
|
||||||
UM_Example = USERMOD_ID_EXAMPLE, // 0x02 // Usermod "usermod_v2_example.h"
|
UM_Example = USERMOD_ID_EXAMPLE, // 0x02 // Usermod "usermod_v2_example.h"
|
||||||
@ -70,53 +77,39 @@ enum struct PinOwner : uint8_t {
|
|||||||
};
|
};
|
||||||
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
||||||
|
|
||||||
class PinManager {
|
namespace PinManager {
|
||||||
private:
|
// De-allocates a single pin
|
||||||
#ifdef ESP8266
|
bool deallocatePin(byte gpio, PinOwner tag);
|
||||||
#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17)
|
// De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified)
|
||||||
static uint32_t pinAlloc; // 1 bit per pin, we use first 17bits
|
bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag);
|
||||||
#else
|
bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag);
|
||||||
#define WLED_NUM_PINS (GPIO_PIN_COUNT)
|
// Allocates a single pin, with an owner tag.
|
||||||
static uint64_t pinAlloc; // 1 bit per pin, we use 50 bits on ESP32-S3
|
// De-allocation requires the same owner tag (or override)
|
||||||
static uint16_t ledcAlloc; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS)
|
bool allocatePin(byte gpio, bool output, PinOwner tag);
|
||||||
#endif
|
// Allocates all the pins, or allocates none of the pins, with owner tag.
|
||||||
static uint8_t i2cAllocCount; // allow multiple allocation of I2C bus pins but keep track of allocations
|
// Provided to simplify error condition handling in clients
|
||||||
static uint8_t spiAllocCount; // allow multiple allocation of SPI bus pins but keep track of allocations
|
// using more than one pin, such as I2C, SPI, rotary encoders,
|
||||||
static PinOwner ownerTag[WLED_NUM_PINS];
|
// ethernet, etc..
|
||||||
|
bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag );
|
||||||
|
|
||||||
public:
|
[[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]]
|
||||||
// De-allocates a single pin
|
inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); }
|
||||||
static bool deallocatePin(byte gpio, PinOwner tag);
|
[[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]]
|
||||||
// De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified)
|
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
||||||
static bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag);
|
|
||||||
static bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag);
|
|
||||||
// Allocates a single pin, with an owner tag.
|
|
||||||
// De-allocation requires the same owner tag (or override)
|
|
||||||
static bool allocatePin(byte gpio, bool output, PinOwner tag);
|
|
||||||
// Allocates all the pins, or allocates none of the pins, with owner tag.
|
|
||||||
// Provided to simplify error condition handling in clients
|
|
||||||
// using more than one pin, such as I2C, SPI, rotary encoders,
|
|
||||||
// ethernet, etc..
|
|
||||||
static bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag );
|
|
||||||
|
|
||||||
[[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]]
|
// will return true for reserved pins
|
||||||
static inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); }
|
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
||||||
[[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]]
|
// will return false for reserved pins
|
||||||
static inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
bool isPinOk(byte gpio, bool output = true);
|
||||||
|
|
||||||
// will return true for reserved pins
|
bool isReadOnlyPin(byte gpio);
|
||||||
static bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
|
||||||
// will return false for reserved pins
|
|
||||||
static bool isPinOk(byte gpio, bool output = true);
|
|
||||||
|
|
||||||
static bool isReadOnlyPin(byte gpio);
|
PinOwner getPinOwner(byte gpio);
|
||||||
|
|
||||||
static PinOwner getPinOwner(byte gpio);
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
byte allocateLedc(byte channels);
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
void deallocateLedc(byte pos, byte channels);
|
||||||
static byte allocateLedc(byte channels);
|
#endif
|
||||||
static void deallocateLedc(byte pos, byte channels);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//extern PinManager pinManager;
|
//extern PinManager pinManager;
|
||||||
|
@ -61,7 +61,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
|
|||||||
if (playlistLen == 0) return -1;
|
if (playlistLen == 0) return -1;
|
||||||
if (playlistLen > 100) playlistLen = 100;
|
if (playlistLen > 100) playlistLen = 100;
|
||||||
|
|
||||||
playlistEntries = new PlaylistEntry[playlistLen];
|
playlistEntries = new(std::nothrow) PlaylistEntry[playlistLen];
|
||||||
if (playlistEntries == nullptr) return -1;
|
if (playlistEntries == nullptr) return -1;
|
||||||
|
|
||||||
byte it = 0;
|
byte it = 0;
|
||||||
@ -146,7 +146,7 @@ if (millis() - presetCycledTime > (100 * playlistEntryDur) || doAdvancePlaylist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0);
|
strip.setTransition(playlistEntries[playlistIndex].tr * 100);
|
||||||
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
||||||
applyPresetFromPlaylist(playlistEntries[playlistIndex].preset);
|
applyPresetFromPlaylist(playlistEntries[playlistIndex].preset);
|
||||||
doAdvancePlaylist = false;
|
doAdvancePlaylist = false;
|
||||||
|
@ -76,8 +76,8 @@ static void doSaveState() {
|
|||||||
// clean up
|
// clean up
|
||||||
saveLedmap = -1;
|
saveLedmap = -1;
|
||||||
presetToSave = 0;
|
presetToSave = 0;
|
||||||
delete[] saveName;
|
free(saveName);
|
||||||
delete[] quickLoad;
|
free(quickLoad);
|
||||||
saveName = nullptr;
|
saveName = nullptr;
|
||||||
quickLoad = nullptr;
|
quickLoad = nullptr;
|
||||||
playlistSave = false;
|
playlistSave = false;
|
||||||
@ -164,6 +164,11 @@ void handlePresets()
|
|||||||
|
|
||||||
DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset);
|
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
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
|
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
|
||||||
deserializeJson(*pDoc,tmpRAMbuffer);
|
deserializeJson(*pDoc,tmpRAMbuffer);
|
||||||
@ -211,8 +216,8 @@ void handlePresets()
|
|||||||
//called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
|
//called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
|
||||||
void savePreset(byte index, const char* pname, JsonObject sObj)
|
void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||||
{
|
{
|
||||||
if (!saveName) saveName = new char[33];
|
if (!saveName) saveName = static_cast<char*>(malloc(33));
|
||||||
if (!quickLoad) quickLoad = new char[9];
|
if (!quickLoad) quickLoad = static_cast<char*>(malloc(9));
|
||||||
if (!saveName || !quickLoad) return;
|
if (!saveName || !quickLoad) return;
|
||||||
|
|
||||||
if (index == 0 || (index > 250 && index < 255)) return;
|
if (index == 0 || (index > 250 && index < 255)) return;
|
||||||
@ -258,8 +263,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
|
|||||||
presetsModifiedTime = toki.second(); //unix time
|
presetsModifiedTime = toki.second(); //unix time
|
||||||
updateFSInfo();
|
updateFSInfo();
|
||||||
}
|
}
|
||||||
delete[] saveName;
|
free(saveName);
|
||||||
delete[] quickLoad;
|
free(quickLoad);
|
||||||
saveName = nullptr;
|
saveName = nullptr;
|
||||||
quickLoad = nullptr;
|
quickLoad = nullptr;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#ifndef WLED_DISABLE_ESPNOW
|
#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_DEACTIVATED -1
|
||||||
#define NIGHT_MODE_BRIGHTNESS 5
|
#define NIGHT_MODE_BRIGHTNESS 5
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ typedef struct WizMoteMessageStructure {
|
|||||||
|
|
||||||
static uint32_t last_seq = UINT32_MAX;
|
static uint32_t last_seq = UINT32_MAX;
|
||||||
static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
|
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
|
// Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3
|
||||||
static const byte brightnessSteps[] = {
|
static const byte brightnessSteps[] = {
|
||||||
@ -121,6 +124,9 @@ static bool remoteJson(int button)
|
|||||||
|
|
||||||
sprintf_P(objKey, PSTR("\"%d\":"), 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
|
// attempt to read command from remote.json
|
||||||
readObjectFromFile(PSTR("/remote.json"), objKey, pDoc);
|
readObjectFromFile(PSTR("/remote.json"), objKey, pDoc);
|
||||||
JsonObject fdo = pDoc->as<JsonObject>();
|
JsonObject fdo = pDoc->as<JsonObject>();
|
||||||
@ -176,7 +182,7 @@ static bool remoteJson(int button)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Callback function that will be executed when data is received
|
// 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);
|
message_structure_t *incoming = reinterpret_cast<message_structure_t *>(incomingData);
|
||||||
|
|
||||||
if (strcmp(last_signal_src, linked_remote) != 0) {
|
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_PRINT(F("] button: "));
|
||||||
DEBUG_PRINTLN(incoming->button);
|
DEBUG_PRINTLN(incoming->button);
|
||||||
|
|
||||||
if (!remoteJson(incoming->button))
|
ESPNowButton = incoming->button; // save state, do not process in callback (can cause glitches)
|
||||||
switch (incoming->button) {
|
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_ON : setOn(); break;
|
||||||
case WIZMOTE_BUTTON_OFF : setOff(); break;
|
case WIZMOTE_BUTTON_OFF : setOff(); break;
|
||||||
case WIZMOTE_BUTTON_ONE : presetWithFallback(1, FX_MODE_STATIC, 0); 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;
|
case WIZ_SMART_BUTTON_BRIGHT_DOWN : brightnessDown(); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
last_seq = cur_seq;
|
}
|
||||||
|
ESPNowButton = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void handleRemote(uint8_t *incomingData, size_t len) {}
|
void handleRemote() {}
|
||||||
#endif
|
#endif
|
||||||
|
@ -136,8 +136,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
strip.correctWB = request->hasArg(F("CCT"));
|
strip.correctWB = request->hasArg(F("CCT"));
|
||||||
strip.cctFromRgb = request->hasArg(F("CR"));
|
strip.cctFromRgb = request->hasArg(F("CR"));
|
||||||
cctICused = request->hasArg(F("IC"));
|
cctICused = request->hasArg(F("IC"));
|
||||||
strip.cctBlending = request->arg(F("CB")).toInt();
|
uint8_t cctBlending = request->arg(F("CB")).toInt();
|
||||||
Bus::setCCTBlend(strip.cctBlending);
|
Bus::setCCTBlend(cctBlending);
|
||||||
Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
|
Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
|
||||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||||
useGlobalLedBuffer = request->hasArg(F("LD"));
|
useGlobalLedBuffer = request->hasArg(F("LD"));
|
||||||
@ -211,7 +211,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
// 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
|
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
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[s] = new(std::nothrow) BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax);
|
||||||
busesChanged = true;
|
busesChanged = true;
|
||||||
}
|
}
|
||||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||||
@ -328,11 +328,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||||
|
|
||||||
fadeTransition = request->hasArg(F("TF"));
|
|
||||||
modeBlending = request->hasArg(F("EB"));
|
|
||||||
t = request->arg(F("TD")).toInt();
|
t = request->arg(F("TD")).toInt();
|
||||||
if (t >= 0) transitionDelayDefault = t;
|
if (t >= 0) transitionDelayDefault = t;
|
||||||
strip.paletteFade = request->hasArg(F("PF"));
|
|
||||||
t = request->arg(F("TP")).toInt();
|
t = request->arg(F("TP")).toInt();
|
||||||
randomPaletteChangeTime = MIN(255,MAX(1,t));
|
randomPaletteChangeTime = MIN(255,MAX(1,t));
|
||||||
useHarmonicRandomPalette = request->hasArg(F("TH"));
|
useHarmonicRandomPalette = request->hasArg(F("TH"));
|
||||||
@ -422,6 +419,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
t = request->arg(F("WO")).toInt();
|
t = request->arg(F("WO")).toInt();
|
||||||
if (t >= -255 && t <= 255) arlsOffset = t;
|
if (t >= -255 && t <= 255) arlsOffset = t;
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
dmxInputTransmitPin = request->arg(F("IDMT")).toInt();
|
||||||
|
dmxInputReceivePin = request->arg(F("IDMR")).toInt();
|
||||||
|
dmxInputEnablePin = request->arg(F("IDME")).toInt();
|
||||||
|
dmxInputPort = request->arg(F("IDMP")).toInt();
|
||||||
|
if(dmxInputPort <= 0 || dmxInputPort > 2) dmxInputPort = 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
alexaEnabled = request->hasArg(F("AL"));
|
alexaEnabled = request->hasArg(F("AL"));
|
||||||
strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33);
|
strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33);
|
||||||
@ -984,18 +989,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
//set color from HEX or 32bit DEC
|
//set color from HEX or 32bit DEC
|
||||||
pos = req.indexOf(F("CL="));
|
pos = req.indexOf(F("CL="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(colIn, req.substring(pos + 3).c_str());
|
||||||
col0Changed = true;
|
col0Changed = true;
|
||||||
}
|
}
|
||||||
pos = req.indexOf(F("C2="));
|
pos = req.indexOf(F("C2="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(colInSec, req.substring(pos + 3).c_str());
|
||||||
col1Changed = true;
|
col1Changed = true;
|
||||||
}
|
}
|
||||||
pos = req.indexOf(F("C3="));
|
pos = req.indexOf(F("C3="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
byte tmpCol[4];
|
byte tmpCol[4];
|
||||||
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(tmpCol, req.substring(pos + 3).c_str());
|
||||||
col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||||
selseg.setColor(2, col2); // defined above (SS= or main)
|
selseg.setColor(2, col2); // defined above (SS= or main)
|
||||||
col2Changed = true;
|
col2Changed = true;
|
||||||
@ -1142,7 +1147,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
|
|
||||||
pos = req.indexOf(F("TT="));
|
pos = req.indexOf(F("TT="));
|
||||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||||
if (fadeTransition) strip.setTransition(transitionDelay);
|
strip.setTransition(transitionDelay);
|
||||||
|
|
||||||
//set time (unix timestamp)
|
//set time (unix timestamp)
|
||||||
pos = req.indexOf(F("ST="));
|
pos = req.indexOf(F("ST="));
|
||||||
|
@ -206,7 +206,7 @@ void notify(byte callMode, bool followUp)
|
|||||||
notificationCount = followUp ? notificationCount + 1 : 0;
|
notificationCount = followUp ? notificationCount + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseNotifyPacket(uint8_t *udpIn) {
|
static void parseNotifyPacket(const uint8_t *udpIn) {
|
||||||
//ignore notification if received within a second after sending a notification ourselves
|
//ignore notification if received within a second after sending a notification ourselves
|
||||||
if (millis() - notificationSentTime < 1000) return;
|
if (millis() - notificationSentTime < 1000) return;
|
||||||
if (udpIn[1] > 199) return; //do not receive custom versions
|
if (udpIn[1] > 199) return; //do not receive custom versions
|
||||||
@ -225,10 +225,8 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
|
|
||||||
// set transition time before making any segment changes
|
// set transition time before making any segment changes
|
||||||
if (version > 3) {
|
if (version > 3) {
|
||||||
if (fadeTransition) {
|
jsonTransitionOnce = true;
|
||||||
jsonTransitionOnce = true;
|
strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00));
|
||||||
strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//apply colors from notification to main segment, only if not syncing full segments
|
//apply colors from notification to main segment, only if not syncing full segments
|
||||||
@ -810,7 +808,7 @@ static size_t sequenceNumber = 0; // this needs to be shared across all ou
|
|||||||
static const size_t ART_NET_HEADER_SIZE = 12;
|
static const size_t ART_NET_HEADER_SIZE = 12;
|
||||||
static const byte ART_NET_HEADER[] PROGMEM = {0x41,0x72,0x74,0x2d,0x4e,0x65,0x74,0x00,0x00,0x50,0x00,0x0e};
|
static const byte ART_NET_HEADER[] PROGMEM = {0x41,0x72,0x74,0x2d,0x4e,0x65,0x74,0x00,0x00,0x50,0x00,0x0e};
|
||||||
|
|
||||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri, bool isRGBW) {
|
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri, bool isRGBW) {
|
||||||
if (!(apActive || interfacesInited) || !client[0] || !length) return 1; // network not initialised or dummy/unset IP address 031522 ajn added check for ap
|
if (!(apActive || interfacesInited) || !client[0] || !length) return 1; // network not initialised or dummy/unset IP address 031522 ajn added check for ap
|
||||||
|
|
||||||
WiFiUDP ddpUdp;
|
WiFiUDP ddpUdp;
|
||||||
@ -963,7 +961,7 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
|
|||||||
|
|
||||||
// handle WiZ Mote data
|
// handle WiZ Mote data
|
||||||
if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {
|
if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {
|
||||||
handleRemote(data, len);
|
handleWiZdata(data, len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
* Registration and management utility for v2 usermods
|
* Registration and management utility for v2 usermods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static Usermod* ums[WLED_MAX_USERMODS] = {nullptr};
|
||||||
|
byte UsermodManager::numMods = 0;
|
||||||
|
|
||||||
//Usermod Manager internals
|
//Usermod Manager internals
|
||||||
void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); }
|
void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); }
|
||||||
void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); }
|
void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); }
|
||||||
@ -69,8 +72,6 @@ bool UsermodManager::add(Usermod* um)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Usermod* UsermodManager::ums[WLED_MAX_USERMODS] = {nullptr};
|
|
||||||
byte UsermodManager::numMods = 0;
|
|
||||||
|
|
||||||
/* Usermod v2 interface shim for oappend */
|
/* Usermod v2 interface shim for oappend */
|
||||||
Print* Usermod::oappend_shim = nullptr;
|
Print* Usermod::oappend_shim = nullptr;
|
||||||
|
@ -242,6 +242,14 @@
|
|||||||
#include "../usermods/LD2410_v2/usermod_ld2410.h"
|
#include "../usermods/LD2410_v2/usermod_ld2410.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_DEEP_SLEEP
|
||||||
|
#include "../usermods/deep_sleep/usermod_deep_sleep.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_RF433
|
||||||
|
#include "../usermods/usermod_v2_RF433/usermod_v2_RF433.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void registerUsermods()
|
void registerUsermods()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -470,4 +478,12 @@ void registerUsermods()
|
|||||||
#ifdef USERMOD_POV_DISPLAY
|
#ifdef USERMOD_POV_DISPLAY
|
||||||
UsermodManager::add(new PovDisplayUsermod());
|
UsermodManager::add(new PovDisplayUsermod());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_DEEP_SLEEP
|
||||||
|
UsermodManager::add(new DeepSleepUsermod());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_RF433
|
||||||
|
UsermodManager::add(new RF433Usermod());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getBoolVal(JsonVariant elem, bool dflt) {
|
bool getBoolVal(const JsonVariant &elem, bool dflt) {
|
||||||
if (elem.is<const char*>() && elem.as<const char*>()[0] == 't') {
|
if (elem.is<const char*>() && elem.as<const char*>()[0] == 't') {
|
||||||
return !dflt;
|
return !dflt;
|
||||||
} else {
|
} else {
|
||||||
@ -151,7 +151,7 @@ bool isAsterisksOnly(const char* str, byte maxLen)
|
|||||||
|
|
||||||
|
|
||||||
//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994
|
//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994
|
||||||
bool requestJSONBufferLock(uint8_t module)
|
bool requestJSONBufferLock(uint8_t moduleID)
|
||||||
{
|
{
|
||||||
if (pDoc == nullptr) {
|
if (pDoc == nullptr) {
|
||||||
DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!"));
|
DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!"));
|
||||||
@ -175,14 +175,14 @@ bool requestJSONBufferLock(uint8_t module)
|
|||||||
#endif
|
#endif
|
||||||
// If the lock is still held - by us, or by another task
|
// If the lock is still held - by us, or by another task
|
||||||
if (jsonBufferLock) {
|
if (jsonBufferLock) {
|
||||||
DEBUG_PRINTF_P(PSTR("ERROR: Locking JSON buffer (%d) failed! (still locked by %d)\n"), module, jsonBufferLock);
|
DEBUG_PRINTF_P(PSTR("ERROR: Locking JSON buffer (%d) failed! (still locked by %d)\n"), moduleID, jsonBufferLock);
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
xSemaphoreGiveRecursive(jsonBufferLockMutex);
|
xSemaphoreGiveRecursive(jsonBufferLockMutex);
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBufferLock = module ? module : 255;
|
jsonBufferLock = moduleID ? moduleID : 255;
|
||||||
DEBUG_PRINTF_P(PSTR("JSON buffer locked. (%d)\n"), jsonBufferLock);
|
DEBUG_PRINTF_P(PSTR("JSON buffer locked. (%d)\n"), jsonBufferLock);
|
||||||
pDoc->clear();
|
pDoc->clear();
|
||||||
return true;
|
return true;
|
||||||
@ -265,16 +265,16 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
|||||||
if (mode < strip.getModeCount()) {
|
if (mode < strip.getModeCount()) {
|
||||||
String lineBuffer = FPSTR(strip.getModeData(mode));
|
String lineBuffer = FPSTR(strip.getModeData(mode));
|
||||||
if (lineBuffer.length() > 0) {
|
if (lineBuffer.length() > 0) {
|
||||||
unsigned start = lineBuffer.indexOf('@');
|
int start = lineBuffer.indexOf('@'); // String::indexOf() returns an int, not an unsigned; -1 means "not found"
|
||||||
unsigned stop = lineBuffer.indexOf(';', start);
|
int stop = lineBuffer.indexOf(';', start);
|
||||||
if (start>0 && stop>0) {
|
if (start>0 && stop>0) {
|
||||||
String names = lineBuffer.substring(start, stop); // include @
|
String names = lineBuffer.substring(start, stop); // include @
|
||||||
unsigned nameBegin = 1, nameEnd, nameDefault;
|
int nameBegin = 1, nameEnd, nameDefault;
|
||||||
if (slider < 10) {
|
if (slider < 10) {
|
||||||
for (size_t i=0; i<=slider; i++) {
|
for (size_t i=0; i<=slider; i++) {
|
||||||
const char *tmpstr;
|
const char *tmpstr;
|
||||||
dest[0] = '\0'; //clear dest buffer
|
dest[0] = '\0'; //clear dest buffer
|
||||||
if (nameBegin == 0) break; // there are no more names
|
if (nameBegin <= 0) break; // there are no more names
|
||||||
nameEnd = names.indexOf(',', nameBegin);
|
nameEnd = names.indexOf(',', nameBegin);
|
||||||
if (i == slider) {
|
if (i == slider) {
|
||||||
nameDefault = names.indexOf('=', nameBegin); // find default value
|
nameDefault = names.indexOf('=', nameBegin); // find default value
|
||||||
@ -470,7 +470,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
for (int i = 0; i<16; i++)
|
for (int i = 0; i<16; i++)
|
||||||
fftResult[i] = beatsin8_t(120 / (i+1), 0, 255);
|
fftResult[i] = beatsin8_t(120 / (i+1), 0, 255);
|
||||||
// fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256;
|
// fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256;
|
||||||
volumeSmth = fftResult[8];
|
volumeSmth = fftResult[8];
|
||||||
break;
|
break;
|
||||||
case UMS_WeWillRockYou:
|
case UMS_WeWillRockYou:
|
||||||
if (ms%2000 < 200) {
|
if (ms%2000 < 200) {
|
||||||
@ -507,7 +507,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
case UMS_10_13:
|
case UMS_10_13:
|
||||||
for (int i = 0; i<16; i++)
|
for (int i = 0; i<16; i++)
|
||||||
fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||||
volumeSmth = fftResult[8];
|
volumeSmth = fftResult[8];
|
||||||
break;
|
break;
|
||||||
case UMS_14_3:
|
case UMS_14_3:
|
||||||
for (int i = 0; i<16; i++)
|
for (int i = 0; i<16; i++)
|
||||||
@ -538,7 +538,7 @@ void enumerateLedmaps() {
|
|||||||
|
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
if (ledmapNames[i-1]) { //clear old name
|
if (ledmapNames[i-1]) { //clear old name
|
||||||
delete[] ledmapNames[i-1];
|
free(ledmapNames[i-1]);
|
||||||
ledmapNames[i-1] = nullptr;
|
ledmapNames[i-1] = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -556,7 +556,7 @@ void enumerateLedmaps() {
|
|||||||
const char *name = root["n"].as<const char*>();
|
const char *name = root["n"].as<const char*>();
|
||||||
if (name != nullptr) len = strlen(name);
|
if (name != nullptr) len = strlen(name);
|
||||||
if (len > 0 && len < 33) {
|
if (len > 0 && len < 33) {
|
||||||
ledmapNames[i-1] = new char[len+1];
|
ledmapNames[i-1] = static_cast<char*>(malloc(len+1));
|
||||||
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33);
|
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -564,7 +564,7 @@ void enumerateLedmaps() {
|
|||||||
char tmp[33];
|
char tmp[33];
|
||||||
snprintf_P(tmp, 32, s_ledmap_tmpl, i);
|
snprintf_P(tmp, 32, s_ledmap_tmpl, i);
|
||||||
len = strlen(tmp);
|
len = strlen(tmp);
|
||||||
ledmapNames[i-1] = new char[len+1];
|
ledmapNames[i-1] = static_cast<char*>(malloc(len+1));
|
||||||
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33);
|
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,6 +595,13 @@ float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
|
|||||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t hashInt(uint32_t s) {
|
||||||
|
// borrowed from https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key
|
||||||
|
s = ((s >> 16) ^ s) * 0x45d9f3b;
|
||||||
|
s = ((s >> 16) ^ s) * 0x45d9f3b;
|
||||||
|
return (s >> 16) ^ s;
|
||||||
|
}
|
||||||
|
|
||||||
// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
||||||
uint32_t hw_random(uint32_t upperlimit) {
|
uint32_t hw_random(uint32_t upperlimit) {
|
||||||
uint32_t rnd = hw_random();
|
uint32_t rnd = hw_random();
|
||||||
|
@ -65,7 +65,10 @@ void WLED::loop()
|
|||||||
handleNotifications();
|
handleNotifications();
|
||||||
handleTransitions();
|
handleTransitions();
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
handleDMX();
|
handleDMXOutput();
|
||||||
|
#endif
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
dmxInput.update();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
@ -84,6 +87,9 @@ void WLED::loop()
|
|||||||
#ifndef WLED_DISABLE_INFRARED
|
#ifndef WLED_DISABLE_INFRARED
|
||||||
handleIR();
|
handleIR();
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef WLED_DISABLE_ESPNOW
|
||||||
|
handleRemote();
|
||||||
|
#endif
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
handleAlexa();
|
handleAlexa();
|
||||||
#endif
|
#endif
|
||||||
@ -524,7 +530,10 @@ void WLED::setup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
initDMX();
|
initDMXOutput();
|
||||||
|
#endif
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
dmxInput.init(dmxInputReceivePin, dmxInputTransmitPin, dmxInputEnablePin, dmxInputPort);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_ADALIGHT
|
#ifdef WLED_ENABLE_ADALIGHT
|
||||||
@ -635,7 +644,6 @@ void WLED::initAP(bool resetAP)
|
|||||||
void WLED::initConnection()
|
void WLED::initConnection()
|
||||||
{
|
{
|
||||||
DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000);
|
DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000);
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
ws.onEvent(wsEvent);
|
ws.onEvent(wsEvent);
|
||||||
#endif
|
#endif
|
||||||
@ -664,6 +672,7 @@ void WLED::initConnection()
|
|||||||
if (!WLED_WIFI_CONFIGURED) {
|
if (!WLED_WIFI_CONFIGURED) {
|
||||||
DEBUG_PRINTLN(F("No connection configured."));
|
DEBUG_PRINTLN(F("No connection configured."));
|
||||||
if (!apActive) initAP(); // instantly go to ap mode
|
if (!apActive) initAP(); // instantly go to ap mode
|
||||||
|
return;
|
||||||
} else if (!apActive) {
|
} else if (!apActive) {
|
||||||
if (apBehavior == AP_BEHAVIOR_ALWAYS) {
|
if (apBehavior == AP_BEHAVIOR_ALWAYS) {
|
||||||
DEBUG_PRINTLN(F("Access point ALWAYS enabled."));
|
DEBUG_PRINTLN(F("Access point ALWAYS enabled."));
|
||||||
|
@ -144,6 +144,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
#include "dmx_input.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "src/dependencies/e131/ESPAsyncE131.h"
|
#include "src/dependencies/e131/ESPAsyncE131.h"
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
|
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
|
||||||
@ -269,7 +273,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
|||||||
// Global Variable definitions
|
// Global Variable definitions
|
||||||
WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION));
|
WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION));
|
||||||
WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // must include the quotes when defining, e.g -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // must include the quotes when defining, e.g -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
||||||
#define WLED_CODENAME "Kōsen"
|
#define WLED_CODENAME "Niji"
|
||||||
|
|
||||||
// AP and OTA default passwords (for maximum security change them!)
|
// AP and OTA default passwords (for maximum security change them!)
|
||||||
WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS);
|
WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS);
|
||||||
@ -459,7 +463,15 @@ WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to f
|
|||||||
WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture
|
WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture
|
||||||
WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start
|
WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start
|
||||||
#endif
|
#endif
|
||||||
WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consecutive universes)
|
#ifdef WLED_ENABLE_DMX_INPUT
|
||||||
|
WLED_GLOBAL int dmxInputTransmitPin _INIT(0);
|
||||||
|
WLED_GLOBAL int dmxInputReceivePin _INIT(0);
|
||||||
|
WLED_GLOBAL int dmxInputEnablePin _INIT(0);
|
||||||
|
WLED_GLOBAL int dmxInputPort _INIT(2);
|
||||||
|
WLED_GLOBAL DMXInput dmxInput;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes)
|
||||||
WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454
|
WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454
|
||||||
WLED_GLOBAL byte e131Priority _INIT(0); // E1.31 port priority (if != 0 priority handling is active)
|
WLED_GLOBAL byte e131Priority _INIT(0); // E1.31 port priority (if != 0 priority handling is active)
|
||||||
WLED_GLOBAL E131Priority highPriority _INIT(3); // E1.31 highest priority tracking, init = timeout in seconds
|
WLED_GLOBAL E131Priority highPriority _INIT(3); // E1.31 highest priority tracking, init = timeout in seconds
|
||||||
@ -482,10 +494,10 @@ WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other
|
|||||||
#endif
|
#endif
|
||||||
WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL);
|
WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL);
|
||||||
WLED_GLOBAL bool mqttEnabled _INIT(false);
|
WLED_GLOBAL bool mqttEnabled _INIT(false);
|
||||||
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
|
WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers
|
||||||
WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
|
WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
|
||||||
WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices)
|
WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices)
|
||||||
WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL)
|
WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL)
|
||||||
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
|
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
|
||||||
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
|
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
|
||||||
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
||||||
@ -577,8 +589,7 @@ WLED_GLOBAL bool wasConnected _INIT(false);
|
|||||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||||
|
|
||||||
// transitions
|
// transitions
|
||||||
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color
|
WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style
|
||||||
WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending
|
|
||||||
WLED_GLOBAL bool transitionActive _INIT(false);
|
WLED_GLOBAL bool transitionActive _INIT(false);
|
||||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
||||||
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
||||||
@ -896,9 +907,6 @@ WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available l
|
|||||||
WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps
|
WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Usermod manager
|
|
||||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
|
||||||
|
|
||||||
// global I2C SDA pin (used for usermods)
|
// global I2C SDA pin (used for usermods)
|
||||||
#ifndef I2CSDAPIN
|
#ifndef I2CSDAPIN
|
||||||
WLED_GLOBAL int8_t i2c_sda _INIT(-1);
|
WLED_GLOBAL int8_t i2c_sda _INIT(-1);
|
||||||
|
6
wled00/wled_eeprom.cpp
Executable file → Normal file
6
wled00/wled_eeprom.cpp
Executable file → Normal file
@ -2,6 +2,10 @@
|
|||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
|
#if defined(WLED_ENABLE_MQTT) && MQTT_MAX_TOPIC_LEN < 32
|
||||||
|
#error "MQTT topics length < 32 is not supported by the EEPROM module!"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DEPRECATED, do not use for new settings
|
* DEPRECATED, do not use for new settings
|
||||||
* Only used to restore config from pre-0.11 installations using the deEEP() methods
|
* Only used to restore config from pre-0.11 installations using the deEEP() methods
|
||||||
@ -220,7 +224,7 @@ void loadSettingsFromEEPROM()
|
|||||||
|
|
||||||
if (lastEEPROMversion > 7)
|
if (lastEEPROMversion > 7)
|
||||||
{
|
{
|
||||||
strip.paletteFade = EEPROM.read(374);
|
//strip.paletteFade = EEPROM.read(374);
|
||||||
strip.paletteBlend = EEPROM.read(382);
|
strip.paletteBlend = EEPROM.read(382);
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
|
@ -220,3 +220,27 @@ float fmod_t(float num, float denom) {
|
|||||||
#endif
|
#endif
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bit-wise integer square root calculation (exact)
|
||||||
|
uint32_t sqrt32_bw(uint32_t x) {
|
||||||
|
uint32_t res = 0;
|
||||||
|
uint32_t bit;
|
||||||
|
uint32_t num = x; // use 32bit for faster calculation
|
||||||
|
|
||||||
|
if(num < 1 << 10) bit = 1 << 10; // speed optimization for small numbers < 32^2
|
||||||
|
else if (num < 1 << 20) bit = 1 << 20; // speed optimization for medium numbers < 1024^2
|
||||||
|
else bit = 1 << 30; // start with highest power of 4 <= 2^32
|
||||||
|
|
||||||
|
while (bit > num) bit >>= 2; // reduce iterations
|
||||||
|
|
||||||
|
while (bit != 0) {
|
||||||
|
if (num >= res + bit) {
|
||||||
|
num -= res + bit;
|
||||||
|
res = (res >> 1) + bit;
|
||||||
|
} else {
|
||||||
|
res >>= 1;
|
||||||
|
}
|
||||||
|
bit >>= 2;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@ -113,8 +113,8 @@ void handleSerial()
|
|||||||
//only send response if TX pin is unused for other purposes
|
//only send response if TX pin is unused for other purposes
|
||||||
if (verboseResponse && serialCanTX) {
|
if (verboseResponse && serialCanTX) {
|
||||||
pDoc->clear();
|
pDoc->clear();
|
||||||
JsonObject state = pDoc->createNestedObject("state");
|
JsonObject stateDoc = pDoc->createNestedObject("state");
|
||||||
serializeState(state);
|
serializeState(stateDoc);
|
||||||
JsonObject info = pDoc->createNestedObject("info");
|
JsonObject info = pDoc->createNestedObject("info");
|
||||||
serializeInfo(info);
|
serializeInfo(info);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ static const char s_accessdenied[] PROGMEM = "Access Denied";
|
|||||||
static const char _common_js[] PROGMEM = "/common.js";
|
static const char _common_js[] PROGMEM = "/common.js";
|
||||||
|
|
||||||
//Is this an IP?
|
//Is this an IP?
|
||||||
static bool isIp(String str) {
|
static bool isIp(const String &str) {
|
||||||
for (size_t i = 0; i < str.length(); i++) {
|
for (size_t i = 0; i < str.length(); i++) {
|
||||||
int c = str.charAt(i);
|
int c = str.charAt(i);
|
||||||
if (c != '.' && (c < '0' || c > '9')) {
|
if (c != '.' && (c < '0' || c > '9')) {
|
||||||
@ -152,9 +152,9 @@ static String msgProcessor(const String& var)
|
|||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
|
static void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool isFinal) {
|
||||||
if (!correctPIN) {
|
if (!correctPIN) {
|
||||||
if (final) request->send(401, FPSTR(CONTENT_TYPE_PLAIN), FPSTR(s_unlock_cfg));
|
if (isFinal) request->send(401, FPSTR(CONTENT_TYPE_PLAIN), FPSTR(s_unlock_cfg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!index) {
|
if (!index) {
|
||||||
@ -170,7 +170,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename,
|
|||||||
if (len) {
|
if (len) {
|
||||||
request->_tempFile.write(data,len);
|
request->_tempFile.write(data,len);
|
||||||
}
|
}
|
||||||
if (final) {
|
if (isFinal) {
|
||||||
request->_tempFile.close();
|
request->_tempFile.close();
|
||||||
if (filename.indexOf(F("cfg.json")) >= 0) { // check for filename with or without slash
|
if (filename.indexOf(F("cfg.json")) >= 0) { // check for filename with or without slash
|
||||||
doReboot = true;
|
doReboot = true;
|
||||||
@ -359,7 +359,7 @@ void initServer()
|
|||||||
|
|
||||||
server.on(F("/upload"), HTTP_POST, [](AsyncWebServerRequest *request) {},
|
server.on(F("/upload"), HTTP_POST, [](AsyncWebServerRequest *request) {},
|
||||||
[](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data,
|
[](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data,
|
||||||
size_t len, bool final) {handleUpload(request, filename, index, data, len, final);}
|
size_t len, bool isFinal) {handleUpload(request, filename, index, data, len, isFinal);}
|
||||||
);
|
);
|
||||||
|
|
||||||
createEditHandler(correctPIN);
|
createEditHandler(correctPIN);
|
||||||
@ -389,7 +389,7 @@ void initServer()
|
|||||||
serveMessage(request, 200, F("Update successful!"), F("Rebooting..."), 131);
|
serveMessage(request, 200, F("Update successful!"), F("Rebooting..."), 131);
|
||||||
doReboot = true;
|
doReboot = true;
|
||||||
}
|
}
|
||||||
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool isFinal){
|
||||||
if (!correctPIN || otaLock) return;
|
if (!correctPIN || otaLock) return;
|
||||||
if(!index){
|
if(!index){
|
||||||
DEBUG_PRINTLN(F("OTA Update Start"));
|
DEBUG_PRINTLN(F("OTA Update Start"));
|
||||||
@ -406,7 +406,7 @@ void initServer()
|
|||||||
Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
||||||
}
|
}
|
||||||
if(!Update.hasError()) Update.write(data, len);
|
if(!Update.hasError()) Update.write(data, len);
|
||||||
if(final){
|
if(isFinal){
|
||||||
if(Update.end(true)){
|
if(Update.end(true)){
|
||||||
DEBUG_PRINTLN(F("Update Success"));
|
DEBUG_PRINTLN(F("Update Success"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,7 +26,7 @@ void XML_response(Print& dest)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extractPin(Print& settingsScript, JsonObject &obj, const char *key) {
|
static void extractPin(Print& settingsScript, const JsonObject &obj, const char *key) {
|
||||||
if (obj[key].is<JsonArray>()) {
|
if (obj[key].is<JsonArray>()) {
|
||||||
JsonArray pins = obj[key].as<JsonArray>();
|
JsonArray pins = obj[key].as<JsonArray>();
|
||||||
for (JsonVariant pv : pins) {
|
for (JsonVariant pv : pins) {
|
||||||
@ -38,7 +38,7 @@ static void extractPin(Print& settingsScript, JsonObject &obj, const char *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// print used pins by scanning JsonObject (1 level deep)
|
// print used pins by scanning JsonObject (1 level deep)
|
||||||
static void fillUMPins(Print& settingsScript, JsonObject &mods)
|
static void fillUMPins(Print& settingsScript, const JsonObject &mods)
|
||||||
{
|
{
|
||||||
for (JsonPair kv : mods) {
|
for (JsonPair kv : mods) {
|
||||||
// kv.key() is usermod name or subobject key
|
// kv.key() is usermod name or subobject key
|
||||||
@ -288,7 +288,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
printSetFormCheckbox(settingsScript,PSTR("CCT"),strip.correctWB);
|
printSetFormCheckbox(settingsScript,PSTR("CCT"),strip.correctWB);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("IC"),cctICused);
|
printSetFormCheckbox(settingsScript,PSTR("IC"),cctICused);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("CR"),strip.cctFromRgb);
|
printSetFormCheckbox(settingsScript,PSTR("CR"),strip.cctFromRgb);
|
||||||
printSetFormValue(settingsScript,PSTR("CB"),strip.cctBlending);
|
printSetFormValue(settingsScript,PSTR("CB"),Bus::getCCTBlend());
|
||||||
printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps());
|
printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps());
|
||||||
printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode());
|
printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode());
|
||||||
printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer);
|
printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer);
|
||||||
@ -372,10 +372,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
printSetFormCheckbox(settingsScript,PSTR("GB"),gammaCorrectBri);
|
printSetFormCheckbox(settingsScript,PSTR("GB"),gammaCorrectBri);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("GC"),gammaCorrectCol);
|
printSetFormCheckbox(settingsScript,PSTR("GC"),gammaCorrectCol);
|
||||||
dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(settingsScript,PSTR("GV"),nS);
|
dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(settingsScript,PSTR("GV"),nS);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("TF"),fadeTransition);
|
|
||||||
printSetFormCheckbox(settingsScript,PSTR("EB"),modeBlending);
|
|
||||||
printSetFormValue(settingsScript,PSTR("TD"),transitionDelayDefault);
|
printSetFormValue(settingsScript,PSTR("TD"),transitionDelayDefault);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("PF"),strip.paletteFade);
|
|
||||||
printSetFormValue(settingsScript,PSTR("TP"),randomPaletteChangeTime);
|
printSetFormValue(settingsScript,PSTR("TP"),randomPaletteChangeTime);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("TH"),useHarmonicRandomPalette);
|
printSetFormCheckbox(settingsScript,PSTR("TH"),useHarmonicRandomPalette);
|
||||||
printSetFormValue(settingsScript,PSTR("BF"),briMultiplier);
|
printSetFormValue(settingsScript,PSTR("BF"),briMultiplier);
|
||||||
@ -439,6 +436,18 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence);
|
printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast);
|
printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast);
|
||||||
printSetFormValue(settingsScript,PSTR("EU"),e131Universe);
|
printSetFormValue(settingsScript,PSTR("EU"),e131Universe);
|
||||||
|
#ifdef WLED_ENABLE_DMX
|
||||||
|
settingsScript.print(SET_F("hideNoDMX();")); // hide "not compiled in" message
|
||||||
|
#endif
|
||||||
|
#ifndef WLED_ENABLE_DMX_INPUT
|
||||||
|
settingsScript.print(SET_F("hideDMXInput();")); // hide "dmx input" settings
|
||||||
|
#else
|
||||||
|
settingsScript.print(SET_F("hideNoDMXInput();")); //hide "not compiled in" message
|
||||||
|
printSetFormValue(settingsScript,SET_F("IDMT"),dmxInputTransmitPin);
|
||||||
|
printSetFormValue(settingsScript,SET_F("IDMR"),dmxInputReceivePin);
|
||||||
|
printSetFormValue(settingsScript,SET_F("IDME"),dmxInputEnablePin);
|
||||||
|
printSetFormValue(settingsScript,SET_F("IDMP"),dmxInputPort);
|
||||||
|
#endif
|
||||||
printSetFormValue(settingsScript,PSTR("DA"),DMXAddress);
|
printSetFormValue(settingsScript,PSTR("DA"),DMXAddress);
|
||||||
printSetFormValue(settingsScript,PSTR("XX"),DMXSegmentSpacing);
|
printSetFormValue(settingsScript,PSTR("XX"),DMXSegmentSpacing);
|
||||||
printSetFormValue(settingsScript,PSTR("PY"),e131Priority);
|
printSetFormValue(settingsScript,PSTR("PY"),e131Priority);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user