use core::marker::PhantomData;
use core::{fmt, mem, slice};
use core::fmt::Debug;
use aligned::{A4, Aligned};
use crate::{
BlockCommand, BlockReadCommand, BlockWriteCommand, Command, ControlCommand, R1, R1b, R2, R3,
R4, R6,
};
pub struct Cmd0;
impl Command for Cmd0 {
const INDEX: u8 = 0;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
0
}
}
impl ControlCommand for Cmd0 {}
pub fn idle() -> Cmd0 {
Cmd0
}
pub struct Cmd2;
impl Command for Cmd2 {
const INDEX: u8 = 2;
type Resp<'a> = R2;
fn arg(&self) -> u32 {
0
}
}
impl ControlCommand for Cmd2 {}
pub fn all_send_cid() -> Cmd2 {
Cmd2
}
pub struct Cmd7 {
pub rca: u16,
}
impl Command for Cmd7 {
const INDEX: u8 = 7;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
(self.rca as u32) << 16
}
}
impl ControlCommand for Cmd7 {}
pub fn select_card(rca: u16) -> Cmd7 {
Cmd7 { rca }
}
pub struct Cmd9 {
pub rca: u16,
}
impl Command for Cmd9 {
const INDEX: u8 = 9;
type Resp<'a> = R2;
fn arg(&self) -> u32 {
(self.rca as u32) << 16
}
}
impl ControlCommand for Cmd9 {}
pub fn send_csd(rca: u16) -> Cmd9 {
Cmd9 { rca }
}
pub struct Cmd10 {
pub rca: u16,
}
impl Command for Cmd10 {
const INDEX: u8 = 10;
type Resp<'a> = R2;
fn arg(&self) -> u32 {
(self.rca as u32) << 16
}
}
impl ControlCommand for Cmd10 {}
pub fn send_cid(rca: u16) -> Cmd10 {
Cmd10 { rca }
}
pub struct Cmd12;
impl Command for Cmd12 {
const INDEX: u8 = 12;
type Resp<'a> = R1b;
fn arg(&self) -> u32 {
0
}
}
impl ControlCommand for Cmd12 {}
pub fn stop_transmission() -> Cmd12 {
Cmd12
}
pub struct Cmd13 {
pub rca: u16,
pub task_status: bool,
}
impl Command for Cmd13 {
const INDEX: u8 = 13;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
(self.rca as u32) << 16 | (self.task_status as u32) << 15
}
}
impl ControlCommand for Cmd13 {}
pub fn card_status(rca: u16, task_status: bool) -> Cmd13 {
Cmd13 { rca, task_status }
}
pub struct Cmd16 {
pub block_len: u32,
}
impl Command for Cmd16 {
const INDEX: u8 = 16;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
self.block_len
}
}
impl ControlCommand for Cmd16 {}
pub fn set_block_length(block_len: u32) -> Cmd16 {
Cmd16 { block_len }
}
pub struct Cmd17<'a, const BLOCK_SIZE: usize> {
pub addr: u32,
pub buf: &'a mut Aligned<A4, [u8; BLOCK_SIZE]>,
}
impl<'a, const BLOCK_SIZE: usize> Command for Cmd17<'a, BLOCK_SIZE> {
const INDEX: u8 = 17;
type Resp<'b>
= R1
where
Self: 'b;
fn arg(&self) -> u32 {
self.addr
}
}
impl<'a, const BLOCK_SIZE: usize> BlockCommand for Cmd17<'a, BLOCK_SIZE> {
fn block_size(&self) -> u16 {
BLOCK_SIZE as u16
}
fn block_count(&self) -> u32 {
1
}
}
impl<'a, const BLOCK_SIZE: usize> BlockReadCommand for Cmd17<'a, BLOCK_SIZE> {
fn buf(&mut self) -> &mut Aligned<A4, [u8]> {
&mut *self.buf
}
}
pub fn read_single_block<const BLOCK_SIZE: usize>(
addr: u32,
buf: &mut Aligned<A4, [u8; BLOCK_SIZE]>,
) -> Cmd17<'_, BLOCK_SIZE> {
Cmd17 { addr, buf }
}
pub struct Cmd18<'a, const BLOCK_SIZE: usize> {
pub addr: u32,
pub buf: &'a mut [Aligned<A4, [u8; BLOCK_SIZE]>],
}
impl<'a, const BLOCK_SIZE: usize> Command for Cmd18<'a, BLOCK_SIZE> {
const INDEX: u8 = 18;
type Resp<'b>
= R1
where
Self: 'b;
fn arg(&self) -> u32 {
self.addr
}
}
impl<'a, const BLOCK_SIZE: usize> BlockCommand for Cmd18<'a, BLOCK_SIZE> {
fn block_size(&self) -> u16 {
BLOCK_SIZE as u16
}
fn block_count(&self) -> u32 {
self.buf.len() as u32
}
}
impl<'a, const BLOCK_SIZE: usize> BlockReadCommand for Cmd18<'a, BLOCK_SIZE> {
fn buf(&mut self) -> &mut Aligned<A4, [u8]> {
unsafe {
mem::transmute(slice::from_raw_parts_mut(
self.buf.as_mut_ptr() as *mut _,
size_of_val(self.buf),
))
}
}
}
pub fn read_multiple_blocks<const BLOCK_SIZE: usize>(
addr: u32,
buf: &mut [Aligned<A4, [u8; BLOCK_SIZE]>],
) -> Cmd18<'_, BLOCK_SIZE> {
Cmd18 { addr, buf }
}
pub struct Cmd24<'a, const BLOCK_SIZE: usize> {
pub addr: u32,
pub buf: &'a Aligned<A4, [u8; BLOCK_SIZE]>,
}
impl<'a, const BLOCK_SIZE: usize> Command for Cmd24<'a, BLOCK_SIZE> {
const INDEX: u8 = 24;
type Resp<'b>
= R1b
where
Self: 'b;
fn arg(&self) -> u32 {
self.addr
}
}
impl<'a, const BLOCK_SIZE: usize> BlockCommand for Cmd24<'a, BLOCK_SIZE> {
fn block_size(&self) -> u16 {
BLOCK_SIZE as u16
}
fn block_count(&self) -> u32 {
1
}
}
impl<'a, const BLOCK_SIZE: usize> BlockWriteCommand for Cmd24<'a, BLOCK_SIZE> {
fn buf(&self) -> &Aligned<A4, [u8]> {
self.buf
}
}
pub fn write_single_block<const BLOCK_SIZE: usize>(
addr: u32,
buf: &Aligned<A4, [u8; BLOCK_SIZE]>,
) -> Cmd24<'_, BLOCK_SIZE> {
Cmd24 { addr, buf }
}
pub struct Cmd25<'a, const BLOCK_SIZE: usize> {
pub addr: u32,
pub buf: &'a [Aligned<A4, [u8; BLOCK_SIZE]>],
}
impl<'a, const BLOCK_SIZE: usize> Command for Cmd25<'a, BLOCK_SIZE> {
const INDEX: u8 = 25;
type Resp<'b>
= R1b
where
Self: 'b;
fn arg(&self) -> u32 {
self.addr
}
}
impl<'a, const BLOCK_SIZE: usize> BlockCommand for Cmd25<'a, BLOCK_SIZE> {
fn block_size(&self) -> u16 {
BLOCK_SIZE as u16
}
fn block_count(&self) -> u32 {
self.buf.len() as u32
}
}
impl<'a, const BLOCK_SIZE: usize> BlockWriteCommand for Cmd25<'a, BLOCK_SIZE> {
fn buf(&self) -> &Aligned<A4, [u8]> {
unsafe {
mem::transmute(slice::from_raw_parts(
self.buf.as_ptr() as *const _,
size_of_val(self.buf),
))
}
}
}
pub fn write_multiple_blocks<const BLOCK_SIZE: usize>(
addr: u32,
buf: &[Aligned<A4, [u8; BLOCK_SIZE]>],
) -> Cmd25<'_, BLOCK_SIZE> {
Cmd25 { addr, buf }
}
pub struct Cmd38;
impl Command for Cmd38 {
const INDEX: u8 = 38;
type Resp<'a> = R1b;
fn arg(&self) -> u32 {
0
}
}
impl ControlCommand for Cmd38 {}
pub fn erase() -> Cmd38 {
Cmd38
}
pub struct Cmd55 {
pub rca: u16,
}
impl Command for Cmd55 {
const INDEX: u8 = 55;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
(self.rca as u32) << 16
}
}
impl ControlCommand for Cmd55 {}
pub fn app_cmd(rca: u16) -> Cmd55 {
Cmd55 { rca }
}
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum CardCapacity {
StandardCapacity,
HighCapacity,
}
impl Default for CardCapacity {
fn default() -> Self {
CardCapacity::StandardCapacity
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BlockSize {
#[non_exhaustive]
B1 = 0,
B2 = 1,
B4 = 2,
B8 = 3,
B16 = 4,
B32 = 5,
B64 = 6,
B128 = 7,
B256 = 8,
B512 = 9,
B1024 = 10,
B2048 = 11,
B4096 = 12,
B8192 = 13,
B16kB = 14,
Unknown = 15,
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
#[allow(dead_code)]
pub enum CurrentState {
Ready = 1,
Identification = 2,
Standby = 3,
Transfer = 4,
Sending = 5,
Receiving = 6,
Programming = 7,
Disconnected = 8,
BusTest = 9,
Sleep = 10,
Error = 128,
}
impl From<u8> for CurrentState {
fn from(n: u8) -> Self {
match n {
1 => Self::Ready,
2 => Self::Identification,
3 => Self::Standby,
4 => Self::Transfer,
5 => Self::Sending,
6 => Self::Receiving,
7 => Self::Programming,
8 => Self::Disconnected,
9 => Self::BusTest,
10 => Self::Sleep,
_ => Self::Error,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
#[allow(non_camel_case_types)]
pub enum CurrentConsumption {
I_0mA,
I_1mA,
I_5mA,
I_10mA,
I_25mA,
I_35mA,
I_45mA,
I_60mA,
I_80mA,
I_100mA,
I_200mA,
}
impl From<&CurrentConsumption> for u32 {
fn from(i: &CurrentConsumption) -> u32 {
match i {
CurrentConsumption::I_0mA => 0,
CurrentConsumption::I_1mA => 1,
CurrentConsumption::I_5mA => 5,
CurrentConsumption::I_10mA => 10,
CurrentConsumption::I_25mA => 25,
CurrentConsumption::I_35mA => 35,
CurrentConsumption::I_45mA => 45,
CurrentConsumption::I_60mA => 60,
CurrentConsumption::I_80mA => 80,
CurrentConsumption::I_100mA => 100,
CurrentConsumption::I_200mA => 200,
}
}
}
impl CurrentConsumption {
fn from_minimum_reg(reg: u128) -> CurrentConsumption {
match reg & 0x7 {
0 => CurrentConsumption::I_0mA,
1 => CurrentConsumption::I_1mA,
2 => CurrentConsumption::I_5mA,
3 => CurrentConsumption::I_10mA,
4 => CurrentConsumption::I_25mA,
5 => CurrentConsumption::I_35mA,
6 => CurrentConsumption::I_60mA,
_ => CurrentConsumption::I_100mA,
}
}
fn from_maximum_reg(reg: u128) -> CurrentConsumption {
match reg & 0x7 {
0 => CurrentConsumption::I_1mA,
1 => CurrentConsumption::I_5mA,
2 => CurrentConsumption::I_10mA,
3 => CurrentConsumption::I_25mA,
4 => CurrentConsumption::I_35mA,
5 => CurrentConsumption::I_45mA,
6 => CurrentConsumption::I_80mA,
_ => CurrentConsumption::I_200mA,
}
}
}
impl fmt::Debug for CurrentConsumption {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ma: u32 = self.into();
write!(f, "{} mA", ma)
}
}
#[derive(Clone, Copy, Default)]
pub struct OCR<Ext>(pub(crate) u32, PhantomData<Ext>);
impl<Ext> From<R3> for OCR<Ext> {
fn from(resp: R3) -> Self {
Self(resp.ocr, PhantomData)
}
}
impl<Ext> From<R4> for OCR<Ext> {
fn from(resp: R4) -> Self {
Self(resp.ocr, PhantomData)
}
}
impl<Ext> OCR<Ext> {
pub fn is_busy(&self) -> bool {
self.0 & 0x8000_0000 == 0 }
}
#[derive(Clone, Copy, Default)]
pub struct CID<Ext> {
pub(crate) bytes: [u8; 16],
ext: PhantomData<Ext>,
}
impl<Ext> From<R2> for CID<Ext> {
fn from(resp: R2) -> Self {
let words = resp.words;
let inner = ((words[3] as u128) << 96)
| ((words[2] as u128) << 64)
| ((words[1] as u128) << 32)
| words[0] as u128;
Self {
bytes: inner.to_be_bytes(),
ext: PhantomData,
}
}
}
impl<Ext> CID<Ext> {
pub(crate) const fn inner(&self) -> u128 {
u128::from_be_bytes(self.bytes)
}
pub fn manufacturer_id(&self) -> u8 {
self.bytes[0]
}
#[allow(unused)]
fn crc7(&self) -> u8 {
(self.bytes[15] >> 1) & 0x7F
}
}
#[derive(Clone, Copy, Default)]
pub struct CSD<Ext>(pub(crate) u128, PhantomData<Ext>);
impl<Ext> From<u128> for CSD<Ext> {
fn from(inner: u128) -> Self {
Self(inner, PhantomData)
}
}
impl<Ext> From<R2> for CSD<Ext> {
fn from(resp: R2) -> Self {
let words = resp.words;
let inner = ((words[3] as u128) << 96)
| ((words[2] as u128) << 64)
| ((words[1] as u128) << 32)
| words[0] as u128;
inner.into()
}
}
impl<Ext> CSD<Ext> {
pub fn version(&self) -> u8 {
(self.0 >> 126) as u8 & 3
}
pub fn transfer_rate(&self) -> u8 {
(self.0 >> 96) as u8
}
pub fn block_length(&self) -> BlockSize {
match (self.0 >> 80) & 0xF {
0 => BlockSize::B1,
1 => BlockSize::B2,
2 => BlockSize::B4,
3 => BlockSize::B8,
4 => BlockSize::B16,
5 => BlockSize::B32,
6 => BlockSize::B64,
7 => BlockSize::B128,
8 => BlockSize::B256,
9 => BlockSize::B512,
10 => BlockSize::B1024,
11 => BlockSize::B2048,
12 => BlockSize::B4096,
13 => BlockSize::B8192,
14 => BlockSize::B16kB,
_ => BlockSize::Unknown,
}
}
pub fn read_current_minimum_vdd(&self) -> CurrentConsumption {
CurrentConsumption::from_minimum_reg((self.0 >> 59) & 0x7)
}
pub fn write_current_minimum_vdd(&self) -> CurrentConsumption {
CurrentConsumption::from_minimum_reg((self.0 >> 56) & 0x7)
}
pub fn read_current_maximum_vdd(&self) -> CurrentConsumption {
CurrentConsumption::from_maximum_reg((self.0 >> 53) & 0x7)
}
pub fn write_current_maximum_vdd(&self) -> CurrentConsumption {
CurrentConsumption::from_maximum_reg((self.0 >> 50) & 0x7)
}
}
#[derive(Clone, Copy)]
pub struct CardStatus<Ext>(pub(crate) u32, PhantomData<Ext>);
impl<Ext> From<R1> for CardStatus<Ext> {
fn from(resp: R1) -> Self {
Self(resp.status, PhantomData)
}
}
impl<Ext> CardStatus<Ext> {
pub fn out_of_range(&self) -> bool {
self.0 & 0x8000_0000 != 0
}
pub fn address_error(&self) -> bool {
self.0 & 0x4000_0000 != 0
}
pub fn block_len_error(&self) -> bool {
self.0 & 0x2000_0000 != 0
}
pub fn erase_seq_error(&self) -> bool {
self.0 & 0x1000_0000 != 0
}
pub fn erase_param(&self) -> bool {
self.0 & 0x800_0000 != 0
}
pub fn wp_violation(&self) -> bool {
self.0 & 0x400_0000 != 0
}
pub fn card_is_locked(&self) -> bool {
self.0 & 0x200_0000 != 0
}
pub fn lock_unlock_failed(&self) -> bool {
self.0 & 0x100_0000 != 0
}
pub fn com_crc_error(&self) -> bool {
self.0 & 0x80_0000 != 0
}
pub fn illegal_command(&self) -> bool {
self.0 & 0x40_0000 != 0
}
pub fn card_ecc_failed(&self) -> bool {
self.0 & 0x20_0000 != 0
}
pub fn cc_error(&self) -> bool {
self.0 & 0x10_0000 != 0
}
pub fn error(&self) -> bool {
self.0 & 0x8_0000 != 0
}
pub fn csd_overwrite(&self) -> bool {
self.0 & 0x1_0000 != 0
}
pub fn wp_erase_skip(&self) -> bool {
self.0 & 0x8000 != 0
}
pub fn erase_reset(&self) -> bool {
self.0 & 0x2000 != 0
}
pub fn state(&self) -> CurrentState {
CurrentState::from(((self.0 >> 9) & 0xF) as u8)
}
pub fn ready_for_data(&self) -> bool {
self.0 & 0x100 != 0
}
pub fn app_cmd(&self) -> bool {
self.0 & 0x20 != 0
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct RCA<Ext>(pub(crate) u32, pub(crate) PhantomData<Ext>);
impl<Ext> From<R6> for RCA<Ext> {
fn from(resp: R6) -> Self {
Self((resp.rca as u32) << 16 & resp.status as u32, PhantomData)
}
}
impl<Ext> RCA<Ext> {
pub fn address(&self) -> u16 {
(self.0 >> 16) as u16
}
}