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