Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/posix/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,40 @@ use crate::{
SerialPortBuilder, StopBits,
};

/// Read mode enumeration.
///
/// The documentation is strongly based on [this documentation](http://www.unixwiz.net/techtips/termios-vmin-vtime.html).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReadMode {
/// If data are available in the input queue, it's transferred to the caller's buffer up to a
/// maximum of nbytes, and returned immediately to the caller. Otherwise the driver blocks
/// until data arrives, or when VTIME tenths expire from the start of the call. If the timer
/// expires without data, zero is returned. A single byte is sufficient to satisfy this read
/// call, but if more is available in the input queue, it's returned to the caller.
TimedRead { timeout: u8 },
/// This is a counted read that is satisfied only when at least VMIN characters have been
/// transferred to the caller's buffer - there is no timing component involved. This read can
/// be satisfied from the driver's input queue (where the call could return immediately), or
/// by waiting for new data to arrive: in this respect the call could block indefinitely.
BlockUntilMinRead { minimal_bytes: u8 },
/// Read calls are satisfied when either VMIN characters have been transferred to the caller's
/// buffer, or when VTIME tenths expire between characters. Since this timer is not started
/// until the first character arrives, this call can block indefinitely if the serial line is
/// idle. This is the most common mode of operation, and we consider VTIME to be an
/// intercharacter timeout, not an overall one. This call should never return zero bytes read.
Blocking {
/// VTIME value in tenths of a second.
inter_byte_timeout: u8,
minimal_bytes: u8,
},
/// This is a completely non-blocking read - the call is satisfied immediately directly from
/// the driver's input queue. If data are available, it's transferred to the caller's buffer up
/// to nbytes and returned. Otherwise zero is immediately returned to indicate "no data".
/// This essentially polls the serial port and should be used with care. If done
/// repeatedly, it can consume enormous amounts of processor time and is highly inefficient.
Immediate,
}

/// Convenience method for removing exclusive access from
/// a fd and closing it.
fn close(fd: RawFd) {
Expand Down Expand Up @@ -352,6 +386,31 @@ impl TTYPort {
.map_err(|e| e.into())
}

/// Set the VMIN and VTIME attributes of the port which determine the behavior
/// of the port on read calls.
///
/// See [this documentation](http://www.unixwiz.net/techtips/termios-vmin-vtime.html) for
/// more details.
pub fn set_vmin_vtime(&mut self, vmin: u8, vtime: u8) -> Result<()> {
let mut termios = termios::get_termios(self.fd)?;
termios.c_cc[nix::sys::termios::SpecialCharacterIndices::VMIN as usize] = vmin;
termios.c_cc[nix::sys::termios::SpecialCharacterIndices::VTIME as usize] = vtime;
termios::set_termios(self.fd, &termios)
}

/// Set the TTY port read mode which configures the VMIN and VTIME parameters.
pub fn set_read_mode(&mut self, read_mode: ReadMode) -> Result<()> {
match read_mode {
ReadMode::TimedRead { timeout } => self.set_vmin_vtime(0, timeout),
ReadMode::BlockUntilMinRead { minimal_bytes } => self.set_vmin_vtime(minimal_bytes, 0),
ReadMode::Blocking {
inter_byte_timeout,
minimal_bytes,
} => self.set_vmin_vtime(minimal_bytes, inter_byte_timeout),
ReadMode::Immediate => self.set_vmin_vtime(0, 0),
}
}

/// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the
/// same serial connection. Please note that if you want a real asynchronous serial port you
/// should look at [mio-serial](https://crates.io/crates/mio-serial) or
Expand Down