opentitanlib/io/console/
logged.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::Write;
6use std::sync::Mutex;
7use std::task::{Context, Poll, ready};
8use std::time::SystemTime;
9
10use anyhow::Result;
11
12use super::ConsoleDevice;
13use crate::io::uart::{FlowControl, Parity, Uart};
14
15/// Middleware that logs the received data.
16pub struct Logged<T> {
17    inner: T,
18    /// If the next character is the beginning of a line.
19    newline: Mutex<bool>,
20}
21
22impl<T> Logged<T> {
23    pub fn new(inner: T) -> Logged<T> {
24        Self {
25            inner,
26            newline: Mutex::new(true),
27        }
28    }
29}
30
31impl<T: ConsoleDevice> ConsoleDevice for Logged<T> {
32    fn poll_read(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
33        // Establish order between readers, if there are many.
34        let mut newline = self.newline.lock().unwrap();
35        let len = ready!(self.inner.poll_read(cx, buf))?;
36
37        let mut stdout = std::io::stdout().lock();
38        for ch in buf[..len].iter().copied() {
39            if *newline {
40                let t = humantime::format_rfc3339_millis(SystemTime::now());
41                stdout.write_fmt(format_args!("[{}  console]", t))?;
42            }
43
44            *newline = ch == b'\n';
45
46            stdout.write_all(std::slice::from_ref(&ch))?;
47        }
48        stdout.flush()?;
49
50        Poll::Ready(Ok(len))
51    }
52
53    fn write(&self, buf: &[u8]) -> Result<()> {
54        self.inner.write(buf)
55    }
56}
57
58impl<T: Uart> Uart for Logged<T> {
59    fn get_baudrate(&self) -> Result<u32> {
60        self.inner.get_baudrate()
61    }
62
63    fn set_baudrate(&self, baudrate: u32) -> Result<()> {
64        self.inner.set_baudrate(baudrate)
65    }
66
67    fn get_flow_control(&self) -> Result<FlowControl> {
68        self.inner.get_flow_control()
69    }
70
71    fn set_flow_control(&self, flow_control: bool) -> Result<()> {
72        self.inner.set_flow_control(flow_control)
73    }
74
75    fn get_device_path(&self) -> Result<String> {
76        self.inner.get_device_path()
77    }
78
79    fn clear_rx_buffer(&self) -> Result<()> {
80        *self.newline.lock().unwrap() = true;
81        self.inner.clear_rx_buffer()
82    }
83
84    fn set_parity(&self, parity: Parity) -> Result<()> {
85        self.inner.set_parity(parity)
86    }
87
88    fn get_parity(&self) -> Result<Parity> {
89        self.inner.get_parity()
90    }
91
92    fn set_break(&self, enable: bool) -> Result<()> {
93        self.inner.set_break(enable)
94    }
95}