1use embedded_hal::spi::SpiDevice;
4
5use crate::{
6 MAX_DISPLAYS, NUM_DIGITS, Result,
7 error::Error,
8 registers::{DecodeMode, Register},
9};
10
11pub struct Max7219<SPI> {
14 spi: SPI,
15 buffer: [u8; MAX_DISPLAYS * 2],
16 device_count: usize,
17}
18
19impl<SPI> Max7219<SPI>
20where
21 SPI: SpiDevice,
22{
23 pub fn new(spi: SPI) -> Self {
32 Self {
33 spi,
34 device_count: 1, buffer: [0; MAX_DISPLAYS * 2],
36 }
37 }
38
39 pub fn device_count(&self) -> usize {
44 self.device_count
45 }
46
47 pub fn with_device_count(mut self, count: usize) -> Result<Self> {
59 if count > MAX_DISPLAYS {
60 return Err(Error::InvalidDeviceCount);
61 }
62 self.device_count = count;
63 Ok(self)
64 }
65
66 pub fn init(&mut self) -> Result<()> {
68 self.power_on()?;
69
70 self.test_all(false)?;
71 self.set_scan_limit_all(NUM_DIGITS)?;
72 self.set_decode_mode_all(DecodeMode::NoDecode)?;
73
74 self.clear_all()?;
75 Ok(())
79 }
80
81 pub(crate) fn write_device_register(
105 &mut self,
106 device_index: usize,
107 register: Register,
108 data: u8,
109 ) -> Result<()> {
110 if device_index >= self.device_count {
111 return Err(Error::InvalidDeviceIndex);
112 }
113
114 self.buffer = [0; MAX_DISPLAYS * 2];
115
116 let offset = device_index * 2; self.buffer[offset] = register as u8;
118 self.buffer[offset + 1] = data;
119
120 self.spi.write(&self.buffer[0..self.device_count * 2])?;
121
122 Ok(())
123 }
124
125 pub(crate) fn write_all_registers(&mut self, ops: &[(Register, u8)]) -> Result<()> {
139 self.buffer = [0; MAX_DISPLAYS * 2];
141
142 for (i, &(reg, data)) in ops.iter().rev().enumerate() {
144 let offset = i * 2;
145 self.buffer[offset] = reg as u8;
146 self.buffer[offset + 1] = data;
147 }
148
149 let len = self.device_count * 2;
151 self.spi.write(&self.buffer[..len])?;
152
153 Ok(())
154 }
155
156 pub fn power_on(&mut self) -> Result<()> {
162 let ops = [(Register::Shutdown, 0x01); MAX_DISPLAYS];
163
164 self.write_all_registers(&ops[..self.device_count])
165 }
166
167 pub fn power_off(&mut self) -> Result<()> {
169 let ops = [(Register::Shutdown, 0x00); MAX_DISPLAYS];
170
171 self.write_all_registers(&ops[..self.device_count])
172 }
173
174 pub fn power_on_device(&mut self, device_index: usize) -> Result<()> {
180 self.write_device_register(device_index, Register::Shutdown, 0x01)
181 }
182
183 pub fn power_off_device(&mut self, device_index: usize) -> Result<()> {
189 self.write_device_register(device_index, Register::Shutdown, 0x00)
190 }
191
192 pub fn test_device(&mut self, device_index: usize, enable: bool) -> Result<()> {
196 let data = if enable { 0x01 } else { 0x00 };
197 self.write_device_register(device_index, Register::DisplayTest, data)
198 }
199
200 pub fn test_all(&mut self, enable: bool) -> Result<()> {
202 let data = if enable { 0x01 } else { 0x00 };
203 let ops: [(Register, u8); MAX_DISPLAYS] = [(Register::DisplayTest, data); MAX_DISPLAYS];
204 self.write_all_registers(&ops[..self.device_count])
205 }
206
207 pub fn set_device_scan_limit(&mut self, device_index: usize, limit: u8) -> Result<()> {
221 if !(1..=8).contains(&limit) {
222 return Err(Error::InvalidScanLimit);
223 }
224
225 self.write_device_register(device_index, Register::ScanLimit, limit - 1)
226 }
227
228 pub fn set_scan_limit_all(&mut self, limit: u8) -> Result<()> {
232 if !(1..=8).contains(&limit) {
233 return Err(Error::InvalidScanLimit);
234 }
235 let val = limit - 1;
236 let ops: [(Register, u8); MAX_DISPLAYS] = [(Register::ScanLimit, val); MAX_DISPLAYS];
237 self.write_all_registers(&ops[..self.device_count])
238 }
239
240 pub fn set_device_decode_mode(&mut self, device_index: usize, mode: DecodeMode) -> Result<()> {
250 self.write_device_register(device_index, Register::DecodeMode, mode as u8)
251 }
252
253 pub fn set_decode_mode_all(&mut self, mode: DecodeMode) -> Result<()> {
255 let byte = mode as u8;
256 let ops: [(Register, u8); MAX_DISPLAYS] = [(Register::DecodeMode, byte); MAX_DISPLAYS];
257 self.write_all_registers(&ops[..self.device_count])
258 }
259
260 pub fn clear_display(&mut self, device_index: usize) -> Result<()> {
267 for digit_register in Register::digits() {
268 self.write_device_register(device_index, digit_register, 0x00)?;
269 }
270 Ok(())
271 }
272
273 pub fn clear_all(&mut self) -> Result<()> {
275 for digit_register in Register::digits() {
276 let ops = [(digit_register, 0x00); MAX_DISPLAYS];
277 self.write_all_registers(&ops[..self.device_count])?;
278 }
279
280 Ok(())
281 }
282
283 pub fn write_raw_digit(&mut self, device_index: usize, digit: u8, value: u8) -> Result<()> {
352 let digit_register = Register::try_digit(digit)?;
353 self.write_device_register(device_index, digit_register, value)
354 }
355
356 pub fn set_intensity(&mut self, device_index: usize, intensity: u8) -> Result<()> {
363 if intensity > 0x0F {
364 return Err(Error::InvalidIntensity);
365 }
366 self.write_device_register(device_index, Register::Intensity, intensity)
367 }
368
369 pub fn set_intensity_all(&mut self, intensity: u8) -> Result<()> {
371 let ops = [(Register::Intensity, intensity); MAX_DISPLAYS];
372 self.write_all_registers(&ops[..self.device_count])
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use crate::{MAX_DISPLAYS, NUM_DIGITS, registers::DecodeMode, registers::Register};
380 use embedded_hal_mock::eh1::{spi::Mock as SpiMock, spi::Transaction};
381
382 #[test]
383 fn test_new() {
384 let mut spi = SpiMock::new(&[]);
385 let driver = Max7219::new(&mut spi);
386 assert_eq!(driver.device_count(), 1);
388
389 spi.done();
390 }
391
392 #[test]
393 fn test_with_device_count_valid() {
394 let mut spi = SpiMock::new(&[]);
395 let driver = Max7219::new(&mut spi);
396 let driver = driver
397 .with_device_count(4)
398 .expect("Should accept valid count");
399 assert_eq!(driver.device_count(), 4);
400 spi.done();
401 }
402
403 #[test]
404 fn test_with_device_count_invalid() {
405 let mut spi = SpiMock::new(&[]);
406 let driver = Max7219::new(&mut spi);
407 let result = driver.with_device_count(MAX_DISPLAYS + 1);
408 assert!(matches!(result, Err(Error::InvalidDeviceCount)));
409
410 spi.done();
411 }
412
413 #[test]
414 fn test_power_on() {
415 let expected_transactions = [
416 Transaction::transaction_start(),
417 Transaction::write_vec(vec![Register::Shutdown.addr(), 0x01]),
418 Transaction::transaction_end(),
419 ];
420 let mut spi = SpiMock::new(&expected_transactions);
421 let mut driver = Max7219::new(&mut spi);
422
423 driver.power_on().expect("Power on should succeed");
424 spi.done();
425 }
426
427 #[test]
428 fn test_power_off() {
429 let expected_transactions = [
430 Transaction::transaction_start(),
431 Transaction::write_vec(vec![Register::Shutdown.addr(), 0x00]),
432 Transaction::transaction_end(),
433 ];
434 let mut spi = SpiMock::new(&expected_transactions);
435 let mut driver = Max7219::new(&mut spi);
436
437 driver.power_off().expect("Power off should succeed");
438 spi.done();
439 }
440
441 #[test]
442 fn test_power_on_device() {
443 let expected_transactions = [
444 Transaction::transaction_start(),
445 Transaction::write_vec(vec![Register::Shutdown.addr(), 0x01]),
446 Transaction::transaction_end(),
447 ];
448 let mut spi = SpiMock::new(&expected_transactions);
449 let mut driver = Max7219::new(&mut spi);
450
451 driver
452 .power_on_device(0)
453 .expect("Power on display should succeed");
454 spi.done();
455 }
456
457 #[test]
459 fn test_power_on_multiple_devices() {
460 let device_count = 3;
461
462 let expected_transactions = [
463 Transaction::transaction_start(),
464 Transaction::write_vec(vec![
465 Register::Shutdown.addr(),
466 0x01,
467 Register::Shutdown.addr(),
468 0x01,
469 Register::Shutdown.addr(),
470 0x01,
471 ]),
472 Transaction::transaction_end(),
473 ];
474 let mut spi = SpiMock::new(&expected_transactions);
475 let mut driver = Max7219::new(&mut spi)
476 .with_device_count(device_count)
477 .expect("Should accept valid count");
478
479 driver.power_on().expect("Power on should succeed");
480 spi.done();
481 }
482
483 #[test]
484 fn test_power_off_device() {
485 let expected_transactions = [
486 Transaction::transaction_start(),
487 Transaction::write_vec(vec![
488 Register::NoOp.addr(),
490 0x00,
491 Register::NoOp.addr(),
492 0x00,
493 Register::Shutdown.addr(),
494 0x00,
495 Register::NoOp.addr(),
496 0x00,
497 ]),
498 Transaction::transaction_end(),
499 ];
500 let mut spi = SpiMock::new(&expected_transactions);
501 let mut driver = Max7219::new(&mut spi)
502 .with_device_count(4)
503 .expect("a valid device count");
504
505 driver
506 .power_off_device(2)
507 .expect("Power off display should succeed");
508 spi.done();
509 }
510
511 #[test]
512 fn test_power_device_invalid_index() {
513 let mut spi = SpiMock::new(&[]);
514 let mut driver = Max7219::new(&mut spi).with_device_count(1).unwrap();
515
516 let result = driver.power_on_device(1);
517 assert_eq!(result, Err(Error::InvalidDeviceIndex));
518
519 let result = driver.power_off_device(1);
520 assert_eq!(result, Err(Error::InvalidDeviceIndex));
521 spi.done();
522 }
523
524 #[test]
525 fn test_test_all_enable() {
526 let expected_transactions = [
527 Transaction::transaction_start(),
528 Transaction::write_vec(vec![
529 Register::DisplayTest.addr(),
530 0x01,
531 Register::DisplayTest.addr(),
532 0x01,
533 Register::DisplayTest.addr(),
534 0x01,
535 Register::DisplayTest.addr(),
536 0x01,
537 ]),
538 Transaction::transaction_end(),
539 ];
540 let mut spi = SpiMock::new(&expected_transactions);
541 let mut driver = Max7219::new(&mut spi)
542 .with_device_count(4)
543 .expect("valid device count");
544
545 driver
546 .test_all(true)
547 .expect("Test all enable should succeed");
548 spi.done();
549 }
550
551 #[test]
552 fn test_test_all_disable() {
553 let expected_transactions = [
554 Transaction::transaction_start(),
555 Transaction::write_vec(vec![Register::DisplayTest.addr(), 0x00]),
556 Transaction::transaction_end(),
557 ];
558 let mut spi = SpiMock::new(&expected_transactions);
559 let mut driver = Max7219::new(&mut spi);
560
561 driver
562 .test_all(false)
563 .expect("Test all disable should succeed");
564 spi.done();
565 }
566
567 #[test]
568 fn test_set_scan_limit_all_valid() {
569 let limit = 4;
570 let expected_transactions = [
571 Transaction::transaction_start(),
572 Transaction::write_vec(vec![Register::ScanLimit.addr(), limit - 1]),
573 Transaction::transaction_end(),
574 ];
575 let mut spi = SpiMock::new(&expected_transactions);
576 let mut driver = Max7219::new(&mut spi);
577
578 driver
579 .set_scan_limit_all(limit)
580 .expect("Set scan limit should succeed");
581 spi.done();
582 }
583
584 #[test]
585 fn test_set_scan_limit_all_invalid_low() {
586 let mut spi = SpiMock::new(&[]);
587 let mut driver = Max7219::new(&mut spi);
588
589 let result = driver.set_scan_limit_all(0);
590 assert_eq!(result, Err(Error::InvalidScanLimit));
591 spi.done();
592 }
593
594 #[test]
595 fn test_set_scan_limit_all_invalid_high() {
596 let mut spi = SpiMock::new(&[]); let mut driver = Max7219::new(&mut spi);
598
599 let result = driver.set_scan_limit_all(9);
600 assert_eq!(result, Err(Error::InvalidScanLimit));
601 spi.done();
602 }
603
604 #[test]
605 fn test_set_decode_mode_all() {
606 let mode = DecodeMode::AllDigits;
607 let expected_transactions = [
608 Transaction::transaction_start(),
609 Transaction::write_vec(vec![
610 Register::DecodeMode.addr(),
611 mode.value(),
612 Register::DecodeMode.addr(),
613 mode.value(),
614 Register::DecodeMode.addr(),
615 mode.value(),
616 Register::DecodeMode.addr(),
617 mode.value(),
618 ]),
619 Transaction::transaction_end(),
620 ];
621 let mut spi = SpiMock::new(&expected_transactions);
622 let mut driver = Max7219::new(&mut spi)
623 .with_device_count(4)
624 .expect("valid device count");
625
626 driver
627 .set_decode_mode_all(mode)
628 .expect("Set decode mode should succeed");
629 spi.done();
630 }
631
632 #[test]
633 fn test_clear_display() {
634 let mut expected_transactions = Vec::new();
635 for digit_register in Register::digits() {
636 expected_transactions.push(Transaction::transaction_start());
637 expected_transactions.push(Transaction::write_vec(vec![digit_register.addr(), 0x00]));
638 expected_transactions.push(Transaction::transaction_end());
639 }
640
641 let mut spi = SpiMock::new(&expected_transactions);
642 let mut driver = Max7219::new(&mut spi);
643
644 driver
645 .clear_display(0)
646 .expect("Clear display should succeed");
647 spi.done();
648 }
649
650 #[test]
651 fn test_clear_display_invalid_index() {
652 let mut spi = SpiMock::new(&[]); let mut driver = Max7219::new(&mut spi)
654 .with_device_count(1)
655 .expect("valid device count");
656
657 let result = driver.clear_display(1);
658 assert_eq!(result, Err(Error::InvalidDeviceIndex));
659 spi.done();
660 }
661
662 #[test]
663 fn test_write_raw_digit() {
664 let device_index = 0;
665 let digit = 3;
666 let data = 0b10101010;
667 let expected_transactions = [
668 Transaction::transaction_start(),
669 Transaction::write_vec(vec![Register::Digit3.addr(), data]),
670 Transaction::transaction_end(),
671 ];
672 let mut spi = SpiMock::new(&expected_transactions);
673 let mut driver = Max7219::new(&mut spi);
674
675 driver
676 .write_raw_digit(device_index, digit, data)
677 .expect("Write raw digit should succeed");
678 spi.done();
679 }
680
681 #[test]
682 fn test_write_raw_digit_invalid_digit() {
683 let mut spi = SpiMock::new(&[]); let mut driver = Max7219::new(&mut spi);
685
686 let result = driver.write_raw_digit(0, 8, 0x00); assert_eq!(result, Err(Error::InvalidDigit));
689
690 spi.done();
691 }
692
693 #[test]
694 fn test_set_intensity_valid() {
695 let device_index = 0;
696 let intensity = 0x0A;
697 let expected_transactions = [
698 Transaction::transaction_start(),
699 Transaction::write_vec(vec![Register::Intensity.addr(), intensity]),
700 Transaction::transaction_end(),
701 ];
702 let mut spi = SpiMock::new(&expected_transactions);
703 let mut driver = Max7219::new(&mut spi);
704
705 driver
706 .set_intensity(device_index, intensity)
707 .expect("Set intensity should succeed");
708 spi.done();
709 }
710
711 #[test]
712 fn test_set_intensity_invalid() {
713 let mut spi = SpiMock::new(&[]); let mut driver = Max7219::new(&mut spi);
715
716 let result = driver.set_intensity(0, 0x10); assert_eq!(result, Err(Error::InvalidIntensity));
718 spi.done();
719 }
720
721 #[test]
722 fn test_init() {
723 let expected_transactions = vec![
732 Transaction::transaction_start(),
734 Transaction::write_vec(vec![Register::Shutdown.addr(), 0x01]),
735 Transaction::transaction_end(),
736 Transaction::transaction_start(),
738 Transaction::write_vec(vec![Register::DisplayTest.addr(), 0x00]),
739 Transaction::transaction_end(),
740 Transaction::transaction_start(),
742 Transaction::write_vec(vec![Register::ScanLimit.addr(), NUM_DIGITS - 1]),
743 Transaction::transaction_end(),
744 Transaction::transaction_start(),
746 Transaction::write_vec(vec![
747 Register::DecodeMode.addr(),
748 DecodeMode::NoDecode.value(),
749 ]),
750 Transaction::transaction_end(),
751 Transaction::transaction_start(),
754 Transaction::write_vec(vec![Register::Digit0.addr(), 0x00]),
755 Transaction::transaction_end(),
756 Transaction::transaction_start(),
757 Transaction::write_vec(vec![Register::Digit1.addr(), 0x00]),
758 Transaction::transaction_end(),
759 Transaction::transaction_start(),
760 Transaction::write_vec(vec![Register::Digit2.addr(), 0x00]),
761 Transaction::transaction_end(),
762 Transaction::transaction_start(),
763 Transaction::write_vec(vec![Register::Digit3.addr(), 0x00]),
764 Transaction::transaction_end(),
765 Transaction::transaction_start(),
766 Transaction::write_vec(vec![Register::Digit4.addr(), 0x00]),
767 Transaction::transaction_end(),
768 Transaction::transaction_start(),
769 Transaction::write_vec(vec![Register::Digit5.addr(), 0x00]),
770 Transaction::transaction_end(),
771 Transaction::transaction_start(),
772 Transaction::write_vec(vec![Register::Digit6.addr(), 0x00]),
773 Transaction::transaction_end(),
774 Transaction::transaction_start(),
775 Transaction::write_vec(vec![Register::Digit7.addr(), 0x00]),
776 Transaction::transaction_end(),
777 ];
778
779 let mut spi = SpiMock::new(&expected_transactions);
780 let mut driver = Max7219::new(&mut spi);
781
782 driver.init().expect("Init should succeed");
783 spi.done();
784 }
785
786 #[test]
787 fn test_write_device_register_valid_index() {
788 let expected_transactions = [
789 Transaction::transaction_start(),
790 Transaction::write_vec(vec![
791 Register::Shutdown.addr(),
792 0x01,
793 0x00, 0x00,
795 ]),
796 Transaction::transaction_end(),
797 ];
798 let mut spi = SpiMock::new(&expected_transactions);
799 let mut driver = Max7219::new(&mut spi)
800 .with_device_count(2)
801 .expect("Should accept valid count");
802
803 driver
804 .write_device_register(0, Register::Shutdown, 0x01)
805 .expect("should write register");
806
807 spi.done();
808 }
809
810 #[test]
811 fn test_write_device_register_invalid_index() {
812 let mut spi = SpiMock::new(&[]); let mut driver = Max7219::new(&mut spi)
814 .with_device_count(2)
815 .expect("Should accept valid count");
816
817 let result = driver.write_device_register(2, Register::Shutdown, 0x01); assert_eq!(result, Err(Error::InvalidDeviceIndex));
819
820 spi.done();
821 }
822
823 #[test]
824 fn test_write_all_registers_valid() {
825 let expected_transactions = [
826 Transaction::transaction_start(),
827 Transaction::write_vec(vec![
828 Register::Intensity.addr(),
829 0x01,
830 Register::Intensity.addr(),
831 0x01,
832 ]),
833 Transaction::transaction_end(),
834 ];
835 let mut spi = SpiMock::new(&expected_transactions);
836 let mut driver = Max7219::new(&mut spi)
837 .with_device_count(2)
838 .expect("Should accept valid count");
839
840 driver
841 .write_all_registers(&[(Register::Intensity, 0x01), (Register::Intensity, 0x01)])
842 .expect("should write all registers");
843
844 spi.done();
845 }
846
847 #[test]
848 fn test_test_device_enable_disable() {
849 let expected_transactions = [
850 Transaction::transaction_start(),
851 Transaction::write_vec(vec![Register::DisplayTest.addr(), 0x01]),
852 Transaction::transaction_end(),
853 Transaction::transaction_start(),
854 Transaction::write_vec(vec![Register::DisplayTest.addr(), 0x00]),
855 Transaction::transaction_end(),
856 ];
857 let mut spi = SpiMock::new(&expected_transactions);
858 let mut driver = Max7219::new(&mut spi);
859
860 driver
861 .test_device(0, true)
862 .expect("Enable test mode failed");
863 driver
864 .test_device(0, false)
865 .expect("Disable test mode failed");
866 spi.done();
867 }
868
869 #[test]
870 fn test_set_device_scan_limit_valid() {
871 let scan_limit = 4;
872
873 let expected_transactions = [
874 Transaction::transaction_start(),
875 Transaction::write_vec(vec![Register::ScanLimit.addr(), scan_limit - 1]),
876 Transaction::transaction_end(),
877 ];
878 let mut spi = SpiMock::new(&expected_transactions);
879 let mut driver = Max7219::new(&mut spi);
880
881 driver
882 .set_device_scan_limit(0, scan_limit)
883 .expect("Scan limit set failed");
884 spi.done();
885 }
886
887 #[test]
888 fn test_set_device_scan_limit_invalid() {
889 let mut spi = SpiMock::new(&[]);
890 let mut driver = Max7219::new(&mut spi);
891
892 let result = driver.set_device_scan_limit(0, 0); assert_eq!(result, Err(Error::InvalidScanLimit));
894
895 let result = driver.set_device_scan_limit(0, 9); assert_eq!(result, Err(Error::InvalidScanLimit));
897 spi.done();
898 }
899
900 #[test]
901 fn test_set_device_decode_mode() {
902 let mode = DecodeMode::Digits0To3;
903 let expected_transactions = [
904 Transaction::transaction_start(),
905 Transaction::write_vec(vec![Register::DecodeMode.addr(), mode.value()]),
906 Transaction::transaction_end(),
907 ];
908 let mut spi = SpiMock::new(&expected_transactions);
909 let mut driver = Max7219::new(&mut spi);
910
911 driver
912 .set_device_decode_mode(0, mode)
913 .expect("Set decode mode failed");
914 spi.done();
915 }
916
917 #[test]
918 fn test_set_intensity_all() {
919 let intensity = 0x05;
920 let expected_transactions = [
921 Transaction::transaction_start(),
922 Transaction::write_vec(vec![
923 Register::Intensity.addr(),
924 intensity,
925 Register::Intensity.addr(),
926 intensity,
927 ]),
928 Transaction::transaction_end(),
929 ];
930 let mut spi = SpiMock::new(&expected_transactions);
931 let mut driver = Max7219::new(&mut spi)
932 .with_device_count(2)
933 .expect("valid count");
934
935 driver
936 .set_intensity_all(intensity)
937 .expect("Set intensity all failed");
938 spi.done();
939 }
940}