vga_rs/
lib.rs

1//! ## vga-rs
2//! Low level VGA(0xB8000) library in freestanding Rust.
3//!
4//! ## Example
5//! ```rust
6//! #![no_std]
7//! extern crate vga_rs;
8//! use vga_rs::*;
9//! extern crate cursor_rs;
10//!
11//! fn reset_screen() {
12//! 	let mut vga_buffer = VgaBuffer::new()
13//! 	let buffer_slice = let mut vga_buffer.as_mut_slice();
14//! 	for vchar in buffer_slice.iter_mut()
15//! 	{
16//!			let VgaChar { codepoint: _,attribute: attr,} = vchar.get_volatile();
17//! 		vchar.set_volatile(VgaChar::new(0u8, Attribute::from_u8(attr)));
18//! 	}
19//!     cursor_rs::set_cursor(0,0);
20//! }
21//! ```
22
23#![no_std]
24
25extern crate vgainfo_rs;
26
27/// Contains 8 bit color.
28#[repr(transparent)]
29#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
30pub struct Color(u8);
31
32impl Color {
33    pub const BLACK: Color = Color(0u8);
34    pub const BLUE: Color = Color(1);
35    pub const GREEN: Color = Color(2);
36    pub const CYAN: Color = Color(3);
37    pub const RED: Color = Color(4);
38    pub const MAGENTA: Color = Color(5);
39    pub const BROWN: Color = Color(6);
40    pub const LIGHTGRAY: Color = Color(7);
41    pub const DARKGRAY: Color = Color(8);
42    pub const LIGHTBLUE: Color = Color(9);
43    pub const LIGHTGREEN: Color = Color(10);
44    pub const LIGHTCYAN: Color = Color(11);
45    pub const LIGHTRED: Color = Color(12);
46    pub const PINK: Color = Color(13);
47    pub const YELLOW: Color = Color(14);
48    pub const WHITE: Color = Color(15);
49
50    pub const EXTRA: Color = Color(1u8 << 3);
51}
52
53impl Color {
54    /// Construct Color from (blue | green | red | extra bit).
55    pub const fn new(b: bool, g: bool, r: bool, extra: bool) -> Self {
56        Self(
57            if b { 1u8 << 0 } else { 0u8 }
58                | if g { 1u8 << 1 } else { 0u8 }
59                | if r { 1u8 << 2 } else { 0u8 }
60                | if extra { 1u8 << 3 } else { 0u8 },
61        )
62    }
63
64    /// Construct Color from u8.
65    #[inline]
66    pub const fn from_u8(bit: u8) -> Self {
67        Self(bit)
68    }
69
70    /// Construct Color from u8. Check bit 4-7.
71    pub const fn from_u8_checked(bit: u8) -> Option<Self> {
72        match bit & 0xf0 {
73            0u8 => Some(Self(bit)),
74            _ => None,
75        }
76    }
77
78    /// Extract Color to u8.
79    #[inline]
80    pub const fn as_u8(self) -> u8 {
81        let Self(x) = self;
82        x
83    }
84}
85
86use core::ops::BitOr;
87impl BitOr for Color {
88    type Output = Self;
89
90    fn bitor(self, rhs: Self) -> Self::Output {
91        let (Self(a), Self(b)) = (self, rhs);
92        Self(a | b)
93    }
94}
95
96/// Contains foreground and background colors.
97#[repr(C, packed)]
98#[derive(Debug, Copy, Clone)]
99pub struct Attribute {
100    pub fgcolor: Color,
101    pub bgcolor: Color,
102}
103
104impl Attribute {
105    /// Construct an Attribute.
106    #[inline]
107    pub const fn new(fgcolor: Color, bgcolor: Color) -> Self {
108        Self {
109            fgcolor: fgcolor,
110            bgcolor: bgcolor,
111        }
112    }
113
114    /// Construct an Attribute from u8.
115    #[inline]
116    pub const fn from_u8(bit: u8) -> Self {
117        Self {
118            fgcolor: Color::from_u8(bit & 0x0f),
119            bgcolor: Color::from_u8((bit & 0xf0) >> 4),
120        }
121    }
122
123    /// Extract Attribute to u8.
124    #[inline]
125    pub const fn as_u8(self) -> u8 {
126        self.fgcolor.as_u8() | (self.bgcolor.as_u8() << 4)
127    }
128}
129
130/// An element of video buffer, contains codepoint and attribute.
131#[repr(C, packed)]
132#[derive(Debug, Copy, Clone)]
133pub struct VgaChar {
134    pub codepoint: u8,
135    pub attribute: u8,
136}
137
138impl VgaChar {
139    /// Construct a VgaChar.
140    #[inline]
141    pub const fn new(cp: u8, attr: Attribute) -> Self {
142        Self {
143            codepoint: cp,
144            attribute: attr.as_u8(),
145        }
146    }
147
148    /// Get a VgaChar and suppress optimization. In case ```self``` is on video buffer.
149    /// ```rust
150    /// let nonnull:NonNull::<VgaChar> = unsafe { NonNull::new_unchecked(VGA_PTR) };
151    /// let vchar = nonnull.as_ref().get_volatile();
152    /// ```
153    pub fn get_volatile(&self) -> Self {
154        let ptr = self as *const Self;
155        let Self {
156            codepoint,
157            attribute,
158        } = unsafe { ptr.read_volatile() };
159
160        Self::new(codepoint, Attribute::from_u8(attribute))
161    }
162
163    /// Set a VgaChar and suppress optimization. In case ```self``` is on video buffer.
164    /// ```rust
165    /// let mut nonnull:NonNull::<VgaChar> = unsafe { NonNull::new_unchecked(VGA_PTR) };
166    /// let mut vchar = nonnull.as_ref().get_volatile();
167    /// vchar.codepoint = 0u8;
168    /// nonnull.as_mut().get_volatile(vchar);
169    /// ```
170    pub fn set_volatile(&mut self, other: Self) {
171        let ptr = self as *mut Self;
172        {
173            unsafe {
174                ptr.write_volatile(other);
175            }
176        };
177    }
178}
179
180use core::ptr::NonNull;
181
182/// Containa a pointer to slice of Vga buffer.
183#[derive(Debug)]
184pub struct VgaBuffer {
185    pointer: NonNull<[VgaChar]>,
186}
187
188impl VgaBuffer {
189    pub const VGA_ADDR: usize = vgainfo_rs::VGA_ADDR;
190
191    pub const WIDTH: usize = vgainfo_rs::WIDTH;
192    pub const HIGH: usize = vgainfo_rs::HIGH;
193    pub const LENGTH: usize = vgainfo_rs::LENGTH;
194
195    pub const VGA_PTR: *mut VgaChar = Self::VGA_ADDR as *mut _;
196
197    /// This static methode converts 2D index to 1D index.
198    #[inline]
199    pub const fn to_index(y: usize, x: usize) -> usize {
200        y * Self::WIDTH + x
201    }
202
203    /// This static methode converts 1D index to 2D index.
204    #[inline]
205    pub const fn to_yx(index: usize) -> (usize, usize) {
206        let y = index / Self::WIDTH;
207        let x = index % Self::WIDTH;
208        (y, x)
209    }
210
211    /// Construct a VgaBuffer.
212    #[inline]
213    pub fn new() -> Self {
214        let nonnull = unsafe { NonNull::new_unchecked(Self::VGA_PTR) };
215        Self {
216            pointer: NonNull::slice_from_raw_parts(nonnull, Self::LENGTH),
217        }
218    }
219
220    /// Set VgaChar to (y,x) coordinates. Uncheck range.
221    pub unsafe fn set_vgachar(&mut self, vchar: VgaChar, y: usize, x: usize) {
222        let index = Self::to_index(y, x);
223        self.pointer
224            .as_mut()
225            .get_unchecked_mut(index)
226            .set_volatile(vchar);
227    }
228
229    /// Get VgaChar at (y,x) coordinates. Uncheck range.
230    pub unsafe fn get_vgachar(&self, y: usize, x: usize) -> VgaChar {
231        let index = Self::to_index(y, x);
232        self.pointer.as_ref().get_unchecked(index).get_volatile()
233    }
234
235    /// Video buffer to a slice.
236    #[inline]
237    pub fn as_slice<'a>(&self) -> &'a [VgaChar] {
238        unsafe { self.pointer.as_ref() }
239    }
240
241    /// Video buffer to a mutable slice.
242    /// ```rust
243    /// let mut vga_buffer = VgaBuffer::new()
244    /// let buffer_slice = vga_buffer.as_mut_slice();
245    /// for vchar_ref in buffer_slice.iter_mut()
246    /// {
247    ///		let mut vchar = vchar_ref.get_volatile();
248    ///		vchar.codepoint = 0u8;
249    /// 	vchar_ref.set_volatile(vchar);
250    /// }
251    /// ```
252    #[inline]
253    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [VgaChar] {
254        unsafe { self.pointer.as_mut() }
255    }
256}
257
258/// Getter and Setter interface.
259pub trait VgaBufferHal {
260    type Item;
261
262    /// Setter interface.
263    fn set(&mut self, item: Self::Item, y: usize, x: usize);
264
265    /// Getter interface.
266    fn get(&self, y: usize, x: usize) -> Self::Item;
267}
268
269impl VgaBufferHal for VgaBuffer {
270    type Item = VgaChar;
271
272    #[inline]
273    fn set(&mut self, item: Self::Item, y: usize, x: usize) {
274        unsafe { self.set_vgachar(item, y, x) };
275    }
276
277    #[inline]
278    fn get(&self, y: usize, x: usize) -> Self::Item {
279        unsafe { self.get_vgachar(y, x) }
280    }
281}