mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Rotary Encoder: Don't call callbacks in the isr (#1456)
This commit is contained in:
		| @@ -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...> { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user