| //! serialport-rs is a cross-platform serial port library. |
| //! |
| //! The goal of this library is to expose a cross-platform and platform-specific API for enumerating |
| //! and using blocking I/O with serial ports. This library exposes a similar API to that provided |
| //! by [Qt's `QSerialPort` library](https://doc.qt.io/qt-5/qserialport.html). |
| //! |
| //! # Feature Overview |
| //! |
| //! The library has been organized such that there is a high-level `SerialPort` trait that provides |
| //! a cross-platform API for accessing serial ports. This is the preferred method of interacting |
| //! with ports. The `SerialPort::new().open*()` and `available_ports()` functions in the root |
| //! provide cross-platform functionality. |
| //! |
| //! For platform-specific functionality, this crate is split into a `posix` and `windows` API with |
| //! corresponding `TTYPort` and `COMPort` structs (that both implement the `SerialPort` trait). |
| //! Using the platform-specific `SerialPort::new().open*()` functions will return the |
| //! platform-specific port object which allows access to platform-specific functionality. |
| |
| #![deny( |
| clippy::dbg_macro, |
| missing_docs, |
| missing_debug_implementations, |
| missing_copy_implementations |
| )] |
| // Document feature-gated elements on docs.rs. See |
| // 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 |
| // and |
| // https://doc.rust-lang.org/rustdoc/unstable-features.html#doc_auto_cfg-automatically-generate-doccfg |
| // for details. |
| #![cfg_attr(docsrs, feature(doc_auto_cfg))] |
| // Don't worry about needing to `unwrap()` or otherwise handle some results in |
| // doc tests. |
| #![doc(test(attr(allow(unused_must_use))))] |
| |
| use std::error::Error as StdError; |
| use std::fmt; |
| use std::io; |
| use std::str::FromStr; |
| use std::time::Duration; |
| |
| #[cfg(unix)] |
| mod posix; |
| #[cfg(unix)] |
| pub use posix::{BreakDuration, TTYPort}; |
| |
| #[cfg(windows)] |
| mod windows; |
| #[cfg(windows)] |
| pub use windows::COMPort; |
| |
| #[cfg(test)] |
| pub(crate) mod tests; |
| |
| /// A type for results generated by interacting with serial ports |
| /// |
| /// The `Err` type is hard-wired to [`serialport::Error`](struct.Error.html). |
| pub type Result<T> = std::result::Result<T, Error>; |
| |
| /// Categories of errors that can occur when interacting with serial ports |
| /// |
| /// This list is intended to grow over time and it is not recommended to |
| /// exhaustively match against it. |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| pub enum ErrorKind { |
| /// The device is not available. |
| /// |
| /// This could indicate that the device is in use by another process or was |
| /// disconnected while performing I/O. |
| NoDevice, |
| |
| /// A parameter was incorrect. |
| InvalidInput, |
| |
| /// An unknown error occurred. |
| Unknown, |
| |
| /// An I/O error occurred. |
| /// |
| /// The type of I/O error is determined by the inner `io::ErrorKind`. |
| Io(io::ErrorKind), |
| } |
| |
| /// An error type for serial port operations |
| #[derive(Debug, Clone)] |
| pub struct Error { |
| /// The kind of error this is |
| pub kind: ErrorKind, |
| /// A description of the error suitable for end-users |
| pub description: String, |
| } |
| |
| impl Error { |
| /// Instantiates a new error |
| pub fn new<T: Into<String>>(kind: ErrorKind, description: T) -> Self { |
| Error { |
| kind, |
| description: description.into(), |
| } |
| } |
| |
| /// Returns the corresponding `ErrorKind` for this error. |
| pub fn kind(&self) -> ErrorKind { |
| self.kind |
| } |
| } |
| |
| impl fmt::Display for Error { |
| fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> { |
| fmt.write_str(&self.description) |
| } |
| } |
| |
| impl StdError for Error { |
| fn description(&self) -> &str { |
| &self.description |
| } |
| } |
| |
| impl From<io::Error> for Error { |
| fn from(io_error: io::Error) -> Error { |
| Error::new(ErrorKind::Io(io_error.kind()), format!("{}", io_error)) |
| } |
| } |
| |
| impl From<Error> for io::Error { |
| fn from(error: Error) -> io::Error { |
| let kind = match error.kind { |
| ErrorKind::NoDevice => io::ErrorKind::NotFound, |
| ErrorKind::InvalidInput => io::ErrorKind::InvalidInput, |
| ErrorKind::Unknown => io::ErrorKind::Other, |
| ErrorKind::Io(kind) => kind, |
| }; |
| |
| io::Error::new(kind, error.description) |
| } |
| } |
| |
| /// Number of bits per character |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum DataBits { |
| /// 5 bits per character |
| Five, |
| |
| /// 6 bits per character |
| Six, |
| |
| /// 7 bits per character |
| Seven, |
| |
| /// 8 bits per character |
| Eight, |
| } |
| |
| impl fmt::Display for DataBits { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match *self { |
| DataBits::Five => write!(f, "Five"), |
| DataBits::Six => write!(f, "Six"), |
| DataBits::Seven => write!(f, "Seven"), |
| DataBits::Eight => write!(f, "Eight"), |
| } |
| } |
| } |
| |
| impl From<DataBits> for u8 { |
| fn from(value: DataBits) -> Self { |
| match value { |
| DataBits::Five => 5, |
| DataBits::Six => 6, |
| DataBits::Seven => 7, |
| DataBits::Eight => 8, |
| } |
| } |
| } |
| |
| impl TryFrom<u8> for DataBits { |
| type Error = (); |
| |
| fn try_from(value: u8) -> core::result::Result<Self, Self::Error> { |
| match value { |
| 5 => Ok(Self::Five), |
| 6 => Ok(Self::Six), |
| 7 => Ok(Self::Seven), |
| 8 => Ok(Self::Eight), |
| _ => Err(()), |
| } |
| } |
| } |
| |
| /// Parity checking modes |
| /// |
| /// When parity checking is enabled (`Odd` or `Even`) an extra bit is transmitted with |
| /// each character. The value of the parity bit is arranged so that the number of 1 bits in the |
| /// character (including the parity bit) is an even number (`Even`) or an odd number |
| /// (`Odd`). |
| /// |
| /// Parity checking is disabled by setting `None`, in which case parity bits are not |
| /// transmitted. |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum Parity { |
| /// No parity bit. |
| None, |
| |
| /// Parity bit sets odd number of 1 bits. |
| Odd, |
| |
| /// Parity bit sets even number of 1 bits. |
| Even, |
| } |
| |
| impl fmt::Display for Parity { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match *self { |
| Parity::None => write!(f, "None"), |
| Parity::Odd => write!(f, "Odd"), |
| Parity::Even => write!(f, "Even"), |
| } |
| } |
| } |
| |
| /// Number of stop bits |
| /// |
| /// Stop bits are transmitted after every character. |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum StopBits { |
| /// One stop bit. |
| One, |
| |
| /// Two stop bits. |
| Two, |
| } |
| |
| impl fmt::Display for StopBits { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match *self { |
| StopBits::One => write!(f, "One"), |
| StopBits::Two => write!(f, "Two"), |
| } |
| } |
| } |
| |
| impl From<StopBits> for u8 { |
| fn from(value: StopBits) -> Self { |
| match value { |
| StopBits::One => 1, |
| StopBits::Two => 2, |
| } |
| } |
| } |
| |
| impl TryFrom<u8> for StopBits { |
| type Error = (); |
| |
| fn try_from(value: u8) -> core::result::Result<Self, Self::Error> { |
| match value { |
| 1 => Ok(Self::One), |
| 2 => Ok(Self::Two), |
| _ => Err(()), |
| } |
| } |
| } |
| |
| /// Flow control modes |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum FlowControl { |
| /// No flow control. |
| None, |
| |
| /// Flow control using XON/XOFF bytes. |
| Software, |
| |
| /// Flow control using RTS/CTS signals. |
| Hardware, |
| } |
| |
| impl fmt::Display for FlowControl { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match *self { |
| FlowControl::None => write!(f, "None"), |
| FlowControl::Software => write!(f, "Software"), |
| FlowControl::Hardware => write!(f, "Hardware"), |
| } |
| } |
| } |
| |
| impl FromStr for FlowControl { |
| type Err = (); |
| |
| fn from_str(s: &str) -> core::result::Result<Self, Self::Err> { |
| match s { |
| "None" | "none" | "n" => Ok(FlowControl::None), |
| "Software" | "software" | "SW" | "sw" | "s" => Ok(FlowControl::Software), |
| "Hardware" | "hardware" | "HW" | "hw" | "h" => Ok(FlowControl::Hardware), |
| _ => Err(()), |
| } |
| } |
| } |
| |
| /// Specifies which buffer or buffers to purge when calling [`clear`] |
| /// |
| /// [`clear`]: trait.SerialPort.html#tymethod.clear |
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum ClearBuffer { |
| /// Specify to clear data received but not read |
| Input, |
| /// Specify to clear data written but not yet transmitted |
| Output, |
| /// Specify to clear both data received and data not yet transmitted |
| All, |
| } |
| |
| /// A struct containing all serial port settings |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| pub struct SerialPortBuilder { |
| /// The port name, usually the device path |
| path: String, |
| /// The baud rate in symbols-per-second |
| baud_rate: u32, |
| /// Number of bits used to represent a character sent on the line |
| data_bits: DataBits, |
| /// The type of signalling to use for controlling data transfer |
| flow_control: FlowControl, |
| /// The type of parity to use for error checking |
| parity: Parity, |
| /// Number of bits to use to signal the end of a character |
| stop_bits: StopBits, |
| /// Amount of time to wait to receive data before timing out |
| timeout: Duration, |
| /// The state to set DTR to when opening the device |
| dtr_on_open: Option<bool>, |
| } |
| |
| impl SerialPortBuilder { |
| /// Set the path to the serial port |
| // TODO: Switch to `clone_into` when bumping our MSRV past 1.63 and remove this exemption. |
| #[allow(clippy::assigning_clones)] |
| #[must_use] |
| pub fn path<'a>(mut self, path: impl Into<std::borrow::Cow<'a, str>>) -> Self { |
| self.path = path.into().as_ref().to_owned(); |
| self |
| } |
| |
| /// Set the baud rate in symbols-per-second |
| #[must_use] |
| pub fn baud_rate(mut self, baud_rate: u32) -> Self { |
| self.baud_rate = baud_rate; |
| self |
| } |
| |
| /// Set the number of bits used to represent a character sent on the line |
| #[must_use] |
| pub fn data_bits(mut self, data_bits: DataBits) -> Self { |
| self.data_bits = data_bits; |
| self |
| } |
| |
| /// Set the type of signalling to use for controlling data transfer |
| #[must_use] |
| pub fn flow_control(mut self, flow_control: FlowControl) -> Self { |
| self.flow_control = flow_control; |
| self |
| } |
| |
| /// Set the type of parity to use for error checking |
| #[must_use] |
| pub fn parity(mut self, parity: Parity) -> Self { |
| self.parity = parity; |
| self |
| } |
| |
| /// Set the number of bits to use to signal the end of a character |
| #[must_use] |
| pub fn stop_bits(mut self, stop_bits: StopBits) -> Self { |
| self.stop_bits = stop_bits; |
| self |
| } |
| |
| /// Set the amount of time to wait to receive data before timing out |
| /// |
| /// <div class="warning"> |
| /// |
| /// The accuracy is limited by the underlying platform's capabilities. Longer timeouts will be |
| /// clamped to the maximum supported value which is expected to be in the magnitude of a few |
| /// days. |
| /// |
| /// </div> |
| #[must_use] |
| pub fn timeout(mut self, timeout: Duration) -> Self { |
| self.timeout = timeout; |
| self |
| } |
| |
| /// Set data terminal ready (DTR) to the given state when opening the device |
| #[must_use] |
| pub fn dtr_on_open(mut self, state: bool) -> Self { |
| self.dtr_on_open = Some(state); |
| self |
| } |
| |
| /// Preserve the state of data terminal ready (DTR) when opening the device. Your outcome may |
| /// vary depending on the operation system. For example, Linux sets DTR by default and Windows |
| /// doesn't. |
| #[must_use] |
| pub fn preserve_dtr_on_open(mut self) -> Self { |
| self.dtr_on_open = None; |
| self |
| } |
| |
| /// Open a cross-platform interface to the port with the specified settings |
| pub fn open(self) -> Result<Box<dyn SerialPort>> { |
| #[cfg(unix)] |
| return posix::TTYPort::open(&self).map(|p| Box::new(p) as Box<dyn SerialPort>); |
| |
| #[cfg(windows)] |
| return windows::COMPort::open(&self).map(|p| Box::new(p) as Box<dyn SerialPort>); |
| |
| #[cfg(not(any(unix, windows)))] |
| Err(Error::new( |
| ErrorKind::Unknown, |
| "open() not implemented for platform", |
| )) |
| } |
| |
| /// Open a platform-specific interface to the port with the specified settings |
| #[cfg(unix)] |
| pub fn open_native(self) -> Result<TTYPort> { |
| posix::TTYPort::open(&self) |
| } |
| |
| /// Open a platform-specific interface to the port with the specified settings |
| #[cfg(windows)] |
| pub fn open_native(self) -> Result<COMPort> { |
| windows::COMPort::open(&self) |
| } |
| } |
| |
| /// A trait for serial port devices |
| /// |
| /// This trait is all that's necessary to implement a new serial port driver |
| /// for a new platform. |
| pub trait SerialPort: Send + io::Read + io::Write { |
| // Port settings getters |
| |
| /// Returns the name of this port if it exists. |
| /// |
| /// This name may not be the canonical device name and instead be shorthand. |
| /// Additionally it may not exist for virtual ports. |
| fn name(&self) -> Option<String>; |
| |
| /// Returns the current baud rate. |
| /// |
| /// This may return a value different from the last specified baud rate depending on the |
| /// platform as some will return the actual device baud rate rather than the last specified |
| /// baud rate. |
| fn baud_rate(&self) -> Result<u32>; |
| |
| /// Returns the character size. |
| /// |
| /// This function returns `None` if the character size could not be determined. This may occur |
| /// if the hardware is in an uninitialized state or is using a non-standard character size. |
| /// Setting a baud rate with `set_char_size()` should initialize the character size to a |
| /// supported value. |
| fn data_bits(&self) -> Result<DataBits>; |
| |
| /// Returns the flow control mode. |
| /// |
| /// This function returns `None` if the flow control mode could not be determined. This may |
| /// occur if the hardware is in an uninitialized state or is using an unsupported flow control |
| /// mode. Setting a flow control mode with `set_flow_control()` should initialize the flow |
| /// control mode to a supported value. |
| fn flow_control(&self) -> Result<FlowControl>; |
| |
| /// Returns the parity-checking mode. |
| /// |
| /// This function returns `None` if the parity mode could not be determined. This may occur if |
| /// the hardware is in an uninitialized state or is using a non-standard parity mode. Setting |
| /// a parity mode with `set_parity()` should initialize the parity mode to a supported value. |
| fn parity(&self) -> Result<Parity>; |
| |
| /// Returns the number of stop bits. |
| /// |
| /// This function returns `None` if the number of stop bits could not be determined. This may |
| /// occur if the hardware is in an uninitialized state or is using an unsupported stop bit |
| /// configuration. Setting the number of stop bits with `set_stop-bits()` should initialize the |
| /// stop bits to a supported value. |
| fn stop_bits(&self) -> Result<StopBits>; |
| |
| /// Returns the current timeout. |
| fn timeout(&self) -> Duration; |
| |
| // Port settings setters |
| |
| /// Sets the baud rate. |
| /// |
| /// ## Errors |
| /// |
| /// If the implementation does not support the requested baud rate, this function may return an |
| /// `InvalidInput` error. Even if the baud rate is accepted by `set_baud_rate()`, it may not be |
| /// supported by the underlying hardware. |
| fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()>; |
| |
| /// Sets the character size. |
| fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()>; |
| |
| /// Sets the flow control mode. |
| fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()>; |
| |
| /// Sets the parity-checking mode. |
| fn set_parity(&mut self, parity: Parity) -> Result<()>; |
| |
| /// Sets the number of stop bits. |
| fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()>; |
| |
| /// Sets the timeout for future I/O operations. |
| /// |
| /// <div class="warning"> |
| /// |
| /// The accuracy is limited by the underlying platform's capabilities. Longer timeouts will be |
| /// clamped to the maximum supported value which is expected to be in the magnitude of a few |
| /// days. |
| /// |
| /// </div> |
| fn set_timeout(&mut self, timeout: Duration) -> Result<()>; |
| |
| // Functions for setting non-data control signal pins |
| |
| /// Sets the state of the RTS (Request To Send) control signal. |
| /// |
| /// Setting a value of `true` asserts the RTS control signal. `false` clears the signal. |
| /// |
| /// ## Errors |
| /// |
| /// This function returns an error if the RTS control signal could not be set to the desired |
| /// state on the underlying hardware: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn write_request_to_send(&mut self, level: bool) -> Result<()>; |
| |
| /// Writes to the Data Terminal Ready pin |
| /// |
| /// Setting a value of `true` asserts the DTR control signal. `false` clears the signal. |
| /// |
| /// ## Errors |
| /// |
| /// This function returns an error if the DTR control signal could not be set to the desired |
| /// state on the underlying hardware: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn write_data_terminal_ready(&mut self, level: bool) -> Result<()>; |
| |
| // Functions for reading additional pins |
| |
| /// Reads the state of the CTS (Clear To Send) control signal. |
| /// |
| /// This function returns a boolean that indicates whether the CTS control signal is asserted. |
| /// |
| /// ## Errors |
| /// |
| /// This function returns an error if the state of the CTS control signal could not be read |
| /// from the underlying hardware: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn read_clear_to_send(&mut self) -> Result<bool>; |
| |
| /// Reads the state of the Data Set Ready control signal. |
| /// |
| /// This function returns a boolean that indicates whether the DSR control signal is asserted. |
| /// |
| /// ## Errors |
| /// |
| /// This function returns an error if the state of the DSR control signal could not be read |
| /// from the underlying hardware: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn read_data_set_ready(&mut self) -> Result<bool>; |
| |
| /// Reads the state of the Ring Indicator control signal. |
| /// |
| /// This function returns a boolean that indicates whether the RI control signal is asserted. |
| /// |
| /// ## Errors |
| /// |
| /// This function returns an error if the state of the RI control signal could not be read from |
| /// the underlying hardware: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn read_ring_indicator(&mut self) -> Result<bool>; |
| |
| /// Reads the state of the Carrier Detect control signal. |
| /// |
| /// This function returns a boolean that indicates whether the CD control signal is asserted. |
| /// |
| /// ## Errors |
| /// |
| /// This function returns an error if the state of the CD control signal could not be read from |
| /// the underlying hardware: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn read_carrier_detect(&mut self) -> Result<bool>; |
| |
| /// Gets the number of bytes available to be read from the input buffer. |
| /// |
| /// # Errors |
| /// |
| /// This function may return the following errors: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn bytes_to_read(&self) -> Result<u32>; |
| |
| /// Get the number of bytes written to the output buffer, awaiting transmission. |
| /// |
| /// # Errors |
| /// |
| /// This function may return the following errors: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn bytes_to_write(&self) -> Result<u32>; |
| |
| /// Discards all bytes from the serial driver's input buffer and/or output buffer. |
| /// |
| /// # Errors |
| /// |
| /// This function may return the following errors: |
| /// |
| /// * `NoDevice` if the device was disconnected. |
| /// * `Io` for any other type of I/O error. |
| fn clear(&self, buffer_to_clear: ClearBuffer) -> Result<()>; |
| |
| // Misc methods |
| |
| /// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the |
| /// same serial connection. Please note that if you want a real asynchronous serial port you |
| /// should look at [mio-serial](https://crates.io/crates/mio-serial) or |
| /// [tokio-serial](https://crates.io/crates/tokio-serial). |
| /// |
| /// Also, you must be very careful when changing the settings of a cloned `SerialPort` : since |
| /// the settings are cached on a per object basis, trying to modify them from two different |
| /// objects can cause some nasty behavior. |
| /// |
| /// # Errors |
| /// |
| /// This function returns an error if the serial port couldn't be cloned. |
| fn try_clone(&self) -> Result<Box<dyn SerialPort>>; |
| |
| /// Start transmitting a break |
| fn set_break(&self) -> Result<()>; |
| |
| /// Stop transmitting a break |
| fn clear_break(&self) -> Result<()>; |
| } |
| |
| impl<T: SerialPort> SerialPort for &mut T { |
| fn name(&self) -> Option<String> { |
| (**self).name() |
| } |
| |
| fn baud_rate(&self) -> Result<u32> { |
| (**self).baud_rate() |
| } |
| |
| fn data_bits(&self) -> Result<DataBits> { |
| (**self).data_bits() |
| } |
| |
| fn flow_control(&self) -> Result<FlowControl> { |
| (**self).flow_control() |
| } |
| |
| fn parity(&self) -> Result<Parity> { |
| (**self).parity() |
| } |
| |
| fn stop_bits(&self) -> Result<StopBits> { |
| (**self).stop_bits() |
| } |
| |
| fn timeout(&self) -> Duration { |
| (**self).timeout() |
| } |
| |
| fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> { |
| (**self).set_baud_rate(baud_rate) |
| } |
| |
| fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()> { |
| (**self).set_data_bits(data_bits) |
| } |
| |
| fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()> { |
| (**self).set_flow_control(flow_control) |
| } |
| |
| fn set_parity(&mut self, parity: Parity) -> Result<()> { |
| (**self).set_parity(parity) |
| } |
| |
| fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()> { |
| (**self).set_stop_bits(stop_bits) |
| } |
| |
| fn set_timeout(&mut self, timeout: Duration) -> Result<()> { |
| (**self).set_timeout(timeout) |
| } |
| |
| fn write_request_to_send(&mut self, level: bool) -> Result<()> { |
| (**self).write_request_to_send(level) |
| } |
| |
| fn write_data_terminal_ready(&mut self, level: bool) -> Result<()> { |
| (**self).write_data_terminal_ready(level) |
| } |
| |
| fn read_clear_to_send(&mut self) -> Result<bool> { |
| (**self).read_clear_to_send() |
| } |
| |
| fn read_data_set_ready(&mut self) -> Result<bool> { |
| (**self).read_data_set_ready() |
| } |
| |
| fn read_ring_indicator(&mut self) -> Result<bool> { |
| (**self).read_ring_indicator() |
| } |
| |
| fn read_carrier_detect(&mut self) -> Result<bool> { |
| (**self).read_carrier_detect() |
| } |
| |
| fn bytes_to_read(&self) -> Result<u32> { |
| (**self).bytes_to_read() |
| } |
| |
| fn bytes_to_write(&self) -> Result<u32> { |
| (**self).bytes_to_write() |
| } |
| |
| fn clear(&self, buffer_to_clear: ClearBuffer) -> Result<()> { |
| (**self).clear(buffer_to_clear) |
| } |
| |
| fn try_clone(&self) -> Result<Box<dyn SerialPort>> { |
| (**self).try_clone() |
| } |
| |
| fn set_break(&self) -> Result<()> { |
| (**self).set_break() |
| } |
| |
| fn clear_break(&self) -> Result<()> { |
| (**self).clear_break() |
| } |
| } |
| |
| impl fmt::Debug for dyn SerialPort { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(f, "SerialPort ( ")?; |
| |
| if let Some(n) = self.name().as_ref() { |
| write!(f, "name: {} ", n)?; |
| }; |
| if let Ok(b) = self.baud_rate().as_ref() { |
| write!(f, "baud_rate: {} ", b)?; |
| }; |
| if let Ok(b) = self.data_bits().as_ref() { |
| write!(f, "data_bits: {} ", b)?; |
| }; |
| if let Ok(c) = self.flow_control().as_ref() { |
| write!(f, "flow_control: {} ", c)?; |
| } |
| if let Ok(p) = self.parity().as_ref() { |
| write!(f, "parity: {} ", p)?; |
| } |
| if let Ok(s) = self.stop_bits().as_ref() { |
| write!(f, "stop_bits: {} ", s)?; |
| } |
| |
| write!(f, ")") |
| } |
| } |
| |
| /// Contains all possible USB information about a `SerialPort` |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct UsbPortInfo { |
| /// Vendor ID |
| pub vid: u16, |
| /// Product ID |
| pub pid: u16, |
| /// Serial number (arbitrary string) |
| pub serial_number: Option<String>, |
| /// Manufacturer (arbitrary string) |
| pub manufacturer: Option<String>, |
| /// Product name (arbitrary string) |
| pub product: Option<String>, |
| /// The interface index of the USB serial port. This can be either the interface number of |
| /// the communication interface (as is the case on Windows and Linux) or the data |
| /// interface (as is the case on macOS), so you should recognize both interface numbers. |
| #[cfg(feature = "usbportinfo-interface")] |
| pub interface: Option<u8>, |
| } |
| |
| /// The physical type of a `SerialPort` |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub enum SerialPortType { |
| /// The serial port is connected via USB |
| UsbPort(UsbPortInfo), |
| /// The serial port is connected via PCI (permanent port) |
| PciPort, |
| /// The serial port is connected via Bluetooth |
| BluetoothPort, |
| /// It can't be determined how the serial port is connected |
| Unknown, |
| } |
| |
| /// A device-independent implementation of serial port information |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| pub struct SerialPortInfo { |
| /// The short name of the serial port |
| pub port_name: String, |
| /// The hardware device type that exposes this port |
| pub port_type: SerialPortType, |
| } |
| |
| /// Construct a builder of `SerialPort` objects |
| /// |
| /// `SerialPort` objects are built using the Builder pattern through the `new` function. The |
| /// resultant `SerialPortBuilder` object can be copied, reconfigured, and saved making working with |
| /// multiple serial ports a little easier. |
| /// |
| /// To open a new serial port: |
| /// ```no_run |
| /// serialport::new("/dev/ttyUSB0", 9600).open().expect("Failed to open port"); |
| /// ``` |
| pub fn new<'a>(path: impl Into<std::borrow::Cow<'a, str>>, baud_rate: u32) -> SerialPortBuilder { |
| SerialPortBuilder { |
| path: path.into().into_owned(), |
| baud_rate, |
| data_bits: DataBits::Eight, |
| flow_control: FlowControl::None, |
| parity: Parity::None, |
| stop_bits: StopBits::One, |
| timeout: Duration::from_millis(0), |
| // By default, set DTR when opening the device. There are USB devices performing "wait for |
| // DTR" before sending any data and users stumbled over this multiple times (see issues #29 |
| // and #204). We are expecting little to no negative consequences from setting DTR by |
| // default but less hassle for users. |
| dtr_on_open: Some(true), |
| } |
| } |
| |
| /// Returns a list of all serial ports on system |
| /// |
| /// It is not guaranteed that these ports exist or are available even if they're |
| /// returned by this function. |
| pub fn available_ports() -> Result<Vec<SerialPortInfo>> { |
| #[cfg(unix)] |
| return crate::posix::available_ports(); |
| |
| #[cfg(windows)] |
| return crate::windows::available_ports(); |
| |
| #[cfg(not(any(unix, windows)))] |
| Err(Error::new( |
| ErrorKind::Unknown, |
| "available_ports() not implemented for platform", |
| )) |
| } |