sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
//! `R3` response to the `ACMD41` command containing the card `OCR` register.

use crate::register::Ocr;
use crate::response::{End, Start};
use crate::result::{Error, Result};
use crate::{lib_bitfield, response};

lib_bitfield! {
    /// Represents the `R3` response to the `ACMD41` command in SD mode.
    pub R3(MSB0 [u8; 6]): u32 {
        raw_start: 47, 40;
        raw_ocr: 39, 8;
        raw_end: 7, 0;
    }
}

response! {
    R3 {
        response_mode: Sd,
    }
}

impl R3 {
    /// Represents the byte length of [R3].
    pub const LEN: usize = 6;
    /// Represents the default byte value of the [R3].
    pub const DEFAULT: [u8; Self::LEN] = [0x3f, 0, 0, 0, 0, 0xff];

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

    /// Attempts to get the [Start] fields of the [R3].
    pub const fn start(&self) -> Result<Start> {
        Start::try_from_bits(self.raw_start() as u8)
    }

    /// Gets the [Ocr] field of the [R3].
    pub const fn ocr(&self) -> Ocr {
        Ocr::from_bits(self.raw_ocr())
    }

    /// Sets the [Ocr] field of the [R3].
    pub fn set_ocr(&mut self, val: Ocr) {
        self.set_raw_ocr(val.bits());
    }

    /// Attempts to get the [End] fields of the [R3].
    pub const fn end(&self) -> Result<End> {
        End::try_from_bits(self.raw_end() as u8)
    }

    /// Attempts to convert a byte slice into a [R3].
    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)),
            _ => {
                let r3 = Self([val[0], val[1], val[2], val[3], val[4], val[5]]);
                let exp_start = Start::from_bits(0x3f);
                let exp_end = End::from_bits(0xff);

                match (r3.start(), r3.end()) {
                    (Ok(exp_start), Ok(exp_end)) => Ok(r3),
                    (_, Ok(exp_end)) => Err(Error::invalid_field_variant(
                        "r3::start",
                        r3.raw_start() as usize,
                    )),
                    (_, _) => Err(Error::invalid_field_variant(
                        "r3::end",
                        r3.raw_end() as usize,
                    )),
                }
            }
        }
    }
}

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

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

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

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

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

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

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

    #[test]
    fn test_valid() {
        let exp_start = Start::from_bits(0x3f);
        let exp_end = End::from_bits(0xff);

        (1..=u32::BITS)
            .map(|r| ((1u64 << r) - 1) as u32)
            .for_each(|raw_ocr| {
                let ocr = Ocr::from_bits(raw_ocr);
                let [ocr0, ocr1, ocr2, ocr3] = ocr.bytes();
                let raw = [0x3f, ocr0, ocr1, ocr2, ocr3, 0xff];

                let mut exp_r3 = R3::new();
                exp_r3.set_ocr(ocr);

                assert_eq!(R3::try_from_bytes(raw.as_ref()), Ok(exp_r3));
                assert_eq!(exp_r3.start(), Ok(exp_start));
                assert_eq!(exp_r3.ocr(), ocr);
                assert_eq!(exp_r3.end(), Ok(exp_end));

                exp_r3.set_ocr(Ocr::new());
                assert_eq!(exp_r3.ocr(), Ocr::new());

                exp_r3.set_ocr(ocr);
                assert_eq!(exp_r3.ocr(), ocr);
            });
    }
}