1#![cfg_attr(feature = "doc-images",
22cfg_attr(all(),
23doc = ::embed_doc_image::embed_image!("latch-circuit", "images/latch-circuit.png")))]
24#![cfg_attr(
25 not(feature = "doc-images"),
26 doc = "**Doc images not enabled**. Compile with feature `doc-images` and Rust version >= 1.54 \
27 to enable."
28)]
29use core::convert::Infallible;
173
174use super::Color;
175use crate::FrameBufferOperations;
176use bitfield::bitfield;
177#[cfg(not(feature = "esp-hal-dma"))]
178use embedded_dma::ReadBuffer;
179use embedded_graphics::pixelcolor::Rgb888;
180use embedded_graphics::pixelcolor::RgbColor;
181use embedded_graphics::prelude::Point;
182#[cfg(feature = "esp-hal-dma")]
183use esp_hal::dma::ReadBuffer;
184
185bitfield! {
186 #[derive(Clone, Copy, Default, PartialEq, Eq)]
221 #[repr(transparent)]
222 struct Address(u8);
223 impl Debug;
224 pub output_enable, set_output_enable: 7;
225 pub latch, set_latch: 6;
226 pub addr, set_addr: 4, 0;
227}
228
229impl Address {
230 pub const fn new() -> Self {
231 Self(0)
232 }
233}
234
235bitfield! {
236 #[derive(Clone, Copy, Default, PartialEq)]
253 #[repr(transparent)]
254 struct Entry(u8);
255 impl Debug;
256 pub output_enable, set_output_enable: 7;
257 pub latch, set_latch: 6;
258 pub blu2, set_blu2: 5;
259 pub grn2, set_grn2: 4;
260 pub red2, set_red2: 3;
261 pub blu1, set_blu1: 2;
262 pub grn1, set_grn1: 1;
263 pub red1, set_red1: 0;
264}
265
266impl Entry {
267 pub const fn new() -> Self {
268 Self(0)
269 }
270
271 const COLOR0_MASK: u8 = 0b0000_0111; const COLOR1_MASK: u8 = 0b0011_1000; #[inline]
276 fn set_color0_bits(&mut self, bits: u8) {
277 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits & Self::COLOR0_MASK);
278 }
279
280 #[inline]
281 fn set_color1_bits(&mut self, bits: u8) {
282 self.0 = (self.0 & !Self::COLOR1_MASK) | ((bits << 3) & Self::COLOR1_MASK);
283 }
284}
285
286#[derive(Clone, Copy, PartialEq, Debug)]
297#[repr(C)]
298struct Row<const COLS: usize> {
299 data: [Entry; COLS],
300 address: [Address; 4],
301}
302
303#[inline]
305const fn map_index(index: usize) -> usize {
306 #[cfg(feature = "esp32-ordering")]
307 {
308 index ^ 2
309 }
310 #[cfg(not(feature = "esp32-ordering"))]
311 {
312 index
313 }
314}
315
316const fn make_addr_table() -> [[Address; 4]; 32] {
319 let mut tbl = [[Address::new(); 4]; 32];
320 let mut addr = 0;
321 while addr < 32 {
322 let mut i = 0;
323 while i < 4 {
324 let latch = i != 3;
325 let mapped_i = map_index(i);
326 let latch_bit = if latch { 1u8 << 6 } else { 0u8 };
327 tbl[addr][mapped_i].0 = latch_bit | addr as u8;
328 i += 1;
329 }
330 addr += 1;
331 }
332 tbl
333}
334
335static ADDR_TABLE: [[Address; 4]; 32] = make_addr_table();
336
337const fn make_data_template<const COLS: usize>() -> [Entry; COLS] {
340 let mut data = [Entry::new(); COLS];
341 let mut i = 0;
342 while i < COLS {
343 let mapped_i = map_index(i);
344 data[mapped_i].0 = if i == COLS - 1 { 0 } else { 0b1000_0000 }; i += 1;
348 }
349 data
350}
351
352impl<const COLS: usize> Row<COLS> {
353 pub const fn new() -> Self {
354 Self {
355 address: [Address::new(); 4],
356 data: [Entry::new(); COLS],
357 }
358 }
359
360 #[inline]
361 pub fn format(&mut self, addr: u8) {
362 self.address.copy_from_slice(&ADDR_TABLE[addr as usize]);
364
365 let data_template = make_data_template::<COLS>();
367 self.data.copy_from_slice(&data_template);
368 }
369
370 #[inline]
372 pub fn clear_colors(&mut self) {
373 const COLOR_CLEAR_MASK: u8 = !0b0011_1111; for entry in &mut self.data {
377 entry.0 &= COLOR_CLEAR_MASK;
378 }
379 }
380
381 #[inline]
382 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
383 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
384 let col = map_index(col);
385 self.data[col].set_color0_bits(bits);
386 }
387
388 #[inline]
389 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
390 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
391 let col = map_index(col);
392 self.data[col].set_color1_bits(bits);
393 }
394}
395
396impl<const COLS: usize> Default for Row<COLS> {
397 fn default() -> Self {
398 Self::new()
399 }
400}
401
402#[derive(Copy, Clone, Debug)]
403#[repr(C)]
404struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
405 rows: [Row<COLS>; NROWS],
406}
407
408impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
409 pub const fn new() -> Self {
410 Self {
411 rows: [Row::new(); NROWS],
412 }
413 }
414
415 #[inline]
416 pub fn format(&mut self) {
417 for (addr, row) in self.rows.iter_mut().enumerate() {
418 row.format(addr as u8);
419 }
420 }
421
422 #[inline]
424 pub fn clear_colors(&mut self) {
425 for row in &mut self.rows {
426 row.clear_colors();
427 }
428 }
429
430 #[inline]
431 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
432 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
433 if y < NROWS {
434 row.set_color0(x, red, green, blue);
435 } else {
436 row.set_color1(x, red, green, blue);
437 }
438 }
439}
440
441impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
442 for Frame<ROWS, COLS, NROWS>
443{
444 fn default() -> Self {
445 Self::new()
446 }
447}
448
449#[derive(Copy, Clone)]
478#[repr(C)]
479#[repr(align(4))]
480pub struct DmaFrameBuffer<
481 const ROWS: usize,
482 const COLS: usize,
483 const NROWS: usize,
484 const BITS: u8,
485 const FRAME_COUNT: usize,
486> {
487 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
488}
489
490impl<
491 const ROWS: usize,
492 const COLS: usize,
493 const NROWS: usize,
494 const BITS: u8,
495 const FRAME_COUNT: usize,
496 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
497{
498 fn default() -> Self {
499 Self::new()
500 }
501}
502
503impl<
504 const ROWS: usize,
505 const COLS: usize,
506 const NROWS: usize,
507 const BITS: u8,
508 const FRAME_COUNT: usize,
509 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
510{
511 #[must_use]
527 pub fn new() -> Self {
528 let mut fb = Self {
529 frames: [Frame::new(); FRAME_COUNT],
530 };
531 fb.format();
532 fb
533 }
534
535 #[cfg(feature = "esp-hal-dma")]
551 #[must_use]
552 pub const fn dma_buffer_size_bytes() -> usize {
553 core::mem::size_of::<[Frame<ROWS, COLS, NROWS>; FRAME_COUNT]>()
554 }
555
556 pub fn format(&mut self) {
573 for frame in &mut self.frames {
574 frame.format();
575 }
576 }
577
578 #[inline]
595 pub fn erase(&mut self) {
596 for frame in &mut self.frames {
597 frame.clear_colors();
598 }
599 }
600
601 pub fn set_pixel(&mut self, p: Point, color: Color) {
617 if p.x < 0 || p.y < 0 {
618 return;
619 }
620 self.set_pixel_internal(p.x as usize, p.y as usize, color);
621 }
622
623 #[inline]
624 fn frames_on(v: u8) -> usize {
625 (v as usize) >> (8 - BITS)
627 }
628
629 #[inline]
630 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Rgb888) {
631 if x >= COLS || y >= ROWS {
632 return;
633 }
634
635 #[cfg(feature = "skip-black-pixels")]
638 if color == Rgb888::BLACK {
639 return;
640 }
641
642 let red_frames = Self::frames_on(color.r());
644 let green_frames = Self::frames_on(color.g());
645 let blue_frames = Self::frames_on(color.b());
646
647 for (frame_idx, frame) in self.frames.iter_mut().enumerate() {
649 frame.set_pixel(
650 y,
651 x,
652 frame_idx < red_frames,
653 frame_idx < green_frames,
654 frame_idx < blue_frames,
655 );
656 }
657 }
658}
659
660impl<
661 const ROWS: usize,
662 const COLS: usize,
663 const NROWS: usize,
664 const BITS: u8,
665 const FRAME_COUNT: usize,
666 > FrameBufferOperations<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
667 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
668{
669 #[inline]
670 fn erase(&mut self) {
671 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
672 }
673
674 #[inline]
675 fn set_pixel(&mut self, p: Point, color: Color) {
676 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
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 > embedded_graphics::prelude::OriginDimensions
687 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
688{
689 fn size(&self) -> embedded_graphics::prelude::Size {
690 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
691 }
692}
693
694impl<
695 const ROWS: usize,
696 const COLS: usize,
697 const NROWS: usize,
698 const BITS: u8,
699 const FRAME_COUNT: usize,
700 > embedded_graphics::draw_target::DrawTarget
701 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
702{
703 type Color = Color;
704
705 type Error = Infallible;
706
707 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
708 where
709 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
710 {
711 for pixel in pixels {
712 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
713 }
714 Ok(())
715 }
716}
717
718unsafe impl<
719 const ROWS: usize,
720 const COLS: usize,
721 const NROWS: usize,
722 const BITS: u8,
723 const FRAME_COUNT: usize,
724 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
725{
726 #[cfg(not(feature = "esp-hal-dma"))]
727 type Word = u8;
728
729 unsafe fn read_buffer(&self) -> (*const u8, usize) {
730 let ptr = (&raw const self.frames).cast::<u8>();
731 let len = core::mem::size_of_val(&self.frames);
732 (ptr, len)
733 }
734}
735
736unsafe impl<
737 const ROWS: usize,
738 const COLS: usize,
739 const NROWS: usize,
740 const BITS: u8,
741 const FRAME_COUNT: usize,
742 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
743{
744 #[cfg(not(feature = "esp-hal-dma"))]
745 type Word = u8;
746
747 unsafe fn read_buffer(&self) -> (*const u8, usize) {
748 let ptr = (&raw const self.frames).cast::<u8>();
749 let len = core::mem::size_of_val(&self.frames);
750 (ptr, len)
751 }
752}
753
754impl<
755 const ROWS: usize,
756 const COLS: usize,
757 const NROWS: usize,
758 const BITS: u8,
759 const FRAME_COUNT: usize,
760 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
761{
762 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
763 let brightness_step = 1 << (8 - BITS);
764 f.debug_struct("DmaFrameBuffer")
765 .field("size", &core::mem::size_of_val(&self.frames))
766 .field("frame_count", &self.frames.len())
767 .field("frame_size", &core::mem::size_of_val(&self.frames[0]))
768 .field("brightness_step", &&brightness_step)
769 .finish()
770 }
771}
772
773#[cfg(feature = "defmt")]
774impl<
775 const ROWS: usize,
776 const COLS: usize,
777 const NROWS: usize,
778 const BITS: u8,
779 const FRAME_COUNT: usize,
780 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
781{
782 fn format(&self, f: defmt::Formatter) {
783 let brightness_step = 1 << (8 - BITS);
784 defmt::write!(
785 f,
786 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
787 ROWS,
788 COLS,
789 NROWS,
790 BITS,
791 FRAME_COUNT
792 );
793 defmt::write!(f, " size: {}", core::mem::size_of_val(&self.frames));
794 defmt::write!(
795 f,
796 " frame_size: {}",
797 core::mem::size_of_val(&self.frames[0])
798 );
799 defmt::write!(f, " brightness_step: {}", brightness_step);
800 }
801}
802
803impl<
804 const ROWS: usize,
805 const COLS: usize,
806 const NROWS: usize,
807 const BITS: u8,
808 const FRAME_COUNT: usize,
809 > super::FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
810 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
811{
812 fn get_word_size(&self) -> super::WordSize {
813 super::WordSize::Eight
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 > embedded_graphics::prelude::OriginDimensions
824 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
825{
826 fn size(&self) -> embedded_graphics::prelude::Size {
827 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
828 }
829}
830
831impl<
832 const ROWS: usize,
833 const COLS: usize,
834 const NROWS: usize,
835 const BITS: u8,
836 const FRAME_COUNT: usize,
837 > super::FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
838 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
839{
840 fn get_word_size(&self) -> super::WordSize {
841 super::WordSize::Eight
842 }
843}
844
845#[cfg(test)]
846mod tests {
847 extern crate std;
848
849 use std::format;
850 use std::vec;
851
852 use super::*;
853 use crate::{FrameBuffer, WordSize};
854 use embedded_graphics::pixelcolor::RgbColor;
855 use embedded_graphics::prelude::*;
856 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
857
858 const TEST_ROWS: usize = 32;
859 const TEST_COLS: usize = 64;
860 const TEST_NROWS: usize = TEST_ROWS / 2;
861 const TEST_BITS: u8 = 3;
862 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
865 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
866
867 #[test]
868 fn test_address_construction() {
869 let addr = Address::new();
870 assert_eq!(addr.0, 0);
871 assert_eq!(addr.latch(), false);
872 assert_eq!(addr.addr(), 0);
873 }
874
875 #[test]
876 fn test_address_setters() {
877 let mut addr = Address::new();
878
879 addr.set_latch(true);
880 assert_eq!(addr.latch(), true);
881 assert_eq!(addr.0 & 0b01000000, 0b01000000);
882
883 addr.set_addr(0b11111);
884 assert_eq!(addr.addr(), 0b11111);
885 assert_eq!(addr.0 & 0b00011111, 0b00011111);
886 }
887
888 #[test]
889 fn test_address_bit_isolation() {
890 let mut addr = Address::new();
891
892 addr.set_addr(0b11111);
894 addr.set_latch(true);
895 assert_eq!(addr.addr(), 0b11111);
896 assert_eq!(addr.latch(), true);
897 }
898
899 #[test]
900 fn test_entry_construction() {
901 let entry = Entry::new();
902 assert_eq!(entry.0, 0);
903 assert_eq!(entry.output_enable(), false);
904 assert_eq!(entry.latch(), false);
905 assert_eq!(entry.red1(), false);
906 assert_eq!(entry.grn1(), false);
907 assert_eq!(entry.blu1(), false);
908 assert_eq!(entry.red2(), false);
909 assert_eq!(entry.grn2(), false);
910 assert_eq!(entry.blu2(), false);
911 }
912
913 #[test]
914 fn test_entry_setters() {
915 let mut entry = Entry::new();
916
917 entry.set_output_enable(true);
918 assert_eq!(entry.output_enable(), true);
919 assert_eq!(entry.0 & 0b10000000, 0b10000000);
920
921 entry.set_latch(true);
922 assert_eq!(entry.latch(), true);
923 assert_eq!(entry.0 & 0b01000000, 0b01000000);
924
925 entry.set_red1(true);
927 entry.set_grn1(true);
928 entry.set_blu1(true);
929 assert_eq!(entry.red1(), true);
930 assert_eq!(entry.grn1(), true);
931 assert_eq!(entry.blu1(), true);
932 assert_eq!(entry.0 & 0b00000111, 0b00000111);
933
934 entry.set_red2(true);
936 entry.set_grn2(true);
937 entry.set_blu2(true);
938 assert_eq!(entry.red2(), true);
939 assert_eq!(entry.grn2(), true);
940 assert_eq!(entry.blu2(), true);
941 assert_eq!(entry.0 & 0b00111000, 0b00111000);
942 }
943
944 #[test]
945 fn test_entry_set_color0() {
946 let mut entry = Entry::new();
947
948 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
950 assert_eq!(entry.red1(), true);
951 assert_eq!(entry.grn1(), false);
952 assert_eq!(entry.blu1(), true);
953 assert_eq!(entry.0 & 0b00000111, 0b00000101); }
955
956 #[test]
957 fn test_entry_set_color1() {
958 let mut entry = Entry::new();
959
960 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
962 assert_eq!(entry.red2(), false);
963 assert_eq!(entry.grn2(), true);
964 assert_eq!(entry.blu2(), true);
965 assert_eq!(entry.0 & 0b00111000, 0b00110000); }
967
968 #[test]
969 fn test_row_construction() {
970 let row: Row<TEST_COLS> = Row::new();
971 assert_eq!(row.data.len(), TEST_COLS);
972 assert_eq!(row.address.len(), 4);
973
974 for entry in &row.data {
976 assert_eq!(entry.0, 0);
977 }
978 for addr in &row.address {
979 assert_eq!(addr.0, 0);
980 }
981 }
982
983 #[test]
984 fn test_row_format() {
985 let mut row: Row<TEST_COLS> = Row::new();
986 let test_addr = 5;
987
988 row.format(test_addr);
989
990 for addr in &row.address {
992 assert_eq!(addr.addr(), test_addr);
993 }
997 let latch_false_count = row.address.iter().filter(|addr| !addr.latch()).count();
1001 assert_eq!(latch_false_count, 1);
1002
1003 for entry in &row.data {
1005 assert_eq!(entry.latch(), false);
1006 }
1007 let oe_false_count = row
1012 .data
1013 .iter()
1014 .filter(|entry| !entry.output_enable())
1015 .count();
1016 assert_eq!(oe_false_count, 1);
1017 }
1018
1019 #[test]
1020 fn test_row_set_color0() {
1021 let mut row: Row<TEST_COLS> = Row::new();
1022
1023 row.set_color0(0, true, false, true);
1024
1025 let mapped_col_0 = map_index(0);
1026 assert_eq!(row.data[mapped_col_0].red1(), true);
1027 assert_eq!(row.data[mapped_col_0].grn1(), false);
1028 assert_eq!(row.data[mapped_col_0].blu1(), true);
1029
1030 row.set_color0(1, false, true, false);
1032
1033 let mapped_col_1 = map_index(1);
1034 assert_eq!(row.data[mapped_col_1].red1(), false);
1035 assert_eq!(row.data[mapped_col_1].grn1(), true);
1036 assert_eq!(row.data[mapped_col_1].blu1(), false);
1037 }
1038
1039 #[test]
1040 fn test_row_set_color1() {
1041 let mut row: Row<TEST_COLS> = Row::new();
1042
1043 row.set_color1(0, true, true, false);
1044
1045 let mapped_col_0 = map_index(0);
1046 assert_eq!(row.data[mapped_col_0].red2(), true);
1047 assert_eq!(row.data[mapped_col_0].grn2(), true);
1048 assert_eq!(row.data[mapped_col_0].blu2(), false);
1049 }
1050
1051 #[test]
1052 fn test_frame_construction() {
1053 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1054 assert_eq!(frame.rows.len(), TEST_NROWS);
1055 }
1056
1057 #[test]
1058 fn test_frame_format() {
1059 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1060
1061 frame.format();
1062
1063 for (addr, row) in frame.rows.iter().enumerate() {
1064 for address in &row.address {
1066 assert_eq!(address.addr() as usize, addr);
1067 }
1068 }
1069 }
1070
1071 #[test]
1072 fn test_frame_set_pixel() {
1073 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1074
1075 frame.set_pixel(5, 10, true, false, true);
1077
1078 let mapped_col_10 = map_index(10);
1079 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1080 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1081 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1082
1083 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1085
1086 let mapped_col_15 = map_index(15);
1087 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1088 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1089 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1090 }
1091
1092 #[test]
1093 fn test_row_default() {
1094 let row1: Row<TEST_COLS> = Row::new();
1095 let row2: Row<TEST_COLS> = Row::default();
1096
1097 assert_eq!(row1, row2);
1099 assert_eq!(row1.data.len(), row2.data.len());
1100 assert_eq!(row1.address.len(), row2.address.len());
1101
1102 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1104 assert_eq!(entry1.0, entry2.0);
1105 assert_eq!(entry1.0, 0);
1106 }
1107 for (addr1, addr2) in row1.address.iter().zip(row2.address.iter()) {
1108 assert_eq!(addr1.0, addr2.0);
1109 assert_eq!(addr1.0, 0);
1110 }
1111 }
1112
1113 #[test]
1114 fn test_frame_default() {
1115 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1116 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1117
1118 assert_eq!(frame1.rows.len(), frame2.rows.len());
1120
1121 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1123 assert_eq!(row1, row2);
1124
1125 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1127 assert_eq!(entry1.0, entry2.0);
1128 assert_eq!(entry1.0, 0);
1129 }
1130 for (addr1, addr2) in row1.address.iter().zip(row2.address.iter()) {
1131 assert_eq!(addr1.0, addr2.0);
1132 assert_eq!(addr1.0, 0);
1133 }
1134 }
1135 }
1136
1137 #[test]
1138 fn test_dma_framebuffer_construction() {
1139 let fb = TestFrameBuffer::new();
1140 assert_eq!(fb.frames.len(), TEST_FRAME_COUNT);
1141 }
1142
1143 #[test]
1144 #[cfg(feature = "esp-hal-dma")]
1145 fn test_dma_framebuffer_dma_buffer_size() {
1146 let expected_size =
1147 core::mem::size_of::<[Frame<TEST_ROWS, TEST_COLS, TEST_NROWS>; TEST_FRAME_COUNT]>();
1148 assert_eq!(TestFrameBuffer::dma_buffer_size_bytes(), expected_size);
1149 }
1150
1151 #[test]
1152 fn test_dma_framebuffer_format() {
1153 let mut fb = TestFrameBuffer {
1154 frames: [Frame::new(); TEST_FRAME_COUNT],
1155 };
1156 fb.format();
1157
1158 for frame in &fb.frames {
1160 for (addr, row) in frame.rows.iter().enumerate() {
1161 for address in &row.address {
1162 assert_eq!(address.addr() as usize, addr);
1163 }
1164 }
1165 }
1166 }
1167
1168 #[test]
1169 fn test_dma_framebuffer_set_pixel_bounds() {
1170 let mut fb = TestFrameBuffer::new();
1171
1172 fb.set_pixel(Point::new(-1, 5), Color::RED);
1174 fb.set_pixel(Point::new(5, -1), Color::RED);
1175
1176 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1178 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1179 }
1180
1181 #[test]
1182 fn test_dma_framebuffer_set_pixel_internal() {
1183 let mut fb = TestFrameBuffer::new();
1184
1185 let red_color = Rgb888::new(255, 0, 0);
1186 fb.set_pixel_internal(10, 5, red_color);
1187
1188 for frame in &fb.frames {
1192 let mapped_col_10 = map_index(10);
1194 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1195 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1196 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1197 }
1198 }
1199
1200 #[test]
1201 fn test_dma_framebuffer_brightness_modulation() {
1202 let mut fb = TestFrameBuffer::new();
1203
1204 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Rgb888::new(test_brightness, 0, 0);
1208
1209 fb.set_pixel_internal(0, 0, color);
1210
1211 for (frame_idx, frame) in fb.frames.iter().enumerate() {
1214 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1215 let should_be_active = test_brightness >= frame_threshold;
1216
1217 let mapped_col_0 = map_index(0);
1218 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1219 }
1220 }
1221
1222 #[test]
1223 fn test_origin_dimensions() {
1224 let fb = TestFrameBuffer::new();
1225 let size = fb.size();
1226 assert_eq!(size.width, TEST_COLS as u32);
1227 assert_eq!(size.height, TEST_ROWS as u32);
1228
1229 let mut fb = TestFrameBuffer::new();
1231 let fb_ref = &mut fb;
1232 let size = fb_ref.size();
1233 assert_eq!(size.width, TEST_COLS as u32);
1234 assert_eq!(size.height, TEST_ROWS as u32);
1235 }
1236
1237 #[test]
1238 fn test_draw_target() {
1239 let mut fb = TestFrameBuffer::new();
1240
1241 let pixels = vec![
1242 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1243 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1244 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1245 ];
1246
1247 let result = fb.draw_iter(pixels);
1248 assert!(result.is_ok());
1249 }
1250
1251 #[test]
1252 fn test_draw_iter_pixel_verification() {
1253 let mut fb = TestFrameBuffer::new();
1254
1255 let pixels = vec![
1257 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), embedded_graphics::Pixel(Point::new(45, 3), Rgb888::new(16, 16, 16)), ];
1271
1272 let result = fb.draw_iter(pixels);
1273 assert!(result.is_ok());
1274
1275 let first_frame = &fb.frames[0];
1277 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = map_index(5);
1283 assert_eq!(
1284 first_frame.rows[2].data[col_idx].red1(),
1285 Color::RED.r() >= first_frame_threshold
1286 );
1287 assert_eq!(
1288 first_frame.rows[2].data[col_idx].grn1(),
1289 Color::RED.g() >= first_frame_threshold
1290 );
1291 assert_eq!(
1292 first_frame.rows[2].data[col_idx].blu1(),
1293 Color::RED.b() >= first_frame_threshold
1294 );
1295
1296 let col_idx = map_index(10);
1298 assert_eq!(
1299 first_frame.rows[5].data[col_idx].red1(),
1300 Color::GREEN.r() >= first_frame_threshold
1301 );
1302 assert_eq!(
1303 first_frame.rows[5].data[col_idx].grn1(),
1304 Color::GREEN.g() >= first_frame_threshold
1305 );
1306 assert_eq!(
1307 first_frame.rows[5].data[col_idx].blu1(),
1308 Color::GREEN.b() >= first_frame_threshold
1309 );
1310
1311 let col_idx = map_index(15);
1313 assert_eq!(
1314 first_frame.rows[8].data[col_idx].red1(),
1315 Color::BLUE.r() >= first_frame_threshold
1316 );
1317 assert_eq!(
1318 first_frame.rows[8].data[col_idx].grn1(),
1319 Color::BLUE.g() >= first_frame_threshold
1320 );
1321 assert_eq!(
1322 first_frame.rows[8].data[col_idx].blu1(),
1323 Color::BLUE.b() >= first_frame_threshold
1324 );
1325
1326 let col_idx = map_index(20);
1328 assert_eq!(
1329 first_frame.rows[10].data[col_idx].red1(),
1330 Color::WHITE.r() >= first_frame_threshold
1331 );
1332 assert_eq!(
1333 first_frame.rows[10].data[col_idx].grn1(),
1334 Color::WHITE.g() >= first_frame_threshold
1335 );
1336 assert_eq!(
1337 first_frame.rows[10].data[col_idx].blu1(),
1338 Color::WHITE.b() >= first_frame_threshold
1339 );
1340
1341 let col_idx = map_index(25);
1344 assert_eq!(
1345 first_frame.rows[3].data[col_idx].red2(),
1346 Color::RED.r() >= first_frame_threshold
1347 );
1348 assert_eq!(
1349 first_frame.rows[3].data[col_idx].grn2(),
1350 Color::RED.g() >= first_frame_threshold
1351 );
1352 assert_eq!(
1353 first_frame.rows[3].data[col_idx].blu2(),
1354 Color::RED.b() >= first_frame_threshold
1355 );
1356
1357 let col_idx = map_index(30);
1359 assert_eq!(
1360 first_frame.rows[7].data[col_idx].red2(),
1361 Color::GREEN.r() >= first_frame_threshold
1362 );
1363 assert_eq!(
1364 first_frame.rows[7].data[col_idx].grn2(),
1365 Color::GREEN.g() >= first_frame_threshold
1366 );
1367 assert_eq!(
1368 first_frame.rows[7].data[col_idx].blu2(),
1369 Color::GREEN.b() >= first_frame_threshold
1370 );
1371
1372 let col_idx = map_index(35);
1374 assert_eq!(
1375 first_frame.rows[12].data[col_idx].red2(),
1376 Color::BLUE.r() >= first_frame_threshold
1377 );
1378 assert_eq!(
1379 first_frame.rows[12].data[col_idx].grn2(),
1380 Color::BLUE.g() >= first_frame_threshold
1381 );
1382 assert_eq!(
1383 first_frame.rows[12].data[col_idx].blu2(),
1384 Color::BLUE.b() >= first_frame_threshold
1385 );
1386
1387 let col_idx = map_index(40);
1389 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1390 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1391 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1392
1393 let col_idx = map_index(45);
1395 assert_eq!(
1396 first_frame.rows[3].data[col_idx].red1(),
1397 16 >= first_frame_threshold
1398 ); assert_eq!(
1400 first_frame.rows[3].data[col_idx].grn1(),
1401 16 >= first_frame_threshold
1402 ); assert_eq!(
1404 first_frame.rows[3].data[col_idx].blu1(),
1405 16 >= first_frame_threshold
1406 ); }
1408
1409 #[test]
1410 fn test_embedded_graphics_integration() {
1411 let mut fb = TestFrameBuffer::new();
1412
1413 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1415 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1416 .draw(&mut fb);
1417 assert!(result.is_ok());
1418
1419 let result = Circle::new(Point::new(30, 15), 8)
1421 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1422 .draw(&mut fb);
1423 assert!(result.is_ok());
1424 }
1425
1426 #[test]
1427 fn test_read_buffer_implementation() {
1428 let fb = TestFrameBuffer::new();
1429
1430 unsafe {
1432 let (ptr, len) = fb.read_buffer();
1433 assert!(!ptr.is_null());
1434 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1435 }
1436
1437 let mut fb = TestFrameBuffer::new();
1439 let fb_ref = &mut fb;
1440 unsafe {
1441 let (ptr, len) = fb_ref.read_buffer();
1442 assert!(!ptr.is_null());
1443 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1444 }
1445 }
1446
1447 #[test]
1448 fn test_framebuffer_trait() {
1449 let fb = TestFrameBuffer::new();
1450 assert_eq!(fb.get_word_size(), WordSize::Eight);
1451
1452 let mut fb = TestFrameBuffer::new();
1453 let fb_ref = &mut fb;
1454 assert_eq!(fb_ref.get_word_size(), WordSize::Eight);
1455 }
1456
1457 #[test]
1458 fn test_debug_formatting() {
1459 let fb = TestFrameBuffer::new();
1460 let debug_string = format!("{:?}", fb);
1461 assert!(debug_string.contains("DmaFrameBuffer"));
1462 assert!(debug_string.contains("frame_count"));
1463 assert!(debug_string.contains("frame_size"));
1464 assert!(debug_string.contains("brightness_step"));
1465 }
1466
1467 #[test]
1468 fn test_default_implementation() {
1469 let fb1 = TestFrameBuffer::new();
1470 let fb2 = TestFrameBuffer::default();
1471
1472 assert_eq!(fb1.frames.len(), fb2.frames.len());
1474 }
1475
1476 #[cfg(feature = "esp32-ordering")]
1477 #[test]
1478 fn test_esp32_mapping() {
1479 assert_eq!(map_index(0), 2);
1481 assert_eq!(map_index(1), 3);
1482 assert_eq!(map_index(2), 0);
1483 assert_eq!(map_index(3), 1);
1484 assert_eq!(map_index(4), 6); assert_eq!(map_index(5), 7); }
1487
1488 #[test]
1489 fn test_memory_alignment() {
1490 let fb = TestFrameBuffer::new();
1491 let ptr = &fb as *const _ as usize;
1492
1493 assert_eq!(ptr % 4, 0);
1495 }
1496
1497 #[test]
1498 fn test_color_values() {
1499 let mut fb = TestFrameBuffer::new();
1500
1501 let colors = [
1503 (Color::RED, (255, 0, 0)),
1504 (Color::GREEN, (0, 255, 0)),
1505 (Color::BLUE, (0, 0, 255)),
1506 (Color::WHITE, (255, 255, 255)),
1507 (Color::BLACK, (0, 0, 0)),
1508 ];
1509
1510 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1511 fb.set_pixel(Point::new(i as i32, 0), *color);
1512 assert_eq!(color.r(), *r);
1513 assert_eq!(color.g(), *g);
1514 assert_eq!(color.b(), *b);
1515 }
1516 }
1517
1518 #[test]
1519 fn test_bits_assertion() {
1520 assert!(TEST_BITS <= 8);
1523 }
1524
1525 #[test]
1526 #[cfg(feature = "skip-black-pixels")]
1527 fn test_skip_black_pixels_enabled() {
1528 let mut fb = TestFrameBuffer::new();
1529
1530 fb.set_pixel_internal(10, 5, Color::RED);
1532
1533 let mapped_col_10 = map_index(10);
1535 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1536 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1537 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1538
1539 fb.set_pixel_internal(10, 5, Color::BLACK);
1541
1542 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1544 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1545 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1546 }
1547
1548 #[test]
1549 #[cfg(not(feature = "skip-black-pixels"))]
1550 fn test_skip_black_pixels_disabled() {
1551 let mut fb = TestFrameBuffer::new();
1552
1553 fb.set_pixel_internal(10, 5, Color::RED);
1555
1556 let mapped_col_10 = map_index(10);
1558 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1559 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1560 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1561
1562 fb.set_pixel_internal(10, 5, Color::BLACK);
1564
1565 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1567 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1568 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1569 }
1570
1571 #[test]
1572 fn test_bcm_frame_overwrite() {
1573 let mut fb = TestFrameBuffer::new();
1574
1575 fb.set_pixel_internal(10, 5, Color::WHITE);
1577
1578 let mapped_col_10 = map_index(10);
1579
1580 for frame in fb.frames.iter() {
1582 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1584 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1585 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1586 }
1587
1588 let half_white = embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128);
1590 fb.set_pixel_internal(10, 5, half_white);
1591
1592 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.frames.iter().enumerate() {
1598 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1599 let should_be_active = 128 >= frame_threshold;
1600
1601 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1602 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1603 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1604 }
1605
1606 for frame_idx in 0..4 {
1609 assert_eq!(
1610 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1611 true
1612 );
1613 }
1614 for frame_idx in 4..TEST_FRAME_COUNT {
1616 assert_eq!(
1617 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1618 false
1619 );
1620 }
1621 }
1622
1623 #[test]
1624 fn test_new_auto_formats() {
1625 let fb = TestFrameBuffer::new();
1626
1627 for frame in &fb.frames {
1629 for (addr, row) in frame.rows.iter().enumerate() {
1630 for address in &row.address {
1631 assert_eq!(address.addr() as usize, addr);
1632 }
1633 }
1634 }
1635 }
1636
1637 #[test]
1638 fn test_erase() {
1639 let mut fb = TestFrameBuffer::new();
1640
1641 fb.set_pixel_internal(10, 5, Color::RED);
1643 fb.set_pixel_internal(20, 10, Color::GREEN);
1644
1645 let mapped_col_10 = map_index(10);
1646 let mapped_col_20 = map_index(20);
1647
1648 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1650 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].grn1(), true);
1651
1652 fb.erase();
1654
1655 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1657 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1658 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1659 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].red1(), false);
1660 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].grn1(), false);
1661 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].blu1(), false);
1662
1663 for frame in &fb.frames {
1665 for (addr, row) in frame.rows.iter().enumerate() {
1666 for address in &row.address {
1668 assert_eq!(address.addr() as usize, addr);
1669 }
1670 let oe_false_count = row
1672 .data
1673 .iter()
1674 .filter(|entry| !entry.output_enable())
1675 .count();
1676 assert_eq!(oe_false_count, 1);
1677 }
1678 }
1679 }
1680
1681 #[test]
1682 fn test_row_clear_colors() {
1683 let mut row: Row<TEST_COLS> = Row::new();
1684 row.format(5);
1685
1686 row.set_color0(0, true, false, true);
1688 row.set_color1(1, false, true, false);
1689
1690 let mapped_col_0 = map_index(0);
1691 let mapped_col_1 = map_index(1);
1692
1693 assert_eq!(row.data[mapped_col_0].red1(), true);
1695 assert_eq!(row.data[mapped_col_0].blu1(), true);
1696 assert_eq!(row.data[mapped_col_1].grn2(), true);
1697
1698 let original_oe_0 = row.data[mapped_col_0].output_enable();
1700 let original_latch_0 = row.data[mapped_col_0].latch();
1701 let original_oe_1 = row.data[mapped_col_1].output_enable();
1702 let original_latch_1 = row.data[mapped_col_1].latch();
1703
1704 row.clear_colors();
1706
1707 assert_eq!(row.data[mapped_col_0].red1(), false);
1709 assert_eq!(row.data[mapped_col_0].grn1(), false);
1710 assert_eq!(row.data[mapped_col_0].blu1(), false);
1711 assert_eq!(row.data[mapped_col_1].red2(), false);
1712 assert_eq!(row.data[mapped_col_1].grn2(), false);
1713 assert_eq!(row.data[mapped_col_1].blu2(), false);
1714
1715 assert_eq!(row.data[mapped_col_0].output_enable(), original_oe_0);
1717 assert_eq!(row.data[mapped_col_0].latch(), original_latch_0);
1718 assert_eq!(row.data[mapped_col_1].output_enable(), original_oe_1);
1719 assert_eq!(row.data[mapped_col_1].latch(), original_latch_1);
1720 }
1721
1722 #[test]
1723 fn test_make_addr_table_function() {
1724 let table = make_addr_table();
1726
1727 assert_eq!(table.len(), 32); let addr_0 = &table[0];
1732 assert_eq!(addr_0.len(), 4); let latch_false_count = addr_0.iter().filter(|addr| !addr.latch()).count();
1736 assert_eq!(latch_false_count, 1);
1737
1738 for addr in addr_0 {
1740 assert_eq!(addr.addr(), 0);
1741 }
1742
1743 let addr_31 = &table[31];
1745 let latch_false_count = addr_31.iter().filter(|addr| !addr.latch()).count();
1746 assert_eq!(latch_false_count, 1);
1747
1748 for addr in addr_31 {
1750 assert_eq!(addr.addr(), 31);
1751 }
1752 }
1753
1754 #[test]
1755 fn test_make_data_template_function() {
1756 let template = make_data_template::<TEST_COLS>();
1758
1759 assert_eq!(template.len(), TEST_COLS);
1761
1762 for entry in &template {
1764 assert_eq!(entry.latch(), false);
1765 }
1766
1767 let oe_false_count = template
1769 .iter()
1770 .filter(|entry| !entry.output_enable())
1771 .count();
1772 assert_eq!(oe_false_count, 1);
1773
1774 let small_template = make_data_template::<4>();
1776 assert_eq!(small_template.len(), 4);
1777
1778 let oe_false_count = small_template
1779 .iter()
1780 .filter(|entry| !entry.output_enable())
1781 .count();
1782 assert_eq!(oe_false_count, 1);
1783
1784 #[cfg(not(feature = "esp32-ordering"))]
1787 {
1788 let single_template = make_data_template::<1>();
1789 assert_eq!(single_template.len(), 1);
1790 assert_eq!(single_template[0].output_enable(), false); assert_eq!(single_template[0].latch(), false);
1792 }
1793 }
1794
1795 #[test]
1796 fn test_addr_table_correctness() {
1797 for addr in 0..32 {
1799 let mut expected_addresses = [Address::new(); 4];
1800
1801 for i in 0..4 {
1803 let latch = !matches!(i, 3);
1804 #[cfg(feature = "esp32-ordering")]
1805 let mapped_i = map_index(i);
1806 #[cfg(not(feature = "esp32-ordering"))]
1807 let mapped_i = i;
1808
1809 expected_addresses[mapped_i].set_latch(latch);
1810 expected_addresses[mapped_i].set_addr(addr);
1811 }
1812
1813 let table_addresses = &ADDR_TABLE[addr as usize];
1815 for i in 0..4 {
1816 assert_eq!(table_addresses[i].0, expected_addresses[i].0);
1817 }
1818 }
1819 }
1820
1821 const CHAR_W: i32 = 6;
1823 const CHAR_H: i32 = 10;
1824
1825 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1828 use embedded_graphics::mock_display::MockDisplay;
1829 use embedded_graphics::mono_font::ascii::FONT_6X10;
1830 use embedded_graphics::mono_font::MonoTextStyle;
1831 use embedded_graphics::text::{Baseline, Text};
1832
1833 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1835 Text::with_baseline("A", origin, style, Baseline::Top)
1836 .draw(fb)
1837 .unwrap();
1838
1839 let mut reference: MockDisplay<Color> = MockDisplay::new();
1841 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1842 .draw(&mut reference)
1843 .unwrap();
1844
1845 for dy in 0..CHAR_H {
1847 for dx in 0..CHAR_W {
1848 let expected_on = reference
1849 .get_pixel(Point::new(dx, dy))
1850 .unwrap_or(Color::BLACK)
1851 != Color::BLACK;
1852
1853 let gx = (origin.x + dx) as usize;
1854 let gy = (origin.y + dy) as usize;
1855
1856 let frame0 = &fb.frames[0];
1863 let e = if gy < TEST_NROWS {
1864 &frame0.rows[gy].data[map_index(gx)]
1865 } else {
1866 &frame0.rows[gy - TEST_NROWS].data[map_index(gx)]
1867 };
1868
1869 let (r, g, b) = if gy >= TEST_NROWS {
1870 (e.red2(), e.grn2(), e.blu2())
1871 } else {
1872 (e.red1(), e.grn1(), e.blu1())
1873 };
1874
1875 if expected_on {
1876 assert!(r && g && b);
1877 } else {
1878 assert!(!r && !g && !b);
1879 }
1880 }
1881 }
1882 }
1883
1884 #[test]
1885 fn test_draw_char_corners() {
1886 let upper_left = Point::new(0, 0);
1888 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1889
1890 let mut fb = TestFrameBuffer::new();
1891
1892 verify_glyph_at(&mut fb, upper_left);
1894 verify_glyph_at(&mut fb, lower_right);
1896 }
1897
1898 #[test]
1899 fn test_framebuffer_operations_trait_erase() {
1900 let mut fb = TestFrameBuffer::new();
1901
1902 fb.set_pixel_internal(10, 5, Color::RED);
1904 fb.set_pixel_internal(20, 10, Color::GREEN);
1905
1906 <TestFrameBuffer as FrameBufferOperations<
1908 TEST_ROWS,
1909 TEST_COLS,
1910 TEST_NROWS,
1911 TEST_BITS,
1912 TEST_FRAME_COUNT,
1913 >>::erase(&mut fb);
1914
1915 let mc10 = map_index(10);
1917 let mc20 = map_index(20);
1918 assert_eq!(fb.frames[0].rows[5].data[mc10].red1(), false);
1919 assert_eq!(fb.frames[0].rows[10].data[mc20].grn1(), false);
1920
1921 let row0 = &fb.frames[0].rows[0];
1923 let oe_false_count = row0
1924 .data
1925 .iter()
1926 .filter(|entry| !entry.output_enable())
1927 .count();
1928 assert_eq!(oe_false_count, 1);
1929 assert!(row0.data.iter().all(|e| !e.latch()));
1930
1931 for (i, addr) in row0.address.iter().enumerate() {
1933 assert_eq!(addr.0, ADDR_TABLE[0][i].0);
1934 }
1935 }
1936
1937 #[test]
1938 fn test_framebuffer_operations_trait_set_pixel() {
1939 let mut fb = TestFrameBuffer::new();
1940
1941 <TestFrameBuffer as FrameBufferOperations<
1943 TEST_ROWS,
1944 TEST_COLS,
1945 TEST_NROWS,
1946 TEST_BITS,
1947 TEST_FRAME_COUNT,
1948 >>::set_pixel(&mut fb, Point::new(8, 3), Color::BLUE);
1949
1950 let idx = map_index(8);
1952 assert_eq!(fb.frames[0].rows[3].data[idx].blu1(), true);
1953 assert_eq!(fb.frames[0].rows[3].data[idx].red1(), false);
1955 assert_eq!(fb.frames[0].rows[3].data[idx].grn1(), false);
1956 }
1957}