diff --git a/kernel/src/main.rs b/kernel/src/main.rs index ddc0d47..4d3c5cc 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -42,7 +42,7 @@ use abi_sys::EntryFn; use bumpalo::Bump; use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::{Executor, Spawner}; -use embassy_futures::{join::join, select::select}; +use embassy_futures::select::select; use embassy_rp::{ Peri, gpio::{Input, Level, Output, Pull}, diff --git a/kernel/src/scsi/mod.rs b/kernel/src/scsi/mod.rs index f941335..fa4d593 100644 --- a/kernel/src/scsi/mod.rs +++ b/kernel/src/scsi/mod.rs @@ -1,6 +1,6 @@ use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_futures::yield_now; use embassy_sync::lazy_lock::LazyLock; -use embassy_time::Timer; use embassy_usb::Builder; use embassy_usb::driver::{Driver, EndpointIn, EndpointOut}; use embedded_sdmmc::{Block, BlockIdx}; @@ -18,21 +18,24 @@ const BULK_ENDPOINT_PACKET_SIZE: usize = 64; // NOT safe to disable usb, or acquire sdcard pub static SCSI_BUSY: AtomicBool = AtomicBool::new(false); +// start no more transfers, usb is trying to stop +pub static SCSI_HALT: AtomicBool = AtomicBool::new(false); + // number of blocks to read from sd at once // higher is better, but is larger. Size is BLOCKS * 512 bytes -const BLOCKS: usize = 1; +const BLOCKS: usize = 5; static mut BLOCK_BUF: LazyLock<[Block; BLOCKS]> = LazyLock::new(|| core::array::from_fn(|_| Block::new())); pub struct MassStorageClass<'d, D: Driver<'d>> { temp_sd: Option, // temporary owns sdcard when scsi is running - pending_eject: bool, + pub pending_eject: bool, bulk_out: D::EndpointOut, bulk_in: D::EndpointIn, } impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { - pub fn new(builder: &mut Builder<'d, D>, temp_sd: Option) -> Self { + pub fn new(builder: &mut Builder<'d, D>) -> 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); @@ -41,7 +44,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { let bulk_in = alt.endpoint_bulk_in(None, BULK_ENDPOINT_PACKET_SIZE as u16); Self { - temp_sd, + temp_sd: None, pending_eject: false, bulk_out, bulk_in, @@ -61,18 +64,31 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { } pub async fn return_sdcard(&mut self) { - if self.temp_sd.is_some() { + if let Some(card) = self.temp_sd.take() { let mut guard = SDCARD.get().lock().await; - guard.replace(self.temp_sd.take().unwrap()).unwrap(); + *guard = Some(card); } } pub async fn poll(&mut self) { loop { + if SCSI_HALT.load(Ordering::Acquire) { + break; + } + + if self.pending_eject { + break; + } self.handle_cbw().await; - Timer::after_millis(10).await; + if self.pending_eject { + break; + } + + yield_now().await; } + + stop_usb(); } async fn handle_cbw(&mut self) { @@ -90,12 +106,6 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { } SCSI_BUSY.store(false, Ordering::Release); - - if self.pending_eject { - if let ScsiCommand::Write { lba: _, len: _ } = command { - stop_usb(); - } - } } } } diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs index 8613cdd..ffe90d1 100644 --- a/kernel/src/ui.rs +++ b/kernel/src/ui.rs @@ -56,32 +56,43 @@ async fn input_handler() { if let KeyState::Pressed = event.state { match event.key { KeyCode::Up => { - let mut selections = SELECTIONS.lock().await; - selections.up(); + if !USB_ACTIVE.load(Ordering::Acquire) { + let mut selections = SELECTIONS.lock().await; + selections.up(); + } } KeyCode::Down => { - let mut selections = SELECTIONS.lock().await; - selections.down(); + if !USB_ACTIVE.load(Ordering::Acquire) { + let mut selections = SELECTIONS.lock().await; + selections.down(); + } } KeyCode::F1 => { match USB_ACTIVE.load(Ordering::Acquire) { - true => stop_usb(), + true => { + stop_usb(); + // wait for sd card to be put back and then reload selections + while USB_ACTIVE.load(Ordering::Acquire) { + Timer::after_millis(100).await + } + update_selections().await + } false => start_usb(), }; - update_selections().await; } KeyCode::Enter | KeyCode::Right => { - stop_usb(); - let selections = SELECTIONS.lock().await; - let selection = - selections.selections[selections.current_selection as usize].clone(); + if !USB_ACTIVE.load(Ordering::Acquire) { + let selections = SELECTIONS.lock().await; + let selection = + selections.selections[selections.current_selection as usize].clone(); - let entry = unsafe { - load_binary(&selection.short_name) - .await - .expect("unable to load binary") - }; - BINARY_CH.send(entry).await; + let entry = unsafe { + load_binary(&selection.short_name) + .await + .expect("unable to load binary") + }; + BINARY_CH.send(entry).await; + } } _ => (), } diff --git a/kernel/src/usb.rs b/kernel/src/usb.rs index 885a0f1..2d4aeae 100644 --- a/kernel/src/usb.rs +++ b/kernel/src/usb.rs @@ -1,9 +1,5 @@ +use crate::scsi::{MassStorageClass, SCSI_BUSY, SCSI_HALT}; use core::sync::atomic::{AtomicBool, Ordering}; - -use crate::{ - scsi::{MassStorageClass, SCSI_BUSY}, - storage::SdCard, -}; use embassy_futures::{join::join, select::select}; use embassy_rp::{peripherals::USB, usb::Driver}; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel}; @@ -39,32 +35,41 @@ pub async fn usb_handler(driver: Driver<'static, USB>) { &mut control_buf, ); - let temp_sd: Option = None; - let mut scsi = MassStorageClass::new(&mut builder, temp_sd); + let mut scsi = MassStorageClass::new(&mut builder); let mut usb = builder.build(); loop { START_USB.receiver().receive().await; - #[cfg(feature = "defmt")] + USB_ACTIVE.store(true, Ordering::Release); + SCSI_HALT.store(false, Ordering::Release); scsi.take_sdcard().await; - defmt::info!("starting usb"); + scsi.pending_eject = false; + + // waits for cancellation signal, and then waits for + // transfers to stop before dropping usb future select( - // waits for cancellation signal, and then waits for - // transfers to stop before dropping usb future async { STOP_USB.receiver().receive().await; + SCSI_HALT.store(true, Ordering::Release); + while SCSI_BUSY.load(Ordering::Acquire) { + Timer::after_millis(100).await; + } + }, + async { + // runs the usb, until cancelled + join( + async { + let _ = usb.remote_wakeup().await; + usb.run().await + }, + scsi.poll(), + ) + .await; }, - // runs the usb, until cancelled - join(usb.run(), scsi.poll()), ) .await; - while SCSI_BUSY.load(Ordering::Acquire) { - Timer::after_millis(100).await; - } - #[cfg(feature = "defmt")] - defmt::info!("disabling usb"); - scsi.return_sdcard().await; usb.disable().await; + scsi.return_sdcard().await; USB_ACTIVE.store(false, Ordering::Release); } } @@ -72,11 +77,9 @@ pub async fn usb_handler(driver: Driver<'static, USB>) { pub fn start_usb() { let _ = STOP_USB.receiver().try_receive(); let _ = START_USB.sender().try_send(()); - USB_ACTIVE.store(true, Ordering::Release); } pub fn stop_usb() { let _ = START_USB.receiver().try_receive(); let _ = STOP_USB.sender().try_send(()); - USB_ACTIVE.store(false, Ordering::Release); }