Skip to main content

sdmmc_protocol/
response.rs

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