WIP4: Add Signal entity
Some checks failed
CI & Unit Tests / Unit-Tests (push) Failing after 18s
CI & Unit Tests / Docs (push) Successful in 12s

This commit is contained in:
Erki 2025-02-21 21:19:42 +02:00
parent 66461af1e4
commit 8d49d2d446
4 changed files with 199 additions and 15 deletions

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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()
{

View 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_;
};
}