#![no_std] #![allow(static_mut_refs)] extern crate alloc; pub use alloc::format; use core::alloc::{GlobalAlloc, Layout}; use rand_core::RngCore; pub use userlib_sys::{keyboard, print}; use userlib_sys::{keyboard::KeyEvent, RngRequest}; #[global_allocator] static ALLOC: Alloc = Alloc; struct Alloc; unsafe impl GlobalAlloc for Alloc { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { userlib_sys::alloc(layout.into()) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { userlib_sys::dealloc(ptr, layout.into()); } } #[macro_export] macro_rules! println { ($($arg:tt)*) => {{ let s = $crate::format!($($arg)*); $crate::print(s.as_ptr(), s.len()); }}; } pub fn sleep(ms: u64) { userlib_sys::sleep(ms); } pub fn get_ms() -> u64 { userlib_sys::get_ms() } pub fn get_key() -> KeyEvent { userlib_sys::keyboard::get_key().into() } pub mod display { use core::sync::atomic::{AtomicBool, Ordering}; use embedded_graphics::{ geometry::{Dimensions, Point}, pixelcolor::Rgb565, prelude::{DrawTarget, Size}, primitives::Rectangle, Pixel, }; use userlib_sys::CPixel; pub const SCREEN_WIDTH: usize = 320; pub const SCREEN_HEIGHT: usize = 320; pub type Pixel565 = Pixel; const BUF_SIZE: usize = 1024; static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE]; static DISPLAY_TAKEN: AtomicBool = AtomicBool::new(false); pub struct Display { _private: (), } impl Display { /// Only one instance of Display can be taken pub fn take() -> Option { if DISPLAY_TAKEN .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) .is_ok() { Some(Self { _private: () }) } else { None } } } impl Dimensions for Display { fn bounding_box(&self) -> Rectangle { Rectangle { top_left: Point { x: 0, y: 0 }, size: Size { width: SCREEN_WIDTH as u32, height: SCREEN_HEIGHT as u32, }, } } } impl DrawTarget for Display { type Color = Rgb565; type Error = (); fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> where I: IntoIterator>, { let mut count = 0; for p in pixels { unsafe { BUF[count] = p.into() }; count += 1; if count == BUF_SIZE - 1 { userlib_sys::draw_iter(unsafe { BUF.as_ptr() }, count); count = 0; } } if count > 0 { userlib_sys::draw_iter(unsafe { BUF.as_ptr() }, count); } Ok(()) } } } fn gen_rand(req: &mut RngRequest) { userlib_sys::gen_rand(req); } pub struct Rng; impl RngCore for Rng { fn next_u32(&mut self) -> u32 { let mut req = RngRequest::U32(0); gen_rand(&mut req); if let RngRequest::U32(i) = req { return i; }; 0 } fn next_u64(&mut self) -> u64 { let mut req = RngRequest::U64(0); gen_rand(&mut req); if let RngRequest::U64(i) = req { return i; }; 0 } fn fill_bytes(&mut self, dst: &mut [u8]) { let mut req = RngRequest::Bytes { ptr: dst.as_mut_ptr(), len: dst.len(), }; gen_rand(&mut req); } } pub mod fs { use alloc::vec::Vec; use core::fmt::Display; pub fn read_file(file: &str, start_from: usize, buf: &mut [u8]) -> usize { userlib_sys::read_file( file.as_ptr(), file.len(), start_from, buf.as_mut_ptr(), buf.len(), ) } pub fn write_file(file: &str, start_from: usize, buf: &[u8]) { userlib_sys::write_file( file.as_ptr(), file.len(), start_from, buf.as_ptr(), buf.len(), ) } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct FileName<'a> { full: &'a str, base: &'a str, ext: Option<&'a str>, } impl<'a> FileName<'a> { pub fn full_name(&self) -> &str { self.full } pub fn base(&self) -> &str { self.base } pub fn extension(&self) -> Option<&str> { self.ext } } impl<'a> Display for FileName<'a> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.full_name()) } } impl<'a> From<&'a str> for FileName<'a> { fn from(s: &'a str) -> FileName<'a> { let full = s; // Split on last dot for extension let (base, ext) = match s.rfind('.') { Some(idx) => (&s[..idx], Some(&s[idx + 1..])), None => (s, None), }; FileName { full, base, ext } } } const MAX_ENTRY_NAME_LEN: usize = 25; const MAX_ENTRIES: usize = 25; #[derive(Clone, Copy, Debug)] pub struct Entries([[u8; MAX_ENTRY_NAME_LEN]; MAX_ENTRIES]); impl Entries { pub fn new() -> Self { Self([[0; MAX_ENTRY_NAME_LEN]; MAX_ENTRIES]) } /// Get list of file names after listing pub fn entries<'a>(&'a self) -> Vec> { self.0 .iter() .filter_map(|buf| { let nul_pos = buf.iter().position(|&b| b == 0).unwrap_or(buf.len()); Some(core::str::from_utf8(&buf[..nul_pos]).ok()?.into()) }) .collect() } fn as_ptrs(&mut self) -> [*mut u8; MAX_ENTRIES] { let mut ptrs: [*mut u8; MAX_ENTRIES] = [core::ptr::null_mut(); MAX_ENTRIES]; for (i, buf) in self.0.iter_mut().enumerate() { ptrs[i] = buf.as_mut_ptr(); } ptrs } } pub fn list_dir(path: &str, entries: &mut Entries) -> usize { userlib_sys::list_dir( path.as_ptr(), path.len(), entries.as_ptrs().as_mut_ptr(), MAX_ENTRIES, MAX_ENTRY_NAME_LEN, ) } pub fn file_len(str: &str) -> usize { userlib_sys::file_len(str.as_ptr(), str.len()) } } pub mod audio { pub use userlib_sys::{audio_buffer_ready, AUDIO_BUFFER_LEN, AUDIO_BUFFER_SAMPLES}; pub fn send_audio_buffer(buf: &[u8]) { userlib_sys::send_audio_buffer(buf.as_ptr(), buf.len()) } }