opentitanlib/io/console/
buf.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::sync::Mutex;
6use std::task::{Context, Poll, ready};
7
8use anyhow::Result;
9
10use super::ConsoleDevice;
11use crate::io::uart::{FlowControl, Parity, Uart};
12
13/// Console wrapper with receive buffer.
14pub struct Buffered<T> {
15    inner: T,
16    buffer: Mutex<Inner>,
17}
18
19struct Inner {
20    buffer: Box<[u8; 256]>,
21    len: usize,
22    offset: usize,
23}
24
25impl<T> Buffered<T> {
26    pub fn new(inner: T) -> Self {
27        Self {
28            inner,
29            buffer: Mutex::new(Inner {
30                buffer: vec![0; 256].try_into().unwrap(),
31                len: 0,
32                offset: 0,
33            }),
34        }
35    }
36}
37
38impl<T: ConsoleDevice> ConsoleDevice for Buffered<T> {
39    fn poll_read(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
40        let mut buffer = self.buffer.lock().unwrap();
41
42        loop {
43            if buffer.len != 0 {
44                let copy_len = std::cmp::min(buffer.len, buf.len());
45                buf[..copy_len].copy_from_slice(&buffer.buffer[buffer.offset..][..copy_len]);
46                buffer.offset += copy_len;
47                buffer.len -= copy_len;
48                return Poll::Ready(Ok(copy_len));
49            }
50
51            if buf.len() >= buffer.buffer.len() {
52                return self.inner.poll_read(cx, buf);
53            }
54
55            buffer.len = ready!(self.inner.poll_read(cx, &mut buffer.buffer[..]))?;
56            buffer.offset = 0;
57        }
58    }
59
60    fn write(&self, buf: &[u8]) -> Result<()> {
61        self.inner.write(buf)
62    }
63}
64
65impl<T: Uart> Uart for Buffered<T> {
66    fn get_baudrate(&self) -> Result<u32> {
67        self.inner.get_baudrate()
68    }
69
70    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
71        self.inner.set_baudrate(baudrate)
72    }
73
74    fn get_flow_control(&self) -> Result<FlowControl> {
75        self.inner.get_flow_control()
76    }
77
78    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
79        self.inner.set_flow_control(flow_control)
80    }
81
82    fn get_device_path(&self) -> Result<String> {
83        self.inner.get_device_path()
84    }
85
86    fn clear_rx_buffer(&self) -> Result<()> {
87        let mut buffer = self.buffer.lock().unwrap();
88        buffer.offset = 0;
89        buffer.len = 0;
90
91        self.inner.clear_rx_buffer()?;
92        Ok(())
93    }
94
95    fn set_parity(&self, parity: Parity) -> Result<()> {
96        self.inner.set_parity(parity)
97    }
98
99    fn get_parity(&self) -> Result<Parity> {
100        self.inner.get_parity()
101    }
102
103    fn set_break(&self, enable: bool) -> Result<()> {
104        self.inner.set_break(enable)
105    }
106}