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.
    TimeAsyncAccessCycles: u8,
    mask: 0x7f,
    default: 0x8,
    {
        /// 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::new()));
        assert_eq!(taac.time_value(), Ok(AccessTimeValue::new()));

        (0..=u8::MAX)
            .filter(|b| {
                AccessTimeUnit::from_raw(b & Taac::UNIT_MASK).is_ok()
                    && AccessTimeValue::from_raw((b & Taac::VALUE_MASK) >> Taac::VALUE_SHIFT)
                        .is_ok()
            })
            .for_each(|raw| {
                let exp_taac = Taac::try_from_inner(raw & Taac::MASK).unwrap();
                let exp_unit = AccessTimeUnit::from_raw(raw & Taac::UNIT_MASK).unwrap();
                let exp_value =
                    AccessTimeValue::from_raw((raw & Taac::VALUE_MASK) >> Taac::VALUE_SHIFT)
                        .unwrap();
                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| AccessTimeUnit::from_raw(b & Taac::UNIT_MASK).is_err())
            .for_each(|raw| {
                assert!(Taac::try_from_inner(raw).is_err());
                assert!(Taac::try_from(raw).is_err());
            });

        (0..=u8::MAX)
            .filter(|b| {
                AccessTimeUnit::from_raw(b & Taac::UNIT_MASK).is_ok()
                    && AccessTimeValue::from_raw((b & Taac::VALUE_MASK) >> Taac::VALUE_SHIFT)
                        .is_err()
            })
            .for_each(|raw| {
                assert!(Taac::try_from_inner(raw).is_err());
                assert!(Taac::try_from(raw).is_err());
            });
    }
}