diff --git a/CHANGELOG.md b/CHANGELOG.md index b2801b866..5b0f64cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cd50b133d..06c221fca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. diff --git a/package-lock.json b/package-lock.json index 38f2099d6..ce2e7a464 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index e3c12629c..e47a46b26 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/platformio.ini b/platformio.ini index 5ebc43f55..016d0d18d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -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 diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 281fba25d..59f6d9271 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -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');")); } /* diff --git a/usermods/Temperature/platformio_override.ini b/usermods/Temperature/platformio_override.ini index 0e354da9e..cc86367fd 100644 --- a/usermods/Temperature/platformio_override.ini +++ b/usermods/Temperature/platformio_override.ini @@ -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 \ No newline at end of file + paulstoffregen/OneWire@~2.3.8 \ No newline at end of file diff --git a/usermods/Temperature/readme.md b/usermods/Temperature/readme.md index b41e3e119..3d65be7eb 100644 --- a/usermods/Temperature/readme.md +++ b/usermods/Temperature/readme.md @@ -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 \ No newline at end of file +* 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 \ No newline at end of file diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index 32208a4fa..916f7da98 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -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 - # - # 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 . - */ - - // 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 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(""); - 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()) { - en = um[FPSTR(_enabled)].as(); - } 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 ... - input.remove(0,10); - String tmp = input.substring(0,input.indexOf(' ')); - - int light_id = -1; - for (uint16_t i=0; iavailable(); - 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 + # + # 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 . + */ + + // 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 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(""); + 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()) { + en = um[FPSTR(_enabled)].as(); + } 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 ... + input.remove(0,10); + String tmp = input.substring(0,input.indexOf(' ')); + + int light_id = -1; + for (uint16_t i=0; iavailable(); + BobClear(); + } + } + } +} diff --git a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h index 5c2fac0d4..111df2967 100644 --- a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h +++ b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h @@ -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 { diff --git a/wled00/FX.h b/wled00/FX.h index b1b1fbcb7..3c28274d6 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -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 customPalettes; // TODO: move custom palettes out of WS2812FX class struct { diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 44919f925..26ec1d608 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -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; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d652435b7..447ceaab9 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -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); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 47a4aab0f..b20095d4c 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -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 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 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 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& 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; igetLength(); return len; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index c9bb5dd8e..24f10f0a7 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -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 _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 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 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 getLEDTypes(void); + static std::vector 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 getLEDTypes(void); + static std::vector 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 getLEDTypes(void); + static std::vector 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 getLEDTypes(void); + static std::vector 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; iisVirtual()) j++; return j; diff --git a/wled00/button.cpp b/wled00/button.cpp index 8b366e055..b5a4e9436 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -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 diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index bcb6f7aad..72aaf14b9 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -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); } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ebea7ea05..478a0a277 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -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); diff --git a/wled00/const.h b/wled00/const.h index c9f62bda4..a0ebeebb1 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -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 diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index f9bfd3dca..b3188f0d8 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -806,11 +806,12 @@ Swap: mA
Use per-output limiter:

Advanced

- Palette blending: + Palette wrapping: