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 pub const fn dma_buffer_size_bytes() -> usize {
552 core::mem::size_of::<[Frame<ROWS, COLS, NROWS>; FRAME_COUNT]>()
553 }
554
555 pub fn format(&mut self) {
572 for frame in &mut self.frames {
573 frame.format();
574 }
575 }
576
577 #[inline]
594 pub fn erase(&mut self) {
595 for frame in &mut self.frames {
596 frame.clear_colors();
597 }
598 }
599
600 pub fn set_pixel(&mut self, p: Point, color: Color) {
616 if p.x < 0 || p.y < 0 {
617 return;
618 }
619 self.set_pixel_internal(p.x as usize, p.y as usize, color);
620 }
621
622 #[inline]
623 fn frames_on(v: u8) -> usize {
624 (v as usize) >> (8 - BITS)
626 }
627
628 #[inline]
629 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Rgb888) {
630 if x >= COLS || y >= ROWS {
631 return;
632 }
633
634 #[cfg(feature = "skip-black-pixels")]
637 if color == Rgb888::BLACK {
638 return;
639 }
640
641 let red_frames = Self::frames_on(color.r());
643 let green_frames = Self::frames_on(color.g());
644 let blue_frames = Self::frames_on(color.b());
645
646 for (frame_idx, frame) in self.frames.iter_mut().enumerate() {
648 frame.set_pixel(
649 y,
650 x,
651 frame_idx < red_frames,
652 frame_idx < green_frames,
653 frame_idx < blue_frames,
654 );
655 }
656 }
657}
658
659impl<
660 const ROWS: usize,
661 const COLS: usize,
662 const NROWS: usize,
663 const BITS: u8,
664 const FRAME_COUNT: usize,
665 > FrameBufferOperations<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
666 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
667{
668 #[inline]
669 fn erase(&mut self) {
670 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
671 }
672
673 #[inline]
674 fn set_pixel(&mut self, p: Point, color: Color) {
675 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
676 }
677}
678
679impl<
680 const ROWS: usize,
681 const COLS: usize,
682 const NROWS: usize,
683 const BITS: u8,
684 const FRAME_COUNT: usize,
685 > embedded_graphics::prelude::OriginDimensions
686 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
687{
688 fn size(&self) -> embedded_graphics::prelude::Size {
689 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
690 }
691}
692
693impl<
694 const ROWS: usize,
695 const COLS: usize,
696 const NROWS: usize,
697 const BITS: u8,
698 const FRAME_COUNT: usize,
699 > embedded_graphics::draw_target::DrawTarget
700 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
701{
702 type Color = Color;
703
704 type Error = Infallible;
705
706 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
707 where
708 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
709 {
710 for pixel in pixels {
711 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
712 }
713 Ok(())
714 }
715}
716
717unsafe impl<
718 const ROWS: usize,
719 const COLS: usize,
720 const NROWS: usize,
721 const BITS: u8,
722 const FRAME_COUNT: usize,
723 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
724{
725 #[cfg(not(feature = "esp-hal-dma"))]
726 type Word = u8;
727
728 unsafe fn read_buffer(&self) -> (*const u8, usize) {
729 let ptr = (&raw const self.frames).cast::<u8>();
730 let len = core::mem::size_of_val(&self.frames);
731 (ptr, len)
732 }
733}
734
735unsafe impl<
736 const ROWS: usize,
737 const COLS: usize,
738 const NROWS: usize,
739 const BITS: u8,
740 const FRAME_COUNT: usize,
741 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
742{
743 #[cfg(not(feature = "esp-hal-dma"))]
744 type Word = u8;
745
746 unsafe fn read_buffer(&self) -> (*const u8, usize) {
747 let ptr = (&raw const self.frames).cast::<u8>();
748 let len = core::mem::size_of_val(&self.frames);
749 (ptr, len)
750 }
751}
752
753impl<
754 const ROWS: usize,
755 const COLS: usize,
756 const NROWS: usize,
757 const BITS: u8,
758 const FRAME_COUNT: usize,
759 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
760{
761 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
762 let brightness_step = 1 << (8 - BITS);
763 f.debug_struct("DmaFrameBuffer")
764 .field("size", &core::mem::size_of_val(&self.frames))
765 .field("frame_count", &self.frames.len())
766 .field("frame_size", &core::mem::size_of_val(&self.frames[0]))
767 .field("brightness_step", &&brightness_step)
768 .finish()
769 }
770}
771
772#[cfg(feature = "defmt")]
773impl<
774 const ROWS: usize,
775 const COLS: usize,
776 const NROWS: usize,
777 const BITS: u8,
778 const FRAME_COUNT: usize,
779 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
780{
781 fn format(&self, f: defmt::Formatter) {
782 let brightness_step = 1 << (8 - BITS);
783 defmt::write!(
784 f,
785 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
786 ROWS,
787 COLS,
788 NROWS,
789 BITS,
790 FRAME_COUNT
791 );
792 defmt::write!(f, " size: {}", core::mem::size_of_val(&self.frames));
793 defmt::write!(
794 f,
795 " frame_size: {}",
796 core::mem::size_of_val(&self.frames[0])
797 );
798 defmt::write!(f, " brightness_step: {}", brightness_step);
799 }
800}
801
802impl<
803 const ROWS: usize,
804 const COLS: usize,
805 const NROWS: usize,
806 const BITS: u8,
807 const FRAME_COUNT: usize,
808 > super::FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
809 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
810{
811 fn get_word_size(&self) -> super::WordSize {
812 super::WordSize::Eight
813 }
814}
815
816impl<
817 const ROWS: usize,
818 const COLS: usize,
819 const NROWS: usize,
820 const BITS: u8,
821 const FRAME_COUNT: usize,
822 > embedded_graphics::prelude::OriginDimensions
823 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
824{
825 fn size(&self) -> embedded_graphics::prelude::Size {
826 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
827 }
828}
829
830impl<
831 const ROWS: usize,
832 const COLS: usize,
833 const NROWS: usize,
834 const BITS: u8,
835 const FRAME_COUNT: usize,
836 > super::FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
837 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
838{
839 fn get_word_size(&self) -> super::WordSize {
840 super::WordSize::Eight
841 }
842}
843
844#[cfg(test)]
845mod tests {
846 extern crate std;
847
848 use std::format;
849 use std::vec;
850
851 use super::*;
852 use crate::{FrameBuffer, WordSize};
853 use embedded_graphics::pixelcolor::RgbColor;
854 use embedded_graphics::prelude::*;
855 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
856
857 const TEST_ROWS: usize = 32;
858 const TEST_COLS: usize = 64;
859 const TEST_NROWS: usize = TEST_ROWS / 2;
860 const TEST_BITS: u8 = 3;
861 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
864 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
865
866 #[test]
867 fn test_address_construction() {
868 let addr = Address::new();
869 assert_eq!(addr.0, 0);
870 assert_eq!(addr.latch(), false);
871 assert_eq!(addr.addr(), 0);
872 }
873
874 #[test]
875 fn test_address_setters() {
876 let mut addr = Address::new();
877
878 addr.set_latch(true);
879 assert_eq!(addr.latch(), true);
880 assert_eq!(addr.0 & 0b01000000, 0b01000000);
881
882 addr.set_addr(0b11111);
883 assert_eq!(addr.addr(), 0b11111);
884 assert_eq!(addr.0 & 0b00011111, 0b00011111);
885 }
886
887 #[test]
888 fn test_address_bit_isolation() {
889 let mut addr = Address::new();
890
891 addr.set_addr(0b11111);
893 addr.set_latch(true);
894 assert_eq!(addr.addr(), 0b11111);
895 assert_eq!(addr.latch(), true);
896 }
897
898 #[test]
899 fn test_entry_construction() {
900 let entry = Entry::new();
901 assert_eq!(entry.0, 0);
902 assert_eq!(entry.output_enable(), false);
903 assert_eq!(entry.latch(), false);
904 assert_eq!(entry.red1(), false);
905 assert_eq!(entry.grn1(), false);
906 assert_eq!(entry.blu1(), false);
907 assert_eq!(entry.red2(), false);
908 assert_eq!(entry.grn2(), false);
909 assert_eq!(entry.blu2(), false);
910 }
911
912 #[test]
913 fn test_entry_setters() {
914 let mut entry = Entry::new();
915
916 entry.set_output_enable(true);
917 assert_eq!(entry.output_enable(), true);
918 assert_eq!(entry.0 & 0b10000000, 0b10000000);
919
920 entry.set_latch(true);
921 assert_eq!(entry.latch(), true);
922 assert_eq!(entry.0 & 0b01000000, 0b01000000);
923
924 entry.set_red1(true);
926 entry.set_grn1(true);
927 entry.set_blu1(true);
928 assert_eq!(entry.red1(), true);
929 assert_eq!(entry.grn1(), true);
930 assert_eq!(entry.blu1(), true);
931 assert_eq!(entry.0 & 0b00000111, 0b00000111);
932
933 entry.set_red2(true);
935 entry.set_grn2(true);
936 entry.set_blu2(true);
937 assert_eq!(entry.red2(), true);
938 assert_eq!(entry.grn2(), true);
939 assert_eq!(entry.blu2(), true);
940 assert_eq!(entry.0 & 0b00111000, 0b00111000);
941 }
942
943 #[test]
944 fn test_entry_set_color0() {
945 let mut entry = Entry::new();
946
947 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
949 assert_eq!(entry.red1(), true);
950 assert_eq!(entry.grn1(), false);
951 assert_eq!(entry.blu1(), true);
952 assert_eq!(entry.0 & 0b00000111, 0b00000101); }
954
955 #[test]
956 fn test_entry_set_color1() {
957 let mut entry = Entry::new();
958
959 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
961 assert_eq!(entry.red2(), false);
962 assert_eq!(entry.grn2(), true);
963 assert_eq!(entry.blu2(), true);
964 assert_eq!(entry.0 & 0b00111000, 0b00110000); }
966
967 #[test]
968 fn test_row_construction() {
969 let row: Row<TEST_COLS> = Row::new();
970 assert_eq!(row.data.len(), TEST_COLS);
971 assert_eq!(row.address.len(), 4);
972
973 for entry in &row.data {
975 assert_eq!(entry.0, 0);
976 }
977 for addr in &row.address {
978 assert_eq!(addr.0, 0);
979 }
980 }
981
982 #[test]
983 fn test_row_format() {
984 let mut row: Row<TEST_COLS> = Row::new();
985 let test_addr = 5;
986
987 row.format(test_addr);
988
989 for addr in &row.address {
991 assert_eq!(addr.addr(), test_addr);
992 }
996 let latch_false_count = row.address.iter().filter(|addr| !addr.latch()).count();
1000 assert_eq!(latch_false_count, 1);
1001
1002 for entry in &row.data {
1004 assert_eq!(entry.latch(), false);
1005 }
1006 let oe_false_count = row
1011 .data
1012 .iter()
1013 .filter(|entry| !entry.output_enable())
1014 .count();
1015 assert_eq!(oe_false_count, 1);
1016 }
1017
1018 #[test]
1019 fn test_row_set_color0() {
1020 let mut row: Row<TEST_COLS> = Row::new();
1021
1022 row.set_color0(0, true, false, true);
1023
1024 let mapped_col_0 = map_index(0);
1025 assert_eq!(row.data[mapped_col_0].red1(), true);
1026 assert_eq!(row.data[mapped_col_0].grn1(), false);
1027 assert_eq!(row.data[mapped_col_0].blu1(), true);
1028
1029 row.set_color0(1, false, true, false);
1031
1032 let mapped_col_1 = map_index(1);
1033 assert_eq!(row.data[mapped_col_1].red1(), false);
1034 assert_eq!(row.data[mapped_col_1].grn1(), true);
1035 assert_eq!(row.data[mapped_col_1].blu1(), false);
1036 }
1037
1038 #[test]
1039 fn test_row_set_color1() {
1040 let mut row: Row<TEST_COLS> = Row::new();
1041
1042 row.set_color1(0, true, true, false);
1043
1044 let mapped_col_0 = map_index(0);
1045 assert_eq!(row.data[mapped_col_0].red2(), true);
1046 assert_eq!(row.data[mapped_col_0].grn2(), true);
1047 assert_eq!(row.data[mapped_col_0].blu2(), false);
1048 }
1049
1050 #[test]
1051 fn test_frame_construction() {
1052 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1053 assert_eq!(frame.rows.len(), TEST_NROWS);
1054 }
1055
1056 #[test]
1057 fn test_frame_format() {
1058 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1059
1060 frame.format();
1061
1062 for (addr, row) in frame.rows.iter().enumerate() {
1063 for address in &row.address {
1065 assert_eq!(address.addr() as usize, addr);
1066 }
1067 }
1068 }
1069
1070 #[test]
1071 fn test_frame_set_pixel() {
1072 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1073
1074 frame.set_pixel(5, 10, true, false, true);
1076
1077 let mapped_col_10 = map_index(10);
1078 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1079 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1080 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1081
1082 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1084
1085 let mapped_col_15 = map_index(15);
1086 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1087 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1088 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1089 }
1090
1091 #[test]
1092 fn test_row_default() {
1093 let row1: Row<TEST_COLS> = Row::new();
1094 let row2: Row<TEST_COLS> = Row::default();
1095
1096 assert_eq!(row1, row2);
1098 assert_eq!(row1.data.len(), row2.data.len());
1099 assert_eq!(row1.address.len(), row2.address.len());
1100
1101 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1103 assert_eq!(entry1.0, entry2.0);
1104 assert_eq!(entry1.0, 0);
1105 }
1106 for (addr1, addr2) in row1.address.iter().zip(row2.address.iter()) {
1107 assert_eq!(addr1.0, addr2.0);
1108 assert_eq!(addr1.0, 0);
1109 }
1110 }
1111
1112 #[test]
1113 fn test_frame_default() {
1114 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1115 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1116
1117 assert_eq!(frame1.rows.len(), frame2.rows.len());
1119
1120 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1122 assert_eq!(row1, row2);
1123
1124 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1126 assert_eq!(entry1.0, entry2.0);
1127 assert_eq!(entry1.0, 0);
1128 }
1129 for (addr1, addr2) in row1.address.iter().zip(row2.address.iter()) {
1130 assert_eq!(addr1.0, addr2.0);
1131 assert_eq!(addr1.0, 0);
1132 }
1133 }
1134 }
1135
1136 #[test]
1137 fn test_dma_framebuffer_construction() {
1138 let fb = TestFrameBuffer::new();
1139 assert_eq!(fb.frames.len(), TEST_FRAME_COUNT);
1140 }
1141
1142 #[test]
1143 #[cfg(feature = "esp-hal-dma")]
1144 fn test_dma_framebuffer_dma_buffer_size() {
1145 let expected_size =
1146 core::mem::size_of::<[Frame<TEST_ROWS, TEST_COLS, TEST_NROWS>; TEST_FRAME_COUNT]>();
1147 assert_eq!(TestFrameBuffer::dma_buffer_size_bytes(), expected_size);
1148 }
1149
1150 #[test]
1151 fn test_dma_framebuffer_format() {
1152 let mut fb = TestFrameBuffer {
1153 frames: [Frame::new(); TEST_FRAME_COUNT],
1154 };
1155 fb.format();
1156
1157 for frame in &fb.frames {
1159 for (addr, row) in frame.rows.iter().enumerate() {
1160 for address in &row.address {
1161 assert_eq!(address.addr() as usize, addr);
1162 }
1163 }
1164 }
1165 }
1166
1167 #[test]
1168 fn test_dma_framebuffer_set_pixel_bounds() {
1169 let mut fb = TestFrameBuffer::new();
1170
1171 fb.set_pixel(Point::new(-1, 5), Color::RED);
1173 fb.set_pixel(Point::new(5, -1), Color::RED);
1174
1175 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1177 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1178 }
1179
1180 #[test]
1181 fn test_dma_framebuffer_set_pixel_internal() {
1182 let mut fb = TestFrameBuffer::new();
1183
1184 let red_color = Rgb888::new(255, 0, 0);
1185 fb.set_pixel_internal(10, 5, red_color);
1186
1187 for frame in &fb.frames {
1191 let mapped_col_10 = map_index(10);
1193 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1194 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1195 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1196 }
1197 }
1198
1199 #[test]
1200 fn test_dma_framebuffer_brightness_modulation() {
1201 let mut fb = TestFrameBuffer::new();
1202
1203 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Rgb888::new(test_brightness, 0, 0);
1207
1208 fb.set_pixel_internal(0, 0, color);
1209
1210 for (frame_idx, frame) in fb.frames.iter().enumerate() {
1213 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1214 let should_be_active = test_brightness >= frame_threshold;
1215
1216 let mapped_col_0 = map_index(0);
1217 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1218 }
1219 }
1220
1221 #[test]
1222 fn test_origin_dimensions() {
1223 let fb = TestFrameBuffer::new();
1224 let size = fb.size();
1225 assert_eq!(size.width, TEST_COLS as u32);
1226 assert_eq!(size.height, TEST_ROWS as u32);
1227
1228 let mut fb = TestFrameBuffer::new();
1230 let fb_ref = &mut fb;
1231 let size = fb_ref.size();
1232 assert_eq!(size.width, TEST_COLS as u32);
1233 assert_eq!(size.height, TEST_ROWS as u32);
1234 }
1235
1236 #[test]
1237 fn test_draw_target() {
1238 let mut fb = TestFrameBuffer::new();
1239
1240 let pixels = vec![
1241 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1242 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1243 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1244 ];
1245
1246 let result = fb.draw_iter(pixels);
1247 assert!(result.is_ok());
1248 }
1249
1250 #[test]
1251 fn test_draw_iter_pixel_verification() {
1252 let mut fb = TestFrameBuffer::new();
1253
1254 let pixels = vec![
1256 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)), ];
1270
1271 let result = fb.draw_iter(pixels);
1272 assert!(result.is_ok());
1273
1274 let first_frame = &fb.frames[0];
1276 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = map_index(5);
1282 assert_eq!(
1283 first_frame.rows[2].data[col_idx].red1(),
1284 Color::RED.r() >= first_frame_threshold
1285 );
1286 assert_eq!(
1287 first_frame.rows[2].data[col_idx].grn1(),
1288 Color::RED.g() >= first_frame_threshold
1289 );
1290 assert_eq!(
1291 first_frame.rows[2].data[col_idx].blu1(),
1292 Color::RED.b() >= first_frame_threshold
1293 );
1294
1295 let col_idx = map_index(10);
1297 assert_eq!(
1298 first_frame.rows[5].data[col_idx].red1(),
1299 Color::GREEN.r() >= first_frame_threshold
1300 );
1301 assert_eq!(
1302 first_frame.rows[5].data[col_idx].grn1(),
1303 Color::GREEN.g() >= first_frame_threshold
1304 );
1305 assert_eq!(
1306 first_frame.rows[5].data[col_idx].blu1(),
1307 Color::GREEN.b() >= first_frame_threshold
1308 );
1309
1310 let col_idx = map_index(15);
1312 assert_eq!(
1313 first_frame.rows[8].data[col_idx].red1(),
1314 Color::BLUE.r() >= first_frame_threshold
1315 );
1316 assert_eq!(
1317 first_frame.rows[8].data[col_idx].grn1(),
1318 Color::BLUE.g() >= first_frame_threshold
1319 );
1320 assert_eq!(
1321 first_frame.rows[8].data[col_idx].blu1(),
1322 Color::BLUE.b() >= first_frame_threshold
1323 );
1324
1325 let col_idx = map_index(20);
1327 assert_eq!(
1328 first_frame.rows[10].data[col_idx].red1(),
1329 Color::WHITE.r() >= first_frame_threshold
1330 );
1331 assert_eq!(
1332 first_frame.rows[10].data[col_idx].grn1(),
1333 Color::WHITE.g() >= first_frame_threshold
1334 );
1335 assert_eq!(
1336 first_frame.rows[10].data[col_idx].blu1(),
1337 Color::WHITE.b() >= first_frame_threshold
1338 );
1339
1340 let col_idx = map_index(25);
1343 assert_eq!(
1344 first_frame.rows[3].data[col_idx].red2(),
1345 Color::RED.r() >= first_frame_threshold
1346 );
1347 assert_eq!(
1348 first_frame.rows[3].data[col_idx].grn2(),
1349 Color::RED.g() >= first_frame_threshold
1350 );
1351 assert_eq!(
1352 first_frame.rows[3].data[col_idx].blu2(),
1353 Color::RED.b() >= first_frame_threshold
1354 );
1355
1356 let col_idx = map_index(30);
1358 assert_eq!(
1359 first_frame.rows[7].data[col_idx].red2(),
1360 Color::GREEN.r() >= first_frame_threshold
1361 );
1362 assert_eq!(
1363 first_frame.rows[7].data[col_idx].grn2(),
1364 Color::GREEN.g() >= first_frame_threshold
1365 );
1366 assert_eq!(
1367 first_frame.rows[7].data[col_idx].blu2(),
1368 Color::GREEN.b() >= first_frame_threshold
1369 );
1370
1371 let col_idx = map_index(35);
1373 assert_eq!(
1374 first_frame.rows[12].data[col_idx].red2(),
1375 Color::BLUE.r() >= first_frame_threshold
1376 );
1377 assert_eq!(
1378 first_frame.rows[12].data[col_idx].grn2(),
1379 Color::BLUE.g() >= first_frame_threshold
1380 );
1381 assert_eq!(
1382 first_frame.rows[12].data[col_idx].blu2(),
1383 Color::BLUE.b() >= first_frame_threshold
1384 );
1385
1386 let col_idx = map_index(40);
1388 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1389 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1390 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1391
1392 let col_idx = map_index(45);
1394 assert_eq!(
1395 first_frame.rows[3].data[col_idx].red1(),
1396 16 >= first_frame_threshold
1397 ); assert_eq!(
1399 first_frame.rows[3].data[col_idx].grn1(),
1400 16 >= first_frame_threshold
1401 ); assert_eq!(
1403 first_frame.rows[3].data[col_idx].blu1(),
1404 16 >= first_frame_threshold
1405 ); }
1407
1408 #[test]
1409 fn test_embedded_graphics_integration() {
1410 let mut fb = TestFrameBuffer::new();
1411
1412 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1414 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1415 .draw(&mut fb);
1416 assert!(result.is_ok());
1417
1418 let result = Circle::new(Point::new(30, 15), 8)
1420 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1421 .draw(&mut fb);
1422 assert!(result.is_ok());
1423 }
1424
1425 #[test]
1426 fn test_read_buffer_implementation() {
1427 let fb = TestFrameBuffer::new();
1428
1429 unsafe {
1431 let (ptr, len) = fb.read_buffer();
1432 assert!(!ptr.is_null());
1433 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1434 }
1435
1436 let mut fb = TestFrameBuffer::new();
1438 let fb_ref = &mut fb;
1439 unsafe {
1440 let (ptr, len) = fb_ref.read_buffer();
1441 assert!(!ptr.is_null());
1442 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1443 }
1444 }
1445
1446 #[test]
1447 fn test_framebuffer_trait() {
1448 let fb = TestFrameBuffer::new();
1449 assert_eq!(fb.get_word_size(), WordSize::Eight);
1450
1451 let mut fb = TestFrameBuffer::new();
1452 let fb_ref = &mut fb;
1453 assert_eq!(fb_ref.get_word_size(), WordSize::Eight);
1454 }
1455
1456 #[test]
1457 fn test_debug_formatting() {
1458 let fb = TestFrameBuffer::new();
1459 let debug_string = format!("{:?}", fb);
1460 assert!(debug_string.contains("DmaFrameBuffer"));
1461 assert!(debug_string.contains("frame_count"));
1462 assert!(debug_string.contains("frame_size"));
1463 assert!(debug_string.contains("brightness_step"));
1464 }
1465
1466 #[test]
1467 fn test_default_implementation() {
1468 let fb1 = TestFrameBuffer::new();
1469 let fb2 = TestFrameBuffer::default();
1470
1471 assert_eq!(fb1.frames.len(), fb2.frames.len());
1473 }
1474
1475 #[cfg(feature = "esp32-ordering")]
1476 #[test]
1477 fn test_esp32_mapping() {
1478 assert_eq!(map_index(0), 2);
1480 assert_eq!(map_index(1), 3);
1481 assert_eq!(map_index(2), 0);
1482 assert_eq!(map_index(3), 1);
1483 assert_eq!(map_index(4), 6); assert_eq!(map_index(5), 7); }
1486
1487 #[test]
1488 fn test_memory_alignment() {
1489 let fb = TestFrameBuffer::new();
1490 let ptr = &fb as *const _ as usize;
1491
1492 assert_eq!(ptr % 4, 0);
1494 }
1495
1496 #[test]
1497 fn test_color_values() {
1498 let mut fb = TestFrameBuffer::new();
1499
1500 let colors = [
1502 (Color::RED, (255, 0, 0)),
1503 (Color::GREEN, (0, 255, 0)),
1504 (Color::BLUE, (0, 0, 255)),
1505 (Color::WHITE, (255, 255, 255)),
1506 (Color::BLACK, (0, 0, 0)),
1507 ];
1508
1509 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1510 fb.set_pixel(Point::new(i as i32, 0), *color);
1511 assert_eq!(color.r(), *r);
1512 assert_eq!(color.g(), *g);
1513 assert_eq!(color.b(), *b);
1514 }
1515 }
1516
1517 #[test]
1518 fn test_bits_assertion() {
1519 assert!(TEST_BITS <= 8);
1522 }
1523
1524 #[test]
1525 #[cfg(feature = "skip-black-pixels")]
1526 fn test_skip_black_pixels_enabled() {
1527 let mut fb = TestFrameBuffer::new();
1528
1529 fb.set_pixel_internal(10, 5, Color::RED);
1531
1532 let mapped_col_10 = map_index(10);
1534 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1535 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1536 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1537
1538 fb.set_pixel_internal(10, 5, Color::BLACK);
1540
1541 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1543 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1544 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1545 }
1546
1547 #[test]
1548 #[cfg(not(feature = "skip-black-pixels"))]
1549 fn test_skip_black_pixels_disabled() {
1550 let mut fb = TestFrameBuffer::new();
1551
1552 fb.set_pixel_internal(10, 5, Color::RED);
1554
1555 let mapped_col_10 = map_index(10);
1557 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1558 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1559 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1560
1561 fb.set_pixel_internal(10, 5, Color::BLACK);
1563
1564 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1566 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1567 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1568 }
1569
1570 #[test]
1571 fn test_bcm_frame_overwrite() {
1572 let mut fb = TestFrameBuffer::new();
1573
1574 fb.set_pixel_internal(10, 5, Color::WHITE);
1576
1577 let mapped_col_10 = map_index(10);
1578
1579 for frame in fb.frames.iter() {
1581 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1583 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1584 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1585 }
1586
1587 let half_white = embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128);
1589 fb.set_pixel_internal(10, 5, half_white);
1590
1591 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.frames.iter().enumerate() {
1597 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1598 let should_be_active = 128 >= frame_threshold;
1599
1600 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1601 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1602 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1603 }
1604
1605 for frame_idx in 0..4 {
1608 assert_eq!(
1609 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1610 true
1611 );
1612 }
1613 for frame_idx in 4..TEST_FRAME_COUNT {
1615 assert_eq!(
1616 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1617 false
1618 );
1619 }
1620 }
1621
1622 #[test]
1623 fn test_new_auto_formats() {
1624 let fb = TestFrameBuffer::new();
1625
1626 for frame in &fb.frames {
1628 for (addr, row) in frame.rows.iter().enumerate() {
1629 for address in &row.address {
1630 assert_eq!(address.addr() as usize, addr);
1631 }
1632 }
1633 }
1634 }
1635
1636 #[test]
1637 fn test_erase() {
1638 let mut fb = TestFrameBuffer::new();
1639
1640 fb.set_pixel_internal(10, 5, Color::RED);
1642 fb.set_pixel_internal(20, 10, Color::GREEN);
1643
1644 let mapped_col_10 = map_index(10);
1645 let mapped_col_20 = map_index(20);
1646
1647 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1649 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].grn1(), true);
1650
1651 fb.erase();
1653
1654 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1656 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1657 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1658 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].red1(), false);
1659 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].grn1(), false);
1660 assert_eq!(fb.frames[0].rows[10].data[mapped_col_20].blu1(), false);
1661
1662 for frame in &fb.frames {
1664 for (addr, row) in frame.rows.iter().enumerate() {
1665 for address in &row.address {
1667 assert_eq!(address.addr() as usize, addr);
1668 }
1669 let oe_false_count = row
1671 .data
1672 .iter()
1673 .filter(|entry| !entry.output_enable())
1674 .count();
1675 assert_eq!(oe_false_count, 1);
1676 }
1677 }
1678 }
1679
1680 #[test]
1681 fn test_row_clear_colors() {
1682 let mut row: Row<TEST_COLS> = Row::new();
1683 row.format(5);
1684
1685 row.set_color0(0, true, false, true);
1687 row.set_color1(1, false, true, false);
1688
1689 let mapped_col_0 = map_index(0);
1690 let mapped_col_1 = map_index(1);
1691
1692 assert_eq!(row.data[mapped_col_0].red1(), true);
1694 assert_eq!(row.data[mapped_col_0].blu1(), true);
1695 assert_eq!(row.data[mapped_col_1].grn2(), true);
1696
1697 let original_oe_0 = row.data[mapped_col_0].output_enable();
1699 let original_latch_0 = row.data[mapped_col_0].latch();
1700 let original_oe_1 = row.data[mapped_col_1].output_enable();
1701 let original_latch_1 = row.data[mapped_col_1].latch();
1702
1703 row.clear_colors();
1705
1706 assert_eq!(row.data[mapped_col_0].red1(), false);
1708 assert_eq!(row.data[mapped_col_0].grn1(), false);
1709 assert_eq!(row.data[mapped_col_0].blu1(), false);
1710 assert_eq!(row.data[mapped_col_1].red2(), false);
1711 assert_eq!(row.data[mapped_col_1].grn2(), false);
1712 assert_eq!(row.data[mapped_col_1].blu2(), false);
1713
1714 assert_eq!(row.data[mapped_col_0].output_enable(), original_oe_0);
1716 assert_eq!(row.data[mapped_col_0].latch(), original_latch_0);
1717 assert_eq!(row.data[mapped_col_1].output_enable(), original_oe_1);
1718 assert_eq!(row.data[mapped_col_1].latch(), original_latch_1);
1719 }
1720
1721 #[test]
1722 fn test_make_addr_table_function() {
1723 let table = make_addr_table();
1725
1726 assert_eq!(table.len(), 32); let addr_0 = &table[0];
1731 assert_eq!(addr_0.len(), 4); let latch_false_count = addr_0.iter().filter(|addr| !addr.latch()).count();
1735 assert_eq!(latch_false_count, 1);
1736
1737 for addr in addr_0 {
1739 assert_eq!(addr.addr(), 0);
1740 }
1741
1742 let addr_31 = &table[31];
1744 let latch_false_count = addr_31.iter().filter(|addr| !addr.latch()).count();
1745 assert_eq!(latch_false_count, 1);
1746
1747 for addr in addr_31 {
1749 assert_eq!(addr.addr(), 31);
1750 }
1751 }
1752
1753 #[test]
1754 fn test_make_data_template_function() {
1755 let template = make_data_template::<TEST_COLS>();
1757
1758 assert_eq!(template.len(), TEST_COLS);
1760
1761 for entry in &template {
1763 assert_eq!(entry.latch(), false);
1764 }
1765
1766 let oe_false_count = template
1768 .iter()
1769 .filter(|entry| !entry.output_enable())
1770 .count();
1771 assert_eq!(oe_false_count, 1);
1772
1773 let small_template = make_data_template::<4>();
1775 assert_eq!(small_template.len(), 4);
1776
1777 let oe_false_count = small_template
1778 .iter()
1779 .filter(|entry| !entry.output_enable())
1780 .count();
1781 assert_eq!(oe_false_count, 1);
1782
1783 #[cfg(not(feature = "esp32-ordering"))]
1786 {
1787 let single_template = make_data_template::<1>();
1788 assert_eq!(single_template.len(), 1);
1789 assert_eq!(single_template[0].output_enable(), false); assert_eq!(single_template[0].latch(), false);
1791 }
1792 }
1793
1794 #[test]
1795 fn test_addr_table_correctness() {
1796 for addr in 0..32 {
1798 let mut expected_addresses = [Address::new(); 4];
1799
1800 for i in 0..4 {
1802 let latch = !matches!(i, 3);
1803 #[cfg(feature = "esp32-ordering")]
1804 let mapped_i = map_index(i);
1805 #[cfg(not(feature = "esp32-ordering"))]
1806 let mapped_i = i;
1807
1808 expected_addresses[mapped_i].set_latch(latch);
1809 expected_addresses[mapped_i].set_addr(addr);
1810 }
1811
1812 let table_addresses = &ADDR_TABLE[addr as usize];
1814 for i in 0..4 {
1815 assert_eq!(table_addresses[i].0, expected_addresses[i].0);
1816 }
1817 }
1818 }
1819
1820 const CHAR_W: i32 = 6;
1822 const CHAR_H: i32 = 10;
1823
1824 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1827 use embedded_graphics::mock_display::MockDisplay;
1828 use embedded_graphics::mono_font::ascii::FONT_6X10;
1829 use embedded_graphics::mono_font::MonoTextStyle;
1830 use embedded_graphics::text::{Baseline, Text};
1831
1832 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1834 Text::with_baseline("A", origin, style, Baseline::Top)
1835 .draw(fb)
1836 .unwrap();
1837
1838 let mut reference: MockDisplay<Color> = MockDisplay::new();
1840 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1841 .draw(&mut reference)
1842 .unwrap();
1843
1844 for dy in 0..CHAR_H {
1846 for dx in 0..CHAR_W {
1847 let expected_on = reference
1848 .get_pixel(Point::new(dx, dy))
1849 .unwrap_or(Color::BLACK)
1850 != Color::BLACK;
1851
1852 let gx = (origin.x + dx) as usize;
1853 let gy = (origin.y + dy) as usize;
1854
1855 let frame0 = &fb.frames[0];
1862 let e = if gy < TEST_NROWS {
1863 &frame0.rows[gy].data[map_index(gx)]
1864 } else {
1865 &frame0.rows[gy - TEST_NROWS].data[map_index(gx)]
1866 };
1867
1868 let (r, g, b) = if gy >= TEST_NROWS {
1869 (e.red2(), e.grn2(), e.blu2())
1870 } else {
1871 (e.red1(), e.grn1(), e.blu1())
1872 };
1873
1874 if expected_on {
1875 assert!(r && g && b);
1876 } else {
1877 assert!(!r && !g && !b);
1878 }
1879 }
1880 }
1881 }
1882
1883 #[test]
1884 fn test_draw_char_corners() {
1885 let upper_left = Point::new(0, 0);
1887 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1888
1889 let mut fb = TestFrameBuffer::new();
1890
1891 verify_glyph_at(&mut fb, upper_left);
1893 verify_glyph_at(&mut fb, lower_right);
1895 }
1896
1897 #[test]
1898 fn test_framebuffer_operations_trait_erase() {
1899 let mut fb = TestFrameBuffer::new();
1900
1901 fb.set_pixel_internal(10, 5, Color::RED);
1903 fb.set_pixel_internal(20, 10, Color::GREEN);
1904
1905 <TestFrameBuffer as FrameBufferOperations<
1907 TEST_ROWS,
1908 TEST_COLS,
1909 TEST_NROWS,
1910 TEST_BITS,
1911 TEST_FRAME_COUNT,
1912 >>::erase(&mut fb);
1913
1914 let mc10 = map_index(10);
1916 let mc20 = map_index(20);
1917 assert_eq!(fb.frames[0].rows[5].data[mc10].red1(), false);
1918 assert_eq!(fb.frames[0].rows[10].data[mc20].grn1(), false);
1919
1920 let row0 = &fb.frames[0].rows[0];
1922 let oe_false_count = row0
1923 .data
1924 .iter()
1925 .filter(|entry| !entry.output_enable())
1926 .count();
1927 assert_eq!(oe_false_count, 1);
1928 assert!(row0.data.iter().all(|e| !e.latch()));
1929
1930 for (i, addr) in row0.address.iter().enumerate() {
1932 assert_eq!(addr.0, ADDR_TABLE[0][i].0);
1933 }
1934 }
1935
1936 #[test]
1937 fn test_framebuffer_operations_trait_set_pixel() {
1938 let mut fb = TestFrameBuffer::new();
1939
1940 <TestFrameBuffer as FrameBufferOperations<
1942 TEST_ROWS,
1943 TEST_COLS,
1944 TEST_NROWS,
1945 TEST_BITS,
1946 TEST_FRAME_COUNT,
1947 >>::set_pixel(&mut fb, Point::new(8, 3), Color::BLUE);
1948
1949 let idx = map_index(8);
1951 assert_eq!(fb.frames[0].rows[3].data[idx].blu1(), true);
1952 assert_eq!(fb.frames[0].rows[3].data[idx].red1(), false);
1954 assert_eq!(fb.frames[0].rows[3].data[idx].grn1(), false);
1955 }
1956}