1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use postcard::{CobsAccumulator, FeedResult};
use serde::{Deserialize, Serialize};
use std::{
    io::{ErrorKind, Read, Write},
    net::TcpStream,
    time::Duration,
};

#[derive(Serialize, Deserialize)]
enum Request {
    Send { offset: u32 },
    Done,
}

#[derive(Serialize, Deserialize)]
enum Response {
    Buffer { start: u32, data: Vec<u8> },
    Done(u32),
    Retry,
}

fn main() {
    let mut args = std::env::args();
    let _ = args.next();
    let ip = args.next().unwrap();
    let port = args.next().unwrap();
    let bin = args.next().unwrap();

    let dest = format!("{}:{}", ip, port);
    let mut conn = TcpStream::connect(&dest).unwrap();
    println!("Connected to '{}'.", dest);
    let mut file = std::fs::File::open(bin).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    println!("Loaded file. {} bytes.", contents.len());

    while (contents.len() % 256) != 0 {
        contents.push(0xFF);
    }

    let mut acc = CobsAccumulator::<256>::new();
    let mut rdbuf = [0u8; 256];

    conn.set_read_timeout(Some(Duration::from_millis(100)))
        .unwrap();

    'outer: loop {
        match conn.read(&mut rdbuf) {
            Ok(len) if len > 0 => {
                let mut window = &rdbuf[..len];
                while !window.is_empty() {
                    match acc.feed::<Request>(window) {
                        FeedResult::Consumed => {
                            window = &[];
                        }
                        FeedResult::OverFull(rem) => {
                            window = rem;
                            let data = postcard::to_stdvec_cobs(&Response::Retry).unwrap();
                            conn.write_all(&data).unwrap();
                        }
                        FeedResult::DeserError(rem) => {
                            window = rem;
                            let data = postcard::to_stdvec_cobs(&Response::Retry).unwrap();
                            conn.write_all(&data).unwrap();
                        }
                        FeedResult::Success { data, remaining } => {
                            window = remaining;
                            match data {
                                Request::Send { offset } => {
                                    let off_usize = offset as usize;
                                    if off_usize < contents.len() {
                                        println!("Sending 0x{:08X}", offset);
                                        let mut data = Vec::new();
                                        data.extend_from_slice(&contents[off_usize..][..256]);
                                        let data = postcard::to_stdvec_cobs(&Response::Buffer {
                                            start: offset,
                                            data,
                                        })
                                        .unwrap();
                                        conn.write_all(&data).unwrap();
                                    } else {
                                        let data = postcard::to_stdvec_cobs(&Response::Done(
                                            contents.len() as u32,
                                        ))
                                        .unwrap();
                                        conn.write_all(&data).unwrap();
                                    }
                                }
                                Request::Done => break 'outer,
                            }
                        }
                    }
                }
            }
            Ok(_) => {
                let data = postcard::to_stdvec_cobs(&Response::Retry).unwrap();
                conn.write_all(&data).unwrap();
            }
            Err(e) if e.kind() == ErrorKind::WouldBlock => {
                let data = postcard::to_stdvec_cobs(&Response::Retry).unwrap();
                conn.write_all(&data).unwrap();
            }
            Err(_) => todo!(),
        }
    }

    println!("Done.");
}