1#![doc = include_str!("../README.md")]
2#![doc(hidden)]
3#![cfg_attr(not(any(test, feature = "std")), no_std)]
4
5#[cfg(all(feature = "async", feature = "async-trait"))]
6extern crate alloc;
7#[macro_use]
8extern crate log;
9#[cfg(feature = "spidev")]
10extern crate spidev;
11
12pub mod bus;
13pub mod delay;
14mod sd;
15
16use bus::Error;
17pub use sd::registers::NumBlocks;
18use sd::{registers::CSD, BLOCK_SIZE};
19
20pub struct SD<BUS> {
21 bus: BUS,
22 card: sd::Card,
23 csd: CSD,
24}
25
26type LBA = u32;
27
28#[cfg_attr(not(feature = "async"), deasync::deasync)]
29impl<E, BUS> SD<BUS>
30where
31 BUS: bus::Read<Error = E> + bus::Write<Error = E> + bus::Bus<Error = E>,
32{
33 pub async fn init(mut bus: BUS, card: sd::Card) -> Result<Self, Error<E>> {
34 bus.before()?;
35 let result = bus.read_csd().await;
36 bus.after()?;
37 result.map(|csd| Self { bus, card, csd })
38 }
39
40 pub fn csd(&self) -> CSD {
41 self.csd
42 }
43
44 pub fn bus<R>(&mut self, f: impl Fn(&mut BUS) -> R) -> R {
45 f(&mut self.bus)
46 }
47
48 pub async fn read<'a, B>(&mut self, address: LBA, blocks: B) -> Result<(), Error<E>>
49 where
50 B: core::iter::ExactSizeIterator<Item = &'a mut [u8; BLOCK_SIZE]> + Send,
51 {
52 if blocks.len() == 0 {
53 return Ok(());
54 }
55 self.bus.before()?;
56 let address = if self.card.high_capacity() { address } else { address * BLOCK_SIZE as u32 };
57 let result = self.bus.read(address, blocks).await;
58 self.bus.after().and(result)
59 }
60
61 pub async fn write<'a, B>(&mut self, address: LBA, blocks: B) -> Result<(), Error<E>>
62 where
63 B: core::iter::ExactSizeIterator<Item = &'a [u8; BLOCK_SIZE]> + Send,
64 {
65 if blocks.len() == 0 {
66 return Ok(());
67 }
68 let address = if self.card.high_capacity() { address } else { address * BLOCK_SIZE as u32 };
69 self.bus.before()?;
70 let result = self.bus.write(address, blocks).await;
71 self.bus.after().and(result)
72 }
73
74 pub fn num_blocks(&self) -> NumBlocks {
75 self.csd.num_blocks()
76 }
77
78 pub fn block_size_shift(&self) -> u8 {
79 self.csd.block_size_shift()
80 }
81}