nihpod/nano5g/src/lcd.rs

149 lines
3.4 KiB
Rust

use embedded_graphics_core::{
pixelcolor::{Rgb565, IntoStorage},
draw_target::DrawTarget,
Pixel,
geometry::{OriginDimensions, Size},
};
pub struct LCD {
p: s5l87xx::LCD
}
pub struct Rectangle {
pub startx: u16,
pub endx: u16,
pub starty: u16,
pub endy: u16,
}
impl Rectangle {
pub fn new(width: u16, height: u16) -> Self {
Self {
startx: 0,
endx: width - 1,
starty: 0,
endy: height - 1,
}
}
fn width(&self) -> u16 {
(self.endx - self.startx) + 1
}
fn height(&self) -> u16 {
(self.endy - self.starty) + 1
}
}
impl LCD {
pub const WIDTH: usize = 240;
pub const HEIGHT: usize = 320;
pub fn new(lcd: s5l87xx::LCD) -> Self {
Self { p: lcd }
}
fn wait_sync(&self) {
loop {
if self.p.status.read().full().bit_is_clear() {
break
}
}
}
fn send_command(&mut self, cmd: u8) {
self.wait_sync();
self.p.wcmd.write(|w| unsafe { w.wcmd().bits(cmd) });
}
fn send_data(&mut self, data: u16) {
let data = data as u32;
let data: u32 = ((data & 0x7f00) << 1) | (data & 0xff);
self.wait_sync();
self.p.wdata.write(|w| unsafe { w.bits(data) });
}
fn setup(&mut self, rect: &Rectangle) {
self.send_command(0x2a);
self.send_data(rect.startx);
self.send_data(rect.endx);
self.send_command(0x2b);
self.send_data(rect.starty);
self.send_data(rect.endy);
self.send_command(0x2c);
}
pub fn draw(&mut self, rect: &Rectangle, data: &[u16]) {
self.setup(rect);
let (w, h) = (rect.width(), rect.height());
for y in 0u16..h {
for x in 0u16..w {
let ix: usize = (y as usize) * (w as usize) + (x as usize);
if ix >= data.len() {
continue
}
let pix = data[ix];
self.send_data(pix);
}
}
}
pub fn full_rect() -> Rectangle {
Rectangle::new(Self::WIDTH as u16, Self::HEIGHT as u16)
}
}
pub struct Display {
underlying: LCD,
framebuffer: [u16; LCD::WIDTH * LCD::HEIGHT ],
}
impl Display {
pub fn new(l: LCD) -> Self {
Self {
underlying: l,
framebuffer: [0; LCD::WIDTH * LCD::HEIGHT ],
}
}
pub fn flush(&mut self) -> Result<(), core::convert::Infallible> {
let rect = LCD::full_rect();
self.underlying.draw(&rect, &self.framebuffer);
Ok(())
}
}
impl DrawTarget for Display {
type Color = Rgb565;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item=Pixel<Self::Color>>,
{
const W: u32 = LCD::WIDTH as u32;
const H: u32 = LCD::HEIGHT as u32;
for Pixel(coord, color) in pixels.into_iter() {
if let Ok((x @ 0..W, y @ 0..H)) = coord.try_into() {
let index: u32 = y * W + x;
self.framebuffer[index as usize] = color.into_storage();
}
}
Ok(())
}
}
impl OriginDimensions for Display {
fn size(&self) -> Size {
Size {
width: LCD::WIDTH as u32,
height: LCD::HEIGHT as u32,
}
}
}