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}