mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 09:17:46 +01:00
Rotary Encoder: Don't call callbacks in the isr (#1456)
This commit is contained in:
parent
c67539cf5b
commit
72002ce70e
2 changed files with 58 additions and 6 deletions
|
@ -90,16 +90,34 @@ void ICACHE_RAM_ATTR HOT RotaryEncoderSensorStore::gpio_intr(RotaryEncoderSensor
|
|||
if (arg->pin_b->digital_read())
|
||||
input_state |= STATE_PIN_B_HIGH;
|
||||
|
||||
int8_t rotation_dir = 0;
|
||||
uint16_t new_state = STATE_LOOKUP_TABLE[input_state];
|
||||
if ((new_state & arg->resolution & STATE_HAS_INCREMENTED) != 0) {
|
||||
if (arg->counter < arg->max_value)
|
||||
arg->counter++;
|
||||
arg->on_clockwise_callback_.call();
|
||||
rotation_dir = 1;
|
||||
}
|
||||
if ((new_state & arg->resolution & STATE_HAS_DECREMENTED) != 0) {
|
||||
if (arg->counter > arg->min_value)
|
||||
arg->counter--;
|
||||
arg->on_anticlockwise_callback_.call();
|
||||
rotation_dir = -1;
|
||||
}
|
||||
|
||||
if (rotation_dir != 0) {
|
||||
auto first_zero = std::find(arg->rotation_events.begin(), arg->rotation_events.end(), 0); // find first zero
|
||||
if (first_zero == arg->rotation_events.begin() // are we at the start (first event this loop iteration)
|
||||
|| std::signbit(*std::prev(first_zero)) !=
|
||||
std::signbit(rotation_dir) // or is the last stored event the wrong direction
|
||||
|| *std::prev(first_zero) == std::numeric_limits<int8_t>::lowest() // or the last event slot is full (negative)
|
||||
|| *std::prev(first_zero) == std::numeric_limits<int8_t>::max()) { // or the last event slot is full (positive)
|
||||
if (first_zero != arg->rotation_events.end()) { // we have a free rotation slot
|
||||
*first_zero += rotation_dir; // store the rotation into a new slot
|
||||
} else {
|
||||
arg->rotation_events_overflow = true;
|
||||
}
|
||||
} else {
|
||||
*std::prev(first_zero) += rotation_dir; // store the rotation into the previous slot
|
||||
}
|
||||
}
|
||||
|
||||
arg->state = new_state;
|
||||
|
@ -137,6 +155,35 @@ void RotaryEncoderSensor::dump_config() {
|
|||
}
|
||||
}
|
||||
void RotaryEncoderSensor::loop() {
|
||||
std::array<int8_t, 8> rotation_events;
|
||||
bool rotation_events_overflow;
|
||||
ets_intr_lock();
|
||||
rotation_events = this->store_.rotation_events;
|
||||
rotation_events_overflow = this->store_.rotation_events_overflow;
|
||||
|
||||
this->store_.rotation_events.fill(0);
|
||||
this->store_.rotation_events_overflow = false;
|
||||
ets_intr_unlock();
|
||||
|
||||
if (rotation_events_overflow) {
|
||||
ESP_LOGW(TAG, "Captured more rotation events than expected");
|
||||
}
|
||||
|
||||
for (auto events : rotation_events) {
|
||||
if (events == 0) // we are at the end of the recorded events
|
||||
break;
|
||||
|
||||
if (events > 0) {
|
||||
while (events--) {
|
||||
this->on_clockwise_callback_.call();
|
||||
}
|
||||
} else {
|
||||
while (events++) {
|
||||
this->on_anticlockwise_callback_.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->pin_i_ != nullptr && this->pin_i_->digital_read()) {
|
||||
this->store_.counter = 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
@ -27,8 +29,8 @@ struct RotaryEncoderSensorStore {
|
|||
int32_t last_read{0};
|
||||
uint8_t state{0};
|
||||
|
||||
CallbackManager<void()> on_clockwise_callback_;
|
||||
CallbackManager<void()> on_anticlockwise_callback_;
|
||||
std::array<int8_t, 8> rotation_events{};
|
||||
bool rotation_events_overflow{false};
|
||||
|
||||
static void gpio_intr(RotaryEncoderSensorStore *arg);
|
||||
};
|
||||
|
@ -66,11 +68,11 @@ class RotaryEncoderSensor : public sensor::Sensor, public Component {
|
|||
float get_setup_priority() const override;
|
||||
|
||||
void add_on_clockwise_callback(std::function<void()> callback) {
|
||||
this->store_.on_clockwise_callback_.add(std::move(callback));
|
||||
this->on_clockwise_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void add_on_anticlockwise_callback(std::function<void()> callback) {
|
||||
this->store_.on_anticlockwise_callback_.add(std::move(callback));
|
||||
this->on_anticlockwise_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -79,6 +81,9 @@ class RotaryEncoderSensor : public sensor::Sensor, public Component {
|
|||
GPIOPin *pin_i_{nullptr}; /// Index pin, if this is not nullptr, the counter will reset to 0 once this pin is HIGH.
|
||||
|
||||
RotaryEncoderSensorStore store_{};
|
||||
|
||||
CallbackManager<void()> on_clockwise_callback_;
|
||||
CallbackManager<void()> on_anticlockwise_callback_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class RotaryEncoderSetValueAction : public Action<Ts...> {
|
||||
|
|
Loading…
Reference in a new issue