sdmmc/
lib.rs

1//! # sdmmc
2//!
3//! > A sdmmc implementation mainly focusing on embedded system with `no_std` and `async` support
4//!
5//! ## Using this crate
6//!
7//! Assuming you already have `SPI` struct which implements `sdmmc::spi::Transfer`
8//!
9//! ```rust
10//! let mut bus = sdmmc::bus::linux::spi(&args.spi, args.cs).map_err(|e| format!("{:?}", e))?;
11//! let card = bus.init(Delay).await.map_err(|e| format!("{:?}", e))?;
12//! debug!("Card: {:?}", card);
13//! let mut sd = SD::init(spi, card).await.map_err(|e| format!("{:?}", e))?;
14//! let size = Size::from_bytes(sd.num_blocks() as u64 * sd.block_size() as u64);
15//! debug!("Size {}", size);
16//!
17//! let options = SpidevOptions { max_speed_hz: Some(2_000_000), ..Default::default() };
18//! sd.bus(|bus| bus.spi(|spi| spi.0.configure(&options))).unwrap();
19//!
20//! let mut buffer = [0u8; 512];
21//! sd.read(0, slice::from_mut(&mut buffer).iter_mut()).await.map_err(|e| format!("{:?}", e))?;
22//! let mbr = MasterBootRecord::from_bytes(&buffer).map_err(|e| format!("{:?}", e))?;
23//! for partition in mbr.partition_table_entries().iter() {
24//!     println!("{:?}", partition);
25//! }
26//! Ok(())
27//! ```
28
29#![cfg_attr(not(any(test, feature = "std")), no_std)]
30
31extern crate alloc;
32#[macro_use]
33extern crate log;
34#[cfg(feature = "spidev")]
35extern crate spidev;
36
37pub mod bus;
38pub mod delay;
39mod sd;
40
41use bus::Error;
42pub use sd::registers::NumBlocks;
43use sd::{registers::CSD, BLOCK_SIZE};
44
45pub struct SD<BUS> {
46    bus: BUS,
47    card: sd::Card,
48    csd: CSD,
49}
50
51type LBA = u32;
52
53#[cfg_attr(not(feature = "async"), deasync::deasync)]
54impl<E, BUS> SD<BUS>
55where
56    BUS: bus::Read<Error = E> + bus::Write<Error = E> + bus::Bus<Error = E>,
57{
58    pub async fn init(mut bus: BUS, card: sd::Card) -> Result<Self, Error<E>> {
59        bus.before()?;
60        let result = bus.read_csd().await;
61        bus.after()?;
62        result.map(|csd| Self { bus, card, csd })
63    }
64
65    pub fn csd(&self) -> CSD {
66        self.csd
67    }
68
69    pub fn bus<R>(&mut self, f: impl Fn(&mut BUS) -> R) -> R {
70        f(&mut self.bus)
71    }
72
73    pub async fn read<'a, B>(&mut self, address: LBA, blocks: B) -> Result<(), Error<E>>
74    where
75        B: core::iter::ExactSizeIterator<Item = &'a mut [u8; BLOCK_SIZE]> + Send,
76    {
77        if blocks.len() == 0 {
78            return Ok(());
79        }
80        self.bus.before()?;
81        let address = if self.card.high_capacity() { address } else { address * BLOCK_SIZE as u32 };
82        let result = self.bus.read(address, blocks).await;
83        self.bus.after().and(result)
84    }
85
86    pub async fn write<'a, B>(&mut self, address: LBA, blocks: B) -> Result<(), Error<E>>
87    where
88        B: core::iter::ExactSizeIterator<Item = &'a [u8; BLOCK_SIZE]> + Send,
89    {
90        if blocks.len() == 0 {
91            return Ok(());
92        }
93        let address = if self.card.high_capacity() { address } else { address * BLOCK_SIZE as u32 };
94        self.bus.before()?;
95        let result = self.bus.write(address, blocks).await;
96        self.bus.after().and(result)
97    }
98
99    pub fn num_blocks(&self) -> NumBlocks {
100        self.csd.num_blocks()
101    }
102
103    pub fn block_size_shift(&self) -> u8 {
104        self.csd.block_size_shift()
105    }
106}