opentitanlib/io/uart/
mod.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use std::io::{self, Read};
6use std::os::fd::BorrowedFd;
7use std::rc::Rc;
8use std::time::Duration;
9
10use anyhow::Result;
11use clap::Args;
12use serde::{Deserialize, Serialize};
13pub use serialport::Parity;
14use thiserror::Error;
15
16use crate::app::TransportWrapper;
17use crate::impl_serializable_error;
18use crate::io::console::{ConsoleDevice, ConsoleExt};
19use crate::transport::TransportError;
20
21pub mod flow;
22pub mod serial;
23
24#[derive(Clone, Debug, Default, Args, Serialize, Deserialize)]
25pub struct UartParams {
26    /// UART instance.
27    #[arg(long, default_value = "CONSOLE")]
28    uart: String,
29
30    /// UART baudrate.
31    #[arg(long)]
32    baudrate: Option<u32>,
33
34    /// Enable software flow control.
35    #[arg(long)]
36    flow_control: bool,
37}
38
39impl UartParams {
40    pub fn create(&self, transport: &TransportWrapper) -> Result<Rc<dyn Uart>> {
41        let uart = transport.uart(&self.uart)?;
42        if let Some(baudrate) = self.baudrate {
43            uart.set_baudrate(baudrate)?;
44        }
45        log::info!("set_flow_control to {}", self.flow_control);
46        uart.set_flow_control(self.flow_control)?;
47        Ok(uart)
48    }
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
52#[repr(u8)]
53pub enum FlowControl {
54    // No flow control.
55    None = 0,
56    // Pause aka XOFF aka Ctrl-S ("Stop")
57    Pause = 19,
58    // Resume aka XON aka Ctrl-Q ("Quit Stopping")
59    Resume = 17,
60}
61
62/// A trait which represents a UART.
63pub trait Uart: ConsoleDevice {
64    /// Returns the UART baudrate.  May return zero for virtual UARTs.
65    fn get_baudrate(&self) -> Result<u32>;
66
67    /// Sets the UART baudrate.  May do nothing for virtual UARTs.
68    fn set_baudrate(&self, baudrate: u32) -> Result<()>;
69
70    // Returns whether software flow control is enabled for the UART `write`s.
71    fn get_flow_control(&self) -> Result<FlowControl> {
72        unimplemented!();
73    }
74
75    /// Enables software flow control for `write`s.
76    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
77        if flow_control {
78            unimplemented!();
79        }
80        Ok(())
81    }
82
83    /// Returns `"/dev/ttyUSBn"` or similar OS device path usable by external programs for
84    /// directly accessing the serial port.
85    fn get_device_path(&self) -> Result<String> {
86        Err(TransportError::UnsupportedOperation.into())
87    }
88
89    /// Clears the UART RX buffer.
90    fn clear_rx_buffer(&self) -> Result<()> {
91        // Keep reading while until the RX buffer is empty.
92        // Note: This default implementation is overriden in backends where we can do better.
93        const TIMEOUT: Duration = Duration::from_millis(5);
94        let mut buf = [0u8; 256];
95        while self.read_timeout(&mut buf, TIMEOUT)? > 0 {}
96        Ok(())
97    }
98
99    fn set_parity(&self, _parity: Parity) -> Result<()> {
100        Err(TransportError::UnsupportedOperation.into())
101    }
102
103    fn get_parity(&self) -> Result<Parity> {
104        Err(TransportError::UnsupportedOperation.into())
105    }
106
107    fn set_break(&self, _enable: bool) -> Result<()> {
108        Err(TransportError::UnsupportedOperation.into())
109    }
110
111    fn borrow_fd(&self) -> Result<BorrowedFd<'_>> {
112        Err(TransportError::UnsupportedOperation.into())
113    }
114}
115
116impl Read for &dyn Uart {
117    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
118        ConsoleExt::read(&**self, buf).map_err(io::Error::other)
119    }
120}
121
122/// Errors related to the UART interface.
123#[derive(Error, Debug, Serialize, Deserialize)]
124pub enum UartError {
125    #[error("Enumerating: {0}")]
126    EnumerationError(String),
127    #[error("Opening: {0}")]
128    OpenError(String),
129    #[error("Invalid option: {0}")]
130    InvalidOption(String),
131    #[error("Invalid speed: {0}")]
132    InvalidSpeed(u32),
133    #[error("Reading: {0}")]
134    ReadError(String),
135    #[error("Writing: {0}")]
136    WriteError(String),
137    #[error("{0}")]
138    GenericError(String),
139}
140impl_serializable_error!(UartError);