1use std::io::*;
17
18use crate::crc::crc16_ccitt;
19
20const SOH: u8 = 0x01;
22const STX: u8 = 0x02;
24const EOT: u8 = 0x04;
26const ACK: u8 = 0x06;
28const NAK: u8 = 0x15;
30const EOF: u8 = 0x1A;
33const CRC: u8 = 0x43;
35
36pub struct Ymodem {
41 crc_mode: bool,
43 blk: u8,
45 retries: usize,
47}
48
49impl Ymodem {
50 pub fn new(crc_mode: bool) -> Self {
56 Self {
57 crc_mode,
58 blk: 0,
59 retries: 10,
60 }
61 }
62
63 fn nak(&self) -> u8 {
64 if self.crc_mode { CRC } else { NAK }
65 }
66
67 fn getc<D: Read>(&mut self, dev: &mut D) -> Result<u8> {
68 let mut buff = [0u8; 1];
69 dev.read_exact(&mut buff)?;
70 Ok(buff[0])
71 }
72
73 fn wait_for_start<D: Read>(&mut self, dev: &mut D) -> Result<()> {
74 loop {
75 match self.getc(dev)? {
76 NAK => {
77 self.crc_mode = false;
78 return Ok(());
79 }
80 CRC => {
81 self.crc_mode = true;
82 return Ok(());
83 }
84 _ => {}
85 }
86 }
87 }
88
89 pub fn send<D: Write + Read, F: Read>(
103 &mut self,
104 dev: &mut D,
105 file: &mut F,
106 name: &str,
107 size: usize,
108 on_progress: impl Fn(usize),
109 ) -> Result<()> {
110 info!("Sending file: {name}");
111
112 self.send_header(dev, name, size)?;
113
114 let mut buff = [0u8; 1024];
115 let mut send_size = 0;
116
117 while let Ok(n) = file.read(&mut buff) {
118 if n == 0 {
119 break;
120 }
121 self.send_blk(dev, &buff[..n], EOF, false)?;
122 send_size += n;
123 on_progress(send_size);
124 }
125
126 dev.write_all(&[EOT])?;
127 dev.flush()?;
128 self.wait_ack(dev)?;
129
130 self.send_blk(dev, &[0], 0, true)?;
131
132 self.wait_for_start(dev)?;
133 Ok(())
134 }
135
136 fn wait_ack<D: Read>(&mut self, dev: &mut D) -> Result<()> {
137 let nak = self.nak();
138 loop {
139 let c = self.getc(dev)?;
140 match c {
141 ACK => return Ok(()),
142 _ => {
143 if c == nak {
144 return Err(Error::new(ErrorKind::BrokenPipe, "NAK"));
145 }
146 stdout().write_all(&[c])?;
147 }
148 }
149 }
150 }
151
152 fn send_header<D: Write + Read>(&mut self, dev: &mut D, name: &str, size: usize) -> Result<()> {
153 let mut buff = Vec::new();
154
155 buff.append(&mut name.as_bytes().to_vec());
156
157 buff.push(0);
158
159 buff.append(&mut format!("{}", size).as_bytes().to_vec());
160
161 buff.push(0);
162
163 self.send_blk(dev, &buff, 0, false)
164 }
165
166 fn send_blk<D: Write + Read>(
167 &mut self,
168 dev: &mut D,
169 data: &[u8],
170 pad: u8,
171 last: bool,
172 ) -> Result<()> {
173 let len;
174 let p;
175
176 if data.len() > 128 {
177 len = 1024;
178 p = STX;
179 } else {
180 len = 128;
181 p = SOH;
182 }
183 let blk = if last { 0 } else { self.blk };
184 let mut err = None;
185 loop {
186 if self.retries == 0 {
187 return Err(err.unwrap_or(Error::new(ErrorKind::BrokenPipe, "retry too much")));
188 }
189
190 dev.write_all(&[p, blk, !blk])?;
191
192 let mut buf = vec![pad; len];
193 buf[..data.len()].copy_from_slice(data);
194
195 dev.write_all(&buf)?;
196
197 if self.crc_mode {
198 let chsum = crc16_ccitt(0, &buf);
199 let crc1 = (chsum >> 8) as u8;
200 let crc2 = (chsum & 0xff) as u8;
201
202 dev.write_all(&[crc1, crc2])?;
203 }
204 dev.flush()?;
205
206 match self.wait_ack(dev) {
207 Ok(_) => break,
208 Err(e) => {
209 err = Some(e);
210 self.retries -= 1;
211 }
212 }
213 }
214
215 if self.blk == u8::MAX {
216 self.blk = 0;
217 } else {
218 self.blk += 1;
219 }
220
221 Ok(())
222 }
223}