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
10pub 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; }
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}