sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
use crate::lib_bitfield;
use crate::result::{Error, Result};

mod time_unit;
mod time_value;

pub use time_unit::AccessTimeUnit;
pub use time_value::AccessTimeValue;

lib_bitfield! {
    /// Represents the asynchronous part of the data access time.
    ///
    /// This structure is used for the `TAAC` field in `CSD` V2, V3, and future fixed value variants.
    TimeAsyncAccessCycles: u8,
    mask: 0x7f,
    default: 0xe,
    {
        /// Represents the [AccessTimeValue] for the [TimeAsyncAccessCycles].
        time_value: AccessTimeValue, 6, 3;
        /// Represents the [AccessTimeUnit] for the [TimeAsyncAccessCycles].
        time_unit: AccessTimeUnit, 2, 0;
    }
}

impl TimeAsyncAccessCycles {
    /// Represents the bitmask for the `time_unit` sub-field.
    pub const UNIT_MASK: u8 = 0x7;
    /// Represents the bitmask for the `time_value` sub-field.
    pub const VALUE_MASK: u8 = 0x78;
    /// Represents the bitshift for the `time_value` sub-field.
    pub const VALUE_SHIFT: usize = 3;

    /// Gets the total time (in nanoseconds) for the [TimeAsyncAccessCycles].
    pub const fn time_ns(&self) -> u32 {
        match (self.time_value(), self.time_unit()) {
            (Ok(time_value), Ok(time_unit)) => (time_value.value_int() * time_unit.ns()) / 10,
            _ => 0,
        }
    }
}

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

    type Taac = TimeAsyncAccessCycles;

    #[test]
    fn test_valid() {
        let taac = Taac::new();

        assert_eq!(taac.time_unit(), Ok(AccessTimeUnit::Ms1));
        assert_eq!(taac.time_value(), Ok(AccessTimeValue::Value10));

        let raw = Taac::DEFAULT;
        let exp_taac = Taac::try_from_inner(raw & Taac::MASK).unwrap();
        let exp_unit = AccessTimeUnit::Ms1;
        let exp_value = AccessTimeValue::Value10;
        let exp_ns = (exp_value.value_int() * exp_unit.ns()) / 10;

        assert_eq!(Taac::try_from_inner(raw), Ok(exp_taac));
        assert_eq!(Taac::try_from(raw), Ok(exp_taac));

        assert_eq!(exp_taac.bits(), raw & Taac::MASK);
        assert_eq!(u8::from(exp_taac), raw & Taac::MASK);

        assert_eq!(exp_taac.time_unit(), Ok(exp_unit));
        assert_eq!(exp_taac.time_value(), Ok(exp_value));
        assert_eq!(exp_taac.time_ns(), exp_ns);
    }

    #[test]
    fn test_invalid() {
        (0..=u8::MAX)
            .filter(|b| (b & Taac::MASK) != Taac::DEFAULT)
            .for_each(|raw| {
                assert!(Taac::try_from_inner(raw).is_err());
                assert!(Taac::try_from(raw).is_err());
            });
    }
}