/* * peripherals_button.hpp * * Created on: Apr 17, 2021 * Author: erki */ #ifndef SKULLC_PERIPHERALS_BUTTON_HPP_ #define SKULLC_PERIPHERALS_BUTTON_HPP_ #include #include "peripherals_hal_concepts.hpp" #ifdef SKULLC_WITH_CORO #include "skullc/coro/sleep.hpp" #include "skullc/coro/task.hpp" #include "skullc/coro/this_coro.hpp" #endif namespace Peripherals { enum class ButtonPress : std::uint32_t { NOT_PRESSED, SHORT_PRESS, LONG_PRESS }; template class Button { public: using gpio = G; using hal = H; gpio sw; static constexpr std::uint32_t TIMEOUT_SHORT_PRESS = 50; static constexpr std::uint32_t TIMEOUT_LONG_PRESS = 500; Button() = delete; explicit Button(const gpio& sw) : sw(sw), was_pressed_(sw.read()) {} void update() { const bool is_pressed = sw.read(); ButtonPress new_state = ButtonPress::NOT_PRESSED; const std::uint32_t time_held = hal::getMillis() - time_pressed_down_; if (is_pressed && !was_pressed_) { time_pressed_down_ = hal::getMillis(); } else if (!is_pressed && was_pressed_) { if (time_held > TIMEOUT_SHORT_PRESS && time_held <= TIMEOUT_LONG_PRESS) { new_state = ButtonPress::SHORT_PRESS; } if (state_exhausted_) { current_state_ = ButtonPress::NOT_PRESSED; state_exhausted_ = false; } time_pressed_down_ = 0; } else if (is_pressed && was_pressed_) { if (current_state_ == ButtonPress::NOT_PRESSED && time_held > TIMEOUT_LONG_PRESS) new_state = ButtonPress::LONG_PRESS; } was_pressed_ = is_pressed; if (!state_exhausted_) current_state_ = new_state; } [[nodiscard]] ButtonPress getState() const { if (!state_exhausted_) { if (current_state_ != ButtonPress::NOT_PRESSED && current_state_ != ButtonPress::SHORT_PRESS) state_exhausted_ = true; return current_state_; } else { return ButtonPress::NOT_PRESSED; } } #ifdef SKULLC_WITH_CORO skullc::coro::Task await_press() { ButtonPress result = ButtonPress::NOT_PRESSED; while (result == ButtonPress::NOT_PRESSED) { update(); result = getState(); if (result == ButtonPress::NOT_PRESSED) co_await skullc::coro::sleep(std::chrono::milliseconds(hal::getMillis()), std::chrono::milliseconds(1)); } co_return result; } #endif private: bool was_pressed_; std::uint32_t time_pressed_down_ = 0; ButtonPress current_state_ = ButtonPress::NOT_PRESSED; mutable bool state_exhausted_ = false; }; }// namespace Peripherals #endif /* SKULLC_PERIPHERALS_BUTTON_HPP_ */