basic fs syscall(s)

This commit is contained in:
2025-09-28 14:07:03 -06:00
parent 7bd6012748
commit 2221ffdbde
7 changed files with 162 additions and 20 deletions

View File

@@ -1,14 +1,18 @@
use abi_sys::{
DrawIterAbi, GenRand, GetKeyAbi, LockDisplay, Modifiers, PrintAbi, RngRequest, SleepAbi,
DrawIterAbi, GenRand, GetKeyAbi, ListDir, LockDisplay, Modifiers, PrintAbi, ReadFile,
RngRequest, SleepAbi,
};
use alloc::vec::Vec;
use core::sync::atomic::Ordering;
use embassy_rp::clocks::{RoscRng, clk_sys_freq};
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
use embedded_sdmmc::{DirEntry, ShortFileName};
use heapless::spsc::Queue;
use shared::keyboard::KeyEvent;
use crate::{
KEY_CACHE,
display::{FB_PAUSED, FRAMEBUFFER},
storage::{Dir, File, SDCARD},
};
const _: PrintAbi = print;
@@ -41,10 +45,13 @@ pub extern "C" fn lock_display(lock: bool) {
const _: DrawIterAbi = draw_iter;
// TODO: maybe return result
pub extern "C" fn draw_iter(pixels: *const Pixel<Rgb565>, len: usize) {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let pixels = unsafe { core::slice::from_raw_parts(pixels, len) };
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() }
}
pub static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
const _: GetKeyAbi = get_key;
pub extern "C" fn get_key() -> KeyEvent {
if let Some(event) = unsafe { KEY_CACHE.dequeue() } {
@@ -66,8 +73,102 @@ pub extern "C" fn gen_rand(req: &mut RngRequest) {
RngRequest::U32(i) => *i = rng.next_u32(),
RngRequest::U64(i) => *i = rng.next_u64(),
RngRequest::Bytes { ptr, len } => {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(*ptr, *len) };
rng.fill_bytes(slice);
}
}
}
fn get_dir_entries(dir: &Dir, files: &mut [Option<DirEntry>]) {
let mut files = files.iter_mut();
dir.iterate_dir(|entry| {
if let Some(f) = files.next() {
*f = Some(entry.clone())
}
})
.unwrap()
}
fn recurse_dir(dir: &Dir, dirs: &[&str], files: &mut [Option<DirEntry>]) {
if dirs.is_empty() {
get_dir_entries(dir, files);
return;
}
let dir = dir.open_dir(dirs[0]).unwrap();
recurse_dir(&dir, &dirs[1..], files);
}
const _: ListDir = list_dir;
pub extern "C" fn list_dir(
dir: *const u8,
len: usize,
files: *mut Option<DirEntry>,
files_len: usize,
) {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let files = unsafe { core::slice::from_raw_parts_mut(files, files_len) };
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let dir = unsafe { core::str::from_raw_parts(dir, len) };
let dirs: Vec<&str> = dir.split('/').collect();
let mut guard = SDCARD.get().try_lock().expect("Failed to get sdcard");
let sd = guard.as_mut().unwrap();
sd.access_root_dir(|root| {
if !dir.is_empty() {
if dirs[0].is_empty() {
get_dir_entries(&root, files);
} else {
recurse_dir(&root, &dirs[1..], files);
}
}
});
}
fn recurse_file<T>(dir: &Dir, dirs: &[&str], mut access: impl FnMut(&mut File) -> T) -> T {
if dirs.len() == 1 {
let file_name = ShortFileName::create_from_str(dirs[0]).unwrap();
let mut file = dir
.open_file_in_dir(file_name, embedded_sdmmc::Mode::ReadWriteAppend)
.unwrap();
return access(&mut file);
}
let dir = dir.open_dir(dirs[0]).unwrap();
recurse_file(&dir, &dirs[1..], access)
}
const _: ReadFile = read_file;
pub extern "C" fn read_file(
str: *const u8,
len: usize,
start_from: usize,
buf: *mut u8,
buf_len: usize,
) -> usize {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let mut buf = unsafe { core::slice::from_raw_parts_mut(buf, buf_len) };
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let file = unsafe { core::str::from_raw_parts(str, len) };
let file: Vec<&str> = file.split('/').collect();
let mut res = 0;
let mut guard = SDCARD.get().try_lock().expect("Failed to get sdcard");
let sd = guard.as_mut().unwrap();
if !file.is_empty() {
if file[0].is_empty() {
} else {
sd.access_root_dir(|root| {
res = recurse_file(&root, &file[1..], |file| {
file.seek_from_start(start_from as u32).unwrap();
file.read(&mut buf).unwrap()
})
});
}
}
res
}

View File

@@ -195,12 +195,14 @@ fn patch_abi(
for (idx, call) in CallAbiTable::iter().enumerate() {
let ptr = match call {
CallAbiTable::Print => abi::print as usize,
CallAbiTable::Sleep => abi::sleep as usize,
CallAbiTable::PrintString => abi::print as usize,
CallAbiTable::SleepMs => abi::sleep as usize,
CallAbiTable::LockDisplay => abi::lock_display as usize,
CallAbiTable::DrawIter => abi::draw_iter as usize,
CallAbiTable::GetKey => abi::get_key as usize,
CallAbiTable::GenRand => abi::gen_rand as usize,
CallAbiTable::ListDir => abi::list_dir as usize,
CallAbiTable::ReadFile => abi::read_file as usize,
};
unsafe {
table_base.add(idx as usize).write(ptr);

View File

@@ -1,4 +1,5 @@
#![feature(impl_trait_in_assoc_type)]
#![feature(str_from_raw_parts)]
#![cfg_attr(not(test), no_std)]
#![cfg_attr(not(test), no_main)]
#![allow(static_mut_refs)]
@@ -17,6 +18,7 @@ mod usb;
mod utils;
use crate::{
abi::KEY_CACHE,
display::{FRAMEBUFFER, display_handler, init_display},
peripherals::{
conf_peripherals,
@@ -57,8 +59,6 @@ use embassy_sync::{
use embassy_time::{Delay, Timer};
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::SdCard as SdmmcSdCard;
use heapless::spsc::Queue;
use shared::keyboard::KeyEvent;
use static_cell::StaticCell;
use talc::*;
@@ -251,23 +251,20 @@ async fn prog_search_handler() {
loop {
{
let mut guard = SDCARD.get().lock().await;
let sd = guard.as_mut().unwrap();
if let Some(sd) = guard.as_mut() {
let files = sd.list_files_by_extension(".bin").unwrap();
let mut select = SELECTIONS.lock().await;
let files = sd.list_files_by_extension(".bin").unwrap();
let mut select = SELECTIONS.lock().await;
if *select.selections() != files {
select.update_selections(files);
select.reset();
}
if *select.selections() != files {
select.update_selections(files);
select.reset();
}
}
Timer::after_secs(5).await;
}
}
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
async fn key_handler() {
loop {
if let Some(event) = read_keyboard_fifo().await {

View File

@@ -22,7 +22,7 @@ type Device = ExclusiveDevice<Spi<'static, SPI0, Blocking>, Output<'static>, emb
type SD = SdmmcSdCard<Device, Delay>;
type VolMgr = VolumeManager<SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub type File<'a> = SdFile<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub static SDCARD: LazyLock<Mutex<CriticalSectionRawMutex, Option<SdCard>>> =