base/terminal/
framebuffer.rs1const LINE_SPACING: usize = 2;
5
6const LETTER_SPACING: usize = 0;
8
9const BORDER_PADDING: usize = 1;
11
12pub fn get_char_raster(c: char) -> RasterizedChar {
14 let get = |c: char| -> Option<RasterizedChar> {
15 get_raster(
16 c,
17 FONT_WEIGHT,
18 CHAR_RASTER_HEIGHT,
19 )
20 };
21
22 get(c).unwrap_or_else(|| get(BACKUP_CHAR).expect("should get raster of backup char"))
23}
24
25pub struct TerminalWriter {
27 buffer: &'static mut [u8],
28 info: FrameBufferInfo,
29 xpos: usize,
30 ypos: usize,
31}
32
33impl TerminalWriter {
34 pub fn new(buffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
36 let mut logger = Self {
37 buffer,
38 info,
39 xpos: 0,
40 ypos: 0,
41 };
42 logger.clear();
43 return logger;
44 }
45
46 pub fn newline(&mut self) {
47 self.ypos += CHAR_RASTER_HEIGHT.val() + LINE_SPACING;
48 self.carriage_return()
49 }
50
51 pub fn carriage_return(&mut self) {
52 self.xpos = BORDER_PADDING;
53 }
54
55 pub fn clear(&mut self) {
57 self.xpos = BORDER_PADDING;
58 self.ypos = BORDER_PADDING;
59 self.buffer.fill(0);
60 }
61
62 #[inline]
63 pub fn width(&self) -> usize {
64 self.info.width
65 }
66
67 #[inline]
68 pub fn height(&self) -> usize {
69 self.info.height
70 }
71
72 pub fn write_char(&mut self, c: char) {
75 match c {
76 '\n' => self.newline(),
77 '\r' => self.carriage_return(),
78 c => {
79 let new_xpos = self.xpos + CHAR_RASTER_WIDTH;
80 if new_xpos >= self.width() {
81 self.newline();
82 }
83
84 let new_ypos = self.ypos + CHAR_RASTER_HEIGHT.val() + BORDER_PADDING;
85
86 if new_ypos >= self.height() {
87 self.clear();
88 }
89
90 self.write_rendered_char(get_char_raster(c));
91 }
92 }
93 }
94
95 pub fn write_rendered_char(&mut self, rendered_char: RasterizedChar) {
98 for (y, row) in rendered_char.raster().iter().enumerate() {
99 for (x, byte) in row.iter().enumerate() {
100 self.write_pixel(self.xpos + x, self.ypos + y, *byte);
101 }
102 }
103 self.xpos += rendered_char.width() + LETTER_SPACING;
104 }
105
106 pub fn write_pixel(&mut self, x: usize, y: usize, intensity: u8) {
107 let pixel_offset = y * self.info.stride + x;
108 let color = match self.info.pixel_format {
109 PixelFormat::Rgb => [intensity, intensity, intensity / 2, 0],
110 PixelFormat::Bgr => [intensity / 2, intensity, intensity, 0],
111 PixelFormat::U8 => [if intensity > 200 { 0xf } else { 0 }, 0, 0, 0],
112 other => {
113 self.info.pixel_format = PixelFormat::Rgb;
116 panic!("pixel format {:?} not supported in logger", other)
117 }
118 };
119 let bytes_per_pixel = self.info.bytes_per_pixel;
120 let byte_offset = pixel_offset * bytes_per_pixel;
121 self.buffer[byte_offset..(byte_offset + bytes_per_pixel)]
122 .copy_from_slice(&color[..bytes_per_pixel]);
123 let _ = unsafe { ptr::read_volatile(&self.buffer[byte_offset]) };
124 }
125}
126
127unsafe impl Send for TerminalWriter {}
128unsafe impl Sync for TerminalWriter {}
129
130impl Write for TerminalWriter {
131 fn write_str(&mut self, s: &str) -> fmt::Result {
132 for c in s.chars() {
133 self.write_char(c);
134 }
135 Ok(())
136 }
137}
138
139use {
142 super::font::{
143 BACKUP_CHAR,
144 CHAR_RASTER_HEIGHT,
145 CHAR_RASTER_WIDTH,
146 FONT_WEIGHT,
147 },
148 crate::uart::SerialPort,
149 conquer_once::spin::OnceCell,
150 core::{fmt::{self, Write}, ptr},
151 noto_sans_mono_bitmap::{RasterizedChar, get_raster},
152 spinning_top::Spinlock,
153 springboard_api::info::{FrameBufferInfo, PixelFormat},
154};