#include "uart.h" #include "ring_buffer.h" #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif struct UART { USART_TypeDef* usart; RingBuffer rx_buffer; RingBuffer 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(g_uart1_rx_buffer, kUART1RxBufferSize), RingBuffer(g_uart1_tx_buffer, kUART1TxBufferSize), }; UART g_uart3{ USART3, RingBuffer(g_uart3_rx_buffer, kUART3RxBufferSize), RingBuffer(g_uart3_tx_buffer, kUART3TxBufferSize), }; UART g_uart4{ USART4, RingBuffer(g_uart4_rx_buffer, kUART4RxBufferSize), RingBuffer(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(buf), size); uart->usart->CR1 |= USART_CR1_TXEIE; return size; } size_t UARTWriteDirect(UART* uart, const void *buf, size_t nbytes) { if (uart == nullptr || buf == nullptr) return 0; const uint8_t *data = reinterpret_cast(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 UARTRead(UART* uart, void *buf, size_t nbytes) { if (uart == nullptr || buf == nullptr) return 0; const size_t size = Min(nbytes, uart->rx_buffer.Occupied()); uart->rx_buffer.Pop(reinterpret_cast(buf), size); return size; } size_t UARTReadDirect(UART* uart, void *buf, size_t nbytes) { if (uart == nullptr || buf == nullptr) return 0; uint8_t *data = reinterpret_cast(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; } void UARTHandleInterrupt(UART* uart) { 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; bool done = true; if (isr & USART_ISR_RXNE) { uart->rx_buffer.Push(usart_regs->RDR); done = false; } if (isr & USART_ISR_TXE) { if (!uart->tx_buffer.IsEmpty()) { usart_regs->TDR = uart->tx_buffer.Pop(); done = false; } else { usart_regs->CR1 &= ~USART_CR1_TXEIE; } } if (done) break; } }