Files
picocalc-os-rs/kernel/src/usb.rs
2025-11-06 11:48:50 -07:00

83 lines
2.6 KiB
Rust

use crate::scsi::{MassStorageClass, SCSI_BUSY, SCSI_HALT};
use core::sync::atomic::{AtomicBool, Ordering};
use embassy_futures::select::select;
use embassy_rp::{peripherals::USB, usb::Driver};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel};
use embassy_time::Timer;
use embassy_usb::{Builder, Config};
static START_USB: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
static STOP_USB: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
// for other tasks to query the status of usb (like ui)
// this is read only for ALL other tasks
pub static USB_ACTIVE: AtomicBool = AtomicBool::new(false);
#[embassy_executor::task]
pub async fn usb_handler(driver: Driver<'static, USB>) {
let mut config = Config::new(0xc0de, 0xbabe);
config.manufacturer = Some("LegitCamper");
config.product = Some("PicoCalc");
config.serial_number = Some("01001100");
config.max_power = 100;
config.max_packet_size_0 = 64;
let mut config_descriptor = [0; 256];
let mut bos_descriptor = [0; 64];
let mut control_buf = [0; 64];
let mut builder = Builder::new(
driver,
config,
&mut config_descriptor,
&mut bos_descriptor,
&mut [],
&mut control_buf,
);
let mut scsi = MassStorageClass::new(&mut builder);
let mut usb = builder.build();
loop {
START_USB.receiver().receive().await;
USB_ACTIVE.store(true, Ordering::Release);
SCSI_HALT.store(false, Ordering::Release);
scsi.take_sdcard().await;
scsi.pending_eject = false;
// waits for cancellation signal, and then waits for
// transfers to stop before dropping usb future
select(
async {
STOP_USB.receiver().receive().await;
SCSI_HALT.store(true, Ordering::Release);
while SCSI_BUSY.load(Ordering::Acquire) {
Timer::after_millis(100).await;
}
},
// runs the usb, until cancelled
select(
async {
let _ = usb.remote_wakeup().await;
usb.run().await;
},
scsi.poll(),
),
)
.await;
usb.disable().await;
scsi.return_sdcard().await;
USB_ACTIVE.store(false, Ordering::Release);
}
}
pub fn start_usb() {
let _ = STOP_USB.receiver().try_receive();
let _ = START_USB.sender().try_send(());
}
pub fn stop_usb() {
let _ = START_USB.receiver().try_receive();
let _ = STOP_USB.sender().try_send(());
}