1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
use core::marker::PhantomData;

/// Host to Card commands
pub struct Cmd<R: Resp> {
    pub cmd: u8,
    pub arg: u32,
    resp: PhantomData<R>,
}

impl<R: Resp> Cmd<R> {
    pub fn response_len(&self) -> ResponseLen {
        R::LENGTH
    }
}

/// Marker for commands that don't have any response
pub struct Rz;
/// R1: Normal response
pub struct R1;
/// R2: CID and CSD register
pub struct R2;
/// R3: OCR register
pub struct R3;
/// R6: Published RCA response
pub struct R6;
/// R7: Card interface condition
pub struct R7;

pub trait Resp {
    const LENGTH: ResponseLen = ResponseLen::R48;
}

impl Resp for Rz {
    const LENGTH: ResponseLen = ResponseLen::Zero;
}

impl Resp for R2 {
    const LENGTH: ResponseLen = ResponseLen::R136;
}

impl Resp for R1 {}
impl Resp for R3 {}
impl Resp for R6 {}
impl Resp for R7 {}

/// Command Response type
#[derive(Eq, PartialEq, Copy, Clone)]
pub enum ResponseLen {
    /// No response expected
    Zero,
    /// Short (48 bit) response
    R48,
    /// Long (136 bit) response
    R136,
}

pub fn cmd<R: Resp>(cmd: u8, arg: u32) -> Cmd<R> {
    Cmd {
        cmd,
        arg,
        resp: PhantomData,
    }
}

/// CMD0: Put card in idle mode
pub fn idle() -> Cmd<Rz> {
    cmd(0, 0)
}

/// CMD2: Ask any card to send their CID
pub fn all_send_cid() -> Cmd<R2> {
    cmd(2, 0)
}

/// CMD3: Send RCA
pub fn send_relative_address() -> Cmd<R6> {
    cmd(3, 0)
}

/// CMD6: Switch Function Command
pub fn cmd6(arg: u32) -> Cmd<R1> {
    cmd(6, arg)
}

/// CMD7: Select or deselect card
pub fn select_card(rca: u16) -> Cmd<R1> {
    cmd(7, u32::from(rca) << 16)
}

/// CMD8: Sends memory card interface conditions
pub fn send_if_cond(voltage: u8, checkpattern: u8) -> Cmd<R7> {
    let arg = u32::from(voltage & 0xF) << 8 | u32::from(checkpattern);
    cmd(8, arg)
}

/// CMD9: Send CSD
pub fn send_csd(rca: u16) -> Cmd<R2> {
    cmd(9, u32::from(rca) << 16)
}

/// CMD10: Send CID
pub fn send_cid(rca: u16) -> Cmd<R2> {
    cmd(10, u32::from(rca) << 16)
}

/// CMD11: Switch to 1.8V bus signaling level
pub fn voltage_switch() -> Cmd<R1> {
    cmd(11, 0)
}

/// CMD12: Stop transmission
pub fn stop_transmission() -> Cmd<R1> {
    cmd(12, 0)
}

/// CMD13: Ask card to send status or task status
pub fn card_status(rca: u16, task_status: bool) -> Cmd<R1> {
    let arg = u32::from(rca) << 16 | u32::from(task_status) << 15;
    cmd(13, arg)
}

/// CMD15: Sends card to inactive state
pub fn go_inactive_state(rca: u16) -> Cmd<Rz> {
    cmd(15, u32::from(rca) << 16)
}

/// CMD16: Set block len
pub fn set_block_length(blocklen: u32) -> Cmd<R1> {
    cmd(16, blocklen)
}

/// CMD17: Read a single block from the card
pub fn read_single_block(addr: u32) -> Cmd<R1> {
    cmd(17, addr)
}

/// CMD18: Read multiple block from the card
pub fn read_multiple_blocks(addr: u32) -> Cmd<R1> {
    cmd(18, addr)
}

/// CMD19: Send tuning pattern
pub fn send_tuning_block(addr: u32) -> Cmd<R1> {
    cmd(19, addr)
}

/// CMD20: Speed class control
pub fn speed_class_control(arg: u32) -> Cmd<R1> {
    cmd(20, arg)
}

/// CMD22: Address extension
pub fn address_extension(arg: u32) -> Cmd<R1> {
    cmd(22, arg)
}

/// CMD23: Address extension
pub fn set_block_count(blockcount: u32) -> Cmd<R1> {
    cmd(23, blockcount)
}

/// CMD24: Write block
pub fn write_single_block(addr: u32) -> Cmd<R1> {
    cmd(24, addr)
}

/// CMD25: Write multiple blocks
pub fn write_multiple_blocks(addr: u32) -> Cmd<R1> {
    cmd(25, addr)
}

/// CMD27: Program CSD
pub fn program_csd() -> Cmd<R1> {
    cmd(27, 0)
}

/// CMD55: App Command. Indicates that next command will be a app command
pub fn app_cmd(rca: u16) -> Cmd<R1> {
    cmd(55, u32::from(rca) << 16)
}

/// ACMD6: Bus Width
/// * `bw4bit` - Enable 4 bit bus width
pub fn set_bus_width(bw4bit: bool) -> Cmd<R1> {
    let arg = if bw4bit { 0b10 } else { 0b00 };
    cmd(6, arg)
}

/// ACMD13: SD Status
pub fn sd_status() -> Cmd<R1> {
    cmd(13, 0)
}

/// ACMD41: App Op Command
///
/// * `high_capacity` - Host supports high capacity cards
/// * `xpc` - Controls the maximum power and default speed mode of SDXC and SDUC cards.
/// * `s18r` - Switch to 1.8V signaling
/// * `voltage_window` - The voltage window the host supports.
pub fn sd_send_op_cond(high_capacity: bool, xpc: bool, s18r: bool, voltage_window: u32) -> Cmd<R3> {
    let arg = u32::from(high_capacity) << 30
        | u32::from(xpc) << 28
        | u32::from(s18r) << 24
        | voltage_window & 0x00FF_FFFF;
    cmd(41, arg)
}

/// ACMD51: Reads the SCR
pub fn send_scr() -> Cmd<R1> {
    cmd(51, 0)
}