Skip to main content

mio_serial/
lib.rs

1//! # mio-serial - Serial port I/O for mio
2//!
3//! This crate provides a serial port implementation compatable with mio.
4//!
5//! **Windows support is present but largely untested by the author**
6//!
7//! ## Links
8//!   - repo:  <https://github.com/berkowski/mio-serial>
9//!   - docs:  <https://docs.rs/mio-serial>
10#![deny(missing_docs)]
11#![warn(rust_2018_idioms)]
12
13// Enums, Structs, and Traits from the serialport crate
14pub use serialport::{
15    // Enums
16    ClearBuffer,
17    DataBits,
18    // Structs
19    Error,
20    ErrorKind,
21    FlowControl,
22    Parity,
23    // Types
24    Result,
25    // Traits
26    SerialPort,
27    SerialPortBuilder,
28    SerialPortInfo,
29    SerialPortType,
30    StopBits,
31    UsbPortInfo,
32};
33
34// Re-export port-enumerating utility function.
35pub use serialport::available_ports;
36
37// Re-export creation of SerialPortBuilder objects
38pub use serialport::new;
39
40use mio::{event::Source, Interest, Registry, Token};
41use std::io::{Error as StdIoError, ErrorKind as StdIoErrorKind, Result as StdIoResult};
42use std::time::Duration;
43
44#[cfg(unix)]
45mod os_prelude {
46    pub use mio::unix::SourceFd;
47    pub use nix::{self, libc};
48    pub use serialport::TTYPort as NativeBlockingSerialPort;
49    pub use std::os::unix::prelude::*;
50}
51
52#[cfg(windows)]
53mod os_prelude {
54    pub use mio::windows::NamedPipe;
55    pub use serialport::COMPort as NativeBlockingSerialPort;
56    pub use std::ffi::OsStr;
57    pub use std::io;
58    pub use std::mem;
59    pub use std::os::windows::ffi::OsStrExt;
60    pub use std::os::windows::io::{FromRawHandle, RawHandle};
61    pub use std::path::Path;
62    pub use std::ptr;
63    pub use windows_sys::Win32::Devices::Communication::{SetCommTimeouts, COMMTIMEOUTS};
64    pub use windows_sys::Win32::Foundation::{
65        GENERIC_READ, GENERIC_WRITE, HANDLE, INVALID_HANDLE_VALUE,
66    };
67    pub use windows_sys::Win32::Storage::FileSystem::{
68        CreateFileW, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_OVERLAPPED, OPEN_EXISTING,
69    };
70}
71use os_prelude::*;
72
73/// A [`SerialStream`].
74#[derive(Debug)]
75pub struct SerialStream {
76    #[cfg(unix)]
77    inner: serialport::TTYPort,
78    #[cfg(windows)]
79    inner: mem::ManuallyDrop<serialport::COMPort>,
80    #[cfg(windows)]
81    pipe: NamedPipe,
82}
83
84impl SerialStream {
85    /// Open a nonblocking serial port from the provided builder
86    ///
87    /// ## Example
88    ///
89    /// ```no_run
90    /// use mio_serial::{SerialPortBuilder, SerialStream};
91    /// use std::path::Path;
92    ///
93    /// let args = mio_serial::new("/dev/ttyUSB0", 9600);
94    /// let serial = SerialStream::open(&args).unwrap();
95    /// ```
96    pub fn open(builder: &crate::SerialPortBuilder) -> crate::Result<Self> {
97        log::debug!("opening serial port in synchronous blocking mode");
98        let port = NativeBlockingSerialPort::open(builder)?;
99        Self::try_from(port)
100    }
101
102    /// Create a pair of pseudo serial terminals
103    ///
104    /// ## Returns
105    /// Two connected `Serial` objects: `(master, slave)`
106    ///
107    /// ## Errors
108    /// Attempting any IO or parameter settings on the slave tty after the master
109    /// tty is closed will return errors.
110    ///
111    /// ## Examples
112    ///
113    /// ```
114    /// use mio_serial::SerialStream;
115    ///
116    /// let (master, slave) = SerialStream::pair().unwrap();
117    /// ```
118    #[cfg(unix)]
119    pub fn pair() -> crate::Result<(Self, Self)> {
120        let (master, slave) = NativeBlockingSerialPort::pair()?;
121
122        let master = Self::try_from(master)?;
123        let slave = Self::try_from(slave)?;
124
125        Ok((master, slave))
126    }
127
128    /// Sets the exclusivity of the port
129    ///
130    /// If a port is exclusive, then trying to open the same device path again
131    /// will fail.
132    ///
133    /// See the man pages for the tiocexcl and tiocnxcl ioctl's for more details.
134    ///
135    /// ## Errors
136    ///
137    /// * `Io` for any error while setting exclusivity for the port.
138    #[cfg(unix)]
139    pub fn set_exclusive(&mut self, exclusive: bool) -> crate::Result<()> {
140        self.inner.set_exclusive(exclusive)
141    }
142
143    /// Returns the exclusivity of the port
144    ///
145    /// If a port is exclusive, then trying to open the same device path again
146    /// will fail.
147    #[cfg(unix)]
148    pub fn exclusive(&self) -> bool {
149        self.inner.exclusive()
150    }
151
152    /// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the
153    /// same serial connection.
154    ///
155    /// Also, you must be very careful when changing the settings of a cloned `SerialPort` : since
156    /// the settings are cached on a per object basis, trying to modify them from two different
157    /// objects can cause some nasty behavior.
158    ///
159    /// This is the same as `SerialPort::try_clone()` but returns the concrete type instead.
160    ///
161    /// # Errors
162    ///
163    /// This function returns an error if the serial port couldn't be cloned.
164    ///
165    /// # DON'T USE THIS AS-IS
166    ///
167    /// This logic has never really completely worked.  Cloned file descriptors in asynchronous
168    /// code is a semantic minefield.  Are you cloning the file descriptor?  Are you cloning the
169    /// event flags on the file descriptor?  Both?  It's a bit of a mess even within one OS,
170    /// let alone across multiple OS's
171    ///
172    /// Maybe it can be done with more work, but until a clear use-case is required (or mio/tokio
173    /// gets an equivalent of the unix `AsyncFd` for async file handles, see
174    /// https://github.com/tokio-rs/tokio/issues/3781 and
175    /// https://github.com/tokio-rs/tokio/pull/3760#issuecomment-839854617) I would rather not
176    /// have any enabled code over a kind-of-works-maybe impl.  So I'll leave this code here
177    /// for now but hard-code it disabled.
178    #[cfg(any())]
179    pub fn try_clone_native(&self) -> Result<SerialStream> {
180        // This works so long as the underlying serialport-rs method doesn't do anything but
181        // duplicate the low-level file descriptor.  This is the case as of serialport-rs:4.0.1
182        let cloned_native = self.inner.try_clone_native()?;
183        #[cfg(unix)]
184        {
185            Ok(Self {
186                inner: cloned_native,
187            })
188        }
189        #[cfg(windows)]
190        {
191            // Same procedure as used in serialport-rs for duplicating raw handles
192            // https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
193            // states that it can be used as well for pipes created with CreateNamedPipe as well
194            let pipe_handle = self.pipe.as_raw_handle();
195
196            let process_handle: HANDLE = unsafe { GetCurrentProcess() };
197            let mut cloned_pipe_handle: HANDLE = INVALID_HANDLE_VALUE;
198            unsafe {
199                DuplicateHandle(
200                    process_handle,
201                    pipe_handle,
202                    process_handle,
203                    &mut cloned_pipe_handle,
204                    0,
205                    TRUE,
206                    DUPLICATE_SAME_ACCESS,
207                );
208                if cloned_pipe_handle != INVALID_HANDLE_VALUE {
209                    let cloned_pipe = unsafe { NamedPipe::from_raw_handle(cloned_pipe_handle) };
210                    Ok(Self {
211                        inner: mem::ManuallyDrop::new(cloned_native),
212                        pipe: cloned_pipe,
213                    })
214                } else {
215                    Err(StdIoError::last_os_error().into())
216                }
217            }
218        }
219    }
220}
221
222impl crate::SerialPort for SerialStream {
223    /// Return the name associated with the serial port, if known.
224    #[inline(always)]
225    fn name(&self) -> Option<String> {
226        self.inner.name()
227    }
228
229    /// Returns the current baud rate.
230    ///
231    /// This function returns `None` if the baud rate could not be determined. This may occur if
232    /// the hardware is in an uninitialized state. Setting a baud rate with `set_baud_rate()`
233    /// should initialize the baud rate to a supported value.
234    #[inline(always)]
235    fn baud_rate(&self) -> crate::Result<u32> {
236        self.inner.baud_rate()
237    }
238
239    /// Returns the character size.
240    ///
241    /// This function returns `None` if the character size could not be determined. This may occur
242    /// if the hardware is in an uninitialized state or is using a non-standard character size.
243    /// Setting a baud rate with `set_char_size()` should initialize the character size to a
244    /// supported value.
245    #[inline(always)]
246    fn data_bits(&self) -> crate::Result<crate::DataBits> {
247        self.inner.data_bits()
248    }
249
250    /// Returns the flow control mode.
251    ///
252    /// This function returns `None` if the flow control mode could not be determined. This may
253    /// occur if the hardware is in an uninitialized state or is using an unsupported flow control
254    /// mode. Setting a flow control mode with `set_flow_control()` should initialize the flow
255    /// control mode to a supported value.
256    #[inline(always)]
257    fn flow_control(&self) -> crate::Result<crate::FlowControl> {
258        self.inner.flow_control()
259    }
260
261    /// Returns the parity-checking mode.
262    ///
263    /// This function returns `None` if the parity mode could not be determined. This may occur if
264    /// the hardware is in an uninitialized state or is using a non-standard parity mode. Setting
265    /// a parity mode with `set_parity()` should initialize the parity mode to a supported value.
266    #[inline(always)]
267    fn parity(&self) -> crate::Result<crate::Parity> {
268        self.inner.parity()
269    }
270
271    /// Returns the number of stop bits.
272    ///
273    /// This function returns `None` if the number of stop bits could not be determined. This may
274    /// occur if the hardware is in an uninitialized state or is using an unsupported stop bit
275    /// configuration. Setting the number of stop bits with `set_stop-bits()` should initialize the
276    /// stop bits to a supported value.
277    #[inline(always)]
278    fn stop_bits(&self) -> crate::Result<crate::StopBits> {
279        self.inner.stop_bits()
280    }
281
282    /// Returns the current timeout. This parameter is const and equal to zero and implemented due
283    /// to required for trait completeness.
284    #[inline(always)]
285    fn timeout(&self) -> Duration {
286        Duration::from_secs(0)
287    }
288
289    /// Sets the baud rate.
290    ///
291    /// ## Errors
292    ///
293    /// If the implementation does not support the requested baud rate, this function may return an
294    /// `InvalidInput` error. Even if the baud rate is accepted by `set_baud_rate()`, it may not be
295    /// supported by the underlying hardware.
296    #[inline(always)]
297    fn set_baud_rate(&mut self, baud_rate: u32) -> crate::Result<()> {
298        self.inner.set_baud_rate(baud_rate)
299    }
300
301    /// Sets the character size.
302    #[inline(always)]
303    fn set_data_bits(&mut self, data_bits: crate::DataBits) -> crate::Result<()> {
304        self.inner.set_data_bits(data_bits)
305    }
306
307    // Port settings setters
308
309    /// Sets the flow control mode.
310    #[inline(always)]
311    fn set_flow_control(&mut self, flow_control: crate::FlowControl) -> crate::Result<()> {
312        self.inner.set_flow_control(flow_control)
313    }
314
315    /// Sets the parity-checking mode.
316    #[inline(always)]
317    fn set_parity(&mut self, parity: crate::Parity) -> crate::Result<()> {
318        self.inner.set_parity(parity)
319    }
320
321    /// Sets the number of stop bits.
322    #[inline(always)]
323    fn set_stop_bits(&mut self, stop_bits: crate::StopBits) -> crate::Result<()> {
324        self.inner.set_stop_bits(stop_bits)
325    }
326
327    /// Sets the timeout for future I/O operations. This parameter is ignored but
328    /// required for trait completeness.
329    #[inline(always)]
330    fn set_timeout(&mut self, _: Duration) -> crate::Result<()> {
331        Ok(())
332    }
333
334    /// Sets the state of the RTS (Request To Send) control signal.
335    ///
336    /// Setting a value of `true` asserts the RTS control signal. `false` clears the signal.
337    ///
338    /// ## Errors
339    ///
340    /// This function returns an error if the RTS control signal could not be set to the desired
341    /// state on the underlying hardware:
342    ///
343    /// * `NoDevice` if the device was disconnected.
344    /// * `Io` for any other type of I/O error.
345    #[inline(always)]
346    fn write_request_to_send(&mut self, level: bool) -> crate::Result<()> {
347        self.inner.write_request_to_send(level)
348    }
349
350    /// Writes to the Data Terminal Ready pin
351    ///
352    /// Setting a value of `true` asserts the DTR control signal. `false` clears the signal.
353    ///
354    /// ## Errors
355    ///
356    /// This function returns an error if the DTR control signal could not be set to the desired
357    /// state on the underlying hardware:
358    ///
359    /// * `NoDevice` if the device was disconnected.
360    /// * `Io` for any other type of I/O error.
361    #[inline(always)]
362    fn write_data_terminal_ready(&mut self, level: bool) -> crate::Result<()> {
363        self.inner.write_data_terminal_ready(level)
364    }
365
366    // Functions for setting non-data control signal pins
367
368    /// Reads the state of the CTS (Clear To Send) control signal.
369    ///
370    /// This function returns a boolean that indicates whether the CTS control signal is asserted.
371    ///
372    /// ## Errors
373    ///
374    /// This function returns an error if the state of the CTS control signal could not be read
375    /// from the underlying hardware:
376    ///
377    /// * `NoDevice` if the device was disconnected.
378    /// * `Io` for any other type of I/O error.
379    #[inline(always)]
380    fn read_clear_to_send(&mut self) -> crate::Result<bool> {
381        self.inner.read_clear_to_send()
382    }
383
384    /// Reads the state of the Data Set Ready control signal.
385    ///
386    /// This function returns a boolean that indicates whether the DSR control signal is asserted.
387    ///
388    /// ## Errors
389    ///
390    /// This function returns an error if the state of the DSR control signal could not be read
391    /// from the underlying hardware:
392    ///
393    /// * `NoDevice` if the device was disconnected.
394    /// * `Io` for any other type of I/O error.
395    #[inline(always)]
396    fn read_data_set_ready(&mut self) -> crate::Result<bool> {
397        self.inner.read_data_set_ready()
398    }
399
400    // Functions for reading additional pins
401
402    /// Reads the state of the Ring Indicator control signal.
403    ///
404    /// This function returns a boolean that indicates whether the RI control signal is asserted.
405    ///
406    /// ## Errors
407    ///
408    /// This function returns an error if the state of the RI control signal could not be read from
409    /// the underlying hardware:
410    ///
411    /// * `NoDevice` if the device was disconnected.
412    /// * `Io` for any other type of I/O error.
413    #[inline(always)]
414    fn read_ring_indicator(&mut self) -> crate::Result<bool> {
415        self.inner.read_ring_indicator()
416    }
417
418    /// Reads the state of the Carrier Detect control signal.
419    ///
420    /// This function returns a boolean that indicates whether the CD control signal is asserted.
421    ///
422    /// ## Errors
423    ///
424    /// This function returns an error if the state of the CD control signal could not be read from
425    /// the underlying hardware:
426    ///
427    /// * `NoDevice` if the device was disconnected.
428    /// * `Io` for any other type of I/O error.
429    #[inline(always)]
430    fn read_carrier_detect(&mut self) -> crate::Result<bool> {
431        self.inner.read_carrier_detect()
432    }
433
434    /// Gets the number of bytes available to be read from the input buffer.
435    ///
436    /// # Errors
437    ///
438    /// This function may return the following errors:
439    ///
440    /// * `NoDevice` if the device was disconnected.
441    /// * `Io` for any other type of I/O error.
442    #[inline(always)]
443    fn bytes_to_read(&self) -> crate::Result<u32> {
444        self.inner.bytes_to_read()
445    }
446
447    /// Get the number of bytes written to the output buffer, awaiting transmission.
448    ///
449    /// # Errors
450    ///
451    /// This function may return the following errors:
452    ///
453    /// * `NoDevice` if the device was disconnected.
454    /// * `Io` for any other type of I/O error.
455    #[inline(always)]
456    fn bytes_to_write(&self) -> crate::Result<u32> {
457        self.inner.bytes_to_write()
458    }
459
460    /// Discards all bytes from the serial driver's input buffer and/or output buffer.
461    ///
462    /// # Errors
463    ///
464    /// This function may return the following errors:
465    ///
466    /// * `NoDevice` if the device was disconnected.
467    /// * `Io` for any other type of I/O error.
468    #[inline(always)]
469    fn clear(&self, buffer_to_clear: crate::ClearBuffer) -> crate::Result<()> {
470        self.inner.clear(buffer_to_clear)
471    }
472
473    /// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the
474    /// same serial connection. Please note that if you want a real asynchronous serial port you
475    /// should look at [mio-serial](https://crates.io/crates/mio-serial) or
476    /// [tokio-serial](https://crates.io/crates/tokio-serial).
477    ///
478    /// Also, you must be very carefull when changing the settings of a cloned `SerialPort` : since
479    /// the settings are cached on a per object basis, trying to modify them from two different
480    /// objects can cause some nasty behavior.
481    ///
482    /// # Errors
483    ///
484    /// This function returns an error if the serial port couldn't be cloned.
485    #[inline(always)]
486    #[cfg(any())]
487    fn try_clone(&self) -> crate::Result<Box<dyn crate::SerialPort>> {
488        Ok(Box::new(self.try_clone_native()?))
489    }
490
491    /// Cloning is not supported for [`SerialStream`] objects
492    ///
493    /// This logic has never really completely worked.  Cloned file descriptors in asynchronous
494    /// code is a semantic minefield.  Are you cloning the file descriptor?  Are you cloning the
495    /// event flags on the file descriptor?  Both?  It's a bit of a mess even within one OS,
496    /// let alone across multiple OS's
497    ///
498    /// Maybe it can be done with more work, but until a clear use-case is required (or mio/tokio
499    /// gets an equivalent of the unix `AsyncFd` for async file handles, see
500    /// <https://github.com/tokio-rs/tokio/issues/3781> and
501    /// <https://github.com/tokio-rs/tokio/pull/3760#issuecomment-839854617>) I would rather not
502    /// have any code available over a kind-of-works-maybe impl.  So I'll leave this code here
503    /// for now but hard-code it disabled.
504    fn try_clone(&self) -> crate::Result<Box<dyn crate::SerialPort>> {
505        Err(crate::Error::new(
506            crate::ErrorKind::Io(StdIoErrorKind::Other),
507            "cloning SerialStream is not supported",
508        ))
509    }
510
511    /// Start transmitting a break
512    #[inline(always)]
513    fn set_break(&self) -> crate::Result<()> {
514        self.inner.set_break()
515    }
516
517    /// Stop transmitting a break
518    #[inline(always)]
519    fn clear_break(&self) -> crate::Result<()> {
520        self.inner.clear_break()
521    }
522}
523
524impl TryFrom<NativeBlockingSerialPort> for SerialStream {
525    type Error = crate::Error;
526    #[cfg(unix)]
527    fn try_from(port: NativeBlockingSerialPort) -> std::result::Result<Self, Self::Error> {
528        // Set the O_NONBLOCK flag.
529        log::debug!(
530            "setting O_NONBLOCK for {}",
531            port.name().unwrap_or_else(|| String::from("<UNKNOWN>"))
532        );
533        let flags = unsafe { libc::fcntl(port.as_raw_fd(), libc::F_GETFL) };
534        if flags < 0 {
535            return Err(StdIoError::last_os_error().into());
536        }
537
538        match unsafe { libc::fcntl(port.as_raw_fd(), libc::F_SETFL, flags | libc::O_NONBLOCK) } {
539            0 => Ok(SerialStream { inner: port }),
540            _ => Err(StdIoError::last_os_error().into()),
541        }
542    }
543    #[cfg(windows)]
544    fn try_from(port: NativeBlockingSerialPort) -> std::result::Result<Self, Self::Error> {
545        log::debug!(
546            "switching {} to asynchronous mode",
547            port.name().unwrap_or_else(|| String::from("<UNKNOWN>"))
548        );
549        log::debug!("reading serial port settings");
550        let name = port
551            .name()
552            .ok_or_else(|| crate::Error::new(crate::ErrorKind::NoDevice, "Empty device name"))?;
553        let baud = port
554            .baud_rate()
555            .inspect_err(|e| log::warn!("failed to read baud rate: {e}"))
556            .ok();
557        let parity = port
558            .parity()
559            .inspect_err(|e| log::warn!("failed to read parity: {e}"))
560            .ok();
561        let data_bits = port
562            .data_bits()
563            .inspect_err(|e| log::warn!("failed to read data bits: {e}"))
564            .ok();
565        let stop_bits = port
566            .stop_bits()
567            .inspect_err(|e| log::warn!("failed to read stop bits: {e}"))
568            .ok();
569        let flow_control = port
570            .flow_control()
571            .inspect_err(|e| log::warn!("failed to read flow control: {e}"))
572            .ok();
573
574        let mut path = Vec::<u16>::new();
575        path.extend(OsStr::new("\\\\.\\").encode_wide());
576        path.extend(Path::new(&name).as_os_str().encode_wide());
577        path.push(0);
578
579        // Drop the port object, we'll reopen the file path as a raw handle
580        log::debug!("closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode");
581        mem::drop(port);
582
583        let handle = unsafe {
584            CreateFileW(
585                path.as_ptr(),
586                GENERIC_READ | GENERIC_WRITE,
587                0,
588                ptr::null_mut(),
589                OPEN_EXISTING,
590                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
591                0 as HANDLE,
592            )
593        };
594
595        if handle == INVALID_HANDLE_VALUE {
596            log::error!("unable to open new async file handle");
597            return Err(crate::Error::from(StdIoError::last_os_error()));
598        }
599
600        // Construct NamedPipe and COMPort from Handle
601        //
602        // We need both the NamedPipe for Read/Write and COMPort for serialport related
603        // actions.  Both are created using FromRawHandle which takes ownership of the
604        // handle which may case a double-free as both objects attempt to close the handle.
605        //
606        // Looking through the source for both NamedPipe and COMPort, NamedPipe does some
607        // cleanup in Drop while COMPort just closes the handle.
608        //
609        // We'll use a ManuallyDrop<T> for COMPort and defer cleanup to the NamedPipe
610        let pipe = unsafe { NamedPipe::from_raw_handle(handle) };
611        let mut com_port =
612            mem::ManuallyDrop::new(unsafe { serialport::COMPort::from_raw_handle(handle) });
613
614        log::debug!("re-setting serial port parameters to original values from synchronous port");
615        if let Some(baud) = baud {
616            com_port.set_baud_rate(baud)?;
617        }
618        if let Some(parity) = parity {
619            com_port.set_parity(parity)?;
620        }
621        if let Some(data_bits) = data_bits {
622            com_port.set_data_bits(data_bits)?;
623        }
624        if let Some(stop_bits) = stop_bits {
625            com_port.set_stop_bits(stop_bits)?;
626        }
627        if let Some(flow_control) = flow_control {
628            com_port.set_flow_control(flow_control)?;
629        }
630        sys::override_comm_timeouts(handle)?;
631
632        Ok(Self {
633            inner: com_port,
634            pipe,
635        })
636    }
637}
638
639#[cfg(unix)]
640mod io {
641    use super::{SerialStream, StdIoError, StdIoResult};
642    use nix::libc;
643    use nix::sys::termios;
644    use std::io::ErrorKind as StdIoErrorKind;
645    use std::io::{Read, Write};
646    use std::os::unix::prelude::*;
647
648    macro_rules! uninterruptibly {
649        ($e:expr) => {{
650            loop {
651                match $e {
652                    Err(ref error) if error.kind() == StdIoErrorKind::Interrupted => {}
653                    res => break res,
654                }
655            }
656        }};
657    }
658
659    impl Read for SerialStream {
660        fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
661            uninterruptibly!(match unsafe {
662                libc::read(
663                    self.as_raw_fd(),
664                    bytes.as_ptr() as *mut libc::c_void,
665                    bytes.len() as libc::size_t,
666                )
667            } {
668                x if x >= 0 => Ok(x as usize),
669                _ => Err(StdIoError::last_os_error()),
670            })
671        }
672    }
673
674    impl Write for SerialStream {
675        fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
676            uninterruptibly!(match unsafe {
677                libc::write(
678                    self.as_raw_fd(),
679                    bytes.as_ptr().cast::<libc::c_void>(),
680                    bytes.len() as libc::size_t,
681                )
682            } {
683                x if x >= 0 => Ok(x as usize),
684                _ => Err(StdIoError::last_os_error()),
685            })
686        }
687
688        fn flush(&mut self) -> StdIoResult<()> {
689            uninterruptibly!(termios::tcdrain(unsafe {
690                BorrowedFd::borrow_raw(self.inner.as_raw_fd())
691            })
692            .map_err(StdIoError::from))
693        }
694    }
695
696    impl Read for &SerialStream {
697        fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
698            uninterruptibly!(match unsafe {
699                libc::read(
700                    self.as_raw_fd(),
701                    bytes.as_ptr() as *mut libc::c_void,
702                    bytes.len() as libc::size_t,
703                )
704            } {
705                x if x >= 0 => Ok(x as usize),
706                _ => Err(StdIoError::last_os_error()),
707            })
708        }
709    }
710
711    impl Write for &SerialStream {
712        fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
713            uninterruptibly!(match unsafe {
714                libc::write(
715                    self.as_raw_fd(),
716                    bytes.as_ptr() as *const libc::c_void,
717                    bytes.len() as libc::size_t,
718                )
719            } {
720                x if x >= 0 => Ok(x as usize),
721                _ => Err(StdIoError::last_os_error()),
722            })
723        }
724
725        fn flush(&mut self) -> StdIoResult<()> {
726            uninterruptibly!(termios::tcdrain(unsafe {
727                BorrowedFd::borrow_raw(self.inner.as_raw_fd())
728            })
729            .map_err(StdIoError::from))
730        }
731    }
732}
733
734#[cfg(windows)]
735mod io {
736    use super::{NativeBlockingSerialPort, SerialStream, StdIoResult};
737    use crate::sys;
738    use mio::windows::NamedPipe;
739    use std::io::{Read, Write};
740    use std::mem;
741    use std::os::windows::prelude::*;
742
743    impl Read for SerialStream {
744        fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
745            self.pipe.read(bytes)
746        }
747    }
748
749    impl Write for SerialStream {
750        fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
751            self.pipe.write(bytes)
752        }
753
754        fn flush(&mut self) -> StdIoResult<()> {
755            self.pipe.flush()
756        }
757    }
758
759    impl AsRawHandle for SerialStream {
760        fn as_raw_handle(&self) -> RawHandle {
761            self.pipe.as_raw_handle()
762        }
763    }
764
765    impl IntoRawHandle for SerialStream {
766        fn into_raw_handle(self) -> RawHandle {
767            // Since NamedPipe doesn't impl IntoRawHandle we'll use AsRawHandle and bypass
768            // NamedPipe's destructor to keep the handle in the current state
769            let manual = mem::ManuallyDrop::new(self.pipe);
770            manual.as_raw_handle()
771        }
772    }
773
774    impl FromRawHandle for SerialStream {
775        /// This method can potentially fail to override the communication timeout
776        /// value set in `sys::override_comm_timeouts` without any indication to the user.
777        unsafe fn from_raw_handle(handle: RawHandle) -> Self {
778            let inner = mem::ManuallyDrop::new(NativeBlockingSerialPort::from_raw_handle(handle));
779            let pipe = NamedPipe::from_raw_handle(handle);
780            sys::override_comm_timeouts(handle).ok();
781
782            Self { inner, pipe }
783        }
784    }
785}
786
787#[cfg(unix)]
788mod sys {
789    use super::{NativeBlockingSerialPort, SerialStream};
790    use std::os::unix::prelude::*;
791
792    impl AsRawFd for SerialStream {
793        fn as_raw_fd(&self) -> RawFd {
794            self.inner.as_raw_fd()
795        }
796    }
797
798    impl IntoRawFd for SerialStream {
799        fn into_raw_fd(self) -> RawFd {
800            self.inner.into_raw_fd()
801        }
802    }
803
804    impl FromRawFd for SerialStream {
805        unsafe fn from_raw_fd(fd: RawFd) -> Self {
806            let port = NativeBlockingSerialPort::from_raw_fd(fd);
807            Self { inner: port }
808        }
809    }
810}
811
812#[cfg(windows)]
813mod sys {
814
815    use super::os_prelude::*;
816    use super::StdIoResult;
817    /// Overrides timeout value set by serialport-rs so that the read end will
818    /// never wake up with 0-byte payload.
819    pub(crate) fn override_comm_timeouts(handle: RawHandle) -> StdIoResult<()> {
820        let timeouts = COMMTIMEOUTS {
821            // wait at most 1ms between two bytes (0 means no timeout)
822            ReadIntervalTimeout: 1,
823            // disable "total" timeout to wait at least 1 byte forever
824            ReadTotalTimeoutMultiplier: 0,
825            ReadTotalTimeoutConstant: 0,
826            // write timeouts are just copied from serialport-rs
827            WriteTotalTimeoutMultiplier: 0,
828            WriteTotalTimeoutConstant: 0,
829        };
830
831        let r = unsafe { SetCommTimeouts(handle, &timeouts) };
832        if r == 0 {
833            return Err(io::Error::last_os_error());
834        }
835        Ok(())
836    }
837}
838
839#[cfg(unix)]
840impl Source for SerialStream {
841    #[inline(always)]
842    fn register(
843        &mut self,
844        registry: &Registry,
845        token: Token,
846        interests: Interest,
847    ) -> StdIoResult<()> {
848        SourceFd(&self.as_raw_fd()).register(registry, token, interests)
849    }
850
851    #[inline(always)]
852    fn reregister(
853        &mut self,
854        registry: &Registry,
855        token: Token,
856        interests: Interest,
857    ) -> StdIoResult<()> {
858        SourceFd(&self.as_raw_fd()).reregister(registry, token, interests)
859    }
860
861    #[inline(always)]
862    fn deregister(&mut self, registry: &Registry) -> StdIoResult<()> {
863        SourceFd(&self.as_raw_fd()).deregister(registry)
864    }
865}
866
867#[cfg(windows)]
868impl Source for SerialStream {
869    fn register(
870        &mut self,
871        registry: &Registry,
872        token: Token,
873        interest: Interest,
874    ) -> StdIoResult<()> {
875        self.pipe.register(registry, token, interest)
876    }
877
878    fn reregister(
879        &mut self,
880        registry: &Registry,
881        token: Token,
882        interest: Interest,
883    ) -> StdIoResult<()> {
884        self.pipe.reregister(registry, token, interest)
885    }
886
887    fn deregister(&mut self, registry: &Registry) -> StdIoResult<()> {
888        self.pipe.deregister(registry)
889    }
890}
891
892/// An extension trait for [`SerialPortBuilder`]
893///
894/// This trait adds an additional method to [`SerialPortBuilder`]:
895///
896/// - open_native_async
897///
898/// These methods mirror the [`SerialPortBuilder::open_native`] methods
899pub trait SerialPortBuilderExt {
900    /// Open a platform-specific interface to the port with the specified settings
901    fn open_native_async(self) -> Result<SerialStream>;
902}
903
904impl SerialPortBuilderExt for SerialPortBuilder {
905    /// Open a platform-specific interface to the port with the specified settings
906    fn open_native_async(self) -> Result<SerialStream> {
907        SerialStream::open(&self)
908    }
909}