extern crate libc;
extern crate memmap;
mod proc;
mod fbio;
pub mod double;
use std::fs::{OpenOptions, File};
use memmap::{MmapMut, MmapOptions};
use std::path::{Path, PathBuf};
pub use self::fbio::{PixelLayout, PixelLayoutChannel, BlankingLevel, ErrnoError, TerminalMode, set_terminal_mode};
#[derive(Debug)]
pub enum ErrorKind {
Io,
Fb,
}
#[derive(Debug)]
pub struct Error {
pub kind: ErrorKind,
pub io: Option<std::io::Error>,
pub fb: Option<fbio::ErrnoError>,
}
impl From<std::io::Error> for Error {
fn from(io: std::io::Error) -> Error {
Error { kind: ErrorKind::Io, io: Some(io), fb: None }
}
}
impl From<fbio::ErrnoError> for Error {
fn from(fb: fbio::ErrnoError) -> Error {
Error { kind: ErrorKind::Fb, io: None, fb: Some(fb) }
}
}
pub struct Framebuffer {
file: File,
finfo: fbio::FixScreeninfo,
vinfo: fbio::VarScreeninfo,
}
impl Framebuffer {
pub fn list() -> std::io::Result<Vec<PathBuf>> {
match proc::devices()?.find(|device| device.driver == "fb") {
None => Ok(vec![]),
Some(device) =>
Ok(std::fs::read_dir("/dev")?.flat_map(|result| {
match result {
Err(_) => None,
Ok(entry) => {
let mut statbuf: libc::stat = unsafe { std::mem::zeroed() };
let path = entry.path();
let cpath = std::ffi::CString::new(path.to_str().unwrap()).unwrap();
match unsafe { libc::stat(cpath.as_ptr(), &mut statbuf) } {
-1 => {
None
},
_ => {
let major = unsafe { libc::major(statbuf.st_rdev) } as u32;
if major == device.major {
Some(path)
} else {
None
}
}
}
}
}
}).collect())
}
}
pub fn new(path: impl AsRef<Path>) -> Result<Framebuffer, Error> {
let file = OpenOptions::new().read(true).write(true).open(path)?;
let finfo = fbio::get_fscreeninfo(&file)?;
let vinfo = fbio::get_vscreeninfo(&file)?;
Ok(Framebuffer { file, finfo, vinfo })
}
pub fn map(&self) -> Result<MmapMut, Error> {
let (width, height) = self.get_virtual_size();
let size = width * height * self.get_bytes_per_pixel();
let mmap = unsafe { MmapOptions::new().len(size as usize).map_mut(&self.file) }?;
Ok(mmap)
}
pub fn get_bytes_per_pixel(&self) -> u32 {
self.vinfo.bytes_per_pixel()
}
pub fn set_bytes_per_pixel(&mut self, value: u32) -> Result<(), Error> {
let mut vinfo = self.vinfo.clone();
vinfo.set_bytes_per_pixel(value);
vinfo.activate_now();
fbio::put_vscreeninfo(&self.file, &mut vinfo)?;
self.vinfo = fbio::get_vscreeninfo(&self.file)?;
Ok(())
}
pub fn get_pixel_layout(&self) -> fbio::PixelLayout {
self.vinfo.pixel_layout()
}
pub fn get_size(&self) -> (u32, u32) {
self.vinfo.size_in_pixels()
}
pub fn get_virtual_size(&self) -> (u32, u32) {
self.vinfo.virtual_size()
}
pub fn set_virtual_size(&mut self, w: u32, h: u32) -> Result<(), Error> {
let mut vinfo = self.vinfo.clone();
vinfo.set_virtual_size(w, h);
vinfo.activate_now();
fbio::put_vscreeninfo(&self.file, &mut vinfo)?;
self.vinfo = fbio::get_vscreeninfo(&self.file)?;
Ok(())
}
pub fn get_offset(&self) -> (u32, u32) {
self.vinfo.offset()
}
pub fn set_offset(&mut self, x: u32, y: u32) -> Result<(), Error> {
let mut vinfo = self.vinfo.clone();
vinfo.set_offset(x, y);
vinfo.activate_now();
fbio::put_vscreeninfo(&self.file, &mut vinfo)?;
self.vinfo = fbio::get_vscreeninfo(&self.file)?;
Ok(())
}
pub fn get_physical_size(&self) -> (u32, u32) {
self.vinfo.size_in_mm()
}
pub fn get_id(&self) -> String {
self.finfo.id()
}
pub fn blank(&self, level: BlankingLevel) -> Result<(), Error> {
fbio::blank(&self.file, level)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
println!("Framebuffer devices: {:?}", crate::Framebuffer::list());
}
}