1use core::convert::Infallible;
2
3use embedded_graphics::{
4 draw_target::DrawTarget,
5 geometry::{OriginDimensions, Point, Size},
6 pixelcolor::PixelColor,
7 Pixel,
8};
9
10use crate::color::{Color, ColorType, TriColor};
11
12#[derive(Debug, Clone, Copy, Default)]
14pub enum DisplayRotation {
15 #[default]
17 Rotate0,
18 Rotate90,
20 Rotate180,
22 Rotate270,
24}
25
26pub const fn buffer_len<C>(width: usize, height: usize) -> usize
29where
30 C: ColorType,
31{
32 (width + 7) / 8 * height * C::BUFFER_COUNT
33}
34
35pub struct Display<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize, C> {
39 buffer: [u8; BUFFER_SIZE],
40 rotation: DisplayRotation,
41 _color: core::marker::PhantomData<C>,
42}
43
44pub type Display290BlackWhite = Display<128, 296, { buffer_len::<Color>(128, 296) }, Color>;
46pub type Display290TriColor = Display<128, 296, { buffer_len::<TriColor>(128, 296) }, TriColor>;
48pub type Display213BlackWhite = Display<128, 250, { buffer_len::<Color>(128, 250) }, Color>;
52pub type Display213TriColor = Display<128, 250, { buffer_len::<TriColor>(128, 250) }, TriColor>;
56
57pub type DisplayBlackWhite<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize> =
61 Display<WIDTH, HEIGHT, BUFFER_SIZE, Color>;
62
63pub type DisplayTriColor<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize> =
67 Display<WIDTH, HEIGHT, BUFFER_SIZE, TriColor>;
68
69impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize>
70 Display<WIDTH, HEIGHT, BUFFER_SIZE, Color>
71{
72 pub fn new() -> Self {
74 Self {
75 buffer: [Color::default().byte_value().0; BUFFER_SIZE],
76 rotation: Default::default(),
77 _color: core::marker::PhantomData,
78 }
79 }
80
81 pub fn buffer(&self) -> &[u8] {
83 &self.buffer
84 }
85
86 pub fn clear(&mut self, color: Color) {
88 self.buffer.fill(color.byte_value().0);
89 }
90}
91
92impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize> Default
93 for Display<WIDTH, HEIGHT, BUFFER_SIZE, Color>
94{
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize>
101 Display<WIDTH, HEIGHT, BUFFER_SIZE, TriColor>
102{
103 pub fn new() -> Self {
105 let background_color = TriColor::default();
106
107 let mut buffer = [0; BUFFER_SIZE];
108 buffer[..(BUFFER_SIZE / 2)].fill(background_color.byte_value().0);
109 buffer[(BUFFER_SIZE / 2)..].fill(background_color.byte_value().1);
110
111 Self {
112 buffer,
113 rotation: Default::default(),
114 _color: core::marker::PhantomData,
115 }
116 }
117
118 pub fn bw_buffer(&self) -> &[u8] {
120 &self.buffer[..(BUFFER_SIZE / 2)]
121 }
122
123 pub fn red_buffer(&self) -> &[u8] {
125 &self.buffer[(BUFFER_SIZE / 2)..]
126 }
127
128 pub fn clear(&mut self, color: TriColor) {
130 self.buffer[..(BUFFER_SIZE / 2)].fill(color.byte_value().0);
131 self.buffer[(BUFFER_SIZE / 2)..].fill(color.byte_value().1);
132 }
133}
134
135impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize> Default
136 for Display<WIDTH, HEIGHT, BUFFER_SIZE, TriColor>
137{
138 fn default() -> Self {
139 Self::new()
140 }
141}
142
143impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize, C>
144 Display<WIDTH, HEIGHT, BUFFER_SIZE, C>
145where
146 C: ColorType + PixelColor,
147{
148 pub fn rotation(&self) -> DisplayRotation {
150 self.rotation
151 }
152
153 pub fn set_rotation(&mut self, rotation: DisplayRotation) {
155 self.rotation = rotation;
156 }
157
158 fn set_pixel(&mut self, pixel: Pixel<C>) {
159 let Pixel(point, color) = pixel;
161 let Point { x, y } = point;
162
163 if outside_display(point, WIDTH, HEIGHT, self.rotation) {
164 return;
165 }
166
167 let (index, bit) =
168 pixel_position_in_buffer(x as u32, y as u32, WIDTH, HEIGHT, self.rotation);
169 let index = index as usize;
170 let (bw_bit, red_bit) = color.bit_value();
171
172 #[allow(clippy::collapsible_else_if)]
173 if C::BUFFER_COUNT == 2 {
174 if red_bit == 1 {
175 self.buffer[index + BUFFER_SIZE / 2] |= bit;
177 } else {
178 if bw_bit == 1 {
179 self.buffer[index] |= bit;
180 } else {
181 self.buffer[index] &= !bit;
182 }
183 self.buffer[index + BUFFER_SIZE / 2] &= !bit;
184 }
185 } else {
186 if bw_bit == 1 {
187 self.buffer[index] |= bit;
188 } else {
189 self.buffer[index] &= !bit;
190 }
191 }
192 }
193}
194
195impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize> DrawTarget
196 for Display<WIDTH, HEIGHT, BUFFER_SIZE, Color>
197{
198 type Color = Color;
199 type Error = Infallible;
200
201 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
202 where
203 I: IntoIterator<Item = Pixel<Self::Color>>,
204 {
205 for p in pixels.into_iter() {
206 self.set_pixel(p);
207 }
208 Ok(())
209 }
210
211 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
212 self.clear(color);
213 Ok(())
214 }
215}
216
217impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize> DrawTarget
218 for Display<WIDTH, HEIGHT, BUFFER_SIZE, TriColor>
219{
220 type Color = TriColor;
221 type Error = Infallible;
222
223 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
224 where
225 I: IntoIterator<Item = Pixel<Self::Color>>,
226 {
227 for p in pixels.into_iter() {
228 self.set_pixel(p);
229 }
230 Ok(())
231 }
232
233 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
234 self.clear(color);
235 Ok(())
236 }
237}
238
239impl PixelColor for Color {
240 type Raw = ();
241}
242
243impl PixelColor for TriColor {
244 type Raw = ();
245}
246
247impl<const WIDTH: u32, const HEIGHT: u32, const BUFFER_SIZE: usize, C> OriginDimensions
248 for Display<WIDTH, HEIGHT, BUFFER_SIZE, C>
249where
250 C: PixelColor + ColorType,
251{
252 fn size(&self) -> Size {
253 match self.rotation() {
255 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => Size::new(WIDTH, HEIGHT),
256 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => Size::new(HEIGHT, WIDTH),
257 }
258 }
259}
260
261fn outside_display(p: Point, width: u32, height: u32, rotation: DisplayRotation) -> bool {
262 if p.x < 0 || p.y < 0 {
263 return true;
264 }
265 let (x, y) = (p.x as u32, p.y as u32);
266 match rotation {
267 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 if x >= width || y >= height => true,
268 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 if y >= width || x >= height => true,
269 _ => false,
270 }
271}
272
273fn pixel_position_in_buffer(
277 x: u32,
278 y: u32,
279 width: u32,
280 height: u32,
281 rotation: DisplayRotation,
282) -> (u32, u8) {
283 let (nx, ny) = find_rotation(x, y, width, height, rotation);
284 (nx / 8 + bytes_per_line(width) * ny, 0x80 >> (nx % 8))
285}
286
287fn find_rotation(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u32) {
288 match rotation {
289 DisplayRotation::Rotate0 => (x, y),
290 DisplayRotation::Rotate90 => (width - 1 - y, x),
291 DisplayRotation::Rotate180 => (width - 1 - x, height - 1 - y),
292 DisplayRotation::Rotate270 => (y, height - 1 - x),
293 }
294}
295
296const fn bytes_per_line(width: u32) -> u32 {
297 (width + 7) / 8
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303
304 #[test]
305 fn pixels_are_set_correctly_in_both_buffers_when_creating_new_tri_color_display() {
306 let display = Display::<8, 1, 2, TriColor>::new();
307 assert_eq!(display.buffer.len(), 2);
308
309 assert_eq!(
310 display.buffer[0], 0b1111_1111,
311 "B/W buffer has incorrect value"
312 );
313 assert_eq!(
314 display.buffer[1], 0b0000_0000,
315 "Red buffer has incorrect value"
316 );
317 }
318
319 #[test]
320 fn pixel_is_set_in_bw_buffer_when_drawing_black() {
321 let mut display = Display::<8, 1, 2, TriColor>::new();
322
323 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Black));
324
325 assert_eq!(
326 display.buffer[0], 0b0111_1111,
327 "B/W buffer has incorrect value"
328 );
329 assert_eq!(
330 display.buffer[1], 0b0000_0000,
331 "Red buffer has incorrect value"
332 );
333 }
334
335 #[test]
336 fn pixel_is_set_in_both_buffers_when_drawing_red() {
337 let mut display = Display::<8, 1, 2, TriColor>::new();
338
339 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Red));
340
341 assert_eq!(
342 display.buffer[0], 0b1111_1111,
343 "B/W buffer has incorrect value"
344 );
345 assert_eq!(
346 display.buffer[1], 0b1000_0000,
347 "Red buffer has incorrect value"
348 );
349 }
350
351 #[test]
352 fn pixel_is_set_in_both_buffers_when_drawing_red_then_black() {
353 let mut display = Display::<8, 1, 2, TriColor>::new();
354
355 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Red));
356 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Black));
357
358 assert_eq!(
359 display.buffer[0], 0b0111_1111,
360 "B/W buffer has incorrect value"
361 );
362 assert_eq!(
363 display.buffer[1], 0b0000_0000,
364 "Red buffer has incorrect value"
365 );
366 }
367
368 #[test]
369 fn pixel_is_set_in_both_buffers_when_drawing_red_black_red() {
370 let mut display = Display::<8, 1, 2, TriColor>::new();
371
372 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Red));
373 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Black));
374 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Red));
375
376 assert_eq!(
377 display.buffer[0], 0b0111_1111,
378 "B/W buffer has incorrect value"
379 );
380 assert_eq!(
381 display.buffer[1], 0b1000_0000,
382 "Red buffer has incorrect value"
383 );
384 }
385
386 #[test]
387 fn clear_sets_both_buffers() {
388 let mut display = Display::<8, 1, 2, TriColor>::new();
389
390 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Black));
391 display.set_pixel(Pixel(Point::new(0, 0), TriColor::Red));
392
393 display.clear(TriColor::White);
394 assert_eq!(
395 display.buffer[0], 0b1111_1111,
396 "B/W buffer has incorrect value"
397 );
398 assert_eq!(
399 display.buffer[1], 0b0000_0000,
400 "Red buffer has incorrect value"
401 );
402
403 display.clear(TriColor::Red);
404 assert_eq!(
405 display.buffer[0], 0b0000_0000,
406 "B/W buffer has incorrect value"
407 );
408 assert_eq!(
409 display.buffer[1], 0b1111_1111,
410 "Red buffer has incorrect value"
411 );
412 }
413}