Skip to main content

serialport/
lib.rs

1//! serialport-rs is a cross-platform serial port library.
2//!
3//! The goal of this library is to expose a cross-platform and platform-specific API for enumerating
4//! and using blocking I/O with serial ports. This library exposes a similar API to that provided
5//! by [Qt's `QSerialPort` library](https://doc.qt.io/qt-5/qserialport.html).
6//!
7//! # Feature Overview
8//!
9//! The library has been organized such that there is a high-level `SerialPort` trait that provides
10//! a cross-platform API for accessing serial ports. This is the preferred method of interacting
11//! with ports. The `SerialPort::new().open*()` and `available_ports()` functions in the root
12//! provide cross-platform functionality.
13//!
14//! For platform-specific functionality, this crate is split into a `posix` and `windows` API with
15//! corresponding `TTYPort` and `COMPort` structs (that both implement the `SerialPort` trait).
16//! Using the platform-specific `SerialPort::new().open*()` functions will return the
17//! platform-specific port object which allows access to platform-specific functionality.
18
19#![allow(clippy::uninlined_format_args)]
20#![deny(
21    clippy::dbg_macro,
22    missing_docs,
23    missing_debug_implementations,
24    missing_copy_implementations
25)]
26// Document feature-gated elements on docs.rs. See
27// https://doc.rust-lang.org/rustdoc/unstable-features.html?highlight=doc(cfg#doccfg-recording-what-platforms-or-features-are-required-for-code-to-be-present
28// and
29// https://doc.rust-lang.org/rustdoc/unstable-features.html#doc_auto_cfg-automatically-generate-doccfg
30// with its latest update https://github.com/rust-lang/rust/pull/138907 for details.
31#![cfg_attr(docsrs, feature(doc_cfg))]
32// Don't worry about needing to `unwrap()` or otherwise handle some results in
33// doc tests.
34#![doc(test(attr(allow(unused_must_use))))]
35
36use std::error::Error as StdError;
37use std::fmt;
38use std::io;
39use std::str::FromStr;
40use std::time::Duration;
41
42#[cfg(unix)]
43mod posix;
44#[cfg(unix)]
45pub use posix::{BreakDuration, TTYPort};
46
47#[cfg(windows)]
48mod windows;
49#[cfg(windows)]
50pub use windows::COMPort;
51
52#[cfg(test)]
53pub(crate) mod tests;
54
55/// A type for results generated by interacting with serial ports
56///
57/// The `Err` type is hard-wired to [`serialport::Error`](struct.Error.html).
58pub type Result<T> = std::result::Result<T, Error>;
59
60/// Categories of errors that can occur when interacting with serial ports
61///
62/// This list is intended to grow over time and it is not recommended to
63/// exhaustively match against it.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum ErrorKind {
66    /// The device is not available.
67    ///
68    /// This could indicate that the device is in use by another process or was
69    /// disconnected while performing I/O.
70    NoDevice,
71
72    /// A parameter was incorrect.
73    InvalidInput,
74
75    /// An unknown error occurred.
76    Unknown,
77
78    /// An I/O error occurred.
79    ///
80    /// The type of I/O error is determined by the inner `io::ErrorKind`.
81    Io(io::ErrorKind),
82}
83
84/// An error type for serial port operations
85#[derive(Debug, Clone)]
86pub struct Error {
87    /// The kind of error this is
88    pub kind: ErrorKind,
89    /// A description of the error suitable for end-users
90    pub description: String,
91}
92
93impl Error {
94    /// Instantiates a new error
95    pub fn new<T: Into<String>>(kind: ErrorKind, description: T) -> Self {
96        Error {
97            kind,
98            description: description.into(),
99        }
100    }
101
102    /// Returns the corresponding `ErrorKind` for this error.
103    pub fn kind(&self) -> ErrorKind {
104        self.kind
105    }
106}
107
108impl fmt::Display for Error {
109    fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
110        fmt.write_str(&self.description)
111    }
112}
113
114impl StdError for Error {
115    fn description(&self) -> &str {
116        &self.description
117    }
118}
119
120impl From<io::Error> for Error {
121    fn from(io_error: io::Error) -> Error {
122        Error::new(ErrorKind::Io(io_error.kind()), format!("{}", io_error))
123    }
124}
125
126impl From<Error> for io::Error {
127    fn from(error: Error) -> io::Error {
128        let kind = match error.kind {
129            ErrorKind::NoDevice => io::ErrorKind::NotFound,
130            ErrorKind::InvalidInput => io::ErrorKind::InvalidInput,
131            ErrorKind::Unknown => io::ErrorKind::Other,
132            ErrorKind::Io(kind) => kind,
133        };
134
135        io::Error::new(kind, error.description)
136    }
137}
138
139/// Number of bits per character
140#[derive(Debug, Copy, Clone, PartialEq, Eq)]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub enum DataBits {
143    /// 5 bits per character
144    Five,
145
146    /// 6 bits per character
147    Six,
148
149    /// 7 bits per character
150    Seven,
151
152    /// 8 bits per character
153    Eight,
154}
155
156impl fmt::Display for DataBits {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        match *self {
159            DataBits::Five => write!(f, "Five"),
160            DataBits::Six => write!(f, "Six"),
161            DataBits::Seven => write!(f, "Seven"),
162            DataBits::Eight => write!(f, "Eight"),
163        }
164    }
165}
166
167impl From<DataBits> for u8 {
168    fn from(value: DataBits) -> Self {
169        match value {
170            DataBits::Five => 5,
171            DataBits::Six => 6,
172            DataBits::Seven => 7,
173            DataBits::Eight => 8,
174        }
175    }
176}
177
178impl TryFrom<u8> for DataBits {
179    type Error = ();
180
181    fn try_from(value: u8) -> core::result::Result<Self, Self::Error> {
182        match value {
183            5 => Ok(Self::Five),
184            6 => Ok(Self::Six),
185            7 => Ok(Self::Seven),
186            8 => Ok(Self::Eight),
187            _ => Err(()),
188        }
189    }
190}
191
192/// Parity checking modes
193///
194/// When parity checking is enabled (`Odd` or `Even`) an extra bit is transmitted with
195/// each character. The value of the parity bit is arranged so that the number of 1 bits in the
196/// character (including the parity bit) is an even number (`Even`) or an odd number
197/// (`Odd`).
198///
199/// Parity checking is disabled by setting `None`, in which case parity bits are not
200/// transmitted.
201#[derive(Debug, Copy, Clone, PartialEq, Eq)]
202#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
203pub enum Parity {
204    /// No parity bit.
205    None,
206
207    /// Parity bit sets odd number of 1 bits.
208    Odd,
209
210    /// Parity bit sets even number of 1 bits.
211    Even,
212}
213
214impl fmt::Display for Parity {
215    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216        match *self {
217            Parity::None => write!(f, "None"),
218            Parity::Odd => write!(f, "Odd"),
219            Parity::Even => write!(f, "Even"),
220        }
221    }
222}
223
224/// Number of stop bits
225///
226/// Stop bits are transmitted after every character.
227#[derive(Debug, Copy, Clone, PartialEq, Eq)]
228#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
229pub enum StopBits {
230    /// One stop bit.
231    One,
232
233    /// Two stop bits.
234    Two,
235}
236
237impl fmt::Display for StopBits {
238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239        match *self {
240            StopBits::One => write!(f, "One"),
241            StopBits::Two => write!(f, "Two"),
242        }
243    }
244}
245
246impl From<StopBits> for u8 {
247    fn from(value: StopBits) -> Self {
248        match value {
249            StopBits::One => 1,
250            StopBits::Two => 2,
251        }
252    }
253}
254
255impl TryFrom<u8> for StopBits {
256    type Error = ();
257
258    fn try_from(value: u8) -> core::result::Result<Self, Self::Error> {
259        match value {
260            1 => Ok(Self::One),
261            2 => Ok(Self::Two),
262            _ => Err(()),
263        }
264    }
265}
266
267/// Flow control modes
268#[derive(Debug, Copy, Clone, PartialEq, Eq)]
269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
270pub enum FlowControl {
271    /// No flow control.
272    None,
273
274    /// Flow control using XON/XOFF bytes.
275    Software,
276
277    /// Flow control using RTS/CTS signals.
278    Hardware,
279}
280
281impl fmt::Display for FlowControl {
282    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283        match *self {
284            FlowControl::None => write!(f, "None"),
285            FlowControl::Software => write!(f, "Software"),
286            FlowControl::Hardware => write!(f, "Hardware"),
287        }
288    }
289}
290
291impl FromStr for FlowControl {
292    type Err = ();
293
294    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
295        match s {
296            "None" | "none" | "n" => Ok(FlowControl::None),
297            "Software" | "software" | "SW" | "sw" | "s" => Ok(FlowControl::Software),
298            "Hardware" | "hardware" | "HW" | "hw" | "h" => Ok(FlowControl::Hardware),
299            _ => Err(()),
300        }
301    }
302}
303
304/// Specifies which buffer or buffers to purge when calling [`clear`]
305///
306/// [`clear`]: trait.SerialPort.html#tymethod.clear
307#[derive(Debug, Copy, Clone, PartialEq, Eq)]
308#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
309pub enum ClearBuffer {
310    /// Specify to clear data received but not read
311    Input,
312    /// Specify to clear data written but not yet transmitted
313    Output,
314    /// Specify to clear both data received and data not yet transmitted
315    All,
316}
317
318/// A struct containing all serial port settings
319#[derive(Debug, Clone, PartialEq, Eq)]
320pub struct SerialPortBuilder {
321    /// The port name, usually the device path
322    path: String,
323    /// The baud rate in symbols-per-second
324    baud_rate: u32,
325    /// Number of bits used to represent a character sent on the line
326    data_bits: DataBits,
327    /// The type of signalling to use for controlling data transfer
328    flow_control: FlowControl,
329    /// The type of parity to use for error checking
330    parity: Parity,
331    /// Number of bits to use to signal the end of a character
332    stop_bits: StopBits,
333    /// Amount of time to wait to receive data before timing out
334    timeout: Duration,
335    /// The state to set DTR to when opening the device
336    dtr_on_open: Option<bool>,
337    /// Whether to enforce exclusive access to the port
338    #[cfg(unix)]
339    exclusive: bool,
340}
341
342impl SerialPortBuilder {
343    /// Set the path to the serial port
344    // TODO: Switch to `clone_into` when bumping our MSRV past 1.63 and remove this exemption.
345    #[allow(clippy::assigning_clones)]
346    #[must_use]
347    pub fn path<'a>(mut self, path: impl Into<std::borrow::Cow<'a, str>>) -> Self {
348        self.path = path.into().as_ref().to_owned();
349        self
350    }
351
352    /// Set the baud rate in symbols-per-second
353    #[must_use]
354    pub fn baud_rate(mut self, baud_rate: u32) -> Self {
355        self.baud_rate = baud_rate;
356        self
357    }
358
359    /// Set the number of bits used to represent a character sent on the line
360    #[must_use]
361    pub fn data_bits(mut self, data_bits: DataBits) -> Self {
362        self.data_bits = data_bits;
363        self
364    }
365
366    /// Set the type of signalling to use for controlling data transfer
367    #[must_use]
368    pub fn flow_control(mut self, flow_control: FlowControl) -> Self {
369        self.flow_control = flow_control;
370        self
371    }
372
373    /// Set the type of parity to use for error checking
374    #[must_use]
375    pub fn parity(mut self, parity: Parity) -> Self {
376        self.parity = parity;
377        self
378    }
379
380    /// Set the number of bits to use to signal the end of a character
381    #[must_use]
382    pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
383        self.stop_bits = stop_bits;
384        self
385    }
386
387    /// Set the amount of time to wait to receive data before timing out
388    ///
389    /// <div class="warning">
390    ///
391    /// The accuracy is limited by the underlying platform's capabilities. Longer timeouts will be
392    /// clamped to the maximum supported value which is expected to be in the magnitude of a few
393    /// days.
394    ///
395    /// </div>
396    #[must_use]
397    pub fn timeout(mut self, timeout: Duration) -> Self {
398        self.timeout = timeout;
399        self
400    }
401
402    /// Set data terminal ready (DTR) to the given state when opening the device
403    ///
404    /// Note: On Linux, DTR is automatically set on open. Even if you set `dtr_on_open` to false,
405    /// DTR will be asserted for a short moment when opening the port. This can't be prevented
406    /// without kernel modifications.
407    #[must_use]
408    pub fn dtr_on_open(mut self, state: bool) -> Self {
409        self.dtr_on_open = Some(state);
410        self
411    }
412
413    /// Preserve the state of data terminal ready (DTR) when opening the device. Your outcome may
414    /// vary depending on the operation system. For example, Linux sets DTR by default and Windows
415    /// doesn't.
416    #[must_use]
417    pub fn preserve_dtr_on_open(mut self) -> Self {
418        self.dtr_on_open = None;
419        self
420    }
421
422    /// Set whether the port should be opened with exclusive access.
423    ///
424    /// By default, ports are opened with exclusive access. This is what you typically want as
425    /// opening and accessing the very same port multiple times results in garbled data on or from
426    /// the wire.
427    #[cfg(unix)]
428    #[must_use]
429    pub fn exclusive(mut self, exclusive: bool) -> Self {
430        self.exclusive = exclusive;
431        self
432    }
433
434    /// Open a cross-platform interface to the port with the specified settings
435    pub fn open(self) -> Result<Box<dyn SerialPort>> {
436        #[cfg(unix)]
437        return posix::TTYPort::open(&self).map(|p| Box::new(p) as Box<dyn SerialPort>);
438
439        #[cfg(windows)]
440        return windows::COMPort::open(&self).map(|p| Box::new(p) as Box<dyn SerialPort>);
441
442        #[cfg(not(any(unix, windows)))]
443        Err(Error::new(
444            ErrorKind::Unknown,
445            "open() not implemented for platform",
446        ))
447    }
448
449    /// Open a platform-specific interface to the port with the specified settings
450    #[cfg(unix)]
451    pub fn open_native(self) -> Result<TTYPort> {
452        posix::TTYPort::open(&self)
453    }
454
455    /// Open a platform-specific interface to the port with the specified settings
456    #[cfg(windows)]
457    pub fn open_native(self) -> Result<COMPort> {
458        windows::COMPort::open(&self)
459    }
460}
461
462/// A trait for serial port devices
463///
464/// This trait is all that's necessary to implement a new serial port driver
465/// for a new platform.
466pub trait SerialPort: Send + io::Read + io::Write {
467    // Port settings getters
468
469    /// Returns the name of this port if it exists.
470    ///
471    /// This name may not be the canonical device name and instead be shorthand.
472    /// Additionally it may not exist for virtual ports.
473    fn name(&self) -> Option<String>;
474
475    /// Returns the current baud rate.
476    ///
477    /// This may return a value different from the last specified baud rate depending on the
478    /// platform as some will return the actual device baud rate rather than the last specified
479    /// baud rate.
480    fn baud_rate(&self) -> Result<u32>;
481
482    /// Returns the character size.
483    ///
484    /// This function returns `None` if the character size could not be determined. This may occur
485    /// if the hardware is in an uninitialized state or is using a non-standard character size.
486    /// Setting a baud rate with `set_char_size()` should initialize the character size to a
487    /// supported value.
488    fn data_bits(&self) -> Result<DataBits>;
489
490    /// Returns the flow control mode.
491    ///
492    /// This function returns `None` if the flow control mode could not be determined. This may
493    /// occur if the hardware is in an uninitialized state or is using an unsupported flow control
494    /// mode. Setting a flow control mode with `set_flow_control()` should initialize the flow
495    /// control mode to a supported value.
496    fn flow_control(&self) -> Result<FlowControl>;
497
498    /// Returns the parity-checking mode.
499    ///
500    /// This function returns `None` if the parity mode could not be determined. This may occur if
501    /// the hardware is in an uninitialized state or is using a non-standard parity mode. Setting
502    /// a parity mode with `set_parity()` should initialize the parity mode to a supported value.
503    fn parity(&self) -> Result<Parity>;
504
505    /// Returns the number of stop bits.
506    ///
507    /// This function returns `None` if the number of stop bits could not be determined. This may
508    /// occur if the hardware is in an uninitialized state or is using an unsupported stop bit
509    /// configuration. Setting the number of stop bits with `set_stop-bits()` should initialize the
510    /// stop bits to a supported value.
511    fn stop_bits(&self) -> Result<StopBits>;
512
513    /// Returns the current timeout.
514    fn timeout(&self) -> Duration;
515
516    // Port settings setters
517
518    /// Sets the baud rate.
519    ///
520    /// ## Errors
521    ///
522    /// If the implementation does not support the requested baud rate, this function may return an
523    /// `InvalidInput` error. Even if the baud rate is accepted by `set_baud_rate()`, it may not be
524    /// supported by the underlying hardware.
525    fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()>;
526
527    /// Sets the character size.
528    fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()>;
529
530    /// Sets the flow control mode.
531    fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()>;
532
533    /// Sets the parity-checking mode.
534    fn set_parity(&mut self, parity: Parity) -> Result<()>;
535
536    /// Sets the number of stop bits.
537    fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()>;
538
539    /// Sets the timeout for future I/O operations.
540    ///
541    /// <div class="warning">
542    ///
543    /// The accuracy is limited by the underlying platform's capabilities. Longer timeouts will be
544    /// clamped to the maximum supported value which is expected to be in the magnitude of a few
545    /// days.
546    ///
547    /// </div>
548    fn set_timeout(&mut self, timeout: Duration) -> Result<()>;
549
550    // Functions for setting non-data control signal pins
551
552    /// Sets the state of the RTS (Request To Send) control signal.
553    ///
554    /// Setting a value of `true` asserts the RTS control signal. `false` clears the signal.
555    ///
556    /// ## Errors
557    ///
558    /// This function returns an error if the RTS control signal could not be set to the desired
559    /// state on the underlying hardware:
560    ///
561    /// * `NoDevice` if the device was disconnected.
562    /// * `Io` for any other type of I/O error.
563    fn write_request_to_send(&mut self, level: bool) -> Result<()>;
564
565    /// Writes to the Data Terminal Ready pin
566    ///
567    /// Setting a value of `true` asserts the DTR control signal. `false` clears the signal.
568    ///
569    /// ## Errors
570    ///
571    /// This function returns an error if the DTR control signal could not be set to the desired
572    /// state on the underlying hardware:
573    ///
574    /// * `NoDevice` if the device was disconnected.
575    /// * `Io` for any other type of I/O error.
576    fn write_data_terminal_ready(&mut self, level: bool) -> Result<()>;
577
578    // Functions for reading additional pins
579
580    /// Reads the state of the CTS (Clear To Send) control signal.
581    ///
582    /// This function returns a boolean that indicates whether the CTS control signal is asserted.
583    ///
584    /// ## Errors
585    ///
586    /// This function returns an error if the state of the CTS control signal could not be read
587    /// from the underlying hardware:
588    ///
589    /// * `NoDevice` if the device was disconnected.
590    /// * `Io` for any other type of I/O error.
591    fn read_clear_to_send(&mut self) -> Result<bool>;
592
593    /// Reads the state of the Data Set Ready control signal.
594    ///
595    /// This function returns a boolean that indicates whether the DSR control signal is asserted.
596    ///
597    /// ## Errors
598    ///
599    /// This function returns an error if the state of the DSR control signal could not be read
600    /// from the underlying hardware:
601    ///
602    /// * `NoDevice` if the device was disconnected.
603    /// * `Io` for any other type of I/O error.
604    fn read_data_set_ready(&mut self) -> Result<bool>;
605
606    /// Reads the state of the Ring Indicator control signal.
607    ///
608    /// This function returns a boolean that indicates whether the RI control signal is asserted.
609    ///
610    /// ## Errors
611    ///
612    /// This function returns an error if the state of the RI control signal could not be read from
613    /// the underlying hardware:
614    ///
615    /// * `NoDevice` if the device was disconnected.
616    /// * `Io` for any other type of I/O error.
617    fn read_ring_indicator(&mut self) -> Result<bool>;
618
619    /// Reads the state of the Carrier Detect control signal.
620    ///
621    /// This function returns a boolean that indicates whether the CD control signal is asserted.
622    ///
623    /// ## Errors
624    ///
625    /// This function returns an error if the state of the CD control signal could not be read from
626    /// the underlying hardware:
627    ///
628    /// * `NoDevice` if the device was disconnected.
629    /// * `Io` for any other type of I/O error.
630    fn read_carrier_detect(&mut self) -> Result<bool>;
631
632    /// Gets the number of bytes available to be read from the input buffer.
633    ///
634    /// # Errors
635    ///
636    /// This function may return the following errors:
637    ///
638    /// * `NoDevice` if the device was disconnected.
639    /// * `Io` for any other type of I/O error.
640    fn bytes_to_read(&self) -> Result<u32>;
641
642    /// Get the number of bytes written to the output buffer, awaiting transmission.
643    ///
644    /// # Errors
645    ///
646    /// This function may return the following errors:
647    ///
648    /// * `NoDevice` if the device was disconnected.
649    /// * `Io` for any other type of I/O error.
650    fn bytes_to_write(&self) -> Result<u32>;
651
652    /// Discards all bytes from the serial driver's input buffer and/or output buffer.
653    ///
654    /// # Errors
655    ///
656    /// This function may return the following errors:
657    ///
658    /// * `NoDevice` if the device was disconnected.
659    /// * `Io` for any other type of I/O error.
660    fn clear(&self, buffer_to_clear: ClearBuffer) -> Result<()>;
661
662    // Misc methods
663
664    /// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the
665    /// same serial connection. Please note that if you want a real asynchronous serial port you
666    /// should look at [mio-serial](https://crates.io/crates/mio-serial) or
667    /// [tokio-serial](https://crates.io/crates/tokio-serial).
668    ///
669    /// Also, you must be very careful when changing the settings of a cloned `SerialPort` : since
670    /// the settings are cached on a per object basis, trying to modify them from two different
671    /// objects can cause some nasty behavior.
672    ///
673    /// # Errors
674    ///
675    /// This function returns an error if the serial port couldn't be cloned.
676    fn try_clone(&self) -> Result<Box<dyn SerialPort>>;
677
678    /// Start transmitting a break
679    fn set_break(&self) -> Result<()>;
680
681    /// Stop transmitting a break
682    fn clear_break(&self) -> Result<()>;
683}
684
685impl<T: SerialPort> SerialPort for &mut T {
686    fn name(&self) -> Option<String> {
687        (**self).name()
688    }
689
690    fn baud_rate(&self) -> Result<u32> {
691        (**self).baud_rate()
692    }
693
694    fn data_bits(&self) -> Result<DataBits> {
695        (**self).data_bits()
696    }
697
698    fn flow_control(&self) -> Result<FlowControl> {
699        (**self).flow_control()
700    }
701
702    fn parity(&self) -> Result<Parity> {
703        (**self).parity()
704    }
705
706    fn stop_bits(&self) -> Result<StopBits> {
707        (**self).stop_bits()
708    }
709
710    fn timeout(&self) -> Duration {
711        (**self).timeout()
712    }
713
714    fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> {
715        (**self).set_baud_rate(baud_rate)
716    }
717
718    fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()> {
719        (**self).set_data_bits(data_bits)
720    }
721
722    fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()> {
723        (**self).set_flow_control(flow_control)
724    }
725
726    fn set_parity(&mut self, parity: Parity) -> Result<()> {
727        (**self).set_parity(parity)
728    }
729
730    fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()> {
731        (**self).set_stop_bits(stop_bits)
732    }
733
734    fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
735        (**self).set_timeout(timeout)
736    }
737
738    fn write_request_to_send(&mut self, level: bool) -> Result<()> {
739        (**self).write_request_to_send(level)
740    }
741
742    fn write_data_terminal_ready(&mut self, level: bool) -> Result<()> {
743        (**self).write_data_terminal_ready(level)
744    }
745
746    fn read_clear_to_send(&mut self) -> Result<bool> {
747        (**self).read_clear_to_send()
748    }
749
750    fn read_data_set_ready(&mut self) -> Result<bool> {
751        (**self).read_data_set_ready()
752    }
753
754    fn read_ring_indicator(&mut self) -> Result<bool> {
755        (**self).read_ring_indicator()
756    }
757
758    fn read_carrier_detect(&mut self) -> Result<bool> {
759        (**self).read_carrier_detect()
760    }
761
762    fn bytes_to_read(&self) -> Result<u32> {
763        (**self).bytes_to_read()
764    }
765
766    fn bytes_to_write(&self) -> Result<u32> {
767        (**self).bytes_to_write()
768    }
769
770    fn clear(&self, buffer_to_clear: ClearBuffer) -> Result<()> {
771        (**self).clear(buffer_to_clear)
772    }
773
774    fn try_clone(&self) -> Result<Box<dyn SerialPort>> {
775        (**self).try_clone()
776    }
777
778    fn set_break(&self) -> Result<()> {
779        (**self).set_break()
780    }
781
782    fn clear_break(&self) -> Result<()> {
783        (**self).clear_break()
784    }
785}
786
787impl fmt::Debug for dyn SerialPort {
788    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
789        write!(f, "SerialPort ( ")?;
790
791        if let Some(n) = self.name().as_ref() {
792            write!(f, "name: {} ", n)?;
793        };
794        if let Ok(b) = self.baud_rate().as_ref() {
795            write!(f, "baud_rate: {} ", b)?;
796        };
797        if let Ok(b) = self.data_bits().as_ref() {
798            write!(f, "data_bits: {} ", b)?;
799        };
800        if let Ok(c) = self.flow_control().as_ref() {
801            write!(f, "flow_control: {} ", c)?;
802        }
803        if let Ok(p) = self.parity().as_ref() {
804            write!(f, "parity: {} ", p)?;
805        }
806        if let Ok(s) = self.stop_bits().as_ref() {
807            write!(f, "stop_bits: {} ", s)?;
808        }
809
810        write!(f, ")")
811    }
812}
813
814/// Contains all possible USB information about a `SerialPort`
815#[derive(Clone, PartialEq, Eq)]
816#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
817pub struct UsbPortInfo {
818    /// Vendor ID
819    pub vid: u16,
820    /// Product ID
821    pub pid: u16,
822    /// Serial number (arbitrary string)
823    pub serial_number: Option<String>,
824    /// Manufacturer (arbitrary string)
825    pub manufacturer: Option<String>,
826    /// Product name (arbitrary string)
827    pub product: Option<String>,
828    /// The interface index of the USB serial port. This can be either the interface number of
829    /// the communication interface (as is the case on Windows and Linux) or the data
830    /// interface (as is the case on macOS), so you should recognize both interface numbers.
831    #[cfg(feature = "usbportinfo-interface")]
832    pub interface: Option<u8>,
833}
834
835struct HexU16(u16);
836
837impl std::fmt::Debug for HexU16 {
838    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
839        write!(f, "0x{:04x}", self.0)
840    }
841}
842
843impl std::fmt::Debug for UsbPortInfo {
844    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
845        let mut d = f.debug_struct("UsbPortInfo");
846        d.field("vid", &HexU16(self.vid))
847            .field("pid", &HexU16(self.pid))
848            .field("serial_number", &self.serial_number)
849            .field("manufacturer", &self.manufacturer)
850            .field("product", &self.product);
851
852        #[cfg(feature = "usbportinfo-interface")]
853        {
854            d.field("interface", &self.interface);
855        }
856
857        d.finish()
858    }
859}
860
861/// The physical type of a `SerialPort`
862#[derive(Debug, Clone, PartialEq, Eq)]
863#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
864pub enum SerialPortType {
865    /// The serial port is connected via USB
866    UsbPort(UsbPortInfo),
867    /// The serial port is connected via PCI (permanent port)
868    PciPort,
869    /// The serial port is connected via Bluetooth
870    BluetoothPort,
871    /// It can't be determined how the serial port is connected
872    Unknown,
873}
874
875/// A device-independent implementation of serial port information
876#[derive(Debug, Clone, PartialEq, Eq)]
877#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
878pub struct SerialPortInfo {
879    /// The short name of the serial port
880    pub port_name: String,
881    /// The hardware device type that exposes this port
882    pub port_type: SerialPortType,
883}
884
885/// Construct a builder of `SerialPort` objects
886///
887/// `SerialPort` objects are built using the Builder pattern through the `new` function. The
888/// resultant `SerialPortBuilder` object can be copied, reconfigured, and saved making working with
889/// multiple serial ports a little easier.
890///
891/// To open a new serial port:
892/// ```no_run
893/// serialport::new("/dev/ttyUSB0", 9600).open().expect("Failed to open port");
894/// ```
895pub fn new<'a>(path: impl Into<std::borrow::Cow<'a, str>>, baud_rate: u32) -> SerialPortBuilder {
896    SerialPortBuilder {
897        path: path.into().into_owned(),
898        baud_rate,
899        data_bits: DataBits::Eight,
900        flow_control: FlowControl::None,
901        parity: Parity::None,
902        stop_bits: StopBits::One,
903        timeout: Duration::from_millis(0),
904        // Leave DTR alone when opening a device. We've started out with setting DTR on open (see
905        // issues #29 and #204) but despite pleasing some Arduino use cases, this apparently caused
906        // problems with other boards and when using pseudo terminals (see issues #243 and #251).
907        //
908        // To me it looks that the fallout from setting DTR on open by default gets on a
909        // substantially larger area than the one benefitting from it, I finally decided to revert
910        // this. Sorry for this back and forth, Christian.
911        dtr_on_open: None,
912        #[cfg(unix)]
913        exclusive: true,
914    }
915}
916
917/// Returns a list of all serial ports on system
918///
919/// It is not guaranteed that these ports exist or are available even if they're
920/// returned by this function.
921pub fn available_ports() -> Result<Vec<SerialPortInfo>> {
922    #[cfg(unix)]
923    return crate::posix::available_ports();
924
925    #[cfg(windows)]
926    return crate::windows::available_ports();
927
928    #[cfg(not(any(unix, windows)))]
929    Err(Error::new(
930        ErrorKind::Unknown,
931        "available_ports() not implemented for platform",
932    ))
933}
934
935#[cfg(test)]
936mod test {
937    use super::*;
938    use rstest::rstest;
939
940    /// Checks parameters and that default values don't get charged by accident.
941    #[rstest]
942    fn builder_new() {
943        let builder = new("port_test_dummy", 12345);
944
945        assert_eq!(builder.path, "port_test_dummy");
946        assert_eq!(builder.baud_rate, 12345);
947
948        assert_eq!(builder.data_bits, DataBits::Eight);
949        assert_eq!(builder.flow_control, FlowControl::None);
950        assert_eq!(builder.parity, Parity::None);
951        assert_eq!(builder.stop_bits, StopBits::One);
952        assert_eq!(builder.timeout, Duration::ZERO);
953        assert_eq!(builder.dtr_on_open, None);
954        #[cfg(unix)]
955        assert!(builder.exclusive);
956    }
957
958    // Checks that the builder's exclusive method changes the state accordingly.
959    #[cfg(unix)]
960    #[rstest]
961    fn builder_exclusive() {
962        let builder = new("port_test_dummy", 12345);
963        assert!(builder.exclusive);
964
965        let builder = builder.exclusive(false);
966        assert!(!builder.exclusive);
967
968        let builder = builder.exclusive(true);
969        assert!(builder.exclusive);
970    }
971
972    #[rstest]
973    fn usbportinfo_debug_representation() {
974        let info = UsbPortInfo {
975            manufacturer: Some(String::from("your manufacutrer here")),
976            vid: 0xbade,
977            pid: 0xaffe,
978            product: Some(String::from("your product here")),
979            serial_number: Some(String::from("your serial_number here")),
980            #[cfg(feature = "usbportinfo-interface")]
981            interface: Some(42),
982        };
983        let formatted = format!("{:?}", info);
984
985        // Set the expectiation for the debug representation basend on a "snapshot" of the current
986        // one, manually cross-checked to contain a VID and PID in hexadecimal digits.
987        #[cfg(not(feature = "usbportinfo-interface"))]
988        let expected = "UsbPortInfo { vid: 0xbade, pid: 0xaffe, serial_number: Some(\"your serial_number here\"), manufacturer: Some(\"your manufacutrer here\"), product: Some(\"your product here\") }";
989        #[cfg(feature = "usbportinfo-interface")]
990        let expected = "UsbPortInfo { vid: 0xbade, pid: 0xaffe, serial_number: Some(\"your serial_number here\"), manufacturer: Some(\"your manufacutrer here\"), product: Some(\"your product here\"), interface: Some(42) }";
991
992        assert_eq!(formatted, expected);
993    }
994}