diff options
Diffstat (limited to 'app/platform/stm32f0-gcc/uart.cpp')
-rw-r--r-- | app/platform/stm32f0-gcc/uart.cpp | 121 |
1 files changed, 101 insertions, 20 deletions
diff --git a/app/platform/stm32f0-gcc/uart.cpp b/app/platform/stm32f0-gcc/uart.cpp index 0fa6527..4d9bf5f 100644 --- a/app/platform/stm32f0-gcc/uart.cpp +++ b/app/platform/stm32f0-gcc/uart.cpp @@ -1,33 +1,114 @@ #include "uart.h" +#include "ring_buffer.h" -size_t UARTWrite(USART_TypeDef* uart, const void *data, size_t nbytes) +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +struct UART +{ + USART_TypeDef* usart; + RingBuffer<uint8_t> rx_buffer; + RingBuffer<uint8_t> tx_buffer; +}; + +static constexpr size_t kUART1RxBufferSize = 100; +static constexpr size_t kUART1TxBufferSize = 256; +static constexpr size_t kUART3RxBufferSize = 256; +static constexpr size_t kUART3TxBufferSize = 256; +static constexpr size_t kUART4RxBufferSize = 100; +static constexpr size_t kUART4TxBufferSize = 100; +static uint8_t g_uart1_rx_buffer[kUART1RxBufferSize]{}; +static uint8_t g_uart1_tx_buffer[kUART1TxBufferSize]{}; +static uint8_t g_uart3_rx_buffer[kUART3RxBufferSize]{}; +static uint8_t g_uart3_tx_buffer[kUART3TxBufferSize]{}; +static uint8_t g_uart4_rx_buffer[kUART4RxBufferSize]{}; +static uint8_t g_uart4_tx_buffer[kUART4TxBufferSize]{}; + +UART g_uart1{ + USART1, + RingBuffer<uint8_t>(g_uart1_rx_buffer, kUART1RxBufferSize), + RingBuffer<uint8_t>(g_uart1_tx_buffer, kUART1TxBufferSize), +}; +UART g_uart3{ + USART3, + RingBuffer<uint8_t>(g_uart3_rx_buffer, kUART3RxBufferSize), + RingBuffer<uint8_t>(g_uart3_tx_buffer, kUART3TxBufferSize), +}; +UART g_uart4{ + USART4, + RingBuffer<uint8_t>(g_uart4_rx_buffer, kUART4RxBufferSize), + RingBuffer<uint8_t>(g_uart4_tx_buffer, kUART4TxBufferSize), +}; + +static constexpr Min(size_t a, size_t b) { return (a >= b) ? a : b; } + +size_t UARTWrite(UART* uart, const void *buf, size_t nbytes) +{ + if (uart == nullptr || buf == nullptr) return 0; + const size_t size = Min(nbytes, uart->tx_buffer.Free()); + if (size == 0) return 0; + uart->tx_buffer.Push(reinterpret_cast<const uint8_t*>(buf), size); + uart->usart->CR1 |= USART_CR1_TXEIE; + return size; +} + +size_t UARTWriteDirect(UART* uart, const void *buf, size_t nbytes) { - if (uart == nullptr) return 0; - (void) data; - (void) nbytes; - return 0; + if (uart == nullptr || buf == nullptr) return 0; + const uint8_t *data = reinterpret_cast<const uint8_t *>(buf); + // TODO disable interrupts here + for (size_t i = 0; i < nbytes; i++) { + while (!(uart->usart->ISR & USART_ISR_TXE)); + uart->usart->TDR = data[i]; + } + // TODO restore (not just enable) interrupts here + return nbytes; } -size_t UARTWriteDirect(USART_TypeDef* uart, const void *data, size_t nbytes) +size_t UARTRead(UART* uart, void *buf, size_t nbytes) { - if (uart == nullptr) return 0; - (void) data; - (void) nbytes; - return 0; + if (uart == nullptr || buf == nullptr) return 0; + const size_t size = Min(nbytes, uart->rx_buffer.Occupied()); + uart->rx_buffer.Pop(reinterpret_cast<uint8_t*>(buf), size); + return size; } -size_t UARTRead(USART_TypeDef* uart, void *data, size_t nbytes) +size_t UARTReadDirect(UART* uart, void *buf, size_t nbytes) { - if (uart == nullptr) return 0; - (void) data; - (void) nbytes; - return 0; + if (uart == nullptr || buf == nullptr) return 0; + uint8_t *data = reinterpret_cast<uint8_t *>(buf); + // TODO disable interrupts here + for (size_t i = 0; i < nbytes; i++) { + while (!(uart->usart->ISR & USART_ISR_RXNE)); + data[i] = uart->usart->RDR; + } + // TODO restore (not just enable) interrupts here + return nbytes; } -size_t UARTReadDirect(USART_TypeDef* uart, void *data, size_t nbytes) +void UARTHandleInterrupt(UART* uart) { - if (uart == nullptr) return 0; - (void) data; - (void) nbytes; - return 0; + volatile USART_TypeDef* usart_regs = uart->usart; + const uint32_t cr1 = usart_regs->CR1; + if ((cr1 & USART_CR1_UE) == 0) + return; + for (int _ = 0; _ < 256; _++) { + const uint32_t isr = usart_regs->ISR; + const bool rxne = isr & USART_ISR_RXNE; + const bool txe = isr & USART_ISR_TXE; + if (!rxne && !txe) + break; + if (rxne) { + uart->rx_buffer.Push(usart_regs->RDR); + } + if (txe) { + if (!uart->tx_buffer.IsEmpty()) { + usart_regs->TDR = uart->tx_buffer.Pop(); + } else { + usart_regs->CR1 &= ~USART_CR1_TXEIE; + } + } + } } |