diff --git a/Cargo.lock b/Cargo.lock index 25dcb88..d5287c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1941,7 +1941,6 @@ dependencies = [ [[package]] name = "st7365p-lcd" version = "0.11.0" -source = "git+https://github.com/legitcamper/st7365p-lcd-rs?rev=87abf450404865dcb535292e9e1a6a2457fd4599#87abf450404865dcb535292e9e1a6a2457fd4599" dependencies = [ "bitvec", "embedded-graphics-core", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2424867..246db51 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -70,7 +70,8 @@ defmt = { version = "0.3", optional = true } defmt-rtt = "0.4.2" embedded-sdmmc = { version = "0.9", default-features = false } -st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", rev = "87abf450404865dcb535292e9e1a6a2457fd4599" } # async branch +# st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", rev = "87abf450404865dcb535292e9e1a6a2457fd4599" } # async branch +st7365p-lcd = { path = "../../ST7365P-lcd-rs" } # async branch embedded-graphics = { version = "0.8.1" } embedded-text = "0.7.2" embedded-layout = "0.4.2" diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 889a0f3..40e5599 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -3,7 +3,6 @@ use core::pin::Pin; use abi_sys::{DrawIterAbi, GetKeyAbi, Pixel, PrintAbi}; use alloc::boxed::Box; use defmt::info; -use embassy_futures::block_on; use embedded_graphics::{ Drawable, draw_target::DrawTarget, @@ -13,7 +12,7 @@ use embedded_graphics::{ }; use shared::keyboard::KeyEvent; -use crate::{KEY_CACHE, display::FRAMEBUFFER}; +use crate::{KEY_CACHE, display::access_framebuffer_blocking}; // ensure the abi and the kernel fn signatures are the same const _: PrintAbi = print; @@ -26,17 +25,15 @@ pub extern "Rust" fn print(msg: &str) { // TODO: maybe return result pub extern "Rust" fn draw_iter(pixels: &[Pixel]) { - for _ in 0..10 { - if let Some(mut framebuffer) = FRAMEBUFFER.try_lock().ok() { - for _ in 0..10 { - // kernel takes() framebuffer - if let Some(framebuffer) = framebuffer.as_mut() { - framebuffer.draw_iter(pixels.iter().copied()).unwrap(); - } - break; - } + loop { + if access_framebuffer_blocking(|fb| { + fb.draw_iter(pixels.iter().copied()).unwrap(); + }) + .is_ok() + { break; } + cortex_m::asm::nop(); } } diff --git a/kernel/src/display.rs b/kernel/src/display.rs index 7f27811..5047a38 100644 --- a/kernel/src/display.rs +++ b/kernel/src/display.rs @@ -21,7 +21,24 @@ pub const SCREEN_HEIGHT: usize = 320; type FB = FrameBuffer; static FRAMEBUFFER_CELL: StaticCell = StaticCell::new(); -pub static FRAMEBUFFER: Mutex> = Mutex::new(None); +static FRAMEBUFFER: Mutex> = Mutex::new(None); + +pub fn access_framebuffer_blocking(mut access: impl FnMut(&mut FB)) -> Result<(), ()> { + let mut guard = FRAMEBUFFER.try_lock().ok().ok_or(())?; + let fb = guard.as_mut().ok_or(())?; + access(fb); + Ok(()) +} + +pub async fn access_framebuffer(mut access: impl FnMut(&mut FB)) -> Result<(), ()> { + let mut guard = FRAMEBUFFER.lock().await; + let fb: Option<&mut &'static mut FB> = guard.as_mut(); + if let Some(fb) = fb { + access(&mut *fb); + return Ok(()); + } + Err(()) +} pub async fn init_display( spi: Spi<'static, SPI1, Async>, @@ -38,28 +55,22 @@ pub async fn init_display( true, Delay, ); - let framebuffer = FRAMEBUFFER_CELL.init(FrameBuffer::new()); + display.init().await.unwrap(); display.set_custom_orientation(0x40).await.unwrap(); - framebuffer.draw(&mut display).await.unwrap(); + let mut framebuffer = FRAMEBUFFER_CELL.init(FrameBuffer::new()); + display.draw(&mut framebuffer).await.unwrap(); display.set_on().await.unwrap(); FRAMEBUFFER.lock().await.replace(framebuffer); display } +static DISPLAYREF: StaticCell = StaticCell::new(); + pub async fn display_handler(mut display: DISPLAY) { - loop { - let fb: &mut FB = { - let mut guard = FRAMEBUFFER.lock().await; - guard.take().unwrap() // take ownership - }; // guard dropped - - fb.partial_draw_batched(&mut display).await.unwrap(); - - // Put it back - FRAMEBUFFER.lock().await.replace(fb); - - Timer::after_millis(32).await; // 30 fps + let mut guard = FRAMEBUFFER.lock().await; + if let Some(fb) = guard.as_mut() { + display.partial_draw_batched(fb).await.unwrap(); } } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index e6083dc..d4e2685 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -17,11 +17,8 @@ mod ui; mod usb; mod utils; -use core::sync::atomic::Ordering; - use crate::{ - display::{display_handler, init_display}, - elf::load_binary, + display::{access_framebuffer, display_handler, init_display}, peripherals::{ conf_peripherals, keyboard::{KeyCode, KeyState, read_keyboard_fifo}, @@ -30,11 +27,7 @@ use crate::{ ui::{SELECTIONS, ui_handler}, usb::usb_handler, }; -use abi_sys::EntryFn; -use alloc::vec::Vec; - -use {defmt_rtt as _, panic_probe as _}; - +use abi_sys::{EntryFn, Rgb565, RgbColor}; use defmt::unwrap; use embassy_executor::{Executor, Spawner}; use embassy_futures::join::{join, join3, join4, join5}; @@ -49,14 +42,18 @@ use embassy_rp::{ spi::{self, Spi}, usb as embassy_rp_usb, }; -use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, mutex::Mutex}; +use embassy_sync::{ + blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, mutex::Mutex, signal::Signal, +}; use embassy_time::{Delay, Timer}; +use embedded_graphics::draw_target::DrawTarget; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_sdmmc::SdCard as SdmmcSdCard; use heapless::spsc::Queue; use shared::keyboard::KeyEvent; use static_cell::StaticCell; use talc::*; +use {defmt_rtt as _, panic_probe as _}; embassy_rp::bind_interrupts!(struct Irqs { I2C1_IRQ => i2c::InterruptHandler; @@ -75,7 +72,9 @@ static ALLOCATOR: Talck, ClaimOnOom> = .lock(); static TASK_STATE: Mutex = Mutex::new(TaskState::Ui); +static TASK_STATE_CHANGED: Signal = Signal::new(); +#[derive(Copy, Clone)] enum TaskState { Ui, Kernel, @@ -131,20 +130,29 @@ async fn userland_task() { let recv = BINARY_CH.receiver(); loop { let entry = recv.receive().await; + defmt::info!("got bin"); // disable kernel ui { let mut state = TASK_STATE.lock().await; *state = TaskState::Kernel; + TASK_STATE_CHANGED.signal(()); } - defmt::info!("Executing Binary"); + access_framebuffer(|fb| { + fb.clear(Rgb565::BLACK).unwrap(); + }) + .await + .unwrap(); + + defmt::info!("running entry"); entry().await; // enable kernel ui { let mut state = TASK_STATE.lock().await; *state = TaskState::Ui; + TASK_STATE_CHANGED.signal(()); } } } diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs index 3485bb0..fd17249 100644 --- a/kernel/src/ui.rs +++ b/kernel/src/ui.rs @@ -1,6 +1,6 @@ use crate::{ BINARY_CH, TASK_STATE, TaskState, - display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH}, + display::{SCREEN_HEIGHT, SCREEN_WIDTH, access_framebuffer}, elf::load_binary, format, peripherals::keyboard, @@ -47,36 +47,51 @@ use shared::keyboard::{KeyCode, KeyState}; pub static SELECTIONS: Mutex = Mutex::new(SelectionList::new()); +pub async fn run_selected() { + info!("Getting selections lock"); + let selections = SELECTIONS.lock().await; + info!("Got selections lock"); + let selection = selections.selections[selections.current_selection as usize - 1].clone(); + + let entry = unsafe { load_binary(&selection.short_name).await.unwrap() }; + info!("loaded binary"); + BINARY_CH.send(entry).await; + info!("sent bin"); +} + pub async fn ui_handler() { loop { - if let TaskState::Ui = *TASK_STATE.lock().await { + let state = *TASK_STATE.lock().await; + if let TaskState::Ui = state { + let mut redraw = false; + if let Some(event) = keyboard::read_keyboard_fifo().await { - if let KeyState::Pressed = event.state { + if event.state == KeyState::Pressed { match event.key { KeyCode::JoyUp => { let mut selections = SELECTIONS.lock().await; selections.up(); + redraw = true; } KeyCode::JoyDown => { let mut selections = SELECTIONS.lock().await; selections.down(); + redraw = true; } - KeyCode::Enter | KeyCode::JoyRight => { - let selections = SELECTIONS.lock().await; - let selection = selections.selections - [selections.current_selection as usize - 1] - .clone(); - - let entry = - unsafe { load_binary(&selection.short_name).await.unwrap() }; - BINARY_CH.send(entry).await; - } - _ => (), + KeyCode::Enter | KeyCode::JoyRight => run_selected().await, + _ => {} } } } - draw_selection().await; + { + let mut selections = SELECTIONS.lock().await; + redraw |= selections.take_changed(); + } + + if redraw { + draw_selection().await; + } } } } @@ -87,8 +102,8 @@ async fn draw_selection() { guard.selections.clone() }; - let mut fb_lock = FRAMEBUFFER.lock().await; - if let Some(fb) = fb_lock.as_mut() { + loop { + if access_framebuffer(|fb|{ let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE); let display_area = fb.bounding_box(); @@ -104,13 +119,13 @@ async fn draw_selection() { ), text_style, ) - .draw(*fb) + .draw(fb) .unwrap(); } else { let mut file_names = file_names.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(*fb).unwrap(); + Point::zero(), text_style).draw(fb).unwrap(); return; }; @@ -129,16 +144,24 @@ async fn draw_selection() { .with_alignment(horizontal::Center) .arrange() .align_to(&display_area, horizontal::Center, vertical::Center) - .draw(*fb) + .draw(fb) .unwrap(); }; } + ).await.is_ok() { + break; + } + + defmt::warn!("Failed to draw selection: framebuffer unavailable"); + Timer::after_micros(10).await; + } } #[derive(Clone)] pub struct SelectionList { current_selection: u16, pub selections: Vec, + has_changed: bool, } impl SelectionList { @@ -146,6 +169,7 @@ impl SelectionList { Self { selections: Vec::new(), current_selection: 0, + has_changed: true, } } @@ -164,4 +188,10 @@ impl SelectionList { self.current_selection -= 1 } } + + pub fn take_changed(&mut self) -> bool { + let changed = self.has_changed; + self.has_changed = false; + changed + } } diff --git a/user-apps/calculator/src/main.rs b/user-apps/calculator/src/main.rs index 337533c..aec987d 100644 --- a/user-apps/calculator/src/main.rs +++ b/user-apps/calculator/src/main.rs @@ -27,29 +27,29 @@ pub async fn main() { let mut text = vec!['H', 'E', 'L', 'L', 'O']; - loop { - Text::with_alignment( - &text.iter().cloned().collect::(), - display.bounding_box().center() + Point::new(0, 15), - character_style, - Alignment::Center, - ) - .draw(&mut display) - .unwrap(); + // loop { + Text::with_alignment( + &text.iter().cloned().collect::(), + display.bounding_box().center() + Point::new(0, 15), + character_style, + Alignment::Center, + ) + .draw(&mut display) + .unwrap(); - if let Some(event) = get_key() { - print("User got event"); - match event.key { - KeyCode::Char(ch) => { - text.push(ch); - } - KeyCode::Backspace => { - text.pop(); - } - _ => (), + if let Some(event) = get_key() { + print("User got event"); + match event.key { + KeyCode::Char(ch) => { + text.push(ch); } + KeyCode::Backspace => { + text.pop(); + } + _ => (), } } + // } } #[unsafe(no_mangle)]