diff --git a/abi_sys/src/lib.rs b/abi_sys/src/lib.rs index 5a200f8..dc52ba4 100644 --- a/abi_sys/src/lib.rs +++ b/abi_sys/src/lib.rs @@ -29,63 +29,49 @@ pub enum CallAbiTable { GenRand = 5, } -pub type PrintAbi = extern "Rust" fn(msg: &str); +pub type PrintAbi = extern "C" fn(ptr: *const u8, len: usize); #[allow(unused)] pub fn print(msg: &str) { - unsafe { - let ptr = CALL_ABI_TABLE[CallAbiTable::Print as usize]; - let f: PrintAbi = core::mem::transmute(ptr); - f(msg); - } + let f: PrintAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Print as usize]) }; + f(msg.as_ptr(), msg.len()); } -pub type SleepAbi = extern "Rust" fn(ms: u64); +pub type SleepAbi = extern "C" fn(ms: u64); #[allow(unused)] pub fn sleep(ms: u64) { - unsafe { - let ptr = CALL_ABI_TABLE[CallAbiTable::Sleep as usize]; - let f: SleepAbi = core::mem::transmute(ptr); - f(ms); - } + let f: SleepAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Sleep as usize]) }; + f(ms); } -pub type LockDisplay = extern "Rust" fn(lock: bool); +pub type LockDisplay = extern "C" fn(lock: bool); #[allow(unused)] pub fn lock_display(lock: bool) { - unsafe { - let ptr = CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]; - let f: LockDisplay = core::mem::transmute(ptr); - f(lock); - } + let f: LockDisplay = + unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]) }; + f(lock); } -pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel]); +pub type DrawIterAbi = extern "C" fn(ptr: *const Pixel, len: usize); #[allow(unused)] pub fn draw_iter(pixels: &[Pixel]) { - unsafe { - let ptr = CALL_ABI_TABLE[CallAbiTable::DrawIter as usize]; - let f: DrawIterAbi = core::mem::transmute(ptr); - f(pixels); - } + let f: DrawIterAbi = + unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::DrawIter as usize]) }; + f(pixels.as_ptr(), pixels.len()); } -pub type GetKeyAbi = extern "Rust" fn() -> Option; +pub type GetKeyAbi = extern "C" fn() -> KeyEvent; #[allow(unused)] -pub fn get_key() -> Option { - unsafe { - let ptr = CALL_ABI_TABLE[CallAbiTable::GetKey as usize]; - let f: GetKeyAbi = core::mem::transmute(ptr); - f() - } +pub fn get_key() -> KeyEvent { + let f: GetKeyAbi = + unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::GetKey as usize]) }; + f() } -pub type GenRand = extern "Rust" fn(req: &mut RngRequest); - #[repr(C)] pub enum RngRequest { U32(u32), @@ -93,6 +79,8 @@ pub enum RngRequest { Bytes { ptr: *mut u8, len: usize }, } +pub type GenRand = extern "C" fn(req: &mut RngRequest); + #[allow(unused)] pub fn gen_rand(req: &mut RngRequest) { unsafe { diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 14a0194..95baf20 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -1,4 +1,6 @@ -use abi_sys::{DrawIterAbi, GetKeyAbi, LockDisplay, PrintAbi, RngRequest, SleepAbi}; +use abi_sys::{ + DrawIterAbi, GenRand, GetKeyAbi, LockDisplay, Modifiers, PrintAbi, RngRequest, SleepAbi, +}; use core::sync::atomic::Ordering; use embassy_rp::clocks::{RoscRng, clk_sys_freq}; use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565}; @@ -9,18 +11,20 @@ use crate::{ display::{FB_PAUSED, FRAMEBUFFER}, }; -// ensure the abi and the kernel fn signatures are the same const _: PrintAbi = print; -const _: SleepAbi = sleep; -const _: LockDisplay = lock_display; -const _: DrawIterAbi = draw_iter; -const _: GetKeyAbi = get_key; +pub extern "C" fn print(ptr: *const u8, len: usize) { + // SAFETY: caller guarantees `ptr` is valid for `len` bytes + let slice = unsafe { core::slice::from_raw_parts(ptr, len) }; -pub extern "Rust" fn print(msg: &str) { - defmt::info!("{:?}", msg); + if let Ok(msg) = core::str::from_utf8(slice) { + defmt::info!("print: {}", msg); + } else { + defmt::warn!("print: "); + } } -pub extern "Rust" fn sleep(ms: u64) { +const _: SleepAbi = sleep; +pub extern "C" fn sleep(ms: u64) { let cycles_per_ms = clk_sys_freq() / 1000; let total_cycles = ms * cycles_per_ms as u64; @@ -29,20 +33,33 @@ pub extern "Rust" fn sleep(ms: u64) { } } -pub extern "Rust" fn lock_display(lock: bool) { +const _: LockDisplay = lock_display; +pub extern "C" fn lock_display(lock: bool) { FB_PAUSED.store(lock, Ordering::Relaxed); } +const _: DrawIterAbi = draw_iter; // TODO: maybe return result -pub extern "Rust" fn draw_iter(pixels: &[Pixel]) { +pub extern "C" fn draw_iter(pixels: *const Pixel, len: usize) { + let pixels = unsafe { core::slice::from_raw_parts(pixels, len) }; unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() } } -pub extern "Rust" fn get_key() -> Option { - unsafe { KEY_CACHE.dequeue() } +const _: GetKeyAbi = get_key; +pub extern "C" fn get_key() -> KeyEvent { + if let Some(event) = unsafe { KEY_CACHE.dequeue() } { + event + } else { + KeyEvent { + key: abi_sys::KeyCode::Unknown(0), + state: abi_sys::KeyState::Idle, + mods: Modifiers::empty(), + } + } } -pub extern "Rust" fn gen_rand(req: &mut RngRequest) { +const _: GenRand = gen_rand; +pub extern "C" fn gen_rand(req: &mut RngRequest) { let mut rng = RoscRng; match req { diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 3823869..b78e205 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -14,6 +14,7 @@ pub mod keyboard { } #[derive(Debug)] + #[repr(C)] pub struct KeyEvent { pub key: KeyCode, pub state: KeyState, @@ -22,6 +23,7 @@ pub mod keyboard { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] pub enum KeyState { Idle = 0, Pressed = 1, diff --git a/user-apps/calculator/src/main.rs b/user-apps/calculator/src/main.rs index 7bb663f..54b9cbb 100644 --- a/user-apps/calculator/src/main.rs +++ b/user-apps/calculator/src/main.rs @@ -2,7 +2,7 @@ #![no_main] extern crate alloc; -use abi::{KeyCode, display::Display, get_key, lock_display, print}; +use abi::{KeyCode, KeyState, display::Display, get_key, lock_display, print}; use alloc::{format, string::String, vec, vec::Vec}; use core::panic::PanicInfo; use embedded_graphics::{ @@ -105,7 +105,8 @@ pub fn main() { lock_display(false); } - if let Some(event) = get_key() { + let event = get_key(); + if event.state != KeyState::Idle { match event.key { KeyCode::Char(ch) => { input.push(ch); diff --git a/user-apps/snake/src/main.rs b/user-apps/snake/src/main.rs index 9ac50df..78d9451 100644 --- a/user-apps/snake/src/main.rs +++ b/user-apps/snake/src/main.rs @@ -3,7 +3,7 @@ extern crate alloc; use abi::{ - KeyCode, Rng, + KeyCode, KeyState, Rng, display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH}, get_key, lock_display, print, sleep, }; @@ -46,7 +46,8 @@ pub fn main() { ); loop { - if let Some(event) = get_key() { + let event = get_key(); + if event.state != KeyState::Idle { let direction = match event.key { KeyCode::Up => Direction::Up, KeyCode::Down => Direction::Down, @@ -56,7 +57,7 @@ pub fn main() { _ => Direction::None, }; game.set_direction(direction); - } + }; // ensure all draws show up at once lock_display(true);