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
144#[cfg(feature = "blank-delay-1")]
145const BLANKING_DELAY: usize = 1;
146#[cfg(feature = "blank-delay-2")]
147const BLANKING_DELAY: usize = 2;
148#[cfg(feature = "blank-delay-4")]
149const BLANKING_DELAY: usize = 4;
150#[cfg(feature = "blank-delay-8")]
151const BLANKING_DELAY: usize = 8;
152
153#[cfg(not(any(
155 feature = "blank-delay-1",
156 feature = "blank-delay-2",
157 feature = "blank-delay-4",
158 feature = "blank-delay-8"
159)))]
160const BLANKING_DELAY: usize = 1;
161
162#[inline]
165const fn make_data_template<const COLS: usize>(addr: u8, prev_addr: u8) -> [Entry; COLS] {
166 let mut data = [Entry::new(); COLS];
167 let mut i = 0;
168
169 while i < COLS {
170 let mut entry = Entry::new();
171 entry.0 = prev_addr as u16;
172
173 if i == 1 {
175 entry.0 |= 0b1_0000_0000; } else if i == COLS - BLANKING_DELAY - 1 {
177 } else if i == COLS - 1 {
179 entry.0 |= 0b0010_0000; entry.0 = (entry.0 & !0b0001_1111) | (addr as u16); } else if i > 1 && i < COLS - BLANKING_DELAY - 1 {
182 entry.0 |= 0b1_0000_0000; }
184
185 data[map_index(i)] = entry;
186 i += 1;
187 }
188
189 data
190}
191
192bitfield! {
193 #[derive(Clone, Copy, Default, PartialEq)]
214 #[repr(transparent)]
215 struct Entry(u16);
216 dummy2, set_dummy2: 15;
217 blu2, set_blu2: 14;
218 grn2, set_grn2: 13;
219 red2, set_red2: 12;
220 blu1, set_blu1: 11;
221 grn1, set_grn1: 10;
222 red1, set_red1: 9;
223 output_enable, set_output_enable: 8;
224 dummy1, set_dummy1: 7;
225 dummy0, set_dummy0: 6;
226 latch, set_latch: 5;
227 addr, set_addr: 4, 0;
228}
229
230impl core::fmt::Debug for Entry {
231 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
232 f.debug_tuple("Entry")
233 .field(&format_args!("{:#x}", self.0))
234 .finish()
235 }
236}
237
238#[cfg(feature = "defmt")]
239impl defmt::Format for Entry {
240 fn format(&self, f: defmt::Formatter) {
241 defmt::write!(f, "Entry({=u16:#x})", self.0);
242 }
243}
244
245impl Entry {
246 const fn new() -> Self {
247 Self(0)
248 }
249
250 const COLOR0_MASK: u16 = 0b0000_1110_0000_0000; const COLOR1_MASK: u16 = 0b0111_0000_0000_0000; #[inline]
255 fn set_color0_bits(&mut self, bits: u8) {
256 let bits16 = u16::from(bits) << 9;
257 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits16 & Self::COLOR0_MASK);
258 }
259
260 #[inline]
261 fn set_color1_bits(&mut self, bits: u8) {
262 let bits16 = u16::from(bits) << 12;
263 self.0 = (self.0 & !Self::COLOR1_MASK) | (bits16 & Self::COLOR1_MASK);
264 }
265}
266
267#[derive(Clone, Copy, PartialEq, Debug)]
276#[repr(C)]
277struct Row<const COLS: usize> {
278 data: [Entry; COLS],
279}
280
281const fn map_index(i: usize) -> usize {
282 #[cfg(feature = "esp32-ordering")]
283 {
284 i ^ 1
285 }
286 #[cfg(not(feature = "esp32-ordering"))]
287 {
288 i
289 }
290}
291
292impl<const COLS: usize> Default for Row<COLS> {
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298impl<const COLS: usize> Row<COLS> {
299 pub const fn new() -> Self {
300 Self {
301 data: [Entry::new(); COLS],
302 }
303 }
304
305 pub fn format(&mut self, addr: u8, prev_addr: u8) {
306 let template = make_data_template::<COLS>(addr, prev_addr);
308 self.data.copy_from_slice(&template);
309 }
310
311 #[inline]
314 pub fn clear_colors(&mut self) {
315 const COLOR_CLEAR_MASK: u16 = !0b0111_1110_0000_0000; for entry in &mut self.data {
319 entry.0 &= COLOR_CLEAR_MASK;
320 }
321 }
322
323 #[inline]
324 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
325 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
326 let col = map_index(col);
327 self.data[col].set_color0_bits(bits);
328 }
329
330 #[inline]
331 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
332 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
333 let col = map_index(col);
334 self.data[col].set_color1_bits(bits);
335 }
336}
337
338#[derive(Copy, Clone, Debug)]
339#[repr(C)]
340struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
341 rows: [Row<COLS>; NROWS],
342}
343
344impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
345 pub const fn new() -> Self {
346 Self {
347 rows: [Row::new(); NROWS],
348 }
349 }
350
351 pub fn format(&mut self) {
352 for (addr, row) in self.rows.iter_mut().enumerate() {
353 let prev_addr = if addr == 0 {
354 NROWS as u8 - 1
355 } else {
356 addr as u8 - 1
357 };
358 row.format(addr as u8, prev_addr);
359 }
360 }
361
362 #[inline]
364 pub fn clear_colors(&mut self) {
365 for row in &mut self.rows {
366 row.clear_colors();
367 }
368 }
369
370 #[inline]
371 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
372 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
373 if y < NROWS {
374 row.set_color0(x, red, green, blue);
375 } else {
376 row.set_color1(x, red, green, blue);
377 }
378 }
379}
380
381impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
382 for Frame<ROWS, COLS, NROWS>
383{
384 fn default() -> Self {
385 Self::new()
386 }
387}
388
389#[derive(Copy, Clone)]
414#[repr(C)]
415pub struct DmaFrameBuffer<
416 const ROWS: usize,
417 const COLS: usize,
418 const NROWS: usize,
419 const BITS: u8,
420 const FRAME_COUNT: usize,
421> {
422 _align: u64,
423 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
424}
425
426impl<
427 const ROWS: usize,
428 const COLS: usize,
429 const NROWS: usize,
430 const BITS: u8,
431 const FRAME_COUNT: usize,
432 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
433{
434 fn default() -> Self {
435 Self::new()
436 }
437}
438
439impl<
440 const ROWS: usize,
441 const COLS: usize,
442 const NROWS: usize,
443 const BITS: u8,
444 const FRAME_COUNT: usize,
445 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
446{
447 #[must_use]
470 pub fn new() -> Self {
471 debug_assert!(BITS <= 8);
472
473 let mut instance = Self {
474 _align: 0,
475 frames: [Frame::new(); FRAME_COUNT],
476 };
477
478 instance.format();
480 instance
481 }
482
483 #[must_use]
486 pub const fn bcm_chunk_count() -> usize {
487 1
488 }
489
490 #[must_use]
493 pub const fn bcm_chunk_bytes() -> usize {
494 core::mem::size_of::<[Frame<ROWS, COLS, NROWS>; FRAME_COUNT]>()
495 }
496
497 #[inline]
517 pub fn format(&mut self) {
518 for frame in &mut self.frames {
519 frame.format();
520 }
521 }
522
523 #[inline]
543 pub fn erase(&mut self) {
544 for frame in &mut self.frames {
545 frame.clear_colors();
546 }
547 }
548
549 pub fn set_pixel(&mut self, p: Point, color: Color) {
565 if p.x < 0 || p.y < 0 {
566 return;
567 }
568 self.set_pixel_internal(p.x as usize, p.y as usize, color);
569 }
570
571 #[inline]
572 fn frames_on(v: u8) -> usize {
573 (v as usize) >> (8 - BITS)
575 }
576
577 #[inline]
578 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Color) {
579 if x >= COLS || y >= ROWS {
580 return;
581 }
582
583 #[cfg(feature = "skip-black-pixels")]
586 if color == Color::BLACK {
587 return;
588 }
589
590 let red_frames = Self::frames_on(color.r());
592 let green_frames = Self::frames_on(color.g());
593 let blue_frames = Self::frames_on(color.b());
594
595 for (frame_idx, frame) in self.frames.iter_mut().enumerate() {
597 frame.set_pixel(
598 y,
599 x,
600 frame_idx < red_frames,
601 frame_idx < green_frames,
602 frame_idx < blue_frames,
603 );
604 }
605 }
606}
607
608impl<
609 const ROWS: usize,
610 const COLS: usize,
611 const NROWS: usize,
612 const BITS: u8,
613 const FRAME_COUNT: usize,
614 > FrameBufferOperations for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
615{
616 #[inline]
617 fn erase(&mut self) {
618 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
619 }
620
621 #[inline]
622 fn set_pixel(&mut self, p: Point, color: Color) {
623 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
624 }
625}
626
627impl<
628 const ROWS: usize,
629 const COLS: usize,
630 const NROWS: usize,
631 const BITS: u8,
632 const FRAME_COUNT: usize,
633 > embedded_graphics::prelude::OriginDimensions
634 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
635{
636 fn size(&self) -> embedded_graphics::prelude::Size {
637 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
638 }
639}
640
641impl<
642 const ROWS: usize,
643 const COLS: usize,
644 const NROWS: usize,
645 const BITS: u8,
646 const FRAME_COUNT: usize,
647 > embedded_graphics::prelude::OriginDimensions
648 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
649{
650 fn size(&self) -> embedded_graphics::prelude::Size {
651 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
652 }
653}
654
655impl<
656 const ROWS: usize,
657 const COLS: usize,
658 const NROWS: usize,
659 const BITS: u8,
660 const FRAME_COUNT: usize,
661 > embedded_graphics::draw_target::DrawTarget
662 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
663{
664 type Color = Color;
665
666 type Error = Infallible;
667
668 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
669 where
670 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
671 {
672 for pixel in pixels {
673 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
674 }
675 Ok(())
676 }
677}
678
679unsafe impl<
680 const ROWS: usize,
681 const COLS: usize,
682 const NROWS: usize,
683 const BITS: u8,
684 const FRAME_COUNT: usize,
685 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
686{
687 type Word = u8;
688
689 unsafe fn read_buffer(&self) -> (*const u8, usize) {
690 let ptr = (&raw const self.frames).cast::<u8>();
691 let len = core::mem::size_of_val(&self.frames);
692 (ptr, len)
693 }
694}
695
696unsafe impl<
697 const ROWS: usize,
698 const COLS: usize,
699 const NROWS: usize,
700 const BITS: u8,
701 const FRAME_COUNT: usize,
702 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
703{
704 type Word = u8;
705
706 unsafe fn read_buffer(&self) -> (*const u8, usize) {
707 let ptr = (&raw const self.frames).cast::<u8>();
708 let len = core::mem::size_of_val(&self.frames);
709 (ptr, len)
710 }
711}
712
713impl<
714 const ROWS: usize,
715 const COLS: usize,
716 const NROWS: usize,
717 const BITS: u8,
718 const FRAME_COUNT: usize,
719 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
720{
721 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
722 let brightness_step = 1 << (8 - BITS);
723 f.debug_struct("DmaFrameBuffer")
724 .field("size", &core::mem::size_of_val(&self.frames))
725 .field("frame_count", &self.frames.len())
726 .field("frame_size", &core::mem::size_of_val(&self.frames[0]))
727 .field("brightness_step", &&brightness_step)
728 .finish_non_exhaustive()
729 }
730}
731
732#[cfg(feature = "defmt")]
733impl<
734 const ROWS: usize,
735 const COLS: usize,
736 const NROWS: usize,
737 const BITS: u8,
738 const FRAME_COUNT: usize,
739 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
740{
741 fn format(&self, f: defmt::Formatter) {
742 let brightness_step = 1 << (8 - BITS);
743 defmt::write!(
744 f,
745 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
746 ROWS,
747 COLS,
748 NROWS,
749 BITS,
750 FRAME_COUNT
751 );
752 defmt::write!(f, " size: {}", core::mem::size_of_val(&self.frames));
753 defmt::write!(
754 f,
755 " frame_size: {}",
756 core::mem::size_of_val(&self.frames[0])
757 );
758 defmt::write!(f, " brightness_step: {}", brightness_step);
759 }
760}
761
762impl<
763 const ROWS: usize,
764 const COLS: usize,
765 const NROWS: usize,
766 const BITS: u8,
767 const FRAME_COUNT: usize,
768 > FrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
769{
770 fn get_word_size(&self) -> WordSize {
771 WordSize::Sixteen
772 }
773
774 fn plane_count(&self) -> usize {
775 1
776 }
777
778 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
779 assert!(plane_idx == 0, "plain DmaFrameBuffer has only 1 plane");
780 let ptr = (&raw const self.frames).cast::<u8>();
781 let len = core::mem::size_of_val(&self.frames);
782 (ptr, len)
783 }
784}
785
786impl<
787 const ROWS: usize,
788 const COLS: usize,
789 const NROWS: usize,
790 const BITS: u8,
791 const FRAME_COUNT: usize,
792 > FrameBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
793{
794 fn get_word_size(&self) -> WordSize {
795 WordSize::Sixteen
796 }
797
798 fn plane_count(&self) -> usize {
799 1
800 }
801
802 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
803 assert!(plane_idx == 0, "plain DmaFrameBuffer has only 1 plane");
804 let ptr = (&raw const self.frames).cast::<u8>();
805 let len = core::mem::size_of_val(&self.frames);
806 (ptr, len)
807 }
808}
809
810impl<
811 const ROWS: usize,
812 const COLS: usize,
813 const NROWS: usize,
814 const BITS: u8,
815 const FRAME_COUNT: usize,
816 > MutableFrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
817{
818}
819
820#[cfg(test)]
821mod tests {
822 extern crate std;
823
824 use std::format;
825 use std::vec;
826
827 use super::*;
828 use crate::{FrameBuffer, WordSize};
829 use embedded_graphics::pixelcolor::RgbColor;
830 use embedded_graphics::prelude::*;
831 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
832
833 const TEST_ROWS: usize = 32;
834 const TEST_COLS: usize = 64;
835 const TEST_NROWS: usize = TEST_ROWS / 2;
836 const TEST_BITS: u8 = 3;
837 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
840 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
841
842 fn get_mapped_index(index: usize) -> usize {
844 map_index(index)
845 }
846
847 #[test]
848 fn test_entry_construction() {
849 let entry = Entry::new();
850 assert_eq!(entry.0, 0);
851 assert_eq!(entry.dummy2(), false);
852 assert_eq!(entry.blu2(), false);
853 assert_eq!(entry.grn2(), false);
854 assert_eq!(entry.red2(), false);
855 assert_eq!(entry.blu1(), false);
856 assert_eq!(entry.grn1(), false);
857 assert_eq!(entry.red1(), false);
858 assert_eq!(entry.output_enable(), false);
859 assert_eq!(entry.dummy1(), false);
860 assert_eq!(entry.dummy0(), false);
861 assert_eq!(entry.latch(), false);
862 assert_eq!(entry.addr(), 0);
863 }
864
865 #[test]
866 fn test_entry_setters() {
867 let mut entry = Entry::new();
868
869 entry.set_dummy2(true);
870 assert_eq!(entry.dummy2(), true);
871 assert_eq!(entry.0 & 0b1000000000000000, 0b1000000000000000);
872
873 entry.set_blu2(true);
874 assert_eq!(entry.blu2(), true);
875 assert_eq!(entry.0 & 0b0100000000000000, 0b0100000000000000);
876
877 entry.set_grn2(true);
878 assert_eq!(entry.grn2(), true);
879 assert_eq!(entry.0 & 0b0010000000000000, 0b0010000000000000);
880
881 entry.set_red2(true);
882 assert_eq!(entry.red2(), true);
883 assert_eq!(entry.0 & 0b0001000000000000, 0b0001000000000000);
884
885 entry.set_blu1(true);
886 assert_eq!(entry.blu1(), true);
887 assert_eq!(entry.0 & 0b0000100000000000, 0b0000100000000000);
888
889 entry.set_grn1(true);
890 assert_eq!(entry.grn1(), true);
891 assert_eq!(entry.0 & 0b0000010000000000, 0b0000010000000000);
892
893 entry.set_red1(true);
894 assert_eq!(entry.red1(), true);
895 assert_eq!(entry.0 & 0b0000001000000000, 0b0000001000000000);
896
897 entry.set_output_enable(true);
898 assert_eq!(entry.output_enable(), true);
899 assert_eq!(entry.0 & 0b0000000100000000, 0b0000000100000000);
900
901 entry.set_dummy1(true);
902 assert_eq!(entry.dummy1(), true);
903 assert_eq!(entry.0 & 0b0000000010000000, 0b0000000010000000);
904
905 entry.set_dummy0(true);
906 assert_eq!(entry.dummy0(), true);
907 assert_eq!(entry.0 & 0b0000000001000000, 0b0000000001000000);
908
909 entry.set_latch(true);
910 assert_eq!(entry.latch(), true);
911 assert_eq!(entry.0 & 0b0000000000100000, 0b0000000000100000);
912
913 entry.set_addr(0b11111);
914 assert_eq!(entry.addr(), 0b11111);
915 assert_eq!(entry.0 & 0b0000000000011111, 0b0000000000011111);
916 }
917
918 #[test]
919 fn test_entry_bit_isolation() {
920 let mut entry = Entry::new();
921
922 entry.set_addr(0b11111);
924 entry.set_latch(true);
925 assert_eq!(entry.addr(), 0b11111);
926 assert_eq!(entry.latch(), true);
927 assert_eq!(entry.output_enable(), false);
928 assert_eq!(entry.red1(), false);
929
930 entry.set_red1(true);
931 entry.set_grn2(true);
932 assert_eq!(entry.addr(), 0b11111);
933 assert_eq!(entry.latch(), true);
934 assert_eq!(entry.red1(), true);
935 assert_eq!(entry.grn2(), true);
936 assert_eq!(entry.blu1(), false);
937 assert_eq!(entry.red2(), false);
938 }
939
940 #[test]
941 fn test_entry_set_color0() {
942 let mut entry = Entry::new();
943
944 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
946 assert_eq!(entry.red1(), true);
947 assert_eq!(entry.grn1(), false);
948 assert_eq!(entry.blu1(), true);
949 assert_eq!(entry.0 & 0b0000101000000000, 0b0000101000000000); }
952
953 #[test]
954 fn test_entry_set_color1() {
955 let mut entry = Entry::new();
956
957 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
959 assert_eq!(entry.red2(), false);
960 assert_eq!(entry.grn2(), true);
961 assert_eq!(entry.blu2(), true);
962 assert_eq!(entry.0 & 0b0110000000000000, 0b0110000000000000); }
965
966 #[test]
967 fn test_entry_debug_formatting() {
968 let entry = Entry(0x1234);
969 let debug_str = format!("{:?}", entry);
970 assert_eq!(debug_str, "Entry(0x1234)");
971
972 let entry = Entry(0xabcd);
973 let debug_str = format!("{:?}", entry);
974 assert_eq!(debug_str, "Entry(0xabcd)");
975 }
976
977 #[test]
978 fn test_row_construction() {
979 let row: Row<TEST_COLS> = Row::new();
980 assert_eq!(row.data.len(), TEST_COLS);
981
982 for entry in &row.data {
984 assert_eq!(entry.0, 0);
985 }
986 }
987
988 #[test]
989 fn test_row_format() {
990 let mut row: Row<TEST_COLS> = Row::new();
991 let test_addr = 5;
992 let prev_addr = 4;
993
994 row.format(test_addr, prev_addr);
995
996 for (physical_i, entry) in row.data.iter().enumerate() {
998 let logical_i = get_mapped_index(physical_i);
999
1000 match logical_i {
1001 i if i == TEST_COLS - BLANKING_DELAY - 1 => {
1002 assert_eq!(entry.output_enable(), false);
1004 assert_eq!(entry.addr(), prev_addr as u16);
1005 assert_eq!(entry.latch(), false);
1006 }
1007 i if i == TEST_COLS - 1 => {
1008 assert_eq!(entry.latch(), true);
1010 assert_eq!(entry.addr(), test_addr as u16);
1011 assert_eq!(entry.output_enable(), false);
1012 }
1013 1 => {
1014 assert_eq!(entry.output_enable(), true);
1016 assert_eq!(entry.addr(), prev_addr as u16);
1017 assert_eq!(entry.latch(), false);
1018 }
1019 _ => {
1020 assert_eq!(entry.addr(), prev_addr as u16);
1022 assert_eq!(entry.latch(), false);
1023 if logical_i > 1 && logical_i < TEST_COLS - BLANKING_DELAY - 1 {
1024 assert_eq!(entry.output_enable(), true);
1025 }
1026 }
1027 }
1028 }
1029 }
1030
1031 #[test]
1032 fn test_row_set_color0() {
1033 let mut row: Row<TEST_COLS> = Row::new();
1034
1035 row.set_color0(0, true, false, true);
1036
1037 let mapped_col_0 = get_mapped_index(0);
1038 assert_eq!(row.data[mapped_col_0].red1(), true);
1039 assert_eq!(row.data[mapped_col_0].grn1(), false);
1040 assert_eq!(row.data[mapped_col_0].blu1(), true);
1041
1042 row.set_color0(1, false, true, false);
1044
1045 let mapped_col_1 = get_mapped_index(1);
1046 assert_eq!(row.data[mapped_col_1].red1(), false);
1047 assert_eq!(row.data[mapped_col_1].grn1(), true);
1048 assert_eq!(row.data[mapped_col_1].blu1(), false);
1049 }
1050
1051 #[test]
1052 fn test_row_set_color1() {
1053 let mut row: Row<TEST_COLS> = Row::new();
1054
1055 row.set_color1(0, true, true, false);
1056
1057 let mapped_col_0 = get_mapped_index(0);
1058 assert_eq!(row.data[mapped_col_0].red2(), true);
1059 assert_eq!(row.data[mapped_col_0].grn2(), true);
1060 assert_eq!(row.data[mapped_col_0].blu2(), false);
1061 }
1062
1063 #[test]
1064 fn test_row_default() {
1065 let row1: Row<TEST_COLS> = Row::new();
1066 let row2: Row<TEST_COLS> = Row::default();
1067
1068 assert_eq!(row1, row2);
1070 assert_eq!(row1.data.len(), row2.data.len());
1071
1072 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1074 assert_eq!(entry1.0, entry2.0);
1075 assert_eq!(entry1.0, 0);
1076 }
1077 }
1078
1079 #[test]
1080 fn test_frame_construction() {
1081 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1082 assert_eq!(frame.rows.len(), TEST_NROWS);
1083 }
1084
1085 #[test]
1086 fn test_frame_format() {
1087 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1088
1089 frame.format();
1090
1091 for addr in 0..TEST_NROWS {
1093 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1094
1095 let row = &frame.rows[addr];
1097
1098 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1100 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1101 assert_eq!(row.data[last_pixel_idx].latch(), true);
1102
1103 let first_pixel_idx = get_mapped_index(0);
1105 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1106 assert_eq!(row.data[first_pixel_idx].latch(), false);
1107 }
1108 }
1109
1110 #[test]
1111 fn test_frame_set_pixel() {
1112 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1113
1114 frame.set_pixel(5, 10, true, false, true);
1116
1117 let mapped_col_10 = get_mapped_index(10);
1118 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1119 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1120 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1121
1122 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1124
1125 let mapped_col_15 = get_mapped_index(15);
1126 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1127 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1128 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1129 }
1130
1131 #[test]
1132 fn test_frame_default() {
1133 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1134 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1135
1136 assert_eq!(frame1.rows.len(), frame2.rows.len());
1138
1139 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1141 assert_eq!(row1, row2);
1142
1143 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1145 assert_eq!(entry1.0, entry2.0);
1146 assert_eq!(entry1.0, 0);
1147 }
1148 }
1149 }
1150
1151 #[test]
1152 fn test_dma_framebuffer_construction() {
1153 let fb = TestFrameBuffer::new();
1154 assert_eq!(fb.frames.len(), TEST_FRAME_COUNT);
1155 assert_eq!(fb._align, 0);
1156 }
1157
1158 #[test]
1159 fn test_bcm_chunk_info() {
1160 let expected_size =
1161 core::mem::size_of::<[Frame<TEST_ROWS, TEST_COLS, TEST_NROWS>; TEST_FRAME_COUNT]>();
1162 assert_eq!(TestFrameBuffer::bcm_chunk_bytes(), expected_size);
1163 assert_eq!(TestFrameBuffer::bcm_chunk_count(), 1);
1164 }
1165
1166 #[test]
1167 fn test_dma_framebuffer_erase() {
1168 let fb = TestFrameBuffer::new();
1169
1170 for frame in &fb.frames {
1172 for addr in 0..TEST_NROWS {
1173 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1174
1175 let row = &frame.rows[addr];
1177
1178 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1180 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1181 assert_eq!(row.data[last_pixel_idx].latch(), true);
1182
1183 let first_pixel_idx = get_mapped_index(0);
1185 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1186 assert_eq!(row.data[first_pixel_idx].latch(), false);
1187 }
1188 }
1189 }
1190
1191 #[test]
1192 fn test_dma_framebuffer_set_pixel_bounds() {
1193 let mut fb = TestFrameBuffer::new();
1194
1195 fb.set_pixel(Point::new(-1, 5), Color::RED);
1197 fb.set_pixel(Point::new(5, -1), Color::RED);
1198
1199 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1201 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1202 }
1203
1204 #[test]
1205 fn test_dma_framebuffer_set_pixel_internal() {
1206 let mut fb = TestFrameBuffer::new();
1207
1208 let red_color = Color::RED;
1209 fb.set_pixel_internal(10, 5, red_color);
1210
1211 for frame in &fb.frames {
1215 let mapped_col_10 = get_mapped_index(10);
1217 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1218 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1219 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1220 }
1221 }
1222
1223 #[test]
1224 fn test_dma_framebuffer_brightness_modulation() {
1225 let mut fb = TestFrameBuffer::new();
1226
1227 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Color::from(embedded_graphics::pixelcolor::Rgb888::new(
1231 test_brightness,
1232 0,
1233 0,
1234 ));
1235
1236 fb.set_pixel_internal(0, 0, color);
1237
1238 for (frame_idx, frame) in fb.frames.iter().enumerate() {
1241 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1242 let should_be_active = test_brightness >= frame_threshold;
1243
1244 let mapped_col_0 = get_mapped_index(0);
1245 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1246 }
1247 }
1248
1249 #[test]
1250 fn test_origin_dimensions() {
1251 let fb = TestFrameBuffer::new();
1252 let size = fb.size();
1253 assert_eq!(size.width, TEST_COLS as u32);
1254 assert_eq!(size.height, TEST_ROWS as u32);
1255
1256 let size = (&fb).size();
1258 assert_eq!(size.width, TEST_COLS as u32);
1259 assert_eq!(size.height, TEST_ROWS as u32);
1260
1261 let mut fb = TestFrameBuffer::new();
1263 let fb_ref = &mut fb;
1264 let size = fb_ref.size();
1265 assert_eq!(size.width, TEST_COLS as u32);
1266 assert_eq!(size.height, TEST_ROWS as u32);
1267 }
1268
1269 #[test]
1270 fn test_draw_target() {
1271 let mut fb = TestFrameBuffer::new();
1272
1273 let pixels = vec![
1274 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1275 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1276 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1277 ];
1278
1279 let result = fb.draw_iter(pixels);
1280 assert!(result.is_ok());
1281
1282 let result = (&mut fb).draw_iter(vec![embedded_graphics::Pixel(
1284 Point::new(3, 3),
1285 Color::WHITE,
1286 )]);
1287 assert!(result.is_ok());
1288 }
1289
1290 #[test]
1291 fn test_draw_iter_pixel_verification() {
1292 let mut fb = TestFrameBuffer::new();
1293
1294 let pixels = vec![
1296 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), ];
1308
1309 let result = fb.draw_iter(pixels);
1310 assert!(result.is_ok());
1311
1312 let first_frame = &fb.frames[0];
1314 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = get_mapped_index(5);
1320 assert_eq!(
1321 first_frame.rows[2].data[col_idx].red1(),
1322 Color::RED.r() >= first_frame_threshold
1323 );
1324 assert_eq!(
1325 first_frame.rows[2].data[col_idx].grn1(),
1326 Color::RED.g() >= first_frame_threshold
1327 );
1328 assert_eq!(
1329 first_frame.rows[2].data[col_idx].blu1(),
1330 Color::RED.b() >= first_frame_threshold
1331 );
1332
1333 let col_idx = get_mapped_index(10);
1335 assert_eq!(
1336 first_frame.rows[5].data[col_idx].red1(),
1337 Color::GREEN.r() >= first_frame_threshold
1338 );
1339 assert_eq!(
1340 first_frame.rows[5].data[col_idx].grn1(),
1341 Color::GREEN.g() >= first_frame_threshold
1342 );
1343 assert_eq!(
1344 first_frame.rows[5].data[col_idx].blu1(),
1345 Color::GREEN.b() >= first_frame_threshold
1346 );
1347
1348 let col_idx = get_mapped_index(15);
1350 assert_eq!(
1351 first_frame.rows[8].data[col_idx].red1(),
1352 Color::BLUE.r() >= first_frame_threshold
1353 );
1354 assert_eq!(
1355 first_frame.rows[8].data[col_idx].grn1(),
1356 Color::BLUE.g() >= first_frame_threshold
1357 );
1358 assert_eq!(
1359 first_frame.rows[8].data[col_idx].blu1(),
1360 Color::BLUE.b() >= first_frame_threshold
1361 );
1362
1363 let col_idx = get_mapped_index(20);
1365 assert_eq!(
1366 first_frame.rows[10].data[col_idx].red1(),
1367 Color::WHITE.r() >= first_frame_threshold
1368 );
1369 assert_eq!(
1370 first_frame.rows[10].data[col_idx].grn1(),
1371 Color::WHITE.g() >= first_frame_threshold
1372 );
1373 assert_eq!(
1374 first_frame.rows[10].data[col_idx].blu1(),
1375 Color::WHITE.b() >= first_frame_threshold
1376 );
1377
1378 let col_idx = get_mapped_index(25);
1381 assert_eq!(
1382 first_frame.rows[3].data[col_idx].red2(),
1383 Color::RED.r() >= first_frame_threshold
1384 );
1385 assert_eq!(
1386 first_frame.rows[3].data[col_idx].grn2(),
1387 Color::RED.g() >= first_frame_threshold
1388 );
1389 assert_eq!(
1390 first_frame.rows[3].data[col_idx].blu2(),
1391 Color::RED.b() >= first_frame_threshold
1392 );
1393
1394 let col_idx = get_mapped_index(30);
1396 assert_eq!(
1397 first_frame.rows[7].data[col_idx].red2(),
1398 Color::GREEN.r() >= first_frame_threshold
1399 );
1400 assert_eq!(
1401 first_frame.rows[7].data[col_idx].grn2(),
1402 Color::GREEN.g() >= first_frame_threshold
1403 );
1404 assert_eq!(
1405 first_frame.rows[7].data[col_idx].blu2(),
1406 Color::GREEN.b() >= first_frame_threshold
1407 );
1408
1409 let col_idx = get_mapped_index(35);
1411 assert_eq!(
1412 first_frame.rows[12].data[col_idx].red2(),
1413 Color::BLUE.r() >= first_frame_threshold
1414 );
1415 assert_eq!(
1416 first_frame.rows[12].data[col_idx].grn2(),
1417 Color::BLUE.g() >= first_frame_threshold
1418 );
1419 assert_eq!(
1420 first_frame.rows[12].data[col_idx].blu2(),
1421 Color::BLUE.b() >= first_frame_threshold
1422 );
1423
1424 let col_idx = get_mapped_index(40);
1426 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1427 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1428 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1429 }
1430
1431 #[test]
1432 fn test_embedded_graphics_integration() {
1433 let mut fb = TestFrameBuffer::new();
1434
1435 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1437 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1438 .draw(&mut fb);
1439 assert!(result.is_ok());
1440
1441 let result = Circle::new(Point::new(30, 15), 8)
1443 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1444 .draw(&mut fb);
1445 assert!(result.is_ok());
1446 }
1447
1448 #[test]
1449 #[cfg(feature = "skip-black-pixels")]
1450 fn test_skip_black_pixels_enabled() {
1451 let mut fb = TestFrameBuffer::new();
1452
1453 fb.set_pixel_internal(10, 5, Color::RED);
1455
1456 let mapped_col_10 = get_mapped_index(10);
1458 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1459 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1460 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1461
1462 fb.set_pixel_internal(10, 5, Color::BLACK);
1464
1465 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1467 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1468 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1469 }
1470
1471 #[test]
1472 #[cfg(not(feature = "skip-black-pixels"))]
1473 fn test_skip_black_pixels_disabled() {
1474 let mut fb = TestFrameBuffer::new();
1475
1476 fb.set_pixel_internal(10, 5, Color::RED);
1478
1479 let mapped_col_10 = get_mapped_index(10);
1481 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1482 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1483 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1484
1485 fb.set_pixel_internal(10, 5, Color::BLACK);
1487
1488 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1490 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1491 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1492 }
1493
1494 #[test]
1495 fn test_bcm_frame_overwrite() {
1496 let mut fb = TestFrameBuffer::new();
1497
1498 fb.set_pixel_internal(10, 5, Color::WHITE);
1500
1501 let mapped_col_10 = get_mapped_index(10);
1502
1503 for frame in fb.frames.iter() {
1505 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1507 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1508 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1509 }
1510
1511 let half_white = Color::from(embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128));
1513 fb.set_pixel_internal(10, 5, half_white);
1514
1515 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.frames.iter().enumerate() {
1521 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1522 let should_be_active = 128 >= frame_threshold;
1523
1524 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1525 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1526 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1527 }
1528
1529 for frame_idx in 0..4 {
1532 assert_eq!(
1533 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1534 true
1535 );
1536 }
1537 for frame_idx in 4..TEST_FRAME_COUNT {
1539 assert_eq!(
1540 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1541 false
1542 );
1543 }
1544 }
1545
1546 #[test]
1547 fn test_read_buffer_implementation() {
1548 let fb = TestFrameBuffer::new();
1550 let expected_size = core::mem::size_of_val(&fb.frames);
1551
1552 unsafe {
1554 let (ptr, len) = <TestFrameBuffer as ReadBuffer>::read_buffer(&fb);
1555 assert!(!ptr.is_null());
1556 assert_eq!(len, expected_size);
1557 }
1558
1559 unsafe {
1561 let (ptr, len) = fb.read_buffer();
1562 assert!(!ptr.is_null());
1563 assert_eq!(len, expected_size);
1564 }
1565
1566 let fb = TestFrameBuffer::new();
1568 let fb_ref = &fb;
1569 unsafe {
1570 let (ptr, len) = fb_ref.read_buffer();
1571 assert!(!ptr.is_null());
1572 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1573 }
1574
1575 let mut fb = TestFrameBuffer::new();
1577 let fb_ref = &mut fb;
1578 unsafe {
1579 let (ptr, len) = fb_ref.read_buffer();
1580 assert!(!ptr.is_null());
1581 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1582 }
1583 }
1584
1585 #[test]
1586 fn test_read_buffer_owned_implementation() {
1587 fn test_owned_read_buffer(fb: TestFrameBuffer) -> (bool, usize) {
1590 unsafe {
1591 let (ptr, len) = fb.read_buffer();
1592 (!ptr.is_null(), len)
1593 }
1594 }
1595
1596 let fb = TestFrameBuffer::new();
1597 let expected_len = core::mem::size_of_val(&fb.frames);
1598
1599 let (ptr_valid, actual_len) = test_owned_read_buffer(fb);
1600 assert!(ptr_valid);
1601 assert_eq!(actual_len, expected_len);
1602 }
1603
1604 #[test]
1605 fn test_framebuffer_trait() {
1606 let fb = TestFrameBuffer::new();
1607 assert_eq!(fb.get_word_size(), WordSize::Sixteen);
1608
1609 let fb_ref = &fb;
1610 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1611
1612 let mut fb = TestFrameBuffer::new();
1613 let fb_ref = &mut fb;
1614 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1615 }
1616
1617 #[test]
1618 fn test_debug_formatting() {
1619 let fb = TestFrameBuffer::new();
1620 let debug_string = format!("{:?}", fb);
1621 assert!(debug_string.contains("DmaFrameBuffer"));
1622 assert!(debug_string.contains("frame_count"));
1623 assert!(debug_string.contains("frame_size"));
1624 assert!(debug_string.contains("brightness_step"));
1625 }
1626
1627 #[test]
1628 fn test_default_implementation() {
1629 let fb1 = TestFrameBuffer::new();
1630 let fb2 = TestFrameBuffer::default();
1631
1632 assert_eq!(fb1.frames.len(), fb2.frames.len());
1634 assert_eq!(fb1._align, fb2._align);
1635 }
1636
1637 #[test]
1638 fn test_memory_alignment() {
1639 let fb = TestFrameBuffer::new();
1640 let ptr = &fb as *const _ as usize;
1641
1642 assert_eq!(ptr % 8, 0);
1644 }
1645
1646 #[test]
1647 fn test_color_values() {
1648 let mut fb = TestFrameBuffer::new();
1649
1650 let colors = [
1652 (Color::RED, (255, 0, 0)),
1653 (Color::GREEN, (0, 255, 0)),
1654 (Color::BLUE, (0, 0, 255)),
1655 (Color::WHITE, (255, 255, 255)),
1656 (Color::BLACK, (0, 0, 0)),
1657 ];
1658
1659 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1660 fb.set_pixel(Point::new(i as i32, 0), *color);
1661 assert_eq!(color.r(), *r);
1662 assert_eq!(color.g(), *g);
1663 assert_eq!(color.b(), *b);
1664 }
1665 }
1666
1667 #[test]
1668 fn test_blanking_delay() {
1669 let mut row: Row<TEST_COLS> = Row::new();
1670 let test_addr = 5;
1671 let prev_addr = 4;
1672
1673 row.format(test_addr, prev_addr);
1674
1675 let blanking_pixel_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 1);
1677 assert_eq!(row.data[blanking_pixel_idx].output_enable(), false);
1678
1679 let before_blanking_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 2);
1681 assert_eq!(row.data[before_blanking_idx].output_enable(), true);
1682 }
1683
1684 #[test]
1685 fn test_esp32_mapping() {
1686 #[cfg(feature = "esp32-ordering")]
1688 {
1689 assert_eq!(map_index(0), 1);
1690 assert_eq!(map_index(1), 0);
1691 assert_eq!(map_index(2), 3);
1692 assert_eq!(map_index(3), 2);
1693 assert_eq!(map_index(4), 5);
1694 assert_eq!(map_index(5), 4);
1695 }
1696 #[cfg(not(feature = "esp32-ordering"))]
1697 {
1698 assert_eq!(map_index(0), 0);
1699 assert_eq!(map_index(1), 1);
1700 assert_eq!(map_index(2), 2);
1701 assert_eq!(map_index(3), 3);
1702 }
1703 }
1704
1705 #[test]
1706 fn test_bits_assertion() {
1707 assert!(TEST_BITS <= 8);
1710 }
1711
1712 #[test]
1713 fn test_fast_clear_method() {
1714 let mut fb = TestFrameBuffer::new();
1715
1716 fb.set_pixel_internal(10, 5, Color::RED);
1718 fb.set_pixel_internal(20, 10, Color::GREEN);
1719
1720 let mapped_col_10 = get_mapped_index(10);
1722 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1723
1724 fb.erase();
1726
1727 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1729 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1730 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1731
1732 let last_col = get_mapped_index(TEST_COLS - 1);
1734 assert_eq!(fb.frames[0].rows[5].data[last_col].latch(), true);
1735 }
1736
1737 const CHAR_W: i32 = 6;
1741 const CHAR_H: i32 = 10;
1742
1743 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1745 use embedded_graphics::mock_display::MockDisplay;
1746 use embedded_graphics::mono_font::ascii::FONT_6X10;
1747 use embedded_graphics::mono_font::MonoTextStyle;
1748 use embedded_graphics::text::{Baseline, Text};
1749
1750 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1752 Text::with_baseline("A", origin, style, Baseline::Top)
1753 .draw(fb)
1754 .unwrap();
1755
1756 let mut reference: MockDisplay<Color> = MockDisplay::new();
1758 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1759 .draw(&mut reference)
1760 .unwrap();
1761
1762 for dy in 0..CHAR_H {
1763 for dx in 0..CHAR_W {
1764 let expected_on = reference
1765 .get_pixel(Point::new(dx, dy))
1766 .unwrap_or(Color::BLACK)
1767 != Color::BLACK;
1768
1769 let gx = (origin.x + dx) as usize;
1770 let gy = (origin.y + dy) as usize;
1771
1772 let frame0 = &fb.frames[0];
1779 let e = if gy < TEST_NROWS {
1780 &frame0.rows[gy].data[get_mapped_index(gx)]
1781 } else {
1782 &frame0.rows[gy - TEST_NROWS].data[get_mapped_index(gx)]
1783 };
1784
1785 let (r, g, b) = if gy >= TEST_NROWS {
1786 (e.red2(), e.grn2(), e.blu2())
1787 } else {
1788 (e.red1(), e.grn1(), e.blu1())
1789 };
1790
1791 if expected_on {
1792 assert!(r && g && b,);
1793 } else {
1794 assert!(!r && !g && !b);
1795 }
1796 }
1797 }
1798 }
1799
1800 #[test]
1801 fn test_draw_char_corners() {
1802 let upper_left = Point::new(0, 0);
1803 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1804
1805 let mut fb = TestFrameBuffer::new();
1806
1807 verify_glyph_at(&mut fb, upper_left);
1808 verify_glyph_at(&mut fb, lower_right);
1809 }
1810
1811 #[test]
1812 fn test_framebuffer_operations_trait_erase() {
1813 let mut fb = TestFrameBuffer::new();
1814
1815 fb.set_pixel_internal(10, 5, Color::RED);
1817 fb.set_pixel_internal(20, 10, Color::GREEN);
1818
1819 <TestFrameBuffer as FrameBufferOperations>::erase(&mut fb);
1821
1822 let mc10 = get_mapped_index(10);
1824 let mc20 = get_mapped_index(20);
1825 assert_eq!(fb.frames[0].rows[5].data[mc10].red1(), false);
1826 assert_eq!(fb.frames[0].rows[10].data[mc20].grn1(), false);
1827
1828 let last_col = get_mapped_index(TEST_COLS - 1);
1830 assert!(fb.frames[0].rows[0].data[last_col].latch());
1831 }
1832
1833 #[test]
1834 fn test_framebuffer_operations_trait_set_pixel() {
1835 let mut fb = TestFrameBuffer::new();
1836
1837 <TestFrameBuffer as FrameBufferOperations>::set_pixel(
1839 &mut fb,
1840 Point::new(8, 3),
1841 Color::BLUE,
1842 );
1843
1844 let idx = get_mapped_index(8);
1845 assert_eq!(fb.frames[0].rows[3].data[idx].blu1(), true);
1846 assert_eq!(fb.frames[0].rows[3].data[idx].red1(), false);
1847 assert_eq!(fb.frames[0].rows[3].data[idx].grn1(), false);
1848 }
1849}