fixes from nes

This commit is contained in:
2025-11-17 08:10:03 -07:00
parent 691ef2b26b
commit 1c1000dfcb
19 changed files with 212 additions and 57 deletions

View File

@@ -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",

View File

@@ -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();

View File

@@ -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;
}
}
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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,

View File

@@ -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));
}