Skip to main content

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}