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;
142
143#[cfg(feature = "lead-blank-1")]
144const LEAD_BLANK_DELAY: usize = 1;
145#[cfg(feature = "lead-blank-2")]
146const LEAD_BLANK_DELAY: usize = 2;
147#[cfg(feature = "lead-blank-4")]
148const LEAD_BLANK_DELAY: usize = 4;
149#[cfg(feature = "lead-blank-8")]
150const LEAD_BLANK_DELAY: usize = 8;
151#[cfg(feature = "lead-blank-16")]
152const LEAD_BLANK_DELAY: usize = 16;
153
154#[cfg(not(any(
155 feature = "lead-blank-1",
156 feature = "lead-blank-2",
157 feature = "lead-blank-4",
158 feature = "lead-blank-8",
159 feature = "lead-blank-16"
160)))]
161const LEAD_BLANK_DELAY: usize = 1;
162
163#[cfg(feature = "trail-blank-1")]
164const TRAIL_BLANK_DELAY: usize = 1;
165#[cfg(feature = "trail-blank-2")]
166const TRAIL_BLANK_DELAY: usize = 2;
167#[cfg(feature = "trail-blank-4")]
168const TRAIL_BLANK_DELAY: usize = 4;
169#[cfg(feature = "trail-blank-8")]
170const TRAIL_BLANK_DELAY: usize = 8;
171#[cfg(feature = "trail-blank-16")]
172const TRAIL_BLANK_DELAY: usize = 16;
173
174#[cfg(not(any(
175 feature = "trail-blank-1",
176 feature = "trail-blank-2",
177 feature = "trail-blank-4",
178 feature = "trail-blank-8",
179 feature = "trail-blank-16"
180)))]
181const TRAIL_BLANK_DELAY: usize = 1;
182
183#[cfg(not(feature = "invert-oe"))]
184const OE_ACTIVE: u16 = 0b1_0000_0000;
185#[cfg(not(feature = "invert-oe"))]
186const OE_BLANK: u16 = 0;
187
188#[cfg(feature = "invert-oe")]
189const OE_ACTIVE: u16 = 0;
190#[cfg(feature = "invert-oe")]
191const OE_BLANK: u16 = 0b1_0000_0000;
192
193#[inline]
196const fn make_data_template<const COLS: usize>(addr: u8, prev_addr: u8) -> [Entry; COLS] {
197 let mut data = [Entry::new(); COLS];
198 let mut i = 0;
199
200 while i < COLS {
201 let mut entry = Entry::new();
202 entry.0 = prev_addr as u16 | OE_BLANK;
204
205 if i == COLS - 1 {
206 entry.0 |= 0b0010_0000; entry.0 = (entry.0 & !0b0001_1111) | (addr as u16); } else if i >= TRAIL_BLANK_DELAY && i < COLS.saturating_sub(LEAD_BLANK_DELAY + 1) {
210 entry.0 = (entry.0 & !0b1_0000_0000) | OE_ACTIVE;
212 }
213
214 data[map_index(i)] = entry;
215 i += 1;
216 }
217
218 data
219}
220
221bitfield! {
222 #[derive(Clone, Copy, Default, PartialEq)]
243 #[repr(transparent)]
244 struct Entry(u16);
245 dummy2, set_dummy2: 15;
246 blu2, set_blu2: 14;
247 grn2, set_grn2: 13;
248 red2, set_red2: 12;
249 blu1, set_blu1: 11;
250 grn1, set_grn1: 10;
251 red1, set_red1: 9;
252 output_enable, set_output_enable: 8;
253 dummy1, set_dummy1: 7;
254 dummy0, set_dummy0: 6;
255 latch, set_latch: 5;
256 addr, set_addr: 4, 0;
257}
258
259impl core::fmt::Debug for Entry {
260 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
261 f.debug_tuple("Entry")
262 .field(&format_args!("{:#x}", self.0))
263 .finish()
264 }
265}
266
267#[cfg(feature = "defmt")]
268impl defmt::Format for Entry {
269 fn format(&self, f: defmt::Formatter) {
270 defmt::write!(f, "Entry({=u16:#x})", self.0);
271 }
272}
273
274impl Entry {
275 const fn new() -> Self {
276 #[cfg(feature = "invert-oe")]
277 {
278 Self(0b1_0000_0000)
279 }
280 #[cfg(not(feature = "invert-oe"))]
281 {
282 Self(0)
283 }
284 }
285
286 const COLOR0_MASK: u16 = 0b0000_1110_0000_0000; const COLOR1_MASK: u16 = 0b0111_0000_0000_0000; #[inline]
291 fn set_color0_bits(&mut self, bits: u8) {
292 let bits16 = u16::from(bits) << 9;
293 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits16 & Self::COLOR0_MASK);
294 }
295
296 #[inline]
297 fn set_color1_bits(&mut self, bits: u8) {
298 let bits16 = u16::from(bits) << 12;
299 self.0 = (self.0 & !Self::COLOR1_MASK) | (bits16 & Self::COLOR1_MASK);
300 }
301}
302
303#[derive(Clone, Copy, PartialEq, Debug)]
312#[repr(C)]
313struct Row<const COLS: usize> {
314 data: [Entry; COLS],
315}
316
317const fn map_index(i: usize) -> usize {
318 #[cfg(feature = "esp32-ordering")]
319 {
320 i ^ 1
321 }
322 #[cfg(not(feature = "esp32-ordering"))]
323 {
324 i
325 }
326}
327
328impl<const COLS: usize> Default for Row<COLS> {
329 fn default() -> Self {
330 Self::new()
331 }
332}
333
334impl<const COLS: usize> Row<COLS> {
335 pub const fn new() -> Self {
336 Self {
337 data: [Entry::new(); COLS],
338 }
339 }
340
341 pub fn format(&mut self, addr: u8, prev_addr: u8) {
342 let template = make_data_template::<COLS>(addr, prev_addr);
344 self.data.copy_from_slice(&template);
345 }
346
347 #[inline]
350 pub fn clear_colors(&mut self) {
351 const COLOR_CLEAR_MASK: u16 = !0b0111_1110_0000_0000; for entry in &mut self.data {
355 entry.0 &= COLOR_CLEAR_MASK;
356 }
357 }
358
359 #[inline]
360 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
361 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
362 let col = map_index(col);
363 self.data[col].set_color0_bits(bits);
364 }
365
366 #[inline]
367 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
368 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
369 let col = map_index(col);
370 self.data[col].set_color1_bits(bits);
371 }
372}
373
374#[derive(Copy, Clone, Debug)]
375#[repr(C)]
376struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
377 rows: [Row<COLS>; NROWS],
378}
379
380impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
381 pub const fn new() -> Self {
382 Self {
383 rows: [Row::new(); NROWS],
384 }
385 }
386
387 pub fn format(&mut self) {
388 for (addr, row) in self.rows.iter_mut().enumerate() {
389 let prev_addr = if addr == 0 {
390 NROWS as u8 - 1
391 } else {
392 addr as u8 - 1
393 };
394 row.format(addr as u8, prev_addr);
395 }
396 }
397
398 #[inline]
400 pub fn clear_colors(&mut self) {
401 for row in &mut self.rows {
402 row.clear_colors();
403 }
404 }
405
406 #[inline]
407 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
408 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
409 if y < NROWS {
410 row.set_color0(x, red, green, blue);
411 } else {
412 row.set_color1(x, red, green, blue);
413 }
414 }
415}
416
417impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
418 for Frame<ROWS, COLS, NROWS>
419{
420 fn default() -> Self {
421 Self::new()
422 }
423}
424
425#[derive(Copy, Clone, Debug)]
428#[repr(C)]
429struct FrameData<const ROWS: usize, const COLS: usize, const NROWS: usize, const FRAME_COUNT: usize>
430{
431 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
432 #[cfg(all(feature = "tail-closes-latch", feature = "esp32-ordering"))]
433 padding: Entry,
434 #[cfg(feature = "tail-closes-latch")]
435 tail: Entry,
436}
437
438impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const FRAME_COUNT: usize>
439 FrameData<ROWS, COLS, NROWS, FRAME_COUNT>
440{
441 const fn new() -> Self {
442 Self {
443 frames: [Frame::new(); FRAME_COUNT],
444 #[cfg(all(feature = "esp32-ordering", feature = "tail-closes-latch"))]
445 padding: Entry::new(),
446 #[cfg(feature = "tail-closes-latch")]
447 tail: Entry::new(),
448 }
449 }
450}
451
452#[derive(Copy, Clone)]
477#[repr(C)]
478pub struct DmaFrameBuffer<
479 const ROWS: usize,
480 const COLS: usize,
481 const NROWS: usize,
482 const BITS: u8,
483 const FRAME_COUNT: usize,
484> {
485 _align: u64,
486 data: FrameData<ROWS, COLS, NROWS, FRAME_COUNT>,
487}
488
489impl<
490 const ROWS: usize,
491 const COLS: usize,
492 const NROWS: usize,
493 const BITS: u8,
494 const FRAME_COUNT: usize,
495 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
496{
497 fn default() -> Self {
498 Self::new()
499 }
500}
501
502impl<
503 const ROWS: usize,
504 const COLS: usize,
505 const NROWS: usize,
506 const BITS: u8,
507 const FRAME_COUNT: usize,
508 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
509{
510 #[must_use]
533 pub fn new() -> Self {
534 debug_assert!(BITS <= 8);
535
536 let mut instance = Self {
537 _align: 0,
538 data: FrameData::new(),
539 };
540
541 instance.format();
543 instance
544 }
545
546 #[must_use]
549 pub const fn bcm_chunk_count() -> usize {
550 1
551 }
552
553 #[must_use]
557 pub const fn bcm_chunk_bytes() -> usize {
558 core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>()
559 }
560
561 #[inline]
581 pub fn format(&mut self) {
582 for frame in &mut self.data.frames {
583 frame.format();
584 }
585 #[cfg(feature = "tail-closes-latch")]
586 {
587 self.data.tail.0 = 0x1f | OE_BLANK;
588 }
589 #[cfg(all(feature = "esp32-ordering", feature = "tail-closes-latch"))]
590 {
591 self.data.padding.0 = 0x1f | OE_BLANK;
592 }
593 }
594
595 #[inline]
615 pub fn erase(&mut self) {
616 for frame in &mut self.data.frames {
617 frame.clear_colors();
618 }
619 }
620
621 pub fn set_pixel(&mut self, p: Point, color: Color) {
637 if p.x < 0 || p.y < 0 {
638 return;
639 }
640 self.set_pixel_internal(p.x as usize, p.y as usize, color);
641 }
642
643 #[inline]
644 fn frames_on(v: u8) -> usize {
645 (v as usize) >> (8 - BITS)
647 }
648
649 #[inline]
650 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Color) {
651 if x >= COLS || y >= ROWS {
652 return;
653 }
654
655 #[cfg(feature = "skip-black-pixels")]
658 if color == Color::BLACK {
659 return;
660 }
661
662 let red_frames = Self::frames_on(color.r());
664 let green_frames = Self::frames_on(color.g());
665 let blue_frames = Self::frames_on(color.b());
666
667 for (frame_idx, frame) in self.data.frames.iter_mut().enumerate() {
669 frame.set_pixel(
670 y,
671 x,
672 frame_idx < red_frames,
673 frame_idx < green_frames,
674 frame_idx < blue_frames,
675 );
676 }
677 }
678}
679
680impl<
681 const ROWS: usize,
682 const COLS: usize,
683 const NROWS: usize,
684 const BITS: u8,
685 const FRAME_COUNT: usize,
686 > FrameBufferOperations for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
687{
688 #[inline]
689 fn erase(&mut self) {
690 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
691 }
692
693 #[inline]
694 fn set_pixel(&mut self, p: Point, color: Color) {
695 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
696 }
697}
698
699impl<
700 const ROWS: usize,
701 const COLS: usize,
702 const NROWS: usize,
703 const BITS: u8,
704 const FRAME_COUNT: usize,
705 > embedded_graphics::prelude::OriginDimensions
706 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
707{
708 fn size(&self) -> embedded_graphics::prelude::Size {
709 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
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 > embedded_graphics::prelude::OriginDimensions
720 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
721{
722 fn size(&self) -> embedded_graphics::prelude::Size {
723 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
724 }
725}
726
727impl<
728 const ROWS: usize,
729 const COLS: usize,
730 const NROWS: usize,
731 const BITS: u8,
732 const FRAME_COUNT: usize,
733 > embedded_graphics::draw_target::DrawTarget
734 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
735{
736 type Color = Color;
737
738 type Error = Infallible;
739
740 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
741 where
742 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
743 {
744 for pixel in pixels {
745 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
746 }
747 Ok(())
748 }
749}
750
751unsafe impl<
752 const ROWS: usize,
753 const COLS: usize,
754 const NROWS: usize,
755 const BITS: u8,
756 const FRAME_COUNT: usize,
757 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
758{
759 type Word = u8;
760
761 unsafe fn read_buffer(&self) -> (*const u8, usize) {
762 let ptr = (&raw const self.data).cast::<u8>();
763 let len = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
764 (ptr, len)
765 }
766}
767
768unsafe impl<
769 const ROWS: usize,
770 const COLS: usize,
771 const NROWS: usize,
772 const BITS: u8,
773 const FRAME_COUNT: usize,
774 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
775{
776 type Word = u8;
777
778 unsafe fn read_buffer(&self) -> (*const u8, usize) {
779 let ptr = (&raw const self.data).cast::<u8>();
780 let len = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
781 (ptr, len)
782 }
783}
784
785impl<
786 const ROWS: usize,
787 const COLS: usize,
788 const NROWS: usize,
789 const BITS: u8,
790 const FRAME_COUNT: usize,
791 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
792{
793 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
794 let brightness_step = 1 << (8 - BITS);
795 let size = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
796 f.debug_struct("DmaFrameBuffer")
797 .field("size", &size)
798 .field("frame_count", &self.data.frames.len())
799 .field("frame_size", &core::mem::size_of_val(&self.data.frames[0]))
800 .field("brightness_step", &&brightness_step)
801 .finish_non_exhaustive()
802 }
803}
804
805#[cfg(feature = "defmt")]
806impl<
807 const ROWS: usize,
808 const COLS: usize,
809 const NROWS: usize,
810 const BITS: u8,
811 const FRAME_COUNT: usize,
812 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
813{
814 fn format(&self, f: defmt::Formatter) {
815 let brightness_step = 1 << (8 - BITS);
816 defmt::write!(
817 f,
818 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
819 ROWS,
820 COLS,
821 NROWS,
822 BITS,
823 FRAME_COUNT
824 );
825 defmt::write!(
826 f,
827 " size: {}",
828 core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>()
829 );
830 defmt::write!(
831 f,
832 " frame_size: {}",
833 core::mem::size_of_val(&self.data.frames[0])
834 );
835 defmt::write!(f, " brightness_step: {}", brightness_step);
836 }
837}
838
839impl<
840 const ROWS: usize,
841 const COLS: usize,
842 const NROWS: usize,
843 const BITS: u8,
844 const FRAME_COUNT: usize,
845 > FrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
846{
847 type Word = u16;
848
849 fn plane_count(&self) -> usize {
850 1
851 }
852
853 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
854 assert!(plane_idx == 0, "plain DmaFrameBuffer has only 1 plane");
855 let ptr = (&raw const self.data).cast::<u8>();
856 let len = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
857 (ptr, len)
858 }
859}
860
861impl<
862 const ROWS: usize,
863 const COLS: usize,
864 const NROWS: usize,
865 const BITS: u8,
866 const FRAME_COUNT: usize,
867 > MutableFrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
868{
869}
870
871#[cfg(test)]
872mod tests {
873 extern crate std;
874
875 use std::format;
876 use std::vec;
877
878 use super::*;
879 use crate::{FrameBuffer, WordSize};
880 use embedded_graphics::pixelcolor::RgbColor;
881 use embedded_graphics::prelude::*;
882 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
883
884 const TEST_ROWS: usize = 32;
885 const TEST_COLS: usize = 64;
886 const TEST_NROWS: usize = TEST_ROWS / 2;
887 const TEST_BITS: u8 = 3;
888 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
891 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
892
893 fn get_mapped_index(index: usize) -> usize {
895 map_index(index)
896 }
897
898 #[test]
899 fn test_entry_construction() {
900 let entry = Entry::new();
901 let expect_oe = cfg!(feature = "invert-oe");
902 assert_eq!(entry.dummy2(), false);
903 assert_eq!(entry.blu2(), false);
904 assert_eq!(entry.grn2(), false);
905 assert_eq!(entry.red2(), false);
906 assert_eq!(entry.blu1(), false);
907 assert_eq!(entry.grn1(), false);
908 assert_eq!(entry.red1(), false);
909 assert_eq!(entry.output_enable(), expect_oe);
910 assert_eq!(entry.dummy1(), false);
911 assert_eq!(entry.dummy0(), false);
912 assert_eq!(entry.latch(), false);
913 assert_eq!(entry.addr(), 0);
914 }
915
916 #[test]
917 fn test_entry_setters() {
918 let mut entry = Entry::new();
919
920 entry.set_dummy2(true);
921 assert_eq!(entry.dummy2(), true);
922 assert_eq!(entry.0 & 0b1000000000000000, 0b1000000000000000);
923
924 entry.set_blu2(true);
925 assert_eq!(entry.blu2(), true);
926 assert_eq!(entry.0 & 0b0100000000000000, 0b0100000000000000);
927
928 entry.set_grn2(true);
929 assert_eq!(entry.grn2(), true);
930 assert_eq!(entry.0 & 0b0010000000000000, 0b0010000000000000);
931
932 entry.set_red2(true);
933 assert_eq!(entry.red2(), true);
934 assert_eq!(entry.0 & 0b0001000000000000, 0b0001000000000000);
935
936 entry.set_blu1(true);
937 assert_eq!(entry.blu1(), true);
938 assert_eq!(entry.0 & 0b0000100000000000, 0b0000100000000000);
939
940 entry.set_grn1(true);
941 assert_eq!(entry.grn1(), true);
942 assert_eq!(entry.0 & 0b0000010000000000, 0b0000010000000000);
943
944 entry.set_red1(true);
945 assert_eq!(entry.red1(), true);
946 assert_eq!(entry.0 & 0b0000001000000000, 0b0000001000000000);
947
948 entry.set_output_enable(true);
949 assert_eq!(entry.output_enable(), true);
950 assert_eq!(entry.0 & 0b0000000100000000, 0b0000000100000000);
951
952 entry.set_dummy1(true);
953 assert_eq!(entry.dummy1(), true);
954 assert_eq!(entry.0 & 0b0000000010000000, 0b0000000010000000);
955
956 entry.set_dummy0(true);
957 assert_eq!(entry.dummy0(), true);
958 assert_eq!(entry.0 & 0b0000000001000000, 0b0000000001000000);
959
960 entry.set_latch(true);
961 assert_eq!(entry.latch(), true);
962 assert_eq!(entry.0 & 0b0000000000100000, 0b0000000000100000);
963
964 entry.set_addr(0b11111);
965 assert_eq!(entry.addr(), 0b11111);
966 assert_eq!(entry.0 & 0b0000000000011111, 0b0000000000011111);
967 }
968
969 #[test]
970 fn test_entry_bit_isolation() {
971 let mut entry = Entry::new();
972 let expect_oe = cfg!(feature = "invert-oe");
973
974 entry.set_addr(0b11111);
976 entry.set_latch(true);
977 assert_eq!(entry.addr(), 0b11111);
978 assert_eq!(entry.latch(), true);
979 assert_eq!(entry.output_enable(), expect_oe);
980 assert_eq!(entry.red1(), false);
981
982 entry.set_red1(true);
983 entry.set_grn2(true);
984 assert_eq!(entry.addr(), 0b11111);
985 assert_eq!(entry.latch(), true);
986 assert_eq!(entry.red1(), true);
987 assert_eq!(entry.grn2(), true);
988 assert_eq!(entry.blu1(), false);
989 assert_eq!(entry.red2(), false);
990 }
991
992 #[test]
993 fn test_entry_set_color0() {
994 let mut entry = Entry::new();
995
996 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
998 assert_eq!(entry.red1(), true);
999 assert_eq!(entry.grn1(), false);
1000 assert_eq!(entry.blu1(), true);
1001 assert_eq!(entry.0 & 0b0000101000000000, 0b0000101000000000); }
1004
1005 #[test]
1006 fn test_entry_set_color1() {
1007 let mut entry = Entry::new();
1008
1009 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
1011 assert_eq!(entry.red2(), false);
1012 assert_eq!(entry.grn2(), true);
1013 assert_eq!(entry.blu2(), true);
1014 assert_eq!(entry.0 & 0b0110000000000000, 0b0110000000000000); }
1017
1018 #[test]
1019 fn test_entry_debug_formatting() {
1020 let entry = Entry(0x1234);
1021 let debug_str = format!("{:?}", entry);
1022 assert_eq!(debug_str, "Entry(0x1234)");
1023
1024 let entry = Entry(0xabcd);
1025 let debug_str = format!("{:?}", entry);
1026 assert_eq!(debug_str, "Entry(0xabcd)");
1027 }
1028
1029 #[test]
1030 fn test_row_construction() {
1031 let row: Row<TEST_COLS> = Row::new();
1032 assert_eq!(row.data.len(), TEST_COLS);
1033
1034 let expected = Entry::new().0;
1035 for entry in &row.data {
1036 assert_eq!(entry.0, expected);
1037 }
1038 }
1039
1040 #[test]
1041 fn test_row_format() {
1042 let mut row: Row<TEST_COLS> = Row::new();
1043 let test_addr = 5;
1044 let prev_addr = 4;
1045
1046 row.format(test_addr, prev_addr);
1047
1048 let oe_active = !cfg!(feature = "invert-oe");
1049
1050 for (physical_i, entry) in row.data.iter().enumerate() {
1052 let logical_i = get_mapped_index(physical_i);
1053
1054 match logical_i {
1055 i if i == TEST_COLS - 1 => {
1056 assert_eq!(entry.latch(), true);
1057 assert_eq!(entry.addr(), test_addr as u16);
1058 assert_eq!(entry.output_enable(), !oe_active);
1059 }
1060 _ => {
1061 assert_eq!(entry.addr(), prev_addr as u16);
1062 assert_eq!(entry.latch(), false);
1063 if logical_i >= TRAIL_BLANK_DELAY
1064 && logical_i < TEST_COLS - LEAD_BLANK_DELAY - 1
1065 {
1066 assert_eq!(entry.output_enable(), oe_active);
1067 } else {
1068 assert_eq!(entry.output_enable(), !oe_active);
1069 }
1070 }
1071 }
1072 }
1073 }
1074
1075 #[test]
1076 fn test_row_set_color0() {
1077 let mut row: Row<TEST_COLS> = Row::new();
1078
1079 row.set_color0(0, true, false, true);
1080
1081 let mapped_col_0 = get_mapped_index(0);
1082 assert_eq!(row.data[mapped_col_0].red1(), true);
1083 assert_eq!(row.data[mapped_col_0].grn1(), false);
1084 assert_eq!(row.data[mapped_col_0].blu1(), true);
1085
1086 row.set_color0(1, false, true, false);
1088
1089 let mapped_col_1 = get_mapped_index(1);
1090 assert_eq!(row.data[mapped_col_1].red1(), false);
1091 assert_eq!(row.data[mapped_col_1].grn1(), true);
1092 assert_eq!(row.data[mapped_col_1].blu1(), false);
1093 }
1094
1095 #[test]
1096 fn test_row_set_color1() {
1097 let mut row: Row<TEST_COLS> = Row::new();
1098
1099 row.set_color1(0, true, true, false);
1100
1101 let mapped_col_0 = get_mapped_index(0);
1102 assert_eq!(row.data[mapped_col_0].red2(), true);
1103 assert_eq!(row.data[mapped_col_0].grn2(), true);
1104 assert_eq!(row.data[mapped_col_0].blu2(), false);
1105 }
1106
1107 #[test]
1108 fn test_row_default() {
1109 let row1: Row<TEST_COLS> = Row::new();
1110 let row2: Row<TEST_COLS> = Row::default();
1111
1112 assert_eq!(row1, row2);
1114 assert_eq!(row1.data.len(), row2.data.len());
1115
1116 let expected = Entry::new().0;
1117 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1118 assert_eq!(entry1.0, entry2.0);
1119 assert_eq!(entry1.0, expected);
1120 }
1121 }
1122
1123 #[test]
1124 fn test_frame_construction() {
1125 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1126 assert_eq!(frame.rows.len(), TEST_NROWS);
1127 }
1128
1129 #[test]
1130 fn test_frame_format() {
1131 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1132
1133 frame.format();
1134
1135 for addr in 0..TEST_NROWS {
1137 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1138
1139 let row = &frame.rows[addr];
1141
1142 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1144 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1145 assert_eq!(row.data[last_pixel_idx].latch(), true);
1146
1147 let first_pixel_idx = get_mapped_index(0);
1149 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1150 assert_eq!(row.data[first_pixel_idx].latch(), false);
1151 }
1152 }
1153
1154 #[test]
1155 fn test_frame_set_pixel() {
1156 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1157
1158 frame.set_pixel(5, 10, true, false, true);
1160
1161 let mapped_col_10 = get_mapped_index(10);
1162 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1163 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1164 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1165
1166 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1168
1169 let mapped_col_15 = get_mapped_index(15);
1170 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1171 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1172 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1173 }
1174
1175 #[test]
1176 fn test_frame_default() {
1177 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1178 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1179
1180 assert_eq!(frame1.rows.len(), frame2.rows.len());
1182
1183 let expected = Entry::new().0;
1184 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1185 assert_eq!(row1, row2);
1186
1187 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1188 assert_eq!(entry1.0, entry2.0);
1189 assert_eq!(entry1.0, expected);
1190 }
1191 }
1192 }
1193
1194 #[test]
1195 fn test_dma_framebuffer_construction() {
1196 let fb = TestFrameBuffer::new();
1197 assert_eq!(fb.data.frames.len(), TEST_FRAME_COUNT);
1198 assert_eq!(fb._align, 0);
1199 }
1200
1201 #[test]
1202 fn test_bcm_chunk_info() {
1203 let expected_size =
1204 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>();
1205 assert_eq!(TestFrameBuffer::bcm_chunk_bytes(), expected_size);
1206 assert_eq!(TestFrameBuffer::bcm_chunk_count(), 1);
1207 }
1208
1209 #[test]
1210 fn test_dma_framebuffer_erase() {
1211 let fb = TestFrameBuffer::new();
1212
1213 for frame in &fb.data.frames {
1215 for addr in 0..TEST_NROWS {
1216 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1217
1218 let row = &frame.rows[addr];
1220
1221 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1223 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1224 assert_eq!(row.data[last_pixel_idx].latch(), true);
1225
1226 let first_pixel_idx = get_mapped_index(0);
1228 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1229 assert_eq!(row.data[first_pixel_idx].latch(), false);
1230 }
1231 }
1232 }
1233
1234 #[test]
1235 fn test_dma_framebuffer_set_pixel_bounds() {
1236 let mut fb = TestFrameBuffer::new();
1237
1238 fb.set_pixel(Point::new(-1, 5), Color::RED);
1240 fb.set_pixel(Point::new(5, -1), Color::RED);
1241
1242 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1244 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1245 }
1246
1247 #[test]
1248 fn test_dma_framebuffer_set_pixel_internal() {
1249 let mut fb = TestFrameBuffer::new();
1250
1251 let red_color = Color::RED;
1252 fb.set_pixel_internal(10, 5, red_color);
1253
1254 for frame in &fb.data.frames {
1258 let mapped_col_10 = get_mapped_index(10);
1260 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1261 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1262 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1263 }
1264 }
1265
1266 #[test]
1267 fn test_dma_framebuffer_brightness_modulation() {
1268 let mut fb = TestFrameBuffer::new();
1269
1270 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Color::from(embedded_graphics::pixelcolor::Rgb888::new(
1274 test_brightness,
1275 0,
1276 0,
1277 ));
1278
1279 fb.set_pixel_internal(0, 0, color);
1280
1281 for (frame_idx, frame) in fb.data.frames.iter().enumerate() {
1284 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1285 let should_be_active = test_brightness >= frame_threshold;
1286
1287 let mapped_col_0 = get_mapped_index(0);
1288 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1289 }
1290 }
1291
1292 #[test]
1293 fn test_origin_dimensions() {
1294 let fb = TestFrameBuffer::new();
1295 let size = fb.size();
1296 assert_eq!(size.width, TEST_COLS as u32);
1297 assert_eq!(size.height, TEST_ROWS as u32);
1298
1299 let size = (&fb).size();
1301 assert_eq!(size.width, TEST_COLS as u32);
1302 assert_eq!(size.height, TEST_ROWS as u32);
1303
1304 let mut fb = TestFrameBuffer::new();
1306 let fb_ref = &mut fb;
1307 let size = fb_ref.size();
1308 assert_eq!(size.width, TEST_COLS as u32);
1309 assert_eq!(size.height, TEST_ROWS as u32);
1310 }
1311
1312 #[test]
1313 fn test_draw_target() {
1314 let mut fb = TestFrameBuffer::new();
1315
1316 let pixels = vec![
1317 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1318 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1319 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1320 ];
1321
1322 let result = fb.draw_iter(pixels);
1323 assert!(result.is_ok());
1324
1325 let result = (&mut fb).draw_iter(vec![embedded_graphics::Pixel(
1327 Point::new(3, 3),
1328 Color::WHITE,
1329 )]);
1330 assert!(result.is_ok());
1331 }
1332
1333 #[test]
1334 fn test_draw_iter_pixel_verification() {
1335 let mut fb = TestFrameBuffer::new();
1336
1337 let pixels = vec![
1339 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), ];
1351
1352 let result = fb.draw_iter(pixels);
1353 assert!(result.is_ok());
1354
1355 let first_frame = &fb.data.frames[0];
1357 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = get_mapped_index(5);
1363 assert_eq!(
1364 first_frame.rows[2].data[col_idx].red1(),
1365 Color::RED.r() >= first_frame_threshold
1366 );
1367 assert_eq!(
1368 first_frame.rows[2].data[col_idx].grn1(),
1369 Color::RED.g() >= first_frame_threshold
1370 );
1371 assert_eq!(
1372 first_frame.rows[2].data[col_idx].blu1(),
1373 Color::RED.b() >= first_frame_threshold
1374 );
1375
1376 let col_idx = get_mapped_index(10);
1378 assert_eq!(
1379 first_frame.rows[5].data[col_idx].red1(),
1380 Color::GREEN.r() >= first_frame_threshold
1381 );
1382 assert_eq!(
1383 first_frame.rows[5].data[col_idx].grn1(),
1384 Color::GREEN.g() >= first_frame_threshold
1385 );
1386 assert_eq!(
1387 first_frame.rows[5].data[col_idx].blu1(),
1388 Color::GREEN.b() >= first_frame_threshold
1389 );
1390
1391 let col_idx = get_mapped_index(15);
1393 assert_eq!(
1394 first_frame.rows[8].data[col_idx].red1(),
1395 Color::BLUE.r() >= first_frame_threshold
1396 );
1397 assert_eq!(
1398 first_frame.rows[8].data[col_idx].grn1(),
1399 Color::BLUE.g() >= first_frame_threshold
1400 );
1401 assert_eq!(
1402 first_frame.rows[8].data[col_idx].blu1(),
1403 Color::BLUE.b() >= first_frame_threshold
1404 );
1405
1406 let col_idx = get_mapped_index(20);
1408 assert_eq!(
1409 first_frame.rows[10].data[col_idx].red1(),
1410 Color::WHITE.r() >= first_frame_threshold
1411 );
1412 assert_eq!(
1413 first_frame.rows[10].data[col_idx].grn1(),
1414 Color::WHITE.g() >= first_frame_threshold
1415 );
1416 assert_eq!(
1417 first_frame.rows[10].data[col_idx].blu1(),
1418 Color::WHITE.b() >= first_frame_threshold
1419 );
1420
1421 let col_idx = get_mapped_index(25);
1424 assert_eq!(
1425 first_frame.rows[3].data[col_idx].red2(),
1426 Color::RED.r() >= first_frame_threshold
1427 );
1428 assert_eq!(
1429 first_frame.rows[3].data[col_idx].grn2(),
1430 Color::RED.g() >= first_frame_threshold
1431 );
1432 assert_eq!(
1433 first_frame.rows[3].data[col_idx].blu2(),
1434 Color::RED.b() >= first_frame_threshold
1435 );
1436
1437 let col_idx = get_mapped_index(30);
1439 assert_eq!(
1440 first_frame.rows[7].data[col_idx].red2(),
1441 Color::GREEN.r() >= first_frame_threshold
1442 );
1443 assert_eq!(
1444 first_frame.rows[7].data[col_idx].grn2(),
1445 Color::GREEN.g() >= first_frame_threshold
1446 );
1447 assert_eq!(
1448 first_frame.rows[7].data[col_idx].blu2(),
1449 Color::GREEN.b() >= first_frame_threshold
1450 );
1451
1452 let col_idx = get_mapped_index(35);
1454 assert_eq!(
1455 first_frame.rows[12].data[col_idx].red2(),
1456 Color::BLUE.r() >= first_frame_threshold
1457 );
1458 assert_eq!(
1459 first_frame.rows[12].data[col_idx].grn2(),
1460 Color::BLUE.g() >= first_frame_threshold
1461 );
1462 assert_eq!(
1463 first_frame.rows[12].data[col_idx].blu2(),
1464 Color::BLUE.b() >= first_frame_threshold
1465 );
1466
1467 let col_idx = get_mapped_index(40);
1469 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1470 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1471 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1472 }
1473
1474 #[test]
1475 fn test_embedded_graphics_integration() {
1476 let mut fb = TestFrameBuffer::new();
1477
1478 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1480 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1481 .draw(&mut fb);
1482 assert!(result.is_ok());
1483
1484 let result = Circle::new(Point::new(30, 15), 8)
1486 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1487 .draw(&mut fb);
1488 assert!(result.is_ok());
1489 }
1490
1491 #[test]
1492 #[cfg(feature = "skip-black-pixels")]
1493 fn test_skip_black_pixels_enabled() {
1494 let mut fb = TestFrameBuffer::new();
1495
1496 fb.set_pixel_internal(10, 5, Color::RED);
1498
1499 let mapped_col_10 = get_mapped_index(10);
1501 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1502 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1503 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1504
1505 fb.set_pixel_internal(10, 5, Color::BLACK);
1507
1508 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1510 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1511 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1512 }
1513
1514 #[test]
1515 #[cfg(not(feature = "skip-black-pixels"))]
1516 fn test_skip_black_pixels_disabled() {
1517 let mut fb = TestFrameBuffer::new();
1518
1519 fb.set_pixel_internal(10, 5, Color::RED);
1521
1522 let mapped_col_10 = get_mapped_index(10);
1524 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1525 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1526 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1527
1528 fb.set_pixel_internal(10, 5, Color::BLACK);
1530
1531 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), false);
1533 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1534 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1535 }
1536
1537 #[test]
1538 fn test_bcm_frame_overwrite() {
1539 let mut fb = TestFrameBuffer::new();
1540
1541 fb.set_pixel_internal(10, 5, Color::WHITE);
1543
1544 let mapped_col_10 = get_mapped_index(10);
1545
1546 for frame in fb.data.frames.iter() {
1548 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1550 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1551 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1552 }
1553
1554 let half_white = Color::from(embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128));
1556 fb.set_pixel_internal(10, 5, half_white);
1557
1558 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.data.frames.iter().enumerate() {
1564 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1565 let should_be_active = 128 >= frame_threshold;
1566
1567 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1568 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1569 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1570 }
1571
1572 for frame_idx in 0..4 {
1575 assert_eq!(
1576 fb.data.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1577 true
1578 );
1579 }
1580 for frame_idx in 4..TEST_FRAME_COUNT {
1582 assert_eq!(
1583 fb.data.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1584 false
1585 );
1586 }
1587 }
1588
1589 #[test]
1590 fn test_read_buffer_implementation() {
1591 let fb = TestFrameBuffer::new();
1593 let expected_size =
1594 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>();
1595
1596 unsafe {
1598 let (ptr, len) = <TestFrameBuffer as ReadBuffer>::read_buffer(&fb);
1599 assert!(!ptr.is_null());
1600 assert_eq!(len, expected_size);
1601 }
1602
1603 unsafe {
1605 let (ptr, len) = fb.read_buffer();
1606 assert!(!ptr.is_null());
1607 assert_eq!(len, expected_size);
1608 }
1609
1610 let fb = TestFrameBuffer::new();
1612 let fb_ref = &fb;
1613 unsafe {
1614 let (ptr, len) = fb_ref.read_buffer();
1615 assert!(!ptr.is_null());
1616 assert_eq!(
1617 len,
1618 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>(
1619 )
1620 );
1621 }
1622
1623 let mut fb = TestFrameBuffer::new();
1625 let fb_ref = &mut fb;
1626 unsafe {
1627 let (ptr, len) = fb_ref.read_buffer();
1628 assert!(!ptr.is_null());
1629 assert_eq!(
1630 len,
1631 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>(
1632 )
1633 );
1634 }
1635 }
1636
1637 #[test]
1638 fn test_read_buffer_owned_implementation() {
1639 fn test_owned_read_buffer(fb: TestFrameBuffer) -> (bool, usize) {
1642 unsafe {
1643 let (ptr, len) = fb.read_buffer();
1644 (!ptr.is_null(), len)
1645 }
1646 }
1647
1648 let fb = TestFrameBuffer::new();
1649 let expected_len =
1650 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>();
1651
1652 let (ptr_valid, actual_len) = test_owned_read_buffer(fb);
1653 assert!(ptr_valid);
1654 assert_eq!(actual_len, expected_len);
1655 }
1656
1657 #[test]
1658 fn test_framebuffer_trait() {
1659 let fb = TestFrameBuffer::new();
1660 assert_eq!(fb.get_word_size(), WordSize::Sixteen);
1661
1662 let fb_ref = &fb;
1663 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1664
1665 let mut fb = TestFrameBuffer::new();
1666 let fb_ref = &mut fb;
1667 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1668 }
1669
1670 #[test]
1671 fn test_debug_formatting() {
1672 let fb = TestFrameBuffer::new();
1673 let debug_string = format!("{:?}", fb);
1674 assert!(debug_string.contains("DmaFrameBuffer"));
1675 assert!(debug_string.contains("frame_count"));
1676 assert!(debug_string.contains("frame_size"));
1677 assert!(debug_string.contains("brightness_step"));
1678 }
1679
1680 #[test]
1681 fn test_default_implementation() {
1682 let fb1 = TestFrameBuffer::new();
1683 let fb2 = TestFrameBuffer::default();
1684
1685 assert_eq!(fb1.data.frames.len(), fb2.data.frames.len());
1687 assert_eq!(fb1._align, fb2._align);
1688 }
1689
1690 #[test]
1691 fn test_memory_alignment() {
1692 let fb = TestFrameBuffer::new();
1693 let ptr = &fb as *const _ as usize;
1694
1695 assert_eq!(ptr % 8, 0);
1697 }
1698
1699 #[test]
1700 fn test_color_values() {
1701 let mut fb = TestFrameBuffer::new();
1702
1703 let colors = [
1705 (Color::RED, (255, 0, 0)),
1706 (Color::GREEN, (0, 255, 0)),
1707 (Color::BLUE, (0, 0, 255)),
1708 (Color::WHITE, (255, 255, 255)),
1709 (Color::BLACK, (0, 0, 0)),
1710 ];
1711
1712 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1713 fb.set_pixel(Point::new(i as i32, 0), *color);
1714 assert_eq!(color.r(), *r);
1715 assert_eq!(color.g(), *g);
1716 assert_eq!(color.b(), *b);
1717 }
1718 }
1719
1720 #[test]
1721 fn test_blanking_delay() {
1722 let mut row: Row<TEST_COLS> = Row::new();
1723 let test_addr = 5;
1724 let prev_addr = 4;
1725
1726 row.format(test_addr, prev_addr);
1727
1728 let oe_active = !cfg!(feature = "invert-oe");
1729
1730 let trail_blank_idx = get_mapped_index(TRAIL_BLANK_DELAY - 1);
1732 assert_eq!(row.data[trail_blank_idx].output_enable(), !oe_active);
1733
1734 let after_trail_idx = get_mapped_index(TRAIL_BLANK_DELAY);
1735 assert_eq!(row.data[after_trail_idx].output_enable(), oe_active);
1736
1737 let before_lead_idx = get_mapped_index(TEST_COLS - LEAD_BLANK_DELAY - 2);
1739 assert_eq!(row.data[before_lead_idx].output_enable(), oe_active);
1740
1741 let lead_blank_idx = get_mapped_index(TEST_COLS - LEAD_BLANK_DELAY - 1);
1742 assert_eq!(row.data[lead_blank_idx].output_enable(), !oe_active);
1743 }
1744
1745 #[test]
1746 fn test_esp32_mapping() {
1747 #[cfg(feature = "esp32-ordering")]
1749 {
1750 assert_eq!(map_index(0), 1);
1751 assert_eq!(map_index(1), 0);
1752 assert_eq!(map_index(2), 3);
1753 assert_eq!(map_index(3), 2);
1754 assert_eq!(map_index(4), 5);
1755 assert_eq!(map_index(5), 4);
1756 }
1757 #[cfg(not(feature = "esp32-ordering"))]
1758 {
1759 assert_eq!(map_index(0), 0);
1760 assert_eq!(map_index(1), 1);
1761 assert_eq!(map_index(2), 2);
1762 assert_eq!(map_index(3), 3);
1763 }
1764 }
1765
1766 #[test]
1767 fn test_bits_assertion() {
1768 assert!(TEST_BITS <= 8);
1771 }
1772
1773 #[test]
1774 fn test_fast_clear_method() {
1775 let mut fb = TestFrameBuffer::new();
1776
1777 fb.set_pixel_internal(10, 5, Color::RED);
1779 fb.set_pixel_internal(20, 10, Color::GREEN);
1780
1781 let mapped_col_10 = get_mapped_index(10);
1783 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1784
1785 fb.erase();
1787
1788 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), false);
1790 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1791 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1792
1793 let last_col = get_mapped_index(TEST_COLS - 1);
1795 assert_eq!(fb.data.frames[0].rows[5].data[last_col].latch(), true);
1796 }
1797
1798 const CHAR_W: i32 = 6;
1802 const CHAR_H: i32 = 10;
1803
1804 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1806 use embedded_graphics::mock_display::MockDisplay;
1807 use embedded_graphics::mono_font::ascii::FONT_6X10;
1808 use embedded_graphics::mono_font::MonoTextStyle;
1809 use embedded_graphics::text::{Baseline, Text};
1810
1811 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1813 Text::with_baseline("A", origin, style, Baseline::Top)
1814 .draw(fb)
1815 .unwrap();
1816
1817 let mut reference: MockDisplay<Color> = MockDisplay::new();
1819 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1820 .draw(&mut reference)
1821 .unwrap();
1822
1823 for dy in 0..CHAR_H {
1824 for dx in 0..CHAR_W {
1825 let expected_on = reference
1826 .get_pixel(Point::new(dx, dy))
1827 .unwrap_or(Color::BLACK)
1828 != Color::BLACK;
1829
1830 let gx = (origin.x + dx) as usize;
1831 let gy = (origin.y + dy) as usize;
1832
1833 let frame0 = &fb.data.frames[0];
1840 let e = if gy < TEST_NROWS {
1841 &frame0.rows[gy].data[get_mapped_index(gx)]
1842 } else {
1843 &frame0.rows[gy - TEST_NROWS].data[get_mapped_index(gx)]
1844 };
1845
1846 let (r, g, b) = if gy >= TEST_NROWS {
1847 (e.red2(), e.grn2(), e.blu2())
1848 } else {
1849 (e.red1(), e.grn1(), e.blu1())
1850 };
1851
1852 if expected_on {
1853 assert!(r && g && b,);
1854 } else {
1855 assert!(!r && !g && !b);
1856 }
1857 }
1858 }
1859 }
1860
1861 #[test]
1862 fn test_draw_char_corners() {
1863 let upper_left = Point::new(0, 0);
1864 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1865
1866 let mut fb = TestFrameBuffer::new();
1867
1868 verify_glyph_at(&mut fb, upper_left);
1869 verify_glyph_at(&mut fb, lower_right);
1870 }
1871
1872 #[test]
1873 fn test_framebuffer_operations_trait_erase() {
1874 let mut fb = TestFrameBuffer::new();
1875
1876 fb.set_pixel_internal(10, 5, Color::RED);
1878 fb.set_pixel_internal(20, 10, Color::GREEN);
1879
1880 <TestFrameBuffer as FrameBufferOperations>::erase(&mut fb);
1882
1883 let mc10 = get_mapped_index(10);
1885 let mc20 = get_mapped_index(20);
1886 assert_eq!(fb.data.frames[0].rows[5].data[mc10].red1(), false);
1887 assert_eq!(fb.data.frames[0].rows[10].data[mc20].grn1(), false);
1888
1889 let last_col = get_mapped_index(TEST_COLS - 1);
1891 assert!(fb.data.frames[0].rows[0].data[last_col].latch());
1892 }
1893
1894 #[test]
1895 fn test_framebuffer_operations_trait_set_pixel() {
1896 let mut fb = TestFrameBuffer::new();
1897
1898 <TestFrameBuffer as FrameBufferOperations>::set_pixel(
1900 &mut fb,
1901 Point::new(8, 3),
1902 Color::BLUE,
1903 );
1904
1905 let idx = get_mapped_index(8);
1906 assert_eq!(fb.data.frames[0].rows[3].data[idx].blu1(), true);
1907 assert_eq!(fb.data.frames[0].rows[3].data[idx].red1(), false);
1908 assert_eq!(fb.data.frames[0].rows[3].data[idx].grn1(), false);
1909 }
1910
1911 #[test]
1912 fn test_entry_new_oe_matches_feature() {
1913 let entry = Entry::new();
1914 if cfg!(feature = "invert-oe") {
1915 assert!(entry.output_enable());
1916 } else {
1917 assert!(!entry.output_enable());
1918 }
1919 }
1920
1921 #[test]
1922 fn test_make_data_template_oe_polarity() {
1923 let mut row = Row::<TEST_COLS>::new();
1924 row.format(5, 4);
1925
1926 let active_idx = get_mapped_index(TRAIL_BLANK_DELAY);
1927 let blank_idx = get_mapped_index(TEST_COLS - LEAD_BLANK_DELAY - 1);
1928 let latch_idx = get_mapped_index(TEST_COLS - 1);
1929
1930 if cfg!(feature = "invert-oe") {
1931 assert!(!row.data[active_idx].output_enable());
1932 assert!(row.data[blank_idx].output_enable());
1933 assert!(row.data[latch_idx].output_enable());
1934 } else {
1935 assert!(row.data[active_idx].output_enable());
1936 assert!(!row.data[blank_idx].output_enable());
1937 assert!(!row.data[latch_idx].output_enable());
1938 }
1939 }
1940}