mirror of https://github.com/meshcore-dev/MeshCore
10 changed files with 207 additions and 11 deletions
@ -0,0 +1,18 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <Arduino.h> |
||||
|
|
||||
|
enum class RotaryInputEvent : uint8_t { |
||||
|
None, |
||||
|
Next, |
||||
|
Prev, |
||||
|
}; |
||||
|
|
||||
|
class RotaryInput { |
||||
|
public: |
||||
|
virtual ~RotaryInput() = default; |
||||
|
|
||||
|
virtual bool begin() = 0; |
||||
|
virtual RotaryInputEvent poll() = 0; |
||||
|
virtual bool isReady() const = 0; |
||||
|
}; |
||||
@ -0,0 +1,122 @@ |
|||||
|
#include "HeltecRC32RotaryInput.h" |
||||
|
|
||||
|
#include <Wire.h> |
||||
|
|
||||
|
namespace { |
||||
|
constexpr uint8_t TCA6408_ADDR = 0x20; |
||||
|
constexpr uint8_t TCA6408_INPUT_REG = 0x00; |
||||
|
constexpr uint8_t TCA6408_POLARITY_REG = 0x02; |
||||
|
constexpr uint8_t TCA6408_CONFIG_REG = 0x03; |
||||
|
constexpr uint8_t TCA6408_ROTARY_A_MASK = 0x01; |
||||
|
constexpr uint8_t TCA6408_ROTARY_B_MASK = 0x02; |
||||
|
constexpr uint8_t TCA6408_ROTARY_MASK = TCA6408_ROTARY_A_MASK | TCA6408_ROTARY_B_MASK; |
||||
|
constexpr uint32_t TCA6408_DEBOUNCE_MS = 5; |
||||
|
} |
||||
|
|
||||
|
bool HeltecRC32RotaryInput::begin() { |
||||
|
initialized = true; |
||||
|
ready = false; |
||||
|
input_state = TCA6408_ROTARY_MASK; |
||||
|
active_low_phase = false; |
||||
|
|
||||
|
if (periph_power && !power_claimed) { |
||||
|
periph_power->claim(); |
||||
|
power_claimed = true; |
||||
|
delay(12); |
||||
|
} |
||||
|
|
||||
|
if (!writeRegister(TCA6408_POLARITY_REG, 0x00) || !writeRegister(TCA6408_CONFIG_REG, 0xFF)) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
uint8_t state = 0; |
||||
|
if (!readInput(state)) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
input_state = state & TCA6408_ROTARY_MASK; |
||||
|
ready = true; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
RotaryInputEvent HeltecRC32RotaryInput::poll() { |
||||
|
if (!initialized) { |
||||
|
begin(); |
||||
|
return RotaryInputEvent::None; |
||||
|
} |
||||
|
|
||||
|
if (!ready) { |
||||
|
return RotaryInputEvent::None; |
||||
|
} |
||||
|
|
||||
|
uint8_t new_state = 0; |
||||
|
if (!readInput(new_state)) { |
||||
|
return RotaryInputEvent::None; |
||||
|
} |
||||
|
|
||||
|
new_state &= TCA6408_ROTARY_MASK; |
||||
|
RotaryInputEvent event = handleTransition(new_state); |
||||
|
input_state = new_state; |
||||
|
return event; |
||||
|
} |
||||
|
|
||||
|
bool HeltecRC32RotaryInput::writeRegister(uint8_t reg, uint8_t value) { |
||||
|
Wire.beginTransmission(TCA6408_ADDR); |
||||
|
Wire.write(reg); |
||||
|
Wire.write(value); |
||||
|
return Wire.endTransmission() == 0; |
||||
|
} |
||||
|
|
||||
|
bool HeltecRC32RotaryInput::readInput(uint8_t& value) { |
||||
|
Wire.beginTransmission(TCA6408_ADDR); |
||||
|
Wire.write(TCA6408_INPUT_REG); |
||||
|
if (Wire.endTransmission(false) != 0) { |
||||
|
return false; |
||||
|
} |
||||
|
if (Wire.requestFrom(TCA6408_ADDR, static_cast<uint8_t>(1)) != 1) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
value = Wire.read(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
RotaryInputEvent HeltecRC32RotaryInput::handleTransition(uint8_t newState) { |
||||
|
uint8_t changed = (input_state ^ newState) & TCA6408_ROTARY_MASK; |
||||
|
RotaryInputEvent event = RotaryInputEvent::None; |
||||
|
bool a_low = (newState & TCA6408_ROTARY_A_MASK) == 0; |
||||
|
bool b_low = (newState & TCA6408_ROTARY_B_MASK) == 0; |
||||
|
|
||||
|
if (!a_low && !b_low) { |
||||
|
active_low_phase = false; |
||||
|
} |
||||
|
|
||||
|
if (!active_low_phase && (changed & TCA6408_ROTARY_A_MASK) && a_low && !b_low) { |
||||
|
event = RotaryInputEvent::Prev; |
||||
|
active_low_phase = true; |
||||
|
} else if (!active_low_phase && (changed & TCA6408_ROTARY_B_MASK) && b_low && !a_low) { |
||||
|
event = RotaryInputEvent::Next; |
||||
|
active_low_phase = true; |
||||
|
} |
||||
|
|
||||
|
if (event == RotaryInputEvent::None && !active_low_phase && (changed & TCA6408_ROTARY_A_MASK)) { |
||||
|
bool a_rising = (newState & TCA6408_ROTARY_A_MASK) != 0; |
||||
|
if (a_rising && b_low) { |
||||
|
event = RotaryInputEvent::Prev; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (event == RotaryInputEvent::None && !active_low_phase && (changed & TCA6408_ROTARY_B_MASK)) { |
||||
|
bool b_rising = (newState & TCA6408_ROTARY_B_MASK) != 0; |
||||
|
if (b_rising && a_low) { |
||||
|
event = RotaryInputEvent::Next; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (event == RotaryInputEvent::None || (millis() - last_event_ms) < TCA6408_DEBOUNCE_MS) { |
||||
|
return RotaryInputEvent::None; |
||||
|
} |
||||
|
|
||||
|
last_event_ms = millis(); |
||||
|
return event; |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <helpers/RefCountedDigitalPin.h> |
||||
|
#include <helpers/ui/RotaryInput.h> |
||||
|
|
||||
|
class HeltecRC32RotaryInput : public RotaryInput { |
||||
|
public: |
||||
|
explicit HeltecRC32RotaryInput(RefCountedDigitalPin* periphPower = nullptr) : periph_power(periphPower) { } |
||||
|
|
||||
|
bool begin() override; |
||||
|
RotaryInputEvent poll() override; |
||||
|
bool isReady() const override { return ready; } |
||||
|
|
||||
|
private: |
||||
|
bool writeRegister(uint8_t reg, uint8_t value); |
||||
|
bool readInput(uint8_t& value); |
||||
|
RotaryInputEvent handleTransition(uint8_t newState); |
||||
|
|
||||
|
uint8_t input_state = 0x03; |
||||
|
uint32_t last_event_ms = 0; |
||||
|
bool ready = false; |
||||
|
bool initialized = false; |
||||
|
bool power_claimed = false; |
||||
|
bool active_low_phase = false; |
||||
|
RefCountedDigitalPin* periph_power = nullptr; |
||||
|
}; |
||||
Loading…
Reference in new issue