firmware 0.1.0

SD card rust driver
use core::ops::ControlFlow;

use embassy_rp::gpio::Output;
use embassy_time::Delay;

use embedded_hal_bus::spi::ExclusiveDevice;

use embedded_sdmmc::{
    Mode,
    RawDirectory,
    RawVolume,
    SdCard as EmbeddedSdCard,
    TimeSource,
    Timestamp,
    VolumeIdx,
    VolumeManager,
};

use xpanse_api::bus::spi::SpiBusHandle;

use crate::SdCard;

pub type SdSpiDevice =
    ExclusiveDevice<SpiBusHandle, Output<'static>, Delay>;

pub type SdBlockDevice =
    EmbeddedSdCard<SdSpiDevice, Delay>;


pub const MAX_DIRS: usize = 4;
pub const MAX_FILES: usize = 4;
pub const MAX_VOLUMES: usize = 1;


pub struct SdTime;

impl TimeSource for SdTime {
    fn get_timestamp(&self) -> Timestamp {
        Timestamp {
            year_since_1970: 56,
            zero_indexed_month: 7,
            zero_indexed_day: 27,
            hours: 0,
            minutes: 0,
            seconds: 0,
        }
    }
}


pub type SdVolumeManager =
    VolumeManager<
        SdBlockDevice,
        SdTime,
        MAX_DIRS,
        MAX_FILES,
        MAX_VOLUMES,
    >;


pub fn create_filesystem(sd: SdCard) -> SdVolumeManager {
    let spi_device = ExclusiveDevice::new(
        sd.spi,
        sd.cs,
        Delay,
    )
    .expect("Failed to create SPI device for SD card");

    let sd_card = EmbeddedSdCard::new(
        spi_device,
        Delay,
    );

    VolumeManager::new(
        sd_card,
        SdTime,
    )
}


pub fn open_volume(
    fs: &SdVolumeManager,
) -> Result<
    RawVolume,
    embedded_sdmmc::Error<
        <SdBlockDevice as embedded_sdmmc::BlockDevice>::Error,
    >,
> {
    fs.open_raw_volume(VolumeIdx(0))
}


pub fn open_root(
    fs: &SdVolumeManager,
    volume: RawVolume,
) -> Result<
    RawDirectory,
    embedded_sdmmc::Error<
        <SdBlockDevice as embedded_sdmmc::BlockDevice>::Error,
    >,
> {
    fs.open_root_dir(volume)
}

pub fn read_file(
    fs: &SdVolumeManager,
    root_dir: RawDirectory,
    file_name: &str,
    buffer: &mut [u8],
) -> Result<
    usize,
    embedded_sdmmc::Error<
        <SdBlockDevice as embedded_sdmmc::BlockDevice>::Error,
    >,
> {
    let file = fs.open_file_in_dir(
        root_dir,
        file_name,
        Mode::ReadOnly,
    )?;

    let bytes_read = fs.read(
        file,
        buffer,
    )?;

    fs.close_file(file)?;

    Ok(bytes_read)
}


pub fn write_file(
    fs: &SdVolumeManager,
    root_dir: RawDirectory,
    file_name: &str,
    data: &[u8],
) -> Result<
    usize,
    embedded_sdmmc::Error<
        <SdBlockDevice as embedded_sdmmc::BlockDevice>::Error,
    >,
> {
    let file = fs.open_file_in_dir(
        root_dir,
        file_name,
        Mode::ReadWriteCreateOrTruncate,
    )?;

    fs.write(
        file,
        data,
    )?;

    fs.close_file(file)?;

    Ok(data.len())
}

pub fn list_root(
    fs: &SdVolumeManager,
    root_dir: RawDirectory,
) -> Result<
    (),
    embedded_sdmmc::Error<
        <SdBlockDevice as embedded_sdmmc::BlockDevice>::Error,
    >,
> {
    fs.iterate_dir(
        root_dir,
        |_entry| {
            ControlFlow::Continue(())
        },
    )?;

    Ok(())
}


pub fn close_filesystem(
    fs: &SdVolumeManager,
    volume: RawVolume,
    root_dir: RawDirectory,
) -> Result<
    (),
    embedded_sdmmc::Error<
        <SdBlockDevice as embedded_sdmmc::BlockDevice>::Error,
    >,
> {
    fs.close_dir(root_dir)?;
    fs.close_volume(volume)?;

    Ok(())
}