Skip to main content

sdmmc_protocol/
response.rs

1pub use sdio_host2::{RawResponse, ResponseType};
2
3use crate::error::{CardError, Error, ErrorContext, Phase};
4
5/// Parsed response from the card
6///
7/// Marked `#[non_exhaustive]`: new response shapes (e.g. SDIO IO_RW
8/// extensions) may be added before 1.0.
9#[derive(Debug, Clone, Copy)]
10#[non_exhaustive]
11pub enum Response {
12    /// No response phase — emitted when the command's [`ResponseType`] is
13    /// [`ResponseType::None`] (e.g. CMD0). Renamed from `Response::None` to
14    /// avoid lexical confusion with [`ResponseType::None`]; the two now read
15    /// at a glance as "no response type configured" vs "no response decoded".
16    Empty,
17    R1(R1Response),
18    R1b(R1Response),
19    R2([u8; 16]),
20    R3(OcrResponse),
21    R4(SdioOcrResponse),
22    R5(SdioRwResponse),
23    R6(RcaResponse),
24    R7(IfCondResponse),
25}
26
27impl Response {
28    /// Convert a typed protocol response into the normalized physical response
29    /// words used by `sdio-host2`.
30    pub fn to_raw_response(self, expected: ResponseType) -> RawResponse {
31        let mut words = [0; 4];
32        match self {
33            Self::Empty => {}
34            Self::R1(resp) | Self::R1b(resp) => words[0] = resp.raw,
35            Self::R2(bytes) => {
36                for (word, chunk) in words.iter_mut().zip(bytes.chunks_exact(4)) {
37                    *word = u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
38                }
39            }
40            Self::R3(resp) => words[0] = resp.raw,
41            Self::R4(resp) => words[0] = resp.raw,
42            Self::R5(resp) => words[0] = resp.raw,
43            Self::R6(resp) => words[0] = resp.raw,
44            Self::R7(resp) => words[0] = resp.raw,
45        }
46        RawResponse::new(expected, words)
47    }
48}
49
50/// Parse normalized physical response words into the protocol response type.
51pub fn response_from_raw(raw: RawResponse) -> Result<Response, Error> {
52    Ok(match raw.ty {
53        ResponseType::None => Response::Empty,
54        ResponseType::R1 => Response::R1(R1Response::from_native_raw(raw.words[0])?),
55        ResponseType::R1b => Response::R1b(R1Response::from_native_raw(raw.words[0])?),
56        ResponseType::R2 => {
57            let mut bytes = [0; 16];
58            for (chunk, word) in bytes.chunks_exact_mut(4).zip(raw.words) {
59                chunk.copy_from_slice(&word.to_be_bytes());
60            }
61            Response::R2(bytes)
62        }
63        ResponseType::R3 => Response::R3(OcrResponse::from_raw(raw.words[0])),
64        ResponseType::R4 => Response::R4(SdioOcrResponse::from_raw(raw.words[0])),
65        ResponseType::R5 => Response::R5(SdioRwResponse::from_raw(raw.words[0])),
66        ResponseType::R6 => Response::R6(RcaResponse::from_raw(raw.words[0])),
67        ResponseType::R7 => Response::R7(IfCondResponse::from_raw(raw.words[0])),
68        _ => return Err(Error::UnsupportedCommand),
69    })
70}
71
72/// R1: Standard response — contains status bits
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct R1Response {
75    pub raw: u32,
76}
77
78impl R1Response {
79    /// Parse a native (SDIO/SDHCI) 32-bit R1 response.
80    ///
81    /// SD Physical Layer spec section 4.10.1 (Table 4-42) places the card
82    /// status error flags at bits 19..=31:
83    ///
84    /// | Bit | Name                |
85    /// |-----|---------------------|
86    /// | 31  | `OUT_OF_RANGE`      |
87    /// | 30  | `ADDRESS_ERROR`     |
88    /// | 29  | `BLOCK_LEN_ERROR`   |
89    /// | 28  | `ERASE_SEQ_ERROR`   |
90    /// | 27  | `ERASE_PARAM`       |
91    /// | 26  | `WP_VIOLATION`      |
92    /// | 25  | `CARD_IS_LOCKED`    |
93    /// | 24  | `LOCK_UNLOCK_FAILED`|
94    /// | 23  | `COM_CRC_ERROR`     |
95    /// | 22  | `ILLEGAL_COMMAND`   |
96    /// | 21  | `CARD_ECC_FAILED`   |
97    /// | 20  | `CC_ERROR`          |
98    /// | 19  | `ERROR`             |
99    ///
100    /// If **any** of those 13 bits is set this returns
101    /// `Err(Error::CardError(..))`. Otherwise the raw value is preserved so
102    /// callers can inspect informational state bits (`current_state`,
103    /// `ready_for_data`, ...).
104    ///
105    /// Note: earlier versions only looked at bits 19..=24 and silently
106    /// dropped `OUT_OF_RANGE`, `ADDRESS_ERROR`, `BLOCK_LEN_ERROR`,
107    /// `ERASE_PARAM`, `WP_VIOLATION`, `CARD_IS_LOCKED`, and `COM_CRC_ERROR`.
108    /// Callers that used to see `Ok` for one of those now correctly see
109    /// `Err(CardError::..)`.
110    pub fn from_native_raw(raw: u32) -> Result<Self, Error> {
111        let err_bits = raw & R1_NATIVE_ERROR_MASK;
112        if err_bits != 0 {
113            return Err(Error::CardError(decode_native_card_error(err_bits)));
114        }
115        Ok(Self { raw })
116    }
117
118    /// Parse a single-byte SPI R1 response.
119    ///
120    /// SPI R1 has a fixed `0` start bit (the high bit must be clear). The
121    /// remaining bits encode informational state (idle, erase reset) and
122    /// soft error flags (illegal command, CRC error, ...). Because some flags
123    /// — especially `illegal_command` — are *expected* during initialization
124    /// (e.g. CMD8 on SD v1 cards), this function does NOT itself convert
125    /// flag bits into `Err`. Callers should inspect the helpers
126    /// ([`R1Response::illegal_command`] etc.) to decide what to do.
127    ///
128    /// Returns `Err(Error::BadResponse(_))` when the high bit is set, which
129    /// indicates a malformed response or that no R1 byte arrived.
130    pub fn from_spi_byte(byte: u8) -> Result<Self, Error> {
131        if byte & 0x80 != 0 {
132            return Err(Error::BadResponse(ErrorContext::new(Phase::ResponseWait)));
133        }
134        Ok(Self { raw: byte as u32 })
135    }
136
137    /// Decode error flag bits in a SPI R1 response into a [`CardError`].
138    ///
139    /// Returns `None` when no error bits are set. Only meaningful for values
140    /// produced by [`R1Response::from_spi_byte`]; native R1 layouts use a
141    /// different bit mapping and report errors directly through
142    /// [`R1Response::from_native_raw`].
143    pub fn spi_card_error(&self) -> Option<CardError> {
144        let bits = (self.raw as u8) & 0b0111_1110;
145        if bits == 0 {
146            None
147        } else {
148            Some(decode_spi_card_error(bits))
149        }
150    }
151
152    /// Card is in idle state
153    pub fn idle(&self) -> bool {
154        self.raw & (1 << 0) != 0
155    }
156
157    /// Erase reset
158    pub fn erase_reset(&self) -> bool {
159        self.raw & (1 << 1) != 0
160    }
161
162    /// Illegal command
163    pub fn illegal_command(&self) -> bool {
164        self.raw & (1 << 2) != 0
165    }
166
167    /// Command CRC failed
168    pub fn command_crc_failed(&self) -> bool {
169        self.raw & (1 << 3) != 0
170    }
171
172    /// Current state of the card state machine (bits 12:15).
173    ///
174    /// Only meaningful for native (SDIO) R1 responses; SPI R1 bytes do not
175    /// encode card state.
176    pub fn current_state(&self) -> CardState {
177        match ((self.raw >> 9) & 0xF) as u8 {
178            0 => CardState::Idle,
179            1 => CardState::Ready,
180            2 => CardState::Identification,
181            3 => CardState::Standby,
182            4 => CardState::Transfer,
183            5 => CardState::SendingData,
184            6 => CardState::ReceiveData,
185            7 => CardState::Programming,
186            8 => CardState::Disconnect,
187            other => CardState::Reserved(other),
188        }
189    }
190
191    /// Card is locked (native R1 only)
192    pub fn card_is_locked(&self) -> bool {
193        self.raw & (1 << 19) != 0
194    }
195
196    /// `READY_FOR_DATA` (bit 8): card buffer is empty and the next data
197    /// transfer can be issued. Used after R1b commands (CMD7, CMD12,
198    /// MMC CMD6 SWITCH) to know when the busy line has cleared.
199    ///
200    /// Only meaningful for native (SDIO) R1 responses.
201    pub fn ready_for_data(&self) -> bool {
202        self.raw & (1 << 8) != 0
203    }
204
205    /// `SWITCH_ERROR` (bit 7): the previous MMC CMD6 SWITCH was rejected
206    /// (e.g. invalid EXT_CSD field, value out of range). Surfaces here
207    /// because CMD6 itself returns R1b with this bit, but most error
208    /// reporters hide bits 0..15.
209    pub fn switch_error(&self) -> bool {
210        self.raw & (1 << 7) != 0
211    }
212}
213
214/// Card state machine states
215///
216/// Marked `#[non_exhaustive]`: SD/MMC specs may carve new state values out of
217/// the reserved range, and downstream match sites must keep a `_ => ...` arm.
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219#[non_exhaustive]
220pub enum CardState {
221    Idle,
222    Ready,
223    Identification,
224    Standby,
225    Transfer,
226    SendingData,
227    ReceiveData,
228    Programming,
229    Disconnect,
230    Reserved(u8),
231}
232
233/// OCR register (R3/CMD58 response)
234#[derive(Debug, Clone, Copy)]
235pub struct OcrResponse {
236    pub raw: u32,
237}
238
239impl OcrResponse {
240    pub fn from_raw(raw: u32) -> Self {
241        Self { raw }
242    }
243
244    /// Card power up status — true if card has completed power-up
245    pub fn card_powered_up(&self) -> bool {
246        self.raw & (1 << 31) != 0
247    }
248
249    /// Card Capacity Status (CCS): true = SDHC/SDXC, false = SDSC
250    pub fn ccs(&self) -> bool {
251        self.raw & (1 << 30) != 0
252    }
253
254    /// Supported voltage range (bits 23:0)
255    pub fn voltage_window(&self) -> u32 {
256        self.raw & 0x00FF_FF00
257    }
258
259    /// Supports 3.5–3.6V
260    pub fn vdd_35_36(&self) -> bool {
261        self.raw & (1 << 23) != 0
262    }
263
264    /// Supports 3.4–3.5V
265    pub fn vdd_34_35(&self) -> bool {
266        self.raw & (1 << 22) != 0
267    }
268
269    /// Supports 3.3–3.4V
270    pub fn vdd_33_34(&self) -> bool {
271        self.raw & (1 << 21) != 0
272    }
273
274    /// Supports 3.2–3.3V
275    pub fn vdd_32_33(&self) -> bool {
276        self.raw & (1 << 20) != 0
277    }
278
279    /// Supports 2.7–3.6V (typical operating range)
280    pub fn supports_2v7_to_3v6(&self) -> bool {
281        self.raw & 0x00FF_8000 != 0
282    }
283
284    /// UHS-II supported
285    pub fn uhs2(&self) -> bool {
286        self.raw & (1 << 29) != 0
287    }
288
289    /// Switching to 1.8 V was accepted during SD ACMD41 negotiation.
290    pub fn s18a(&self) -> bool {
291        self.raw & (1 << 24) != 0
292    }
293}
294
295/// R6: Published RCA response
296#[derive(Debug, Clone, Copy)]
297pub struct RcaResponse {
298    pub raw: u32,
299}
300
301impl RcaResponse {
302    pub fn from_raw(raw: u32) -> Self {
303        Self { raw }
304    }
305
306    /// Relative card address (bits 31:16)
307    pub fn rca(&self) -> u16 {
308        ((self.raw >> 16) & 0xFFFF) as u16
309    }
310
311    /// Status bits (bits 15:0) — subset of R1 status
312    pub fn status(&self) -> u16 {
313        (self.raw & 0xFFFF) as u16
314    }
315}
316
317/// R7: Interface condition response
318#[derive(Debug, Clone, Copy)]
319pub struct IfCondResponse {
320    pub raw: u32,
321}
322
323impl IfCondResponse {
324    pub fn from_raw(raw: u32) -> Self {
325        Self { raw }
326    }
327
328    /// Supported voltage (bits 11:8)
329    pub fn voltage(&self) -> u8 {
330        ((self.raw >> 8) & 0xF) as u8
331    }
332
333    /// Echo-back check pattern (bits 7:0)
334    pub fn check_pattern(&self) -> u8 {
335        (self.raw & 0xFF) as u8
336    }
337
338    /// Verify response matches expected voltage and pattern
339    pub fn verify(&self, voltage: u8, pattern: u8) -> bool {
340        self.voltage() == voltage && self.check_pattern() == pattern
341    }
342}
343
344/// CSD register (CMD9 response, raw 16 bytes MSB-first as delivered by both
345/// SPI and SDIO transports).
346#[derive(Debug, Clone, Copy)]
347pub struct CsdResponse {
348    pub raw: [u8; 16],
349}
350
351impl CsdResponse {
352    pub fn from_raw(raw: [u8; 16]) -> Self {
353        Self { raw }
354    }
355
356    /// CSD structure version: 0 = v1 (SDSC), 1 = v2 (SDHC/SDXC), 2 = v3 (SDUC)
357    pub fn version(&self) -> u8 {
358        (self.raw[0] >> 6) & 0x03
359    }
360
361    /// User-data capacity in 512-byte blocks.
362    ///
363    /// Returns `None` for unknown / unsupported CSD structures (e.g. SDUC v3,
364    /// which encodes a 28-bit C_SIZE that does not fit the v2 formula).
365    pub fn capacity_blocks(&self) -> Option<u64> {
366        match self.version() {
367            0 => Some(self.csd_v1_capacity_blocks()),
368            1 => Some(self.csd_v2_capacity_blocks()),
369            _ => None,
370        }
371    }
372
373    fn csd_v1_capacity_blocks(&self) -> u64 {
374        // CSD v1 fields (bit numbering as in SD spec, MSB = bit 127):
375        //   READ_BL_LEN [83:80]   — log2 of read block length
376        //   C_SIZE      [73:62]   — 12-bit
377        //   C_SIZE_MULT [49:47]   — 3-bit
378        // capacity_bytes = (C_SIZE + 1) * 2^(C_SIZE_MULT + 2) * 2^READ_BL_LEN
379        let read_bl_len = (self.raw[5] & 0x0F) as u32;
380        let c_size = (((self.raw[6] & 0x03) as u32) << 10)
381            | ((self.raw[7] as u32) << 2)
382            | ((self.raw[8] as u32) >> 6);
383        let c_size_mult = (((self.raw[9] & 0x03) as u32) << 1) | ((self.raw[10] as u32) >> 7);
384        let mult = 1u64 << (c_size_mult + 2);
385        let block_len = 1u64 << read_bl_len;
386        let bytes = (c_size as u64 + 1) * mult * block_len;
387        bytes / 512
388    }
389
390    fn csd_v2_capacity_blocks(&self) -> u64 {
391        // CSD v2 (SDHC/SDXC):
392        //   C_SIZE [69:48] — 22-bit
393        //   capacity_bytes = (C_SIZE + 1) * 512 KiB
394        //   capacity_blocks = (C_SIZE + 1) * 1024
395        let c_size = (((self.raw[7] & 0x3F) as u32) << 16)
396            | ((self.raw[8] as u32) << 8)
397            | (self.raw[9] as u32);
398        (c_size as u64 + 1) * 1024
399    }
400}
401
402/// CID register (CMD2/CMD10 response). Identifies the card's manufacturer,
403/// product, serial number, and manufacturing date.
404///
405/// Field layout follows SD Physical Layer spec section 5.2; only SD cards are
406/// decoded here. eMMC uses a different field layout and is not supported.
407#[derive(Debug, Clone, Copy)]
408pub struct CidResponse {
409    pub raw: [u8; 16],
410}
411
412impl CidResponse {
413    pub fn from_raw(raw: [u8; 16]) -> Self {
414        Self { raw }
415    }
416
417    /// Manufacturer ID (MID) — 8-bit code assigned by the SD Association.
418    pub fn manufacturer_id(&self) -> u8 {
419        self.raw[0]
420    }
421
422    /// OEM/Application ID (OID) — two ASCII characters identifying the card
423    /// OEM. Returned as a `[u8; 2]`; bytes outside printable ASCII are
424    /// preserved verbatim so callers can detect non-conforming firmware.
425    pub fn oem_id(&self) -> [u8; 2] {
426        [self.raw[1], self.raw[2]]
427    }
428
429    /// Product name (PNM) — 5 ASCII characters.
430    pub fn product_name(&self) -> [u8; 5] {
431        [
432            self.raw[3],
433            self.raw[4],
434            self.raw[5],
435            self.raw[6],
436            self.raw[7],
437        ]
438    }
439
440    /// Product revision (PRV) as a `(major, minor)` pair, both 4-bit BCD.
441    pub fn product_revision(&self) -> (u8, u8) {
442        (self.raw[8] >> 4, self.raw[8] & 0x0F)
443    }
444
445    /// Product serial number (PSN) — 32-bit big-endian.
446    pub fn serial_number(&self) -> u32 {
447        u32::from_be_bytes([self.raw[9], self.raw[10], self.raw[11], self.raw[12]])
448    }
449
450    /// Manufacturing date as `(year, month)` where year is the absolute
451    /// 4-digit year (SD spec offsets year by 2000).
452    ///
453    /// Layout: bits 19:8 of bytes 13..=14 hold the date — 12 bits split as
454    /// year (8 bits) and month (4 bits).
455    pub fn manufacture_date(&self) -> (u16, u8) {
456        let year = ((self.raw[13] & 0x0F) << 4) | (self.raw[14] >> 4);
457        let month = self.raw[14] & 0x0F;
458        (2000 + year as u16, month)
459    }
460}
461
462/// 64-byte SD function-switch status, returned in the data phase of CMD6.
463///
464/// See SD Physical Layer spec section 4.3.10 (Switch Function). Field
465/// numbering uses the spec's bit-435..=0 convention but accessors here are
466/// expressed in byte offsets within `raw[0..64]` for clarity.
467#[derive(Debug, Clone, Copy)]
468pub struct SwitchStatus {
469    pub raw: [u8; 64],
470}
471
472impl SwitchStatus {
473    pub fn from_raw(raw: [u8; 64]) -> Self {
474        Self { raw }
475    }
476
477    /// Selected function for `group` (1-based, 1..=6) after a switch
478    /// operation. `0xF` means the group is not supported by the card.
479    ///
480    /// Group 1 selection lives in the low nibble of byte 16; group 2 in the
481    /// high nibble of the same byte; group 3 in the low nibble of byte 15;
482    /// and so on, paired big-endian over bytes 14..=16.
483    pub fn selected_function(&self, group: u8) -> u8 {
484        match group {
485            1 => self.raw[16] & 0x0F,
486            2 => self.raw[16] >> 4,
487            3 => self.raw[15] & 0x0F,
488            4 => self.raw[15] >> 4,
489            5 => self.raw[14] & 0x0F,
490            6 => self.raw[14] >> 4,
491            _ => 0xF,
492        }
493    }
494
495    /// Returns true iff group 1 reports high-speed (function 1) selected.
496    pub fn high_speed_active(&self) -> bool {
497        self.selected_function(1) == 1
498    }
499
500    /// Returns true iff SD access-mode group 1 advertises `function`.
501    ///
502    /// The support bitmap for group 1 is carried in byte 13 in the 64-byte
503    /// switch status block; bit `n` means function `n` is selectable.
504    pub fn access_mode_supported(&self, function: u8) -> bool {
505        function < 8 && (self.raw[13] & (1 << function)) != 0
506    }
507}
508
509/// SDIO OCR (R4/CMD5 response)
510#[derive(Debug, Clone, Copy)]
511pub struct SdioOcrResponse {
512    pub raw: u32,
513}
514
515impl SdioOcrResponse {
516    pub fn from_raw(raw: u32) -> Self {
517        Self { raw }
518    }
519
520    /// Number of I/O functions (bits 27:28)
521    pub fn io_functions(&self) -> u8 {
522        ((self.raw >> 28) & 0x7) as u8
523    }
524
525    /// Memory present
526    pub fn memory_present(&self) -> bool {
527        self.raw & (1 << 27) != 0
528    }
529
530    /// I/O ready
531    pub fn io_ready(&self) -> bool {
532        self.raw & (1 << 31) != 0
533    }
534}
535
536/// SDIO R5 response
537#[derive(Debug, Clone, Copy)]
538pub struct SdioRwResponse {
539    pub raw: u32,
540}
541
542impl SdioRwResponse {
543    pub fn from_raw(raw: u32) -> Self {
544        Self { raw }
545    }
546
547    /// Read/write data (bits 7:0)
548    pub fn data(&self) -> u8 {
549        (self.raw & 0xFF) as u8
550    }
551
552    /// Response flags (bits 15:8)
553    pub fn flags(&self) -> u8 {
554        ((self.raw >> 8) & 0xFF) as u8
555    }
556}
557
558/// Bitmask covering every native R1 error flag (bits 19..=31 of the 32-bit
559/// response, per SD spec section 4.10.1). `from_native_raw` ANDs the raw
560/// response against this and routes any non-zero result through
561/// `decode_native_card_error`.
562const R1_NATIVE_ERROR_MASK: u32 = 0xFFF8_0000;
563
564const R1_BIT_OUT_OF_RANGE: u32 = 1 << 31;
565const R1_BIT_ADDRESS_ERROR: u32 = 1 << 30;
566const R1_BIT_BLOCK_LEN_ERROR: u32 = 1 << 29;
567const R1_BIT_ERASE_SEQ_ERROR: u32 = 1 << 28;
568const R1_BIT_ERASE_PARAM: u32 = 1 << 27;
569const R1_BIT_WP_VIOLATION: u32 = 1 << 26;
570const R1_BIT_CARD_IS_LOCKED: u32 = 1 << 25;
571const R1_BIT_LOCK_UNLOCK_FAILED: u32 = 1 << 24;
572const R1_BIT_COM_CRC_ERROR: u32 = 1 << 23;
573const R1_BIT_ILLEGAL_COMMAND: u32 = 1 << 22;
574const R1_BIT_CARD_ECC_FAILED: u32 = 1 << 21;
575const R1_BIT_CC_ERROR: u32 = 1 << 20;
576const R1_BIT_ERROR: u32 = 1 << 19;
577
578/// Decode SPI R1 byte error bits (bits 1..=6 of the byte).
579///
580/// SPI R1 layout (SD spec, simplified):
581///   bit 1 = erase reset
582///   bit 2 = illegal command
583///   bit 3 = command CRC error
584///   bit 4 = erase sequence error
585///   bit 5 = address error
586///   bit 6 = parameter error
587///
588/// When multiple bits are set we return the first known error in priority
589/// order (CRC > illegal command > address > parameter > erase sequence >
590/// erase reset). If no known bit is set we preserve the raw pattern.
591fn decode_spi_card_error(bits: u8) -> CardError {
592    if bits & 0b0000_1000 != 0 {
593        CardError::CommandCrcFailed
594    } else if bits & 0b0000_0100 != 0 {
595        CardError::IllegalCommand
596    } else if bits & 0b0010_0000 != 0 {
597        CardError::AddressError
598    } else if bits & 0b0100_0000 != 0 {
599        // SPI PARAMETER_ERROR maps to native BLOCK_LEN_ERROR/parameter family.
600        CardError::BlockLenError
601    } else if bits & (0b0001_0000 | 0b0000_0010) != 0 {
602        // ERASE_SEQ_ERROR or ERASE_RESET — both fall under EraseSequence.
603        CardError::EraseSequence
604    } else {
605        CardError::Unknown(bits as u32)
606    }
607}
608
609/// Decode the native R1 error bits (bits 19..=31 of the 32-bit response).
610///
611/// Caller passes `raw & R1_NATIVE_ERROR_MASK` (non-zero). When multiple bits
612/// are set we surface the most-severe-first variant per SD spec convention:
613/// argument/addressing errors first (so a write to an invalid LBA is reported
614/// as `OutOfRange` even if the card also raises lower-priority companions),
615/// then bus-integrity errors, then card-state errors, then catch-all
616/// erase/generic. Unknown patterns preserve the raw 13-bit error nibble
617/// (shifted to bit 0) so callers can log the exact bits.
618fn decode_native_card_error(err_bits: u32) -> CardError {
619    if err_bits & R1_BIT_OUT_OF_RANGE != 0 {
620        CardError::OutOfRange
621    } else if err_bits & R1_BIT_ADDRESS_ERROR != 0 {
622        CardError::AddressError
623    } else if err_bits & R1_BIT_BLOCK_LEN_ERROR != 0 {
624        CardError::BlockLenError
625    } else if err_bits & R1_BIT_WP_VIOLATION != 0 {
626        CardError::WriteProtect
627    } else if err_bits & R1_BIT_COM_CRC_ERROR != 0 {
628        CardError::CommandCrcFailed
629    } else if err_bits & R1_BIT_ILLEGAL_COMMAND != 0 {
630        CardError::IllegalCommand
631    } else if err_bits & R1_BIT_CARD_ECC_FAILED != 0 {
632        CardError::CardEccFailed
633    } else if err_bits & R1_BIT_CC_ERROR != 0 {
634        CardError::ControllerError
635    } else if err_bits & R1_BIT_LOCK_UNLOCK_FAILED != 0 {
636        CardError::LockUnlockFailed
637    } else if err_bits & R1_BIT_CARD_IS_LOCKED != 0 {
638        CardError::CardIsLocked
639    } else if err_bits & (R1_BIT_ERASE_SEQ_ERROR | R1_BIT_ERASE_PARAM) != 0 {
640        CardError::EraseSequence
641    } else if err_bits & R1_BIT_ERROR != 0 {
642        CardError::GenericError
643    } else {
644        CardError::Unknown(err_bits >> 19)
645    }
646}
647
648#[cfg(test)]
649mod tests {
650    use super::*;
651
652    #[test]
653    fn spi_r1_idle_uses_bit_zero() {
654        let response = R1Response::from_spi_byte(0x01).unwrap();
655        assert!(response.idle());
656        assert!(!response.illegal_command());
657        assert!(response.spi_card_error().is_none());
658    }
659
660    #[test]
661    fn spi_r1_illegal_command_sets_flag_and_card_error() {
662        let response = R1Response::from_spi_byte(0x04).unwrap();
663        assert!(response.illegal_command());
664        assert_eq!(response.spi_card_error(), Some(CardError::IllegalCommand));
665    }
666
667    #[test]
668    fn spi_r1_idle_plus_illegal_command_preserves_both() {
669        let response = R1Response::from_spi_byte(0x05).unwrap();
670        assert!(response.idle());
671        assert!(response.illegal_command());
672        assert_eq!(response.spi_card_error(), Some(CardError::IllegalCommand));
673    }
674
675    #[test]
676    fn spi_r1_high_bit_is_bus_error() {
677        assert!(matches!(
678            R1Response::from_spi_byte(0x80),
679            Err(Error::BadResponse(_))
680        ));
681        assert!(matches!(
682            R1Response::from_spi_byte(0xFF),
683            Err(Error::BadResponse(_))
684        ));
685    }
686
687    #[test]
688    fn native_r1_status_bits_decoded() {
689        // status = card in transfer state (bits 12..=9 = 4)
690        let r1 = R1Response::from_native_raw(4 << 9).unwrap();
691        assert_eq!(r1.current_state(), CardState::Transfer);
692    }
693
694    #[test]
695    fn native_r1_with_illegal_command_returns_error() {
696        // illegal command = bit 22 in native R1
697        let err = R1Response::from_native_raw(1 << 22).unwrap_err();
698        assert_eq!(err, Error::CardError(CardError::IllegalCommand));
699    }
700
701    /// Regression: bits 25..=31 used to be silently dropped because
702    /// `from_native_raw` only masked bits 19..=24. A write to an LBA past
703    /// the end of the card raises `OUT_OF_RANGE` (bit 31) and used to be
704    /// reported as `Ok`. After the mask widening it must surface as an
705    /// `Err(CardError::OutOfRange)`.
706    #[test]
707    fn native_r1_out_of_range_was_previously_dropped() {
708        let err = R1Response::from_native_raw(1 << 31).unwrap_err();
709        assert_eq!(err, Error::CardError(CardError::OutOfRange));
710    }
711
712    #[test]
713    fn native_r1_decodes_each_priority_class() {
714        let cases = [
715            (1u32 << 31, CardError::OutOfRange),
716            (1 << 30, CardError::AddressError),
717            (1 << 29, CardError::BlockLenError),
718            (1 << 26, CardError::WriteProtect),
719            (1 << 25, CardError::CardIsLocked),
720            (1 << 24, CardError::LockUnlockFailed),
721            (1 << 23, CardError::CommandCrcFailed),
722            (1 << 22, CardError::IllegalCommand),
723            (1 << 21, CardError::CardEccFailed),
724            (1 << 20, CardError::ControllerError),
725            (1 << 19, CardError::GenericError),
726            (1 << 28, CardError::EraseSequence),
727            (1 << 27, CardError::EraseSequence),
728        ];
729        for (raw, expected) in cases {
730            let err = R1Response::from_native_raw(raw).unwrap_err();
731            assert_eq!(err, Error::CardError(expected), "raw={raw:#010x}");
732        }
733    }
734
735    /// OUT_OF_RANGE outranks WP_VIOLATION when the card sets both — exercises
736    /// the priority ordering in `decode_native_card_error`.
737    #[test]
738    fn native_r1_priority_picks_argument_errors_first() {
739        let err = R1Response::from_native_raw((1 << 31) | (1 << 26)).unwrap_err();
740        assert_eq!(err, Error::CardError(CardError::OutOfRange));
741    }
742
743    /// Informational status bits (bit 8 READY_FOR_DATA, current_state nibble)
744    /// must not be treated as errors. Regression guard against accidentally
745    /// extending the mask too far.
746    #[test]
747    fn native_r1_status_only_response_is_ok() {
748        let raw = (1u32 << 8) | (4u32 << 9); // READY_FOR_DATA + Transfer state
749        let r1 = R1Response::from_native_raw(raw).unwrap();
750        assert!(r1.ready_for_data());
751        assert_eq!(r1.current_state(), CardState::Transfer);
752    }
753
754    #[test]
755    fn decode_spi_card_error_priority_handles_multiple_bits() {
756        // Both illegal command (0x04) + crc failed (0x08) bits set. CRC wins.
757        assert_eq!(
758            decode_spi_card_error(0b0000_1100),
759            CardError::CommandCrcFailed
760        );
761    }
762
763    #[test]
764    fn decode_spi_card_error_unknown_for_unrecognized_bits() {
765        // bit 7 cannot occur after our mask; this exercises the fallback.
766        assert_eq!(decode_spi_card_error(0b0000_0000), CardError::Unknown(0));
767    }
768
769    #[test]
770    fn csd_v2_decodes_2gib_capacity() {
771        // CSD v2 with C_SIZE = 0x000F0F (3855) ⇒ (3855 + 1) * 1024 blocks
772        // = 3,948,544 blocks ≈ 1.88 GiB. Layout: byte 0 high bits = 0x40
773        // (CSD_STRUCTURE = 1), byte 7 low 6 bits + byte 8 + byte 9 = C_SIZE.
774        let mut raw = [0u8; 16];
775        raw[0] = 0x40;
776        raw[7] = 0x00;
777        raw[8] = 0x0F;
778        raw[9] = 0x0F;
779        let csd = CsdResponse::from_raw(raw);
780        assert_eq!(csd.version(), 1);
781        assert_eq!(csd.capacity_blocks(), Some((0x0F0F + 1) * 1024));
782    }
783
784    #[test]
785    fn csd_v1_decodes_known_capacity() {
786        // CSD v1 example: READ_BL_LEN = 9, C_SIZE = 0x0EFF, C_SIZE_MULT = 7
787        // ⇒ blocks = (0x0EFF+1) * 2^(7+2) * 2^9 / 512
788        //          = 3840 * 512 * 512 / 512 = 3840 * 512 = 1,966,080 blocks
789        let mut raw = [0u8; 16];
790        raw[0] = 0x00; // CSD v1
791        raw[5] = 0x09; // low nibble = READ_BL_LEN = 9
792        // C_SIZE = 0x0EFF stored across bytes 6 (low 2 bits) | 7 | 8 (high 2 bits)
793        // 0x0EFF = 0b0000_1110_1111_1111
794        // bits 11:10 = 00 → byte6 low 2 = 0
795        // bits 9:2  = 0b0011_1011 = 0x3B → byte7 = 0x3B
796        // bits 1:0  = 0b11 → byte8 high 2 = 0b11_xx_xxxx
797        raw[6] = 0b0000_0011; // low 2 bits = top 2 of C_SIZE = 11 → wait, recompute
798        // Actually: C_SIZE bits 11:10 → byte6[1:0]; bits 9:2 → byte7[7:0]; bits 1:0 → byte8[7:6]
799        // For C_SIZE = 0x0EFF = 0b1110_1111_1111:
800        //   bits 11:10 = 11
801        //   bits 9:2  = 0b1011_1111 = 0xBF
802        //   bits 1:0  = 0b11
803        raw[6] = 0b0000_0011;
804        raw[7] = 0xBF;
805        raw[8] = 0b1100_0000;
806        // C_SIZE_MULT = 7 = 0b111 stored in byte9[1:0] (top 2 bits of MULT)
807        // and byte10[7] (low bit of MULT)
808        raw[9] = 0b0000_0011;
809        raw[10] = 0b1000_0000;
810        let csd = CsdResponse::from_raw(raw);
811        assert_eq!(csd.version(), 0);
812        let expected = (0x0EFFu64 + 1) * (1 << (7 + 2)) * (1 << 9) / 512;
813        assert_eq!(csd.capacity_blocks(), Some(expected));
814    }
815
816    #[test]
817    fn csd_unknown_version_returns_none() {
818        let mut raw = [0u8; 16];
819        raw[0] = 0x80; // CSD_STRUCTURE = 2 (SDUC v3) — not yet supported
820        let csd = CsdResponse::from_raw(raw);
821        assert_eq!(csd.version(), 2);
822        assert_eq!(csd.capacity_blocks(), None);
823    }
824
825    #[test]
826    fn cid_decodes_manufacturer_oem_product_serial_and_date() {
827        // Hand-rolled CID: MID=0x03, OID="SD", PNM="ABC12", PRV=2.7,
828        //   PSN=0xDEAD_BEEF, MDT year=2026 (offset 26 = 0x1A) month=5.
829        let mut raw = [0u8; 16];
830        raw[0] = 0x03;
831        raw[1] = b'S';
832        raw[2] = b'D';
833        raw[3] = b'A';
834        raw[4] = b'B';
835        raw[5] = b'C';
836        raw[6] = b'1';
837        raw[7] = b'2';
838        raw[8] = (2 << 4) | 7;
839        raw[9] = 0xDE;
840        raw[10] = 0xAD;
841        raw[11] = 0xBE;
842        raw[12] = 0xEF;
843        // MDT bits 19:8 = year[7:0] (8 bits) + month[3:0] (4 bits)
844        // year = 0x1A = 0001 1010: high nibble in raw[13][3:0], low nibble in raw[14][7:4]
845        raw[13] = 0x01; // year high nibble = 1
846        raw[14] = 0xA5; // year low nibble = A, month nibble = 5
847
848        let cid = CidResponse::from_raw(raw);
849        assert_eq!(cid.manufacturer_id(), 0x03);
850        assert_eq!(&cid.oem_id(), b"SD");
851        assert_eq!(&cid.product_name(), b"ABC12");
852        assert_eq!(cid.product_revision(), (2, 7));
853        assert_eq!(cid.serial_number(), 0xDEAD_BEEF);
854        assert_eq!(cid.manufacture_date(), (2026, 5));
855    }
856
857    #[test]
858    fn switch_status_reports_high_speed_when_group_one_function_one() {
859        let mut raw = [0u8; 64];
860        raw[16] = 0x01; // group 2 = 0, group 1 = 1 (high speed)
861        let status = SwitchStatus::from_raw(raw);
862        assert_eq!(status.selected_function(1), 1);
863        assert!(status.high_speed_active());
864    }
865
866    #[test]
867    fn switch_status_reports_access_mode_support_bits() {
868        let mut raw = [0u8; 64];
869        raw[13] = (1 << 1) | (1 << 3);
870        let status = SwitchStatus::from_raw(raw);
871
872        assert!(status.access_mode_supported(1));
873        assert!(status.access_mode_supported(3));
874        assert!(!status.access_mode_supported(2));
875        assert!(!status.access_mode_supported(8));
876    }
877
878    #[test]
879    fn switch_status_reports_default_when_group_one_function_zero() {
880        let raw = [0u8; 64];
881        let status = SwitchStatus::from_raw(raw);
882        assert_eq!(status.selected_function(1), 0);
883        assert!(!status.high_speed_active());
884    }
885
886    #[test]
887    fn switch_status_unsupported_group_returns_0xf() {
888        let mut raw = [0u8; 64];
889        raw[16] = 0xF0; // group 2 unsupported, group 1 = 0
890        let status = SwitchStatus::from_raw(raw);
891        assert_eq!(status.selected_function(2), 0xF);
892        assert_eq!(status.selected_function(7), 0xF); // out of range
893    }
894}