From b7354d3bf1aa9d9d128277b48af4b1f29ddb2ec9 Mon Sep 17 00:00:00 2001 From: Christian Meusel Date: Sat, 4 Jan 2025 22:04:29 +0100 Subject: [PATCH] Set DTR when opening a serial port by default --- src/lib.rs | 23 +++++++++++++++++++++++ src/posix/tty.rs | 13 +++++++++++-- src/windows/com.rs | 4 ++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 79d0f377..158fdef1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,6 +331,8 @@ pub struct SerialPortBuilder { 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, } impl SerialPortBuilder { @@ -393,6 +395,22 @@ impl SerialPortBuilder { 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> { #[cfg(unix)] @@ -837,6 +855,11 @@ pub fn new<'a>(path: impl Into>, baud_rate: u32) -> Se 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), } } diff --git a/src/posix/tty.rs b/src/posix/tty.rs index fe7e8499..47449d90 100644 --- a/src/posix/tty.rs +++ b/src/posix/tty.rs @@ -183,14 +183,23 @@ impl TTYPort { termios::set_termios(fd.0, &termios)?; // Return the final port object - Ok(TTYPort { + let mut port = TTYPort { fd: fd.into_raw(), timeout: builder.timeout, exclusive: true, port_name: Some(builder.path.clone()), #[cfg(any(target_os = "ios", target_os = "macos"))] baud_rate: builder.baud_rate, - }) + }; + + // Ignore setting DTR for pseudo terminals (indicated by baud_rate == 0). + if builder.baud_rate > 0 { + if let Some(dtr) = builder.dtr_on_open { + port.write_data_terminal_ready(dtr)?; + } + } + + Ok(port) } /// Returns the exclusivity of the port diff --git a/src/windows/com.rs b/src/windows/com.rs index fa1abbca..1bf368f6 100644 --- a/src/windows/com.rs +++ b/src/windows/com.rs @@ -85,6 +85,10 @@ impl COMPort { dcb::set_flow_control(&mut dcb, builder.flow_control); dcb::set_dcb(handle, dcb)?; + if let Some(dtr) = builder.dtr_on_open { + com.write_data_terminal_ready(dtr)?; + } + com.set_timeout(builder.timeout)?; com.port_name = Some(builder.path.clone()); Ok(com)