max7219_display/
registers.rs

1//! MAX7219 register definitions and constants
2
3use crate::{Error, Result};
4
5/// MAX7219 control register addresses.
6///
7/// Each variant corresponds to a register in the MAX7219 display driver chip.
8/// These registers are used to control display behavior, including digit data,
9/// decoding mode, brightness, scan limit, power state, and test mode.
10///
11/// This enum is typically used when sending 16-bit data packets to the MAX7219,
12/// where the upper byte specifies the target register.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[repr(u8)]
15pub enum Register {
16    /// No-op register
17    NoOp = 0x00,
18    /// Digit 0 register
19    Digit0 = 0x01,
20    /// Digit 1 register
21    Digit1 = 0x02,
22    /// Digit 2 register
23    Digit2 = 0x03,
24    /// Digit 3 register
25    Digit3 = 0x04,
26    /// Digit 4 register
27    Digit4 = 0x05,
28    /// Digit 5 register
29    Digit5 = 0x06,
30    /// Digit 6 register
31    Digit6 = 0x07,
32    /// Digit 7 register
33    Digit7 = 0x08,
34    /// Decode mode register
35    DecodeMode = 0x09,
36    /// Intensity register
37    Intensity = 0x0A,
38    /// Scan limit register
39    ScanLimit = 0x0B,
40    /// Shutdown register
41    Shutdown = 0x0C,
42    /// Display test register
43    DisplayTest = 0x0F,
44}
45
46impl Register {
47    /// Convert register to u8 value
48    pub const fn addr(self) -> u8 {
49        self as u8
50    }
51
52    /// Try to convert a digit index (0-7) into a corresponding `Register::DigitN`.
53    pub(crate) fn try_digit(digit: u8) -> Result<Self> {
54        match digit {
55            0 => Ok(Register::Digit0),
56            1 => Ok(Register::Digit1),
57            2 => Ok(Register::Digit2),
58            3 => Ok(Register::Digit3),
59            4 => Ok(Register::Digit4),
60            5 => Ok(Register::Digit5),
61            6 => Ok(Register::Digit6),
62            7 => Ok(Register::Digit7),
63            _ => Err(Error::InvalidDigit),
64        }
65    }
66
67    /// Returns an iterator over all digit registers (Digit0 to Digit7).
68    ///
69    /// Useful for iterating through display rows or columns when writing
70    /// to all digits of a MAX7219 device in order.
71    pub fn digits() -> impl Iterator<Item = Register> {
72        [
73            Register::Digit0,
74            Register::Digit1,
75            Register::Digit2,
76            Register::Digit3,
77            Register::Digit4,
78            Register::Digit5,
79            Register::Digit6,
80            Register::Digit7,
81        ]
82        .into_iter()
83    }
84}
85
86/// Decode mode configuration for the MAX7219 display driver.
87///
88/// Code B decoding allows the driver to automatically convert certain values
89/// (such as 0-9, E, H, L, and others) into their corresponding 7-segment patterns.
90/// Digits not using Code B must be controlled manually using raw segment data.
91///
92/// Use this to configure which digits should use Code B decoding and which
93/// should remain in raw segment mode.
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95#[repr(u8)]
96pub enum DecodeMode {
97    /// Disable Code B decoding for all digits (DIG0 to DIG7).
98    ///
99    /// In this mode, you must manually set each segment (A to G and DP)
100    /// using raw segment data.
101    NoDecode = 0x00,
102
103    /// Enable Code B decoding for only digit 0 (DIG0).
104    ///
105    /// All other digits (DIG1 to DIG7) must be controlled manually.
106    Digit0 = 0x01,
107
108    /// Enable Code B decoding for digits 0 through 3 (DIG0 to DIG3).
109    ///
110    /// This is commonly used for 4-digit numeric displays.
111    Digits0To3 = 0x0F,
112
113    /// Enable Code B decoding for all digits (DIG0 to DIG7).
114    ///
115    /// This is typically used for full 8-digit numeric displays.
116    AllDigits = 0xFF,
117}
118
119impl DecodeMode {
120    /// Convert decode mode to u8 value
121    pub const fn value(self) -> u8 {
122        self as u8
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_register_addr() {
132        assert_eq!(Register::NoOp.addr(), 0x00);
133        assert_eq!(Register::Digit0.addr(), 0x01);
134        assert_eq!(Register::Digit7.addr(), 0x08);
135        assert_eq!(Register::DecodeMode.addr(), 0x09);
136        assert_eq!(Register::Intensity.addr(), 0x0A);
137        assert_eq!(Register::ScanLimit.addr(), 0x0B);
138        assert_eq!(Register::Shutdown.addr(), 0x0C);
139        assert_eq!(Register::DisplayTest.addr(), 0x0F);
140    }
141
142    #[test]
143    fn test_try_digit_valid() {
144        assert_eq!(Register::try_digit(0), Ok(Register::Digit0));
145        assert_eq!(Register::try_digit(1), Ok(Register::Digit1));
146        assert_eq!(Register::try_digit(2), Ok(Register::Digit2));
147        assert_eq!(Register::try_digit(3), Ok(Register::Digit3));
148        assert_eq!(Register::try_digit(4), Ok(Register::Digit4));
149        assert_eq!(Register::try_digit(5), Ok(Register::Digit5));
150        assert_eq!(Register::try_digit(6), Ok(Register::Digit6));
151        assert_eq!(Register::try_digit(7), Ok(Register::Digit7));
152    }
153
154    #[test]
155    fn test_try_digit_invalid() {
156        assert_eq!(Register::try_digit(8), Err(Error::InvalidDigit));
157        assert_eq!(Register::try_digit(255), Err(Error::InvalidDigit));
158    }
159
160    #[test]
161    fn test_digits_iterator() {
162        let expected = [
163            Register::Digit0,
164            Register::Digit1,
165            Register::Digit2,
166            Register::Digit3,
167            Register::Digit4,
168            Register::Digit5,
169            Register::Digit6,
170            Register::Digit7,
171        ];
172        let actual: Vec<Register> = Register::digits().collect();
173        assert_eq!(actual, expected);
174    }
175
176    #[test]
177    fn test_decode_mode_value() {
178        assert_eq!(DecodeMode::NoDecode.value(), 0x00);
179        assert_eq!(DecodeMode::Digit0.value(), 0x01);
180        assert_eq!(DecodeMode::Digits0To3.value(), 0x0F);
181        assert_eq!(DecodeMode::AllDigits.value(), 0xFF);
182    }
183}