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 = "blank-delay-1")]
144const BLANKING_DELAY: usize = 1;
145#[cfg(feature = "blank-delay-2")]
146const BLANKING_DELAY: usize = 2;
147#[cfg(feature = "blank-delay-4")]
148const BLANKING_DELAY: usize = 4;
149#[cfg(feature = "blank-delay-8")]
150const BLANKING_DELAY: usize = 8;
151
152#[cfg(not(any(
154 feature = "blank-delay-1",
155 feature = "blank-delay-2",
156 feature = "blank-delay-4",
157 feature = "blank-delay-8"
158)))]
159const BLANKING_DELAY: usize = 1;
160
161#[cfg(not(feature = "invert-oe"))]
162const OE_ACTIVE: u16 = 0b1_0000_0000;
163#[cfg(not(feature = "invert-oe"))]
164const OE_BLANK: u16 = 0;
165
166#[cfg(feature = "invert-oe")]
167const OE_ACTIVE: u16 = 0;
168#[cfg(feature = "invert-oe")]
169const OE_BLANK: u16 = 0b1_0000_0000;
170
171#[inline]
174const fn make_data_template<const COLS: usize>(addr: u8, prev_addr: u8) -> [Entry; COLS] {
175 let mut data = [Entry::new(); COLS];
176 let mut i = 0;
177
178 while i < COLS {
179 let mut entry = Entry::new();
180 entry.0 = prev_addr as u16 | OE_BLANK;
182
183 if i == COLS - 1 {
184 entry.0 |= 0b0010_0000; entry.0 = (entry.0 & !0b0001_1111) | (addr as u16); } else if i >= BLANKING_DELAY && i < COLS - BLANKING_DELAY - 1 {
188 entry.0 = (entry.0 & !0b1_0000_0000) | OE_ACTIVE;
190 }
191
192 data[map_index(i)] = entry;
193 i += 1;
194 }
195
196 data
197}
198
199bitfield! {
200 #[derive(Clone, Copy, Default, PartialEq)]
221 #[repr(transparent)]
222 struct Entry(u16);
223 dummy2, set_dummy2: 15;
224 blu2, set_blu2: 14;
225 grn2, set_grn2: 13;
226 red2, set_red2: 12;
227 blu1, set_blu1: 11;
228 grn1, set_grn1: 10;
229 red1, set_red1: 9;
230 output_enable, set_output_enable: 8;
231 dummy1, set_dummy1: 7;
232 dummy0, set_dummy0: 6;
233 latch, set_latch: 5;
234 addr, set_addr: 4, 0;
235}
236
237impl core::fmt::Debug for Entry {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 f.debug_tuple("Entry")
240 .field(&format_args!("{:#x}", self.0))
241 .finish()
242 }
243}
244
245#[cfg(feature = "defmt")]
246impl defmt::Format for Entry {
247 fn format(&self, f: defmt::Formatter) {
248 defmt::write!(f, "Entry({=u16:#x})", self.0);
249 }
250}
251
252impl Entry {
253 const fn new() -> Self {
254 #[cfg(feature = "invert-oe")]
255 {
256 Self(0b1_0000_0000)
257 }
258 #[cfg(not(feature = "invert-oe"))]
259 {
260 Self(0)
261 }
262 }
263
264 const COLOR0_MASK: u16 = 0b0000_1110_0000_0000; const COLOR1_MASK: u16 = 0b0111_0000_0000_0000; #[inline]
269 fn set_color0_bits(&mut self, bits: u8) {
270 let bits16 = u16::from(bits) << 9;
271 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits16 & Self::COLOR0_MASK);
272 }
273
274 #[inline]
275 fn set_color1_bits(&mut self, bits: u8) {
276 let bits16 = u16::from(bits) << 12;
277 self.0 = (self.0 & !Self::COLOR1_MASK) | (bits16 & Self::COLOR1_MASK);
278 }
279}
280
281#[derive(Clone, Copy, PartialEq, Debug)]
290#[repr(C)]
291struct Row<const COLS: usize> {
292 data: [Entry; COLS],
293}
294
295const fn map_index(i: usize) -> usize {
296 #[cfg(feature = "esp32-ordering")]
297 {
298 i ^ 1
299 }
300 #[cfg(not(feature = "esp32-ordering"))]
301 {
302 i
303 }
304}
305
306impl<const COLS: usize> Default for Row<COLS> {
307 fn default() -> Self {
308 Self::new()
309 }
310}
311
312impl<const COLS: usize> Row<COLS> {
313 pub const fn new() -> Self {
314 Self {
315 data: [Entry::new(); COLS],
316 }
317 }
318
319 pub fn format(&mut self, addr: u8, prev_addr: u8) {
320 let template = make_data_template::<COLS>(addr, prev_addr);
322 self.data.copy_from_slice(&template);
323 }
324
325 #[inline]
328 pub fn clear_colors(&mut self) {
329 const COLOR_CLEAR_MASK: u16 = !0b0111_1110_0000_0000; for entry in &mut self.data {
333 entry.0 &= COLOR_CLEAR_MASK;
334 }
335 }
336
337 #[inline]
338 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
339 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
340 let col = map_index(col);
341 self.data[col].set_color0_bits(bits);
342 }
343
344 #[inline]
345 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
346 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
347 let col = map_index(col);
348 self.data[col].set_color1_bits(bits);
349 }
350}
351
352#[derive(Copy, Clone, Debug)]
353#[repr(C)]
354struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
355 rows: [Row<COLS>; NROWS],
356}
357
358impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
359 pub const fn new() -> Self {
360 Self {
361 rows: [Row::new(); NROWS],
362 }
363 }
364
365 pub fn format(&mut self) {
366 for (addr, row) in self.rows.iter_mut().enumerate() {
367 let prev_addr = if addr == 0 {
368 NROWS as u8 - 1
369 } else {
370 addr as u8 - 1
371 };
372 row.format(addr as u8, prev_addr);
373 }
374 }
375
376 #[inline]
378 pub fn clear_colors(&mut self) {
379 for row in &mut self.rows {
380 row.clear_colors();
381 }
382 }
383
384 #[inline]
385 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
386 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
387 if y < NROWS {
388 row.set_color0(x, red, green, blue);
389 } else {
390 row.set_color1(x, red, green, blue);
391 }
392 }
393}
394
395impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
396 for Frame<ROWS, COLS, NROWS>
397{
398 fn default() -> Self {
399 Self::new()
400 }
401}
402
403#[derive(Copy, Clone, Debug)]
406#[repr(C)]
407struct FrameData<const ROWS: usize, const COLS: usize, const NROWS: usize, const FRAME_COUNT: usize>
408{
409 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
410 #[cfg(all(feature = "tail-closes-latch", feature = "esp32-ordering"))]
411 padding: Entry,
412 #[cfg(feature = "tail-closes-latch")]
413 tail: Entry,
414}
415
416impl<const ROWS: usize, const COLS: usize, const NROWS: usize, const FRAME_COUNT: usize>
417 FrameData<ROWS, COLS, NROWS, FRAME_COUNT>
418{
419 const fn new() -> Self {
420 Self {
421 frames: [Frame::new(); FRAME_COUNT],
422 #[cfg(all(feature = "esp32-ordering", feature = "tail-closes-latch"))]
423 padding: Entry::new(),
424 #[cfg(feature = "tail-closes-latch")]
425 tail: Entry::new(),
426 }
427 }
428}
429
430#[derive(Copy, Clone)]
455#[repr(C)]
456pub struct DmaFrameBuffer<
457 const ROWS: usize,
458 const COLS: usize,
459 const NROWS: usize,
460 const BITS: u8,
461 const FRAME_COUNT: usize,
462> {
463 _align: u64,
464 data: FrameData<ROWS, COLS, NROWS, FRAME_COUNT>,
465}
466
467impl<
468 const ROWS: usize,
469 const COLS: usize,
470 const NROWS: usize,
471 const BITS: u8,
472 const FRAME_COUNT: usize,
473 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
474{
475 fn default() -> Self {
476 Self::new()
477 }
478}
479
480impl<
481 const ROWS: usize,
482 const COLS: usize,
483 const NROWS: usize,
484 const BITS: u8,
485 const FRAME_COUNT: usize,
486 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
487{
488 #[must_use]
511 pub fn new() -> Self {
512 debug_assert!(BITS <= 8);
513
514 let mut instance = Self {
515 _align: 0,
516 data: FrameData::new(),
517 };
518
519 instance.format();
521 instance
522 }
523
524 #[must_use]
527 pub const fn bcm_chunk_count() -> usize {
528 1
529 }
530
531 #[must_use]
535 pub const fn bcm_chunk_bytes() -> usize {
536 core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>()
537 }
538
539 #[inline]
559 pub fn format(&mut self) {
560 for frame in &mut self.data.frames {
561 frame.format();
562 }
563 #[cfg(feature = "tail-closes-latch")]
564 {
565 self.data.tail.0 = 0x1f | OE_BLANK;
566 }
567 #[cfg(all(feature = "esp32-ordering", feature = "tail-closes-latch"))]
568 {
569 self.data.padding.0 = 0x1f | OE_BLANK;
570 }
571 }
572
573 #[inline]
593 pub fn erase(&mut self) {
594 for frame in &mut self.data.frames {
595 frame.clear_colors();
596 }
597 }
598
599 pub fn set_pixel(&mut self, p: Point, color: Color) {
615 if p.x < 0 || p.y < 0 {
616 return;
617 }
618 self.set_pixel_internal(p.x as usize, p.y as usize, color);
619 }
620
621 #[inline]
622 fn frames_on(v: u8) -> usize {
623 (v as usize) >> (8 - BITS)
625 }
626
627 #[inline]
628 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Color) {
629 if x >= COLS || y >= ROWS {
630 return;
631 }
632
633 #[cfg(feature = "skip-black-pixels")]
636 if color == Color::BLACK {
637 return;
638 }
639
640 let red_frames = Self::frames_on(color.r());
642 let green_frames = Self::frames_on(color.g());
643 let blue_frames = Self::frames_on(color.b());
644
645 for (frame_idx, frame) in self.data.frames.iter_mut().enumerate() {
647 frame.set_pixel(
648 y,
649 x,
650 frame_idx < red_frames,
651 frame_idx < green_frames,
652 frame_idx < blue_frames,
653 );
654 }
655 }
656}
657
658impl<
659 const ROWS: usize,
660 const COLS: usize,
661 const NROWS: usize,
662 const BITS: u8,
663 const FRAME_COUNT: usize,
664 > FrameBufferOperations for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
665{
666 #[inline]
667 fn erase(&mut self) {
668 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
669 }
670
671 #[inline]
672 fn set_pixel(&mut self, p: Point, color: Color) {
673 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
674 }
675}
676
677impl<
678 const ROWS: usize,
679 const COLS: usize,
680 const NROWS: usize,
681 const BITS: u8,
682 const FRAME_COUNT: usize,
683 > embedded_graphics::prelude::OriginDimensions
684 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
685{
686 fn size(&self) -> embedded_graphics::prelude::Size {
687 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
688 }
689}
690
691impl<
692 const ROWS: usize,
693 const COLS: usize,
694 const NROWS: usize,
695 const BITS: u8,
696 const FRAME_COUNT: usize,
697 > embedded_graphics::prelude::OriginDimensions
698 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
699{
700 fn size(&self) -> embedded_graphics::prelude::Size {
701 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
702 }
703}
704
705impl<
706 const ROWS: usize,
707 const COLS: usize,
708 const NROWS: usize,
709 const BITS: u8,
710 const FRAME_COUNT: usize,
711 > embedded_graphics::draw_target::DrawTarget
712 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
713{
714 type Color = Color;
715
716 type Error = Infallible;
717
718 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
719 where
720 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
721 {
722 for pixel in pixels {
723 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
724 }
725 Ok(())
726 }
727}
728
729unsafe impl<
730 const ROWS: usize,
731 const COLS: usize,
732 const NROWS: usize,
733 const BITS: u8,
734 const FRAME_COUNT: usize,
735 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
736{
737 type Word = u8;
738
739 unsafe fn read_buffer(&self) -> (*const u8, usize) {
740 let ptr = (&raw const self.data).cast::<u8>();
741 let len = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
742 (ptr, len)
743 }
744}
745
746unsafe impl<
747 const ROWS: usize,
748 const COLS: usize,
749 const NROWS: usize,
750 const BITS: u8,
751 const FRAME_COUNT: usize,
752 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
753{
754 type Word = u8;
755
756 unsafe fn read_buffer(&self) -> (*const u8, usize) {
757 let ptr = (&raw const self.data).cast::<u8>();
758 let len = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
759 (ptr, len)
760 }
761}
762
763impl<
764 const ROWS: usize,
765 const COLS: usize,
766 const NROWS: usize,
767 const BITS: u8,
768 const FRAME_COUNT: usize,
769 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
770{
771 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
772 let brightness_step = 1 << (8 - BITS);
773 let size = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
774 f.debug_struct("DmaFrameBuffer")
775 .field("size", &size)
776 .field("frame_count", &self.data.frames.len())
777 .field("frame_size", &core::mem::size_of_val(&self.data.frames[0]))
778 .field("brightness_step", &&brightness_step)
779 .finish_non_exhaustive()
780 }
781}
782
783#[cfg(feature = "defmt")]
784impl<
785 const ROWS: usize,
786 const COLS: usize,
787 const NROWS: usize,
788 const BITS: u8,
789 const FRAME_COUNT: usize,
790 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
791{
792 fn format(&self, f: defmt::Formatter) {
793 let brightness_step = 1 << (8 - BITS);
794 defmt::write!(
795 f,
796 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
797 ROWS,
798 COLS,
799 NROWS,
800 BITS,
801 FRAME_COUNT
802 );
803 defmt::write!(
804 f,
805 " size: {}",
806 core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>()
807 );
808 defmt::write!(
809 f,
810 " frame_size: {}",
811 core::mem::size_of_val(&self.data.frames[0])
812 );
813 defmt::write!(f, " brightness_step: {}", brightness_step);
814 }
815}
816
817impl<
818 const ROWS: usize,
819 const COLS: usize,
820 const NROWS: usize,
821 const BITS: u8,
822 const FRAME_COUNT: usize,
823 > FrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
824{
825 type Word = u16;
826
827 fn plane_count(&self) -> usize {
828 1
829 }
830
831 fn plane_ptr_len(&self, plane_idx: usize) -> (*const u8, usize) {
832 assert!(plane_idx == 0, "plain DmaFrameBuffer has only 1 plane");
833 let ptr = (&raw const self.data).cast::<u8>();
834 let len = core::mem::size_of::<FrameData<ROWS, COLS, NROWS, FRAME_COUNT>>();
835 (ptr, len)
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 > MutableFrameBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
846{
847}
848
849#[cfg(test)]
850mod tests {
851 extern crate std;
852
853 use std::format;
854 use std::vec;
855
856 use super::*;
857 use crate::{FrameBuffer, WordSize};
858 use embedded_graphics::pixelcolor::RgbColor;
859 use embedded_graphics::prelude::*;
860 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
861
862 const TEST_ROWS: usize = 32;
863 const TEST_COLS: usize = 64;
864 const TEST_NROWS: usize = TEST_ROWS / 2;
865 const TEST_BITS: u8 = 3;
866 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
869 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
870
871 fn get_mapped_index(index: usize) -> usize {
873 map_index(index)
874 }
875
876 #[test]
877 fn test_entry_construction() {
878 let entry = Entry::new();
879 let expect_oe = cfg!(feature = "invert-oe");
880 assert_eq!(entry.dummy2(), false);
881 assert_eq!(entry.blu2(), false);
882 assert_eq!(entry.grn2(), false);
883 assert_eq!(entry.red2(), false);
884 assert_eq!(entry.blu1(), false);
885 assert_eq!(entry.grn1(), false);
886 assert_eq!(entry.red1(), false);
887 assert_eq!(entry.output_enable(), expect_oe);
888 assert_eq!(entry.dummy1(), false);
889 assert_eq!(entry.dummy0(), false);
890 assert_eq!(entry.latch(), false);
891 assert_eq!(entry.addr(), 0);
892 }
893
894 #[test]
895 fn test_entry_setters() {
896 let mut entry = Entry::new();
897
898 entry.set_dummy2(true);
899 assert_eq!(entry.dummy2(), true);
900 assert_eq!(entry.0 & 0b1000000000000000, 0b1000000000000000);
901
902 entry.set_blu2(true);
903 assert_eq!(entry.blu2(), true);
904 assert_eq!(entry.0 & 0b0100000000000000, 0b0100000000000000);
905
906 entry.set_grn2(true);
907 assert_eq!(entry.grn2(), true);
908 assert_eq!(entry.0 & 0b0010000000000000, 0b0010000000000000);
909
910 entry.set_red2(true);
911 assert_eq!(entry.red2(), true);
912 assert_eq!(entry.0 & 0b0001000000000000, 0b0001000000000000);
913
914 entry.set_blu1(true);
915 assert_eq!(entry.blu1(), true);
916 assert_eq!(entry.0 & 0b0000100000000000, 0b0000100000000000);
917
918 entry.set_grn1(true);
919 assert_eq!(entry.grn1(), true);
920 assert_eq!(entry.0 & 0b0000010000000000, 0b0000010000000000);
921
922 entry.set_red1(true);
923 assert_eq!(entry.red1(), true);
924 assert_eq!(entry.0 & 0b0000001000000000, 0b0000001000000000);
925
926 entry.set_output_enable(true);
927 assert_eq!(entry.output_enable(), true);
928 assert_eq!(entry.0 & 0b0000000100000000, 0b0000000100000000);
929
930 entry.set_dummy1(true);
931 assert_eq!(entry.dummy1(), true);
932 assert_eq!(entry.0 & 0b0000000010000000, 0b0000000010000000);
933
934 entry.set_dummy0(true);
935 assert_eq!(entry.dummy0(), true);
936 assert_eq!(entry.0 & 0b0000000001000000, 0b0000000001000000);
937
938 entry.set_latch(true);
939 assert_eq!(entry.latch(), true);
940 assert_eq!(entry.0 & 0b0000000000100000, 0b0000000000100000);
941
942 entry.set_addr(0b11111);
943 assert_eq!(entry.addr(), 0b11111);
944 assert_eq!(entry.0 & 0b0000000000011111, 0b0000000000011111);
945 }
946
947 #[test]
948 fn test_entry_bit_isolation() {
949 let mut entry = Entry::new();
950 let expect_oe = cfg!(feature = "invert-oe");
951
952 entry.set_addr(0b11111);
954 entry.set_latch(true);
955 assert_eq!(entry.addr(), 0b11111);
956 assert_eq!(entry.latch(), true);
957 assert_eq!(entry.output_enable(), expect_oe);
958 assert_eq!(entry.red1(), false);
959
960 entry.set_red1(true);
961 entry.set_grn2(true);
962 assert_eq!(entry.addr(), 0b11111);
963 assert_eq!(entry.latch(), true);
964 assert_eq!(entry.red1(), true);
965 assert_eq!(entry.grn2(), true);
966 assert_eq!(entry.blu1(), false);
967 assert_eq!(entry.red2(), false);
968 }
969
970 #[test]
971 fn test_entry_set_color0() {
972 let mut entry = Entry::new();
973
974 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
976 assert_eq!(entry.red1(), true);
977 assert_eq!(entry.grn1(), false);
978 assert_eq!(entry.blu1(), true);
979 assert_eq!(entry.0 & 0b0000101000000000, 0b0000101000000000); }
982
983 #[test]
984 fn test_entry_set_color1() {
985 let mut entry = Entry::new();
986
987 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
989 assert_eq!(entry.red2(), false);
990 assert_eq!(entry.grn2(), true);
991 assert_eq!(entry.blu2(), true);
992 assert_eq!(entry.0 & 0b0110000000000000, 0b0110000000000000); }
995
996 #[test]
997 fn test_entry_debug_formatting() {
998 let entry = Entry(0x1234);
999 let debug_str = format!("{:?}", entry);
1000 assert_eq!(debug_str, "Entry(0x1234)");
1001
1002 let entry = Entry(0xabcd);
1003 let debug_str = format!("{:?}", entry);
1004 assert_eq!(debug_str, "Entry(0xabcd)");
1005 }
1006
1007 #[test]
1008 fn test_row_construction() {
1009 let row: Row<TEST_COLS> = Row::new();
1010 assert_eq!(row.data.len(), TEST_COLS);
1011
1012 let expected = Entry::new().0;
1013 for entry in &row.data {
1014 assert_eq!(entry.0, expected);
1015 }
1016 }
1017
1018 #[test]
1019 fn test_row_format() {
1020 let mut row: Row<TEST_COLS> = Row::new();
1021 let test_addr = 5;
1022 let prev_addr = 4;
1023
1024 row.format(test_addr, prev_addr);
1025
1026 let oe_active = !cfg!(feature = "invert-oe");
1027
1028 for (physical_i, entry) in row.data.iter().enumerate() {
1030 let logical_i = get_mapped_index(physical_i);
1031
1032 match logical_i {
1033 i if i == TEST_COLS - 1 => {
1034 assert_eq!(entry.latch(), true);
1035 assert_eq!(entry.addr(), test_addr as u16);
1036 assert_eq!(entry.output_enable(), !oe_active);
1037 }
1038 _ => {
1039 assert_eq!(entry.addr(), prev_addr as u16);
1040 assert_eq!(entry.latch(), false);
1041 if logical_i >= BLANKING_DELAY && logical_i < TEST_COLS - BLANKING_DELAY - 1 {
1042 assert_eq!(entry.output_enable(), oe_active);
1043 } else {
1044 assert_eq!(entry.output_enable(), !oe_active);
1045 }
1046 }
1047 }
1048 }
1049 }
1050
1051 #[test]
1052 fn test_row_set_color0() {
1053 let mut row: Row<TEST_COLS> = Row::new();
1054
1055 row.set_color0(0, true, false, true);
1056
1057 let mapped_col_0 = get_mapped_index(0);
1058 assert_eq!(row.data[mapped_col_0].red1(), true);
1059 assert_eq!(row.data[mapped_col_0].grn1(), false);
1060 assert_eq!(row.data[mapped_col_0].blu1(), true);
1061
1062 row.set_color0(1, false, true, false);
1064
1065 let mapped_col_1 = get_mapped_index(1);
1066 assert_eq!(row.data[mapped_col_1].red1(), false);
1067 assert_eq!(row.data[mapped_col_1].grn1(), true);
1068 assert_eq!(row.data[mapped_col_1].blu1(), false);
1069 }
1070
1071 #[test]
1072 fn test_row_set_color1() {
1073 let mut row: Row<TEST_COLS> = Row::new();
1074
1075 row.set_color1(0, true, true, false);
1076
1077 let mapped_col_0 = get_mapped_index(0);
1078 assert_eq!(row.data[mapped_col_0].red2(), true);
1079 assert_eq!(row.data[mapped_col_0].grn2(), true);
1080 assert_eq!(row.data[mapped_col_0].blu2(), false);
1081 }
1082
1083 #[test]
1084 fn test_row_default() {
1085 let row1: Row<TEST_COLS> = Row::new();
1086 let row2: Row<TEST_COLS> = Row::default();
1087
1088 assert_eq!(row1, row2);
1090 assert_eq!(row1.data.len(), row2.data.len());
1091
1092 let expected = Entry::new().0;
1093 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1094 assert_eq!(entry1.0, entry2.0);
1095 assert_eq!(entry1.0, expected);
1096 }
1097 }
1098
1099 #[test]
1100 fn test_frame_construction() {
1101 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1102 assert_eq!(frame.rows.len(), TEST_NROWS);
1103 }
1104
1105 #[test]
1106 fn test_frame_format() {
1107 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1108
1109 frame.format();
1110
1111 for addr in 0..TEST_NROWS {
1113 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1114
1115 let row = &frame.rows[addr];
1117
1118 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1120 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1121 assert_eq!(row.data[last_pixel_idx].latch(), true);
1122
1123 let first_pixel_idx = get_mapped_index(0);
1125 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1126 assert_eq!(row.data[first_pixel_idx].latch(), false);
1127 }
1128 }
1129
1130 #[test]
1131 fn test_frame_set_pixel() {
1132 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1133
1134 frame.set_pixel(5, 10, true, false, true);
1136
1137 let mapped_col_10 = get_mapped_index(10);
1138 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1139 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1140 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1141
1142 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1144
1145 let mapped_col_15 = get_mapped_index(15);
1146 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1147 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1148 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1149 }
1150
1151 #[test]
1152 fn test_frame_default() {
1153 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1154 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1155
1156 assert_eq!(frame1.rows.len(), frame2.rows.len());
1158
1159 let expected = Entry::new().0;
1160 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1161 assert_eq!(row1, row2);
1162
1163 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1164 assert_eq!(entry1.0, entry2.0);
1165 assert_eq!(entry1.0, expected);
1166 }
1167 }
1168 }
1169
1170 #[test]
1171 fn test_dma_framebuffer_construction() {
1172 let fb = TestFrameBuffer::new();
1173 assert_eq!(fb.data.frames.len(), TEST_FRAME_COUNT);
1174 assert_eq!(fb._align, 0);
1175 }
1176
1177 #[test]
1178 fn test_bcm_chunk_info() {
1179 let expected_size =
1180 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>();
1181 assert_eq!(TestFrameBuffer::bcm_chunk_bytes(), expected_size);
1182 assert_eq!(TestFrameBuffer::bcm_chunk_count(), 1);
1183 }
1184
1185 #[test]
1186 fn test_dma_framebuffer_erase() {
1187 let fb = TestFrameBuffer::new();
1188
1189 for frame in &fb.data.frames {
1191 for addr in 0..TEST_NROWS {
1192 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1193
1194 let row = &frame.rows[addr];
1196
1197 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1199 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1200 assert_eq!(row.data[last_pixel_idx].latch(), true);
1201
1202 let first_pixel_idx = get_mapped_index(0);
1204 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1205 assert_eq!(row.data[first_pixel_idx].latch(), false);
1206 }
1207 }
1208 }
1209
1210 #[test]
1211 fn test_dma_framebuffer_set_pixel_bounds() {
1212 let mut fb = TestFrameBuffer::new();
1213
1214 fb.set_pixel(Point::new(-1, 5), Color::RED);
1216 fb.set_pixel(Point::new(5, -1), Color::RED);
1217
1218 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1220 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1221 }
1222
1223 #[test]
1224 fn test_dma_framebuffer_set_pixel_internal() {
1225 let mut fb = TestFrameBuffer::new();
1226
1227 let red_color = Color::RED;
1228 fb.set_pixel_internal(10, 5, red_color);
1229
1230 for frame in &fb.data.frames {
1234 let mapped_col_10 = get_mapped_index(10);
1236 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1237 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1238 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1239 }
1240 }
1241
1242 #[test]
1243 fn test_dma_framebuffer_brightness_modulation() {
1244 let mut fb = TestFrameBuffer::new();
1245
1246 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Color::from(embedded_graphics::pixelcolor::Rgb888::new(
1250 test_brightness,
1251 0,
1252 0,
1253 ));
1254
1255 fb.set_pixel_internal(0, 0, color);
1256
1257 for (frame_idx, frame) in fb.data.frames.iter().enumerate() {
1260 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1261 let should_be_active = test_brightness >= frame_threshold;
1262
1263 let mapped_col_0 = get_mapped_index(0);
1264 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1265 }
1266 }
1267
1268 #[test]
1269 fn test_origin_dimensions() {
1270 let fb = TestFrameBuffer::new();
1271 let size = fb.size();
1272 assert_eq!(size.width, TEST_COLS as u32);
1273 assert_eq!(size.height, TEST_ROWS as u32);
1274
1275 let size = (&fb).size();
1277 assert_eq!(size.width, TEST_COLS as u32);
1278 assert_eq!(size.height, TEST_ROWS as u32);
1279
1280 let mut fb = TestFrameBuffer::new();
1282 let fb_ref = &mut fb;
1283 let size = fb_ref.size();
1284 assert_eq!(size.width, TEST_COLS as u32);
1285 assert_eq!(size.height, TEST_ROWS as u32);
1286 }
1287
1288 #[test]
1289 fn test_draw_target() {
1290 let mut fb = TestFrameBuffer::new();
1291
1292 let pixels = vec![
1293 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1294 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1295 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1296 ];
1297
1298 let result = fb.draw_iter(pixels);
1299 assert!(result.is_ok());
1300
1301 let result = (&mut fb).draw_iter(vec![embedded_graphics::Pixel(
1303 Point::new(3, 3),
1304 Color::WHITE,
1305 )]);
1306 assert!(result.is_ok());
1307 }
1308
1309 #[test]
1310 fn test_draw_iter_pixel_verification() {
1311 let mut fb = TestFrameBuffer::new();
1312
1313 let pixels = vec![
1315 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), ];
1327
1328 let result = fb.draw_iter(pixels);
1329 assert!(result.is_ok());
1330
1331 let first_frame = &fb.data.frames[0];
1333 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = get_mapped_index(5);
1339 assert_eq!(
1340 first_frame.rows[2].data[col_idx].red1(),
1341 Color::RED.r() >= first_frame_threshold
1342 );
1343 assert_eq!(
1344 first_frame.rows[2].data[col_idx].grn1(),
1345 Color::RED.g() >= first_frame_threshold
1346 );
1347 assert_eq!(
1348 first_frame.rows[2].data[col_idx].blu1(),
1349 Color::RED.b() >= first_frame_threshold
1350 );
1351
1352 let col_idx = get_mapped_index(10);
1354 assert_eq!(
1355 first_frame.rows[5].data[col_idx].red1(),
1356 Color::GREEN.r() >= first_frame_threshold
1357 );
1358 assert_eq!(
1359 first_frame.rows[5].data[col_idx].grn1(),
1360 Color::GREEN.g() >= first_frame_threshold
1361 );
1362 assert_eq!(
1363 first_frame.rows[5].data[col_idx].blu1(),
1364 Color::GREEN.b() >= first_frame_threshold
1365 );
1366
1367 let col_idx = get_mapped_index(15);
1369 assert_eq!(
1370 first_frame.rows[8].data[col_idx].red1(),
1371 Color::BLUE.r() >= first_frame_threshold
1372 );
1373 assert_eq!(
1374 first_frame.rows[8].data[col_idx].grn1(),
1375 Color::BLUE.g() >= first_frame_threshold
1376 );
1377 assert_eq!(
1378 first_frame.rows[8].data[col_idx].blu1(),
1379 Color::BLUE.b() >= first_frame_threshold
1380 );
1381
1382 let col_idx = get_mapped_index(20);
1384 assert_eq!(
1385 first_frame.rows[10].data[col_idx].red1(),
1386 Color::WHITE.r() >= first_frame_threshold
1387 );
1388 assert_eq!(
1389 first_frame.rows[10].data[col_idx].grn1(),
1390 Color::WHITE.g() >= first_frame_threshold
1391 );
1392 assert_eq!(
1393 first_frame.rows[10].data[col_idx].blu1(),
1394 Color::WHITE.b() >= first_frame_threshold
1395 );
1396
1397 let col_idx = get_mapped_index(25);
1400 assert_eq!(
1401 first_frame.rows[3].data[col_idx].red2(),
1402 Color::RED.r() >= first_frame_threshold
1403 );
1404 assert_eq!(
1405 first_frame.rows[3].data[col_idx].grn2(),
1406 Color::RED.g() >= first_frame_threshold
1407 );
1408 assert_eq!(
1409 first_frame.rows[3].data[col_idx].blu2(),
1410 Color::RED.b() >= first_frame_threshold
1411 );
1412
1413 let col_idx = get_mapped_index(30);
1415 assert_eq!(
1416 first_frame.rows[7].data[col_idx].red2(),
1417 Color::GREEN.r() >= first_frame_threshold
1418 );
1419 assert_eq!(
1420 first_frame.rows[7].data[col_idx].grn2(),
1421 Color::GREEN.g() >= first_frame_threshold
1422 );
1423 assert_eq!(
1424 first_frame.rows[7].data[col_idx].blu2(),
1425 Color::GREEN.b() >= first_frame_threshold
1426 );
1427
1428 let col_idx = get_mapped_index(35);
1430 assert_eq!(
1431 first_frame.rows[12].data[col_idx].red2(),
1432 Color::BLUE.r() >= first_frame_threshold
1433 );
1434 assert_eq!(
1435 first_frame.rows[12].data[col_idx].grn2(),
1436 Color::BLUE.g() >= first_frame_threshold
1437 );
1438 assert_eq!(
1439 first_frame.rows[12].data[col_idx].blu2(),
1440 Color::BLUE.b() >= first_frame_threshold
1441 );
1442
1443 let col_idx = get_mapped_index(40);
1445 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1446 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1447 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1448 }
1449
1450 #[test]
1451 fn test_embedded_graphics_integration() {
1452 let mut fb = TestFrameBuffer::new();
1453
1454 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1456 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1457 .draw(&mut fb);
1458 assert!(result.is_ok());
1459
1460 let result = Circle::new(Point::new(30, 15), 8)
1462 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1463 .draw(&mut fb);
1464 assert!(result.is_ok());
1465 }
1466
1467 #[test]
1468 #[cfg(feature = "skip-black-pixels")]
1469 fn test_skip_black_pixels_enabled() {
1470 let mut fb = TestFrameBuffer::new();
1471
1472 fb.set_pixel_internal(10, 5, Color::RED);
1474
1475 let mapped_col_10 = get_mapped_index(10);
1477 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1478 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1479 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1480
1481 fb.set_pixel_internal(10, 5, Color::BLACK);
1483
1484 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1486 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1487 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1488 }
1489
1490 #[test]
1491 #[cfg(not(feature = "skip-black-pixels"))]
1492 fn test_skip_black_pixels_disabled() {
1493 let mut fb = TestFrameBuffer::new();
1494
1495 fb.set_pixel_internal(10, 5, Color::RED);
1497
1498 let mapped_col_10 = get_mapped_index(10);
1500 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1501 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1502 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1503
1504 fb.set_pixel_internal(10, 5, Color::BLACK);
1506
1507 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), false);
1509 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1510 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1511 }
1512
1513 #[test]
1514 fn test_bcm_frame_overwrite() {
1515 let mut fb = TestFrameBuffer::new();
1516
1517 fb.set_pixel_internal(10, 5, Color::WHITE);
1519
1520 let mapped_col_10 = get_mapped_index(10);
1521
1522 for frame in fb.data.frames.iter() {
1524 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1526 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1527 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1528 }
1529
1530 let half_white = Color::from(embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128));
1532 fb.set_pixel_internal(10, 5, half_white);
1533
1534 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.data.frames.iter().enumerate() {
1540 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1541 let should_be_active = 128 >= frame_threshold;
1542
1543 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1544 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1545 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1546 }
1547
1548 for frame_idx in 0..4 {
1551 assert_eq!(
1552 fb.data.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1553 true
1554 );
1555 }
1556 for frame_idx in 4..TEST_FRAME_COUNT {
1558 assert_eq!(
1559 fb.data.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1560 false
1561 );
1562 }
1563 }
1564
1565 #[test]
1566 fn test_read_buffer_implementation() {
1567 let fb = TestFrameBuffer::new();
1569 let expected_size =
1570 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>();
1571
1572 unsafe {
1574 let (ptr, len) = <TestFrameBuffer as ReadBuffer>::read_buffer(&fb);
1575 assert!(!ptr.is_null());
1576 assert_eq!(len, expected_size);
1577 }
1578
1579 unsafe {
1581 let (ptr, len) = fb.read_buffer();
1582 assert!(!ptr.is_null());
1583 assert_eq!(len, expected_size);
1584 }
1585
1586 let fb = TestFrameBuffer::new();
1588 let fb_ref = &fb;
1589 unsafe {
1590 let (ptr, len) = fb_ref.read_buffer();
1591 assert!(!ptr.is_null());
1592 assert_eq!(
1593 len,
1594 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>(
1595 )
1596 );
1597 }
1598
1599 let mut fb = TestFrameBuffer::new();
1601 let fb_ref = &mut fb;
1602 unsafe {
1603 let (ptr, len) = fb_ref.read_buffer();
1604 assert!(!ptr.is_null());
1605 assert_eq!(
1606 len,
1607 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>(
1608 )
1609 );
1610 }
1611 }
1612
1613 #[test]
1614 fn test_read_buffer_owned_implementation() {
1615 fn test_owned_read_buffer(fb: TestFrameBuffer) -> (bool, usize) {
1618 unsafe {
1619 let (ptr, len) = fb.read_buffer();
1620 (!ptr.is_null(), len)
1621 }
1622 }
1623
1624 let fb = TestFrameBuffer::new();
1625 let expected_len =
1626 core::mem::size_of::<FrameData<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_FRAME_COUNT>>();
1627
1628 let (ptr_valid, actual_len) = test_owned_read_buffer(fb);
1629 assert!(ptr_valid);
1630 assert_eq!(actual_len, expected_len);
1631 }
1632
1633 #[test]
1634 fn test_framebuffer_trait() {
1635 let fb = TestFrameBuffer::new();
1636 assert_eq!(fb.get_word_size(), WordSize::Sixteen);
1637
1638 let fb_ref = &fb;
1639 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1640
1641 let mut fb = TestFrameBuffer::new();
1642 let fb_ref = &mut fb;
1643 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1644 }
1645
1646 #[test]
1647 fn test_debug_formatting() {
1648 let fb = TestFrameBuffer::new();
1649 let debug_string = format!("{:?}", fb);
1650 assert!(debug_string.contains("DmaFrameBuffer"));
1651 assert!(debug_string.contains("frame_count"));
1652 assert!(debug_string.contains("frame_size"));
1653 assert!(debug_string.contains("brightness_step"));
1654 }
1655
1656 #[test]
1657 fn test_default_implementation() {
1658 let fb1 = TestFrameBuffer::new();
1659 let fb2 = TestFrameBuffer::default();
1660
1661 assert_eq!(fb1.data.frames.len(), fb2.data.frames.len());
1663 assert_eq!(fb1._align, fb2._align);
1664 }
1665
1666 #[test]
1667 fn test_memory_alignment() {
1668 let fb = TestFrameBuffer::new();
1669 let ptr = &fb as *const _ as usize;
1670
1671 assert_eq!(ptr % 8, 0);
1673 }
1674
1675 #[test]
1676 fn test_color_values() {
1677 let mut fb = TestFrameBuffer::new();
1678
1679 let colors = [
1681 (Color::RED, (255, 0, 0)),
1682 (Color::GREEN, (0, 255, 0)),
1683 (Color::BLUE, (0, 0, 255)),
1684 (Color::WHITE, (255, 255, 255)),
1685 (Color::BLACK, (0, 0, 0)),
1686 ];
1687
1688 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1689 fb.set_pixel(Point::new(i as i32, 0), *color);
1690 assert_eq!(color.r(), *r);
1691 assert_eq!(color.g(), *g);
1692 assert_eq!(color.b(), *b);
1693 }
1694 }
1695
1696 #[test]
1697 fn test_blanking_delay() {
1698 let mut row: Row<TEST_COLS> = Row::new();
1699 let test_addr = 5;
1700 let prev_addr = 4;
1701
1702 row.format(test_addr, prev_addr);
1703
1704 let oe_active = !cfg!(feature = "invert-oe");
1705
1706 let blanking_pixel_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 1);
1707 assert_eq!(row.data[blanking_pixel_idx].output_enable(), !oe_active);
1708
1709 let before_blanking_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 2);
1710 assert_eq!(row.data[before_blanking_idx].output_enable(), oe_active);
1711 }
1712
1713 #[test]
1714 fn test_esp32_mapping() {
1715 #[cfg(feature = "esp32-ordering")]
1717 {
1718 assert_eq!(map_index(0), 1);
1719 assert_eq!(map_index(1), 0);
1720 assert_eq!(map_index(2), 3);
1721 assert_eq!(map_index(3), 2);
1722 assert_eq!(map_index(4), 5);
1723 assert_eq!(map_index(5), 4);
1724 }
1725 #[cfg(not(feature = "esp32-ordering"))]
1726 {
1727 assert_eq!(map_index(0), 0);
1728 assert_eq!(map_index(1), 1);
1729 assert_eq!(map_index(2), 2);
1730 assert_eq!(map_index(3), 3);
1731 }
1732 }
1733
1734 #[test]
1735 fn test_bits_assertion() {
1736 assert!(TEST_BITS <= 8);
1739 }
1740
1741 #[test]
1742 fn test_fast_clear_method() {
1743 let mut fb = TestFrameBuffer::new();
1744
1745 fb.set_pixel_internal(10, 5, Color::RED);
1747 fb.set_pixel_internal(20, 10, Color::GREEN);
1748
1749 let mapped_col_10 = get_mapped_index(10);
1751 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), true);
1752
1753 fb.erase();
1755
1756 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].red1(), false);
1758 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1759 assert_eq!(fb.data.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1760
1761 let last_col = get_mapped_index(TEST_COLS - 1);
1763 assert_eq!(fb.data.frames[0].rows[5].data[last_col].latch(), true);
1764 }
1765
1766 const CHAR_W: i32 = 6;
1770 const CHAR_H: i32 = 10;
1771
1772 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1774 use embedded_graphics::mock_display::MockDisplay;
1775 use embedded_graphics::mono_font::ascii::FONT_6X10;
1776 use embedded_graphics::mono_font::MonoTextStyle;
1777 use embedded_graphics::text::{Baseline, Text};
1778
1779 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1781 Text::with_baseline("A", origin, style, Baseline::Top)
1782 .draw(fb)
1783 .unwrap();
1784
1785 let mut reference: MockDisplay<Color> = MockDisplay::new();
1787 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1788 .draw(&mut reference)
1789 .unwrap();
1790
1791 for dy in 0..CHAR_H {
1792 for dx in 0..CHAR_W {
1793 let expected_on = reference
1794 .get_pixel(Point::new(dx, dy))
1795 .unwrap_or(Color::BLACK)
1796 != Color::BLACK;
1797
1798 let gx = (origin.x + dx) as usize;
1799 let gy = (origin.y + dy) as usize;
1800
1801 let frame0 = &fb.data.frames[0];
1808 let e = if gy < TEST_NROWS {
1809 &frame0.rows[gy].data[get_mapped_index(gx)]
1810 } else {
1811 &frame0.rows[gy - TEST_NROWS].data[get_mapped_index(gx)]
1812 };
1813
1814 let (r, g, b) = if gy >= TEST_NROWS {
1815 (e.red2(), e.grn2(), e.blu2())
1816 } else {
1817 (e.red1(), e.grn1(), e.blu1())
1818 };
1819
1820 if expected_on {
1821 assert!(r && g && b,);
1822 } else {
1823 assert!(!r && !g && !b);
1824 }
1825 }
1826 }
1827 }
1828
1829 #[test]
1830 fn test_draw_char_corners() {
1831 let upper_left = Point::new(0, 0);
1832 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1833
1834 let mut fb = TestFrameBuffer::new();
1835
1836 verify_glyph_at(&mut fb, upper_left);
1837 verify_glyph_at(&mut fb, lower_right);
1838 }
1839
1840 #[test]
1841 fn test_framebuffer_operations_trait_erase() {
1842 let mut fb = TestFrameBuffer::new();
1843
1844 fb.set_pixel_internal(10, 5, Color::RED);
1846 fb.set_pixel_internal(20, 10, Color::GREEN);
1847
1848 <TestFrameBuffer as FrameBufferOperations>::erase(&mut fb);
1850
1851 let mc10 = get_mapped_index(10);
1853 let mc20 = get_mapped_index(20);
1854 assert_eq!(fb.data.frames[0].rows[5].data[mc10].red1(), false);
1855 assert_eq!(fb.data.frames[0].rows[10].data[mc20].grn1(), false);
1856
1857 let last_col = get_mapped_index(TEST_COLS - 1);
1859 assert!(fb.data.frames[0].rows[0].data[last_col].latch());
1860 }
1861
1862 #[test]
1863 fn test_framebuffer_operations_trait_set_pixel() {
1864 let mut fb = TestFrameBuffer::new();
1865
1866 <TestFrameBuffer as FrameBufferOperations>::set_pixel(
1868 &mut fb,
1869 Point::new(8, 3),
1870 Color::BLUE,
1871 );
1872
1873 let idx = get_mapped_index(8);
1874 assert_eq!(fb.data.frames[0].rows[3].data[idx].blu1(), true);
1875 assert_eq!(fb.data.frames[0].rows[3].data[idx].red1(), false);
1876 assert_eq!(fb.data.frames[0].rows[3].data[idx].grn1(), false);
1877 }
1878
1879 #[test]
1880 fn test_entry_new_oe_matches_feature() {
1881 let entry = Entry::new();
1882 if cfg!(feature = "invert-oe") {
1883 assert!(entry.output_enable());
1884 } else {
1885 assert!(!entry.output_enable());
1886 }
1887 }
1888
1889 #[test]
1890 fn test_make_data_template_oe_polarity() {
1891 let mut row = Row::<TEST_COLS>::new();
1892 row.format(5, 4);
1893
1894 let active_idx = get_mapped_index(BLANKING_DELAY);
1895 let blank_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 1);
1896 let latch_idx = get_mapped_index(TEST_COLS - 1);
1897
1898 if cfg!(feature = "invert-oe") {
1899 assert!(!row.data[active_idx].output_enable());
1900 assert!(row.data[blank_idx].output_enable());
1901 assert!(row.data[latch_idx].output_enable());
1902 } else {
1903 assert!(row.data[active_idx].output_enable());
1904 assert!(!row.data[blank_idx].output_enable());
1905 assert!(!row.data[latch_idx].output_enable());
1906 }
1907 }
1908}