diff --git a/firmware/application/hw/debounce.cpp b/firmware/application/hw/debounce.cpp index 7caf4ed2..5e2bf51c 100644 --- a/firmware/application/hw/debounce.cpp +++ b/firmware/application/hw/debounce.cpp @@ -27,11 +27,28 @@ bool Debounce::feed(const uint8_t bit) { history_ = (history_ << 1) | (bit & 1); + // "Repeat" handling - simulated button release + if (repeat_ctr_) { + // Make sure the button is still being held continuously + if (history_ == 0xFF) { + // Simulate button press every REPEAT_SUBSEQUENT_DELAY ticks + if (--repeat_ctr_ == 0) { + state_ = !state_; + repeat_ctr_ = REPEAT_SUBSEQUENT_DELAY / 2; + return true; + } + } else { + // It's a real button release; stop simulating + repeat_ctr_ = 0; + } + } + if (state_ == 0) { // Previous button state was 0 (released); // Has button been held for DEBOUNCE_COUNT ticks? if ((history_ & DEBOUNCE_MASK) == DEBOUNCE_MASK) { state_ = 1; + held_time_ = 0; return true; } } else { @@ -41,6 +58,21 @@ bool Debounce::feed(const uint8_t bit) { state_ = 0; return true; } + + // Repeat support is limited to the 4 directional buttons + if (repeat_enabled_) { + // Has button been held continuously for DEBOUNCE_REPEAT_DELAY? + if (history_ == 0xFF) { + if (++held_time_ == REPEAT_INITIAL_DELAY) { + // Delay reached; trigger repeat code on NEXT tick + repeat_ctr_ = 1; + held_time_ = 0; + } + } else { + // Button not continuously pressed; reset counter + held_time_ = 0; + } + } } return false; } diff --git a/firmware/application/hw/debounce.hpp b/firmware/application/hw/debounce.hpp index 52dfe106..14ba29e9 100644 --- a/firmware/application/hw/debounce.hpp +++ b/firmware/application/hw/debounce.hpp @@ -28,6 +28,10 @@ #define DEBOUNCE_COUNT 4 #define DEBOUNCE_MASK ((1 << DEBOUNCE_COUNT) - 1) +// # of timer0 ticks before a held button starts being counted as repeated presses +#define REPEAT_INITIAL_DELAY 250 +#define REPEAT_SUBSEQUENT_DELAY 92 + class Debounce { public: bool feed(const uint8_t bit); @@ -36,9 +40,16 @@ class Debounce { return state_; } + void enable_repeat() { + repeat_enabled_ = true; + } + private: uint8_t history_{0}; uint8_t state_{0}; + bool repeat_enabled_{0}; + uint16_t repeat_ctr_{0}; + uint16_t held_time_{0}; }; #endif /*__DEBOUNCE_H__*/ diff --git a/firmware/application/irq_controls.cpp b/firmware/application/irq_controls.cpp index 8619d4bb..bd31e378 100644 --- a/firmware/application/irq_controls.cpp +++ b/firmware/application/irq_controls.cpp @@ -187,6 +187,10 @@ void controls_init() { */ gptStart(&GPTD1, &timer0_config); gptStartContinuous(&GPTD1, timer0_match_count); + + // Enable repeat for directional switches only + for (size_t i = 0; i < 4; i++) + switch_debounce[i].enable_repeat(); } SwitchesState get_switches_state() {