summaryrefslogtreecommitdiff
path: root/app/platform/stm32f0-gcc/uart.cpp
blob: 89472ee29ede01d7dfdfc31000aa2ee71dbe955f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#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<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 || 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 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<uint8_t*>(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<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;
}

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;
    }
}