max7456/
lines_writer.rs

1use core::cmp::min;
2
3use peripheral_register::Register;
4
5use crate::registers::{DisplayMemoryMode, OperationMode, Registers};
6use crate::{Attributes, Display, COLUMN, ROW};
7
8const MAX_ADDRESS: u16 = (ROW * COLUMN) as u16;
9
10/// Full lines writer which write every char with specified row and column
11/// `null` chars will be ignored
12pub struct LinesWriter<'a, T> {
13    lines: &'a [T],
14    attributes: Attributes,
15    address: u16,
16}
17
18impl<'a, T: AsRef<[u8]>> LinesWriter<'a, T> {
19    pub fn new(lines: &'a [T], attributes: Attributes) -> Self {
20        Self { lines, attributes, address: 0 }
21    }
22
23    fn dump_bytes(&mut self, limit: u16, buffer: &mut [u8]) -> usize {
24        let mut offset = 0;
25        let max_column = min(self.lines[0].as_ref().len(), COLUMN);
26        let real_limit = min(limit, ((self.lines.len() - 1) * COLUMN + max_column) as u16);
27        while self.address < real_limit {
28            let row = self.address as usize / COLUMN;
29            let column = self.address as usize % COLUMN;
30            if column >= max_column {
31                self.address += 1;
32                continue;
33            }
34            let byte = self.lines[row].as_ref()[column];
35            if byte == 0 {
36                self.address += 1;
37                continue;
38            }
39            buffer[offset] = Registers::DisplayMemoryAddressLow as u8;
40            buffer[offset + 1] = self.address as u8;
41            buffer[offset + 2] = Registers::DisplayMemoryDataIn as u8;
42            buffer[offset + 3] = byte;
43            offset += 4;
44            self.address += 1;
45            if offset + 4 >= buffer.len() {
46                break;
47            }
48        }
49        return offset;
50    }
51
52    pub fn write<'b>(&mut self, buffer: &'b mut [u8]) -> Display<'b> {
53        assert!(buffer.len() >= 8);
54
55        buffer[0] = Registers::DisplayMemoryMode as u8;
56        let mut dmm = Register::<u8, DisplayMemoryMode>::new(0);
57        dmm.set(DisplayMemoryMode::OperationMode, OperationMode::Mode16Bit as u8);
58        dmm.set(
59            DisplayMemoryMode::LocalBackgroundControl,
60            self.attributes.local_background_control as u8,
61        );
62        dmm.set(DisplayMemoryMode::Blink, self.attributes.blink as u8);
63        dmm.set(DisplayMemoryMode::Invert, self.attributes.revert as u8);
64        buffer[1] = dmm.value;
65        let mut offset = 2;
66        if self.address < 0x100 {
67            buffer[2] = Registers::DisplayMemoryAddressHigh as u8;
68            buffer[3] = 0;
69            let length = self.dump_bytes(0x100, &mut buffer[4..]);
70            if length > 0 {
71                offset += length + 2;
72                if offset + 6 > buffer.len() {
73                    return Display(&buffer[..offset]);
74                }
75            }
76        }
77        buffer[offset] = Registers::DisplayMemoryAddressHigh as u8;
78        buffer[offset + 1] = 1;
79        let length = self.dump_bytes(MAX_ADDRESS, &mut buffer[offset + 2..]);
80        if length > 0 {
81            offset += length + 2;
82        }
83        if offset < buffer.len() {
84            buffer[offset] = 0; // in case of revert
85        }
86
87        Display(&buffer[..if offset > 2 { offset } else { 0 }])
88    }
89}
90
91pub fn revert(buffer: &mut [u8]) -> Display {
92    if buffer[0] != Registers::DisplayMemoryMode as u8 {
93        return Display(&buffer[..0]);
94    }
95    for i in 1..buffer.len() / 2 {
96        match buffer[i * 2] {
97            b if b == Registers::DisplayMemoryDataIn as u8 => buffer[i * 2 + 1] = 0u8,
98            b if b == Registers::CharacterMemoryAddressLow as u8 => continue,
99            b if b == Registers::CharacterMemoryAddressHigh as u8 => continue,
100            0 => return Display(&buffer[..(i - 1) * 2]),
101            _ => return Display(&buffer[..0]),
102        }
103    }
104    Display(buffer)
105}
106
107#[cfg(test)]
108mod test {
109    use super::LinesWriter;
110
111    #[test]
112    fn test_low_address() {
113        let mut output = [0u8; 32];
114        let mut lines = [[0u8; 30]; 16];
115        lines[7][29] = 't' as u8;
116        let mut writer = LinesWriter::new(&lines, Default::default());
117        let expected = hex!("04 00 05 00 06 EF 07 74");
118        assert_eq!(writer.write(&mut output).0, expected);
119    }
120
121    #[test]
122    fn test_high_address() {
123        let mut output = [0u8; 32];
124        let mut lines = [[0u8; 30]; 16];
125        lines[8][29] = 't' as u8;
126        let mut writer = LinesWriter::new(&lines, Default::default());
127        let expected = hex!("04 00 05 01 06 0D 07 74");
128        assert_eq!(writer.write(&mut output).0, expected);
129    }
130
131    #[test]
132    fn test_within_addreess() {
133        let mut output = [0u8; 32];
134        let mut lines = [[0u8; 30]; 16];
135        lines[7][29] = 't' as u8;
136        lines[8][15] = 't' as u8;
137        let mut writer = LinesWriter::new(&lines, Default::default());
138        let expected = hex!("04 00 05 00 06 EF 07 74 06 FF 07 74");
139        assert_eq!(writer.write(&mut output).0, expected);
140    }
141
142    #[test]
143    fn test_cross_address() {
144        let mut output = [0u8; 32];
145        let mut lines = [[0u8; 30]; 16];
146        lines[7][29] = 't' as u8;
147        lines[8][29] = 't' as u8;
148        let mut writer = LinesWriter::new(&lines, Default::default());
149        let expected = hex!("04 00 05 00 06 EF 07 74 05 01 06 0D 07 74");
150        assert_eq!(writer.write(&mut output).0, expected);
151    }
152
153    #[test]
154    fn test_exactly_one_buffer() {
155        let mut output = [0u8; 14];
156        let mut lines = [[0u8; 30]; 16];
157        lines[7][29] = 't' as u8;
158        lines[8][29] = 't' as u8;
159        let mut writer = LinesWriter::new(&lines, Default::default());
160        let expected = hex!("04 00 05 00 06 EF 07 74 05 01 06 0D 07 74");
161        assert_eq!(writer.write(&mut output).0, expected);
162        assert_eq!(writer.write(&mut output).0.len(), 0)
163    }
164
165    #[test]
166    fn test_multiple_buffer() {
167        let mut output = [0u8; 8];
168        let mut lines = [[0u8; 30]; 16];
169        lines[7][29] = 't' as u8;
170        lines[8][29] = 't' as u8;
171        let mut writer = LinesWriter::new(&lines, Default::default());
172        let expected = hex!("04 00 05 00 06 EF 07 74");
173        assert_eq!(writer.write(&mut output).0, expected);
174
175        let expected = hex!("04 00 05 01 06 0D 07 74");
176        assert_eq!(writer.write(&mut output).0, expected);
177    }
178
179    #[test]
180    fn test_non_standard_screen() {
181        let mut output = [0u8; 8];
182        let mut lines = [[0u8; 29]; 15];
183        lines[7][28] = 't' as u8;
184        lines[8][28] = 't' as u8;
185        let mut writer = LinesWriter::new(&lines, Default::default());
186        let expected = hex!("04 00 05 00 06 EE 07 74");
187        assert_eq!(writer.write(&mut output).0, expected);
188
189        let expected = hex!("04 00 05 01 06 0C 07 74");
190        assert_eq!(writer.write(&mut output).0, expected);
191    }
192}