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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use core;

use nb;
use hal::serial::Write;

use heapless::consts::*;
use heapless::spsc::Queue;

pub struct LightCliOutput<'a, E: 'a> {
    rb: Queue<u8, U128>,
    writer: &'a mut Write<u8, Error=E>
}

impl<'a, E> core::fmt::Write for LightCliOutput<'a, E> {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        for c in s.as_bytes() {
            loop {
                if self.rb.enqueue(c.clone()).is_ok() {
                    break;
                } else {
                    match self.flush() {
                        Err(nb::Error::Other(_)) => return Err(core::fmt::Error),
                        _ => () // otherwise either non blocking or ok, so try to repeat
                    }
                }
            }
        }
        Ok(())
    }
}

impl<'a, E> LightCliOutput<'a, E> {
    /// Creates a now buffered console output instance. 
    /// 
    /// # Arguments
    /// * `writer`: The serial output instance, implementing the [`Write<u8>`] interface.
    /// 
    /// [`Write<u8>`]: ../embedded_hal/serial/trait.Write.html
    pub fn new(writer: &'a mut Write<u8, Error = E>) -> Self {
        Self {
            rb: Queue::new(),
            writer: writer
        }
    }

    fn peek(&self) -> Option<u8> {
        match self.rb.iter().next() {
            None => None,
            Some(v) => Some(v.clone())
        }
    }

    /// Tries to send as many characters as it can until the interface
    /// starts blocking or there are no charactors to submit. 
    /// 
    /// # Remarks 
    /// 
    /// If the function returns Ok, then the buffer has succesfully been flushed
    /// whereas the error `WouldBlock` indicates that it is not empty
    /// but would have blocked if it tried to submit the character.
    /// 
    /// To completely empty the buffer, use `block!(cl_output.flush()).unwrap()`.
    pub fn flush(&mut self) -> nb::Result<(), E> {
        let mut co = self.peek();
        
        loop {
            match co {
                None => return Ok(()),
                Some(c) => {
                    let res = self.writer.write(c.clone());
                    match res {
                        Err(nb::Error::WouldBlock) => return Err(nb::Error::WouldBlock),
                        Err(nb::Error::Other(o)) => return Err(nb::Error::Other(o)),
                        Ok(()) => {
                            self.rb.dequeue().unwrap();
                            co = self.peek();
                        },
                    }
                }
            }
        }
    }
}