cs-midi/Selectors/EncoderSelector.hpp

86 lines
2.6 KiB
C++

#pragma once
#include "Selector.hpp"
#include <AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.hpp>
#include <Def/Def.hpp>
#include <Def/TypeTraits.hpp>
#include <Submodules/Encoder/AHEncoder.hpp>
BEGIN_CS_NAMESPACE
template <setting_t N, class Callback = EmptySelectorCallback>
class GenericEncoderSelector : public GenericSelector<N, Callback> {
using Parent = GenericSelector<N, Callback>;
public:
GenericEncoderSelector(Selectable<N> &selectable, const Callback &callback,
const EncoderSwitchPinList &pins,
int8_t pulsesPerStep = 4, Wrap wrap = Wrap::Wrap)
: GenericSelector<N, Callback> {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 <setting_t N>
class EncoderSelector : public GenericEncoderSelector<N> {
public:
EncoderSelector(Selectable<N> &selectable, const EncoderSwitchPinList &pins,
int8_t pulsesPerStep = 4, Wrap wrap = Wrap::Wrap)
: GenericEncoderSelector<N> {
selectable, {}, pins, pulsesPerStep, wrap,
} {}
};
END_CS_NAMESPACE