1use core::convert::Infallible;
133
134use bitfield::bitfield;
135#[cfg(not(feature = "esp-hal-dma"))]
136use embedded_dma::ReadBuffer;
137use embedded_graphics::pixelcolor::RgbColor;
138use embedded_graphics::prelude::Point;
139#[cfg(feature = "esp-hal-dma")]
140use esp_hal::dma::ReadBuffer;
141
142use super::Color;
143use super::FrameBuffer;
144use super::WordSize;
145
146const BLANKING_DELAY: usize = 1;
147
148const ADDR_TABLE: [u16; 32] = [
151 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
152 26, 27, 28, 29, 30, 31,
153];
154
155#[inline]
158const fn make_data_template<const COLS: usize>(addr: u8, prev_addr: u8) -> [Entry; COLS] {
159 let mut data = [Entry::new(); COLS];
160 let mut i = 0;
161
162 while i < COLS {
163 let mut entry = Entry::new();
164 entry.0 = ADDR_TABLE[prev_addr as usize];
165
166 if i == 1 {
168 entry.0 |= 0b1_0000_0000; } else if i == COLS - BLANKING_DELAY - 1 {
170 } else if i == COLS - 1 {
172 entry.0 |= 0b0010_0000; entry.0 = (entry.0 & !0b0001_1111) | ADDR_TABLE[addr as usize]; } else if i > 1 && i < COLS - BLANKING_DELAY - 1 {
175 entry.0 |= 0b1_0000_0000; }
177
178 data[map_index(i)] = entry;
179 i += 1;
180 }
181
182 data
183}
184
185bitfield! {
186 #[derive(Clone, Copy, Default, PartialEq)]
207 #[repr(transparent)]
208 struct Entry(u16);
209 dummy2, set_dummy2: 15;
210 blu2, set_blu2: 14;
211 grn2, set_grn2: 13;
212 red2, set_red2: 12;
213 blu1, set_blu1: 11;
214 grn1, set_grn1: 10;
215 red1, set_red1: 9;
216 output_enable, set_output_enable: 8;
217 dummy1, set_dummy1: 7;
218 dummy0, set_dummy0: 6;
219 latch, set_latch: 5;
220 addr, set_addr: 4, 0;
221}
222
223impl core::fmt::Debug for Entry {
224 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
225 f.debug_tuple("Entry")
226 .field(&format_args!("{:#x}", self.0))
227 .finish()
228 }
229}
230
231#[cfg(feature = "defmt")]
232impl defmt::Format for Entry {
233 fn format(&self, f: defmt::Formatter) {
234 defmt::write!(f, "Entry({=u16:#x})", self.0);
235 }
236}
237
238impl Entry {
239 const fn new() -> Self {
240 Self(0)
241 }
242
243 const COLOR0_MASK: u16 = 0b0000_1110_0000_0000; const COLOR1_MASK: u16 = 0b0111_0000_0000_0000; #[inline]
248 fn set_color0_bits(&mut self, bits: u8) {
249 let bits16 = u16::from(bits) << 9;
250 self.0 = (self.0 & !Self::COLOR0_MASK) | (bits16 & Self::COLOR0_MASK);
251 }
252
253 #[inline]
254 fn set_color1_bits(&mut self, bits: u8) {
255 let bits16 = u16::from(bits) << 12;
256 self.0 = (self.0 & !Self::COLOR1_MASK) | (bits16 & Self::COLOR1_MASK);
257 }
258}
259
260#[derive(Clone, Copy, PartialEq, Debug)]
269#[repr(C)]
270struct Row<const COLS: usize> {
271 data: [Entry; COLS],
272}
273
274const fn map_index(i: usize) -> usize {
275 #[cfg(feature = "esp32-ordering")]
276 {
277 i ^ 1
278 }
279 #[cfg(not(feature = "esp32-ordering"))]
280 {
281 i
282 }
283}
284
285impl<const COLS: usize> Default for Row<COLS> {
286 fn default() -> Self {
287 Self::new()
288 }
289}
290
291impl<const COLS: usize> Row<COLS> {
292 pub const fn new() -> Self {
293 Self {
294 data: [Entry::new(); COLS],
295 }
296 }
297
298 pub fn format(&mut self, addr: u8, prev_addr: u8) {
299 let template = make_data_template::<COLS>(addr, prev_addr);
301 self.data.copy_from_slice(&template);
302 }
303
304 #[inline]
307 pub fn clear_colors(&mut self) {
308 const COLOR_CLEAR_MASK: u16 = !0b0111_1110_0000_0000; for entry in &mut self.data {
312 entry.0 &= COLOR_CLEAR_MASK;
313 }
314 }
315
316 #[inline]
317 pub fn set_color0(&mut self, col: usize, r: bool, g: bool, b: bool) {
318 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
319 let col = map_index(col);
320 self.data[col].set_color0_bits(bits);
321 }
322
323 #[inline]
324 pub fn set_color1(&mut self, col: usize, r: bool, g: bool, b: bool) {
325 let bits = (u8::from(b) << 2) | (u8::from(g) << 1) | u8::from(r);
326 let col = map_index(col);
327 self.data[col].set_color1_bits(bits);
328 }
329}
330
331#[derive(Copy, Clone, Debug)]
332#[repr(C)]
333struct Frame<const ROWS: usize, const COLS: usize, const NROWS: usize> {
334 rows: [Row<COLS>; NROWS],
335}
336
337impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Frame<ROWS, COLS, NROWS> {
338 pub const fn new() -> Self {
339 Self {
340 rows: [Row::new(); NROWS],
341 }
342 }
343
344 pub fn format(&mut self) {
345 for (addr, row) in self.rows.iter_mut().enumerate() {
346 let prev_addr = if addr == 0 {
347 NROWS as u8 - 1
348 } else {
349 addr as u8 - 1
350 };
351 row.format(addr as u8, prev_addr);
352 }
353 }
354
355 #[inline]
357 pub fn clear_colors(&mut self) {
358 for row in &mut self.rows {
359 row.clear_colors();
360 }
361 }
362
363 #[inline]
364 pub fn set_pixel(&mut self, y: usize, x: usize, red: bool, green: bool, blue: bool) {
365 let row = &mut self.rows[if y < NROWS { y } else { y - NROWS }];
366 if y < NROWS {
367 row.set_color0(x, red, green, blue);
368 } else {
369 row.set_color1(x, red, green, blue);
370 }
371 }
372}
373
374impl<const ROWS: usize, const COLS: usize, const NROWS: usize> Default
375 for Frame<ROWS, COLS, NROWS>
376{
377 fn default() -> Self {
378 Self::new()
379 }
380}
381
382#[derive(Copy, Clone)]
407#[repr(C)]
408pub struct DmaFrameBuffer<
409 const ROWS: usize,
410 const COLS: usize,
411 const NROWS: usize,
412 const BITS: u8,
413 const FRAME_COUNT: usize,
414> {
415 _align: u64,
416 frames: [Frame<ROWS, COLS, NROWS>; FRAME_COUNT],
417}
418
419impl<
420 const ROWS: usize,
421 const COLS: usize,
422 const NROWS: usize,
423 const BITS: u8,
424 const FRAME_COUNT: usize,
425 > Default for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
426{
427 fn default() -> Self {
428 Self::new()
429 }
430}
431
432impl<
433 const ROWS: usize,
434 const COLS: usize,
435 const NROWS: usize,
436 const BITS: u8,
437 const FRAME_COUNT: usize,
438 > DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
439{
440 #[must_use]
463 pub fn new() -> Self {
464 debug_assert!(BITS <= 8);
465
466 let mut instance = Self {
467 _align: 0,
468 frames: [Frame::new(); FRAME_COUNT],
469 };
470
471 instance.format();
473 instance
474 }
475
476 #[cfg(feature = "esp-hal-dma")]
492 pub const fn dma_buffer_size_bytes() -> usize {
493 core::mem::size_of::<[Frame<ROWS, COLS, NROWS>; FRAME_COUNT]>()
494 }
495
496 #[inline]
516 pub fn format(&mut self) {
517 for frame in &mut self.frames {
518 frame.format();
519 }
520 }
521
522 #[inline]
542 pub fn erase(&mut self) {
543 for frame in &mut self.frames {
544 frame.clear_colors();
545 }
546 }
547
548 pub fn set_pixel(&mut self, p: Point, color: Color) {
564 if p.x < 0 || p.y < 0 {
565 return;
566 }
567 self.set_pixel_internal(p.x as usize, p.y as usize, color);
568 }
569
570 #[inline]
571 fn frames_on(v: u8) -> usize {
572 (v as usize) >> (8 - BITS)
574 }
575
576 #[inline]
577 fn set_pixel_internal(&mut self, x: usize, y: usize, color: Color) {
578 if x >= COLS || y >= ROWS {
579 return;
580 }
581
582 #[cfg(feature = "skip-black-pixels")]
585 if color == Color::BLACK {
586 return;
587 }
588
589 let red_frames = Self::frames_on(color.r());
591 let green_frames = Self::frames_on(color.g());
592 let blue_frames = Self::frames_on(color.b());
593
594 for (frame_idx, frame) in self.frames.iter_mut().enumerate() {
596 frame.set_pixel(
597 y,
598 x,
599 frame_idx < red_frames,
600 frame_idx < green_frames,
601 frame_idx < blue_frames,
602 );
603 }
604 }
605}
606
607impl<
608 const ROWS: usize,
609 const COLS: usize,
610 const NROWS: usize,
611 const BITS: u8,
612 const FRAME_COUNT: usize,
613 > embedded_graphics::prelude::OriginDimensions
614 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
615{
616 fn size(&self) -> embedded_graphics::prelude::Size {
617 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
618 }
619}
620
621impl<
622 const ROWS: usize,
623 const COLS: usize,
624 const NROWS: usize,
625 const BITS: u8,
626 const FRAME_COUNT: usize,
627 > embedded_graphics::prelude::OriginDimensions
628 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
629{
630 fn size(&self) -> embedded_graphics::prelude::Size {
631 embedded_graphics::prelude::Size::new(COLS as u32, ROWS as u32)
632 }
633}
634
635impl<
636 const ROWS: usize,
637 const COLS: usize,
638 const NROWS: usize,
639 const BITS: u8,
640 const FRAME_COUNT: usize,
641 > embedded_graphics::draw_target::DrawTarget
642 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
643{
644 type Color = Color;
645
646 type Error = Infallible;
647
648 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
649 where
650 I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
651 {
652 for pixel in pixels {
653 self.set_pixel_internal(pixel.0.x as usize, pixel.0.y as usize, pixel.1);
654 }
655 Ok(())
656 }
657}
658
659unsafe impl<
660 const ROWS: usize,
661 const COLS: usize,
662 const NROWS: usize,
663 const BITS: u8,
664 const FRAME_COUNT: usize,
665 > ReadBuffer for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
666{
667 #[cfg(not(feature = "esp-hal-dma"))]
668 type Word = u8;
669
670 unsafe fn read_buffer(&self) -> (*const u8, usize) {
671 let ptr = (&raw const self.frames).cast::<u8>();
672 let len = core::mem::size_of_val(&self.frames);
673 (ptr, len)
674 }
675}
676
677unsafe impl<
678 const ROWS: usize,
679 const COLS: usize,
680 const NROWS: usize,
681 const BITS: u8,
682 const FRAME_COUNT: usize,
683 > ReadBuffer for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
684{
685 #[cfg(not(feature = "esp-hal-dma"))]
686 type Word = u8;
687
688 unsafe fn read_buffer(&self) -> (*const u8, usize) {
689 let ptr = (&raw const self.frames).cast::<u8>();
690 let len = core::mem::size_of_val(&self.frames);
691 (ptr, len)
692 }
693}
694
695impl<
696 const ROWS: usize,
697 const COLS: usize,
698 const NROWS: usize,
699 const BITS: u8,
700 const FRAME_COUNT: usize,
701 > core::fmt::Debug for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
702{
703 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
704 let brightness_step = 1 << (8 - BITS);
705 f.debug_struct("DmaFrameBuffer")
706 .field("size", &core::mem::size_of_val(&self.frames))
707 .field("frame_count", &self.frames.len())
708 .field("frame_size", &core::mem::size_of_val(&self.frames[0]))
709 .field("brightness_step", &&brightness_step)
710 .finish_non_exhaustive()
711 }
712}
713
714#[cfg(feature = "defmt")]
715impl<
716 const ROWS: usize,
717 const COLS: usize,
718 const NROWS: usize,
719 const BITS: u8,
720 const FRAME_COUNT: usize,
721 > defmt::Format for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
722{
723 fn format(&self, f: defmt::Formatter) {
724 let brightness_step = 1 << (8 - BITS);
725 defmt::write!(
726 f,
727 "DmaFrameBuffer<{}, {}, {}, {}, {}>",
728 ROWS,
729 COLS,
730 NROWS,
731 BITS,
732 FRAME_COUNT
733 );
734 defmt::write!(f, " size: {}", core::mem::size_of_val(&self.frames));
735 defmt::write!(
736 f,
737 " frame_size: {}",
738 core::mem::size_of_val(&self.frames[0])
739 );
740 defmt::write!(f, " brightness_step: {}", brightness_step);
741 }
742}
743
744impl<
745 const ROWS: usize,
746 const COLS: usize,
747 const NROWS: usize,
748 const BITS: u8,
749 const FRAME_COUNT: usize,
750 > FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
751 for DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
752{
753 fn get_word_size(&self) -> WordSize {
754 WordSize::Sixteen
755 }
756}
757
758impl<
759 const ROWS: usize,
760 const COLS: usize,
761 const NROWS: usize,
762 const BITS: u8,
763 const FRAME_COUNT: usize,
764 > FrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
765 for &mut DmaFrameBuffer<ROWS, COLS, NROWS, BITS, FRAME_COUNT>
766{
767 fn get_word_size(&self) -> WordSize {
768 WordSize::Sixteen
769 }
770}
771
772#[cfg(test)]
773mod tests {
774 extern crate std;
775
776 use std::format;
777 use std::vec;
778
779 use super::*;
780 use crate::{FrameBuffer, WordSize};
781 use embedded_graphics::pixelcolor::RgbColor;
782 use embedded_graphics::prelude::*;
783 use embedded_graphics::primitives::{Circle, PrimitiveStyle, Rectangle};
784
785 const TEST_ROWS: usize = 32;
786 const TEST_COLS: usize = 64;
787 const TEST_NROWS: usize = TEST_ROWS / 2;
788 const TEST_BITS: u8 = 3;
789 const TEST_FRAME_COUNT: usize = (1 << TEST_BITS) - 1; type TestFrameBuffer =
792 DmaFrameBuffer<TEST_ROWS, TEST_COLS, TEST_NROWS, TEST_BITS, TEST_FRAME_COUNT>;
793
794 fn get_mapped_index(index: usize) -> usize {
796 map_index(index)
797 }
798
799 #[test]
800 fn test_entry_construction() {
801 let entry = Entry::new();
802 assert_eq!(entry.0, 0);
803 assert_eq!(entry.dummy2(), false);
804 assert_eq!(entry.blu2(), false);
805 assert_eq!(entry.grn2(), false);
806 assert_eq!(entry.red2(), false);
807 assert_eq!(entry.blu1(), false);
808 assert_eq!(entry.grn1(), false);
809 assert_eq!(entry.red1(), false);
810 assert_eq!(entry.output_enable(), false);
811 assert_eq!(entry.dummy1(), false);
812 assert_eq!(entry.dummy0(), false);
813 assert_eq!(entry.latch(), false);
814 assert_eq!(entry.addr(), 0);
815 }
816
817 #[test]
818 fn test_entry_setters() {
819 let mut entry = Entry::new();
820
821 entry.set_dummy2(true);
822 assert_eq!(entry.dummy2(), true);
823 assert_eq!(entry.0 & 0b1000000000000000, 0b1000000000000000);
824
825 entry.set_blu2(true);
826 assert_eq!(entry.blu2(), true);
827 assert_eq!(entry.0 & 0b0100000000000000, 0b0100000000000000);
828
829 entry.set_grn2(true);
830 assert_eq!(entry.grn2(), true);
831 assert_eq!(entry.0 & 0b0010000000000000, 0b0010000000000000);
832
833 entry.set_red2(true);
834 assert_eq!(entry.red2(), true);
835 assert_eq!(entry.0 & 0b0001000000000000, 0b0001000000000000);
836
837 entry.set_blu1(true);
838 assert_eq!(entry.blu1(), true);
839 assert_eq!(entry.0 & 0b0000100000000000, 0b0000100000000000);
840
841 entry.set_grn1(true);
842 assert_eq!(entry.grn1(), true);
843 assert_eq!(entry.0 & 0b0000010000000000, 0b0000010000000000);
844
845 entry.set_red1(true);
846 assert_eq!(entry.red1(), true);
847 assert_eq!(entry.0 & 0b0000001000000000, 0b0000001000000000);
848
849 entry.set_output_enable(true);
850 assert_eq!(entry.output_enable(), true);
851 assert_eq!(entry.0 & 0b0000000100000000, 0b0000000100000000);
852
853 entry.set_dummy1(true);
854 assert_eq!(entry.dummy1(), true);
855 assert_eq!(entry.0 & 0b0000000010000000, 0b0000000010000000);
856
857 entry.set_dummy0(true);
858 assert_eq!(entry.dummy0(), true);
859 assert_eq!(entry.0 & 0b0000000001000000, 0b0000000001000000);
860
861 entry.set_latch(true);
862 assert_eq!(entry.latch(), true);
863 assert_eq!(entry.0 & 0b0000000000100000, 0b0000000000100000);
864
865 entry.set_addr(0b11111);
866 assert_eq!(entry.addr(), 0b11111);
867 assert_eq!(entry.0 & 0b0000000000011111, 0b0000000000011111);
868 }
869
870 #[test]
871 fn test_entry_bit_isolation() {
872 let mut entry = Entry::new();
873
874 entry.set_addr(0b11111);
876 entry.set_latch(true);
877 assert_eq!(entry.addr(), 0b11111);
878 assert_eq!(entry.latch(), true);
879 assert_eq!(entry.output_enable(), false);
880 assert_eq!(entry.red1(), false);
881
882 entry.set_red1(true);
883 entry.set_grn2(true);
884 assert_eq!(entry.addr(), 0b11111);
885 assert_eq!(entry.latch(), true);
886 assert_eq!(entry.red1(), true);
887 assert_eq!(entry.grn2(), true);
888 assert_eq!(entry.blu1(), false);
889 assert_eq!(entry.red2(), false);
890 }
891
892 #[test]
893 fn test_entry_set_color0() {
894 let mut entry = Entry::new();
895
896 let bits = (u8::from(true) << 2) | (u8::from(false) << 1) | u8::from(true); entry.set_color0_bits(bits);
898 assert_eq!(entry.red1(), true);
899 assert_eq!(entry.grn1(), false);
900 assert_eq!(entry.blu1(), true);
901 assert_eq!(entry.0 & 0b0000101000000000, 0b0000101000000000); }
904
905 #[test]
906 fn test_entry_set_color1() {
907 let mut entry = Entry::new();
908
909 let bits = (u8::from(true) << 2) | (u8::from(true) << 1) | u8::from(false); entry.set_color1_bits(bits);
911 assert_eq!(entry.red2(), false);
912 assert_eq!(entry.grn2(), true);
913 assert_eq!(entry.blu2(), true);
914 assert_eq!(entry.0 & 0b0110000000000000, 0b0110000000000000); }
917
918 #[test]
919 fn test_entry_debug_formatting() {
920 let entry = Entry(0x1234);
921 let debug_str = format!("{:?}", entry);
922 assert_eq!(debug_str, "Entry(0x1234)");
923
924 let entry = Entry(0xabcd);
925 let debug_str = format!("{:?}", entry);
926 assert_eq!(debug_str, "Entry(0xabcd)");
927 }
928
929 #[test]
930 fn test_row_construction() {
931 let row: Row<TEST_COLS> = Row::new();
932 assert_eq!(row.data.len(), TEST_COLS);
933
934 for entry in &row.data {
936 assert_eq!(entry.0, 0);
937 }
938 }
939
940 #[test]
941 fn test_row_format() {
942 let mut row: Row<TEST_COLS> = Row::new();
943 let test_addr = 5;
944 let prev_addr = 4;
945
946 row.format(test_addr, prev_addr);
947
948 for (physical_i, entry) in row.data.iter().enumerate() {
950 let logical_i = get_mapped_index(physical_i);
951
952 match logical_i {
953 i if i == TEST_COLS - BLANKING_DELAY - 1 => {
954 assert_eq!(entry.output_enable(), false);
956 assert_eq!(entry.addr(), prev_addr as u16);
957 assert_eq!(entry.latch(), false);
958 }
959 i if i == TEST_COLS - 1 => {
960 assert_eq!(entry.latch(), true);
962 assert_eq!(entry.addr(), test_addr as u16);
963 assert_eq!(entry.output_enable(), false);
964 }
965 1 => {
966 assert_eq!(entry.output_enable(), true);
968 assert_eq!(entry.addr(), prev_addr as u16);
969 assert_eq!(entry.latch(), false);
970 }
971 _ => {
972 assert_eq!(entry.addr(), prev_addr as u16);
974 assert_eq!(entry.latch(), false);
975 if logical_i > 1 && logical_i < TEST_COLS - BLANKING_DELAY - 1 {
976 assert_eq!(entry.output_enable(), true);
977 }
978 }
979 }
980 }
981 }
982
983 #[test]
984 fn test_row_set_color0() {
985 let mut row: Row<TEST_COLS> = Row::new();
986
987 row.set_color0(0, true, false, true);
988
989 let mapped_col_0 = get_mapped_index(0);
990 assert_eq!(row.data[mapped_col_0].red1(), true);
991 assert_eq!(row.data[mapped_col_0].grn1(), false);
992 assert_eq!(row.data[mapped_col_0].blu1(), true);
993
994 row.set_color0(1, false, true, false);
996
997 let mapped_col_1 = get_mapped_index(1);
998 assert_eq!(row.data[mapped_col_1].red1(), false);
999 assert_eq!(row.data[mapped_col_1].grn1(), true);
1000 assert_eq!(row.data[mapped_col_1].blu1(), false);
1001 }
1002
1003 #[test]
1004 fn test_row_set_color1() {
1005 let mut row: Row<TEST_COLS> = Row::new();
1006
1007 row.set_color1(0, true, true, false);
1008
1009 let mapped_col_0 = get_mapped_index(0);
1010 assert_eq!(row.data[mapped_col_0].red2(), true);
1011 assert_eq!(row.data[mapped_col_0].grn2(), true);
1012 assert_eq!(row.data[mapped_col_0].blu2(), false);
1013 }
1014
1015 #[test]
1016 fn test_row_default() {
1017 let row1: Row<TEST_COLS> = Row::new();
1018 let row2: Row<TEST_COLS> = Row::default();
1019
1020 assert_eq!(row1, row2);
1022 assert_eq!(row1.data.len(), row2.data.len());
1023
1024 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1026 assert_eq!(entry1.0, entry2.0);
1027 assert_eq!(entry1.0, 0);
1028 }
1029 }
1030
1031 #[test]
1032 fn test_frame_construction() {
1033 let frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1034 assert_eq!(frame.rows.len(), TEST_NROWS);
1035 }
1036
1037 #[test]
1038 fn test_frame_format() {
1039 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1040
1041 frame.format();
1042
1043 for addr in 0..TEST_NROWS {
1045 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1046
1047 let row = &frame.rows[addr];
1049
1050 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1052 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1053 assert_eq!(row.data[last_pixel_idx].latch(), true);
1054
1055 let first_pixel_idx = get_mapped_index(0);
1057 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1058 assert_eq!(row.data[first_pixel_idx].latch(), false);
1059 }
1060 }
1061
1062 #[test]
1063 fn test_frame_set_pixel() {
1064 let mut frame: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1065
1066 frame.set_pixel(5, 10, true, false, true);
1068
1069 let mapped_col_10 = get_mapped_index(10);
1070 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1071 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1072 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1073
1074 frame.set_pixel(TEST_NROWS + 5, 15, false, true, false);
1076
1077 let mapped_col_15 = get_mapped_index(15);
1078 assert_eq!(frame.rows[5].data[mapped_col_15].red2(), false);
1079 assert_eq!(frame.rows[5].data[mapped_col_15].grn2(), true);
1080 assert_eq!(frame.rows[5].data[mapped_col_15].blu2(), false);
1081 }
1082
1083 #[test]
1084 fn test_frame_default() {
1085 let frame1: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::new();
1086 let frame2: Frame<TEST_ROWS, TEST_COLS, TEST_NROWS> = Frame::default();
1087
1088 assert_eq!(frame1.rows.len(), frame2.rows.len());
1090
1091 for (row1, row2) in frame1.rows.iter().zip(frame2.rows.iter()) {
1093 assert_eq!(row1, row2);
1094
1095 for (entry1, entry2) in row1.data.iter().zip(row2.data.iter()) {
1097 assert_eq!(entry1.0, entry2.0);
1098 assert_eq!(entry1.0, 0);
1099 }
1100 }
1101 }
1102
1103 #[test]
1104 fn test_dma_framebuffer_construction() {
1105 let fb = TestFrameBuffer::new();
1106 assert_eq!(fb.frames.len(), TEST_FRAME_COUNT);
1107 assert_eq!(fb._align, 0);
1108 }
1109
1110 #[test]
1111 #[cfg(feature = "esp-hal-dma")]
1112 fn test_dma_framebuffer_dma_buffer_size() {
1113 let expected_size =
1114 core::mem::size_of::<[Frame<TEST_ROWS, TEST_COLS, TEST_NROWS>; TEST_FRAME_COUNT]>();
1115 assert_eq!(TestFrameBuffer::dma_buffer_size_bytes(), expected_size);
1116 }
1117
1118 #[test]
1119 fn test_dma_framebuffer_erase() {
1120 let fb = TestFrameBuffer::new();
1121
1122 for frame in &fb.frames {
1124 for addr in 0..TEST_NROWS {
1125 let prev_addr = if addr == 0 { TEST_NROWS - 1 } else { addr - 1 };
1126
1127 let row = &frame.rows[addr];
1129
1130 let last_pixel_idx = get_mapped_index(TEST_COLS - 1);
1132 assert_eq!(row.data[last_pixel_idx].addr(), addr as u16);
1133 assert_eq!(row.data[last_pixel_idx].latch(), true);
1134
1135 let first_pixel_idx = get_mapped_index(0);
1137 assert_eq!(row.data[first_pixel_idx].addr(), prev_addr as u16);
1138 assert_eq!(row.data[first_pixel_idx].latch(), false);
1139 }
1140 }
1141 }
1142
1143 #[test]
1144 fn test_dma_framebuffer_set_pixel_bounds() {
1145 let mut fb = TestFrameBuffer::new();
1146
1147 fb.set_pixel(Point::new(-1, 5), Color::RED);
1149 fb.set_pixel(Point::new(5, -1), Color::RED);
1150
1151 fb.set_pixel(Point::new(TEST_COLS as i32, 5), Color::RED);
1153 fb.set_pixel(Point::new(5, TEST_ROWS as i32), Color::RED);
1154 }
1155
1156 #[test]
1157 fn test_dma_framebuffer_set_pixel_internal() {
1158 let mut fb = TestFrameBuffer::new();
1159
1160 let red_color = Color::RED;
1161 fb.set_pixel_internal(10, 5, red_color);
1162
1163 for frame in &fb.frames {
1167 let mapped_col_10 = get_mapped_index(10);
1169 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1170 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), false);
1171 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), false);
1172 }
1173 }
1174
1175 #[test]
1176 fn test_dma_framebuffer_brightness_modulation() {
1177 let mut fb = TestFrameBuffer::new();
1178
1179 let brightness_step = 1 << (8 - TEST_BITS); let test_brightness = brightness_step * 3; let color = Color::from(embedded_graphics::pixelcolor::Rgb888::new(
1183 test_brightness,
1184 0,
1185 0,
1186 ));
1187
1188 fb.set_pixel_internal(0, 0, color);
1189
1190 for (frame_idx, frame) in fb.frames.iter().enumerate() {
1193 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1194 let should_be_active = test_brightness >= frame_threshold;
1195
1196 let mapped_col_0 = get_mapped_index(0);
1197 assert_eq!(frame.rows[0].data[mapped_col_0].red1(), should_be_active);
1198 }
1199 }
1200
1201 #[test]
1202 fn test_origin_dimensions() {
1203 let fb = TestFrameBuffer::new();
1204 let size = fb.size();
1205 assert_eq!(size.width, TEST_COLS as u32);
1206 assert_eq!(size.height, TEST_ROWS as u32);
1207
1208 let size = (&fb).size();
1210 assert_eq!(size.width, TEST_COLS as u32);
1211 assert_eq!(size.height, TEST_ROWS as u32);
1212
1213 let mut fb = TestFrameBuffer::new();
1215 let fb_ref = &mut fb;
1216 let size = fb_ref.size();
1217 assert_eq!(size.width, TEST_COLS as u32);
1218 assert_eq!(size.height, TEST_ROWS as u32);
1219 }
1220
1221 #[test]
1222 fn test_draw_target() {
1223 let mut fb = TestFrameBuffer::new();
1224
1225 let pixels = vec![
1226 embedded_graphics::Pixel(Point::new(0, 0), Color::RED),
1227 embedded_graphics::Pixel(Point::new(1, 1), Color::GREEN),
1228 embedded_graphics::Pixel(Point::new(2, 2), Color::BLUE),
1229 ];
1230
1231 let result = fb.draw_iter(pixels);
1232 assert!(result.is_ok());
1233
1234 let result = (&mut fb).draw_iter(vec![embedded_graphics::Pixel(
1236 Point::new(3, 3),
1237 Color::WHITE,
1238 )]);
1239 assert!(result.is_ok());
1240 }
1241
1242 #[test]
1243 fn test_draw_iter_pixel_verification() {
1244 let mut fb = TestFrameBuffer::new();
1245
1246 let pixels = vec![
1248 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), ];
1260
1261 let result = fb.draw_iter(pixels);
1262 assert!(result.is_ok());
1263
1264 let first_frame = &fb.frames[0];
1266 let brightness_step = 1 << (8 - TEST_BITS); let first_frame_threshold = brightness_step; let col_idx = get_mapped_index(5);
1272 assert_eq!(
1273 first_frame.rows[2].data[col_idx].red1(),
1274 Color::RED.r() >= first_frame_threshold
1275 );
1276 assert_eq!(
1277 first_frame.rows[2].data[col_idx].grn1(),
1278 Color::RED.g() >= first_frame_threshold
1279 );
1280 assert_eq!(
1281 first_frame.rows[2].data[col_idx].blu1(),
1282 Color::RED.b() >= first_frame_threshold
1283 );
1284
1285 let col_idx = get_mapped_index(10);
1287 assert_eq!(
1288 first_frame.rows[5].data[col_idx].red1(),
1289 Color::GREEN.r() >= first_frame_threshold
1290 );
1291 assert_eq!(
1292 first_frame.rows[5].data[col_idx].grn1(),
1293 Color::GREEN.g() >= first_frame_threshold
1294 );
1295 assert_eq!(
1296 first_frame.rows[5].data[col_idx].blu1(),
1297 Color::GREEN.b() >= first_frame_threshold
1298 );
1299
1300 let col_idx = get_mapped_index(15);
1302 assert_eq!(
1303 first_frame.rows[8].data[col_idx].red1(),
1304 Color::BLUE.r() >= first_frame_threshold
1305 );
1306 assert_eq!(
1307 first_frame.rows[8].data[col_idx].grn1(),
1308 Color::BLUE.g() >= first_frame_threshold
1309 );
1310 assert_eq!(
1311 first_frame.rows[8].data[col_idx].blu1(),
1312 Color::BLUE.b() >= first_frame_threshold
1313 );
1314
1315 let col_idx = get_mapped_index(20);
1317 assert_eq!(
1318 first_frame.rows[10].data[col_idx].red1(),
1319 Color::WHITE.r() >= first_frame_threshold
1320 );
1321 assert_eq!(
1322 first_frame.rows[10].data[col_idx].grn1(),
1323 Color::WHITE.g() >= first_frame_threshold
1324 );
1325 assert_eq!(
1326 first_frame.rows[10].data[col_idx].blu1(),
1327 Color::WHITE.b() >= first_frame_threshold
1328 );
1329
1330 let col_idx = get_mapped_index(25);
1333 assert_eq!(
1334 first_frame.rows[3].data[col_idx].red2(),
1335 Color::RED.r() >= first_frame_threshold
1336 );
1337 assert_eq!(
1338 first_frame.rows[3].data[col_idx].grn2(),
1339 Color::RED.g() >= first_frame_threshold
1340 );
1341 assert_eq!(
1342 first_frame.rows[3].data[col_idx].blu2(),
1343 Color::RED.b() >= first_frame_threshold
1344 );
1345
1346 let col_idx = get_mapped_index(30);
1348 assert_eq!(
1349 first_frame.rows[7].data[col_idx].red2(),
1350 Color::GREEN.r() >= first_frame_threshold
1351 );
1352 assert_eq!(
1353 first_frame.rows[7].data[col_idx].grn2(),
1354 Color::GREEN.g() >= first_frame_threshold
1355 );
1356 assert_eq!(
1357 first_frame.rows[7].data[col_idx].blu2(),
1358 Color::GREEN.b() >= first_frame_threshold
1359 );
1360
1361 let col_idx = get_mapped_index(35);
1363 assert_eq!(
1364 first_frame.rows[12].data[col_idx].red2(),
1365 Color::BLUE.r() >= first_frame_threshold
1366 );
1367 assert_eq!(
1368 first_frame.rows[12].data[col_idx].grn2(),
1369 Color::BLUE.g() >= first_frame_threshold
1370 );
1371 assert_eq!(
1372 first_frame.rows[12].data[col_idx].blu2(),
1373 Color::BLUE.b() >= first_frame_threshold
1374 );
1375
1376 let col_idx = get_mapped_index(40);
1378 assert_eq!(first_frame.rows[1].data[col_idx].red1(), false);
1379 assert_eq!(first_frame.rows[1].data[col_idx].grn1(), false);
1380 assert_eq!(first_frame.rows[1].data[col_idx].blu1(), false);
1381 }
1382
1383 #[test]
1384 fn test_embedded_graphics_integration() {
1385 let mut fb = TestFrameBuffer::new();
1386
1387 let result = Rectangle::new(Point::new(5, 5), Size::new(10, 8))
1389 .into_styled(PrimitiveStyle::with_fill(Color::RED))
1390 .draw(&mut fb);
1391 assert!(result.is_ok());
1392
1393 let result = Circle::new(Point::new(30, 15), 8)
1395 .into_styled(PrimitiveStyle::with_fill(Color::BLUE))
1396 .draw(&mut fb);
1397 assert!(result.is_ok());
1398 }
1399
1400 #[test]
1401 #[cfg(feature = "skip-black-pixels")]
1402 fn test_skip_black_pixels_enabled() {
1403 let mut fb = TestFrameBuffer::new();
1404
1405 fb.set_pixel_internal(10, 5, Color::RED);
1407
1408 let mapped_col_10 = get_mapped_index(10);
1410 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1411 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1412 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1413
1414 fb.set_pixel_internal(10, 5, Color::BLACK);
1416
1417 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1419 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1420 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1421 }
1422
1423 #[test]
1424 #[cfg(not(feature = "skip-black-pixels"))]
1425 fn test_skip_black_pixels_disabled() {
1426 let mut fb = TestFrameBuffer::new();
1427
1428 fb.set_pixel_internal(10, 5, Color::RED);
1430
1431 let mapped_col_10 = get_mapped_index(10);
1433 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 fb.set_pixel_internal(10, 5, Color::BLACK);
1439
1440 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1442 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1443 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1444 }
1445
1446 #[test]
1447 fn test_bcm_frame_overwrite() {
1448 let mut fb = TestFrameBuffer::new();
1449
1450 fb.set_pixel_internal(10, 5, Color::WHITE);
1452
1453 let mapped_col_10 = get_mapped_index(10);
1454
1455 for frame in fb.frames.iter() {
1457 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), true);
1459 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), true);
1460 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), true);
1461 }
1462
1463 let half_white = Color::from(embedded_graphics::pixelcolor::Rgb888::new(128, 128, 128));
1465 fb.set_pixel_internal(10, 5, half_white);
1466
1467 let brightness_step = 1 << (8 - TEST_BITS); for (frame_idx, frame) in fb.frames.iter().enumerate() {
1473 let frame_threshold = (frame_idx as u8 + 1) * brightness_step;
1474 let should_be_active = 128 >= frame_threshold;
1475
1476 assert_eq!(frame.rows[5].data[mapped_col_10].red1(), should_be_active);
1477 assert_eq!(frame.rows[5].data[mapped_col_10].grn1(), should_be_active);
1478 assert_eq!(frame.rows[5].data[mapped_col_10].blu1(), should_be_active);
1479 }
1480
1481 for frame_idx in 0..4 {
1484 assert_eq!(
1485 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1486 true
1487 );
1488 }
1489 for frame_idx in 4..TEST_FRAME_COUNT {
1491 assert_eq!(
1492 fb.frames[frame_idx].rows[5].data[mapped_col_10].red1(),
1493 false
1494 );
1495 }
1496 }
1497
1498 #[test]
1499 fn test_read_buffer_implementation() {
1500 let fb = TestFrameBuffer::new();
1502 let expected_size = core::mem::size_of_val(&fb.frames);
1503
1504 unsafe {
1506 let (ptr, len) = <TestFrameBuffer as ReadBuffer>::read_buffer(&fb);
1507 assert!(!ptr.is_null());
1508 assert_eq!(len, expected_size);
1509 }
1510
1511 unsafe {
1513 let (ptr, len) = fb.read_buffer();
1514 assert!(!ptr.is_null());
1515 assert_eq!(len, expected_size);
1516 }
1517
1518 let fb = TestFrameBuffer::new();
1520 let fb_ref = &fb;
1521 unsafe {
1522 let (ptr, len) = fb_ref.read_buffer();
1523 assert!(!ptr.is_null());
1524 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1525 }
1526
1527 let mut fb = TestFrameBuffer::new();
1529 let fb_ref = &mut fb;
1530 unsafe {
1531 let (ptr, len) = fb_ref.read_buffer();
1532 assert!(!ptr.is_null());
1533 assert_eq!(len, core::mem::size_of_val(&fb.frames));
1534 }
1535 }
1536
1537 #[test]
1538 fn test_read_buffer_owned_implementation() {
1539 fn test_owned_read_buffer(fb: TestFrameBuffer) -> (bool, usize) {
1542 unsafe {
1543 let (ptr, len) = fb.read_buffer();
1544 (!ptr.is_null(), len)
1545 }
1546 }
1547
1548 let fb = TestFrameBuffer::new();
1549 let expected_len = core::mem::size_of_val(&fb.frames);
1550
1551 let (ptr_valid, actual_len) = test_owned_read_buffer(fb);
1552 assert!(ptr_valid);
1553 assert_eq!(actual_len, expected_len);
1554 }
1555
1556 #[test]
1557 fn test_framebuffer_trait() {
1558 let fb = TestFrameBuffer::new();
1559 assert_eq!(fb.get_word_size(), WordSize::Sixteen);
1560
1561 let fb_ref = &fb;
1562 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1563
1564 let mut fb = TestFrameBuffer::new();
1565 let fb_ref = &mut fb;
1566 assert_eq!(fb_ref.get_word_size(), WordSize::Sixteen);
1567 }
1568
1569 #[test]
1570 fn test_debug_formatting() {
1571 let fb = TestFrameBuffer::new();
1572 let debug_string = format!("{:?}", fb);
1573 assert!(debug_string.contains("DmaFrameBuffer"));
1574 assert!(debug_string.contains("frame_count"));
1575 assert!(debug_string.contains("frame_size"));
1576 assert!(debug_string.contains("brightness_step"));
1577 }
1578
1579 #[test]
1580 fn test_default_implementation() {
1581 let fb1 = TestFrameBuffer::new();
1582 let fb2 = TestFrameBuffer::default();
1583
1584 assert_eq!(fb1.frames.len(), fb2.frames.len());
1586 assert_eq!(fb1._align, fb2._align);
1587 }
1588
1589 #[test]
1590 fn test_memory_alignment() {
1591 let fb = TestFrameBuffer::new();
1592 let ptr = &fb as *const _ as usize;
1593
1594 assert_eq!(ptr % 8, 0);
1596 }
1597
1598 #[test]
1599 fn test_color_values() {
1600 let mut fb = TestFrameBuffer::new();
1601
1602 let colors = [
1604 (Color::RED, (255, 0, 0)),
1605 (Color::GREEN, (0, 255, 0)),
1606 (Color::BLUE, (0, 0, 255)),
1607 (Color::WHITE, (255, 255, 255)),
1608 (Color::BLACK, (0, 0, 0)),
1609 ];
1610
1611 for (i, (color, (r, g, b))) in colors.iter().enumerate() {
1612 fb.set_pixel(Point::new(i as i32, 0), *color);
1613 assert_eq!(color.r(), *r);
1614 assert_eq!(color.g(), *g);
1615 assert_eq!(color.b(), *b);
1616 }
1617 }
1618
1619 #[test]
1620 fn test_blanking_delay() {
1621 let mut row: Row<TEST_COLS> = Row::new();
1622 let test_addr = 5;
1623 let prev_addr = 4;
1624
1625 row.format(test_addr, prev_addr);
1626
1627 let blanking_pixel_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 1);
1629 assert_eq!(row.data[blanking_pixel_idx].output_enable(), false);
1630
1631 let before_blanking_idx = get_mapped_index(TEST_COLS - BLANKING_DELAY - 2);
1633 assert_eq!(row.data[before_blanking_idx].output_enable(), true);
1634 }
1635
1636 #[test]
1637 fn test_esp32_mapping() {
1638 #[cfg(feature = "esp32-ordering")]
1640 {
1641 assert_eq!(map_index(0), 1);
1642 assert_eq!(map_index(1), 0);
1643 assert_eq!(map_index(2), 3);
1644 assert_eq!(map_index(3), 2);
1645 assert_eq!(map_index(4), 5);
1646 assert_eq!(map_index(5), 4);
1647 }
1648 #[cfg(not(feature = "esp32-ordering"))]
1649 {
1650 assert_eq!(map_index(0), 0);
1651 assert_eq!(map_index(1), 1);
1652 assert_eq!(map_index(2), 2);
1653 assert_eq!(map_index(3), 3);
1654 }
1655 }
1656
1657 #[test]
1658 fn test_bits_assertion() {
1659 assert!(TEST_BITS <= 8);
1662 }
1663
1664 #[test]
1665 fn test_fast_clear_method() {
1666 let mut fb = TestFrameBuffer::new();
1667
1668 fb.set_pixel_internal(10, 5, Color::RED);
1670 fb.set_pixel_internal(20, 10, Color::GREEN);
1671
1672 let mapped_col_10 = get_mapped_index(10);
1674 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), true);
1675
1676 fb.erase();
1678
1679 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].red1(), false);
1681 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].grn1(), false);
1682 assert_eq!(fb.frames[0].rows[5].data[mapped_col_10].blu1(), false);
1683
1684 let last_col = get_mapped_index(TEST_COLS - 1);
1686 assert_eq!(fb.frames[0].rows[5].data[last_col].latch(), true);
1687 }
1688
1689 const CHAR_W: i32 = 6;
1693 const CHAR_H: i32 = 10;
1694
1695 fn verify_glyph_at(fb: &mut TestFrameBuffer, origin: Point) {
1697 use embedded_graphics::mock_display::MockDisplay;
1698 use embedded_graphics::mono_font::ascii::FONT_6X10;
1699 use embedded_graphics::mono_font::MonoTextStyle;
1700 use embedded_graphics::text::{Baseline, Text};
1701
1702 let style = MonoTextStyle::new(&FONT_6X10, Color::WHITE);
1704 Text::with_baseline("A", origin, style, Baseline::Top)
1705 .draw(fb)
1706 .unwrap();
1707
1708 let mut reference: MockDisplay<Color> = MockDisplay::new();
1710 Text::with_baseline("A", Point::zero(), style, Baseline::Top)
1711 .draw(&mut reference)
1712 .unwrap();
1713
1714 for dy in 0..CHAR_H {
1715 for dx in 0..CHAR_W {
1716 let expected_on = reference
1717 .get_pixel(Point::new(dx, dy))
1718 .unwrap_or(Color::BLACK)
1719 != Color::BLACK;
1720
1721 let gx = (origin.x + dx) as usize;
1722 let gy = (origin.y + dy) as usize;
1723
1724 let frame0 = &fb.frames[0];
1731 let e = if gy < TEST_NROWS {
1732 &frame0.rows[gy].data[get_mapped_index(gx)]
1733 } else {
1734 &frame0.rows[gy - TEST_NROWS].data[get_mapped_index(gx)]
1735 };
1736
1737 let (r, g, b) = if gy >= TEST_NROWS {
1738 (e.red2(), e.grn2(), e.blu2())
1739 } else {
1740 (e.red1(), e.grn1(), e.blu1())
1741 };
1742
1743 if expected_on {
1744 assert!(r && g && b,);
1745 } else {
1746 assert!(!r && !g && !b);
1747 }
1748 }
1749 }
1750 }
1751
1752 #[test]
1753 fn test_draw_char_corners() {
1754 let upper_left = Point::new(0, 0);
1755 let lower_right = Point::new(TEST_COLS as i32 - CHAR_W, TEST_ROWS as i32 - CHAR_H);
1756
1757 let mut fb = TestFrameBuffer::new();
1758
1759 verify_glyph_at(&mut fb, upper_left);
1760 verify_glyph_at(&mut fb, lower_right);
1761 }
1762}