diff --git a/src/serial.rs b/src/serial.rs index 8eb0b17f54c8caa5b78421772b44ee17634e9dd3..f6e107fa8f67aff657205fddd2d1ee72804799c1 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -6,7 +6,7 @@ use std::{ Arc, }, thread::{self, JoinHandle}, - time::Duration, + time::{Duration, Instant}, }; use hashbrown::HashMap; @@ -26,6 +26,8 @@ struct SerialQueue { _handle: JoinHandle<()>, sender: Sender<Vec<u8>>, serial: Arc<Mutex<Box<dyn SerialPort>>>, + /// this the timeout after which it returns a timeout error + read_timeout: Duration, } impl SerialManager { @@ -60,13 +62,20 @@ impl SerialManager { let port = map.get(name).ok_or(Error::SerialNotOpen)?; let mut buf = vec![0; n]; // implement a read exact to allow better error messages - let mut reader = port.lock(); let mut filled = 0; + let start = Instant::now(); while filled < n { + let mut reader = port.lock(); match reader.read(&mut buf[filled..]) { Ok(n) => filled += n, Err(e) => match e.kind() { std::io::ErrorKind::TimedOut => { + // if timeout hasn't been reached yet + if start.elapsed() < port.read_timeout { + continue; // this triggers a waiting mutex on the writing side + } + + // otherwise if filled == 0 { return Err(Error::NoDataAvailable); } @@ -103,9 +112,10 @@ impl SerialQueue { /// Open the serial port and start a thread to write data as soon as it is /// available (by using a channel) fn open(port: &str, baudrate: u32) -> SResult<Self> { + let read_waiting_interval = Duration::from_millis(50); let serial = Arc::new(Mutex::new( serialport::new(port, baudrate) - .timeout(Duration::from_millis(1000)) + .timeout(read_waiting_interval) .open()?, )); let (tx, rx) = channel::<Vec<u8>>(); @@ -119,6 +129,7 @@ impl SerialQueue { _handle, sender: tx, serial, + read_timeout: Duration::from_millis(1000), }) }