From fe65e0b003f2a320993d3cef15119f504a0d0877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Tue, 4 Aug 2026 01:47:58 +0200 Subject: [PATCH] config: allow disabling CTS check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most modern hardware only hooks up the RX and TX lines, and doesn't bother with the flow control pins. This means that, in practice, waiting for CTS before sending data will prevent the UART from working, without a clear indication of what's wrong. This commit introduces an option for configuring whether the CTS line should be checked before sending data. We default to not checking the CTS line, believing that: - it's a more useful default on modern hardware, with receive FIFO overruns being virtually unheard of despite the lack of a CTS pin; - even when the CTS line is usefully exposed, ignoring its state leads to more useful behavior when the UART is not connected, for the usecase of emitting logs – logging into the void is better than hanging the system. - when hardware flow control is necessary, the clear symptom of FIFO overruns should be much easier to track down than a silent hang. --- CHANGELOG.md | 5 +++++ src/config.rs | 7 +++++++ src/lib.rs | 14 ++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9131061..c0b9f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ - **Breaking:** Changed the return type of `Uart16550::config(&self)` from `(&Config, &B::Address)` to `(&Config, &B)` +- **Breaking:** `ready_to_send()` (and `send_bytes()` in turn) doesn't check + `MSR::CTS` anymore by default, as modern hardware tends to leave that pin + disconnected. This behavior is configurable through `Config::flow_control`. + Additionally, for manual checks, users can check + `if device.msr().contains(MSR::CTS) {}`. ## 0.6.0 - 2026-03-28 diff --git a/src/config.rs b/src/config.rs index f6eb47b..6777db4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -151,6 +151,12 @@ pub struct Config { pub extra_stop_bits: bool, /// Whether parity bits should be used. pub parity: Parity, + /// Whether to wait for CTS before sending. + /// + /// Only activate this if your hardware connects the CTS/RTS flow control + /// signals and you wish to make use of them. Keep this setting disabled to + /// make sure that the UART works when CTS is left disconnected. + pub flow_control: bool, } impl Config { @@ -176,6 +182,7 @@ impl Config { data_bits: WordLength::EightBits, extra_stop_bits: false, parity: Parity::Disabled, + flow_control: false, }; } diff --git a/src/lib.rs b/src/lib.rs index dfc8c2a..7fb3281 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -668,8 +668,6 @@ impl Uart16550 { /// an established connection. pub fn ready_to_send(&mut self) -> Result<(), ByteSendError> { let lsr = self.lsr(); - let msr = self.msr(); - let mcr = self.mcr(); // In FIFO mode, this bit is set when the transmitter’s FIFO is // completely empty, being 0 if there is at least one byte in the @@ -681,8 +679,16 @@ impl Uart16550 { // Software flow control. TODO, what to do with hardware flow control? // Is this something we can and should support? - if !mcr.contains(MCR::LOOP_BACK) && !msr.contains(MSR::CTS) { - return Err(ByteSendError::RemoteNotClearToSend); + if self.config.flow_control { + // The CTS line is meaningless when in loopback mode. + let mcr = self.mcr(); + if !mcr.contains(MCR::LOOP_BACK) { + let msr = self.msr(); + + if !msr.contains(MSR::CTS) { + return Err(ByteSendError::RemoteNotClearToSend); + } + } } Ok(())