1use core::task::Waker;
2use core::{fmt, mem};
3
4use heapless::Vec;
5use hermit_sync::{InterruptTicketMutex, Lazy};
6
7use crate::arch;
8
9const SERIAL_BUFFER_SIZE: usize = 256;
10
11pub(crate) struct Console {
12 pub inner: arch::kernel::Console,
13 buffer: Vec<u8, SERIAL_BUFFER_SIZE>,
14}
15
16impl Console {
17 fn new() -> Self {
18 Self {
19 inner: arch::kernel::Console::new(),
20 buffer: Vec::new(),
21 }
22 }
23
24 pub fn write(&mut self, buf: &[u8]) {
28 if SERIAL_BUFFER_SIZE - self.buffer.len() >= buf.len() {
29 self.buffer.extend_from_slice(buf).unwrap();
31 if buf.contains(&b'\n') {
32 self.flush();
33 }
34 } else {
35 self.inner.write(&self.buffer);
36 self.buffer.clear();
37 if buf.len() >= SERIAL_BUFFER_SIZE {
38 self.inner.write(buf);
39 } else {
40 self.buffer.extend_from_slice(buf).unwrap();
42 if buf.contains(&b'\n') {
43 self.flush();
44 }
45 }
46 }
47 }
48
49 pub fn flush(&mut self) {
51 self.inner.write(&self.buffer);
52 self.buffer.clear();
53 }
54
55 pub fn read(&mut self) -> Option<u8> {
56 self.inner.read()
57 }
58
59 pub fn is_empty(&self) -> bool {
60 self.inner.is_empty()
61 }
62
63 pub fn register_waker(&mut self, waker: &Waker) {
64 self.inner.register_waker(waker);
65 }
66}
67
68impl fmt::Write for Console {
71 #[inline]
73 fn write_str(&mut self, s: &str) -> fmt::Result {
74 if !s.is_empty() {
75 self.write(s.as_bytes());
76 }
77
78 Ok(())
79 }
80}
81
82pub(crate) static CONSOLE: Lazy<InterruptTicketMutex<Console>> =
83 Lazy::new(|| InterruptTicketMutex::new(Console::new()));
84
85#[doc(hidden)]
86pub fn _print(args: fmt::Arguments<'_>) {
87 use fmt::Write;
88 CONSOLE.lock().write_fmt(args).unwrap();
89}
90
91#[doc(hidden)]
92pub fn _panic_print(args: fmt::Arguments<'_>) {
93 use fmt::Write;
94 let mut console = unsafe { CONSOLE.make_guard_unchecked() };
95 console.write_fmt(args).ok();
96 mem::forget(console);
97}
98
99#[cfg(all(test, not(target_os = "none")))]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_console() {
105 println!("HelloWorld");
106 }
107}