can mount but not access
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
11
src/main.rs
11
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));
|
||||
|
||||
157
src/scsi/mod.rs
157
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<ScsiError>,
|
||||
}
|
||||
|
||||
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<u8, 64> = 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<u8, 64> = 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(&[
|
||||
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();
|
||||
])?;
|
||||
|
||||
// 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<u8, 64> = 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<u8, 64> = 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()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Spi<'static, SPI0, Async>, Output<'static>, embassy_time::Delay>;
|
||||
type Device = ExclusiveDevice<Spi<'static, SPI0, Blocking>, 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>;
|
||||
@@ -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<Vol<'_>, ()> {
|
||||
pub fn open_volume(&mut self) -> Result<Vol<'_>, ()> {
|
||||
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 {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user