1use core::future::Future;
20
21use embassy_executor::SendSpawner;
22use embassy_sync::pipe::TryWriteError;
23use embassy_sync::signal::Signal;
24use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe};
25use esp_hal::Async;
26use esp_hal::gpio::AnyPin;
27#[cfg(feature = "bench-loopback")]
28use esp_hal::gpio::Flex;
29use esp_hal::peripherals::UART1;
30use esp_hal::uart::{Config, DataBits, Parity, RxConfig, StopBits, Uart};
31use portable_atomic::{AtomicUsize, Ordering};
32use ssh_stamp::serial::BufferedSerial;
33use ssh_stamp_hal::{Parity as LineParity, UartParams};
34use static_cell::StaticCell;
35
36const INWARD_BUF_SZ: usize = 512;
37const OUTWARD_BUF_SZ: usize = 256;
38const UART_BUF_SZ: usize = 64;
39
40const MAX_BAUD: u32 = 5_000_000;
42
43pub struct BufferedUart {
45 outward: Pipe<CriticalSectionRawMutex, OUTWARD_BUF_SZ>,
46 inward: Pipe<CriticalSectionRawMutex, INWARD_BUF_SZ>,
47 dropped_rx_bytes: AtomicUsize,
48}
49
50impl BufferedUart {
51 #[must_use]
52 pub fn new() -> Self {
53 BufferedUart {
54 outward: Pipe::new(),
55 inward: Pipe::new(),
56 dropped_rx_bytes: AtomicUsize::from(0),
57 }
58 }
59
60 pub async fn run(&self, uart: Uart<'_, Async>) {
65 let (mut uart_rx, mut uart_tx) = uart.split();
66 let mut rx_buf = [0u8; UART_BUF_SZ];
67 let mut tx_buf = [0u8; UART_BUF_SZ];
68
69 loop {
70 use embassy_futures::select::select;
71
72 let rd_from = async {
73 loop {
74 let Ok(n) = uart_rx.read_async(&mut rx_buf).await else {
75 continue;
76 };
77
78 let mut rx_slice = &rx_buf[..n];
79
80 while !rx_slice.is_empty() {
81 rx_slice = match self.inward.try_write(rx_slice) {
82 Ok(w) => &rx_slice[w..],
83 Err(TryWriteError::Full) => {
84 let mut drop_buf = [0u8; UART_BUF_SZ];
85 let dropped = self
86 .inward
87 .try_read(&mut drop_buf[..rx_slice.len()])
88 .unwrap_or(0);
89 let _ = self.dropped_rx_bytes.fetch_update(
90 Ordering::Relaxed,
91 Ordering::Relaxed,
92 |d| Some(d.saturating_add(dropped)),
93 );
94 rx_slice
95 }
96 };
97 }
98 }
99 };
100
101 let rd_to = async {
102 loop {
103 let n = self.outward.read(&mut tx_buf).await;
104
105 let mut tx_slice = &tx_buf[..n];
109 while !tx_slice.is_empty() {
110 let Ok(written) = uart_tx.write_async(tx_slice).await else {
111 break;
112 };
113
114 tx_slice = &tx_slice[written..];
115 }
116 }
117 };
118
119 select(rd_from, rd_to).await;
120 }
121 }
122
123 pub async fn read(&self, buf: &mut [u8]) -> usize {
124 self.inward.read(buf).await
125 }
126
127 pub async fn write(&self, buf: &[u8]) {
128 self.outward.write_all(buf).await;
129 }
130
131 pub fn check_dropped_bytes(&self) -> usize {
133 self.dropped_rx_bytes.swap(0, Ordering::Relaxed)
134 }
135}
136
137impl Default for BufferedUart {
138 fn default() -> Self {
139 Self::new()
140 }
141}
142
143impl BufferedSerial for BufferedUart {
144 fn read(&self, buf: &mut [u8]) -> impl Future<Output = usize> {
145 BufferedUart::read(self, buf)
146 }
147
148 fn write(&self, buf: &[u8]) -> impl Future<Output = ()> {
149 BufferedUart::write(self, buf)
150 }
151
152 fn check_dropped_bytes(&self) -> usize {
153 BufferedUart::check_dropped_bytes(self)
154 }
155}
156
157pub struct EspUartPins<'a> {
163 pub rx: AnyPin<'a>,
164 pub tx: AnyPin<'a>,
165}
166
167pub static UART_BUF: StaticCell<BufferedUart> = StaticCell::new();
169
170pub static UART_SIGNAL: Signal<CriticalSectionRawMutex, u8> = Signal::new();
173
174fn esp_uart_config(params: UartParams) -> Config {
181 let data_bits = match params.data_bits {
182 5 => DataBits::_5,
183 6 => DataBits::_6,
184 7 => DataBits::_7,
185 _ => DataBits::_8,
186 };
187 let parity = match params.parity {
188 LineParity::Even => Parity::Even,
189 LineParity::Odd => Parity::Odd,
190 LineParity::None => Parity::None,
191 };
192 let stop_bits = if params.stop_bits == 2 {
193 StopBits::_2
194 } else {
195 StopBits::_1
196 };
197
198 Config::default()
199 .with_baudrate(params.baud.clamp(1, MAX_BAUD))
200 .with_data_bits(data_bits)
201 .with_parity(parity)
202 .with_stop_bits(stop_bits)
203}
204
205#[embassy_executor::task]
212pub async fn uart_task(
213 uart_buf: &'static BufferedUart,
214 uart1: UART1<'static>,
215 pins: EspUartPins<'static>,
216 params: UartParams,
217) {
218 UART_SIGNAL.wait().await;
219
220 let uart_config = esp_uart_config(params).with_rx(
221 RxConfig::default()
222 .with_fifo_full_threshold(16)
223 .with_timeout(1),
224 );
225
226 let uart = Uart::new(uart1, uart_config).expect("UART config error");
227
228 #[cfg(feature = "bench-loopback")]
230 let uart = {
231 log::warn!("bench-loopback active, the TX is looped back to RX.");
232 let (rx_sig, tx_sig) = Flex::new(pins.tx).split();
233 uart.with_rx(rx_sig).with_tx(tx_sig).into_async()
234 };
235 #[cfg(not(feature = "bench-loopback"))]
236 let uart = uart.with_rx(pins.rx).with_tx(pins.tx).into_async();
237
238 uart_buf.run(uart).await;
239}
240
241pub fn spawn_uart(
253 spawner: SendSpawner,
254 uart1: UART1<'static>,
255 pins: EspUartPins<'static>,
256 params: UartParams,
257) -> &'static BufferedUart {
258 let uart_buf = UART_BUF.init_with(BufferedUart::new);
259 spawner.spawn(uart_task(uart_buf, uart1, pins, params).expect("uart_task spawn failed"));
260 uart_buf
261}