diff --git a/code/espurna/button.cpp b/code/espurna/button.cpp index 6de0b492..f851f105 100644 --- a/code/espurna/button.cpp +++ b/code/espurna/button.cpp @@ -16,6 +16,7 @@ Copyright (C) 2019-2021 by Maxim Prokhorov , 4> ButtonProviderOptions PROGMEM { +static constexpr std::array, 5> ButtonProviderOptions PROGMEM { {{ButtonProvider::None, None}, {ButtonProvider::Dummy, Dummy}, {ButtonProvider::Gpio, Gpio}, - {ButtonProvider::Analog, Analog}} + {ButtonProvider::Analog, Analog}, + {ButtonProvider::Lightfox, Lightfox}} }; [[gnu::unused]] PROGMEM_STRING(Toggle, "relay-toggle"); @@ -1418,6 +1422,14 @@ ButtonEventDelays _buttonDelays(size_t index) { .lnglngclick = espurna::button::settings::longLongClickDelay(index)}; } +void _buttonAddWithPin(size_t index, BasePinPtr&& pin) { + espurna::button::internal::buttons.emplace_back( + std::move(pin), + _buttonRuntimeConfig(index), + _buttonActions(index), + _buttonDelays(index)); +} + bool _buttonSetupProvider(size_t index, ButtonProvider provider) { bool result { false }; @@ -1437,16 +1449,19 @@ bool _buttonSetupProvider(size_t index, ButtonProvider provider) { break; } - espurna::button::internal::buttons.emplace_back( - std::move(pin), - _buttonRuntimeConfig(index), - _buttonActions(index), - _buttonDelays(index)); + _buttonAddWithPin(index, std::move(pin)); result = true; #endif break; } + case ButtonProvider::Lightfox: +#ifdef FOXEL_LIGHTFOX_DUAL + _buttonAddWithPin(index, lightfoxMakeButtonPin(index)); + result = true; +#endif + break; + case ButtonProvider::None: break; @@ -1464,18 +1479,6 @@ void _buttonSettingsMigrate(int version) { } // namespace -bool buttonAdd() { - const size_t index { buttonCount() }; - if ((index + 1) < ButtonsMax) { - espurna::button::internal::buttons.emplace_back( - _buttonActions(index), - _buttonDelays(index)); - return true; - } - - return false; -} - void buttonSetup() { migrateVersion(_buttonSettingsMigrate); espurna::button::settings::query::setup(); diff --git a/code/espurna/button.h b/code/espurna/button.h index df4e5ee6..c28cc43e 100644 --- a/code/espurna/button.h +++ b/code/espurna/button.h @@ -57,7 +57,5 @@ ButtonAction buttonAction(size_t id, const ButtonEvent event); void buttonEvent(size_t id, ButtonEvent event); void buttonOnEvent(ButtonEventHandler); -bool buttonAdd(); - size_t buttonCount(); void buttonSetup(); diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h index a37791c6..7f074227 100644 --- a/code/espurna/config/hardware.h +++ b/code/espurna/config/hardware.h @@ -4497,16 +4497,20 @@ #define RELAY2_PROVIDER RELAY_PROVIDER_LIGHTFOX // Buttons - #define LIGHTFOX_BUTTONS 4 - + #define BUTTON1_PROVIDER BUTTON_PROVIDER_LIGHTFOX #define BUTTON1_CLICK BUTTON_ACTION_TOGGLE - #define BUTTON2_CLICK BUTTON_ACTION_TOGGLE - #define BUTTON3_CLICK BUTTON_ACTION_TOGGLE - #define BUTTON4_CLICK BUTTON_ACTION_TOGGLE - #define BUTTON1_RELAY 1 + + #define BUTTON2_PROVIDER BUTTON_PROVIDER_LIGHTFOX + #define BUTTON2_CLICK BUTTON_ACTION_TOGGLE #define BUTTON2_RELAY 2 + + #define BUTTON3_PROVIDER BUTTON_PROVIDER_LIGHTFOX + #define BUTTON3_CLICK BUTTON_ACTION_TOGGLE #define BUTTON3_RELAY 2 + + #define BUTTON4_PROVIDER BUTTON_PROVIDER_LIGHTFOX + #define BUTTON4_CLICK BUTTON_ACTION_TOGGLE #define BUTTON4_RELAY 1 // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 96e4dbd0..58180131 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -61,8 +61,10 @@ // configure where do we get the button events #define BUTTON_PROVIDER_NONE ButtonProvider::None +#define BUTTON_PROVIDER_DUMMY ButtonProvider::Dummy #define BUTTON_PROVIDER_GPIO ButtonProvider::Gpio #define BUTTON_PROVIDER_ANALOG ButtonProvider::Analog +#define BUTTON_PROVIDER_LIGHTFOX ButtonProvider::Lightfox //------------------------------------------------------------------------------ // ENCODER diff --git a/code/espurna/lightfox.cpp b/code/espurna/lightfox.cpp index 194ac337..4c81cc47 100644 --- a/code/espurna/lightfox.cpp +++ b/code/espurna/lightfox.cpp @@ -22,10 +22,6 @@ static_assert(1 == (BUTTON_SUPPORT), ""); #include #include -#ifndef LIGHTFOX_BUTTONS -#define LIGHTFOX_BUTTONS 4 -#endif - #ifndef LIGHTFOX_PORT #define LIGHTFOX_PORT 1 #endif @@ -37,10 +33,6 @@ namespace { namespace build { -constexpr size_t buttons() { - return LIGHTFOX_BUTTONS; -} - constexpr size_t port() { return LIGHTFOX_PORT - 1; } @@ -53,9 +45,6 @@ namespace internal { Stream* port { nullptr }; -size_t button_offset { 0 }; -size_t buttons { 0 }; - } // namespace internal constexpr uint8_t CodeStart { 0xa0 }; @@ -213,30 +202,99 @@ void setup() { // ----------------------------------------------------------------------------- -void loop() { - if (internal::port->available() < 4) { - return; +class ButtonPin final : public BasePin { +public: + ButtonPin() = delete; + explicit ButtonPin(size_t index) : + _index(index) + { + _readings.push_back(Reading{}); } - unsigned char bytes[4] = {0}; - internal::port->readBytes(bytes, 4); - if ((bytes[0] != 0xA0) && (bytes[1] != 0x04) && (bytes[3] != 0xA1)) { - return; + String description() const override { + String out; + + out += STRING_VIEW("lightfox id:"); + out += _index; + out += STRING_VIEW(" status:#"); + out += _readings[_index].status ? 't' : 'f'; + + return out; } - // Unlike DUAL, inputs may have different IDs than the outputs - // ref. https://github.com/foxel/esp-dual-rf-switch - constexpr unsigned long InputsMask { 0xf }; - unsigned long mask { static_cast(bytes[2]) & InputsMask }; - unsigned long id { 0 }; + static void loop() { + const auto now = TimeSource::now(); - for (size_t button = 0; id < internal::buttons; ++button) { - if (mask & (1ul << button)) { - buttonEvent(button + internal::button_offset, ButtonEvent::Click); + // Emulate 'Click' behaviour by expiring our readings + // But, unlike previous version, we could make either a switch or a button + for (auto& reading : _readings) { + if (reading.status && ((now - reading.last) > ReadInterval)) { + reading.status = false; + } + } + + if (internal::port->available() < 4) { + return; + } + + uint8_t bytes[4] = {0}; + internal::port->readBytes(bytes, 4); + if ((bytes[0] != 0xA0) && (bytes[1] != 0x04) && (bytes[3] != 0xA1)) { + return; + } + + // Unlike DUAL, inputs may have different IDs than the outputs + // ref. https://github.com/foxel/esp-dual-rf-switch + static constexpr uint8_t Digits { std::numeric_limits::digits }; + const auto mask = bytes[2]; + + for (uint8_t index = 0; index < Digits; ++index) { + if (((mask & index) > 0) && (index < _readings.size())) { + _readings[index].status = true; + _readings[index].last = now; + } } } + + unsigned char pin() const override { + return _index; + } + + const char* id() const override { + return "LightfoxPin"; + } + + // Simulate LOW level when the range matches and HIGH when it does not + int digitalRead() override { + return _readings[_index].status; + } + + void pinMode(int8_t) override { + } + + void digitalWrite(int8_t val) override { + } + +private: + using TimeSource = time::SystemClock; + static constexpr TimeSource::duration ReadInterval + = duration::Milliseconds{ 100 }; + + struct Reading { + bool status { false }; + TimeSource::time_point last; + }; + + size_t _index; + static std::vector _readings; +}; + +BasePinPtr make_button(size_t index) { + return std::make_unique(index); } +std::vector ButtonPin::_readings; + void setup() { const auto port = uartPort(build::port()); if (!port) { @@ -252,14 +310,7 @@ void setup() { terminal::setup(); #endif - internal::button_offset = buttonCount(); - for (size_t index = 0; index < build::buttons(); ++index) { - if (buttonAdd()) { - ++internal::buttons; - } - } - - ::espurnaRegisterLoop(lightfox::loop); + ::espurnaRegisterLoop(ButtonPin::loop); } } // namespace @@ -267,6 +318,10 @@ void setup() { } // namespace hardware } // namespace espurna +BasePinPtr lightfoxMakeButtonPin(size_t index) { + return espurna::hardware::lightfox::make_button(index); +} + RelayProviderBasePtr lightfoxMakeRelayProvider(size_t index) { return espurna::hardware::lightfox::make_relay(index); } diff --git a/code/espurna/lightfox.h b/code/espurna/lightfox.h index b843a002..138e8b2f 100644 --- a/code/espurna/lightfox.h +++ b/code/espurna/lightfox.h @@ -14,4 +14,7 @@ Copyright (C) 2019 by Andrey F. Kupreychik class RelayProviderBase; std::unique_ptr lightfoxMakeRelayProvider(size_t); +class BasePin; +std::unique_ptr lightfoxMakeButtonPin(size_t); + void lightfoxSetup();