1use core::convert::Infallible;
133
134use crate::{FrameBufferOperations, MutableFrameBuffer};
135use bitfield::bitfield;
136use embedded_dma::ReadBuffer;
137use embedded_graphics::pixelcolor::RgbColor;
138use embedded_graphics::prelude::Point;
139
140use super::Color;
141use super::FrameBuffer;
142use super::WordSize;
143
144const BLANKING_DELAY: usize = 1;
145
146#[inline]
149const fn make_data_template<const COLS: usize>(addr: u8, prev_addr: u8) -> [Entry; COLS] {
150 let mut data = [Entry::new(); COLS];
151 let mut i = 0;
152
153 while i < COLS {
154 let mut entry = Entry::new();
155 entry.0 = prev_addr as u16;
156
157 if i == 1 {
159 entry.0 |= 0b1_0000_0000; } else if i == COLS - BLANKING_DELAY - 1 {
161 } else if i == COLS - 1 {
163 entry.0 |= 0b0010_0000; entry.0 = (entry.0 & !0b0001_1111) | (addr as u16); } else if i > 1 && i < COLS - BLANKING_DELAY - 1 {
166 entry.0 |= 0b1_0000_0000; }
168
169 data[map_index(i)] = entry;
170 i += 1;
171 }
172
173 data
174}
175
176bitfield! {
177 #[derive(Clone, Copy, Default, PartialEq)]
198 #[repr(transparent)]
199 struct Entry(u16);
200 dummy2, set_dummy2: 15;
201 blu2, set_blu2: 14;
202 grn2, set_grn2: 13;
203 red2, set_red2: 12;
204 blu1, set_blu1: 11;
205 grn1, set_grn1: 10;
206 red1, set_red1: 9;
207 output_enable, set_output_enable: 8;
208 dummy1, set_dummy1: 7;
209 dummy0, set_dummy0: 6;
210 latch, set_latch: 5;
211 addr, set_addr: 4, 0;
212}
213
214impl core::fmt::Debug for Entry {
215 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216 f.debug_tuple("Entry")
217 .field(&format_args!("{:#x}", self.0))
218 .finish()
219 }
220}
221
222#[cfg(feature = "defmt")]
223impl defmt::Format for Entry {
224 fn format(&self, f: defmt::Formatter) {
225 defmt::write!(f, "Entry({=u16:#x})", self.0);
226 }
227}
228
229impl Entry {
230 const fn new() -> Self {
231 Self(0)
232 }
233
234 const COLOR0_MASK: u16 = 0b0000_1110_0000_0000; const COLOR1_MASK: u16 = 0b0111_0000_0000_0000; #[inline]
239 fn set_color0_bits(&mut self, bits: u8) {
240 let bits16 = u16::from(bits) << 9;
241 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits16 & Self::COLOR0_MASK);
242 }
243
244 #[inline]
245 fn set_color1_bits(&mut self, bits: u8) {
246 let bits16 = u16::from(bits) << 12;
247 self.0 = (self.0 & !Self::COLOR1_MASK) | (bits16 & Self::COLOR1_MASK);
248 }
249}
250
251#[derive(Clone, Copy, PartialEq, Debug)]
260#[repr(C)]
261struct Row<const COLS: usize> {
262 data: [Entry; COLS],
263}
264
265const fn map_index(i: usize) -> usize {
266 #[cfg(feature = "esp32-ordering")]
267 {
268 i ^ 1
269 }
270 #[cfg(not(feature = "esp32-ordering"))]
271 {
272 i
273 }
274}
275
276impl<const COLS: usize> Default for Row<COLS> {
277 fn default() -> Self {
278 Self::new()
279 }
280}
281
282impl<const COLS: usize> Row<COLS> {
283 pub const fn new() -> Self {
284 Self {
285 data: [Entry::new(); COLS],
286 }
287 }
288
289 pub fn format(&mut self, addr: u8, prev_addr: u8) {
290 let template = make_data_template::<COLS>(addr, prev_addr);
292 self.data.copy_from_slice(&template);
293 }
294
295 #[inline]
298 pub fn clear_colors(&mut self) {
299 const COLOR_CLEAR_MASK: u16 = !0b0111_1110_0000_0000; for entry in &mut self.data {
303 entry.0 &= COLOR_CLEAR_MASK;
304 }
305 }
306
307 #[inline]
308 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
309 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
310 let col = map_index(col);
311 self.data[col].set_color0_bits(bits);
312 }
313
314 #[inline]
315 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
316 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
317 let col = map_index(col);
318 self.data[col].set_color1_bits(bits);
319 }
320}
321
322#[derive(Copy, Clone, Debug)]
323#[repr(C)]
324struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
325 rows: [Row<COLS>; NROWS],
326}
327
328impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
329 pub const fn new() -> Self {
330 Self {
331 rows: [Row::new(); NROWS],
332 }
333 }
334
335 pub fn format(&mut self) {
336 for (addr, row) in self.rows.iter_mut().enumerate() {
337 let prev_addr = if addr == 0 {
338 NROWS as u8 - 1
339 } else {
340 addr as u8 - 1
341 };
342 row.format(addr as u8, prev_addr);
343 }
344 }
345
346 #[inline]
348 pub fn clear_colors(&mut self) {
349 for row in &mut self.rows {
350 row.clear_colors();
351 }
352 }
353
354 #[inline]
355 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
356 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
357 if y < NROWS {
358 row.set_color0(x, red, green, blue);
359 } else {
360 row.set_color1(x, red, green, blue);
361 }
362 }
363}
364
365impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
366 for Frame<ROWS, COLS, NROWS>
367{
368 fn default() -> Self {
369 Self::new()
370 }
371}
372
373#[derive(Copy, Clone)]
398#[repr(C)]
399pub struct DmaFrameBuffer<
400 const ROWS: usize,
401 const COLS: usize,
402 const NROWS: usize,
403 const BITS: u8,
404 const FRAME_COUNT: usize,
405> {
406 _align: u64,
407 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
408}
409
410impl<
411 const ROWS: usize,
412 const COLS: usize,
413 const NROWS: usize,
414 const BITS: u8,
415 const FRAME_COUNT: usize,
416 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
417{
418 fn default() -> Self {
419 Self::new()
420 }
421}
422
423impl<
424 const ROWS: usize,
425 const COLS: usize,
426 const NROWS: usize,
427 const BITS: u8,
428 const FRAME_COUNT: usize,
429 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
430{
431 #[must_use]
454 pub fn new() -> Self {
455 debug_assert!(BITS <= 8);
456
457 let mut instance = Self {
458 _align: 0,
459 frames: [Frame::new(); FRAME_COUNT],
460 };
461
462 instance.format();
464 instance
465 }
466
467 #[must_use]
470 pub const fn bcm_chunk_count() -> usize {
471 1
472 }
473
474 #[must_use]
477 pub const fn bcm_chunk_bytes() -> usize {
478 core::mem::size_of::<[Frame<ROWS, COLS, NROWS>; FRAME_COUNT]>()
479 }
480
481 #[inline]
501 pub fn format(&mut self) {
502 for frame in &mut self.frames {
503 frame.format();
504 }
505 }
506
507 #[inline]
527 pub fn erase(&mut self) {
528 for frame in &mut self.frames {
529 frame.clear_colors();
530 }
531 }
532
533 pub fn set_pixel(&mut self, p: Point, color: Color) {
549 if p.x < 0 || p.y < 0 {
550 return;
551 }
552 self.set_pixel_internal(p.x as usize, p.y as usize, color);
553 }
554
555 #[inline]
556 fn frames_on(v: u8) -> usize {
557 (v as usize) >> (8 - BITS)
559 }
560
561 #[inline]
562 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Color) {
563 if x >= COLS || y >= ROWS {
564 return;
565 }
566
567 #[cfg(feature = "skip-black-pixels")]
570 if color == Color::BLACK {
571 return;
572 }
573
574 let red_frames = Self::frames_on(color.r());
576 let green_frames = Self::frames_on(color.g());
577 let blue_frames = Self::frames_on(color.b());
578
579 for (frame_idx, frame) in self.frames.iter_mut().enumerate() {
581 frame.set_pixel(
582 y,
583 x,
584 frame_idx < red_frames,
585 frame_idx < green_frames,
586 frame_idx < blue_frames,
587 );
588 }
589 }
590}
591
592impl<
593 const ROWS: usize,
594 const COLS: usize,
595 const NROWS: usize,
596 const BITS: u8,
597 const FRAME_COUNT: usize,
598 > FrameBufferOperations for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
599{
600 #[inline]
601 fn erase(&mut self) {
602 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
603 }
604
605 #[inline]
606 fn set_pixel(&mut self, p: Point, color: Color) {
607 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
608 }
609}
610
611impl<
612 const ROWS: usize,
613 const COLS: usize,
614 const NROWS: usize,
615 const BITS: u8,
616 const FRAME_COUNT: usize,
617 > embedded_graphics::prelude::OriginDimensions
618 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
619{
620 fn size(&self) -> embedded_graphics::prelude::Size {
621 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
622 }
623}
624
625impl<
626 const ROWS: usize,
627 const COLS: usize,
628 const NROWS: usize,
629 const BITS: u8,
630 const FRAME_COUNT: usize,
631 > embedded_graphics::prelude::OriginDimensions
632 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
633{
634 fn size(&self) -> embedded_graphics::prelude::Size {
635 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
636 }
637}
638
639impl<
640 const ROWS: usize,
641 const COLS: usize,
642 const NROWS: usize,
643 const BITS: u8,
644 const FRAME_COUNT: usize,
645 > embedded_graphics::draw_target::DrawTarget
646 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
647{
648 type Color = Color;
649
650 type Error = Infallible;
651
652 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
653 where
654 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
655 {
656 for pixel in pixels {
657 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
658 }
659 Ok(())
660 }
661}
662
663unsafe impl<
664 const ROWS: usize,
665 const COLS: usize,
666 const NROWS: usize,
667 const BITS: u8,
668 const FRAME_COUNT: usize,
669 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
670{
671 type Word = u8;
672
673 unsafe fn read_buffer(&self) -> (*const u8, usize) {
674 let ptr = (&raw const self.frames).cast::<u8>();
675 let len = core::mem::size_of_val(&self.frames);
676 (ptr, len)
677 }
678}
679
680unsafe impl<
681 const ROWS: usize,
682 const COLS: usize,
683 const NROWS: usize,
684 const BITS: u8,
685 const FRAME_COUNT: usize,
686 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
687{
688 type Word = u8;
689
690 unsafe fn read_buffer(&self) -> (*const u8, usize) {
691 let ptr = (&raw const self.frames).cast::<u8>();
692 let len = core::mem::size_of_val(&self.frames);
693 (ptr, len)
694 }
695}
696
697impl<
698 const ROWS: usize,
699 const COLS: usize,
700 const NROWS: usize,
701 const BITS: u8,
702 const FRAME_COUNT: usize,
703 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
704{
705 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
706 let brightness_step = 1 << (8 - BITS);
707 f.debug_struct("DmaFrameBuffer")
708 .field("size", &core::mem::size_of_val(&self.frames))
709 .field("frame_count", &self.frames.len())
710 .field("frame_size", &core::mem::size_of_val(&self.frames[0]))
711 .field("brightness_step", &&brightness_step)
712 .finish_non_exhaustive()
713 }
714}
715
716#[cfg(feature = "defmt")]
717impl<
718 const ROWS: usize,
719 const COLS: usize,
720 const NROWS: usize,
721 const BITS: u8,
722 const FRAME_COUNT: usize,
723 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
724{
725 fn format(&self, f: defmt::Formatter) {
726 let brightness_step = 1 << (8 - BITS);
727 defmt::write!(
728 f,
729 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
730 ROWS,
731 COLS,
732 NROWS,
733 BITS,
734 FRAME_COUNT
735 );
736 defmt::write!(f, " size: {}", core::mem::size_of_val(&self.frames));
737 defmt::write!(
738 f,
739 " frame_size: {}",
740 core::mem::size_of_val(&self.frames[0])
741 );
742 defmt::write!(f, " brightness_step: {}", brightness_step);
743 }
744}
745
746impl<
747 const ROWS: usize,
748 const COLS: usize,
749 const NROWS: usize,
750 const BITS: u8,
751 const FRAME_COUNT: usize,
752 > FrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
753{
754 fn get_word_size(&self) -> WordSize {
755 WordSize::Sixteen
756 }
757
758 fn plane_count(&self) -> usize {
759 1
760 }
761
762 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
763 assert!(plane_idx == 0, "plain DmaFrameBuffer has only 1 plane");
764 let ptr = (&raw const self.frames).cast::<u8>();
765 let len = core::mem::size_of_val(&self.frames);
766 (ptr, len)
767 }
768}
769
770impl<
771 const ROWS: usize,
772 const COLS: usize,
773 const NROWS: usize,
774 const BITS: u8,
775 const FRAME_COUNT: usize,
776 > FrameBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
777{
778 fn get_word_size(&self) -> WordSize {
779 WordSize::Sixteen
780 }
781
782 fn plane_count(&self) -> usize {
783 1
784 }
785
786 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
787 assert!(plane_idx == 0, "plain DmaFrameBuffer has only 1 plane");
788 let ptr = (&raw const self.frames).cast::<u8>();
789 let len = core::mem::size_of_val(&self.frames);
790 (ptr, len)
791 }
792}
793
794impl<
795 const ROWS: usize,
796 const COLS: usize,
797 const NROWS: usize,
798 const BITS: u8,
799 const FRAME_COUNT: usize,
800 > MutableFrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
801{
802}
803
804#[cfg(test)]
805mod tests {
806 extern crate std;
807
808 use std::format;
809 use std::vec;
810
811 use super::*;
812 use crate::{FrameBuffer, WordSize};
813 use embedded_graphics::pixelcolor::RgbColor;
814 use embedded_graphics::prelude::*;
815 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
816
817 const TEST_ROWS: usize = 32;
818 const TEST_COLS: usize = 64;
819 const TEST_NROWS: usize = TEST_ROWS / 2;
820 const TEST_BITS: u8 = 3;
821 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
824 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
825
826 fn get_mapped_index(index: usize) -> usize {
828 map_index(index)
829 }
830
831 #[test]
832 fn test_entry_construction() {
833 let entry = Entry::new();
834 assert_eq!(entry.0, 0);
835 assert_eq!(entry.dummy2(), false);
836 assert_eq!(entry.blu2(), false);
837 assert_eq!(entry.grn2(), false);
838 assert_eq!(entry.red2(), false);
839 assert_eq!(entry.blu1(), false);
840 assert_eq!(entry.grn1(), false);
841 assert_eq!(entry.red1(), false);
842 assert_eq!(entry.output_enable(), false);
843 assert_eq!(entry.dummy1(), false);
844 assert_eq!(entry.dummy0(), false);
845 assert_eq!(entry.latch(), false);
846 assert_eq!(entry.addr(), 0);
847 }
848
849 #[test]
850 fn test_entry_setters() {
851 let mut entry = Entry::new();
852
853 entry.set_dummy2(true);
854 assert_eq!(entry.dummy2(), true);
855 assert_eq!(entry.0 & 0b1000000000000000, 0b1000000000000000);
856
857 entry.set_blu2(true);
858 assert_eq!(entry.blu2(), true);
859 assert_eq!(entry.0 & 0b0100000000000000, 0b0100000000000000);
860
861 entry.set_grn2(true);
862 assert_eq!(entry.grn2(), true);
863 assert_eq!(entry.0 & 0b0010000000000000, 0b0010000000000000);
864
865 entry.set_red2(true);
866 assert_eq!(entry.red2(), true);
867 assert_eq!(entry.0 & 0b0001000000000000, 0b0001000000000000);
868
869 entry.set_blu1(true);
870 assert_eq!(entry.blu1(), true);
871 assert_eq!(entry.0 & 0b0000100000000000, 0b0000100000000000);
872
873 entry.set_grn1(true);
874 assert_eq!(entry.grn1(), true);
875 assert_eq!(entry.0 & 0b0000010000000000, 0b0000010000000000);
876
877 entry.set_red1(true);
878 assert_eq!(entry.red1(), true);
879 assert_eq!(entry.0 & 0b0000001000000000, 0b0000001000000000);
880
881 entry.set_output_enable(true);
882 assert_eq!(entry.output_enable(), true);
883 assert_eq!(entry.0 & 0b0000000100000000, 0b0000000100000000);
884
885 entry.set_dummy1(true);
886 assert_eq!(entry.dummy1(), true);
887 assert_eq!(entry.0 & 0b0000000010000000, 0b0000000010000000);
888
889 entry.set_dummy0(true);
890 assert_eq!(entry.dummy0(), true);
891 assert_eq!(entry.0 & 0b0000000001000000, 0b0000000001000000);
892
893 entry.set_latch(true);
894 assert_eq!(entry.latch(), true);
895 assert_eq!(entry.0 & 0b0000000000100000, 0b0000000000100000);
896
897 entry.set_addr(0b11111);
898 assert_eq!(entry.addr(), 0b11111);
899 assert_eq!(entry.0 & 0b0000000000011111, 0b0000000000011111);
900 }
901
902 #[test]
903 fn test_entry_bit_isolation() {
904 let mut entry = Entry::new();
905
906 entry.set_addr(0b11111);
908 entry.set_latch(true);
909 assert_eq!(entry.addr(), 0b11111);
910 assert_eq!(entry.latch(), true);
911 assert_eq!(entry.output_enable(), false);
912 assert_eq!(entry.red1(), false);
913
914 entry.set_red1(true);
915 entry.set_grn2(true);
916 assert_eq!(entry.addr(), 0b11111);
917 assert_eq!(entry.latch(), true);
918 assert_eq!(entry.red1(), true);
919 assert_eq!(entry.grn2(), true);
920 assert_eq!(entry.blu1(), false);
921 assert_eq!(entry.red2(), false);
922 }
923
924 #[test]
925 fn test_entry_set_color0() {
926 let mut entry = Entry::new();
927
928 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
930 assert_eq!(entry.red1(), true);
931 assert_eq!(entry.grn1(), false);
932 assert_eq!(entry.blu1(), true);
933 assert_eq!(entry.0 & 0b0000101000000000, 0b0000101000000000); }
936
937 #[test]
938 fn test_entry_set_color1() {
939 let mut entry = Entry::new();
940
941 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
943 assert_eq!(entry.red2(), false);
944 assert_eq!(entry.grn2(), true);
945 assert_eq!(entry.blu2(), true);
946 assert_eq!(entry.0 & 0b0110000000000000, 0b0110000000000000); }
949
950 #[test]
951 fn test_entry_debug_formatting() {
952 let entry = Entry(0x1234);
953 let debug_str = format!("{:?}", entry);
954 assert_eq!(debug_str, "Entry(0x1234)");
955
956 let entry = Entry(0xabcd);
957 let debug_str = format!("{:?}", entry);
958 assert_eq!(debug_str, "Entry(0xabcd)");
959 }
960
961 #[test]
962 fn test_row_construction() {
963 let row: Row<TEST_COLS> = Row::new();
964 assert_eq!(row.data.len(), TEST_COLS);
965
966 for entry in &row.data {
968 assert_eq!(entry.0, 0);
969 }
970 }
971
972 #[test]
973 fn test_row_format() {
974 let mut row: Row<TEST_COLS> = Row::new();
975 let test_addr = 5;
976 let prev_addr = 4;
977
978 row.format(test_addr, prev_addr);
979
980 for (physical_i, entry) in row.data.iter().enumerate() {
982 let logical_i = get_mapped_index(physical_i);
983
984 match logical_i {
985 i if i == TEST_COLS - BLANKING_DELAY - 1 => {
986 assert_eq!(entry.output_enable(), false);
988 assert_eq!(entry.addr(), prev_addr as u16);
989 assert_eq!(entry.latch(), false);
990 }
991 i if i == TEST_COLS - 1 => {
992 assert_eq!(entry.latch(), true);
994 assert_eq!(entry.addr(), test_addr as u16);
995 assert_eq!(entry.output_enable(), false);
996 }
997 1 => {
998 assert_eq!(entry.output_enable(), true);
1000 assert_eq!(entry.addr(), prev_addr as u16);
1001 assert_eq!(entry.latch(), false);
1002 }
1003 _ => {
1004 assert_eq!(entry.addr(), prev_addr as u16);
1006 assert_eq!(entry.latch(), false);
1007 if logical_i > 1 && logical_i < TEST_COLS - BLANKING_DELAY - 1 {
1008 assert_eq!(entry.output_enable(), true);
1009 }
1010 }
1011 }
1012 }
1013 }
1014
1015 #[test]
1016 fn test_row_set_color0() {
1017 let mut row: Row<TEST_COLS> = Row::new();
1018
1019 row.set_color0(0, true, false, true);
1020
1021 let mapped_col_0 = get_mapped_index(0);
1022 assert_eq!(row.data[mapped_col_0].red1(), true);
1023 assert_eq!(row.data[mapped_col_0].grn1(), false);
1024 assert_eq!(row.data[mapped_col_0].blu1(), true);
1025
1026 row.set_color0(1, false, true, false);
1028
1029 let mapped_col_1 = get_mapped_index(1);
1030 assert_eq!(row.data[mapped_col_1].red1(), false);
1031 assert_eq!(row.data[mapped_col_1].grn1(), true);
1032 assert_eq!(row.data[mapped_col_1].blu1(), false);
1033 }
1034
1035 #[test]
1036 fn test_row_set_color1() {
1037 let mut row: Row<TEST_COLS> = Row::new();
1038
1039 row.set_color1(0, true, true, false);
1040
1041 let mapped_col_0 = get_mapped_index(0);
1042 assert_eq!(row.data[mapped_col_0].red2(), true);
1043 assert_eq!(row.data[mapped_col_0].grn2(), true);
1044 assert_eq!(row.data[mapped_col_0].blu2(), false);
1045 }
1046
1047 #[test]
1048 fn test_row_default() {
1049 let row1: Row<TEST_COLS> = Row::new();
1050 let row2: Row<TEST_COLS> = Row::default();
1051
1052 assert_eq!(row1, row2);
1054 assert_eq!(row1.data.len(), row2.data.len());
1055
1056 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1058 assert_eq!(entry1.0, entry2.0);
1059 assert_eq!(entry1.0, 0);
1060 }
1061 }
1062
1063 #[test]
1064 fn test_frame_construction() {
1065 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1066 assert_eq!(frame.rows.len(), TEST_NROWS);
1067 }
1068
1069 #[test]
1070 fn test_frame_format() {
1071 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1072
1073 frame.format();
1074
1075 for addr in 0..TEST_NROWS {
1077 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1078
1079 let row = &frame.rows[addr];
1081
1082 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1084 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1085 assert_eq!(row.data[last_pixel_idx].latch(), true);
1086
1087 let first_pixel_idx = get_mapped_index(0);
1089 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1090 assert_eq!(row.data[first_pixel_idx].latch(), false);
1091 }
1092 }
1093
1094 #[test]
1095 fn test_frame_set_pixel() {
1096 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1097
1098 frame.set_pixel(5, 10, true, false, true);
1100
1101 let mapped_col_10 = get_mapped_index(10);
1102 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1103 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1104 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1105
1106 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1108
1109 let mapped_col_15 = get_mapped_index(15);
1110 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1111 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1112 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1113 }
1114
1115 #[test]
1116 fn test_frame_default() {
1117 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1118 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1119
1120 assert_eq!(frame1.rows.len(), frame2.rows.len());
1122
1123 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1125 assert_eq!(row1, row2);
1126
1127 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1129 assert_eq!(entry1.0, entry2.0);
1130 assert_eq!(entry1.0, 0);
1131 }
1132 }
1133 }
1134
1135 #[test]
1136 fn test_dma_framebuffer_construction() {
1137 let fb = TestFrameBuffer::new();
1138 assert_eq!(fb.frames.len(), TEST_FRAME_COUNT);
1139 assert_eq!(fb._align, 0);
1140 }
1141
1142 #[test]
1143 fn test_bcm_chunk_info() {
1144 let expected_size =
1145 core::mem::size_of::<[Frame<TEST_ROWS, TEST_COLS, TEST_NROWS>; TEST_FRAME_COUNT]>();
1146 assert_eq!(TestFrameBuffer::bcm_chunk_bytes(), expected_size);
1147 assert_eq!(TestFrameBuffer::bcm_chunk_count(), 1);
1148 }
1149
1150 #[test]
1151 fn test_dma_framebuffer_erase() {
1152 let fb = TestFrameBuffer::new();
1153
1154 for frame in &fb.frames {
1156 for addr in 0..TEST_NROWS {
1157 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1158
1159 let row = &frame.rows[addr];
1161
1162 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1164 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1165 assert_eq!(row.data[last_pixel_idx].latch(), true);
1166
1167 let first_pixel_idx = get_mapped_index(0);
1169 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1170 assert_eq!(row.data[first_pixel_idx].latch(), false);
1171 }
1172 }
1173 }
1174
1175 #[test]
1176 fn test_dma_framebuffer_set_pixel_bounds() {
1177 let mut fb = TestFrameBuffer::new();
1178
1179 fb.set_pixel(Point::new(-1, 5), Color::RED);
1181 fb.set_pixel(Point::new(5, -1), Color::RED);
1182
1183 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1185 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1186 }
1187
1188 #[test]
1189 fn test_dma_framebuffer_set_pixel_internal() {
1190 let mut fb = TestFrameBuffer::new();
1191
1192 let red_color = Color::RED;
1193 fb.set_pixel_internal(10, 5, red_color);
1194
1195 for frame in &fb.frames {
1199 let mapped_col_10 = get_mapped_index(10);
1201 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1202 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1203 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1204 }
1205 }
1206
1207 #[test]
1208 fn test_dma_framebuffer_brightness_modulation() {
1209 let mut fb = TestFrameBuffer::new();
1210
1211 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Color::from(embedded_graphics::pixelcolor::Rgb888::new(
1215 test_brightness,
1216 0,
1217 0,
1218 ));
1219
1220 fb.set_pixel_internal(0, 0, color);
1221
1222 for (frame_idx, frame) in fb.frames.iter().enumerate() {
1225 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1226 let should_be_active = test_brightness >= frame_threshold;
1227
1228 let mapped_col_0 = get_mapped_index(0);
1229 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1230 }
1231 }
1232
1233 #[test]
1234 fn test_origin_dimensions() {
1235 let fb = TestFrameBuffer::new();
1236 let size = fb.size();
1237 assert_eq!(size.width, TEST_COLS as u32);
1238 assert_eq!(size.height, TEST_ROWS as u32);
1239
1240 let size = (&fb).size();
1242 assert_eq!(size.width, TEST_COLS as u32);
1243 assert_eq!(size.height, TEST_ROWS as u32);
1244
1245 let mut fb = TestFrameBuffer::new();
1247 let fb_ref = &mut fb;
1248 let size = fb_ref.size();
1249 assert_eq!(size.width, TEST_COLS as u32);
1250 assert_eq!(size.height, TEST_ROWS as u32);
1251 }
1252
1253 #[test]
1254 fn test_draw_target() {
1255 let mut fb = TestFrameBuffer::new();
1256
1257 let pixels = vec![
1258 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1259 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1260 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1261 ];
1262
1263 let result = fb.draw_iter(pixels);
1264 assert!(result.is_ok());
1265
1266 let result = (&mut fb).draw_iter(vec![embedded_graphics::Pixel(
1268 Point::new(3, 3),
1269 Color::WHITE,
1270 )]);
1271 assert!(result.is_ok());
1272 }
1273
1274 #[test]
1275 fn test_draw_iter_pixel_verification() {
1276 let mut fb = TestFrameBuffer::new();
1277
1278 let pixels = vec![
1280 embedded_graphics::Pixel(Point::new(5, 2), Color::RED), embedded_graphics::Pixel(Point::new(10, 5), Color::GREEN), embedded_graphics::Pixel(Point::new(15, 8), Color::BLUE), embedded_graphics::Pixel(Point::new(20, 10), Color::WHITE), embedded_graphics::Pixel(Point::new(25, (TEST_NROWS + 3) as i32), Color::RED), embedded_graphics::Pixel(Point::new(30, (TEST_NROWS + 7) as i32), Color::GREEN), embedded_graphics::Pixel(Point::new(35, (TEST_NROWS + 12) as i32), Color::BLUE), embedded_graphics::Pixel(Point::new(40, 1), Color::BLACK), ];
1292
1293 let result = fb.draw_iter(pixels);
1294 assert!(result.is_ok());
1295
1296 let first_frame = &fb.frames[0];
1298 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = get_mapped_index(5);
1304 assert_eq!(
1305 first_frame.rows[2].data[col_idx].red1(),
1306 Color::RED.r() >= first_frame_threshold
1307 );
1308 assert_eq!(
1309 first_frame.rows[2].data[col_idx].grn1(),
1310 Color::RED.g() >= first_frame_threshold
1311 );
1312 assert_eq!(
1313 first_frame.rows[2].data[col_idx].blu1(),
1314 Color::RED.b() >= first_frame_threshold
1315 );
1316
1317 let col_idx = get_mapped_index(10);
1319 assert_eq!(
1320 first_frame.rows[5].data[col_idx].red1(),
1321 Color::GREEN.r() >= first_frame_threshold
1322 );
1323 assert_eq!(
1324 first_frame.rows[5].data[col_idx].grn1(),
1325 Color::GREEN.g() >= first_frame_threshold
1326 );
1327 assert_eq!(
1328 first_frame.rows[5].data[col_idx].blu1(),
1329 Color::GREEN.b() >= first_frame_threshold
1330 );
1331
1332 let col_idx = get_mapped_index(15);
1334 assert_eq!(
1335 first_frame.rows[8].data[col_idx].red1(),
1336 Color::BLUE.r() >= first_frame_threshold
1337 );
1338 assert_eq!(
1339 first_frame.rows[8].data[col_idx].grn1(),
1340 Color::BLUE.g() >= first_frame_threshold
1341 );
1342 assert_eq!(
1343 first_frame.rows[8].data[col_idx].blu1(),
1344 Color::BLUE.b() >= first_frame_threshold
1345 );
1346
1347 let col_idx = get_mapped_index(20);
1349 assert_eq!(
1350 first_frame.rows[10].data[col_idx].red1(),
1351 Color::WHITE.r() >= first_frame_threshold
1352 );
1353 assert_eq!(
1354 first_frame.rows[10].data[col_idx].grn1(),
1355 Color::WHITE.g() >= first_frame_threshold
1356 );
1357 assert_eq!(
1358 first_frame.rows[10].data[col_idx].blu1(),
1359 Color::WHITE.b() >= first_frame_threshold
1360 );
1361
1362 let col_idx = get_mapped_index(25);
1365 assert_eq!(
1366 first_frame.rows[3].data[col_idx].red2(),
1367 Color::RED.r() >= first_frame_threshold
1368 );
1369 assert_eq!(
1370 first_frame.rows[3].data[col_idx].grn2(),
1371 Color::RED.g() >= first_frame_threshold
1372 );
1373 assert_eq!(
1374 first_frame.rows[3].data[col_idx].blu2(),
1375 Color::RED.b() >= first_frame_threshold
1376 );
1377
1378 let col_idx = get_mapped_index(30);
1380 assert_eq!(
1381 first_frame.rows[7].data[col_idx].red2(),
1382 Color::GREEN.r() >= first_frame_threshold
1383 );
1384 assert_eq!(
1385 first_frame.rows[7].data[col_idx].grn2(),
1386 Color::GREEN.g() >= first_frame_threshold
1387 );
1388 assert_eq!(
1389 first_frame.rows[7].data[col_idx].blu2(),
1390 Color::GREEN.b() >= first_frame_threshold
1391 );
1392
1393 let col_idx = get_mapped_index(35);
1395 assert_eq!(
1396 first_frame.rows[12].data[col_idx].red2(),
1397 Color::BLUE.r() >= first_frame_threshold
1398 );
1399 assert_eq!(
1400 first_frame.rows[12].data[col_idx].grn2(),
1401 Color::BLUE.g() >= first_frame_threshold
1402 );
1403 assert_eq!(
1404 first_frame.rows[12].data[col_idx].blu2(),
1405 Color::BLUE.b() >= first_frame_threshold
1406 );
1407
1408 let col_idx = get_mapped_index(40);
1410 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1411 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1412 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1413 }
1414
1415 #[test]
1416 fn test_embedded_graphics_integration() {
1417 let mut fb = TestFrameBuffer::new();
1418
1419 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1421 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1422 .draw(&mut fb);
1423 assert!(result.is_ok());
1424
1425 let result = Circle::new(Point::new(30, 15), 8)
1427 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1428 .draw(&mut fb);
1429 assert!(result.is_ok());
1430 }
1431
1432 #[test]
1433 #[cfg(feature = "skip-black-pixels")]
1434 fn test_skip_black_pixels_enabled() {
1435 let mut fb = TestFrameBuffer::new();
1436
1437 fb.set_pixel_internal(10, 5, Color::RED);
1439
1440 let mapped_col_10 = get_mapped_index(10);
1442 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1443 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1444 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1445
1446 fb.set_pixel_internal(10, 5, Color::BLACK);
1448
1449 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1451 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1452 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1453 }
1454
1455 #[test]
1456 #[cfg(not(feature = "skip-black-pixels"))]
1457 fn test_skip_black_pixels_disabled() {
1458 let mut fb = TestFrameBuffer::new();
1459
1460 fb.set_pixel_internal(10, 5, Color::RED);
1462
1463 let mapped_col_10 = get_mapped_index(10);
1465 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1466 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1467 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1468
1469 fb.set_pixel_internal(10, 5, Color::BLACK);
1471
1472 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1474 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1475 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1476 }
1477
1478 #[test]
1479 fn test_bcm_frame_overwrite() {
1480 let mut fb = TestFrameBuffer::new();
1481
1482 fb.set_pixel_internal(10, 5, Color::WHITE);
1484
1485 let mapped_col_10 = get_mapped_index(10);
1486
1487 for frame in fb.frames.iter() {
1489 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1491 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1492 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1493 }
1494
1495 let half_white = Color::from(embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128));
1497 fb.set_pixel_internal(10, 5, half_white);
1498
1499 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.frames.iter().enumerate() {
1505 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1506 let should_be_active = 128 >= frame_threshold;
1507
1508 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1509 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1510 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1511 }
1512
1513 for frame_idx in 0..4 {
1516 assert_eq!(
1517 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1518 true
1519 );
1520 }
1521 for frame_idx in 4..TEST_FRAME_COUNT {
1523 assert_eq!(
1524 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1525 false
1526 );
1527 }
1528 }
1529
1530 #[test]
1531 fn test_read_buffer_implementation() {
1532 let fb = TestFrameBuffer::new();
1534 let expected_size = core::mem::size_of_val(&fb.frames);
1535
1536 unsafe {
1538 let (ptr, len) = <TestFrameBuffer as ReadBuffer>::read_buffer(&fb);
1539 assert!(!ptr.is_null());
1540 assert_eq!(len, expected_size);
1541 }
1542
1543 unsafe {
1545 let (ptr, len) = fb.read_buffer();
1546 assert!(!ptr.is_null());
1547 assert_eq!(len, expected_size);
1548 }
1549
1550 let fb = TestFrameBuffer::new();
1552 let fb_ref = &fb;
1553 unsafe {
1554 let (ptr, len) = fb_ref.read_buffer();
1555 assert!(!ptr.is_null());
1556 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1557 }
1558
1559 let mut fb = TestFrameBuffer::new();
1561 let fb_ref = &mut fb;
1562 unsafe {
1563 let (ptr, len) = fb_ref.read_buffer();
1564 assert!(!ptr.is_null());
1565 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1566 }
1567 }
1568
1569 #[test]
1570 fn test_read_buffer_owned_implementation() {
1571 fn test_owned_read_buffer(fb: TestFrameBuffer) -> (bool, usize) {
1574 unsafe {
1575 let (ptr, len) = fb.read_buffer();
1576 (!ptr.is_null(), len)
1577 }
1578 }
1579
1580 let fb = TestFrameBuffer::new();
1581 let expected_len = core::mem::size_of_val(&fb.frames);
1582
1583 let (ptr_valid, actual_len) = test_owned_read_buffer(fb);
1584 assert!(ptr_valid);
1585 assert_eq!(actual_len, expected_len);
1586 }
1587
1588 #[test]
1589 fn test_framebuffer_trait() {
1590 let fb = TestFrameBuffer::new();
1591 assert_eq!(fb.get_word_size(), WordSize::Sixteen);
1592
1593 let fb_ref = &fb;
1594 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1595
1596 let mut fb = TestFrameBuffer::new();
1597 let fb_ref = &mut fb;
1598 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1599 }
1600
1601 #[test]
1602 fn test_debug_formatting() {
1603 let fb = TestFrameBuffer::new();
1604 let debug_string = format!("{:?}", fb);
1605 assert!(debug_string.contains("DmaFrameBuffer"));
1606 assert!(debug_string.contains("frame_count"));
1607 assert!(debug_string.contains("frame_size"));
1608 assert!(debug_string.contains("brightness_step"));
1609 }
1610
1611 #[test]
1612 fn test_default_implementation() {
1613 let fb1 = TestFrameBuffer::new();
1614 let fb2 = TestFrameBuffer::default();
1615
1616 assert_eq!(fb1.frames.len(), fb2.frames.len());
1618 assert_eq!(fb1._align, fb2._align);
1619 }
1620
1621 #[test]
1622 fn test_memory_alignment() {
1623 let fb = TestFrameBuffer::new();
1624 let ptr = &fb as *const _ as usize;
1625
1626 assert_eq!(ptr % 8, 0);
1628 }
1629
1630 #[test]
1631 fn test_color_values() {
1632 let mut fb = TestFrameBuffer::new();
1633
1634 let colors = [
1636 (Color::RED, (255, 0, 0)),
1637 (Color::GREEN, (0, 255, 0)),
1638 (Color::BLUE, (0, 0, 255)),
1639 (Color::WHITE, (255, 255, 255)),
1640 (Color::BLACK, (0, 0, 0)),
1641 ];
1642
1643 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1644 fb.set_pixel(Point::new(i as i32, 0), *color);
1645 assert_eq!(color.r(), *r);
1646 assert_eq!(color.g(), *g);
1647 assert_eq!(color.b(), *b);
1648 }
1649 }
1650
1651 #[test]
1652 fn test_blanking_delay() {
1653 let mut row: Row<TEST_COLS> = Row::new();
1654 let test_addr = 5;
1655 let prev_addr = 4;
1656
1657 row.format(test_addr, prev_addr);
1658
1659 let blanking_pixel_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 1);
1661 assert_eq!(row.data[blanking_pixel_idx].output_enable(), false);
1662
1663 let before_blanking_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 2);
1665 assert_eq!(row.data[before_blanking_idx].output_enable(), true);
1666 }
1667
1668 #[test]
1669 fn test_esp32_mapping() {
1670 #[cfg(feature = "esp32-ordering")]
1672 {
1673 assert_eq!(map_index(0), 1);
1674 assert_eq!(map_index(1), 0);
1675 assert_eq!(map_index(2), 3);
1676 assert_eq!(map_index(3), 2);
1677 assert_eq!(map_index(4), 5);
1678 assert_eq!(map_index(5), 4);
1679 }
1680 #[cfg(not(feature = "esp32-ordering"))]
1681 {
1682 assert_eq!(map_index(0), 0);
1683 assert_eq!(map_index(1), 1);
1684 assert_eq!(map_index(2), 2);
1685 assert_eq!(map_index(3), 3);
1686 }
1687 }
1688
1689 #[test]
1690 fn test_bits_assertion() {
1691 assert!(TEST_BITS <= 8);
1694 }
1695
1696 #[test]
1697 fn test_fast_clear_method() {
1698 let mut fb = TestFrameBuffer::new();
1699
1700 fb.set_pixel_internal(10, 5, Color::RED);
1702 fb.set_pixel_internal(20, 10, Color::GREEN);
1703
1704 let mapped_col_10 = get_mapped_index(10);
1706 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1707
1708 fb.erase();
1710
1711 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1713 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1714 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1715
1716 let last_col = get_mapped_index(TEST_COLS - 1);
1718 assert_eq!(fb.frames[0].rows[5].data[last_col].latch(), true);
1719 }
1720
1721 const CHAR_W: i32 = 6;
1725 const CHAR_H: i32 = 10;
1726
1727 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1729 use embedded_graphics::mock_display::MockDisplay;
1730 use embedded_graphics::mono_font::ascii::FONT_6X10;
1731 use embedded_graphics::mono_font::MonoTextStyle;
1732 use embedded_graphics::text::{Baseline, Text};
1733
1734 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1736 Text::with_baseline("A", origin, style, Baseline::Top)
1737 .draw(fb)
1738 .unwrap();
1739
1740 let mut reference: MockDisplay<Color> = MockDisplay::new();
1742 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1743 .draw(&mut reference)
1744 .unwrap();
1745
1746 for dy in 0..CHAR_H {
1747 for dx in 0..CHAR_W {
1748 let expected_on = reference
1749 .get_pixel(Point::new(dx, dy))
1750 .unwrap_or(Color::BLACK)
1751 != Color::BLACK;
1752
1753 let gx = (origin.x + dx) as usize;
1754 let gy = (origin.y + dy) as usize;
1755
1756 let frame0 = &fb.frames[0];
1763 let e = if gy < TEST_NROWS {
1764 &frame0.rows[gy].data[get_mapped_index(gx)]
1765 } else {
1766 &frame0.rows[gy - TEST_NROWS].data[get_mapped_index(gx)]
1767 };
1768
1769 let (r, g, b) = if gy >= TEST_NROWS {
1770 (e.red2(), e.grn2(), e.blu2())
1771 } else {
1772 (e.red1(), e.grn1(), e.blu1())
1773 };
1774
1775 if expected_on {
1776 assert!(r && g && b,);
1777 } else {
1778 assert!(!r && !g && !b);
1779 }
1780 }
1781 }
1782 }
1783
1784 #[test]
1785 fn test_draw_char_corners() {
1786 let upper_left = Point::new(0, 0);
1787 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1788
1789 let mut fb = TestFrameBuffer::new();
1790
1791 verify_glyph_at(&mut fb, upper_left);
1792 verify_glyph_at(&mut fb, lower_right);
1793 }
1794
1795 #[test]
1796 fn test_framebuffer_operations_trait_erase() {
1797 let mut fb = TestFrameBuffer::new();
1798
1799 fb.set_pixel_internal(10, 5, Color::RED);
1801 fb.set_pixel_internal(20, 10, Color::GREEN);
1802
1803 <TestFrameBuffer as FrameBufferOperations>::erase(&mut fb);
1805
1806 let mc10 = get_mapped_index(10);
1808 let mc20 = get_mapped_index(20);
1809 assert_eq!(fb.frames[0].rows[5].data[mc10].red1(), false);
1810 assert_eq!(fb.frames[0].rows[10].data[mc20].grn1(), false);
1811
1812 let last_col = get_mapped_index(TEST_COLS - 1);
1814 assert!(fb.frames[0].rows[0].data[last_col].latch());
1815 }
1816
1817 #[test]
1818 fn test_framebuffer_operations_trait_set_pixel() {
1819 let mut fb = TestFrameBuffer::new();
1820
1821 <TestFrameBuffer as FrameBufferOperations>::set_pixel(
1823 &mut fb,
1824 Point::new(8, 3),
1825 Color::BLUE,
1826 );
1827
1828 let idx = get_mapped_index(8);
1829 assert_eq!(fb.frames[0].rows[3].data[idx].blu1(), true);
1830 assert_eq!(fb.frames[0].rows[3].data[idx].red1(), false);
1831 assert_eq!(fb.frames[0].rows[3].data[idx].grn1(), false);
1832 }
1833}