WIP4: Add Signal entity
This commit is contained in:
parent
66461af1e4
commit
8d49d2d446
@ -33,20 +33,26 @@ std::uint32_t HAL::millis = 1;
|
||||
|
||||
struct Gpio
|
||||
{
|
||||
static bool set;
|
||||
static bool is_set;
|
||||
|
||||
Gpio()
|
||||
{
|
||||
set = false;
|
||||
is_set = false;
|
||||
}
|
||||
|
||||
bool read()
|
||||
bool read() const
|
||||
{
|
||||
return set;
|
||||
return is_set;
|
||||
}
|
||||
|
||||
void set(const bool value)
|
||||
{ }
|
||||
|
||||
void toggle()
|
||||
{ }
|
||||
};
|
||||
|
||||
bool Gpio::set = false;
|
||||
bool Gpio::is_set = false;
|
||||
|
||||
}// namespace
|
||||
|
||||
@ -75,13 +81,13 @@ TEST_CASE("Button reads presses properly.", "[peripherals],[button]")
|
||||
|
||||
Button button{g};
|
||||
|
||||
Gpio::set = true;
|
||||
Gpio::is_set = true;
|
||||
button.update();
|
||||
|
||||
SECTION("Too short of a press is debounced.")
|
||||
{
|
||||
HAL::millis = Button::TIMEOUT_SHORT_PRESS - 1;
|
||||
Gpio::set = false;
|
||||
Gpio::is_set = false;
|
||||
|
||||
button.update();
|
||||
|
||||
@ -91,7 +97,7 @@ TEST_CASE("Button reads presses properly.", "[peripherals],[button]")
|
||||
SECTION("Short press is identified properly.")
|
||||
{
|
||||
HAL::millis = Button::TIMEOUT_SHORT_PRESS + 2;
|
||||
Gpio::set = false;
|
||||
Gpio::is_set = false;
|
||||
|
||||
button.update();
|
||||
|
||||
@ -124,7 +130,7 @@ TEST_CASE("Button reads presses properly.", "[peripherals],[button]")
|
||||
SECTION("Releasing keeps NOT_PRESSED state.")
|
||||
{
|
||||
HAL::millis += 1;
|
||||
Gpio::set = false;
|
||||
Gpio::is_set = false;
|
||||
|
||||
button.update();
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "skullc/coro/sleep.hpp"
|
||||
#include "skullc/coro/task.hpp"
|
||||
#include "skullc/coro/this_coro.hpp"
|
||||
#include "skullc/coro/signal.hpp"
|
||||
|
||||
#include <semaphore>
|
||||
|
||||
@ -159,7 +160,7 @@ struct TestGpio
|
||||
}
|
||||
};
|
||||
|
||||
skullc::coro::Task<> await_pin_edge(TestGpio* pin, const Peripherals::Hal::Edge edge)
|
||||
skullc::coro::Task<> await_edge(TestGpio* pin, const Peripherals::Hal::Edge edge)
|
||||
{
|
||||
co_await skullc::coro::PinEdgeAwaiter(pin, edge);
|
||||
test_coro_called = 1;
|
||||
@ -180,7 +181,7 @@ TEST_CASE("Peripheral awaiters work.", "[coro],[awaiters]")
|
||||
SECTION("Pin edge awaiter works with rising edge.")
|
||||
{
|
||||
TestGpio gpio{false};
|
||||
scheduler.start_tasks(await_pin_edge(&gpio, Peripherals::Hal::Edge::Rising));
|
||||
scheduler.start_tasks(await_edge(&gpio, Peripherals::Hal::Edge::Rising));
|
||||
scheduler.loop(0);
|
||||
|
||||
REQUIRE(test_coro_called == 0);
|
||||
@ -207,7 +208,7 @@ TEST_CASE("Peripheral awaiters work.", "[coro],[awaiters]")
|
||||
SECTION("Pin edge awaiter works with falling edge.")
|
||||
{
|
||||
TestGpio gpio{true};
|
||||
scheduler.start_tasks(await_pin_edge(&gpio, Peripherals::Hal::Edge::Falling));
|
||||
scheduler.start_tasks(await_edge(&gpio, Peripherals::Hal::Edge::Falling));
|
||||
scheduler.loop(0);
|
||||
|
||||
REQUIRE(test_coro_called == 0);
|
||||
@ -231,3 +232,88 @@ TEST_CASE("Peripheral awaiters work.", "[coro],[awaiters]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
skullc::coro::Task<> await_signal(const int expected, skullc::coro::Signal<int>* signal)
|
||||
{
|
||||
const int value = co_await signal->receive();
|
||||
REQUIRE(value == expected);
|
||||
test_coro_called = 1;
|
||||
co_return;
|
||||
}
|
||||
|
||||
skullc::coro::Task<> await_signal_n(const auto& expecteds, skullc::coro::Signal<int>* signal)
|
||||
{
|
||||
for (const int e : expecteds)
|
||||
{
|
||||
const int value = co_await signal->receive();
|
||||
REQUIRE(value == e);
|
||||
test_coro_called++;
|
||||
}
|
||||
co_return;
|
||||
}
|
||||
|
||||
skullc::coro::Task<> send_signal(const int value, skullc::coro::Signal<int>* signal)
|
||||
{
|
||||
co_await skullc::coro::sleep(0ms, 10ms);
|
||||
signal->send(value);
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Signal awaiters work.", "[coro],[signal]")
|
||||
{
|
||||
using namespace skullc::coro;
|
||||
Scheduler<std::vector> scheduler;
|
||||
skullc::this_coro::scheduler.register_scheduler(scheduler);
|
||||
|
||||
test_coro_called = 0;
|
||||
|
||||
Signal<int> signal;
|
||||
|
||||
SECTION("Sending from main thread.")
|
||||
{
|
||||
scheduler.start_tasks(await_signal(10, &signal));
|
||||
scheduler.loop(0);
|
||||
scheduler.loop(1);
|
||||
REQUIRE(test_coro_called == 0);
|
||||
|
||||
signal.send(10);
|
||||
scheduler.loop(2);
|
||||
REQUIRE(test_coro_called == 1);
|
||||
}
|
||||
|
||||
SECTION("Sending from another coroutine.")
|
||||
{
|
||||
scheduler.start_tasks(await_signal(10, &signal), send_signal(10, &signal));
|
||||
scheduler.loop(0);
|
||||
scheduler.loop(1);
|
||||
REQUIRE(test_coro_called == 0);
|
||||
|
||||
scheduler.loop(10);
|
||||
REQUIRE(test_coro_called == 0);
|
||||
scheduler.loop(10);
|
||||
REQUIRE(test_coro_called == 1);
|
||||
}
|
||||
|
||||
const std::vector<int> values = { 10, 11, 13 };
|
||||
|
||||
SECTION("Sending multiple values.")
|
||||
{
|
||||
scheduler.start_tasks(await_signal_n(values, &signal));
|
||||
scheduler.loop(0);
|
||||
scheduler.loop(1);
|
||||
REQUIRE(test_coro_called == 0);
|
||||
|
||||
for (int i = 0; i < values.size(); i++)
|
||||
{
|
||||
signal.send(values[i]);
|
||||
scheduler.loop(i + 1);
|
||||
REQUIRE(test_coro_called == i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,9 +26,10 @@ struct PinEdgeAwaiter : TaskPoller
|
||||
~PinEdgeAwaiter() override
|
||||
{
|
||||
if (continuation)
|
||||
{
|
||||
this_coro::scheduler().remove(continuation);
|
||||
}
|
||||
|
||||
if (stored_coro)
|
||||
this_coro::scheduler().remove(stored_coro);
|
||||
}
|
||||
|
||||
bool await_ready() { return false; }
|
||||
@ -36,7 +37,7 @@ struct PinEdgeAwaiter : TaskPoller
|
||||
{
|
||||
continuation = h;
|
||||
stored_coro = continuation;
|
||||
skullc::this_coro::scheduler().add_poller(this);
|
||||
this_coro::scheduler().add_poller(this);
|
||||
}
|
||||
auto await_resume()
|
||||
{
|
||||
|
||||
91
coro/inc/skullc/coro/signal.hpp
Normal file
91
coro/inc/skullc/coro/signal.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// Created by erki on 06/02/25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
|
||||
#include "skullc/coro/this_coro.hpp"
|
||||
|
||||
namespace skullc::coro
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Signal
|
||||
{
|
||||
struct Awaiter
|
||||
{
|
||||
Signal* signal;
|
||||
std::coroutine_handle<> continuation;
|
||||
|
||||
Awaiter() = delete;
|
||||
Awaiter(const Awaiter&) = delete;
|
||||
Awaiter(Awaiter&&) = delete;
|
||||
explicit Awaiter(Signal* signal)
|
||||
: signal(signal)
|
||||
{}
|
||||
|
||||
Awaiter& operator=(const Awaiter&) = delete;
|
||||
Awaiter& operator=(Awaiter&&) = delete;
|
||||
|
||||
~Awaiter()
|
||||
{
|
||||
if (continuation)
|
||||
this_coro::scheduler().remove(continuation);
|
||||
}
|
||||
|
||||
bool await_ready() { return false; }
|
||||
|
||||
void await_suspend(std::coroutine_handle<> h)
|
||||
{
|
||||
continuation = h;
|
||||
}
|
||||
|
||||
T&& await_resume()
|
||||
{
|
||||
continuation = {};
|
||||
return std::move(*signal->data_);
|
||||
}
|
||||
|
||||
T&& get_return_object() noexcept
|
||||
{
|
||||
return std::move(*signal->data_);
|
||||
}
|
||||
|
||||
void trigger_resume()
|
||||
{
|
||||
this_coro::scheduler().schedule(continuation, 0);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void send(const T& value)
|
||||
{
|
||||
data_.emplace(value);
|
||||
|
||||
if (awaiter_.has_value())
|
||||
awaiter_->trigger_resume();
|
||||
}
|
||||
|
||||
void send(T&& value)
|
||||
{
|
||||
data_.emplace(value);
|
||||
|
||||
if (awaiter_.has_value())
|
||||
awaiter_->trigger_resume();
|
||||
}
|
||||
|
||||
auto& receive()
|
||||
{
|
||||
awaiter_.emplace(this);
|
||||
|
||||
return *awaiter_;
|
||||
}
|
||||
private:
|
||||
std::optional<T> data_;
|
||||
std::optional<Awaiter> awaiter_;
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user