Enhance rotary encoder with custom sliders.

Soft watchdog timer (by poelzi)
This commit is contained in:
Blaz Kristan 2022-05-24 13:45:35 +02:00
parent 34a4382920
commit 17be0a2c12
6 changed files with 199 additions and 31 deletions

View File

@ -47,7 +47,7 @@
// The last UI state, remove color and saturation option if diplay not active(too many options) // The last UI state, remove color and saturation option if diplay not active(too many options)
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
#define LAST_UI_STATE 8 #define LAST_UI_STATE 11
#else #else
#define LAST_UI_STATE 4 #define LAST_UI_STATE 4
#endif #endif
@ -366,19 +366,43 @@ public:
if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) { //same speed as in button.cpp if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) { //same speed as in button.cpp
buttonWaitTime = 0; buttonWaitTime = 0;
char newState = select_state + 1; char newState = select_state + 1;
bool changedState = true; bool changedState = false;
if (newState > LAST_UI_STATE || (newState == 8 && presetHigh==0 && presetLow == 0)) newState = 0; 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) { if (display != nullptr) {
switch (newState) { switch (newState) {
case 0: changedState = changeState(PSTR("Brightness"), 1, 0, 1); break; //1 = sun case 0: changedState = changeState(lineBuffer, 1, 0, 1); break; //1 = sun
case 1: changedState = changeState(PSTR("Speed"), 1, 4, 2); break; //2 = skip forward case 1: changedState = changeState(lineBuffer, 1, 4, 2); break; //2 = skip forward
case 2: changedState = changeState(PSTR("Intensity"), 1, 8, 3); break; //3 = fire case 2: changedState = changeState(lineBuffer, 1, 8, 3); break; //3 = fire
case 3: changedState = changeState(PSTR("Color Palette"), 2, 0, 4); break; //4 = custom palette case 3: changedState = changeState(lineBuffer, 2, 0, 4); break; //4 = custom palette
case 4: changedState = changeState(PSTR("Effect"), 3, 0, 5); break; //5 = puzzle piece case 4: changedState = changeState(lineBuffer, 3, 0, 5); break; //5 = puzzle piece
case 5: changedState = changeState(PSTR("Main Color"), 255, 255, 7); break; //7 = brush case 5: changedState = changeState(lineBuffer, 255, 255, 7); break; //7 = brush
case 6: changedState = changeState(PSTR("Saturation"), 255, 255, 8); break; //8 = contrast case 6: changedState = changeState(lineBuffer, 255, 255, 8); break; //8 = contrast
case 7: changedState = changeState(PSTR("CCT"), 255, 255, 10); break; //10 = star case 7: changedState = changeState(lineBuffer, 255, 255, 10); break; //10 = star
case 8: changedState = changeState(PSTR("Preset"), 255, 255, 11); break; //11 = heart 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; 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 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 { // B is high so clockwise
switch(select_state) { switch(select_state) {
case 0: changeBrightness(true); break; case 0: changeBrightness(true); break;
case 1: changeEffectSpeed(true); break; case 1: changeEffectSpeed(true); break;
case 2: changeEffectIntensity(true); break; case 2: changeEffectIntensity(true); break;
case 3: changePalette(true); break; case 3: changePalette(true); break;
case 4: changeEffect(true); break; case 4: changeEffect(true); break;
case 5: changeHue(true); break; case 5: changeHue(true); break;
case 6: changeSat(true); break; case 6: changeSat(true); break;
case 7: changeCCT(true); break; case 7: changeCCT(true); break;
case 8: changePreset(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) else if (Enc_B == HIGH)
{ // B is low so counter-clockwise { // B is low so counter-clockwise
switch(select_state) { switch(select_state) {
case 0: changeBrightness(false); break; case 0: changeBrightness(false); break;
case 1: changeEffectSpeed(false); break; case 1: changeEffectSpeed(false); break;
case 2: changeEffectIntensity(false); break; case 2: changeEffectIntensity(false); break;
case 3: changePalette(false); break; case 3: changePalette(false); break;
case 4: changeEffect(false); break; case 4: changeEffect(false); break;
case 5: changeHue(false); break; case 5: changeHue(false); break;
case 6: changeSat(false); break; case 6: changeSat(false); break;
case 7: changeCCT(false); break; case 7: changeCCT(false); break;
case 8: changePreset(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; i<strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || i == id) continue;
switch (par) {
case 3: strip.getSegment(i).custom3 = strip.getSegment(id).custom3; break;
case 2: strip.getSegment(i).custom2 = strip.getSegment(id).custom2; break;
default: strip.getSegment(i).custom1 = strip.getSegment(id).custom1; break;
}
}
} else {
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
switch (par) {
case 3: val = seg.custom3 = max(min((increase ? seg.custom3+fadeAmount : seg.custom3-fadeAmount), 255), 0); break;
case 2: val = seg.custom2 = max(min((increase ? seg.custom2+fadeAmount : seg.custom2-fadeAmount), 255), 0); break;
default: val = seg.custom1 = max(min((increase ? seg.custom1+fadeAmount : seg.custom1-fadeAmount), 255), 0); break;
}
}
lampUdated();
#ifdef USERMOD_FOUR_LINE_DISPLAY
char lineBuffer[64];
sprintf(lineBuffer, "%d", val);
display->overlay(lineBuffer, 500, 10); // use star
#endif
}
void changePalette(bool increase) { void changePalette(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {

View File

@ -278,6 +278,7 @@ bool isAsterisksOnly(const char* str, byte maxLen);
bool requestJSONBufferLock(uint8_t module=255); bool requestJSONBufferLock(uint8_t module=255);
void releaseJSONBufferLock(); void releaseJSONBufferLock();
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); 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); uint16_t crc16(const unsigned char* data_p, size_t length);
//wled_eeprom.cpp //wled_eeprom.cpp

View File

@ -234,7 +234,7 @@ void releaseJSONBufferLock()
// caller must provide large enough buffer for name (incluing SR extensions)! // 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) 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) { if (mode < MODE_COUNT) {
char lineBuffer[256]; char lineBuffer[256];
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); //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); 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<strlen(dest); i++) if (dest[i]=='=') { dest[i]='\0'; break; } // truncate default value
} else {
// defaults to just speed and intensity since there is no slider data
switch (slider) {
case 0: strncpy_P(dest, PSTR("FX Speed"), maxLen); break;
case 1: strncpy_P(dest, PSTR("FX Intensity"), maxLen); break;
}
}
}
return strlen(dest);
}
return 0;
}
uint16_t crc16(const unsigned char* data_p, size_t length) { uint16_t crc16(const unsigned char* data_p, size_t length) {
uint8_t x; uint8_t x;
uint16_t crc = 0xFFFF; uint16_t crc = 0xFFFF;

View File

@ -216,6 +216,35 @@ void WLED::loop()
toki.resetTick(); toki.resetTick();
} }
void WLED::enableWatchdog() {
#if WLED_WATCHDOG_TIMEOUT > 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() void WLED::setup()
{ {
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
@ -240,6 +269,8 @@ void WLED::setup()
DEBUG_PRINT(F("heap ")); DEBUG_PRINT(F("heap "));
DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINTLN(ESP.getFreeHeap());
enableWatchdog();
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if (psramFound()) { if (psramFound()) {
// GPIO16/GPIO17 reserved for SPI RAM // GPIO16/GPIO17 reserved for SPI RAM
@ -337,8 +368,13 @@ void WLED::setup()
#ifdef ESP8266 #ifdef ESP8266
wifi_set_sleep_type(NONE_SLEEP_T); wifi_set_sleep_type(NONE_SLEEP_T);
#endif #endif
WLED::instance().disableWatchdog();
DEBUG_PRINTLN(F("Start ArduinoOTA")); DEBUG_PRINTLN(F("Start ArduinoOTA"));
}); });
ArduinoOTA.onError([](ota_error_t error) {
// reenable watchdog on failed update
WLED::instance().enableWatchdog();
});
if (strlen(cmDNS) > 0) if (strlen(cmDNS) > 0)
ArduinoOTA.setHostname(cmDNS); ArduinoOTA.setHostname(cmDNS);
} }

View File

@ -707,5 +707,7 @@ public:
void initConnection(); void initConnection();
void initInterfaces(); void initInterfaces();
void handleStatusLED(); void handleStatusLED();
void enableWatchdog();
void disableWatchdog();
}; };
#endif // WLED_H #endif // WLED_H

View File

@ -281,6 +281,7 @@ void initServer()
if (!correctPIN || otaLock) return; if (!correctPIN || otaLock) return;
if(!index){ if(!index){
DEBUG_PRINTLN(F("OTA Update Start")); DEBUG_PRINTLN(F("OTA Update Start"));
WLED::instance().disableWatchdog();
lastEditTime = millis(); // make sure PIN does not lock during update lastEditTime = millis(); // make sure PIN does not lock during update
#ifdef ESP8266 #ifdef ESP8266
Update.runAsync(true); Update.runAsync(true);
@ -293,6 +294,7 @@ void initServer()
DEBUG_PRINTLN(F("Update Success")); DEBUG_PRINTLN(F("Update Success"));
} else { } else {
DEBUG_PRINTLN(F("Update Failed")); DEBUG_PRINTLN(F("Update Failed"));
WLED::instance().enableWatchdog();
} }
} }
}); });