use core::marker::PhantomData;
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
}
}
pub struct Rz;
pub struct R1;
pub struct R2;
pub struct R3;
pub struct R6;
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 {}
#[derive(Eq, PartialEq, Copy, Clone)]
pub enum ResponseLen {
Zero,
R48,
R136,
}
pub fn cmd<R: Resp>(cmd: u8, arg: u32) -> Cmd<R> {
Cmd {
cmd,
arg,
resp: PhantomData,
}
}
pub fn idle() -> Cmd<Rz> {
cmd(0, 0)
}
pub fn all_send_cid() -> Cmd<R2> {
cmd(2, 0)
}
pub fn send_relative_address() -> Cmd<R6> {
cmd(3, 0)
}
pub fn cmd6(arg: u32) -> Cmd<R1> {
cmd(6, arg)
}
pub fn select_card(rca: u16) -> Cmd<R1> {
cmd(7, u32::from(rca) << 16)
}
pub fn send_if_cond(voltage: u8, checkpattern: u8) -> Cmd<R7> {
let arg = u32::from(voltage & 0xF) << 8 | u32::from(checkpattern);
cmd(8, arg)
}
pub fn send_csd(rca: u16) -> Cmd<R2> {
cmd(9, u32::from(rca) << 16)
}
pub fn send_cid(rca: u16) -> Cmd<R2> {
cmd(10, u32::from(rca) << 16)
}
pub fn voltage_switch() -> Cmd<R1> {
cmd(11, 0)
}
pub fn stop_transmission() -> Cmd<R1> {
cmd(12, 0)
}
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)
}
pub fn go_inactive_state(rca: u16) -> Cmd<Rz> {
cmd(15, u32::from(rca) << 16)
}
pub fn set_block_length(blocklen: u32) -> Cmd<R1> {
cmd(16, blocklen)
}
pub fn read_single_block(addr: u32) -> Cmd<R1> {
cmd(17, addr)
}
pub fn read_multiple_blocks(addr: u32) -> Cmd<R1> {
cmd(18, addr)
}
pub fn send_tuning_block(addr: u32) -> Cmd<R1> {
cmd(19, addr)
}
pub fn speed_class_control(arg: u32) -> Cmd<R1> {
cmd(20, arg)
}
pub fn address_extension(arg: u32) -> Cmd<R1> {
cmd(22, arg)
}
pub fn set_block_count(blockcount: u32) -> Cmd<R1> {
cmd(23, blockcount)
}
pub fn write_single_block(addr: u32) -> Cmd<R1> {
cmd(24, addr)
}
pub fn write_multiple_blocks(addr: u32) -> Cmd<R1> {
cmd(25, addr)
}
pub fn program_csd() -> Cmd<R1> {
cmd(27, 0)
}
pub fn app_cmd(rca: u16) -> Cmd<R1> {
cmd(55, u32::from(rca) << 16)
}
pub fn set_bus_width(bw4bit: bool) -> Cmd<R1> {
let arg = if bw4bit { 0b10 } else { 0b00 };
cmd(6, arg)
}
pub fn sd_status() -> Cmd<R1> {
cmd(13, 0)
}
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)
}
pub fn send_scr() -> Cmd<R1> {
cmd(51, 0)
}