mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 07:45:28 +00:00
working on binary selection
This commit is contained in:
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -893,6 +893,17 @@ dependencies = [
|
|||||||
"embedded-storage",
|
"embedded-storage",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-text"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "005680edc0d075af5e02d5788ca291737bd9aba7fc404ae031cc9dfa715e5f7d"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"embedded-graphics",
|
||||||
|
"object-chain",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ena"
|
name = "ena"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
@@ -1214,6 +1225,7 @@ dependencies = [
|
|||||||
"embedded-hal-bus",
|
"embedded-hal-bus",
|
||||||
"embedded-layout",
|
"embedded-layout",
|
||||||
"embedded-sdmmc",
|
"embedded-sdmmc",
|
||||||
|
"embedded-text",
|
||||||
"goblin",
|
"goblin",
|
||||||
"heapless",
|
"heapless",
|
||||||
"num_enum 0.7.4",
|
"num_enum 0.7.4",
|
||||||
@@ -1417,6 +1429,12 @@ dependencies = [
|
|||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object-chain"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41af26158b0f5530f7b79955006c2727cd23d0d8e7c3109dc316db0a919784dd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ defmt-rtt = "0.4.2"
|
|||||||
embedded-sdmmc = { version = "0.9", default-features = false }
|
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
|
||||||
embedded-graphics = { version = "0.8.1" }
|
embedded-graphics = { version = "0.8.1" }
|
||||||
|
embedded-text = "0.7.2"
|
||||||
embedded-layout = "0.4.2"
|
embedded-layout = "0.4.2"
|
||||||
|
|
||||||
static_cell = "2.1.1"
|
static_cell = "2.1.1"
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ mod ui;
|
|||||||
mod usb;
|
mod usb;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::{display_handler, init_display},
|
display::{display_handler, init_display},
|
||||||
elf::load_binary,
|
elf::load_binary,
|
||||||
@@ -25,8 +27,8 @@ use crate::{
|
|||||||
keyboard::{KeyCode, KeyState, read_keyboard_fifo},
|
keyboard::{KeyCode, KeyState, read_keyboard_fifo},
|
||||||
},
|
},
|
||||||
storage::{SDCARD, SdCard},
|
storage::{SDCARD, SdCard},
|
||||||
ui::ui_handler,
|
ui::{SELECTIONS, ui_handler},
|
||||||
usb::{ENABLE_SCSI, usb_handler},
|
usb::usb_handler,
|
||||||
};
|
};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
@@ -34,7 +36,7 @@ use {defmt_rtt as _, panic_probe as _};
|
|||||||
|
|
||||||
use defmt::unwrap;
|
use defmt::unwrap;
|
||||||
use embassy_executor::{Executor, Spawner};
|
use embassy_executor::{Executor, Spawner};
|
||||||
use embassy_futures::join::{join, join3, join4};
|
use embassy_futures::join::{join, join3, join4, join5};
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
gpio::{Input, Level, Output, Pull},
|
gpio::{Input, Level, Output, Pull},
|
||||||
i2c::{self, I2c},
|
i2c::{self, I2c},
|
||||||
@@ -188,6 +190,25 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
|
|||||||
|
|
||||||
let ui_fut = ui_handler();
|
let ui_fut = ui_handler();
|
||||||
|
|
||||||
|
let binary_search_fut = async {
|
||||||
|
loop {
|
||||||
|
{
|
||||||
|
let mut guard = SDCARD.get().lock().await;
|
||||||
|
|
||||||
|
if let Some(sd) = guard.as_mut() {
|
||||||
|
let files = sd.list_files_by_extension(".bin").unwrap();
|
||||||
|
let mut select = SELECTIONS.lock().await;
|
||||||
|
|
||||||
|
if select.selections != files {
|
||||||
|
select.selections = files;
|
||||||
|
select.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timer::after_secs(5).await;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut config = spi::Config::default();
|
let mut config = spi::Config::default();
|
||||||
config.frequency = 400_000;
|
config.frequency = 400_000;
|
||||||
@@ -213,8 +234,7 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ENABLE_SCSI.store(true, core::sync::atomic::Ordering::Relaxed);
|
join4(display_fut, ui_fut, binary_search_fut, key_abi_fut).await;
|
||||||
join4(usb_fut, display_fut, key_abi_fut, ui_fut).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use core::str::FromStr;
|
||||||
use embassy_rp::gpio::{Input, Output};
|
use embassy_rp::gpio::{Input, Output};
|
||||||
use embassy_rp::peripherals::SPI0;
|
use embassy_rp::peripherals::SPI0;
|
||||||
use embassy_rp::spi::{Blocking, Spi};
|
use embassy_rp::spi::{Blocking, Spi};
|
||||||
@@ -6,6 +8,7 @@ use embassy_sync::lazy_lock::LazyLock;
|
|||||||
use embassy_sync::mutex::Mutex;
|
use embassy_sync::mutex::Mutex;
|
||||||
use embassy_time::Delay;
|
use embassy_time::Delay;
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
|
use embedded_sdmmc::LfnBuffer;
|
||||||
use embedded_sdmmc::{
|
use embedded_sdmmc::{
|
||||||
Block, BlockCount, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource,
|
Block, BlockCount, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource,
|
||||||
Timestamp, Volume, VolumeIdx, VolumeManager, sdcard::Error,
|
Timestamp, Volume, VolumeIdx, VolumeManager, sdcard::Error,
|
||||||
@@ -57,13 +60,6 @@ impl SdCard {
|
|||||||
self.det.is_low()
|
self.det.is_low()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_volume(&mut self) -> Result<Vol<'_>, ()> {
|
|
||||||
if self.is_attached() {
|
|
||||||
return Ok(self.volume_mgr.open_volume(VolumeIdx(0)).map_err(|_| ())?);
|
|
||||||
}
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(&self) -> u64 {
|
pub fn size(&self) -> u64 {
|
||||||
let mut result = 0;
|
let mut result = 0;
|
||||||
|
|
||||||
@@ -103,4 +99,38 @@ impl SdCard {
|
|||||||
});
|
});
|
||||||
res.map_err(|_| ())
|
res.map_err(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn access_root_dir(&mut self, mut access: impl FnMut(Dir)) {
|
||||||
|
let volume0 = self.volume_mgr.open_volume(VolumeIdx(0)).unwrap();
|
||||||
|
let root_dir = volume0.open_root_dir().unwrap();
|
||||||
|
|
||||||
|
access(root_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a Vec of file names (long format) that match the given extension (e.g., "BIN")
|
||||||
|
pub fn list_files_by_extension(&mut self, ext: &str) -> Result<Vec<String>, ()> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
// Only proceed if card is inserted
|
||||||
|
if !self.is_attached() {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lfn_storage = [0; 50];
|
||||||
|
let mut lfn_buffer = LfnBuffer::new(&mut lfn_storage);
|
||||||
|
|
||||||
|
self.access_root_dir(|dir| {
|
||||||
|
dir.iterate_dir_lfn(&mut lfn_buffer, |_entry, name| {
|
||||||
|
if let Some(name) = name {
|
||||||
|
let name = String::from_str(name).unwrap();
|
||||||
|
if name.contains(ext) {
|
||||||
|
result.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ use crate::{
|
|||||||
display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH},
|
display::{FRAMEBUFFER, SCREEN_HEIGHT, SCREEN_WIDTH},
|
||||||
format,
|
format,
|
||||||
peripherals::keyboard,
|
peripherals::keyboard,
|
||||||
|
usb::RESTART_USB,
|
||||||
};
|
};
|
||||||
use alloc::{string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
use core::fmt::Debug;
|
use core::{fmt::Debug, str::FromStr, sync::atomic::Ordering};
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
gpio::{Level, Output},
|
gpio::{Level, Output},
|
||||||
@@ -23,10 +24,10 @@ use embedded_graphics::{
|
|||||||
draw_target::DrawTarget,
|
draw_target::DrawTarget,
|
||||||
mono_font::{
|
mono_font::{
|
||||||
MonoTextStyle,
|
MonoTextStyle,
|
||||||
ascii::{FONT_6X10, FONT_9X15, FONT_10X20},
|
ascii::{FONT_6X9, FONT_6X10, FONT_9X15, FONT_10X20},
|
||||||
},
|
},
|
||||||
pixelcolor::Rgb565,
|
pixelcolor::Rgb565,
|
||||||
prelude::{Dimensions, Point, RgbColor, Size},
|
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
|
||||||
primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
|
primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
|
||||||
text::Text,
|
text::Text,
|
||||||
};
|
};
|
||||||
@@ -38,22 +39,29 @@ use embedded_layout::{
|
|||||||
object_chain::Chain,
|
object_chain::Chain,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use shared::keyboard::KeyCode;
|
use embedded_text::TextBox;
|
||||||
|
use shared::keyboard::{KeyCode, KeyState};
|
||||||
|
|
||||||
static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
|
pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
|
||||||
Mutex::new(SelectionList::new(Vec::new()));
|
Mutex::new(SelectionList::new(Vec::new()));
|
||||||
|
|
||||||
pub async fn ui_handler() {
|
pub async fn ui_handler() {
|
||||||
loop {
|
loop {
|
||||||
let state = TASK_STATE.lock().await;
|
if let TaskState::Ui = *TASK_STATE.lock().await {
|
||||||
if let TaskState::Ui = *state {
|
|
||||||
let mut selections = SELECTIONS.lock().await;
|
|
||||||
if let Some(event) = keyboard::read_keyboard_fifo().await {
|
if let Some(event) = keyboard::read_keyboard_fifo().await {
|
||||||
match event.key {
|
if let KeyState::Pressed = event.state {
|
||||||
KeyCode::JoyUp => selections.up(),
|
match event.key {
|
||||||
KeyCode::JoyDown => selections.down(),
|
KeyCode::JoyUp => {
|
||||||
KeyCode::Enter | KeyCode::JoyRight => (),
|
let mut selections = SELECTIONS.lock().await;
|
||||||
_ => (),
|
selections.up();
|
||||||
|
}
|
||||||
|
KeyCode::JoyDown => {
|
||||||
|
let mut selections = SELECTIONS.lock().await;
|
||||||
|
selections.down();
|
||||||
|
}
|
||||||
|
KeyCode::Enter | KeyCode::JoyRight => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,38 +71,62 @@ pub async fn ui_handler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn draw_selection() {
|
async fn draw_selection() {
|
||||||
|
let file_names: Vec<String> = {
|
||||||
|
let guard = SELECTIONS.lock().await;
|
||||||
|
guard.selections.clone()
|
||||||
|
};
|
||||||
|
|
||||||
let mut fb_lock = FRAMEBUFFER.lock().await;
|
let mut fb_lock = FRAMEBUFFER.lock().await;
|
||||||
if let Some(fb) = fb_lock.as_mut() {
|
if let Some(fb) = fb_lock.as_mut() {
|
||||||
info!("UIINg");
|
|
||||||
let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE);
|
let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE);
|
||||||
|
let display_area = fb.bounding_box();
|
||||||
|
|
||||||
let guard = SELECTIONS.lock().await;
|
const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory";
|
||||||
let mut file_names = guard.selections.iter();
|
let no_bins = String::from_str(NO_BINS).unwrap();
|
||||||
|
|
||||||
let Some(first) = file_names.next() else {
|
if file_names.is_empty() {
|
||||||
Text::new("No Programs found on SD Card\nEnsure programs end with '.bin',\nand are located in the root directory",
|
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(*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;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let chain = Chain::new(Text::new(first, Point::zero(), text_style));
|
let chain = Chain::new(Text::new(first, Point::zero(), text_style));
|
||||||
|
|
||||||
|
// for _ in 0..file_names.len() {
|
||||||
|
// let chain = chain.append(Text::new(
|
||||||
|
// file_names.next().unwrap(),
|
||||||
|
// Point::zero(),
|
||||||
|
// text_style,
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
for _ in 0..10 {
|
|
||||||
LinearLayout::vertical(chain)
|
LinearLayout::vertical(chain)
|
||||||
.with_alignment(horizontal::Center)
|
.with_alignment(horizontal::Center)
|
||||||
.arrange()
|
.arrange()
|
||||||
.align_to(&fb.bounding_box(), horizontal::Center, vertical::Center)
|
.align_to(&display_area, horizontal::Center, vertical::Center)
|
||||||
.draw(*fb)
|
.draw(*fb)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
break;
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SelectionList {
|
pub struct SelectionList {
|
||||||
current_selection: u16,
|
current_selection: u16,
|
||||||
selections: Vec<String>,
|
pub selections: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectionList {
|
impl SelectionList {
|
||||||
@@ -105,13 +137,17 @@ impl SelectionList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn down(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
|
self.current_selection = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(&mut self) {
|
||||||
if self.current_selection + 1 < self.selections.len() as u16 {
|
if self.current_selection + 1 < self.selections.len() as u16 {
|
||||||
self.current_selection += 1
|
self.current_selection += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn up(&mut self) {
|
fn up(&mut self) {
|
||||||
if self.current_selection > self.selections.len() as u16 {
|
if self.current_selection > self.selections.len() as u16 {
|
||||||
self.current_selection -= 1
|
self.current_selection -= 1
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user