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) {
100 if ((new_state & arg->
resolution & STATE_HAS_DECREMENTED) != 0) {
109 || std::signbit(*std::prev(first_zero)) !=
110 std::signbit(rotation_dir)
111 || *std::prev(first_zero) == std::numeric_limits<int8_t>::lowest()
112 || *std::prev(first_zero) == std::numeric_limits<int8_t>::max()) {
114 *first_zero += rotation_dir;
119 *std::prev(first_zero) += rotation_dir;
124 arg->
state = new_state;
128 ESP_LOGCONFIG(TAG,
"Setting up Rotary Encoder '%s'...", this->name_.c_str());
130 int32_t initial_value = 0;
131 switch (this->restore_mode_) {
134 if (!this->rtc_.load(&initial_value)) {
142 initial_value =
clamp(initial_value, this->store_.min_value, this->store_.max_value);
144 this->store_.counter = initial_value;
145 this->store_.last_read = initial_value;
147 this->pin_a_->setup();
148 this->store_.pin_a = this->pin_a_->to_isr();
149 this->pin_b_->setup();
150 this->store_.pin_b = this->pin_b_->to_isr();
152 if (this->pin_i_ !=
nullptr) {
153 this->pin_i_->setup();
160 LOG_SENSOR(
"",
"Rotary Encoder",
this);
161 LOG_PIN(
" Pin A: ", this->pin_a_);
162 LOG_PIN(
" Pin B: ", this->pin_b_);
163 LOG_PIN(
" Pin I: ", this->pin_i_);
165 const LogString *restore_mode = LOG_STR(
"");
166 switch (this->restore_mode_) {
168 restore_mode = LOG_STR(
"Restore (Defaults to zero)");
171 restore_mode = LOG_STR(
"Always zero");
174 ESP_LOGCONFIG(TAG,
" Restore Mode: %s", LOG_STR_ARG(restore_mode));
176 switch (this->store_.resolution) {
178 ESP_LOGCONFIG(TAG,
" Resolution: 1 Pulse Per Cycle");
181 ESP_LOGCONFIG(TAG,
" Resolution: 2 Pulses Per Cycle");
184 ESP_LOGCONFIG(TAG,
" Resolution: 4 Pulse Per Cycle");
193 rotation_events = this->store_.rotation_events;
194 rotation_events_overflow = this->store_.rotation_events_overflow;
196 this->store_.rotation_events.fill(0);
197 this->store_.rotation_events_overflow =
false;
200 if (rotation_events_overflow) {
201 ESP_LOGW(TAG,
"Captured more rotation events than expected");
204 for (
auto events : rotation_events) {
210 this->on_clockwise_callback_.call();
214 this->on_anticlockwise_callback_.call();
219 if (this->pin_i_ !=
nullptr && this->pin_i_->digital_read()) {
220 this->store_.counter = 0;
222 int counter = this->store_.counter;
223 if (this->store_.last_read != counter || this->publish_initial_value_) {
225 this->rtc_.save(&counter);
227 this->store_.last_read =
counter;
228 this->publish_state(counter);
229 this->listeners_.call(counter);
230 this->publish_initial_value_ =
false;
236 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