mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
basic fs syscall(s)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -30,6 +30,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
|
"embedded-sdmmc",
|
||||||
"shared",
|
"shared",
|
||||||
"strum",
|
"strum",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ embedded-graphics = "0.8.1"
|
|||||||
strum = { version = "0.27.2", default-features = false, features = ["derive"] }
|
strum = { version = "0.27.2", default-features = false, features = ["derive"] }
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
shared = { path = "../shared" }
|
shared = { path = "../shared" }
|
||||||
|
embedded-sdmmc = { version = "0.9.0", default-features = false }
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use embedded_graphics::{
|
|||||||
geometry::Point,
|
geometry::Point,
|
||||||
pixelcolor::{Rgb565, RgbColor},
|
pixelcolor::{Rgb565, RgbColor},
|
||||||
};
|
};
|
||||||
|
use embedded_sdmmc::DirEntry;
|
||||||
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||||
use strum::{EnumCount, EnumIter};
|
use strum::{EnumCount, EnumIter};
|
||||||
|
|
||||||
@@ -21,19 +22,22 @@ pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable::
|
|||||||
#[derive(Clone, Copy, EnumIter, EnumCount)]
|
#[derive(Clone, Copy, EnumIter, EnumCount)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum CallAbiTable {
|
pub enum CallAbiTable {
|
||||||
Print = 0,
|
PrintString = 0,
|
||||||
Sleep = 1,
|
SleepMs = 1,
|
||||||
LockDisplay = 2,
|
LockDisplay = 2,
|
||||||
DrawIter = 3,
|
DrawIter = 3,
|
||||||
GetKey = 4,
|
GetKey = 4,
|
||||||
GenRand = 5,
|
GenRand = 5,
|
||||||
|
ListDir = 6,
|
||||||
|
ReadFile = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PrintAbi = extern "C" fn(ptr: *const u8, len: usize);
|
pub type PrintAbi = extern "C" fn(ptr: *const u8, len: usize);
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn print(msg: &str) {
|
pub fn print(msg: &str) {
|
||||||
let f: PrintAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Print as usize]) };
|
let f: PrintAbi =
|
||||||
|
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::PrintString as usize]) };
|
||||||
f(msg.as_ptr(), msg.len());
|
f(msg.as_ptr(), msg.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +45,8 @@ pub type SleepAbi = extern "C" fn(ms: u64);
|
|||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn sleep(ms: u64) {
|
pub fn sleep(ms: u64) {
|
||||||
let f: SleepAbi = unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::Sleep as usize]) };
|
let f: SleepAbi =
|
||||||
|
unsafe { core::mem::transmute(CALL_ABI_TABLE[CallAbiTable::SleepMs as usize]) };
|
||||||
f(ms);
|
f(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,3 +94,38 @@ pub fn gen_rand(req: &mut RngRequest) {
|
|||||||
f(req)
|
f(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ListDir =
|
||||||
|
extern "C" fn(str: *const u8, len: usize, files: *mut Option<DirEntry>, file_len: usize);
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn list_dir(path: &str, files: &mut [Option<DirEntry>]) {
|
||||||
|
unsafe {
|
||||||
|
let ptr = CALL_ABI_TABLE[CallAbiTable::ListDir as usize];
|
||||||
|
let f: ListDir = core::mem::transmute(ptr);
|
||||||
|
f(path.as_ptr(), path.len(), files.as_mut_ptr(), files.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ReadFile = extern "C" fn(
|
||||||
|
str: *const u8,
|
||||||
|
len: usize,
|
||||||
|
read_from: usize,
|
||||||
|
buf: *mut u8,
|
||||||
|
buf_len: usize,
|
||||||
|
) -> usize;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn read_file(file: &str, read_from: usize, buf: &mut [u8]) -> usize {
|
||||||
|
unsafe {
|
||||||
|
let ptr = CALL_ABI_TABLE[CallAbiTable::ReadFile as usize];
|
||||||
|
let f: ReadFile = core::mem::transmute(ptr);
|
||||||
|
f(
|
||||||
|
file.as_ptr(),
|
||||||
|
file.len(),
|
||||||
|
read_from,
|
||||||
|
buf.as_mut_ptr(),
|
||||||
|
buf.len(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
use abi_sys::{
|
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 core::sync::atomic::Ordering;
|
||||||
use embassy_rp::clocks::{RoscRng, clk_sys_freq};
|
use embassy_rp::clocks::{RoscRng, clk_sys_freq};
|
||||||
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
|
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
|
||||||
|
use embedded_sdmmc::{DirEntry, ShortFileName};
|
||||||
|
use heapless::spsc::Queue;
|
||||||
use shared::keyboard::KeyEvent;
|
use shared::keyboard::KeyEvent;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
KEY_CACHE,
|
|
||||||
display::{FB_PAUSED, FRAMEBUFFER},
|
display::{FB_PAUSED, FRAMEBUFFER},
|
||||||
|
storage::{Dir, File, SDCARD},
|
||||||
};
|
};
|
||||||
|
|
||||||
const _: PrintAbi = print;
|
const _: PrintAbi = print;
|
||||||
@@ -41,10 +45,13 @@ pub extern "C" fn lock_display(lock: bool) {
|
|||||||
const _: DrawIterAbi = draw_iter;
|
const _: DrawIterAbi = draw_iter;
|
||||||
// TODO: maybe return result
|
// TODO: maybe return result
|
||||||
pub extern "C" fn draw_iter(pixels: *const Pixel<Rgb565>, len: usize) {
|
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) };
|
let pixels = unsafe { core::slice::from_raw_parts(pixels, len) };
|
||||||
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() }
|
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
||||||
|
|
||||||
const _: GetKeyAbi = get_key;
|
const _: GetKeyAbi = get_key;
|
||||||
pub extern "C" fn get_key() -> KeyEvent {
|
pub extern "C" fn get_key() -> KeyEvent {
|
||||||
if let Some(event) = unsafe { KEY_CACHE.dequeue() } {
|
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::U32(i) => *i = rng.next_u32(),
|
||||||
RngRequest::U64(i) => *i = rng.next_u64(),
|
RngRequest::U64(i) => *i = rng.next_u64(),
|
||||||
RngRequest::Bytes { ptr, len } => {
|
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) };
|
let slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(*ptr, *len) };
|
||||||
rng.fill_bytes(slice);
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -195,12 +195,14 @@ fn patch_abi(
|
|||||||
|
|
||||||
for (idx, call) in CallAbiTable::iter().enumerate() {
|
for (idx, call) in CallAbiTable::iter().enumerate() {
|
||||||
let ptr = match call {
|
let ptr = match call {
|
||||||
CallAbiTable::Print => abi::print as usize,
|
CallAbiTable::PrintString => abi::print as usize,
|
||||||
CallAbiTable::Sleep => abi::sleep as usize,
|
CallAbiTable::SleepMs => abi::sleep as usize,
|
||||||
CallAbiTable::LockDisplay => abi::lock_display as usize,
|
CallAbiTable::LockDisplay => abi::lock_display as usize,
|
||||||
CallAbiTable::DrawIter => abi::draw_iter as usize,
|
CallAbiTable::DrawIter => abi::draw_iter as usize,
|
||||||
CallAbiTable::GetKey => abi::get_key as usize,
|
CallAbiTable::GetKey => abi::get_key as usize,
|
||||||
CallAbiTable::GenRand => abi::gen_rand as usize,
|
CallAbiTable::GenRand => abi::gen_rand as usize,
|
||||||
|
CallAbiTable::ListDir => abi::list_dir as usize,
|
||||||
|
CallAbiTable::ReadFile => abi::read_file as usize,
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
table_base.add(idx as usize).write(ptr);
|
table_base.add(idx as usize).write(ptr);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#![feature(impl_trait_in_assoc_type)]
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
#![feature(str_from_raw_parts)]
|
||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![cfg_attr(not(test), no_main)]
|
#![cfg_attr(not(test), no_main)]
|
||||||
#![allow(static_mut_refs)]
|
#![allow(static_mut_refs)]
|
||||||
@@ -17,6 +18,7 @@ mod usb;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
abi::KEY_CACHE,
|
||||||
display::{FRAMEBUFFER, display_handler, init_display},
|
display::{FRAMEBUFFER, display_handler, init_display},
|
||||||
peripherals::{
|
peripherals::{
|
||||||
conf_peripherals,
|
conf_peripherals,
|
||||||
@@ -57,8 +59,6 @@ use embassy_sync::{
|
|||||||
use embassy_time::{Delay, Timer};
|
use embassy_time::{Delay, Timer};
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
||||||
use heapless::spsc::Queue;
|
|
||||||
use shared::keyboard::KeyEvent;
|
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use talc::*;
|
use talc::*;
|
||||||
|
|
||||||
@@ -251,8 +251,8 @@ async fn prog_search_handler() {
|
|||||||
loop {
|
loop {
|
||||||
{
|
{
|
||||||
let mut guard = SDCARD.get().lock().await;
|
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 files = sd.list_files_by_extension(".bin").unwrap();
|
||||||
let mut select = SELECTIONS.lock().await;
|
let mut select = SELECTIONS.lock().await;
|
||||||
|
|
||||||
@@ -261,13 +261,10 @@ async fn prog_search_handler() {
|
|||||||
select.reset();
|
select.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Timer::after_secs(5).await;
|
Timer::after_secs(5).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
|
||||||
|
|
||||||
async fn key_handler() {
|
async fn key_handler() {
|
||||||
loop {
|
loop {
|
||||||
if let Some(event) = read_keyboard_fifo().await {
|
if let Some(event) = read_keyboard_fifo().await {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type Device = ExclusiveDevice<Spi<'static, SPI0, Blocking>, Output<'static>, emb
|
|||||||
type SD = SdmmcSdCard<Device, Delay>;
|
type SD = SdmmcSdCard<Device, Delay>;
|
||||||
type VolMgr = VolumeManager<SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
|
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 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 type File<'a> = SdFile<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
|
||||||
|
|
||||||
pub static SDCARD: LazyLock<Mutex<CriticalSectionRawMutex, Option<SdCard>>> =
|
pub static SDCARD: LazyLock<Mutex<CriticalSectionRawMutex, Option<SdCard>>> =
|
||||||
|
|||||||
Reference in New Issue
Block a user