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
|
struct Gpio
|
||||||
{
|
{
|
||||||
static bool set;
|
static bool is_set;
|
||||||
|
|
||||||
Gpio()
|
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
|
}// namespace
|
||||||
|
|
||||||
@ -75,13 +81,13 @@ TEST_CASE("Button reads presses properly.", "[peripherals],[button]")
|
|||||||
|
|
||||||
Button button{g};
|
Button button{g};
|
||||||
|
|
||||||
Gpio::set = true;
|
Gpio::is_set = true;
|
||||||
button.update();
|
button.update();
|
||||||
|
|
||||||
SECTION("Too short of a press is debounced.")
|
SECTION("Too short of a press is debounced.")
|
||||||
{
|
{
|
||||||
HAL::millis = Button::TIMEOUT_SHORT_PRESS - 1;
|
HAL::millis = Button::TIMEOUT_SHORT_PRESS - 1;
|
||||||
Gpio::set = false;
|
Gpio::is_set = false;
|
||||||
|
|
||||||
button.update();
|
button.update();
|
||||||
|
|
||||||
@ -91,7 +97,7 @@ TEST_CASE("Button reads presses properly.", "[peripherals],[button]")
|
|||||||
SECTION("Short press is identified properly.")
|
SECTION("Short press is identified properly.")
|
||||||
{
|
{
|
||||||
HAL::millis = Button::TIMEOUT_SHORT_PRESS + 2;
|
HAL::millis = Button::TIMEOUT_SHORT_PRESS + 2;
|
||||||
Gpio::set = false;
|
Gpio::is_set = false;
|
||||||
|
|
||||||
button.update();
|
button.update();
|
||||||
|
|
||||||
@ -124,7 +130,7 @@ TEST_CASE("Button reads presses properly.", "[peripherals],[button]")
|
|||||||
SECTION("Releasing keeps NOT_PRESSED state.")
|
SECTION("Releasing keeps NOT_PRESSED state.")
|
||||||
{
|
{
|
||||||
HAL::millis += 1;
|
HAL::millis += 1;
|
||||||
Gpio::set = false;
|
Gpio::is_set = false;
|
||||||
|
|
||||||
button.update();
|
button.update();
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "skullc/coro/sleep.hpp"
|
#include "skullc/coro/sleep.hpp"
|
||||||
#include "skullc/coro/task.hpp"
|
#include "skullc/coro/task.hpp"
|
||||||
#include "skullc/coro/this_coro.hpp"
|
#include "skullc/coro/this_coro.hpp"
|
||||||
|
#include "skullc/coro/signal.hpp"
|
||||||
|
|
||||||
#include <semaphore>
|
#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);
|
co_await skullc::coro::PinEdgeAwaiter(pin, edge);
|
||||||
test_coro_called = 1;
|
test_coro_called = 1;
|
||||||
@ -180,7 +181,7 @@ TEST_CASE("Peripheral awaiters work.", "[coro],[awaiters]")
|
|||||||
SECTION("Pin edge awaiter works with rising edge.")
|
SECTION("Pin edge awaiter works with rising edge.")
|
||||||
{
|
{
|
||||||
TestGpio gpio{false};
|
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);
|
scheduler.loop(0);
|
||||||
|
|
||||||
REQUIRE(test_coro_called == 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.")
|
SECTION("Pin edge awaiter works with falling edge.")
|
||||||
{
|
{
|
||||||
TestGpio gpio{true};
|
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);
|
scheduler.loop(0);
|
||||||
|
|
||||||
REQUIRE(test_coro_called == 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
|
~PinEdgeAwaiter() override
|
||||||
{
|
{
|
||||||
if (continuation)
|
if (continuation)
|
||||||
{
|
|
||||||
this_coro::scheduler().remove(continuation);
|
this_coro::scheduler().remove(continuation);
|
||||||
}
|
|
||||||
|
if (stored_coro)
|
||||||
|
this_coro::scheduler().remove(stored_coro);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool await_ready() { return false; }
|
bool await_ready() { return false; }
|
||||||
@ -36,7 +37,7 @@ struct PinEdgeAwaiter : TaskPoller
|
|||||||
{
|
{
|
||||||
continuation = h;
|
continuation = h;
|
||||||
stored_coro = continuation;
|
stored_coro = continuation;
|
||||||
skullc::this_coro::scheduler().add_poller(this);
|
this_coro::scheduler().add_poller(this);
|
||||||
}
|
}
|
||||||
auto await_resume()
|
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