tft_rs/
display.rs

1use crate::drivers::DisplayDriver;
2use crate::Error;
3use embedded_graphics_core::draw_target::DrawTarget;
4use embedded_graphics_core::geometry::Dimensions;
5use embedded_graphics_core::prelude::*;
6use embedded_graphics_core::primitives::Rectangle;
7use embedded_graphics_core::Pixel;
8use embedded_hal::delay::DelayNs;
9use embedded_hal::digital::OutputPin;
10use embedded_hal::spi::SpiDevice;
11
12pub struct Display<DI: DisplayInterface, BL, DRIVER> {
13    di: DI,
14    bl: Option<BL>,
15    driver: DRIVER,
16}
17
18impl<SPI, DC, RST, DELAY, BL, DRIVER> Display<DisplayInterfaceImpl<SPI, DC, RST, DELAY>, BL, DRIVER>
19where
20    BL: OutputPin,
21    DRIVER: DisplayDriver,
22    SPI: SpiDevice,
23    DC: OutputPin,
24    RST: OutputPin,
25    DELAY: DelayNs,
26{
27    pub fn new(
28        spi: SPI,
29        dc: DC,
30        rst: RST,
31        bl: Option<BL>,
32        delay: DELAY,
33        driver: DRIVER,
34    ) -> Result<Self, Error> {
35        let di = DisplayInterfaceImpl {
36            spi,
37            dc,
38            rst,
39            delay,
40        };
41        let mut device = Self { di, bl, driver };
42        device.driver.init(&mut device.di)?;
43        if let Some(bl) = &mut device.bl {
44            bl.set_high().map_err(|_| Error::GPIO)?;
45        }
46        Ok(device)
47    }
48}
49
50pub struct DisplayInterfaceImpl<SPI: SpiDevice, DC: OutputPin, RST: OutputPin, DELAY: DelayNs> {
51    spi: SPI,
52    dc: DC,
53    rst: RST,
54    delay: DELAY,
55}
56
57pub trait DisplayInterface {
58    fn spi(&mut self) -> &mut impl SpiDevice;
59    fn dc(&mut self) -> &mut impl OutputPin;
60    fn reset(&mut self) -> &mut impl OutputPin;
61    fn delay(&mut self) -> &mut impl DelayNs;
62}
63
64impl<SPI: SpiDevice, DC: OutputPin, RST: OutputPin, DELAY: DelayNs> DisplayInterface
65    for DisplayInterfaceImpl<SPI, DC, RST, DELAY>
66{
67    fn spi(&mut self) -> &mut impl SpiDevice {
68        &mut self.spi
69    }
70
71    fn dc(&mut self) -> &mut impl OutputPin {
72        &mut self.dc
73    }
74
75    fn reset(&mut self) -> &mut impl OutputPin {
76        &mut self.rst
77    }
78
79    fn delay(&mut self) -> &mut impl DelayNs {
80        &mut self.delay
81    }
82}
83
84impl<DI: DisplayInterface, BL, DRIVER: DisplayDriver> Dimensions for Display<DI, BL, DRIVER> {
85    fn bounding_box(&self) -> Rectangle {
86        Rectangle::new(Point::new(0, 0), self.driver.bounding_box().size)
87    }
88}
89
90impl<DI: DisplayInterface, BL, DRIVER: DisplayDriver> DrawTarget for Display<DI, BL, DRIVER> {
91    type Color = DRIVER::Color;
92    type Error = Error;
93
94    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
95    where
96        I: IntoIterator<Item = Pixel<Self::Color>>,
97    {
98        for Pixel(p, c) in pixels {
99            if !(self.bounding_box().contains(p)) {
100                continue;
101            }
102            self.driver
103                .set_draw_area(&mut self.di, &Rectangle::new(p, Size::new(2, 2)))?;
104            self.driver.write_color_data(&mut self.di, [c])?
105        }
106        Ok(())
107    }
108
109    fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
110    where
111        I: IntoIterator<Item = Self::Color>,
112    {
113        let bb = self.bounding_box();
114        let area = self.bounding_box().intersection(area);
115        self.driver.set_draw_area(&mut self.di, &area)?;
116        let iter = area
117            .points()
118            .zip(colors)
119            .filter(|(p, _)| bb.contains(*p))
120            .map(|x| x.1);
121        self.driver.write_color_data(&mut self.di, iter)
122    }
123}