aboutsummaryrefslogtreecommitdiff
path: root/src/bsp/drivers/uart/console.rs
blob: e3ee2f296f592e67b534f2d4edba7c02a06e426b (plain)
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! # UART Console Definition
use super::*;
use crate::bsp::drivers::gpio::*;
use crate::cpu::*;
use crate::lib::sync::interface::Mutex;
use crate::lib::sync::SpinLock;
use core::fmt;

/// # UART Inner Structure
///
/// Keeps record of the console statistics.
struct UartInner {
    chars_written: usize,
}

/// # UART Structure
///
/// Wraps the UART writer in a sharable lock.
pub struct Uart {
    inner: SpinLock<UartInner>,
}

impl UartInner {
    /// # Clear statistics
    ///
    /// Create the writer with cleared statistics
    pub const fn new() -> Self {
        Self { chars_written: 0 }
    }

    /// # Initialize the UART setup
    ///
    /// Set baud rate and timings
    pub fn init(&mut self) {
        UART::CR::off();
        GPPUDCLK0::init();
        UART::ICR::clear();
        UART::IBRD::set(9);
        UART::FBRD::set(49);
        UART::LCRH::enable8();
        UART::IMSC::mask();
        UART::CR::all_on();
    }

    /// # Write `char` to UART
    fn write_char(&mut self, ch: char) {
        while UART::FR::TXFF::is_set() {
            nop();
        }
        UART::DR::set(ch);
        self.chars_written += 1;
    }

    /// # Flush UART
    fn flush(&self) {
        while UART::FR::BUSY::is_set() {
            nop();
        }
    }
}

impl fmt::Write for UartInner {
    /// # Write string to UART console
    fn write_str(&mut self, s: &str) -> fmt::Result {
        for c in s.chars() {
            self.write_char(c);
        }
        Ok(())
    }
}

impl Uart {
    /// # Create sharable UART wrapper
    pub const fn new() -> Self {
        Self {
            inner: SpinLock::new(UartInner::new()),
        }
    }

    /// # Call UART initialization
    pub fn init(&self) -> Result<(), &'static str> {
        self.inner.lock(|inner| inner.init());
        Ok(())
    }
}

impl crate::lib::console::interface::Write for Uart {
    /// # Write `char` to UART
    fn write_char(&self, c: char) {
        self.inner.lock(|inner| inner.write_char(c));
    }

    /// # Write formatted string to UART
    fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
        self.inner.lock(|inner| fmt::Write::write_fmt(inner, args))
    }

    /// # Flush UART
    fn flush(&self) {
        self.inner.lock(|inner| inner.flush());
    }
}

impl crate::lib::console::interface::Statistics for Uart {
    /// # Get `char` written stats
    fn chars_written(&self) -> usize {
        self.inner.lock(|inner| inner.chars_written)
    }
}

/// # UART Writer + Stats
impl crate::lib::console::interface::All for Uart {}