bern_test/
serial.rs

1//! Serial interface transport.
2//!
3//! Setup any serial interface for transport.
4//!
5//! # Example
6//! ```no_run
7//! #[cortex_m_rt::entry]
8//! fn main() -> ! {
9//!     let mut board = Board::new();
10//!     let vcp = board.vcp.take().unwrap();
11//!
12//!     // Set serial uplink
13//!     Serial::set_write(move |b| {
14//!         match tx.write(b) {
15//!             Ok(_) => {
16//!                 nb::block!(vcp.tx.flush()).ok();
17//!                 Ok(())
18//!             },
19//!             Err(e) => match e {
20//!                 WouldBlock => Err(WouldBlock),
21//!                 _ => Err(Other(serial::Error::Peripheral)),
22//!             }
23//!         }
24//!     });
25//!     /*...*/
26//! }
27//! ```
28use core::{fmt, mem};
29use nb::{block, Error::Other};
30use core::fmt::Write;
31
32/// Serial Errors.
33#[derive(Debug)]
34pub enum Error {
35    /// Error from peripheral.
36    Peripheral,
37    /// No function to send defined.
38    NoUplink,
39    /// No function to receive defined.
40    NoDownlink,
41    /// RX buffer overrun
42    BufferOverrun,
43}
44
45static mut SERIAL: Serial = Serial {
46    write: None,
47    read: None,
48};
49
50#[doc(hidden)]
51pub struct Serial {
52    write: Option<&'static mut dyn FnMut(u8) -> nb::Result<(), Error>>,
53    read: Option<&'static mut dyn FnMut() -> nb::Result<u8, Error>>,
54}
55
56// todo: interrupt driven read and write
57impl Serial {
58    /// Set a serial write function (mandatory).
59    ///
60    /// # Safety
61    /// We basically want to create a memory leak/unbounded lifetime, so we can
62    /// access a serial write function from anywhere. This is quite unsafe, but
63    /// at least `mem::transmute` checks that the buffer has the correct size.
64    // todo: critical section, reentrancy check
65    pub fn set_write<F>(write: F)
66        where F: FnMut(u8) -> nb::Result<(), Error> + 'static
67    {
68        static mut TX: [u8; 4] = [0; 4];
69        unsafe {
70            TX = mem::transmute(&write);
71            let write_ptr = &mut *(TX.as_mut_ptr() as *mut F);
72            SERIAL.write = Some(write_ptr);
73        }
74    }
75
76    /// Set a serial read function.
77    ///
78    /// # Safety
79    /// see [`Self::set_write`]
80    pub fn set_read<F>(read: F)
81        where F: FnMut() -> nb::Result<u8, Error> + 'static
82    {
83        static mut RX: [u8; 4] = [0; 4];
84        unsafe {
85            RX = mem::transmute(&read);
86            let read_ptr = &mut *(RX.as_mut_ptr() as *mut F);
87            SERIAL.read = Some(read_ptr);
88        }
89    }
90
91    pub unsafe fn steal() -> &'static mut Self {
92        &mut SERIAL
93    }
94
95    #[doc(hidden)]
96    pub fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
97        match &mut self.write {
98            Some(w) => (w)(byte),
99            _ => Err(nb::Error::Other(Error::NoUplink)),
100        }
101    }
102
103    #[doc(hidden)]
104    pub fn write_str(s: &str) {
105        let ser = unsafe { Serial::steal() };
106        ser.write_str(s).ok();
107    }
108
109    #[doc(hidden)]
110    pub fn write_fmt(arg: fmt::Arguments) {
111        let ser = unsafe { Serial::steal() };
112        ser.write_fmt(arg).ok();
113    }
114
115    #[doc(hidden)]
116    pub fn read(&mut self) -> nb::Result<u8, Error> {
117        match &mut self.read {
118            Some(r) => (r)(),
119            _ => Err(Other(Error::NoDownlink)),
120        }
121    }
122
123    #[doc(hidden)]
124    pub fn readln(&mut self, buffer: &mut [u8]) -> nb::Result<usize, Error> {
125        if self.read.is_none() {
126            return Err(Other(Error::NoDownlink));
127        }
128
129        for (i, item) in buffer.iter_mut().enumerate() {
130            let c = block!(self.read());
131            match c {
132                Ok(c) => match c {
133                    b'\n' | b'\r' => return Ok(i),
134                    b => {
135                        *item = b;
136                    },
137                },
138                Err(e) => return Err(Other(e)),
139            }
140        }
141        return Err(Other(Error::BufferOverrun));
142    }
143}
144
145impl fmt::Write for Serial
146{
147    fn write_str(&mut self, s: &str) -> fmt::Result {
148        s.as_bytes()
149            .iter()
150            .try_for_each(|c| block!(self.write(*c)))
151            .map_err(|_| fmt::Error)
152    }
153}
154
155// from probe-rs
156#[macro_export]
157#[doc(hidden)]
158macro_rules! sprintln {
159    ($fmt:expr) => {
160        $crate::serial::Serial::write_str(concat!($fmt, "\r\n"));
161    };
162    ($fmt:expr, $($arg:tt)*) => {
163        $crate::serial::Serial::write_fmt(format_args!(concat!($fmt, "\r\n"), $($arg)*));
164    };
165}
166
167#[macro_export]
168#[doc(hidden)]
169macro_rules! sprint {
170    ($fmt:expr) => {
171        $crate::serial::Serial::write_str($fmt);
172    };
173    ($fmt:expr, $($arg:tt)*) => {
174        $crate::serial::Serial::write_fmt(format_args!($fmt, $($arg)*));
175    };
176}
177