opentitanlib/io/uart/
flow.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::cell::{Cell, RefCell};
6use std::collections::VecDeque;
7use std::os::fd::BorrowedFd;
8use std::task::{Context, Poll, Waker, ready};
9use std::time::Duration;
10
11use anyhow::{Context as _, Result};
12
13use super::{FlowControl, Parity, Uart};
14use crate::io::console::ConsoleDevice;
15
16/// Add software flow control to a UART device.
17///
18/// Flow control is performed using XON/XOFF bytes.
19pub struct SoftwareFlowControl<T> {
20    inner: T,
21    flow_control: Cell<FlowControl>,
22    rxbuf: RefCell<VecDeque<u8>>,
23}
24
25impl<T: Uart> SoftwareFlowControl<T> {
26    /// Open the given serial device, such as `/dev/ttyUSB0`.
27    pub fn new(inner: T) -> Self {
28        SoftwareFlowControl {
29            inner,
30            flow_control: Cell::new(FlowControl::None),
31            rxbuf: RefCell::default(),
32        }
33    }
34
35    /// Attempt to read more data into the buffer, and handle flow control characters.
36    ///
37    /// This may not add more data to the buffer if all characters are flow control.
38    fn poll_read_to_buffer(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
39        let mut buf = [0u8; 256];
40        let len = ready!(self.inner.poll_read(cx, &mut buf)).context("UART read error")?;
41
42        for &ch in &buf[..len] {
43            if self.flow_control.get() != FlowControl::None {
44                if ch == FlowControl::Resume as u8 {
45                    log::debug!("Got RESUME");
46                    self.flow_control.set(FlowControl::Resume);
47                    continue;
48                } else if ch == FlowControl::Pause as u8 {
49                    log::debug!("Got PAUSE");
50                    self.flow_control.set(FlowControl::Pause);
51                    continue;
52                }
53            }
54            self.rxbuf.borrow_mut().push_back(ch);
55        }
56        Poll::Ready(Ok(()))
57    }
58}
59
60impl<T: Uart> ConsoleDevice for SoftwareFlowControl<T> {
61    fn poll_read(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
62        let mut rxbuf = self.rxbuf.borrow_mut();
63
64        while rxbuf.is_empty() {
65            drop(rxbuf);
66            ready!(self.poll_read_to_buffer(cx))?;
67            rxbuf = self.rxbuf.borrow_mut();
68        }
69
70        // `VecDeque` can be viewed as two slices.
71        let (front, back) = rxbuf.as_slices();
72
73        let front_copy = std::cmp::min(buf.len(), front.len());
74        buf[..front_copy].copy_from_slice(&front[..front_copy]);
75
76        let back_copy = std::cmp::min(buf.len() - front_copy, back.len());
77        buf[front_copy..][..back_copy].copy_from_slice(&back[..back_copy]);
78
79        let copy_len = front_copy + back_copy;
80        rxbuf.drain(..copy_len);
81        Poll::Ready(Ok(copy_len))
82    }
83
84    /// Writes data from `buf` to the UART.
85    fn write(&self, buf: &[u8]) -> Result<()> {
86        if self.flow_control.get() == FlowControl::None {
87            return self.inner.write(buf);
88        }
89
90        // The constant of 10 is approximately 10 uart bit times per byte.
91        let pacing = Duration::from_nanos(10 * 1_000_000_000u64 / (self.get_baudrate()? as u64));
92        log::debug!(
93            "flow control: {:?}, pacing = {:?}",
94            self.flow_control.get(),
95            pacing
96        );
97
98        for b in buf.iter() {
99            // If flow control is enabled, read data from the input stream and
100            // process the flow control chars.
101            loop {
102                let _ = self.poll_read_to_buffer(&mut Context::from_waker(Waker::noop()))?;
103                // If we're ok to send, then break out of the flow-control loop and send the data.
104                if self.flow_control.get() == FlowControl::Resume {
105                    break;
106                }
107                // Sleep one uart character time to avoid busy polling the UART.
108                std::thread::sleep(pacing);
109            }
110            self.inner
111                .write(std::slice::from_ref(b))
112                .context("UART write error")?;
113            // Sleep one uart character time after writing to the uart to pace characters into the
114            // usb-serial device so that we don't fill any device-internal buffers.  The Chip Whisperer board (for
115            // example) appears to have a large internal buffer that will keep transmitting to OT
116            // even if an XOFF is sent.
117            std::thread::sleep(pacing);
118        }
119        Ok(())
120    }
121}
122
123impl<T: Uart> Uart for SoftwareFlowControl<T> {
124    fn get_baudrate(&self) -> Result<u32> {
125        self.inner.get_baudrate()
126    }
127
128    /// Sets the UART baudrate.  May do nothing for virtual UARTs.
129    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
130        self.inner.set_baudrate(baudrate)
131    }
132
133    fn get_flow_control(&self) -> Result<FlowControl> {
134        Ok(self.flow_control.get())
135    }
136
137    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
138        self.flow_control.set(match flow_control {
139            false => FlowControl::None,
140            // When flow-control is enabled, assume we haven't
141            // already been put into a pause state.
142            true => FlowControl::Resume,
143        });
144        Ok(())
145    }
146
147    fn get_device_path(&self) -> Result<String> {
148        self.inner.get_device_path()
149    }
150
151    fn set_parity(&self, parity: Parity) -> Result<()> {
152        self.inner.set_parity(parity)
153    }
154
155    /// Clears the UART RX buffer.
156    fn clear_rx_buffer(&self) -> Result<()> {
157        self.rxbuf.borrow_mut().clear();
158
159        // Clear the host input buffer.
160        self.inner.clear_rx_buffer()
161    }
162
163    fn set_break(&self, enable: bool) -> Result<()> {
164        self.inner.set_break(enable)
165    }
166
167    fn borrow_fd(&self) -> Result<BorrowedFd<'_>> {
168        self.inner.borrow_fd()
169    }
170}