From e4fbf705683e2116ab5025a84907f9c79418ae1c Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 9 Sep 2022 17:16:52 +0200 Subject: [PATCH] Preset loading tuning. Multi-relay toggle support. Fire2012 tuning. 2D functions tuning. Global SPI comments & tuning. Bugfix in 4LD usermod. On & bri support fix. --- usermods/multi_relay/usermod_multi_relay.h | 54 +++++++++++-------- .../usermod_v2_four_line_display_ALT.h | 19 ++++++- wled00/FX.cpp | 6 +-- wled00/FX.h | 2 +- wled00/FX_2Dfcn.cpp | 9 ++-- wled00/bus_wrapper.h | 5 +- wled00/cfg.cpp | 6 ++- wled00/json.cpp | 28 ++++------ wled00/led.cpp | 1 + wled00/set.cpp | 8 ++- wled00/wled.h | 2 +- 11 files changed, 85 insertions(+), 55 deletions(-) diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 75258608..3e0cc833 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -80,7 +80,7 @@ class MultiRelay : public Usermod { void handleOffTimer() { unsigned long now = millis(); bool activeRelays = false; - for (uint8_t i=0; i 0 && now - _switchTimerStart > (_relay[i].delay*1000)) { if (!_relay[i].external) toggleRelay(i); _relay[i].active = false; @@ -182,7 +182,7 @@ class MultiRelay : public Usermod { */ MultiRelay() { const int8_t defPins[] = {MULTI_RELAY_PINS}; - for (uint8_t i=0; i=0) count++; + for (int i=0; i=0) count++; return count; } @@ -268,7 +268,7 @@ class MultiRelay : public Usermod { strcat_P(subuf, PSTR("/relay/#")); mqtt->subscribe(subuf, 0); if (HAautodiscovery) publishHomeAssistantAutodiscovery(); - for (uint8_t i=0; i=0 && !_relay[i].external) _relay[i].active = true; } } @@ -382,7 +382,7 @@ class MultiRelay : public Usermod { } bool handled = false; - for (uint8_t i=0; i WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce) - for (uint8_t i=0; i=0 && _relay[i].button == b) { + for (int i=0; i 350 && !buttonPressedBefore[b]) { buttonWaitTime[b] = 0; //shortPressAction(b); //not exposed - for (uint8_t i=0; i=0 && _relay[i].button == b) { + for (int i=0; i 1 JsonArray rel_arr = multiRelay.createNestedArray(F("relays")); - for (uint8_t i=0; i() && usermod[FPSTR(_relay_str)].is() && usermod[FPSTR(_relay_str)].as()>=0) { - switchRelay(usermod[FPSTR(_relay_str)].as(), usermod["on"].as()); + if (usermod[FPSTR(_relay_str)].is() && usermod[FPSTR(_relay_str)].as()>=0) { + int rly = usermod[FPSTR(_relay_str)].as(); + if (usermod["on"].is()) { + switchRelay(rly, usermod["on"].as()); + } else if (usermod["on"].is() && usermod["on"].as()[0] == 't') { + toggleRelay(rly); + } } } else if (root[FPSTR(_name)].is()) { JsonArray relays = root[FPSTR(_name)].as(); for (JsonVariant r : relays) { - if (r["on"].is() && r[FPSTR(_relay_str)].is() && r[FPSTR(_relay_str)].as()>=0) { - switchRelay(r[FPSTR(_relay_str)].as(), r["on"].as()); + if (r[FPSTR(_relay_str)].is() && r[FPSTR(_relay_str)].as()>=0) { + int rly = r[FPSTR(_relay_str)].as(); + if (r["on"].is()) { + switchRelay(rly, r["on"].as()); + } else if (r["on"].is() && r["on"].as()[0] == 't') { + toggleRelay(rly); + } } } } @@ -548,7 +558,7 @@ class MultiRelay : public Usermod { top[FPSTR(_enabled)] = enabled; top[FPSTR(_broadcast)] = periodicBroadcastSec; - for (uint8_t i=0; i=0) { pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay); } // allocate new pins - for (uint8_t i=0; i=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) { if (!_relay[i].external) { _relay[i].state = !offMode; 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 38a055a5..2c373158 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 @@ -402,10 +402,12 @@ class FourLineDisplayUsermod : public Usermod { else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA break; case SSD1306_SPI: + // u8x8 uses global SPI variable that is attached to VSPI bus on ESP32 if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset break; case SSD1306_SPI64: + // u8x8 uses global SPI variable that is attached to VSPI bus on ESP32 if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset break; @@ -1052,10 +1054,25 @@ 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) { + // determine if we are using global HW pins (data & clock) + int8_t hw_dta, hw_clk; + if ((type == SSD1306_SPI || type == SSD1306_SPI64)) { + hw_clk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk; + hw_dta = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi; + } else { + hw_clk = i2c_scl<0 ? HW_PIN_SCL : i2c_scl; + hw_dta = i2c_sda<0 ? HW_PIN_SDA : i2c_sda; + } + JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; + JsonArray io_pin = top.createNestedArray("pin"); - for (byte i=0; i<5; i++) io_pin.add(ioPin[i]); + for (int i=0; i<5; i++) { + if (i==0 && ioPin[i]==hw_clk) io_pin.add(-1); // do not store global HW pin + else if (i==1 && ioPin[i]==hw_dta) io_pin.add(-1); // do not store global HW pin + else io_pin.add(ioPin[i]); + } top["type"] = type; top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_contrast)] = contrast; diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 540a1ad3..19383817 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1982,11 +1982,11 @@ uint16_t mode_fire_2012() uint8_t cool = random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2); uint8_t minTemp = 0; if (idy ? dx : -dy)/2, e2; for (;;) { - setPixelColorXY(x0,y0,c); + addPixelColorXY(x0,y0,c); if (x0==x1 && y0==y1) break; e2 = err; if (e2 >-dx) { err -= dy; x0 += sx; } @@ -466,7 +465,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 #include "src/font/console_font_7x9.h" // draws a raster font character on canvas -// only supports 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM +// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color) { if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported chr -= 32; // align with font table entries @@ -491,7 +490,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, for (int j = 0; j= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen - setPixelColorXY(x0, y0, color); + addPixelColorXY(x0, y0, color); } } } diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index e2783236..b9f5cb4d 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -829,10 +829,9 @@ class PolyBus { #ifdef ESP8266 if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true; #else - // temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0 + // temporary hack to limit use of hardware SPI to a single SPI peripheral (HSPI): only allow ESP32 hardware serial on segment 0 + // SPI global variable is normally linked to VSPI on ESP32 (or FSPI C3, S3) if (!num) isHSPI = true; - //if (num==0 && pins[0] == P_32_VS_MOSI && pins[1] == P_32_VS_CLK) isHSPI = true; // no nultiplexing, up to 80MHz clock - //if (num==1 && pins[0] == P_32_HS_MOSI && pins[1] == P_32_HS_CLK) isHSPI = true; #endif uint8_t t = I_NONE; switch (busType) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index fe0ae194..f615f966 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -286,7 +286,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(spi_miso, hw_if_spi[2]); PinManagerPinType spi[3] = { { spi_mosi, true }, { spi_miso, true }, { spi_sclk, true } }; if (spi_mosi >= 0 && spi_sclk >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) { - // do not initialise bus here + #ifdef ESP32 + SPI.begin(spi_sclk, spi_miso, spi_mosi); // SPI global uses VSPI on ESP32 and FSPI on C3, S3 + #else + SPI.begin(); + #endif } else { spi_mosi = -1; spi_miso = -1; diff --git a/wled00/json.cpp b/wled00/json.cpp index c7d583e1..bbd81373 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -287,22 +287,13 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) bool stateResponse = root[F("v")] | false; bool onBefore = bri; - uint8_t tmpBri = bri; - getVal(root["bri"], &tmpBri); + getVal(root["bri"], &bri); - if (root["on"].isNull()) { - if ((onBefore && tmpBri==0) || (!onBefore && tmpBri>0)) toggleOnOff(); - bri = tmpBri; - } else { - bool on = root["on"] | onBefore; - if (on != onBefore || (root["on"].is() && root["on"].as()[0] == 't')) { - toggleOnOff(); - // a hack is needed after toggleOnOf() - if (!root["bri"].isNull()) { - if (bri==0) briLast = tmpBri; - else bri = tmpBri; - } - } + bool on = root["on"] | (bri > 0); + if (!on != !bri) toggleOnOff(); + + if (root["on"].is() && root["on"].as()[0] == 't') { + if (onBefore || !bri) toggleOnOff(); // do not toggle off again if just turned on by bri (makes e.g. "{"on":"t","bri":32}" work) } if (bri && !onBefore) { // unfreeze all segments when turning on @@ -433,9 +424,12 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) if (root["win"].isNull()) presetCycCurr = currentPreset; stateChanged = false; // cancel state change update (preset was set directly by applying values stored in UI JSON array) } else if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) { - // b) preset ID only (use embedded cycling limits if they exist in getVal()) + // b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal()) presetCycCurr = ps; - applyPreset(ps, callMode); // async load + root.remove(F("v")); // may be added in UI call + root.remove(F("time")); // may be added in UI call + root.remove("ps"); + if (root.size() == 0) applyPreset(ps, callMode); // async load (only preset ID was specified) return stateResponse; } } diff --git a/wled00/led.cpp b/wled00/led.cpp index 720f11e1..34dd85d9 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -63,6 +63,7 @@ void toggleOnOff() briLast = bri; bri = 0; } + stateChanged = true; } diff --git a/wled00/set.cpp b/wled00/set.cpp index c1a6b3f5..7ee26b04 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -515,7 +515,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) spi_mosi = hw_mosi_pin; spi_miso = hw_miso_pin; spi_sclk = hw_sclk_pin; - // no bus initialisation + // no bus re-initialisation as usermods do not get any notification + //SPI.end(); + #ifdef ESP32 + //SPI.begin(spi_sclk, spi_miso, spi_mosi); + #else + //SPI.begin(); + #endif } else { //SPI.end(); DEBUG_PRINTLN(F("Could not allocate SPI pins.")); diff --git a/wled00/wled.h b/wled00/wled.h index 055d65d3..135d4e9b 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2209061 +#define VERSION 2209091 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG