blob: 9a391feb7a8a1939321b3ac8b811d2f2ae03ff32 [file] [log] [blame] [edit]
use crate::io;
pub struct Stdin;
pub struct Stdout;
pub type Stderr = Stdout;
pub const STDIO_CHANNEL: u32 = 1;
impl Stdin {
pub const fn new() -> Stdin {
Stdin
}
}
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut count = 0;
for out_byte in buf.iter_mut() {
let byte = unsafe { vex_sdk::vexSerialReadChar(STDIO_CHANNEL) };
if byte < 0 {
break;
}
*out_byte = byte as u8;
count += 1;
}
Ok(count)
}
}
impl Stdout {
pub const fn new() -> Stdout {
Stdout
}
}
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut written = 0;
// HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1
// roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we
// must block until that buffer is flushed to USB1 before writing the rest of `buf`.
//
// This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed
// recursive panic when using macros such as `print!` to write large amounts of data
// (buf.len() > 2048) to stdout at once.
for chunk in buf.chunks(STDOUT_BUF_SIZE) {
if unsafe { vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize } < chunk.len() {
self.flush().unwrap();
}
let count: usize = unsafe {
vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, chunk.as_ptr(), chunk.len() as u32)
}
.try_into()
.map_err(|_| {
io::const_error!(io::ErrorKind::Uncategorized, "internal write error occurred")
})?;
written += count;
// This is a sanity check to ensure that we don't end up with non-contiguous
// buffer writes. e.g. a chunk gets only partially written, but we continue
// attempting to write the remaining chunks.
//
// In practice, this should never really occur since the previous flush ensures
// enough space in FIFO to write the entire chunk to vexSerialWriteBuffer.
if count != chunk.len() {
break;
}
}
Ok(written)
}
fn flush(&mut self) -> io::Result<()> {
// This may block for up to a millisecond.
unsafe {
while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE {
vex_sdk::vexTasksRun();
}
}
Ok(())
}
}
pub const STDIN_BUF_SIZE: usize = 4096;
pub const STDOUT_BUF_SIZE: usize = 2048;
pub fn is_ebadf(_err: &io::Error) -> bool {
false
}
pub fn panic_output() -> Option<impl io::Write> {
Some(Stdout::new())
}