mirror of
https://github.com/wled/WLED.git
synced 2025-04-19 12:27:17 +00:00
Merge branch 'main' into blending-styles
This commit is contained in:
commit
3a426e258b
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"
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# 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
|
||||
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.
|
||||
;; 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_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
-DARDUINO_ARCH_ESP32 -DESP32
|
||||
-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
|
||||
-D WLED_ENABLE_DMX_INPUT
|
||||
lib_deps =
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
https://github.com/someweisguy/esp_dmx.git#47db25d
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
@ -309,7 +311,6 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for
|
||||
[esp32c3]
|
||||
;; generic definitions for all ESP32-C3 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
@ -324,11 +325,11 @@ lib_deps =
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
board_build.flash_mode = qio
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DESP32
|
||||
@ -432,10 +433,21 @@ lib_deps = ${esp32.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
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]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
@ -451,7 +463,6 @@ board_upload.maximum_size = 8388608
|
||||
[env:esp32dev_16M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
@ -494,7 +505,6 @@ board_build.partitions = ${esp32.default_partitions}
|
||||
[env:esp32_wrover]
|
||||
extends = esp32_idf_V4
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
board = ttgo-t7-v14-mini32
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
@ -510,7 +520,6 @@ lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
[env:esp32c3dev]
|
||||
extends = esp32c3
|
||||
platform = ${esp32c3.platform}
|
||||
platform_packages = ${esp32c3.platform_packages}
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
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_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D 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_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D 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
|
||||
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
|
||||
board_build.arduino.memory_type = opi_opi
|
||||
upload_speed = 921600
|
||||
@ -598,7 +604,6 @@ monitor_filters = esp32_exception_decoder
|
||||
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
|
||||
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
||||
@ -616,7 +621,6 @@ monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:lolin_s2_mini]
|
||||
platform = ${esp32s2.platform}
|
||||
platform_packages = ${esp32s2.platform_packages}
|
||||
board = lolin_s2_mini
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = qio
|
||||
|
@ -529,3 +529,14 @@ monitor_filters = esp32_exception_decoder
|
||||
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
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 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.
@ -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`.
|
||||
|
||||
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
|
||||
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`)
|
||||
|
||||
### 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
|
||||
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
|
||||
|
||||
WLED current protection will override the calculated value if it is too high.
|
||||
|
@ -97,6 +97,11 @@ private:
|
||||
#else
|
||||
void* ptr = nullptr;
|
||||
#endif
|
||||
#ifdef USERMOD_BH1750
|
||||
Usermod_BH1750* bh1750 = nullptr;
|
||||
#else
|
||||
void* bh1750 = nullptr;
|
||||
#endif
|
||||
|
||||
void _overlaySevenSegmentDraw() {
|
||||
int displayMaskLen = static_cast<int>(umSSDRDisplayMask.length());
|
||||
@ -387,6 +392,9 @@ public:
|
||||
#ifdef USERMOD_SN_PHOTORESISTOR
|
||||
ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR);
|
||||
#endif
|
||||
#ifdef USERMOD_BH1750
|
||||
bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750);
|
||||
#endif
|
||||
DEBUG_PRINTLN(F("Setup done"));
|
||||
}
|
||||
|
||||
@ -410,6 +418,20 @@ public:
|
||||
umSSDRLastRefresh = millis();
|
||||
}
|
||||
#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() {
|
||||
|
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
|
||||
*/
|
||||
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 perc = strip.now % cycleTime;
|
||||
unsigned prog = (perc * 65535) / cycleTime;
|
||||
@ -410,7 +410,7 @@ static const char _data_FX_MODE_FADE[] PROGMEM = "Fade@!;!,!;!;01";
|
||||
* Scan mode parent function
|
||||
*/
|
||||
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 perc = strip.now % cycleTime;
|
||||
int prog = (perc * 65535) / cycleTime;
|
||||
@ -642,11 +642,12 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
|
||||
* Dissolve function
|
||||
*/
|
||||
uint16_t dissolve(uint32_t color) {
|
||||
unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED
|
||||
unsigned dataSize = sizeof(uint32_t) * SEGLEN;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
memset(SEGMENT.data, 0xFF, dataSize); // start by fading pixels up
|
||||
for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = SEGCOLOR(1);
|
||||
SEGENV.aux0 = 1;
|
||||
}
|
||||
|
||||
@ -654,33 +655,26 @@ uint16_t dissolve(uint32_t color) {
|
||||
if (hw_random8() <= SEGMENT.intensity) {
|
||||
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
|
||||
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 (fadeUp) {
|
||||
if (color == SEGCOLOR(0)) {
|
||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else {
|
||||
SEGMENT.setPixelColor(i, color);
|
||||
}
|
||||
bitWrite(SEGENV.data[index], bitNum, false);
|
||||
if (pixels[i] == SEGCOLOR(1)) {
|
||||
pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color;
|
||||
break; //only spawn 1 new pixel per frame per 50 LEDs
|
||||
}
|
||||
} else { //dissolve to secondary
|
||||
if (!fadeUp) {
|
||||
SEGMENT.setPixelColor(i, SEGCOLOR(1)); break;
|
||||
bitWrite(SEGENV.data[index], bitNum, true);
|
||||
if (pixels[i] != SEGCOLOR(1)) {
|
||||
pixels[i] = SEGCOLOR(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fix for #4401
|
||||
for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]);
|
||||
|
||||
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
|
||||
SEGENV.aux0 = !SEGENV.aux0;
|
||||
SEGENV.step = 0;
|
||||
memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading
|
||||
} else {
|
||||
SEGENV.step++;
|
||||
}
|
||||
@ -1023,7 +1017,7 @@ static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2,
|
||||
* Emulates a traffic light.
|
||||
*/
|
||||
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++)
|
||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
||||
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
|
||||
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);
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
|
||||
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.
|
||||
*/
|
||||
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 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"
|
||||
*/
|
||||
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 index = (counter * SEGLEN) >> 16;
|
||||
if (SEGENV.call == 0) SEGENV.aux0 = index;
|
||||
@ -1254,7 +1248,7 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!"
|
||||
* Fireworks function.
|
||||
*/
|
||||
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 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
|
||||
uint16_t mode_rain() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
const unsigned width = SEG_W;
|
||||
const unsigned height = SEG_H;
|
||||
SEGENV.step += FRAMETIME;
|
||||
@ -1362,7 +1356,7 @@ static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!;0
|
||||
* Gradient run base function
|
||||
*/
|
||||
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 pp = (counter * SEGLEN) >> 16;
|
||||
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
|
||||
*/
|
||||
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
|
||||
uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
|
||||
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 (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
|
||||
oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8);
|
||||
if((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) {
|
||||
if((oscillators[i].dir == -1) && (oscillators[i].pos > SEGLEN << 1)) { // use integer overflow
|
||||
oscillators[i].pos = 0;
|
||||
oscillators[i].dir = 1;
|
||||
// make bigger steps for faster speeds
|
||||
@ -1843,7 +1837,7 @@ uint16_t mode_oscillate(void) {
|
||||
for (unsigned i = 0; i < SEGLEN; i++) {
|
||||
uint32_t color = BLACK;
|
||||
for (unsigned j = 0; j < numOscillators; j++) {
|
||||
if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -1858,7 +1852,7 @@ static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate";
|
||||
|
||||
//TODO
|
||||
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 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);
|
||||
@ -1899,52 +1893,76 @@ uint16_t mode_lightning(void) {
|
||||
}
|
||||
static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!";
|
||||
|
||||
|
||||
// Pride2015
|
||||
// Animated, ever-changing rainbows.
|
||||
// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
|
||||
uint16_t mode_pride_2015(void) {
|
||||
// combined function from original pride and colorwaves
|
||||
uint16_t mode_colorwaves_pride_base(bool isPride2015) {
|
||||
unsigned duration = 10 + SEGMENT.speed;
|
||||
unsigned sPseudotime = SEGENV.step;
|
||||
unsigned sHue16 = SEGENV.aux0;
|
||||
|
||||
uint8_t sat8 = beatsin88_t( 87, 220, 250);
|
||||
uint8_t brightdepth = beatsin88_t( 341, 96, 224);
|
||||
unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256));
|
||||
uint8_t sat8 = isPride2015 ? beatsin88_t(87, 220, 250) : 255;
|
||||
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, 1, 3000);
|
||||
unsigned hue16 = sHue16;
|
||||
unsigned hueinc16 = isPride2015 ? beatsin88_t(113, 1, 3000) :
|
||||
beatsin88_t(113, 60, 300) * SEGMENT.intensity * 10 / 255;
|
||||
|
||||
sPseudotime += duration * msmultiplier;
|
||||
sHue16 += duration * beatsin88_t( 400, 5,9);
|
||||
sHue16 += duration * beatsin88_t(400, 5, 9);
|
||||
unsigned brightnesstheta16 = sPseudotime;
|
||||
|
||||
for (unsigned i = 0 ; i < SEGLEN; i++) {
|
||||
for (unsigned i = 0; i < SEGLEN; i++) {
|
||||
hue16 += hueinc16;
|
||||
uint8_t hue8 = hue16 >> 8;
|
||||
uint8_t hue8;
|
||||
|
||||
brightnesstheta16 += brightnessthetainc16;
|
||||
unsigned b16 = sin16_t( brightnesstheta16 ) + 32768;
|
||||
if (isPride2015) {
|
||||
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;
|
||||
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
|
||||
bri8 += (255 - brightdepth);
|
||||
|
||||
CRGB newcolor = CHSV(hue8, sat8, bri8);
|
||||
SEGMENT.blendPixelColor(i, newcolor, 64);
|
||||
if (isPride2015) {
|
||||
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.aux0 = sHue16;
|
||||
|
||||
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@!;;";
|
||||
|
||||
// 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
|
||||
uint16_t mode_juggle(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
|
||||
SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4));
|
||||
CRGB fastled_col;
|
||||
@ -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
|
||||
// in step 3 above) (Effect Intensity = Sparking).
|
||||
uint16_t mode_fire_2012() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
const unsigned strips = SEGMENT.nrOfVStrips();
|
||||
if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed
|
||||
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
|
||||
|
||||
|
||||
// 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)
|
||||
uint16_t mode_bpm() {
|
||||
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.
|
||||
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
||||
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
|
||||
const bool meteorSmooth = SEGMENT.check3;
|
||||
byte* trail = SEGENV.data;
|
||||
@ -2436,7 +2407,7 @@ static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient,,
|
||||
|
||||
//Railway Crossing / Christmas Fairy lights
|
||||
uint16_t mode_railway() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
unsigned dur = (256 - SEGMENT.speed) * 40;
|
||||
uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
|
||||
if (SEGENV.step > dur)
|
||||
@ -2537,7 +2508,7 @@ static uint16_t ripple_base(uint8_t blurAmount = 0) {
|
||||
|
||||
|
||||
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
|
||||
SEGMENT.fade_out(250);
|
||||
else
|
||||
@ -2549,7 +2520,7 @@ static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Over
|
||||
|
||||
|
||||
uint16_t mode_ripple_rainbow(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
if (SEGENV.call ==0) {
|
||||
SEGENV.aux0 = hw_random8();
|
||||
SEGENV.aux1 = hw_random8();
|
||||
@ -2727,7 +2698,7 @@ uint16_t mode_halloween_eyes()
|
||||
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 HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEG_W>>4: SEGLEN>>5);
|
||||
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)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||
|
||||
unsigned maxZones = SEGLEN >> 2;
|
||||
@ -2968,7 +2939,7 @@ typedef struct Ball {
|
||||
* Bouncing Balls Effect
|
||||
*/
|
||||
uint16_t mode_bouncing_balls(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
//allocate segment data
|
||||
const unsigned strips = SEGMENT.nrOfVStrips(); // adapt for 2D
|
||||
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
|
||||
*/
|
||||
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);
|
||||
unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1);
|
||||
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
|
||||
*/
|
||||
uint16_t mode_popcorn(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
//allocate segment data
|
||||
unsigned strips = SEGMENT.nrOfVStrips();
|
||||
unsigned usablePopcorns = maxNumPopcorn;
|
||||
@ -3426,7 +3397,7 @@ typedef struct particle {
|
||||
} star;
|
||||
|
||||
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 segs = strip.getActiveSegmentsNum();
|
||||
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)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
const int cols = SEGMENT.is2D() ? SEG_W : 1;
|
||||
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)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
//allocate segment data
|
||||
unsigned strips = SEGMENT.nrOfVStrips();
|
||||
const int maxNumDrops = 4;
|
||||
@ -3779,7 +3750,7 @@ typedef struct Tetris {
|
||||
} tetris;
|
||||
|
||||
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 dataSize = sizeof(tetris);
|
||||
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
|
||||
//
|
||||
// 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 waveangle = ioff;
|
||||
@ -4086,7 +4057,7 @@ static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=5
|
||||
* Mode simulates a gradual sunrise
|
||||
*/
|
||||
uint16_t mode_sunrise() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
//speed 0 - static sun
|
||||
//speed 1 - 60: sunrise time in minutes
|
||||
//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)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
SEGMENT.fade_out(254); // add a bit of trail
|
||||
unsigned counter = strip.now * (6 + (SEGMENT.speed >> 4));
|
||||
unsigned numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
||||
@ -4344,7 +4315,7 @@ typedef struct Spotlight {
|
||||
*/
|
||||
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
|
||||
bool initialize = 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.
|
||||
// Controls are speed, # of pixels, faderate.
|
||||
uint16_t mode_perlinmove(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
SEGMENT.fade_out(255-SEGMENT.custom1);
|
||||
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.
|
||||
@ -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
|
||||
uint16_t mode_FlowStripe(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
const int hl = SEGLEN * 10 / 13;
|
||||
uint8_t hue = strip.now / (SEGMENT.speed+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
|
||||
unsigned dx = abs(x - x1);
|
||||
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);
|
||||
dy = abs(y - y2);
|
||||
dist += sqrt16((dx * dx) + (dy * dy));
|
||||
dist += sqrt32_bw((dx * dx) + (dy * dy));
|
||||
|
||||
dx = abs(x - x3);
|
||||
dy = abs(y - y3);
|
||||
dist += sqrt16((dx * dx) + (dy * dy));
|
||||
dist += sqrt32_bw((dx * dx) + (dy * dy));
|
||||
|
||||
// inverse result
|
||||
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
|
||||
sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||
} 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));
|
||||
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("#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("#HH"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%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("#HH"),3)) sprintf (text, zero? ("%02d") : ("%d"), AmPmHour);
|
||||
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);
|
||||
@ -6568,23 +6549,31 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!;
|
||||
// * MATRIPIX //
|
||||
//////////////////////
|
||||
uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||
// effect can work on single pixels, we just lose the shifting effect
|
||||
unsigned dataSize = sizeof(uint32_t) * SEGLEN;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||
|
||||
um_data_t *um_data = getAudioData();
|
||||
int volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.fill(BLACK);
|
||||
for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer
|
||||
}
|
||||
|
||||
uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16;
|
||||
if(SEGENV.aux0 != secondHand) {
|
||||
SEGENV.aux0 = secondHand;
|
||||
|
||||
uint8_t pixBri = volumeRaw * SEGMENT.intensity / 64;
|
||||
for (unsigned i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
|
||||
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri));
|
||||
int pixBri = volumeRaw * SEGMENT.intensity / 64;
|
||||
unsigned k = SEGLEN-1;
|
||||
// loop will not execute if SEGLEN equals 1
|
||||
for (unsigned i = 0; i < k; i++) {
|
||||
pixels[i] = pixels[i+1]; // shift left
|
||||
SEGMENT.setPixelColor(i, pixels[i]);
|
||||
}
|
||||
pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri);
|
||||
SEGMENT.setPixelColor(k, pixels[k]);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
@ -6596,7 +6585,7 @@ static const char _data_FX_MODE_MATRIPIX[] PROGMEM = "Matripix@!,Brightness;!,!;
|
||||
// * MIDNOISE //
|
||||
//////////////////////
|
||||
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.
|
||||
|
||||
um_data_t *um_data = getAudioData();
|
||||
@ -6687,7 +6676,7 @@ static const char _data_FX_MODE_NOISEMETER[] PROGMEM = "Noisemeter@Fade rate,Wid
|
||||
// * PIXELWAVE //
|
||||
//////////////////////
|
||||
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
|
||||
|
||||
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
|
||||
uint16_t mode_puddles_base(bool peakdetect) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGLEN <= 1) return mode_static();
|
||||
unsigned size = 0;
|
||||
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
|
||||
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 //
|
||||
//////////////////////
|
||||
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
|
||||
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 //
|
||||
//////////////////////
|
||||
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
|
||||
|
||||
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 //
|
||||
////////////////////
|
||||
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
|
||||
// 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.
|
||||
uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline
|
||||
// effect can work on single pixels, we just lose the shifting effect
|
||||
|
||||
um_data_t *um_data = getAudioData();
|
||||
unsigned dataSize = sizeof(uint32_t) * SEGLEN;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
||||
float FFT_MajorPeak = *(float*) um_data->u_data[4];
|
||||
uint8_t *maxVol = (uint8_t*)um_data->u_data[6];
|
||||
@ -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 (SEGENV.call == 0) {
|
||||
SEGMENT.fill(BLACK);
|
||||
for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer
|
||||
SEGENV.aux0 = 255;
|
||||
SEGMENT.custom1 = *binNum;
|
||||
SEGMENT.custom2 = *maxVol * 2;
|
||||
@ -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.
|
||||
if (FFT_MajorPeak < 182.0f) pixCol = 0; // handle underflow
|
||||
|
||||
unsigned k = SEGLEN-1;
|
||||
if (samplePeak) {
|
||||
SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92));
|
||||
pixels[k] = (uint32_t)CRGB(CHSV(92,92,92));
|
||||
} else {
|
||||
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (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
|
||||
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;
|
||||
|
73
wled00/FX.h
73
wled00/FX.h
@ -79,9 +79,9 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default (S2 is short on free RAM)
|
||||
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM)
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default
|
||||
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -488,7 +488,7 @@ typedef struct Segment {
|
||||
{}
|
||||
} *_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:
|
||||
|
||||
@ -546,7 +546,7 @@ typedef struct Segment {
|
||||
//if (data) Serial.printf(" %d->(%p)", (int)_dataLen, data);
|
||||
//Serial.println();
|
||||
#endif
|
||||
if (name) { delete[] name; name = nullptr; }
|
||||
if (name) { free(name); name = nullptr; }
|
||||
stopTransition();
|
||||
deallocateData();
|
||||
}
|
||||
@ -562,7 +562,6 @@ typedef struct Segment {
|
||||
inline bool isSelected() const { return selected; }
|
||||
inline bool isInTransition() const { return _t != nullptr; }
|
||||
inline bool isActive() const { return stop > start; }
|
||||
inline bool is2D() const { return (width()>1 && height()>1); }
|
||||
inline bool hasRGB() const { return _isRGB; }
|
||||
inline bool hasWhite() const { return _hasW; }
|
||||
inline bool isCCT() const { return _isCCT; }
|
||||
@ -616,10 +615,10 @@ typedef struct Segment {
|
||||
inline void handleTransition() { updateTransitionProgress(); if (progress() == 0xFFFFU) stopTransition(); }
|
||||
#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 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
|
||||
[[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)
|
||||
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)
|
||||
@ -627,14 +626,14 @@ typedef struct Segment {
|
||||
|
||||
// 1D strip
|
||||
[[gnu::hot]] uint16_t virtualLength() const;
|
||||
[[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
|
||||
inline void setPixelColor(unsigned n, uint32_t c) { 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, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); }
|
||||
[[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) const { setPixelColor(int(n), c); }
|
||||
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) const { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); }
|
||||
#ifdef WLED_USE_AA_PIXELS
|
||||
void setPixelColor(float i, uint32_t c, bool aa = true);
|
||||
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, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
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) const { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
||||
inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
#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; };
|
||||
@ -674,16 +673,17 @@ typedef struct Segment {
|
||||
#endif
|
||||
}
|
||||
#ifndef WLED_DISABLE_2D
|
||||
[[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment
|
||||
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), 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, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); }
|
||||
inline bool is2D() const { return (width()>1 && height()>1); }
|
||||
[[gnu::hot]] int XY(int x, int y) const; // support function to get relative index within segment
|
||||
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c) const; // set relative pixel within segment with color
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) const { setPixelColorXY(int(x), int(y), c); }
|
||||
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) 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
|
||||
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true);
|
||||
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, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
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) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), 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
|
||||
[[gnu::hot]] bool isPixelXYClipped(int x, int y) const;
|
||||
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
|
||||
@ -711,7 +711,8 @@ typedef struct Segment {
|
||||
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)); }
|
||||
#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(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)); }
|
||||
@ -810,7 +811,7 @@ class WS2812FX { // 96 bytes
|
||||
}
|
||||
|
||||
~WS2812FX() {
|
||||
if (customMappingTable) delete[] customMappingTable;
|
||||
if (customMappingTable) free(customMappingTable);
|
||||
_mode.clear();
|
||||
_modeData.clear();
|
||||
_segments.clear();
|
||||
@ -836,7 +837,7 @@ class WS2812FX { // 96 bytes
|
||||
resetSegments(), // marks all segments for reset
|
||||
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
||||
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
|
||||
setTargetFps(unsigned fps),
|
||||
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
||||
@ -844,9 +845,9 @@ class WS2812FX { // 96 bytes
|
||||
inline void resetTimebase() { timebase = 0UL - millis(); }
|
||||
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 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, CRGB c) { 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 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) const { setPixelColor(n, c.red, c.green, c.blue); }
|
||||
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 setShowCallback(show_callback cb) { _callback = cb; }
|
||||
inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
|
||||
@ -855,7 +856,7 @@ class WS2812FX { // 96 bytes
|
||||
inline void resume() { _suspend = false; } // will resume strip.service() execution
|
||||
|
||||
bool
|
||||
checkSegmentAlignment(),
|
||||
checkSegmentAlignment() const,
|
||||
hasRGBWBus() const,
|
||||
hasCCTBus() const,
|
||||
deserializeMap(unsigned n = 0);
|
||||
@ -899,7 +900,7 @@ class WS2812FX { // 96 bytes
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
@ -948,11 +949,11 @@ class WS2812FX { // 96 bytes
|
||||
void setUpMatrix(); // sets up automatic matrix ledmap from panel configuration
|
||||
|
||||
// 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, byte r, byte g, byte b, byte w = 0) { 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, 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) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||
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
|
||||
|
||||
@ -966,7 +967,7 @@ class WS2812FX { // 96 bytes
|
||||
};
|
||||
|
||||
std::vector<segment> _segments;
|
||||
friend class Segment;
|
||||
friend struct Segment;
|
||||
|
||||
private:
|
||||
volatile bool _suspend;
|
||||
|
@ -50,8 +50,8 @@ void WS2812FX::setUpMatrix() {
|
||||
|
||||
customMappingSize = 0; // prevent use of mapping if anything goes wrong
|
||||
|
||||
if (customMappingTable) delete[] customMappingTable;
|
||||
customMappingTable = new uint16_t[getLengthTotal()];
|
||||
if (customMappingTable) free(customMappingTable);
|
||||
customMappingTable = static_cast<uint16_t*>(malloc(sizeof(uint16_t)*getLengthTotal()));
|
||||
|
||||
if (customMappingTable) {
|
||||
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,...]
|
||||
// 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)
|
||||
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);
|
||||
size_t gapSize = 0;
|
||||
int8_t *gapTable = nullptr;
|
||||
@ -85,7 +85,7 @@ void WS2812FX::setUpMatrix() {
|
||||
JsonArray map = pDoc->as<JsonArray>();
|
||||
gapSize = map.size();
|
||||
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++) {
|
||||
gapTable[i] = constrain(map[i], -1, 1);
|
||||
}
|
||||
@ -113,7 +113,7 @@ void WS2812FX::setUpMatrix() {
|
||||
}
|
||||
|
||||
// delete gap array as we no longer need it
|
||||
if (gapTable) delete[] gapTable;
|
||||
if (gapTable) free(gapTable);
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("Matrix ledmap:"));
|
||||
@ -146,7 +146,7 @@ void WS2812FX::setUpMatrix() {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
||||
// 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 vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
@ -154,7 +154,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
||||
}
|
||||
|
||||
// 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 baseY = startY + y;
|
||||
@ -210,7 +210,7 @@ bool IRAM_ATTR_YN Segment::isPixelXYClipped(int x, int y) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
|
||||
@ -258,7 +258,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
|
||||
#ifdef WLED_USE_AA_PIXELS
|
||||
// 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 (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||
@ -334,7 +334,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) {
|
||||
if (!isActive()) return; // not active
|
||||
const unsigned cols = vWidth();
|
||||
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;
|
||||
if (blur_x) {
|
||||
const uint8_t keepx = smear ? 255 : 255 - blur_x;
|
||||
|
@ -98,7 +98,7 @@ Segment::Segment(const Segment &orig) {
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_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); }
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
//DEBUG_PRINTF_P(PSTR("-- Copying segment: %p -> %p\n"), &orig, this);
|
||||
if (this != &orig) {
|
||||
// clean destination
|
||||
if (name) { delete[] name; name = nullptr; }
|
||||
if (name) { free(name); name = nullptr; }
|
||||
stopTransition();
|
||||
deallocateData();
|
||||
// copy source
|
||||
@ -126,7 +126,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
// 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); }
|
||||
}
|
||||
return *this;
|
||||
@ -136,7 +136,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
//DEBUG_PRINTF_P(PSTR("-- Moving segment: %p -> %p\n"), &orig, this);
|
||||
if (this != &orig) {
|
||||
if (name) { delete[] name; name = nullptr; } // free old name
|
||||
if (name) { free(name); name = nullptr; } // free old name
|
||||
stopTransition();
|
||||
deallocateData(); // free old runtime data
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
@ -257,7 +257,7 @@ void Segment::startTransition(uint16_t dur) {
|
||||
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
|
||||
_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
|
||||
|
||||
//DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t);
|
||||
@ -297,6 +297,7 @@ void Segment::stopTransition() {
|
||||
delete _t;
|
||||
_t = nullptr;
|
||||
}
|
||||
_transitionprogress = 0xFFFFU; // stop means stop - transition has ended
|
||||
}
|
||||
|
||||
// transition progression between 0-65535
|
||||
@ -327,7 +328,7 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
|
||||
tmpSeg._callT = call;
|
||||
tmpSeg._dataT = data;
|
||||
tmpSeg._dataLenT = _dataLen;
|
||||
if (_t && &tmpSeg != &(_t->_segT)) {
|
||||
if (isInTransition() && &tmpSeg != &(_t->_segT)) {
|
||||
// swap SEGENV with transitional data
|
||||
options = _t->_segT._optionsT;
|
||||
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = _t->_segT._colorT[i];
|
||||
@ -348,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);
|
||||
if (_t && &(_t->_segT) != &tmpSeg) {
|
||||
if (isInTransition() && &(_t->_segT) != &tmpSeg) {
|
||||
// update possibly changed variables to keep old effect running correctly
|
||||
_t->_segT._aux0T = aux0;
|
||||
_t->_segT._aux1T = aux1;
|
||||
@ -380,7 +381,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
||||
#endif
|
||||
|
||||
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) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
@ -399,7 +400,7 @@ uint8_t Segment::currentBri(bool useCct) const {
|
||||
|
||||
uint8_t Segment::currentMode() const {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
unsigned prog = progress();
|
||||
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
||||
if (prog == 0xFFFFU) return mode;
|
||||
if (blendingStyle != BLEND_STYLE_FADE) {
|
||||
// workaround for on/off transition to respect blending style
|
||||
@ -436,18 +437,18 @@ void Segment::beginDraw() {
|
||||
_vHeight = virtualHeight();
|
||||
_vLength = virtualLength();
|
||||
_segBri = currentBri();
|
||||
unsigned prog = isInTransition() ? progress() : 0xFFFFU; // transition progress; 0xFFFFU = no transition active
|
||||
// adjust gamma for effects
|
||||
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||
#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
|
||||
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
|
||||
_currentColors[i] = gamma32(col);
|
||||
}
|
||||
// load palette into _currentPalette
|
||||
loadPalette(_currentPalette, palette);
|
||||
unsigned prog = progress();
|
||||
if (prog < 0xFFFFU) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (blendingStyle > BLEND_STYLE_FADE) {
|
||||
@ -711,7 +712,7 @@ uint16_t Segment::virtualLength() const {
|
||||
vLen = max(vW,vH); // get the longest dimension
|
||||
break;
|
||||
case M12_pArc:
|
||||
vLen = sqrt16(vH*vH + vW*vW); // use diagonal
|
||||
vLen = sqrt32_bw(vH*vH + vW*vW); // use diagonal
|
||||
break;
|
||||
case M12_sPinwheel:
|
||||
vLen = getPinwheelLength(vW, vH);
|
||||
@ -756,7 +757,7 @@ bool IRAM_ATTR_YN Segment::isPixelClipped(int i) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
|
||||
{
|
||||
if (!isActive() || i < 0) return; // not active or invalid index
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -943,7 +944,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
|
||||
#ifdef WLED_USE_AA_PIXELS
|
||||
// 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
|
||||
int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows)
|
||||
@ -998,7 +999,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
||||
break; }
|
||||
case M12_pArc:
|
||||
if (i >= vW && i >= vH) {
|
||||
unsigned vI = sqrt16(i*i/2);
|
||||
unsigned vI = sqrt32_bw(i*i/2);
|
||||
return getPixelColorXY(vI,vI); // use diagonal
|
||||
}
|
||||
case M12_pCorner:
|
||||
@ -1222,7 +1223,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
unsigned vlength = vLength();
|
||||
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 curnew = BLACK;
|
||||
for (unsigned i = 0; i < vlength; i++) {
|
||||
@ -1559,7 +1560,7 @@ void WS2812FX::service() {
|
||||
#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);
|
||||
if (i >= _length) return;
|
||||
BusManager::setPixelColor(i, col);
|
||||
@ -1840,9 +1841,9 @@ void WS2812FX::fixInvalidSegments() {
|
||||
|
||||
//true if all segments align with a bus, or if a segment covers the total length
|
||||
//irrelevant in 2D set-up
|
||||
bool WS2812FX::checkSegmentAlignment() {
|
||||
bool WS2812FX::checkSegmentAlignment() const {
|
||||
bool aligned = false;
|
||||
for (segment &seg : _segments) {
|
||||
for (const segment &seg : _segments) {
|
||||
for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
||||
@ -1954,8 +1955,8 @@ bool WS2812FX::deserializeMap(unsigned n) {
|
||||
Segment::maxHeight = min(max(root[F("height")].as<int>(), 1), 128);
|
||||
}
|
||||
|
||||
if (customMappingTable) delete[] customMappingTable;
|
||||
customMappingTable = new uint16_t[getLengthTotal()];
|
||||
if (customMappingTable) free(customMappingTable);
|
||||
customMappingTable = static_cast<uint16_t*>(malloc(sizeof(uint16_t)*getLengthTotal()));
|
||||
|
||||
if (customMappingTable) {
|
||||
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);
|
||||
|
||||
//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
|
||||
#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))
|
||||
, _skip(bc.skipAmount) //sacrificial pixels
|
||||
, _colorOrder(bc.colorOrder)
|
||||
@ -448,7 +448,7 @@ void BusDigital::cleanup() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
BusPwm::BusPwm(BusConfig &bc)
|
||||
BusPwm::BusPwm(const BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed, bc.refreshReq) // hijack Off refresh flag to indicate usage of dithering
|
||||
{
|
||||
if (!isPWM(bc.type)) return;
|
||||
@ -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)
|
||||
, _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)
|
||||
, _broadcastLock(false)
|
||||
{
|
||||
@ -778,7 +778,7 @@ void BusNetwork::cleanup() {
|
||||
|
||||
|
||||
//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;
|
||||
|
||||
unsigned len = bc.count + bc.skipAmount;
|
||||
@ -803,7 +803,7 @@ uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned
|
||||
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 (Bus::isVirtual(bc.type)) {
|
||||
busses[numBusses] = new BusNetwork(bc);
|
||||
|
@ -198,7 +198,7 @@ class Bus {
|
||||
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
||||
BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
||||
~BusDigital() { cleanup(); }
|
||||
|
||||
void show() override;
|
||||
@ -250,7 +250,7 @@ class BusDigital : public Bus {
|
||||
|
||||
class BusPwm : public Bus {
|
||||
public:
|
||||
BusPwm(BusConfig &bc);
|
||||
BusPwm(const BusConfig &bc);
|
||||
~BusPwm() { cleanup(); }
|
||||
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
@ -277,7 +277,7 @@ class BusPwm : public Bus {
|
||||
|
||||
class BusOnOff : public Bus {
|
||||
public:
|
||||
BusOnOff(BusConfig &bc);
|
||||
BusOnOff(const BusConfig &bc);
|
||||
~BusOnOff() { cleanup(); }
|
||||
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
@ -296,7 +296,7 @@ class BusOnOff : public Bus {
|
||||
|
||||
class BusNetwork : public Bus {
|
||||
public:
|
||||
BusNetwork(BusConfig &bc);
|
||||
BusNetwork(const BusConfig &bc);
|
||||
~BusNetwork() { cleanup(); }
|
||||
|
||||
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
||||
@ -379,12 +379,12 @@ class BusManager {
|
||||
BusManager() {};
|
||||
|
||||
//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 uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
||||
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
||||
|
||||
static int add(BusConfig &bc);
|
||||
static int add(const BusConfig &bc);
|
||||
static void useParallelOutput(); // workaround for inaccessible PolyBus
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
|
@ -90,12 +90,12 @@ void doublePressAction(uint8_t b)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isButtonPressed(uint8_t i)
|
||||
bool isButtonPressed(uint8_t b)
|
||||
{
|
||||
if (btnPin[i]<0) return false;
|
||||
unsigned pin = btnPin[i];
|
||||
if (btnPin[b]<0) return false;
|
||||
unsigned pin = btnPin[b];
|
||||
|
||||
switch (buttonType[i]) {
|
||||
switch (buttonType[b]) {
|
||||
case BTN_TYPE_NONE:
|
||||
case BTN_TYPE_RESERVED:
|
||||
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)
|
||||
if (touchInterruptGetLastStatus(pin)) return true;
|
||||
#else
|
||||
if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) return true;
|
||||
if (digitalPinToTouchChannel(btnPin[b]) >= 0 && touchRead(pin) <= touchThreshold) return true;
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
|
@ -519,6 +519,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
tdd = if_live[F("timeout")] | -1;
|
||||
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(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
||||
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
||||
@ -995,6 +1003,12 @@ void serializeConfig() {
|
||||
if_live_dmx[F("addr")] = DMXAddress;
|
||||
if_live_dmx[F("dss")] = DMXSegmentSpacing;
|
||||
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("maxbri")] = arlsForceMaxBri;
|
||||
|
@ -122,7 +122,7 @@ void setRandomColor(byte* rgb)
|
||||
* 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
|
||||
*/
|
||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
||||
CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette)
|
||||
{
|
||||
CHSV palettecolors[4]; // array of colors for the new palette
|
||||
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);
|
||||
}
|
||||
|
||||
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 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
|
||||
|
||||
//RRGGBB / WWRRGGBB order for hex
|
||||
void colorFromDecOrHexString(byte* rgb, char* in)
|
||||
void colorFromDecOrHexString(byte* rgb, const char* in)
|
||||
{
|
||||
if (in[0] == 0) return;
|
||||
char first = in[0];
|
||||
|
@ -204,6 +204,7 @@
|
||||
#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_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h"
|
||||
#define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@ -249,6 +250,7 @@
|
||||
#define REALTIME_MODE_ARTNET 6
|
||||
#define REALTIME_MODE_TPM2NET 7
|
||||
#define REALTIME_MODE_DDP 8
|
||||
#define REALTIME_MODE_DMX 9
|
||||
|
||||
//realtime override modes
|
||||
#define REALTIME_OVERRIDE_NONE 0
|
||||
|
@ -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>
|
||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||
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">
|
||||
<h3>Alexa Voice Assistant</h3>
|
||||
<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"
|
||||
|
||||
/*
|
||||
* 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/SparkFunDMX.cpp, if needed (ESP32)
|
||||
* ESP8266 Library from:
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
|
||||
void handleDMX()
|
||||
void handleDMXOutput()
|
||||
{
|
||||
// don't act, when in DMX Proxy mode
|
||||
if (e131ProxyUniverse != 0) return;
|
||||
@ -68,11 +68,14 @@ void handleDMX()
|
||||
dmx.update(); // update the DMX bus
|
||||
}
|
||||
|
||||
void initDMX() {
|
||||
void initDMXOutput() {
|
||||
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
dmx.init(512); // initialize with bus length
|
||||
#else
|
||||
dmx.initWrite(512); // initialize with bus length
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void initDMXOutput(){}
|
||||
void handleDMXOutput() {}
|
||||
#endif
|
@ -116,6 +116,11 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
|
||||
// update status info
|
||||
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;
|
||||
unsigned totalLen = strip.getLengthTotal();
|
||||
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
|
||||
if (protocol == P_ARTNET && dataOffset > 0) {
|
||||
if (mde == REALTIME_MODE_ARTNET && dataOffset > 0) {
|
||||
dataOffset--;
|
||||
}
|
||||
|
||||
@ -211,7 +216,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
else
|
||||
dataOffset = DMXAddress;
|
||||
// Modify address for Art-Net data
|
||||
if (protocol == P_ARTNET && dataOffset > 0)
|
||||
if (mde == REALTIME_MODE_ARTNET && dataOffset > 0)
|
||||
dataOffset--;
|
||||
// Skip out of universe addresses
|
||||
if (dataOffset > dmxChannels - dmxEffectChannels + 1)
|
||||
@ -285,7 +290,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
}
|
||||
} else {
|
||||
// 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;
|
||||
unsigned ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed;
|
||||
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * ledsPerUniverse;
|
||||
|
@ -161,12 +161,12 @@ class NeoGammaWLEDMethod {
|
||||
};
|
||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(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); };
|
||||
[[gnu::hot]] 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]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
|
||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
|
||||
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
||||
[[gnu::hot, gnu::pure]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
||||
[[gnu::hot, gnu::pure]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
|
||||
CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette);
|
||||
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]))); }
|
||||
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb);
|
||||
@ -176,33 +176,38 @@ inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) <<
|
||||
void colorKtoRGB(uint16_t kelvin, byte* 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 colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO
|
||||
void colorFromDecOrHexString(byte* rgb, char* in);
|
||||
void colorRGBtoXY(const byte* rgb, float* xy); // only defined if huesync disabled TODO
|
||||
void colorFromDecOrHexString(byte* rgb, const char* in);
|
||||
bool colorFromHexString(byte* rgb, const char* in);
|
||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||
void setRandomColor(byte* rgb);
|
||||
|
||||
//dmx.cpp
|
||||
void initDMX();
|
||||
void handleDMX();
|
||||
//dmx_output.cpp
|
||||
void initDMXOutput();
|
||||
void handleDMXOutput();
|
||||
|
||||
//dmx_input.cpp
|
||||
void initDMXInput();
|
||||
void handleDMXInput();
|
||||
|
||||
//e131.cpp
|
||||
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 prepareArtnetPollReply(ArtPollReply* reply);
|
||||
void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t portAddress);
|
||||
|
||||
//file.cpp
|
||||
bool handleFileRead(AsyncWebServerRequest*, String path);
|
||||
bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content);
|
||||
bool writeObjectToFile(const char* file, const char* key, JsonDocument* content);
|
||||
bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content);
|
||||
bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content);
|
||||
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest);
|
||||
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest);
|
||||
void updateFSInfo();
|
||||
void closeFile();
|
||||
inline bool writeObjectToFileUsingId(const String &file, uint16_t id, 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 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, 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 readObjectFromFile(const String &file, const char* key, JsonDocument* dest) { return readObjectFromFile(file.c_str(), key, dest); };
|
||||
|
||||
@ -243,11 +248,11 @@ void handleIR();
|
||||
|
||||
bool deserializeSegment(JsonObject elem, byte it, 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 serializeInfo(JsonObject root);
|
||||
void serializeModeNames(JsonArray root);
|
||||
void serializeModeData(JsonArray root);
|
||||
void serializeModeNames(JsonArray arr);
|
||||
void serializeModeData(JsonArray fxdata);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
@ -318,7 +323,8 @@ void deletePreset(byte index);
|
||||
bool getPresetName(byte index, String& name);
|
||||
|
||||
//remote.cpp
|
||||
void handleRemote(uint8_t *data, size_t len);
|
||||
void handleWiZdata(uint8_t *incomingData, size_t len);
|
||||
void handleRemote();
|
||||
|
||||
//set.cpp
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
@ -327,7 +333,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=tru
|
||||
|
||||
//udp.cpp
|
||||
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 exitRealtime();
|
||||
void handleNotifications();
|
||||
@ -461,10 +467,10 @@ void userLoop();
|
||||
#include "soc/wdev_reg.h"
|
||||
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
||||
#endif
|
||||
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);
|
||||
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
||||
bool getBoolVal(JsonVariant elem, bool dflt);
|
||||
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form)
|
||||
[[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);
|
||||
size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val);
|
||||
size_t printSetFormValue(Print& settingsScript, const char* key, int val);
|
||||
@ -472,8 +478,8 @@ size_t printSetFormValue(Print& settingsScript, const char* key, const char* val
|
||||
size_t printSetFormIndex(Print& settingsScript, const char* key, int index);
|
||||
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val);
|
||||
void prepareHostname(char* hostname);
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
bool requestJSONBufferLock(uint8_t module=255);
|
||||
[[gnu::pure]] bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
bool requestJSONBufferLock(uint8_t moduleID=255);
|
||||
void releaseJSONBufferLock();
|
||||
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);
|
||||
@ -485,8 +491,8 @@ 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);
|
||||
um_data_t* simulateSound(uint8_t simulationId);
|
||||
void enumerateLedmaps();
|
||||
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]] uint8_t get_random_wheel_index(uint8_t pos);
|
||||
[[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
|
||||
@ -547,6 +553,7 @@ float asin_t(float x);
|
||||
template <typename T> T atan_t(T x);
|
||||
float floor_t(float x);
|
||||
float fmod_t(float num, float denom);
|
||||
uint32_t sqrt32_bw(uint32_t x);
|
||||
#define sin_t sin_approx
|
||||
#define cos_t cos_approx
|
||||
#define tan_t tan_approx
|
||||
|
@ -176,7 +176,7 @@ static void writeSpace(size_t 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
|
||||
DEBUGFS_PRINTLN(F("Append"));
|
||||
@ -255,14 +255,14 @@ bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint
|
||||
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];
|
||||
sprintf(objKey, "\"%d\":", id);
|
||||
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
|
||||
#ifdef WLED_DEBUG_FS
|
||||
|
@ -68,7 +68,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (elem["n"]) {
|
||||
// name field exists
|
||||
if (seg.name) { //clear old name
|
||||
delete[] seg.name;
|
||||
free(seg.name);
|
||||
seg.name = nullptr;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (name != nullptr) len = strlen(name);
|
||||
if (len > 0) {
|
||||
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);
|
||||
} else {
|
||||
// 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) {
|
||||
// clearing or setting segment without name field
|
||||
if (seg.name) {
|
||||
delete[] seg.name;
|
||||
free(seg.name);
|
||||
seg.name = nullptr;
|
||||
}
|
||||
}
|
||||
@ -498,7 +498,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
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;
|
||||
if (segmentBounds) {
|
||||
|
@ -73,8 +73,7 @@ byte scaledBri(byte in)
|
||||
|
||||
//applies global temporary brightness (briT) to strip
|
||||
void applyBri() {
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
if (!(realtimeMode && arlsForceMaxBri)) {
|
||||
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
||||
strip.setBrightness(scaledBri(briT));
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ bool parseLx(int lxValue, byte* rgbw)
|
||||
} else if ((lxValue >= 200000000) && (lxValue <= 201006500)) {
|
||||
// Loxone Lumitech
|
||||
ok = true;
|
||||
float tmpBri = floor((lxValue - 200000000) / 10000); ;
|
||||
float tmpBri = floor((lxValue - 200000000) / 10000);
|
||||
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
|
||||
|
||||
tmpBri *= 2.55f;
|
||||
|
@ -68,8 +68,8 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
||||
}
|
||||
|
||||
if (index == 0) { // start (1st partial packet or the only packet)
|
||||
if (payloadStr) delete[] payloadStr; // fail-safe: release buffer
|
||||
payloadStr = new char[total+1]; // allocate new buffer
|
||||
if (payloadStr) free(payloadStr); // fail-safe: release buffer
|
||||
payloadStr = static_cast<char*>(malloc(total+1)); // allocate new buffer
|
||||
}
|
||||
if (payloadStr == nullptr) return; // buffer not allocated
|
||||
|
||||
@ -94,7 +94,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
||||
} else {
|
||||
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
|
||||
UsermodManager::onMqttMessage(topic, payloadStr);
|
||||
delete[] payloadStr;
|
||||
free(payloadStr);
|
||||
payloadStr = nullptr;
|
||||
return;
|
||||
}
|
||||
@ -124,7 +124,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
||||
// topmost topic (just wled/MAC)
|
||||
parseMQTTBriPayload(payloadStr);
|
||||
}
|
||||
delete[] payloadStr;
|
||||
free(payloadStr);
|
||||
payloadStr = nullptr;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ void sendNTPPacket()
|
||||
ntpUdp.endPacket();
|
||||
}
|
||||
|
||||
static bool isValidNtpResponse(byte * ntpPacket) {
|
||||
static bool isValidNtpResponse(const byte* ntpPacket) {
|
||||
// Perform a few validity checks on the packet
|
||||
// based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp
|
||||
if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC
|
||||
|
@ -141,7 +141,9 @@ bool PinManager::allocateMultiplePins(const managed_pin_type * mptArray, byte ar
|
||||
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
|
||||
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
|
||||
if (gpio < 255) { // 255 (-1) is the "not defined GPIO"
|
||||
if (!isPinOk(gpio, output)) {
|
||||
|
@ -35,15 +35,16 @@ enum struct PinOwner : uint8_t {
|
||||
Ethernet = 0x81,
|
||||
BusDigital = 0x82,
|
||||
BusOnOff = 0x83,
|
||||
BusPwm = 0x84, // 'BusP' == PWM output using BusPwm
|
||||
Button = 0x85, // 'Butn' == button from configuration
|
||||
IR = 0x86, // 'IR' == IR receiver pin from configuration
|
||||
Relay = 0x87, // 'Rly' == Relay pin from configuration
|
||||
SPI_RAM = 0x88, // 'SpiR' == SPI RAM
|
||||
DebugOut = 0x89, // 'Dbg' == debug output always IO1
|
||||
DMX = 0x8A, // 'DMX' == hard-coded to IO2
|
||||
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)
|
||||
BusPwm = 0x84, // 'BusP' == PWM output using BusPwm
|
||||
Button = 0x85, // 'Butn' == button from configuration
|
||||
IR = 0x86, // 'IR' == IR receiver pin from configuration
|
||||
Relay = 0x87, // 'Rly' == Relay pin from configuration
|
||||
SPI_RAM = 0x88, // 'SpiR' == SPI RAM
|
||||
DebugOut = 0x89, // 'Dbg' == debug output always IO1
|
||||
DMX = 0x8A, // 'DMX' == hard-coded to IO2
|
||||
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)
|
||||
DMX_INPUT = 0x8D, // 'DMX_INPUT' == DMX input via serial
|
||||
// Use UserMod IDs from const.h here
|
||||
UM_Unspecified = USERMOD_ID_UNSPECIFIED, // 0x01
|
||||
UM_Example = USERMOD_ID_EXAMPLE, // 0x02 // Usermod "usermod_v2_example.h"
|
||||
|
@ -61,7 +61,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
|
||||
if (playlistLen == 0) return -1;
|
||||
if (playlistLen > 100) playlistLen = 100;
|
||||
|
||||
playlistEntries = new PlaylistEntry[playlistLen];
|
||||
playlistEntries = new(std::nothrow) PlaylistEntry[playlistLen];
|
||||
if (playlistEntries == nullptr) return -1;
|
||||
|
||||
byte it = 0;
|
||||
|
@ -76,8 +76,8 @@ static void doSaveState() {
|
||||
// clean up
|
||||
saveLedmap = -1;
|
||||
presetToSave = 0;
|
||||
delete[] saveName;
|
||||
delete[] quickLoad;
|
||||
free(saveName);
|
||||
free(quickLoad);
|
||||
saveName = nullptr;
|
||||
quickLoad = nullptr;
|
||||
playlistSave = false;
|
||||
@ -216,8 +216,8 @@ void handlePresets()
|
||||
//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)
|
||||
{
|
||||
if (!saveName) saveName = new char[33];
|
||||
if (!quickLoad) quickLoad = new char[9];
|
||||
if (!saveName) saveName = static_cast<char*>(malloc(33));
|
||||
if (!quickLoad) quickLoad = static_cast<char*>(malloc(9));
|
||||
if (!saveName || !quickLoad) return;
|
||||
|
||||
if (index == 0 || (index > 250 && index < 255)) return;
|
||||
@ -263,8 +263,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||
presetsModifiedTime = toki.second(); //unix time
|
||||
updateFSInfo();
|
||||
}
|
||||
delete[] saveName;
|
||||
delete[] quickLoad;
|
||||
free(saveName);
|
||||
free(quickLoad);
|
||||
saveName = nullptr;
|
||||
quickLoad = nullptr;
|
||||
} else {
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "wled.h"
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
|
||||
#define ESPNOW_BUSWAIT_TIMEOUT 24 // one frame timeout to wait for bus to finish updating
|
||||
|
||||
#define NIGHT_MODE_DEACTIVATED -1
|
||||
#define NIGHT_MODE_BRIGHTNESS 5
|
||||
|
||||
@ -38,6 +40,7 @@ typedef struct WizMoteMessageStructure {
|
||||
|
||||
static uint32_t last_seq = UINT32_MAX;
|
||||
static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
|
||||
static int16_t ESPNowButton = -1; // set in callback if new button value is received
|
||||
|
||||
// Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3
|
||||
static const byte brightnessSteps[] = {
|
||||
@ -121,6 +124,9 @@ static bool remoteJson(int button)
|
||||
|
||||
sprintf_P(objKey, PSTR("\"%d\":"), button);
|
||||
|
||||
unsigned long start = millis();
|
||||
while (strip.isUpdating() && millis()-start < ESPNOW_BUSWAIT_TIMEOUT) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches
|
||||
|
||||
// attempt to read command from remote.json
|
||||
readObjectFromFile(PSTR("/remote.json"), objKey, pDoc);
|
||||
JsonObject fdo = pDoc->as<JsonObject>();
|
||||
@ -176,7 +182,7 @@ static bool remoteJson(int button)
|
||||
}
|
||||
|
||||
// Callback function that will be executed when data is received
|
||||
void handleRemote(uint8_t *incomingData, size_t len) {
|
||||
void handleWiZdata(uint8_t *incomingData, size_t len) {
|
||||
message_structure_t *incoming = reinterpret_cast<message_structure_t *>(incomingData);
|
||||
|
||||
if (strcmp(last_signal_src, linked_remote) != 0) {
|
||||
@ -202,8 +208,15 @@ void handleRemote(uint8_t *incomingData, size_t len) {
|
||||
DEBUG_PRINT(F("] button: "));
|
||||
DEBUG_PRINTLN(incoming->button);
|
||||
|
||||
if (!remoteJson(incoming->button))
|
||||
switch (incoming->button) {
|
||||
ESPNowButton = incoming->button; // save state, do not process in callback (can cause glitches)
|
||||
last_seq = cur_seq;
|
||||
}
|
||||
|
||||
// process ESPNow button data (acesses FS, should not be called while update to avoid glitches)
|
||||
void handleRemote() {
|
||||
if(ESPNowButton >= 0) {
|
||||
if (!remoteJson(ESPNowButton))
|
||||
switch (ESPNowButton) {
|
||||
case WIZMOTE_BUTTON_ON : setOn(); break;
|
||||
case WIZMOTE_BUTTON_OFF : setOff(); break;
|
||||
case WIZMOTE_BUTTON_ONE : presetWithFallback(1, FX_MODE_STATIC, 0); break;
|
||||
@ -219,9 +232,10 @@ void handleRemote(uint8_t *incomingData, size_t len) {
|
||||
case WIZ_SMART_BUTTON_BRIGHT_DOWN : brightnessDown(); break;
|
||||
default: break;
|
||||
}
|
||||
last_seq = cur_seq;
|
||||
}
|
||||
ESPNowButton = -1;
|
||||
}
|
||||
|
||||
#else
|
||||
void handleRemote(uint8_t *incomingData, size_t len) {}
|
||||
void handleRemote() {}
|
||||
#endif
|
||||
|
@ -209,7 +209,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, 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;
|
||||
}
|
||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||
@ -417,6 +417,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
t = request->arg(F("WO")).toInt();
|
||||
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
|
||||
alexaEnabled = request->hasArg(F("AL"));
|
||||
strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33);
|
||||
@ -979,18 +987,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
//set color from HEX or 32bit DEC
|
||||
pos = req.indexOf(F("CL="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
|
||||
colorFromDecOrHexString(colIn, req.substring(pos + 3).c_str());
|
||||
col0Changed = true;
|
||||
}
|
||||
pos = req.indexOf(F("C2="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str());
|
||||
colorFromDecOrHexString(colInSec, req.substring(pos + 3).c_str());
|
||||
col1Changed = true;
|
||||
}
|
||||
pos = req.indexOf(F("C3="));
|
||||
if (pos > 0) {
|
||||
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]);
|
||||
selseg.setColor(2, col2); // defined above (SS= or main)
|
||||
col2Changed = true;
|
||||
|
@ -206,7 +206,7 @@ void notify(byte callMode, bool followUp)
|
||||
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
|
||||
if (millis() - notificationSentTime < 1000) return;
|
||||
if (udpIn[1] > 199) return; //do not receive custom versions
|
||||
@ -808,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 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
|
||||
|
||||
WiFiUDP ddpUdp;
|
||||
@ -961,7 +961,7 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
|
||||
|
||||
// handle WiZ Mote data
|
||||
if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {
|
||||
handleRemote(data, len);
|
||||
handleWiZdata(data, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -242,11 +242,14 @@
|
||||
#include "../usermods/LD2410_v2/usermod_ld2410.h"
|
||||
#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()
|
||||
{
|
||||
/*
|
||||
@ -477,6 +480,10 @@ void registerUsermods()
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_DEEP_SLEEP
|
||||
usermods.add(new DeepSleepUsermod());
|
||||
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') {
|
||||
return !dflt;
|
||||
} 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
|
||||
bool requestJSONBufferLock(uint8_t module)
|
||||
bool requestJSONBufferLock(uint8_t moduleID)
|
||||
{
|
||||
if (pDoc == nullptr) {
|
||||
DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!"));
|
||||
@ -175,14 +175,14 @@ bool requestJSONBufferLock(uint8_t module)
|
||||
#endif
|
||||
// If the lock is still held - by us, or by another task
|
||||
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
|
||||
xSemaphoreGiveRecursive(jsonBufferLockMutex);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
jsonBufferLock = module ? module : 255;
|
||||
jsonBufferLock = moduleID ? moduleID : 255;
|
||||
DEBUG_PRINTF_P(PSTR("JSON buffer locked. (%d)\n"), jsonBufferLock);
|
||||
pDoc->clear();
|
||||
return true;
|
||||
@ -265,16 +265,16 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
||||
if (mode < strip.getModeCount()) {
|
||||
String lineBuffer = FPSTR(strip.getModeData(mode));
|
||||
if (lineBuffer.length() > 0) {
|
||||
unsigned start = lineBuffer.indexOf('@');
|
||||
unsigned stop = lineBuffer.indexOf(';', start);
|
||||
int start = lineBuffer.indexOf('@'); // String::indexOf() returns an int, not an unsigned; -1 means "not found"
|
||||
int stop = lineBuffer.indexOf(';', start);
|
||||
if (start>0 && stop>0) {
|
||||
String names = lineBuffer.substring(start, stop); // include @
|
||||
unsigned nameBegin = 1, nameEnd, nameDefault;
|
||||
int nameBegin = 1, nameEnd, nameDefault;
|
||||
if (slider < 10) {
|
||||
for (size_t i=0; i<=slider; i++) {
|
||||
const char *tmpstr;
|
||||
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);
|
||||
if (i == slider) {
|
||||
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++)
|
||||
fftResult[i] = beatsin8_t(120 / (i+1), 0, 255);
|
||||
// fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256;
|
||||
volumeSmth = fftResult[8];
|
||||
volumeSmth = fftResult[8];
|
||||
break;
|
||||
case UMS_WeWillRockYou:
|
||||
if (ms%2000 < 200) {
|
||||
@ -507,7 +507,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
case UMS_10_13:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||
volumeSmth = fftResult[8];
|
||||
volumeSmth = fftResult[8];
|
||||
break;
|
||||
case UMS_14_3:
|
||||
for (int i = 0; i<16; i++)
|
||||
@ -538,7 +538,7 @@ void enumerateLedmaps() {
|
||||
|
||||
#ifndef ESP8266
|
||||
if (ledmapNames[i-1]) { //clear old name
|
||||
delete[] ledmapNames[i-1];
|
||||
free(ledmapNames[i-1]);
|
||||
ledmapNames[i-1] = nullptr;
|
||||
}
|
||||
#endif
|
||||
@ -556,7 +556,7 @@ void enumerateLedmaps() {
|
||||
const char *name = root["n"].as<const char*>();
|
||||
if (name != nullptr) len = strlen(name);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -564,7 +564,7 @@ void enumerateLedmaps() {
|
||||
char tmp[33];
|
||||
snprintf_P(tmp, 32, s_ledmap_tmpl, i);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,10 @@ void WLED::loop()
|
||||
handleNotifications();
|
||||
handleTransitions();
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
handleDMX();
|
||||
handleDMXOutput();
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_DMX_INPUT
|
||||
dmxInput.update();
|
||||
#endif
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
@ -84,6 +87,9 @@ void WLED::loop()
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
handleIR();
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
handleRemote();
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
handleAlexa();
|
||||
#endif
|
||||
@ -524,7 +530,10 @@ void WLED::setup()
|
||||
}
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
initDMX();
|
||||
initDMXOutput();
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_DMX_INPUT
|
||||
dmxInput.init(dmxInputReceivePin, dmxInputTransmitPin, dmxInputEnablePin, dmxInputPort);
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_ADALIGHT
|
||||
@ -775,7 +784,6 @@ int8_t WLED::findWiFi(bool doScan) {
|
||||
void WLED::initConnection()
|
||||
{
|
||||
DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000);
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
ws.onEvent(wsEvent);
|
||||
#endif
|
||||
@ -804,6 +812,7 @@ void WLED::initConnection()
|
||||
if (!WLED_WIFI_CONFIGURED) {
|
||||
DEBUG_PRINTLN(F("No connection configured."));
|
||||
if (!apActive) initAP(); // instantly go to ap mode
|
||||
return;
|
||||
} else if (!apActive) {
|
||||
if (apBehavior == AP_BEHAVIOR_ALWAYS) {
|
||||
DEBUG_PRINTLN(F("Access point ALWAYS enabled."));
|
||||
|
@ -144,6 +144,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_DMX_INPUT
|
||||
#include "dmx_input.h"
|
||||
#endif
|
||||
|
||||
#include "src/dependencies/e131/ESPAsyncE131.h"
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
|
||||
@ -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 DMXStartLED _INIT(0); // LED from which DMX fixtures start
|
||||
#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 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
|
||||
|
@ -220,3 +220,27 @@ float fmod_t(float num, float denom) {
|
||||
#endif
|
||||
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
|
||||
if (verboseResponse && serialCanTX) {
|
||||
pDoc->clear();
|
||||
JsonObject state = pDoc->createNestedObject("state");
|
||||
serializeState(state);
|
||||
JsonObject stateDoc = pDoc->createNestedObject("state");
|
||||
serializeState(stateDoc);
|
||||
JsonObject info = pDoc->createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
|
||||
|
@ -21,7 +21,7 @@ static const char s_accessdenied[] PROGMEM = "Access Denied";
|
||||
static const char _common_js[] PROGMEM = "/common.js";
|
||||
|
||||
//Is this an IP?
|
||||
static bool isIp(String str) {
|
||||
static bool isIp(const String &str) {
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
int c = str.charAt(i);
|
||||
if (c != '.' && (c < '0' || c > '9')) {
|
||||
@ -152,9 +152,9 @@ static String msgProcessor(const String& var)
|
||||
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 (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;
|
||||
}
|
||||
if (!index) {
|
||||
@ -170,7 +170,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename,
|
||||
if (len) {
|
||||
request->_tempFile.write(data,len);
|
||||
}
|
||||
if (final) {
|
||||
if (isFinal) {
|
||||
request->_tempFile.close();
|
||||
if (filename.indexOf(F("cfg.json")) >= 0) { // check for filename with or without slash
|
||||
doReboot = true;
|
||||
@ -359,7 +359,7 @@ void initServer()
|
||||
|
||||
server.on(F("/upload"), HTTP_POST, [](AsyncWebServerRequest *request) {},
|
||||
[](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);
|
||||
@ -389,7 +389,7 @@ void initServer()
|
||||
serveMessage(request, 200, F("Update successful!"), F("Rebooting..."), 131);
|
||||
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(!index){
|
||||
DEBUG_PRINTLN(F("OTA Update Start"));
|
||||
@ -406,7 +406,7 @@ void initServer()
|
||||
Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
||||
}
|
||||
if(!Update.hasError()) Update.write(data, len);
|
||||
if(final){
|
||||
if(isFinal){
|
||||
if(Update.end(true)){
|
||||
DEBUG_PRINTLN(F("Update Success"));
|
||||
} 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>()) {
|
||||
JsonArray pins = obj[key].as<JsonArray>();
|
||||
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)
|
||||
static void fillUMPins(Print& settingsScript, JsonObject &mods)
|
||||
static void fillUMPins(Print& settingsScript, const JsonObject &mods)
|
||||
{
|
||||
for (JsonPair kv : mods) {
|
||||
// kv.key() is usermod name or subobject key
|
||||
@ -433,6 +433,18 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
||||
printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence);
|
||||
printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast);
|
||||
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("XX"),DMXSegmentSpacing);
|
||||
printSetFormValue(settingsScript,PSTR("PY"),e131Priority);
|
||||
|
Loading…
x
Reference in New Issue
Block a user