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

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "picolibc"]
path = picolibc
url = https://github.com/picolibc/picolibc
[submodule "user-apps/gboy/Peanut-GB"]
path = user-apps/gboy/Peanut-GB
url = https://github.com/deltabeard/Peanut-GB

View File

@@ -23,7 +23,7 @@ codegen-units = 1
lto = true lto = true
debug = false debug = false
opt-level = "z" opt-level = "z"
panic = "abort" panic = "unwind"
[profile.dev] [profile.dev]
lto = true lto = true

View File

@@ -3,8 +3,8 @@
extern crate alloc; extern crate alloc;
pub use abi_sys::{self, keyboard};
use abi_sys::{RngRequest, alloc, dealloc, keyboard::KeyEvent}; use abi_sys::{RngRequest, alloc, dealloc, keyboard::KeyEvent};
pub use abi_sys::{keyboard, print};
pub use alloc::format; pub use alloc::format;
use core::alloc::{GlobalAlloc, Layout}; use core::alloc::{GlobalAlloc, Layout};
use rand_core::RngCore; use rand_core::RngCore;
@@ -25,10 +25,10 @@ unsafe impl GlobalAlloc for Alloc {
} }
#[macro_export] #[macro_export]
macro_rules! print { macro_rules! println {
($($arg:tt)*) => {{ ($($arg:tt)*) => {{
let s = $crate::format!($($arg)*); let s = $crate::format!($($arg)*);
$crate::abi_sys::print(s.as_ptr(), s.len()); $crate::print(s.as_ptr(), s.len());
}}; }};
} }
@@ -61,10 +61,8 @@ pub mod display {
pub type Pixel565 = Pixel<Rgb565>; pub type Pixel565 = Pixel<Rgb565>;
const BUF_SIZE: usize = 15 * 1024; // tune this for performance const BUF_SIZE: usize = 1024;
static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE]; static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE];
// const BUF_SIZE: usize = 250 * 1024; // tune this for performance
// static mut BUF: Lazy<Vec<CPixel>> = Lazy::new(|| vec![const { CPixel::new() }; BUF_SIZE]);
static DISPLAY_TAKEN: AtomicBool = AtomicBool::new(false); static DISPLAY_TAKEN: AtomicBool = AtomicBool::new(false);
@@ -160,20 +158,30 @@ impl RngCore for Rng {
} }
pub mod fs { pub mod fs {
use alloc::vec::Vec;
use core::fmt::Display; use core::fmt::Display;
use alloc::{format, vec::Vec}; pub fn read_file(file: &str, start_from: usize, buf: &mut [u8]) -> usize {
pub fn read_file(file: &str, read_from: usize, buf: &mut [u8]) -> usize {
abi_sys::read_file( abi_sys::read_file(
file.as_ptr(), file.as_ptr(),
file.len(), file.len(),
read_from, start_from,
buf.as_mut_ptr(), buf.as_mut_ptr(),
buf.len(), buf.len(),
) )
} }
pub fn write_file(file: &str, start_from: usize, buf: &[u8]) {
abi_sys::write_file(
file.as_ptr(),
file.len(),
start_from,
buf.as_ptr(),
buf.len(),
)
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FileName<'a> { pub struct FileName<'a> {
full: &'a str, full: &'a str,
base: &'a str, base: &'a str,
@@ -217,7 +225,7 @@ pub mod fs {
const MAX_ENTRY_NAME_LEN: usize = 25; const MAX_ENTRY_NAME_LEN: usize = 25;
const MAX_ENTRIES: usize = 25; const MAX_ENTRIES: usize = 25;
#[derive(Clone, Copy)] #[derive(Clone, Copy, Debug)]
pub struct Entries([[u8; MAX_ENTRY_NAME_LEN]; MAX_ENTRIES]); pub struct Entries([[u8; MAX_ENTRY_NAME_LEN]; MAX_ENTRIES]);
impl Entries { impl Entries {

View File

@@ -12,7 +12,7 @@ use strum::{EnumCount, EnumIter};
pub type EntryFn = fn(); pub type EntryFn = fn();
pub const ABI_CALL_TABLE_COUNT: usize = 11; pub const ABI_CALL_TABLE_COUNT: usize = 12;
const _: () = assert!(ABI_CALL_TABLE_COUNT == CallTable::COUNT); const _: () = assert!(ABI_CALL_TABLE_COUNT == CallTable::COUNT);
#[derive(Clone, Copy, EnumIter, EnumCount)] #[derive(Clone, Copy, EnumIter, EnumCount)]
@@ -28,7 +28,8 @@ pub enum CallTable {
GenRand = 7, GenRand = 7,
ListDir = 8, ListDir = 8,
ReadFile = 9, ReadFile = 9,
FileLen = 10, WriteFile = 10,
FileLen = 11,
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@@ -438,6 +439,24 @@ pub extern "C" fn read_file(
} }
} }
pub type WriteFile =
extern "C" fn(str: *const u8, len: usize, write_from: usize, buf: *const u8, buf_len: usize);
#[unsafe(no_mangle)]
pub extern "C" fn write_file(
str: *const u8,
len: usize,
write_from: usize,
buf: *const u8,
buf_len: usize,
) {
unsafe {
let ptr = CALL_ABI_TABLE[CallTable::WriteFile as usize];
let f: WriteFile = core::mem::transmute(ptr);
f(str, len, write_from, buf, buf_len)
}
}
pub type FileLen = extern "C" fn(str: *const u8, len: usize) -> usize; pub type FileLen = extern "C" fn(str: *const u8, len: usize) -> usize;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]

View File

@@ -1,5 +1,7 @@
kernel-dev board: kernel-dev board:
cargo run --bin kernel --features {{board}} --features fps cargo run --bin kernel --features {{board}} --features fps
kernel-release-probe board:
cargo run --bin kernel --profile release --features {{board}} --features fps
kernel-release board: kernel-release board:
cargo build --bin kernel --release --no-default-features --features {{board}} cargo build --bin kernel --release --no-default-features --features {{board}}
elf2uf2-rs -d target/thumbv8m.main-none-eabihf/release/kernel elf2uf2-rs -d target/thumbv8m.main-none-eabihf/release/kernel
@@ -9,6 +11,26 @@ binary-args := "RUSTFLAGS=\"-C link-arg=-pie -C relocation-model=pic\""
cbindgen: cbindgen:
cbindgen abi_sys --output abi_sys.h -q cbindgen abi_sys --output abi_sys.h -q
newlib:
#!/bin/bash
cd picolibc
mkdir build
cd build
CONFIG_PICOLIBC=true ../scripts/do-configure thumbv8m_main_fp-none-eabi \
--buildtype=minsize \
-Dtests=true \
-Dtinystdio=false \
-Dsingle-thread=true \
-Db_pie=true \
-Ddefault_library=static \
-Dtinystdio=false \
-Dnewlib-nano-malloc=true \
-Dmultilib=false \
-Dpicolib=true \
"$@"
DESTDIR=./install meson install
ninja
userapp app: userapp app:
{{binary-args}} cargo build --bin {{app}} --profile release-binary {{binary-args}} cargo build --bin {{app}} --profile release-binary
@@ -17,3 +39,18 @@ userapps: cbindgen
just userapp snake just userapp snake
just userapp gallery just userapp gallery
just userapp gif just userapp gif
copy-userapp app:
cp ./target/thumbv8m.main-none-eabihf/release-binary/{{app}} /run/media/$(whoami)/PICOCALC/{{app}}.bin
copy-userapps:
#!/bin/bash
just userapps
just copy-userapp calculator
just copy-userapp snake
just copy-userapp gallery
just copy-userapp gif
DEV=$(lsblk -o LABEL,NAME -nr | awk -v L="PICOCALC" '$1==L {print "/dev/" $2}')
udisksctl unmount -b "$DEV"
udisksctl power-off -b "$DEV"

View File

@@ -17,6 +17,7 @@ pimoroni2w = ["rp235x", "psram"]
rp235x = ["embassy-rp/rp235xb"] rp235x = ["embassy-rp/rp235xb"]
trouble = ["dep:bt-hci", "dep:cyw43", "dep:cyw43-pio", "dep:trouble-host"] trouble = ["dep:bt-hci", "dep:cyw43", "dep:cyw43-pio", "dep:trouble-host"]
psram = ["dep:embedded-alloc"] psram = ["dep:embedded-alloc"]
overclock = []
fps = [] fps = []
defmt = [ defmt = [
"dep:defmt", "dep:defmt",

View File

@@ -1,6 +1,6 @@
use abi_sys::{ use abi_sys::{
AllocAbi, CLayout, CPixel, DeallocAbi, DrawIterAbi, FileLen, GenRand, GetMsAbi, ListDir, 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 alloc::{string::ToString, vec::Vec};
use core::{ffi::c_char, ptr, sync::atomic::Ordering}; use core::{ffi::c_char, ptr, sync::atomic::Ordering};
@@ -207,6 +207,7 @@ fn recurse_file<T>(
dirs: &[&str], dirs: &[&str],
mut access: impl FnMut(&mut File) -> T, mut access: impl FnMut(&mut File) -> T,
) -> Result<T, ()> { ) -> Result<T, ()> {
defmt::info!("dir: {}, dirs: {}", dir, dirs);
if dirs.len() == 1 { if dirs.len() == 1 {
let mut b = [0_u8; 50]; let mut b = [0_u8; 50];
let mut buf = LfnBuffer::new(&mut b); 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 { if let Some(name) = short_name {
let mut file = dir let mut file = dir
.open_file_in_dir(name, embedded_sdmmc::Mode::ReadWriteAppend) .open_file_in_dir(name, embedded_sdmmc::Mode::ReadWriteAppend)
@@ -242,7 +244,17 @@ pub extern "C" fn read_file(
) -> usize { ) -> usize {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes // SAFETY: caller guarantees `ptr` is valid for `len` bytes
let file = unsafe { core::str::from_raw_parts(str, len) }; 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 // SAFETY: caller guarantees `ptr` is valid for `len` bytes
let mut buf = unsafe { core::slice::from_raw_parts_mut(buf, buf_len) }; 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(); let sd = guard.as_mut().unwrap();
if !file.is_empty() { if !file.is_empty() {
sd.access_root_dir(|root| { sd.access_root_dir(|root| {
if let Ok(result) = recurse_file(&root, &file[1..], |file| { if let Ok(result) = recurse_file(&root, &components[1..count], |file| {
file.seek_from_start(start_from as u32).unwrap(); file.seek_from_start(start_from as u32).unwrap_or(());
file.read(&mut buf).unwrap() file.read(&mut buf).unwrap()
}) { }) {
read = result read = result
@@ -263,9 +275,46 @@ pub extern "C" fn read_file(
read 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; const _: FileLen = file_len;
pub extern "C" fn file_len(str: *const u8, len: usize) -> usize { 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 = unsafe { core::str::from_raw_parts(str, len) };
let file: Vec<&str> = file.split('/').collect(); let file: Vec<&str> = file.split('/').collect();

View File

@@ -87,8 +87,14 @@ pub async fn init_display(
#[embassy_executor::task] #[embassy_executor::task]
pub async fn display_handler(mut display: DISPLAY) { 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 { loop {
// renders fps text to canvas let start = Instant::now();
#[cfg(feature = "fps")] #[cfg(feature = "fps")]
unsafe { unsafe {
if FPS_COUNTER.should_draw() { if FPS_COUNTER.should_draw() {
@@ -103,11 +109,15 @@ pub async fn display_handler(mut display: DISPLAY) {
.unwrap() .unwrap()
.partial_draw(&mut display) .partial_draw(&mut display)
.await .await
.unwrap() .unwrap();
}; }
} }
// small yield to allow other tasks to run let elapsed = start.elapsed().as_millis() as u64;
Timer::after_millis(10).await; 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::GenRand => abi::gen_rand as usize,
CallTable::ListDir => abi::list_dir as usize, CallTable::ListDir => abi::list_dir as usize,
CallTable::ReadFile => abi::read_file as usize, CallTable::ReadFile => abi::read_file as usize,
CallTable::WriteFile => abi::write_file as usize,
CallTable::FileLen => abi::file_len as usize, CallTable::FileLen => abi::file_len as usize,
}; };
unsafe { unsafe {

View File

@@ -47,6 +47,8 @@ use embassy_executor::{Executor, Spawner};
use embassy_futures::{join::join, select::select}; use embassy_futures::{join::join, select::select};
use embassy_rp::{ use embassy_rp::{
Peri, Peri,
clocks::ClockConfig,
config::Config,
gpio::{Input, Level, Output, Pull}, gpio::{Input, Level, Output, Pull},
i2c::{self, I2c}, i2c::{self, I2c},
multicore::{Stack, spawn_core1}, multicore::{Stack, spawn_core1},
@@ -119,7 +121,13 @@ static UI_CHANGE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { 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( spawn_core1(
p.CORE1, p.CORE1,
@@ -255,7 +263,7 @@ async fn setup_mcu(mcu: Mcu) {
async fn setup_display(display: Display, spawner: Spawner) { async fn setup_display(display: Display, spawner: Spawner) {
let mut config = spi::Config::default(); let mut config = spi::Config::default();
config.frequency = 64_000_000; config.frequency = 192_000_000;
let spi = Spi::new( let spi = Spi::new(
display.spi, display.spi,
display.clk, display.clk,
@@ -331,6 +339,9 @@ async fn kernel_task(
.spawn(watchdog_task(Watchdog::new(watchdog))) .spawn(watchdog_task(Watchdog::new(watchdog)))
.unwrap(); .unwrap();
#[cfg(feature = "debug")]
defmt::info!("Clock: {}", embassy_rp::clocks::clk_sys_freq());
setup_mcu(mcu).await; setup_mcu(mcu).await;
#[cfg(feature = "defmt")] #[cfg(feature = "defmt")]
@@ -364,7 +375,8 @@ async fn prog_search_handler() {
let mut guard = SDCARD.get().lock().await; let mut guard = SDCARD.get().lock().await;
let sd = guard.as_mut().unwrap(); 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; let mut select = SELECTIONS.lock().await;
if *select.selections() != files { if *select.selections() != files {
@@ -379,12 +391,10 @@ async fn prog_search_handler() {
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 {
if let KeyState::Pressed = event.state {
unsafe { unsafe {
let _ = KEY_CACHE.enqueue(event); let _ = KEY_CACHE.enqueue(event);
} }
} }
}
Timer::after_millis(50).await; 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 struct FileName {
pub long_name: String, pub long_name: String,
pub short_name: ShortFileName, 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 { pub struct SdCard {
det: Input<'static>, det: Input<'static>,
volume_mgr: VolMgr, volume_mgr: VolMgr,

View File

@@ -75,7 +75,7 @@ pub async fn clear_selection() {
async fn draw_selection() { async fn draw_selection() {
let mut guard = SELECTIONS.lock().await; 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 text_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
let display_area = unsafe { FRAMEBUFFER.as_mut().unwrap().bounding_box() }; let display_area = unsafe { FRAMEBUFFER.as_mut().unwrap().bounding_box() };
@@ -99,7 +99,7 @@ async fn draw_selection() {
} else { } else {
let mut views: alloc::vec::Vec<Text<MonoTextStyle<Rgb565>>> = Vec::new(); 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)); views.push(Text::new(&i.long_name, Point::zero(), text_style));
} }

1
picolibc Submodule

Submodule picolibc added at d664643068

View File

@@ -6,7 +6,6 @@ use abi::{
display::Display, display::Display,
get_key, get_key,
keyboard::{KeyCode, KeyState}, keyboard::{KeyCode, KeyState},
print,
}; };
use alloc::vec::Vec; use alloc::vec::Vec;
use embedded_graphics::{ use embedded_graphics::{
@@ -55,6 +54,9 @@ impl<'a> SelectionUi<'a> {
if key.state == KeyState::Pressed { if key.state == KeyState::Pressed {
if let Some(s) = self.update(display, key.key)? { if let Some(s) = self.update(display, key.key)? {
selection = Some(s); selection = Some(s);
display
.clear(Rgb565::BLACK)
.map_err(|e| SelectionUiError::DisplayError(e))?;
break; break;
} }
} }
@@ -69,7 +71,6 @@ impl<'a> SelectionUi<'a> {
display: &mut Display, display: &mut Display,
key: KeyCode, key: KeyCode,
) -> Result<Option<usize>, SelectionUiError<<Display as DrawTarget>::Error>> { ) -> Result<Option<usize>, SelectionUiError<<Display as DrawTarget>::Error>> {
print!("Got Key: {:?}", key);
match key { match key {
KeyCode::Down => { KeyCode::Down => {
self.selection = (self.selection + 1).min(self.items.len() - 1); self.selection = (self.selection + 1).min(self.items.len() - 1);
@@ -80,7 +81,6 @@ impl<'a> SelectionUi<'a> {
KeyCode::Enter | KeyCode::Right => return Ok(Some(self.selection)), KeyCode::Enter | KeyCode::Right => return Ok(Some(self.selection)),
_ => return Ok(None), _ => return Ok(None),
}; };
print!("new selection: {:?}", self.selection);
self.draw(display)?; self.draw(display)?;
Ok(None) Ok(None)
} }

View File

@@ -6,7 +6,7 @@ use abi::{
display::Display, display::Display,
get_key, get_key,
keyboard::{KeyCode, KeyState}, keyboard::{KeyCode, KeyState},
print, println,
}; };
use alloc::{format, string::String, vec, vec::Vec}; use alloc::{format, string::String, vec, vec::Vec};
use core::panic::PanicInfo; use core::panic::PanicInfo;
@@ -28,7 +28,7 @@ use embedded_layout::{
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
print!("user panic: {} @ {:?}", info.message(), info.location(),); println!("user panic: {} @ {:?}", info.message(), info.location(),);
loop {} loop {}
} }
@@ -38,7 +38,7 @@ pub extern "Rust" fn _start() {
} }
pub fn main() { pub fn main() {
print!("Starting Calculator app"); println!("Starting Calculator app");
let mut display = Display::take().unwrap(); let mut display = Display::take().unwrap();
let mut input = vec!['e', 'x', 'p', 'r', ':', ' ']; let mut input = vec!['e', 'x', 'p', 'r', ':', ' '];
@@ -104,7 +104,7 @@ pub fn main() {
} }
let event = get_key(); let event = get_key();
if event.state != KeyState::Idle { if event.state == KeyState::Released {
match event.key { match event.key {
KeyCode::Char(ch) => { KeyCode::Char(ch) => {
input.push(ch); input.push(ch);

View File

@@ -8,7 +8,7 @@ use abi::{
fs::{Entries, list_dir, read_file}, fs::{Entries, list_dir, read_file},
get_key, get_key,
keyboard::{KeyCode, KeyState}, keyboard::{KeyCode, KeyState},
print, println,
}; };
use alloc::{format, vec}; use alloc::{format, vec};
use core::panic::PanicInfo; use core::panic::PanicInfo;
@@ -20,7 +20,7 @@ use tinybmp::Bmp;
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
print!("user panic: {} @ {:?}", info.message(), info.location()); println!("user panic: {} @ {:?}", info.message(), info.location());
loop {} loop {}
} }
@@ -30,7 +30,7 @@ pub extern "Rust" fn _start() {
} }
pub fn main() { pub fn main() {
print!("Starting Gallery app"); println!("Starting Gallery app");
let mut bmp_buf = vec![0_u8; 100_000]; let mut bmp_buf = vec![0_u8; 100_000];
let mut display = Display::take().unwrap(); let mut display = Display::take().unwrap();
@@ -49,7 +49,7 @@ pub fn main() {
break; // only draw 3x3 break; // only draw 3x3
} }
print!("file: {}", file); println!("file: {}", file);
if file.extension().unwrap_or("") == "bmp" || file.extension().unwrap_or("") == "BMP" { if file.extension().unwrap_or("") == "bmp" || file.extension().unwrap_or("") == "BMP" {
let file_path = format!("/images/{}", file); let file_path = format!("/images/{}", file);

View File

@@ -5,6 +5,6 @@ edition = "2024"
[dependencies] [dependencies]
abi = { path = "../../abi" } abi = { path = "../../abi" }
embedded-graphics = "0.8.1"
selection_ui = { path = "../../selection_ui" } selection_ui = { path = "../../selection_ui" }
embedded-graphics = "0.8.1"
tinygif = { git = "https://github.com/LegitCamper/tinygif" } tinygif = { git = "https://github.com/LegitCamper/tinygif" }

View File

@@ -7,7 +7,7 @@ use abi::{
fs::{Entries, file_len, list_dir, read_file}, fs::{Entries, file_len, list_dir, read_file},
get_key, get_ms, get_key, get_ms,
keyboard::{KeyCode, KeyState}, keyboard::{KeyCode, KeyState},
print, sleep, println, sleep,
}; };
use alloc::{format, vec, vec::Vec}; use alloc::{format, vec, vec::Vec};
use core::panic::PanicInfo; use core::panic::PanicInfo;
@@ -23,7 +23,7 @@ use tinygif::Gif;
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
print!("user panic: {} @ {:?}", info.message(), info.location(),); println!("user panic: {} @ {:?}", info.message(), info.location(),);
loop {} loop {}
} }
@@ -33,7 +33,7 @@ pub extern "Rust" fn _start() {
} }
pub fn main() { pub fn main() {
print!("Starting Gif app"); println!("Starting Gif app");
let mut display = Display::take().unwrap(); let mut display = Display::take().unwrap();
let mut entries = Entries::new(); let mut entries = Entries::new();
@@ -41,9 +41,10 @@ pub fn main() {
let mut files = entries.entries(); let mut files = entries.entries();
files.retain(|e| e.extension().unwrap_or("") == "gif"); files.retain(|e| e.extension().unwrap_or("") == "gif");
let gifs = &files.iter().map(|e| e.full_name()).collect::<Vec<&str>>(); let mut gifs = files.iter().map(|e| e.full_name()).collect::<Vec<&str>>();
gifs.sort();
let mut selection_ui = SelectionUi::new(&gifs); let mut selection_ui = SelectionUi::new(&mut gifs);
let selection = match selection_ui.run_selection_ui(&mut display) { let selection = match selection_ui.run_selection_ui(&mut display) {
Ok(maybe_sel) => maybe_sel, Ok(maybe_sel) => maybe_sel,
Err(e) => match e { Err(e) => match e {
@@ -66,7 +67,7 @@ pub fn main() {
let size = file_len(&file_name); let size = file_len(&file_name);
let mut buf = vec![0_u8; size]; let mut buf = vec![0_u8; size];
let read = read_file(&file_name, 0, &mut buf); let read = read_file(&file_name, 0, &mut buf);
print!("read: {}, file size: {}", read, size); println!("read: {}, file size: {}", read, size);
assert!(read == size); assert!(read == size);
let gif = Gif::<Rgb565>::from_slice(&buf).expect("Failed to parse gif"); let gif = Gif::<Rgb565>::from_slice(&buf).expect("Failed to parse gif");

View File

@@ -7,7 +7,7 @@ use abi::{
display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH}, display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH},
get_key, get_key,
keyboard::{KeyCode, KeyState}, keyboard::{KeyCode, KeyState},
print, sleep, println, sleep,
}; };
use core::panic::PanicInfo; use core::panic::PanicInfo;
use embedded_graphics::{pixelcolor::Rgb565, prelude::RgbColor}; use embedded_graphics::{pixelcolor::Rgb565, prelude::RgbColor};
@@ -15,7 +15,7 @@ use embedded_snake::{Direction, SnakeGame};
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
print!("user panic: {} @ {:?}", info.message(), info.location(),); println!("user panic: {} @ {:?}", info.message(), info.location(),);
loop {} loop {}
} }
@@ -27,7 +27,7 @@ pub extern "Rust" fn _start() {
const CELL_SIZE: usize = 8; const CELL_SIZE: usize = 8;
pub fn main() { pub fn main() {
print!("Starting Snake app"); println!("Starting Snake app");
let mut display = Display::take().unwrap(); let mut display = Display::take().unwrap();
let mut game = SnakeGame::<100, Rgb565, Rng>::new( let mut game = SnakeGame::<100, Rgb565, Rng>::new(