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 winapi::um::commapi::SetCommTimeouts;
64 pub use winapi::um::fileapi::*;
65 pub use winapi::um::handleapi::INVALID_HANDLE_VALUE;
66 pub use winapi::um::winbase::{COMMTIMEOUTS, FILE_FLAG_OVERLAPPED};
67 pub use winapi::um::winnt::{
68 FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE,
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.baud_rate()?;
554 let parity = port.parity()?;
555 let data_bits = port.data_bits()?;
556 let stop_bits = port.stop_bits()?;
557 let flow_control = port.flow_control()?;
558
559 let mut path = Vec::<u16>::new();
560 path.extend(OsStr::new("\\\\.\\").encode_wide());
561 path.extend(Path::new(&name).as_os_str().encode_wide());
562 path.push(0);
563
564 // Drop the port object, we'll reopen the file path as a raw handle
565 log::debug!("closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode");
566 mem::drop(port);
567
568 let handle = unsafe {
569 CreateFileW(
570 path.as_ptr(),
571 GENERIC_READ | GENERIC_WRITE,
572 0,
573 ptr::null_mut(),
574 OPEN_EXISTING,
575 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
576 0 as HANDLE,
577 )
578 };
579
580 if handle == INVALID_HANDLE_VALUE {
581 log::error!("unable to open new async file handle");
582 return Err(crate::Error::from(StdIoError::last_os_error()));
583 }
584
585 // Construct NamedPipe and COMPort from Handle
586 //
587 // We need both the NamedPipe for Read/Write and COMPort for serialport related
588 // actions. Both are created using FromRawHandle which takes ownership of the
589 // handle which may case a double-free as both objects attempt to close the handle.
590 //
591 // Looking through the source for both NamedPipe and COMPort, NamedPipe does some
592 // cleanup in Drop while COMPort just closes the handle.
593 //
594 // We'll use a ManuallyDrop<T> for COMPort and defer cleanup to the NamedPipe
595 let pipe = unsafe { NamedPipe::from_raw_handle(handle) };
596 let mut com_port =
597 mem::ManuallyDrop::new(unsafe { serialport::COMPort::from_raw_handle(handle) });
598
599 log::debug!("re-setting serial port parameters to original values from synchronous port");
600 com_port.set_baud_rate(baud)?;
601 com_port.set_parity(parity)?;
602 com_port.set_data_bits(data_bits)?;
603 com_port.set_stop_bits(stop_bits)?;
604 com_port.set_flow_control(flow_control)?;
605 sys::override_comm_timeouts(handle)?;
606
607 Ok(Self {
608 inner: com_port,
609 pipe,
610 })
611 }
612}
613
614#[cfg(unix)]
615mod io {
616 use super::{SerialStream, StdIoError, StdIoResult};
617 use nix::libc;
618 use nix::sys::termios;
619 use std::io::ErrorKind as StdIoErrorKind;
620 use std::io::{Read, Write};
621 use std::os::unix::prelude::*;
622
623 macro_rules! uninterruptibly {
624 ($e:expr) => {{
625 loop {
626 match $e {
627 Err(ref error) if error.kind() == StdIoErrorKind::Interrupted => {}
628 res => break res,
629 }
630 }
631 }};
632 }
633
634 impl Read for SerialStream {
635 fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
636 uninterruptibly!(match unsafe {
637 libc::read(
638 self.as_raw_fd(),
639 bytes.as_ptr() as *mut libc::c_void,
640 bytes.len() as libc::size_t,
641 )
642 } {
643 x if x >= 0 => Ok(x as usize),
644 _ => Err(StdIoError::last_os_error()),
645 })
646 }
647 }
648
649 impl Write for SerialStream {
650 fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
651 uninterruptibly!(match unsafe {
652 libc::write(
653 self.as_raw_fd(),
654 bytes.as_ptr().cast::<libc::c_void>(),
655 bytes.len() as libc::size_t,
656 )
657 } {
658 x if x >= 0 => Ok(x as usize),
659 _ => Err(StdIoError::last_os_error()),
660 })
661 }
662
663 fn flush(&mut self) -> StdIoResult<()> {
664 uninterruptibly!(termios::tcdrain(unsafe {
665 BorrowedFd::borrow_raw(self.inner.as_raw_fd())
666 })
667 .map_err(StdIoError::from))
668 }
669 }
670
671 impl<'a> Read for &'a SerialStream {
672 fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
673 uninterruptibly!(match unsafe {
674 libc::read(
675 self.as_raw_fd(),
676 bytes.as_ptr() as *mut libc::c_void,
677 bytes.len() as libc::size_t,
678 )
679 } {
680 x if x >= 0 => Ok(x as usize),
681 _ => Err(StdIoError::last_os_error()),
682 })
683 }
684 }
685
686 impl<'a> Write for &'a SerialStream {
687 fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
688 uninterruptibly!(match unsafe {
689 libc::write(
690 self.as_raw_fd(),
691 bytes.as_ptr() as *const libc::c_void,
692 bytes.len() as libc::size_t,
693 )
694 } {
695 x if x >= 0 => Ok(x as usize),
696 _ => Err(StdIoError::last_os_error()),
697 })
698 }
699
700 fn flush(&mut self) -> StdIoResult<()> {
701 uninterruptibly!(termios::tcdrain(unsafe {
702 BorrowedFd::borrow_raw(self.inner.as_raw_fd())
703 })
704 .map_err(StdIoError::from))
705 }
706 }
707}
708
709#[cfg(windows)]
710mod io {
711 use super::{NativeBlockingSerialPort, SerialStream, StdIoResult};
712 use crate::sys;
713 use mio::windows::NamedPipe;
714 use std::io::{Read, Write};
715 use std::mem;
716 use std::os::windows::prelude::*;
717
718 impl Read for SerialStream {
719 fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
720 self.pipe.read(bytes)
721 }
722 }
723
724 impl Write for SerialStream {
725 fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
726 self.pipe.write(bytes)
727 }
728
729 fn flush(&mut self) -> StdIoResult<()> {
730 self.pipe.flush()
731 }
732 }
733
734 impl AsRawHandle for SerialStream {
735 fn as_raw_handle(&self) -> RawHandle {
736 self.pipe.as_raw_handle()
737 }
738 }
739
740 impl IntoRawHandle for SerialStream {
741 fn into_raw_handle(self) -> RawHandle {
742 // Since NamedPipe doesn't impl IntoRawHandle we'll use AsRawHandle and bypass
743 // NamedPipe's destructor to keep the handle in the current state
744 let manual = mem::ManuallyDrop::new(self.pipe);
745 manual.as_raw_handle()
746 }
747 }
748
749 impl FromRawHandle for SerialStream {
750 /// This method can potentially fail to override the communication timeout
751 /// value set in `sys::override_comm_timeouts` without any indication to the user.
752 unsafe fn from_raw_handle(handle: RawHandle) -> Self {
753 let inner = mem::ManuallyDrop::new(NativeBlockingSerialPort::from_raw_handle(handle));
754 let pipe = NamedPipe::from_raw_handle(handle);
755 sys::override_comm_timeouts(handle).ok();
756
757 Self { inner, pipe }
758 }
759 }
760}
761
762#[cfg(unix)]
763mod sys {
764 use super::{NativeBlockingSerialPort, SerialStream};
765 use std::os::unix::prelude::*;
766
767 impl AsRawFd for SerialStream {
768 fn as_raw_fd(&self) -> RawFd {
769 self.inner.as_raw_fd()
770 }
771 }
772
773 impl IntoRawFd for SerialStream {
774 fn into_raw_fd(self) -> RawFd {
775 self.inner.into_raw_fd()
776 }
777 }
778
779 impl FromRawFd for SerialStream {
780 unsafe fn from_raw_fd(fd: RawFd) -> Self {
781 let port = NativeBlockingSerialPort::from_raw_fd(fd);
782 Self { inner: port }
783 }
784 }
785}
786
787#[cfg(windows)]
788mod sys {
789
790 use super::os_prelude::*;
791 use super::StdIoResult;
792 /// Overrides timeout value set by serialport-rs so that the read end will
793 /// never wake up with 0-byte payload.
794 pub(crate) fn override_comm_timeouts(handle: RawHandle) -> StdIoResult<()> {
795 let mut timeouts = COMMTIMEOUTS {
796 // wait at most 1ms between two bytes (0 means no timeout)
797 ReadIntervalTimeout: 1,
798 // disable "total" timeout to wait at least 1 byte forever
799 ReadTotalTimeoutMultiplier: 0,
800 ReadTotalTimeoutConstant: 0,
801 // write timeouts are just copied from serialport-rs
802 WriteTotalTimeoutMultiplier: 0,
803 WriteTotalTimeoutConstant: 0,
804 };
805
806 let r = unsafe { SetCommTimeouts(handle, &mut timeouts) };
807 if r == 0 {
808 return Err(io::Error::last_os_error());
809 }
810 Ok(())
811 }
812}
813
814#[cfg(unix)]
815impl Source for SerialStream {
816 #[inline(always)]
817 fn register(
818 &mut self,
819 registry: &Registry,
820 token: Token,
821 interests: Interest,
822 ) -> StdIoResult<()> {
823 SourceFd(&self.as_raw_fd()).register(registry, token, interests)
824 }
825
826 #[inline(always)]
827 fn reregister(
828 &mut self,
829 registry: &Registry,
830 token: Token,
831 interests: Interest,
832 ) -> StdIoResult<()> {
833 SourceFd(&self.as_raw_fd()).reregister(registry, token, interests)
834 }
835
836 #[inline(always)]
837 fn deregister(&mut self, registry: &Registry) -> StdIoResult<()> {
838 SourceFd(&self.as_raw_fd()).deregister(registry)
839 }
840}
841
842#[cfg(windows)]
843impl Source for SerialStream {
844 fn register(
845 &mut self,
846 registry: &Registry,
847 token: Token,
848 interest: Interest,
849 ) -> StdIoResult<()> {
850 self.pipe.register(registry, token, interest)
851 }
852
853 fn reregister(
854 &mut self,
855 registry: &Registry,
856 token: Token,
857 interest: Interest,
858 ) -> StdIoResult<()> {
859 self.pipe.reregister(registry, token, interest)
860 }
861
862 fn deregister(&mut self, registry: &Registry) -> StdIoResult<()> {
863 self.pipe.deregister(registry)
864 }
865}
866
867/// An extension trait for [`SerialPortBuilder`]
868///
869/// This trait adds an additional method to [`SerialPortBuilder`]:
870///
871/// - open_native_async
872///
873/// These methods mirror the [`SerialPortBuilder::open_native`] methods
874pub trait SerialPortBuilderExt {
875 /// Open a platform-specific interface to the port with the specified settings
876 fn open_native_async(self) -> Result<SerialStream>;
877}
878
879impl SerialPortBuilderExt for SerialPortBuilder {
880 /// Open a platform-specific interface to the port with the specified settings
881 fn open_native_async(self) -> Result<SerialStream> {
882 SerialStream::open(&self)
883 }
884}