#[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; pub mod time; #[expect(dead_code)] #[path = "../unsupported/common.rs"] mod unsupported_common; pub use unsupported_common::{ decode_error_kind, init, is_interrupted, unsupported, unsupported_err, }; use crate::arch::global_asm; use crate::ptr; use crate::sys::stdio; use crate::time::{Duration, Instant}; global_asm!( r#" .section .boot, "ax" .global _boot _boot: ldr sp, =__stack_top @ Set up the user stack. b _start @ Jump to the Rust entrypoint. "# ); #[cfg(not(test))] #[unsafe(no_mangle)] pub unsafe extern "C" fn _start() -> ! { unsafe extern "C" { static mut __bss_start: u8; static mut __bss_end: u8; fn main() -> i32; } // Clear the .bss (uninitialized statics) section by filling it with zeroes. // This is required, since the compiler assumes it will be zeroed on first access. ptr::write_bytes( &raw mut __bss_start, 0, (&raw mut __bss_end).offset_from_unsigned(&raw mut __bss_start), ); main(); cleanup(); abort_internal() } // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { let exit_time = Instant::now(); const FLUSH_TIMEOUT: Duration = Duration::from_millis(15); // Force the serial buffer to flush while exit_time.elapsed() < FLUSH_TIMEOUT { vex_sdk::vexTasksRun(); // If the buffer has been fully flushed, exit the loop if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) { break; } } } pub fn abort_internal() -> ! { unsafe { vex_sdk::vexSystemExitRequest(); loop { vex_sdk::vexTasksRun(); } } }