Skip to main content

virtio_drivers/device/console/
embedded_io.rs

1//! Implementation of `embedded-io` traits for `VirtIOConsole`.
2
3use super::VirtIOConsole;
4use crate::{Error, Hal, transport::Transport};
5use core::cmp::min;
6use embedded_io::{BufRead, ErrorType, Read, ReadReady, Write};
7
8impl<H: Hal, T: Transport> ErrorType for VirtIOConsole<H, T> {
9    type Error = Error;
10}
11
12impl<H: Hal, T: Transport> Write for VirtIOConsole<H, T> {
13    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
14        if buf.is_empty() {
15            Ok(0)
16        } else {
17            self.send_bytes(buf)?;
18            Ok(buf.len())
19        }
20    }
21
22    fn flush(&mut self) -> Result<(), Self::Error> {
23        // We don't buffer writes, so nothing to do here.
24        Ok(())
25    }
26}
27
28impl<H: Hal, T: Transport> ReadReady for VirtIOConsole<H, T> {
29    fn read_ready(&mut self) -> Result<bool, Self::Error> {
30        self.finish_receive()?;
31        Ok(self.cursor != self.pending_len)
32    }
33}
34
35impl<H: Hal, T: Transport> Read for VirtIOConsole<H, T> {
36    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
37        if buf.is_empty() {
38            Ok(0)
39        } else {
40            self.wait_for_receive()?;
41            let read_length = min(buf.len(), self.pending_len - self.cursor);
42            buf[..read_length]
43                .copy_from_slice(&self.queue_buf_rx[self.cursor..self.cursor + read_length]);
44            self.cursor += read_length;
45            Ok(read_length)
46        }
47    }
48}
49
50impl<H: Hal, T: Transport> BufRead for VirtIOConsole<H, T> {
51    fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
52        self.wait_for_receive()?;
53        Ok(&self.queue_buf_rx[self.cursor..self.pending_len])
54    }
55
56    fn consume(&mut self, amt: usize) {
57        assert!(self.cursor + amt <= self.pending_len);
58        self.cursor += amt;
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use alloc::{sync::Arc, vec};
65    use embedded_io::{BufRead, Read};
66    use std::{sync::Mutex, thread};
67
68    use crate::{
69        config::{ReadOnly, WriteOnly},
70        device::console::{Config, QUEUE_RECEIVEQ_PORT_0, QUEUE_SIZE, VirtIOConsole},
71        hal::fake::FakeHal,
72        transport::{
73            DeviceType,
74            fake::{FakeTransport, QueueStatus, State},
75        },
76    };
77
78    fn setup_test() -> (
79        VirtIOConsole<FakeHal, FakeTransport<Config>>,
80        Arc<Mutex<State<Config>>>,
81    ) {
82        let config_space = Config {
83            cols: ReadOnly::new(80),
84            rows: ReadOnly::new(24),
85            max_nr_ports: ReadOnly::new(4),
86            emerg_wr: WriteOnly::default(),
87        };
88        let state = Arc::new(Mutex::new(State::new(
89            vec![QueueStatus::default(), QueueStatus::default()],
90            config_space,
91        )));
92        let transport = FakeTransport {
93            device_type: DeviceType::Console,
94            max_queue_size: 2,
95            device_features: 0,
96            state: state.clone(),
97        };
98        let console = VirtIOConsole::<FakeHal, FakeTransport<Config>>::new(transport).unwrap();
99        (console, state)
100    }
101
102    #[test]
103    fn read() {
104        let (mut console, state) = setup_test();
105
106        {
107            let mut state = state.lock().unwrap();
108            state.write_to_queue::<QUEUE_SIZE>(QUEUE_RECEIVEQ_PORT_0, &[42, 43, 44, 45, 46, 47]);
109            state.interrupt_pending = true;
110        }
111
112        let mut buf = [0; 3];
113        let n = console.read(&mut buf).unwrap();
114        assert_eq!(n, 3);
115        assert_eq!(&buf, &[42, 43, 44]);
116        let n = console.read(&mut buf).unwrap();
117        assert_eq!(n, 3);
118        assert_eq!(&buf, &[45, 46, 47]);
119    }
120
121    #[test]
122    fn bufread() {
123        let (mut console, state) = setup_test();
124
125        {
126            let mut state = state.lock().unwrap();
127            state.write_to_queue::<QUEUE_SIZE>(QUEUE_RECEIVEQ_PORT_0, &[42, 43, 44, 45, 46, 47]);
128            state.interrupt_pending = true;
129        }
130
131        console.fill_buf().unwrap();
132        console.consume(3);
133        let mut buf = [0; 3];
134        let n = console.read(&mut buf).unwrap();
135        assert_eq!(n, 3);
136        assert_eq!(&buf, &[45, 46, 47]);
137    }
138
139    #[test]
140    fn read_exact() {
141        let (mut console, state) = setup_test();
142
143        let mut recv_buf = [0; 100];
144
145        let data = {
146            let mut data = Vec::new();
147            for i in 0..recv_buf.len() {
148                data.push((42 + i % 256) as u8);
149            }
150            data
151        };
152        let expect = data.clone();
153
154        thread::spawn(move || {
155            // Make a character available, and simulate an interrupt.
156            for chunk in data.chunks(5) {
157                thread::sleep(std::time::Duration::from_millis(10));
158                let mut state = state.lock().unwrap();
159                state.write_to_queue::<QUEUE_SIZE>(QUEUE_RECEIVEQ_PORT_0, chunk);
160                state.interrupt_pending = true;
161            }
162        });
163
164        console.read_exact(&mut recv_buf).unwrap();
165        assert_eq!(&recv_buf, expect.as_slice());
166    }
167}