sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
//! R2 response for SPI mode.

use crate::response::spi::r1::R1;
use crate::result::{Error, Result};
use crate::{lib_bitfield, response};

lib_bitfield! {
    /// Represents the response to the `SEND_STATUS` command in SPI mode.
    pub R2(u16): u8 {
        raw_r1: 15, 8;
        /// An out-of-range access was attempted.
        pub out_of_range: 7;
        /// An invalid sector for erase.
        pub erase_param: 6;
        /// An attempt was made to write to a write-protected block.
        pub wp_violation: 5;
        /// Internal card ECC failed to correct data error.
        pub card_ecc_failed: 4;
        /// Internal card control error.
        pub cc_error: 3;
        /// A general or unknown error occurred.
        pub error: 2;
        /// Card lock/unlock failed, or write-protect erase skip
        pub lock_failed: 1;
        /// SD card is locked.
        pub card_locked: 0;
    }
}

response! {
    R2 {
        response_mode: Spi,
    }
}

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

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

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

    /// Sets the [R1] portion of the [R2] response.
    pub fn set_r1(&mut self, r1: R1) {
        self.set_raw_r1(r1.bits() as u16);
    }

    /// Builder function that sets the [R1] portion of the [R2] response.
    pub const fn with_r1(mut self, r1: R1) -> Self {
        Self(((r1.bits() as u16) << 8) | (self.bits() & 0xff))
    }

    /// Attempts to convert a [`u16`] into a [R2].
    pub const fn try_from_bits(val: u16) -> Result<Self> {
        match Self(val) {
            r if r.r1().is_ok() => Ok(r),
            _ => Err(Error::invalid_field_variant("r2", val as usize)),
        }
    }

    /// Converts the [R2] into a byte array.
    pub const fn bytes(&self) -> [u8; Self::LEN] {
        self.0.to_be_bytes()
    }

    /// Attempts to convert a byte slice into a [R2].
    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)),
            _ => R2::try_from_bits(u16::from_be_bytes([val[0], val[1]])),
        }
    }
}

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

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

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

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

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

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

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

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

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

    #[test]
    fn test_fields() {
        let mut r2 = R2::new();

        test_field!(r2, card_locked: 0);
        test_field!(r2, lock_failed: 1);
        test_field!(r2, error: 2);
        test_field!(r2, cc_error: 3);
        test_field!(r2, card_ecc_failed: 4);
        test_field!(r2, wp_violation: 5);
        test_field!(r2, erase_param: 6);
        test_field!(r2, out_of_range: 7);

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

        (0..=u16::MAX).for_each(|v| {
            let [r1, _] = v.to_be_bytes();

            match v {
                v if R1::try_from_bits(r1).is_err() => {
                    assert_eq!(
                        R2::try_from(v),
                        Err(Error::invalid_field_variant("r2", v as usize))
                    )
                }
                v => {
                    let exp_r1 = R1::try_from_bits(r1).unwrap();
                    assert_eq!(R2::try_from(v), Ok(R2(v)));
                    assert_eq!(R2(v).r1(), Ok(exp_r1));
                    assert_eq!(R2::new().with_r1(exp_r1).r1(), Ok(exp_r1));
                }
            }
        });
    }
}