1#![no_std]
2
3pub mod area;
4pub mod bus;
5pub mod color;
6pub mod panel;
7
8pub use crate::area::Area;
9pub use crate::bus::{
10 BusBytesIo, BusHardwareFill, DisplayBus, FrameControl, Metadata, SimpleDisplayBus,
11};
12pub use color::{ColorFormat, ColorType, SolidColor};
13pub use panel::{reset::LCDResetOption, Orientation, Panel, PanelSetBrightness};
14
15use embedded_hal_async::delay::DelayNs;
16
17#[derive(Debug)]
19pub enum DisplayError<E> {
20 BusError(E),
22 Unsupported,
24 OutOfRange,
26 InvalidArgs,
28 UnalignedArea,
30}
31
32impl<E> From<E> for DisplayError<E> {
33 fn from(error: E) -> Self {
34 Self::BusError(error)
35 }
36}
37
38pub struct DisplayDriverBuilder<B: DisplayBus, P: Panel<B>> {
51 bus: B,
52 panel: P,
53 color_format: Option<ColorFormat>,
54 orientation: Option<Orientation>,
55}
56
57impl<B: DisplayBus, P: Panel<B>> DisplayDriverBuilder<B, P> {
58 fn new(bus: B, panel: P) -> Self {
60 Self {
61 bus,
62 panel,
63 color_format: None,
64 orientation: None,
65 }
66 }
67
68 pub fn with_color_format(mut self, color_format: ColorFormat) -> Self {
70 self.color_format = Some(color_format);
71 self
72 }
73
74 pub fn with_orientation(mut self, orientation: Orientation) -> Self {
76 self.orientation = Some(orientation);
77 self
78 }
79
80 pub async fn init<D: DelayNs>(
87 mut self,
88 delay: &mut D,
89 ) -> Result<DisplayDriver<B, P>, DisplayError<B::Error>> {
90 self.panel
91 .init(&mut self.bus, delay)
92 .await
93 .map_err(DisplayError::BusError)?;
94
95 if let Some(color_format) = self.color_format {
96 self.panel
97 .set_color_format(&mut self.bus, color_format)
98 .await?;
99 }
100
101 if let Some(orientation) = self.orientation {
102 self.panel
103 .set_orientation(&mut self.bus, orientation)
104 .await?;
105 }
106
107 Ok(DisplayDriver {
108 bus: self.bus,
109 panel: self.panel,
110 })
111 }
112}
113
114pub struct DisplayDriver<B: DisplayBus, P: Panel<B>> {
120 pub bus: B,
122 pub panel: P,
124}
125
126impl<B: DisplayBus, P: Panel<B>> DisplayDriver<B, P> {
127 pub fn builder(bus: B, panel: P) -> DisplayDriverBuilder<B, P> {
137 DisplayDriverBuilder::new(bus, panel)
138 }
139
140 pub fn new(bus: B, panel: P) -> Self {
144 Self { bus, panel }
145 }
146
147 pub async fn init(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError<B::Error>> {
149 self.panel
150 .init(&mut self.bus, delay)
151 .await
152 .map_err(DisplayError::BusError)
153 }
154
155 pub async fn set_window(&mut self, area: Area) -> Result<(), DisplayError<B::Error>> {
160 if self.panel.x_alignment() > 1 || self.panel.y_alignment() > 1 {
161 if area.x % self.panel.x_alignment() != 0
162 || area.y % self.panel.y_alignment() != 0
163 || area.w % self.panel.x_alignment() != 0
164 || area.h % self.panel.y_alignment() != 0
165 {
166 return Err(DisplayError::UnalignedArea);
167 }
168 }
169
170 let (x1, y1) = area.bottom_right();
171 self.panel
172 .set_window(&mut self.bus, area.x, area.y, x1, y1)
173 .await
174 }
175
176 pub async fn set_color_format(
178 &mut self,
179 color_format: ColorFormat,
180 ) -> Result<(), DisplayError<B::Error>> {
181 self.panel
182 .set_color_format(&mut self.bus, color_format)
183 .await
184 }
185
186 pub async fn set_orientation(
188 &mut self,
189 orientation: Orientation,
190 ) -> Result<(), DisplayError<B::Error>> {
191 self.panel.set_orientation(&mut self.bus, orientation).await
192 }
193
194 pub async fn write_pixels(
196 &mut self,
197 area: Area,
198 frame_control: FrameControl,
199 buffer: &[u8],
200 ) -> Result<(), DisplayError<B::Error>> {
201 self.set_window(area).await?;
202 let cmd = &P::PIXEL_WRITE_CMD[0..P::CMD_LEN];
203 let metadata = Metadata {
204 area: Some(area),
205 frame_control,
206 };
207 self.bus.write_pixels(cmd, buffer, metadata).await
208 }
209
210 pub async fn write_frame(&mut self, buffer: &[u8]) -> Result<(), DisplayError<B::Error>> {
212 self.write_pixels(
213 Area::from_origin_size(self.panel.size()),
214 FrameControl::new_standalone(),
215 buffer,
216 )
217 .await
218 }
219}
220
221impl<B: DisplayBus, P: Panel<B> + PanelSetBrightness<B>> DisplayDriver<B, P> {
222 pub async fn set_brightness(&mut self, brightness: u8) -> Result<(), DisplayError<B::Error>> {
224 self.panel.set_brightness(&mut self.bus, brightness).await
225 }
226}
227
228impl<B: DisplayBus + BusHardwareFill, P: Panel<B>> DisplayDriver<B, P> {
229 pub async fn fill_solid_via_bus(
231 &mut self,
232 color: SolidColor,
233 area: Area,
234 ) -> Result<(), DisplayError<B::Error>> {
235 self.set_window(area).await?;
236 let cmd = &P::PIXEL_WRITE_CMD[0..P::CMD_LEN];
237 self.bus.fill_solid(cmd, color, area).await
238 }
239
240 pub async fn fill_screen_via_bus(
242 &mut self,
243 color: SolidColor,
244 ) -> Result<(), DisplayError<B::Error>> {
245 self.fill_solid_via_bus(color, Area::from_origin_size(self.panel.size()))
246 .await
247 }
248}
249
250impl<B, P> DisplayDriver<B, P>
251where
252 B: DisplayBus + BusBytesIo,
253 P: Panel<B>,
254{
255 pub async fn fill_solid_batch<const N: usize>(
257 &mut self,
258 color: SolidColor,
259 area: Area,
260 ) -> Result<(), DisplayError<B::Error>> {
261 self.set_window(area).await?;
262 let cmd = &P::PIXEL_WRITE_CMD[0..P::CMD_LEN];
263
264 self.bus
265 .write_cmd_bytes(cmd)
266 .await
267 .map_err(DisplayError::BusError)?;
268
269 let pixel_size = color.format.size_bytes() as usize;
270 let total_pixels = area.total_pixels();
271 let mut remaining_pixels = total_pixels;
272
273 let mut buffer = [0u8; N];
274
275 let pixels_per_chunk = buffer.len() / pixel_size;
277
278 let color_bytes = &color.raw[..pixel_size];
280
281 for i in 0..pixels_per_chunk {
283 buffer[i * pixel_size..(i + 1) * pixel_size].copy_from_slice(color_bytes);
284 }
285
286 while remaining_pixels > 0 {
287 let current_pixels = remaining_pixels.min(pixels_per_chunk);
288 let byte_count = current_pixels * pixel_size;
289 self.bus
290 .write_data_bytes(&buffer[0..byte_count])
291 .await
292 .map_err(DisplayError::BusError)?;
293 remaining_pixels -= current_pixels;
294 }
295
296 Ok(())
297 }
298
299 pub async fn fill_screen_batch<const N: usize>(
301 &mut self,
302 color: SolidColor,
303 ) -> Result<(), DisplayError<B::Error>> {
304 self.fill_solid_batch::<N>(color, Area::from_origin_size(self.panel.size()))
305 .await
306 }
307}