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 3765001eb..310843763 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 @@ -47,7 +47,7 @@ // The last UI state, remove color and saturation option if diplay not active(too many options) #ifdef USERMOD_FOUR_LINE_DISPLAY - #define LAST_UI_STATE 8 + #define LAST_UI_STATE 11 #else #define LAST_UI_STATE 4 #endif @@ -366,19 +366,43 @@ public: if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) { //same speed as in button.cpp buttonWaitTime = 0; char newState = select_state + 1; - bool changedState = true; - if (newState > LAST_UI_STATE || (newState == 8 && presetHigh==0 && presetLow == 0)) newState = 0; + bool changedState = false; + char lineBuffer[64]; + do { + // finde new state + switch (newState) { + case 0: strcpy_P(lineBuffer, PSTR("Brightness")); changedState = true; break; + case 1: if (!extractModeSlider(effectCurrent, 0, lineBuffer, 63)) newState++; else changedState = true; break; // speed + case 2: if (!extractModeSlider(effectCurrent, 1, lineBuffer, 63)) newState++; else changedState = true; break; // intensity + case 3: strcpy_P(lineBuffer, PSTR("Color Palette")); changedState = true; break; + case 4: strcpy_P(lineBuffer, PSTR("Effect")); changedState = true; break; + case 5: strcpy_P(lineBuffer, PSTR("Main Color")); changedState = true; break; + case 6: strcpy_P(lineBuffer, PSTR("Saturation")); changedState = true; break; + case 7: + if (!(strip.getSegment(applyToAll ? strip.getFirstSelectedSegId() : strip.getMainSegmentId()).getLightCapabilities() & 0x04)) newState++; + else { strcpy_P(lineBuffer, PSTR("CCT")); changedState = true; } + break; + case 8: if (presetHigh==0 || presetLow == 0) newState++; else { strcpy_P(lineBuffer, PSTR("Preset")); changedState = true; } break; + case 9: + case 10: + case 11: if (!extractModeSlider(effectCurrent, newState-7, lineBuffer, 63)) newState++; else changedState = true; break; // custom + } + if (newState > LAST_UI_STATE) newState = 0; + } while (!changedState); if (display != nullptr) { switch (newState) { - case 0: changedState = changeState(PSTR("Brightness"), 1, 0, 1); break; //1 = sun - case 1: changedState = changeState(PSTR("Speed"), 1, 4, 2); break; //2 = skip forward - case 2: changedState = changeState(PSTR("Intensity"), 1, 8, 3); break; //3 = fire - case 3: changedState = changeState(PSTR("Color Palette"), 2, 0, 4); break; //4 = custom palette - case 4: changedState = changeState(PSTR("Effect"), 3, 0, 5); break; //5 = puzzle piece - case 5: changedState = changeState(PSTR("Main Color"), 255, 255, 7); break; //7 = brush - case 6: changedState = changeState(PSTR("Saturation"), 255, 255, 8); break; //8 = contrast - case 7: changedState = changeState(PSTR("CCT"), 255, 255, 10); break; //10 = star - case 8: changedState = changeState(PSTR("Preset"), 255, 255, 11); break; //11 = heart + case 0: changedState = changeState(lineBuffer, 1, 0, 1); break; //1 = sun + case 1: changedState = changeState(lineBuffer, 1, 4, 2); break; //2 = skip forward + case 2: changedState = changeState(lineBuffer, 1, 8, 3); break; //3 = fire + case 3: changedState = changeState(lineBuffer, 2, 0, 4); break; //4 = custom palette + case 4: changedState = changeState(lineBuffer, 3, 0, 5); break; //5 = puzzle piece + case 5: changedState = changeState(lineBuffer, 255, 255, 7); break; //7 = brush + case 6: changedState = changeState(lineBuffer, 255, 255, 8); break; //8 = contrast + case 7: changedState = changeState(lineBuffer, 255, 255, 10); break; //10 = star + case 8: changedState = changeState(lineBuffer, 255, 255, 11); break; //11 = heart + case 9: changedState = changeState(lineBuffer, 255, 255, 10); break; //10 = star + case 10: changedState = changeState(lineBuffer, 255, 255, 10); break; //10 = star + case 11: changedState = changeState(lineBuffer, 255, 255, 10); break; //10 = star } } if (changedState) select_state = newState; @@ -391,29 +415,35 @@ public: if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse { // B is high so clockwise switch(select_state) { - case 0: changeBrightness(true); break; - case 1: changeEffectSpeed(true); break; - case 2: changeEffectIntensity(true); break; - case 3: changePalette(true); break; - case 4: changeEffect(true); break; - case 5: changeHue(true); break; - case 6: changeSat(true); break; - case 7: changeCCT(true); break; - case 8: changePreset(true); break; + case 0: changeBrightness(true); break; + case 1: changeEffectSpeed(true); break; + case 2: changeEffectIntensity(true); break; + case 3: changePalette(true); break; + case 4: changeEffect(true); break; + case 5: changeHue(true); break; + case 6: changeSat(true); break; + case 7: changeCCT(true); break; + case 8: changePreset(true); break; + case 9: changeCustom(1,true); break; + case 10: changeCustom(2,true); break; + case 11: changeCustom(3,true); break; } } else if (Enc_B == HIGH) { // B is low so counter-clockwise switch(select_state) { - case 0: changeBrightness(false); break; - case 1: changeEffectSpeed(false); break; - case 2: changeEffectIntensity(false); break; - case 3: changePalette(false); break; - case 4: changeEffect(false); break; - case 5: changeHue(false); break; - case 6: changeSat(false); break; - case 7: changeCCT(false); break; - case 8: changePreset(false); break; + case 0: changeBrightness(false); break; + case 1: changeEffectSpeed(false); break; + case 2: changeEffectIntensity(false); break; + case 3: changePalette(false); break; + case 4: changeEffect(false); break; + case 5: changeHue(false); break; + case 6: changeSat(false); break; + case 7: changeCCT(false); break; + case 8: changePreset(false); break; + case 9: changeCustom(1,false); break; + case 10: changeCustom(2,false); break; + case 11: changeCustom(3,false); break; } } } @@ -569,6 +599,50 @@ public: } + void changeCustom(uint8_t par, bool increase) { + uint8_t val = 0; + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + stateChanged = true; + if (applyToAll) { + uint8_t id = strip.getFirstSelectedSegId(); + switch (par) { + case 3: val = strip.getSegment(id).custom3 = max(min((increase ? strip.getSegment(id).custom3+fadeAmount : strip.getSegment(id).custom3-fadeAmount), 255), 0); break; + case 2: val = strip.getSegment(id).custom2 = max(min((increase ? strip.getSegment(id).custom2+fadeAmount : strip.getSegment(id).custom2-fadeAmount), 255), 0); break; + default: val = strip.getSegment(id).custom1 = max(min((increase ? strip.getSegment(id).custom1+fadeAmount : strip.getSegment(id).custom1-fadeAmount), 255), 0); break; + } + for (byte i=0; ioverlay(lineBuffer, 500, 10); // use star + #endif + } + + void changePalette(bool increase) { #ifdef USERMOD_FOUR_LINE_DISPLAY if (display && display->wakeDisplay()) { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 060567cb7..ccc819d2a 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -278,6 +278,7 @@ bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); void releaseJSONBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); +uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen); uint16_t crc16(const unsigned char* data_p, size_t length); //wled_eeprom.cpp diff --git a/wled00/util.cpp b/wled00/util.cpp index b57d02e02..0a54b2ad2 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -234,7 +234,7 @@ void releaseJSONBufferLock() // caller must provide large enough buffer for name (incluing SR extensions)! uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen) { - if (src == JSON_mode_names) { + if (src == JSON_mode_names || src == nullptr) { if (mode < MODE_COUNT) { char lineBuffer[256]; //strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); @@ -281,6 +281,59 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe return strlen(dest); } + +// extracts effect slider data (1st group after @) +uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen) +{ + dest[0] = '\0'; // start by clearing buffer + + if (mode < MODE_COUNT) { + String lineBuffer = WS2812FX::_modeData[mode]; + if (lineBuffer.length() > 0) { + int16_t start = lineBuffer.indexOf('@'); + int16_t stop = lineBuffer.indexOf(';', start); + if (start>0 && stop>0) { + String names = lineBuffer.substring(start+1, stop); + int16_t nameBegin = 0, nameEnd; + for (size_t i=0; i<=slider; i++) { + const char *tmpstr; + dest[0] = '\0'; //clear dest buffer + if (i > 0 && nameBegin == 0) break; // there are no more names + nameEnd = names.indexOf(',', nameBegin); + if (names.charAt(nameBegin) == '!') { + switch (i) { + case 0: tmpstr = PSTR("FX Speed"); break; + case 1: tmpstr = PSTR("FX Intensity"); break; + case 2: tmpstr = PSTR("FX Custom 1"); break; + case 3: tmpstr = PSTR("FX Custom 2"); break; + case 4: tmpstr = PSTR("FX Custom 3"); break; + default: tmpstr = PSTR("FX Custom"); break; + } + } else { + if (nameEnd<0) tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name? + else tmpstr = names.substring(nameBegin, nameEnd).c_str(); + } + strncpy(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous) + nameBegin = nameEnd+1; // next name (if "," is not found it will be 0) + } // next slider + + // we have slider name (including default value) in the dest buffer + for (size_t i=0; i 0 +#ifdef ARDUINO_ARCH_ESP32 + esp_err_t watchdog = esp_task_wdt_init(WLED_WATCHDOG_TIMEOUT, true); + DEBUG_PRINT(F("Watchdog enabled: ")); + if (watchdog == ESP_OK) { + DEBUG_PRINTLN(F("OK")); + } else { + DEBUG_PRINTLN(watchdog); + return; + } + esp_task_wdt_add(NULL); +#else + ESP.wdtEnable(WLED_WATCHDOG_TIMEOUT * 1000); +#endif +#endif +} + +void WLED::disableWatchdog() { +#if WLED_WATCHDOG_TIMEOUT > 0 +DEBUG_PRINTLN(F("Watchdog: disabled")); +#ifdef ARDUINO_ARCH_ESP32 + esp_task_wdt_delete(NULL); +#else + ESP.wdtDisable(); +#endif +#endif +} + void WLED::setup() { #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) @@ -240,6 +269,8 @@ void WLED::setup() DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + enableWatchdog(); + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) if (psramFound()) { // GPIO16/GPIO17 reserved for SPI RAM @@ -337,8 +368,13 @@ void WLED::setup() #ifdef ESP8266 wifi_set_sleep_type(NONE_SLEEP_T); #endif + WLED::instance().disableWatchdog(); DEBUG_PRINTLN(F("Start ArduinoOTA")); }); + ArduinoOTA.onError([](ota_error_t error) { + // reenable watchdog on failed update + WLED::instance().enableWatchdog(); + }); if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); } diff --git a/wled00/wled.h b/wled00/wled.h index 970daa9d6..0c09d24ae 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -707,5 +707,7 @@ public: void initConnection(); void initInterfaces(); void handleStatusLED(); + void enableWatchdog(); + void disableWatchdog(); }; #endif // WLED_H diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index e40e20e47..67de51ccd 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -281,6 +281,7 @@ void initServer() if (!correctPIN || otaLock) return; if(!index){ DEBUG_PRINTLN(F("OTA Update Start")); + WLED::instance().disableWatchdog(); lastEditTime = millis(); // make sure PIN does not lock during update #ifdef ESP8266 Update.runAsync(true); @@ -293,6 +294,7 @@ void initServer() DEBUG_PRINTLN(F("Update Success")); } else { DEBUG_PRINTLN(F("Update Failed")); + WLED::instance().enableWatchdog(); } } });