blob: 81cc0c5c36b53ce5fb1b5b585a50ee7eff0ab6ac [file] [log] [blame] [edit]
// Copyright 2024 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once
#include <chrono>
#include "modules/pubsub/pubsub_events.h"
#include "pw_allocator/allocator.h"
#include "pw_assert/check.h"
#include "pw_async2/coro.h"
#include "pw_async2/coro_or_else_task.h"
#include "pw_async2/dispatcher.h"
#include "pw_async2/time_provider.h"
#include "pw_chrono/system_clock.h"
#include "pw_digital_io/digital_io.h"
#include "pw_status/status.h"
namespace sense {
class Debouncer final {
public:
constexpr static pw::chrono::SystemClock::duration kDebounceInterval =
std::chrono::milliseconds(30);
Debouncer(pw::digital_io::State initial_state)
: last_input_(initial_state) {};
pw::digital_io::State UpdateState(pw::chrono::SystemClock::time_point now,
pw::digital_io::State state);
private:
pw::chrono::SystemClock::time_point last_update_ =
pw::chrono::SystemClock::time_point();
pw::digital_io::State last_input_ = pw::digital_io::State::kInactive;
pw::digital_io::State output_ = pw::digital_io::State::kInactive;
};
class EdgeDetector final {
public:
EdgeDetector(pw::digital_io::State initial_state)
: current_state_(initial_state) {};
enum StateChange {
kNone,
kActivate,
kDeactivate,
};
StateChange UpdateState(pw::digital_io::State state);
private:
pw::digital_io::State current_state_;
};
class Button {
public:
Button(pw::digital_io::DigitalIn& io) : io_(io) {
PW_CHECK_OK(io_.Enable());
};
pw::Result<EdgeDetector::StateChange> Sample(
pw::chrono::SystemClock::time_point now);
private:
pw::digital_io::DigitalIn& io_;
Debouncer debouncer_ = Debouncer(pw::digital_io::State::kInactive);
EdgeDetector edge_detector_ = EdgeDetector(pw::digital_io::State::kInactive);
};
/// DOCME
class ButtonManager final {
public:
constexpr static pw::chrono::SystemClock::duration kSampleInterval =
std::chrono::milliseconds(10);
ButtonManager(pw::digital_io::DigitalIn& button_a,
pw::digital_io::DigitalIn& button_b,
pw::digital_io::DigitalIn& button_x,
pw::digital_io::DigitalIn& button_y);
~ButtonManager();
void Init(pw::async2::Dispatcher& dispatcher,
pw::async2::TimeProvider<pw::chrono::SystemClock>& time,
pw::Allocator& allocator,
PubSub& pub_sub);
void Start() {
if (!sample_task_.IsRegistered()) {
dispatcher_->Post(sample_task_);
}
}
void Stop() { sample_task_.Deregister(); }
private:
Button buttons_[4];
pw::async2::Coro<pw::Status> SampleLoop(pw::async2::CoroContext cx);
template <typename ButtonEvent>
pw::Status SampleButton(Button& button, pw::chrono::SystemClock::time_point);
pw::Status SampleButtons(pw::chrono::SystemClock::time_point);
PubSub* pub_sub_ = nullptr;
pw::async2::Dispatcher* dispatcher_ = nullptr;
pw::async2::TimeProvider<pw::chrono::SystemClock>* time_;
pw::async2::CoroOrElseTask sample_task_;
};
} // namespace sense