Skip to content

File RotaryEncoder.h

File List > Firmware > Libraries > PanelGroup > Inputs > RotaryEncoder > RotaryEncoder.h

Go to the documentation of this file

#pragma once
#ifdef ARDUINO_ARCH_STM32

#include <PanelGroup.h>  // InputBase, PinRef

namespace OpenSkyhawk {

enum class EncoderStepsPerDetent : uint8_t {
    One   = 1,
    Two   = 2,
    Four  = 4,
    Eight = 8,
};

enum class EncoderMode : uint8_t {
    Rel,  
    Dir,  
};

class RotaryEncoder : public InputBase {
public:
    static constexpr int16_t DEFAULT_STEP = 3200;  

    RotaryEncoder(uint16_t controlId, PinRef pinA, PinRef pinB,
                  EncoderStepsPerDetent stepsPerDetent = EncoderStepsPerDetent::One,
                  EncoderMode mode = EncoderMode::Rel, int16_t step = DEFAULT_STEP);

    void poll() override;

    void forceReport() override;

    void configure() override;

    void sampleTick() override;

    static constexpr int8_t   MAX_MOMENTUM         = 4;
    static constexpr uint32_t FAST_THRESHOLD_MS    = 175;
    static constexpr uint32_t STOPPED_THRESHOLD_MS = 500;

#ifdef ROTARYENCODER_TEST
    void debugSeed(uint8_t state) {
        _lastState = (uint8_t)(state & 0x3); _delta = 0; _pendingDetents = 0; _pendingFast = 0;
        _momentum = 0; _hasLastDetent = false; _lastDetentMs = millis(); _initialized = true;
    }
    void debugStep(uint8_t ab) { decode((uint8_t)(ab & 0x3)); drainPending(); }
    void debugDecode(uint8_t ab) { decode((uint8_t)(ab & 0x3)); }
    void debugDrain() { drainPending(); }
    uint16_t emitCount() const { return _emitCount; }
    int16_t lastValue() const { return _lastValue; }
    uint32_t lastFrame() const { return _lastFrame; }
    int32_t netDetents() const { return _netDetents; }
    int8_t momentum() const { return _momentum; }
#endif

protected:
    RotaryEncoder(uint16_t controlId, PinRef pinA, PinRef pinB,
                  EncoderStepsPerDetent stepsPerDetent, EncoderMode mode, int16_t step,
                  bool momentumFilter, int16_t fastStep);

    uint8_t readState();   

private:
    void decode(uint8_t state);          
    void countDetent(int8_t dir);        
    void drainPending();                 
    void emit(int16_t value);            

    uint16_t   _controlId;
    PinRef     _pinA;
    PinRef     _pinB;
    EncoderMode _mode;
    int16_t    _step;        
    uint8_t    _stepsPerDetent;
    uint8_t    _lastState;   
    int8_t     _delta;       
    volatile int8_t _pendingDetents;  
    volatile int8_t _pendingFast;     
    bool       _filter;      
    int16_t    _fastStep;    
    int8_t     _momentum;    
    uint32_t   _lastDetentMs;   
    bool       _hasLastDetent;  
    volatile bool   _sampled;         
    bool       _initialized; 
#ifdef ROTARYENCODER_TEST
    uint16_t _emitCount = 0;
    int16_t  _lastValue = 0;
    uint32_t _lastFrame = 0;
    int32_t  _netDetents = 0;
#endif
};

}  // namespace OpenSkyhawk

#endif  // ARDUINO_ARCH_STM32