synth/mbv/apps/async/uart2.cc

120 lines
2.8 KiB
C++

#include "uart2.h"
#include "gpio.h"
#include "lock.h"
#include "pol0.h"
#include "ring_buffer.h"
#include "xuartlite.h"
namespace {
constexpr uintptr_t kUart0BaseAddress = UART0_BASE;
XUartLite uart0_inst;
XUartLite_Config uart0_config = {
.DeviceId = 0,
.RegBaseAddr = kUart0BaseAddress,
.BaudRate = 115200,
.UseParity = false,
.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;
volatile int sending = 0;
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 (tx_ring_buffer.AvailableData() > 0 && sending < 1) {
sending += 1;
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), 1);
}
}
std::byte UartReadByte() {
std::byte c;
while (!rx_ring_buffer.Load(std::span{&c, 1})) {
}
return c;
}
void UartWriteByte(std::byte c) {
while (!tx_ring_buffer.Store(std::span{&c, 1})) {
}
{
InterruptLock lock;
StartSending();
}
}
} // namespace
void InitUarts() {
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
StartReceiving();
XUartLite_EnableInterrupt(uart0);
}
void UartWriteCrash(std::span<const std::byte> data) {
XUartLite_DisableInterrupt(uart0);
while (data.size() > 0) {
while (XUartLite_IsSending(uart0)) {
}
auto* dat =
reinterpret_cast<uint8_t*>(const_cast<std::byte*>(data.data()));
uint8_t sent = XUartLite_Send(uart0, dat, data.size());
data = data.subspan(sent);
}
while (XUartLite_IsSending(uart0)) {
}
XUartLite_EnableInterrupt(uart0);
}
void UartEcho() {
while (1) {
gpio0->data = tx_ring_buffer.AvailableData();
std::byte c = UartReadByte();
UartWriteByte(c);
//gpio0->data = uart0->Stats.ReceiveOverrunErrors;
}
}
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
sending -= 1;
tx_ring_buffer.Pop(transmitted);
StartSending();
}
void HandleUartRxFromIsr(void*, unsigned int transmitted) {
rx_ring_buffer.Push(transmitted);
StartReceiving();
}
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }