mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
WIP
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1941,7 +1941,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "st7365p-lcd"
|
name = "st7365p-lcd"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "git+https://github.com/legitcamper/st7365p-lcd-rs?rev=87abf450404865dcb535292e9e1a6a2457fd4599#87abf450404865dcb535292e9e1a6a2457fd4599"
|
source = "git+https://github.com/legitcamper/st7365p-lcd-rs?rev=2a484aaab5f6b9824cc813fe4ae087250c9e39c1#2a484aaab5f6b9824cc813fe4ae087250c9e39c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"embedded-graphics-core",
|
"embedded-graphics-core",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use abi_sys::draw_iter;
|
use abi_sys::draw_iter;
|
||||||
pub use abi_sys::{get_key, print};
|
pub use abi_sys::{get_key, print, sleep};
|
||||||
pub use embassy_time;
|
pub use embassy_time;
|
||||||
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||||
use talc::*;
|
use talc::*;
|
||||||
|
|||||||
@@ -21,12 +21,13 @@ pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable::
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum CallAbiTable {
|
pub enum CallAbiTable {
|
||||||
Print = 0,
|
Print = 0,
|
||||||
DrawIter = 1,
|
Sleep = 1,
|
||||||
GetKey = 2,
|
DrawIter = 2,
|
||||||
|
GetKey = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallAbiTable {
|
impl CallAbiTable {
|
||||||
pub const COUNT: usize = 3;
|
pub const COUNT: usize = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PrintAbi = extern "Rust" fn(msg: &str);
|
pub type PrintAbi = extern "Rust" fn(msg: &str);
|
||||||
@@ -39,6 +40,16 @@ pub fn print(msg: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type SleepAbi = extern "Rust" fn(ticks: u64);
|
||||||
|
|
||||||
|
pub fn sleep(ticks: u64) {
|
||||||
|
unsafe {
|
||||||
|
let ptr = CALL_ABI_TABLE[CallAbiTable::Print as usize];
|
||||||
|
let f: SleepAbi = core::mem::transmute(ptr);
|
||||||
|
f(ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]);
|
pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]);
|
||||||
|
|
||||||
pub fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
pub fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
defmt-rtt = "0.4.2"
|
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 = "2a484aaab5f6b9824cc813fe4ae087250c9e39c1" } # async branch
|
||||||
embedded-graphics = { version = "0.8.1" }
|
embedded-graphics = { version = "0.8.1" }
|
||||||
embedded-text = "0.7.2"
|
embedded-text = "0.7.2"
|
||||||
embedded-layout = "0.4.2"
|
embedded-layout = "0.4.2"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use core::pin::Pin;
|
use core::{pin::Pin, time::Duration};
|
||||||
|
|
||||||
use abi_sys::{DrawIterAbi, GetKeyAbi, Pixel, PrintAbi};
|
use abi_sys::{DrawIterAbi, GetKeyAbi, Pixel, PrintAbi, SleepAbi};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_futures::block_on;
|
use embassy_futures::block_on;
|
||||||
|
use embassy_time::Timer;
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
Drawable,
|
Drawable,
|
||||||
draw_target::DrawTarget,
|
draw_target::DrawTarget,
|
||||||
@@ -17,6 +18,7 @@ use crate::{KEY_CACHE, display::FRAMEBUFFER};
|
|||||||
|
|
||||||
// ensure the abi and the kernel fn signatures are the same
|
// ensure the abi and the kernel fn signatures are the same
|
||||||
const _: PrintAbi = print;
|
const _: PrintAbi = print;
|
||||||
|
const _: SleepAbi = sleep;
|
||||||
const _: DrawIterAbi = draw_iter;
|
const _: DrawIterAbi = draw_iter;
|
||||||
const _: GetKeyAbi = get_key;
|
const _: GetKeyAbi = get_key;
|
||||||
|
|
||||||
@@ -24,20 +26,23 @@ pub extern "Rust" fn print(msg: &str) {
|
|||||||
defmt::info!("{:?}", msg);
|
defmt::info!("{:?}", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub extern "Rust" fn sleep(ticks: u64) {
|
||||||
|
for _ in 0..ticks {
|
||||||
|
for _ in 0..100 {
|
||||||
|
cortex_m::asm::nop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: maybe return result
|
// TODO: maybe return result
|
||||||
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
||||||
for _ in 0..10 {
|
loop {
|
||||||
if let Some(mut framebuffer) = FRAMEBUFFER.try_lock().ok() {
|
let fb = FRAMEBUFFER.get().try_lock();
|
||||||
for _ in 0..10 {
|
if let Ok(mut fb) = fb {
|
||||||
// kernel takes() framebuffer
|
fb.draw_iter(pixels.iter().copied()).unwrap();
|
||||||
if let Some(framebuffer) = framebuffer.as_mut() {
|
return;
|
||||||
framebuffer.draw_iter(pixels.iter().copied()).unwrap();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
cortex_m::asm::nop();
|
sleep(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,16 @@ use embassy_rp::{
|
|||||||
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
|
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
|
||||||
spi::{Async, Spi},
|
spi::{Async, Spi},
|
||||||
};
|
};
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
use embassy_sync::{
|
||||||
|
blocking_mutex::raw::CriticalSectionRawMutex, lazy_lock::LazyLock, mutex::Mutex,
|
||||||
|
};
|
||||||
use embassy_time::{Delay, Timer};
|
use embassy_time::{Delay, Timer};
|
||||||
|
use embedded_graphics::{
|
||||||
|
draw_target::DrawTarget,
|
||||||
|
pixelcolor::{Rgb565, RgbColor},
|
||||||
|
};
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use st7365p_lcd::{FrameBuffer, ST7365P};
|
use st7365p_lcd::{FrameBuffer, ST7365P};
|
||||||
use static_cell::StaticCell;
|
|
||||||
|
|
||||||
type DISPLAY = ST7365P<
|
type DISPLAY = ST7365P<
|
||||||
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
|
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
|
||||||
@@ -20,8 +25,8 @@ pub const SCREEN_WIDTH: usize = 320;
|
|||||||
pub const SCREEN_HEIGHT: usize = 320;
|
pub const SCREEN_HEIGHT: usize = 320;
|
||||||
|
|
||||||
type FB = FrameBuffer<SCREEN_WIDTH, SCREEN_HEIGHT, { SCREEN_WIDTH * SCREEN_HEIGHT }>;
|
type FB = FrameBuffer<SCREEN_WIDTH, SCREEN_HEIGHT, { SCREEN_WIDTH * SCREEN_HEIGHT }>;
|
||||||
static FRAMEBUFFER_CELL: StaticCell<FB> = StaticCell::new();
|
pub static FRAMEBUFFER: LazyLock<Mutex<CriticalSectionRawMutex, FB>> =
|
||||||
pub static FRAMEBUFFER: Mutex<CriticalSectionRawMutex, Option<&'static mut FB>> = Mutex::new(None);
|
LazyLock::new(|| Mutex::new(FrameBuffer::new()));
|
||||||
|
|
||||||
pub async fn init_display(
|
pub async fn init_display(
|
||||||
spi: Spi<'static, SPI1, Async>,
|
spi: Spi<'static, SPI1, Async>,
|
||||||
@@ -38,27 +43,27 @@ pub async fn init_display(
|
|||||||
true,
|
true,
|
||||||
Delay,
|
Delay,
|
||||||
);
|
);
|
||||||
let framebuffer = FRAMEBUFFER_CELL.init(FrameBuffer::new());
|
let mut fb = FRAMEBUFFER.get().lock().await;
|
||||||
display.init().await.unwrap();
|
display.init().await.unwrap();
|
||||||
display.set_custom_orientation(0x40).await.unwrap();
|
display.set_custom_orientation(0x40).await.unwrap();
|
||||||
framebuffer.draw(&mut display).await.unwrap();
|
display.draw(&mut fb).await.unwrap();
|
||||||
display.set_on().await.unwrap();
|
display.set_on().await.unwrap();
|
||||||
FRAMEBUFFER.lock().await.replace(framebuffer);
|
|
||||||
|
|
||||||
display
|
display
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn clear_fb() {
|
||||||
|
let mut fb = FRAMEBUFFER.get().lock().await;
|
||||||
|
let fb = &mut *fb;
|
||||||
|
fb.clear(Rgb565::BLACK).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn display_handler(mut display: DISPLAY) {
|
pub async fn display_handler(mut display: DISPLAY) {
|
||||||
loop {
|
loop {
|
||||||
let fb: &mut FB = {
|
{
|
||||||
let mut guard = FRAMEBUFFER.lock().await;
|
let mut fb = FRAMEBUFFER.get().lock().await;
|
||||||
guard.take().unwrap() // take ownership
|
display.partial_draw_batched(&mut fb).await.unwrap();
|
||||||
}; // 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
|
Timer::after_millis(32).await; // 30 fps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Result<EntryFn, &str> {
|
|||||||
// MUST MATCH ABI EXACTLY
|
// MUST MATCH ABI EXACTLY
|
||||||
let entries: &[(CallAbiTable, usize)] = &[
|
let entries: &[(CallAbiTable, usize)] = &[
|
||||||
(CallAbiTable::Print, abi::print as usize),
|
(CallAbiTable::Print, abi::print as usize),
|
||||||
|
(CallAbiTable::Sleep, abi::sleep as usize),
|
||||||
(CallAbiTable::DrawIter, abi::draw_iter as usize),
|
(CallAbiTable::DrawIter, abi::draw_iter as usize),
|
||||||
(CallAbiTable::GetKey, abi::get_key as usize),
|
(CallAbiTable::GetKey, abi::get_key as usize),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ mod utils;
|
|||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::Ordering;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::{display_handler, init_display},
|
display::{FRAMEBUFFER, clear_fb, display_handler, init_display},
|
||||||
elf::load_binary,
|
elf::load_binary,
|
||||||
peripherals::{
|
peripherals::{
|
||||||
conf_peripherals,
|
conf_peripherals,
|
||||||
@@ -49,7 +49,9 @@ use embassy_rp::{
|
|||||||
spi::{self, Spi},
|
spi::{self, Spi},
|
||||||
usb as embassy_rp_usb,
|
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 embassy_time::{Delay, Timer};
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
||||||
@@ -75,7 +77,9 @@ static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
|||||||
.lock();
|
.lock();
|
||||||
|
|
||||||
static TASK_STATE: Mutex<CriticalSectionRawMutex, TaskState> = Mutex::new(TaskState::Ui);
|
static TASK_STATE: Mutex<CriticalSectionRawMutex, TaskState> = Mutex::new(TaskState::Ui);
|
||||||
|
static TASK_STATE_CHANGED: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum TaskState {
|
enum TaskState {
|
||||||
Ui,
|
Ui,
|
||||||
Kernel,
|
Kernel,
|
||||||
@@ -131,6 +135,7 @@ async fn userland_task() {
|
|||||||
let recv = BINARY_CH.receiver();
|
let recv = BINARY_CH.receiver();
|
||||||
loop {
|
loop {
|
||||||
let entry = recv.receive().await;
|
let entry = recv.receive().await;
|
||||||
|
defmt::info!("Got Entry");
|
||||||
|
|
||||||
// disable kernel ui
|
// disable kernel ui
|
||||||
{
|
{
|
||||||
@@ -138,6 +143,8 @@ async fn userland_task() {
|
|||||||
*state = TaskState::Kernel;
|
*state = TaskState::Kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear_fb().await; // blocks future exec?
|
||||||
|
|
||||||
defmt::info!("Executing Binary");
|
defmt::info!("Executing Binary");
|
||||||
entry().await;
|
entry().await;
|
||||||
|
|
||||||
@@ -237,8 +244,8 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
|
|||||||
SDCARD.get().lock().await.replace(SdCard::new(sdcard, det));
|
SDCARD.get().lock().await.replace(SdCard::new(sdcard, det));
|
||||||
};
|
};
|
||||||
|
|
||||||
// let usb = embassy_rp_usb::Driver::new(usb, Irqs);
|
let usb = embassy_rp_usb::Driver::new(usb, Irqs);
|
||||||
// let usb_fut = usb_handler(usb);
|
let usb_fut = usb_handler(usb);
|
||||||
|
|
||||||
let key_abi_fut = async {
|
let key_abi_fut = async {
|
||||||
loop {
|
loop {
|
||||||
@@ -247,7 +254,7 @@ async fn kernel_task(display: Display, sd: Sd, mcu: Mcu, usb: USB) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
join4(display_fut, ui_fut, binary_search_fut, key_abi_fut).await;
|
join5(display_fut, ui_fut, usb_fut, binary_search_fut, key_abi_fut).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
|
||||||
|
|||||||
@@ -8,18 +8,17 @@ use heapless::Vec;
|
|||||||
mod scsi_types;
|
mod scsi_types;
|
||||||
use scsi_types::*;
|
use scsi_types::*;
|
||||||
|
|
||||||
use crate::storage::SdCard;
|
use crate::storage::{SDCARD, SdCard};
|
||||||
|
|
||||||
const BULK_ENDPOINT_PACKET_SIZE: usize = 64;
|
const BULK_ENDPOINT_PACKET_SIZE: usize = 64;
|
||||||
|
|
||||||
pub struct MassStorageClass<'d, 's, D: Driver<'d>> {
|
pub struct MassStorageClass<'d, D: Driver<'d>> {
|
||||||
sdcard: &'s SdCard,
|
|
||||||
bulk_out: D::EndpointOut,
|
bulk_out: D::EndpointOut,
|
||||||
bulk_in: D::EndpointIn,
|
bulk_in: D::EndpointIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
||||||
pub fn new(builder: &mut Builder<'d, D>, sdcard: &'s SdCard) -> Self {
|
pub fn new(builder: &mut Builder<'d, D>) -> Self {
|
||||||
let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class
|
let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class
|
||||||
let mut interface = function.interface();
|
let mut interface = function.interface();
|
||||||
let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None);
|
let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None);
|
||||||
@@ -27,11 +26,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
let bulk_out = alt.endpoint_bulk_out(BULK_ENDPOINT_PACKET_SIZE as u16);
|
let bulk_out = alt.endpoint_bulk_out(BULK_ENDPOINT_PACKET_SIZE as u16);
|
||||||
let bulk_in = alt.endpoint_bulk_in(BULK_ENDPOINT_PACKET_SIZE as u16);
|
let bulk_in = alt.endpoint_bulk_in(BULK_ENDPOINT_PACKET_SIZE as u16);
|
||||||
|
|
||||||
Self {
|
Self { bulk_out, bulk_in }
|
||||||
bulk_out,
|
|
||||||
bulk_in,
|
|
||||||
sdcard,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn poll(&mut self) {
|
pub async fn poll(&mut self) {
|
||||||
@@ -139,7 +134,9 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
||||||
}
|
}
|
||||||
ScsiCommand::TestUnitReady => {
|
ScsiCommand::TestUnitReady => {
|
||||||
if self.sdcard.is_attached() {
|
let guard = SDCARD.get().lock().await;
|
||||||
|
let sdcard = guard.as_ref().unwrap();
|
||||||
|
if sdcard.is_attached() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
@@ -185,8 +182,11 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
||||||
}
|
}
|
||||||
ScsiCommand::ReadCapacity10 => {
|
ScsiCommand::ReadCapacity10 => {
|
||||||
|
let guard = SDCARD.get().lock().await;
|
||||||
|
let sdcard = guard.as_ref().unwrap();
|
||||||
|
|
||||||
let block_size = SdCard::BLOCK_SIZE as u64;
|
let block_size = SdCard::BLOCK_SIZE as u64;
|
||||||
let total_blocks = self.sdcard.size() / block_size;
|
let total_blocks = sdcard.size() / block_size;
|
||||||
|
|
||||||
let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
|
let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
|
||||||
|
|
||||||
@@ -196,8 +196,11 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
self.bulk_in.write(&response).await.map_err(|_| ())
|
self.bulk_in.write(&response).await.map_err(|_| ())
|
||||||
}
|
}
|
||||||
ScsiCommand::ReadCapacity16 { alloc_len } => {
|
ScsiCommand::ReadCapacity16 { alloc_len } => {
|
||||||
|
let guard = SDCARD.get().lock().await;
|
||||||
|
let sdcard = guard.as_ref().unwrap();
|
||||||
|
|
||||||
let block_size = SdCard::BLOCK_SIZE as u64;
|
let block_size = SdCard::BLOCK_SIZE as u64;
|
||||||
let total_blocks = self.sdcard.size() / block_size;
|
let total_blocks = sdcard.size() / block_size;
|
||||||
|
|
||||||
let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
|
let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
|
||||||
|
|
||||||
@@ -209,9 +212,12 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
|
||||||
}
|
}
|
||||||
ScsiCommand::Read { lba, len } => {
|
ScsiCommand::Read { lba, len } => {
|
||||||
|
let guard = SDCARD.get().lock().await;
|
||||||
|
let sdcard = guard.as_ref().unwrap();
|
||||||
|
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let block_idx = BlockIdx(lba as u32 + i as u32);
|
let block_idx = BlockIdx(lba as u32 + i as u32);
|
||||||
self.sdcard.read_blocks(&mut block, block_idx)?;
|
sdcard.read_blocks(&mut block, block_idx)?;
|
||||||
for chunk in block[0].contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) {
|
for chunk in block[0].contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) {
|
||||||
self.bulk_in.write(chunk).await.map_err(|_| ())?;
|
self.bulk_in.write(chunk).await.map_err(|_| ())?;
|
||||||
}
|
}
|
||||||
@@ -219,6 +225,9 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
ScsiCommand::Write { lba, len } => {
|
ScsiCommand::Write { lba, len } => {
|
||||||
|
let guard = SDCARD.get().lock().await;
|
||||||
|
let sdcard = guard.as_ref().unwrap();
|
||||||
|
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let block_idx = BlockIdx(lba as u32 + i as u32);
|
let block_idx = BlockIdx(lba as u32 + i as u32);
|
||||||
for chunk in block[0]
|
for chunk in block[0]
|
||||||
@@ -227,13 +236,16 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, 's, D> {
|
|||||||
{
|
{
|
||||||
self.bulk_out.read(chunk).await.map_err(|_| ())?;
|
self.bulk_out.read(chunk).await.map_err(|_| ())?;
|
||||||
}
|
}
|
||||||
self.sdcard.write_blocks(&mut block, block_idx)?;
|
sdcard.write_blocks(&mut block, block_idx)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
ScsiCommand::ReadFormatCapacities { alloc_len } => {
|
ScsiCommand::ReadFormatCapacities { alloc_len } => {
|
||||||
|
let guard = SDCARD.get().lock().await;
|
||||||
|
let sdcard = guard.as_ref().unwrap();
|
||||||
|
|
||||||
let block_size = SdCard::BLOCK_SIZE as u32;
|
let block_size = SdCard::BLOCK_SIZE as u32;
|
||||||
let num_blocks = (self.sdcard.size() / block_size as u64) as u32;
|
let num_blocks = (sdcard.size() / block_size as u64) as u32;
|
||||||
|
|
||||||
let mut response = [0u8; 12];
|
let mut response = [0u8; 12];
|
||||||
|
|
||||||
|
|||||||
104
kernel/src/ui.rs
104
kernel/src/ui.rs
@@ -5,36 +5,21 @@ use crate::{
|
|||||||
format,
|
format,
|
||||||
peripherals::keyboard,
|
peripherals::keyboard,
|
||||||
storage::FileName,
|
storage::FileName,
|
||||||
usb::RESTART_USB,
|
|
||||||
};
|
};
|
||||||
use alloc::{string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
use core::{fmt::Debug, str::FromStr, sync::atomic::Ordering};
|
use core::{fmt::Debug, str::FromStr, sync::atomic::Ordering};
|
||||||
use defmt::info;
|
|
||||||
use embassy_rp::{
|
|
||||||
gpio::{Level, Output},
|
|
||||||
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
|
|
||||||
spi::{Async, Spi},
|
|
||||||
};
|
|
||||||
use embassy_sync::{
|
use embassy_sync::{
|
||||||
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex},
|
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex},
|
||||||
mutex::Mutex,
|
mutex::Mutex,
|
||||||
signal::Signal,
|
|
||||||
};
|
};
|
||||||
use embassy_time::{Delay, Timer};
|
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
Drawable,
|
Drawable,
|
||||||
draw_target::DrawTarget,
|
mono_font::{MonoTextStyle, ascii::FONT_9X15},
|
||||||
mono_font::{
|
|
||||||
MonoTextStyle,
|
|
||||||
ascii::{FONT_6X9, FONT_6X10, FONT_9X15, FONT_10X20},
|
|
||||||
},
|
|
||||||
pixelcolor::Rgb565,
|
pixelcolor::Rgb565,
|
||||||
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
|
prelude::{Dimensions, Point, RgbColor, Size},
|
||||||
primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
|
primitives::Rectangle,
|
||||||
text::Text,
|
text::Text,
|
||||||
};
|
};
|
||||||
use embedded_hal_async::spi::SpiDevice;
|
|
||||||
use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay};
|
|
||||||
use embedded_layout::{
|
use embedded_layout::{
|
||||||
align::{horizontal, vertical},
|
align::{horizontal, vertical},
|
||||||
layout::linear::LinearLayout,
|
layout::linear::LinearLayout,
|
||||||
@@ -77,6 +62,8 @@ pub async fn ui_handler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw_selection().await;
|
draw_selection().await;
|
||||||
|
} else {
|
||||||
|
embassy_time::Timer::after_millis(50).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,51 +74,50 @@ async fn draw_selection() {
|
|||||||
guard.selections.clone()
|
guard.selections.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut fb_lock = FRAMEBUFFER.lock().await;
|
let mut fb = FRAMEBUFFER.get().lock().await;
|
||||||
if let Some(fb) = fb_lock.as_mut() {
|
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 display_area = fb.bounding_box();
|
|
||||||
|
|
||||||
const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory";
|
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();
|
let no_bins = String::from_str(NO_BINS).unwrap();
|
||||||
|
|
||||||
if file_names.is_empty() {
|
if file_names.is_empty() {
|
||||||
TextBox::new(
|
TextBox::new(
|
||||||
&no_bins,
|
&no_bins,
|
||||||
Rectangle::new(
|
Rectangle::new(
|
||||||
Point::new(25, 25),
|
Point::new(25, 25),
|
||||||
Size::new(display_area.size.width - 50, display_area.size.width - 50),
|
Size::new(display_area.size.width - 50, display_area.size.width - 50),
|
||||||
),
|
),
|
||||||
text_style,
|
text_style,
|
||||||
)
|
)
|
||||||
.draw(*fb)
|
.draw(&mut *fb)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let mut file_names = file_names.iter();
|
let mut file_names = file_names.iter();
|
||||||
let Some(first) = file_names.next() else {
|
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",
|
Text::new(NO_BINS, Point::zero(), text_style)
|
||||||
Point::zero(), text_style).draw(*fb).unwrap();
|
.draw(&mut *fb)
|
||||||
|
|
||||||
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(*fb)
|
|
||||||
.unwrap();
|
.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(&mut *fb)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use core::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
TASK_STATE, TASK_STATE_CHANGED, TaskState,
|
||||||
scsi::MassStorageClass,
|
scsi::MassStorageClass,
|
||||||
storage::{SDCARD, SdCard},
|
storage::{SDCARD, SdCard},
|
||||||
};
|
};
|
||||||
@@ -13,9 +12,6 @@ use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, signal::Signal};
|
|||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use portable_atomic::AtomicBool;
|
use portable_atomic::AtomicBool;
|
||||||
|
|
||||||
pub static RESTART_USB: Signal<ThreadModeRawMutex, ()> = Signal::new();
|
|
||||||
pub static ENABLE_SCSI: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
pub async fn usb_handler(driver: Driver<'static, USB>) {
|
pub async fn usb_handler(driver: Driver<'static, USB>) {
|
||||||
let mut config = Config::new(0xc0de, 0xbabe);
|
let mut config = Config::new(0xc0de, 0xbabe);
|
||||||
config.manufacturer = Some("LegitCamper");
|
config.manufacturer = Some("LegitCamper");
|
||||||
@@ -37,27 +33,17 @@ pub async fn usb_handler(driver: Driver<'static, USB>) {
|
|||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
let lock = SDCARD.get().lock().await;
|
let mut scsi = MassStorageClass::new(&mut builder);
|
||||||
let sdcard = lock.as_ref().unwrap();
|
|
||||||
|
|
||||||
let mut scsi = MassStorageClass::new(&mut builder, &sdcard);
|
|
||||||
let mut usb = builder.build();
|
let mut usb = builder.build();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
select3(
|
defmt::info!("in: {}", *TASK_STATE.lock().await as u32);
|
||||||
async {
|
if *TASK_STATE.lock().await == TaskState::Ui {
|
||||||
loop {
|
defmt::info!("running scsi and usb");
|
||||||
RESTART_USB.wait().await;
|
select(join(usb.run(), scsi.poll()), TASK_STATE_CHANGED.wait()).await;
|
||||||
return;
|
} else {
|
||||||
}
|
defmt::info!("not in ui state");
|
||||||
},
|
TASK_STATE_CHANGED.wait().await;
|
||||||
usb.run(),
|
}
|
||||||
async {
|
|
||||||
if ENABLE_SCSI.load(Ordering::Acquire) {
|
|
||||||
scsi.poll().await
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ pub async fn main() {
|
|||||||
.draw(&mut display)
|
.draw(&mut display)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
embassy_time::Timer::after_millis(1000).await;
|
||||||
|
|
||||||
if let Some(event) = get_key() {
|
if let Some(event) = get_key() {
|
||||||
print("User got event");
|
print("User got event");
|
||||||
match event.key {
|
match event.key {
|
||||||
|
|||||||
Reference in New Issue
Block a user