arm: more uart async & debug stuff

This commit is contained in:
Paul Mathieu 2022-06-19 09:45:04 +02:00
parent e1eaa0ec0a
commit 9ae472afaf
4 changed files with 138 additions and 9 deletions

View File

@ -30,6 +30,64 @@ 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);
if (parent) {
TRACE(tracing::TraceEvent::kAsyncCallParent);
parent.resume();
TRACE(tracing::TraceEvent::kAsyncCallParentDone);
}
}
T await_resume() {
waiting = false;
TRACE(tracing::TraceEvent::kAsyncGimmeResume);
return std::move(stuff);
}
// parent interface
auto feed(T&& s) {
struct awaitable {
bool await_ready() {
if (g.waiting) {
return true;
}
// TODO: handle g.ha.done()
return false;
}
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;
parent = {};
ha.resume();
return awaitable{.g = *this};
}
bool waiting = false;
std::coroutine_handle<> ha;
T stuff;
std::coroutine_handle<> parent;
};
template <typename T = void> template <typename T = void>
struct task; struct task;

View File

@ -1,10 +1,11 @@
#include "uart.h" #include "uart.h"
#include "uart_async.h"
#include "async.h" #include "async.h"
#include "gpio.h" #include "gpio.h"
#include "lock.h"
#include "ring_buffer.h" #include "ring_buffer.h"
#include "trace.h" #include "trace.h"
#include "uart_async.h"
#include "xuartlite.h" #include "xuartlite.h"
namespace { namespace {
@ -54,38 +55,93 @@ void UartWriteCrash(std::span<const std::byte> data) {
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;
if (!XUartLite_IsSending(uart0)) { if (!XUartLite_IsSending(uart0)) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData()); tx_ring_buffer.ContiguousAvailableData());
} }
}
} }
#define GCC_HAS_BUG_101133 1 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101133
#if !GCC_HAS_BUG_101133
async::task<> UartWriteLoop(async::gimme<std::span<const std::byte>>& data_gen) {
while (1) {
auto data = co_await data_gen;
while (!tx_ring_buffer.Store(data)) {
tracing::trace(tracing::TraceEvent::kUartTxBufferFull);
co_await async::await(AwaitableType::kUartTx);
tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull);
}
{
InterruptLock lock;
if (!XUartLite_IsSending(uart0)) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
}
}
}
#endif // !GCC_HAS_BUG_101133
void UartReadBlocking(std::span<std::byte> data) { void UartReadBlocking(std::span<std::byte> data) {
size_t bytes_received = 0; size_t bytes_received = 0;
while (bytes_received < data.size()) { while (bytes_received < data.size()) {
auto* buffer = reinterpret_cast<uint8_t*>(data.data() + bytes_received); auto* buffer = reinterpret_cast<uint8_t*>(data.data() + bytes_received);
tracing::trace(tracing::TraceEvent::kUartRecv);
bytes_received += bytes_received +=
XUartLite_Recv(uart0, buffer, data.size() - bytes_received); XUartLite_Recv(uart0, buffer, data.size() - bytes_received);
} }
} }
void UartWriteBlocking(std::span<const std::byte> data) { void UartWriteBlocking(std::span<const std::byte> data) {
if (__get_PRIMASK() != 0) {
UartWriteCrash("\r\nUartWriteBlocking called with interupts disabled!\r\n");
__builtin_trap();
}
while (!tx_ring_buffer.Store(data)) { while (!tx_ring_buffer.Store(data)) {
} }
{
InterruptLock lock;
if (!XUartLite_IsSending(uart0)) { if (!XUartLite_IsSending(uart0)) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData()); tx_ring_buffer.ContiguousAvailableData());
} }
}
}
async::task<uint8_t> UartReadLoop() {
uint8_t c;
while (1) {
tracing::trace(tracing::TraceEvent::kUartRecv);
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_yield c;
}
} }
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()); auto* data = reinterpret_cast<uint8_t*>(buff.data.data());
tracing::trace(tracing::TraceEvent::kUartRecv);
size_t received = XUartLite_Recv(uart0, data, buff.data.size()); 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()) { if (received < buff.data.size()) {
co_await async::await(AwaitableType::kUartRx); co_await async::await(AwaitableType::kUartRx);
} }
@ -93,9 +149,9 @@ async::task<buffer> UartRead(int size) {
} }
void HandleUartTxFromIsr(void*, unsigned int transmitted) { void HandleUartTxFromIsr(void*, unsigned int transmitted) {
tracing::trace(tracing::TraceEvent::kUartTxCb);
tx_ring_buffer.Pop(transmitted); tx_ring_buffer.Pop(transmitted);
if (tx_ring_buffer.AvailableData() > 0) { if (tx_ring_buffer.AvailableData() > 0) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData()); tx_ring_buffer.ContiguousAvailableData());
} }
@ -103,8 +159,17 @@ void HandleUartTxFromIsr(void*, unsigned int transmitted) {
} }
void HandleUartRxFromIsr(void*, unsigned int) { void HandleUartRxFromIsr(void*, unsigned int) {
tracing::trace(tracing::TraceEvent::kUartRxCb);
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;
}

View File

@ -28,3 +28,7 @@ inline void UartWriteBlocking(std::string_view s) {
void HandleUartTxFromIsr(void*, unsigned int transmitted); void HandleUartTxFromIsr(void*, unsigned int transmitted);
void HandleUartRxFromIsr(void*, unsigned int); void HandleUartRxFromIsr(void*, unsigned int);
void HandleUartIsr(); void HandleUartIsr();
uint8_t UartStatus();
void LogStuff();

View File

@ -7,7 +7,9 @@
#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<> 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()}));
} }
async::task<> UartWriteLoop(async::gimme<std::span<const std::byte>>& data);