diff --git a/CHANGELOG.md b/CHANGELOG.md index 17c37c530..2d3a683b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,27 @@ ## WLED changelog -#### Build 2309120 till build 2201060 +#### Build 2309120 till build 2401270 - WLED version 0.15.0-a0 +- BREAKING: Effect: updated Palette effect to support 2D (#3683 by @TripleWhy) +- "SuperSync" from WLED MM (by @MoonModules) +- Effect: DNA Spiral Effect Speed Fix (#3723 by @Derek4aty1) +- Fix for #3693 +- Orange flash fix (#3196) for transitions +- Add own background image upload (#3596 by @WoodyLetsCode) +- WLED time overrides (`WLED_NTP_ENABLED`, `WLED_TIMEZONE`, `WLED_UTC_OFFSET`, `WLED_LAT` and `WLED_LON`) +- Better sorting and naming of static palettes (by @WoodyLetsCode) +- ANIMartRIX usermod and effects (#3673 by @netmindz) +- Use canvas instead of CSS gradient for liveview (#3621 by @zanhecht) +- Fix for #3672 +- ColoOrderMap W channel swap (color order overrides now have W swap) +- En-/disable LED maps when receiving realtime data (#3554 by @ezcGman) +- Added PWM frequency selection to UI (Settings) +- Automatically build UI before compiling (#3598, #3666 by @WoodyLetsCode) +- Internal: Added *suspend* API to `strip` (`WS2812FX class`) +- Possible fix for #3589 & partial fix for #3605 +- MPU6050 upgrade (#3654 by @willmmiles) +- UI internals (#3656 by @WoodyLetsCode) +- ColorPicker fix (#3658 by @WoodyLetsCode) - Global JSON buffer guarding (#3648 by @willmmiles, resolves #3641, #3312, #3367, #3637, #3646, #3447) - Effect: Fireworks 1D (fix for matrix trailing strip) - BREAKING: Reduced number of segments (12) on ESP8266 due to less available RAM diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index 43648b588..910e0cae2 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -87,7 +87,7 @@ class MyExampleUsermod : public Usermod { * readFromConfig() is called prior to setup() * You can use it to initialize variables, sensors or similar. */ - void setup() { + void setup() override { // do your set-up here //Serial.println("Hello from my usermod!"); initDone = true; @@ -98,7 +98,7 @@ class MyExampleUsermod : public Usermod { * connected() is called every time the WiFi is (re)connected * Use it to initialize network interfaces */ - void connected() { + void connected() override { //Serial.println("Connected to WiFi!"); } @@ -113,7 +113,7 @@ class MyExampleUsermod : public Usermod { * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. * Instead, use a timer check as shown here. */ - void loop() { + void loop() override { // if usermod is disabled or called during strip updating just exit // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly if (!enabled || strip.isUpdating()) return; @@ -131,7 +131,7 @@ class MyExampleUsermod : public Usermod { * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - void addToJsonInfo(JsonObject& root) + void addToJsonInfo(JsonObject& root) override { // if "u" object does not exist yet wee need to create it JsonObject user = root["u"]; @@ -156,7 +156,7 @@ class MyExampleUsermod : public Usermod { * 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) + void addToJsonState(JsonObject& root) override { if (!initDone || !enabled) return; // prevent crash on boot applyPreset() @@ -171,7 +171,7 @@ class MyExampleUsermod : public Usermod { * 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) + void readFromJsonState(JsonObject& root) override { if (!initDone) return; // prevent crash on boot applyPreset() @@ -220,7 +220,7 @@ class MyExampleUsermod : public Usermod { * * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ - void addToConfig(JsonObject& root) + void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; @@ -253,7 +253,7 @@ class MyExampleUsermod : public Usermod { * * This function is guaranteed to be called on boot, but could also be called every time settings are updated */ - bool readFromConfig(JsonObject& root) + bool readFromConfig(JsonObject& root) override { // default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor // setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed) @@ -285,7 +285,7 @@ class MyExampleUsermod : public Usermod { * it may add additional metadata for certain entry fields (adding drop down is possible) * be careful not to add too much as oappend() buffer is limited to 3k */ - void appendConfigData() + void appendConfigData() override { oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'(this is a great config value)');")); oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');")); @@ -300,7 +300,7 @@ class MyExampleUsermod : public Usermod { * 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() + void handleOverlayDraw() override { //strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black } @@ -311,7 +311,7 @@ class MyExampleUsermod : public Usermod { * will prevent button working in a default way. * Replicating button.cpp */ - bool handleButton(uint8_t b) { + bool handleButton(uint8_t b) override { yield(); // ignore certain button types as they may have other consequences if (!enabled @@ -334,7 +334,7 @@ class MyExampleUsermod : public Usermod { * handling of MQTT message * topic only contains stripped topic (part after /wled/MAC) */ - bool onMqttMessage(char* topic, char* payload) { + bool onMqttMessage(char* topic, char* payload) override { // check if we received a command //if (strlen(topic) == 8 && strncmp_P(topic, PSTR("/command"), 8) == 0) { // String action = payload; @@ -355,7 +355,7 @@ class MyExampleUsermod : public Usermod { /** * onMqttConnect() is called when MQTT connection is established */ - void onMqttConnect(bool sessionPresent) { + void onMqttConnect(bool sessionPresent) override { // do any MQTT related initialisation here //publishMqtt("I am alive!"); } @@ -366,7 +366,7 @@ class MyExampleUsermod : public Usermod { * onStateChanged() is used to detect WLED state change * @mode parameter is CALL_MODE_... parameter used for notifications */ - void onStateChange(uint8_t mode) { + void onStateChange(uint8_t mode) override { // do something if WLED state changed (color, brightness, effect, preset, etc) } @@ -375,7 +375,7 @@ class MyExampleUsermod : public Usermod { * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() + uint16_t getId() override { return USERMOD_ID_EXAMPLE; } diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 4d0777037..2e909ae0e 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -117,7 +117,7 @@ public: * setup() is called once at boot. WiFi is not yet connected at this point. * You can use it to initialize variables, sensors or similar. */ - void setup(); + void setup() override; /** * connected() is called every time the WiFi is (re)connected @@ -128,24 +128,24 @@ public: /** * onMqttConnect() is called when MQTT connection is established */ - void onMqttConnect(bool sessionPresent); + void onMqttConnect(bool sessionPresent) override; /** * loop() is called continuously. Here you can check for events, read sensors, etc. */ - void loop(); + void loop() override; /** * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * * Add PIR sensor state and switch off timer duration to jsoninfo */ - void addToJsonInfo(JsonObject &root); + void addToJsonInfo(JsonObject &root) override; /** * onStateChanged() is used to detect WLED state change */ - void onStateChange(uint8_t mode); + void onStateChange(uint8_t mode) override; /** * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). @@ -157,17 +157,17 @@ public: * 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); + void readFromJsonState(JsonObject &root) override; /** * provide the changeable values */ - void addToConfig(JsonObject &root); + void addToConfig(JsonObject &root) override; /** * provide UI information and allow extending UI options */ - void appendConfigData(); + void appendConfigData() override; /** * restore the changeable values @@ -175,13 +175,13 @@ public: * * The function should return true if configuration was successfully loaded or false if there was no configuration. */ - bool readFromConfig(JsonObject &root); + bool readFromConfig(JsonObject &root) override; /** * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() { return USERMOD_ID_PIRSWITCH; } + uint16_t getId() override { return USERMOD_ID_PIRSWITCH; } }; // strings to reduce flash memory usage (used more than twice) diff --git a/usermods/PWM_fan/usermod_PWM_fan.h b/usermods/PWM_fan/usermod_PWM_fan.h index 05b6d9b3b..1b78cfd4c 100644 --- a/usermods/PWM_fan/usermod_PWM_fan.h +++ b/usermods/PWM_fan/usermod_PWM_fan.h @@ -188,7 +188,7 @@ class PWMFanUsermod : public Usermod { // gets called once at boot. Do all initialization that doesn't depend on // network here - void setup() { + void setup() override { #ifdef USERMOD_DALLASTEMPERATURE // This Usermod requires Temperature usermod tempUM = (UsermodTemperature*) usermods.lookup(USERMOD_ID_TEMPERATURE); @@ -203,12 +203,12 @@ class PWMFanUsermod : public Usermod { // gets called every time WiFi is (re-)connected. Initialize own network // interfaces here - void connected() {} + void connected() override {} /* * Da loop. */ - void loop() { + void loop() override { if (!enabled || strip.isUpdating()) return; unsigned long now = millis(); @@ -223,7 +223,7 @@ class PWMFanUsermod : public Usermod { * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - void addToJsonInfo(JsonObject& root) { + void addToJsonInfo(JsonObject& root) override { JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); @@ -272,7 +272,7 @@ class PWMFanUsermod : public Usermod { * 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) { + void readFromJsonState(JsonObject& root) override { if (!initDone) return; // prevent crash on boot applyPreset() JsonObject usermod = root[FPSTR(_name)]; if (!usermod.isNull()) { @@ -305,7 +305,7 @@ class PWMFanUsermod : public Usermod { * * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ - void addToConfig(JsonObject& root) { + void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname top[FPSTR(_enabled)] = enabled; top[FPSTR(_pwmPin)] = pwmPin; @@ -328,7 +328,7 @@ class PWMFanUsermod : public Usermod { * * The function should return true if configuration was successfully loaded or false if there was no configuration. */ - bool readFromConfig(JsonObject& root) { + bool readFromConfig(JsonObject& root) override { int8_t newTachoPin = tachoPin; int8_t newPwmPin = pwmPin; @@ -380,7 +380,7 @@ class PWMFanUsermod : public Usermod { * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() { + uint16_t getId() override { return USERMOD_ID_PWM_FAN; } }; diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 59e9cd231..281fba25d 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -132,7 +132,7 @@ class St7789DisplayUsermod : public Usermod { * setup() is called once at boot. WiFi is not yet connected at this point. * You can use it to initialize variables, sensors or similar. */ - void setup() + void setup() override { PinManagerPinType spiPins[] = { { spi_mosi, true }, { spi_miso, false}, { spi_sclk, true } }; if (!pinManager.allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { enabled = false; return; } @@ -162,7 +162,7 @@ class St7789DisplayUsermod : public Usermod { * connected() is called every time the WiFi is (re)connected * Use it to initialize network interfaces */ - void connected() { + void connected() override { //Serial.println("Connected to WiFi!"); } @@ -176,7 +176,7 @@ class St7789DisplayUsermod : public Usermod { * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. * Instead, use a timer check as shown here. */ - void loop() { + void loop() override { char buff[LINE_BUFFER_SIZE]; // Check if we time interval for redrawing passes. @@ -316,7 +316,7 @@ class St7789DisplayUsermod : public Usermod { * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - void addToJsonInfo(JsonObject& root) + void addToJsonInfo(JsonObject& root) override { JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); @@ -330,7 +330,7 @@ class St7789DisplayUsermod : public Usermod { * 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) + void addToJsonState(JsonObject& root) override { //root["user0"] = userVar0; } @@ -340,7 +340,7 @@ class St7789DisplayUsermod : public Usermod { * 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) + void readFromJsonState(JsonObject& root) override { //userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); @@ -361,7 +361,7 @@ class St7789DisplayUsermod : public Usermod { * * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ - void addToConfig(JsonObject& root) + void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject("ST7789"); JsonArray pins = top.createNestedArray("pin"); @@ -373,7 +373,7 @@ class St7789DisplayUsermod : public Usermod { } - void appendConfigData() { + void appendConfigData() override { 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');")); @@ -388,7 +388,7 @@ class St7789DisplayUsermod : public Usermod { * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) */ - bool readFromConfig(JsonObject& root) + bool readFromConfig(JsonObject& root) override { //JsonObject top = root["top"]; //userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot) @@ -400,7 +400,7 @@ class St7789DisplayUsermod : public Usermod { * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() + uint16_t getId() override { return USERMOD_ID_ST7789_DISPLAY; } diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index 1c2d67dee..4d4f04368 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -76,26 +76,26 @@ class UsermodTemperature : public Usermod { inline float getTemperatureF() { return temperature * 1.8f + 32.0f; } float getTemperature(); const char *getTemperatureUnit(); - uint16_t getId() { return USERMOD_ID_TEMPERATURE; } + uint16_t getId() override { return USERMOD_ID_TEMPERATURE; } - void setup(); - void loop(); - //void connected(); + void setup() override; + void loop() override; + //void connected() override; #ifndef WLED_DISABLE_MQTT - void onMqttConnect(bool sessionPresent); + void onMqttConnect(bool sessionPresent) override; #endif - //void onUpdateBegin(bool init); + //void onUpdateBegin(bool init) override; - //bool handleButton(uint8_t b); - //void handleOverlayDraw(); + //bool handleButton(uint8_t b) override; + //void handleOverlayDraw() override; - void addToJsonInfo(JsonObject& root); - //void addToJsonState(JsonObject &root); - //void readFromJsonState(JsonObject &root); - void addToConfig(JsonObject &root); - bool readFromConfig(JsonObject &root); + void addToJsonInfo(JsonObject& root) override; + //void addToJsonState(JsonObject &root) override; + //void readFromJsonState(JsonObject &root) override; + void addToConfig(JsonObject &root) override; + bool readFromConfig(JsonObject &root) override; - void appendConfigData(); + void appendConfigData() override; }; //Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013 diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 55fe0169d..50555ca54 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1094,7 +1094,7 @@ class AudioReactive : public Usermod { * You can use it to initialize variables, sensors or similar. * It is called *AFTER* readFromConfig() */ - void setup() + void setup() override { disableSoundProcessing = true; // just to be sure if (!initDone) { @@ -1217,7 +1217,7 @@ class AudioReactive : public Usermod { * connected() is called every time the WiFi is (re)connected * Use it to initialize network interfaces */ - void connected() + void connected() override { if (udpSyncConnected) { // clean-up: if open, close old UDP sync connection udpSyncConnected = false; @@ -1244,7 +1244,7 @@ class AudioReactive : public Usermod { * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. * Instead, use a timer check as shown here. */ - void loop() + void loop() override { static unsigned long lastUMRun = millis(); @@ -1375,7 +1375,7 @@ class AudioReactive : public Usermod { } - bool getUMData(um_data_t **data) + bool getUMData(um_data_t **data) override { if (!data || !enabled) return false; // no pointer provided by caller or not enabled -> exit *data = um_data; @@ -1383,7 +1383,7 @@ class AudioReactive : public Usermod { } - void onUpdateBegin(bool init) + void onUpdateBegin(bool init) override { #ifdef WLED_DEBUG fftTime = sampleTime = 0; @@ -1438,7 +1438,7 @@ class AudioReactive : public Usermod { * handleButton() can be used to override default button behaviour. Returning true * will prevent button working in a default way. */ - bool handleButton(uint8_t b) { + bool handleButton(uint8_t b) override { yield(); // crude way of determining if audio input is analog // better would be for AudioSource to implement getType() @@ -1461,7 +1461,7 @@ class AudioReactive : public Usermod { * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - void addToJsonInfo(JsonObject& root) + void addToJsonInfo(JsonObject& root) override { char myStringBuffer[16]; // buffer for snprintf() JsonObject user = root["u"]; @@ -1600,7 +1600,7 @@ class AudioReactive : public Usermod { * 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) + void addToJsonState(JsonObject& root) override { if (!initDone) return; // prevent crash on boot applyPreset() JsonObject usermod = root[FPSTR(_name)]; @@ -1615,7 +1615,7 @@ class AudioReactive : public Usermod { * 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) + void readFromJsonState(JsonObject& root) override { if (!initDone) return; // prevent crash on boot applyPreset() bool prevEnabled = enabled; @@ -1640,7 +1640,7 @@ class AudioReactive : public Usermod { } } - void onStateChange(uint8_t callMode) { + void onStateChange(uint8_t callMode) override { if (initDone && enabled && addPalettes && palettes==0 && strip.customPalettes.size()<10) { // if palettes were removed during JSON call re-add them createAudioPalettes(); @@ -1682,7 +1682,7 @@ class AudioReactive : public Usermod { * * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ - void addToConfig(JsonObject& root) + void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; @@ -1735,7 +1735,7 @@ class AudioReactive : public Usermod { * * This function is guaranteed to be called on boot, but could also be called every time settings are updated */ - bool readFromConfig(JsonObject& root) + bool readFromConfig(JsonObject& root) override { JsonObject top = root[FPSTR(_name)]; bool configComplete = !top.isNull(); @@ -1786,7 +1786,7 @@ class AudioReactive : public Usermod { } - void appendConfigData() + void appendConfigData() override { oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) @@ -1841,7 +1841,7 @@ class AudioReactive : public Usermod { * 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() + //void handleOverlayDraw() override //{ //strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black //} @@ -1851,7 +1851,7 @@ class AudioReactive : public Usermod { * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() + uint16_t getId() override { return USERMOD_ID_AUDIOREACTIVE; } diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index a1e257758..55803a24d 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -187,7 +187,7 @@ class BobLightUsermod : public Usermod { public: - void setup() { + void setup() override { uint16_t totalLights = bottom + left + top + right; if ( totalLights > strip.getLengthTotal() ) { DEBUG_PRINTLN(F("BobLight: Too many lights.")); @@ -202,14 +202,14 @@ class BobLightUsermod : public Usermod { initDone = true; } - void connected() { + 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() { + void loop() override { if (!enabled || strip.isUpdating()) return; if (millis() - lastTime > 10) { lastTime = millis(); @@ -225,7 +225,7 @@ class BobLightUsermod : public Usermod { * 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) { + bool onMqttMessage(char* topic, char* payload) override { //if (strlen(topic) == 6 && strncmp_P(topic, PSTR("/subtopic"), 6) == 0) { // String action = payload; // if (action == "on") { @@ -242,7 +242,7 @@ class BobLightUsermod : public Usermod { /** * subscribe to MQTT topic for controlling usermod */ - void onMqttConnect(bool sessionPresent) { + void onMqttConnect(bool sessionPresent) override { //char subuf[64]; //if (mqttDeviceTopic[0] != 0) { // strcpy(subuf, mqttDeviceTopic); @@ -252,7 +252,7 @@ class BobLightUsermod : public Usermod { } #endif - void addToJsonInfo(JsonObject& root) + void addToJsonInfo(JsonObject& root) override { JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); @@ -273,7 +273,7 @@ class BobLightUsermod : public Usermod { * 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) + void addToJsonState(JsonObject& root) override { } @@ -281,7 +281,7 @@ class BobLightUsermod : public Usermod { * 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) { + void readFromJsonState(JsonObject& root) override { if (!initDone) return; // prevent crash on boot applyPreset() bool en = enabled; JsonObject um = root[FPSTR(_name)]; @@ -304,7 +304,7 @@ class BobLightUsermod : public Usermod { } } - void appendConfigData() { + 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);")); @@ -315,7 +315,7 @@ class BobLightUsermod : public Usermod { oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field } - void addToConfig(JsonObject& root) { + void addToConfig(JsonObject& root) override { JsonObject umData = root.createNestedObject(FPSTR(_name)); umData[FPSTR(_enabled)] = enabled; umData[F("port")] = bobPort; @@ -326,7 +326,7 @@ class BobLightUsermod : public Usermod { umData[F("pct")] = pct; } - bool readFromConfig(JsonObject& root) { + bool readFromConfig(JsonObject& root) override { JsonObject umData = root[FPSTR(_name)]; bool configComplete = !umData.isNull(); @@ -355,11 +355,11 @@ class BobLightUsermod : public Usermod { * 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() { + void handleOverlayDraw() override { //strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black } - uint16_t getId() { return USERMOD_ID_BOBLIGHT; } + uint16_t getId() override { return USERMOD_ID_BOBLIGHT; } }; @@ -445,7 +445,7 @@ void BobLightUsermod::pollBob() { //strip.setPixelColor(light_id, RGBW32(red, green, blue, 0)); setRealtimePixel(light_id, red, green, blue, 0); } // currently no support for interpolation or speed, we just ignore this - } else if (input.startsWith(F("sync"))) { + } else if (input.startsWith("sync")) { BobSync(); } else { // Client sent gibberish diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 1342ab6dc..22fa6496d 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -143,7 +143,7 @@ class MultiRelay : public Usermod { * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - inline uint16_t getId() { return USERMOD_ID_MULTI_RELAY; } + inline uint16_t getId() override { return USERMOD_ID_MULTI_RELAY; } /** * switch relay on/off @@ -161,22 +161,22 @@ class MultiRelay : public Usermod { * setup() is called once at boot. WiFi is not yet connected at this point. * You can use it to initialize variables, sensors or similar. */ - void setup(); + void setup() override; /** * connected() is called every time the WiFi is (re)connected * Use it to initialize network interfaces */ - inline void connected() { InitHtmlAPIHandle(); } + inline void connected() override { InitHtmlAPIHandle(); } /** * loop() is called continuously. Here you can check for events, read sensors, etc. */ - void loop(); + void loop() override; #ifndef WLED_DISABLE_MQTT - bool onMqttMessage(char* topic, char* payload); - void onMqttConnect(bool sessionPresent); + bool onMqttMessage(char* topic, char* payload) override; + void onMqttConnect(bool sessionPresent) override; #endif /** @@ -184,31 +184,31 @@ class MultiRelay : public Usermod { * will prevent button working in a default way. * Replicating button.cpp */ - bool handleButton(uint8_t b); + bool handleButton(uint8_t b) override; /** * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. */ - void addToJsonInfo(JsonObject &root); + void addToJsonInfo(JsonObject &root) override; /** * 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); + 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); + void readFromJsonState(JsonObject &root) override; /** * provide the changeable values */ - void addToConfig(JsonObject &root); + void addToConfig(JsonObject &root) override; - void appendConfigData(); + void appendConfigData() override; /** * restore the changeable values @@ -216,7 +216,7 @@ class MultiRelay : public Usermod { * * The function should return true if configuration was successfully loaded or false if there was no configuration. */ - bool readFromConfig(JsonObject &root); + bool readFromConfig(JsonObject &root) override; }; diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index 48dab8f0c..40136a92d 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -211,16 +211,16 @@ class FourLineDisplayUsermod : public Usermod { // gets called once at boot. Do all initialization that doesn't depend on // network here - void setup(); + void setup() override; // gets called every time WiFi is (re-)connected. Initialize own network // interfaces here - void connected(); + void connected() override; /** * Da loop. */ - void loop(); + void loop() override; //function to update lastredraw inline void updateRedrawTime() { lastRedraw = millis(); } @@ -287,28 +287,28 @@ class FourLineDisplayUsermod : public Usermod { */ bool handleButton(uint8_t b); - void onUpdateBegin(bool init); + void onUpdateBegin(bool init) override; /* * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - //void addToJsonInfo(JsonObject& root); + //void addToJsonInfo(JsonObject& root) override; /* * 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); + //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); + //void readFromJsonState(JsonObject& root) override; - void appendConfigData(); + void appendConfigData() override; /* * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. @@ -324,7 +324,7 @@ class FourLineDisplayUsermod : public Usermod { * * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ - void addToConfig(JsonObject& root); + void addToConfig(JsonObject& root) override; /* * readFromConfig() can be used to read back the custom settings you added with addToConfig(). @@ -334,13 +334,13 @@ class FourLineDisplayUsermod : public Usermod { * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) */ - bool readFromConfig(JsonObject& root); + bool readFromConfig(JsonObject& root) override; /* * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() { + uint16_t getId() override { return USERMOD_ID_FOUR_LINE_DISP; } }; diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 858e16540..adea86774 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -285,7 +285,7 @@ class RotaryEncoderUIUsermod : public Usermod { * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() { return USERMOD_ID_ROTARY_ENC_UI; } + uint16_t getId() override { return USERMOD_ID_ROTARY_ENC_UI; } /** * Enable/Disable the usermod */ @@ -300,7 +300,7 @@ class RotaryEncoderUIUsermod : public Usermod { * setup() is called once at boot. WiFi is not yet connected at this point. * You can use it to initialize variables, sensors or similar. */ - void setup(); + void setup() override; /** * connected() is called every time the WiFi is (re)connected @@ -311,11 +311,11 @@ class RotaryEncoderUIUsermod : public Usermod { /** * loop() is called continuously. Here you can check for events, read sensors, etc. */ - void loop(); + void loop() override; #ifndef WLED_DISABLE_MQTT - //bool onMqttMessage(char* topic, char* payload); - //void onMqttConnect(bool sessionPresent); + //bool onMqttMessage(char* topic, char* payload) override; + //void onMqttConnect(bool sessionPresent) override; #endif /** @@ -323,31 +323,31 @@ class RotaryEncoderUIUsermod : public Usermod { * will prevent button working in a default way. * Replicating button.cpp */ - //bool handleButton(uint8_t b); + //bool handleButton(uint8_t b) override; /** * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. */ - //void addToJsonInfo(JsonObject &root); + //void addToJsonInfo(JsonObject &root) override; /** * 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); + //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); + //void readFromJsonState(JsonObject &root) override; /** * provide the changeable values */ - void addToConfig(JsonObject &root); + void addToConfig(JsonObject &root) override; - void appendConfigData(); + void appendConfigData() override; /** * restore the changeable values @@ -355,7 +355,7 @@ class RotaryEncoderUIUsermod : public Usermod { * * The function should return true if configuration was successfully loaded or false if there was no configuration. */ - bool readFromConfig(JsonObject &root); + bool readFromConfig(JsonObject &root) override; // custom methods void displayNetworkInfo(); diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.h index a83b9fe78..c4e1fd504 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.h @@ -67,8 +67,8 @@ class WireguardUsermod : public Usermod { JsonObject top = root.createNestedObject(F("WireGuard")); top[F("host")] = endpoint_address; top[F("port")] = endpoint_port; - top[F("ip")] = local_ip.toString(); - top[F("psk")] = preshared_key; + top["ip"] = local_ip.toString(); + top["psk"] = preshared_key; top[F("pem")] = private_key; top[F("pub")] = public_key; top[F("tz")] = posix_tz; @@ -77,11 +77,11 @@ class WireguardUsermod : public Usermod { bool readFromConfig(JsonObject& root) { JsonObject top = root[F("WireGuard")]; - if (top["host"].isNull() || top["port"].isNull() || top["ip"].isNull() || top["pem"].isNull() || top["pub"].isNull() || top["tz"].isNull()) { + if (top[F("host")].isNull() || top[F("port")].isNull() || top["ip"].isNull() || top[F("pem")].isNull() || top[F("pub")].isNull() || top[F("tz")].isNull()) { is_enabled = false; return false; } else { - const char* host = top["host"]; + const char* host = top[F("host")]; strncpy(endpoint_address, host, 100); const char* ip_s = top["ip"]; @@ -89,16 +89,16 @@ class WireguardUsermod : public Usermod { sscanf(ip_s, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]); local_ip = IPAddress(ip[0], ip[1], ip[2], ip[3]); - const char* pem = top["pem"]; + const char* pem = top[F("pem")]; strncpy(private_key, pem, 45); - const char* pub = top["pub"]; + const char* pub = top[F("pub")]; strncpy(public_key, pub, 45); - const char* tz = top["tz"]; + const char* tz = top[F("tz")]; strncpy(posix_tz, tz, 150); - endpoint_port = top["port"]; + endpoint_port = top[F("port")]; if (!top["psk"].isNull()) { const char* psk = top["psk"]; diff --git a/usermods/word-clock-matrix/usermod_word_clock_matrix.h b/usermods/word-clock-matrix/usermod_word_clock_matrix.h index 582563004..506c1275e 100644 --- a/usermods/word-clock-matrix/usermod_word_clock_matrix.h +++ b/usermods/word-clock-matrix/usermod_word_clock_matrix.h @@ -325,8 +325,8 @@ public: void addToConfig(JsonObject& root) { JsonObject modName = root.createNestedObject("id"); - modName["mdns"] = "wled-word-clock"; - modName["name"] = "WLED WORD CLOCK"; + modName[F("mdns")] = "wled-word-clock"; + modName[F("name")] = "WLED WORD CLOCK"; } uint16_t getId() diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a27fc4fbe..a6303810f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1848,10 +1848,10 @@ uint16_t mode_lightning(void) { } SEGENV.aux1--; - SEGENV.step = millis(); + SEGENV.step = strip.now; //return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds } else { - if (millis() - SEGENV.step > SEGENV.aux0) { + if (strip.now - SEGENV.step > SEGENV.aux0) { SEGENV.aux1--; if (SEGENV.aux1 < 2) SEGENV.aux1 = 0; @@ -1859,7 +1859,7 @@ uint16_t mode_lightning(void) { if (SEGENV.aux1 == 2) { SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes } - SEGENV.step = millis(); + SEGENV.step = strip.now; } } return FRAMETIME; @@ -1929,22 +1929,102 @@ static const char _data_FX_MODE_JUGGLE[] PROGMEM = "Juggle@!,Trail;;!;;sx=64,ix= uint16_t mode_palette() { - uint16_t counter = 0; - if (SEGMENT.speed != 0) - { - counter = (strip.now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; - counter = counter >> 8; - } + // Set up some compile time constants so that we can handle integer and float based modes using the same code base. +#ifdef ESP8266 + using mathType = int32_t; + using wideMathType = int64_t; + using angleType = uint16_t; + constexpr mathType sInt16Scale = 0x7FFF; + constexpr mathType maxAngle = 0x8000; + constexpr mathType staticRotationScale = 256; + constexpr mathType animatedRotationScale = 1; + constexpr int16_t (*sinFunction)(uint16_t) = &sin16; + constexpr int16_t (*cosFunction)(uint16_t) = &cos16; +#else + using mathType = float; + using wideMathType = float; + using angleType = float; + constexpr mathType sInt16Scale = 1.0f; + constexpr mathType maxAngle = M_PI / 256.0; + constexpr mathType staticRotationScale = 1.0f; + constexpr mathType animatedRotationScale = M_TWOPI / double(0xFFFF); + constexpr float (*sinFunction)(float) = &sin_t; + constexpr float (*cosFunction)(float) = &cos_t; +#endif + const bool isMatrix = strip.isMatrix; + const int cols = SEGMENT.virtualWidth(); + const int rows = isMatrix ? SEGMENT.virtualHeight() : strip.getActiveSegmentsNum(); - for (int i = 0; i < SEGLEN; i++) - { - uint8_t colorIndex = (i * 255 / SEGLEN) - counter; - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_MOVING_WRAP, 255)); - } + const int inputShift = SEGMENT.speed; + const int inputSize = SEGMENT.intensity; + const int inputRotation = SEGMENT.custom1; + const bool inputAnimateShift = SEGMENT.check1; + const bool inputAnimateRotation = SEGMENT.check2; + const bool inputAssumeSquare = SEGMENT.check3; + const angleType theta = (!inputAnimateRotation) ? (inputRotation * maxAngle / staticRotationScale) : (((strip.now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); + const mathType sinTheta = sinFunction(theta); + const mathType cosTheta = cosFunction(theta); + + const mathType maxX = std::max(1, cols-1); + const mathType maxY = std::max(1, rows-1); + // Set up some parameters according to inputAssumeSquare, so that we can handle anamorphic mode using the same code base. + const mathType maxXIn = inputAssumeSquare ? maxX : mathType(1); + const mathType maxYIn = inputAssumeSquare ? maxY : mathType(1); + const mathType maxXOut = !inputAssumeSquare ? maxX : mathType(1); + const mathType maxYOut = !inputAssumeSquare ? maxY : mathType(1); + const mathType centerX = sInt16Scale * maxXOut / mathType(2); + const mathType centerY = sInt16Scale * maxYOut / mathType(2); + // The basic idea for this effect is to rotate a rectangle that is filled with the palette along one axis, then map our + // display to it, to find what color a pixel should have. + // However, we want a) no areas of solid color (in front of or behind the palette), and b) we want to make use of the full palette. + // So the rectangle needs to have exactly the right size. That size depends on the rotation. + // This scale computation here only considers one dimension. You can think of it like the rectangle is always scaled so that + // the left and right most points always match the left and right side of the display. + const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); + // 2D simulation: + // If we are dealing with a 1D setup, we assume that each segment represents one line on a 2-dimensional display. + // The function is called once per segments, so we need to handle one line at a time. + const int yFrom = isMatrix ? 0 : strip.getCurrSegmentId(); + const int yTo = isMatrix ? maxY : yFrom; + for (int y = yFrom; y <= yTo; ++y) { + // translate, scale, rotate + const mathType ytCosTheta = mathType((wideMathType(cosTheta) * wideMathType(y * sInt16Scale - centerY * maxYIn))/wideMathType(maxYIn * scale)); + for (int x = 0; x < cols; ++x) { + // translate, scale, rotate + const mathType xtSinTheta = mathType((wideMathType(sinTheta) * wideMathType(x * sInt16Scale - centerX * maxXIn))/wideMathType(maxXIn * scale)); + // Map the pixel coordinate to an imaginary-rectangle-coordinate. + // The y coordinate doesn't actually matter, as our imaginary rectangle is filled with the palette from left to right, + // so all points at a given x-coordinate have the same color. + const mathType sourceX = xtSinTheta + ytCosTheta + centerX; + // The computation was scaled just right so that the result should always be in range [0, maxXOut], but enforce this anyway + // to account for imprecision. Then scale it so that the range is [0, 255], which we can use with the palette. + int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * 255) / (sInt16Scale * maxXOut); + // inputSize determines by how much we want to scale the palette: + // values < 128 display a fraction of a palette, + // values > 128 display multiple palettes. + if (inputSize <= 128) { + colorIndex = (colorIndex * inputSize) / 128; + } else { + // Linear function that maps colorIndex 128=>1, 256=>9. + // With this function every full palette repetition is exactly 16 configuration steps wide. + // That allows displaying exactly 2 repetitions for example. + colorIndex = ((inputSize - 112) * colorIndex) / 16; + } + // Finally, shift the palette a bit. + const int paletteOffset = (!inputAnimateShift) ? (inputShift-128) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); + colorIndex += paletteOffset; + const uint32_t color = SEGMENT.color_wheel((uint8_t)colorIndex); + if (isMatrix) { + SEGMENT.setPixelColorXY(x, y, color); + } else { + SEGMENT.setPixelColor(x, color); + } + } + } return FRAMETIME; } -static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!;;c3=0,o2=0"; +static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;c1=128,c2=128,c3=128,o1=1,o2=1,o3=0"; // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active @@ -2899,7 +2979,7 @@ uint16_t mode_bouncing_balls(void) { uint16_t numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball const float gravity = -9.81f; // standard value of gravity const bool hasCol2 = SEGCOLOR(2); - const unsigned long time = millis(); + const unsigned long time = strip.now; if (SEGENV.call == 0) { for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time; @@ -3336,7 +3416,7 @@ uint16_t mode_starburst(void) { if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - uint32_t it = millis(); + uint32_t it = strip.now; star* stars = reinterpret_cast(SEGENV.data); @@ -3692,7 +3772,7 @@ uint16_t mode_tetrix(void) { // initialize dropping on first call or segment full if (SEGENV.call == 0) { drop->stack = 0; // reset brick stack size - drop->step = millis() + 2000; // start by fading out strip + drop->step = strip.now + 2000; // start by fading out strip if (SEGMENT.check1) drop->col = 0;// use only one color from palette } @@ -3726,13 +3806,13 @@ uint16_t mode_tetrix(void) { } else { // we hit bottom drop->step = 0; // proceed with next brick, go back to init drop->stack += drop->brick; // increase the stack size - if (drop->stack >= SEGLEN) drop->step = millis() + 2000; // fade out stack + if (drop->stack >= SEGLEN) drop->step = strip.now + 2000; // fade out stack } } if (drop->step > 2) { // fade strip drop->brick = 0; // reset brick size (no more growing) - if (drop->step > millis()) { + if (drop->step > strip.now) { // allow fading of virtual strip for (int i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend } else { @@ -3991,7 +4071,7 @@ uint16_t mode_sunrise() { //speed 60 - 120 : sunset time in minutes - 60; //speed above: "breathing" rise and set if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) { - SEGENV.step = millis(); //save starting time, millis() because now can change from sync + SEGENV.step = millis(); //save starting time, millis() because strip.now can change from sync SEGENV.aux0 = SEGMENT.speed; } @@ -4104,9 +4184,9 @@ uint16_t mode_noisepal(void) { // Slow noise CRGBPalette16* palettes = reinterpret_cast(SEGENV.data); uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec - if (millis() - SEGENV.step > changePaletteMs) + if (strip.now - SEGENV.step > changePaletteMs) { - SEGENV.step = millis(); + SEGENV.step = strip.now; uint8_t baseI = random8(); palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); @@ -4261,7 +4341,7 @@ uint16_t mode_dancing_shadows(void) SEGMENT.fill(BLACK); - unsigned long time = millis(); + unsigned long time = strip.now; bool respawn = false; for (size_t i = 0; i < numSpotlights; i++) { @@ -4455,8 +4535,8 @@ uint16_t mode_tv_simulator(void) { } // create a new sceene - if (((millis() - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { - tvSimulator->sceeneStart = millis(); // remember the start of the new sceene + if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { + tvSimulator->sceeneStart = strip.now; // remember the start of the new sceene tvSimulator->sceeneDuration = random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider) tvSimulator->sceeneColorHue = random16( 0, 768); // random start color-tone for the sceene tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene @@ -4507,11 +4587,11 @@ uint16_t mode_tv_simulator(void) { tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time - tvSimulator->startTime = millis(); + tvSimulator->startTime = strip.now; } // end of initialization // how much time is elapsed ? - tvSimulator->elapsed = millis() - tvSimulator->startTime; + tvSimulator->elapsed = strip.now - tvSimulator->startTime; // fade from prev volor to next color if (tvSimulator->elapsed < tvSimulator->fadeTime) { @@ -4715,7 +4795,7 @@ uint16_t mode_perlinmove(void) { if (SEGLEN == 1) return mode_static(); SEGMENT.fade_out(255-SEGMENT.custom1); for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) { - uint16_t locn = inoise16(millis()*128/(260-SEGMENT.speed)+i*15000, millis()*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. + uint16_t locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. uint16_t pixloc = map(locn, 50*256, 192*256, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. SEGMENT.setPixelColor(pixloc, SEGMENT.color_from_palette(pixloc%255, false, PALETTE_SOLID_WRAP, 0)); } @@ -4732,7 +4812,7 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(millis()/4 + i * SEGMENT.intensity); + uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); @@ -4750,8 +4830,8 @@ static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness vari uint16_t mode_FlowStripe(void) { const uint16_t hl = SEGLEN * 10 / 13; - uint8_t hue = millis() / (SEGMENT.speed+1); - uint32_t t = millis() / (SEGMENT.intensity/8+1); + uint8_t hue = strip.now / (SEGMENT.speed+1); + uint32_t t = strip.now / (SEGMENT.intensity/8+1); for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; @@ -4781,7 +4861,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma uint16_t x, y; SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails - unsigned long t = millis()/128; // timebase + unsigned long t = strip.now/128; // timebase // outer stars for (size_t i = 0; i < 8; i++) { x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); @@ -4867,8 +4947,8 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+millis()/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+millis()/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); } SEGMENT.blur(SEGMENT.intensity>>3); @@ -4880,7 +4960,7 @@ static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur;;!;2"; ///////////////////////// // 2D DNA Spiral // ///////////////////////// -uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , modified by: Andrew Tuline +uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/512-dna-spiral-variation , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const uint16_t cols = SEGMENT.virtualWidth(); @@ -4890,10 +4970,10 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.fill(BLACK); } - uint8_t speeds = SEGMENT.speed/2 + 1; + uint8_t speeds = SEGMENT.speed/2 + 7; uint8_t freq = SEGMENT.intensity/8; - uint32_t ms = millis() / 20; + uint32_t ms = strip.now / 20; SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { @@ -4933,7 +5013,7 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli SEGMENT.fadeToBlackBy(128); const uint16_t maxDim = MAX(cols, rows)/2; - unsigned long t = millis() / (32 - (SEGMENT.speed>>3)); + unsigned long t = strip.now / (32 - (SEGMENT.speed>>3)); unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup for (float i = 1; i < maxDim; i += 0.25) { float angle = radians(t * (maxDim - i)); @@ -4972,7 +5052,7 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline for (int j=0; j < cols; j++) { for (int i=0; i < rows; i++) { - indexx = inoise8(j*yscale*rows/255, i*xscale+millis()/4); // We're moving along our Perlin map. + indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map. SEGMENT.setPixelColorXY(j, i, ColorFromPalette(SEGPALETTE, min(i*(indexx)>>4, 255), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. } // for i } // for j @@ -5203,8 +5283,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sin_t((float)millis()/305.f)/20.f; - imAg += sin_t((float)millis()/405.f)/20.f; + reAl += sin_t((float)strip.now/305.f)/20.f; + imAg += sin_t((float)strip.now/405.f)/20.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -5263,7 +5343,7 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline const uint16_t rows = SEGMENT.virtualHeight(); SEGMENT.fadeToBlackBy(SEGMENT.intensity); - uint_fast16_t phase = (millis() * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed + uint_fast16_t phase = (strip.now * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed //for (int i=0; i < 4*(cols+rows); i ++) { for (int i=0; i < 256; i ++) { @@ -5273,7 +5353,7 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline uint_fast8_t ylocn = cos8(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() - SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); } return FRAMETIME; @@ -5423,7 +5503,7 @@ uint16_t mode_2Dnoise(void) { // By Andrew Tuline for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { - uint8_t pixelHue8 = inoise8(x * scale, y * scale, millis() / (16 - SEGMENT.speed/16)); + uint8_t pixelHue8 = inoise8(x * scale, y * scale, strip.now / (16 - SEGMENT.speed/16)); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, pixelHue8)); } } @@ -5443,7 +5523,7 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito const uint16_t rows = SEGMENT.virtualHeight(); SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); - uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float + uint_fast32_t t = (strip.now * 8) / (256 - SEGMENT.speed); // optimized to avoid float for (int i = 0; i < cols; i++) { uint16_t thisVal = inoise8(i * 30, t, t); uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1); @@ -5561,7 +5641,7 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); - byte t1 = millis() / (257 - SEGMENT.speed); // 20; + byte t1 = strip.now / (257 - SEGMENT.speed); // 20; byte t2 = sin8(t1) / 4 * 2; for (int i = 0; i < 13; i++) { byte x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! @@ -5600,11 +5680,9 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g uint8_t n = beatsin8(15, kBorderWidth, rows-kBorderWidth); uint8_t p = beatsin8(20, kBorderWidth, rows-kBorderWidth); - uint16_t ms = millis(); - - SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, ms/29, 255, LINEARBLEND)); - SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, ms/41, 255, LINEARBLEND)); - SEGMENT.addPixelColorXY(k, p, ColorFromPalette(SEGPALETTE, ms/73, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, strip.now/29, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, strip.now/41, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(k, p, ColorFromPalette(SEGPALETTE, strip.now/73, 255, LINEARBLEND)); return FRAMETIME; } // mode_2Dsquaredswirl() @@ -5627,7 +5705,7 @@ uint16_t mode_2DSunradiation(void) { // By: ldirko https://edi SEGMENT.fill(BLACK); } - unsigned long t = millis() / 4; + unsigned long t = strip.now / 4; int index = 0; uint8_t someVal = SEGMENT.speed/4; // Was 25. for (int j = 0; j < (rows + 2); j++) { @@ -5759,14 +5837,14 @@ uint16_t mode_2Dcrazybees(void) { int8_t deltaX, deltaY, signX, signY, error; void aimed(uint16_t w, uint16_t h) { //random16_set_seed(millis()); - aimX = random8(0, w); - aimY = random8(0, h); - hue = random8(); + aimX = random8(0, w); + aimY = random8(0, h); + hue = random8(); deltaX = abs(aimX - posX); deltaY = abs(aimY - posY); - signX = posX < aimX ? 1 : -1; - signY = posY < aimY ? 1 : -1; - error = deltaX - deltaY; + signX = posX < aimX ? 1 : -1; + signY = posY < aimY ? 1 : -1; + error = deltaX - deltaY; }; } bee_t; @@ -5774,6 +5852,7 @@ uint16_t mode_2Dcrazybees(void) { bee_t *bee = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { + random16_set_seed(strip.now); for (size_t i = 0; i < n; i++) { bee[i].posX = random8(0, cols); bee[i].posY = random8(0, rows); @@ -5781,8 +5860,8 @@ uint16_t mode_2Dcrazybees(void) { } } - if (millis() > SEGENV.step) { - SEGENV.step = millis() + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1)); + if (strip.now > SEGENV.step) { + SEGENV.step = strip.now + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1)); SEGMENT.fadeToBlackBy(32); @@ -5859,8 +5938,8 @@ uint16_t mode_2Dghostrider(void) { } } - if (millis() > SEGENV.step) { - SEGENV.step = millis() + 1024 / (cols+rows); + if (strip.now > SEGENV.step) { + SEGENV.step = strip.now + 1024 / (cols+rows); SEGMENT.fadeToBlackBy((SEGMENT.speed>>2)+64); @@ -5948,7 +6027,7 @@ uint16_t mode_2Dfloatingblobs(void) { // Bounce balls around for (size_t i = 0; i < Amount; i++) { - if (SEGENV.step < millis()) blob->color[i] = add8(blob->color[i], 4); // slowly change color + if (SEGENV.step < strip.now) blob->color[i] = add8(blob->color[i], 4); // slowly change color // change radius if needed if (blob->grow[i]) { // enlarge radius until it is >= 4 @@ -5995,7 +6074,7 @@ uint16_t mode_2Dfloatingblobs(void) { } SEGMENT.blur(SEGMENT.custom1>>2); - if (SEGENV.step < millis()) SEGENV.step = millis() + 2000; // change colors every 2 seconds + if (SEGENV.step < strip.now) SEGENV.step = strip.now + 2000; // change colors every 2 seconds return FRAMETIME; } @@ -6059,13 +6138,12 @@ uint16_t mode_2Dscrollingtext(void) { } const int numberOfLetters = strlen(text); - const unsigned long now = millis(); // reduce millis() calls int width = (numberOfLetters * rotLW); int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-rotLH)/2; if (width <= cols) { // scroll vertically (e.g. ^^ Way out ^^) if it fits int speed = map(SEGMENT.speed, 0, 255, 5000, 1000); - int frac = now % speed + 1; + int frac = strip.now % speed + 1; if (SEGMENT.intensity == 255) { yoffset = (2 * frac * rows)/speed - rows; } else if (SEGMENT.intensity == 0) { @@ -6073,7 +6151,7 @@ uint16_t mode_2Dscrollingtext(void) { } } - if (SEGENV.step < now) { + if (SEGENV.step < strip.now) { // calculate start offset if (width > cols) { if (SEGMENT.check3) { @@ -6082,7 +6160,7 @@ uint16_t mode_2Dscrollingtext(void) { } else ++SEGENV.aux0 %= width + cols; } else SEGENV.aux0 = (cols + width)/2; ++SEGENV.aux1 &= 0xFF; // color shift - SEGENV.step = now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms + SEGENV.step = strip.now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms } if (!SEGMENT.check2) SEGMENT.fade_out(255 - (SEGMENT.custom1>>4)); // trail @@ -6130,6 +6208,51 @@ uint16_t mode_2Ddriftrose(void) { } static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;2"; +///////////////////////////// +// 2D PLASMA ROTOZOOMER // +///////////////////////////// +// Plasma Rotozoomer by ldirko (c)2020 [https://editor.soulmatelights.com/gallery/457-plasma-rotozoomer], adapted for WLED by Blaz Kristan (AKA blazoncek) +uint16_t mode_2Dplasmarotozoom() { + if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up + + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + + uint16_t dataSize = SEGMENT.length() + sizeof(float); + if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + float *a = reinterpret_cast(SEGENV.data); + byte *plasma = reinterpret_cast(SEGENV.data+sizeof(float)); + + uint16_t ms = strip.now/15; + + // plasma + for (int j = 0; j < rows; j++) { + int index = j*cols; + for (int i = 0; i < cols; i++) { + if (SEGMENT.check1) plasma[index+i] = (i * 4 ^ j * 4) + ms / 6; + else plasma[index+i] = inoise8(i * 40, j * 40, ms); + } + } + + // rotozoom + float f = (sin_t(*a/2)+((128-SEGMENT.intensity)/128.0f)+1.1f)/1.5f; // scale factor + float kosinus = cos_t(*a) * f; + float sinus = sin_t(*a) * f; + for (int i = 0; i < cols; i++) { + float u1 = i * kosinus; + float v1 = i * sinus; + for (int j = 0; j < rows; j++) { + byte u = abs8(u1 - j * sinus) % cols; + byte v = abs8(v1 + j * kosinus) % rows; + SEGMENT.setPixelColorXY(i, j, SEGMENT.color_from_palette(plasma[v*cols+u], false, PALETTE_SOLID_WRAP, 0)); + } + } + *a -= 0.03f + float(SEGENV.speed-128)*0.0002f; // rotation speed + + return FRAMETIME; +} +static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale,,,,Alt;;!;2;pal=54"; + #endif // WLED_DISABLE_2D @@ -6280,7 +6403,6 @@ uint16_t mode_2DSwirl(void) { uint8_t j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); uint8_t ni = (cols - 1) - i; uint8_t nj = (cols - 1) - j; - uint16_t ms = millis(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -6290,12 +6412,12 @@ uint16_t mode_2DSwirl(void) { float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg??? int16_t volumeRaw = *(int16_t*) um_data->u_data[1]; - SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (ms / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255); - SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (ms / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255); - SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (ms / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255); - SEGMENT.addPixelColorXY(nj,ni, ColorFromPalette(SEGPALETTE, (ms / 29 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 29, 200, 255); - SEGMENT.addPixelColorXY( i,nj, ColorFromPalette(SEGPALETTE, (ms / 37 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 37, 200, 255); - SEGMENT.addPixelColorXY(ni, j, ColorFromPalette(SEGPALETTE, (ms / 41 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 41, 200, 255); + SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (strip.now / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255); + SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (strip.now / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255); + SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (strip.now / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255); + SEGMENT.addPixelColorXY(nj,ni, ColorFromPalette(SEGPALETTE, (strip.now / 29 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 29, 200, 255); + SEGMENT.addPixelColorXY( i,nj, ColorFromPalette(SEGPALETTE, (strip.now / 37 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 37, 200, 255); + SEGMENT.addPixelColorXY(ni, j, ColorFromPalette(SEGPALETTE, (strip.now / 41 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 41, 200, 255); return FRAMETIME; } // mode_2DSwirl() @@ -6321,7 +6443,7 @@ uint16_t mode_2DWaverly(void) { SEGMENT.fadeToBlackBy(SEGMENT.speed); - long t = millis() / 2; + long t = strip.now / 2; for (int i = 0; i < cols; i++) { uint16_t thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2; // use audio if available @@ -6383,7 +6505,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; itopLED--; if (gravcen->topLED >= 0) { - SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); - SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; @@ -6435,7 +6557,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; itopLED--; if (gravcen->topLED > 0) { - SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; @@ -6519,7 +6641,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); for (size_t i=0; i SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } @@ -6775,7 +6897,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. } for (int i=0; iu_data[0]; - myVals[millis()%32] = volumeSmth; // filling values semi randomly + myVals[strip.now%32] = volumeSmth; // filling values semi randomly SEGMENT.fade_out(64+(SEGMENT.speed>>1)); @@ -7188,7 +7310,7 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli uint8_t numBins = map(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins. for (int i=0; i= (256U - SEGMENT.intensity)) { - SEGENV.step = millis(); + if (strip.now - SEGENV.step >= (256U - SEGMENT.intensity)) { + SEGENV.step = strip.now; rippleTime = true; } @@ -7522,7 +7644,7 @@ uint16_t mode_2Ddistortionwaves() { uint8_t w = 2; - uint16_t a = millis()/32; + uint16_t a = strip.now/32; uint16_t a2 = a/2; uint16_t a3 = a/3; @@ -7740,7 +7862,7 @@ uint16_t mode_2Dwavingcell() { const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - uint32_t t = millis()/(257-SEGMENT.speed); + uint32_t t = strip.now/(257-SEGMENT.speed); uint8_t aX = SEGMENT.custom1/16 + 9; uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; @@ -7945,6 +8067,7 @@ void WS2812FX::setupEffectData() { // --- 2D effects --- #ifndef WLED_DISABLE_2D + addEffect(FX_MODE_2DPLASMAROTOZOOM, &mode_2Dplasmarotozoom, _data_FX_MODE_2DPLASMAROTOZOOM); addEffect(FX_MODE_2DSPACESHIPS, &mode_2Dspaceships, _data_FX_MODE_2DSPACESHIPS); addEffect(FX_MODE_2DCRAZYBEES, &mode_2Dcrazybees, _data_FX_MODE_2DCRAZYBEES); addEffect(FX_MODE_2DGHOSTRIDER, &mode_2Dghostrider, _data_FX_MODE_2DGHOSTRIDER); diff --git a/wled00/FX.h b/wled00/FX.h index c4725ec97..abf33f997 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -241,7 +241,7 @@ #define FX_MODE_CHUNCHUN 111 #define FX_MODE_DANCING_SHADOWS 112 #define FX_MODE_WASHING_MACHINE 113 -// #define FX_MODE_CANDY_CANE 114 // removed in 0.14! +#define FX_MODE_2DPLASMAROTOZOOM 114 // was Candy Cane prior to 0.14 (use Chase 2) #define FX_MODE_BLENDS 115 #define FX_MODE_TV_SIMULATOR 116 #define FX_MODE_DYNAMIC_SMOOTH 117 // candidate for removal (check3 in dynamic) @@ -802,8 +802,7 @@ class WS2812FX { // 96 bytes getActiveSegmentsNum(void), getFirstSelectedSegId(void), getLastActiveSegmentId(void), - getActiveSegsLightCapabilities(bool selectedOnly = false), - setPixelSegment(uint8_t n); + getActiveSegsLightCapabilities(bool selectedOnly = false); inline uint8_t getBrightness(void) { return _brightness; } // returns current strip brightness inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 96e397aba..eeaa2c1e1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -425,7 +425,7 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { uint32_t prog = progress(); if (prog < 0xFFFFU) { uint32_t curBri = (useCct ? cct : (on ? opacity : 0)) * prog; - curBri += (useCct ? _t->_cctT : (on ? _t->_briT : 0)) * (0xFFFFU - prog); + curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog); return curBri / 0xFFFFU; } return (useCct ? cct : (on ? opacity : 0)); @@ -440,6 +440,7 @@ uint8_t IRAM_ATTR Segment::currentMode() { } uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { + 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]; #else @@ -1025,7 +1026,7 @@ void Segment::blur(uint8_t blur_amount) { * Inspired by the Adafruit examples. */ uint32_t Segment::color_wheel(uint8_t pos) { - if (palette) return color_from_palette(pos, false, true, 0); + if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" uint8_t w = W(currentColor(0)); pos = 255 - pos; if (pos < 85) { @@ -1056,6 +1057,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ uint8_t paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); + // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGBPalette16 curPal; curPal = currentPalette(curPal, palette); @@ -1140,7 +1142,7 @@ void WS2812FX::service() { _isServicing = true; _segment_index = 0; - Segment::handleRandomPalette(); // move it into for loop when each segment has individual random palette + for (segment &seg : _segments) { if (_suspend) return; // immediately stop processing segments if suspend requested during service() @@ -1203,6 +1205,7 @@ void WS2812FX::service() { #endif if (doShow) { yield(); + Segment::handleRandomPalette(); // slowly transtion random palette; move it into for loop when each segment has individual random palette show(); } #ifdef WLED_DEBUG @@ -1453,6 +1456,7 @@ void WS2812FX::resetSegments() { segment seg = Segment(0, _length); #endif _segments.push_back(seg); + _segments.shrink_to_fit(); // just in case ... _mainSegment = 0; } @@ -1571,18 +1575,7 @@ bool WS2812FX::checkSegmentAlignment() { return true; } -//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) -//Note: If called in an interrupt (e.g. JSON API), original segment must be restored, -//otherwise it can lead to a crash on ESP32 because _segment_index is modified while in use by the main thread -uint8_t WS2812FX::setPixelSegment(uint8_t n) { - uint8_t prevSegId = _segment_index; - if (n < _segments.size()) { - _segment_index = n; - _virtualSegmentLength = _segments[_segment_index].virtualLength(); - } - return prevSegId; -} - +// used by analog clock overlay void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) { if (i2 < i) std::swap(i,i2); for (unsigned x = i; x <= i2; x++) setPixelColor(x, col); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 56267c117..822ff49db 100755 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -606,29 +606,34 @@ void BusNetwork::cleanup() { //utility to get the approx. memory usage of a given BusConfig uint32_t BusManager::memUsage(BusConfig &bc) { - uint8_t type = bc.type; + if (bc.type == TYPE_ONOFF || IS_PWM(bc.type)) return 5; + uint16_t len = bc.count + bc.skipAmount; - if (type > 15 && type < 32) { // digital types - if (type == TYPE_UCS8903 || type == TYPE_UCS8904) len *= 2; // 16-bit LEDs + uint16_t channels = 3; + uint16_t multiplier = 1; + if (IS_DIGITAL(bc.type)) { // digital types + if (IS_16BIT(bc.type)) len *= 2; // 16-bit LEDs #ifdef ESP8266 + if (bc.type > 28) channels = 4; //RGBW if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem - if (type > 28) return len*20; //RGBW - return len*15; + multiplier = 5; } - if (type > 28) return len*4; //RGBW - return len*3; - #else //ESP32 RMT uses double buffer? - if (type > 28) return len*8; //RGBW - return len*6; + #else //ESP32 RMT uses double buffer, I2S uses 5x buffer + if (bc.type > 28) channels = 4; //RGBW + multiplier = 2; #endif } - if (type > 31 && type < 48) return 5; - return len*3; //RGB + if (IS_VIRTUAL(bc.type)) { + switch (bc.type) { + case TYPE_NET_DDP_RGBW: channels = 4; break; + } + } + return len * channels * multiplier; //RGB } int BusManager::add(BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; - if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) { + if (IS_VIRTUAL(bc.type)) { busses[numBusses] = new BusNetwork(bc); } else if (IS_DIGITAL(bc.type)) { busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 12fb81b39..b2dbd50fa 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -129,10 +129,9 @@ class Bus { virtual void setPixelColor(uint16_t pix, uint32_t c) = 0; virtual uint32_t getPixelColor(uint16_t pix) { return 0; } virtual void setBrightness(uint8_t b) { _bri = b; }; - virtual void cleanup() = 0; virtual uint8_t getPins(uint8_t* pinArray) { return 0; } virtual uint16_t getLength() { return _len; } - virtual void setColorOrder() {} + virtual void setColorOrder(uint8_t co) {} virtual uint8_t getColorOrder() { return COL_ORDER_RGB; } virtual uint8_t skippedLeds() { return 0; } virtual uint16_t getFrequency() { return 0U; } @@ -207,21 +206,21 @@ class BusDigital : public Bus { BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com); ~BusDigital() { cleanup(); } - void show(); - bool canShow(); - void setBrightness(uint8_t b); - void setStatusPixel(uint32_t c); - void setPixelColor(uint16_t pix, uint32_t c); - void setColorOrder(uint8_t colorOrder); - uint32_t getPixelColor(uint16_t pix); - uint8_t getColorOrder() { return _colorOrder; } - uint8_t getPins(uint8_t* pinArray); - uint8_t skippedLeds() { return _skip; } - uint16_t getFrequency() { return _frequencykHz; } + void show() override; + bool canShow() override; + void setBrightness(uint8_t b) override; + void setStatusPixel(uint32_t c) override; + void setPixelColor(uint16_t pix, uint32_t c) override; + void setColorOrder(uint8_t colorOrder) override; + uint32_t getPixelColor(uint16_t pix) override; + uint8_t getColorOrder() override { return _colorOrder; } + uint8_t getPins(uint8_t* pinArray) override; + uint8_t skippedLeds() override { return _skip; } + uint16_t getFrequency() override { return _frequencykHz; } uint8_t estimateCurrentAndLimitBri(); - uint16_t getLEDCurrent() { return _milliAmpsPerLed; } - uint16_t getUsedCurrent() { return _milliAmpsTotal; } - uint16_t getMaxCurrent() { return _milliAmpsMax; } + uint16_t getLEDCurrent() override { return _milliAmpsPerLed; } + uint16_t getUsedCurrent() override { return _milliAmpsTotal; } + uint16_t getMaxCurrent() override { return _milliAmpsMax; } void reinit(); void cleanup(); @@ -256,11 +255,11 @@ class BusPwm : public Bus { BusPwm(BusConfig &bc); ~BusPwm() { cleanup(); } - void setPixelColor(uint16_t pix, uint32_t c); - uint32_t getPixelColor(uint16_t pix); //does no index check - uint8_t getPins(uint8_t* pinArray); - uint16_t getFrequency() { return _frequency; } - void show(); + void setPixelColor(uint16_t pix, uint32_t c) override; + uint32_t getPixelColor(uint16_t pix) override; //does no index check + uint8_t getPins(uint8_t* pinArray) override; + uint16_t getFrequency() override { return _frequency; } + void show() override; void cleanup() { deallocatePins(); } private: @@ -280,10 +279,10 @@ class BusOnOff : public Bus { BusOnOff(BusConfig &bc); ~BusOnOff() { cleanup(); } - void setPixelColor(uint16_t pix, uint32_t c); - uint32_t getPixelColor(uint16_t pix); - uint8_t getPins(uint8_t* pinArray); - void show(); + void setPixelColor(uint16_t pix, uint32_t c) override; + uint32_t getPixelColor(uint16_t pix) override; + uint8_t getPins(uint8_t* pinArray) override; + void show() override; void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); } private: @@ -297,13 +296,13 @@ class BusNetwork : public Bus { BusNetwork(BusConfig &bc); ~BusNetwork() { cleanup(); } - bool hasRGB() { return true; } - bool hasWhite() { return _rgbw; } - bool canShow() { 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); - uint32_t getPixelColor(uint16_t pix); - uint8_t getPins(uint8_t* pinArray); - void show(); + bool hasRGB() override { return true; } + bool hasWhite() override { return _rgbw; } + bool canShow() 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) override; + uint8_t getPins(uint8_t* pinArray) override; + void show() override; void cleanup(); private: diff --git a/wled00/const.h b/wled00/const.h index 4bab0c4a8..f707268e1 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -225,7 +225,7 @@ #define TYPE_NONE 0 //light is not configured #define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light -//Digital types (data pin only) (16-31) +//Digital types (data pin only) (16-39) #define TYPE_WS2812_1CH 18 //white-only chips (1 channel per IC) (unused) #define TYPE_WS2812_1CH_X3 19 //white-only chips (3 channels per IC) #define TYPE_WS2812_2CH_X3 20 //CCT chips (1st IC controls WW + CW of 1st zone and CW of 2nd zone, 2nd IC controls WW of 2nd zone and WW + CW of 3rd zone) @@ -236,11 +236,11 @@ #define TYPE_TM1829 25 #define TYPE_UCS8903 26 #define TYPE_APA106 27 -#define TYPE_UCS8904 29 +#define TYPE_UCS8904 29 //first RGBW digital type (hardcoded in busmanager.cpp, memUsage()) #define TYPE_SK6812_RGBW 30 #define TYPE_TM1814 31 -//"Analog" types (PWM) (32-47) -#define TYPE_ONOFF 40 //binary output (relays etc.) +//"Analog" types (40-47) +#define TYPE_ONOFF 40 //binary output (relays etc.; NOT PWM) #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel #define TYPE_ANALOG_2CH 42 //analog WW + CW #define TYPE_ANALOG_3CH 43 //analog RGB @@ -258,11 +258,13 @@ #define TYPE_NET_ARTNET_RGB 82 //network ArtNet RGB bus (master broadcast bus, unused) #define TYPE_NET_DDP_RGBW 88 //network DDP RGBW bus (master broadcast bus) -#define IS_DIGITAL(t) ((t) < 80 && ((t) & 0x10)) //digital are 16-31 and 48-63 -#define IS_PWM(t) ((t) > 40 && (t) < 46) -#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only -#define IS_2PIN(t) ((t) > 47) -#define IS_VIRTUAL(t) ((t) >= 80) +#define IS_TYPE_VALID(t) ((t) > 15 && (t) < 128) +#define IS_DIGITAL(t) (((t) > 15 && (t) < 40) || ((t) > 47 && (t) < 64)) //digital are 16-39 and 48-63 +#define IS_2PIN(t) ((t) > 47 && (t) < 64) +#define IS_16BIT(t) ((t) == TYPE_UCS8903 || (t) == TYPE_UCS8904) +#define IS_PWM(t) ((t) > 40 && (t) < 46) //does not include on/Off type +#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only +#define IS_VIRTUAL(t) ((t) >= 80 && (t) < 96) //this was a poor choice a better would be 96-111 //Color orders #define COL_ORDER_GRB 0 //GRB(w),defaut diff --git a/wled00/data/index.js b/wled00/data/index.js index ec8fcb23a..bdaa3ed60 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2161,7 +2161,7 @@ function selGrp(g) var sel = gId(`segcont`).querySelectorAll(`div[data-set="${g}"]`); var obj = {"seg":[]}; for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":false}); - if (sel) for (let s of sel||[]) { + for (let s of (sel||[])) { let i = parseInt(s.id.substring(3)); obj.seg[i] = {"id":i,"sel":true}; } diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm old mode 100755 new mode 100644 index dd262c22d..e80cad741 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -16,11 +16,13 @@ function B(){window.open(getURL("/settings"),"_self");} function gId(n){return d.getElementById(n);} function off(n){d.getElementsByName(n)[0].value = -1;} - function isPWM(t) { return t > 40 && t < 46; } // is PWM type - function isAna(t) { return t == 40 || isPWM(t); } // is analog type - function isDig(t) { return t < 80 && (t & 0x10); }// is digital type - function isD2P(t) { return t > 47 && t < 64; } // is digital 2 pin type - function isVir(t) { return t >= 80; } // is virtual type + // these functions correspond to C macros found in const.h + function isPWM(t) { return t > 40 && t < 46; } // is PWM type + function isAna(t) { return t == 40 || isPWM(t); } // is analog type + function isDig(t) { return (t > 15 && t < 40) || isD2P(t); } // is digital type + function isD2P(t) { return t > 47 && t < 64; } // is digital 2 pin type + function is16b(t) { return t == 26 || t == 29 } // is digital 16 bit type + function isVir(t) { return t >= 80 && t < 96; } // is virtual type // 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"); @@ -175,25 +177,25 @@ } //returns mem usage function getMem(t, n) { + if (isAna(t)) return 5; // analog let len = parseInt(d.getElementsByName("LC"+n)[0].value); len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too let dbl = 0; - if (d.Sf.LD.checked) dbl = len * 4; // double buffering - if (t < 32) { - if (t==26 || t==29) len *= 2; // 16 bit LEDs + let ch = 3; + let mul = 1; + if (isDig(t)) { + if (is16b(t)) len *= 2; // 16 bit LEDs + if (t > 28 && t < 40) ch = 4; //RGBW if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem - if (t > 28) return len*20 + dbl; //RGBW - return len*15 + dbl; - } else if (maxM >= 10000) //ESP32 RMT uses double buffer? - { - if (t > 28) return len*8 + dbl; //RGBW - return len*6 + dbl; + mul = 5; } - if (t > 28) return len*4 + dbl; //RGBW - return len*3 + dbl; + if (maxM >= 10000) { //ESP32 RMT uses double buffer? + mul = 2; + } + if (d.Sf.LD.checked) dbl = len * ch; // double buffering } - if (t > 31 && t < 48) return 5; // analog - return len*3 + dbl; + if (isVir(t) && t == 88) ch = 4; + return len * ch * mul + dbl; } function UI(change=false) diff --git a/wled00/file.cpp b/wled00/file.cpp index 4edbdd6fb..fc3dc7eeb 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -377,27 +377,27 @@ void updateFSInfo() { //Un-comment any file types you need static String getContentType(AsyncWebServerRequest* request, String filename){ - if(request->hasArg("download")) return "application/octet-stream"; - else if(filename.endsWith(".htm")) return "text/html"; - else if(filename.endsWith(".html")) return "text/html"; - else if(filename.endsWith(".css")) return "text/css"; - else if(filename.endsWith(".js")) return "application/javascript"; - else if(filename.endsWith(".json")) return "application/json"; - else if(filename.endsWith(".png")) return "image/png"; - else if(filename.endsWith(".gif")) return "image/gif"; - else if(filename.endsWith(".jpg")) return "image/jpeg"; - else if(filename.endsWith(".ico")) return "image/x-icon"; -// else if(filename.endsWith(".xml")) return "text/xml"; -// else if(filename.endsWith(".pdf")) return "application/x-pdf"; -// else if(filename.endsWith(".zip")) return "application/x-zip"; -// else if(filename.endsWith(".gz")) return "application/x-gzip"; + if(request->hasArg(F("download"))) return SET_F("application/octet-stream"); + else if(filename.endsWith(F(".htm"))) return SET_F("text/html"); + else if(filename.endsWith(F(".html"))) return SET_F("text/html"); + else if(filename.endsWith(F(".css"))) return SET_F("text/css"); + else if(filename.endsWith(F(".js"))) return SET_F("application/javascript"); + else if(filename.endsWith(F(".json"))) return SET_F("application/json"); + else if(filename.endsWith(F(".png"))) return SET_F("image/png"); + else if(filename.endsWith(F(".gif"))) return SET_F("image/gif"); + else if(filename.endsWith(F(".jpg"))) return SET_F("image/jpeg"); + else if(filename.endsWith(F(".ico"))) return SET_F("image/x-icon"); +// else if(filename.endsWith(F(".xml"))) return SET_F("text/xml"); +// else if(filename.endsWith(F(".pdf"))) return SET_F("application/x-pdf"); +// else if(filename.endsWith(F(".zip"))) return SET_F("application/x-zip"); +// else if(filename.endsWith(F(".gz"))) return SET_F("application/x-gzip"); return "text/plain"; } bool handleFileRead(AsyncWebServerRequest* request, String path){ DEBUG_PRINTLN("WS FileRead: " + path); if(path.endsWith("/")) path += "index.htm"; - if(path.indexOf("sec") > -1) return false; + if(path.indexOf(F("sec")) > -1) return false; String contentType = getContentType(request, path); /*String pathWithGz = path + ".gz"; if(WLED_FS.exists(pathWithGz)){ diff --git a/wled00/json.cpp b/wled00/json.cpp index 395ee7cbc..90770f834 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -611,7 +611,7 @@ void serializeInfo(JsonObject root) root[F("vid")] = VERSION; root[F("cn")] = F(WLED_CODENAME); - JsonObject leds = root.createNestedObject("leds"); + JsonObject leds = root.createNestedObject(F("leds")); leds[F("count")] = strip.getLengthTotal(); leds[F("pwr")] = BusManager::currentMilliamps(); leds["fps"] = strip.getFps(); @@ -622,7 +622,7 @@ void serializeInfo(JsonObject root) #ifndef WLED_DISABLE_2D if (strip.isMatrix) { - JsonObject matrix = leds.createNestedObject("matrix"); + JsonObject matrix = leds.createNestedObject(F("matrix")); matrix["w"] = Segment::maxWidth; matrix["h"] = Segment::maxHeight; } @@ -702,7 +702,7 @@ void serializeInfo(JsonObject root) } } - JsonObject wifi_info = root.createNestedObject("wifi"); + JsonObject wifi_info = root.createNestedObject(F("wifi")); wifi_info[F("bssid")] = WiFi.BSSIDstr(); int qrssi = WiFi.RSSI(); wifi_info[F("rssi")] = qrssi; diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 6268aa983..4a03d4847 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -170,7 +170,7 @@ #endif #ifdef USERMOD_KLIPPER_PERCENTAGE - #include "..\usermods\usermod_v2_klipper_percentage\usermod_v2_klipper_percentage.h" + #include "../usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h" #endif #ifdef USERMOD_BOBLIGHT diff --git a/wled00/wled.cpp b/wled00/wled.cpp index d21e75a4c..32b33931a 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -386,7 +386,7 @@ void WLED::setup() //DEBUG_PRINT(F("LEDs inited. heap usage ~")); //DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); -#ifdef WLED_DEBUG +#if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output #endif #ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin @@ -537,6 +537,13 @@ void WLED::beginStrip() else if (bri == 0) bri = 128; } else { // fix for #3196 + if (bootPreset > 0) { + bool oldTransition = fadeTransition; // workaround if transitions are enabled + fadeTransition = false; // ignore transitions temporarily + strip.setColor(0, BLACK); // set all segments black + fadeTransition = oldTransition; // restore transitions + col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated() + } briLast = briS; bri = 0; strip.fill(BLACK); strip.show(); diff --git a/wled00/wled.h b/wled00/wled.h index 217acd627..23cd43636 100755 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2401130 +#define VERSION 2401270 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -364,7 +364,6 @@ WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module - use d #else WLED_GLOBAL char serverDescription[33] _INIT(SERVERNAME); // use predefined name #endif -//WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 82cc55014..57e0c84b9 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -532,18 +532,18 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { const String& url = request->url(); if (url.indexOf("sett") >= 0) { - if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS; - else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS; - else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI; - else if (url.indexOf("leds") > 0) subPage = SUBPAGE_LEDS; - else if (url.indexOf("ui") > 0) subPage = SUBPAGE_UI; - else if (url.indexOf("sync") > 0) subPage = SUBPAGE_SYNC; - else if (url.indexOf("time") > 0) subPage = SUBPAGE_TIME; - else if (url.indexOf("sec") > 0) subPage = SUBPAGE_SEC; - else if (url.indexOf("dmx") > 0) subPage = SUBPAGE_DMX; - else if (url.indexOf("um") > 0) subPage = SUBPAGE_UM; - else if (url.indexOf("2D") > 0) subPage = SUBPAGE_2D; - else if (url.indexOf("lock") > 0) subPage = SUBPAGE_LOCK; + if (url.indexOf(F(".js")) > 0) subPage = SUBPAGE_JS; + else if (url.indexOf(F(".css")) > 0) subPage = SUBPAGE_CSS; + else if (url.indexOf(F("wifi")) > 0) subPage = SUBPAGE_WIFI; + else if (url.indexOf(F("leds")) > 0) subPage = SUBPAGE_LEDS; + else if (url.indexOf(F("ui")) > 0) subPage = SUBPAGE_UI; + else if (url.indexOf( "sync") > 0) subPage = SUBPAGE_SYNC; + else if (url.indexOf( "time") > 0) subPage = SUBPAGE_TIME; + else if (url.indexOf(F("sec")) > 0) subPage = SUBPAGE_SEC; + else if (url.indexOf( "dmx") > 0) subPage = SUBPAGE_DMX; + else if (url.indexOf( "um") > 0) subPage = SUBPAGE_UM; + else if (url.indexOf( "2D") > 0) subPage = SUBPAGE_2D; + else if (url.indexOf(F("lock")) > 0) subPage = SUBPAGE_LOCK; } else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check //else if (url.indexOf("/edit") >= 0) subPage = 10; diff --git a/wled00/xml.cpp b/wled00/xml.cpp index de183c5a6..acb43ba1e 100755 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -157,8 +157,8 @@ void appendGPIOinfo() { oappend(SET_F(",2")); // DMX hardcoded pin #endif - #ifdef WLED_DEBUG - oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10));// debug output (TX) pin + #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) + oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10)); // debug output (TX) pin #endif //Note: Using pin 3 (RX) disables Adalight / Serial JSON