use core::fmt;
use core::marker::PhantomData;
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum CardCapacity {
StandardCapacity,
HighCapacity,
}
impl Default for CardCapacity {
fn default() -> Self {
CardCapacity::StandardCapacity
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum BusWidth {
#[non_exhaustive]
Unknown,
One = 1,
Four = 4,
Eight = 8,
}
#[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<u32> for OCR<Ext> {
fn from(word: u32) -> Self {
Self(word, 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) inner: u128,
pub(crate) bytes: [u8; 16],
ext: PhantomData<Ext>,
}
impl<Ext> From<u128> for CID<Ext> {
fn from(inner: u128) -> Self {
Self {
inner,
bytes: inner.to_be_bytes(),
ext: PhantomData,
}
}
}
impl<Ext> From<[u32; 4]> for CID<Ext> {
fn from(words: [u32; 4]) -> Self {
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> CID<Ext> {
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<[u32; 4]> for CSD<Ext> {
fn from(words: [u32; 4]) -> Self {
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<u32> for CardStatus<Ext> {
fn from(word: u32) -> Self {
Self(word, 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, PhantomData<Ext>);
impl<Ext> From<u32> for RCA<Ext> {
fn from(word: u32) -> Self {
Self(word, PhantomData)
}
}
impl<Ext> RCA<Ext> {
pub fn address(&self) -> u16 {
(self.0 >> 16) as u16
}
}