sdmmc_protocol/error.rs
1//! Error and diagnostic context types returned by drivers and parsers.
2//!
3//! See [`Phase`] and [`ErrorContext`] for the operational metadata that
4//! recoverable [`Error`] variants carry.
5
6/// Where in the driver pipeline a fault was observed.
7///
8/// Attached to recoverable [`Error`] variants via [`ErrorContext`] so callers
9/// can distinguish e.g. a CMD0 send timeout from a `BusyWait` programming
10/// timeout without parsing log strings.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
12pub enum Phase {
13 /// Phase was not recorded.
14 ///
15 /// Used as a default placeholder; real driver paths should pick a
16 /// concrete variant.
17 #[default]
18 Unspecified,
19 /// Power-up / running CMD0 → ACMD41 / sending CMD2/3/9/7.
20 Init,
21 /// Putting the command bytes onto the bus.
22 CommandSend,
23 /// Waiting for the card's response token / R1–R7 payload.
24 ResponseWait,
25 /// Streaming a data block to the card (CMD24 / CMD25 etc).
26 DataWrite,
27 /// Streaming a data block from the card (CMD17 / CMD18 etc).
28 DataRead,
29 /// Polling the card's busy line / programming status.
30 BusyWait,
31 /// Switching bus speed, width or function (CMD6 / ACMD6).
32 Switch,
33 /// Erase sequence (CMD32 / CMD33 / CMD38).
34 Erase,
35}
36
37/// Operational context attached to recoverable bus / protocol errors.
38///
39/// Helps callers triage failures: which phase of the SD/MMC pipeline
40/// raised the error, and which CMD/ACMD index was being processed at
41/// the time, when known.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
43pub struct ErrorContext {
44 /// Pipeline phase when the fault was raised.
45 pub phase: Phase,
46 /// CMD/ACMD index being processed, if applicable.
47 pub cmd: Option<u8>,
48}
49
50impl ErrorContext {
51 /// Build a context with only the phase populated.
52 #[inline]
53 pub const fn new(phase: Phase) -> Self {
54 Self { phase, cmd: None }
55 }
56
57 /// Build a context tied to a specific CMD/ACMD index.
58 #[inline]
59 pub const fn for_cmd(phase: Phase, cmd: u8) -> Self {
60 Self {
61 phase,
62 cmd: Some(cmd),
63 }
64 }
65}
66
67/// Errors returned by SD/MMC protocol parsers and drivers.
68///
69/// Recoverable bus / protocol variants carry an [`ErrorContext`] pinpointing
70/// the phase and (when known) command index that raised them. Caller-facing
71/// programming errors (`Misaligned`, `InvalidArgument`) and card-state
72/// reports (`NoCard`, `CardError`, `CardLocked`) do not.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum Error {
75 /// No response from card within the deadline for the wrapped phase.
76 Timeout(ErrorContext),
77 /// CRC check failed during the wrapped phase.
78 Crc(ErrorContext),
79 /// Card is not responding or not inserted.
80 NoCard,
81 /// Command index is not supported on this transport.
82 UnsupportedCommand,
83 /// Bad response received during the wrapped phase.
84 BadResponse(ErrorContext),
85 /// Card returned an error in its R1 response.
86 CardError(CardError),
87 /// Write operation failed during the wrapped phase.
88 WriteError(ErrorContext),
89 /// Read operation failed during the wrapped phase.
90 ReadError(ErrorContext),
91 /// Misaligned address or length passed by the caller.
92 Misaligned,
93 /// Caller passed an invalid argument.
94 InvalidArgument,
95 /// Card is locked (host needs to unlock before further I/O).
96 CardLocked,
97 /// Generic communication error on the bus during the wrapped phase.
98 BusError(ErrorContext),
99}
100
101/// Per-bit error status decoded out of an R1 response.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum CardError {
104 /// A command was issued out of sequence.
105 IllegalCommand,
106 /// CRC check of the last command failed.
107 CommandCrcFailed,
108 /// Erase sequence error.
109 EraseSequence,
110 /// Address alignment error.
111 AddressError,
112 /// Card internal ECC error.
113 CardEccFailed,
114 /// Generic controller error.
115 ControllerError,
116 /// Unknown error bit set.
117 Unknown(u8),
118}