mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
scsi improvements
This commit is contained in:
@@ -42,7 +42,7 @@ use abi_sys::EntryFn;
|
|||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use embassy_executor::{Executor, Spawner};
|
use embassy_executor::{Executor, Spawner};
|
||||||
use embassy_futures::{join::join, select::select};
|
use embassy_futures::select::select;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
Peri,
|
Peri,
|
||||||
gpio::{Input, Level, Output, Pull},
|
gpio::{Input, Level, Output, Pull},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use embassy_futures::yield_now;
|
||||||
use embassy_sync::lazy_lock::LazyLock;
|
use embassy_sync::lazy_lock::LazyLock;
|
||||||
use embassy_time::Timer;
|
|
||||||
use embassy_usb::Builder;
|
use embassy_usb::Builder;
|
||||||
use embassy_usb::driver::{Driver, EndpointIn, EndpointOut};
|
use embassy_usb::driver::{Driver, EndpointIn, EndpointOut};
|
||||||
use embedded_sdmmc::{Block, BlockIdx};
|
use embedded_sdmmc::{Block, BlockIdx};
|
||||||
@@ -18,21 +18,24 @@ const BULK_ENDPOINT_PACKET_SIZE: usize = 64;
|
|||||||
// NOT safe to disable usb, or acquire sdcard
|
// NOT safe to disable usb, or acquire sdcard
|
||||||
pub static SCSI_BUSY: AtomicBool = AtomicBool::new(false);
|
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
|
// number of blocks to read from sd at once
|
||||||
// higher is better, but is larger. Size is BLOCKS * 512 bytes
|
// 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]> =
|
static mut BLOCK_BUF: LazyLock<[Block; BLOCKS]> =
|
||||||
LazyLock::new(|| core::array::from_fn(|_| Block::new()));
|
LazyLock::new(|| core::array::from_fn(|_| Block::new()));
|
||||||
|
|
||||||
pub struct MassStorageClass<'d, D: Driver<'d>> {
|
pub struct MassStorageClass<'d, D: Driver<'d>> {
|
||||||
temp_sd: Option<SdCard>, // temporary owns sdcard when scsi is running
|
temp_sd: Option<SdCard>, // temporary owns sdcard when scsi is running
|
||||||
pending_eject: bool,
|
pub pending_eject: bool,
|
||||||
bulk_out: D::EndpointOut,
|
bulk_out: D::EndpointOut,
|
||||||
bulk_in: D::EndpointIn,
|
bulk_in: D::EndpointIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
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 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);
|
||||||
@@ -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);
|
let bulk_in = alt.endpoint_bulk_in(None, BULK_ENDPOINT_PACKET_SIZE as u16);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
temp_sd,
|
temp_sd: None,
|
||||||
pending_eject: false,
|
pending_eject: false,
|
||||||
bulk_out,
|
bulk_out,
|
||||||
bulk_in,
|
bulk_in,
|
||||||
@@ -61,18 +64,31 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn return_sdcard(&mut self) {
|
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;
|
let mut guard = SDCARD.get().lock().await;
|
||||||
guard.replace(self.temp_sd.take().unwrap()).unwrap();
|
*guard = Some(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn poll(&mut self) {
|
pub async fn poll(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
|
if SCSI_HALT.load(Ordering::Acquire) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.pending_eject {
|
||||||
|
break;
|
||||||
|
}
|
||||||
self.handle_cbw().await;
|
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) {
|
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);
|
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 {
|
if let KeyState::Pressed = event.state {
|
||||||
match event.key {
|
match event.key {
|
||||||
KeyCode::Up => {
|
KeyCode::Up => {
|
||||||
let mut selections = SELECTIONS.lock().await;
|
if !USB_ACTIVE.load(Ordering::Acquire) {
|
||||||
selections.up();
|
let mut selections = SELECTIONS.lock().await;
|
||||||
|
selections.up();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Down => {
|
KeyCode::Down => {
|
||||||
let mut selections = SELECTIONS.lock().await;
|
if !USB_ACTIVE.load(Ordering::Acquire) {
|
||||||
selections.down();
|
let mut selections = SELECTIONS.lock().await;
|
||||||
|
selections.down();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KeyCode::F1 => {
|
KeyCode::F1 => {
|
||||||
match USB_ACTIVE.load(Ordering::Acquire) {
|
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(),
|
false => start_usb(),
|
||||||
};
|
};
|
||||||
update_selections().await;
|
|
||||||
}
|
}
|
||||||
KeyCode::Enter | KeyCode::Right => {
|
KeyCode::Enter | KeyCode::Right => {
|
||||||
stop_usb();
|
if !USB_ACTIVE.load(Ordering::Acquire) {
|
||||||
let selections = SELECTIONS.lock().await;
|
let selections = SELECTIONS.lock().await;
|
||||||
let selection =
|
let selection =
|
||||||
selections.selections[selections.current_selection as usize].clone();
|
selections.selections[selections.current_selection as usize].clone();
|
||||||
|
|
||||||
let entry = unsafe {
|
let entry = unsafe {
|
||||||
load_binary(&selection.short_name)
|
load_binary(&selection.short_name)
|
||||||
.await
|
.await
|
||||||
.expect("unable to load binary")
|
.expect("unable to load binary")
|
||||||
};
|
};
|
||||||
BINARY_CH.send(entry).await;
|
BINARY_CH.send(entry).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
|
use crate::scsi::{MassStorageClass, SCSI_BUSY, SCSI_HALT};
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::{
|
|
||||||
scsi::{MassStorageClass, SCSI_BUSY},
|
|
||||||
storage::SdCard,
|
|
||||||
};
|
|
||||||
use embassy_futures::{join::join, select::select};
|
use embassy_futures::{join::join, select::select};
|
||||||
use embassy_rp::{peripherals::USB, usb::Driver};
|
use embassy_rp::{peripherals::USB, usb::Driver};
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel};
|
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,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
let temp_sd: Option<SdCard> = None;
|
let mut scsi = MassStorageClass::new(&mut builder);
|
||||||
let mut scsi = MassStorageClass::new(&mut builder, temp_sd);
|
|
||||||
let mut usb = builder.build();
|
let mut usb = builder.build();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
START_USB.receiver().receive().await;
|
START_USB.receiver().receive().await;
|
||||||
#[cfg(feature = "defmt")]
|
USB_ACTIVE.store(true, Ordering::Release);
|
||||||
|
SCSI_HALT.store(false, Ordering::Release);
|
||||||
scsi.take_sdcard().await;
|
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(
|
select(
|
||||||
// waits for cancellation signal, and then waits for
|
|
||||||
// transfers to stop before dropping usb future
|
|
||||||
async {
|
async {
|
||||||
STOP_USB.receiver().receive().await;
|
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;
|
.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;
|
usb.disable().await;
|
||||||
|
scsi.return_sdcard().await;
|
||||||
USB_ACTIVE.store(false, Ordering::Release);
|
USB_ACTIVE.store(false, Ordering::Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,11 +77,9 @@ pub async fn usb_handler(driver: Driver<'static, USB>) {
|
|||||||
pub fn start_usb() {
|
pub fn start_usb() {
|
||||||
let _ = STOP_USB.receiver().try_receive();
|
let _ = STOP_USB.receiver().try_receive();
|
||||||
let _ = START_USB.sender().try_send(());
|
let _ = START_USB.sender().try_send(());
|
||||||
USB_ACTIVE.store(true, Ordering::Release);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_usb() {
|
pub fn stop_usb() {
|
||||||
let _ = START_USB.receiver().try_receive();
|
let _ = START_USB.receiver().try_receive();
|
||||||
let _ = STOP_USB.sender().try_send(());
|
let _ = STOP_USB.sender().try_send(());
|
||||||
USB_ACTIVE.store(false, Ordering::Release);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user