aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-04-30 04:21:11 +0200
committerpennae <[email protected]>2023-05-01 15:32:58 +0200
commit861f49cfd4380d89aa13d507234a97b30a84473d (patch)
treec04ff6eb09a61ad5e2c549c9f044d6709963c3b4 /tests
parent7ab9fe0522de81583592bd09c5c57910bed1c181 (diff)
rp/uart: report errors from buffered uart
this reports errors at the same location the blocking uart would, which works out to being mostly exact (except in the case of overruns, where one extra character is dropped). this is actually easier than going nuclear in the case of errors and nuking both the buffer contents and the rx fifo, both of which are things we'd have to do in addition to what's added here, and neither are needed for correctness.
Diffstat (limited to 'tests')
-rw-r--r--tests/rp/src/bin/uart_buffered.rs249
1 files changed, 229 insertions, 20 deletions
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index a1f0e2bf3..1deb22ce6 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -2,39 +2,248 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::{assert_eq, *}; 5use defmt::{assert_eq, panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::gpio::{Level, Output};
7use embassy_rp::interrupt; 8use embassy_rp::interrupt;
8use embassy_rp::uart::{BufferedUart, Config}; 9use embassy_rp::uart::{BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
9use embedded_io::asynch::{Read, Write}; 10use embassy_time::{Duration, Timer};
11use embedded_io::asynch::{Read, ReadExactError, Write};
10use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
11 13
14async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> {
15 let mut buf = [255; N];
16 match uart.read_exact(&mut buf).await {
17 Ok(()) => Ok(buf),
18 // we should not ever produce an Eof condition
19 Err(ReadExactError::UnexpectedEof) => panic!(),
20 Err(ReadExactError::Other(e)) => Err(e),
21 }
22}
23
24async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> {
25 let mut buf = [255; N];
26 match uart.read_exact(&mut buf).await {
27 Ok(()) => Ok(buf),
28 // we should not ever produce an Eof condition
29 Err(ReadExactError::UnexpectedEof) => panic!(),
30 Err(ReadExactError::Other(e)) => Err(e),
31 }
32}
33
34async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) {
35 pin.set_low();
36 Timer::after(Duration::from_millis(1)).await;
37 for i in 0..8 {
38 if v & (1 << i) == 0 {
39 pin.set_low();
40 } else {
41 pin.set_high();
42 }
43 Timer::after(Duration::from_millis(1)).await;
44 }
45 if let Some(b) = parity {
46 if b {
47 pin.set_high();
48 } else {
49 pin.set_low();
50 }
51 Timer::after(Duration::from_millis(1)).await;
52 }
53 pin.set_high();
54 Timer::after(Duration::from_millis(1)).await;
55}
56
12#[embassy_executor::main] 57#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 58async fn main(_spawner: Spawner) {
14 let p = embassy_rp::init(Default::default()); 59 let p = embassy_rp::init(Default::default());
15 info!("Hello World!"); 60 info!("Hello World!");
16 61
17 let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); 62 let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
63 let mut irq = interrupt::take!(UART0_IRQ);
64
65 {
66 let config = Config::default();
67 let tx_buf = &mut [0u8; 16];
68 let rx_buf = &mut [0u8; 16];
69 let mut uart = BufferedUart::new(&mut uart, &mut irq, &mut tx, &mut rx, tx_buf, rx_buf, config);
70
71 // Make sure we send more bytes than fits in the FIFO, to test the actual
72 // bufferedUart.
73
74 let data = [
75 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,
76 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
77 ];
78 uart.write_all(&data).await.unwrap();
79 info!("Done writing");
80
81 assert_eq!(read(&mut uart).await.unwrap(), data);
82 }
83
84 info!("test overflow detection");
85 {
86 let config = Config::default();
87 let tx_buf = &mut [0u8; 16];
88 let rx_buf = &mut [0u8; 16];
89 let mut uart = BufferedUart::new(&mut uart, &mut irq, &mut tx, &mut rx, tx_buf, rx_buf, config);
90
91 // Make sure we send more bytes than fits in the FIFO, to test the actual
92 // bufferedUart.
93
94 let data = [
95 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,
96 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
97 ];
98 let overflow = [
99 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
100 ];
101 // give each block time to settle into the fifo. we want the overrun to occur at a well-defined point.
102 uart.write_all(&data).await.unwrap();
103 uart.blocking_flush().unwrap();
104 while uart.busy() {}
105 uart.write_all(&overflow).await.unwrap();
106 uart.blocking_flush().unwrap();
107 while uart.busy() {}
108
109 // already buffered/fifod prefix is valid
110 assert_eq!(read(&mut uart).await.unwrap(), data);
111 // next received character causes overrun error and is discarded
112 uart.write_all(&[1, 2, 3]).await.unwrap();
113 uart.blocking_flush().unwrap();
114 assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Overrun);
115 assert_eq!(read(&mut uart).await.unwrap(), [2, 3]);
116 }
117
118 info!("test break detection");
119 {
120 let mut config = Config::default();
121 config.baudrate = 1000;
122 let tx_buf = &mut [0u8; 16];
123 let rx_buf = &mut [0u8; 16];
124 let mut uart = BufferedUart::new(&mut uart, &mut irq, &mut tx, &mut rx, tx_buf, rx_buf, config);
125
126 // break on empty buffer
127 uart.send_break(20).await;
128 assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Break);
129 uart.write_all(&[64]).await.unwrap();
130 assert_eq!(read(&mut uart).await.unwrap(), [64]);
131
132 // break on partially filled buffer
133 uart.write_all(&[65; 2]).await.unwrap();
134 uart.send_break(20).await;
135 uart.write_all(&[66]).await.unwrap();
136 assert_eq!(read(&mut uart).await.unwrap(), [65; 2]);
137 assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Break);
138 assert_eq!(read(&mut uart).await.unwrap(), [66]);
139
140 // break on full buffer
141 uart.write_all(&[64; 16]).await.unwrap();
142 uart.send_break(20).await;
143 uart.write_all(&[65]).await.unwrap();
144 assert_eq!(read(&mut uart).await.unwrap(), [64; 16]);
145 assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Break);
146 assert_eq!(read(&mut uart).await.unwrap(), [65]);
147 }
148
149 // parity detection. here we bitbang to not require two uarts.
150 info!("test parity error detection");
151 {
152 let mut pin = Output::new(&mut tx, Level::High);
153 // choose a very slow baud rate to make tests reliable even with O0
154 let mut config = Config::default();
155 config.baudrate = 1000;
156 config.parity = Parity::ParityEven;
157 let rx_buf = &mut [0u8; 16];
158 let mut uart = BufferedUartRx::new(&mut uart, &mut irq, &mut rx, rx_buf, config);
159
160 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) {
161 send(pin, v, Some(parity != 0)).await;
162 }
163
164 // first check that we can send correctly
165 chr(&mut pin, 64, 1).await;
166 assert_eq!(read1(&mut uart).await.unwrap(), [64]);
167
168 // parity on empty buffer
169 chr(&mut pin, 64, 0).await;
170 chr(&mut pin, 4, 1).await;
171 assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity);
172 assert_eq!(read1(&mut uart).await.unwrap(), [4]);
173
174 // parity on partially filled buffer
175 chr(&mut pin, 64, 1).await;
176 chr(&mut pin, 32, 1).await;
177 chr(&mut pin, 64, 0).await;
178 chr(&mut pin, 65, 0).await;
179 assert_eq!(read1(&mut uart).await.unwrap(), [64, 32]);
180 assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity);
181 assert_eq!(read1(&mut uart).await.unwrap(), [65]);
182
183 // parity on full buffer
184 for i in 0..16 {
185 chr(&mut pin, i, i.count_ones() % 2).await;
186 }
187 chr(&mut pin, 64, 0).await;
188 chr(&mut pin, 65, 0).await;
189 assert_eq!(
190 read1(&mut uart).await.unwrap(),
191 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
192 );
193 assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity);
194 assert_eq!(read1(&mut uart).await.unwrap(), [65]);
195 }
196
197 // framing error detection. here we bitbang because there's no other way.
198 info!("test framing error detection");
199 {
200 let mut pin = Output::new(&mut tx, Level::High);
201 // choose a very slow baud rate to make tests reliable even with O0
202 let mut config = Config::default();
203 config.baudrate = 1000;
204 let rx_buf = &mut [0u8; 16];
205 let mut uart = BufferedUartRx::new(&mut uart, &mut irq, &mut rx, rx_buf, config);
206
207 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) {
208 if good {
209 send(pin, v, None).await;
210 } else {
211 send(pin, v, Some(false)).await;
212 }
213 }
18 214
19 let config = Config::default(); 215 // first check that we can send correctly
20 let irq = interrupt::take!(UART0_IRQ); 216 chr(&mut pin, 64, true).await;
21 let tx_buf = &mut [0u8; 16]; 217 assert_eq!(read1(&mut uart).await.unwrap(), [64]);
22 let rx_buf = &mut [0u8; 16];
23 let mut uart = BufferedUart::new(uart, irq, tx, rx, tx_buf, rx_buf, config);
24 218
25 // Make sure we send more bytes than fits in the FIFO, to test the actual 219 // framing on empty buffer
26 // bufferedUart. 220 chr(&mut pin, 64, false).await;
221 assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing);
222 chr(&mut pin, 65, true).await;
223 assert_eq!(read1(&mut uart).await.unwrap(), [65]);
27 224
28 let data = [ 225 // framing on partially filled buffer
29 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, 226 chr(&mut pin, 64, true).await;
30 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 227 chr(&mut pin, 32, true).await;
31 ]; 228 chr(&mut pin, 64, false).await;
32 uart.write_all(&data).await.unwrap(); 229 chr(&mut pin, 65, true).await;
33 info!("Done writing"); 230 assert_eq!(read1(&mut uart).await.unwrap(), [64, 32]);
231 assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing);
232 assert_eq!(read1(&mut uart).await.unwrap(), [65]);
34 233
35 let mut buf = [0; 48]; 234 // framing on full buffer
36 uart.read_exact(&mut buf).await.unwrap(); 235 for i in 0..16 {
37 assert_eq!(buf, data); 236 chr(&mut pin, i, true).await;
237 }
238 chr(&mut pin, 64, false).await;
239 chr(&mut pin, 65, true).await;
240 assert_eq!(
241 read1(&mut uart).await.unwrap(),
242 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
243 );
244 assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing);
245 assert_eq!(read1(&mut uart).await.unwrap(), [65]);
246 }
38 247
39 info!("Test OK"); 248 info!("Test OK");
40 cortex_m::asm::bkpt(); 249 cortex_m::asm::bkpt();