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:
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
39
justfile
39
justfile
@@ -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"
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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,10 +391,8 @@ 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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
1
picolibc
Submodule
Submodule picolibc added at d664643068
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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" }
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user