sdmmc_core/response/sd/
r7.rs

1use crate::crc::Crc7;
2use crate::result::{Error, Result};
3use crate::{lib_bitfield, response};
4
5mod voltage_accepted;
6
7pub use voltage_accepted::*;
8
9const COMMAND_INDEX: u8 = 0b00_1000;
10
11lib_bitfield! {
12    /// Represents the response to the `SEND_IF_COND` command (`CMD8`) in SD mode.
13    pub R7(MSB0 [u8; 6]): u8 {
14        start_bit: 47;
15        direction: 46;
16        raw_command_index: 45, 40;
17        /// PCIe VDD3 (1.2V power rail) supported.
18        pub pcie_12v_support: 21;
19        /// PCIe accepted by card.
20        pub pcie: 20;
21        raw_voltage_accepted: 19, 16;
22        /// Echo-back of the check pattern for the [R7].
23        pub echo_check: 15, 8;
24        raw_crc: 7, 1;
25        end_bit: 0;
26    }
27}
28
29response! {
30    R7 {
31        response_mode: Sd,
32    }
33}
34
35impl R7 {
36    /// Represents the byte length of the [R7] response in SD mode.
37    pub const LEN: usize = 6;
38    /// Represents the default byte value of [R7].
39    pub const DEFAULT: [u8; Self::LEN] = [COMMAND_INDEX, 0, 0, 0x1, 0, 0x41];
40
41    /// Creates a new [R7].
42    pub const fn new() -> Self {
43        Self(Self::DEFAULT)
44    }
45
46    /// Gets the command index field for the [R7].
47    pub const fn command_index(&self) -> u8 {
48        self.raw_command_index()
49    }
50
51    /// Gets the [VoltageAccepted] value of the [R7] response.
52    pub const fn voltage_accepted(&self) -> Result<VoltageAccepted> {
53        VoltageAccepted::from_raw(self.raw_voltage_accepted())
54    }
55
56    /// Sets the [VoltageAccepted] value of the [R7] response.
57    pub fn set_voltage_accepted(&mut self, voltage_accepted: VoltageAccepted) {
58        self.set_raw_voltage_accepted(voltage_accepted.into_raw());
59    }
60
61    /// Gets the [Crc7] field of the [R7].
62    pub const fn crc(&self) -> Crc7 {
63        Crc7::from_bits(self.raw_crc())
64    }
65
66    /// Calculates and sets the [Crc7] field of the [R7].
67    ///
68    /// Returns the calculated [Crc7].
69    pub fn calculate_crc(&mut self) -> Crc7 {
70        let crc = Crc7::calculate(self.0[..Self::LEN - 1].as_ref());
71        self.set_raw_crc(crc.bits());
72        crc
73    }
74
75    /// Attempts to convert a byte slice into a [R7].
76    pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
77        match val.len() {
78            len if len < Self::LEN => Err(Error::invalid_length(len, Self::LEN)),
79            _ => {
80                let crc = Crc7::calculate(&[val[0], val[1], val[2], val[3], val[4]]);
81
82                match R7([val[0], val[1], val[2], val[3], val[4], val[5]]) {
83                    r7 if r7.start_bit() => Err(Error::invalid_field_variant("r7::start_bit", 1)),
84                    r7 if r7.direction() => Err(Error::invalid_field_variant("r7::direction", 1)),
85                    r7 if r7.command_index() != COMMAND_INDEX => Err(Error::invalid_field_variant(
86                        "r7::command_index",
87                        r7.command_index() as usize,
88                    )),
89                    r7 if r7.voltage_accepted().is_err() => Err(Error::invalid_field_variant(
90                        "r7::voltage_accepted",
91                        r7.raw_voltage_accepted() as usize,
92                    )),
93                    r7 if r7.raw_crc() != crc.bits() => {
94                        Err(Error::invalid_crc7(r7.raw_crc(), crc.bits()))
95                    }
96                    r7 if !r7.end_bit() => Err(Error::invalid_field_variant("r7::end_bit", 0)),
97                    r7 => Ok(r7),
98                }
99            }
100        }
101    }
102}
103
104impl Default for R7 {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110impl From<R7> for [u8; R7::LEN] {
111    fn from(val: R7) -> Self {
112        val.bytes()
113    }
114}
115
116impl TryFrom<&[u8]> for R7 {
117    type Error = Error;
118
119    fn try_from(val: &[u8]) -> Result<Self> {
120        Self::try_from_bytes(val)
121    }
122}
123
124impl<const N: usize> TryFrom<[u8; N]> for R7 {
125    type Error = Error;
126
127    fn try_from(val: [u8; N]) -> Result<Self> {
128        Self::try_from_bytes(val.as_ref())
129    }
130}
131
132impl<const N: usize> TryFrom<&[u8; N]> for R7 {
133    type Error = Error;
134
135    fn try_from(val: &[u8; N]) -> Result<Self> {
136        Self::try_from_bytes(val.as_ref())
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use crate::test_field;
144    use crate::util::raw_with_crc;
145
146    #[test]
147    fn test_fields() {
148        let mut r7 = R7::new();
149
150        assert!(!r7.pcie());
151        assert!(!r7.pcie_12v_support());
152
153        test_field!(r7, pcie { bit: 20, [u8; R7::LEN] });
154        test_field!(r7, pcie_12v_support { bit: 21, [u8; R7::LEN] });
155
156        assert_eq!(r7.voltage_accepted(), Ok(VoltageAccepted::new()));
157        assert_eq!(r7.echo_check(), 0);
158
159        (0..=u8::MAX).zip(0..=u8::MAX).for_each(|(flags, echo)| {
160            let (raw, _crc) = raw_with_crc([COMMAND_INDEX, 0, 0, flags, echo, 0]);
161            let raw_va = flags & 0xf;
162
163            match VoltageAccepted::from_raw(raw_va) {
164                Ok(va) => {
165                    r7 = R7(raw);
166
167                    assert_eq!(R7::try_from_bytes(raw.as_ref()), Ok(r7));
168                    assert_eq!(R7::try_from(raw), Ok(r7));
169                    assert_eq!(r7.bytes(), raw);
170
171                    test_field!(r7, pcie { bit: 20, [u8; R7::LEN] });
172                    test_field!(r7, pcie_12v_support { bit: 21, [u8; R7::LEN] });
173
174                    assert_eq!(r7.voltage_accepted(), Ok(va));
175
176                    r7.set_voltage_accepted(VoltageAccepted::new());
177                    assert_eq!(r7.voltage_accepted(), Ok(VoltageAccepted::new()));
178
179                    r7.set_voltage_accepted(va);
180                    assert_eq!(r7.voltage_accepted(), Ok(va));
181
182                    assert_eq!(r7.echo_check(), echo);
183
184                    r7.set_echo_check(0);
185                    assert_eq!(r7.echo_check(), 0);
186
187                    r7.set_echo_check(echo);
188                    assert_eq!(r7.echo_check(), echo);
189                }
190                Err(_) => {
191                    assert_eq!(
192                        R7::try_from_bytes(raw.as_ref()),
193                        Err(Error::invalid_field_variant(
194                            "r7::voltage_accepted",
195                            raw_va as usize
196                        ))
197                    );
198                    assert_eq!(
199                        R7::try_from(raw),
200                        Err(Error::invalid_field_variant(
201                            "r7::voltage_accepted",
202                            raw_va as usize
203                        ))
204                    );
205                }
206            }
207        });
208    }
209}