Skip to content

Commit

Permalink
sdk: add Controller::setAutoRepeat (closes #100) (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
and3rson authored Apr 14, 2024
1 parent 85b6525 commit 7407324
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 1 deletion.
3 changes: 3 additions & 0 deletions firmware/keira/src/apps/launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ ITEM_LIST dev_items = {
};

void LauncherApp::run() {
for (lilka::Button button : {lilka::Button::UP, lilka::Button::DOWN, lilka::Button::LEFT, lilka::Button::RIGHT}) {
lilka::controller.setAutoRepeat(button, 10, 300);
}
lilka::Menu menu("Головне меню");
menu.addItem("Додатки", &demos_img, lilka::colors::Pink);
menu.addItem("Браузер SD-карти", &sdcard_img, lilka::colors::Arylide_yellow);
Expand Down
37 changes: 36 additions & 1 deletion sdk/lib/lilka/src/lilka/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Controller::Controller() : state{}, semaphore(xSemaphoreCreateRecursiveMutex())
.justPressed = false,
.justReleased = false,
.time = 0,
.nextRepeatTime = 0,
.repeatRate = 0,
.repeatDelay = 0,
};
}
xSemaphoreGive(semaphore);
Expand All @@ -53,8 +56,14 @@ void Controller::inputTask() {
if (millis() - buttonState->time < LILKA_DEBOUNCE_TIME) {
continue;
}

// Is the button being held down?
bool pressed = !digitalRead(pins[i]);
if (pressed != buttonState->pressed) {
// Should the button repeat right now?
bool shouldRepeat = buttonState->nextRepeatTime && millis() >= buttonState->nextRepeatTime;

// Make/break
if (pressed != buttonState->pressed || shouldRepeat) {
buttonState->pressed = pressed;
buttonState->justPressed = pressed;
buttonState->justReleased = !pressed;
Expand All @@ -69,6 +78,24 @@ void Controller::inputTask() {
}
buttonState->time = millis();
}

// Calculate repeats
if (pressed) {
// Button is being held down, check if we need to repeat
if (buttonState->repeatRate && buttonState->repeatDelay) {
// Repeat is enabled, set next repeat time
if (buttonState->nextRepeatTime == 0) {
// This is the first repeat, delay by repeatDelay
buttonState->nextRepeatTime = millis() + buttonState->repeatDelay;
} else if (millis() >= buttonState->nextRepeatTime) {
// Delay subsequent repeats by 1/repeatRate seconds
buttonState->nextRepeatTime += 1000 / buttonState->repeatRate;
}
}
} else {
// Button is not being held down, reset repeat
buttonState->nextRepeatTime = 0;
}
}
}

Expand Down Expand Up @@ -144,6 +171,14 @@ void Controller::clearHandlers() {
globalHandler = NULL;
}

void Controller::setAutoRepeat(Button button, uint32_t rate, uint32_t delay) {
AcquireController acquire(semaphore);
_StateButtons& buttons = *reinterpret_cast<_StateButtons*>(&state);
ButtonState* buttonState = &buttons[button];
buttonState->repeatRate = rate;
buttonState->repeatDelay = delay;
}

Controller controller;

} // namespace lilka
17 changes: 17 additions & 0 deletions sdk/lib/lilka/src/lilka/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ typedef struct {
/// `true`, якщо кнопка була вперше відпущена в момент виклику `lilka::controller.getState()` (до цього була натиснута).
bool justReleased;
uint64_t time;
uint64_t nextRepeatTime;
uint32_t repeatRate;
uint32_t repeatDelay;
} ButtonState;

/// Містить стани всіх кнопок, які були виміряні в певний момент часу.
Expand Down Expand Up @@ -97,6 +100,20 @@ class Controller {
void setHandler(Button button, void (*handler)(bool));
/// Видалити всі обробники подій.
void clearHandlers();
/// Налаштувати автоматичне повторення натискання кнопки.
///
/// Після виклику цього методу кнопка буде автоматично натискатися з певною затримкою та частотою.
///
/// Щоб вимкнути автоматичне повторення натискання кнопки, викличте цей метод з параметрами `delay = 0` та `rate = 0`.
///
/// \param button Кнопка, для якої налаштовується автоматичне повторення натискання.
/// \param rate Частота автоматичного повторення натискання (кількість натискань на секунду).
/// \param delay Затримка перед початком автоматичного повторення натискання (в мілісекундах).
/// \code
/// // Натискання кнопки "Вгору" буде повторюватись з частотою 5 натискань на секунду після початкової затримки 500 мс:
/// lilka::controller.setAutoRepeat(lilka::Button::UP, 5, 500);
/// \endcode
void setAutoRepeat(Button button, uint32_t rate, uint32_t delay);

private:
// Input task FreeRTOS semaphore
Expand Down

0 comments on commit 7407324

Please sign in to comment.