From 60ed910a889a156003dd1da296d3ee52cbb098ab Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 28 Jul 2025 12:57:50 -0600 Subject: [PATCH] can mount but not access --- Cargo.lock | 24 +----- Cargo.toml | 2 +- src/main.rs | 11 +-- src/scsi/mod.rs | 165 +++++++++++++++++++++++++++-------------- src/scsi/scsi_types.rs | 8 ++ src/storage.rs | 49 +++++++----- 6 files changed, 151 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c447be..f22d25c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,21 +87,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "bisync" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5020822f6d6f23196ccaf55e228db36f9de1cf788052b37992e17cbc96ec41a7" -dependencies = [ - "bisync_macros", -] - -[[package]] -name = "bisync_macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d21f40d350a700f6aa107e45fb26448cf489d34794b2ba4522181dc9f1173af6" - [[package]] name = "bit-set" version = "0.5.3" @@ -818,17 +803,14 @@ dependencies = [ [[package]] name = "embedded-sdmmc" -version = "0.8.0" -source = "git+https://github.com/Be-ing/embedded-sdmmc-rs?branch=bisync#835b2e4f9d3482b6287f674d7ecf6ae5d0618c18" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce3c7f9ea039eeafc4a49597b7bd5ae3a1c8e51b2803a381cb0f29ce90fe1ec6" dependencies = [ - "bisync", "byteorder", "defmt 0.3.100", - "embassy-futures", "embedded-hal 1.0.0", - "embedded-hal-async", "embedded-io", - "embedded-io-async", "heapless", ] diff --git a/Cargo.toml b/Cargo.toml index 94c83a7..71ceef4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ defmt = { version = "0.3", optional = true } defmt-rtt = "0.4.2" embedded-graphics = { version = "0.8.1" } -embedded-sdmmc = { git = "https://github.com/Be-ing/embedded-sdmmc-rs", branch = "bisync", default-features = false } +embedded-sdmmc = { version = "0.9", default-features = false } st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", branch = "async" } static_cell = "2.1.1" diff --git a/src/main.rs b/src/main.rs index 03c90fc..40da69f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,7 @@ use embassy_sync::mutex::Mutex; use embassy_time::{Delay, Timer}; use embedded_graphics::primitives::Rectangle; use embedded_hal_bus::spi::ExclusiveDevice; -use embedded_sdmmc::asynchronous::SdCard as SdmmcSdCard; +use embedded_sdmmc::SdCard as SdmmcSdCard; use heapless::String; mod peripherals; @@ -66,25 +66,18 @@ async fn main(_spawner: Spawner) { let sdcard = { let mut config = spi::Config::default(); config.frequency = 400_000; - let mut spi = Spi::new( + let spi = Spi::new_blocking( p.SPI0, p.PIN_18, // clk p.PIN_19, // mosi p.PIN_16, // miso - p.DMA_CH2, - p.DMA_CH3, config.clone(), ); let cs = Output::new(p.PIN_17, Level::High); let det = Input::new(p.PIN_22, Pull::None); let device = ExclusiveDevice::new(spi, cs, Delay).unwrap(); - Timer::after_millis(500).await; let sdcard = SdmmcSdCard::new(device, Delay); - while sdcard.num_bytes().await.is_err() { - Timer::after_millis(250).await; - defmt::error!("Sd init failed, trying again"); - } config.frequency = 32_000_000; sdcard.spi(|dev| dev.bus_mut().set_config(&config)); diff --git a/src/scsi/mod.rs b/src/scsi/mod.rs index 464140a..da127fb 100644 --- a/src/scsi/mod.rs +++ b/src/scsi/mod.rs @@ -2,6 +2,7 @@ use crate::format; use embassy_usb::driver::{Driver, EndpointIn, EndpointOut}; use embassy_usb::types::StringIndex; use embassy_usb::{Builder, Config}; +use embedded_sdmmc::{Block, BlockIdx}; use heapless::Vec; mod scsi_types; @@ -13,13 +14,14 @@ pub struct MassStorageClass<'d, D: Driver<'d>> { sdcard: SdCard, bulk_out: D::EndpointOut, bulk_in: D::EndpointIn, + last_sense: Option, } impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { pub fn new(builder: &mut Builder<'d, D>, sdcard: SdCard) -> Self { - let mut function = builder.function(0x08, 0x06, 0x50); // Mass Storage class + let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class let mut interface = function.interface(); - let mut alt = interface.alt_setting(0x08, 0x06, 0x50, None); + let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None); let bulk_out = alt.endpoint_bulk_out(64); let bulk_in = alt.endpoint_bulk_in(64); @@ -28,6 +30,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { bulk_out, bulk_in, sdcard, + last_sense: None, } } @@ -50,6 +53,9 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { } async fn handle_command(&mut self, cbw: &[u8]) -> Result<(), ()> { + let mut response: Vec = Vec::new(); + let mut block = [Block::new(); 1]; + match parse_cb(cbw) { ScsiCommand::Unknown => { #[cfg(feature = "defmt")] @@ -61,26 +67,17 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { page_code, alloc_len, } => { - #[cfg(feature = "defmt")] - defmt::info!( - "SCSI INQUIRY: evpd={}, page_code=0x{:02x}, alloc_len={}", - evpd, - page_code, - alloc_len - ); - - let mut response: Vec = Vec::new(); if !evpd { - response.push(0x00).unwrap(); // Direct-access block device - response.push(0x80).unwrap(); // Removable - response.push(0x05).unwrap(); // SPC-3 compliance - response.push(0x02).unwrap(); // Response data format - response.push(0).unwrap(); // Additional length + response.push(0x00).map_err(|_| ())?; // Direct-access block device + response.push(0x80).map_err(|_| ())?; // Removable + response.push(0x05).map_err(|_| ())?; // SPC-3 compliance + response.push(0x02).map_err(|_| ())?; // Response data format + response.push(0).map_err(|_| ())?; // Additional length // Vendor ID (8 bytes) - response.extend_from_slice(b"RUSTUSB ").unwrap(); + response.extend_from_slice(b"LEGTCMPR")?; // Product ID (16 bytes) - response.extend_from_slice(b"Mass Storage ").unwrap(); + response.extend_from_slice(b"Pico Calc Sdcard")?; // Product Revision (4 bytes): encode volume size in GB let size_bytes = self.sdcard.size(); @@ -88,36 +85,42 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { let rev_str = format!(4, "{}", size_gb); let rev_bytes = rev_str.as_bytes(); - response - .extend_from_slice(&[ - *rev_bytes.get(0).unwrap_or(&b'0'), - *rev_bytes.get(1).unwrap_or(&b'0'), - *rev_bytes.get(2).unwrap_or(&b'0'), - *rev_bytes.get(3).unwrap_or(&b'0'), - ]) - .unwrap(); + response.extend_from_slice(&[ + *rev_bytes.get(0).unwrap_or(&b'0'), + *rev_bytes.get(1).unwrap_or(&b'0'), + *rev_bytes.get(2).unwrap_or(&b'0'), + *rev_bytes.get(3).unwrap_or(&b'0'), + ])?; - // Now fix up the Additional Length let addl_len = response.len() - 5; response[4] = addl_len as u8; } else { match page_code { 0x00 => { response - .extend_from_slice(&[0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x83]) - .unwrap(); + .extend_from_slice(&[ + 0x00, // Peripheral Qualifier + Peripheral Device Type (0x00 = Direct-access block device) + 0x00, // Page Code (same as requested: 0x00) + 0x00, 0x03, // Page Length: 3 bytes follow + 0x00, // Supported VPD Page: 0x00 (this one — the "Supported VPD Pages" page itself) + 0x80, // Supported VPD Page: 0x80 (Unit Serial Number) + 0x83, // Supported VPD Page: 0x83 (Device Identification) + ]) + .map_err(|_| ())? } 0x80 => { - let serial = b"RUST1234"; - let mut data: Vec = Vec::new(); - data.extend_from_slice(&[0x00, 0x80, 0x00, serial.len() as u8]) - .unwrap(); - data.extend_from_slice(serial).unwrap(); + let serial = b"Pico Calc"; + response.extend_from_slice(&[ + 0x00, // Peripheral Qualifier & Device Type + 0x80, // Page Code = 0x80 (Unit Serial Number) + 0x00, // Reserved + serial.len() as u8, + ])?; + response.extend_from_slice(serial)?; } 0x83 => { - let id = b"RUSTVOL1"; - let mut data: Vec = Vec::new(); - data.extend_from_slice(&[ + let id = b"SdCard"; + response.extend_from_slice(&[ 0x00, 0x83, // Page code 0x00, @@ -126,9 +129,8 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { 0x01, // Identifier type 0x00, // Reserved id.len() as u8, - ]) - .unwrap(); - data.extend_from_slice(id).unwrap(); + ])?; + response.extend_from_slice(id)?; } _ => (), } @@ -144,38 +146,87 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { Err(()) } } - ScsiCommand::RequestSense { desc, alloc_len } => todo!(), + ScsiCommand::RequestSense { desc, alloc_len } => Ok(()), ScsiCommand::ModeSense6 { dbd, page_control, page_code, subpage_code, alloc_len, - } => todo!(), + } => Ok(()), ScsiCommand::ModeSense10 { dbd, page_control, page_code, subpage_code, alloc_len, - } => todo!(), + } => Ok(()), ScsiCommand::ReadCapacity10 => { - const block_size: u64 = 512; + let block_size = SdCard::BLOCK_SIZE as u64; let total_blocks = self.sdcard.size() / block_size; - defmt::info!("total size: {}", self.sdcard.size()); let last_lba = total_blocks - 1; - let mut resp = [0u8; 8]; - resp[0..4].copy_from_slice(&(last_lba as u32).to_be_bytes()); - resp[4..8].copy_from_slice(&(block_size as u32).to_be_bytes()); + response.extend_from_slice(&(last_lba as u32).to_be_bytes())?; + response.extend_from_slice(&(block_size as u32).to_be_bytes())?; - self.bulk_in.write(&resp).await.map_err(|_| ()) + self.bulk_in.write(&response).await.map_err(|_| ()) + } + ScsiCommand::ReadCapacity16 { alloc_len } => { + let block_size = SdCard::BLOCK_SIZE as u64; + let total_blocks = self.sdcard.size() / block_size; + + let last_lba = total_blocks.checked_sub(1).unwrap_or(0); + + response.extend_from_slice(&last_lba.to_be_bytes()); // 8 bytes last LBA + response.extend_from_slice(&(block_size as u32).to_be_bytes()); // 4 bytes block length + response.extend_from_slice(&[0u8; 20]); // 20 reserved bytes zeroed + + let len = alloc_len.min(response.len() as u32) as usize; + self.bulk_in.write(&response[..len]).await.map_err(|_| ()) + } + ScsiCommand::Read { lba, len } => { + for i in 0..len { + let block_idx = BlockIdx(lba as u32 + i as u32); + self.sdcard.read_blocks(&mut block, block_idx); + self.bulk_in + .write(&block[0].contents) + .await + .map_err(|_| ())?; + } + Ok(()) + } + ScsiCommand::Write { lba, len } => { + for i in 0..len { + let block_idx = BlockIdx(lba as u32 + i as u32); + self.bulk_out + .read(&mut block[0].contents) + .await + .map_err(|_| ())?; + self.sdcard.write_blocks(&mut block, block_idx); + } + Ok(()) + } + ScsiCommand::ReadFormatCapacities { alloc_len } => { + let block_size = SdCard::BLOCK_SIZE as u32; + let num_blocks = (self.sdcard.size() / block_size as u64) as u32; + + let mut response = [0u8; 12]; + + // Capacity List Length (8 bytes follows) + response[3] = 8; + + // Descriptor + response[4..8].copy_from_slice(&num_blocks.to_be_bytes()); + response[8] = 0x02; // formatted media + response[9..12].copy_from_slice(&block_size.to_be_bytes()[1..4]); // only 3 bytes + + let response_len = alloc_len.min(response.len() as u16) as usize; + self.bulk_in + .write(&response[..response_len]) + .await + .map_err(|_| ()) } - ScsiCommand::ReadCapacity16 { alloc_len } => todo!(), - ScsiCommand::Read { lba, len } => todo!(), - ScsiCommand::Write { lba, len } => todo!(), - ScsiCommand::ReadFormatCapacities { alloc_len } => todo!(), } } @@ -213,18 +264,18 @@ impl CommandBlockWrapper { if buf.len() < 31 { return None; } - let dCBWSignature = u32::from_le_bytes(buf[0..4].try_into().unwrap()); + let dCBWSignature = u32::from_le_bytes(buf[0..4].try_into().ok()?); 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()), + dCBWTag: u32::from_le_bytes(buf[4..8].try_into().ok()?), + dCBWDataTransferLength: u32::from_le_bytes(buf[8..12].try_into().ok()?), bmCBWFlags: buf[12], bCBWLUN: buf[13], bCBWCBLength: buf[14], - CBWCB: buf[15..31].try_into().unwrap(), + CBWCB: buf[15..31].try_into().ok()?, }) } } diff --git a/src/scsi/scsi_types.rs b/src/scsi/scsi_types.rs index 99dce71..20a070f 100644 --- a/src/scsi/scsi_types.rs +++ b/src/scsi/scsi_types.rs @@ -1,5 +1,13 @@ use num_enum::TryFromPrimitive; +#[derive(Debug, Clone, Copy)] +pub enum ScsiError { + IllegalRequest { asc: u8, ascq: u8 }, + NotReady { asc: u8, ascq: u8 }, + MediumError { asc: u8, ascq: u8 }, + // Add others as needed +} + /// THE CODE BELOW ORIGINATES FROM: https://github.com/apohrebniak/usbd-storage/blob/master/usbd-storage/src/subclass/scsi.rs /// SCSI device subclass code diff --git a/src/storage.rs b/src/storage.rs index 991367c..f41a56b 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,19 +1,19 @@ use embassy_futures::block_on; use embassy_rp::gpio::{Input, Output}; use embassy_rp::peripherals::SPI0; -use embassy_rp::spi::{Async, Spi}; +use embassy_rp::spi::{Blocking, Spi}; use embedded_hal_bus::spi::ExclusiveDevice; -use embedded_sdmmc; -use embedded_sdmmc::asynchronous::{ - BlockCount, BlockDevice, Directory, SdCard as SdmmcSdCard, Volume, VolumeIdx, VolumeManager, +use embedded_sdmmc::{self, Block, BlockIdx}; +use embedded_sdmmc::{ + BlockCount, BlockDevice, Directory, SdCard as SdmmcSdCard, TimeSource, Timestamp, 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, Output<'static>, embassy_time::Delay>; +type Device = ExclusiveDevice, Output<'static>, embassy_time::Delay>; type SD = SdmmcSdCard; type VolMgr = VolumeManager; type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; @@ -32,12 +32,11 @@ pub struct SdCard { } impl SdCard { + pub const BLOCK_SIZE: u16 = 512; + pub fn new(sdcard: SD, det: Input<'static>) -> Self { - block_on(sdcard.get_card_type()).unwrap(); - defmt::info!( - "Card size is {} bytes", - block_on(sdcard.num_bytes()).unwrap() - ); + sdcard.get_card_type().unwrap(); + defmt::info!("Card size is {} bytes", sdcard.num_bytes().unwrap()); let volume_mgr = VolumeManager::<_, _, MAX_DIRS, MAX_FILES, MAX_VOLUMES>::new_with_limits( sdcard, DummyTimeSource {}, @@ -55,13 +54,9 @@ impl SdCard { self.det.is_low() } - pub async fn open_volume(&mut self) -> Result, ()> { + pub fn open_volume(&mut self) -> Result, ()> { if self.is_attached() { - return Ok(self - .volume_mgr - .open_volume(VolumeIdx(0)) - .await - .map_err(|_| ())?); + return Ok(self.volume_mgr.open_volume(VolumeIdx(0)).map_err(|_| ())?); } Err(()) } @@ -70,21 +65,35 @@ impl SdCard { let mut result = 0; self.volume_mgr.device(|sd| { - result = block_on(sd.num_bytes()).unwrap_or(0); + result = sd.num_bytes().unwrap_or(0); DummyTimeSource {} }); result } - pub fn blocks(&self) -> u32 { + pub fn num_blocks(&self) -> u32 { let mut result = 0; self.volume_mgr.device(|sd| { - result = block_on(sd.num_blocks()).unwrap_or(BlockCount(0)).0; + result = sd.num_blocks().unwrap_or(BlockCount(0)).0; DummyTimeSource {} }); result } + + pub fn read_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) { + self.volume_mgr.device(|sd| { + sd.read(blocks, start_block_idx); + DummyTimeSource {} + }); + } + + pub fn write_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) { + self.volume_mgr.device(|sd| { + sd.write(blocks, start_block_idx); + DummyTimeSource {} + }); + } }