#pragma once #include "Selector.hpp" #include #include #include #include BEGIN_CS_NAMESPACE template class GenericEncoderSelector : public GenericSelector { using Parent = GenericSelector; public: GenericEncoderSelector(Selectable &selectable, const Callback &callback, const EncoderSwitchPinList &pins, int8_t pulsesPerStep = 4, Wrap wrap = Wrap::Wrap) : GenericSelector {selectable, callback}, encoder {pins.A, pins.B}, switchPin(pins.switchPin), pulsesPerStep(pulsesPerStep), wrap(wrap) {} void begin() override { Parent::begin(); if (switchPin != NO_PIN) AH::ExtIO::pinMode(switchPin, INPUT_PULLUP); begin_if_possible(encoder); } void update() override { Parent::update(); // TODO: use EncoderState long currentPosition = encoder.read(); long difference = (currentPosition - previousPosition) / pulsesPerStep; if (difference) { previousPosition += difference * pulsesPerStep; if (difference > 0) while (difference-- > 0) this->increment(wrap); else while (difference++ < 0) this->decrement(wrap); } if (switchPin != NO_PIN) { bool currentState = AH::ExtIO::digitalRead(switchPin); if (previousSwitchState == HIGH && currentState == LOW) { // TODO: invert? this->reset(); } previousSwitchState = currentState; } } private: AHEncoder encoder; pin_t switchPin; int8_t pulsesPerStep; Wrap wrap; long previousPosition = 0; bool previousSwitchState = HIGH; }; // -------------------------------------------------------------------------- // /** * @brief Selector that reads from a rotary encoder. * * @ingroup Selectors * * @tparam N * The number of settings. */ template class EncoderSelector : public GenericEncoderSelector { public: EncoderSelector(Selectable &selectable, const EncoderSwitchPinList &pins, int8_t pulsesPerStep = 4, Wrap wrap = Wrap::Wrap) : GenericEncoderSelector { selectable, {}, pins, pulsesPerStep, wrap, } {} }; END_CS_NAMESPACE