128 lines
2.6 KiB
C++
128 lines
2.6 KiB
C++
/*
|
|
* peripherals_button.hpp
|
|
*
|
|
* Created on: Apr 17, 2021
|
|
* Author: erki
|
|
*/
|
|
|
|
#ifndef SKULLC_PERIPHERALS_BUTTON_HPP_
|
|
#define SKULLC_PERIPHERALS_BUTTON_HPP_
|
|
|
|
#include <cstdint>
|
|
|
|
#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<Hal::Gpio G, Hal::StaticHal H>
|
|
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<ButtonPress> 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_ */
|