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::rc::Rc;
7use std::time::Duration;
8
9use anyhow::Result;
10use clap::Args;
11use serde::{Deserialize, Serialize};
12pub use serialport::Parity;
13use thiserror::Error;
14
15use crate::app::TransportWrapper;
16use crate::impl_serializable_error;
17use crate::io::console::{ConsoleDevice, ConsoleExt};
18use crate::transport::TransportError;
19
20pub mod flow;
21pub mod serial;
22
23#[derive(Clone, Debug, Args, Serialize, Deserialize)]
24pub struct UartParams {
25    /// UART instance.
26    #[arg(long, default_value = "CONSOLE")]
27    uart: String,
28
29    /// UART baudrate.
30    #[arg(long)]
31    baudrate: Option<u32>,
32
33    /// Enable software flow control.
34    #[arg(long)]
35    flow_control: bool,
36}
37
38impl UartParams {
39    pub fn create(&self, transport: &TransportWrapper) -> Result<Rc<dyn Uart>> {
40        let uart = transport.uart(&self.uart)?;
41        if let Some(baudrate) = self.baudrate {
42            uart.set_baudrate(baudrate)?;
43        }
44        log::info!("set_flow_control to {}", self.flow_control);
45        uart.set_flow_control(self.flow_control)?;
46        Ok(uart)
47    }
48}
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
51#[repr(u8)]
52pub enum FlowControl {
53    // No flow control.
54    None = 0,
55    // Pause aka XOFF aka Ctrl-S ("Stop")
56    Pause = 19,
57    // Resume aka XON aka Ctrl-Q ("Quit Stopping")
58    Resume = 17,
59}
60
61/// A trait which represents a UART.
62pub trait Uart: ConsoleDevice {
63    /// Returns the UART baudrate.  May return zero for virtual UARTs.
64    fn get_baudrate(&self) -> Result<u32>;
65
66    /// Sets the UART baudrate.  May do nothing for virtual UARTs.
67    fn set_baudrate(&self, baudrate: u32) -> Result<()>;
68
69    // Returns whether software flow control is enabled for the UART `write`s.
70    fn get_flow_control(&self) -> Result<FlowControl> {
71        unimplemented!();
72    }
73
74    /// Enables software flow control for `write`s.
75    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
76        if flow_control {
77            unimplemented!();
78        }
79        Ok(())
80    }
81
82    /// Returns `"/dev/ttyUSBn"` or similar OS device path usable by external programs for
83    /// directly accessing the serial port.
84    fn get_device_path(&self) -> Result<String> {
85        Err(TransportError::UnsupportedOperation.into())
86    }
87
88    /// Clears the UART RX buffer.
89    fn clear_rx_buffer(&self) -> Result<()> {
90        // Keep reading while until the RX buffer is empty.
91        // Note: This default implementation is overriden in backends where we can do better.
92        const TIMEOUT: Duration = Duration::from_millis(5);
93        let mut buf = [0u8; 256];
94        while self.read_timeout(&mut buf, TIMEOUT)? > 0 {}
95        Ok(())
96    }
97
98    fn set_parity(&self, _parity: Parity) -> Result<()> {
99        Err(TransportError::UnsupportedOperation.into())
100    }
101
102    fn get_parity(&self) -> Result<Parity> {
103        Err(TransportError::UnsupportedOperation.into())
104    }
105
106    fn set_break(&self, _enable: bool) -> Result<()> {
107        Err(TransportError::UnsupportedOperation.into())
108    }
109}
110
111impl<T: Uart + ?Sized> Uart for &T {
112    fn get_baudrate(&self) -> Result<u32> {
113        T::get_baudrate(self)
114    }
115
116    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
117        T::set_baudrate(self, baudrate)
118    }
119
120    fn get_flow_control(&self) -> Result<FlowControl> {
121        T::get_flow_control(self)
122    }
123
124    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
125        T::set_flow_control(self, flow_control)
126    }
127
128    fn get_device_path(&self) -> Result<String> {
129        T::get_device_path(self)
130    }
131
132    fn clear_rx_buffer(&self) -> Result<()> {
133        T::clear_rx_buffer(self)
134    }
135
136    fn set_parity(&self, parity: Parity) -> Result<()> {
137        T::set_parity(self, parity)
138    }
139
140    fn get_parity(&self) -> Result<Parity> {
141        T::get_parity(self)
142    }
143
144    fn set_break(&self, enable: bool) -> Result<()> {
145        T::set_break(self, enable)
146    }
147}
148
149impl<T: Uart + ?Sized> Uart for Rc<T> {
150    fn get_baudrate(&self) -> Result<u32> {
151        T::get_baudrate(self)
152    }
153
154    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
155        T::set_baudrate(self, baudrate)
156    }
157
158    fn get_flow_control(&self) -> Result<FlowControl> {
159        T::get_flow_control(self)
160    }
161
162    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
163        T::set_flow_control(self, flow_control)
164    }
165
166    fn get_device_path(&self) -> Result<String> {
167        T::get_device_path(self)
168    }
169
170    fn clear_rx_buffer(&self) -> Result<()> {
171        T::clear_rx_buffer(self)
172    }
173
174    fn set_parity(&self, parity: Parity) -> Result<()> {
175        T::set_parity(self, parity)
176    }
177
178    fn get_parity(&self) -> Result<Parity> {
179        T::get_parity(self)
180    }
181
182    fn set_break(&self, enable: bool) -> Result<()> {
183        T::set_break(self, enable)
184    }
185}
186
187impl Read for &dyn Uart {
188    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
189        ConsoleExt::read(&**self, buf).map_err(io::Error::other)
190    }
191}
192
193/// Errors related to the UART interface.
194#[derive(Error, Debug, Serialize, Deserialize)]
195pub enum UartError {
196    #[error("Enumerating: {0}")]
197    EnumerationError(String),
198    #[error("Opening: {0}")]
199    OpenError(String),
200    #[error("Invalid option: {0}")]
201    InvalidOption(String),
202    #[error("Invalid speed: {0}")]
203    InvalidSpeed(u32),
204    #[error("Reading: {0}")]
205    ReadError(String),
206    #[error("Writing: {0}")]
207    WriteError(String),
208    #[error("{0}")]
209    GenericError(String),
210}
211impl_serializable_error!(UartError);