//! ThreadX stdio implemented over semihosting #![no_std] #[unsafe(no_mangle)] fn __rust_threadx_stdout_write(buf: &[u8]) -> usize { use cortex_m_semihosting::hio; // `write_all` loops until the whole buffer is sent or the host reports an // error, so a success means every byte was written. let Ok(mut out) = hio::hstdout() else { return 0; }; match out.write_all(buf) { Ok(()) => buf.len(), Err(()) => 0, } } #[unsafe(no_mangle)] fn __rust_threadx_stderr_write(buf: &[u8]) -> usize { use cortex_m_semihosting::hio; let Ok(mut out) = hio::hstderr() else { return 0; }; match out.write_all(buf) { Ok(()) => buf.len(), Err(()) => 0, } } #[unsafe(no_mangle)] fn __rust_threadx_stdin_read(buf: &mut [u8]) -> usize { use cortex_m_semihosting::{nr, syscall}; if buf.is_empty() { return 0; } // `hio` only opens the host console for writing, so open it for reading // directly. `:tt` is the special semihosting path for the console. let name = b":tt\0"; let fd = match unsafe { syscall!(OPEN, name.as_ptr(), nr::open::R, name.len() - 1) } as isize { -1 => return 0, fd => fd as usize, }; // SYS_READ returns the number of bytes that were *not* read; on error it // returns a value larger than the request, which `saturating_sub` maps to 0. let not_read = unsafe { syscall!(READ, fd, buf.as_mut_ptr(), buf.len()) }; let _ = unsafe { syscall!(CLOSE, fd) }; buf.len().saturating_sub(not_read) }