Browse Source

lightfox: button provider experiments

another pin provider, similar to analogpin
instead of generating events, use last serial reading (with a timeout)
pull/2575/head
Maxim Prokhorov 1 year ago
parent
commit
dca13574d9
6 changed files with 127 additions and 62 deletions
  1. +23
    -20
      code/espurna/button.cpp
  2. +0
    -2
      code/espurna/button.h
  3. +10
    -6
      code/espurna/config/hardware.h
  4. +2
    -0
      code/espurna/config/types.h
  5. +89
    -34
      code/espurna/lightfox.cpp
  6. +3
    -0
      code/espurna/lightfox.h

+ 23
- 20
code/espurna/button.cpp View File

@ -16,6 +16,7 @@ Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com
#include "fan.h" #include "fan.h"
#include "gpio.h" #include "gpio.h"
#include "light.h" #include "light.h"
#include "lightfox.h"
#include "mqtt.h" #include "mqtt.h"
#include "relay.h" #include "relay.h"
#include "system.h" #include "system.h"
@ -35,7 +36,8 @@ enum class ButtonProvider {
None, None,
Dummy, Dummy,
Gpio, Gpio,
Analog
Analog,
Lightfox,
}; };
struct ButtonActions { struct ButtonActions {
@ -147,12 +149,14 @@ PROGMEM_STRING(None, "none");
PROGMEM_STRING(Dummy, "dummy"); PROGMEM_STRING(Dummy, "dummy");
PROGMEM_STRING(Gpio, "gpio"); PROGMEM_STRING(Gpio, "gpio");
PROGMEM_STRING(Analog, "analog"); PROGMEM_STRING(Analog, "analog");
PROGMEM_STRING(Lightfox, "lightfox");
static constexpr std::array<Enumeration<ButtonProvider>, 4> ButtonProviderOptions PROGMEM {
static constexpr std::array<Enumeration<ButtonProvider>, 5> ButtonProviderOptions PROGMEM {
{{ButtonProvider::None, None}, {{ButtonProvider::None, None},
{ButtonProvider::Dummy, Dummy}, {ButtonProvider::Dummy, Dummy},
{ButtonProvider::Gpio, Gpio}, {ButtonProvider::Gpio, Gpio},
{ButtonProvider::Analog, Analog}}
{ButtonProvider::Analog, Analog},
{ButtonProvider::Lightfox, Lightfox}}
}; };
[[gnu::unused]] PROGMEM_STRING(Toggle, "relay-toggle"); [[gnu::unused]] PROGMEM_STRING(Toggle, "relay-toggle");
@ -1418,6 +1422,14 @@ ButtonEventDelays _buttonDelays(size_t index) {
.lnglngclick = espurna::button::settings::longLongClickDelay(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 _buttonSetupProvider(size_t index, ButtonProvider provider) {
bool result { false }; bool result { false };
@ -1437,16 +1449,19 @@ bool _buttonSetupProvider(size_t index, ButtonProvider provider) {
break; break;
} }
espurna::button::internal::buttons.emplace_back(
std::move(pin),
_buttonRuntimeConfig(index),
_buttonActions(index),
_buttonDelays(index));
_buttonAddWithPin(index, std::move(pin));
result = true; result = true;
#endif #endif
break; break;
} }
case ButtonProvider::Lightfox:
#ifdef FOXEL_LIGHTFOX_DUAL
_buttonAddWithPin(index, lightfoxMakeButtonPin(index));
result = true;
#endif
break;
case ButtonProvider::None: case ButtonProvider::None:
break; break;
@ -1464,18 +1479,6 @@ void _buttonSettingsMigrate(int version) {
} // namespace } // 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() { void buttonSetup() {
migrateVersion(_buttonSettingsMigrate); migrateVersion(_buttonSettingsMigrate);
espurna::button::settings::query::setup(); espurna::button::settings::query::setup();


+ 0
- 2
code/espurna/button.h View File

@ -57,7 +57,5 @@ ButtonAction buttonAction(size_t id, const ButtonEvent event);
void buttonEvent(size_t id, ButtonEvent event); void buttonEvent(size_t id, ButtonEvent event);
void buttonOnEvent(ButtonEventHandler); void buttonOnEvent(ButtonEventHandler);
bool buttonAdd();
size_t buttonCount(); size_t buttonCount();
void buttonSetup(); void buttonSetup();

+ 10
- 6
code/espurna/config/hardware.h View File

@ -4497,16 +4497,20 @@
#define RELAY2_PROVIDER RELAY_PROVIDER_LIGHTFOX #define RELAY2_PROVIDER RELAY_PROVIDER_LIGHTFOX
// Buttons // Buttons
#define LIGHTFOX_BUTTONS 4
#define BUTTON1_PROVIDER BUTTON_PROVIDER_LIGHTFOX
#define BUTTON1_CLICK BUTTON_ACTION_TOGGLE #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 BUTTON1_RELAY 1
#define BUTTON2_PROVIDER BUTTON_PROVIDER_LIGHTFOX
#define BUTTON2_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON2_RELAY 2 #define BUTTON2_RELAY 2
#define BUTTON3_PROVIDER BUTTON_PROVIDER_LIGHTFOX
#define BUTTON3_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON3_RELAY 2 #define BUTTON3_RELAY 2
#define BUTTON4_PROVIDER BUTTON_PROVIDER_LIGHTFOX
#define BUTTON4_CLICK BUTTON_ACTION_TOGGLE
#define BUTTON4_RELAY 1 #define BUTTON4_RELAY 1
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 2
- 0
code/espurna/config/types.h View File

@ -61,8 +61,10 @@
// configure where do we get the button events // configure where do we get the button events
#define BUTTON_PROVIDER_NONE ButtonProvider::None #define BUTTON_PROVIDER_NONE ButtonProvider::None
#define BUTTON_PROVIDER_DUMMY ButtonProvider::Dummy
#define BUTTON_PROVIDER_GPIO ButtonProvider::Gpio #define BUTTON_PROVIDER_GPIO ButtonProvider::Gpio
#define BUTTON_PROVIDER_ANALOG ButtonProvider::Analog #define BUTTON_PROVIDER_ANALOG ButtonProvider::Analog
#define BUTTON_PROVIDER_LIGHTFOX ButtonProvider::Lightfox
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// ENCODER // ENCODER


+ 89
- 34
code/espurna/lightfox.cpp View File

@ -22,10 +22,6 @@ static_assert(1 == (BUTTON_SUPPORT), "");
#include <array> #include <array>
#include <vector> #include <vector>
#ifndef LIGHTFOX_BUTTONS
#define LIGHTFOX_BUTTONS 4
#endif
#ifndef LIGHTFOX_PORT #ifndef LIGHTFOX_PORT
#define LIGHTFOX_PORT 1 #define LIGHTFOX_PORT 1
#endif #endif
@ -37,10 +33,6 @@ namespace {
namespace build { namespace build {
constexpr size_t buttons() {
return LIGHTFOX_BUTTONS;
}
constexpr size_t port() { constexpr size_t port() {
return LIGHTFOX_PORT - 1; return LIGHTFOX_PORT - 1;
} }
@ -53,9 +45,6 @@ namespace internal {
Stream* port { nullptr }; Stream* port { nullptr };
size_t button_offset { 0 };
size_t buttons { 0 };
} // namespace internal } // namespace internal
constexpr uint8_t CodeStart { 0xa0 }; 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<unsigned long>(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<uint8_t>::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<Reading> _readings;
};
BasePinPtr make_button(size_t index) {
return std::make_unique<ButtonPin>(index);
} }
std::vector<ButtonPin::Reading> ButtonPin::_readings;
void setup() { void setup() {
const auto port = uartPort(build::port()); const auto port = uartPort(build::port());
if (!port) { if (!port) {
@ -252,14 +310,7 @@ void setup() {
terminal::setup(); terminal::setup();
#endif #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 } // namespace
@ -267,6 +318,10 @@ void setup() {
} // namespace hardware } // namespace hardware
} // namespace espurna } // namespace espurna
BasePinPtr lightfoxMakeButtonPin(size_t index) {
return espurna::hardware::lightfox::make_button(index);
}
RelayProviderBasePtr lightfoxMakeRelayProvider(size_t index) { RelayProviderBasePtr lightfoxMakeRelayProvider(size_t index) {
return espurna::hardware::lightfox::make_relay(index); return espurna::hardware::lightfox::make_relay(index);
} }


+ 3
- 0
code/espurna/lightfox.h View File

@ -14,4 +14,7 @@ Copyright (C) 2019 by Andrey F. Kupreychik <foxle@quickfox.ru>
class RelayProviderBase; class RelayProviderBase;
std::unique_ptr<RelayProviderBase> lightfoxMakeRelayProvider(size_t); std::unique_ptr<RelayProviderBase> lightfoxMakeRelayProvider(size_t);
class BasePin;
std::unique_ptr<BasePin> lightfoxMakeButtonPin(size_t);
void lightfoxSetup(); void lightfoxSetup();

Loading…
Cancel
Save