1#![deny(unsafe_code)]
8#![deny(warnings)]
9#![no_std]
10
11use embedded_hal_async::spi::SpiDevice;
12
13pub const NUM_DIGITS: usize = 8;
15
16#[derive(Clone, Copy)]
18pub enum Register {
19 Noop = 0x00,
20 Digit0 = 0x01,
21 Digit1 = 0x02,
22 Digit2 = 0x03,
23 Digit3 = 0x04,
24 Digit4 = 0x05,
25 Digit5 = 0x06,
26 Digit6 = 0x07,
27 Digit7 = 0x08,
28 DecodeMode = 0x09,
29 Intensity = 0x0A,
30 ScanLimit = 0x0B,
31 Power = 0x0C,
32 DisplayTest = 0x0F,
33}
34
35impl From<Register> for u8 {
36 fn from(command: Register) -> u8 {
37 command as u8
38 }
39}
40
41#[derive(Copy, Clone)]
43pub enum DecodeMode {
44 NoDecode = 0x00,
46 CodeBDigit0 = 0x01,
47 CodeBDigits3_0 = 0x0F,
48 CodeBDigits7_0 = 0xFF,
49}
50
51pub struct Max7219<SPI> {
55 pub spi: SPI,
56}
57
58impl<SPI> Max7219<SPI>
59where
60 SPI: SpiDevice,
61{
62 async fn write_reg(&mut self, register: impl Into<u8>, data: u8) -> Result<(), SPI::Error> {
64 self.spi.write(&[register.into(), data]).await
65 }
66
67 pub async fn power_on(&mut self) -> Result<(), SPI::Error> {
69 self.write_reg(Register::Power, 0x01).await
70 }
71
72 pub async fn power_off(&mut self) -> Result<(), SPI::Error> {
74 self.write_reg(Register::Power, 0x00).await
75 }
76
77 pub async fn clear(&mut self) -> Result<(), SPI::Error> {
79 self.write_raw(&[0; NUM_DIGITS]).await
80 }
81
82 pub async fn set_intensity(&mut self, intensity: u8) -> Result<(), SPI::Error> {
84 self.write_reg(Register::Intensity, intensity).await
85 }
86
87 pub async fn set_decode_mode(&mut self, mode: DecodeMode) -> Result<(), SPI::Error> {
91 self.write_reg(Register::DecodeMode, mode as u8).await
92 }
93
94 #[inline]
116 pub async fn write_digit_bytes(&mut self, digit: u8, value: u8) -> Result<(), SPI::Error> {
117 self.write_reg(digit + 1, value).await
118 }
119
120 pub async fn write_str(
127 &mut self,
128 string: &[u8; NUM_DIGITS],
129 dots: u8,
130 ) -> Result<(), SPI::Error> {
131 for (i, b) in string.iter().enumerate() {
132 let reg = NUM_DIGITS as u8 - i as u8; let dot = (dots >> (reg - 1)) & 1 == 1;
134 self.write_reg(reg, ssb_byte(*b, dot)).await?;
135 }
136
137 Ok(())
138 }
139
140 pub async fn write_integer(&mut self, value: i32) -> Result<(), SPI::Error> {
142 let mut buf = [0u8; 8];
143 let j = base_10_bytes(value, &mut buf);
144 buf = pad_left(j);
145 self.write_str(&buf, 0b00000000).await
146 }
147
148 pub async fn write_hex(&mut self, value: u32) -> Result<(), SPI::Error> {
150 let mut buf = [0u8; 8];
151 let j = hex_bytes(value, &mut buf);
152 buf = pad_left(j);
153 self.write_str(&buf, 0b00000000).await
154 }
155
156 pub async fn write_raw(&mut self, raw: &[u8; NUM_DIGITS]) -> Result<(), SPI::Error> {
158 for (n, b) in raw.iter().enumerate() {
159 self.write_digit_bytes(n as u8, *b).await?;
160 }
161 Ok(())
162 }
163
164 pub async fn set_test(&mut self, enable: bool) -> Result<(), SPI::Error> {
166 self.write_reg(Register::DisplayTest, if enable { 0x01 } else { 0x00 })
167 .await
168 }
169
170 pub const fn new(spi: SPI) -> Self {
175 Self { spi }
176 }
177
178 pub async fn set_scan_limit(&mut self, limit: u8) -> Result<(), SPI::Error> {
180 self.write_reg(Register::ScanLimit, limit - 1).await
181 }
182
183 pub async fn init(&mut self) -> Result<(), SPI::Error> {
185 self.set_test(false).await?;
186 self.set_scan_limit(NUM_DIGITS as u8).await?;
187 self.set_decode_mode(DecodeMode::NoDecode).await?;
188 self.clear().await?;
189 self.power_off().await?;
190 self.power_on().await?;
191
192 Ok(())
193 }
194}
195
196fn ssb_byte(b: u8, dot: bool) -> u8 {
200 let mut result = match b as char {
201 ' ' => 0b0000_0000, '.' => 0b1000_0000,
203 '-' => 0b0000_0001, '_' => 0b0000_1000, '0' => 0b0111_1110,
206 '1' => 0b0011_0000,
207 '2' => 0b0110_1101,
208 '3' => 0b0111_1001,
209 '4' => 0b0011_0011,
210 '5' => 0b0101_1011,
211 '6' => 0b0101_1111,
212 '7' => 0b0111_0000,
213 '8' => 0b0111_1111,
214 '9' => 0b0111_1011,
215 'a' | 'A' => 0b0111_0111,
216 'b' => 0b0001_1111,
217 'c' | 'C' => 0b0100_1110,
218 'd' => 0b0011_1101,
219 'e' | 'E' => 0b0100_1111,
220 'f' | 'F' => 0b0100_0111,
221 'g' | 'G' => 0b0101_1110,
222 'h' | 'H' => 0b0011_0111,
223 'i' | 'I' => 0b0011_0000,
224 'j' | 'J' => 0b0011_1100,
225 'l' | 'L' => 0b0000_1110,
227 'n' | 'N' => 0b0001_0101,
229 'o' | 'O' => 0b0111_1110,
230 'p' | 'P' => 0b0110_0111,
231 'q' => 0b0111_0011,
232 'r' | 'R' => 0b0000_0101,
233 's' | 'S' => 0b0101_1011,
234 'u' | 'U' => 0b0011_1110,
236 _ => 0b1110_0101, };
243
244 if dot {
245 result |= 0b1000_0000; }
247
248 result
249}
250
251fn base_10_bytes(mut n: i32, buf: &mut [u8]) -> &[u8] {
253 let mut sign: bool = false;
254 if n == 0 {
255 return b"0";
256 }
257 if !(-9999999..=99999999).contains(&n) {
259 return b"Err";
260 }
261 if n < 0 {
262 n = -n;
263 sign = true;
264 }
265 let mut i = 0;
266 while n > 0 {
267 buf[i] = (n % 10) as u8 + b'0';
268 n /= 10;
269 i += 1;
270 }
271 if sign {
272 buf[i] = b'-';
273 i += 1;
274 }
275 let slice = &mut buf[..i];
276 slice.reverse();
277 &*slice
278}
279
280fn hex_bytes(mut n: u32, buf: &mut [u8]) -> &[u8] {
282 if n == 0 {
283 return b"0";
284 }
285 let mut i = 0;
286 while n > 0 {
287 let digit = (n % 16) as u8;
288 buf[i] = match digit {
289 0 => b'0',
290 1 => b'1',
291 2 => b'2',
292 3 => b'3',
293 4 => b'4',
294 5 => b'5',
295 6 => b'6',
296 7 => b'7',
297 8 => b'8',
298 9 => b'9',
299 10 => b'a',
300 11 => b'b',
301 12 => b'c',
302 13 => b'd',
303 14 => b'e',
304 15 => b'f',
305 _ => b'?',
306 };
307 n /= 16;
308 i += 1;
309 }
310 let slice = &mut buf[..i];
311 slice.reverse();
312 &*slice
313}
314
315fn pad_left(val: &[u8]) -> [u8; 8] {
317 assert!(val.len() <= 8);
318 let size: usize = 8;
319 let pos: usize = val.len();
320 let mut cur: usize = 1;
321 let mut out: [u8; 8] = *b" ";
322 while cur <= pos {
323 out[size - cur] = val[pos - cur];
324 cur += 1;
325 }
326 out
327}