From 6655e2664e81e59a5ffbedf3a4121ab0f7c61d95 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Thu, 29 Aug 2024 13:18:48 +0200 Subject: [PATCH 01/50] rebase to bus-config --- wled00/FX_fcn.cpp | 39 +++++++++++++++++++++++++++------------ wled00/bus_manager.cpp | 2 +- wled00/bus_manager.h | 9 +++------ wled00/const.h | 7 +++++++ 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a06d4f843b..69a742c3de 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -44,8 +44,8 @@ */ //factory defaults LED setup -//#define PIXEL_COUNTS 30, 30, 30, 30 -//#define DATA_PINS 16, 1, 3, 4 +//#define PIXEL_COUNTS 30 +//#define DATA_PINS 2 (8266/C3) or 16 //#define DEFAULT_LED_TYPE TYPE_WS2812_RGB #ifndef PIXEL_COUNTS @@ -56,8 +56,8 @@ #define DATA_PINS LEDPIN #endif -#ifndef DEFAULT_LED_TYPE - #define DEFAULT_LED_TYPE TYPE_WS2812_RGB +#ifndef LED_TYPES + #define LED_TYPES DEFAULT_LED_TYPE #endif #ifndef DEFAULT_LED_COLOR_ORDER @@ -1215,17 +1215,30 @@ void WS2812FX::finalizeInit(void) { //if busses failed to load, add default (fresh install, FS issue, ...) if (BusManager::getNumBusses() == 0) { DEBUG_PRINTLN(F("No busses, init default")); + constexpr unsigned defDataTypes[] = {LED_TYPES}; const unsigned defDataPins[] = {DATA_PINS}; const unsigned defCounts[] = {PIXEL_COUNTS}; - const unsigned defNumPins = ((sizeof defDataPins) / (sizeof defDataPins[0])); + const unsigned defNumTypes = ((sizeof defDataTypes) / (sizeof defDataTypes[0])); + constexpr unsigned defNumPins = ((sizeof defDataPins) / (sizeof defDataPins[0])); const unsigned defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); - // if number of pins is divisible by counts, use number of counts to determine number of buses, otherwise use pins - const unsigned defNumBusses = defNumPins > defNumCounts && defNumPins%defNumCounts == 0 ? defNumCounts : defNumPins; - const unsigned pinsPerBus = defNumPins / defNumBusses; + + static_assert(Bus::getNumberOfPins(defDataTypes[0]) <= defNumPins, + "The first LED type configured requires more pins than have been defined!"); + unsigned prevLen = 0; - for (unsigned i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { - uint8_t defPin[5]; // max 5 pins - for (unsigned j = 0; j < pinsPerBus; j++) defPin[j] = defDataPins[i*pinsPerBus + j]; + unsigned pinsIndex = 0; + for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { + uint8_t defPin[OUTPUT_MAX_PINS]; // max 5 pins + // if we have less types than requested outputs and they do not align, use last known type to set current type + unsigned dataType = defDataTypes[(i < defNumTypes) ? i : defNumTypes -1]; + unsigned busPins = Bus::getNumberOfPins(dataType); + // check if we have enough pins left to configure an output of this type + if (pinsIndex + busPins > defNumPins) { + DEBUG_PRINTLN(F("LED outputs misaligned with defined pins. Some pins will remain unused.")); + break; + } + for (unsigned j = 0; j < busPins && j < OUTPUT_MAX_PINS; j++) defPin[j] = defDataPins[pinsIndex + j]; + pinsIndex += busPins; // when booting without config (1st boot) we need to make sure GPIOs defined for LED output don't clash with hardware // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), etc if (pinManager.isPinAllocated(defPin[0])) { @@ -1235,8 +1248,10 @@ void WS2812FX::finalizeInit(void) { unsigned start = prevLen; // if we have less counts than pins and they do not align, use last known count to set current count unsigned count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; + // analog always has length 1 + if (Bus::isPWM(dataType)) count = 1; prevLen += count; - BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); + BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); if (BusManager::add(defCfg) == -1) break; } } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index e5918ce95f..77e60ba4fa 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -673,7 +673,7 @@ void BusNetwork::cleanup(void) { //utility to get the approx. memory usage of a given BusConfig uint32_t BusManager::memUsage(BusConfig &bc) { - if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return 5; + if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; unsigned len = bc.count + bc.skipAmount; unsigned channels = Bus::getNumberOfChannels(bc.type); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 1d1136fd83..f6aa4b5790 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -267,8 +267,8 @@ class BusPwm : public Bus { void cleanup(void) { deallocatePins(); } private: - uint8_t _pins[5]; - uint8_t _pwmdata[5]; + uint8_t _pins[OUTPUT_MAX_PINS]; + uint8_t _pwmdata[OUTPUT_MAX_PINS]; #ifdef ARDUINO_ARCH_ESP32 uint8_t _ledcStart; #endif @@ -346,10 +346,7 @@ struct BusConfig { { refreshReq = (bool) GET_BIT(busType,7); type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh) - size_t nPins = 1; - if (Bus::isVirtual(type)) nPins = 4; //virtual network bus. 4 "pins" store IP address - else if (Bus::is2Pin(type)) nPins = 2; - else if (Bus::isPWM(type)) nPins = Bus::numPWMPins(type); + size_t nPins = Bus::getNumberOfPins(type); for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i]; } diff --git a/wled00/const.h b/wled00/const.h index bdc80aab93..cb50a108fa 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -466,6 +466,9 @@ #define NTP_PACKET_SIZE 48 // size of NTP receive buffer #define NTP_MIN_PACKET_SIZE 48 // min expected size - NTP v4 allows for "extended information" appended to the standard fields +// Maximum number of pins per output. 5 for RGBCCT analog LEDs. +#define OUTPUT_MAX_PINS 5 + //maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses #ifndef MAX_LEDS #ifdef ESP8266 @@ -577,6 +580,10 @@ #endif #endif +#ifndef DEFAULT_LED_TYPE + #define DEFAULT_LED_TYPE TYPE_WS2812_RGB +#endif + #ifndef DEFAULT_LED_COUNT #define DEFAULT_LED_COUNT 30 #endif From fcc344ba995b6c39d8004d440057046fb5ecefa6 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Sun, 1 Sep 2024 21:31:19 +0200 Subject: [PATCH 02/50] add read/only pin logic and check --- wled00/FX_fcn.cpp | 26 +++++++++++++++----------- wled00/const.h | 13 +++++++++++++ wled00/pin_manager.cpp | 23 +++++++++++++++++++++++ wled00/pin_manager.h | 3 +++ wled00/xml.cpp | 20 +++++++++----------- 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 69a742c3de..331ceb0774 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1216,11 +1216,11 @@ void WS2812FX::finalizeInit(void) { if (BusManager::getNumBusses() == 0) { DEBUG_PRINTLN(F("No busses, init default")); constexpr unsigned defDataTypes[] = {LED_TYPES}; - const unsigned defDataPins[] = {DATA_PINS}; - const unsigned defCounts[] = {PIXEL_COUNTS}; - const unsigned defNumTypes = ((sizeof defDataTypes) / (sizeof defDataTypes[0])); + constexpr unsigned defDataPins[] = {DATA_PINS}; + constexpr unsigned defCounts[] = {PIXEL_COUNTS}; + constexpr unsigned defNumTypes = ((sizeof defDataTypes) / (sizeof defDataTypes[0])); constexpr unsigned defNumPins = ((sizeof defDataPins) / (sizeof defDataPins[0])); - const unsigned defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); + constexpr unsigned defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); static_assert(Bus::getNumberOfPins(defDataTypes[0]) <= defNumPins, "The first LED type configured requires more pins than have been defined!"); @@ -1237,14 +1237,18 @@ void WS2812FX::finalizeInit(void) { DEBUG_PRINTLN(F("LED outputs misaligned with defined pins. Some pins will remain unused.")); break; } - for (unsigned j = 0; j < busPins && j < OUTPUT_MAX_PINS; j++) defPin[j] = defDataPins[pinsIndex + j]; - pinsIndex += busPins; - // when booting without config (1st boot) we need to make sure GPIOs defined for LED output don't clash with hardware - // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), etc - if (pinManager.isPinAllocated(defPin[0])) { - defPin[0] = 1; // start with GPIO1 and work upwards - while (pinManager.isPinAllocated(defPin[0]) && defPin[0] < WLED_NUM_PINS) defPin[0]++; + for (unsigned j = 0; j < busPins && j < OUTPUT_MAX_PINS; j++) { + defPin[j] = defDataPins[pinsIndex + j]; + + // when booting without config (1st boot) we need to make sure GPIOs defined for LED output don't clash with hardware + // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), read/only pins, etc. + if (pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) { + defPin[j] = 1; // start with GPIO1 and work upwards + while (pinManager.isPinAllocated(defPin[j]) && pinManager.isReadOnlyPin(defPin[j]) && defPin[j] < WLED_NUM_PINS) defPin[j]++; + } } + pinsIndex += busPins; + unsigned start = prevLen; // if we have less counts than pins and they do not align, use last known count to set current count unsigned count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; diff --git a/wled00/const.h b/wled00/const.h index cb50a108fa..ffefb3ca5e 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -572,6 +572,19 @@ #endif #endif +// List of read only pins. Cannot be used for LED outputs. +#if defined(CONFIG_IDF_TARGET_ESP32S2) + #define READ_ONLY_PINS 46 +#elif defined(CONFIG_IDF_TARGET_ESP32S3) +// none for S3 +#elif defined(CONFIG_IDF_TARGET_ESP32C3) +// none for C3 +#elif defined(ESP32) + #define READ_ONLY_PINS 34,35,36,37,38,39 +#else +// none for ESP8266 +#endif + #ifdef WLED_ENABLE_DMX #if (LEDPIN == 2) #undef LEDPIN diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 0a0f391554..507ce81cd1 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -267,6 +267,29 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const return false; } +unsigned *PinManagerClass::getReadOnlyPins() +{ + #ifdef READ_ONLY_PINS + static unsigned readOnlyPins[] = {READ_ONLY_PINS}; + #elif + static unsigned readOnlyPins[] = 255; + #endif + return readOnlyPins; +} + +bool PinManagerClass::isReadOnlyPin(byte gpio) +{ + const unsigned* pins = PinManagerClass::getReadOnlyPins(); + const unsigned numPins = sizeof(pins) / sizeof(pins[0]); + + for (unsigned i = 0; i < numPins; i++) { + if (pins[i] == gpio) { + return true; + } + } + return false; +} + PinOwner PinManagerClass::getPinOwner(byte gpio) const { if (!isPinOk(gpio, false)) return PinOwner::None; diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index 986964a7f5..b441b89af2 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -112,6 +112,9 @@ class PinManagerClass { // will return false for reserved pins bool isPinOk(byte gpio, bool output = true) const; + static unsigned* getReadOnlyPins(); + static bool isReadOnlyPin(byte gpio); + PinOwner getPinOwner(byte gpio) const; #ifdef ARDUINO_ARCH_ESP32 diff --git a/wled00/xml.cpp b/wled00/xml.cpp index c06b027686..8f8dd9e7d4 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -191,17 +191,15 @@ void appendGPIOinfo() { // add info for read-only GPIO oappend(SET_F("d.ro_gpio=[")); - #if defined(CONFIG_IDF_TARGET_ESP32S2) - oappendi(46); - #elif defined(CONFIG_IDF_TARGET_ESP32S3) - // none for S3 - #elif defined(CONFIG_IDF_TARGET_ESP32C3) - // none for C3 - #elif defined(ESP32) - oappend(SET_F("34,35,36,37,38,39")); - #else - // none for ESP8266 - #endif + const unsigned* readOnlyPins = pinManager.getReadOnlyPins(); + const unsigned numReadOnlyPins = ((sizeof readOnlyPins) / (sizeof readOnlyPins[0])); + for (unsigned i = 0; i < numReadOnlyPins; i++) { + // Ignore 255 + if (readOnlyPins[i] <= WLED_NUM_PINS) { + oappendi(readOnlyPins[i]); + if (i != numReadOnlyPins) oappend(SET_F(",")); + } + } oappend(SET_F("];")); // add info about max. # of pins From c9423454531999027d6b7e50444a51d036cd5794 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Sun, 1 Sep 2024 21:35:09 +0200 Subject: [PATCH 03/50] bug fix --- wled00/pin_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 507ce81cd1..3ba48ead42 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -271,7 +271,7 @@ unsigned *PinManagerClass::getReadOnlyPins() { #ifdef READ_ONLY_PINS static unsigned readOnlyPins[] = {READ_ONLY_PINS}; - #elif + #else static unsigned readOnlyPins[] = 255; #endif return readOnlyPins; From 9bb979f2e8cab910ad0a2ec8a7d3026b1f93413c Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Sun, 1 Sep 2024 21:46:30 +0200 Subject: [PATCH 04/50] bug fix --- wled00/pin_manager.cpp | 4 ++-- wled00/xml.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 3ba48ead42..527e4470c4 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -272,7 +272,7 @@ unsigned *PinManagerClass::getReadOnlyPins() #ifdef READ_ONLY_PINS static unsigned readOnlyPins[] = {READ_ONLY_PINS}; #else - static unsigned readOnlyPins[] = 255; + static unsigned readOnlyPins[] = {255}; #endif return readOnlyPins; } @@ -280,7 +280,7 @@ unsigned *PinManagerClass::getReadOnlyPins() bool PinManagerClass::isReadOnlyPin(byte gpio) { const unsigned* pins = PinManagerClass::getReadOnlyPins(); - const unsigned numPins = sizeof(pins) / sizeof(pins[0]); + const unsigned numPins = (sizeof *pins) / (sizeof pins[0]); for (unsigned i = 0; i < numPins; i++) { if (pins[i] == gpio) { diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 8f8dd9e7d4..dfb3d67df2 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -192,7 +192,7 @@ void appendGPIOinfo() { // add info for read-only GPIO oappend(SET_F("d.ro_gpio=[")); const unsigned* readOnlyPins = pinManager.getReadOnlyPins(); - const unsigned numReadOnlyPins = ((sizeof readOnlyPins) / (sizeof readOnlyPins[0])); + const unsigned numReadOnlyPins = (sizeof *readOnlyPins) / (sizeof readOnlyPins[0]); for (unsigned i = 0; i < numReadOnlyPins; i++) { // Ignore 255 if (readOnlyPins[i] <= WLED_NUM_PINS) { From d79d5dbadd99925d792f907464e8279808438c0a Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Tue, 3 Sep 2024 17:29:38 +0200 Subject: [PATCH 05/50] remove getReadOnlyPins() function --- wled00/pin_manager.cpp | 23 +++++++---------------- wled00/pin_manager.h | 3 +-- wled00/xml.cpp | 16 ++++++++-------- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 527e4470c4..2bd82115f6 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -267,26 +267,17 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const return false; } -unsigned *PinManagerClass::getReadOnlyPins() -{ - #ifdef READ_ONLY_PINS - static unsigned readOnlyPins[] = {READ_ONLY_PINS}; - #else - static unsigned readOnlyPins[] = {255}; - #endif - return readOnlyPins; -} - bool PinManagerClass::isReadOnlyPin(byte gpio) { - const unsigned* pins = PinManagerClass::getReadOnlyPins(); - const unsigned numPins = (sizeof *pins) / (sizeof pins[0]); + #ifdef READ_ONLY_PINS + const unsigned pins[] = {READ_ONLY_PINS}; + const unsigned numPins = ((sizeof pins) / (sizeof pins[0])); - for (unsigned i = 0; i < numPins; i++) { - if (pins[i] == gpio) { - return true; - } + if (gpio <= WLED_NUM_PINS) { + for (unsigned i = 0; i < numPins; i++) if (gpio == pins[i]) return true; } + #endif + return false; } diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index b441b89af2..a8ddf5f751 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -111,8 +111,7 @@ class PinManagerClass { bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None) const; // will return false for reserved pins bool isPinOk(byte gpio, bool output = true) const; - - static unsigned* getReadOnlyPins(); + static bool isReadOnlyPin(byte gpio); PinOwner getPinOwner(byte gpio) const; diff --git a/wled00/xml.cpp b/wled00/xml.cpp index dfb3d67df2..fce453cfc1 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -191,14 +191,14 @@ void appendGPIOinfo() { // add info for read-only GPIO oappend(SET_F("d.ro_gpio=[")); - const unsigned* readOnlyPins = pinManager.getReadOnlyPins(); - const unsigned numReadOnlyPins = (sizeof *readOnlyPins) / (sizeof readOnlyPins[0]); - for (unsigned i = 0; i < numReadOnlyPins; i++) { - // Ignore 255 - if (readOnlyPins[i] <= WLED_NUM_PINS) { - oappendi(readOnlyPins[i]); - if (i != numReadOnlyPins) oappend(SET_F(",")); - } + bool firstPin = true; + for (unsigned i = 0; i < WLED_NUM_PINS; i++) { + if (pinManager.isReadOnlyPin(i)) { + // No comma before the first pin + if (!firstPin) oappend(SET_F(",")); + oappendi(i); + firstPin = false; + } } oappend(SET_F("];")); From c1c707c77ad8f97260557e953d1c7537700f5755 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:38:03 +0200 Subject: [PATCH 06/50] 8266 compatibility builds for older chips (another attempt t o solve #3690 and #3685) some users have reported that releases after 0.14.0 are not working reliably. So we add a few "compat" for 8266 that try to reproduce the buildenv of 0.14.0 as much as possible. * platform and platform_packages from 0.14.0 * not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 * due to smaller IRAM, we had to move some functions back from IRAM to normal flash (may cause slowdown) --- platformio.ini | 56 ++++++++++++++++++++++++++++++++++++++++++++- wled00/FX_2Dfcn.cpp | 6 ++--- wled00/FX_fcn.cpp | 16 ++++++------- wled00/const.h | 8 +++++++ 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5ebc43f559..9888ea1022 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, esp32dev_audioreactive, 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,6 +347,14 @@ 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 @@ -329,6 +369,13 @@ 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 @@ -344,6 +391,13 @@ 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 diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 44919f925c..efae0e5e33 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(uint16_t x, uint16_t 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 @@ -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 bc5c8b0519..7a6fa40b52 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -146,7 +146,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 @@ -170,7 +170,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 @@ -202,7 +202,7 @@ void Segment::resetIfRequired() { reset = false; } -CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { +CRGBPalette16 IRAM_ATTR_YN &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 @@ -417,7 +417,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 IRAM_ATTR_YN Segment::currentMode() const { #ifndef WLED_DISABLE_MODE_BLEND unsigned prog = progress(); if (modeBlending && prog < 0xFFFFU) return _t->_modeT; @@ -425,7 +425,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]; @@ -618,7 +618,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()) { @@ -701,7 +701,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 @@ -895,7 +895,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 diff --git a/wled00/const.h b/wled00/const.h index d5cd049d5e..af6d4a70b1 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -628,4 +628,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 From 8e4f8fcbc8eb069306a7eca3c7750061734da8fc Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Wed, 4 Sep 2024 13:27:04 +0200 Subject: [PATCH 07/50] fix bug in reassignment logic --- wled00/FX_fcn.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 331ceb0774..a737fb5490 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1237,6 +1237,7 @@ void WS2812FX::finalizeInit(void) { DEBUG_PRINTLN(F("LED outputs misaligned with defined pins. Some pins will remain unused.")); break; } + for (unsigned j = 0; j < busPins && j < OUTPUT_MAX_PINS; j++) { defPin[j] = defDataPins[pinsIndex + j]; @@ -1244,7 +1245,7 @@ void WS2812FX::finalizeInit(void) { // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), read/only pins, etc. if (pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) { defPin[j] = 1; // start with GPIO1 and work upwards - while (pinManager.isPinAllocated(defPin[j]) && pinManager.isReadOnlyPin(defPin[j]) && defPin[j] < WLED_NUM_PINS) defPin[j]++; + while ((pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) && defPin[j] < WLED_NUM_PINS) defPin[j]++; } } pinsIndex += busPins; From 329173e1452846a419feb426bcbc041e9163cc93 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Wed, 4 Sep 2024 13:28:43 +0200 Subject: [PATCH 08/50] added complete validation logic for pins and types --- wled00/FX_fcn.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a737fb5490..74d6125643 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -69,6 +69,18 @@ #error "Max segments must be at least max number of busses!" #endif +static constexpr unsigned sumPinsRequired(const unsigned* current, size_t count) { + return (count > 0) ? (Bus::getNumberOfPins(*current) + sumPinsRequired(current+1,count-1)) : 0; +} + +static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTypes, unsigned numPins ) { + // Pins provided < pins required -> always invalid + // Pins provided = pins required -> always valid + // Pins provided > pins required -> last type will repeat until we run out of pins, make sure excess pins modulo last type pins == 0 + return (sumPinsRequired(types, numTypes) > numPins) ? false : + (numPins - sumPinsRequired(types, numTypes)) % Bus::getNumberOfPins(types[numTypes-1]) == 0; +} + /////////////////////////////////////////////////////////////////////////////// // Segment class implementation @@ -1222,9 +1234,9 @@ void WS2812FX::finalizeInit(void) { constexpr unsigned defNumPins = ((sizeof defDataPins) / (sizeof defDataPins[0])); constexpr unsigned defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); - static_assert(Bus::getNumberOfPins(defDataTypes[0]) <= defNumPins, - "The first LED type configured requires more pins than have been defined!"); - + static_assert(validatePinsAndTypes(defDataTypes, defNumTypes, defNumPins), + "The default pin list defined in DATA_PINS does not match the pin requirements for the default buses defined in LED_TYPES"); + unsigned prevLen = 0; unsigned pinsIndex = 0; for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { @@ -1232,7 +1244,9 @@ void WS2812FX::finalizeInit(void) { // if we have less types than requested outputs and they do not align, use last known type to set current type unsigned dataType = defDataTypes[(i < defNumTypes) ? i : defNumTypes -1]; unsigned busPins = Bus::getNumberOfPins(dataType); + // check if we have enough pins left to configure an output of this type + // should never happen due to static assert above if (pinsIndex + busPins > defNumPins) { DEBUG_PRINTLN(F("LED outputs misaligned with defined pins. Some pins will remain unused.")); break; @@ -1245,6 +1259,7 @@ void WS2812FX::finalizeInit(void) { // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), read/only pins, etc. if (pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) { defPin[j] = 1; // start with GPIO1 and work upwards + // @FIX pins are allocated after the loop, so if we reassign to a pin that's already in the array for this output 2 fields will have the same pin while ((pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) && defPin[j] < WLED_NUM_PINS) defPin[j]++; } } From b9080f9479fc18bc1b3ba28ba55ec546ea256e87 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 4 Sep 2024 21:17:21 +0200 Subject: [PATCH 09/50] Mirroring bugfix. --- wled00/FX_2Dfcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index efae0e5e33..df2dc8d066 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -211,7 +211,7 @@ void IRAM_ATTR_YN 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); } } } From 0642b17ab0135bebc15890d8a14b303744311598 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 6 Sep 2024 17:54:36 +0200 Subject: [PATCH 10/50] Bugfix --- usermods/ST7789_display/ST7789_display.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 281fba25de..59f6d9271d 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');")); } /* From 81cec6a25ae6447d3ec8b7169d522ea7992cfb5e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 6 Sep 2024 19:36:24 +0200 Subject: [PATCH 11/50] Update usermod_seven_segment_reloaded.h - prevent array bounds violation (solves #4121) I'm not the maintainer of this usermod, but its obvious that the code might overrun array bounds, so fixing this. --- .../usermod_seven_segment_reloaded.h | 2 ++ 1 file changed, 2 insertions(+) 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 5c2fac0d4d..572d4cebdb 100644 --- a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h +++ b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h @@ -236,6 +236,8 @@ class UsermodSSDR : public Usermod { } 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 ((number < 0) || (countSegments < 0) || (lastSeenLedNr <0)) return; // prevent array out of range access if ((colon && umSSDRColonblink) || umSSDRNumbers[number][countSegments]) { From 340a9f8b762195b10f64ff42af9228e5140bb6b3 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 6 Sep 2024 20:09:25 +0200 Subject: [PATCH 12/50] better bugfix for seven-seg-reloaded * only reject invalid ranges when array access will be actually performed * fixed another stupid pointer arithmetic error Hint: I AM NOT THE MAINTAINER of this usermod. I'm just fixing an obvious coding error without knowing what the usermod really does. --- .../usermod_seven_segment_reloaded.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 572d4cebdb..111df29672 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 @@ class UsermodSSDR : public Usermod { 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) { @@ -237,12 +237,12 @@ class UsermodSSDR : public Usermod { 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 ((number < 0) || (countSegments < 0) || (lastSeenLedNr <0)) return; // prevent array out of range access + 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 { From b4315152e2636244beb78d3b862e2b9ac851f0aa Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 8 Sep 2024 11:07:53 +0200 Subject: [PATCH 13/50] Add numPins() --- wled00/data/settings_leds.htm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 58bd842058..f9bfd3dcad 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -30,6 +30,7 @@ function hasW(t) { return !!(gT(t).c & 0x02); } // has white channel function hasCCT(t) { return !!(gT(t).c & 0x04); } // is white CCT enabled function is16b(t) { return !!(gT(t).c & 0x10); } // is digital 16 bit type + function numPins(t){ return Math.max(gT(t).t.length, 1); } // type length determines number of GPIO pins // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript function loadJS(FILE_URL, async = true) { let scE = d.createElement("script"); @@ -83,7 +84,7 @@ let t = parseInt(d.Sf["LT"+n].value, 10); // LED type SELECT // ignore IP address if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") { - if (t>=80) return; + if (isNet(t)) return; } //check for pin conflicts if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4") @@ -237,7 +238,7 @@ p0d = "Data "+p0d; break; case 'A': // PWM analog - if (gT(t).t.length > 1) p0d = "GPIOs:"; + if (numPins(t) > 1) p0d = "GPIOs:"; off = "Dithering"; break; case 'N': // network @@ -412,7 +413,7 @@ let t = s.value; if (isDig(t) && !isD2P(t)) digitalB++; if (isD2P(t)) twopinB++; - if (isPWM(t)) analogB += t-40; // type defines PWM pins + if (isPWM(t)) analogB += numPins(t); // each GPIO is assigned to a channel if (isVir(t)) virtB++; }); From eb06e575c2ff00aa663ca9d1ee0c5d5ce9ad2bf6 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Tue, 10 Sep 2024 01:03:19 +0200 Subject: [PATCH 14/50] add check for pin reassigned conflict with pin defined for current bus --- wled00/FX_fcn.cpp | 19 +++++++++++++++---- wled00/pin_manager.cpp | 7 +++++++ wled00/pin_manager.h | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 74d6125643..6f218c93f8 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -76,7 +76,7 @@ static constexpr unsigned sumPinsRequired(const unsigned* current, size_t count) static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTypes, unsigned numPins ) { // Pins provided < pins required -> always invalid // Pins provided = pins required -> always valid - // Pins provided > pins required -> last type will repeat until we run out of pins, make sure excess pins modulo last type pins == 0 + // Pins provided > pins required -> valid if excess pins are a product of last type pins since it will be repeated return (sumPinsRequired(types, numTypes) > numPins) ? false : (numPins - sumPinsRequired(types, numTypes)) % Bus::getNumberOfPins(types[numTypes-1]) == 0; } @@ -1240,7 +1240,7 @@ void WS2812FX::finalizeInit(void) { unsigned prevLen = 0; unsigned pinsIndex = 0; for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { - uint8_t defPin[OUTPUT_MAX_PINS]; // max 5 pins + uint8_t defPin[OUTPUT_MAX_PINS]; // if we have less types than requested outputs and they do not align, use last known type to set current type unsigned dataType = defDataTypes[(i < defNumTypes) ? i : defNumTypes -1]; unsigned busPins = Bus::getNumberOfPins(dataType); @@ -1259,8 +1259,19 @@ void WS2812FX::finalizeInit(void) { // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), read/only pins, etc. if (pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) { defPin[j] = 1; // start with GPIO1 and work upwards - // @FIX pins are allocated after the loop, so if we reassign to a pin that's already in the array for this output 2 fields will have the same pin - while ((pinManager.isPinAllocated(defPin[j]) || pinManager.isReadOnlyPin(defPin[j])) && defPin[j] < WLED_NUM_PINS) defPin[j]++; + while ( + ( + pinManager.isPinAllocated(defPin[j]) || + pinManager.isReadOnlyPin(defPin[j]) || + // Check if pin is defined for current bus + pinManager.isPinDefined(defPin[j], defDataPins, pinsIndex + j, pinsIndex + busPins) + ) + && + defPin[j] < WLED_NUM_PINS + ) + { + defPin[j]++; + } } } pinsIndex += busPins; diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 2bd82115f6..814d81c1a9 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -281,6 +281,13 @@ bool PinManagerClass::isReadOnlyPin(byte gpio) return false; } +bool PinManagerClass::isPinDefined(byte gpio, const unsigned *pins, unsigned start, unsigned end) { + for (unsigned i = start; i < end; i++) { + if (pins[i] == gpio) return true; + } + return false; +} + PinOwner PinManagerClass::getPinOwner(byte gpio) const { if (!isPinOk(gpio, false)) return PinOwner::None; diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index a8ddf5f751..1263dc4f4c 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -113,6 +113,7 @@ class PinManagerClass { bool isPinOk(byte gpio, bool output = true) const; static bool isReadOnlyPin(byte gpio); + static bool isPinDefined(byte gpio, const unsigned* pins, unsigned start = 0, unsigned end = WLED_NUM_PINS); PinOwner getPinOwner(byte gpio) const; From 20444ee7d5f6cc255783e66adcb6a3a41806e2b7 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 10 Sep 2024 15:20:34 +0200 Subject: [PATCH 15/50] Debug optimisations --- wled00/button.cpp | 16 +++--- wled00/cfg.cpp | 6 +- wled00/e131.cpp | 8 +-- wled00/json.cpp | 7 +-- wled00/mqtt.cpp | 3 +- wled00/ntp.cpp | 7 +-- wled00/presets.cpp | 11 ++-- wled00/remote.cpp | 3 +- wled00/set.cpp | 10 ++-- wled00/src/dependencies/toki/Toki.h | 4 +- wled00/udp.cpp | 20 +++---- wled00/wled.cpp | 87 +++++++++++++---------------- wled00/wled_server.cpp | 5 +- wled00/ws.cpp | 8 +-- wled00/xml.cpp | 3 +- 15 files changed, 84 insertions(+), 114 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 8b366e055c..b5a4e9436d 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 89076efab6..a6c3ab74de 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -277,9 +277,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 { @@ -290,7 +288,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/e131.cpp b/wled00/e131.cpp index e28750db34..7c074759e7 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -108,13 +108,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ if (e131SkipOutOfSequence) if (seq < e131LastSequenceNumber[previousUniverses] && seq > 20 && e131LastSequenceNumber[previousUniverses] < 250){ - DEBUG_PRINT(F("skipping E1.31 frame (last seq=")); - DEBUG_PRINT(e131LastSequenceNumber[previousUniverses]); - DEBUG_PRINT(F(", current seq=")); - DEBUG_PRINT(seq); - DEBUG_PRINT(F(", universe=")); - DEBUG_PRINT(uni); - DEBUG_PRINTLN(")"); + DEBUG_PRINTF_P(PSTR("skipping E1.31 frame (last seq=%d, current seq=%d, universe=%d)\n"), e131LastSequenceNumber[previousUniverses], seq, uni); return; } e131LastSequenceNumber[previousUniverses] = seq; diff --git a/wled00/json.cpp b/wled00/json.cpp index 01acc7ba37..596bd780e1 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -1144,11 +1144,8 @@ void serveJson(AsyncWebServerRequest* request) DEBUG_PRINTF_P(PSTR("JSON buffer size: %u for request: %d\n"), lDoc.memoryUsage(), subJson); - #ifdef WLED_DEBUG - size_t len = - #endif - response->setLength(); - DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len); + [[maybe_unused]] size_t len = response->setLength(); + DEBUG_PRINTF_P(PSTR("JSON content length: %u\n"), len); request->send(response); } diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 775a4fe582..833e6eb7d4 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -55,8 +55,7 @@ static void onMqttConnect(bool sessionPresent) static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { static char *payloadStr; - DEBUG_PRINT(F("MQTT msg: ")); - DEBUG_PRINTLN(topic); + DEBUG_PRINTF_P(PSTR("MQTT msg: %s\n"), topic); // paranoia check to avoid npe if no payload if (payload==nullptr) { diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 056110a580..7b7dac96e2 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -246,8 +246,7 @@ bool checkNTPResponse() } uint32_t ntpPacketReceivedTime = millis(); - DEBUG_PRINT(F("NTP recv, l=")); - DEBUG_PRINTLN(cb); + DEBUG_PRINTF_P(PSTR("NTP recv, l=%d\n"), cb); byte pbuf[NTP_PACKET_SIZE]; ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer if (!isValidNtpResponse(pbuf)) return false; // verify we have a valid response to client @@ -493,7 +492,7 @@ void calculateSunriseAndSunset() { do { time_t theDay = localTime - retryCount * 86400; // one day back = 86400 seconds minUTC = getSunriseUTC(year(theDay), month(theDay), day(theDay), latitude, longitude, false); - DEBUG_PRINT(F("* sunrise (minutes from UTC) = ")); DEBUG_PRINTLN(minUTC); + DEBUG_PRINTF_P(PSTR("* sunrise (minutes from UTC) = %d\n"), minUTC); retryCount ++; } while ((abs(minUTC) > SUNSET_MAX) && (retryCount <= 3)); @@ -512,7 +511,7 @@ void calculateSunriseAndSunset() { do { time_t theDay = localTime - retryCount * 86400; // one day back = 86400 seconds minUTC = getSunriseUTC(year(theDay), month(theDay), day(theDay), latitude, longitude, true); - DEBUG_PRINT(F("* sunset (minutes from UTC) = ")); DEBUG_PRINTLN(minUTC); + DEBUG_PRINTF_P(PSTR("* sunset (minutes from UTC) = %d\n"), minUTC); retryCount ++; } while ((abs(minUTC) > SUNSET_MAX) && (retryCount <= 3)); diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 2916d337a5..20edfd91e8 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -117,8 +117,7 @@ void initPresetsFile() bool applyPresetFromPlaylist(byte index) { - DEBUG_PRINT(F("Request to apply preset: ")); - DEBUG_PRINTLN(index); + DEBUG_PRINTF_P(PSTR("Request to apply preset: %d\n"), index); presetToApply = index; callModeToApply = CALL_MODE_DIRECT_CHANGE; return true; @@ -127,8 +126,7 @@ bool applyPresetFromPlaylist(byte index) bool applyPreset(byte index, byte callMode) { unloadPlaylist(); // applying a preset unloads the playlist (#3827) - DEBUG_PRINT(F("Request to apply preset: ")); - DEBUG_PRINTLN(index); + DEBUG_PRINTF_P(PSTR("Request to apply preset: %u\n"), index); presetToApply = index; callModeToApply = callMode; return true; @@ -163,8 +161,7 @@ void handlePresets() presetToApply = 0; //clear request for preset callModeToApply = 0; - DEBUG_PRINT(F("Applying preset: ")); - DEBUG_PRINTLN(tmpPreset); + DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset); #ifdef ARDUINO_ARCH_ESP32 if (tmpPreset==255 && tmpRAMbuffer!=nullptr) { @@ -222,7 +219,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj) else sprintf_P(saveName, PSTR("Preset %d"), index); } - DEBUG_PRINT(F("Saving preset (")); DEBUG_PRINT(index); DEBUG_PRINT(F(") ")); DEBUG_PRINTLN(saveName); + DEBUG_PRINTF_P(PSTR("Saving preset (%d) %s\n"), index, saveName); presetToSave = index; playlistSave = false; diff --git a/wled00/remote.cpp b/wled00/remote.cpp index 9d8b94df02..9bc5430c01 100644 --- a/wled00/remote.cpp +++ b/wled00/remote.cpp @@ -186,8 +186,7 @@ void handleRemote(uint8_t *incomingData, size_t len) { } if (len != sizeof(message_structure_t)) { - DEBUG_PRINT(F("Unknown incoming ESP Now message received of length ")); - DEBUG_PRINTLN(len); + DEBUG_PRINTF_P(PSTR("Unknown incoming ESP Now message received of length %u\n"), len); return; } diff --git a/wled00/set.cpp b/wled00/set.cpp index 2811d70885..7814e55d96 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -157,8 +157,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED mA char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max mA if (!request->hasArg(lp)) { - DEBUG_PRINT(F("No data for ")); - DEBUG_PRINTLN(s); + DEBUG_PRINTF_P(PSTR("No data for %d\n"), s); break; } for (int i = 0; i < 5; i++) { @@ -729,7 +728,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) else subObj[name].add(value.toInt()); // we may have an int j++; } - DEBUG_PRINT(F("[")); DEBUG_PRINT(j); DEBUG_PRINT(F("] = ")); DEBUG_PRINTLN(value); + DEBUG_PRINTF_P(PSTR("[%d] = %s\n"), j, value.c_str()); } else { // we are using a hidden field with the same name as our parameter (!before the actual parameter!) // to describe the type of parameter (text,float,int), for boolean parameters the first field contains "off" @@ -748,7 +747,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } else if (type == "int") subObj[name] = value.toInt(); else subObj[name] = value; // text fields } - DEBUG_PRINT(F(" = ")); DEBUG_PRINTLN(value); + DEBUG_PRINTF_P(PSTR(" = %s\n"), value.c_str()); } } usermods.readFromConfig(um); // force change of usermod parameters @@ -809,8 +808,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (!(req.indexOf("win") >= 0)) return false; int pos = 0; - DEBUG_PRINT(F("API req: ")); - DEBUG_PRINTLN(req); + DEBUG_PRINTF_P(PSTR("API req: %s\n"), req.c_str()); //segment select (sets main segment) pos = req.indexOf(F("SM=")); diff --git a/wled00/src/dependencies/toki/Toki.h b/wled00/src/dependencies/toki/Toki.h index e7f12a4530..0e849d3c2f 100644 --- a/wled00/src/dependencies/toki/Toki.h +++ b/wled00/src/dependencies/toki/Toki.h @@ -155,7 +155,7 @@ class Toki { return (tick == TickT::active); } - void printTime(const Time& t) { - Serial.printf_P(PSTR("%u,%03u\n"),t.sec,t.ms); + void printTime(const Time& t, Print &dest = Serial) { + dest.printf_P(PSTR("%u,%03u\n"),t.sec,t.ms); } }; \ No newline at end of file diff --git a/wled00/udp.cpp b/wled00/udp.cpp index c2221e2cf6..d030b66559 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -213,7 +213,7 @@ void parseNotifyPacket(uint8_t *udpIn) { //compatibilityVersionByte: byte version = udpIn[11]; - DEBUG_PRINT(F("UDP packet version: ")); DEBUG_PRINTLN(version); + DEBUG_PRINTF_P(PSTR("UDP packet version: %d\n"), (int)version); // if we are not part of any sync group ignore message if (version < 9) { @@ -256,7 +256,7 @@ void parseNotifyPacket(uint8_t *udpIn) { if (applyEffects && currentPlaylist >= 0) unloadPlaylist(); if (version > 10 && (receiveSegmentOptions || receiveSegmentBounds)) { unsigned numSrcSegs = udpIn[39]; - DEBUG_PRINT(F("UDP segments: ")); DEBUG_PRINTLN(numSrcSegs); + DEBUG_PRINTF_P(PSTR("UDP segments: %d\n"), numSrcSegs); // are we syncing bounds and slave has more active segments than master? if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) { DEBUG_PRINTLN(F("Removing excessive segments.")); @@ -270,13 +270,13 @@ void parseNotifyPacket(uint8_t *udpIn) { for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) { unsigned ofs = 41 + i*udpIn[40]; //start of segment offset byte unsigned id = udpIn[0 +ofs]; - DEBUG_PRINT(F("UDP segment received: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("UDP segment received: %u\n"), id); if (id > strip.getSegmentsNum()) break; else if (id == strip.getSegmentsNum()) { if (receiveSegmentBounds && id < strip.getMaxSegments()) strip.appendSegment(); else break; } - DEBUG_PRINT(F("UDP segment check: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("UDP segment check: %u\n"), id); Segment& selseg = strip.getSegment(id); // if we are not syncing bounds skip unselected segments if (selseg.isActive() && !(selseg.isSelected() || receiveSegmentBounds)) continue; @@ -290,7 +290,7 @@ void parseNotifyPacket(uint8_t *udpIn) { id += inactiveSegs; // adjust id } } - DEBUG_PRINT(F("UDP segment processing: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("UDP segment processing: %u\n"), id); uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]); uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]); @@ -307,14 +307,14 @@ void parseNotifyPacket(uint8_t *udpIn) { selseg.options = (selseg.options & 0x0071U) | (udpIn[9 +ofs] & 0x0E); // ignore selected, freeze, reset & transitional selseg.setOpacity(udpIn[10+ofs]); if (applyEffects) { - DEBUG_PRINT(F("Apply effect: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("Apply effect: %u\n"), id); selseg.setMode(udpIn[11+ofs]); selseg.speed = udpIn[12+ofs]; selseg.intensity = udpIn[13+ofs]; selseg.palette = udpIn[14+ofs]; } if (receiveNotificationColor || !someSel) { - DEBUG_PRINT(F("Apply color: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("Apply color: %u\n"), id); selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs])); selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs])); selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs])); @@ -324,10 +324,10 @@ void parseNotifyPacket(uint8_t *udpIn) { // when applying synced options ignore selected as it may be used as indicator of which segments to sync // freeze, reset should never be synced // LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2) - DEBUG_PRINT(F("Apply options: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("Apply options: %u\n"), id); selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset if (applyEffects) { - DEBUG_PRINT(F("Apply sliders: ")); DEBUG_PRINTLN(id); + DEBUG_PRINTF_P(PSTR("Apply sliders: %u\n"), id); selseg.custom1 = udpIn[29+ofs]; selseg.custom2 = udpIn[30+ofs]; selseg.custom3 = udpIn[31+ofs] & 0x1F; @@ -561,7 +561,7 @@ void handleNotifications() //wled notifier, ignore if realtime packets active if (udpIn[0] == 0 && !realtimeMode && receiveGroups) { - DEBUG_PRINT(F("UDP notification from: ")); DEBUG_PRINTLN(notifierUdp.remoteIP()); + DEBUG_PRINTF_P(PSTR("UDP notification from: %d.%d.%d.%d\n"), notifierUdp.remoteIP()[0], notifierUdp.remoteIP()[1], notifierUdp.remoteIP()[2], notifierUdp.remoteIP()[3]); parseNotifyPacket(udpIn); return; } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index a6143eee6f..840c06bf7e 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -159,7 +159,7 @@ void WLED::loop() if (millis() - heapTime > 15000) { uint32_t heap = ESP.getFreeHeap(); if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { - DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap); + DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap); forceReconnect = true; strip.resetSegments(); // remove all but one segments from memory } else if (heap < MIN_HEAP_SIZE) { @@ -264,9 +264,9 @@ void WLED::loop() if (loopMillis > maxLoopMillis) maxLoopMillis = loopMillis; if (millis() - debugTime > 29999) { DEBUG_PRINTLN(F("---DEBUG INFO---")); - DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis()); - DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime()); - DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("Runtime: %u\n"), millis()); + DEBUG_PRINTF_P(PSTR("Unix time: %u,%03u\n"), toki.getTime().sec, toki.getTime().ms); + DEBUG_PRINTF_P(PSTR("Free heap: %u\n"), ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) if (psramFound()) { DEBUG_PRINTF_P(PSTR("PSRAM: %dkB/%dkB\n"), ESP.getFreePsram()/1024, ESP.getPsramSize()/1024); @@ -276,21 +276,21 @@ void WLED::loop() #endif DEBUG_PRINTF_P(PSTR("Wifi state: %d\n"), WiFi.status()); #ifndef WLED_DISABLE_ESPNOW - DEBUG_PRINT(F("ESP-NOW state: ")); DEBUG_PRINTLN(statusESPNow); + DEBUG_PRINTF_P(PSTR("ESP-NOW state: %u\n"), statusESPNow); #endif if (WiFi.status() != lastWifiState) { wifiStateChangedTime = millis(); } lastWifiState = WiFi.status(); - DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime); - DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime); - DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP()); + DEBUG_PRINTF_P(PSTR("State time: %u\n"), wifiStateChangedTime); + DEBUG_PRINTF_P(PSTR("NTP last sync: %u\n"), ntpLastSyncTime); + DEBUG_PRINTF_P(PSTR("Client IP: %u.%u.%u.%u\n"), Network.localIP()[0], Network.localIP()[1], Network.localIP()[2], Network.localIP()[3]); if (loops > 0) { // avoid division by zero - DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 30); - DEBUG_PRINT(F("Loop time[ms]: ")); DEBUG_PRINT(avgLoopMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxLoopMillis); - DEBUG_PRINT(F("UM time[ms]: ")); DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis); - DEBUG_PRINT(F("Strip time[ms]: ")); DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis); + DEBUG_PRINTF_P(PSTR("Loops/sec: %u\n"), loops / 30); + DEBUG_PRINTF_P(PSTR("Loop time[ms]: %u/%u\n"), avgLoopMillis/loops, maxLoopMillis); + DEBUG_PRINTF_P(PSTR("UM time[ms]: %u/%u\n"), avgUsermodMillis/loops, maxUsermodMillis); + DEBUG_PRINTF_P(PSTR("Strip time[ms]:%u/%u\n"), avgStripMillis/loops, maxStripMillis); } strip.printSize(); loops = 0; @@ -358,45 +358,38 @@ void WLED::setup() Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC #endif DEBUG_PRINTLN(); - DEBUG_PRINT(F("---WLED ")); - DEBUG_PRINT(versionString); - DEBUG_PRINT(F(" ")); - DEBUG_PRINT(VERSION); - DEBUG_PRINTLN(F(" INIT---")); + DEBUG_PRINTF_P(PSTR("---WLED %s %u INIT---\n"), versionString, VERSION); + DEBUG_PRINTLN(); #ifdef ARDUINO_ARCH_ESP32 - DEBUG_PRINT(F("esp32 ")); - DEBUG_PRINTLN(ESP.getSdkVersion()); + DEBUG_PRINTF_P(PSTR("esp32 %s\n"), ESP.getSdkVersion()); #if defined(ESP_ARDUINO_VERSION) - //DEBUG_PRINTF_P(PSTR("arduino-esp32 0x%06x\n"), ESP_ARDUINO_VERSION); - DEBUG_PRINTF_P(PSTR("arduino-esp32 v%d.%d.%d\n"), int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // availeable since v2.0.0 + DEBUG_PRINTF_P(PSTR("arduino-esp32 v%d.%d.%d\n"), int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // available since v2.0.0 #else DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail. #endif - DEBUG_PRINT(F("CPU: ")); DEBUG_PRINT(ESP.getChipModel()); - DEBUG_PRINT(F(" rev.")); DEBUG_PRINT(ESP.getChipRevision()); - DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getChipCores()); DEBUG_PRINT(F(" core(s)")); - DEBUG_PRINT(F(", ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINTLN(F("MHz.")); - DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024); - DEBUG_PRINT(F("MB, Mode ")); DEBUG_PRINT(ESP.getFlashChipMode()); + DEBUG_PRINTF_P(PSTR("CPU: "), ESP.getChipModel()); + DEBUG_PRINTF_P(PSTR(" rev."), ESP.getChipRevision()); + DEBUG_PRINTF_P(PSTR(", %d core(s)"), ESP.getChipCores()); + DEBUG_PRINTF_P(PSTR(", %d MHz.\n"), ESP.getCpuFreqMHz()); + DEBUG_PRINTF_P(PSTR("FLASH: %dMB, Mode %d "), (ESP.getFlashChipSize()/1024)/1024, ESP.getFlashChipMode()); #ifdef WLED_DEBUG switch (ESP.getFlashChipMode()) { // missing: Octal modes - case FM_QIO: DEBUG_PRINT(F(" (QIO)")); break; - case FM_QOUT: DEBUG_PRINT(F(" (QOUT)"));break; - case FM_DIO: DEBUG_PRINT(F(" (DIO)")); break; - case FM_DOUT: DEBUG_PRINT(F(" (DOUT)"));break; + case FM_QIO: DEBUG_PRINT(F("(QIO)")); break; + case FM_QOUT: DEBUG_PRINT(F("(QOUT)"));break; + case FM_DIO: DEBUG_PRINT(F("(DIO)")); break; + case FM_DOUT: DEBUG_PRINT(F("(DOUT)"));break; default: break; } #endif - DEBUG_PRINT(F(", speed ")); DEBUG_PRINT(ESP.getFlashChipSpeed()/1000000);DEBUG_PRINTLN(F("MHz.")); + DEBUG_PRINTF_P(PSTR(", speed %u MHz.\n"), ESP.getFlashChipSpeed()/1000000); #else - DEBUG_PRINT(F("esp8266 @ ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINT(F("MHz.\nCore: ")); - DEBUG_PRINTLN(ESP.getCoreVersion()); - DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024); DEBUG_PRINTLN(F(" MB")); + DEBUG_PRINTF_P(PSTR("esp8266 @ %u MHz.\nCore: %s\n"), ESP.getCpuFreqMHz(), ESP.getCoreVersion()); + DEBUG_PRINTF_P(PSTR("FLASH: %u MB\n"), (ESP.getFlashChipSize()/1024)/1024); #endif - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) // BOARD_HAS_PSRAM also means that a compiler flag "-mfix-esp32-psram-cache-issue" was used and so PSRAM is safe to use on rev.1 ESP32 @@ -405,7 +398,7 @@ void WLED::setup() if (!psramSafe) DEBUG_PRINTLN(F("Not using PSRAM.")); #endif pDoc = new PSRAMDynamicJsonDocument((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE); - DEBUG_PRINT(F("JSON buffer allocated: ")); DEBUG_PRINTLN((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE); + DEBUG_PRINTF_P(PSTR("JSON buffer allocated: %u\n"), (psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE); // if the above fails requestJsonBufferLock() will always return false preventing crashes if (psramFound()) { DEBUG_PRINTF_P(PSTR("PSRAM: %dkB/%dkB\n"), ESP.getFreePsram()/1024, ESP.getPsramSize()/1024); @@ -427,7 +420,7 @@ void WLED::setup() DEBUG_PRINTLN(F("Registering usermods ...")); registerUsermods(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); bool fsinit = false; DEBUGFS_PRINTLN(F("Mount FS")); @@ -457,7 +450,7 @@ void WLED::setup() DEBUG_PRINTLN(F("Reading config")); deserializeConfigFromFS(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); #if defined(STATUSLED) && STATUSLED>=0 if (!pinManager.isPinAllocated(STATUSLED)) { @@ -469,12 +462,12 @@ void WLED::setup() DEBUG_PRINTLN(F("Initializing strip")); beginStrip(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); DEBUG_PRINTLN(F("Usermods setup")); userSetup(); usermods.setup(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0) showWelcomePage = true; @@ -537,13 +530,13 @@ void WLED::setup() // HTTP server page init DEBUG_PRINTLN(F("initServer")); initServer(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); #ifndef WLED_DISABLE_INFRARED // init IR DEBUG_PRINTLN(F("initIR")); initIR(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); #endif // Seed FastLED random functions with an esp random value, which already works properly at this point. @@ -654,11 +647,11 @@ bool WLED::initEthernet() return false; } if (ethernetType >= WLED_NUM_ETH_TYPES) { - DEBUG_PRINT(F("initE: Ignoring attempt for invalid ethernetType ")); DEBUG_PRINTLN(ethernetType); + DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType); return false; } - DEBUG_PRINT(F("initE: Attempting ETH config: ")); DEBUG_PRINTLN(ethernetType); + DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType); // Ethernet initialization should only succeed once -- else reboot required ethernet_settings es = ethernetBoards[ethernetType]; @@ -689,9 +682,7 @@ bool WLED::initEthernet() pinsToAllocate[9].pin = 17; pinsToAllocate[9].isOutput = true; } else { - DEBUG_PRINT(F("initE: Failing due to invalid eth_clk_mode (")); - DEBUG_PRINT(es.eth_clk_mode); - DEBUG_PRINTLN(")"); + DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode); return false; } diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index d184e98789..291f6f5fcb 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -163,8 +163,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename, } request->_tempFile = WLED_FS.open(finalname, "w"); - DEBUG_PRINT(F("Uploading ")); - DEBUG_PRINTLN(finalname); + DEBUG_PRINTF_P(PSTR("Uploading %s\n"), finalname.c_str()); if (finalname.equals(FPSTR(getPresetsFileName()))) presetsModifiedTime = toki.second(); } if (len) { @@ -466,7 +465,7 @@ void initServer() //called when the url is not defined here, ajax-in; get-settings server.onNotFound([](AsyncWebServerRequest *request){ - DEBUG_PRINT(F("Not-Found HTTP call: ")); DEBUG_PRINTLN(request->url()); + DEBUG_PRINTF_P(PSTR("Not-Found HTTP call: %s\n"), request->url().c_str()); if (captivePortal(request)) return; //make API CORS compatible diff --git a/wled00/ws.cpp b/wled00/ws.cpp index 3dec548f4c..45640b68ce 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -125,7 +125,7 @@ void sendDataWs(AsyncWebSocketClient * client) // the following may no longer be necessary as heap management has been fixed by @willmmiles in AWS size_t heap1 = ESP.getFreeHeap(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); #ifdef ESP8266 if (len>heap1) { DEBUG_PRINTLN(F("Out of memory (WS)!")); @@ -135,7 +135,7 @@ void sendDataWs(AsyncWebSocketClient * client) AsyncWebSocketBuffer buffer(len); #ifdef ESP8266 size_t heap2 = ESP.getFreeHeap(); - DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); #else size_t heap2 = 0; // ESP32 variants do not have the same issue and will work without checking heap allocation #endif @@ -150,11 +150,11 @@ void sendDataWs(AsyncWebSocketClient * client) DEBUG_PRINT(F("Sending WS data ")); if (client) { - client->text(std::move(buffer)); DEBUG_PRINTLN(F("to a single client.")); + client->text(std::move(buffer)); } else { - ws.textAll(std::move(buffer)); DEBUG_PRINTLN(F("to multiple clients.")); + ws.textAll(std::move(buffer)); } releaseJSONBufferLock(); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 25c0c6298d..6c3ee83dc7 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -224,8 +224,7 @@ void appendGPIOinfo() { void getSettingsJS(byte subPage, char* dest) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec - DEBUG_PRINT(F("settings resp")); - DEBUG_PRINTLN(subPage); + DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage); obuf = dest; olen = 0; From fd00e5eaae9a587d3cf5950465f786a5f8ed60e0 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 10 Sep 2024 15:23:27 +0200 Subject: [PATCH 16/50] LED settings text update --- wled00/data/settings_leds.htm | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index b7d2d18a7d..06bcf3e6e3 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -805,12 +805,13 @@

LED & Hardware setup

Automatically limits brightness to stay close to the limit.
Keep at <1A if poweing LEDs directly from the ESP 5V pin!
+ If using multiple outputs it is recommended to use per-output limiter.
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.
Maximum PSU Current: mA
Use per-output limiter: