1use core::convert::Infallible;
133
134use crate::FrameBufferOperations;
135use bitfield::bitfield;
136#[cfg(not(feature = "esp-hal-dma"))]
137use embedded_dma::ReadBuffer;
138use embedded_graphics::pixelcolor::RgbColor;
139use embedded_graphics::prelude::Point;
140#[cfg(feature = "esp-hal-dma")]
141use esp_hal::dma::ReadBuffer;
142
143use super::Color;
144use super::FrameBuffer;
145use super::WordSize;
146
147const BLANKING_DELAY: usize = 1;
148
149#[inline]
152const fn make_data_template<const COLS: usize>(addr: u8, prev_addr: u8) -> [Entry; COLS] {
153 let mut data = [Entry::new(); COLS];
154 let mut i = 0;
155
156 while i < COLS {
157 let mut entry = Entry::new();
158 entry.0 = prev_addr as u16;
159
160 if i == 1 {
162 entry.0 |= 0b1_0000_0000; } else if i == COLS - BLANKING_DELAY - 1 {
164 } else if i == COLS - 1 {
166 entry.0 |= 0b0010_0000; entry.0 = (entry.0 & !0b0001_1111) | (addr as u16); } else if i > 1 && i < COLS - BLANKING_DELAY - 1 {
169 entry.0 |= 0b1_0000_0000; }
171
172 data[map_index(i)] = entry;
173 i += 1;
174 }
175
176 data
177}
178
179bitfield! {
180 #[derive(Clone, Copy, Default, PartialEq)]
201 #[repr(transparent)]
202 struct Entry(u16);
203 dummy2, set_dummy2: 15;
204 blu2, set_blu2: 14;
205 grn2, set_grn2: 13;
206 red2, set_red2: 12;
207 blu1, set_blu1: 11;
208 grn1, set_grn1: 10;
209 red1, set_red1: 9;
210 output_enable, set_output_enable: 8;
211 dummy1, set_dummy1: 7;
212 dummy0, set_dummy0: 6;
213 latch, set_latch: 5;
214 addr, set_addr: 4, 0;
215}
216
217impl core::fmt::Debug for Entry {
218 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
219 f.debug_tuple("Entry")
220 .field(&format_args!("{:#x}", self.0))
221 .finish()
222 }
223}
224
225#[cfg(feature = "defmt")]
226impl defmt::Format for Entry {
227 fn format(&self, f: defmt::Formatter) {
228 defmt::write!(f, "Entry({=u16:#x})", self.0);
229 }
230}
231
232impl Entry {
233 const fn new() -> Self {
234 Self(0)
235 }
236
237 const COLOR0_MASK: u16 = 0b0000_1110_0000_0000; const COLOR1_MASK: u16 = 0b0111_0000_0000_0000; #[inline]
242 fn set_color0_bits(&mut self, bits: u8) {
243 let bits16 = u16::from(bits) << 9;
244 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits16 & Self::COLOR0_MASK);
245 }
246
247 #[inline]
248 fn set_color1_bits(&mut self, bits: u8) {
249 let bits16 = u16::from(bits) << 12;
250 self.0 = (self.0 & !Self::COLOR1_MASK) | (bits16 & Self::COLOR1_MASK);
251 }
252}
253
254#[derive(Clone, Copy, PartialEq, Debug)]
263#[repr(C)]
264struct Row<const COLS: usize> {
265 data: [Entry; COLS],
266}
267
268const fn map_index(i: usize) -> usize {
269 #[cfg(feature = "esp32-ordering")]
270 {
271 i ^ 1
272 }
273 #[cfg(not(feature = "esp32-ordering"))]
274 {
275 i
276 }
277}
278
279impl<const COLS: usize> Default for Row<COLS> {
280 fn default() -> Self {
281 Self::new()
282 }
283}
284
285impl<const COLS: usize> Row<COLS> {
286 pub const fn new() -> Self {
287 Self {
288 data: [Entry::new(); COLS],
289 }
290 }
291
292 pub fn format(&mut self, addr: u8, prev_addr: u8) {
293 let template = make_data_template::<COLS>(addr, prev_addr);
295 self.data.copy_from_slice(&template);
296 }
297
298 #[inline]
301 pub fn clear_colors(&mut self) {
302 const COLOR_CLEAR_MASK: u16 = !0b0111_1110_0000_0000; for entry in &mut self.data {
306 entry.0 &= COLOR_CLEAR_MASK;
307 }
308 }
309
310 #[inline]
311 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
312 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
313 let col = map_index(col);
314 self.data[col].set_color0_bits(bits);
315 }
316
317 #[inline]
318 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
319 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
320 let col = map_index(col);
321 self.data[col].set_color1_bits(bits);
322 }
323}
324
325#[derive(Copy, Clone, Debug)]
326#[repr(C)]
327struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
328 rows: [Row<COLS>; NROWS],
329}
330
331impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
332 pub const fn new() -> Self {
333 Self {
334 rows: [Row::new(); NROWS],
335 }
336 }
337
338 pub fn format(&mut self) {
339 for (addr, row) in self.rows.iter_mut().enumerate() {
340 let prev_addr = if addr == 0 {
341 NROWS as u8 - 1
342 } else {
343 addr as u8 - 1
344 };
345 row.format(addr as u8, prev_addr);
346 }
347 }
348
349 #[inline]
351 pub fn clear_colors(&mut self) {
352 for row in &mut self.rows {
353 row.clear_colors();
354 }
355 }
356
357 #[inline]
358 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
359 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
360 if y < NROWS {
361 row.set_color0(x, red, green, blue);
362 } else {
363 row.set_color1(x, red, green, blue);
364 }
365 }
366}
367
368impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
369 for Frame<ROWS, COLS, NROWS>
370{
371 fn default() -> Self {
372 Self::new()
373 }
374}
375
376#[derive(Copy, Clone)]
401#[repr(C)]
402pub struct DmaFrameBuffer<
403 const ROWS: usize,
404 const COLS: usize,
405 const NROWS: usize,
406 const BITS: u8,
407 const FRAME_COUNT: usize,
408> {
409 _align: u64,
410 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
411}
412
413impl<
414 const ROWS: usize,
415 const COLS: usize,
416 const NROWS: usize,
417 const BITS: u8,
418 const FRAME_COUNT: usize,
419 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
420{
421 fn default() -> Self {
422 Self::new()
423 }
424}
425
426impl<
427 const ROWS: usize,
428 const COLS: usize,
429 const NROWS: usize,
430 const BITS: u8,
431 const FRAME_COUNT: usize,
432 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
433{
434 #[must_use]
457 pub fn new() -> Self {
458 debug_assert!(BITS <= 8);
459
460 let mut instance = Self {
461 _align: 0,
462 frames: [Frame::new(); FRAME_COUNT],
463 };
464
465 instance.format();
467 instance
468 }
469
470 #[cfg(feature = "esp-hal-dma")]
486 #[must_use]
487 pub const fn dma_buffer_size_bytes() -> usize {
488 core::mem::size_of::<[Frame<ROWS, COLS, NROWS>; FRAME_COUNT]>()
489 }
490
491 #[inline]
511 pub fn format(&mut self) {
512 for frame in &mut self.frames {
513 frame.format();
514 }
515 }
516
517 #[inline]
537 pub fn erase(&mut self) {
538 for frame in &mut self.frames {
539 frame.clear_colors();
540 }
541 }
542
543 pub fn set_pixel(&mut self, p: Point, color: Color) {
559 if p.x < 0 || p.y < 0 {
560 return;
561 }
562 self.set_pixel_internal(p.x as usize, p.y as usize, color);
563 }
564
565 #[inline]
566 fn frames_on(v: u8) -> usize {
567 (v as usize) >> (8 - BITS)
569 }
570
571 #[inline]
572 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Color) {
573 if x >= COLS || y >= ROWS {
574 return;
575 }
576
577 #[cfg(feature = "skip-black-pixels")]
580 if color == Color::BLACK {
581 return;
582 }
583
584 let red_frames = Self::frames_on(color.r());
586 let green_frames = Self::frames_on(color.g());
587 let blue_frames = Self::frames_on(color.b());
588
589 for (frame_idx, frame) in self.frames.iter_mut().enumerate() {
591 frame.set_pixel(
592 y,
593 x,
594 frame_idx < red_frames,
595 frame_idx < green_frames,
596 frame_idx < blue_frames,
597 );
598 }
599 }
600}
601
602impl<
603 const ROWS: usize,
604 const COLS: usize,
605 const NROWS: usize,
606 const BITS: u8,
607 const FRAME_COUNT: usize,
608 > FrameBufferOperations<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
609 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
610{
611 #[inline]
612 fn erase(&mut self) {
613 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::erase(self);
614 }
615
616 #[inline]
617 fn set_pixel(&mut self, p: Point, color: Color) {
618 DmaFrameBuffer::<ROWS, COLS, NROWS, BITS, FRAME_COUNT>::set_pixel(self, p, color);
619 }
620}
621
622impl<
623 const ROWS: usize,
624 const COLS: usize,
625 const NROWS: usize,
626 const BITS: u8,
627 const FRAME_COUNT: usize,
628 > embedded_graphics::prelude::OriginDimensions
629 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
630{
631 fn size(&self) -> embedded_graphics::prelude::Size {
632 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
633 }
634}
635
636impl<
637 const ROWS: usize,
638 const COLS: usize,
639 const NROWS: usize,
640 const BITS: u8,
641 const FRAME_COUNT: usize,
642 > embedded_graphics::prelude::OriginDimensions
643 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
644{
645 fn size(&self) -> embedded_graphics::prelude::Size {
646 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
647 }
648}
649
650impl<
651 const ROWS: usize,
652 const COLS: usize,
653 const NROWS: usize,
654 const BITS: u8,
655 const FRAME_COUNT: usize,
656 > embedded_graphics::draw_target::DrawTarget
657 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
658{
659 type Color = Color;
660
661 type Error = Infallible;
662
663 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
664 where
665 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
666 {
667 for pixel in pixels {
668 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
669 }
670 Ok(())
671 }
672}
673
674unsafe impl<
675 const ROWS: usize,
676 const COLS: usize,
677 const NROWS: usize,
678 const BITS: u8,
679 const FRAME_COUNT: usize,
680 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
681{
682 #[cfg(not(feature = "esp-hal-dma"))]
683 type Word = u8;
684
685 unsafe fn read_buffer(&self) -> (*const u8, usize) {
686 let ptr = (&raw const self.frames).cast::<u8>();
687 let len = core::mem::size_of_val(&self.frames);
688 (ptr, len)
689 }
690}
691
692unsafe impl<
693 const ROWS: usize,
694 const COLS: usize,
695 const NROWS: usize,
696 const BITS: u8,
697 const FRAME_COUNT: usize,
698 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
699{
700 #[cfg(not(feature = "esp-hal-dma"))]
701 type Word = u8;
702
703 unsafe fn read_buffer(&self) -> (*const u8, usize) {
704 let ptr = (&raw const self.frames).cast::<u8>();
705 let len = core::mem::size_of_val(&self.frames);
706 (ptr, len)
707 }
708}
709
710impl<
711 const ROWS: usize,
712 const COLS: usize,
713 const NROWS: usize,
714 const BITS: u8,
715 const FRAME_COUNT: usize,
716 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
717{
718 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
719 let brightness_step = 1 << (8 - BITS);
720 f.debug_struct("DmaFrameBuffer")
721 .field("size", &core::mem::size_of_val(&self.frames))
722 .field("frame_count", &self.frames.len())
723 .field("frame_size", &core::mem::size_of_val(&self.frames[0]))
724 .field("brightness_step", &&brightness_step)
725 .finish_non_exhaustive()
726 }
727}
728
729#[cfg(feature = "defmt")]
730impl<
731 const ROWS: usize,
732 const COLS: usize,
733 const NROWS: usize,
734 const BITS: u8,
735 const FRAME_COUNT: usize,
736 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
737{
738 fn format(&self, f: defmt::Formatter) {
739 let brightness_step = 1 << (8 - BITS);
740 defmt::write!(
741 f,
742 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
743 ROWS,
744 COLS,
745 NROWS,
746 BITS,
747 FRAME_COUNT
748 );
749 defmt::write!(f, " size: {}", core::mem::size_of_val(&self.frames));
750 defmt::write!(
751 f,
752 " frame_size: {}",
753 core::mem::size_of_val(&self.frames[0])
754 );
755 defmt::write!(f, " brightness_step: {}", brightness_step);
756 }
757}
758
759impl<
760 const ROWS: usize,
761 const COLS: usize,
762 const NROWS: usize,
763 const BITS: u8,
764 const FRAME_COUNT: usize,
765 > FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
766 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
767{
768 fn get_word_size(&self) -> WordSize {
769 WordSize::Sixteen
770 }
771}
772
773impl<
774 const ROWS: usize,
775 const COLS: usize,
776 const NROWS: usize,
777 const BITS: u8,
778 const FRAME_COUNT: usize,
779 > FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
780 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
781{
782 fn get_word_size(&self) -> WordSize {
783 WordSize::Sixteen
784 }
785}
786
787#[cfg(test)]
788mod tests {
789 extern crate std;
790
791 use std::format;
792 use std::vec;
793
794 use super::*;
795 use crate::{FrameBuffer, WordSize};
796 use embedded_graphics::pixelcolor::RgbColor;
797 use embedded_graphics::prelude::*;
798 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
799
800 const TEST_ROWS: usize = 32;
801 const TEST_COLS: usize = 64;
802 const TEST_NROWS: usize = TEST_ROWS / 2;
803 const TEST_BITS: u8 = 3;
804 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
807 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
808
809 fn get_mapped_index(index: usize) -> usize {
811 map_index(index)
812 }
813
814 #[test]
815 fn test_entry_construction() {
816 let entry = Entry::new();
817 assert_eq!(entry.0, 0);
818 assert_eq!(entry.dummy2(), false);
819 assert_eq!(entry.blu2(), false);
820 assert_eq!(entry.grn2(), false);
821 assert_eq!(entry.red2(), false);
822 assert_eq!(entry.blu1(), false);
823 assert_eq!(entry.grn1(), false);
824 assert_eq!(entry.red1(), false);
825 assert_eq!(entry.output_enable(), false);
826 assert_eq!(entry.dummy1(), false);
827 assert_eq!(entry.dummy0(), false);
828 assert_eq!(entry.latch(), false);
829 assert_eq!(entry.addr(), 0);
830 }
831
832 #[test]
833 fn test_entry_setters() {
834 let mut entry = Entry::new();
835
836 entry.set_dummy2(true);
837 assert_eq!(entry.dummy2(), true);
838 assert_eq!(entry.0 & 0b1000000000000000, 0b1000000000000000);
839
840 entry.set_blu2(true);
841 assert_eq!(entry.blu2(), true);
842 assert_eq!(entry.0 & 0b0100000000000000, 0b0100000000000000);
843
844 entry.set_grn2(true);
845 assert_eq!(entry.grn2(), true);
846 assert_eq!(entry.0 & 0b0010000000000000, 0b0010000000000000);
847
848 entry.set_red2(true);
849 assert_eq!(entry.red2(), true);
850 assert_eq!(entry.0 & 0b0001000000000000, 0b0001000000000000);
851
852 entry.set_blu1(true);
853 assert_eq!(entry.blu1(), true);
854 assert_eq!(entry.0 & 0b0000100000000000, 0b0000100000000000);
855
856 entry.set_grn1(true);
857 assert_eq!(entry.grn1(), true);
858 assert_eq!(entry.0 & 0b0000010000000000, 0b0000010000000000);
859
860 entry.set_red1(true);
861 assert_eq!(entry.red1(), true);
862 assert_eq!(entry.0 & 0b0000001000000000, 0b0000001000000000);
863
864 entry.set_output_enable(true);
865 assert_eq!(entry.output_enable(), true);
866 assert_eq!(entry.0 & 0b0000000100000000, 0b0000000100000000);
867
868 entry.set_dummy1(true);
869 assert_eq!(entry.dummy1(), true);
870 assert_eq!(entry.0 & 0b0000000010000000, 0b0000000010000000);
871
872 entry.set_dummy0(true);
873 assert_eq!(entry.dummy0(), true);
874 assert_eq!(entry.0 & 0b0000000001000000, 0b0000000001000000);
875
876 entry.set_latch(true);
877 assert_eq!(entry.latch(), true);
878 assert_eq!(entry.0 & 0b0000000000100000, 0b0000000000100000);
879
880 entry.set_addr(0b11111);
881 assert_eq!(entry.addr(), 0b11111);
882 assert_eq!(entry.0 & 0b0000000000011111, 0b0000000000011111);
883 }
884
885 #[test]
886 fn test_entry_bit_isolation() {
887 let mut entry = Entry::new();
888
889 entry.set_addr(0b11111);
891 entry.set_latch(true);
892 assert_eq!(entry.addr(), 0b11111);
893 assert_eq!(entry.latch(), true);
894 assert_eq!(entry.output_enable(), false);
895 assert_eq!(entry.red1(), false);
896
897 entry.set_red1(true);
898 entry.set_grn2(true);
899 assert_eq!(entry.addr(), 0b11111);
900 assert_eq!(entry.latch(), true);
901 assert_eq!(entry.red1(), true);
902 assert_eq!(entry.grn2(), true);
903 assert_eq!(entry.blu1(), false);
904 assert_eq!(entry.red2(), false);
905 }
906
907 #[test]
908 fn test_entry_set_color0() {
909 let mut entry = Entry::new();
910
911 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
913 assert_eq!(entry.red1(), true);
914 assert_eq!(entry.grn1(), false);
915 assert_eq!(entry.blu1(), true);
916 assert_eq!(entry.0 & 0b0000101000000000, 0b0000101000000000); }
919
920 #[test]
921 fn test_entry_set_color1() {
922 let mut entry = Entry::new();
923
924 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
926 assert_eq!(entry.red2(), false);
927 assert_eq!(entry.grn2(), true);
928 assert_eq!(entry.blu2(), true);
929 assert_eq!(entry.0 & 0b0110000000000000, 0b0110000000000000); }
932
933 #[test]
934 fn test_entry_debug_formatting() {
935 let entry = Entry(0x1234);
936 let debug_str = format!("{:?}", entry);
937 assert_eq!(debug_str, "Entry(0x1234)");
938
939 let entry = Entry(0xabcd);
940 let debug_str = format!("{:?}", entry);
941 assert_eq!(debug_str, "Entry(0xabcd)");
942 }
943
944 #[test]
945 fn test_row_construction() {
946 let row: Row<TEST_COLS> = Row::new();
947 assert_eq!(row.data.len(), TEST_COLS);
948
949 for entry in &row.data {
951 assert_eq!(entry.0, 0);
952 }
953 }
954
955 #[test]
956 fn test_row_format() {
957 let mut row: Row<TEST_COLS> = Row::new();
958 let test_addr = 5;
959 let prev_addr = 4;
960
961 row.format(test_addr, prev_addr);
962
963 for (physical_i, entry) in row.data.iter().enumerate() {
965 let logical_i = get_mapped_index(physical_i);
966
967 match logical_i {
968 i if i == TEST_COLS - BLANKING_DELAY - 1 => {
969 assert_eq!(entry.output_enable(), false);
971 assert_eq!(entry.addr(), prev_addr as u16);
972 assert_eq!(entry.latch(), false);
973 }
974 i if i == TEST_COLS - 1 => {
975 assert_eq!(entry.latch(), true);
977 assert_eq!(entry.addr(), test_addr as u16);
978 assert_eq!(entry.output_enable(), false);
979 }
980 1 => {
981 assert_eq!(entry.output_enable(), true);
983 assert_eq!(entry.addr(), prev_addr as u16);
984 assert_eq!(entry.latch(), false);
985 }
986 _ => {
987 assert_eq!(entry.addr(), prev_addr as u16);
989 assert_eq!(entry.latch(), false);
990 if logical_i > 1 && logical_i < TEST_COLS - BLANKING_DELAY - 1 {
991 assert_eq!(entry.output_enable(), true);
992 }
993 }
994 }
995 }
996 }
997
998 #[test]
999 fn test_row_set_color0() {
1000 let mut row: Row<TEST_COLS> = Row::new();
1001
1002 row.set_color0(0, true, false, true);
1003
1004 let mapped_col_0 = get_mapped_index(0);
1005 assert_eq!(row.data[mapped_col_0].red1(), true);
1006 assert_eq!(row.data[mapped_col_0].grn1(), false);
1007 assert_eq!(row.data[mapped_col_0].blu1(), true);
1008
1009 row.set_color0(1, false, true, false);
1011
1012 let mapped_col_1 = get_mapped_index(1);
1013 assert_eq!(row.data[mapped_col_1].red1(), false);
1014 assert_eq!(row.data[mapped_col_1].grn1(), true);
1015 assert_eq!(row.data[mapped_col_1].blu1(), false);
1016 }
1017
1018 #[test]
1019 fn test_row_set_color1() {
1020 let mut row: Row<TEST_COLS> = Row::new();
1021
1022 row.set_color1(0, true, true, false);
1023
1024 let mapped_col_0 = get_mapped_index(0);
1025 assert_eq!(row.data[mapped_col_0].red2(), true);
1026 assert_eq!(row.data[mapped_col_0].grn2(), true);
1027 assert_eq!(row.data[mapped_col_0].blu2(), false);
1028 }
1029
1030 #[test]
1031 fn test_row_default() {
1032 let row1: Row<TEST_COLS> = Row::new();
1033 let row2: Row<TEST_COLS> = Row::default();
1034
1035 assert_eq!(row1, row2);
1037 assert_eq!(row1.data.len(), row2.data.len());
1038
1039 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1041 assert_eq!(entry1.0, entry2.0);
1042 assert_eq!(entry1.0, 0);
1043 }
1044 }
1045
1046 #[test]
1047 fn test_frame_construction() {
1048 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1049 assert_eq!(frame.rows.len(), TEST_NROWS);
1050 }
1051
1052 #[test]
1053 fn test_frame_format() {
1054 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1055
1056 frame.format();
1057
1058 for addr in 0..TEST_NROWS {
1060 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1061
1062 let row = &frame.rows[addr];
1064
1065 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1067 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1068 assert_eq!(row.data[last_pixel_idx].latch(), true);
1069
1070 let first_pixel_idx = get_mapped_index(0);
1072 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1073 assert_eq!(row.data[first_pixel_idx].latch(), false);
1074 }
1075 }
1076
1077 #[test]
1078 fn test_frame_set_pixel() {
1079 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1080
1081 frame.set_pixel(5, 10, true, false, true);
1083
1084 let mapped_col_10 = get_mapped_index(10);
1085 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1086 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1087 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1088
1089 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1091
1092 let mapped_col_15 = get_mapped_index(15);
1093 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1094 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1095 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1096 }
1097
1098 #[test]
1099 fn test_frame_default() {
1100 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1101 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1102
1103 assert_eq!(frame1.rows.len(), frame2.rows.len());
1105
1106 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1108 assert_eq!(row1, row2);
1109
1110 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1112 assert_eq!(entry1.0, entry2.0);
1113 assert_eq!(entry1.0, 0);
1114 }
1115 }
1116 }
1117
1118 #[test]
1119 fn test_dma_framebuffer_construction() {
1120 let fb = TestFrameBuffer::new();
1121 assert_eq!(fb.frames.len(), TEST_FRAME_COUNT);
1122 assert_eq!(fb._align, 0);
1123 }
1124
1125 #[test]
1126 #[cfg(feature = "esp-hal-dma")]
1127 fn test_dma_framebuffer_dma_buffer_size() {
1128 let expected_size =
1129 core::mem::size_of::<[Frame<TEST_ROWS, TEST_COLS, TEST_NROWS>; TEST_FRAME_COUNT]>();
1130 assert_eq!(TestFrameBuffer::dma_buffer_size_bytes(), expected_size);
1131 }
1132
1133 #[test]
1134 fn test_dma_framebuffer_erase() {
1135 let fb = TestFrameBuffer::new();
1136
1137 for frame in &fb.frames {
1139 for addr in 0..TEST_NROWS {
1140 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1141
1142 let row = &frame.rows[addr];
1144
1145 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1147 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1148 assert_eq!(row.data[last_pixel_idx].latch(), true);
1149
1150 let first_pixel_idx = get_mapped_index(0);
1152 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1153 assert_eq!(row.data[first_pixel_idx].latch(), false);
1154 }
1155 }
1156 }
1157
1158 #[test]
1159 fn test_dma_framebuffer_set_pixel_bounds() {
1160 let mut fb = TestFrameBuffer::new();
1161
1162 fb.set_pixel(Point::new(-1, 5), Color::RED);
1164 fb.set_pixel(Point::new(5, -1), Color::RED);
1165
1166 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1168 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1169 }
1170
1171 #[test]
1172 fn test_dma_framebuffer_set_pixel_internal() {
1173 let mut fb = TestFrameBuffer::new();
1174
1175 let red_color = Color::RED;
1176 fb.set_pixel_internal(10, 5, red_color);
1177
1178 for frame in &fb.frames {
1182 let mapped_col_10 = get_mapped_index(10);
1184 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1185 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1186 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1187 }
1188 }
1189
1190 #[test]
1191 fn test_dma_framebuffer_brightness_modulation() {
1192 let mut fb = TestFrameBuffer::new();
1193
1194 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Color::from(embedded_graphics::pixelcolor::Rgb888::new(
1198 test_brightness,
1199 0,
1200 0,
1201 ));
1202
1203 fb.set_pixel_internal(0, 0, color);
1204
1205 for (frame_idx, frame) in fb.frames.iter().enumerate() {
1208 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1209 let should_be_active = test_brightness >= frame_threshold;
1210
1211 let mapped_col_0 = get_mapped_index(0);
1212 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1213 }
1214 }
1215
1216 #[test]
1217 fn test_origin_dimensions() {
1218 let fb = TestFrameBuffer::new();
1219 let size = fb.size();
1220 assert_eq!(size.width, TEST_COLS as u32);
1221 assert_eq!(size.height, TEST_ROWS as u32);
1222
1223 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 let result = (&mut fb).draw_iter(vec![embedded_graphics::Pixel(
1251 Point::new(3, 3),
1252 Color::WHITE,
1253 )]);
1254 assert!(result.is_ok());
1255 }
1256
1257 #[test]
1258 fn test_draw_iter_pixel_verification() {
1259 let mut fb = TestFrameBuffer::new();
1260
1261 let pixels = vec![
1263 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), ];
1275
1276 let result = fb.draw_iter(pixels);
1277 assert!(result.is_ok());
1278
1279 let first_frame = &fb.frames[0];
1281 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = get_mapped_index(5);
1287 assert_eq!(
1288 first_frame.rows[2].data[col_idx].red1(),
1289 Color::RED.r() >= first_frame_threshold
1290 );
1291 assert_eq!(
1292 first_frame.rows[2].data[col_idx].grn1(),
1293 Color::RED.g() >= first_frame_threshold
1294 );
1295 assert_eq!(
1296 first_frame.rows[2].data[col_idx].blu1(),
1297 Color::RED.b() >= first_frame_threshold
1298 );
1299
1300 let col_idx = get_mapped_index(10);
1302 assert_eq!(
1303 first_frame.rows[5].data[col_idx].red1(),
1304 Color::GREEN.r() >= first_frame_threshold
1305 );
1306 assert_eq!(
1307 first_frame.rows[5].data[col_idx].grn1(),
1308 Color::GREEN.g() >= first_frame_threshold
1309 );
1310 assert_eq!(
1311 first_frame.rows[5].data[col_idx].blu1(),
1312 Color::GREEN.b() >= first_frame_threshold
1313 );
1314
1315 let col_idx = get_mapped_index(15);
1317 assert_eq!(
1318 first_frame.rows[8].data[col_idx].red1(),
1319 Color::BLUE.r() >= first_frame_threshold
1320 );
1321 assert_eq!(
1322 first_frame.rows[8].data[col_idx].grn1(),
1323 Color::BLUE.g() >= first_frame_threshold
1324 );
1325 assert_eq!(
1326 first_frame.rows[8].data[col_idx].blu1(),
1327 Color::BLUE.b() >= first_frame_threshold
1328 );
1329
1330 let col_idx = get_mapped_index(20);
1332 assert_eq!(
1333 first_frame.rows[10].data[col_idx].red1(),
1334 Color::WHITE.r() >= first_frame_threshold
1335 );
1336 assert_eq!(
1337 first_frame.rows[10].data[col_idx].grn1(),
1338 Color::WHITE.g() >= first_frame_threshold
1339 );
1340 assert_eq!(
1341 first_frame.rows[10].data[col_idx].blu1(),
1342 Color::WHITE.b() >= first_frame_threshold
1343 );
1344
1345 let col_idx = get_mapped_index(25);
1348 assert_eq!(
1349 first_frame.rows[3].data[col_idx].red2(),
1350 Color::RED.r() >= first_frame_threshold
1351 );
1352 assert_eq!(
1353 first_frame.rows[3].data[col_idx].grn2(),
1354 Color::RED.g() >= first_frame_threshold
1355 );
1356 assert_eq!(
1357 first_frame.rows[3].data[col_idx].blu2(),
1358 Color::RED.b() >= first_frame_threshold
1359 );
1360
1361 let col_idx = get_mapped_index(30);
1363 assert_eq!(
1364 first_frame.rows[7].data[col_idx].red2(),
1365 Color::GREEN.r() >= first_frame_threshold
1366 );
1367 assert_eq!(
1368 first_frame.rows[7].data[col_idx].grn2(),
1369 Color::GREEN.g() >= first_frame_threshold
1370 );
1371 assert_eq!(
1372 first_frame.rows[7].data[col_idx].blu2(),
1373 Color::GREEN.b() >= first_frame_threshold
1374 );
1375
1376 let col_idx = get_mapped_index(35);
1378 assert_eq!(
1379 first_frame.rows[12].data[col_idx].red2(),
1380 Color::BLUE.r() >= first_frame_threshold
1381 );
1382 assert_eq!(
1383 first_frame.rows[12].data[col_idx].grn2(),
1384 Color::BLUE.g() >= first_frame_threshold
1385 );
1386 assert_eq!(
1387 first_frame.rows[12].data[col_idx].blu2(),
1388 Color::BLUE.b() >= first_frame_threshold
1389 );
1390
1391 let col_idx = get_mapped_index(40);
1393 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1394 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1395 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1396 }
1397
1398 #[test]
1399 fn test_embedded_graphics_integration() {
1400 let mut fb = TestFrameBuffer::new();
1401
1402 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1404 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1405 .draw(&mut fb);
1406 assert!(result.is_ok());
1407
1408 let result = Circle::new(Point::new(30, 15), 8)
1410 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1411 .draw(&mut fb);
1412 assert!(result.is_ok());
1413 }
1414
1415 #[test]
1416 #[cfg(feature = "skip-black-pixels")]
1417 fn test_skip_black_pixels_enabled() {
1418 let mut fb = TestFrameBuffer::new();
1419
1420 fb.set_pixel_internal(10, 5, Color::RED);
1422
1423 let mapped_col_10 = get_mapped_index(10);
1425 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1426 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1427 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1428
1429 fb.set_pixel_internal(10, 5, Color::BLACK);
1431
1432 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1434 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1435 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1436 }
1437
1438 #[test]
1439 #[cfg(not(feature = "skip-black-pixels"))]
1440 fn test_skip_black_pixels_disabled() {
1441 let mut fb = TestFrameBuffer::new();
1442
1443 fb.set_pixel_internal(10, 5, Color::RED);
1445
1446 let mapped_col_10 = get_mapped_index(10);
1448 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1449 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1450 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1451
1452 fb.set_pixel_internal(10, 5, Color::BLACK);
1454
1455 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1457 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1458 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1459 }
1460
1461 #[test]
1462 fn test_bcm_frame_overwrite() {
1463 let mut fb = TestFrameBuffer::new();
1464
1465 fb.set_pixel_internal(10, 5, Color::WHITE);
1467
1468 let mapped_col_10 = get_mapped_index(10);
1469
1470 for frame in fb.frames.iter() {
1472 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1474 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1475 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1476 }
1477
1478 let half_white = Color::from(embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128));
1480 fb.set_pixel_internal(10, 5, half_white);
1481
1482 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.frames.iter().enumerate() {
1488 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1489 let should_be_active = 128 >= frame_threshold;
1490
1491 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1492 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1493 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1494 }
1495
1496 for frame_idx in 0..4 {
1499 assert_eq!(
1500 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1501 true
1502 );
1503 }
1504 for frame_idx in 4..TEST_FRAME_COUNT {
1506 assert_eq!(
1507 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1508 false
1509 );
1510 }
1511 }
1512
1513 #[test]
1514 fn test_read_buffer_implementation() {
1515 let fb = TestFrameBuffer::new();
1517 let expected_size = core::mem::size_of_val(&fb.frames);
1518
1519 unsafe {
1521 let (ptr, len) = <TestFrameBuffer as ReadBuffer>::read_buffer(&fb);
1522 assert!(!ptr.is_null());
1523 assert_eq!(len, expected_size);
1524 }
1525
1526 unsafe {
1528 let (ptr, len) = fb.read_buffer();
1529 assert!(!ptr.is_null());
1530 assert_eq!(len, expected_size);
1531 }
1532
1533 let fb = TestFrameBuffer::new();
1535 let fb_ref = &fb;
1536 unsafe {
1537 let (ptr, len) = fb_ref.read_buffer();
1538 assert!(!ptr.is_null());
1539 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1540 }
1541
1542 let mut fb = TestFrameBuffer::new();
1544 let fb_ref = &mut fb;
1545 unsafe {
1546 let (ptr, len) = fb_ref.read_buffer();
1547 assert!(!ptr.is_null());
1548 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1549 }
1550 }
1551
1552 #[test]
1553 fn test_read_buffer_owned_implementation() {
1554 fn test_owned_read_buffer(fb: TestFrameBuffer) -> (bool, usize) {
1557 unsafe {
1558 let (ptr, len) = fb.read_buffer();
1559 (!ptr.is_null(), len)
1560 }
1561 }
1562
1563 let fb = TestFrameBuffer::new();
1564 let expected_len = core::mem::size_of_val(&fb.frames);
1565
1566 let (ptr_valid, actual_len) = test_owned_read_buffer(fb);
1567 assert!(ptr_valid);
1568 assert_eq!(actual_len, expected_len);
1569 }
1570
1571 #[test]
1572 fn test_framebuffer_trait() {
1573 let fb = TestFrameBuffer::new();
1574 assert_eq!(fb.get_word_size(), WordSize::Sixteen);
1575
1576 let fb_ref = &fb;
1577 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1578
1579 let mut fb = TestFrameBuffer::new();
1580 let fb_ref = &mut fb;
1581 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1582 }
1583
1584 #[test]
1585 fn test_debug_formatting() {
1586 let fb = TestFrameBuffer::new();
1587 let debug_string = format!("{:?}", fb);
1588 assert!(debug_string.contains("DmaFrameBuffer"));
1589 assert!(debug_string.contains("frame_count"));
1590 assert!(debug_string.contains("frame_size"));
1591 assert!(debug_string.contains("brightness_step"));
1592 }
1593
1594 #[test]
1595 fn test_default_implementation() {
1596 let fb1 = TestFrameBuffer::new();
1597 let fb2 = TestFrameBuffer::default();
1598
1599 assert_eq!(fb1.frames.len(), fb2.frames.len());
1601 assert_eq!(fb1._align, fb2._align);
1602 }
1603
1604 #[test]
1605 fn test_memory_alignment() {
1606 let fb = TestFrameBuffer::new();
1607 let ptr = &fb as *const _ as usize;
1608
1609 assert_eq!(ptr % 8, 0);
1611 }
1612
1613 #[test]
1614 fn test_color_values() {
1615 let mut fb = TestFrameBuffer::new();
1616
1617 let colors = [
1619 (Color::RED, (255, 0, 0)),
1620 (Color::GREEN, (0, 255, 0)),
1621 (Color::BLUE, (0, 0, 255)),
1622 (Color::WHITE, (255, 255, 255)),
1623 (Color::BLACK, (0, 0, 0)),
1624 ];
1625
1626 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1627 fb.set_pixel(Point::new(i as i32, 0), *color);
1628 assert_eq!(color.r(), *r);
1629 assert_eq!(color.g(), *g);
1630 assert_eq!(color.b(), *b);
1631 }
1632 }
1633
1634 #[test]
1635 fn test_blanking_delay() {
1636 let mut row: Row<TEST_COLS> = Row::new();
1637 let test_addr = 5;
1638 let prev_addr = 4;
1639
1640 row.format(test_addr, prev_addr);
1641
1642 let blanking_pixel_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 1);
1644 assert_eq!(row.data[blanking_pixel_idx].output_enable(), false);
1645
1646 let before_blanking_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 2);
1648 assert_eq!(row.data[before_blanking_idx].output_enable(), true);
1649 }
1650
1651 #[test]
1652 fn test_esp32_mapping() {
1653 #[cfg(feature = "esp32-ordering")]
1655 {
1656 assert_eq!(map_index(0), 1);
1657 assert_eq!(map_index(1), 0);
1658 assert_eq!(map_index(2), 3);
1659 assert_eq!(map_index(3), 2);
1660 assert_eq!(map_index(4), 5);
1661 assert_eq!(map_index(5), 4);
1662 }
1663 #[cfg(not(feature = "esp32-ordering"))]
1664 {
1665 assert_eq!(map_index(0), 0);
1666 assert_eq!(map_index(1), 1);
1667 assert_eq!(map_index(2), 2);
1668 assert_eq!(map_index(3), 3);
1669 }
1670 }
1671
1672 #[test]
1673 fn test_bits_assertion() {
1674 assert!(TEST_BITS <= 8);
1677 }
1678
1679 #[test]
1680 fn test_fast_clear_method() {
1681 let mut fb = TestFrameBuffer::new();
1682
1683 fb.set_pixel_internal(10, 5, Color::RED);
1685 fb.set_pixel_internal(20, 10, Color::GREEN);
1686
1687 let mapped_col_10 = get_mapped_index(10);
1689 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1690
1691 fb.erase();
1693
1694 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1696 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1697 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1698
1699 let last_col = get_mapped_index(TEST_COLS - 1);
1701 assert_eq!(fb.frames[0].rows[5].data[last_col].latch(), true);
1702 }
1703
1704 const CHAR_W: i32 = 6;
1708 const CHAR_H: i32 = 10;
1709
1710 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1712 use embedded_graphics::mock_display::MockDisplay;
1713 use embedded_graphics::mono_font::ascii::FONT_6X10;
1714 use embedded_graphics::mono_font::MonoTextStyle;
1715 use embedded_graphics::text::{Baseline, Text};
1716
1717 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1719 Text::with_baseline("A", origin, style, Baseline::Top)
1720 .draw(fb)
1721 .unwrap();
1722
1723 let mut reference: MockDisplay<Color> = MockDisplay::new();
1725 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1726 .draw(&mut reference)
1727 .unwrap();
1728
1729 for dy in 0..CHAR_H {
1730 for dx in 0..CHAR_W {
1731 let expected_on = reference
1732 .get_pixel(Point::new(dx, dy))
1733 .unwrap_or(Color::BLACK)
1734 != Color::BLACK;
1735
1736 let gx = (origin.x + dx) as usize;
1737 let gy = (origin.y + dy) as usize;
1738
1739 let frame0 = &fb.frames[0];
1746 let e = if gy < TEST_NROWS {
1747 &frame0.rows[gy].data[get_mapped_index(gx)]
1748 } else {
1749 &frame0.rows[gy - TEST_NROWS].data[get_mapped_index(gx)]
1750 };
1751
1752 let (r, g, b) = if gy >= TEST_NROWS {
1753 (e.red2(), e.grn2(), e.blu2())
1754 } else {
1755 (e.red1(), e.grn1(), e.blu1())
1756 };
1757
1758 if expected_on {
1759 assert!(r && g && b,);
1760 } else {
1761 assert!(!r && !g && !b);
1762 }
1763 }
1764 }
1765 }
1766
1767 #[test]
1768 fn test_draw_char_corners() {
1769 let upper_left = Point::new(0, 0);
1770 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1771
1772 let mut fb = TestFrameBuffer::new();
1773
1774 verify_glyph_at(&mut fb, upper_left);
1775 verify_glyph_at(&mut fb, lower_right);
1776 }
1777
1778 #[test]
1779 fn test_framebuffer_operations_trait_erase() {
1780 let mut fb = TestFrameBuffer::new();
1781
1782 fb.set_pixel_internal(10, 5, Color::RED);
1784 fb.set_pixel_internal(20, 10, Color::GREEN);
1785
1786 <TestFrameBuffer as FrameBufferOperations<
1788 TEST_ROWS,
1789 TEST_COLS,
1790 TEST_NROWS,
1791 TEST_BITS,
1792 TEST_FRAME_COUNT,
1793 >>::erase(&mut fb);
1794
1795 let mc10 = get_mapped_index(10);
1797 let mc20 = get_mapped_index(20);
1798 assert_eq!(fb.frames[0].rows[5].data[mc10].red1(), false);
1799 assert_eq!(fb.frames[0].rows[10].data[mc20].grn1(), false);
1800
1801 let last_col = get_mapped_index(TEST_COLS - 1);
1803 assert!(fb.frames[0].rows[0].data[last_col].latch());
1804 }
1805
1806 #[test]
1807 fn test_framebuffer_operations_trait_set_pixel() {
1808 let mut fb = TestFrameBuffer::new();
1809
1810 <TestFrameBuffer as FrameBufferOperations<
1812 TEST_ROWS,
1813 TEST_COLS,
1814 TEST_NROWS,
1815 TEST_BITS,
1816 TEST_FRAME_COUNT,
1817 >>::set_pixel(&mut fb, Point::new(8, 3), Color::BLUE);
1818
1819 let idx = get_mapped_index(8);
1820 assert_eq!(fb.frames[0].rows[3].data[idx].blu1(), true);
1821 assert_eq!(fb.frames[0].rows[3].data[idx].red1(), false);
1822 assert_eq!(fb.frames[0].rows[3].data[idx].grn1(), false);
1823 }
1824}