149 lines
3.4 KiB
Rust
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,
|
|
}
|
|
}
|
|
}
|