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<T: Uart + ?Sized> Uart for &T {
117    fn get_baudrate(&self) -> Result<u32> {
118        T::get_baudrate(self)
119    }
120
121    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
122        T::set_baudrate(self, baudrate)
123    }
124
125    fn get_flow_control(&self) -> Result<FlowControl> {
126        T::get_flow_control(self)
127    }
128
129    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
130        T::set_flow_control(self, flow_control)
131    }
132
133    fn get_device_path(&self) -> Result<String> {
134        T::get_device_path(self)
135    }
136
137    fn clear_rx_buffer(&self) -> Result<()> {
138        T::clear_rx_buffer(self)
139    }
140
141    fn set_parity(&self, parity: Parity) -> Result<()> {
142        T::set_parity(self, parity)
143    }
144
145    fn get_parity(&self) -> Result<Parity> {
146        T::get_parity(self)
147    }
148
149    fn set_break(&self, enable: bool) -> Result<()> {
150        T::set_break(self, enable)
151    }
152}
153
154impl<T: Uart + ?Sized> Uart for Rc<T> {
155    fn get_baudrate(&self) -> Result<u32> {
156        T::get_baudrate(self)
157    }
158
159    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
160        T::set_baudrate(self, baudrate)
161    }
162
163    fn get_flow_control(&self) -> Result<FlowControl> {
164        T::get_flow_control(self)
165    }
166
167    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
168        T::set_flow_control(self, flow_control)
169    }
170
171    fn get_device_path(&self) -> Result<String> {
172        T::get_device_path(self)
173    }
174
175    fn clear_rx_buffer(&self) -> Result<()> {
176        T::clear_rx_buffer(self)
177    }
178
179    fn set_parity(&self, parity: Parity) -> Result<()> {
180        T::set_parity(self, parity)
181    }
182
183    fn get_parity(&self) -> Result<Parity> {
184        T::get_parity(self)
185    }
186
187    fn set_break(&self, enable: bool) -> Result<()> {
188        T::set_break(self, enable)
189    }
190
191    fn borrow_fd(&self) -> Result<BorrowedFd<'_>> {
192        Err(TransportError::UnsupportedOperation.into())
193    }
194}
195
196impl Read for &dyn Uart {
197    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
198        ConsoleExt::read(&**self, buf).map_err(io::Error::other)
199    }
200}
201
202/// Errors related to the UART interface.
203#[derive(Error, Debug, Serialize, Deserialize)]
204pub enum UartError {
205    #[error("Enumerating: {0}")]
206    EnumerationError(String),
207    #[error("Opening: {0}")]
208    OpenError(String),
209    #[error("Invalid option: {0}")]
210    InvalidOption(String),
211    #[error("Invalid speed: {0}")]
212    InvalidSpeed(u32),
213    #[error("Reading: {0}")]
214    ReadError(String),
215    #[error("Writing: {0}")]
216    WriteError(String),
217    #[error("{0}")]
218    GenericError(String),
219}
220impl_serializable_error!(UartError);