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::middleware::{ConsoleMiddleware, Middleware, UartMiddleware};
12use crate::io::uart::Uart;
13
14/// Console wrapper with receive buffer.
15pub struct Buffered<T> {
16    inner: T,
17    buffer: Mutex<Inner>,
18}
19
20struct Inner {
21    buffer: Box<[u8; 256]>,
22    len: usize,
23    offset: usize,
24}
25
26impl<T> Buffered<T> {
27    pub fn new(inner: T) -> Self {
28        Self {
29            inner,
30            buffer: Mutex::new(Inner {
31                buffer: vec![0; 256].try_into().unwrap(),
32                len: 0,
33                offset: 0,
34            }),
35        }
36    }
37}
38
39impl<T: ConsoleDevice> Middleware for Buffered<T> {
40    type Inner = T;
41    fn inner(&self) -> &T {
42        &self.inner
43    }
44}
45
46impl<T: ConsoleDevice> ConsoleMiddleware for Buffered<T> {
47    fn poll_read_impl(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
48        let mut buffer = self.buffer.lock().unwrap();
49
50        loop {
51            if buffer.len != 0 {
52                let copy_len = std::cmp::min(buffer.len, buf.len());
53                buf[..copy_len].copy_from_slice(&buffer.buffer[buffer.offset..][..copy_len]);
54                buffer.offset += copy_len;
55                buffer.len -= copy_len;
56                return Poll::Ready(Ok(copy_len));
57            }
58
59            if buf.len() >= buffer.buffer.len() {
60                return self.inner.poll_read(cx, buf);
61            }
62
63            buffer.len = ready!(self.inner.poll_read(cx, &mut buffer.buffer[..]))?;
64            buffer.offset = 0;
65        }
66    }
67}
68
69impl<T: Uart> UartMiddleware for Buffered<T> {
70    fn clear_rx_buffer_impl(&self) -> Result<()> {
71        let mut buffer = self.buffer.lock().unwrap();
72        buffer.offset = 0;
73        buffer.len = 0;
74
75        self.inner.clear_rx_buffer()?;
76        Ok(())
77    }
78}