Merge branch '0_15' into compile_different_busses

This commit is contained in:
Blaz Kristan 2024-09-14 09:27:37 +02:00
commit 6a188033c6
36 changed files with 929 additions and 838 deletions

View File

@ -1,8 +1,37 @@
## WLED changelog
#### Build 2409100
- WLED 0.15.0-b5 release
- Audioreactive usermod included by default in all compatible builds (including ESP8266)
- Demystified some byte definitions of WiZmote ESP-NOW message (#4114 by @ChuckMash)
- Update usermod "Battery" improved MQTT support (#4110 by @itCarl)
- Added a usermod for interacting with BLE Pixels Dice (#4093 by @axlan)
- Allow lower values for touch threshold (#4081 by @RobinMeis)
- Added POV image effect usermod (#3539 by @Liliputech)
- Remove repeating code to fetch audio data (#4103 by @netmindz)
- Loxone JSON parser doesn't handle lx=0 correctly (#4104 by @FreakyJ, fixes #3809)
- Rename wled00.ino to wled_main.cpp (#4090 by @willmmiles)
- SM16825 chip support including WW & CW channel swap (#4092)
- Add stress testing scripts (#4088 by @willmmiles)
- Improve jsonBufferLock management (#4089 by @willmmiles)
- Fix incorrect PWM bit depth on Esp32 with XTAL clock (#4082 by @PaoloTK)
- Devcontainer args (#4073 by @axlan)
- Effect: Fire2012 optional blur amount (#4078 by @apanteleev)
- Effect: GEQ fix bands (#4077 by @adrianschroeter)
- Boot delay option (#4060 by @DedeHai)
- ESP8266 Audioreactive sync (#3962 by @gaaat98, @netmindz, @softhack007)
- ESP8266 PWM crash fix (#4035 by @willmmiles)
- Usermod: Battery fix (#4051 by @Nickbert7)
- Usermod: Mpu6050 usermod crash fix (#4048 by @willmmiles)
- Usermod: Internal Temperature V2 (#4033 by @adamsthws)
- Various fixes and improvements (including build environments to emulate 0.14.0 for ESP8266)
#### Build 2407070
- Various fixes and improvements (mainly LED settings fix)
#### Build 2406290
- WLED 0.15.0-b4 release
- LED settings bus management update (WARNING only allow available outputs)
- LED settings bus management update (WARNING: only allows available outputs)
- Add ETH support for LILYGO-POE-Pro (#4030 by @rorosaurus)
- Update usermod_sn_photoresistor (#4017 by @xkvmoto)
- Several internal fixes and optimisations

View File

@ -16,6 +16,20 @@ A good description helps us to review and understand your proposed changes. For
Please make all PRs against the `0_15` branch.
### Updating your code
While the PR is open - and under review by maintainers - you may be asked to modify your PR source code.
You can simply update your own branch, and push changes in response to reviewer recommendations.
Github will pick up the changes so your PR stays up-to-date.
> [!CAUTION]
> Do not use "force-push" while your PR is open!
> It has many subtle and unexpected consequences on our github reposistory.
> For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push.
You can find a collection of very useful tips and tricks here: https://github.com/Aircoookie/WLED/wiki/How-to-properly-submit-a-PR
### Code style
When in doubt, it is easiest to replicate the code style you find in the files you want to edit :)
@ -37,6 +51,11 @@ if (a == b) {
}
```
```cpp
if (a == b) doStuff(a);
```
Acceptable - however the first variant is usually easier to read:
```cpp
if (a == b)
{
@ -44,9 +63,6 @@ if (a == b)
}
```
```cpp
if (a == b) doStuff(a);
```
There should always be a space between a keyword and its condition and between the condition and brace.
Within the condition, no space should be between the parenthesis and variables.

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "wled",
"version": "0.15.0-b4",
"version": "0.15.0-b5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wled",
"version": "0.15.0-b4",
"version": "0.15.0-b5",
"license": "ISC",
"dependencies": {
"clean-css": "^5.3.3",

View File

@ -1,6 +1,6 @@
{
"name": "wled",
"version": "0.15.0-b4",
"version": "0.15.0-b5",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {

View File

@ -10,7 +10,7 @@
# ------------------------------------------------------------------------------
# CI/release binaries
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, 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, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
src_dir = ./wled00
data_dir = ./wled00/data
@ -205,6 +205,38 @@ lib_deps =
ESP8266PWM
${env.lib_deps}
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
build_flags_compat =
-DESP8266
-DFP_IN_IROM
;;-Wno-deprecated-declarations
-Wno-misleading-indentation
;;-Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
-DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
-DVTABLES_IN_FLASH
-DMIMETYPE_MINIMAL
-DWLED_SAVE_IRAM ;; needed to prevent linker error
;; this platform version was used for WLED 0.14.0
platform_compat = espressif8266@4.2.0
platform_packages_compat =
platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
platformio/tool-esptool #@ ~1.413.0
platformio/tool-esptoolpy #@ ~1.30000.0
;; experimental - for using older NeoPixelBus 2.7.9
lib_deps_compat =
ESPAsyncTCP @ 1.2.2
ESPAsyncUDP
ESP8266PWM
fastled/FastLED @ 3.6.0
IRremoteESP8266 @ 2.8.2
makuna/NeoPixelBus @ 2.7.9
https://github.com/blazoncek/QuickESPNow.git#optional-debug
https://github.com/Aircoookie/ESPAsyncWebServer.git @ 2.2.1
[esp32]
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
platform = espressif32@3.5.0
@ -315,10 +347,19 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=
lib_deps = ${esp8266.lib_deps}
monitor_filters = esp8266_exception_decoder
[env:nodemcuv2_compat]
extends = env:nodemcuv2
;; using platform version and build options from WLED 0.14.0
platform = ${esp8266.platform_compat}
platform_packages = ${esp8266.platform_packages_compat}
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP8266_compat #-DWLED_DISABLE_2D
;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9
[env:nodemcuv2_160]
extends = env:nodemcuv2
board_build.f_cpu = 160000000L
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266_160 #-DWLED_DISABLE_2D
-D USERMOD_AUDIOREACTIVE
[env:esp8266_2m]
board = esp_wroom_02
@ -329,10 +370,18 @@ build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02
lib_deps = ${esp8266.lib_deps}
[env:esp8266_2m_compat]
extends = env:esp8266_2m
;; using platform version and build options from WLED 0.14.0
platform = ${esp8266.platform_compat}
platform_packages = ${esp8266.platform_packages_compat}
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP02_compat #-DWLED_DISABLE_2D
[env:esp8266_2m_160]
extends = env:esp8266_2m
board_build.f_cpu = 160000000L
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02_160
-D USERMOD_AUDIOREACTIVE
[env:esp01_1m_full]
board = esp01_1m
@ -344,10 +393,18 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
lib_deps = ${esp8266.lib_deps}
[env:esp01_1m_full_compat]
extends = env:esp01_1m_full
;; using platform version and build options from WLED 0.14.0
platform = ${esp8266.platform_compat}
platform_packages = ${esp8266.platform_packages_compat}
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP01_compat -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
[env:esp01_1m_full_160]
extends = env:esp01_1m_full
board_build.f_cpu = 160000000L
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA
-D USERMOD_AUDIOREACTIVE
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
[env:esp32dev]
@ -356,7 +413,9 @@ platform = ${esp32.platform}
platform_packages = ${esp32.platform_packages}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BROWNOUT_DET
${esp32.AR_build_flags}
lib_deps = ${esp32.lib_deps}
${esp32.AR_lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.default_partitions}
@ -373,19 +432,19 @@ monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.large_partitions}
; board_build.f_flash = 80000000L
[env:esp32dev_audioreactive]
board = esp32dev
platform = ${esp32.platform}
platform_packages = ${esp32.platform_packages}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET
${esp32.AR_build_flags}
lib_deps = ${esp32.lib_deps}
${esp32.AR_lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.default_partitions}
; board_build.f_flash = 80000000L
; board_build.flash_mode = dio
;[env:esp32dev_audioreactive]
;board = esp32dev
;platform = ${esp32.platform}
;platform_packages = ${esp32.platform_packages}
;build_unflags = ${common.build_unflags}
;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET
; ${esp32.AR_build_flags}
;lib_deps = ${esp32.lib_deps}
; ${esp32.AR_lib_deps}
;monitor_filters = esp32_exception_decoder
;board_build.partitions = ${esp32.default_partitions}
;; board_build.f_flash = 80000000L
;; board_build.flash_mode = dio
[env:esp32_eth]
board = esp32-poe
@ -394,8 +453,10 @@ platform_packages = ${esp32.platform_packages}
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
-D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
${esp32.AR_build_flags}
lib_deps = ${esp32.lib_deps}
${esp32.AR_lib_deps}
board_build.partitions = ${esp32.default_partitions}
[env:esp32_wrover]
@ -405,14 +466,14 @@ platform_packages = ${esp32_idf_V4.platform_packages}
board = ttgo-t7-v14-mini32
board_build.f_flash = 80000000L
board_build.flash_mode = qio
board_build.partitions = ${esp32.default_partitions}
board_build.partitions = ${esp32.extended_partitions}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_WROVER
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
-D LEDPIN=25
; ${esp32.AR_build_flags}
${esp32.AR_build_flags}
lib_deps = ${esp32_idf_V4.lib_deps}
; ${esp32.AR_lib_deps}
${esp32.AR_lib_deps}
[env:esp32c3dev]
extends = esp32c3

View File

@ -23,6 +23,9 @@
#ifndef TFT_RST
#error Please define TFT_RST
#endif
#ifndef TFT_CS
#error Please define TFT_CS
#endif
#ifndef LOAD_GLCD
#error Please define LOAD_GLCD
#endif
@ -377,7 +380,7 @@ class St7789DisplayUsermod : public Usermod {
oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI BL');"));
oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');"));
}
/*

View File

@ -7,6 +7,4 @@
extends = env:d1_mini
build_flags = ${common.build_flags_esp8266} -D USERMOD_DALLASTEMPERATURE
lib_deps = ${env.lib_deps}
paulstoffregen/OneWire@~2.3.7
# you may want to use following with ESP32
; https://github.com/blazoncek/OneWire.git # fixes Sensor error on ESP32
paulstoffregen/OneWire@~2.3.8

View File

@ -43,10 +43,8 @@ default_envs = d1_mini
...
lib_deps =
...
#For Dallas sensor uncomment following line
OneWire@~2.3.7
# ... or you may want to use following with ESP32
; https://github.com/blazoncek/OneWire.git # fixes Sensor error on ESP32...
#For Dallas sensor uncomment following
paulstoffregen/OneWire @ ~2.3.8
```
## Change Log
@ -56,8 +54,14 @@ lib_deps =
* Do not report erroneous low temperatures to MQTT
* Disable plugin if temperature sensor not detected
* Report the number of seconds until the first read in the info screen instead of sensor error
2021-04
* Adaptation for runtime configuration.
2023-05
* Rewrite to conform to newer recommendations.
* Recommended @blazoncek fork of OneWire for ESP32 to avoid Sensor error
* Recommended @blazoncek fork of OneWire for ESP32 to avoid Sensor error
2024-09
* Update OneWire to version 2.3.8, which includes stickbreaker's and garyd9's ESP32 fixes:
blazoncek's fork is no longer needed

View File

@ -1,459 +1,459 @@
#pragma once
#include "wled.h"
/*
* Usermod that implements BobLight "ambilight" protocol
*
* See the accompanying README.md file for more info.
*/
#ifndef BOB_PORT
#define BOB_PORT 19333 // Default boblightd port
#endif
class BobLightUsermod : public Usermod {
typedef struct _LIGHT {
char lightname[5];
float hscan[2];
float vscan[2];
} light_t;
private:
unsigned long lastTime = 0;
bool enabled = false;
bool initDone = false;
light_t *lights = nullptr;
uint16_t numLights = 0; // 16 + 9 + 16 + 9
uint16_t top, bottom, left, right; // will be filled in readFromConfig()
uint16_t pct;
WiFiClient bobClient;
WiFiServer *bob;
uint16_t bobPort = BOB_PORT;
static const char _name[];
static const char _enabled[];
/*
# boblight
# Copyright (C) Bob 2009
#
# makeboblight.sh created by Adam Boeglin <adamrb@gmail.com>
#
# boblight is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# boblight is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// fills the lights[] array with position & depth of scan for each LED
void fillBobLights(int bottom, int left, int top, int right, float pct_scan) {
int lightcount = 0;
int total = top+left+right+bottom;
int bcount;
if (total > strip.getLengthTotal()) {
DEBUG_PRINTLN(F("BobLight: Too many lights."));
return;
}
// start left part of bottom strip (clockwise direction, 1st half)
if (bottom > 0) {
bcount = 1;
float brange = 100.0/bottom;
float bcurrent = 50.0;
if (bottom < top) {
int diff = top - bottom;
brange = 100.0/top;
bcurrent -= (diff/2)*brange;
}
while (bcount <= bottom/2) {
float btop = bcurrent - brange;
String name = "b"+String(bcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = btop;
lights[lightcount].hscan[1] = bcurrent;
lights[lightcount].vscan[0] = 100 - pct_scan;
lights[lightcount].vscan[1] = 100;
lightcount+=1;
bcurrent = btop;
bcount+=1;
}
}
// left side
if (left > 0) {
int lcount = 1;
float lrange = 100.0/left;
float lcurrent = 100.0;
while (lcount <= left) {
float ltop = lcurrent - lrange;
String name = "l"+String(lcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = 0;
lights[lightcount].hscan[1] = pct_scan;
lights[lightcount].vscan[0] = ltop;
lights[lightcount].vscan[1] = lcurrent;
lightcount+=1;
lcurrent = ltop;
lcount+=1;
}
}
// top side
if (top > 0) {
int tcount = 1;
float trange = 100.0/top;
float tcurrent = 0;
while (tcount <= top) {
float ttop = tcurrent + trange;
String name = "t"+String(tcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = tcurrent;
lights[lightcount].hscan[1] = ttop;
lights[lightcount].vscan[0] = 0;
lights[lightcount].vscan[1] = pct_scan;
lightcount+=1;
tcurrent = ttop;
tcount+=1;
}
}
// right side
if (right > 0) {
int rcount = 1;
float rrange = 100.0/right;
float rcurrent = 0;
while (rcount <= right) {
float rtop = rcurrent + rrange;
String name = "r"+String(rcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = 100-pct_scan;
lights[lightcount].hscan[1] = 100;
lights[lightcount].vscan[0] = rcurrent;
lights[lightcount].vscan[1] = rtop;
lightcount+=1;
rcurrent = rtop;
rcount+=1;
}
}
// right side of bottom strip (2nd half)
if (bottom > 0) {
float brange = 100.0/bottom;
float bcurrent = 100;
if (bottom < top) {
brange = 100.0/top;
}
while (bcount <= bottom) {
float btop = bcurrent - brange;
String name = "b"+String(bcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = btop;
lights[lightcount].hscan[1] = bcurrent;
lights[lightcount].vscan[0] = 100 - pct_scan;
lights[lightcount].vscan[1] = 100;
lightcount+=1;
bcurrent = btop;
bcount+=1;
}
}
numLights = lightcount;
#if WLED_DEBUG
DEBUG_PRINTLN(F("Fill light data: "));
DEBUG_PRINTF_P(PSTR(" lights %d\n"), numLights);
for (int i=0; i<numLights; i++) {
DEBUG_PRINTF_P(PSTR(" light %s scan %2.1f %2.1f %2.1f %2.1f\n"), lights[i].lightname, lights[i].vscan[0], lights[i].vscan[1], lights[i].hscan[0], lights[i].hscan[1]);
}
#endif
}
void BobSync() { yield(); } // allow other tasks, should also be used to force pixel redraw (not with WLED)
void BobClear() { for (size_t i=0; i<numLights; i++) setRealtimePixel(i, 0, 0, 0, 0); }
void pollBob();
public:
void setup() override {
uint16_t totalLights = bottom + left + top + right;
if ( totalLights > strip.getLengthTotal() ) {
DEBUG_PRINTLN(F("BobLight: Too many lights."));
DEBUG_PRINTF_P(PSTR("%d+%d+%d+%d>%d\n"), bottom, left, top, right, strip.getLengthTotal());
totalLights = strip.getLengthTotal();
top = bottom = (uint16_t) roundf((float)totalLights * 16.0f / 50.0f);
left = right = (uint16_t) roundf((float)totalLights * 9.0f / 50.0f);
}
lights = new light_t[totalLights];
if (lights) fillBobLights(bottom, left, top, right, float(pct)); // will fill numLights
else enable(false);
initDone = true;
}
void connected() override {
// we can only start server when WiFi is connected
if (!bob) bob = new WiFiServer(bobPort, 1);
bob->begin();
bob->setNoDelay(true);
}
void loop() override {
if (!enabled || strip.isUpdating()) return;
if (millis() - lastTime > 10) {
lastTime = millis();
pollBob();
}
}
void enable(bool en) { enabled = en; }
#ifndef WLED_DISABLE_MQTT
/**
* handling of MQTT message
* topic only contains stripped topic (part after /wled/MAC)
* topic should look like: /swipe with amessage of [up|down]
*/
bool onMqttMessage(char* topic, char* payload) override {
//if (strlen(topic) == 6 && strncmp_P(topic, PSTR("/subtopic"), 6) == 0) {
// String action = payload;
// if (action == "on") {
// enable(true);
// return true;
// } else if (action == "off") {
// enable(false);
// return true;
// }
//}
return false;
}
/**
* subscribe to MQTT topic for controlling usermod
*/
void onMqttConnect(bool sessionPresent) override {
//char subuf[64];
//if (mqttDeviceTopic[0] != 0) {
// strcpy(subuf, mqttDeviceTopic);
// strcat_P(subuf, PSTR("/subtopic"));
// mqtt->subscribe(subuf, 0);
//}
}
#endif
void addToJsonInfo(JsonObject& root) override
{
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
String uiDomString = F("<button class=\"btn btn-xs\" onclick=\"requestJson({");
uiDomString += FPSTR(_name);
uiDomString += F(":{");
uiDomString += FPSTR(_enabled);
uiDomString += enabled ? F(":false}});\">") : F(":true}});\">");
uiDomString += F("<i class=\"icons ");
uiDomString += enabled ? "on" : "off";
uiDomString += F("\">&#xe08f;</i></button>");
infoArr.add(uiDomString);
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root) override
{
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root) override {
if (!initDone) return; // prevent crash on boot applyPreset()
bool en = enabled;
JsonObject um = root[FPSTR(_name)];
if (!um.isNull()) {
if (um[FPSTR(_enabled)].is<bool>()) {
en = um[FPSTR(_enabled)].as<bool>();
} else {
String str = um[FPSTR(_enabled)]; // checkbox -> off or on
en = (bool)(str!="off"); // off is guaranteed to be present
}
if (en != enabled && lights) {
enable(en);
if (!enabled && bob && bob->hasClient()) {
if (bobClient) bobClient.stop();
bobClient = bob->available();
BobClear();
exitRealtime();
}
}
}
}
void appendConfigData() override {
//oappend(SET_F("dd=addDropdown('usermod','selectfield');"));
//oappend(SET_F("addOption(dd,'1st value',0);"));
//oappend(SET_F("addOption(dd,'2nd value',1);"));
oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field
}
void addToConfig(JsonObject& root) override {
JsonObject umData = root.createNestedObject(FPSTR(_name));
umData[FPSTR(_enabled)] = enabled;
umData[ "port" ] = bobPort;
umData[F("top")] = top;
umData[F("bottom")] = bottom;
umData[F("left")] = left;
umData[F("right")] = right;
umData[F("pct")] = pct;
}
bool readFromConfig(JsonObject& root) override {
JsonObject umData = root[FPSTR(_name)];
bool configComplete = !umData.isNull();
bool en = enabled;
configComplete &= getJsonValue(umData[FPSTR(_enabled)], en);
enable(en);
configComplete &= getJsonValue(umData[ "port" ], bobPort);
configComplete &= getJsonValue(umData[F("bottom")], bottom, 16);
configComplete &= getJsonValue(umData[F("top")], top, 16);
configComplete &= getJsonValue(umData[F("left")], left, 9);
configComplete &= getJsonValue(umData[F("right")], right, 9);
configComplete &= getJsonValue(umData[F("pct")], pct, 5); // Depth of scan [%]
pct = MIN(50,MAX(1,pct));
uint16_t totalLights = bottom + left + top + right;
if (initDone && numLights != totalLights) {
if (lights) delete[] lights;
setup();
}
return configComplete;
}
/*
* handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors.
* Use this to blank out some LEDs or set them to a different color regardless of the set effect mode.
* Commonly used for custom clocks (Cronixie, 7 segment)
*/
void handleOverlayDraw() override {
//strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black
}
uint16_t getId() override { return USERMOD_ID_BOBLIGHT; }
};
// strings to reduce flash memory usage (used more than twice)
const char BobLightUsermod::_name[] PROGMEM = "BobLight";
const char BobLightUsermod::_enabled[] PROGMEM = "enabled";
// main boblight handling (definition here prevents inlining)
void BobLightUsermod::pollBob() {
//check if there are any new clients
if (bob && bob->hasClient()) {
//find free/disconnected spot
if (!bobClient || !bobClient.connected()) {
if (bobClient) bobClient.stop();
bobClient = bob->available();
DEBUG_PRINTLN(F("Boblight: Client connected."));
}
//no free/disconnected spot so reject
WiFiClient bobClientTmp = bob->available();
bobClientTmp.stop();
BobClear();
exitRealtime();
}
//check clients for data
if (bobClient && bobClient.connected()) {
realtimeLock(realtimeTimeoutMs); // lock strip as we have a client connected
//get data from the client
while (bobClient.available()) {
String input = bobClient.readStringUntil('\n');
// DEBUG_PRINT(F("Client: ")); DEBUG_PRINTLN(input); // may be to stressful on Serial
if (input.startsWith(F("hello"))) {
DEBUG_PRINTLN(F("hello"));
bobClient.print(F("hello\n"));
} else if (input.startsWith(F("ping"))) {
DEBUG_PRINTLN(F("ping 1"));
bobClient.print(F("ping 1\n"));
} else if (input.startsWith(F("get version"))) {
DEBUG_PRINTLN(F("version 5"));
bobClient.print(F("version 5\n"));
} else if (input.startsWith(F("get lights"))) {
char tmp[64];
String answer = "";
sprintf_P(tmp, PSTR("lights %d\n"), numLights);
DEBUG_PRINT(tmp);
answer.concat(tmp);
for (int i=0; i<numLights; i++) {
sprintf_P(tmp, PSTR("light %s scan %2.1f %2.1f %2.1f %2.1f\n"), lights[i].lightname, lights[i].vscan[0], lights[i].vscan[1], lights[i].hscan[0], lights[i].hscan[1]);
DEBUG_PRINT(tmp);
answer.concat(tmp);
}
bobClient.print(answer);
} else if (input.startsWith(F("set priority"))) {
DEBUG_PRINTLN(F("set priority not implemented"));
// not implemented
} else if (input.startsWith(F("set light "))) { // <id> <cmd in rgb, speed, interpolation> <value> ...
input.remove(0,10);
String tmp = input.substring(0,input.indexOf(' '));
int light_id = -1;
for (uint16_t i=0; i<numLights; i++) {
if (strncmp(lights[i].lightname, tmp.c_str(), 4) == 0) {
light_id = i;
break;
}
}
if (light_id == -1) return;
input.remove(0,input.indexOf(' ')+1);
if (input.startsWith(F("rgb "))) {
input.remove(0,4);
tmp = input.substring(0,input.indexOf(' '));
uint8_t red = (uint8_t)(255.0f*tmp.toFloat());
input.remove(0,input.indexOf(' ')+1); // remove first float value
tmp = input.substring(0,input.indexOf(' '));
uint8_t green = (uint8_t)(255.0f*tmp.toFloat());
input.remove(0,input.indexOf(' ')+1); // remove second float value
tmp = input.substring(0,input.indexOf(' '));
uint8_t blue = (uint8_t)(255.0f*tmp.toFloat());
//strip.setPixelColor(light_id, RGBW32(red, green, blue, 0));
setRealtimePixel(light_id, red, green, blue, 0);
} // currently no support for interpolation or speed, we just ignore this
} else if (input.startsWith("sync")) {
BobSync();
} else {
// Client sent gibberish
DEBUG_PRINTLN(F("Client sent gibberish."));
bobClient.stop();
bobClient = bob->available();
BobClear();
}
}
}
}
#pragma once
#include "wled.h"
/*
* Usermod that implements BobLight "ambilight" protocol
*
* See the accompanying README.md file for more info.
*/
#ifndef BOB_PORT
#define BOB_PORT 19333 // Default boblightd port
#endif
class BobLightUsermod : public Usermod {
typedef struct _LIGHT {
char lightname[5];
float hscan[2];
float vscan[2];
} light_t;
private:
unsigned long lastTime = 0;
bool enabled = false;
bool initDone = false;
light_t *lights = nullptr;
uint16_t numLights = 0; // 16 + 9 + 16 + 9
uint16_t top, bottom, left, right; // will be filled in readFromConfig()
uint16_t pct;
WiFiClient bobClient;
WiFiServer *bob;
uint16_t bobPort = BOB_PORT;
static const char _name[];
static const char _enabled[];
/*
# boblight
# Copyright (C) Bob 2009
#
# makeboblight.sh created by Adam Boeglin <adamrb@gmail.com>
#
# boblight is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# boblight is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// fills the lights[] array with position & depth of scan for each LED
void fillBobLights(int bottom, int left, int top, int right, float pct_scan) {
int lightcount = 0;
int total = top+left+right+bottom;
int bcount;
if (total > strip.getLengthTotal()) {
DEBUG_PRINTLN(F("BobLight: Too many lights."));
return;
}
// start left part of bottom strip (clockwise direction, 1st half)
if (bottom > 0) {
bcount = 1;
float brange = 100.0/bottom;
float bcurrent = 50.0;
if (bottom < top) {
int diff = top - bottom;
brange = 100.0/top;
bcurrent -= (diff/2)*brange;
}
while (bcount <= bottom/2) {
float btop = bcurrent - brange;
String name = "b"+String(bcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = btop;
lights[lightcount].hscan[1] = bcurrent;
lights[lightcount].vscan[0] = 100 - pct_scan;
lights[lightcount].vscan[1] = 100;
lightcount+=1;
bcurrent = btop;
bcount+=1;
}
}
// left side
if (left > 0) {
int lcount = 1;
float lrange = 100.0/left;
float lcurrent = 100.0;
while (lcount <= left) {
float ltop = lcurrent - lrange;
String name = "l"+String(lcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = 0;
lights[lightcount].hscan[1] = pct_scan;
lights[lightcount].vscan[0] = ltop;
lights[lightcount].vscan[1] = lcurrent;
lightcount+=1;
lcurrent = ltop;
lcount+=1;
}
}
// top side
if (top > 0) {
int tcount = 1;
float trange = 100.0/top;
float tcurrent = 0;
while (tcount <= top) {
float ttop = tcurrent + trange;
String name = "t"+String(tcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = tcurrent;
lights[lightcount].hscan[1] = ttop;
lights[lightcount].vscan[0] = 0;
lights[lightcount].vscan[1] = pct_scan;
lightcount+=1;
tcurrent = ttop;
tcount+=1;
}
}
// right side
if (right > 0) {
int rcount = 1;
float rrange = 100.0/right;
float rcurrent = 0;
while (rcount <= right) {
float rtop = rcurrent + rrange;
String name = "r"+String(rcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = 100-pct_scan;
lights[lightcount].hscan[1] = 100;
lights[lightcount].vscan[0] = rcurrent;
lights[lightcount].vscan[1] = rtop;
lightcount+=1;
rcurrent = rtop;
rcount+=1;
}
}
// right side of bottom strip (2nd half)
if (bottom > 0) {
float brange = 100.0/bottom;
float bcurrent = 100;
if (bottom < top) {
brange = 100.0/top;
}
while (bcount <= bottom) {
float btop = bcurrent - brange;
String name = "b"+String(bcount);
strncpy(lights[lightcount].lightname, name.c_str(), 4);
lights[lightcount].hscan[0] = btop;
lights[lightcount].hscan[1] = bcurrent;
lights[lightcount].vscan[0] = 100 - pct_scan;
lights[lightcount].vscan[1] = 100;
lightcount+=1;
bcurrent = btop;
bcount+=1;
}
}
numLights = lightcount;
#if WLED_DEBUG
DEBUG_PRINTLN(F("Fill light data: "));
DEBUG_PRINTF_P(PSTR(" lights %d\n"), numLights);
for (int i=0; i<numLights; i++) {
DEBUG_PRINTF_P(PSTR(" light %s scan %2.1f %2.1f %2.1f %2.1f\n"), lights[i].lightname, lights[i].vscan[0], lights[i].vscan[1], lights[i].hscan[0], lights[i].hscan[1]);
}
#endif
}
void BobSync() { yield(); } // allow other tasks, should also be used to force pixel redraw (not with WLED)
void BobClear() { for (size_t i=0; i<numLights; i++) setRealtimePixel(i, 0, 0, 0, 0); }
void pollBob();
public:
void setup() override {
uint16_t totalLights = bottom + left + top + right;
if ( totalLights > strip.getLengthTotal() ) {
DEBUG_PRINTLN(F("BobLight: Too many lights."));
DEBUG_PRINTF_P(PSTR("%d+%d+%d+%d>%d\n"), bottom, left, top, right, strip.getLengthTotal());
totalLights = strip.getLengthTotal();
top = bottom = (uint16_t) roundf((float)totalLights * 16.0f / 50.0f);
left = right = (uint16_t) roundf((float)totalLights * 9.0f / 50.0f);
}
lights = new light_t[totalLights];
if (lights) fillBobLights(bottom, left, top, right, float(pct)); // will fill numLights
else enable(false);
initDone = true;
}
void connected() override {
// we can only start server when WiFi is connected
if (!bob) bob = new WiFiServer(bobPort, 1);
bob->begin();
bob->setNoDelay(true);
}
void loop() override {
if (!enabled || strip.isUpdating()) return;
if (millis() - lastTime > 10) {
lastTime = millis();
pollBob();
}
}
void enable(bool en) { enabled = en; }
#ifndef WLED_DISABLE_MQTT
/**
* handling of MQTT message
* topic only contains stripped topic (part after /wled/MAC)
* topic should look like: /swipe with amessage of [up|down]
*/
bool onMqttMessage(char* topic, char* payload) override {
//if (strlen(topic) == 6 && strncmp_P(topic, PSTR("/subtopic"), 6) == 0) {
// String action = payload;
// if (action == "on") {
// enable(true);
// return true;
// } else if (action == "off") {
// enable(false);
// return true;
// }
//}
return false;
}
/**
* subscribe to MQTT topic for controlling usermod
*/
void onMqttConnect(bool sessionPresent) override {
//char subuf[64];
//if (mqttDeviceTopic[0] != 0) {
// strcpy(subuf, mqttDeviceTopic);
// strcat_P(subuf, PSTR("/subtopic"));
// mqtt->subscribe(subuf, 0);
//}
}
#endif
void addToJsonInfo(JsonObject& root) override
{
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
String uiDomString = F("<button class=\"btn btn-xs\" onclick=\"requestJson({");
uiDomString += FPSTR(_name);
uiDomString += F(":{");
uiDomString += FPSTR(_enabled);
uiDomString += enabled ? F(":false}});\">") : F(":true}});\">");
uiDomString += F("<i class=\"icons ");
uiDomString += enabled ? "on" : "off";
uiDomString += F("\">&#xe08f;</i></button>");
infoArr.add(uiDomString);
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root) override
{
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root) override {
if (!initDone) return; // prevent crash on boot applyPreset()
bool en = enabled;
JsonObject um = root[FPSTR(_name)];
if (!um.isNull()) {
if (um[FPSTR(_enabled)].is<bool>()) {
en = um[FPSTR(_enabled)].as<bool>();
} else {
String str = um[FPSTR(_enabled)]; // checkbox -> off or on
en = (bool)(str!="off"); // off is guaranteed to be present
}
if (en != enabled && lights) {
enable(en);
if (!enabled && bob && bob->hasClient()) {
if (bobClient) bobClient.stop();
bobClient = bob->available();
BobClear();
exitRealtime();
}
}
}
}
void appendConfigData() override {
//oappend(SET_F("dd=addDropdown('usermod','selectfield');"));
//oappend(SET_F("addOption(dd,'1st value',0);"));
//oappend(SET_F("addOption(dd,'2nd value',1);"));
oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field
}
void addToConfig(JsonObject& root) override {
JsonObject umData = root.createNestedObject(FPSTR(_name));
umData[FPSTR(_enabled)] = enabled;
umData[ "port" ] = bobPort;
umData[F("top")] = top;
umData[F("bottom")] = bottom;
umData[F("left")] = left;
umData[F("right")] = right;
umData[F("pct")] = pct;
}
bool readFromConfig(JsonObject& root) override {
JsonObject umData = root[FPSTR(_name)];
bool configComplete = !umData.isNull();
bool en = enabled;
configComplete &= getJsonValue(umData[FPSTR(_enabled)], en);
enable(en);
configComplete &= getJsonValue(umData[ "port" ], bobPort);
configComplete &= getJsonValue(umData[F("bottom")], bottom, 16);
configComplete &= getJsonValue(umData[F("top")], top, 16);
configComplete &= getJsonValue(umData[F("left")], left, 9);
configComplete &= getJsonValue(umData[F("right")], right, 9);
configComplete &= getJsonValue(umData[F("pct")], pct, 5); // Depth of scan [%]
pct = MIN(50,MAX(1,pct));
uint16_t totalLights = bottom + left + top + right;
if (initDone && numLights != totalLights) {
if (lights) delete[] lights;
setup();
}
return configComplete;
}
/*
* handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors.
* Use this to blank out some LEDs or set them to a different color regardless of the set effect mode.
* Commonly used for custom clocks (Cronixie, 7 segment)
*/
void handleOverlayDraw() override {
//strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black
}
uint16_t getId() override { return USERMOD_ID_BOBLIGHT; }
};
// strings to reduce flash memory usage (used more than twice)
const char BobLightUsermod::_name[] PROGMEM = "BobLight";
const char BobLightUsermod::_enabled[] PROGMEM = "enabled";
// main boblight handling (definition here prevents inlining)
void BobLightUsermod::pollBob() {
//check if there are any new clients
if (bob && bob->hasClient()) {
//find free/disconnected spot
if (!bobClient || !bobClient.connected()) {
if (bobClient) bobClient.stop();
bobClient = bob->available();
DEBUG_PRINTLN(F("Boblight: Client connected."));
}
//no free/disconnected spot so reject
WiFiClient bobClientTmp = bob->available();
bobClientTmp.stop();
BobClear();
exitRealtime();
}
//check clients for data
if (bobClient && bobClient.connected()) {
realtimeLock(realtimeTimeoutMs); // lock strip as we have a client connected
//get data from the client
while (bobClient.available()) {
String input = bobClient.readStringUntil('\n');
// DEBUG_PRINT(F("Client: ")); DEBUG_PRINTLN(input); // may be to stressful on Serial
if (input.startsWith(F("hello"))) {
DEBUG_PRINTLN(F("hello"));
bobClient.print(F("hello\n"));
} else if (input.startsWith(F("ping"))) {
DEBUG_PRINTLN(F("ping 1"));
bobClient.print(F("ping 1\n"));
} else if (input.startsWith(F("get version"))) {
DEBUG_PRINTLN(F("version 5"));
bobClient.print(F("version 5\n"));
} else if (input.startsWith(F("get lights"))) {
char tmp[64];
String answer = "";
sprintf_P(tmp, PSTR("lights %d\n"), numLights);
DEBUG_PRINT(tmp);
answer.concat(tmp);
for (int i=0; i<numLights; i++) {
sprintf_P(tmp, PSTR("light %s scan %2.1f %2.1f %2.1f %2.1f\n"), lights[i].lightname, lights[i].vscan[0], lights[i].vscan[1], lights[i].hscan[0], lights[i].hscan[1]);
DEBUG_PRINT(tmp);
answer.concat(tmp);
}
bobClient.print(answer);
} else if (input.startsWith(F("set priority"))) {
DEBUG_PRINTLN(F("set priority not implemented"));
// not implemented
} else if (input.startsWith(F("set light "))) { // <id> <cmd in rgb, speed, interpolation> <value> ...
input.remove(0,10);
String tmp = input.substring(0,input.indexOf(' '));
int light_id = -1;
for (uint16_t i=0; i<numLights; i++) {
if (strncmp(lights[i].lightname, tmp.c_str(), 4) == 0) {
light_id = i;
break;
}
}
if (light_id == -1) return;
input.remove(0,input.indexOf(' ')+1);
if (input.startsWith(F("rgb "))) {
input.remove(0,4);
tmp = input.substring(0,input.indexOf(' '));
uint8_t red = (uint8_t)(255.0f*tmp.toFloat());
input.remove(0,input.indexOf(' ')+1); // remove first float value
tmp = input.substring(0,input.indexOf(' '));
uint8_t green = (uint8_t)(255.0f*tmp.toFloat());
input.remove(0,input.indexOf(' ')+1); // remove second float value
tmp = input.substring(0,input.indexOf(' '));
uint8_t blue = (uint8_t)(255.0f*tmp.toFloat());
//strip.setPixelColor(light_id, RGBW32(red, green, blue, 0));
setRealtimePixel(light_id, red, green, blue, 0);
} // currently no support for interpolation or speed, we just ignore this
} else if (input.startsWith("sync")) {
BobSync();
} else {
// Client sent gibberish
DEBUG_PRINTLN(F("Client sent gibberish."));
bobClient.stop();
bobClient = bob->available();
BobClear();
}
}
}
}

View File

@ -165,7 +165,7 @@ private:
void _showElements(String *map, int timevar, bool isColon, bool removeZero
) {
if (!(*map).equals("") && !(*map) == NULL) {
if ((map != nullptr) && (*map != nullptr) && !(*map).equals("")) {
int length = String(timevar).length();
bool addZero = false;
if (length == 1) {
@ -236,11 +236,13 @@ private:
}
void _setLeds(int lednr, int lastSeenLedNr, bool range, int countSegments, int number, bool colon) {
if ((lednr < 0) || (lednr >= umSSDRLength)) return; // prevent array bounds violation
if (!(colon && umSSDRColonblink) && ((number < 0) || (countSegments < 0))) return;
if ((colon && umSSDRColonblink) || umSSDRNumbers[number][countSegments]) {
if (range) {
for(int i = lastSeenLedNr; i <= lednr; i++) {
for(int i = max(0, lastSeenLedNr); i <= lednr; i++) {
umSSDRMask[i] = true;
}
} else {

View File

@ -517,26 +517,26 @@ typedef struct Segment {
#endif
inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); }
inline bool isSelected(void) const { return selected; }
inline bool isInTransition(void) const { return _t != nullptr; }
inline bool isActive(void) const { return stop > start; }
inline bool is2D(void) const { return (width()>1 && height()>1); }
inline bool hasRGB(void) const { return _isRGB; }
inline bool hasWhite(void) const { return _hasW; }
inline bool isCCT(void) const { return _isCCT; }
inline uint16_t width(void) const { return isActive() ? (stop - start) : 0; } // segment width in physical pixels (length if 1D)
inline uint16_t height(void) const { return stopY - startY; } // segment height (if 2D) in physical pixels (it *is* always >=1)
inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels
inline uint16_t groupLength(void) const { return grouping + spacing; }
inline uint8_t getLightCapabilities(void) const { return _capabilities; }
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; }
inline uint16_t width() const { return isActive() ? (stop - start) : 0; } // segment width in physical pixels (length if 1D)
inline uint16_t height() const { return stopY - startY; } // segment height (if 2D) in physical pixels (it *is* always >=1)
inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
inline uint16_t groupLength() const { return grouping + spacing; }
inline uint8_t getLightCapabilities() const { return _capabilities; }
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
inline static uint16_t getUsedSegmentData() { return _usedSegmentData; }
inline static void addUsedSegmentData(int len) { _usedSegmentData += len; }
#ifndef WLED_DISABLE_MODE_BLEND
static void modeBlend(bool blend) { _modeBlend = blend; }
inline static void modeBlend(bool blend) { _modeBlend = blend; }
#endif
static void handleRandomPalette();
inline static const CRGBPalette16 &getCurrentPalette(void) { return Segment::_currentPalette; }
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
@ -546,39 +546,39 @@ typedef struct Segment {
void setMode(uint8_t fx, bool loadDefaults = false);
void setPalette(uint8_t pal);
uint8_t differs(Segment& b) const;
void refreshLightCapabilities(void);
void refreshLightCapabilities();
// runtime data functions
inline uint16_t dataSize(void) const { return _dataLen; }
inline uint16_t dataSize() const { return _dataLen; }
bool allocateData(size_t len); // allocates effect data buffer in heap and clears it
void deallocateData(void); // deallocates (frees) effect data buffer from heap
void resetIfRequired(void); // sets all SEGENV variables to 0 and clears data buffer
void deallocateData(); // deallocates (frees) effect data buffer from heap
void resetIfRequired(); // sets all SEGENV variables to 0 and clears data buffer
/**
* Flags that before the next effect is calculated,
* the internal segment state should be reset.
* Call resetIfRequired before calling the next effect function.
* Safe to call from interrupts and network requests.
*/
inline void markForReset(void) { reset = true; } // setOption(SEG_OPTION_RESET, true)
inline void markForReset() { reset = true; } // setOption(SEG_OPTION_RESET, true)
// transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change
void stopTransition(void); // ends transition mode by destroying transition structure (does nothing if not in transition)
inline void handleTransition(void) { if (progress() == 0xFFFFU) stopTransition(); }
void stopTransition(); // ends transition mode by destroying transition structure (does nothing if not in transition)
inline void handleTransition() { 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
#endif
uint16_t progress(void) const; // transition progression between 0-65535
uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition)
uint8_t currentMode(void) const; // currently active effect/mode (while in transition)
uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
[[gnu::hot]] uint16_t progress() const; // 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)
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
void setCurrentPalette(void);
void setCurrentPalette();
// 1D strip
uint16_t virtualLength(void) const;
void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
[[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)); }
@ -587,7 +587,7 @@ typedef struct Segment {
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); }
#endif
uint32_t getPixelColor(int i) const;
[[gnu::hot]] uint32_t getPixelColor(int i) const;
// 1D support functions (some implement 2D as well)
void blur(uint8_t, bool smear = false);
void fill(uint32_t c);
@ -599,8 +599,8 @@ typedef struct Segment {
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); }
inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); }
inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); }
uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
uint32_t color_wheel(uint8_t pos) const;
[[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
[[gnu::hot]] uint32_t color_wheel(uint8_t pos) const;
// 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur)
inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns
@ -613,12 +613,12 @@ typedef struct Segment {
}
// 2D matrix
uint16_t virtualWidth(void) const; // segment width in virtual pixels (accounts for groupping and spacing)
uint16_t virtualHeight(void) const; // segment height in virtual pixels (accounts for groupping and spacing)
uint16_t nrOfVStrips(void) const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
[[gnu::hot]] uint16_t virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing)
[[gnu::hot]] uint16_t virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing)
uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
#ifndef WLED_DISABLE_2D
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
[[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)); }
@ -628,7 +628,7 @@ typedef struct Segment {
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); }
#endif
uint32_t getPixelColorXY(int x, int y) const;
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
// 2D support functions
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
@ -697,8 +697,8 @@ typedef struct Segment {
// main "strip" class
class WS2812FX { // 96 bytes
typedef uint16_t (*mode_ptr)(void); // pointer to mode function
typedef void (*show_callback)(void); // pre show callback
typedef uint16_t (*mode_ptr)(); // pointer to mode function
typedef void (*show_callback)(); // pre show callback
typedef struct ModeData {
uint8_t _id; // mode (effect) id
mode_ptr _fcn; // mode (effect) function
@ -764,29 +764,29 @@ class WS2812FX { // 96 bytes
customPalettes.clear();
}
static WS2812FX* getInstance(void) { return instance; }
static WS2812FX* getInstance() { return instance; }
void
#ifdef WLED_DEBUG
printSize(), // prints memory usage for strip components
#endif
finalizeInit(), // initialises strip components
service(void), // executes effect functions when due and calls strip.show()
service(), // executes effect functions when due and calls strip.show()
setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API)
setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API)
setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
setBrightness(uint8_t b, bool direct = false), // sets strip brightness
setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay
purgeSegments(void), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1),
setMainSegmentId(uint8_t n),
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
show(void), // initiates LED output
show(), // initiates LED output
setTargetFps(uint8_t fps),
setupEffectData(void); // add default effects to the list; defined in FX.cpp
setupEffectData(); // add default effects to the list; defined in FX.cpp
inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); }
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
@ -794,74 +794,74 @@ class WS2812FX { // 96 bytes
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 trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
inline void trigger() { _triggered = true; } // Forces the next frame to be computed on all active segments.
inline void setShowCallback(show_callback cb) { _callback = cb; }
inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
inline void suspend(void) { _suspend = true; } // will suspend (and canacel) strip.service() execution
inline void resume(void) { _suspend = false; } // will resume strip.service() execution
inline void suspend() { _suspend = true; } // will suspend (and canacel) strip.service() execution
inline void resume() { _suspend = false; } // will resume strip.service() execution
bool
paletteFade,
checkSegmentAlignment(void),
hasRGBWBus(void) const,
hasCCTBus(void) const,
isUpdating(void) const, // return true if the strip is being sent pixel updates
checkSegmentAlignment(),
hasRGBWBus() const,
hasCCTBus() const,
isUpdating() const, // return true if the strip is being sent pixel updates
deserializeMap(uint8_t n=0);
inline bool isServicing(void) const { return _isServicing; } // returns true if strip.service() is executing
inline bool hasWhiteChannel(void) const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
inline bool isOffRefreshRequired(void) const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
inline bool isSuspended(void) const { return _suspend; } // returns true if strip.service() execution is suspended
inline bool needsUpdate(void) const { return _triggered; } // returns true if strip received a trigger() request
inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing
inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
inline bool isSuspended() const { return _suspend; } // returns true if strip.service() execution is suspended
inline bool needsUpdate() const { return _triggered; } // returns true if strip received a trigger() request
uint8_t
paletteBlend,
cctBlending,
getActiveSegmentsNum(void) const,
getFirstSelectedSegId(void) const,
getLastActiveSegmentId(void) const,
getActiveSegmentsNum() const,
getFirstSelectedSegId() const,
getLastActiveSegmentId() const,
getActiveSegsLightCapabilities(bool selectedOnly = false) const,
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp;
inline uint8_t getBrightness(void) const { return _brightness; } // returns current strip brightness
inline uint8_t getMaxSegments(void) const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
inline uint8_t getSegmentsNum(void) const { return _segments.size(); } // returns currently present segments
inline uint8_t getCurrSegmentId(void) const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
inline uint8_t getMainSegmentId(void) const { return _mainSegment; } // returns main segment index
inline uint8_t getPaletteCount() const { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
inline uint8_t getTargetFps() const { return _targetFps; } // returns rough FPS value for las 2s interval
inline uint8_t getModeCount() const { return _modeCount; } // returns number of registered modes/effects
inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness
inline uint8_t getMaxSegments() const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments
inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index
inline uint8_t getPaletteCount() const { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
inline uint8_t getTargetFps() const { return _targetFps; } // returns rough FPS value for las 2s interval
inline uint8_t getModeCount() const { return _modeCount; } // returns number of registered modes/effects
uint16_t
getLengthPhysical(void) const,
getLengthTotal(void) const, // will include virtual/nonexistent pixels in matrix
getLengthPhysical() const,
getLengthTotal() const, // will include virtual/nonexistent pixels in matrix
getFps() const,
getMappedPixelIndex(uint16_t index) const;
inline uint16_t getFrameTime(void) const { return _frametime; } // returns amount of time a frame should take (in ms)
inline uint16_t getMinShowDelay(void) const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
inline uint16_t getLength(void) const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
inline uint16_t getTransition(void) const { return _transitionDur; } // returns currently set transition time (in ms)
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
uint32_t
now,
timebase,
getPixelColor(uint16_t) const;
inline uint32_t getLastShow(void) const { return _lastShow; } // returns millis() timestamp of last strip.show() call
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
const char *
getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
const char **
getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data
getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data
Segment& getSegment(uint8_t id);
inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; } // returns reference to main segment
inline Segment* getSegments(void) { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment
inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
// 2D support (panels)
bool
@ -908,7 +908,7 @@ class WS2812FX { // 96 bytes
// end 2D support
void loadCustomPalettes(void); // loads custom palettes from JSON
void loadCustomPalettes(); // loads custom palettes from JSON
std::vector<CRGBPalette16> customPalettes; // TODO: move custom palettes out of WS2812FX class
struct {

View File

@ -161,14 +161,14 @@ 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 Segment::XY(uint16_t x, uint16_t y)
uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
{
unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1)
return isActive() ? (x%width) + (y%height) * width : 0;
}
void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
{
if (!isActive()) return; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
@ -211,7 +211,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
}
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol);
strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, tmpCol);
}
}
}
@ -264,7 +264,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
#endif
// returns RGBW values of pixel
uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) const {
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
if (!isActive()) return 0; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if (reverse ) x = virtualWidth() - x - 1;

View File

@ -158,7 +158,7 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
}
// allocates effect data buffer on heap and initialises (erases) it
bool IRAM_ATTR Segment::allocateData(size_t len) {
bool IRAM_ATTR_YN Segment::allocateData(size_t len) {
if (len == 0) return false; // nothing to do
if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation)
if (call == 0) memset(data, 0, len); // erase buffer if called during effect initialisation
@ -182,7 +182,7 @@ bool IRAM_ATTR Segment::allocateData(size_t len) {
return true;
}
void IRAM_ATTR Segment::deallocateData() {
void IRAM_ATTR_YN Segment::deallocateData() {
if (!data) { _dataLen = 0; return; }
//DEBUG_PRINTF_P(PSTR("--- Released data (%p): %d/%d -> %p\n"), this, _dataLen, Segment::getUsedSegmentData(), data);
if ((Segment::getUsedSegmentData() > 0) && (_dataLen > 0)) { // check that we don't have a dangling / inconsistent data pointer
@ -214,7 +214,7 @@ void Segment::resetIfRequired() {
reset = false;
}
CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip
//default palette. Differs depending on effect
@ -429,7 +429,7 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const {
return (useCct ? cct : (on ? opacity : 0));
}
uint8_t IRAM_ATTR Segment::currentMode() const {
uint8_t Segment::currentMode() const {
#ifndef WLED_DISABLE_MODE_BLEND
unsigned prog = progress();
if (modeBlending && prog < 0xFFFFU) return _t->_modeT;
@ -437,7 +437,7 @@ uint8_t IRAM_ATTR Segment::currentMode() const {
return mode;
}
uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) const {
uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const {
if (slot >= NUM_COLORS) slot = 0;
#ifndef WLED_DISABLE_MODE_BLEND
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot];
@ -630,7 +630,7 @@ uint16_t IRAM_ATTR Segment::virtualHeight() const {
return vHeight;
}
uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const {
unsigned vLen = 1;
#ifndef WLED_DISABLE_2D
if (is2D()) {
@ -713,7 +713,7 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
return vLength;
}
void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
{
if (!isActive()) return; // not active
#ifndef WLED_DISABLE_2D
@ -907,7 +907,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
}
#endif
uint32_t IRAM_ATTR Segment::getPixelColor(int i) const
uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
{
if (!isActive()) return 0; // not active
#ifndef WLED_DISABLE_2D
@ -1209,7 +1209,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
///////////////////////////////////////////////////////////////////////////////
//do not call this method from system context (network callback)
void WS2812FX::finalizeInit(void) {
void WS2812FX::finalizeInit() {
//reset segment runtimes
for (segment &seg : _segments) {
seg.markForReset();
@ -1408,7 +1408,7 @@ uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const {
return BusManager::getPixelColor(i);
}
void WS2812FX::show(void) {
void WS2812FX::show() {
// avoid race condition, capture _callback value
show_callback callback = _callback;
if (callback) callback();
@ -1505,7 +1505,7 @@ uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) const {
return totalLC;
}
uint8_t WS2812FX::getFirstSelectedSegId(void) const {
uint8_t WS2812FX::getFirstSelectedSegId() const {
size_t i = 0;
for (const segment &seg : _segments) {
if (seg.isActive() && seg.isSelected()) return i;
@ -1523,14 +1523,14 @@ void WS2812FX::setMainSegmentId(uint8_t n) {
return;
}
uint8_t WS2812FX::getLastActiveSegmentId(void) const {
uint8_t WS2812FX::getLastActiveSegmentId() const {
for (size_t i = _segments.size() -1; i > 0; i--) {
if (_segments[i].isActive()) return i;
}
return 0;
}
uint8_t WS2812FX::getActiveSegmentsNum(void) const {
uint8_t WS2812FX::getActiveSegmentsNum() const {
uint8_t c = 0;
for (size_t i = 0; i < _segments.size(); i++) {
if (_segments[i].isActive()) c++;
@ -1538,13 +1538,13 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) const {
return c;
}
uint16_t WS2812FX::getLengthTotal(void) const {
uint16_t WS2812FX::getLengthTotal() const {
unsigned len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D
if (isMatrix && _length > len) len = _length; // for 2D with trailing strip
return len;
}
uint16_t WS2812FX::getLengthPhysical(void) const {
uint16_t WS2812FX::getLengthPhysical() const {
unsigned len = 0;
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = BusManager::getBus(b);
@ -1557,7 +1557,7 @@ uint16_t WS2812FX::getLengthPhysical(void) const {
//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw.
//returns if there is an RGBW bus (supports RGB and White, not only white)
//not influenced by auto-white mode, also true if white slider does not affect output white channel
bool WS2812FX::hasRGBWBus(void) const {
bool WS2812FX::hasRGBWBus() const {
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = BusManager::getBus(b);
if (bus == nullptr || bus->getLength()==0) break;
@ -1566,7 +1566,7 @@ bool WS2812FX::hasRGBWBus(void) const {
return false;
}
bool WS2812FX::hasCCTBus(void) const {
bool WS2812FX::hasCCTBus() const {
if (cctFromRgb && !correctWB) return false;
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = BusManager::getBus(b);

View File

@ -173,7 +173,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
//I am NOT to be held liable for burned down garages or houses!
// To disable brightness limiter we either set output max current to 0 or single LED current to 0
uint8_t BusDigital::estimateCurrentAndLimitBri(void) {
uint8_t BusDigital::estimateCurrentAndLimitBri() {
bool useWackyWS2815PowerModel = false;
byte actualMilliampsPerLed = _milliAmpsPerLed;
@ -225,7 +225,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri(void) {
return newBri;
}
void BusDigital::show(void) {
void BusDigital::show() {
_milliAmpsTotal = 0;
if (!_valid) return;
@ -286,7 +286,7 @@ void BusDigital::show(void) {
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, _bri);
}
bool BusDigital::canShow(void) const {
bool BusDigital::canShow() const {
if (!_valid) return true;
return PolyBus::canShow(_busPtr, _iType);
}
@ -410,12 +410,12 @@ std::vector<LEDType> BusDigital::getLEDTypes() {
};
}
void BusDigital::reinit(void) {
void BusDigital::reinit() {
if (!_valid) return;
PolyBus::begin(_busPtr, _iType, _pins);
}
void BusDigital::cleanup(void) {
void BusDigital::cleanup() {
DEBUG_PRINTLN(F("Digital Cleanup."));
PolyBus::cleanup(_busPtr, _iType);
_iType = I_NONE;
@ -637,7 +637,7 @@ std::vector<LEDType> BusPwm::getLEDTypes() {
};
}
void BusPwm::deallocatePins(void) {
void BusPwm::deallocatePins() {
unsigned numPins = getPins();
for (unsigned i = 0; i < numPins; i++) {
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
@ -689,7 +689,7 @@ uint32_t BusOnOff::getPixelColor(uint16_t pix) const {
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
}
void BusOnOff::show(void) {
void BusOnOff::show() {
if (!_valid) return;
digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
}
@ -751,7 +751,7 @@ uint32_t BusNetwork::getPixelColor(uint16_t pix) const {
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0));
}
void BusNetwork::show(void) {
void BusNetwork::show() {
if (!_valid || !canShow()) return;
_broadcastLock = true;
realtimeBroadcast(_UDPtype, _client, _len, _data, _bri, hasWhite());
@ -778,7 +778,7 @@ std::vector<LEDType> BusNetwork::getLEDTypes() {
};
}
void BusNetwork::cleanup(void) {
void BusNetwork::cleanup() {
_type = I_NONE;
_valid = false;
freeData();
@ -839,7 +839,7 @@ static String LEDTypesToJson(const std::vector<LEDType>& types) {
}
// credit @willmmiles & @netmindz https://github.com/Aircoookie/WLED/pull/4056
String BusManager::getLEDTypesJSONString(void) {
String BusManager::getLEDTypesJSONString() {
String json = "[";
json += LEDTypesToJson(BusDigital::getLEDTypes());
json += LEDTypesToJson(BusOnOff::getLEDTypes());
@ -850,13 +850,13 @@ String BusManager::getLEDTypesJSONString(void) {
return json;
}
void BusManager::useParallelOutput(void) {
void BusManager::useParallelOutput() {
_parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods
PolyBus::setParallelI2S1Output();
}
//do not call this method from system context (network callback)
void BusManager::removeAll(void) {
void BusManager::removeAll() {
DEBUG_PRINTLN(F("Removing all."));
//prevents crashes due to deleting busses while in use.
while (!canAllShow()) yield();
@ -870,7 +870,7 @@ void BusManager::removeAll(void) {
// #2478
// If enabled, RMT idle level is set to HIGH when off
// to prevent leakage current when using an N-channel MOSFET to toggle LED power
void BusManager::esp32RMTInvertIdle(void) {
void BusManager::esp32RMTInvertIdle() {
bool idle_out;
unsigned rmt = 0;
for (unsigned u = 0; u < numBusses(); u++) {
@ -901,7 +901,7 @@ void BusManager::esp32RMTInvertIdle(void) {
}
#endif
void BusManager::on(void) {
void BusManager::on() {
#ifdef ESP8266
//Fix for turning off onboard LED breaking bus
if (pinManager.getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
@ -922,7 +922,7 @@ void BusManager::on(void) {
#endif
}
void BusManager::off(void) {
void BusManager::off() {
#ifdef ESP8266
// turn off built-in LED if strip is turned off
// this will break digital bus so will need to be re-initialised on On
@ -937,7 +937,7 @@ void BusManager::off(void) {
#endif
}
void BusManager::show(void) {
void BusManager::show() {
_milliAmpsUsed = 0;
for (unsigned i = 0; i < numBusses; i++) {
busses[i]->show();
@ -984,7 +984,7 @@ uint32_t BusManager::getPixelColor(uint16_t pix) {
return 0;
}
bool BusManager::canAllShow(void) {
bool BusManager::canAllShow() {
for (unsigned i = 0; i < numBusses; i++) {
if (!busses[i]->canShow()) return false;
}
@ -997,7 +997,7 @@ Bus* BusManager::getBus(uint8_t busNr) {
}
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t BusManager::getTotalLength(void) {
uint16_t BusManager::getTotalLength() {
unsigned len = 0;
for (unsigned i=0; i<numBusses; i++) len += busses[i]->getLength();
return len;

View File

@ -47,7 +47,7 @@ struct ColorOrderMap {
return &(_mappings[n]);
}
uint8_t getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const;
[[gnu::hot]] uint8_t getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const;
private:
std::vector<ColorOrderMapEntry> _mappings;
@ -79,46 +79,46 @@ class Bus {
virtual ~Bus() {} //throw the bus under the bus
virtual void show(void) = 0;
virtual bool canShow(void) const { return true; }
virtual void setStatusPixel(uint32_t c) {}
virtual void show() = 0;
virtual bool canShow() const { return true; }
virtual void setStatusPixel(uint32_t c) {}
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
virtual void setBrightness(uint8_t b) { _bri = b; };
virtual void setColorOrder(uint8_t co) {}
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
virtual uint16_t getLength(void) const { return isOk() ? _len : 0; }
virtual uint8_t getColorOrder(void) const { return COL_ORDER_RGB; }
virtual uint8_t skippedLeds(void) const { return 0; }
virtual uint16_t getFrequency(void) const { return 0U; }
virtual uint16_t getLEDCurrent(void) const { return 0; }
virtual uint16_t getUsedCurrent(void) const { return 0; }
virtual uint16_t getMaxCurrent(void) const { return 0; }
virtual void setBrightness(uint8_t b) { _bri = b; };
virtual void setColorOrder(uint8_t co) {}
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
virtual uint8_t skippedLeds() const { return 0; }
virtual uint16_t getFrequency() const { return 0U; }
virtual uint16_t getLEDCurrent() const { return 0; }
virtual uint16_t getUsedCurrent() const { return 0; }
virtual uint16_t getMaxCurrent() const { return 0; }
inline bool hasRGB(void) const { return _hasRgb; }
inline bool hasWhite(void) const { return _hasWhite; }
inline bool hasCCT(void) const { return _hasCCT; }
inline bool isDigital(void) const { return isDigital(_type); }
inline bool is2Pin(void) const { return is2Pin(_type); }
inline bool isOnOff(void) const { return isOnOff(_type); }
inline bool isPWM(void) const { return isPWM(_type); }
inline bool isVirtual(void) const { return isVirtual(_type); }
inline bool is16bit(void) const { return is16bit(_type); }
inline void setReversed(bool reversed) { _reversed = reversed; }
inline void setStart(uint16_t start) { _start = start; }
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
inline uint8_t getAutoWhiteMode(void) const { return _autoWhiteMode; }
inline uint8_t getNumberOfChannels(void) const { return hasWhite() + 3*hasRGB() + hasCCT(); }
inline uint16_t getStart(void) const { return _start; }
inline uint8_t getType(void) const { return _type; }
inline bool isOk(void) const { return _valid; }
inline bool isReversed(void) const { return _reversed; }
inline bool isOffRefreshRequired(void) const { return _needsRefresh; }
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
inline bool hasRGB() const { return _hasRgb; }
inline bool hasWhite() const { return _hasWhite; }
inline bool hasCCT() const { return _hasCCT; }
inline bool isDigital() const { return isDigital(_type); }
inline bool is2Pin() const { return is2Pin(_type); }
inline bool isOnOff() const { return isOnOff(_type); }
inline bool isPWM() const { return isPWM(_type); }
inline bool isVirtual() const { return isVirtual(_type); }
inline bool is16bit() const { return is16bit(_type); }
inline void setReversed(bool reversed) { _reversed = reversed; }
inline void setStart(uint16_t start) { _start = start; }
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
inline uint8_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
inline uint16_t getStart() const { return _start; }
inline uint8_t getType() const { return _type; }
inline bool isOk() const { return _valid; }
inline bool isReversed() const { return _reversed; }
inline bool isOffRefreshRequired() const { return _needsRefresh; }
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
static inline std::vector<LEDType> getLEDTypes(void) { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
static constexpr bool hasRGB(uint8_t type) {
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
}
@ -144,11 +144,11 @@ class Bus {
static constexpr bool is16bit(uint8_t type) { return type == TYPE_UCS8903 || type == TYPE_UCS8904 || type == TYPE_SM16825; }
static constexpr int numPWMPins(uint8_t type) { return (type - 40); }
static inline int16_t getCCT(void) { return _cct; }
static inline int16_t getCCT() { return _cct; }
static inline void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
static inline uint8_t getGlobalAWMode(void) { return _gAWM; }
static inline uint8_t getGlobalAWMode() { return _gAWM; }
static inline void setCCT(int16_t cct) { _cct = cct; }
static inline uint8_t getCCTBlend(void) { return _cctBlend; }
static inline uint8_t getCCTBlend() { return _cctBlend; }
static inline void setCCTBlend(uint8_t b) {
_cctBlend = (std::min((int)b,100) * 127) / 100;
//compile-time limiter for hardware that can't power both white channels at max
@ -197,24 +197,24 @@ class BusDigital : public Bus {
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
~BusDigital() { cleanup(); }
void show(void) override;
bool canShow(void) const override;
void show() override;
bool canShow() const override;
void setBrightness(uint8_t b) override;
void setStatusPixel(uint32_t c) override;
void setPixelColor(uint16_t pix, uint32_t c) override;
[[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override;
void setColorOrder(uint8_t colorOrder) override;
uint32_t getPixelColor(uint16_t pix) const override;
uint8_t getColorOrder(void) const override { return _colorOrder; }
[[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override;
uint8_t getColorOrder() const override { return _colorOrder; }
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
uint8_t skippedLeds(void) const override { return _skip; }
uint16_t getFrequency(void) const override { return _frequencykHz; }
uint16_t getLEDCurrent(void) const override { return _milliAmpsPerLed; }
uint16_t getUsedCurrent(void) const override { return _milliAmpsTotal; }
uint16_t getMaxCurrent(void) const override { return _milliAmpsMax; }
void reinit(void);
void cleanup(void);
uint8_t skippedLeds() const override { return _skip; }
uint16_t getFrequency() const override { return _frequencykHz; }
uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; }
uint16_t getUsedCurrent() const override { return _milliAmpsTotal; }
uint16_t getMaxCurrent() const override { return _milliAmpsMax; }
void reinit();
void cleanup();
static std::vector<LEDType> getLEDTypes(void);
static std::vector<LEDType> getLEDTypes();
private:
uint8_t _skip;
@ -240,7 +240,7 @@ class BusDigital : public Bus {
return c;
}
uint8_t estimateCurrentAndLimitBri(void);
uint8_t estimateCurrentAndLimitBri();
};
@ -252,11 +252,11 @@ class BusPwm : public Bus {
void setPixelColor(uint16_t pix, uint32_t c) override;
uint32_t getPixelColor(uint16_t pix) const override; //does no index check
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
uint16_t getFrequency(void) const override { return _frequency; }
void show(void) override;
void cleanup(void) { deallocatePins(); }
uint16_t getFrequency() const override { return _frequency; }
void show() override;
void cleanup() { deallocatePins(); }
static std::vector<LEDType> getLEDTypes(void);
static std::vector<LEDType> getLEDTypes();
private:
uint8_t _pins[OUTPUT_MAX_PINS];
@ -267,7 +267,7 @@ class BusPwm : public Bus {
uint8_t _depth;
uint16_t _frequency;
void deallocatePins(void);
void deallocatePins();
};
@ -279,10 +279,10 @@ class BusOnOff : public Bus {
void setPixelColor(uint16_t pix, uint32_t c) override;
uint32_t getPixelColor(uint16_t pix) const override;
uint8_t getPins(uint8_t* pinArray) const override;
void show(void) override;
void cleanup(void) { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); }
void show() override;
void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); }
static std::vector<LEDType> getLEDTypes(void);
static std::vector<LEDType> getLEDTypes();
private:
uint8_t _pin;
@ -295,14 +295,14 @@ class BusNetwork : public Bus {
BusNetwork(BusConfig &bc);
~BusNetwork() { cleanup(); }
bool canShow(void) const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
void setPixelColor(uint16_t pix, uint32_t c) override;
uint32_t getPixelColor(uint16_t pix) const override;
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
void show(void) override;
void cleanup(void);
void show() override;
void cleanup();
static std::vector<LEDType> getLEDTypes(void);
static std::vector<LEDType> getLEDTypes();
private:
IPAddress _client;
@ -367,38 +367,38 @@ class BusManager {
//utility to get the approx. memory usage of a given BusConfig
static uint32_t memUsage(BusConfig &bc);
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
static uint16_t currentMilliamps(void) { return _milliAmpsUsed; }
static uint16_t ablMilliampsMax(void) { return _milliAmpsMax; }
static uint16_t currentMilliamps() { return _milliAmpsUsed; }
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
static int add(BusConfig &bc);
static void useParallelOutput(void); // workaround for inaccessible PolyBus
static void useParallelOutput(); // workaround for inaccessible PolyBus
//do not call this method from system context (network callback)
static void removeAll(void);
static void removeAll();
static void on(void);
static void off(void);
static void on();
static void off();
static void show(void);
static bool canAllShow(void);
static void show();
static bool canAllShow();
static void setStatusPixel(uint32_t c);
static void setPixelColor(uint16_t pix, uint32_t c);
[[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c);
static void setBrightness(uint8_t b);
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
static uint32_t getPixelColor(uint16_t pix);
static inline int16_t getSegmentCCT(void) { return Bus::getCCT(); }
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
static Bus* getBus(uint8_t busNr);
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
static uint16_t getTotalLength(void);
static inline uint8_t getNumBusses(void) { return numBusses; }
static String getLEDTypesJSONString(void);
static uint16_t getTotalLength();
static inline uint8_t getNumBusses() { return numBusses; }
static String getLEDTypesJSONString();
static inline ColorOrderMap& getColorOrderMap(void) { return colorOrderMap; }
static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; }
private:
static uint8_t numBusses;
@ -409,9 +409,9 @@ class BusManager {
static uint8_t _parallelOutputs;
#ifdef ESP32_DATA_IDLE_HIGH
static void esp32RMTInvertIdle(void) ;
static void esp32RMTInvertIdle() ;
#endif
static uint8_t getNumVirtualBusses(void) {
static uint8_t getNumVirtualBusses() {
int j = 0;
for (int i=0; i<numBusses; i++) if (busses[i]->isVirtual()) j++;
return j;

View File

@ -125,7 +125,7 @@ void handleSwitch(uint8_t b)
{
// isButtonPressed() handles inverted/noninverted logic
if (buttonPressedBefore[b] != isButtonPressed(b)) {
DEBUG_PRINT(F("Switch: State changed ")); DEBUG_PRINTLN(b);
DEBUG_PRINTF_P(PSTR("Switch: State changed %u\n"), b);
buttonPressedTime[b] = millis();
buttonPressedBefore[b] = !buttonPressedBefore[b];
}
@ -133,15 +133,15 @@ void handleSwitch(uint8_t b)
if (buttonLongPressed[b] == buttonPressedBefore[b]) return;
if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
DEBUG_PRINT(F("Switch: Activating ")); DEBUG_PRINTLN(b);
DEBUG_PRINTF_P(PSTR("Switch: Activating %u\n"), b);
if (!buttonPressedBefore[b]) { // on -> off
DEBUG_PRINT(F("Switch: On -> Off ")); DEBUG_PRINTLN(b);
DEBUG_PRINTF_P(PSTR("Switch: On -> Off (%u)\n"), b);
if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
else { //turn on
if (!bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
}
} else { // off -> on
DEBUG_PRINT(F("Switch: Off -> On ")); DEBUG_PRINTLN(b);
DEBUG_PRINTF_P(PSTR("Switch: Off -> On (%u)\n"), b);
if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
else { //turn off
if (bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
@ -173,7 +173,7 @@ void handleAnalog(uint8_t b)
static float filteredReading[WLED_MAX_BUTTONS] = {0.0f};
unsigned rawReading; // raw value from analogRead, scaled to 12bit
DEBUG_PRINT(F("Analog: Reading button ")); DEBUG_PRINTLN(b);
DEBUG_PRINTF_P(PSTR("Analog: Reading button %u\n"), b);
#ifdef ESP8266
rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit
@ -193,8 +193,8 @@ void handleAnalog(uint8_t b)
// remove noise & reduce frequency of UI updates
if (abs(int(aRead) - int(oldRead[b])) <= POT_SENSITIVITY) return; // no significant change in reading
DEBUG_PRINT(F("Analog: Raw = ")); DEBUG_PRINT(rawReading);
DEBUG_PRINT(F(" Filtered = ")); DEBUG_PRINTLN(aRead);
DEBUG_PRINTF_P(PSTR("Analog: Raw = %u\n"), rawReading);
DEBUG_PRINTF_P(PSTR(" Filtered = %u\n"), aRead);
// Unomment the next lines if you still see flickering related to potentiometer
// This waits until strip finishes updating (why: strip was not updating at the start of handleButton() but may have started during analogRead()?)
@ -207,7 +207,7 @@ void handleAnalog(uint8_t b)
// if no macro for "short press" and "long press" is defined use brightness control
if (!macroButton[b] && !macroLongPress[b]) {
DEBUG_PRINT(F("Analog: Action = ")); DEBUG_PRINTLN(macroDoublePress[b]);
DEBUG_PRINTF_P(PSTR("Analog: Action = %u\n"), macroDoublePress[b]);
// if "double press" macro defines which option to change
if (macroDoublePress[b] >= 250) {
// global brightness

View File

@ -273,9 +273,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if ((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) {
if (digitalPinToAnalogChannel(btnPin[s]) < 0) {
// not an ADC analog pin
DEBUG_PRINT(F("PIN ALLOC error: GPIO")); DEBUG_PRINT(btnPin[s]);
DEBUG_PRINT(F("for analog button #")); DEBUG_PRINT(s);
DEBUG_PRINTLN(F(" is not an analog pin!"));
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n"), btnPin[s], s);
btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button);
} else {
@ -286,7 +284,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
{
if (digitalPinToTouchChannel(btnPin[s]) < 0) {
// not a touch pin
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), btnPin[s], s);
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not a touch pin!\n"), btnPin[s], s);
btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button);
}

View File

@ -37,6 +37,8 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16)
*/
uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
{
if (c1 == BLACK) return c2;
if (c2 == BLACK) return c1;
if (fast) {
uint8_t r = R(c1);
uint8_t g = G(c1);
@ -68,17 +70,18 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
{
if (c1 == BLACK || amount + video == 0) return BLACK;
uint32_t scaledcolor; // color order is: W R G B from MSB to LSB
uint32_t r = R(c1);
uint32_t g = G(c1);
uint32_t b = B(c1);
uint32_t w = W(c1);
uint32_t scale = amount + !video; // 32bit for faster calculation
uint32_t scale = amount; // 32bit for faster calculation
if (video) {
scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0);
scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0);
scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0);
scaledcolor |= (((w * scale) >> 8) << 24) + ((w && scale) ? 1 : 0);
scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16;
scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8;
scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0);
scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24;
} else {
scaledcolor = ((r * scale) >> 8) << 16;
scaledcolor |= ((g * scale) >> 8) << 8;
@ -195,7 +198,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
RGBpalettecolors[3]);
}
CRGBPalette16 generateRandomPalette(void) //generate fully random palette
CRGBPalette16 generateRandomPalette() //generate fully random palette
{
return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)),
@ -476,14 +479,14 @@ void NeoGammaWLEDMethod::calcGammaTable(float gamma)
}
}
uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
uint8_t IRAM_ATTR_YN NeoGammaWLEDMethod::Correct(uint8_t value)
{
if (!gammaCorrectCol) return value;
return gammaT[value];
}
// used for color gamma correction
uint32_t NeoGammaWLEDMethod::Correct32(uint32_t color)
uint32_t IRAM_ATTR_YN NeoGammaWLEDMethod::Correct32(uint32_t color)
{
if (!gammaCorrectCol) return color;
uint8_t w = W(color);

View File

@ -657,4 +657,12 @@
#define HW_PIN_MISOSPI MISO
#endif
// IRAM_ATTR for 8266 with 32Kb IRAM causes error: section `.text1' will not fit in region `iram1_0_seg'
// this hack removes the IRAM flag for some 1D/2D functions - somewhat slower, but it solves problems with some older 8266 chips
#ifdef WLED_SAVE_IRAM
#define IRAM_ATTR_YN
#else
#define IRAM_ATTR_YN IRAM_ATTR
#endif
#endif

View File

@ -806,11 +806,12 @@ Swap: <select id="xw${s}" name="XW${s}">
<div id="abl">
<i>Automatically limits brightness to stay close to the limit.<br>
Keep at &lt;1A if poweing LEDs directly from the ESP 5V pin!<br>
If using multiple outputs it is recommended to use per-output limiter.<br>
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
Use per-output limiter: <input type="checkbox" name="PPL" onchange="UI()"><br>
<div id="ppldis" style="display:none;">
<i>Make sure you enter correct values in each LED output.<br>
<i>Make sure you enter correct value for each LED output.<br>
If using multiple outputs with only one PSU, distribute its power proportionally amongst outputs.</i><br>
</div>
<div id="ampwarning" class="warn" style="display: none;">
@ -825,7 +826,7 @@ Swap: <select id="xw${s}" name="XW${s}">
<hr class="sml">
<button type="button" id="+" onclick="addLEDs(1,false)">+</button>
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
LED memory usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
<div id="ledwarning" class="warn" style="display: none;">
&#9888; You might run into stability or lag issues.<br>
@ -869,8 +870,7 @@ Swap: <select id="xw${s}" name="XW${s}">
<h3>Defaults</h3>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
Default brightness: <input name="CA" type="number" class="m" min="1" max="255" required> (1-255)<br><br>
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses defaults)
<br><br>
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses values from above)<br><br>
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br>
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
@ -879,14 +879,14 @@ Swap: <select id="xw${s}" name="XW${s}">
Enable transitions: <input type="checkbox" name="TF" onchange="gId('tran').style.display=this.checked?'inline':'none';"><br>
<span id="tran">
Effect blending: <input type="checkbox" name="EB"><br>
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
Default transition time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
Palette transitions: <input type="checkbox" name="PF"><br>
</span>
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
Use harmonic <i>Random Cycle</i> Palette: <input type="checkbox" name="TH"><br>
<h3>Timed light</h3>
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
Default Target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br>
Default duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
Default target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br>
Mode:
<select name="TW">
<option value="0">Wait and set</option>
@ -913,7 +913,7 @@ Swap: <select id="xw${s}" name="XW${s}">
<i class="warn">WARNING: When using H-bridge for reverse polarity (2-wire) CCT LED strip<br><b>make sure this value is 0</b>.<br>(ESP32 variants only, ESP8266 does not support H-bridges)</i>
</div>
<h3>Advanced</h3>
Palette blending:
Palette wrapping:
<select name="PB">
<option value="0">Linear (wrap if moving)</option>
<option value="1">Linear (always wrap)</option>

View File

@ -108,13 +108,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
if (e131SkipOutOfSequence)
if (seq < e131LastSequenceNumber[previousUniverses] && seq > 20 && e131LastSequenceNumber[previousUniverses] < 250){
DEBUG_PRINT(F("skipping E1.31 frame (last seq="));
DEBUG_PRINT(e131LastSequenceNumber[previousUniverses]);
DEBUG_PRINT(F(", current seq="));
DEBUG_PRINT(seq);
DEBUG_PRINT(F(", universe="));
DEBUG_PRINT(uni);
DEBUG_PRINTLN(")");
DEBUG_PRINTF_P(PSTR("skipping E1.31 frame (last seq=%d, current seq=%d, universe=%d)\n"), e131LastSequenceNumber[previousUniverses], seq, uni);
return;
}
e131LastSequenceNumber[previousUniverses] = seq;

View File

@ -69,20 +69,20 @@ typedef struct WiFiConfig {
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
class NeoGammaWLEDMethod {
public:
static uint8_t Correct(uint8_t value); // apply Gamma to single channel
static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
[[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel
[[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
private:
static uint8_t gammaT[];
};
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
uint32_t color_add(uint32_t,uint32_t, bool fast=false);
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false);
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
CRGBPalette16 generateRandomPalette(void);
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 colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
void colorKtoRGB(uint16_t kelvin, byte* rgb);

View File

@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
char vString[20];
sprintf_P(vString, PSTR("0.15.0-b4/%i"), VERSION);
sprintf_P(vString, PSTR("0.15.0-b5/%i"), VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);

View File

@ -1144,11 +1144,8 @@ void serveJson(AsyncWebServerRequest* request)
DEBUG_PRINTF_P(PSTR("JSON buffer size: %u for request: %d\n"), lDoc.memoryUsage(), subJson);
#ifdef WLED_DEBUG
size_t len =
#endif
response->setLength();
DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len);
[[maybe_unused]] size_t len = response->setLength();
DEBUG_PRINTF_P(PSTR("JSON content length: %u\n"), len);
request->send(response);
}

View File

@ -55,8 +55,7 @@ static void onMqttConnect(bool sessionPresent)
static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
static char *payloadStr;
DEBUG_PRINT(F("MQTT msg: "));
DEBUG_PRINTLN(topic);
DEBUG_PRINTF_P(PSTR("MQTT msg: %s\n"), topic);
// paranoia check to avoid npe if no payload
if (payload==nullptr) {

View File

@ -246,8 +246,7 @@ bool checkNTPResponse()
}
uint32_t ntpPacketReceivedTime = millis();
DEBUG_PRINT(F("NTP recv, l="));
DEBUG_PRINTLN(cb);
DEBUG_PRINTF_P(PSTR("NTP recv, l=%d\n"), cb);
byte pbuf[NTP_PACKET_SIZE];
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
if (!isValidNtpResponse(pbuf)) return false; // verify we have a valid response to client
@ -493,7 +492,7 @@ void calculateSunriseAndSunset() {
do {
time_t theDay = localTime - retryCount * 86400; // one day back = 86400 seconds
minUTC = getSunriseUTC(year(theDay), month(theDay), day(theDay), latitude, longitude, false);
DEBUG_PRINT(F("* sunrise (minutes from UTC) = ")); DEBUG_PRINTLN(minUTC);
DEBUG_PRINTF_P(PSTR("* sunrise (minutes from UTC) = %d\n"), minUTC);
retryCount ++;
} while ((abs(minUTC) > SUNSET_MAX) && (retryCount <= 3));
@ -512,7 +511,7 @@ void calculateSunriseAndSunset() {
do {
time_t theDay = localTime - retryCount * 86400; // one day back = 86400 seconds
minUTC = getSunriseUTC(year(theDay), month(theDay), day(theDay), latitude, longitude, true);
DEBUG_PRINT(F("* sunset (minutes from UTC) = ")); DEBUG_PRINTLN(minUTC);
DEBUG_PRINTF_P(PSTR("* sunset (minutes from UTC) = %d\n"), minUTC);
retryCount ++;
} while ((abs(minUTC) > SUNSET_MAX) && (retryCount <= 3));

View File

@ -117,8 +117,7 @@ void initPresetsFile()
bool applyPresetFromPlaylist(byte index)
{
DEBUG_PRINT(F("Request to apply preset: "));
DEBUG_PRINTLN(index);
DEBUG_PRINTF_P(PSTR("Request to apply preset: %d\n"), index);
presetToApply = index;
callModeToApply = CALL_MODE_DIRECT_CHANGE;
return true;
@ -127,8 +126,7 @@ bool applyPresetFromPlaylist(byte index)
bool applyPreset(byte index, byte callMode)
{
unloadPlaylist(); // applying a preset unloads the playlist (#3827)
DEBUG_PRINT(F("Request to apply preset: "));
DEBUG_PRINTLN(index);
DEBUG_PRINTF_P(PSTR("Request to apply preset: %u\n"), index);
presetToApply = index;
callModeToApply = callMode;
return true;
@ -163,8 +161,7 @@ void handlePresets()
presetToApply = 0; //clear request for preset
callModeToApply = 0;
DEBUG_PRINT(F("Applying preset: "));
DEBUG_PRINTLN(tmpPreset);
DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset);
#ifdef ARDUINO_ARCH_ESP32
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
@ -222,7 +219,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
else sprintf_P(saveName, PSTR("Preset %d"), index);
}
DEBUG_PRINT(F("Saving preset (")); DEBUG_PRINT(index); DEBUG_PRINT(F(") ")); DEBUG_PRINTLN(saveName);
DEBUG_PRINTF_P(PSTR("Saving preset (%d) %s\n"), index, saveName);
presetToSave = index;
playlistSave = false;

View File

@ -186,8 +186,7 @@ void handleRemote(uint8_t *incomingData, size_t len) {
}
if (len != sizeof(message_structure_t)) {
DEBUG_PRINT(F("Unknown incoming ESP Now message received of length "));
DEBUG_PRINTLN(len);
DEBUG_PRINTF_P(PSTR("Unknown incoming ESP Now message received of length %u\n"), len);
return;
}

View File

@ -157,8 +157,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED mA
char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max mA
if (!request->hasArg(lp)) {
DEBUG_PRINT(F("No data for "));
DEBUG_PRINTLN(s);
DEBUG_PRINTF_P(PSTR("No data for %d\n"), s);
break;
}
for (int i = 0; i < 5; i++) {
@ -728,7 +727,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
else subObj[name].add(value.toInt()); // we may have an int
j++;
}
DEBUG_PRINT(F("[")); DEBUG_PRINT(j); DEBUG_PRINT(F("] = ")); DEBUG_PRINTLN(value);
DEBUG_PRINTF_P(PSTR("[%d] = %s\n"), j, value.c_str());
} else {
// we are using a hidden field with the same name as our parameter (!before the actual parameter!)
// to describe the type of parameter (text,float,int), for boolean parameters the first field contains "off"
@ -747,7 +746,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
} else if (type == "int") subObj[name] = value.toInt();
else subObj[name] = value; // text fields
}
DEBUG_PRINT(F(" = ")); DEBUG_PRINTLN(value);
DEBUG_PRINTF_P(PSTR(" = %s\n"), value.c_str());
}
}
usermods.readFromConfig(um); // force change of usermod parameters
@ -808,8 +807,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (!(req.indexOf("win") >= 0)) return false;
int pos = 0;
DEBUG_PRINT(F("API req: "));
DEBUG_PRINTLN(req);
DEBUG_PRINTF_P(PSTR("API req: %s\n"), req.c_str());
//segment select (sets main segment)
pos = req.indexOf(F("SM="));

View File

@ -155,7 +155,7 @@ class Toki {
return (tick == TickT::active);
}
void printTime(const Time& t) {
Serial.printf_P(PSTR("%u,%03u\n"),t.sec,t.ms);
void printTime(const Time& t, Print &dest = Serial) {
dest.printf_P(PSTR("%u,%03u\n"),t.sec,t.ms);
}
};

View File

@ -213,7 +213,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
//compatibilityVersionByte:
byte version = udpIn[11];
DEBUG_PRINT(F("UDP packet version: ")); DEBUG_PRINTLN(version);
DEBUG_PRINTF_P(PSTR("UDP packet version: %d\n"), (int)version);
// if we are not part of any sync group ignore message
if (version < 9) {
@ -256,7 +256,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
if (applyEffects && currentPlaylist >= 0) unloadPlaylist();
if (version > 10 && (receiveSegmentOptions || receiveSegmentBounds)) {
unsigned numSrcSegs = udpIn[39];
DEBUG_PRINT(F("UDP segments: ")); DEBUG_PRINTLN(numSrcSegs);
DEBUG_PRINTF_P(PSTR("UDP segments: %d\n"), numSrcSegs);
// are we syncing bounds and slave has more active segments than master?
if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) {
DEBUG_PRINTLN(F("Removing excessive segments."));
@ -270,13 +270,13 @@ void parseNotifyPacket(uint8_t *udpIn) {
for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) {
unsigned ofs = 41 + i*udpIn[40]; //start of segment offset byte
unsigned id = udpIn[0 +ofs];
DEBUG_PRINT(F("UDP segment received: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("UDP segment received: %u\n"), id);
if (id > strip.getSegmentsNum()) break;
else if (id == strip.getSegmentsNum()) {
if (receiveSegmentBounds && id < strip.getMaxSegments()) strip.appendSegment();
else break;
}
DEBUG_PRINT(F("UDP segment check: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("UDP segment check: %u\n"), id);
Segment& selseg = strip.getSegment(id);
// if we are not syncing bounds skip unselected segments
if (selseg.isActive() && !(selseg.isSelected() || receiveSegmentBounds)) continue;
@ -290,7 +290,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
id += inactiveSegs; // adjust id
}
}
DEBUG_PRINT(F("UDP segment processing: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("UDP segment processing: %u\n"), id);
uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
@ -307,14 +307,14 @@ void parseNotifyPacket(uint8_t *udpIn) {
selseg.options = (selseg.options & 0x0071U) | (udpIn[9 +ofs] & 0x0E); // ignore selected, freeze, reset & transitional
selseg.setOpacity(udpIn[10+ofs]);
if (applyEffects) {
DEBUG_PRINT(F("Apply effect: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("Apply effect: %u\n"), id);
selseg.setMode(udpIn[11+ofs]);
selseg.speed = udpIn[12+ofs];
selseg.intensity = udpIn[13+ofs];
selseg.palette = udpIn[14+ofs];
}
if (receiveNotificationColor || !someSel) {
DEBUG_PRINT(F("Apply color: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("Apply color: %u\n"), id);
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]));
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]));
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]));
@ -324,10 +324,10 @@ void parseNotifyPacket(uint8_t *udpIn) {
// when applying synced options ignore selected as it may be used as indicator of which segments to sync
// freeze, reset should never be synced
// LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2)
DEBUG_PRINT(F("Apply options: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("Apply options: %u\n"), id);
selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
if (applyEffects) {
DEBUG_PRINT(F("Apply sliders: ")); DEBUG_PRINTLN(id);
DEBUG_PRINTF_P(PSTR("Apply sliders: %u\n"), id);
selseg.custom1 = udpIn[29+ofs];
selseg.custom2 = udpIn[30+ofs];
selseg.custom3 = udpIn[31+ofs] & 0x1F;
@ -561,7 +561,7 @@ void handleNotifications()
//wled notifier, ignore if realtime packets active
if (udpIn[0] == 0 && !realtimeMode && receiveGroups)
{
DEBUG_PRINT(F("UDP notification from: ")); DEBUG_PRINTLN(notifierUdp.remoteIP());
DEBUG_PRINTF_P(PSTR("UDP notification from: %d.%d.%d.%d\n"), notifierUdp.remoteIP()[0], notifierUdp.remoteIP()[1], notifierUdp.remoteIP()[2], notifierUdp.remoteIP()[3]);
parseNotifyPacket(udpIn);
return;
}

View File

@ -159,7 +159,7 @@ void WLED::loop()
if (millis() - heapTime > 15000) {
uint32_t heap = ESP.getFreeHeap();
if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) {
DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap);
DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap);
forceReconnect = true;
strip.resetSegments(); // remove all but one segments from memory
} else if (heap < MIN_HEAP_SIZE) {
@ -264,9 +264,9 @@ void WLED::loop()
if (loopMillis > maxLoopMillis) maxLoopMillis = loopMillis;
if (millis() - debugTime > 29999) {
DEBUG_PRINTLN(F("---DEBUG INFO---"));
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("Runtime: %lu\n"), millis());
DEBUG_PRINTF_P(PSTR("Unix time: %u,%03u\n"), toki.getTime().sec, toki.getTime().ms);
DEBUG_PRINTF_P(PSTR("Free heap: %u\n"), ESP.getFreeHeap());
#if defined(ARDUINO_ARCH_ESP32)
if (psramFound()) {
DEBUG_PRINTF_P(PSTR("PSRAM: %dkB/%dkB\n"), ESP.getFreePsram()/1024, ESP.getPsramSize()/1024);
@ -276,21 +276,21 @@ void WLED::loop()
#endif
DEBUG_PRINTF_P(PSTR("Wifi state: %d\n"), WiFi.status());
#ifndef WLED_DISABLE_ESPNOW
DEBUG_PRINT(F("ESP-NOW state: ")); DEBUG_PRINTLN(statusESPNow);
DEBUG_PRINTF_P(PSTR("ESP-NOW state: %u\n"), statusESPNow);
#endif
if (WiFi.status() != lastWifiState) {
wifiStateChangedTime = millis();
}
lastWifiState = WiFi.status();
DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime);
DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime);
DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP());
DEBUG_PRINTF_P(PSTR("State time: %lu\n"), wifiStateChangedTime);
DEBUG_PRINTF_P(PSTR("NTP last sync: %lu\n"), ntpLastSyncTime);
DEBUG_PRINTF_P(PSTR("Client IP: %u.%u.%u.%u\n"), Network.localIP()[0], Network.localIP()[1], Network.localIP()[2], Network.localIP()[3]);
if (loops > 0) { // avoid division by zero
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 30);
DEBUG_PRINT(F("Loop time[ms]: ")); DEBUG_PRINT(avgLoopMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxLoopMillis);
DEBUG_PRINT(F("UM time[ms]: ")); DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis);
DEBUG_PRINT(F("Strip time[ms]: ")); DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis);
DEBUG_PRINTF_P(PSTR("Loops/sec: %u\n"), loops / 30);
DEBUG_PRINTF_P(PSTR("Loop time[ms]: %u/%lu\n"), avgLoopMillis/loops, maxLoopMillis);
DEBUG_PRINTF_P(PSTR("UM time[ms]: %u/%lu\n"), avgUsermodMillis/loops, maxUsermodMillis);
DEBUG_PRINTF_P(PSTR("Strip time[ms]:%u/%lu\n"), avgStripMillis/loops, maxStripMillis);
}
strip.printSize();
loops = 0;
@ -358,45 +358,35 @@ void WLED::setup()
Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC
#endif
DEBUG_PRINTLN();
DEBUG_PRINT(F("---WLED "));
DEBUG_PRINT(versionString);
DEBUG_PRINT(F(" "));
DEBUG_PRINT(VERSION);
DEBUG_PRINTLN(F(" INIT---"));
DEBUG_PRINTF_P(PSTR("---WLED %s %u INIT---\n"), versionString, VERSION);
DEBUG_PRINTLN();
#ifdef ARDUINO_ARCH_ESP32
DEBUG_PRINT(F("esp32 "));
DEBUG_PRINTLN(ESP.getSdkVersion());
DEBUG_PRINTF_P(PSTR("esp32 %s\n"), ESP.getSdkVersion());
#if defined(ESP_ARDUINO_VERSION)
//DEBUG_PRINTF_P(PSTR("arduino-esp32 0x%06x\n"), ESP_ARDUINO_VERSION);
DEBUG_PRINTF_P(PSTR("arduino-esp32 v%d.%d.%d\n"), int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // availeable since v2.0.0
DEBUG_PRINTF_P(PSTR("arduino-esp32 v%d.%d.%d\n"), int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // available since v2.0.0
#else
DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail.
#endif
DEBUG_PRINT(F("CPU: ")); DEBUG_PRINT(ESP.getChipModel());
DEBUG_PRINT(F(" rev.")); DEBUG_PRINT(ESP.getChipRevision());
DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getChipCores()); DEBUG_PRINT(F(" core(s)"));
DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINTLN(F("MHz."));
DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024);
DEBUG_PRINT(F("MB, Mode ")); DEBUG_PRINT(ESP.getFlashChipMode());
DEBUG_PRINTF_P(PSTR("CPU: %s rev.%d, %d core(s), %d MHz.\n"), ESP.getChipModel(), (int)ESP.getChipRevision(), ESP.getChipCores(), ESP.getCpuFreqMHz());
DEBUG_PRINTF_P(PSTR("FLASH: %d MB, Mode %d "), (ESP.getFlashChipSize()/1024)/1024, (int)ESP.getFlashChipMode());
#ifdef WLED_DEBUG
switch (ESP.getFlashChipMode()) {
// missing: Octal modes
case FM_QIO: DEBUG_PRINT(F(" (QIO)")); break;
case FM_QOUT: DEBUG_PRINT(F(" (QOUT)"));break;
case FM_DIO: DEBUG_PRINT(F(" (DIO)")); break;
case FM_DOUT: DEBUG_PRINT(F(" (DOUT)"));break;
case FM_QIO: DEBUG_PRINT(F("(QIO)")); break;
case FM_QOUT: DEBUG_PRINT(F("(QOUT)"));break;
case FM_DIO: DEBUG_PRINT(F("(DIO)")); break;
case FM_DOUT: DEBUG_PRINT(F("(DOUT)"));break;
default: break;
}
#endif
DEBUG_PRINT(F(", speed ")); DEBUG_PRINT(ESP.getFlashChipSpeed()/1000000);DEBUG_PRINTLN(F("MHz."));
DEBUG_PRINTF_P(PSTR(", speed %u MHz.\n"), ESP.getFlashChipSpeed()/1000000);
#else
DEBUG_PRINT(F("esp8266 @ ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINT(F("MHz.\nCore: "));
DEBUG_PRINTLN(ESP.getCoreVersion());
DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024); DEBUG_PRINTLN(F(" MB"));
DEBUG_PRINTF_P(PSTR("esp8266 @ %u MHz.\nCore: %s\n"), ESP.getCpuFreqMHz(), ESP.getCoreVersion());
DEBUG_PRINTF_P(PSTR("FLASH: %u MB\n"), (ESP.getFlashChipSize()/1024)/1024);
#endif
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#if defined(ARDUINO_ARCH_ESP32)
// BOARD_HAS_PSRAM also means that a compiler flag "-mfix-esp32-psram-cache-issue" was used and so PSRAM is safe to use on rev.1 ESP32
@ -405,7 +395,7 @@ void WLED::setup()
if (!psramSafe) DEBUG_PRINTLN(F("Not using PSRAM."));
#endif
pDoc = new PSRAMDynamicJsonDocument((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE);
DEBUG_PRINT(F("JSON buffer allocated: ")); DEBUG_PRINTLN((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE);
DEBUG_PRINTF_P(PSTR("JSON buffer allocated: %u\n"), (psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE);
// if the above fails requestJsonBufferLock() will always return false preventing crashes
if (psramFound()) {
DEBUG_PRINTF_P(PSTR("PSRAM: %dkB/%dkB\n"), ESP.getFreePsram()/1024, ESP.getPsramSize()/1024);
@ -427,7 +417,7 @@ void WLED::setup()
DEBUG_PRINTLN(F("Registering usermods ..."));
registerUsermods();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
bool fsinit = false;
DEBUGFS_PRINTLN(F("Mount FS"));
@ -457,7 +447,7 @@ void WLED::setup()
DEBUG_PRINTLN(F("Reading config"));
deserializeConfigFromFS();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#if defined(STATUSLED) && STATUSLED>=0
if (!pinManager.isPinAllocated(STATUSLED)) {
@ -469,12 +459,12 @@ void WLED::setup()
DEBUG_PRINTLN(F("Initializing strip"));
beginStrip();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
DEBUG_PRINTLN(F("Usermods setup"));
userSetup();
usermods.setup();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0)
showWelcomePage = true;
@ -537,13 +527,13 @@ void WLED::setup()
// HTTP server page init
DEBUG_PRINTLN(F("initServer"));
initServer();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#ifndef WLED_DISABLE_INFRARED
// init IR
DEBUG_PRINTLN(F("initIR"));
initIR();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#endif
// Seed FastLED random functions with an esp random value, which already works properly at this point.
@ -654,11 +644,11 @@ bool WLED::initEthernet()
return false;
}
if (ethernetType >= WLED_NUM_ETH_TYPES) {
DEBUG_PRINT(F("initE: Ignoring attempt for invalid ethernetType ")); DEBUG_PRINTLN(ethernetType);
DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType);
return false;
}
DEBUG_PRINT(F("initE: Attempting ETH config: ")); DEBUG_PRINTLN(ethernetType);
DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType);
// Ethernet initialization should only succeed once -- else reboot required
ethernet_settings es = ethernetBoards[ethernetType];
@ -689,9 +679,7 @@ bool WLED::initEthernet()
pinsToAllocate[9].pin = 17;
pinsToAllocate[9].isOutput = true;
} else {
DEBUG_PRINT(F("initE: Failing due to invalid eth_clk_mode ("));
DEBUG_PRINT(es.eth_clk_mode);
DEBUG_PRINTLN(")");
DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode);
return false;
}

View File

@ -3,12 +3,12 @@
/*
Main sketch, global variable declarations
@title WLED project sketch
@version 0.15.0-b4
@version 0.15.0-b5
@author Christian Schwinne
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2407070
#define VERSION 2409100
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG

View File

@ -163,8 +163,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename,
}
request->_tempFile = WLED_FS.open(finalname, "w");
DEBUG_PRINT(F("Uploading "));
DEBUG_PRINTLN(finalname);
DEBUG_PRINTF_P(PSTR("Uploading %s\n"), finalname.c_str());
if (finalname.equals(FPSTR(getPresetsFileName()))) presetsModifiedTime = toki.second();
}
if (len) {
@ -466,7 +465,7 @@ void initServer()
//called when the url is not defined here, ajax-in; get-settings
server.onNotFound([](AsyncWebServerRequest *request){
DEBUG_PRINT(F("Not-Found HTTP call: ")); DEBUG_PRINTLN(request->url());
DEBUG_PRINTF_P(PSTR("Not-Found HTTP call: %s\n"), request->url().c_str());
if (captivePortal(request)) return;
//make API CORS compatible

View File

@ -125,7 +125,7 @@ void sendDataWs(AsyncWebSocketClient * client)
// the following may no longer be necessary as heap management has been fixed by @willmmiles in AWS
size_t heap1 = ESP.getFreeHeap();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#ifdef ESP8266
if (len>heap1) {
DEBUG_PRINTLN(F("Out of memory (WS)!"));
@ -135,7 +135,7 @@ void sendDataWs(AsyncWebSocketClient * client)
AsyncWebSocketBuffer buffer(len);
#ifdef ESP8266
size_t heap2 = ESP.getFreeHeap();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#else
size_t heap2 = 0; // ESP32 variants do not have the same issue and will work without checking heap allocation
#endif
@ -150,11 +150,11 @@ void sendDataWs(AsyncWebSocketClient * client)
DEBUG_PRINT(F("Sending WS data "));
if (client) {
client->text(std::move(buffer));
DEBUG_PRINTLN(F("to a single client."));
client->text(std::move(buffer));
} else {
ws.textAll(std::move(buffer));
DEBUG_PRINTLN(F("to multiple clients."));
ws.textAll(std::move(buffer));
}
releaseJSONBufferLock();

View File

@ -222,8 +222,7 @@ void appendGPIOinfo() {
void getSettingsJS(byte subPage, char* dest)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec
DEBUG_PRINT(F("settings resp"));
DEBUG_PRINTLN(subPage);
DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage);
obuf = dest;
olen = 0;