diff options
Diffstat (limited to 'src/buttonhandler')
-rw-r--r-- | src/buttonhandler/ButtonHandler.cpp | 85 | ||||
-rw-r--r-- | src/buttonhandler/ButtonHandler.h | 24 |
2 files changed, 109 insertions, 0 deletions
diff --git a/src/buttonhandler/ButtonHandler.cpp b/src/buttonhandler/ButtonHandler.cpp new file mode 100644 index 00000000..997409e5 --- /dev/null +++ b/src/buttonhandler/ButtonHandler.cpp @@ -0,0 +1,85 @@ +#include "ButtonHandler.h" + +using namespace Pinetime::Controllers; + +void ButtonTimerCallback(TimerHandle_t xTimer) { + auto* buttonHandler = static_cast<ButtonHandler*>(pvTimerGetTimerID(xTimer)); + buttonHandler->HandleEvent(ButtonHandler::Timer); +} + +void ButtonHandler::Init(Pinetime::System::SystemTask* systemTask) { + this->systemTask = systemTask; + buttonTimer = xTimerCreate("buttonTimer", 0, pdFALSE, this, ButtonTimerCallback); +} + +void ButtonHandler::HandleEvent(events event) { + static constexpr TickType_t doubleClickTime = pdMS_TO_TICKS(200); + static constexpr TickType_t longPressTime = pdMS_TO_TICKS(400); + static constexpr TickType_t longerPressTime = pdMS_TO_TICKS(2000); + + if (systemTask->IsSleeping()) { + // This is for faster wakeup, sacrificing special longpress and doubleclick handling while sleeping + systemTask->PushMessage(System::Messages::GoToRunning); + } else { + systemTask->PushMessage(System::Messages::ReloadIdleTimer); + } + + if (event == Press) { + buttonPressed = true; + } else if (event == Release) { + releaseTime = xTaskGetTickCount(); + buttonPressed = false; + } + + switch (state) { + case Idle: + if (event == Press) { + xTimerChangePeriod(buttonTimer, doubleClickTime, 0); + xTimerStart(buttonTimer, 0); + state = Pressed; + } + break; + case Pressed: + if (event == Press) { + if (xTaskGetTickCount() - releaseTime < doubleClickTime) { + systemTask->PushMessage(System::Messages::OnButtonDoubleClicked); + xTimerStop(buttonTimer, 0); + state = Idle; + } + } else if (event == Release) { + xTimerChangePeriod(buttonTimer, doubleClickTime, 0); + xTimerStart(buttonTimer, 0); + } else if (event == Timer) { + if (buttonPressed) { + xTimerChangePeriod(buttonTimer, longPressTime - doubleClickTime, 0); + xTimerStart(buttonTimer, 0); + state = Holding; + } else { + systemTask->PushMessage(System::Messages::OnButtonPushed); + state = Idle; + } + } + break; + case Holding: + if (event == Release) { + systemTask->PushMessage(System::Messages::OnButtonPushed); + xTimerStop(buttonTimer, 0); + state = Idle; + } else if (event == Timer) { + xTimerChangePeriod(buttonTimer, longerPressTime - longPressTime - doubleClickTime, 0); + xTimerStart(buttonTimer, 0); + systemTask->PushMessage(System::Messages::OnButtonLongPressed); + state = LongHeld; + } + break; + case LongHeld: + if (event == Release) { + xTimerStop(buttonTimer, 0); + state = Idle; + } else if (event == Timer) { + systemTask->PushMessage(System::Messages::OnButtonLongerPressed); + state = Idle; + } + break; + } +} diff --git a/src/buttonhandler/ButtonHandler.h b/src/buttonhandler/ButtonHandler.h new file mode 100644 index 00000000..5d5b57e9 --- /dev/null +++ b/src/buttonhandler/ButtonHandler.h @@ -0,0 +1,24 @@ +#pragma once + +#include "systemtask/SystemTask.h" +#include <FreeRTOS.h> +#include <timers.h> + +namespace Pinetime { + namespace Controllers { + class ButtonHandler { + public: + enum events { Press, Release, Timer }; + void Init(Pinetime::System::SystemTask* systemTask); + void HandleEvent(events event); + + private: + Pinetime::System::SystemTask* systemTask = nullptr; + TickType_t releaseTime = 0; + TimerHandle_t buttonTimer; + bool buttonPressed = false; + enum states { Idle, Pressed, Holding, LongHeld }; + states state = Idle; + }; + } +} |