1use core::marker::PhantomData;
2
3/// Host to Card commands
4pub struct Cmd<R: Resp> {
5 pub cmd: u8,
6 pub arg: u32,
7 resp: PhantomData<R>,
8}
9
10impl<R: Resp> Cmd<R> {
11 pub fn response_len(&self) -> ResponseLen {
12 R::LENGTH
13 }
14}
15
16/// Marker for commands that don't have any response
17pub struct Rz;
18/// R1: Normal response
19pub struct R1;
20/// R2: CID and CSD register
21pub struct R2;
22/// R3: OCR register
23pub struct R3;
24/// R6: Published RCA response
25pub struct R6;
26/// R7: Card interface condition
27pub struct R7;
28
29pub trait Resp {
30 const LENGTH: ResponseLen = ResponseLen::R48;
31}
32
33impl Resp for Rz {
34 const LENGTH: ResponseLen = ResponseLen::Zero;
35}
36
37impl Resp for R2 {
38 const LENGTH: ResponseLen = ResponseLen::R136;
39}
40
41impl Resp for R1 {}
42impl Resp for R3 {}
43impl Resp for R6 {}
44impl Resp for R7 {}
45
46/// Command Response type
47#[derive(Eq, PartialEq, Copy, Clone)]
48pub enum ResponseLen {
49 /// No response expected
50 Zero,
51 /// Short (48 bit) response
52 R48,
53 /// Long (136 bit) response
54 R136,
55}
56
57pub fn cmd<R: Resp>(cmd: u8, arg: u32) -> Cmd<R> {
58 Cmd {
59 cmd,
60 arg,
61 resp: PhantomData,
62 }
63}
64
65/// CMD0: Put card in idle mode
66pub fn idle() -> Cmd<Rz> {
67 cmd(cmd:0, arg:0)
68}
69
70/// CMD2: Ask any card to send their CID
71pub fn all_send_cid() -> Cmd<R2> {
72 cmd(cmd:2, arg:0)
73}
74
75/// CMD3: Send RCA
76pub fn send_relative_address() -> Cmd<R6> {
77 cmd(cmd:3, arg:0)
78}
79
80/// CMD6: Switch Function Command
81pub fn cmd6(arg: u32) -> Cmd<R1> {
82 cmd(cmd:6, arg)
83}
84
85/// CMD7: Select or deselect card
86pub fn select_card(rca: u16) -> Cmd<R1> {
87 cmd(cmd:7, arg:u32::from(rca) << 16)
88}
89
90/// CMD8: Sends memory card interface conditions
91pub fn send_if_cond(voltage: u8, checkpattern: u8) -> Cmd<R7> {
92 let arg: u32 = u32::from(voltage & 0xF) << 8 | u32::from(checkpattern);
93 cmd(cmd:8, arg)
94}
95
96/// CMD9: Send CSD
97pub fn send_csd(rca: u16) -> Cmd<R2> {
98 cmd(cmd:9, arg:u32::from(rca) << 16)
99}
100
101/// CMD10: Send CID
102pub fn send_cid(rca: u16) -> Cmd<R2> {
103 cmd(cmd:10, arg:u32::from(rca) << 16)
104}
105
106/// CMD11: Switch to 1.8V bus signaling level
107pub fn voltage_switch() -> Cmd<R1> {
108 cmd(cmd:11, arg:0)
109}
110
111/// CMD12: Stop transmission
112pub fn stop_transmission() -> Cmd<R1> {
113 cmd(cmd:12, arg:0)
114}
115
116/// CMD13: Ask card to send status or task status
117pub fn card_status(rca: u16, task_status: bool) -> Cmd<R1> {
118 let arg: u32 = u32::from(rca) << 16 | u32::from(task_status) << 15;
119 cmd(cmd:13, arg)
120}
121
122/// CMD15: Sends card to inactive state
123pub fn go_inactive_state(rca: u16) -> Cmd<Rz> {
124 cmd(cmd:15, arg:u32::from(rca) << 16)
125}
126
127/// CMD16: Set block len
128pub fn set_block_length(blocklen: u32) -> Cmd<R1> {
129 cmd(cmd:16, arg:blocklen)
130}
131
132/// CMD17: Read a single block from the card
133pub fn read_single_block(addr: u32) -> Cmd<R1> {
134 cmd(cmd:17, arg:addr)
135}
136
137/// CMD18: Read multiple block from the card
138pub fn read_multiple_blocks(addr: u32) -> Cmd<R1> {
139 cmd(cmd:18, arg:addr)
140}
141
142/// CMD19: Send tuning pattern
143pub fn send_tuning_block(addr: u32) -> Cmd<R1> {
144 cmd(cmd:19, arg:addr)
145}
146
147/// CMD20: Speed class control
148pub fn speed_class_control(arg: u32) -> Cmd<R1> {
149 cmd(cmd:20, arg)
150}
151
152/// CMD22: Address extension
153pub fn address_extension(arg: u32) -> Cmd<R1> {
154 cmd(cmd:22, arg)
155}
156
157/// CMD23: Address extension
158pub fn set_block_count(blockcount: u32) -> Cmd<R1> {
159 cmd(cmd:23, arg:blockcount)
160}
161
162/// CMD24: Write block
163pub fn write_single_block(addr: u32) -> Cmd<R1> {
164 cmd(cmd:24, arg:addr)
165}
166
167/// CMD25: Write multiple blocks
168pub fn write_multiple_blocks(addr: u32) -> Cmd<R1> {
169 cmd(cmd:25, arg:addr)
170}
171
172/// CMD27: Program CSD
173pub fn program_csd() -> Cmd<R1> {
174 cmd(cmd:27, arg:0)
175}
176
177/// CMD55: App Command. Indicates that next command will be a app command
178pub fn app_cmd(rca: u16) -> Cmd<R1> {
179 cmd(cmd:55, arg:u32::from(rca) << 16)
180}
181
182/// ACMD6: Bus Width
183/// * `bw4bit` - Enable 4 bit bus width
184pub fn set_bus_width(bw4bit: bool) -> Cmd<R1> {
185 let arg: u32 = if bw4bit { 0b10 } else { 0b00 };
186 cmd(cmd:6, arg)
187}
188
189/// ACMD13: SD Status
190pub fn sd_status() -> Cmd<R1> {
191 cmd(cmd:13, arg:0)
192}
193
194/// ACMD41: App Op Command
195///
196/// * `high_capacity` - Host supports high capacity cards
197/// * `xpc` - Controls the maximum power and default speed mode of SDXC and SDUC cards.
198/// * `s18r` - Switch to 1.8V signaling
199/// * `voltage_window` - The voltage window the host supports.
200pub fn sd_send_op_cond(high_capacity: bool, xpc: bool, s18r: bool, voltage_window: u32) -> Cmd<R3> {
201 let arg: u32 = u32::from(high_capacity) << 30
202 | u32::from(xpc) << 28
203 | u32::from(s18r) << 24
204 | voltage_window & 0x00FF_FFFF;
205 cmd(cmd:41, arg)
206}
207
208/// ACMD51: Reads the SCR
209pub fn send_scr() -> Cmd<R1> {
210 cmd(cmd:51, arg:0)
211}
212