sdmmc-core 0.5.0

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

lib_bitfield! {
    /// Represents the response to the `IO_RW_DIRECT` command (`CMD52`) in SPI mode.
    pub R5(u16): u8 {
        raw_r1: 15, 8;
        raw_data: 7, 0;
    }
}

response! {
    R5 {
        response_mode: Spi,
    }
}

impl R5 {
    /// Represents the byte length of the [R5] response.
    pub const LEN: usize = 2;
    /// Represents the default value of the [R5] response.
    pub const DEFAULT: u16 = 0;

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

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

    /// Sets the [R1] field of the [R5].
    pub fn set_r1(&mut self, val: R1) {
        self.set_raw_r1(val.bits() as u16);
    }

    /// Gets the read/write `data` field of the [R5].
    pub const fn data(&self) -> u8 {
        self.raw_data()
    }

    /// Sets the read/write `data` field of the [R5].
    pub fn set_data(&mut self, val: u8) {
        self.set_raw_data(val as u16);
    }

    /// Attempts to convert a [`u16`] into a [R5].
    pub const fn try_from_bits(val: u16) -> Result<Self> {
        Self::try_from_bytes(&val.to_be_bytes())
    }

    /// Gets the byte value of the [R5].
    pub const fn bytes(&self) -> [u8; Self::LEN] {
        self.0.to_be_bytes()
    }

    /// Attempts to convert a byte slice into a [R5].
    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)),
            _ if R1::try_from_bits(val[0]).is_err() => {
                Err(Error::invalid_field_variant("r5::r1", val[0] as usize))
            }
            _ => Ok(Self(u16::from_be_bytes([val[0], val[1]]))),
        }
    }
}

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

impl TryFrom<u16> for R5 {
    type Error = Error;

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

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

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

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

impl<const N: usize> TryFrom<[u8; N]> for R5 {
    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 R5 {
    type Error = Error;

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

impl From<R5> for [u8; R5::LEN] {
    fn from(val: R5) -> Self {
        val.bytes()
    }
}

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

    #[test]
    fn test_fields() {
        let r5 = R5::new();

        let r1 = r5.r1().unwrap();

        assert!(!r1.idle());
        assert!(!r1.illegal_command());
        assert!(!r1.crc_error());
        assert!(!r1.function_number_error());
        assert!(!r1.parameter_error());

        assert_eq!(r5.data(), 0);

        (0..=u8::MAX).zip(0..=u8::MAX).for_each(|(r1, data)| {
            let raw = [r1, data];
            let raw_r5 = u16::from_be_bytes(raw);

            match R5::try_from_bytes(raw.as_ref()) {
                Ok(mut r5) => {
                    assert_eq!(R5::try_from_bytes(raw.as_ref()), Ok(r5));
                    assert_eq!(R5::try_from(raw), Ok(r5));

                    let mut r1 = r5.r1().unwrap();

                    test_field!(r1, idle: 0);
                    test_field!(r1, illegal_command: 2);
                    test_field!(r1, crc_error: 3);
                    test_field!(r1, function_number_error: 4);
                    test_field!(r1, parameter_error: 6);

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

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

                    assert_eq!(r5.data(), data);

                    r5.set_data(0);
                    assert_eq!(r5.data(), 0);

                    r5.set_data(data);
                    assert_eq!(r5.data(), data);
                }
                Err(_) => {
                    assert_eq!(
                        R5::try_from_bytes(raw.as_ref()),
                        Err(Error::invalid_field_variant("r5::r1", r1 as usize))
                    );
                    assert_eq!(
                        R5::try_from(raw),
                        Err(Error::invalid_field_variant("r5::r1", r1 as usize))
                    );
                }
            }
        });
    }
}