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