mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 05:24:53 +01:00
Rotary Encoder: Don't call callbacks in the isr (#1456)
This commit is contained in:
parent
5df398ec31
commit
02dc49c272
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())
|
if (arg->pin_b->digital_read())
|
||||||
input_state |= STATE_PIN_B_HIGH;
|
input_state |= STATE_PIN_B_HIGH;
|
||||||
|
|
||||||
|
int8_t rotation_dir = 0;
|
||||||
uint16_t new_state = STATE_LOOKUP_TABLE[input_state];
|
uint16_t new_state = STATE_LOOKUP_TABLE[input_state];
|
||||||
if ((new_state & arg->resolution & STATE_HAS_INCREMENTED) != 0) {
|
if ((new_state & arg->resolution & STATE_HAS_INCREMENTED) != 0) {
|
||||||
if (arg->counter < arg->max_value)
|
if (arg->counter < arg->max_value)
|
||||||
arg->counter++;
|
arg->counter++;
|
||||||
arg->on_clockwise_callback_.call();
|
rotation_dir = 1;
|
||||||
}
|
}
|
||||||
if ((new_state & arg->resolution & STATE_HAS_DECREMENTED) != 0) {
|
if ((new_state & arg->resolution & STATE_HAS_DECREMENTED) != 0) {
|
||||||
if (arg->counter > arg->min_value)
|
if (arg->counter > arg->min_value)
|
||||||
arg->counter--;
|
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;
|
arg->state = new_state;
|
||||||
|
@ -137,6 +155,35 @@ void RotaryEncoderSensor::dump_config() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void RotaryEncoderSensor::loop() {
|
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()) {
|
if (this->pin_i_ != nullptr && this->pin_i_->digital_read()) {
|
||||||
this->store_.counter = 0;
|
this->store_.counter = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/esphal.h"
|
#include "esphome/core/esphal.h"
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
@ -27,8 +29,8 @@ struct RotaryEncoderSensorStore {
|
||||||
int32_t last_read{0};
|
int32_t last_read{0};
|
||||||
uint8_t state{0};
|
uint8_t state{0};
|
||||||
|
|
||||||
CallbackManager<void()> on_clockwise_callback_;
|
std::array<int8_t, 8> rotation_events{};
|
||||||
CallbackManager<void()> on_anticlockwise_callback_;
|
bool rotation_events_overflow{false};
|
||||||
|
|
||||||
static void gpio_intr(RotaryEncoderSensorStore *arg);
|
static void gpio_intr(RotaryEncoderSensorStore *arg);
|
||||||
};
|
};
|
||||||
|
@ -66,11 +68,11 @@ class RotaryEncoderSensor : public sensor::Sensor, public Component {
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
void add_on_clockwise_callback(std::function<void()> callback) {
|
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) {
|
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:
|
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.
|
GPIOPin *pin_i_{nullptr}; /// Index pin, if this is not nullptr, the counter will reset to 0 once this pin is HIGH.
|
||||||
|
|
||||||
RotaryEncoderSensorStore store_{};
|
RotaryEncoderSensorStore store_{};
|
||||||
|
|
||||||
|
CallbackManager<void()> on_clockwise_callback_;
|
||||||
|
CallbackManager<void()> on_anticlockwise_callback_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class RotaryEncoderSetValueAction : public Action<Ts...> {
|
template<typename... Ts> class RotaryEncoderSetValueAction : public Action<Ts...> {
|
||||||
|
|
Loading…
Reference in a new issue