1pub static GLOBAL_WRITER: OnceCell<LockedWriter> = OnceCell::uninit();
3
4pub fn init_writer(
6 buffer: &'static mut [u8],
7 info: FrameBufferInfo,
8 with_framebuffer: bool,
9 with_serial: bool,
10) {
11 let writer = GLOBAL_WRITER.get_or_init(move || {
12 LockedWriter::new(buffer, info, with_framebuffer, with_serial)
13 });
14
15 log::set_logger(writer).expect("logger already exists");
16 log::set_max_level(LevelFilter::Trace);
17 log::info!("Global writer/logger successfully initialised: {:?}", info);
18}
19
20pub struct LockedWriter {
21 pub writer: Option<Spinlock<TerminalWriter>>,
22 pub serial: Option<Spinlock<SerialPort>>,
23}
24
25impl LockedWriter {
26 pub fn new(
27 buffer: &'static mut [u8],
28 info: FrameBufferInfo,
29 writer_log_status: bool,
30 serial_log_status: bool,
31 ) -> Self {
32 let port = unsafe {
33 let mut serial = SerialPort::new(0x3F8);
34 serial.init();
35 serial
36 };
37
38 let writer = match writer_log_status {
39 true => Some(Spinlock::new(TerminalWriter::new(buffer, info))),
40 false => None,
41 };
42
43 let serial = match serial_log_status {
44 true => Some(Spinlock::new(port)),
45 false => None,
46 };
47
48 return LockedWriter {
49 writer,
50 serial,
51 };
52 }
53
54 pub unsafe fn force_unlock(&self) {
59 if let Some(framebuffer) = &self.writer {
60 unsafe { framebuffer.force_unlock() };
61 }
62
63 if let Some(serial) = &self.serial {
64 unsafe { serial.force_unlock() };
65 }
66 }
67}
68
69impl log::Log for LockedWriter {
70 fn enabled(&self, _metadata: &log::Metadata) -> bool {
71 true
72 }
73
74 fn log(&self, record: &log::Record) {
75 if let Some(writer) = &self.writer {
76 let mut writer = writer.lock();
77 writeln!(writer, "{:5}: {}", record.level(), record.args()).unwrap();
78 }
79
80 if let Some(serial) = &self.serial {
81 let mut serial = serial.lock();
82 writeln!(serial, "{:5}: {}", record.level(), record.args()).unwrap();
83 }
84 }
85
86 fn flush(&self) {}
87}
88
89#[macro_export]
92macro_rules! print {
93 ($($args:tt)+) => ({
94 use core::fmt::Write;
95
96 if let Some(writer) = &$crate::terminal::GLOBAL_WRITER.get().unwrap().writer {
97 let mut writer = writer.lock();
98 let _ = write!(writer, $($args)+).unwrap();
99 }
100
101 if let Some(serial) = &$crate::terminal::GLOBAL_WRITER.get().unwrap().serial {
102 let mut serial = serial.lock();
103 let _ = write!(serial, $($args)+).unwrap();
104 }
105 });
106}
107
108#[macro_export]
109macro_rules! println {
110 () => ({
111 print!("\n");
112 });
113
114 ($fmt:expr) => ({
115 print!(concat!($fmt, "\r\n"))
116 });
117
118 ($fmt:expr, $($args:tt)+) => ({
119 print!(concat!($fmt, "\r\n"), $($args)+)
120 });
121}
122
123#[macro_export]
124pub macro clear_screen {
125 () => {
126 if let Some(writer) = &$crate::terminal::GLOBAL_WRITER.get().unwrap().writer {
127 let mut writer = writer.lock();
128 writer.clear();
129 }
130 }
131}
132
133#[doc(hidden)]
134pub fn _print(args: fmt::Arguments) {
135 use core::fmt::Write;
136
137 if let Some(writer) = &GLOBAL_WRITER.get().unwrap().writer {
138 let mut writer = writer.lock();
139 writer.write_fmt(args).unwrap();
140 }
141
142 if let Some(serial) = &GLOBAL_WRITER.get().unwrap().serial {
143 let mut serial = serial.lock();
144 serial.write_fmt(args).unwrap();
145 }
146}
147
148pub mod font;
152
153pub mod framebuffer;
156
157use {
160 crate::uart::SerialPort,
161 self::framebuffer::TerminalWriter,
162 conquer_once::spin::OnceCell,
163 core::fmt::{self, Write},
164 log::LevelFilter,
165 spinning_top::Spinlock,
166 springboard_api::info::{FrameBufferInfo, PixelFormat},
167};