arm: more uart async & debug stuff
This commit is contained in:
parent
e1eaa0ec0a
commit
9ae472afaf
58
arm/async.h
58
arm/async.h
@ -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;
|
||||||
|
|
||||||
|
83
arm/uart.cc
83
arm/uart.cc
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!XUartLite_IsSending(uart0)) {
|
{
|
||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
InterruptLock lock;
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
if (!XUartLite_IsSending(uart0)) {
|
||||||
|
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||||
|
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||||
|
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)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!XUartLite_IsSending(uart0)) {
|
{
|
||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
InterruptLock lock;
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
if (!XUartLite_IsSending(uart0)) {
|
||||||
|
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||||
|
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user