serial-unix-0.4.0/Cargo.toml01006440000765000002400000002231131260451060014116 0ustar0000000000000000# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "serial-unix" version = "0.4.0" authors = ["David Cuddeback "] description = "Serial port implementation for Unix." homepage = "https://github.com/dcuddeback/serial-rs" documentation = "https://dcuddeback.github.io/serial-rs/serial-unix/" readme = "README.md" keywords = ["serial", "hardware", "system", "RS232"] categories = ["hardware-support", "os", "os::unix-apis"] license = "MIT" repository = "https://github.com/dcuddeback/serial-rs" [dependencies.ioctl-rs] version = "0.1.5" [dependencies.libc] version = "0.2.1" [dependencies.serial-core] version = "0.4" [dependencies.termios] version = "0.2.2" serial-unix-0.4.0/Cargo.toml.orig01006440000765000002400000001144131260451060015057 0ustar0000000000000000[package] name = "serial-unix" version = "0.4.0" authors = ["David Cuddeback "] description = "Serial port implementation for Unix." homepage = "https://github.com/dcuddeback/serial-rs" repository = "https://github.com/dcuddeback/serial-rs" documentation = "https://dcuddeback.github.io/serial-rs/serial-unix/" license = "MIT" readme = "README.md" keywords = ["serial", "hardware", "system", "RS232"] categories = ["hardware-support", "os", "os::unix-apis"] [dependencies] serial-core = { version = "0.4", path = "../serial-core" } libc = "0.2.1" termios = "0.2.2" ioctl-rs = "0.1.5" serial-unix-0.4.0/examples/poll.rs01006440000765000002400000001410131260451060015316 0ustar0000000000000000extern crate serial_unix; extern crate libc; use std::io; use std::path::Path; use std::io::prelude::*; use std::os::unix::prelude::*; fn main() { let mut port = serial_unix::TTYPort::open(Path::new("/dev/ttyUSB0")).unwrap(); let mut fds = vec![libc::pollfd { fd: port.as_raw_fd(), events: libc::POLLIN, revents: 0, }]; loop { let retval = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::nfds_t, 100) }; if retval < 0 { panic!("{:?}", io::Error::last_os_error()); } if retval > 0 && fds[0].revents & libc::POLLIN != 0 { let mut buffer = Vec::::new(); port.read_to_end(&mut buffer).unwrap(); println!("{:?}", buffer); } } } serial-unix-0.4.0/LICENSE01006440000765000002400000002043127073112130013173 0ustar0000000000000000Copyright (c) 2015 David Cuddeback Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serial-unix-0.4.0/README.md01006440000765000002400000002103131260451060013443 0ustar0000000000000000# Unix Serial Ports The `serial-unix` crate provides a serial port implementation for Unix operating systems. * [Documentation](http://dcuddeback.github.io/serial-rs/serial_unix/) ## Compatibility The `serial-unix` crate is compatible with any Unix operating system that implements the termios API. The following platforms are confirmed to be compatible: * Linux (x86_64, armv6l) * OS X (x86_64) * FreeBSD (amd64) * OpenBSD (amd64) ## Usage In general, one shouldn't need to use the `serial-unix` library directly. The implementation provided by `serial-unix` is also exposed through a cross-platform API in the [`serial` crate](../serial/). The serial port type defined in `serial-unix` works with any Unix TTY device. In addition to implementing the standard serial port traits, it also implements `std::os::unix::io::AsRawFd`, which can be used for integrating with other I/O libraries. See [`examples/poll.rs`](examples/poll.rs) for an example of using `AsRawFd` for event-driven I/O. ## License Copyright © 2015 David Cuddeback Distributed under the [MIT License](LICENSE). serial-unix-0.4.0/src/error.rs01006440000765000002400000005566131260451060014472 0ustar0000000000000000use core; use std::error::Error; use std::ffi::CStr; use std::io; use std::str; use libc::{c_int, c_char, size_t}; pub fn last_os_error() -> core::Error { from_raw_os_error(errno()) } pub fn from_raw_os_error(errno: i32) -> core::Error { use libc::{EBUSY, EISDIR, ELOOP, ENOTDIR, ENOENT, ENODEV, ENXIO, EACCES, EINVAL, ENAMETOOLONG, EINTR, EWOULDBLOCK}; let kind = match errno { EBUSY | EISDIR | ELOOP | ENOTDIR | ENOENT | ENODEV | ENXIO | EACCES => core::ErrorKind::NoDevice, EINVAL | ENAMETOOLONG => core::ErrorKind::InvalidInput, EINTR => core::ErrorKind::Io(io::ErrorKind::Interrupted), EWOULDBLOCK => core::ErrorKind::Io(io::ErrorKind::WouldBlock), _ => core::ErrorKind::Io(io::ErrorKind::Other), }; core::Error::new(kind, error_string(errno)) } pub fn from_io_error(io_error: io::Error) -> core::Error { match io_error.raw_os_error() { Some(errno) => from_raw_os_error(errno), None => { let description = io_error.description().to_string(); core::Error::new(core::ErrorKind::Io(io_error.kind()), description) } } } // the rest of this module is borrowed from libstd const TMPBUF_SZ: usize = 128; pub fn errno() -> i32 { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] unsafe fn errno_location() -> *const c_int { extern { fn __error() -> *const c_int; } __error() } #[cfg(target_os = "bitrig")] fn errno_location() -> *const c_int { extern { fn __errno() -> *const c_int; } unsafe { __errno() } } #[cfg(target_os = "dragonfly")] unsafe fn errno_location() -> *const c_int { extern { fn __dfly_error() -> *const c_int; } __dfly_error() } #[cfg(target_os = "openbsd")] unsafe fn errno_location() -> *const c_int { extern { fn __errno() -> *const c_int; } __errno() } #[cfg(any(target_os = "linux", target_os = "android"))] unsafe fn errno_location() -> *const c_int { extern { fn __errno_location() -> *const c_int; } __errno_location() } unsafe { (*errno_location()) as i32 } } pub fn error_string(errno: i32) -> String { #[cfg(target_os = "linux")] extern { #[link_name = "__xpg_strerror_r"] fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; } #[cfg(not(target_os = "linux"))] extern { fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; } let mut buf = [0 as c_char; TMPBUF_SZ]; let p = buf.as_mut_ptr(); unsafe { if strerror_r(errno as c_int, p, buf.len() as size_t) < 0 { panic!("strerror_r failure"); } let p = p as *const _; str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string() } } serial-unix-0.4.0/src/lib.rs01006440000765000002400000000327131260451060014075 0ustar0000000000000000//! Serial port implementation for Unix operating systems. extern crate serial_core as core; extern crate libc; extern crate termios; extern crate ioctl_rs as ioctl; pub use tty::*; mod error; mod poll; mod tty; serial-unix-0.4.0/src/poll.rs01006440000765000002400000005356131260451060014304 0ustar0000000000000000#![allow(non_camel_case_types,dead_code)] use libc; use std::io; use std::time::Duration; use libc::{c_int, c_short}; #[cfg(target_os = "linux")] type nfds_t = libc::c_ulong; #[cfg(not(target_os = "linux"))] type nfds_t = libc::c_uint; #[derive(Debug)] #[repr(C)] struct pollfd { fd: c_int, events: c_short, revents: c_short, } const POLLIN: c_short = 0x0001; const POLLPRI: c_short = 0x0002; const POLLOUT: c_short = 0x0004; const POLLERR: c_short = 0x0008; const POLLHUP: c_short = 0x0010; const POLLNVAL: c_short = 0x0020; pub fn wait_read_fd(fd: c_int, timeout: Duration) -> io::Result<()> { wait_fd(fd, POLLIN, timeout) } pub fn wait_write_fd(fd: c_int, timeout: Duration) -> io::Result<()> { wait_fd(fd, POLLOUT, timeout) } fn wait_fd(fd: c_int, events: c_short, timeout: Duration) -> io::Result<()> { use libc::{EINTR, EPIPE, EIO}; let mut fds = vec!(pollfd { fd: fd, events: events, revents: 0 }); let wait = do_poll(&mut fds, timeout); if wait < 0 { let errno = super::error::errno(); let kind = match errno { EINTR => io::ErrorKind::Interrupted, _ => io::ErrorKind::Other, }; return Err(io::Error::new(kind, super::error::error_string(errno))); } if wait == 0 { return Err(io::Error::new(io::ErrorKind::TimedOut, "Operation timed out")); } if fds[0].revents & events != 0 { return Ok(()); } if fds[0].revents & (POLLHUP | POLLNVAL) != 0 { return Err(io::Error::new(io::ErrorKind::BrokenPipe, super::error::error_string(EPIPE))); } Err(io::Error::new(io::ErrorKind::Other, super::error::error_string(EIO))) } #[cfg(target_os = "linux")] #[inline] fn do_poll(fds: &mut Vec, timeout: Duration) -> c_int { use std::ptr; use libc::c_void; #[repr(C)] struct sigset_t { __private: c_void, } extern "C" { fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout_ts: *mut libc::timespec, sigmask: *const sigset_t) -> c_int; } let mut timeout_ts = libc::timespec { tv_sec: timeout.as_secs() as libc::time_t, tv_nsec: timeout.subsec_nanos() as libc::c_long, }; unsafe { ppoll((&mut fds[..]).as_mut_ptr(), fds.len() as nfds_t, &mut timeout_ts, ptr::null()) } } #[cfg(not(target_os = "linux"))] #[inline] fn do_poll(fds: &mut Vec, timeout: Duration) -> c_int { extern "C" { fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int; } let milliseconds = timeout.as_secs() * 1000 + timeout.subsec_nanos() as u64 / 1_000_000; unsafe { poll((&mut fds[..]).as_mut_ptr(), fds.len() as nfds_t, milliseconds as c_int) } } serial-unix-0.4.0/src/tty.rs01006440000765000002400000050217131260451060014152 0ustar0000000000000000use core; use libc; use termios; use ioctl; use std::ffi::CString; use std::io; use std::path::Path; use std::time::Duration; use std::os::unix::prelude::*; use libc::{c_int, c_void, size_t}; use core::{SerialDevice, SerialPortSettings}; #[cfg(target_os = "linux")] const O_NOCTTY: c_int = 0x00000100; #[cfg(target_os = "macos")] const O_NOCTTY: c_int = 0x00020000; #[cfg(not(any(target_os = "linux", target_os = "macos")))] const O_NOCTTY: c_int = 0; /// A TTY-based serial port implementation. /// /// The port will be closed when the value is dropped. pub struct TTYPort { fd: RawFd, timeout: Duration, } impl TTYPort { /// Opens a TTY device as a serial port. /// /// `path` should be the path to a TTY device, e.g., `/dev/ttyS0`. /// /// ```no_run /// use std::path::Path; /// /// serial_unix::TTYPort::open(Path::new("/dev/ttyS0")).unwrap(); /// ``` /// /// ## Errors /// /// * `NoDevice` if the device could not be opened. This could indicate that the device is /// already in use. /// * `InvalidInput` if `port` is not a valid device name. /// * `Io` for any other error while opening or initializing the device. pub fn open(path: &Path) -> core::Result { use libc::{O_RDWR, O_NONBLOCK, F_SETFL, EINVAL}; let cstr = match CString::new(path.as_os_str().as_bytes()) { Ok(s) => s, Err(_) => return Err(super::error::from_raw_os_error(EINVAL)), }; let fd = unsafe { libc::open(cstr.as_ptr(), O_RDWR | O_NOCTTY | O_NONBLOCK, 0) }; if fd < 0 { return Err(super::error::last_os_error()); } let mut port = TTYPort { fd: fd, timeout: Duration::from_millis(100), }; // get exclusive access to device if let Err(err) = ioctl::tiocexcl(port.fd) { return Err(super::error::from_io_error(err)); } // clear O_NONBLOCK flag if unsafe { libc::fcntl(port.fd, F_SETFL, 0) } < 0 { return Err(super::error::last_os_error()); } // apply initial settings let settings = try!(port.read_settings()); try!(port.write_settings(&settings)); Ok(port) } fn set_pin(&mut self, pin: c_int, level: bool) -> core::Result<()> { let retval = if level { ioctl::tiocmbis(self.fd, pin) } else { ioctl::tiocmbic(self.fd, pin) }; match retval { Ok(()) => Ok(()), Err(err) => Err(super::error::from_io_error(err)), } } fn read_pin(&mut self, pin: c_int) -> core::Result { match ioctl::tiocmget(self.fd) { Ok(pins) => Ok(pins & pin != 0), Err(err) => Err(super::error::from_io_error(err)), } } } impl Drop for TTYPort { fn drop(&mut self) { #![allow(unused_must_use)] ioctl::tiocnxcl(self.fd); unsafe { libc::close(self.fd); } } } impl AsRawFd for TTYPort { fn as_raw_fd(&self) -> RawFd { self.fd } } impl io::Read for TTYPort { fn read(&mut self, buf: &mut [u8]) -> io::Result { try!(super::poll::wait_read_fd(self.fd, self.timeout)); let len = unsafe { libc::read(self.fd, buf.as_ptr() as *mut c_void, buf.len() as size_t) }; if len >= 0 { Ok(len as usize) } else { Err(io::Error::last_os_error()) } } } impl io::Write for TTYPort { fn write(&mut self, buf: &[u8]) -> io::Result { try!(super::poll::wait_write_fd(self.fd, self.timeout)); let len = unsafe { libc::write(self.fd, buf.as_ptr() as *mut c_void, buf.len() as size_t) }; if len >= 0 { Ok(len as usize) } else { Err(io::Error::last_os_error()) } } fn flush(&mut self) -> io::Result<()> { termios::tcdrain(self.fd) } } impl SerialDevice for TTYPort { type Settings = TTYSettings; fn read_settings(&self) -> core::Result { use termios::{CREAD, CLOCAL}; // cflags use termios::{ICANON, ECHO, ECHOE, ECHOK, ECHONL, ISIG, IEXTEN}; // lflags use termios::{OPOST}; // oflags use termios::{INLCR, IGNCR, ICRNL, IGNBRK}; // iflags use termios::{VMIN, VTIME}; // c_cc indexes let mut termios = match termios::Termios::from_fd(self.fd) { Ok(t) => t, Err(e) => return Err(super::error::from_io_error(e)), }; // setup TTY for binary serial port access termios.c_cflag |= CREAD | CLOCAL; termios.c_lflag &= !(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN); termios.c_oflag &= !OPOST; termios.c_iflag &= !(INLCR | IGNCR | ICRNL | IGNBRK); termios.c_cc[VMIN] = 0; termios.c_cc[VTIME] = 0; Ok(TTYSettings::new(termios)) } fn write_settings(&mut self, settings: &TTYSettings) -> core::Result<()> { use termios::{tcsetattr, tcflush}; use termios::{TCSANOW, TCIOFLUSH}; // write settings to TTY if let Err(err) = tcsetattr(self.fd, TCSANOW, &settings.termios) { return Err(super::error::from_io_error(err)); } if let Err(err) = tcflush(self.fd, TCIOFLUSH) { return Err(super::error::from_io_error(err)); } Ok(()) } fn timeout(&self) -> Duration { self.timeout } fn set_timeout(&mut self, timeout: Duration) -> core::Result<()> { self.timeout = timeout; Ok(()) } fn set_rts(&mut self, level: bool) -> core::Result<()> { self.set_pin(ioctl::TIOCM_RTS, level) } fn set_dtr(&mut self, level: bool) -> core::Result<()> { self.set_pin(ioctl::TIOCM_DTR, level) } fn read_cts(&mut self) -> core::Result { self.read_pin(ioctl::TIOCM_CTS) } fn read_dsr(&mut self) -> core::Result { self.read_pin(ioctl::TIOCM_DSR) } fn read_ri(&mut self) -> core::Result { self.read_pin(ioctl::TIOCM_RI) } fn read_cd(&mut self) -> core::Result { self.read_pin(ioctl::TIOCM_CD) } } /// Serial port settings for TTY devices. #[derive(Debug,Copy,Clone)] pub struct TTYSettings { termios: termios::Termios, } impl TTYSettings { fn new(termios: termios::Termios) -> Self { TTYSettings { termios: termios } } } impl SerialPortSettings for TTYSettings { fn baud_rate(&self) -> Option { use termios::{cfgetospeed, cfgetispeed}; use termios::{B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200, B38400}; use termios::os::target::{B57600, B115200, B230400}; #[cfg(target_os = "linux")] use termios::os::linux::{B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000}; #[cfg(target_os = "macos")] use termios::os::macos::{B7200, B14400, B28800, B76800}; #[cfg(target_os = "freebsd")] use termios::os::freebsd::{B7200, B14400, B28800, B76800, B460800, B921600}; #[cfg(target_os = "openbsd")] use termios::os::openbsd::{B7200, B14400, B28800, B76800}; let ospeed = cfgetospeed(&self.termios); let ispeed = cfgetispeed(&self.termios); if ospeed != ispeed { return None; } match ospeed { B50 => Some(core::BaudOther(50)), B75 => Some(core::BaudOther(75)), B110 => Some(core::Baud110), B134 => Some(core::BaudOther(134)), B150 => Some(core::BaudOther(150)), B200 => Some(core::BaudOther(200)), B300 => Some(core::Baud300), B600 => Some(core::Baud600), B1200 => Some(core::Baud1200), B1800 => Some(core::BaudOther(1800)), B2400 => Some(core::Baud2400), B4800 => Some(core::Baud4800), #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] B7200 => Some(core::BaudOther(7200)), B9600 => Some(core::Baud9600), #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] B14400 => Some(core::BaudOther(14400)), B19200 => Some(core::Baud19200), #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] B28800 => Some(core::BaudOther(28800)), B38400 => Some(core::Baud38400), B57600 => Some(core::Baud57600), #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] B76800 => Some(core::BaudOther(76800)), B115200 => Some(core::Baud115200), B230400 => Some(core::BaudOther(230400)), #[cfg(any(target_os = "linux", target_os = "freebsd"))] B460800 => Some(core::BaudOther(460800)), #[cfg(target_os = "linux")] B500000 => Some(core::BaudOther(500000)), #[cfg(target_os = "linux")] B576000 => Some(core::BaudOther(576000)), #[cfg(any(target_os = "linux", target_os = "freebsd"))] B921600 => Some(core::BaudOther(921600)), #[cfg(target_os = "linux")] B1000000 => Some(core::BaudOther(1000000)), #[cfg(target_os = "linux")] B1152000 => Some(core::BaudOther(1152000)), #[cfg(target_os = "linux")] B1500000 => Some(core::BaudOther(1500000)), #[cfg(target_os = "linux")] B2000000 => Some(core::BaudOther(2000000)), #[cfg(target_os = "linux")] B2500000 => Some(core::BaudOther(2500000)), #[cfg(target_os = "linux")] B3000000 => Some(core::BaudOther(3000000)), #[cfg(target_os = "linux")] B3500000 => Some(core::BaudOther(3500000)), #[cfg(target_os = "linux")] B4000000 => Some(core::BaudOther(4000000)), _ => None, } } fn char_size(&self) -> Option { use termios::{CSIZE, CS5, CS6, CS7, CS8}; match self.termios.c_cflag & CSIZE { CS8 => Some(core::Bits8), CS7 => Some(core::Bits7), CS6 => Some(core::Bits6), CS5 => Some(core::Bits5), _ => None, } } fn parity(&self) -> Option { use termios::{PARENB, PARODD}; if self.termios.c_cflag & PARENB != 0 { if self.termios.c_cflag & PARODD != 0 { Some(core::ParityOdd) } else { Some(core::ParityEven) } } else { Some(core::ParityNone) } } fn stop_bits(&self) -> Option { use termios::CSTOPB; if self.termios.c_cflag & CSTOPB != 0 { Some(core::Stop2) } else { Some(core::Stop1) } } fn flow_control(&self) -> Option { use termios::{IXON, IXOFF}; use termios::os::target::CRTSCTS; if self.termios.c_cflag & CRTSCTS != 0 { Some(core::FlowHardware) } else if self.termios.c_iflag & (IXON | IXOFF) != 0 { Some(core::FlowSoftware) } else { Some(core::FlowNone) } } fn set_baud_rate(&mut self, baud_rate: core::BaudRate) -> core::Result<()> { use libc::EINVAL; use termios::cfsetspeed; use termios::{B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200, B38400}; use termios::os::target::{B57600, B115200, B230400}; #[cfg(target_os = "linux")] use termios::os::linux::{B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000}; #[cfg(target_os = "macos")] use termios::os::macos::{B7200, B14400, B28800, B76800}; #[cfg(target_os = "freebsd")] use termios::os::freebsd::{B7200, B14400, B28800, B76800, B460800, B921600}; #[cfg(target_os = "openbsd")] use termios::os::openbsd::{B7200, B14400, B28800, B76800}; let baud = match baud_rate { core::BaudOther(50) => B50, core::BaudOther(75) => B75, core::Baud110 => B110, core::BaudOther(134) => B134, core::BaudOther(150) => B150, core::BaudOther(200) => B200, core::Baud300 => B300, core::Baud600 => B600, core::Baud1200 => B1200, core::BaudOther(1800) => B1800, core::Baud2400 => B2400, core::Baud4800 => B4800, #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] core::BaudOther(7200) => B7200, core::Baud9600 => B9600, #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] core::BaudOther(14400) => B14400, core::Baud19200 => B19200, #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] core::BaudOther(28800) => B28800, core::Baud38400 => B38400, core::Baud57600 => B57600, #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] core::BaudOther(76800) => B76800, core::Baud115200 => B115200, core::BaudOther(230400) => B230400, #[cfg(any(target_os = "linux", target_os = "freebsd"))] core::BaudOther(460800) => B460800, #[cfg(target_os = "linux")] core::BaudOther(500000) => B500000, #[cfg(target_os = "linux")] core::BaudOther(576000) => B576000, #[cfg(any(target_os = "linux", target_os = "freebsd"))] core::BaudOther(921600) => B921600, #[cfg(target_os = "linux")] core::BaudOther(1000000) => B1000000, #[cfg(target_os = "linux")] core::BaudOther(1152000) => B1152000, #[cfg(target_os = "linux")] core::BaudOther(1500000) => B1500000, #[cfg(target_os = "linux")] core::BaudOther(2000000) => B2000000, #[cfg(target_os = "linux")] core::BaudOther(2500000) => B2500000, #[cfg(target_os = "linux")] core::BaudOther(3000000) => B3000000, #[cfg(target_os = "linux")] core::BaudOther(3500000) => B3500000, #[cfg(target_os = "linux")] core::BaudOther(4000000) => B4000000, core::BaudOther(_) => return Err(super::error::from_raw_os_error(EINVAL)), }; match cfsetspeed(&mut self.termios, baud) { Ok(()) => Ok(()), Err(err) => Err(super::error::from_io_error(err)), } } fn set_char_size(&mut self, char_size: core::CharSize) { use termios::{CSIZE, CS5, CS6, CS7, CS8}; let size = match char_size { core::Bits5 => CS5, core::Bits6 => CS6, core::Bits7 => CS7, core::Bits8 => CS8, }; self.termios.c_cflag &= !CSIZE; self.termios.c_cflag |= size; } fn set_parity(&mut self, parity: core::Parity) { use termios::{PARENB, PARODD, INPCK, IGNPAR}; match parity { core::ParityNone => { self.termios.c_cflag &= !(PARENB | PARODD); self.termios.c_iflag &= !INPCK; self.termios.c_iflag |= IGNPAR; } core::ParityOdd => { self.termios.c_cflag |= PARENB | PARODD; self.termios.c_iflag |= INPCK; self.termios.c_iflag &= !IGNPAR; } core::ParityEven => { self.termios.c_cflag &= !PARODD; self.termios.c_cflag |= PARENB; self.termios.c_iflag |= INPCK; self.termios.c_iflag &= !IGNPAR; } }; } fn set_stop_bits(&mut self, stop_bits: core::StopBits) { use termios::CSTOPB; match stop_bits { core::Stop1 => self.termios.c_cflag &= !CSTOPB, core::Stop2 => self.termios.c_cflag |= CSTOPB, }; } fn set_flow_control(&mut self, flow_control: core::FlowControl) { use termios::{IXON, IXOFF}; use termios::os::target::CRTSCTS; match flow_control { core::FlowNone => { self.termios.c_iflag &= !(IXON | IXOFF); self.termios.c_cflag &= !CRTSCTS; } core::FlowSoftware => { self.termios.c_iflag |= IXON | IXOFF; self.termios.c_cflag &= !CRTSCTS; } core::FlowHardware => { self.termios.c_iflag &= !(IXON | IXOFF); self.termios.c_cflag |= CRTSCTS; } }; } } #[cfg(test)] mod tests { use core; use std::mem; use super::TTYSettings; use core::prelude::*; fn default_settings() -> TTYSettings { TTYSettings { termios: unsafe { mem::uninitialized() } } } #[test] fn tty_settings_sets_baud_rate() { let mut settings = default_settings(); settings.set_baud_rate(core::Baud600).unwrap(); assert_eq!(settings.baud_rate(), Some(core::Baud600)); } #[test] fn tty_settings_overwrites_baud_rate() { let mut settings = default_settings(); settings.set_baud_rate(core::Baud600).unwrap(); settings.set_baud_rate(core::Baud1200).unwrap(); assert_eq!(settings.baud_rate(), Some(core::Baud1200)); } #[test] fn tty_settings_sets_char_size() { let mut settings = default_settings(); settings.set_char_size(core::Bits8); assert_eq!(settings.char_size(), Some(core::Bits8)); } #[test] fn tty_settings_overwrites_char_size() { let mut settings = default_settings(); settings.set_char_size(core::Bits8); settings.set_char_size(core::Bits7); assert_eq!(settings.char_size(), Some(core::Bits7)); } #[test] fn tty_settings_sets_parity_even() { let mut settings = default_settings(); settings.set_parity(core::ParityEven); assert_eq!(settings.parity(), Some(core::ParityEven)); } #[test] fn tty_settings_sets_parity_odd() { let mut settings = default_settings(); settings.set_parity(core::ParityOdd); assert_eq!(settings.parity(), Some(core::ParityOdd)); } #[test] fn tty_settings_sets_parity_none() { let mut settings = default_settings(); settings.set_parity(core::ParityEven); settings.set_parity(core::ParityNone); assert_eq!(settings.parity(), Some(core::ParityNone)); } #[test] fn tty_settings_sets_stop_bits_1() { let mut settings = default_settings(); settings.set_stop_bits(core::Stop2); settings.set_stop_bits(core::Stop1); assert_eq!(settings.stop_bits(), Some(core::Stop1)); } #[test] fn tty_settings_sets_stop_bits_2() { let mut settings = default_settings(); settings.set_stop_bits(core::Stop1); settings.set_stop_bits(core::Stop2); assert_eq!(settings.stop_bits(), Some(core::Stop2)); } #[test] fn tty_settings_sets_flow_control_software() { let mut settings = default_settings(); settings.set_flow_control(core::FlowSoftware); assert_eq!(settings.flow_control(), Some(core::FlowSoftware)); } #[test] fn tty_settings_sets_flow_control_hardware() { let mut settings = default_settings(); settings.set_flow_control(core::FlowHardware); assert_eq!(settings.flow_control(), Some(core::FlowHardware)); } #[test] fn tty_settings_sets_flow_control_none() { let mut settings = default_settings(); settings.set_flow_control(core::FlowHardware); settings.set_flow_control(core::FlowNone); assert_eq!(settings.flow_control(), Some(core::FlowNone)); } }