diff --git a/src/error.rs b/src/error.rs index c6f8e9b5e6fd247d708b39c3a34ba681e5b03b13..f9b35dbb2f6ce76638ccd50e15b2de6fd3e20ce2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -86,6 +86,13 @@ pub enum Error { SerialPort(#[from] serialport::Error), #[error("I/O error: {0}")] IO(#[from] std::io::Error), + #[error("No data available to read from serial (or timeout too short)")] + NoDataAvailable, + #[error("Incomplete read: {amount_read} bytes read. {inner}")] + IncompleteRead { + amount_read: usize, + inner: Box<Self>, + }, #[error("Channel error: {0}")] Channel(#[from] std::sync::mpsc::SendError<Vec<u8>>), #[error("Parse error")] @@ -121,6 +128,8 @@ impl Error { Error::InvalidWriteData(_) => "serialbridge:invalid_input", Error::SerialPort(_) => "serialbridge:serial_error", Error::IO(_) => "serialbridge:serial_error", + Error::NoDataAvailable => "serialbridge:serial_error", + Error::IncompleteRead { .. } => "serialbridge:serial_error", Error::Channel(_) => "serialbridge:channel_error", Error::Parse => "serialbridge:parse_error", Error::Matlab(_) => "serialbridge:matlab_error", diff --git a/src/lib.rs b/src/lib.rs index 2e2dd29ac4c0d5eee99f4753034f5b9abbacb2d6..4ef314a031cc163ef7c193d75002815b9e84d20d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,15 +146,20 @@ fn read_from_serial(mut outputs: Output<'_>, args: Args<'_>) -> SResult<()> { Error::InvalidMatlabType("do not use decimal units, use a positive integer".into()), ))); } - let n_doubles = arg as usize; + let n_singles = arg as usize; // Read n_doubles from the serial port - let bytes = SERIAL.read().read_n_bytes(&port, n_doubles * 4)?; + let n_bytes = n_singles * 4; + let bytes = SERIAL.read().read_n_bytes(&port, n_bytes)?; let doubles = bytes .chunks_exact(4) .map(|chunk| f32::from_be_bytes(chunk.try_into().unwrap())) .collect::<Vec<f32>>(); - warn_debug!("Read {} bytes from serial port", n_doubles); + warn_debug!( + "Read {} ({} singles) bytes from serial port", + n_bytes, + n_singles + ); outputs.set(doubles.to_vec())?; Ok(()) diff --git a/src/serial.rs b/src/serial.rs index 731be06a7bab7ae620bec11d3498e4d7757d0001..95d08c250cc8b7ddd939c513a42960b475d17e04 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -59,7 +59,26 @@ impl SerialManager { let map = self.serial_map.read(); let port = map.get(name).ok_or(Error::SerialNotOpen)?; let mut buf = vec![0; n]; - port.lock().read_exact(&mut buf)?; + // implement a read exact to allow better error messages + let mut reader = port.lock(); + let mut filled = 0; + while filled < n { + match reader.read(&mut buf[filled..]) { + Ok(n) => filled += n, + Err(e) => match e.kind() { + std::io::ErrorKind::TimedOut => { + if filled == 0 { + return Err(Error::NoDataAvailable); + } + return Err(Error::IncompleteRead { + amount_read: filled, + inner: Box::new(Error::NoDataAvailable), + }); + } + _ => return Err(e.into()), + }, + } + } Ok(buf) } diff --git a/src/types.rs b/src/types.rs index c2e78b2b3479d490edf5e0ccdbc17dc3ecb3d2dd..97fca4f661d40606d0e9bac8636660938060a5dc 100644 --- a/src/types.rs +++ b/src/types.rs @@ -16,7 +16,9 @@ pub trait IntoRustType<T> { impl IntoRustType<CString> for MxArray { fn into_rust(self) -> SResult<CString> { Ok(CharArray::from_mx_array(self) - .mexerr(Error::InvalidMatlabType("use a string instead".into()))? + .mexerr(Error::InvalidMatlabType( + "use a char array instead ('value')".into(), + ))? .get_cstring()) } } @@ -32,7 +34,7 @@ impl IntoRustType<f64> for MxArray { fn into_rust(self) -> SResult<f64> { let out = Numeric::<f64, _>::from_mx_array(self) .mexerr(Error::InvalidMatlabType( - "use a numerical type instead".into(), + "use a double numerical type instead".into(), ))? .data() .first() @@ -58,7 +60,7 @@ impl IntoRustType<Vec<f32>> for MxArray { fn into_rust(self) -> SResult<Vec<f32>> { let out = Numeric::<f32, _>::from_mx_array(self) .mexerr(Error::InvalidMatlabType( - "use a numerical type instead".into(), + "use an array of singles (floats) type instead".into(), ))? .data() .to_owned(); @@ -70,7 +72,7 @@ impl IntoRustType<Vec<f64>> for MxArray { fn into_rust(self) -> SResult<Vec<f64>> { let out = Numeric::<f64, _>::from_mx_array(self) .mexerr(Error::InvalidMatlabType( - "use a numerical type instead".into(), + "use an array of doubles type instead".into(), ))? .data() .to_owned();