From 8ca55fcdaf087de58bd921d05786e8570e14c773 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Fri, 1 Aug 2025 16:24:37 -0600 Subject: [PATCH] working on bin selection ui --- Cargo.lock | 66 ++++++++++++++++++ abi/src/lib.rs | 4 ++ kernel/Cargo.toml | 11 +-- kernel/src/abi.rs | 3 +- kernel/src/display.rs | 4 +- kernel/src/main.rs | 9 +-- kernel/src/scsi/mod.rs | 8 +-- kernel/src/storage.rs | 6 ++ kernel/src/ui.rs | 117 ++++++++++++++++++++++++++++++++ kernel/src/usb.rs | 12 +++- user-apps/calculator/Cargo.toml | 1 + 11 files changed, 222 insertions(+), 19 deletions(-) create mode 100644 kernel/src/ui.rs diff --git a/Cargo.lock b/Cargo.lock index ccfebe5..de4d866 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,6 +205,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "calculator" version = "0.1.0" +dependencies = [ + "abi", +] [[package]] name = "cfg-if" @@ -419,6 +422,17 @@ dependencies = [ "defmt 0.3.100", ] +[[package]] +name = "delegate" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6178a82cf56c836a3ba61a7935cdb1c49bfaa6fa4327cd5bf554a503087de26b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "diff" version = "0.1.13" @@ -471,6 +485,26 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + +[[package]] +name = "elf_loader" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a0da8db95cff71e500b3d7015c2441a4eb628e0df788b23d1b8d1243314342" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "delegate", + "elf", + "portable-atomic", + "portable-atomic-util", +] + [[package]] name = "embassy-embedded-hal" version = "0.3.1" @@ -812,6 +846,27 @@ dependencies = [ "embedded-io", ] +[[package]] +name = "embedded-layout" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a90553247f2b05c59ac7894ea13d830636c2b1203fa03bff400eddbd1fa9f52" +dependencies = [ + "embedded-graphics", + "embedded-layout-macros", +] + +[[package]] +name = "embedded-layout-macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f6e621fe4c7e05b695274b722dc0a60bacd1c8696b58191baa0154713d52400" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "embedded-sdmmc" version = "0.9.0" @@ -1407,6 +1462,7 @@ dependencies = [ "cyw43-pio", "defmt 0.3.100", "defmt-rtt", + "elf_loader", "embassy-embedded-hal", "embassy-executor", "embassy-futures", @@ -1418,6 +1474,7 @@ dependencies = [ "embedded-hal 0.2.7", "embedded-hal-async", "embedded-hal-bus", + "embedded-layout", "embedded-sdmmc", "heapless", "num_enum 0.7.4", @@ -1540,6 +1597,15 @@ dependencies = [ "critical-section", ] +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "precomputed-hash" version = "0.1.1" diff --git a/abi/src/lib.rs b/abi/src/lib.rs index 1dbc74a..398e386 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -3,6 +3,10 @@ use core::ffi::c_void; use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; +unsafe extern "C" { + fn call_abi(call: *const Syscall); +} + #[repr(C)] pub enum Syscall { DrawPixel { x: u32, y: u32, color: u16 }, diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0fefc21..39dcdca 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -70,12 +70,10 @@ portable-atomic = { version = "1.11", features = ["critical-section"] } defmt = { version = "0.3", optional = true } defmt-rtt = "0.4.2" -embedded-graphics = { version = "0.8.1" } embedded-sdmmc = { version = "0.9", default-features = false } st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", rev = "87abf450404865dcb535292e9e1a6a2457fd4599" } # async branch - -shared = { path = "../shared" } -abi = { path = "../abi" } +embedded-graphics = { version = "0.8.1" } +embedded-layout = "0.4.2" static_cell = "2.1.1" bitflags = "2.9.1" @@ -83,3 +81,8 @@ talc = "4.4.3" spin = "0.10.0" heapless = "0.8.0" num_enum = { version = "0.7.4", default-features = false } +elf_loader = {version ="0.12.0", default-features = false, features = ["portable-atomic"]} + +shared = { path = "../shared" } +abi = { path = "../abi" } + diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 4cf56ca..8bb55ec 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -10,12 +10,11 @@ use embedded_graphics::{ use crate::display::FRAMEBUFFER; #[unsafe(no_mangle)] -pub extern "C" fn syscall_dispatch(call: *const Syscall) -> usize { +pub extern "C" fn call_abi(call: *const Syscall) { let call = unsafe { &*call }; match call { Syscall::DrawPixel { x, y, color } => { draw_pixel(*x, *y, *color); - 0 } } } diff --git a/kernel/src/display.rs b/kernel/src/display.rs index 5615e03..388f9bf 100644 --- a/kernel/src/display.rs +++ b/kernel/src/display.rs @@ -17,8 +17,8 @@ type DISPLAY = ST7365P< Delay, >; -const SCREEN_WIDTH: usize = 320; -const SCREEN_HEIGHT: usize = 320; +pub const SCREEN_WIDTH: usize = 320; +pub const SCREEN_HEIGHT: usize = 320; type FB = FrameBuffer; static FRAMEBUFFER_CELL: StaticCell = StaticCell::new(); diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 09acd98..4b89055 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -8,6 +8,7 @@ mod display; mod peripherals; mod scsi; mod storage; +mod ui; mod usb; mod utils; @@ -17,7 +18,7 @@ use crate::{ conf_peripherals, keyboard::{KeyCode, KeyState, read_keyboard_fifo}, }, - storage::SdCard, + storage::{SDCARD, SdCard}, usb::usb_handler, }; @@ -68,7 +69,7 @@ async fn main(_spawner: Spawner) { display_handler(display) }; - let sdcard = { + { let mut config = spi::Config::default(); config.frequency = 400_000; let clk = p.PIN_18; @@ -83,11 +84,11 @@ async fn main(_spawner: Spawner) { config.frequency = 32_000_000; sdcard.spi(|dev| dev.bus_mut().set_config(&config)); - SdCard::new(sdcard, det) + SDCARD.get().lock().await.replace(SdCard::new(sdcard, det)); }; let usb = embassy_rp_usb::Driver::new(p.USB, Irqs); - let usb_fut = usb_handler(usb, sdcard); + let usb_fut = usb_handler(usb); join(usb_fut, display_fut).await; } diff --git a/kernel/src/scsi/mod.rs b/kernel/src/scsi/mod.rs index a50ff26..7859fa5 100644 --- a/kernel/src/scsi/mod.rs +++ b/kernel/src/scsi/mod.rs @@ -12,14 +12,14 @@ use crate::storage::SdCard; const BULK_ENDPOINT_PACKET_SIZE: usize = 64; -pub struct MassStorageClass<'d, D: Driver<'d>> { - sdcard: SdCard, +pub struct MassStorageClass<'d, 's, D: Driver<'d>> { + sdcard: &'s SdCard, bulk_out: D::EndpointOut, bulk_in: D::EndpointIn, } -impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { - pub fn new(builder: &mut Builder<'d, D>, sdcard: SdCard) -> Self { +impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> { + pub fn new(builder: &mut Builder<'d, D>, sdcard: &'s SdCard) -> Self { let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class let mut interface = function.interface(); let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None); diff --git a/kernel/src/storage.rs b/kernel/src/storage.rs index 04b4353..ea698b0 100644 --- a/kernel/src/storage.rs +++ b/kernel/src/storage.rs @@ -1,6 +1,9 @@ use embassy_rp::gpio::{Input, Output}; use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Blocking, Spi}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::lazy_lock::LazyLock; +use embassy_sync::mutex::Mutex; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_sdmmc::{ @@ -18,6 +21,9 @@ type VolMgr = VolumeManager = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; +pub static SDCARD: LazyLock>> = + LazyLock::new(|| Mutex::new(None)); + pub struct DummyTimeSource {} impl TimeSource for DummyTimeSource { fn get_timestamp(&self) -> Timestamp { diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs new file mode 100644 index 0000000..acb80fd --- /dev/null +++ b/kernel/src/ui.rs @@ -0,0 +1,117 @@ +use crate::{ + display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH}, + format, +}; +use core::fmt::Debug; +use defmt::info; +use embassy_rp::{ + gpio::{Level, Output}, + peripherals::{PIN_13, PIN_14, PIN_15, SPI1}, + spi::{Async, Spi}, +}; +use embassy_time::{Delay, Timer}; +use embedded_graphics::{ + Drawable, + draw_target::DrawTarget, + mono_font::{ + MonoTextStyle, + ascii::{FONT_6X10, FONT_9X15, FONT_10X20}, + }, + pixelcolor::Rgb565, + prelude::{Dimensions, Point, RgbColor, Size}, + primitives::{PrimitiveStyle, Rectangle, StyledDrawable}, + text::Text, +}; +use embedded_hal_async::spi::SpiDevice; +use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay}; +use embedded_layout::{ + align::{horizontal, vertical}, + layout::linear::LinearLayout, + object_chain::Chain, + prelude::*, +}; +use heapless::{String, Vec}; + +pub struct UI { + pub selections_list: SelectionList, +} + +impl UI { + pub fn new() -> Self { + Self { + selections_list: SelectionList::new(Vec::new()), + } + } + + pub async fn draw>(&mut self) + where + ::Error: Debug, + { + self.draw_selection().await; + } + + async fn draw_selection(&mut self) { + let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE); + + let selection = Rectangle::new( + Point::new(0, 0), + Size::new(SCREEN_WIDTH as u32 - 1, SCREEN_HEIGHT as u32 - 1), + ); + + let mut file_names = self.selections_list.selections.iter(); + + let Some(first) = file_names.next() else { + Text::new("No Programs found on SD Card\nEnsure programs end with '.bin',\nand are located in the root directory", + Point::zero(), text_style).draw(*FRAMEBUFFER.lock().await.borrow_mut().as_mut().unwrap()).unwrap(); + + return; + }; + + let chain = Chain::new(Text::new(first, Point::zero(), text_style)); + + LinearLayout::vertical(chain) + .with_alignment(horizontal::Center) + .arrange() + .align_to( + &FRAMEBUFFER + .lock() + .await + .borrow_mut() + .as_mut() + .unwrap() + .bounding_box(), + horizontal::Center, + vertical::Center, + ) + .draw(*FRAMEBUFFER.lock().await.borrow_mut().as_mut().unwrap()) + .unwrap(); + } +} + +pub struct SelectionList { + current_selection: u16, + selections: Vec, MAX_SELECTION>, +} + +impl + SelectionList +{ + pub fn new(selections: Vec, MAX_SELECTION>) -> Self { + Self { + selections, + current_selection: 0, + } + } + + pub fn down(&mut self) { + if self.current_selection + 1 < self.selections.len() as u16 { + self.current_selection += 1 + } + } + + pub fn up(&mut self) { + if self.current_selection > self.selections.len() as u16 { + self.current_selection -= 1 + } + } +} diff --git a/kernel/src/usb.rs b/kernel/src/usb.rs index 161f5da..50dd4e7 100644 --- a/kernel/src/usb.rs +++ b/kernel/src/usb.rs @@ -1,6 +1,9 @@ use core::sync::atomic::Ordering; -use crate::{scsi::MassStorageClass, storage::SdCard}; +use crate::{ + scsi::MassStorageClass, + storage::{SDCARD, SdCard}, +}; use embassy_futures::{ join::join, select::{select, select3}, @@ -13,7 +16,7 @@ use portable_atomic::AtomicBool; static RESTART_USB: Signal = Signal::new(); static ENABLE_SCSI: AtomicBool = AtomicBool::new(false); -pub async fn usb_handler(driver: Driver<'static, USB>, sdcard: SdCard) { +pub async fn usb_handler(driver: Driver<'static, USB>) { let mut config = Config::new(0xc0de, 0xcafe); config.manufacturer = Some("LegitCamper"); config.product = Some("PicoCalc"); @@ -34,10 +37,13 @@ pub async fn usb_handler(driver: Driver<'static, USB>, sdcard: SdCard) { &mut control_buf, ); + let lock = SDCARD.get().lock().await; + let mut sdcard = lock.as_ref().unwrap(); + if sdcard.is_attached() { ENABLE_SCSI.store(true, Ordering::Relaxed); } - let mut scsi = MassStorageClass::new(&mut builder, sdcard); + let mut scsi = MassStorageClass::new(&mut builder, &sdcard); let mut usb = builder.build(); loop { diff --git a/user-apps/calculator/Cargo.toml b/user-apps/calculator/Cargo.toml index ed5cba5..13d39be 100644 --- a/user-apps/calculator/Cargo.toml +++ b/user-apps/calculator/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +abi = { path ="../../abi" }