This commit is contained in:
2025-09-18 10:57:08 -06:00
parent dadde9048d
commit 177c15e9cc
6 changed files with 99 additions and 34 deletions

1
Cargo.lock generated
View File

@@ -232,7 +232,6 @@ version = "0.1.0"
dependencies = [ dependencies = [
"abi", "abi",
"embedded-graphics", "embedded-graphics",
"kolibri-embedded-gui",
] ]
[[package]] [[package]]

View File

@@ -11,7 +11,7 @@ pub use embedded_graphics::{
}; };
use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
pub type EntryFn = fn() -> Pin<Box<dyn Future<Output = ()>>>; pub type EntryFn = fn();
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
#[unsafe(link_section = ".user_reloc")] #[unsafe(link_section = ".user_reloc")]

View File

@@ -39,6 +39,7 @@ use defmt::unwrap;
use embassy_executor::{Executor, Spawner}; use embassy_executor::{Executor, Spawner};
use embassy_futures::{ use embassy_futures::{
join::{join, join3, join5}, join::{join, join3, join5},
select::select,
yield_now, yield_now,
}; };
use embassy_rp::{ use embassy_rp::{
@@ -81,6 +82,7 @@ static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
.lock(); .lock();
static ENABLE_UI: AtomicBool = AtomicBool::new(true); static ENABLE_UI: AtomicBool = AtomicBool::new(true);
static UI_CHANGE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
#[embassy_executor::main] #[embassy_executor::main]
async fn main(spawner: Spawner) { async fn main(spawner: Spawner) {
@@ -137,16 +139,18 @@ async fn userland_task() {
// disable kernel ui // disable kernel ui
{ {
ENABLE_UI.store(false, Ordering::Release); ENABLE_UI.store(false, Ordering::Release);
UI_CHANGE.signal(());
// clear_fb(); // clear_fb();
MSC_SHUTDOWN.signal(()); MSC_SHUTDOWN.signal(());
} }
defmt::info!("Executing Binary"); defmt::info!("Executing Binary");
entry().await; entry();
// enable kernel ui // enable kernel ui
{ {
ENABLE_UI.store(true, Ordering::Release); ENABLE_UI.store(true, Ordering::Release);
UI_CHANGE.signal(());
// clear_fb(); // clear_fb();
} }
} }
@@ -230,19 +234,18 @@ async fn kernel_task(
setup_sd(sd).await; setup_sd(sd).await;
let usb = embassy_rp_usb::Driver::new(usb, Irqs); let usb = embassy_rp_usb::Driver::new(usb, Irqs);
spawner.spawn(usb_handler(usb)).unwrap(); // spawner.spawn(usb_handler(usb)).unwrap();
spawner.spawn(key_handler()).unwrap();
loop { loop {
if ENABLE_UI.load(Ordering::Relaxed) { let ui_enabled = ENABLE_UI.load(Ordering::Relaxed);
if ui_enabled {
let ui_fut = ui_handler(); let ui_fut = ui_handler();
let binary_search_fut = prog_search_handler(); let binary_search_fut = prog_search_handler();
join(ui_fut, binary_search_fut).await; select(join(ui_fut, binary_search_fut), UI_CHANGE.wait()).await;
} else {
select(key_handler(), UI_CHANGE.wait()).await;
} }
yield_now().await;
} }
} }
@@ -267,7 +270,6 @@ async fn prog_search_handler() {
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new(); static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
#[embassy_executor::task]
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 {

View File

@@ -1,13 +1,23 @@
use core::sync::atomic::Ordering;
use crate::{ use crate::{
BINARY_CH, display::FRAMEBUFFER, elf::load_binary, peripherals::keyboard, storage::FileName, BINARY_CH, display::FRAMEBUFFER, elf::load_binary, peripherals::keyboard, storage::FileName,
usb::USB_ACTIVE,
}; };
use alloc::vec::Vec; use alloc::{str::FromStr, string::String, vec::Vec};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex}; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
use embedded_graphics::mono_font::ascii; use embedded_graphics::{
use kolibri_embedded_gui::{label::Label, style::medsize_rgb565_style, ui::Ui}; Drawable,
mono_font::{MonoTextStyle, ascii::FONT_9X15},
pixelcolor::Rgb565,
prelude::{Dimensions, Point, RgbColor, Size},
primitives::Rectangle,
text::Text,
};
use embedded_layout::{
align::{horizontal, vertical},
layout::linear::LinearLayout,
object_chain::Chain,
prelude::*,
};
use embedded_text::TextBox;
use shared::keyboard::{KeyCode, KeyState}; use shared::keyboard::{KeyCode, KeyState};
pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> = pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
@@ -47,20 +57,54 @@ pub async fn ui_handler() {
} }
async fn draw_selection() { async fn draw_selection() {
const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory";
let file_names: Vec<FileName> = { let file_names: Vec<FileName> = {
let guard = SELECTIONS.lock().await; let guard = SELECTIONS.lock().await;
guard.selections.clone() guard.selections.clone()
}; };
let mut ui = Ui::new_fullscreen(unsafe { &mut FRAMEBUFFER }, medsize_rgb565_style()); let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE);
let display_area = unsafe { FRAMEBUFFER.bounding_box() };
const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory";
let no_bins = String::from_str(NO_BINS).unwrap();
if file_names.is_empty() { if file_names.is_empty() {
ui.add(Label::new(NO_BINS).with_font(ascii::FONT_10X20)); TextBox::new(
&no_bins,
Rectangle::new(
Point::new(25, 25),
Size::new(display_area.size.width - 50, display_area.size.width - 50),
),
text_style,
)
.draw(unsafe { &mut FRAMEBUFFER })
.unwrap();
} else { } else {
for file in file_names { let mut file_names = file_names.iter();
ui.add(Label::new(&file.long_name).with_font(ascii::FONT_10X20)); let Some(first) = file_names.next() else {
} Text::new(NO_BINS, Point::zero(), text_style)
.draw(unsafe { &mut FRAMEBUFFER })
.unwrap();
return;
};
let chain = Chain::new(Text::new(&first.long_name, Point::zero(), text_style));
// for _ in 0..file_names.len() {
// let chain = chain.append(Text::new(
// file_names.next().unwrap(),
// Point::zero(),
// text_style,
// ));
// }
LinearLayout::vertical(chain)
.with_alignment(horizontal::Center)
.arrange()
.align_to(&display_area, horizontal::Center, vertical::Center)
.draw(unsafe { &mut FRAMEBUFFER })
.unwrap();
} }
let mut sel = SELECTIONS.lock().await; let mut sel = SELECTIONS.lock().await;

View File

@@ -6,4 +6,3 @@ edition = "2024"
[dependencies] [dependencies]
abi = { path = "../../abi" } abi = { path = "../../abi" }
embedded-graphics = "0.8.1" embedded-graphics = "0.8.1"
kolibri-embedded-gui = "0.1.0"

View File

@@ -3,7 +3,7 @@
extern crate alloc; extern crate alloc;
use abi::{KeyCode, display::Display, get_key, print, sleep}; use abi::{KeyCode, display::Display, get_key, print, sleep};
use alloc::{boxed::Box, string::String, vec}; use alloc::{boxed::Box, format, string::String, vec};
use core::{panic::PanicInfo, pin::Pin}; use core::{panic::PanicInfo, pin::Pin};
use embedded_graphics::{ use embedded_graphics::{
Drawable, Drawable,
@@ -17,27 +17,48 @@ use embedded_graphics::{
primitives::{PrimitiveStyle, Rectangle}, primitives::{PrimitiveStyle, Rectangle},
text::{Alignment, Text}, text::{Alignment, Text},
}; };
use kolibri_embedded_gui::{label::Label, style::medsize_rgb565_style, ui::Ui};
#[panic_handler] #[panic_handler]
fn panic(_info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
print(&format!(
"user panic: {} @ {:?}",
info.message(),
info.location(),
));
loop {} loop {}
} }
pub async fn main() { pub fn main() {
print("Starting Async Calculator app"); print("Starting Async Calculator app");
let mut display = Display; let mut display = Display;
let character_style = MonoTextStyle::new(&FONT_6X10, Rgb565::RED);
let mut text = vec!['T', 'y', 'p', 'e']; let mut text = vec!['T', 'y', 'p', 'e'];
let mut dirty = true; let mut dirty = true;
let mut last_area: Option<Rectangle> = None;
loop { loop {
if dirty { if dirty {
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style()); if let Some(area) = last_area {
let text = text.iter().cloned().collect::<String>(); Rectangle::new(area.top_left, area.size)
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(&mut display)
.unwrap();
}
let text = text.iter().cloned().collect::<String>();
let aligned_text = Text::with_alignment(
&text,
display.bounding_box().center() + Point::new(0, 15),
character_style,
Alignment::Center,
);
last_area = Some(aligned_text.bounding_box());
aligned_text.draw(&mut display).unwrap();
// ui.clear_background();
ui.add(Label::new(&text).with_font(ascii::FONT_10X20));
dirty = false; dirty = false;
} }
@@ -61,6 +82,6 @@ pub async fn main() {
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub extern "Rust" fn _start() -> Pin<Box<dyn Future<Output = ()>>> { pub extern "Rust" fn _start() {
Box::pin(async { main().await }) main()
} }