use crate::io; pub struct Stdin; pub struct Stdout {} pub struct Stderr; use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection}; use crate::os::xous::services::{log_server, try_connect, LogScalar}; impl Stdin { pub const fn new() -> Stdin { Stdin } } impl io::Read for Stdin { fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } } impl Stdout { pub const fn new() -> Stdout { Stdout {} } } impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { #[repr(align(4096))] struct LendBuffer([u8; 4096]); let mut lend_buffer = LendBuffer([0u8; 4096]); let connection = log_server(); for chunk in buf.chunks(lend_buffer.0.len()) { for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) { *dest = *src; } lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); } Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl Stderr { pub const fn new() -> Stderr { Stderr } } impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { #[repr(align(4096))] struct LendBuffer([u8; 4096]); let mut lend_buffer = LendBuffer([0u8; 4096]); let connection = log_server(); for chunk in buf.chunks(lend_buffer.0.len()) { for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) { *dest = *src; } lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); } Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } pub const STDIN_BUF_SIZE: usize = 0; pub fn is_ebadf(_err: &io::Error) -> bool { true } #[derive(Copy, Clone)] pub struct PanicWriter { log: Connection, gfx: Option, } impl io::Write for PanicWriter { fn write(&mut self, s: &[u8]) -> core::result::Result { for c in s.chunks(core::mem::size_of::() * 4) { // Text is grouped into 4x `usize` words. The id is 1100 plus // the number of characters in this message. // Ignore errors since we're already panicking. try_scalar(self.log, LogScalar::AppendPanicMessage(&c).into()).ok(); } // Serialize the text to the graphics panic handler, only if we were able // to acquire a connection to it. Text length is encoded in the `valid` field, // the data itself in the buffer. Typically several messages are require to // fully transmit the entire panic message. if let Some(gfx) = self.gfx { #[repr(C, align(4096))] struct Request([u8; 4096]); let mut request = Request([0u8; 4096]); for (&s, d) in s.iter().zip(request.0.iter_mut()) { *d = s; } try_lend(gfx, 0 /* AppendPanicText */, &request.0, 0, s.len()).ok(); } Ok(s.len()) } // Tests show that this does not seem to be reliably called at the end of a panic // print, so, we can't rely on this to e.g. trigger a graphics update. fn flush(&mut self) -> io::Result<()> { Ok(()) } } pub fn panic_output() -> Option { // Generally this won't fail because every server has already connected, so // this is likely to succeed. let log = log_server(); // Send the "We're panicking" message (1000). try_scalar(log, LogScalar::BeginPanic.into()).ok(); // This is will fail in the case that the connection table is full, or if the // graphics server is not running. Most servers do not already have this connection. let gfx = try_connect("panic-to-screen!"); Some(PanicWriter { log, gfx }) }