mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 07:45:28 +00:00
fixes from nes
This commit is contained in:
@@ -17,6 +17,7 @@ pimoroni2w = ["rp235x", "psram"]
|
||||
rp235x = ["embassy-rp/rp235xb"]
|
||||
trouble = ["dep:bt-hci", "dep:cyw43", "dep:cyw43-pio", "dep:trouble-host"]
|
||||
psram = ["dep:embedded-alloc"]
|
||||
overclock = []
|
||||
fps = []
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use abi_sys::{
|
||||
AllocAbi, CLayout, CPixel, DeallocAbi, DrawIterAbi, FileLen, GenRand, GetMsAbi, ListDir,
|
||||
PrintAbi, ReadFile, RngRequest, SleepMsAbi, keyboard::*,
|
||||
PrintAbi, ReadFile, RngRequest, SleepMsAbi, WriteFile, keyboard::*,
|
||||
};
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use core::{ffi::c_char, ptr, sync::atomic::Ordering};
|
||||
@@ -207,6 +207,7 @@ fn recurse_file<T>(
|
||||
dirs: &[&str],
|
||||
mut access: impl FnMut(&mut File) -> T,
|
||||
) -> Result<T, ()> {
|
||||
defmt::info!("dir: {}, dirs: {}", dir, dirs);
|
||||
if dirs.len() == 1 {
|
||||
let mut b = [0_u8; 50];
|
||||
let mut buf = LfnBuffer::new(&mut b);
|
||||
@@ -218,7 +219,8 @@ fn recurse_file<T>(
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
.expect("Failed to iterate dir");
|
||||
|
||||
if let Some(name) = short_name {
|
||||
let mut file = dir
|
||||
.open_file_in_dir(name, embedded_sdmmc::Mode::ReadWriteAppend)
|
||||
@@ -242,7 +244,17 @@ pub extern "C" fn read_file(
|
||||
) -> usize {
|
||||
// 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 components: [&str; 8] = [""; 8];
|
||||
let mut count = 0;
|
||||
for part in file.split('/') {
|
||||
if count >= components.len() {
|
||||
break;
|
||||
}
|
||||
components[count] = part;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
|
||||
let mut buf = unsafe { core::slice::from_raw_parts_mut(buf, buf_len) };
|
||||
|
||||
@@ -252,8 +264,8 @@ pub extern "C" fn read_file(
|
||||
let sd = guard.as_mut().unwrap();
|
||||
if !file.is_empty() {
|
||||
sd.access_root_dir(|root| {
|
||||
if let Ok(result) = recurse_file(&root, &file[1..], |file| {
|
||||
file.seek_from_start(start_from as u32).unwrap();
|
||||
if let Ok(result) = recurse_file(&root, &components[1..count], |file| {
|
||||
file.seek_from_start(start_from as u32).unwrap_or(());
|
||||
file.read(&mut buf).unwrap()
|
||||
}) {
|
||||
read = result
|
||||
@@ -263,9 +275,46 @@ pub extern "C" fn read_file(
|
||||
read
|
||||
}
|
||||
|
||||
const _: WriteFile = write_file;
|
||||
pub extern "C" fn write_file(
|
||||
str: *const u8,
|
||||
len: usize,
|
||||
start_from: usize,
|
||||
buf: *const u8,
|
||||
buf_len: usize,
|
||||
) {
|
||||
// SAFETY: caller guarantees str ptr is valid for `len` bytes
|
||||
let file = unsafe { core::str::from_raw_parts(str, len) };
|
||||
|
||||
let mut components: [&str; 8] = [""; 8];
|
||||
let mut count = 0;
|
||||
for part in file.split('/') {
|
||||
if count >= components.len() {
|
||||
break;
|
||||
}
|
||||
components[count] = part;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// SAFETY: caller guarantees buf ptr is valid for `buf_len` bytes
|
||||
let buf = unsafe { core::slice::from_raw_parts(buf, buf_len) };
|
||||
|
||||
let mut guard = SDCARD.get().try_lock().expect("Failed to get sdcard");
|
||||
let sd = guard.as_mut().unwrap();
|
||||
if !file.is_empty() {
|
||||
sd.access_root_dir(|root| {
|
||||
recurse_file(&root, &components[1..count], |file| {
|
||||
file.seek_from_start(start_from as u32).unwrap();
|
||||
file.write(&buf).unwrap()
|
||||
})
|
||||
.unwrap_or(())
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const _: FileLen = file_len;
|
||||
pub extern "C" fn file_len(str: *const u8, len: usize) -> usize {
|
||||
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
|
||||
// SAFETY: caller guarantees str ptr is valid for `len` bytes
|
||||
let file = unsafe { core::str::from_raw_parts(str, len) };
|
||||
let file: Vec<&str> = file.split('/').collect();
|
||||
|
||||
|
||||
@@ -87,8 +87,14 @@ pub async fn init_display(
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn display_handler(mut display: DISPLAY) {
|
||||
use embassy_time::{Instant, Timer};
|
||||
|
||||
// Target ~60 Hz refresh (≈16.67 ms per frame)
|
||||
const FRAME_TIME_MS: u64 = 1000 / 60;
|
||||
|
||||
loop {
|
||||
// renders fps text to canvas
|
||||
let start = Instant::now();
|
||||
|
||||
#[cfg(feature = "fps")]
|
||||
unsafe {
|
||||
if FPS_COUNTER.should_draw() {
|
||||
@@ -103,11 +109,15 @@ pub async fn display_handler(mut display: DISPLAY) {
|
||||
.unwrap()
|
||||
.partial_draw(&mut display)
|
||||
.await
|
||||
.unwrap()
|
||||
};
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// small yield to allow other tasks to run
|
||||
Timer::after_millis(10).await;
|
||||
let elapsed = start.elapsed().as_millis() as u64;
|
||||
if elapsed < FRAME_TIME_MS {
|
||||
Timer::after_millis(FRAME_TIME_MS - elapsed).await;
|
||||
} else {
|
||||
Timer::after_millis(1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +206,7 @@ fn patch_abi(
|
||||
CallTable::GenRand => abi::gen_rand as usize,
|
||||
CallTable::ListDir => abi::list_dir as usize,
|
||||
CallTable::ReadFile => abi::read_file as usize,
|
||||
CallTable::WriteFile => abi::write_file as usize,
|
||||
CallTable::FileLen => abi::file_len as usize,
|
||||
};
|
||||
unsafe {
|
||||
|
||||
@@ -47,6 +47,8 @@ use embassy_executor::{Executor, Spawner};
|
||||
use embassy_futures::{join::join, select::select};
|
||||
use embassy_rp::{
|
||||
Peri,
|
||||
clocks::ClockConfig,
|
||||
config::Config,
|
||||
gpio::{Input, Level, Output, Pull},
|
||||
i2c::{self, I2c},
|
||||
multicore::{Stack, spawn_core1},
|
||||
@@ -119,7 +121,13 @@ static UI_CHANGE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let p = if cfg!(feature = "overclock") {
|
||||
let clocks = ClockConfig::system_freq(300_000_000).unwrap();
|
||||
let config = Config::new(clocks);
|
||||
embassy_rp::init(config)
|
||||
} else {
|
||||
embassy_rp::init(Default::default())
|
||||
};
|
||||
|
||||
spawn_core1(
|
||||
p.CORE1,
|
||||
@@ -255,7 +263,7 @@ async fn setup_mcu(mcu: Mcu) {
|
||||
|
||||
async fn setup_display(display: Display, spawner: Spawner) {
|
||||
let mut config = spi::Config::default();
|
||||
config.frequency = 64_000_000;
|
||||
config.frequency = 192_000_000;
|
||||
let spi = Spi::new(
|
||||
display.spi,
|
||||
display.clk,
|
||||
@@ -331,6 +339,9 @@ async fn kernel_task(
|
||||
.spawn(watchdog_task(Watchdog::new(watchdog)))
|
||||
.unwrap();
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
defmt::info!("Clock: {}", embassy_rp::clocks::clk_sys_freq());
|
||||
|
||||
setup_mcu(mcu).await;
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
@@ -364,7 +375,8 @@ async fn prog_search_handler() {
|
||||
let mut guard = SDCARD.get().lock().await;
|
||||
let sd = guard.as_mut().unwrap();
|
||||
|
||||
let files = sd.list_files_by_extension(".bin").unwrap();
|
||||
let mut files = sd.list_files_by_extension(".bin").unwrap();
|
||||
files.sort();
|
||||
let mut select = SELECTIONS.lock().await;
|
||||
|
||||
if *select.selections() != files {
|
||||
@@ -379,10 +391,8 @@ async fn prog_search_handler() {
|
||||
async fn key_handler() {
|
||||
loop {
|
||||
if let Some(event) = read_keyboard_fifo().await {
|
||||
if let KeyState::Pressed = event.state {
|
||||
unsafe {
|
||||
let _ = KEY_CACHE.enqueue(event);
|
||||
}
|
||||
unsafe {
|
||||
let _ = KEY_CACHE.enqueue(event);
|
||||
}
|
||||
}
|
||||
Timer::after_millis(50).await;
|
||||
|
||||
@@ -35,12 +35,24 @@ impl TimeSource for DummyTimeSource {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct FileName {
|
||||
pub long_name: String,
|
||||
pub short_name: ShortFileName,
|
||||
}
|
||||
|
||||
impl PartialOrd for FileName {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.long_name.cmp(&other.long_name))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for FileName {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
self.long_name.cmp(&other.long_name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SdCard {
|
||||
det: Input<'static>,
|
||||
volume_mgr: VolMgr,
|
||||
|
||||
@@ -75,7 +75,7 @@ pub async fn clear_selection() {
|
||||
|
||||
async fn draw_selection() {
|
||||
let mut guard = SELECTIONS.lock().await;
|
||||
let file_names = &guard.selections.clone();
|
||||
let file_names = guard.selections.clone();
|
||||
|
||||
let text_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
||||
let display_area = unsafe { FRAMEBUFFER.as_mut().unwrap().bounding_box() };
|
||||
@@ -99,7 +99,7 @@ async fn draw_selection() {
|
||||
} else {
|
||||
let mut views: alloc::vec::Vec<Text<MonoTextStyle<Rgb565>>> = Vec::new();
|
||||
|
||||
for i in file_names {
|
||||
for i in &file_names {
|
||||
views.push(Text::new(&i.long_name, Point::zero(), text_style));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user