6 namespace rotary_encoder {
8 static const char *
const TAG =
"rotary_encoder";
11 static const uint8_t STATE_LUT_MASK = 0x1C;
12 static const uint16_t STATE_PIN_A_HIGH = 0x01;
13 static const uint16_t STATE_PIN_B_HIGH = 0x02;
14 static const uint16_t STATE_S0 = 0x00;
15 static const uint16_t STATE_S1 = 0x04;
16 static const uint16_t STATE_S2 = 0x08;
17 static const uint16_t STATE_S3 = 0x0C;
18 static const uint16_t STATE_CCW = 0x00;
19 static const uint16_t STATE_CW = 0x10;
20 static const uint16_t STATE_HAS_INCREMENTED = 0x0700;
21 static const uint16_t STATE_INCREMENT_COUNTER_4 = 0x0700;
22 static const uint16_t STATE_INCREMENT_COUNTER_2 = 0x0300;
23 static const uint16_t STATE_INCREMENT_COUNTER_1 = 0x0100;
24 static const uint16_t STATE_HAS_DECREMENTED = 0x7000;
25 static const uint16_t STATE_DECREMENT_COUNTER_4 = 0x7000;
26 static const uint16_t STATE_DECREMENT_COUNTER_2 = 0x3000;
27 static const uint16_t STATE_DECREMENT_COUNTER_1 = 0x1000;
41 static const uint16_t DRAM_ATTR STATE_LOOKUP_TABLE[32] = {
44 STATE_CW | STATE_S1 | STATE_INCREMENT_COUNTER_1,
46 STATE_CCW | STATE_S3 | STATE_DECREMENT_COUNTER_4,
50 STATE_CCW | STATE_S0 | STATE_DECREMENT_COUNTER_1,
51 STATE_CW | STATE_S2 | STATE_INCREMENT_COUNTER_4,
53 STATE_CCW | STATE_S1 | STATE_DECREMENT_COUNTER_2,
55 STATE_CW | STATE_S3 | STATE_INCREMENT_COUNTER_1,
58 STATE_CW | STATE_S0 | STATE_INCREMENT_COUNTER_2,
59 STATE_CCW | STATE_S2 | STATE_DECREMENT_COUNTER_1,
65 STATE_CW | STATE_S1 | STATE_INCREMENT_COUNTER_1,
67 STATE_CCW | STATE_S3 | STATE_DECREMENT_COUNTER_4,
71 STATE_CCW | STATE_S0 | STATE_DECREMENT_COUNTER_1,
72 STATE_CW | STATE_S2 | STATE_INCREMENT_COUNTER_4,
74 STATE_CCW | STATE_S1 | STATE_DECREMENT_COUNTER_2,
76 STATE_CW | STATE_S3 | STATE_INCREMENT_COUNTER_1,
79 STATE_CW | STATE_S0 | STATE_INCREMENT_COUNTER_2,
80 STATE_CCW | STATE_S2 | STATE_DECREMENT_COUNTER_1,
87 uint8_t input_state = arg->
state & STATE_LUT_MASK;
89 input_state |= STATE_PIN_A_HIGH;
91 input_state |= STATE_PIN_B_HIGH;
93 int8_t rotation_dir = 0;
94 uint16_t new_state = STATE_LOOKUP_TABLE[input_state];
95 if ((new_state & arg->
resolution & STATE_HAS_INCREMENTED) != 0) {
102 if ((new_state & arg->
resolution & STATE_HAS_DECREMENTED) != 0) {
113 || std::signbit(*std::prev(first_zero)) !=
114 std::signbit(rotation_dir)
115 || *std::prev(first_zero) == std::numeric_limits<int8_t>::lowest()
116 || *std::prev(first_zero) == std::numeric_limits<int8_t>::max()) {
118 *first_zero += rotation_dir;
123 *std::prev(first_zero) += rotation_dir;
128 arg->
state = new_state;
132 ESP_LOGCONFIG(TAG,
"Setting up Rotary Encoder '%s'...", this->name_.c_str());
134 int32_t initial_value = 0;
135 switch (this->restore_mode_) {
138 if (!this->rtc_.load(&initial_value)) {
146 initial_value =
clamp(initial_value, this->store_.min_value, this->store_.max_value);
148 this->store_.counter = initial_value;
149 this->store_.last_read = initial_value;
151 this->pin_a_->setup();
152 this->store_.pin_a = this->pin_a_->to_isr();
153 this->pin_b_->setup();
154 this->store_.pin_b = this->pin_b_->to_isr();
156 if (this->pin_i_ !=
nullptr) {
157 this->pin_i_->setup();
164 LOG_SENSOR(
"",
"Rotary Encoder",
this);
165 LOG_PIN(
" Pin A: ", this->pin_a_);
166 LOG_PIN(
" Pin B: ", this->pin_b_);
167 LOG_PIN(
" Pin I: ", this->pin_i_);
169 const LogString *restore_mode;
170 switch (this->restore_mode_) {
172 restore_mode = LOG_STR(
"Restore (Defaults to zero)");
175 restore_mode = LOG_STR(
"Always zero");
178 restore_mode = LOG_STR(
"");
180 ESP_LOGCONFIG(TAG,
" Restore Mode: %s", LOG_STR_ARG(restore_mode));
182 switch (this->store_.resolution) {
184 ESP_LOGCONFIG(TAG,
" Resolution: 1 Pulse Per Cycle");
187 ESP_LOGCONFIG(TAG,
" Resolution: 2 Pulses Per Cycle");
190 ESP_LOGCONFIG(TAG,
" Resolution: 4 Pulse Per Cycle");
199 rotation_events = this->store_.rotation_events;
200 rotation_events_overflow = this->store_.rotation_events_overflow;
202 this->store_.rotation_events.fill(0);
203 this->store_.rotation_events_overflow =
false;
206 if (rotation_events_overflow) {
207 ESP_LOGW(TAG,
"Captured more rotation events than expected");
210 for (
auto events : rotation_events) {
216 this->on_clockwise_callback_.call();
220 this->on_anticlockwise_callback_.call();
225 if (this->pin_i_ !=
nullptr && this->pin_i_->digital_read()) {
226 this->store_.counter = 0;
228 int counter = this->store_.counter;
229 if (this->store_.last_read != counter || this->publish_initial_value_) {
231 this->rtc_.save(&counter);
233 this->store_.last_read =
counter;
234 this->publish_state(counter);
235 this->listeners_.call(counter);
236 this->publish_initial_value_ =
false;
242 this->restore_mode_ = restore_mode;
RotaryEncoderResolution
All possible resolutions for the rotary encoder.
const float DATA
For components that import data from directly connected sensors like DHT.
void set_min_value(int32_t min_value)
increment counter by 2 with every A-B cycle
static void gpio_intr(RotaryEncoderSensorStore *arg)
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
RotaryEncoderRestoreMode
All possible restore modes for the rotary encoder.
std::array< int8_t, 8 > rotation_events
void set_max_value(int32_t max_value)
bool rotation_events_overflow
try to restore counter, otherwise set to zero
ESPPreferences * global_preferences
RotaryEncoderResolution resolution
BedjetMode mode
BedJet operating mode.
increment counter by 1 with every A-B cycle, slow response but accurate
Helper class to disable interrupts.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
Implementation of SPI Controller mode.
void set_resolution(RotaryEncoderResolution mode)
Set the resolution of the rotary encoder.
void set_restore_mode(RotaryEncoderRestoreMode restore_mode)
Set the restore mode of the rotary encoder.
float get_setup_priority() const override
void dump_config() override