| 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()) | |
| } |