scsi improvements

This commit is contained in:
2025-11-05 14:15:20 -07:00
parent 8290ec40a7
commit 5cbee3715f
4 changed files with 76 additions and 52 deletions

View File

@@ -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},

View File

@@ -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<SdCard>, // 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<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 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();
}
}
}
}
}

View File

@@ -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;
}
}
_ => (),
}

View File

@@ -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<SdCard> = 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);
}