dmx_serial/posix/
tty.rs

1extern crate libc;
2extern crate dmx_termios as termios;
3extern crate ioctl_rs as ioctl;
4
5use std::ffi::CString;
6use std::io;
7use std::path::Path;
8use std::time::Duration;
9
10use std::os::unix::prelude::*;
11
12use self::libc::{c_int,c_uint,c_void,size_t};
13
14use ::{SerialDevice,SerialPortSettings};
15
16
17#[cfg(target_os = "linux")]
18const O_NOCTTY: c_int = 0x00000100;
19
20#[cfg(target_os = "macos")]
21const O_NOCTTY: c_int = 0x00020000;
22
23#[cfg(not(any(target_os = "linux", target_os = "macos")))]
24const O_NOCTTY: c_int = 0;
25
26// FIXME: This constant should move to the termios crate
27#[cfg(target_os = "linux")]
28const BOTHER: c_uint = 0x1000;
29
30// FIXME: This constant should move to the termios crate
31#[cfg(target_os = "linux")]
32const TCSETS2: c_int = 0x402c542b;
33
34
35/// A TTY-based serial port implementation.
36///
37/// The port will be closed when the value is dropped.
38pub struct TTYPort {
39    fd: RawFd,
40    timeout: Duration
41}
42
43impl TTYPort {
44    /// Opens a TTY device as a serial port.
45    ///
46    /// `path` should be the path to a TTY device, e.g., `/dev/ttyS0`.
47    ///
48    /// ```no_run
49    /// use std::path::Path;
50    ///
51    /// serial::posix::TTYPort::open(Path::new("/dev/ttyS0")).unwrap();
52    /// ```
53    ///
54    /// ## Errors
55    ///
56    /// * `NoDevice` if the device could not be opened. This could indicate that the device is
57    ///   already in use.
58    /// * `InvalidInput` if `port` is not a valid device name.
59    /// * `Io` for any other error while opening or initializing the device.
60    pub fn open(path: &Path) -> ::Result<Self> {
61        use self::libc::{O_RDWR,O_NONBLOCK,F_SETFL,EINVAL};
62
63        let cstr = match CString::new(path.as_os_str().as_bytes()) {
64            Ok(s) => s,
65            Err(_) => return Err(super::error::from_raw_os_error(EINVAL))
66        };
67
68        let fd = unsafe { libc::open(cstr.as_ptr(), O_RDWR | O_NOCTTY | O_NONBLOCK, 0) };
69        if fd < 0 {
70            return Err(super::error::last_os_error());
71        }
72
73        let mut port = TTYPort {
74            fd: fd,
75            timeout: Duration::from_millis(100)
76        };
77
78        // get exclusive access to device
79        if let Err(err) = ioctl::tiocexcl(port.fd) {
80            return Err(super::error::from_io_error(err))
81        }
82
83        // clear O_NONBLOCK flag
84        if unsafe { libc::fcntl(port.fd, F_SETFL, 0) } < 0 {
85            return Err(super::error::last_os_error());
86        }
87
88        // apply initial settings
89        let settings = try!(port.read_settings());
90        try!(port.write_settings(&settings));
91
92        Ok(port)
93    }
94
95    fn set_pin(&mut self, pin: c_int, level: bool) -> ::Result<()> {
96        let retval = if level {
97            ioctl::tiocmbis(self.fd, pin)
98        }
99        else {
100            ioctl::tiocmbic(self.fd, pin)
101        };
102
103        match retval {
104            Ok(()) => Ok(()),
105            Err(err) => Err(super::error::from_io_error(err))
106        }
107    }
108
109    fn read_pin(&mut self, pin: c_int) -> ::Result<bool> {
110        match ioctl::tiocmget(self.fd) {
111            Ok(pins) => Ok(pins & pin != 0),
112            Err(err) => Err(super::error::from_io_error(err))
113        }
114    }
115}
116
117impl Drop for TTYPort {
118    fn drop(&mut self) {
119        #![allow(unused_must_use)]
120        ioctl::tiocnxcl(self.fd);
121
122        unsafe {
123            libc::close(self.fd);
124        }
125    }
126}
127
128impl AsRawFd for TTYPort {
129    fn as_raw_fd(&self) -> RawFd {
130        self.fd
131    }
132}
133
134impl io::Read for TTYPort {
135    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
136        try!(super::poll::wait_read_fd(self.fd, self.timeout));
137
138        let len = unsafe { libc::read(self.fd, buf.as_ptr() as *mut c_void, buf.len() as size_t) };
139
140        if len >= 0 {
141            Ok(len as usize)
142        }
143        else {
144            Err(io::Error::last_os_error())
145        }
146    }
147}
148
149impl io::Write for TTYPort {
150    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
151        try!(super::poll::wait_write_fd(self.fd, self.timeout));
152
153        let len = unsafe { libc::write(self.fd, buf.as_ptr() as *mut c_void, buf.len() as size_t) };
154
155        if len >= 0 {
156            Ok(len as usize)
157        }
158        else {
159            Err(io::Error::last_os_error())
160        }
161    }
162
163    fn flush(&mut self) -> io::Result<()> {
164        termios::tcdrain(self.fd)
165    }
166}
167
168impl SerialDevice for TTYPort {
169    type Settings = TTYSettings;
170
171    fn read_settings(&self) -> ::Result<TTYSettings> {
172        use self::termios::{CREAD,CLOCAL}; // cflags
173        use self::termios::{ICANON,ECHO,ECHOE,ECHOK,ECHONL,ISIG,IEXTEN}; // lflags
174        use self::termios::{OPOST}; // oflags
175        use self::termios::{INLCR,IGNCR,ICRNL,IGNBRK}; // iflags
176        use self::termios::{VMIN,VTIME}; // c_cc indexes
177
178        let mut termios = match termios::Termios::from_fd(self.fd) {
179            Ok(t) => t,
180            Err(e) => return Err(super::error::from_io_error(e))
181        };
182
183        // setup TTY for binary serial port access
184        termios.c_cflag |= CREAD | CLOCAL;
185        termios.c_lflag &= !(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN);
186        termios.c_oflag &= !OPOST;
187        termios.c_iflag &= !(INLCR | IGNCR | ICRNL | IGNBRK);
188
189        termios.c_cc[VMIN] = 0;
190        termios.c_cc[VTIME] = 0;
191
192        Ok(TTYSettings::new(termios))
193    }
194
195    #[cfg(target_os = "linux")]
196    fn write_settings(&mut self, settings: &TTYSettings) -> ::Result<()> {
197        let err = unsafe { ioctl::ioctl(self.fd, TCSETS2, &settings.termios) };
198
199        if err != 0 {
200            return Err(super::error::from_raw_os_error(err));
201        }
202        Ok(())
203    }
204
205    #[cfg(not(target_os = "linux"))]
206    fn write_settings(&mut self, settings: &TTYSettings) -> ::Result<()> {
207        use self::termios::{tcsetattr, tcflush};
208        use self::termios::{TCSANOW, TCIOFLUSH};
209
210
211        // write settings to TTY
212        if let Err(err) = tcsetattr(self.fd, TCSANOW, &settings.termios) {
213            return Err(super::error::from_io_error(err));
214        }
215
216        if let Err(err) = tcflush(self.fd, TCIOFLUSH) {
217            return Err(super::error::from_io_error(err));
218        }
219
220        Ok(())
221    }
222
223    fn timeout(&self) -> Duration {
224        self.timeout
225    }
226
227    fn set_timeout(&mut self, timeout: Duration) -> ::Result<()> {
228        self.timeout = timeout;
229        Ok(())
230    }
231
232    fn set_rts(&mut self, level: bool) -> ::Result<()> {
233        self.set_pin(ioctl::TIOCM_RTS, level)
234    }
235
236    fn set_dtr(&mut self, level: bool) -> ::Result<()> {
237        self.set_pin(ioctl::TIOCM_DTR, level)
238    }
239
240    fn read_cts(&mut self) -> ::Result<bool> {
241        self.read_pin(ioctl::TIOCM_CTS)
242    }
243
244    fn read_dsr(&mut self) -> ::Result<bool> {
245        self.read_pin(ioctl::TIOCM_DSR)
246    }
247
248    fn read_ri(&mut self) -> ::Result<bool> {
249        self.read_pin(ioctl::TIOCM_RI)
250    }
251
252    fn read_cd(&mut self) -> ::Result<bool> {
253        self.read_pin(ioctl::TIOCM_CD)
254    }
255}
256
257/// Serial port settings for TTY devices.
258#[derive(Debug,Copy,Clone)]
259pub struct TTYSettings {
260    termios: termios::Termios
261}
262
263impl TTYSettings {
264    fn new(termios: termios::Termios) -> Self {
265        TTYSettings {
266            termios: termios
267        }
268    }
269}
270
271impl SerialPortSettings for TTYSettings {
272    fn baud_rate(&self) -> Option<::BaudRate> {
273        use self::termios::{cfgetospeed,cfgetispeed};
274        use self::termios::{B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400};
275        use self::termios::os::target::{B57600,B115200,B230400};
276
277        #[cfg(target_os = "linux")]
278        use self::termios::os::linux::{B460800,B500000,B576000,B921600,B1000000,B1152000,B1500000,B2000000,B2500000,B3000000,B3500000,B4000000};
279
280        #[cfg(target_os = "macos")]
281        use self::termios::os::macos::{B7200,B14400,B28800,B76800};
282
283        #[cfg(target_os = "freebsd")]
284        use self::termios::os::freebsd::{B7200,B14400,B28800,B76800,B460800,B921600};
285
286        #[cfg(target_os = "openbsd")]
287        use self::termios::os::openbsd::{B7200,B14400,B28800,B76800};
288
289        let ospeed = cfgetospeed(&self.termios);
290        let ispeed = cfgetispeed(&self.termios);
291
292        if ospeed != ispeed {
293            return None
294        }
295
296        match ospeed {
297            B50      => Some(::BaudOther(50)),
298            B75      => Some(::BaudOther(75)),
299            B110     => Some(::Baud110),
300            B134     => Some(::BaudOther(134)),
301            B150     => Some(::BaudOther(150)),
302            B200     => Some(::BaudOther(200)),
303            B300     => Some(::Baud300),
304            B600     => Some(::Baud600),
305            B1200    => Some(::Baud1200),
306            B1800    => Some(::BaudOther(1800)),
307            B2400    => Some(::Baud2400),
308            B4800    => Some(::Baud4800),
309            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
310            B7200    => Some(::BaudOther(7200)),
311            B9600    => Some(::Baud9600),
312            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
313            B14400   => Some(::BaudOther(14400)),
314            B19200   => Some(::Baud19200),
315            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
316            B28800   => Some(::BaudOther(28800)),
317            B38400   => Some(::Baud38400),
318            B57600   => Some(::Baud57600),
319            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
320            B76800   => Some(::BaudOther(76800)),
321            B115200  => Some(::Baud115200),
322            B230400  => Some(::BaudOther(230400)),
323            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
324            B460800  => Some(::BaudOther(460800)),
325            #[cfg(target_os = "linux")]
326            B500000  => Some(::BaudOther(500000)),
327            #[cfg(target_os = "linux")]
328            B576000  => Some(::BaudOther(576000)),
329            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
330            B921600  => Some(::BaudOther(921600)),
331            #[cfg(target_os = "linux")]
332            B1000000 => Some(::BaudOther(1000000)),
333            #[cfg(target_os = "linux")]
334            B1152000 => Some(::BaudOther(1152000)),
335            #[cfg(target_os = "linux")]
336            B1500000 => Some(::BaudOther(1500000)),
337            #[cfg(target_os = "linux")]
338            B2000000 => Some(::BaudOther(2000000)),
339            #[cfg(target_os = "linux")]
340            B2500000 => Some(::BaudOther(2500000)),
341            #[cfg(target_os = "linux")]
342            B3000000 => Some(::BaudOther(3000000)),
343            #[cfg(target_os = "linux")]
344            B3500000 => Some(::BaudOther(3500000)),
345            #[cfg(target_os = "linux")]
346            B4000000 => Some(::BaudOther(4000000)),
347            #[cfg(target_os = "linux")]
348            BOTHER => {
349
350                if self.termios.c_ospeed != self.termios.c_ispeed {
351                    return None;
352                }
353
354                Some(::BaudOther(self.termios.c_ospeed as usize))
355            }
356
357            _ => None
358        }
359    }
360
361    fn char_size(&self) -> Option<::CharSize> {
362        use self::termios::{CSIZE,CS5,CS6,CS7,CS8};
363
364        match self.termios.c_cflag & CSIZE {
365            CS8 => Some(::Bits8),
366            CS7 => Some(::Bits7),
367            CS6 => Some(::Bits6),
368            CS5 => Some(::Bits5),
369
370            _ => None
371        }
372    }
373
374    fn parity(&self) -> Option<::Parity> {
375        use self::termios::{PARENB,PARODD};
376
377        if self.termios.c_cflag & PARENB != 0 {
378            if self.termios.c_cflag & PARODD != 0 {
379                Some(::ParityOdd)
380            }
381            else {
382                Some(::ParityEven)
383            }
384        }
385        else {
386            Some(::ParityNone)
387        }
388    }
389
390    fn stop_bits(&self) -> Option<::StopBits> {
391        use self::termios::{CSTOPB};
392
393        if self.termios.c_cflag & CSTOPB != 0 {
394            Some(::Stop2)
395        }
396        else {
397            Some(::Stop1)
398        }
399    }
400
401    fn flow_control(&self) -> Option<::FlowControl> {
402        use self::termios::{IXON,IXOFF};
403        use self::termios::os::target::{CRTSCTS};
404
405        if self.termios.c_cflag & CRTSCTS != 0 {
406            Some(::FlowHardware)
407        }
408        else if self.termios.c_iflag & (IXON | IXOFF) != 0 {
409            Some(::FlowSoftware)
410        }
411        else {
412            Some(::FlowNone)
413        }
414    }
415
416    fn set_baud_rate(&mut self, baud_rate: ::BaudRate) -> ::Result<()> {
417        use self::termios::cfsetspeed;
418        use self::termios::{B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400};
419        use self::termios::os::target::{B57600,B115200,B230400};
420
421        #[cfg(target_os = "linux")]
422        use self::termios::os::linux::{B460800,B500000,B576000,B921600,B1000000,B1152000,B1500000,B2000000,B2500000,B3000000,B3500000,B4000000};
423
424        #[cfg(target_os = "macos")]
425        use self::termios::os::macos::{B7200,B14400,B28800,B76800};
426
427        #[cfg(target_os = "freebsd")]
428        use self::termios::os::freebsd::{B7200,B14400,B28800,B76800,B460800,B921600};
429
430        #[cfg(target_os = "openbsd")]
431        use self::termios::os::openbsd::{B7200,B14400,B28800,B76800};
432
433        let baud = match baud_rate {
434            ::BaudOther(50)      => B50,
435            ::BaudOther(75)      => B75,
436            ::Baud110            => B110,
437            ::BaudOther(134)     => B134,
438            ::BaudOther(150)     => B150,
439            ::BaudOther(200)     => B200,
440            ::Baud300            => B300,
441            ::Baud600            => B600,
442            ::Baud1200           => B1200,
443            ::BaudOther(1800)    => B1800,
444            ::Baud2400           => B2400,
445            ::Baud4800           => B4800,
446            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
447            ::BaudOther(7200)    => B7200,
448            ::Baud9600           => B9600,
449            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
450            ::BaudOther(14400)   => B14400,
451            ::Baud19200          => B19200,
452            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
453            ::BaudOther(28800)   => B28800,
454            ::Baud38400          => B38400,
455            ::Baud57600          => B57600,
456            #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
457            ::BaudOther(76800)   => B76800,
458            ::Baud115200         => B115200,
459            ::BaudOther(230400)  => B230400,
460            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
461            ::BaudOther(460800)  => B460800,
462            #[cfg(target_os = "linux")]
463            ::BaudOther(500000)  => B500000,
464            #[cfg(target_os = "linux")]
465            ::BaudOther(576000)  => B576000,
466            #[cfg(any(target_os = "linux", target_os = "freebsd"))]
467            ::BaudOther(921600)  => B921600,
468            #[cfg(target_os = "linux")]
469            ::BaudOther(1000000) => B1000000,
470            #[cfg(target_os = "linux")]
471            ::BaudOther(1152000) => B1152000,
472            #[cfg(target_os = "linux")]
473            ::BaudOther(1500000) => B1500000,
474            #[cfg(target_os = "linux")]
475            ::BaudOther(2000000) => B2000000,
476            #[cfg(target_os = "linux")]
477            ::BaudOther(2500000) => B2500000,
478            #[cfg(target_os = "linux")]
479            ::BaudOther(3000000) => B3000000,
480            #[cfg(target_os = "linux")]
481            ::BaudOther(3500000) => B3500000,
482            #[cfg(target_os = "linux")]
483            ::BaudOther(4000000) => B4000000,
484
485            ::BaudOther(rate) => {
486                // Custom baud rates are only supported on Linux for now.
487                // Test this on other platforms and remove the early
488                // return for those that pass/support this feature
489                #[cfg(target_os = "linux")]
490                {
491                    use self::termios::os::linux::CBAUD;
492
493                    self.termios.c_cflag &= !CBAUD;
494                    self.termios.c_cflag |= BOTHER;
495                    self.termios.c_ispeed = rate as c_uint;
496                    self.termios.c_ospeed = rate as c_uint;
497
498                    return Ok(());
499                }
500
501                #[cfg(not(target_os = "linux"))]
502                {
503                    use self::libc::EINVAL;
504                    return Err(super::error::from_raw_os_error(EINVAL));
505                }
506            }
507        };
508
509        match cfsetspeed(&mut self.termios, baud) {
510            Ok(()) => Ok(()),
511            Err(err) => Err(super::error::from_io_error(err))
512        }
513    }
514
515    fn set_char_size(&mut self, char_size: ::CharSize) {
516        use self::termios::{CSIZE,CS5,CS6,CS7,CS8};
517
518        let size = match char_size {
519            ::Bits5 => CS5,
520            ::Bits6 => CS6,
521            ::Bits7 => CS7,
522            ::Bits8 => CS8
523        };
524
525        self.termios.c_cflag &= !CSIZE;
526        self.termios.c_cflag |= size;
527    }
528
529    fn set_parity(&mut self, parity: ::Parity) {
530        use self::termios::{PARENB,PARODD,INPCK,IGNPAR};
531
532        match parity {
533            ::ParityNone => {
534                self.termios.c_cflag &= !(PARENB | PARODD);
535                self.termios.c_iflag &= !INPCK;
536                self.termios.c_iflag |= IGNPAR;
537            },
538            ::ParityOdd => {
539                self.termios.c_cflag |= PARENB | PARODD;
540                self.termios.c_iflag |= INPCK;
541                self.termios.c_iflag &= !IGNPAR;
542            },
543            ::ParityEven => {
544                self.termios.c_cflag &= !PARODD;
545                self.termios.c_cflag |= PARENB;
546                self.termios.c_iflag |= INPCK;
547                self.termios.c_iflag &= !IGNPAR;
548            }
549        };
550    }
551
552    fn set_stop_bits(&mut self, stop_bits: ::StopBits) {
553        use self::termios::{CSTOPB};
554
555        match stop_bits {
556            ::Stop1 => self.termios.c_cflag &= !CSTOPB,
557            ::Stop2 => self.termios.c_cflag |= CSTOPB
558        };
559    }
560
561    fn set_flow_control(&mut self, flow_control: ::FlowControl) {
562        use self::termios::{IXON,IXOFF};
563        use self::termios::os::target::{CRTSCTS};
564
565        match flow_control {
566            ::FlowNone => {
567                self.termios.c_iflag &= !(IXON | IXOFF);
568                self.termios.c_cflag &= !CRTSCTS;
569            },
570            ::FlowSoftware => {
571                self.termios.c_iflag |= IXON | IXOFF;
572                self.termios.c_cflag &= !CRTSCTS;
573            },
574            ::FlowHardware => {
575                self.termios.c_iflag &= !(IXON | IXOFF);
576                self.termios.c_cflag |= CRTSCTS;
577            }
578        };
579    }
580}
581
582
583#[cfg(test)]
584mod tests {
585    use std::mem;
586
587    use super::TTYSettings;
588    use ::prelude::*;
589
590    fn default_settings() -> TTYSettings {
591        TTYSettings {
592            termios: unsafe { mem::uninitialized() }
593        }
594    }
595
596    #[test]
597    fn tty_settings_sets_baud_rate() {
598        let mut settings = default_settings();
599
600        settings.set_baud_rate(::Baud600).unwrap();
601        assert_eq!(settings.baud_rate(), Some(::Baud600));
602    }
603
604    #[test]
605    fn tty_settings_overwrites_baud_rate() {
606        let mut settings = default_settings();
607
608        settings.set_baud_rate(::Baud600).unwrap();
609        settings.set_baud_rate(::Baud1200).unwrap();
610        assert_eq!(settings.baud_rate(), Some(::Baud1200));
611    }
612
613    #[test]
614    fn tty_settings_sets_nonstandard_baud_rate() {
615        let mut settings = default_settings();
616
617        settings.set_baud_rate(::BaudOther(12345)).unwrap();
618        assert_eq!(settings.baud_rate(), Some(::BaudOther(12345)));
619    }
620
621    #[test]
622    fn tty_settings_sets_char_size() {
623        let mut settings = default_settings();
624
625        settings.set_char_size(::Bits8);
626        assert_eq!(settings.char_size(), Some(::Bits8));
627    }
628
629    #[test]
630    fn tty_settings_overwrites_char_size() {
631        let mut settings = default_settings();
632
633        settings.set_char_size(::Bits8);
634        settings.set_char_size(::Bits7);
635        assert_eq!(settings.char_size(), Some(::Bits7));
636    }
637
638    #[test]
639    fn tty_settings_sets_parity_even() {
640        let mut settings = default_settings();
641
642        settings.set_parity(::ParityEven);
643        assert_eq!(settings.parity(), Some(::ParityEven));
644    }
645
646    #[test]
647    fn tty_settings_sets_parity_odd() {
648        let mut settings = default_settings();
649
650        settings.set_parity(::ParityOdd);
651        assert_eq!(settings.parity(), Some(::ParityOdd));
652    }
653
654    #[test]
655    fn tty_settings_sets_parity_none() {
656        let mut settings = default_settings();
657
658        settings.set_parity(::ParityEven);
659        settings.set_parity(::ParityNone);
660        assert_eq!(settings.parity(), Some(::ParityNone));
661    }
662
663    #[test]
664    fn tty_settings_sets_stop_bits_1() {
665        let mut settings = default_settings();
666
667        settings.set_stop_bits(::Stop2);
668        settings.set_stop_bits(::Stop1);
669        assert_eq!(settings.stop_bits(), Some(::Stop1));
670    }
671
672    #[test]
673    fn tty_settings_sets_stop_bits_2() {
674        let mut settings = default_settings();
675
676        settings.set_stop_bits(::Stop1);
677        settings.set_stop_bits(::Stop2);
678        assert_eq!(settings.stop_bits(), Some(::Stop2));
679    }
680
681    #[test]
682    fn tty_settings_sets_flow_control_software() {
683        let mut settings = default_settings();
684
685        settings.set_flow_control(::FlowSoftware);
686        assert_eq!(settings.flow_control(), Some(::FlowSoftware));
687    }
688
689    #[test]
690    fn tty_settings_sets_flow_control_hardware() {
691        let mut settings = default_settings();
692
693        settings.set_flow_control(::FlowHardware);
694        assert_eq!(settings.flow_control(), Some(::FlowHardware));
695    }
696
697    #[test]
698    fn tty_settings_sets_flow_control_none() {
699        let mut settings = default_settings();
700
701        settings.set_flow_control(::FlowHardware);
702        settings.set_flow_control(::FlowNone);
703        assert_eq!(settings.flow_control(), Some(::FlowNone));
704    }
705}