rpi_pal/uart.rs
1//! Interface for the UART peripherals and any USB to serial adapters.
2//!
3//! rpi-pal controls the Raspberry Pi's UART peripherals through the `ttyAMA0`
4//! (PL011) and `ttyS0` (mini UART) character devices. USB to serial adapters
5//! are controlled using the `ttyUSBx` and `ttyACMx` character devices.
6//!
7//! ## UART peripherals
8//!
9//! The Raspberry Pi's BCM283x SoC features two UART peripherals.
10//! `/dev/ttyAMA0` represents the PL011 UART, which offers a full set of
11//! features. `/dev/ttyS0` represents an auxiliary peripheral that's referred
12//! to as mini UART, with limited capabilities. More details on the differences
13//! between the PL011 and mini UART can be found in the official Raspberry Pi
14//! [documentation].
15//!
16//! On earlier Raspberry Pi models without Bluetooth, `/dev/ttyAMA0` is
17//! configured as a Linux serial console. On more recent models with Bluetooth,
18//! `/dev/ttyAMA0` is connected to the Bluetooth
19//! module, and `/dev/ttyS0` is used as a serial console instead. Due to the
20//! limitations of `/dev/ttyS0` and the requirement for a fixed core frequency,
21//! in most cases you'll want to use `/dev/ttyAMA0` for serial communication.
22//!
23//! By default, TX (outgoing data) is tied to BCM GPIO 14 (physical pin 8) and
24//! RX (incoming data) is tied to BCM GPIO 15 (physical pin 10). You can move
25//! these lines to different GPIO pins using the `uart0` and `uart1` overlays,
26//! but the alternative pin options aren't exposed through the GPIO header on
27//! any of the current Raspberry Pi models. They are only available on the
28//! Compute Module's SO-DIMM pads.
29//!
30//! ## Configure `/dev/ttyAMA0` for serial communication (recommended)
31//!
32//! Disable the Linux serial console by either deactivating it through
33//! `sudo raspi-config`, or manually removing the parameter
34//! `console=serial0,115200` from `/boot/firmware/cmdline.txt`.
35//!
36//! Remove any lines containing `enable_uart=0` or `enable_uart=1` from
37//! `/boot/firmware/config.txt`.
38//!
39//! On Raspberry Pi models with a Bluetooth module, an extra step is required
40//! to either disable Bluetooth or move it to `/dev/ttyS0`, so `/dev/ttyAMA0`
41//! becomes available for serial communication.
42//!
43//! To disable Bluetooth, add `dtoverlay=pi3-disable-bt` to `/boot/firmware/config.txt`.
44//! You'll also need to disable the service that initializes Bluetooth with
45//! `sudo systemctl disable hciuart`.
46//!
47//! To move the Bluetooth module to `/dev/ttyS0`, instead of disabling it with
48//! the above-mentioned steps, add `dtoverlay=pi3-miniuart-bt` and
49//! `core_freq=250` to `/boot/firmware/config.txt`.
50//!
51//! Remember to reboot the Raspberry Pi after making any changes.
52//!
53//! ## Configure `/dev/ttyS0` for serial communication
54//!
55//! If you prefer to leave the Bluetooth module connected to `/dev/ttyAMA0`,
56//! you can configure `/dev/ttyS0` for serial communication instead.
57//!
58//! Disable the Linux serial console by either deactivating it through
59//! `sudo raspi-config`, or manually removing the parameter
60//! `console=serial0,115200` from `/boot/firmware/cmdline.txt`.
61//!
62//! Add the line `enable_uart=1` to `/boot/firmware/config.txt` to enable serial
63//! communication on `/dev/ttyS0`, which also sets a fixed core frequency.
64//!
65//! Remember to reboot the Raspberry Pi after making any changes.
66//!
67//! ## USB to serial adapters
68//!
69//! In addition to controlling the hardware UART peripherals, [`Uart`] can
70//! also be used for USB to serial adapters. Depending on the type of
71//! device, these can be accessed either through `/dev/ttyUSBx` or
72//! `/dev/ttyACMx`, where `x` is an index starting at `0`. The numbering is
73//! based on the order in which the devices are discovered by the kernel.
74//!
75//! When you have multiple USB to serial adapters connected at the same time,
76//! you can uniquely identify a specific device by searching for the relevant
77//! symlink in the `/dev/serial/by-id` directory, or by adding your own
78//! `udev` rules.
79//!
80//! Support for automatic software (XON/XOFF) and hardware (RTS/CTS) flow
81//! control for USB to serial adapters depends on the USB interface IC on the
82//! device, and the relevant Linux driver. Some ICs use an older,
83//! incompatible RTS/CTS implementation, sometimes referred to as legacy or
84//! simplex mode, where RTS is used to indicate data is about to be
85//! transmitted, rather than to request the external device to resume its
86//! transmission.
87//!
88//! ## Hardware flow control
89//!
90//! The RTS/CTS hardware flow control implementation supported by [`Uart`]
91//! and used by the Raspberry Pi's UART peripherals requires RTS on one
92//! device to be connected to CTS on the other device. The RTS signal is
93//! used to request the other device to pause or resume its transmission.
94//!
95//! Some devices use an older, incompatible RTS/CTS implementation, sometimes
96//! referred to as legacy or simplex mode, where RTS is connected to RTS, and
97//! CTS to CTS. The RTS signal is used to indicate data is about to be
98//! transmitted. [`Uart`] is not compatible with this implementation.
99//! Connecting the Raspberry Pi's RTS and CTS pins incorrectly could damage
100//! the Pi or the external device.
101//!
102//! When [`Uart`] is controlling a UART peripheral, enabling hardware flow
103//! control will also configure the RTS and CTS pins. On Raspberry Pi models
104//! with a 40-pin GPIO header, RTS is tied to BCM GPIO 17 (physical pin 11)
105//! and CTS is tied to BCM GPIO 16 (physical pin 36). RTS and CTS aren't
106//! available on models with a 26-pin header, except for the Raspberry Pi B
107//! Rev 2, which exposes RTS and CTS through its unpopulated P5 header with
108//! RTS on BCM GPIO 31 (physical pin 6) and CTS on BCM GPIO 30 (physical pin
109//! 5).
110//!
111//! The RTS and CTS pins are reset to their original state when [`Uart`] goes
112//! out of scope. Note that `drop` methods aren't called when a process is
113//! abnormally terminated, for instance when a user presses <kbd>Ctrl</kbd> +
114//! <kbd>C</kbd> and the `SIGINT` signal isn't caught, which prevents [`Uart`]
115//! from resetting the pins. You can catch those using crates such as
116//! [`simple_signal`].
117//!
118//! ## Troubleshooting
119//!
120//! ### Permission denied
121//!
122//! If [`new`] or [`with_path`] returns an `io::ErrorKind::PermissionDenied`
123//! error, make sure the file permissions for the specified device are correct,
124//! and the current user is a member of the group that owns the device, which is
125//! usually either `dialout` or `tty`.
126//!
127//! [documentation]: https://www.raspberrypi.org/documentation/configuration/uart.md
128//! [`simple_signal`]: https://crates.io/crates/simple-signal
129//! [`Uart`]: struct.Uart.html
130//! [`new`]: struct.Uart.html#method.new
131//! [`with_path`]: struct.Uart.html#method.with_path
132
133use std::error;
134use std::fmt;
135use std::fs::{self, File, OpenOptions};
136use std::io;
137use std::io::{Read, Write};
138use std::os::unix::fs::OpenOptionsExt;
139use std::os::unix::io::{AsRawFd, RawFd};
140use std::path::Path;
141use std::result;
142use std::time::Duration;
143
144use libc::{c_int, O_NOCTTY, O_NONBLOCK};
145use libc::{TIOCM_CAR, TIOCM_CTS, TIOCM_DSR, TIOCM_DTR, TIOCM_RNG, TIOCM_RTS};
146
147use crate::gpio::{self, Gpio, IoPin, Mode};
148use crate::system::{self, DeviceInfo, Model, SoC};
149
150#[cfg(any(
151 feature = "embedded-hal-0",
152 feature = "embedded-hal",
153 feature = "embedded-hal-nb"
154))]
155mod hal;
156mod termios;
157
158const GPIO_RTS: u8 = 17;
159const GPIO_CTS: u8 = 16;
160
161const GPIO_RTS_BREV2: u8 = 31;
162const GPIO_CTS_BREV2: u8 = 30;
163
164const GPIO_RTS_MODE_UART0: Mode = Mode::Alt3;
165const GPIO_CTS_MODE_UART0: Mode = Mode::Alt3;
166
167const GPIO_RTS_MODE_UART1: Mode = Mode::Alt5;
168const GPIO_CTS_MODE_UART1: Mode = Mode::Alt5;
169
170/// Errors that can occur when accessing the UART peripheral.
171#[derive(Debug)]
172pub enum Error {
173 /// I/O error.
174 Io(io::Error),
175 /// GPIO error.
176 Gpio(gpio::Error),
177 /// Invalid or unsupported value.
178 InvalidValue,
179}
180
181impl fmt::Display for Error {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 match *self {
184 Error::Io(ref err) => write!(f, "I/O error: {}", err),
185 Error::Gpio(ref err) => write!(f, "GPIO error: {}", err),
186 Error::InvalidValue => write!(f, "Invalid or unsupported value"),
187 }
188 }
189}
190
191impl error::Error for Error {}
192
193impl From<io::Error> for Error {
194 fn from(err: io::Error) -> Error {
195 Error::Io(err)
196 }
197}
198
199impl From<gpio::Error> for Error {
200 fn from(err: gpio::Error) -> Error {
201 Error::Gpio(err)
202 }
203}
204
205impl From<system::Error> for Error {
206 fn from(_err: system::Error) -> Error {
207 Error::Gpio(gpio::Error::UnknownModel)
208 }
209}
210
211/// Result type returned from methods that can have `uart::Error`s.
212pub type Result<T> = result::Result<T, Error>;
213
214/// Parity bit modes.
215///
216/// The parity bit mode determines how the parity bit is calculated.
217///
218/// `None` omits the parity bit. `Even` and `Odd` count the total number of
219/// 1-bits in the data bits. `Mark` and `Space` always set the parity
220/// bit to `1` or `0` respectively.
221#[derive(Debug, PartialEq, Eq, Copy, Clone)]
222pub enum Parity {
223 /// No parity bit.
224 None,
225 /// Even parity.
226 Even,
227 /// Odd parity.
228 Odd,
229 /// Sets parity bit to `1`.
230 Mark,
231 /// Sets parity bit to `0`.
232 Space,
233}
234
235impl fmt::Display for Parity {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 match *self {
238 Parity::None => write!(f, "None"),
239 Parity::Even => write!(f, "Even"),
240 Parity::Odd => write!(f, "Odd"),
241 Parity::Mark => write!(f, "Mark"),
242 Parity::Space => write!(f, "Space"),
243 }
244 }
245}
246
247/// Parity check modes.
248///
249/// The parity check mode determines how parity errors are handled.
250#[derive(Debug, PartialEq, Eq, Copy, Clone)]
251pub enum ParityCheck {
252 /// Ignores parity errors.
253 None,
254 /// Removes bytes with parity errors from the input queue.
255 Strip,
256 /// Replaces bytes with parity errors with a `0` byte.
257 Replace,
258 /// Marks bytes with parity errors with a preceding `255` and `0` byte.
259 ///
260 /// Actual `255` bytes are replaced with two `255` bytes to avoid confusion
261 /// with parity errors.
262 Mark,
263}
264
265impl fmt::Display for ParityCheck {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 match *self {
268 ParityCheck::None => write!(f, "None"),
269 ParityCheck::Strip => write!(f, "Strip"),
270 ParityCheck::Replace => write!(f, "Replace"),
271 ParityCheck::Mark => write!(f, "Mark"),
272 }
273 }
274}
275
276/// Queue types.
277#[derive(Debug, PartialEq, Eq, Copy, Clone)]
278pub enum Queue {
279 /// Input queue.
280 Input,
281 /// Output queue.
282 Output,
283 /// Both queues.
284 Both,
285}
286
287impl fmt::Display for Queue {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 match *self {
290 Queue::Input => write!(f, "Input"),
291 Queue::Output => write!(f, "Output"),
292 Queue::Both => write!(f, "Both"),
293 }
294 }
295}
296
297/// Control signal status.
298pub struct Status {
299 tiocm: c_int,
300}
301
302impl Status {
303 /// Returns `true` if RTS is active.
304 ///
305 /// RTS (active low) is controlled by [`Uart`]. An active signal indicates
306 /// [`Uart`] is ready to receive more data.
307 ///
308 /// [`Uart`]: struct.Uart.html
309 pub fn rts(&self) -> bool {
310 self.tiocm & TIOCM_RTS > 0
311 }
312
313 /// Returns `true` if CTS is active.
314 ///
315 /// CTS (active low) is controlled by the external device. An active signal
316 /// indicates the external device is ready to receive more data.
317 pub fn cts(&self) -> bool {
318 self.tiocm & TIOCM_CTS > 0
319 }
320
321 /// Returns `true` if DTR is active.
322 ///
323 /// DTR (active low) is controlled by [`Uart`]. When communicating with a
324 /// modem, an active signal is used to place or accept a call. An inactive
325 /// signal causes the modem to hang up. Other devices may use DTR and DSR
326 /// for flow control.
327 ///
328 /// DTR is not supported by the Raspberry Pi's UART peripherals,
329 /// but may be available on some USB to serial adapters.
330 ///
331 /// [`Uart`]: struct.Uart.html
332 pub fn dtr(&self) -> bool {
333 self.tiocm & TIOCM_DTR > 0
334 }
335
336 /// Returns `true` if DSR is active.
337 ///
338 /// DSR (active low) is controlled by the external device. When
339 /// communicating with a modem, an active signal indicates the modem is
340 /// ready for data transmission. Other devices may use DTR and DSR for flow
341 /// control.
342 ///
343 /// DSR is not supported by the Raspberry Pi's UART peripherals,
344 /// but may be available on some USB to serial adapters.
345 pub fn dsr(&self) -> bool {
346 self.tiocm & TIOCM_DSR > 0
347 }
348
349 /// Returns `true` if DCD is active.
350 ///
351 /// DCD (active low) is controlled by the external device. When
352 /// communicating with a modem, an active signal indicates a connection is
353 /// established.
354 ///
355 /// DCD is not supported by the Raspberry Pi's UART peripherals,
356 /// but may be available on some USB to serial adapters.
357 pub fn dcd(&self) -> bool {
358 self.tiocm & TIOCM_CAR > 0
359 }
360
361 /// Returns `true` if RI is active.
362 ///
363 /// RI (active low) is controlled by the external device. When
364 /// communicating with a modem, an active signal indicates an incoming
365 /// call.
366 ///
367 /// RI is not supported by the Raspberry Pi's UART peripherals,
368 /// but may be available on some USB to serial adapters.
369 pub fn ri(&self) -> bool {
370 self.tiocm & TIOCM_RNG > 0
371 }
372}
373
374impl fmt::Debug for Status {
375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376 f.debug_struct("Status")
377 .field("rts", &self.rts())
378 .field("cts", &self.cts())
379 .field("dtr", &self.dtr())
380 .field("dsr", &self.dsr())
381 .field("dcd", &self.dcd())
382 .field("ri", &self.ri())
383 .finish()
384 }
385}
386
387#[derive(Debug)]
388struct UartInner {
389 device: File,
390 fd: RawFd,
391 rtscts_mode: Option<(Mode, Mode)>,
392 rtscts_pins: Option<(IoPin, IoPin)>,
393 blocking_read: bool,
394 blocking_write: bool,
395 baud_rate: u32,
396 parity: Parity,
397 parity_check: ParityCheck,
398 data_bits: u8,
399 stop_bits: u8,
400 software_flow_control: bool,
401 hardware_flow_control: bool,
402}
403
404/// Provides access to the Raspberry Pi's UART peripherals and any USB to
405/// serial adapters.
406///
407/// The `embedded-hal` trait implementations for `Uart` can be enabled by specifying
408/// the optional `hal` feature in the dependency declaration for the `rpi_pal` crate.
409#[derive(Debug)]
410pub struct Uart {
411 inner: UartInner,
412}
413
414impl Uart {
415 /// Constructs a new `Uart`.
416 ///
417 /// `new` attempts to identify the UART peripheral tied to BCM GPIO 14 and
418 /// 15, and then calls [`with_path`] with the appropriate device path.
419 ///
420 /// [`with_path`]: #method.with_path
421 pub fn new(baud_rate: u32, parity: Parity, data_bits: u8, stop_bits: u8) -> Result<Uart> {
422 // On the Raspberry Pi 5, by default /dev/serial0 will point to the UART on the debug header,
423 // which is /dev/ttyAMA10. Check if /dev/ttyAMA0 exists first, which would mean the user
424 // enabled UART on GPIO14/15 and likely wants to use that one instead.
425 let path = match DeviceInfo::new()?.soc() {
426 SoC::Bcm2712 => {
427 if Path::new("/dev/ttyAMA0").exists() {
428 "/dev/ttyAMA0"
429 } else {
430 "/dev/serial0"
431 }
432 }
433 // Older models should use whatever /dev/serial0 points to.
434 _ => "/dev/serial0",
435 };
436
437 Self::with_path(path, baud_rate, parity, data_bits, stop_bits)
438 }
439
440 /// Constructs a new `Uart` connected to the serial character device
441 /// specified by `path`.
442 ///
443 /// `with_path` can be used to connect to either a UART peripheral or a USB
444 /// to serial adapter.
445 ///
446 /// When a new `Uart` is constructed, the specified device is configured
447 /// for non-canonical mode which processes input per character, ignores any
448 /// special terminal input or output characters and disables local echo. DCD
449 /// is ignored, all flow control is disabled, and the input and output queues
450 /// are flushed.
451 pub fn with_path<P: AsRef<Path>>(
452 path: P,
453 baud_rate: u32,
454 parity: Parity,
455 data_bits: u8,
456 stop_bits: u8,
457 ) -> Result<Uart> {
458 // Follow symbolic links
459 let path = fs::canonicalize(path)?;
460
461 // Check if we're using /dev/ttyAMA0 or /dev/ttyS0 so we can set the
462 // correct RTS/CTS pin modes when needed.
463 let rtscts_mode = if let Some(path_str) = path.to_str() {
464 match path_str {
465 "/dev/ttyAMA0" => Some((GPIO_RTS_MODE_UART0, GPIO_CTS_MODE_UART0)),
466 "/dev/ttyS0" => Some((GPIO_RTS_MODE_UART1, GPIO_CTS_MODE_UART1)),
467 _ => None,
468 }
469 } else {
470 None
471 };
472
473 let device = OpenOptions::new()
474 .read(true)
475 .write(true)
476 .custom_flags(O_NOCTTY | O_NONBLOCK)
477 .open(path)?;
478
479 let fd = device.as_raw_fd();
480
481 // Enables character input mode, disables echoing and any special
482 // processing
483 termios::set_raw_mode(fd)?;
484
485 // Non-blocking reads
486 termios::set_read_mode(fd, 0, Duration::default())?;
487
488 // Ignore modem control lines (CLOCAL)
489 termios::ignore_carrier_detect(fd)?;
490
491 // Enable receiver (CREAD)
492 termios::enable_read(fd)?;
493
494 // Disable software flow control (XON/XOFF)
495 termios::set_software_flow_control(fd, false, false)?;
496
497 // Disable hardware flow control (RTS/CTS)
498 termios::set_hardware_flow_control(fd, false)?;
499
500 termios::set_line_speed(fd, baud_rate)?;
501 termios::set_parity(fd, parity)?;
502 termios::set_data_bits(fd, data_bits)?;
503 termios::set_stop_bits(fd, stop_bits)?;
504
505 // Pass through parity errors unfiltered
506 termios::set_parity_check(fd, ParityCheck::None)?;
507
508 // Flush the input and output queue
509 termios::flush(fd, Queue::Both)?;
510
511 Ok(Uart {
512 inner: UartInner {
513 device,
514 fd,
515 rtscts_mode,
516 rtscts_pins: None,
517 blocking_read: false,
518 blocking_write: false,
519 baud_rate,
520 parity,
521 parity_check: ParityCheck::None,
522 data_bits,
523 stop_bits,
524 software_flow_control: false,
525 hardware_flow_control: false,
526 },
527 })
528 }
529
530 /// Returns the line speed in baud (Bd).
531 pub fn baud_rate(&self) -> u32 {
532 self.inner.baud_rate
533 }
534
535 /// Sets the line speed in baud (Bd).
536 ///
537 /// On the Raspberry Pi, baud rate is equivalent to bit rate in bits per
538 /// second (bit/s).
539 ///
540 /// Accepted values:
541 /// `0`, `50`, `75`, `110`, `134`, `150`, `200`, `300`, `600`, `1_200`,
542 /// `1_800`, `2_400`, `4_800`, `9_600`, `19_200`, `38_400`, `57_600`,
543 /// `115_200`, `230_400`, `460_800`, `500_000`, `576_000`, `921_600`,
544 /// `1_000_000`, `1_152_000`, `1_500_000`, `2_000_000`, `2_500_000`,
545 /// `3_000_000`, `3_500_000`, `4_000_000`.
546 ///
547 /// Support for some values may be device-dependent.
548 pub fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> {
549 termios::set_line_speed(self.inner.fd, baud_rate)?;
550
551 self.inner.baud_rate = baud_rate;
552
553 Ok(())
554 }
555
556 /// Returns the parity bit mode.
557 pub fn parity(&self) -> Parity {
558 self.inner.parity
559 }
560
561 /// Sets the parity bit mode.
562 ///
563 /// The parity bit mode determines how the parity bit is calculated.
564 ///
565 /// Support for some modes may be device-dependent.
566 pub fn set_parity(&mut self, parity: Parity) -> Result<()> {
567 termios::set_parity(self.inner.fd, parity)?;
568
569 self.inner.parity = parity;
570
571 Ok(())
572 }
573
574 /// Returns the parity check mode for incoming data.
575 pub fn parity_check(&self) -> ParityCheck {
576 self.inner.parity_check
577 }
578
579 /// Configures parity checking for incoming data.
580 ///
581 /// The parity check mode determines how parity errors are handled.
582 ///
583 /// By default, `parity_check` is set to [`None`].
584 ///
585 /// Support for some modes may be device-dependent.
586 ///
587 /// [`None`]: enum.ParityCheck.html#variant.None
588 pub fn set_parity_check(&mut self, parity_check: ParityCheck) -> Result<()> {
589 termios::set_parity_check(self.inner.fd, parity_check)?;
590
591 self.inner.parity_check = parity_check;
592
593 Ok(())
594 }
595
596 /// Returns the number of data bits.
597 pub fn data_bits(&self) -> u8 {
598 self.inner.data_bits
599 }
600
601 /// Sets the number of data bits.
602 ///
603 /// Accepted values: `5`, `6`, `7`, `8`.
604 ///
605 /// Support for some values may be device-dependent.
606 pub fn set_data_bits(&mut self, data_bits: u8) -> Result<()> {
607 termios::set_data_bits(self.inner.fd, data_bits)?;
608
609 self.inner.data_bits = data_bits;
610
611 Ok(())
612 }
613
614 /// Returns the number of stop bits.
615 pub fn stop_bits(&self) -> u8 {
616 self.inner.stop_bits
617 }
618
619 /// Sets the number of stop bits.
620 ///
621 /// Accepted values: `1`, `2`.
622 ///
623 /// Support for some values may be device-dependent.
624 pub fn set_stop_bits(&mut self, stop_bits: u8) -> Result<()> {
625 termios::set_stop_bits(self.inner.fd, stop_bits)?;
626
627 self.inner.stop_bits = stop_bits;
628
629 Ok(())
630 }
631
632 /// Returns the status of the control signals.
633 pub fn status(&self) -> Result<Status> {
634 let tiocm = termios::status(self.inner.fd)?;
635
636 Ok(Status { tiocm })
637 }
638
639 /// Sets DTR to active (`true`) or inactive (`false`).
640 ///
641 /// DTR is not supported by the Raspberry Pi's UART peripherals,
642 /// but may be available on some USB to serial adapters.
643 pub fn set_dtr(&mut self, dtr: bool) -> Result<()> {
644 termios::set_dtr(self.inner.fd, dtr)
645 }
646
647 /// Sets RTS to active (`true`) or inactive (`false`).
648 pub fn set_rts(&mut self, rts: bool) -> Result<()> {
649 termios::set_rts(self.inner.fd, rts)
650 }
651
652 /// Returns `true` if XON/XOFF software flow control is enabled.
653 pub fn software_flow_control(&self) -> bool {
654 self.inner.software_flow_control
655 }
656
657 /// Enables or disables XON/XOFF software flow control.
658 ///
659 /// When software flow control is enabled, incoming XON (decimal 17) and
660 /// XOFF (decimal 19) control characters are filtered from the input queue.
661 /// When XOFF is received, the transmission of data in the output queue is
662 /// paused until the external device sends XON. XOFF is automatically sent
663 /// to the external device to prevent the input queue from overflowing.
664 /// XON is sent when the input queue is ready for more data. You can also
665 /// manually send these control characters by calling [`send_stop`] and
666 /// [`send_start`].
667 ///
668 /// By default, software flow control is disabled.
669 ///
670 /// Support for XON/XOFF software flow control is
671 /// device-dependent. You can manually implement XON/XOFF by disabling
672 /// software flow control, parsing incoming XON/XOFF control characters
673 /// received with [`read`], and sending XON/XOFF when needed using
674 /// [`write`].
675 ///
676 /// [`send_start`]: #method.send_start
677 /// [`send_stop`]: #method.send_stop
678 /// [`read`]: #method.read
679 /// [`write`]: #method.write
680 pub fn set_software_flow_control(&mut self, software_flow_control: bool) -> Result<()> {
681 termios::set_software_flow_control(
682 self.inner.fd,
683 software_flow_control,
684 software_flow_control,
685 )?;
686
687 self.inner.software_flow_control = software_flow_control;
688
689 Ok(())
690 }
691
692 /// Returns `true` if RTS/CTS hardware flow control is enabled.
693 pub fn hardware_flow_control(&self) -> bool {
694 self.inner.hardware_flow_control
695 }
696
697 /// Enables or disables RTS/CTS hardware flow control.
698 ///
699 /// When hardware flow control is enabled, the RTS line (active low) is
700 /// automatically driven high to prevent the input queue from overflowing,
701 /// and driven low when the input queue is ready for more data. When the
702 /// CTS line (active low) is driven high by the external device, all data
703 /// in the output queue is held until CTS is driven low. You can also
704 /// manually change the active state of RTS by calling [`send_stop`] and
705 /// [`send_start`].
706 ///
707 /// When `Uart` is controlling a UART peripheral, enabling hardware flow
708 /// control will also configure the RTS and CTS pins.
709 ///
710 /// More information on hardware flow control can be found [here].
711 ///
712 /// By default, hardware flow control is disabled.
713 ///
714 /// Support for RTS/CTS hardware flow control is device-dependent. You can
715 /// manually implement RTS/CTS using [`cts`], [`send_stop`] and
716 /// [`send_start`], or by disabling hardware flow control and configuring
717 /// an [`OutputPin`] for RTS and an [`InputPin`] for CTS.
718 ///
719 /// [here]: index.html#hardware-flow-control
720 /// [`cts`]: struct.Status.html#method.cts
721 /// [`send_start`]: #method.send_start
722 /// [`send_stop`]: #method.send_stop
723 /// [`OutputPin`]: ../gpio/struct.OutputPin.html
724 /// [`InputPin`]: ../gpio/struct.InputPin.html
725 pub fn set_hardware_flow_control(&mut self, hardware_flow_control: bool) -> Result<()> {
726 if hardware_flow_control && self.inner.rtscts_pins.is_none() {
727 // Configure and store RTS/CTS GPIO pins for UART0/UART1, so their
728 // mode is automatically reset when Uart goes out of scope.
729 if let Some((rts_mode, cts_mode)) = self.inner.rtscts_mode {
730 let gpio = Gpio::new()?;
731
732 let (gpio_rts, gpio_cts) = if DeviceInfo::new()?.model() == Model::RaspberryPiBRev2
733 {
734 // The Pi B Rev 2 exposes RTS/CTS through its (unpopulated) P5 header
735 (GPIO_RTS_BREV2, GPIO_CTS_BREV2)
736 } else {
737 // All other models with a 40-pin header use these GPIO pins
738 (GPIO_RTS, GPIO_CTS)
739 };
740
741 let pin_rts = gpio.get(gpio_rts)?.into_io(rts_mode);
742 let pin_cts = gpio.get(gpio_cts)?.into_io(cts_mode);
743
744 self.inner.rtscts_pins = Some((pin_rts, pin_cts));
745 }
746 } else if !hardware_flow_control {
747 self.inner.rtscts_pins = None;
748 }
749
750 termios::set_hardware_flow_control(self.inner.fd, hardware_flow_control)?;
751
752 self.inner.hardware_flow_control = hardware_flow_control;
753
754 Ok(())
755 }
756
757 /// Requests the external device to pause its transmission using flow control.
758 ///
759 /// If software flow control is enabled, `send_stop`
760 /// sends the XOFF control character.
761 ///
762 /// If hardware flow control is enabled, `send_stop` sets RTS to its
763 /// inactive state.
764 pub fn send_stop(&self) -> Result<()> {
765 if self.inner.software_flow_control {
766 termios::send_stop(self.inner.fd)?;
767 }
768
769 if self.inner.hardware_flow_control {
770 termios::set_rts(self.inner.fd, false)?;
771 }
772
773 Ok(())
774 }
775
776 /// Requests the external device to resume its transmission using flow control.
777 ///
778 /// If software flow control is enabled, `send_start`
779 /// sends the XON control character.
780 ///
781 /// If hardware flow control is enabled, `send_start` sets RTS to its
782 /// active state.
783 pub fn send_start(&self) -> Result<()> {
784 if self.inner.software_flow_control {
785 termios::send_start(self.inner.fd)?;
786 }
787
788 if self.inner.hardware_flow_control {
789 termios::set_rts(self.inner.fd, true)?;
790 }
791
792 Ok(())
793 }
794
795 /// Returns `true` if [`read`] is configured to block when needed.
796 ///
797 /// [`read`]: #method.write
798 pub fn is_read_blocking(&self) -> bool {
799 self.inner.blocking_read
800 }
801
802 /// Returns `true` if [`write`] is configured to block when needed.
803 ///
804 /// [`write`]: #method.write
805 pub fn is_write_blocking(&self) -> bool {
806 self.inner.blocking_write
807 }
808
809 /// Sets the blocking mode for subsequent calls to [`read`].
810 ///
811 /// `min_length` indicates the minimum number of requested bytes. This
812 /// value may differ from the actual buffer length. Maximum value: 255
813 /// bytes.
814 ///
815 /// `timeout` indicates how long [`read`] blocks while waiting for
816 /// incoming data. `timeout` uses a 0.1 second resolution. Maximum
817 /// value: 25.5 seconds.
818 ///
819 /// [`read`] operates in one of four modes, depending on the specified
820 /// `min_length` and `timeout` values:
821 ///
822 /// * **Non-blocking read** (`min_length` = 0, `timeout` = 0). [`read`]
823 /// retrieves any available data and returns immediately.
824 /// * **Blocking read** (`min_length` > 0, `timeout` = 0). [`read`] blocks
825 /// until at least `min_length` bytes are available, or the provided buffer
826 /// is full.
827 /// * **Read with timeout** (`min_length` = 0, `timeout` > 0). [`read`]
828 /// blocks until at least one byte is available, or the `timeout` duration
829 /// elapses.
830 /// * **Read with inter-byte timeout** (`min_length` > 0, `timeout` > 0).
831 /// [`read`] blocks until at least `min_length` bytes are available, the
832 /// provided buffer is full, or the `timeout` duration elapses
833 /// after receiving one or more bytes. The timer is started after an
834 /// initial byte becomes available, and is restarted after each additional
835 /// byte. That means [`read`] will block indefinitely until at least one
836 /// byte has been received.
837 ///
838 /// By default, [`read`] is configured as non-blocking.
839 ///
840 /// [`read`]: #method.read
841 pub fn set_read_mode(&mut self, min_length: u8, timeout: Duration) -> Result<()> {
842 termios::set_read_mode(self.inner.fd, min_length, timeout)?;
843
844 self.inner.blocking_read = min_length > 0 || timeout.as_millis() > 0;
845
846 // If both read() and write() are non-blocking, we can safely set
847 // O_NONBLOCK once instead of toggling it for every write. We can't
848 // leave it set when read() should block, because it ignores the
849 // VMIN and VTIME settings.
850 if self.inner.blocking_read || self.inner.blocking_write {
851 unsafe {
852 libc::fcntl(self.inner.fd, libc::F_SETFL, 0);
853 }
854 } else {
855 unsafe {
856 libc::fcntl(self.inner.fd, libc::F_SETFL, libc::O_NONBLOCK);
857 }
858 }
859
860 Ok(())
861 }
862
863 /// Sets the blocking mode for subsequent calls to [`write`].
864 ///
865 /// [`write`] operates in one of two modes, depending on the specified
866 /// `blocking` value:
867 ///
868 /// * **Non-blocking write**. [`write`] returns immediately after
869 /// copying as much of the contents of the provided buffer to the output queue
870 /// as it's able to fit.
871 /// * **Blocking write**. [`write`] blocks until the entire contents of the provided buffer
872 /// can be copied to the output queue. If flow control is enabled and the
873 /// external device has sent a stop request, the transmission of any waiting data
874 /// in the output queue is paused until a start request has been received.
875 ///
876 /// By default, [`write`] is configured as non-blocking.
877 ///
878 /// [`write`]: #method.write
879 pub fn set_write_mode(&mut self, blocking: bool) -> Result<()> {
880 self.inner.blocking_write = blocking;
881
882 // If both read() and write() are non-blocking, we can safely set
883 // O_NONBLOCK once instead of toggling it for every write. We can't
884 // leave it set when read() should block, because it ignores the
885 // VMIN and VTIME settings.
886 if self.inner.blocking_read || self.inner.blocking_write {
887 unsafe {
888 libc::fcntl(self.inner.fd, libc::F_SETFL, 0);
889 }
890 } else {
891 unsafe {
892 libc::fcntl(self.inner.fd, libc::F_SETFL, libc::O_NONBLOCK);
893 }
894 }
895
896 Ok(())
897 }
898
899 /// Returns the number of bytes waiting in the input queue.
900 pub fn input_len(&self) -> Result<usize> {
901 termios::input_len(self.inner.fd)
902 }
903
904 /// Returns the number of bytes waiting in the output queue.
905 pub fn output_len(&self) -> Result<usize> {
906 termios::output_len(self.inner.fd)
907 }
908
909 /// Receives incoming data from the external device and stores it in
910 /// `buffer`.
911 ///
912 /// `read` operates in one of four (non)blocking modes, depending on the
913 /// settings configured by [`set_read_mode`]. By default, `read` is configured
914 /// as non-blocking.
915 ///
916 /// Returns how many bytes were read.
917 ///
918 /// [`set_read_mode`]: #method.set_read_mode
919 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
920 self.inner.device.read(buffer).or_else(|e| {
921 if e.kind() == io::ErrorKind::WouldBlock {
922 Ok(0)
923 } else {
924 Err(Error::Io(e))
925 }
926 })
927 }
928
929 /// Sends the contents of `buffer` to the external device.
930 ///
931 /// `write` operates in either blocking or non-blocking mode, depending on the
932 /// settings configured by [`set_write_mode`]. By default, `write` is configured
933 /// as non-blocking.
934 ///
935 /// Returns how many bytes were written.
936 ///
937 /// [`set_write_mode`]: #method.set_write_mode
938 pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
939 // We only need to toggle O_NONBLOCK when read() is configured as
940 // blocking. If read() is non-blocking, either with_path() or
941 // set_read_mode() will have already enabled O_NONBLOCK.
942 if self.inner.blocking_read && !self.inner.blocking_write {
943 unsafe {
944 libc::fcntl(self.inner.fd, libc::F_SETFL, libc::O_NONBLOCK);
945 }
946 }
947
948 let result = self.inner.device.write(buffer).or_else(|e| {
949 if e.kind() == io::ErrorKind::WouldBlock {
950 Ok(0)
951 } else {
952 Err(Error::Io(e))
953 }
954 });
955
956 if self.inner.blocking_read && !self.inner.blocking_write {
957 unsafe {
958 libc::fcntl(self.inner.fd, libc::F_SETFL, 0);
959 }
960 }
961
962 result
963 }
964
965 /// Blocks until all data in the output queue has been transmitted.
966 pub fn drain(&self) -> Result<()> {
967 termios::drain(self.inner.fd)
968 }
969
970 /// Discards all data in the input and/or output queue.
971 pub fn flush(&self, queue_type: Queue) -> Result<()> {
972 termios::flush(self.inner.fd, queue_type)
973 }
974}