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}