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