@@ -4,7 +4,7 @@ pub struct Stdin;
44pub struct Stdout ;
55pub type Stderr = Stdout ;
66
7- const STDIO_CHANNEL : u32 = 1 ;
7+ pub const STDIO_CHANNEL : u32 = 1 ;
88
99impl Stdin {
1010 pub const fn new ( ) -> Stdin {
@@ -14,7 +14,7 @@ impl Stdin {
1414
1515impl io:: Read for Stdin {
1616 fn read ( & mut self , mut buf : & mut [ u8 ] ) -> io:: Result < usize > {
17- let mut written = 0 ;
17+ let mut count = 0 ;
1818
1919 while let Some ( ( out_byte, new_buf) ) = buf. split_first_mut ( ) {
2020 buf = new_buf;
@@ -25,10 +25,10 @@ impl io::Read for Stdin {
2525 }
2626
2727 * out_byte = byte as u8 ;
28- written += 1 ;
28+ count += 1 ;
2929 }
3030
31- Ok ( written )
31+ Ok ( count )
3232 }
3333}
3434
@@ -40,20 +40,48 @@ impl Stdout {
4040
4141impl io:: Write for Stdout {
4242 fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
43- let written =
44- unsafe { vex_sdk:: vexSerialWriteBuffer ( STDIO_CHANNEL , buf. as_ptr ( ) , buf. len ( ) as u32 ) } ;
45-
46- if written < 0 {
47- return Err ( io:: Error :: new (
48- io:: ErrorKind :: Uncategorized ,
49- "Internal write error occurred." ,
50- ) ) ;
43+ let mut written = 0 ;
44+
45+ // HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1
46+ // roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we
47+ // must block until that buffer is flushed to USB1 before writing the rest of `buf`.
48+ //
49+ // This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed
50+ // recursive panic when using macros such as `print!` to write large amounts of data
51+ // (buf.len() > 2048) to stdout at once.
52+ for chunk in buf. chunks ( STDOUT_BUF_SIZE ) {
53+ if unsafe { vex_sdk:: vexSerialWriteFree ( STDIO_CHANNEL ) as usize } < chunk. len ( ) {
54+ self . flush ( ) . unwrap ( ) ;
55+ }
56+
57+ let count = unsafe {
58+ vex_sdk:: vexSerialWriteBuffer ( STDIO_CHANNEL , chunk. as_ptr ( ) , chunk. len ( ) as u32 )
59+ } ;
60+ if count < 0 {
61+ return Err ( io:: Error :: new (
62+ io:: ErrorKind :: Uncategorized ,
63+ "Internal write error occurred." ,
64+ ) ) ;
65+ }
66+
67+ written += count;
68+
69+ // This is a sanity check to ensure that we don't end up with non-contiguous
70+ // buffer writes. e.g. a chunk gets only partially written, but we continue
71+ // attempting to write the remaining chunks.
72+ //
73+ // In practice, this should never really occur since the previous flush ensures
74+ // enough space in FIFO to write the entire chunk to vexSerialWriteBuffer.
75+ if count != chunk. len ( ) {
76+ break ;
77+ }
5178 }
5279
5380 Ok ( written as usize )
5481 }
5582
5683 fn flush ( & mut self ) -> io:: Result < ( ) > {
84+ // This may block for up to a millisecond.
5785 unsafe {
5886 while ( vex_sdk:: vexSerialWriteFree ( STDIO_CHANNEL ) as usize ) != STDOUT_BUF_SIZE {
5987 vex_sdk:: vexTasksRun ( ) ;
0 commit comments