diff --git a/Cargo.toml b/Cargo.toml index bbab6d9..2147186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" description = "An implementation of the XMODEM file-transfer protocol." [dependencies] -log = "^0.3" +log = "^0.4.17" crc16 = "^0.3" [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 1860609..9504479 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,8 @@ extern crate log; extern crate crc16; -use std::io::{self, Read, Write}; use std::convert::From; +use std::io::{self, Read, Write}; // TODO: Send CAN byte after too many errors // TODO: Handle CAN bytes while sending @@ -95,11 +95,11 @@ impl Xmodem { self.errors = 0; debug!("Starting XMODEM transfer"); - try!(self.start_send(dev)); - debug!("First byte received. Sending stream."); - try!(self.send_stream(dev, stream)); + self.start_send(dev)?; + info!("First byte received. Sending stream."); + self.send_stream(dev, stream)?; debug!("Sending EOT"); - try!(self.finish_send(dev)); + self.finish_send(dev)?; Ok(()) } @@ -116,121 +116,134 @@ impl Xmodem { /// to set the timeout of the device before calling this method. Timeouts on receiving /// bytes will be counted against `max_errors`, but timeouts on transmitting bytes /// will be considered a fatal error. - pub fn recv(&mut self, - dev: &mut D, - outstream: &mut W, - checksum : Checksum) -> Result<()> { + pub fn recv( + &mut self, + dev: &mut D, + outstream: &mut W, + checksum: Checksum, + ) -> Result<()> { self.errors = 0; self.checksum_mode = checksum; let ncg = match self.checksum_mode { Checksum::Standard => NAK, - Checksum::CRC16 => CRC }; + Checksum::CRC16 => CRC, + }; debug!("Starting XMODEM receive"); - try!(dev.write(&[ncg])); + // FIXME: handle written amount + let _ = dev.write(&[ncg])?; debug!("NCG sent. Receiving stream."); - let mut packet_num : u8 = 1; + let mut packet_num: u8 = 1; loop { - match try!(get_byte_timeout(dev)) { - bt @ Some(SOH) | bt @ Some(STX) => { // Handle next packet + match get_byte_timeout(dev)? { + bt @ Some(SOH) | bt @ Some(STX) => { + // Handle next packet let data_size = match bt { Some(SOH) => 128, Some(STX) => 1024, _ => 0, // Why does the compiler need this? }; - let mut data : Vec = Vec::new(); + let mut data: Vec = Vec::new(); let packet_size = data_size + 2 + match self.checksum_mode { Checksum::Standard => 1, Checksum::CRC16 => 2, }; - data.resize(packet_size,0); + data.resize(packet_size, 0); match dev.read_exact(&mut data) { Ok(_) => { // Check packet number let pnum = data[0]; let pnum_1c = data[1]; - if (packet_num != pnum) || (255-pnum != pnum_1c) { + if (packet_num != pnum) || (255 - pnum != pnum_1c) { // We've lost data; cancel this transmission warn!("Cancelling transmission."); - try!(dev.write(&[CAN])); - try!(dev.write(&[CAN])); - return Err(Error::Canceled) + let n = dev.write(&[CAN])?; + debug!("CAN sent, {n} bytes"); + let n = dev.write(&[CAN])?; + debug!("CAN sent, {n} bytes"); + return Err(Error::Canceled); } // Check checksum let check_ok = match self.checksum_mode { Checksum::Standard => { - let recv_checksum = data[packet_size-1]; - calc_checksum(&data[2..packet_size-1]) == recv_checksum }, + let recv_checksum = data[packet_size - 1]; + calc_checksum(&data[2..packet_size - 1]) == recv_checksum + } Checksum::CRC16 => { - let recv_checksum = - ((data[packet_size-2] as u16) << 8) + - (data[packet_size-1] as u16); - calc_crc(&data[2..packet_size-2]) == recv_checksum }, + let recv_checksum = ((data[packet_size - 2] as u16) << 8) + + (data[packet_size - 1] as u16); + calc_crc(&data[2..packet_size - 2]) == recv_checksum + } }; // Response if check_ok { packet_num = packet_num.wrapping_add(1); - try!(dev.write(&[ACK])); - try!(outstream.write_all(&data[2..data_size+2])); + let n = dev.write(&[ACK])?; + debug!("ACK sent, {n} bytes"); + outstream.write_all(&data[2..data_size + 2])?; } else { info!("Packet failed."); - try!(dev.write(&[NAK])); + let n = dev.write(&[NAK])?; + debug!("NAK sent, {n} bytes"); self.errors += 1; } - }, + } Err(e) => { - error!("Error is {}",e); + error!("Error is {}", e); // Timeout self.errors += 1; warn!("Timeout in packet! Resending NAK."); - try!(dev.write(&[NAK])); - }, + let _ = dev.write(&[NAK])?; + } } - }, - Some(EOT) => { // End of file - try!(dev.write(&[ACK])); - break - }, + } + Some(EOT) => { + // End of file + let _ = dev.write(&[ACK])?; + break; + } Some(x) => { - warn!("Unrecognized symbol {:X}!",x); - }, + warn!("Unrecognized symbol {:X}!", x); + } None => { self.errors += 1; warn!("Timeout! Resending NAK."); - try!(dev.write(&[NAK])); - }, + let _ = dev.write(&[NAK])?; + } } if self.errors >= self.max_errors { - error!("Exhausted max retries ({}) while waiting for ACK for EOT", self.max_errors); + error!( + "Exhausted max retries ({}) while waiting for ACK for EOT", + self.max_errors + ); return Err(Error::ExhaustedRetries); } } Ok(()) } - + fn start_send(&mut self, dev: &mut D) -> Result<()> { let mut cancels = 0u32; loop { - match try!(get_byte_timeout(dev)) { - Some(c) => { - match c { - NAK => { - debug!("Standard checksum requested"); - self.checksum_mode = Checksum::Standard; - return Ok(()); - } - CRC => { - debug!("16-bit CRC requested"); - self.checksum_mode = Checksum::CRC16; - return Ok(()); - } - CAN => { - warn!("Cancel (CAN) byte received"); - cancels += 1; - }, - c => warn!("Unknown byte received at start of XMODEM transfer: {}", c), + debug!("Send..."); + match get_byte_timeout(dev)? { + Some(c) => match c { + NAK => { + debug!("Standard checksum requested"); + self.checksum_mode = Checksum::Standard; + return Ok(()); } + CRC => { + debug!("16-bit CRC requested"); + self.checksum_mode = Checksum::CRC16; + return Ok(()); + } + CAN => { + warn!("Cancel (CAN) byte received"); + cancels += 1; + } + b => warn!("Unknown byte received at start of XMODEM transfer: {b:x}",), }, None => warn!("Timed out waiting for start of XMODEM transfer."), } @@ -238,13 +251,18 @@ impl Xmodem { self.errors += 1; if cancels >= 2 { - error!("Transmission canceled: received two cancel (CAN) bytes \ - at start of XMODEM transfer"); + error!( + "Transmission canceled: received two cancel (CAN) bytes \ + at start of XMODEM transfer" + ); return Err(Error::Canceled); } if self.errors >= self.max_errors { - error!("Exhausted max retries ({}) at start of XMODEM transfer.", self.max_errors); + error!( + "Exhausted max retries ({}) at start of XMODEM transfer.", + self.max_errors + ); if let Err(err) = dev.write_all(&[CAN]) { warn!("Error sending CAN byte: {}", err); } @@ -257,7 +275,7 @@ impl Xmodem { let mut block_num = 0u32; loop { let mut buff = vec![self.pad_byte; self.block_length as usize + 3]; - let n = try!(stream.read(&mut buff[3..])); + let n = stream.read(&mut buff[3..])?; if n == 0 { debug!("Reached EOF"); return Ok(()); @@ -275,7 +293,7 @@ impl Xmodem { Checksum::Standard => { let checksum = calc_checksum(&buff[3..]); buff.push(checksum); - }, + } Checksum::CRC16 => { let crc = calc_crc(&buff[3..]); buff.push(((crc >> 8) & 0xFF) as u8); @@ -283,27 +301,41 @@ impl Xmodem { } } - debug!("Sending block {}", block_num); - try!(dev.write_all(&buff)); + info!("Sending block {block_num}"); + dev.write_all(&buff)?; - match try!(get_byte_timeout(dev)) { + match get_byte_timeout(dev)? { Some(c) => { - if c == ACK { - debug!("Received ACK for block {}", block_num); - continue - } else { - warn!("Expected ACK, got {}", c); + match c { + ACK => { + debug!("Received ACK for block {block_num}"); + continue; + } + NAK => { + error!("Received NAK for block {block_num} :("); + } + CAN => { + // TODO handle CAN bytes + warn!("Received CAN for block {block_num}, currently unhandled"); + } + b'C' => { + warn!("Expected ACK, got C..."); + } + b => { + warn!("Expected ACK, got 0x{b:x}"); + } } - // TODO handle CAN bytes - }, + } None => warn!("Timeout waiting for ACK for block {}", block_num), } self.errors += 1; if self.errors >= self.max_errors { - error!("Exhausted max retries ({}) while sending block {} in XMODEM transfer", - self.max_errors, block_num); + error!( + "Exhausted max retries ({}) while sending block {} in XMODEM transfer", + self.max_errors, block_num + ); return Err(Error::ExhaustedRetries); } } @@ -311,15 +343,19 @@ impl Xmodem { fn finish_send(&mut self, dev: &mut D) -> Result<()> { loop { - try!(dev.write_all(&[EOT])); + dev.write_all(&[EOT])?; - match try!(get_byte_timeout(dev)) { - Some(c) => { - if c == ACK { + match get_byte_timeout(dev)? { + Some(c) => match c { + ACK => { info!("XMODEM transmission successful"); return Ok(()); - } else { - warn!("Expected ACK, got {}", c); + } + NAK => { + error!("Received NAK, transfer error :("); + } + b => { + warn!("Expected ACK, got {b:x}, transfer error"); } }, None => warn!("Timeout waiting for ACK for EOT"), @@ -328,7 +364,10 @@ impl Xmodem { self.errors += 1; if self.errors >= self.max_errors { - error!("Exhausted max retries ({}) while waiting for ACK for EOT", self.max_errors); + error!( + "Exhausted max retries ({}) while waiting for ACK for EOT", + self.max_errors + ); return Err(Error::ExhaustedRetries); } } @@ -345,15 +384,21 @@ fn calc_crc(data: &[u8]) -> u16 { fn get_byte(reader: &mut R) -> std::io::Result { let mut buff = [0]; - try!(reader.read_exact(&mut buff)); + trace!("Read a byte..."); + reader.read_exact(&mut buff)?; Ok(buff[0]) } /// Turns timeout errors into `Ok(None)` fn get_byte_timeout(reader: &mut R) -> std::io::Result> { + trace!("Get a byte..."); match get_byte(reader) { - Ok(c) => Ok(Some(c)), + Ok(c) => { + trace!("Got a byte."); + Ok(Some(c)) + } Err(err) => { + trace!("Got no byte."); if err.kind() == io::ErrorKind::TimedOut { Ok(None) } else {