From 7a64a4a6bf46711f8507ab66d61ba42529b568d3 Mon Sep 17 00:00:00 2001 From: Max Prokhorov Date: Thu, 15 Oct 2020 19:55:23 +0300 Subject: [PATCH] btn: generate pressed & released events from switch changes (#2379) - Add ::Released button event to be used specifically with switches, opposite of ::Pressed - Always use default state for switches instead of ignoring it and using current pin reading as value. This allows us to boot with the switch held in the opposite state and trigger the correct event immediately (meaning, switches now depend on the BUTTON_DEFAULT_HIGH presence to detect the default position) - BREAKING: Fixup hardware.h. Any custom board needs manual changes. - BREAKING: Rework MQTT button messages to send text from debug messages instead of numeric code --- code/espurna/DebounceEvent.cpp | 8 ++-- code/espurna/button.cpp | 74 +++++++++---------------------- code/espurna/button.h | 17 +++---- code/espurna/button_config.h | 13 ++++++ code/espurna/config/defaults.h | 25 +++++++++++ code/espurna/config/hardware.h | 51 ++++++++++++++------- code/espurna/config/types.h | 4 +- code/espurna/libs/DebounceEvent.h | 1 - 8 files changed, 109 insertions(+), 84 deletions(-) diff --git a/code/espurna/DebounceEvent.cpp b/code/espurna/DebounceEvent.cpp index ae7bc571..ef45e1a1 100644 --- a/code/espurna/DebounceEvent.cpp +++ b/code/espurna/DebounceEvent.cpp @@ -42,7 +42,7 @@ EventEmitter::EventEmitter(types::Pin pin, types::EventHandler callback, const t _default_value(config.default_value == types::PinValue::High), _delay(debounce_delay), _repeat(repeat), - _value(false), + _value(_default_value), _ready(false), _reset_count(true), _event_start(0), @@ -70,8 +70,6 @@ EventEmitter::EventEmitter(types::Pin pin, types::EventHandler callback, const t } else { _pin->pinMode(INPUT); } - - _value = _is_switch ? (_pin->digitalRead() == (HIGH)) : _default_value; } EventEmitter::EventEmitter(types::Pin pin, const types::Config& config, unsigned long delay, unsigned long repeat) : @@ -119,7 +117,9 @@ types::Event EventEmitter::loop() { _value = !_value; if (_is_switch) { - event = types::EventChanged; + event = isPressed() + ? types::EventPressed + : types::EventReleased; } else { if (_value == _default_value) { _event_length = millis() - _event_start; diff --git a/code/espurna/button.cpp b/code/espurna/button.cpp index 0db0b36e..19eb1cfb 100644 --- a/code/espurna/button.cpp +++ b/code/espurna/button.cpp @@ -141,6 +141,7 @@ constexpr const debounce_event::types::Config _buttonDecodeConfigBitmask(const u constexpr const button_action_t _buttonDecodeEventAction(const button_actions_t& actions, button_event_t event) { return ( (event == button_event_t::Pressed) ? actions.pressed : + (event == button_event_t::Released) ? actions.released : (event == button_event_t::Click) ? actions.click : (event == button_event_t::DoubleClick) ? actions.dblclick : (event == button_event_t::LongClick) ? actions.lngclick : @@ -151,6 +152,7 @@ constexpr const button_action_t _buttonDecodeEventAction(const button_actions_t& constexpr const button_event_t _buttonMapReleased(uint8_t count, unsigned long length, unsigned long lngclick_delay, unsigned long lnglngclick_delay) { return ( + (0 == count) ? button_event_t::Released : (1 == count) ? ( (length > lnglngclick_delay) ? button_event_t::LongLongClick : (length > lngclick_delay) ? button_event_t::LongClick : button_event_t::Click @@ -164,6 +166,7 @@ constexpr const button_event_t _buttonMapReleased(uint8_t count, unsigned long l button_actions_t _buttonConstructActions(unsigned char index) { return { _buttonPress(index), + _buttonRelease(index), _buttonClick(index), _buttonDoubleClick(index), _buttonLongClick(index), @@ -220,20 +223,10 @@ bool button_t::state() { } button_event_t button_t::loop() { - if (!event_emitter) { - return button_event_t::None; - } - - auto event = event_emitter->loop(); - if (event == debounce_event::types::EventNone) { - return button_event_t::None; - } - - switch (event) { + if (event_emitter) { + switch (event_emitter->loop()) { case debounce_event::types::EventPressed: return button_event_t::Pressed; - case debounce_event::types::EventChanged: - return button_event_t::Click; case debounce_event::types::EventReleased: { return _buttonMapReleased( event_emitter->getEventCount(), @@ -243,8 +236,8 @@ button_event_t button_t::loop() { ); } case debounce_event::types::EventNone: - default: break; + } } return button_event_t::None; @@ -267,13 +260,6 @@ std::bitset _buttons_mqtt_retain( (1 == BUTTON_MQTT_RETAIN) ? 0xFFFFFFFFUL : 0UL ); -void buttonMQTT(unsigned char id, button_event_t event) { - char payload[4] = {0}; - itoa(_buttonEventNumber(event), payload, 10); - // mqttSend(topic, id, payload, force, retain) - mqttSend(MQTT_TOPIC_BUTTON, id, payload, false, _buttons_mqtt_retain[id]); -} - #endif #if WEB_SUPPORT @@ -391,60 +377,40 @@ button_action_t buttonAction(unsigned char id, const button_event_t event) { return _buttonDecodeEventAction(_buttons[id].actions, event); } -// Approach based on https://github.com/esp8266/Arduino/pull/6950 -// "PROGMEM footprint cleanup for responseCodeToString (#6950)" +// Note that we don't directly return F(...), but use a temporary to assign it conditionally +// (ref. https://github.com/esp8266/Arduino/pull/6950 "PROGMEM footprint cleanup for responseCodeToString") // In this particular case, saves 76 bytes (120 vs 44) -#if 1 String _buttonEventString(button_event_t event) { const __FlashStringHelper* ptr = nullptr; switch (event) { case button_event_t::Pressed: - ptr = F("Pressed"); + ptr = F("pressed"); + break; + case button_event_t::Released: + ptr = F("released"); break; case button_event_t::Click: - ptr = F("Click"); + ptr = F("click"); break; case button_event_t::DoubleClick: - ptr = F("Double-click"); + ptr = F("double-click"); break; case button_event_t::LongClick: - ptr = F("Long-click"); + ptr = F("long-click"); break; case button_event_t::LongLongClick: - ptr = F("Looong-click"); + ptr = F("looong-click"); break; case button_event_t::TripleClick: - ptr = F("Triple-click"); + ptr = F("triple-click"); break; case button_event_t::None: - default: - ptr = F("None"); + ptr = F("none"); break; } return String(ptr); } -#else -String _buttonEventString(button_event_t event) { - switch (event) { - case button_event_t::Pressed: - return F("Pressed"); - case button_event_t::Click: - return F("Click"); - case button_event_t::DoubleClick: - return F("Double-click"); - case button_event_t::LongClick: - return F("Long-click"); - case button_event_t::LongLongClick: - return F("Looong-click"); - case button_event_t::TripleClick: - return F("Triple-click"); - case button_event_t::None: - default: - return F("None"); - } -} -#endif void buttonEvent(unsigned char id, button_event_t event) { @@ -462,7 +428,7 @@ void buttonEvent(unsigned char id, button_event_t event) { #if MQTT_SUPPORT if (action || _buttons_mqtt_send_all[id]) { - buttonMQTT(id, event); + mqttSend(MQTT_TOPIC_BUTTON, id, _buttonEventString(event).c_str(), false, _buttons_mqtt_retain[id]); } #endif @@ -828,6 +794,7 @@ void buttonSetup() { for (unsigned char index = 0; index < buttons; ++index) { const button_actions_t actions { + BUTTON_ACTION_NONE, BUTTON_ACTION_NONE, // The only generated event is ::Click getSetting({"btnClick", index}, _buttonClick(index)), @@ -872,6 +839,7 @@ void buttonSetup() { const button_actions_t actions { getSetting({"btnPress", index}, _buttonPress(index)), + getSetting({"btnRlse", index}, _buttonRelease(index)), getSetting({"btnClick", index}, _buttonClick(index)), getSetting({"btnDclk", index}, _buttonDoubleClick(index)), getSetting({"btnLclk", index}, _buttonLongClick(index)), diff --git a/code/espurna/button.h b/code/espurna/button.h index 951c8cc4..0acdddc2 100644 --- a/code/espurna/button.h +++ b/code/espurna/button.h @@ -23,17 +23,19 @@ constexpr size_t ButtonsMax = 32; using button_action_t = uint8_t; enum class button_event_t { - None = 0, - Pressed = 1, - Click = 2, - DoubleClick = 3, - LongClick = 4, - LongLongClick = 5, - TripleClick = 6 + None, + Pressed, + Released, + Click, + DoubleClick, + LongClick, + LongLongClick, + TripleClick }; struct button_actions_t { button_action_t pressed; + button_action_t released; button_action_t click; button_action_t dblclick; button_action_t lngclick; @@ -74,7 +76,6 @@ BrokerDeclare(ButtonBroker, void(unsigned char id, button_event_t event)); bool buttonState(unsigned char id); button_action_t buttonAction(unsigned char id, const button_event_t event); -void buttonMQTT(unsigned char id, button_event_t event); void buttonEvent(unsigned char id, button_event_t event); unsigned char buttonCount(); diff --git a/code/espurna/button_config.h b/code/espurna/button_config.h index 66e07bd9..ebcbad46 100644 --- a/code/espurna/button_config.h +++ b/code/espurna/button_config.h @@ -46,6 +46,19 @@ constexpr const unsigned char _buttonConfigBitmask(unsigned char index) { ); } +constexpr const unsigned char _buttonRelease(unsigned char index) { + return ( + (index == 0) ? BUTTON1_RELEASE : + (index == 1) ? BUTTON2_RELEASE : + (index == 2) ? BUTTON3_RELEASE : + (index == 3) ? BUTTON4_RELEASE : + (index == 4) ? BUTTON5_RELEASE : + (index == 5) ? BUTTON6_RELEASE : + (index == 6) ? BUTTON7_RELEASE : + (index == 7) ? BUTTON8_RELEASE : BUTTON_ACTION_NONE + ); +} + constexpr const unsigned char _buttonPress(unsigned char index) { return ( (index == 0) ? BUTTON1_PRESS : diff --git a/code/espurna/config/defaults.h b/code/espurna/config/defaults.h index 789eda5b..d77fc3d6 100644 --- a/code/espurna/config/defaults.h +++ b/code/espurna/config/defaults.h @@ -83,6 +83,31 @@ #define BUTTON8_PRESS BUTTON_ACTION_NONE #endif +#ifndef BUTTON1_RELEASE +#define BUTTON1_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON2_RELEASE +#define BUTTON2_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON3_RELEASE +#define BUTTON3_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON4_RELEASE +#define BUTTON4_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON5_RELEASE +#define BUTTON5_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON6_RELEASE +#define BUTTON6_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON7_RELEASE +#define BUTTON7_RELEASE BUTTON_ACTION_NONE +#endif +#ifndef BUTTON8_RELEASE +#define BUTTON8_RELEASE BUTTON_ACTION_NONE +#endif + #ifndef BUTTON1_CLICK #define BUTTON1_CLICK BUTTON_ACTION_TOGGLE #endif diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h index 080a98c5..082db49e 100644 --- a/code/espurna/config/hardware.h +++ b/code/espurna/config/hardware.h @@ -1682,11 +1682,16 @@ // Buttons #define BUTTON1_PIN 5 - #define BUTTON2_PIN 4 #define BUTTON1_RELAY 1 - #define BUTTON2_RELAY 2 #define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF + + #define BUTTON2_PIN 4 + #define BUTTON2_RELAY 2 #define BUTTON2_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP + #define BUTTON2_PRESS BUTTON_ACTION_ON + #define BUTTON2_RELEASE BUTTON_ACTION_OFF // Relays #define RELAY1_PIN 14 @@ -2560,11 +2565,8 @@ #define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_SET_PULLUP | BUTTON_DEFAULT_HIGH #define BUTTON1_RELAY 1 - #define BUTTON1_PRESS BUTTON_ACTION_NONE - #define BUTTON1_CLICK BUTTON_ACTION_TOGGLE - #define BUTTON1_DBLCLICK BUTTON_ACTION_NONE - #define BUTTON1_LNGCLICK BUTTON_ACTION_NONE - #define BUTTON1_LNGLNGCLICK BUTTON_ACTION_NONE + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF // Relays #define RELAY1_PIN 5 // D1 @@ -2842,17 +2844,15 @@ #define BUTTON1_RELAY 1 #define BUTTON1_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH //Hardware Pullup - #define BUTTON1_PRESS BUTTON_ACTION_NONE - #define BUTTON1_CLICK BUTTON_ACTION_TOGGLE - #define BUTTON1_DBLCLICK BUTTON_ACTION_NONE - #define BUTTON1_LNGCLICK BUTTON_ACTION_NONE - #define BUTTON1_LNGLNGCLICK BUTTON_ACTION_NONE + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF #define BUTTON2_PIN 13 #define BUTTON2_RELAY 2 #define BUTTON2_CONFIG BUTTON_SWITCH | BUTTON_DEFAULT_HIGH //Hardware Pullup - #define BUTTON2_CLICK BUTTON_ACTION_TOGGLE + #define BUTTON2_PRESS BUTTON_ACTION_ON + #define BUTTON2_RELEASE BUTTON_ACTION_OFF // Relays #define RELAY1_PIN 4 @@ -3664,6 +3664,9 @@ #define BUTTON1_CONFIG BUTTON_SWITCH #define BUTTON1_RELAY 1 + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF + // Relays #define RELAY1_PIN 4 #define RELAY1_TYPE RELAY_TYPE_NORMAL @@ -3676,12 +3679,19 @@ // Buttons #define BUTTON1_PIN 12 - #define BUTTON2_PIN 14 - #define BUTTON1_CONFIG BUTTON_SWITCH - #define BUTTON2_CONFIG BUTTON_SWITCH #define BUTTON1_RELAY 1 + #define BUTTON1_CONFIG BUTTON_SWITCH + + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF + + #define BUTTON2_PIN 14 + #define BUTTON2_CONFIG BUTTON_SWITCH #define BUTTON2_RELAY 2 + #define BUTTON2_PRESS BUTTON_ACTION_ON + #define BUTTON2_RELEASE BUTTON_ACTION_OFF + // Relays #define RELAY1_PIN 4 #define RELAY1_TYPE RELAY_TYPE_NORMAL @@ -3698,6 +3708,9 @@ #define BUTTON1_CONFIG BUTTON_SWITCH #define BUTTON1_RELAY 1 + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF + #define BUTTON2_PIN 2 #define BUTTON2_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH #define BUTTON2_LNGCLICK BUTTON_ACTION_RESET @@ -3741,10 +3754,16 @@ #define BUTTON1_CONFIG BUTTON_SWITCH #define BUTTON1_RELAY 1 + #define BUTTON1_PRESS BUTTON_ACTION_ON + #define BUTTON1_RELEASE BUTTON_ACTION_OFF + #define BUTTON2_PIN 5 #define BUTTON2_CONFIG BUTTON_SWITCH #define BUTTON2_RELAY 2 + #define BUTTON2_PRESS BUTTON_ACTION_ON + #define BUTTON2_RELEASE BUTTON_ACTION_OFF + #define BUTTON3_PIN 2 #define BUTTON3_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH #define BUTTON3_LNGCLICK BUTTON_ACTION_RESET diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 08ccacbc..241a7fb9 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -19,7 +19,7 @@ // BUTTONS //------------------------------------------------------------------------------ -// button actions, limited to 4-bit number (0b1111 / 0xf / 15) +// button actions, limited to 8-bit number (0b11111111 / 0xff / 255) #define BUTTON_ACTION_NONE 0u #define BUTTON_ACTION_TOGGLE 1u #define BUTTON_ACTION_ON 2u @@ -33,7 +33,7 @@ #define BUTTON_ACTION_DIM_UP 10u #define BUTTON_ACTION_DIM_DOWN 11u #define BUTTON_ACTION_DISPLAY_ON 12u -#define BUTTON_ACTION_MAX 15u +#define BUTTON_ACTION_MAX 255u // Deprecated: legacy mapping, changed to action from above #define BUTTON_MODE_NONE BUTTON_ACTION_NONE diff --git a/code/espurna/libs/DebounceEvent.h b/code/espurna/libs/DebounceEvent.h index 473cea7f..d19aca34 100644 --- a/code/espurna/libs/DebounceEvent.h +++ b/code/espurna/libs/DebounceEvent.h @@ -69,7 +69,6 @@ namespace types { enum Event { EventNone, - EventChanged, EventPressed, EventReleased };