tft-rs 0.1.0

An interfacing library for several TFT LCD displays
Documentation
use crate::drivers::DisplayDriver;
use crate::Error;
use embedded_graphics_core::draw_target::DrawTarget;
use embedded_graphics_core::geometry::Dimensions;
use embedded_graphics_core::prelude::*;
use embedded_graphics_core::primitives::Rectangle;
use embedded_graphics_core::Pixel;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::SpiDevice;

pub struct Display<DI: DisplayInterface, BL, DRIVER> {
    di: DI,
    bl: Option<BL>,
    driver: DRIVER,
}

impl<SPI, DC, RST, DELAY, BL, DRIVER> Display<DisplayInterfaceImpl<SPI, DC, RST, DELAY>, BL, DRIVER>
where
    BL: OutputPin,
    DRIVER: DisplayDriver,
    SPI: SpiDevice,
    DC: OutputPin,
    RST: OutputPin,
    DELAY: DelayNs,
{
    pub fn new(
        spi: SPI,
        dc: DC,
        rst: RST,
        bl: Option<BL>,
        delay: DELAY,
        driver: DRIVER,
    ) -> Result<Self, Error> {
        let di = DisplayInterfaceImpl {
            spi,
            dc,
            rst,
            delay,
        };
        let mut device = Self { di, bl, driver };
        device.driver.init(&mut device.di)?;
        if let Some(bl) = &mut device.bl {
            bl.set_high().map_err(|_| Error::GPIO)?;
        }
        Ok(device)
    }
}

pub struct DisplayInterfaceImpl<SPI: SpiDevice, DC: OutputPin, RST: OutputPin, DELAY: DelayNs> {
    spi: SPI,
    dc: DC,
    rst: RST,
    delay: DELAY,
}

pub trait DisplayInterface {
    fn spi(&mut self) -> &mut impl SpiDevice;
    fn dc(&mut self) -> &mut impl OutputPin;
    fn reset(&mut self) -> &mut impl OutputPin;
    fn delay(&mut self) -> &mut impl DelayNs;
}

impl<SPI: SpiDevice, DC: OutputPin, RST: OutputPin, DELAY: DelayNs> DisplayInterface
    for DisplayInterfaceImpl<SPI, DC, RST, DELAY>
{
    fn spi(&mut self) -> &mut impl SpiDevice {
        &mut self.spi
    }

    fn dc(&mut self) -> &mut impl OutputPin {
        &mut self.dc
    }

    fn reset(&mut self) -> &mut impl OutputPin {
        &mut self.rst
    }

    fn delay(&mut self) -> &mut impl DelayNs {
        &mut self.delay
    }
}

impl<DI: DisplayInterface, BL, DRIVER: DisplayDriver> Dimensions for Display<DI, BL, DRIVER> {
    fn bounding_box(&self) -> Rectangle {
        Rectangle::new(Point::new(0, 0), self.driver.bounding_box().size)
    }
}

impl<DI: DisplayInterface, BL, DRIVER: DisplayDriver> DrawTarget for Display<DI, BL, DRIVER> {
    type Color = DRIVER::Color;
    type Error = Error;

    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
    where
        I: IntoIterator<Item = Pixel<Self::Color>>,
    {
        for Pixel(p, c) in pixels {
            if !(self.bounding_box().contains(p)) {
                continue;
            }
            self.driver
                .set_draw_area(&mut self.di, &Rectangle::new(p, Size::new(2, 2)))?;
            self.driver.write_color_data(&mut self.di, [c])?
        }
        Ok(())
    }

    fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
    where
        I: IntoIterator<Item = Self::Color>,
    {
        let bb = self.bounding_box();
        let area = self.bounding_box().intersection(area);
        self.driver.set_draw_area(&mut self.di, &area)?;
        let iter = area
            .points()
            .zip(colors)
            .filter(|(p, _)| bb.contains(*p))
            .map(|x| x.1);
        self.driver.write_color_data(&mut self.di, iter)
    }
}