1use std::{error::Error, io::Write};
2
3use bitvec::prelude::*;
4use embedded_graphics::{pixelcolor::BinaryColor, prelude::*};
5
6const HEX: &[u8; 16] = b"0123456789ABCDEF";
7
8fn byte_to_hex(b: &u8) -> [u8; 2] {
9 [HEX[((*b & 0xf0) >> 4) as usize], HEX[(*b & 0xf) as usize]]
10}
11
12pub struct HanoverFlipdot {
13 addr: u8,
14 w: u32,
15 h: u32,
16 framebuffer: BitVec<u8, Lsb0>,
17}
18
19impl HanoverFlipdot {
20 pub fn new(w: u32, h: u32, addr: u8) -> Self {
21 assert!(addr < 16);
22 Self {
23 addr,
24 w,
25 h,
26 framebuffer: bitvec![u8, Lsb0; 0; (w*h) as usize],
27 }
28 }
29 pub fn write_frame<W>(&self, writer: &mut W) -> Result<(), Box<dyn Error>>
30 where
31 W: Write,
32 {
33 let mut data = vec![0x2];
37 data.extend(
38 [self.addr + 17, ((self.h * self.w) / 8) as u8]
39 .iter()
40 .chain(self.framebuffer.as_raw_slice().into_iter())
41 .flat_map(byte_to_hex),
42 );
43 data.push(0x03);
44 let sum = data.iter().skip(1).map(|x| *x as u64).sum::<u64>() as u8;
45 data.extend(byte_to_hex(&((sum ^ 0xFF).wrapping_add(1))));
46 writer.write(&data)?;
47 Ok(())
48 }
49}
50
51impl DrawTarget for HanoverFlipdot {
52 type Color = BinaryColor;
53 type Error = core::convert::Infallible;
54 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
55 where
56 I: IntoIterator<Item = Pixel<Self::Color>>,
57 {
58 for Pixel(coord, color) in pixels.into_iter() {
59 if let Ok((x, y)) = <(u32, u32)>::try_from(coord) {
60 if (0..self.w).contains(&x) && (0..self.h).contains(&y) {
61 let index: u32 = x * self.h + y;
62 self.framebuffer.set(index as usize, color.is_on());
63 }
64 }
65 }
66 Ok(())
67 }
68}
69
70impl OriginDimensions for HanoverFlipdot {
71 fn size(&self) -> Size {
72 Size::new(self.w, self.h)
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_b2h() {
82 assert_eq!(byte_to_hex(&192), *b"C0");
83 assert_eq!(byte_to_hex(&0), *b"00");
84 assert_eq!(byte_to_hex(&255), *b"FF");
85 }
86}