This commit is contained in:
2025-07-21 23:12:16 -06:00
parent 2d31e62d82
commit beae5b2fd9
8 changed files with 526 additions and 60 deletions

131
Cargo.lock generated
View File

@@ -12,6 +12,18 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "ahash"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.3" version = "1.1.3"
@@ -126,6 +138,12 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
[[package]]
name = "bitfield"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@@ -215,7 +233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
dependencies = [ dependencies = [
"bare-metal", "bare-metal",
"bitfield", "bitfield 0.13.2",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"volatile-register", "volatile-register",
] ]
@@ -686,6 +704,21 @@ dependencies = [
"heapless", "heapless",
] ]
[[package]]
name = "embassy-usb"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e651b9b7b47b514e6e6d1940a6e2e300891a2c33641917130643602a0cb6386"
dependencies = [
"embassy-futures",
"embassy-net-driver-channel",
"embassy-sync 0.6.2",
"embassy-usb-driver",
"heapless",
"ssmarshal",
"usbd-hid",
]
[[package]] [[package]]
name = "embassy-usb-driver" name = "embassy-usb-driver"
version = "0.1.1" version = "0.1.1"
@@ -822,6 +855,12 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@@ -996,6 +1035,15 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.4" version = "0.15.4"
@@ -1031,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown 0.15.4",
] ]
[[package]] [[package]]
@@ -1370,12 +1418,14 @@ dependencies = [
"embassy-rp 0.4.0", "embassy-rp 0.4.0",
"embassy-sync 0.7.0", "embassy-sync 0.7.0",
"embassy-time", "embassy-time",
"embassy-usb",
"embedded-graphics", "embedded-graphics",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal-async", "embedded-hal-async",
"embedded-hal-bus", "embedded-hal-bus",
"embedded-sdmmc", "embedded-sdmmc",
"heapless", "heapless",
"num_enum 0.7.4",
"panic-probe", "panic-probe",
"portable-atomic", "portable-atomic",
"spin", "spin",
@@ -1710,6 +1760,26 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "sha2-const-stable" name = "sha2-const-stable"
version = "0.1.0" version = "0.1.0"
@@ -1765,6 +1835,16 @@ dependencies = [
"lock_api", "lock_api",
] ]
[[package]]
name = "ssmarshal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850"
dependencies = [
"encode_unicode",
"serde",
]
[[package]] [[package]]
name = "st7365p-lcd" name = "st7365p-lcd"
version = "0.11.0" version = "0.11.0"
@@ -1983,6 +2063,53 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "usb-device"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6"
dependencies = [
"heapless",
"portable-atomic",
]
[[package]]
name = "usbd-hid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c"
dependencies = [
"serde",
"ssmarshal",
"usb-device",
"usbd-hid-macros",
]
[[package]]
name = "usbd-hid-descriptors"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed"
dependencies = [
"bitfield 0.14.0",
]
[[package]]
name = "usbd-hid-macros"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38"
dependencies = [
"byteorder",
"hashbrown 0.13.2",
"log",
"proc-macro2",
"quote",
"serde",
"syn 1.0.109",
"usbd-hid-descriptors",
]
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.17.0" version = "1.17.0"

View File

@@ -45,8 +45,9 @@ embassy-rp = { version = "0.4.0", features = [
] } ] }
embassy-futures = "0.1.1" embassy-futures = "0.1.1"
embassy-time = "0.4.0" embassy-time = "0.4.0"
embassy-embedded-hal = "0.3.0" embassy-embedded-hal = "0.3.1"
embassy-sync = { version = "0.7" } embassy-sync = "0.7"
embassy-usb = "0.4.0"
trouble-host = { version = "0.1", features = [ trouble-host = { version = "0.1", features = [
"derive", "derive",
"scan", "scan",
@@ -78,3 +79,4 @@ bitflags = "2.9.1"
talc = "4.4.3" talc = "4.4.3"
spin = "0.10.0" spin = "0.10.0"
heapless = "0.8.0" heapless = "0.8.0"
num_enum = { version = "0.7.4", default-features = false }

View File

@@ -21,8 +21,6 @@ use embedded_hal_bus::spi::ExclusiveDevice;
use portable_atomic::AtomicBool; use portable_atomic::AtomicBool;
use st7365p_lcd::{FrameBuffer, ST7365P}; use st7365p_lcd::{FrameBuffer, ST7365P};
use crate::LAST_TEXT_RECT;
const SCREEN_WIDTH: usize = 320; const SCREEN_WIDTH: usize = 320;
const SCREEN_HEIGHT: usize = 320; const SCREEN_HEIGHT: usize = 320;
@@ -58,24 +56,7 @@ pub async fn display_handler(
loop { loop {
DISPLAY_SIGNAL.wait().await; DISPLAY_SIGNAL.wait().await;
let text_string = crate::STRING.lock().await.clone(); // text.draw(&mut framebuffer).unwrap();
let text = Text::with_alignment(
&text_string,
Point::new(160, 160),
MonoTextStyle::new(&FONT_10X20, Rgb565::RED),
Alignment::Center,
);
{
let rect = LAST_TEXT_RECT.lock().await;
if let Some(rect) = *rect.borrow() {
framebuffer.fill_solid(&rect, Rgb565::BLACK).unwrap();
}
*rect.borrow_mut() = Some(text.bounding_box());
}
text.draw(&mut framebuffer).unwrap();
let start = Instant::now(); let start = Instant::now();
framebuffer framebuffer

View File

@@ -6,6 +6,8 @@
use crate::{ use crate::{
display::DISPLAY_SIGNAL, display::DISPLAY_SIGNAL,
peripherals::keyboard::{KeyCode, KeyState, read_keyboard_fifo}, peripherals::keyboard::{KeyCode, KeyState, read_keyboard_fifo},
storage::SdCard,
usb::usb_handler,
}; };
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@@ -13,70 +15,74 @@ use {defmt_rtt as _, panic_probe as _};
use core::cell::RefCell; use core::cell::RefCell;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::join::join; use embassy_futures::join::join;
use embassy_rp::peripherals::I2C1; use embassy_rp::{
gpio::{Input, Level, Output, Pull},
peripherals::{I2C1, USB},
spi::Spi,
usb as embassy_rp_usb,
};
use embassy_rp::{i2c, i2c::I2c, spi}; use embassy_rp::{i2c, i2c::I2c, spi};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embassy_time::Timer; use embassy_time::{Delay, Timer};
use embedded_graphics::primitives::Rectangle; use embedded_graphics::primitives::Rectangle;
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::asynchronous::SdCard as SdmmcSdCard;
use heapless::String; use heapless::String;
mod peripherals; mod peripherals;
use peripherals::conf_peripherals; use peripherals::conf_peripherals;
mod display; mod display;
use display::display_handler; use display::display_handler;
mod scsi;
mod storage;
mod usb;
embassy_rp::bind_interrupts!(struct Irqs { embassy_rp::bind_interrupts!(struct Irqs {
I2C1_IRQ => i2c::InterruptHandler<I2C1>; I2C1_IRQ => i2c::InterruptHandler<I2C1>;
USBCTRL_IRQ => embassy_rp_usb::InterruptHandler<USB>;
}); });
static STRING: Mutex<ThreadModeRawMutex, String<25>> = Mutex::new(String::new());
static LAST_TEXT_RECT: Mutex<ThreadModeRawMutex, RefCell<Option<Rectangle>>> =
Mutex::new(RefCell::new(None));
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
STRING.lock().await.push_str("Press Del").unwrap(); // MCU i2c bus for peripherals
// configure keyboard event handler
let mut config = i2c::Config::default(); let mut config = i2c::Config::default();
config.frequency = 400_000; config.frequency = 400_000;
let i2c1 = I2c::new_async(p.I2C1, p.PIN_7, p.PIN_6, Irqs, config); let i2c1 = I2c::new_async(p.I2C1, p.PIN_7, p.PIN_6, Irqs, config);
conf_peripherals(i2c1).await; conf_peripherals(i2c1).await;
// SPI1 bus display
let mut config = spi::Config::default(); let mut config = spi::Config::default();
config.frequency = 16_000_000; config.frequency = 16_000_000;
let spi1 = spi::Spi::new( let spi1 = spi::Spi::new(
p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, config, p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, config,
); );
join( let usb = embassy_rp_usb::Driver::new(p.USB, Irqs);
async {
loop { let sdcard = {
Timer::after_millis(20).await; let mut config = spi::Config::default();
if let Some(key) = read_keyboard_fifo().await config.frequency = 400_000;
&& key.state == KeyState::Pressed let spi = Spi::new(
{ p.SPI0,
let mut string = STRING.lock().await; p.PIN_18,
match key.key { p.PIN_19,
KeyCode::Backspace => { p.PIN_16,
string.pop().unwrap(); p.DMA_CH2,
} p.DMA_CH3,
KeyCode::Del => { config.clone(),
string.clear(); );
} let cs = Output::new(p.PIN_5, Level::High);
KeyCode::Char(c) => {
string.push(c).unwrap(); let device = ExclusiveDevice::new(spi, cs, Delay).unwrap();
} let sdcard = SdmmcSdCard::new(device, Delay);
_ => (),
} config.frequency = 32_000_000;
DISPLAY_SIGNAL.signal(()); sdcard.spi(|dev| dev.bus_mut().set_config(&config));
} SdCard::new(sdcard, Input::new(p.PIN_22, Pull::None))
} };
},
display_handler(spi1, p.PIN_13, p.PIN_14, p.PIN_15), usb_handler(usb, sdcard).await;
)
.await;
} }

107
src/scsi/mod.rs Normal file
View File

@@ -0,0 +1,107 @@
use embassy_usb::driver::{Driver, EndpointIn, EndpointOut};
use embassy_usb::types::StringIndex;
use embassy_usb::{Builder, Config};
mod scsi_types;
use scsi_types::*;
use crate::storage::SdCard;
pub struct MassStorageClass<'d, 'c, D: Driver<'d>> {
sdcard: SdCard<'c>,
bulk_out: D::EndpointOut,
bulk_in: D::EndpointIn,
}
impl<'d, 'c, D: Driver<'d>> MassStorageClass<'d, 'c, D> {
pub fn new(builder: &mut Builder<'d, D>, sdcard: SdCard<'c>) -> Self {
let mut function = builder.function(0x08, 0x06, 0x50); // Mass Storage class
let mut interface = function.interface();
let mut alt = interface.alt_setting(0x08, 0x06, 0x50, None);
let bulk_out = alt.endpoint_bulk_out(64);
let bulk_in = alt.endpoint_bulk_in(64);
Self {
bulk_out,
bulk_in,
sdcard,
}
}
pub async fn poll(&mut self) {
let mut cbw_buf = [0u8; 31];
if let Ok(n) = self.bulk_out.read(&mut cbw_buf).await {
if let Some(cbw) = CommandBlockWrapper::parse(&cbw_buf[..n]) {
self.handle_command(&cbw.CBWCB).await;
}
}
}
async fn handle_command(&self, cbw: &[u8]) {
match parse_cb(cbw) {
ScsiCommand::Unknown => {
#[cfg(feature = "defmt")]
defmt::info!("Got unexpected scsi command: {}", cbw);
}
ScsiCommand::Inquiry {
evpd,
page_code,
alloc_len,
} => todo!(),
ScsiCommand::TestUnitReady => todo!(),
ScsiCommand::RequestSense { desc, alloc_len } => todo!(),
ScsiCommand::ModeSense6 {
dbd,
page_control,
page_code,
subpage_code,
alloc_len,
} => todo!(),
ScsiCommand::ModeSense10 {
dbd,
page_control,
page_code,
subpage_code,
alloc_len,
} => todo!(),
ScsiCommand::ReadCapacity10 => todo!(),
ScsiCommand::ReadCapacity16 { alloc_len } => todo!(),
ScsiCommand::Read { lba, len } => todo!(),
ScsiCommand::Write { lba, len } => todo!(),
ScsiCommand::ReadFormatCapacities { alloc_len } => todo!(),
}
}
}
#[repr(C, packed)]
struct CommandBlockWrapper {
dCBWSignature: u32,
dCBWTag: u32,
dCBWDataTransferLength: u32,
bmCBWFlags: u8,
bCBWLUN: u8,
bCBWCBLength: u8,
CBWCB: [u8; 16],
}
impl CommandBlockWrapper {
fn parse(buf: &[u8]) -> Option<Self> {
if buf.len() < 31 {
return None;
}
let dCBWSignature = u32::from_le_bytes(buf[0..4].try_into().unwrap());
if dCBWSignature != 0x43425355 {
return None; // invalid signature
}
Some(Self {
dCBWSignature,
dCBWTag: u32::from_le_bytes(buf[4..8].try_into().unwrap()),
dCBWDataTransferLength: u32::from_le_bytes(buf[8..12].try_into().unwrap()),
bmCBWFlags: buf[12],
bCBWLUN: buf[13],
bCBWCBLength: buf[14],
CBWCB: buf[15..31].try_into().unwrap(),
})
}
}

140
src/scsi/scsi_types.rs Normal file
View File

@@ -0,0 +1,140 @@
use num_enum::TryFromPrimitive;
/// THE CODE BELOW ORIGINATES FROM: https://github.com/apohrebniak/usbd-storage/blob/master/usbd-storage/src/subclass/scsi.rs
/// SCSI device subclass code
pub const SUBCLASS_SCSI: u8 = 0x06; // SCSI Transparent command set
/* SCSI codes */
/* SPC */
const TEST_UNIT_READY: u8 = 0x00;
const REQUEST_SENSE: u8 = 0x03;
const INQUIRY: u8 = 0x12;
const MODE_SENSE_6: u8 = 0x1A;
const MODE_SENSE_10: u8 = 0x5A;
/* SBC */
const READ_10: u8 = 0x28;
const READ_16: u8 = 0x88;
const READ_CAPACITY_10: u8 = 0x25;
const READ_CAPACITY_16: u8 = 0x9E;
const WRITE_10: u8 = 0x2A;
/* MMC */
const READ_FORMAT_CAPACITIES: u8 = 0x23;
/// SCSI command
///
/// Refer to specifications (SPC,SAM,SBC,MMC,etc.)
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum ScsiCommand {
Unknown,
/* SPC */
Inquiry {
evpd: bool,
page_code: u8,
alloc_len: u16,
},
TestUnitReady,
RequestSense {
desc: bool,
alloc_len: u8,
},
ModeSense6 {
dbd: bool,
page_control: PageControl,
page_code: u8,
subpage_code: u8,
alloc_len: u8,
},
ModeSense10 {
dbd: bool,
page_control: PageControl,
page_code: u8,
subpage_code: u8,
alloc_len: u16,
},
/* SBC */
ReadCapacity10,
ReadCapacity16 {
alloc_len: u32,
},
Read {
lba: u64,
len: u64,
},
Write {
lba: u64,
len: u64,
},
/* MMC */
ReadFormatCapacities {
alloc_len: u16,
},
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, TryFromPrimitive)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PageControl {
CurrentValues = 0b00,
ChangeableValues = 0b01,
DefaultValues = 0b10,
SavedValues = 0b11,
}
#[allow(dead_code)]
pub fn parse_cb(cb: &[u8]) -> ScsiCommand {
match cb[0] {
TEST_UNIT_READY => ScsiCommand::TestUnitReady,
INQUIRY => ScsiCommand::Inquiry {
evpd: (cb[1] & 0b00000001) != 0,
page_code: cb[2],
alloc_len: u16::from_be_bytes([cb[3], cb[4]]),
},
REQUEST_SENSE => ScsiCommand::RequestSense {
desc: (cb[1] & 0b00000001) != 0,
alloc_len: cb[4],
},
READ_CAPACITY_10 => ScsiCommand::ReadCapacity10,
READ_CAPACITY_16 => ScsiCommand::ReadCapacity16 {
alloc_len: u32::from_be_bytes([cb[10], cb[11], cb[12], cb[13]]),
},
READ_10 => ScsiCommand::Read {
lba: u32::from_be_bytes([cb[2], cb[3], cb[4], cb[5]]) as u64,
len: u16::from_be_bytes([cb[7], cb[8]]) as u64,
},
READ_16 => ScsiCommand::Read {
lba: u64::from_be_bytes((&cb[2..10]).try_into().unwrap()),
len: u32::from_be_bytes((&cb[10..14]).try_into().unwrap()) as u64,
},
WRITE_10 => ScsiCommand::Write {
lba: u32::from_be_bytes([cb[2], cb[3], cb[4], cb[5]]) as u64,
len: u16::from_be_bytes([cb[7], cb[8]]) as u64,
},
MODE_SENSE_6 => ScsiCommand::ModeSense6 {
dbd: (cb[1] & 0b00001000) != 0,
page_control: PageControl::try_from_primitive(cb[2] >> 6).unwrap(),
page_code: cb[2] & 0b00111111,
subpage_code: cb[3],
alloc_len: cb[4],
},
MODE_SENSE_10 => ScsiCommand::ModeSense10 {
dbd: (cb[1] & 0b00001000) != 0,
page_control: PageControl::try_from_primitive(cb[2] >> 6).unwrap(),
page_code: cb[2] & 0b00111111,
subpage_code: cb[3],
alloc_len: u16::from_be_bytes([cb[7], cb[8]]),
},
READ_FORMAT_CAPACITIES => ScsiCommand::ReadFormatCapacities {
alloc_len: u16::from_be_bytes([cb[7], cb[8]]),
},
_ => ScsiCommand::Unknown,
}
}

66
src/storage.rs Normal file
View File

@@ -0,0 +1,66 @@
use embassy_rp::gpio::{Input, Output};
use embassy_rp::peripherals::SPI0;
use embassy_rp::spi::{Async, Spi};
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc;
use embedded_sdmmc::asynchronous::{
Directory, SdCard as SdmmcSdCard, Volume, VolumeIdx, VolumeManager,
};
use embedded_sdmmc::blocking::{TimeSource, Timestamp};
pub const MAX_DIRS: usize = 4;
pub const MAX_FILES: usize = 5;
pub const MAX_VOLUMES: usize = 1;
type Device = ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, embassy_time::Delay>;
type SD = SdmmcSdCard<Device, embassy_time::Delay>;
type VolMgr = VolumeManager<SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub struct DummyTimeSource {}
impl TimeSource for DummyTimeSource {
fn get_timestamp(&self) -> Timestamp {
Timestamp::from_calendar(2022, 1, 1, 0, 0, 0).unwrap()
}
}
pub struct SdCard<'a> {
det: Input<'static>,
volume_mgr: VolMgr,
volume: Option<Vol<'a>>,
root: Option<Dir<'a>>,
}
impl<'a> SdCard<'a> {
pub fn new(sdcard: SD, det: Input<'static>) -> Self {
let volume_mgr = VolumeManager::<_, _, MAX_DIRS, MAX_FILES, MAX_VOLUMES>::new_with_limits(
sdcard,
DummyTimeSource {},
5000,
);
Self {
det: det,
volume_mgr,
volume: None,
root: None,
}
}
/// Returns true if an SD card is inserted.
/// The DET pin is active-low via mechanical switch in the socket.
fn attached(&self) -> bool {
self.det.is_low()
}
async fn get_root(&'a mut self) {
let vol = self.volume.as_mut().unwrap();
let root = vol.open_root_dir().unwrap();
self.root = Some(root);
}
async fn get_volume(&'a mut self) {
let vol = self.volume_mgr.open_volume(VolumeIdx(0)).await.unwrap();
self.volume = Some(vol);
}
}

37
src/usb.rs Normal file
View File

@@ -0,0 +1,37 @@
use crate::{scsi::MassStorageClass, storage::SdCard};
use embassy_futures::join::{self, join};
use embassy_rp::{
gpio::Output,
peripherals::{SPI0, USB},
spi::{Async, Spi},
usb::Driver,
};
use embassy_time::Delay;
use embassy_usb::{Builder, Config};
pub async fn usb_handler(driver: Driver<'static, USB>, mut sdcard: SdCard<'_>) {
let mut config = Config::new(0xc0de, 0xcafe);
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, sdcard);
let mut usb = builder.build();
join(usb.run(), scsi.poll()).await;
}