mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 07:45:28 +00:00
scsi improvements
This commit is contained in:
@@ -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},
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user