Howdy. I'm having difficulty opening a serial port with Rust on Linux where I'm also attempting to specify a timeout on reads (VTIME). My reads block indefinitely whereas I'm expecting them to return after one sceond.
I realise I could use the serialport-rs project, but it is bothering me that I can't read with a timeout in a similar fashion to how I'd go about it in C. Admittedly, it could be non-Rust related, but I'm trying to follow the giudelines on this. Here's my code for establishing the serial port connection:
let fd = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(libc::O_NOCTTY | libc::O_NDELAY) // UPDATE: Makes no diff if O_NDELAY is specified
.open(uart_path)?;
let r = unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFL, 0) };
if r < 0 {
return Err(io::Error::last_os_error().into());
}
let mut tty = termios::tcgetattr(fd.as_raw_fd()).unwrap();
termios::cfmakeraw(&mut tty);
termios::cfsetispeed(&mut tty, BaudRate::B115200).unwrap();
termios::cfsetospeed(&mut tty, BaudRate::B115200).unwrap();
tty.control_flags.set(ControlFlags::CREAD, true);
tty.control_flags.set(ControlFlags::CLOCAL, true);
tty.control_flags.set(ControlFlags::CSTOPB, false);
tty.control_flags.set(ControlFlags::CRTSCTS, false);
tty.control_chars[libc::VMIN] = MIN_PACKET_SIZE as u8;
tty.control_chars[libc::VTIME] = 10;
termios::tcsetattr(fd.as_raw_fd(), SetArg::TCSANOW, &tty).unwrap();
This method allows you to tell the serial driver you need exactly N bytes and any read call will return 0 or N bytes. However, the timeout only applies to the first character read, so if for some reason the driver misses one character inside the N byte packet then the read call could block forever waiting for additional input characters.
I'm actually now beginning to think that the problem is with my target being mipsel-unknown-linux-musl. There's an old issue with nix-rust that makes me suspicious, plus no explicit Tier 1 support from the project's README.
I also notice that the Baud enum is being cast to a u32, which is bad because B115200 won't have the right value. I might try the rustix crate as it is lists support for my target, or perhaps just use serialport-rs as I'm now appreciating why.