sdmmc-core 0.5.0

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

mod io_current_state;

pub use io_current_state::*;

lib_bitfield! {
    /// Represents the response flags for the [R5](super::R5) response in SD mode.
    pub Flags(u8): u8 {
        /// CRC check failed from previous command.
        pub crc_error: 7;
        /// Command not legal for the card state.
        pub illegal_command: 6;
        raw_io_current_state: 5, 4;
        /// A general or unknown error occurred.
        pub error: 3;
        /// An invalid function number requested.
        pub function_number: 1;
        /// Command argument out of range for this card.
        pub out_of_range: 0;
    }
}

impl Flags {
    /// Creates a new [Flags].
    pub const fn new() -> Self {
        Self(0)
    }

    /// Gets the `IO_CURRENT_STATE` field of [Flags].
    pub const fn io_current_state(&self) -> Result<IoCurrentState> {
        IoCurrentState::from_raw(self.raw_io_current_state())
    }

    /// Sets the `IO_CURRENT_STATE` field of [Flags].
    pub fn set_io_current_state(&mut self, val: IoCurrentState) {
        self.set_raw_io_current_state(val.into_raw())
    }

    /// Attempts to convert a [`u8`] into a [Flags].
    pub const fn try_from_bits(val: u8) -> Result<Self> {
        let flags = Self(val);

        match flags.io_current_state() {
            Ok(_) => Ok(flags),
            Err(_) => Err(Error::invalid_field_variant(
                "r5::flags::io_current_state",
                flags.raw_io_current_state() as usize,
            )),
        }
    }
}

impl Default for Flags {
    fn default() -> Self {
        Self::new()
    }
}

impl From<Flags> for u8 {
    fn from(val: Flags) -> Self {
        val.bits()
    }
}

impl TryFrom<u8> for Flags {
    type Error = Error;

    fn try_from(val: u8) -> Result<Self> {
        Self::try_from_bits(val)
    }
}

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

    #[test]
    fn test_valid() {
        let mut flags = Flags::new();

        test_field!(flags, out_of_range: 0);
        test_field!(flags, function_number: 1);
        test_field!(flags, error: 3);
        test_field!(flags, illegal_command: 6);
        test_field!(flags, crc_error: 7);

        [
            IoCurrentState::Disabled,
            IoCurrentState::Command,
            IoCurrentState::Transfer,
        ]
        .into_iter()
        .for_each(|io_cs| {
            let raw_io_cs = io_cs.into_raw();
            let mut exp_flags = Flags(raw_io_cs << 4);
            assert_eq!(Flags::try_from_bits(raw_io_cs << 4), Ok(exp_flags));
            assert_eq!(exp_flags.io_current_state(), Ok(io_cs));

            exp_flags.set_io_current_state(IoCurrentState::new());
            assert_eq!(exp_flags.io_current_state(), Ok(IoCurrentState::new()));
        });
    }

    #[test]
    fn test_invalid() {
        let raw_io_cs = [
            IoCurrentState::Disabled,
            IoCurrentState::Command,
            IoCurrentState::Transfer,
        ]
        .map(|r| r.into_raw());

        (0..=u8::MAX)
            .filter(|b| !raw_io_cs.iter().any(|&c| ((b >> 4) & 0x3) == c))
            .for_each(|invalid_bits| {
                let invalid_io_cs = (invalid_bits >> 4) & 0x3;

                assert_eq!(
                    Flags::try_from_bits(invalid_bits),
                    Err(Error::invalid_field_variant(
                        "r5::flags::io_current_state",
                        invalid_io_cs as usize
                    )),
                );
            });
    }
}