mbv: i really though async would work this time
There's still a glitch/race somewhere.
This commit is contained in:
parent
724f8db1b1
commit
f0f26af791
@ -86,7 +86,7 @@ void step() {
|
|||||||
|
|
||||||
if (stuff->h.done()) {
|
if (stuff->h.done()) {
|
||||||
stuff->h.destroy();
|
stuff->h.destroy();
|
||||||
}
|
} // XXX: else??
|
||||||
|
|
||||||
{
|
{
|
||||||
InterruptLock lock;
|
InterruptLock lock;
|
||||||
|
@ -27,38 +27,6 @@ struct task_final_suspend {
|
|||||||
std::coroutine_handle<> parent;
|
std::coroutine_handle<> parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct gimme {
|
|
||||||
// child interface
|
|
||||||
bool await_ready() { return false; }
|
|
||||||
void await_suspend(std::coroutine_handle<> h) {
|
|
||||||
ha = h;
|
|
||||||
waiting = true;
|
|
||||||
TRACE(tracing::TraceEvent::kAsyncGimmeWaiting);
|
|
||||||
}
|
|
||||||
T await_resume() {
|
|
||||||
waiting = false;
|
|
||||||
TRACE(tracing::TraceEvent::kAsyncGimmeResume);
|
|
||||||
return std::move(stuff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parent interface
|
|
||||||
void feed(T&& s) {
|
|
||||||
if (!waiting) {
|
|
||||||
__builtin_trap();
|
|
||||||
}
|
|
||||||
if (!ha) {
|
|
||||||
__builtin_trap();
|
|
||||||
}
|
|
||||||
stuff = s;
|
|
||||||
ha.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool waiting = false;
|
|
||||||
std::coroutine_handle<> ha;
|
|
||||||
T stuff;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T = void>
|
template <typename T = void>
|
||||||
struct task;
|
struct task;
|
||||||
|
|
||||||
@ -205,4 +173,58 @@ inline auto delay(int ms) {
|
|||||||
return awaitable{ms};
|
return awaitable{ms};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct gimme {
|
||||||
|
// child interface
|
||||||
|
bool await_ready() { return false; }
|
||||||
|
void await_suspend(std::coroutine_handle<> h) {
|
||||||
|
ha = h;
|
||||||
|
waiting = true;
|
||||||
|
TRACE(tracing::TraceEvent::kAsyncGimmeWaiting);
|
||||||
|
if (suspended) {
|
||||||
|
schedule(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T await_resume() {
|
||||||
|
suspended = false;
|
||||||
|
waiting = false;
|
||||||
|
TRACE(tracing::TraceEvent::kAsyncGimmeResume);
|
||||||
|
return std::move(stuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parent interface
|
||||||
|
auto feed(T&& s) {
|
||||||
|
struct awaitable {
|
||||||
|
bool await_ready() {
|
||||||
|
g->ha.resume();
|
||||||
|
if (!g->waiting) {
|
||||||
|
g->suspended = true;
|
||||||
|
}
|
||||||
|
return !g->suspended;
|
||||||
|
}
|
||||||
|
void await_suspend(std::coroutine_handle<> h) {
|
||||||
|
g->parent = h;
|
||||||
|
}
|
||||||
|
void await_resume() { }
|
||||||
|
|
||||||
|
gimme<T>* g;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!waiting) {
|
||||||
|
__builtin_trap();
|
||||||
|
}
|
||||||
|
if (!ha) {
|
||||||
|
__builtin_trap();
|
||||||
|
}
|
||||||
|
stuff = s;
|
||||||
|
return awaitable{.g = this};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool suspended = false;
|
||||||
|
bool waiting = false;
|
||||||
|
std::coroutine_handle<> ha;
|
||||||
|
std::coroutine_handle<> parent;
|
||||||
|
T stuff;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace async
|
} // namespace async
|
||||||
|
@ -11,11 +11,9 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using async::AwaitableType;
|
|
||||||
Timer* timer0;
|
Timer* timer0;
|
||||||
|
|
||||||
void Uart0Isr() {
|
void Uart0Isr() {
|
||||||
ToggleLed(7);
|
|
||||||
HandleUartIsr();
|
HandleUartIsr();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,16 +46,23 @@ void SetupInterrupts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async::task<> echo() {
|
async::task<> echo() {
|
||||||
async::task<uint8_t> reader = UartReadLoop();
|
async::task<std::byte> reader = UartReadLoop();
|
||||||
async::gimme<std::span<const std::byte>> feeder;
|
async::gimme<std::span<const std::byte>> feeder;
|
||||||
async::task<> writer = UartWriteLoop(feeder);
|
async::task<> writer = UartWriteLoop(feeder);
|
||||||
writer.h.resume(); // advance to first yield
|
writer.h.resume(); // advance to first yield
|
||||||
while (1) {
|
while (1) {
|
||||||
SetLed(1);
|
SetLed(1);
|
||||||
uint8_t c = co_await reader;
|
std::byte c = co_await reader;
|
||||||
ClearLed(1);
|
ClearLed(1);
|
||||||
ToggleLed(2);
|
co_await feeder.feed(std::span{&c, 1});
|
||||||
feeder.feed(std::as_bytes(std::span{&c, 1}));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async::task<> blink() {
|
||||||
|
while (1) {
|
||||||
|
co_await async::delay(500);
|
||||||
|
ToggleLed(0);
|
||||||
|
timer0->Pet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,25 +70,19 @@ async::task<> echo() {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
SetupUart();
|
SetupUart();
|
||||||
UartWriteCrash("uart setup done\r\n");
|
UartWriteBlocking("uart setup done\r\n");
|
||||||
SetupTimer();
|
SetupTimer();
|
||||||
UartWriteCrash("timer setup done\r\n");
|
UartWriteBlocking("timer setup done\r\n");
|
||||||
|
|
||||||
gpio0->data = 0;
|
gpio0->data = 0;
|
||||||
SetupInterrupts();
|
SetupInterrupts();
|
||||||
|
|
||||||
async::schedule(echo().h);
|
async::schedule(echo().h);
|
||||||
|
async::schedule(blink().h);
|
||||||
|
|
||||||
UartWriteCrash("init done. starting main loop\r\n");
|
UartWriteBlocking("init done. starting main loop\r\n");
|
||||||
|
|
||||||
async::main_loop([]() {
|
async::main_loop(nullptr);
|
||||||
static int cnt = 0;
|
|
||||||
timer0->Pet();
|
|
||||||
if ((cnt++ % 100000) == 0) {
|
|
||||||
ToggleLed(0);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
// should never get here
|
// should never get here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,13 +22,43 @@ XUartLite_Config uart0_config = {
|
|||||||
.DataBits = 8,
|
.DataBits = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr size_t kUartRxBufferSize = 256;
|
||||||
|
std::array<std::byte, kUartRxBufferSize> rx_buffer = {};
|
||||||
|
RingBuffer rx_ring_buffer{.buffer = rx_buffer};
|
||||||
|
|
||||||
constexpr size_t kUartTxBufferSize = 256;
|
constexpr size_t kUartTxBufferSize = 256;
|
||||||
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
||||||
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
||||||
|
|
||||||
XUartLite* uart0 = &uart0_inst;
|
XUartLite* uart0 = &uart0_inst;
|
||||||
|
|
||||||
bool sending;
|
volatile bool sending;
|
||||||
|
|
||||||
|
void StartReceiving() {
|
||||||
|
while (1) {
|
||||||
|
if (rx_ring_buffer.FreeSpace() < 1) {
|
||||||
|
// woops, full. discard some data
|
||||||
|
// TODO: keep track of overrun stats
|
||||||
|
rx_ring_buffer.Pop(1);
|
||||||
|
}
|
||||||
|
if (XUartLite_Recv(uart0, rx_ring_buffer.RawWritePointer(), 1) < 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rx_ring_buffer.Push(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartSending() {
|
||||||
|
if (sending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t tosend = tx_ring_buffer.ContiguousAvailableData();
|
||||||
|
if (tosend < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sending = true;
|
||||||
|
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), tosend);
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void InitUarts() {
|
void InitUarts() {
|
||||||
@ -36,6 +66,7 @@ void InitUarts() {
|
|||||||
|
|
||||||
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
||||||
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
||||||
|
StartReceiving();
|
||||||
XUartLite_EnableInterrupt(uart0);
|
XUartLite_EnableInterrupt(uart0);
|
||||||
|
|
||||||
sending = false;
|
sending = false;
|
||||||
@ -53,23 +84,18 @@ void UartWriteCrash(std::span<const std::byte> data) {
|
|||||||
}
|
}
|
||||||
while (XUartLite_IsSending(uart0)) {
|
while (XUartLite_IsSending(uart0)) {
|
||||||
}
|
}
|
||||||
|
XUartLite_Send(uart0, nullptr, 0); // reset buffer before enabling interrupts
|
||||||
XUartLite_EnableInterrupt(uart0);
|
XUartLite_EnableInterrupt(uart0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async::task<> UartWrite(std::span<const std::byte> data) {
|
async::task<> UartWrite(std::span<const std::byte> data) {
|
||||||
while (!tx_ring_buffer.Store(data)) {
|
while (!tx_ring_buffer.Store(data)) {
|
||||||
tracing::trace(tracing::TraceEvent::kUartTxBufferFull);
|
|
||||||
co_await async::await(AwaitableType::kUartTx);
|
co_await async::await(AwaitableType::kUartTx);
|
||||||
tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
InterruptLock lock;
|
InterruptLock lock;
|
||||||
if (!XUartLite_IsSending(uart0)) {
|
StartSending();
|
||||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
|
||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,30 +104,19 @@ async::task<> UartWriteLoop(
|
|||||||
while (1) {
|
while (1) {
|
||||||
auto data = co_await data_gen;
|
auto data = co_await data_gen;
|
||||||
while (!tx_ring_buffer.Store(data)) {
|
while (!tx_ring_buffer.Store(data)) {
|
||||||
tracing::trace(tracing::TraceEvent::kUartTxBufferFull);
|
|
||||||
co_await async::await(AwaitableType::kUartTx);
|
co_await async::await(AwaitableType::kUartTx);
|
||||||
tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
InterruptLock lock;
|
InterruptLock lock;
|
||||||
if (!sending) {
|
StartSending();
|
||||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
|
||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
|
||||||
sending = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use chunks to allow receiving more than 256 bytes at once
|
||||||
void UartReadBlocking(std::span<std::byte> data) {
|
void UartReadBlocking(std::span<std::byte> data) {
|
||||||
size_t bytes_received = 0;
|
while (!rx_ring_buffer.Load(data)) {
|
||||||
while (bytes_received < data.size()) {
|
|
||||||
auto* buffer = reinterpret_cast<uint8_t*>(data.data() + bytes_received);
|
|
||||||
tracing::trace(tracing::TraceEvent::kUartRecv);
|
|
||||||
bytes_received +=
|
|
||||||
XUartLite_Recv(uart0, buffer, data.size() - bytes_received);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,21 +126,14 @@ void UartWriteBlocking(std::span<const std::byte> data) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
InterruptLock lock;
|
InterruptLock lock;
|
||||||
if (!XUartLite_IsSending(uart0)) {
|
StartSending();
|
||||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
|
||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async::task<uint8_t> UartReadLoop() {
|
async::task<std::byte> UartReadLoop() {
|
||||||
uint8_t c;
|
std::byte c;
|
||||||
while (1) {
|
while (1) {
|
||||||
tracing::trace(tracing::TraceEvent::kUartRecv);
|
while (!rx_ring_buffer.Load(std::span{&c, 1})) {
|
||||||
size_t received = XUartLite_Recv(uart0, &c, 1);
|
|
||||||
// some data may already be in the fifo, but if not, wait:
|
|
||||||
if (received < 1) {
|
|
||||||
co_await async::await(AwaitableType::kUartRx);
|
co_await async::await(AwaitableType::kUartRx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,11 +143,7 @@ async::task<uint8_t> UartReadLoop() {
|
|||||||
|
|
||||||
async::task<buffer> UartRead(int size) {
|
async::task<buffer> UartRead(int size) {
|
||||||
auto buff = buffer::make(size);
|
auto buff = buffer::make(size);
|
||||||
auto* data = reinterpret_cast<uint8_t*>(buff.data.data());
|
while (!rx_ring_buffer.Load(buff.data)) {
|
||||||
tracing::trace(tracing::TraceEvent::kUartRecv);
|
|
||||||
size_t received = XUartLite_Recv(uart0, data, buff.data.size());
|
|
||||||
// some data may already be in the fifo, but if not, wait:
|
|
||||||
if (received < buff.data.size()) {
|
|
||||||
co_await async::await(AwaitableType::kUartRx);
|
co_await async::await(AwaitableType::kUartRx);
|
||||||
}
|
}
|
||||||
co_return buff;
|
co_return buff;
|
||||||
@ -148,27 +152,14 @@ async::task<buffer> UartRead(int size) {
|
|||||||
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
||||||
sending = false;
|
sending = false;
|
||||||
tx_ring_buffer.Pop(transmitted);
|
tx_ring_buffer.Pop(transmitted);
|
||||||
if (tx_ring_buffer.AvailableData() > 0) {
|
StartSending();
|
||||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
|
||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
|
||||||
sending = true;
|
|
||||||
}
|
|
||||||
async::resume(AwaitableType::kUartTx);
|
async::resume(AwaitableType::kUartTx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleUartRxFromIsr(void*, unsigned int) {
|
void HandleUartRxFromIsr(void*, unsigned int transmitted) {
|
||||||
|
rx_ring_buffer.Push(transmitted);
|
||||||
|
StartReceiving();
|
||||||
async::resume(AwaitableType::kUartRx);
|
async::resume(AwaitableType::kUartRx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }
|
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }
|
||||||
|
|
||||||
extern "C" uint8_t XUartLite_GetSR(XUartLite*);
|
|
||||||
|
|
||||||
uint8_t UartStatus() { return XUartLite_GetSR(uart0); }
|
|
||||||
|
|
||||||
void LogStuff() {
|
|
||||||
uint8_t data = gpio0->data;
|
|
||||||
data |= (uart0->ReceiveBuffer.RemainingBytes & 0xf) << 4;
|
|
||||||
gpio0->data = data;
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
async::task<buffer> UartRead(int size);
|
async::task<buffer> UartRead(int size);
|
||||||
async::task<uint8_t> UartReadLoop();
|
async::task<std::byte> UartReadLoop();
|
||||||
async::task<> UartWrite(std::span<const std::byte> data);
|
async::task<> UartWrite(std::span<const std::byte> data);
|
||||||
inline async::task<> UartWrite(std::string_view s) {
|
inline async::task<> UartWrite(std::string_view s) {
|
||||||
co_await UartWrite(std::as_bytes(std::span{s.data(), s.size()}));
|
co_await UartWrite(std::as_bytes(std::span{s.data(), s.size()}));
|
||||||
|
4
mbv/configure
vendored
4
mbv/configure
vendored
@ -304,9 +304,9 @@ all = [
|
|||||||
app_image("async", sources=[
|
app_image("async", sources=[
|
||||||
"apps/async/async.cc",
|
"apps/async/async.cc",
|
||||||
"apps/async/lock.cc",
|
"apps/async/lock.cc",
|
||||||
"apps/async/main2.cc",
|
"apps/async/main.cc",
|
||||||
"apps/async/trace.cc",
|
"apps/async/trace.cc",
|
||||||
"apps/async/uart2.cc",
|
"apps/async/uart.cc",
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user