sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
use crate::response::sd::r7::VoltageAccepted;
use crate::response::spi::r1::R1;
use crate::result::{Error, Result};
use crate::{lib_bitfield, response};

lib_bitfield! {
    /// Represents the response to the `SEND_IF_COND` command (`CMD8`) in SPI mode.
    pub R7(MSB0 [u8; 5]): u8 {
        raw_r1: 39, 32;
        pub command_version: 31, 28;
        raw_voltage_accepted: 11, 8;
        pub echo_check: 7, 0;
    }
}

response! {
    R7 {
        response_mode: Spi,
    }
}

impl R7 {
    /// Represents the byte length of the [R7] response.
    pub const LEN: usize = 5;
    /// Represents the default byte value of the [R7] response.
    pub const DEFAULT: [u8; Self::LEN] = [0, 0, 0, 0x1, 0];

    /// Creates a new [R7].
    pub const fn new() -> Self {
        Self(Self::DEFAULT)
    }

    /// Gets the [R1] for the [R7].
    pub const fn r1(&self) -> Result<R1> {
        R1::try_from_bits(self.raw_r1())
    }

    /// Sets the [R1] for the [R7].
    pub fn set_r1(&mut self, r1: R1) {
        self.set_raw_r1(r1.bits());
    }

    /// Gets the [VoltageAccepted] value of the [R7] response.
    pub const fn voltage_accepted(&self) -> Result<VoltageAccepted> {
        VoltageAccepted::from_raw(self.raw_voltage_accepted())
    }

    /// Sets the [VoltageAccepted] value of the [R7] response.
    pub fn set_voltage_accepted(&mut self, voltage_accepted: VoltageAccepted) {
        self.set_raw_voltage_accepted(voltage_accepted.into_raw());
    }

    /// Attempts to convert a byte slice into a [R7].
    pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
        match val.len() {
            len if len < Self::LEN => Err(Error::invalid_length(len, Self::LEN)),
            _ => match R7([val[0], val[1], val[2], val[3], val[4]]) {
                r7 if r7.r1().is_err() => {
                    Err(Error::invalid_field_variant("r7::r1", r7.raw_r1() as usize))
                }
                r7 if r7.voltage_accepted().is_err() => Err(Error::invalid_field_variant(
                    "r7::voltage_accepted",
                    r7.raw_voltage_accepted() as usize,
                )),
                r7 => Ok(r7),
            },
        }
    }
}

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

impl TryFrom<&[u8]> for R7 {
    type Error = Error;

    fn try_from(val: &[u8]) -> Result<Self> {
        Self::try_from_bytes(val)
    }
}

impl<const N: usize> TryFrom<[u8; N]> for R7 {
    type Error = Error;

    fn try_from(val: [u8; N]) -> Result<Self> {
        Self::try_from_bytes(val.as_ref())
    }
}

impl<const N: usize> TryFrom<&[u8; N]> for R7 {
    type Error = Error;

    fn try_from(val: &[u8; N]) -> Result<Self> {
        Self::try_from_bytes(val.as_ref())
    }
}

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

    #[test]
    fn test_fields() {
        let mut r7 = R7::new();

        assert_eq!(r7.r1(), Ok(R1::new()));
        assert_eq!(r7.command_version(), 0);
        assert_eq!(r7.voltage_accepted(), Ok(VoltageAccepted::new()));
        assert_eq!(r7.echo_check(), 0);

        (0..=u8::MAX)
            .zip(0..=u8::MAX)
            .map(|(r1, cmd)| (r1, cmd & 0xf))
            .zip(0..=u8::MAX)
            .map(|(s, va)| (s, va & 0xf))
            .zip(0..=u8::MAX)
            .for_each(|(((r1, cmd), va), echo)| {
                let raw = [r1, cmd << 4, 0, va, echo];

                match (R1::try_from_bits(r1), VoltageAccepted::from_raw(va)) {
                    (Ok(r1), Ok(va)) => {
                        r7 = R7(raw);

                        assert_eq!(R7::try_from_bytes(raw.as_ref()), Ok(r7));
                        assert_eq!(R7::try_from(raw), Ok(r7));

                        assert_eq!(r7.r1(), Ok(r1));
                        assert_eq!(r7.command_version(), cmd);
                        assert_eq!(r7.voltage_accepted(), Ok(va));
                        assert_eq!(r7.echo_check(), echo);

                        r7.set_r1(R1::new());
                        assert_eq!(r7.r1(), Ok(R1::new()));

                        r7.set_r1(r1);
                        assert_eq!(r7.r1(), Ok(r1));

                        r7.set_command_version(0);
                        assert_eq!(r7.command_version(), 0);

                        r7.set_command_version(cmd);
                        assert_eq!(r7.command_version(), cmd);

                        r7.set_echo_check(0);
                        assert_eq!(r7.echo_check(), 0);

                        r7.set_echo_check(echo);
                        assert_eq!(r7.echo_check(), echo);

                        r7.set_voltage_accepted(VoltageAccepted::new());
                        assert_eq!(r7.voltage_accepted(), Ok(VoltageAccepted::new()));

                        r7.set_voltage_accepted(va);
                        assert_eq!(r7.voltage_accepted(), Ok(va));
                    }
                    (Err(_), _) => {
                        assert_eq!(
                            R7::try_from_bytes(raw.as_ref()),
                            Err(Error::invalid_field_variant("r7::r1", r1 as usize))
                        );
                        assert_eq!(
                            R7::try_from(raw),
                            Err(Error::invalid_field_variant("r7::r1", r1 as usize))
                        );
                    }
                    (_, Err(_)) => {
                        assert_eq!(
                            R7::try_from_bytes(raw.as_ref()),
                            Err(Error::invalid_field_variant(
                                "r7::voltage_accepted",
                                va as usize
                            ))
                        );
                        assert_eq!(
                            R7::try_from(raw),
                            Err(Error::invalid_field_variant(
                                "r7::voltage_accepted",
                                va as usize
                            ))
                        );
                    }
                }
            });
    }
}