mbv: i really though async would work this time
There's still a glitch/race somewhere.
This commit is contained in:
@@ -22,13 +22,43 @@ XUartLite_Config uart0_config = {
|
||||
.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;
|
||||
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
||||
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
||||
|
||||
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
|
||||
|
||||
void InitUarts() {
|
||||
@@ -36,6 +66,7 @@ void InitUarts() {
|
||||
|
||||
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
||||
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
||||
StartReceiving();
|
||||
XUartLite_EnableInterrupt(uart0);
|
||||
|
||||
sending = false;
|
||||
@@ -53,23 +84,18 @@ void UartWriteCrash(std::span<const std::byte> data) {
|
||||
}
|
||||
while (XUartLite_IsSending(uart0)) {
|
||||
}
|
||||
XUartLite_Send(uart0, nullptr, 0); // reset buffer before enabling interrupts
|
||||
XUartLite_EnableInterrupt(uart0);
|
||||
}
|
||||
|
||||
async::task<> UartWrite(std::span<const std::byte> data) {
|
||||
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());
|
||||
}
|
||||
StartSending();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,30 +104,19 @@ async::task<> UartWriteLoop(
|
||||
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 (!sending) {
|
||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||
tx_ring_buffer.ContiguousAvailableData());
|
||||
sending = true;
|
||||
}
|
||||
StartSending();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use chunks to allow receiving more than 256 bytes at once
|
||||
void UartReadBlocking(std::span<std::byte> data) {
|
||||
size_t bytes_received = 0;
|
||||
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);
|
||||
while (!rx_ring_buffer.Load(data)) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,21 +126,14 @@ void UartWriteBlocking(std::span<const std::byte> data) {
|
||||
|
||||
{
|
||||
InterruptLock lock;
|
||||
if (!XUartLite_IsSending(uart0)) {
|
||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||
tx_ring_buffer.ContiguousAvailableData());
|
||||
}
|
||||
StartSending();
|
||||
}
|
||||
}
|
||||
|
||||
async::task<uint8_t> UartReadLoop() {
|
||||
uint8_t c;
|
||||
async::task<std::byte> UartReadLoop() {
|
||||
std::byte 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) {
|
||||
while (!rx_ring_buffer.Load(std::span{&c, 1})) {
|
||||
co_await async::await(AwaitableType::kUartRx);
|
||||
}
|
||||
|
||||
@@ -135,11 +143,7 @@ async::task<uint8_t> UartReadLoop() {
|
||||
|
||||
async::task<buffer> UartRead(int size) {
|
||||
auto buff = buffer::make(size);
|
||||
auto* data = reinterpret_cast<uint8_t*>(buff.data.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()) {
|
||||
while (!rx_ring_buffer.Load(buff.data)) {
|
||||
co_await async::await(AwaitableType::kUartRx);
|
||||
}
|
||||
co_return buff;
|
||||
@@ -148,27 +152,14 @@ async::task<buffer> UartRead(int size) {
|
||||
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
||||
sending = false;
|
||||
tx_ring_buffer.Pop(transmitted);
|
||||
if (tx_ring_buffer.AvailableData() > 0) {
|
||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||
tx_ring_buffer.ContiguousAvailableData());
|
||||
sending = true;
|
||||
}
|
||||
StartSending();
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user