#pragma once #include #include #include namespace async { struct task_final_suspend { bool await_ready() noexcept(true) { return false; } void await_suspend(std::coroutine_handle<> h) noexcept(true) { if (parent) { parent(); } h.destroy(); } void await_resume() noexcept(true) {} std::coroutine_handle<> parent; }; template struct task { struct promise_type; using handle_type = std::coroutine_handle; struct promise_type { task get_return_object() { return {.h = handle_type::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } task_final_suspend final_suspend() noexcept { return {.parent = parent}; } void return_value(T&& value) { ret_value = std::move(value); } void unhandled_exception() {} T ret_value; std::coroutine_handle<> parent; }; // awaitable bool await_ready() { return h.done(); } void await_suspend(std::coroutine_handle<> ha) { h(); h.promise().parent = ha; } T await_resume() { return std::move(h.promise().ret_value); } std::coroutine_handle h; }; template <> struct task { struct promise_type; using handle_type = std::coroutine_handle; struct promise_type { task get_return_object() { return {.h = handle_type::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } task_final_suspend final_suspend() noexcept { return {.parent = parent}; } void return_void() {} void unhandled_exception() {} std::coroutine_handle<> parent; }; // awaitable bool await_ready() { return h.done(); } void await_suspend(std::coroutine_handle<> ha) { h.promise().parent = ha; h(); } void await_resume() {} std::coroutine_handle h; }; enum class AwaitableType { kUnknown = 0, kUartRx = 1, kUartTx = 2, kNumTypes }; void schedule(std::coroutine_handle<> h, int ms = 0); void enqueue(std::coroutine_handle<> h, AwaitableType type); void resume(AwaitableType type); // typically called from an ISR void main_loop(void (*idle_function)()); inline auto await(AwaitableType type) { struct awaitable { AwaitableType type; bool await_ready() { return false; }; void await_suspend(std::coroutine_handle<> h) { enqueue(h, type); } void await_resume() {} }; return awaitable{type}; } inline auto delay(int ms) { struct awaitable { int ms; bool await_ready() { return false; }; void await_suspend(std::coroutine_handle<> h) { schedule(h, ms); } void await_resume() {} }; return awaitable{ms}; } } // namespace async