use nix::fcntl::OFlag; use nix::sys::termios; use nix::Error; use std::io; use std::os::unix::io::{AsRawFd, RawFd}; pub struct SerialPort { fd: RawFd, } impl SerialPort { pub fn new<'a, P: ?Sized + nix::NixPath>( path: &P, baudrate: termios::BaudRate, ) -> io::Result { let fd = nix::fcntl::open( path, OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, nix::sys::stat::Mode::empty(), ) .map_err(to_io_error)?; let mut cfg = termios::tcgetattr(fd).map_err(to_io_error)?; cfg.input_flags = termios::InputFlags::empty(); cfg.output_flags = termios::OutputFlags::empty(); cfg.control_flags = termios::ControlFlags::empty(); cfg.local_flags = termios::LocalFlags::empty(); termios::cfmakeraw(&mut cfg); cfg.input_flags |= termios::InputFlags::IGNBRK; cfg.control_flags |= termios::ControlFlags::CREAD; //cfg.control_flags |= termios::ControlFlags::CRTSCTS; termios::cfsetospeed(&mut cfg, baudrate).map_err(to_io_error)?; termios::cfsetispeed(&mut cfg, baudrate).map_err(to_io_error)?; termios::cfsetspeed(&mut cfg, baudrate).map_err(to_io_error)?; // Set VMIN = 1 to block until at least one character is received. cfg.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; termios::tcsetattr(fd, termios::SetArg::TCSANOW, &cfg).map_err(to_io_error)?; termios::tcflush(fd, termios::FlushArg::TCIOFLUSH).map_err(to_io_error)?; Ok(Self { fd }) } } impl AsRawFd for SerialPort { fn as_raw_fd(&self) -> RawFd { self.fd } } impl io::Read for SerialPort { fn read(&mut self, buf: &mut [u8]) -> io::Result { nix::unistd::read(self.fd, buf).map_err(to_io_error) } } impl io::Write for SerialPort { fn write(&mut self, buf: &[u8]) -> io::Result { nix::unistd::write(self.fd, buf).map_err(to_io_error) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } fn to_io_error(e: Error) -> io::Error { match e { Error::Sys(errno) => errno.into(), e => io::Error::new(io::ErrorKind::InvalidInput, e), } }