/* * Rotary encoder: A = GPIO42, B = GPIO4, button on expander P5. * * Quadrature decoding uses the PCNT peripheral with a glitch filter rather * than a polling task. The vendor example polls A in a task and infers * direction from B, which drops detents when the UI is busy — not acceptable * for a knob that sets a heating setpoint. * * The button is on the I2C expander, so it has to be polled. 20ms with a * 3-sample debounce is well inside human reaction time and costs one short * I2C transaction per poll. */ #pragma once #include #include #include "esp_err.h" #define ENCODER_PIN_A 42 #define ENCODER_PIN_B 4 typedef enum { ENCODER_BTN_NONE = 0, ENCODER_BTN_CLICK, ENCODER_BTN_LONG_PRESS, } encoder_button_event_t; esp_err_t encoder_init(void); /* * Detents accumulated since the last call, positive clockwise. Reading * clears the accumulator, so exactly one consumer should call this — the UI. */ int encoder_take_delta(void); /* * Pending button event, cleared by reading. Long press is 800ms; the click is * reported on release so the two never both fire. */ encoder_button_event_t encoder_take_button_event(void); /* Instantaneous button state, for diagnostics. */ bool encoder_button_is_down(void);