orange_cli/
isp.rs

1use byteorder::{ByteOrder, LittleEndian, WriteBytesExt, ReadBytesExt};
2use serialport::SerialPort;
3use std::io::{BufReader, BufRead};
4
5static ISP_IMAGE: &'static [u8] = include_bytes!("./orange-isp.bin");
6
7#[derive(Copy, Clone, Debug)]
8pub enum IspCommand<'a> {
9    Boot,
10    Flash(&'a [u8]),
11}
12
13pub fn upload_isp_image(port: &mut dyn SerialPort) {
14    let mut write_half = port.try_clone().expect("cannot clone port");
15    println!("Waiting for device...");
16    let reader = BufReader::new(port);
17    let mut lines = reader.lines();
18    loop {
19        let line = match lines.next().expect("expecting first line") {
20            Ok(x) => x,
21            Err(_) => continue // invalid encoding?
22        };
23        let expected = "OrangeLoader SERIAL BOOT ";
24        if line.starts_with(expected) {
25            println!("OrangeLoader version: {}", &line[expected.len()..]);
26            break;
27        }
28    }
29
30    transmit_boot_image(&mut *write_half, ISP_IMAGE);
31    if lines.next().unwrap().unwrap() != "OrangeISP" {
32        panic!("Bad response from ISP");
33    }
34    println!("ISP loaded to device.");
35}
36
37fn transmit_boot_image(port: &mut dyn SerialPort, image: &[u8]) {
38    let mut sum: u32 = 0;
39    let mut len_buf: [u8; 4] = [0; 4];
40    LittleEndian::write_u32(&mut len_buf, image.len() as u32);
41
42    for i in 0..4 {
43        sum += len_buf[i] as u32;
44    }
45    port.write(&len_buf).unwrap();
46
47    for b in image {
48        sum += *b as u32;
49    }
50    port.write(image).unwrap();
51
52    let mut sum_buf: [u8; 4] = [0; 4];
53    LittleEndian::write_u32(&mut sum_buf, sum);
54    port.write_all(&sum_buf).unwrap();
55}
56
57impl<'a> IspCommand<'a> {
58    pub fn send(&self, port: &mut dyn SerialPort) {
59        match *self {
60            IspCommand::Boot => {
61                port.write(&[0x00]).expect("write failed");
62            }
63            IspCommand::Flash(image) => {
64                port.write(&[0x01]).expect("write failed");
65
66                let num_blocks = ((image.len() + 65535) / 65536) as u32;
67                port.write_u32::<LittleEndian>(num_blocks).unwrap();
68
69                for i in (0..image.len()).step_by(65536) {
70                    println!("Writing 0x{:x}.", i);
71                    let mut buf = vec![0u8; 65536];
72                    let copy_len = if image.len() - i > 65536 {
73                        65536
74                    } else {
75                        image.len() - i
76                    };
77                    buf[0..copy_len].copy_from_slice(&image[i..i + copy_len]);
78                    let checksum = crc::crc32::checksum_ieee(&buf);
79                    port.write(&buf).unwrap();
80                    port.write_u32::<LittleEndian>(checksum).unwrap();
81                    let block_end = port.read_u8().unwrap();
82                    assert_eq!(block_end, 0x66);
83                }
84                let transmit_end = port.read_u8().unwrap();
85                assert_eq!(transmit_end, 0x33);
86            }
87        }
88    }
89}