-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuart.cpp
140 lines (120 loc) · 2.73 KB
/
uart.cpp
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "main.h"
#include "uart.hpp"
#include <usart.h>
using std::string_view;
namespace uart {
namespace {
struct Channel {
constexpr static int size = 128;
uint8_t mem[size];
int head = 0;
int tail = 0;
void push(char c, const IrqGuard&) volatile {
int next_tail = (tail + 1) % size;
if (next_tail != head) {
mem[tail] = static_cast<uint8_t>(c);
tail = next_tail;
}
}
char pop(const IrqGuard&) volatile {
if (head == tail) {
return 0;
} else {
char c = mem[head];
head = (head + 1) % size;
return c;
}
}
};
volatile Channel tx;
volatile Channel rx;
volatile bool tx_in_flight = false;
bool use_irq = false;
constexpr UART_HandleTypeDef* the_uart = &huart6;
constexpr int timeout_ms = 200;
char recv_char() {
if (use_irq) {
while (true) {
poll_peripherals();
auto no_irq = IrqGuard();
auto next = rx.pop(no_irq);
if (next) {
return next;
}
}
} else {
uint8_t c = 0;
poll_peripherals();
HAL_UART_Receive(the_uart, &c, 1, timeout_ms);
return static_cast<char>(c);
}
}
} // namespace
string_view recv(std::span<char> buf) {
char* const begin = buf.data();
char* const end = begin + buf.size();
char* it = begin;
while (it != end) {
char c = recv_char();
if (c == 0) {
continue;
}
send(string_view(&c, &c+1));
if (c == '\r') {
send("\n");
break;
}
*it++ = c;
}
return string_view(begin, it);
}
extern "C" void HAL_UART_RxCpltCallback(UART_HandleTypeDef* u) {
static volatile char next_byte = 0;
if (next_byte) {
rx.push(next_byte, IrqGuard());
}
HAL_UART_Receive_IT(u, (uint8_t*) &next_byte, 1);
}
void send(string_view line) {
if (use_irq) {
auto no_irq = IrqGuard();
for (char c: line) {
tx.push(c, no_irq);
}
// Kickstart tx if needed
if (!tx_in_flight) {
tx_in_flight = true;
HAL_UART_TxCpltCallback(the_uart);
}
} else {
HAL_UART_Transmit(the_uart, (const uint8_t*) line.data(), line.size(), timeout_ms);
}
}
extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef* u) {
static volatile char next_byte;
auto no_irq = IrqGuard();
next_byte = tx.pop(no_irq);
if (next_byte) {
HAL_UART_Transmit_IT(u, (const uint8_t*) &next_byte, 1);
} else {
tx_in_flight = false;
}
}
void sendln(string_view line) {
send(line);
send("\r\n");
}
void toggle_irq_mode() {
use_irq ^= true;
if (use_irq) {
HAL_NVIC_EnableIRQ(USART6_IRQn);
HAL_UART_RxCpltCallback(the_uart); // Kickstart rx
} else {
HAL_UART_AbortReceive(the_uart);
HAL_NVIC_DisableIRQ(USART6_IRQn);
tx_in_flight = false;
}
send("Async mode is now ");
sendln(use_irq ? "ON" : "OFF");
}
} // namespace uart