1use crate::serial::SerialDevice;
2use bitflags::bitflags;
3
4bitflags! {
5 struct PrinterStatus : u8 {
6 const LOW_BATTERY = 1 << 7;
7 const OTHER_ERR = 1 << 6;
8 const PAPER_JAM = 1 << 5;
9 const PACKET_ERR = 1 << 4;
10 const READY_TO_PRINT = 1 << 3;
11 const IMAGE_DATA_FULL = 1 << 2;
12 const PRINTING = 1 << 1;
13 const CHECKSUM_ERR = 1;
14 }
15}
16
17enum PacketState {
18 Magic1,
19 Magic2,
20 Command,
21 CompressionFlag,
22 DataLengthLow,
23 DataLengthHigh,
24 CommandData,
25 ChecksumLow,
26 ChecksumHigh,
27 AliveIndicator,
28 Status,
29}
30
31#[derive(Default, Debug)]
32struct Packet {
33 command: u8,
34 compression_flag: u8,
35 data_length: u16,
36 data: Vec<u8>,
37 checksum: u16,
38}
39
40impl Packet {
41 fn clear(&mut self) {
42 let _ = std::mem::take(self);
43 }
44
45 fn compute_checksum(&self) -> u16 {
46 let mut sum = 0;
47 sum += self.command as u16;
48 sum += self.compression_flag as u16;
49 sum += self.data_length & 0xFF;
50 sum += self.data_length >> 8;
51 sum += self
52 .data
53 .iter()
54 .map(|&x| x as u16)
55 .fold(0u16, |a, b| a.wrapping_add(b));
56
57 sum
58 }
59}
60
61pub struct Printer {
67 ram: [u8; 0x2000],
68 ram_next_write_pointer: usize,
69 current_packet: Packet,
70 packet_input_state: PacketState,
71 remaining_data_length: u16,
72 byte_to_send: u8,
73 received_byte: u8,
74 status: PrinterStatus,
75 ready_to_print_next: bool,
78 printing_delay: u8,
79 received_bit_counter: u8,
80
81 image_buffer: Vec<u8>,
84 image_size: (u32, u32),
85}
86
87impl Default for Printer {
88 fn default() -> Self {
89 Self {
90 ram: [0; 0x2000],
91 ram_next_write_pointer: 0,
92 current_packet: Packet::default(),
93 packet_input_state: PacketState::Magic1,
94 remaining_data_length: 0,
95 byte_to_send: 0,
96 received_byte: 0,
97 status: PrinterStatus::empty(),
98 ready_to_print_next: false,
99 printing_delay: 0,
100 received_bit_counter: 0,
101 image_buffer: Vec::new(),
102 image_size: (0, 0),
103 }
104 }
105}
106
107impl Printer {
108 pub fn get_image_buffer(&self) -> &[u8] {
112 &self.image_buffer
113 }
114
115 pub fn get_image_size(&self) -> (u32, u32) {
117 self.image_size
118 }
119
120 pub fn clear_image_buffer(&mut self) {
122 self.image_buffer.clear();
123 self.image_size = (0, 0);
124 }
125}
126
127impl Printer {
128 fn handle_next_byte(&mut self, byte: u8) {
129 match self.packet_input_state {
130 PacketState::Magic1 => {
131 if byte == 0x88 {
132 self.packet_input_state = PacketState::Magic2;
133 self.current_packet.clear();
134 }
135 }
136 PacketState::Magic2 => {
137 if byte == 0x33 {
138 self.packet_input_state = PacketState::Command;
139 } else {
140 self.packet_input_state = PacketState::Magic1;
141 }
142 }
143 PacketState::Command => {
144 self.current_packet.command = byte;
145 self.packet_input_state = PacketState::CompressionFlag;
146 }
147 PacketState::CompressionFlag => {
148 self.current_packet.compression_flag = byte;
149 self.packet_input_state = PacketState::DataLengthLow;
150 }
151 PacketState::DataLengthLow => {
152 self.current_packet.data_length &= 0xFF00;
153 self.current_packet.data_length |= byte as u16;
154 self.packet_input_state = PacketState::DataLengthHigh;
155 }
156 PacketState::DataLengthHigh => {
157 self.current_packet.data_length &= 0x00FF;
158 self.current_packet.data_length |= (byte as u16) << 8;
159
160 self.remaining_data_length = self.current_packet.data_length;
161 self.packet_input_state = if self.remaining_data_length != 0 {
162 PacketState::CommandData
163 } else {
164 PacketState::ChecksumLow
165 };
166 }
167 PacketState::CommandData => {
168 self.current_packet.data.push(byte);
169
170 self.remaining_data_length -= 1;
171
172 if self.remaining_data_length == 0 {
173 self.packet_input_state = PacketState::ChecksumLow;
174 }
175 }
176 PacketState::ChecksumLow => {
177 self.current_packet.checksum &= 0xFF00;
178 self.current_packet.checksum |= byte as u16;
179 self.packet_input_state = PacketState::ChecksumHigh;
180 }
181
182 PacketState::ChecksumHigh => {
183 self.current_packet.checksum &= 0x00FF;
184 self.current_packet.checksum |= (byte as u16) << 8;
185 self.packet_input_state = PacketState::AliveIndicator;
186
187 self.byte_to_send = 0x81;
189 }
190 PacketState::AliveIndicator => {
191 self.packet_input_state = PacketState::Status;
192
193 self.byte_to_send = self.status.bits();
194 self.process_packet();
195 }
196 PacketState::Status => {
197 self.packet_input_state = PacketState::Magic1;
199 }
200 }
201 }
202
203 fn process_packet(&mut self) {
204 if self.current_packet.checksum != self.current_packet.compute_checksum() {
205 self.status |= PrinterStatus::CHECKSUM_ERR;
206 panic!("checksum failed");
207 }
208
209 match self.current_packet.command {
210 1 => {
211 self.ram = [0; 0x2000];
212 self.ram_next_write_pointer = 0;
213 self.status = PrinterStatus::empty();
214 self.ready_to_print_next = false;
215 }
216 2 => {
217 if self.ready_to_print_next {
218 if self.current_packet.data_length != 4 {
219 self.status |= PrinterStatus::PACKET_ERR;
220 } else {
221 self.status |= PrinterStatus::PRINTING;
223 self.status.remove(PrinterStatus::READY_TO_PRINT);
224 self.printing_delay = 20;
225
226 let number_of_sheets = self.current_packet.data[0];
227 let margins = self.current_packet.data[1];
228 let palette = self.current_packet.data[2];
229 let exposure = self.current_packet.data[3];
230
231 self.print(
232 number_of_sheets,
233 margins,
234 palette,
235 exposure,
236 self.ram_next_write_pointer,
237 );
238 }
239 self.ready_to_print_next = false;
240 }
241 }
242 4 => {
243 if self.current_packet.data_length == 0 {
244 self.ready_to_print_next = true;
245 } else {
246 let start = self.ram_next_write_pointer;
247 let end = start + self.current_packet.data_length as usize;
248 self.ram_next_write_pointer = end;
249 if end > self.ram.len() {
250 panic!("end is bigger than ram size");
252 }
253
254 assert_eq!(
255 self.current_packet.data.len(),
256 self.current_packet.data_length as usize
257 );
258 self.ram[start..end].copy_from_slice(&self.current_packet.data);
259 }
260
261 self.status |= PrinterStatus::READY_TO_PRINT
262 }
263 0xF => {
264 if self.status.contains(PrinterStatus::PRINTING) {
265 self.printing_delay = self.printing_delay.saturating_sub(1);
266 if self.printing_delay == 0 {
267 self.status.remove(PrinterStatus::PRINTING);
268 }
269 }
270 }
271 _ => {
272 self.status |= PrinterStatus::PACKET_ERR;
273 }
274 };
275 }
276
277 fn print(
280 &mut self,
281 number_of_sheets: u8,
282 margins: u8,
283 palette: u8,
284 exposure: u8,
285 max_data_len: usize,
286 ) {
287 if number_of_sheets == 0 {
289 self.print_line_feed();
290 return;
291 }
292
293 let margin_before = margins >> 4;
295 let margin_after = margins & 0xF;
297
298 let exposure_multiply = compute_exposure_multiply(exposure);
299
300 for _ in 0..margin_before {
303 self.print_line_feed();
304 }
305
306 let rows_to_print = max_data_len / 40;
307
308 let (_, old_height) = self.image_size;
309 let new_width = 160;
310 let new_height = old_height + rows_to_print as u32;
311
312 self.image_size = (new_width, new_height);
313
314 let old_size = self.image_buffer.len();
316 let extra_space = rows_to_print * 160 * 3;
317 self.image_buffer.reserve(extra_space);
318
319 for y in 0..rows_to_print {
320 for x in 0..20 {
321 let scroll_y = y / 8;
322 let fine_y_scroll = y % 8;
323
324 let tile = scroll_y * 20 + x;
325 let tile_index = tile * 16;
326 let ram_index = tile_index + (fine_y_scroll * 2);
327
328 let low = self.ram[ram_index];
329 let high = self.ram[ram_index + 1];
330
331 let mut result = [0; 8];
332 for (i, result_item) in result.iter_mut().enumerate() {
333 let bin_i = 7 - i;
334 *result_item = ((high >> bin_i) & 1) << 1 | ((low >> bin_i) & 1);
335 }
336
337 for pixel in &result {
338 let color = (palette >> (pixel * 2)) & 0b11;
339
340 let inverted_gray_shade = 85 * color;
343 let exposured_invertd_gray_shade =
345 inverted_gray_shade as f64 * exposure_multiply;
346 let exposured_invertd_gray_shade = exposured_invertd_gray_shade.clamp(0., 255.);
349
350 let gray_shade = 255 - (exposured_invertd_gray_shade as u8);
352
353 for _ in 0..3 {
355 self.image_buffer.push(gray_shade);
356 }
357 }
358 }
359 }
360
361 assert_eq!(old_size + extra_space, self.image_buffer.len());
363
364 for _ in 0..margin_after {
365 self.print_line_feed();
366 }
367
368 if number_of_sheets > 1 {
369 self.print(
371 number_of_sheets - 1,
372 margins,
373 palette,
374 exposure,
375 max_data_len,
376 );
377 }
378 }
379
380 fn print_line_feed(&mut self) {
382 let (_, old_height) = self.image_size;
383 self.image_size = (160, old_height + 1);
385
386 self.image_buffer.reserve(160 * 3);
388
389 for _ in 0..(160 * 3) {
390 self.image_buffer.push(255);
391 }
392 }
393}
394
395fn map_num(inp: i32, inp_start: i32, inp_end: i32, out_start: i32, out_end: i32) -> i32 {
397 ((inp - inp_start) as f64 / (inp_end - inp_start) as f64 * (out_end - out_start) as f64
398 + out_start as f64) as i32
399}
400
401fn compute_exposure_multiply(exposure: u8) -> f64 {
404 (100 + map_num((exposure & 0x7F) as i32, 0, 0x7F, -25, 25)) as f64 / 100.
405}
406
407#[test]
408fn map_num_test() {
409 let a = map_num(5, 0, 100, 1, 11);
410 assert_eq!(a, 1);
411}
412
413#[test]
414fn compute_exposure_multiply_test() {
415 let mut min = 200f64;
416 let mut max = -200f64;
417
418 for exposure in 0..=0x7F {
419 let a = compute_exposure_multiply(exposure);
420
421 if exposure != 0 {
424 assert!(a >= min);
425 assert!(a >= max);
426 }
427
428 min = min.min(a);
429 max = max.max(a);
430 }
431
432 assert_eq!(min, 0.75);
434 assert_eq!(max, 1.25);
435}
436
437impl SerialDevice for Printer {
438 fn exchange_bit_external_clock(&mut self, bit: bool) -> bool {
439 self.received_bit_counter += 1;
440
441 if self.received_bit_counter == 9 {
442 self.handle_next_byte(self.received_byte);
443 self.received_byte = 0;
444 self.received_bit_counter = 1;
445 }
446
447 self.received_byte = self.received_byte.wrapping_shl(1);
448 self.received_byte |= bit as u8;
449
450 let out = self.byte_to_send & 0x80 != 0;
451 self.byte_to_send = self.byte_to_send.wrapping_shl(1);
452
453 out
454 }
455}