hanover_flipdot/
lib.rs

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        // Encode the address and resolution.
34        // The address is the number on the address selector on the flipdot PCB + 17. For
35        // some reason.
36        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}