sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
use crate::lib_bitfield;

use super::{ExtCsd, ExtCsdIndex};

lib_bitfield! {
    /// Represents the `SEC_COUNT` field of the [ExtCsd] register.
    SectorCount: u32,
    mask: 0xffff_ffff,
    default: 0,
    {
        /// Indicates the sector count of the device.
        count: 31, 0;
    }
}

impl SectorCount {
    /// Represents the density multiplier (bytes-per-sector).
    pub const DENSITY: u64 = 512;

    /// Gets the device density in bytes (assuming 512B sectors).
    ///
    /// # Note
    ///
    /// The density is caculated with the following algorithm:
    ///
    /// ```no_build,no_run
    /// density = SEC_COUNT * 512B
    /// ```
    #[inline]
    pub const fn density(&self) -> u64 {
        (self.count() as u64) * Self::DENSITY
    }
}

impl ExtCsd {
    /// Gets the `SEC_COUNT` field of the [ExtCsd] register.
    pub const fn sec_count(&self) -> SectorCount {
        let start = ExtCsdIndex::SEC_COUNT_START;
        let raw = u32::from_le_bytes([
            self.0[start],
            self.0[start + 1],
            self.0[start + 2],
            self.0[start + 3],
        ]);
        SectorCount::from_inner(raw)
    }

    /// Sets the `SEC_COUNT` field of the [ExtCsd] register.
    pub(crate) fn set_sec_count(&mut self, val: SectorCount) {
        let start = ExtCsdIndex::SEC_COUNT_START;

        let [s0, s1, s2, s3] = val.into_inner().to_le_bytes();

        self.0[start] = s0;
        self.0[start + 1] = s1;
        self.0[start + 2] = s2;
        self.0[start + 3] = s3;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_sec_count() {
        let mut ext_csd = ExtCsd::new();

        assert_eq!(ext_csd.sec_count(), SectorCount::new());

        (0..=u32::BITS)
            .map(|r| SectorCount::from_inner(((1u64 << r) - 1) as u32))
            .for_each(|sec_count| {
                ext_csd.set_sec_count(sec_count);
                assert_eq!(ext_csd.sec_count(), sec_count);
                assert_eq!(
                    sec_count.density(),
                    (sec_count.into_inner() as u64) * SectorCount::DENSITY
                );
            });
    }
}