use crate::spi::{InnerDelay, SpiBusWrapper, SpiDev, SpiInitError, make_device};
use embedded_sdmmc::{SdCard, TimeSource, Timestamp, VolumeManager};
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::peripherals::GPIO16;
pub type SDC<'a> = SdCard<SpiDev<'a>, InnerDelay>;
#[derive(Default)]
pub struct Timesource();
impl TimeSource for Timesource {
fn get_timestamp(&self) -> Timestamp {
Timestamp {
year_since_1970: 0,
zero_indexed_month: 0,
zero_indexed_day: 0,
hours: 0,
minutes: 0,
seconds: 0,
}
}
}
pub type SdVolMgr<'a> = VolumeManager<SDC<'a>, Timesource>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SdInitError {
SpiDevice(SpiInitError),
CardReadFailed,
}
impl SdInitError {
pub const fn as_str(self) -> &'static str {
match self {
Self::SpiDevice(err) => err.as_str(),
Self::CardReadFailed => "SD card read failed",
}
}
}
pub fn init_sd<'a>(
spi_bus: &'a SpiBusWrapper,
sd_cs: GPIO16<'a>,
delay: InnerDelay,
) -> Result<SDC<'a>, SdInitError> {
let sd_cs = Output::new(sd_cs, Level::Low, OutputConfig::default());
let spi_dev = make_device(spi_bus, sd_cs, delay.clone()).map_err(SdInitError::SpiDevice)?;
let sdcard = SdCard::new(spi_dev, delay);
let mut card_size = None;
for attempt in 1..=5 {
match sdcard.num_bytes() {
Ok(size) => {
card_size = Some(size);
defmt::info!("SD: Detected on attempt {}", attempt);
break;
}
Err(_e) => {
defmt::debug!("SD: num_bytes attempt {} failed", attempt);
if attempt < 5 {
delay.delay_millis(50);
}
}
}
}
match card_size {
Some(size) => {
let size_mb = size / (1024 * 1024);
let size_gb = size / (1024 * 1024 * 1024);
if size_gb > 0 {
defmt::info!(
"SD: {}.{} GB detected",
size_gb,
(size % (1024 * 1024 * 1024)) / (100 * 1024 * 1024)
);
} else {
defmt::info!("SD: {} MB detected", size_mb);
}
}
None => defmt::warn!("SD: Card not ready during init; continuing without mounted card"),
}
Ok(sdcard)
}