diff --git a/src/posix/termios.rs b/src/posix/termios.rs index 2ff9f152..fbaee993 100644 --- a/src/posix/termios.rs +++ b/src/posix/termios.rs @@ -100,7 +100,13 @@ pub(crate) fn get_termios(fd: RawFd) -> Result { pub(crate) fn set_termios(fd: RawFd, termios: &libc::termios, baud_rate: u32) -> Result<()> { let res = unsafe { libc::tcsetattr(fd, libc::TCSANOW, termios) }; nix::errno::Errno::result(res)?; - crate::posix::ioctl::iossiospeed(fd, &(baud_rate as libc::speed_t))?; + + // Note: attempting to set the baud rate on a pseudo terminal via this ioctl call will faill + // with the `ENOTTY` error. + if baud_rate > 0 { + crate::posix::ioctl::iossiospeed(fd, &(baud_rate as libc::speed_t))?; + } + Ok(()) } diff --git a/src/posix/tty.rs b/src/posix/tty.rs index 0d3a1879..f97a065b 100644 --- a/src/posix/tty.rs +++ b/src/posix/tty.rs @@ -37,6 +37,21 @@ fn close(fd: RawFd) { /// should not be instantiated directly by using `TTYPort::open()`, instead use /// the cross-platform `serialport::open()` or /// `serialport::open_with_settings()`. +/// +/// Note: on macOS, when connecting to a pseudo-terminal (`pty` opened via +/// `posix_openpt`), the `baud_rate` should be set to 0; this will be used to +/// explicitly _skip_ an attempt to set the baud rate of the file descriptor +/// that would otherwise happen via an `ioctl` command. +/// +/// ``` +/// use serialport::{TTYPort, SerialPort}; +/// +/// let (mut master, slave) = TTYPort::pair().expect("Unable to create ptty pair"); +/// +/// // ... elsewhere +/// +/// let mut port = TTYPort::open(&serialport::new(slave.name().unwrap(), 0)).expect("unable to open"); +/// ``` #[derive(Debug)] pub struct TTYPort { fd: RawFd, diff --git a/tests/test_tty.rs b/tests/test_tty.rs index fc76ef05..d7772ca5 100644 --- a/tests/test_tty.rs +++ b/tests/test_tty.rs @@ -90,6 +90,29 @@ fn test_ttyport_timeout() { } } +#[test] +#[cfg(any(target_os = "ios", target_os = "macos"))] +fn test_osx_pty_pair() { + #![allow(unused_variables)] + let (mut master, slave) = TTYPort::pair().expect("Unable to create ptty pair"); + let (output_sink, output_stream) = std::sync::mpsc::sync_channel(1); + let name = slave.name().unwrap(); + + master.write("12".as_bytes()).expect(""); + + let reader_thread = std::thread::spawn(move || { + let mut port = TTYPort::open(&serialport::new(&name, 0)).expect("unable to open"); + let mut buffer = [0u8; 2]; + let amount = port.read_exact(&mut buffer); + output_sink + .send(String::from_utf8(buffer.to_vec()).expect("buffer not read as valid utf-8")) + .expect("unable to send from thread"); + }); + + reader_thread.join().expect("unable to join sink thread"); + assert_eq!(output_stream.recv().unwrap(), "12"); +} + // On Mac this should work (in fact used to in b77768a) but now fails. It's not functionality that // should be required, and the ptys work otherwise. So going to just diable this test instead. #[test]