rivet_bsp_support/serial.rs
1//! `embedded-hal-nb::serial::{Read, Write}` over [`rivet::console`]
2//! (plan.md Phase 15).
3//!
4//! Genuinely board-agnostic: `rivet::console`'s RX/TX rings (plan.md
5//! Phase 14) are already portable kernel API, so this wrapper works
6//! identically on every board that's wired one up — no per-board code
7//! needed, unlike GPIO (which is real, per-board register layout).
8
9use embedded_hal_nb::serial::{ErrorType, Read, Write};
10
11/// Zero-sized handle to the board's console UART, for code written
12/// against `embedded-hal-nb`'s serial traits rather than
13/// `rivet::console` directly.
14pub struct Serial;
15
16impl ErrorType for Serial {
17 type Error = core::convert::Infallible;
18}
19
20impl Read<u8> for Serial {
21 fn read(&mut self) -> nb::Result<u8, Self::Error> {
22 rivet::console::try_read_byte().ok_or(nb::Error::WouldBlock)
23 }
24}
25
26impl Write<u8> for Serial {
27 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
28 rivet::console::write_bytes(&[word]);
29 Ok(())
30 }
31
32 fn flush(&mut self) -> nb::Result<(), Self::Error> {
33 // `write_bytes` already fully handed the byte to the TX ring (or
34 // wrote it directly, on the blocking-polling fallback path) —
35 // there's no separate "in-flight, not yet queued" state to wait
36 // out here.
37 Ok(())
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 // Compile-only: proves `Serial` is usable through generic
46 // `embedded-hal-nb` code, not just directly.
47 #[allow(dead_code)]
48 fn generic_read<R: Read<u8>>(r: &mut R) -> nb::Result<u8, R::Error> {
49 r.read()
50 }
51
52 #[allow(dead_code)]
53 fn generic_write<W: Write<u8>>(w: &mut W, b: u8) -> nb::Result<(), W::Error> {
54 w.write(b)
55 }
56
57 #[test]
58 fn type_checks() {
59 let _ = generic_read::<Serial>;
60 let _ = generic_write::<Serial>;
61 }
62}