use crate::Crc7;
use crate::result::{Error, Result};
mod bl_len;
mod ccc;
mod copied;
mod dsr_imp;
mod erase_blk_en;
mod file_format;
mod file_format_grp;
pub mod mmc;
mod nsac;
mod perm_write_protect;
mod r2w_factor;
mod read_bl_partial;
mod read_blk_misalign;
mod sector_size;
mod structure;
mod tmp_write_protect;
mod tran_speed;
pub mod v1;
pub mod v2;
pub mod v3;
mod vdd_curr;
mod wp_grp_enable;
mod wp_grp_size;
mod wp_upc;
mod write_bl_len;
mod write_bl_partial;
mod write_blk_misalign;
pub use bl_len::*;
pub use ccc::*;
pub use copied::Copied;
pub use dsr_imp::DsrImplemented;
pub use erase_blk_en::EraseBlockEnable;
pub use file_format::*;
pub use file_format_grp::FileFormatGroup;
pub use mmc::{ContentProtectionApp, CsdMmc, CsdStructure as MmcCsdStructure, Ecc};
pub use nsac::*;
pub use perm_write_protect::PermanentWriteProtect;
pub use r2w_factor::WriteSpeedFactor;
pub use read_bl_partial::ReadBlockPartial;
pub use read_blk_misalign::ReadBlockMisalign;
pub use sector_size::SectorSize;
pub use structure::CsdStructure as SdCsdStructure;
pub use tmp_write_protect::TemporaryWriteProtect;
pub use tran_speed::*;
pub use v1::CsdV1;
pub use v2::CsdV2;
pub use v3::CsdV3;
pub use vdd_curr::*;
pub use wp_grp_enable::WriteProtectGroupEnable;
pub use wp_grp_size::WriteProtectGroupSize;
pub use wp_upc::WriteProtectUntilPowerCycle;
pub use write_bl_len::*;
pub use write_bl_partial::WriteBlockPartial;
pub use write_blk_misalign::WriteBlockMisalign;
pub const CSD_LEN: usize = 16;
pub enum CsdStructure {
Sd(SdCsdStructure),
Mmc(MmcCsdStructure),
}
impl CsdStructure {
pub const fn into_sd(self) -> Result<SdCsdStructure> {
match self {
Self::Sd(csd) => Ok(csd),
_ => Err(Error::Invalid),
}
}
pub const fn into_mmc(self) -> Result<MmcCsdStructure> {
match self {
Self::Mmc(csd) => Ok(csd),
_ => Err(Error::Invalid),
}
}
}
pub enum Taac {
V1(v1::TimeAsyncAccessCycles),
V2(v2::TimeAsyncAccessCycles),
V3(v3::TimeAsyncAccessCycles),
Mmc(mmc::TimeAsyncAccessCycles),
}
impl Taac {
pub const fn into_v1(self) -> Result<v1::TimeAsyncAccessCycles> {
match self {
Self::V1(taac) => Ok(taac),
_ => Err(Error::Invalid),
}
}
pub const fn into_v2(self) -> Result<v2::TimeAsyncAccessCycles> {
match self {
Self::V2(taac) => Ok(taac),
_ => Err(Error::Invalid),
}
}
pub const fn into_v3(self) -> Result<v3::TimeAsyncAccessCycles> {
match self {
Self::V3(taac) => Ok(taac),
_ => Err(Error::Invalid),
}
}
pub const fn into_mmc(self) -> Result<mmc::TimeAsyncAccessCycles> {
match self {
Self::Mmc(taac) => Ok(taac),
_ => Err(Error::Invalid),
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Csd {
V1(CsdV1),
V2(CsdV2),
V3(CsdV3),
Mmc(CsdMmc),
}
impl Csd {
pub const LEN: usize = CSD_LEN;
pub const fn new() -> Self {
Self::V1(CsdV1::new())
}
pub const fn len(&self) -> usize {
Self::LEN
}
pub const fn is_empty(&self) -> bool {
false
}
pub const fn parse_v1(val: &[u8]) -> Result<Self> {
match CsdV1::try_from_bytes(val) {
Ok(v) => Ok(Self::V1(v)),
Err(err) => Err(err),
}
}
pub const fn parse_v2(val: &[u8]) -> Result<Self> {
match CsdV2::try_from_bytes(val) {
Ok(v) => Ok(Self::V2(v)),
Err(err) => Err(err),
}
}
pub const fn parse_v3(val: &[u8]) -> Result<Self> {
match CsdV3::try_from_bytes(val) {
Ok(v) => Ok(Self::V3(v)),
Err(err) => Err(err),
}
}
pub const fn parse_mmc(val: &[u8]) -> Result<Self> {
match CsdMmc::try_from_bytes(val) {
Ok(v) => Ok(Self::Mmc(v)),
Err(err) => Err(err),
}
}
pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
match val.len() {
len if len < Self::LEN => Err(Error::invalid_length(len, Self::LEN)),
_ => {
let is_mmc = matches!(
mmc::SpecificationVersion::try_from_inner((val[0] >> 2) & 0xf),
Ok(mmc::SpecificationVersion::Version4x5x),
);
match SdCsdStructure::from_raw(val[0]) {
Ok(SdCsdStructure::V1) if !is_mmc => Self::parse_v1(val),
Ok(SdCsdStructure::V2) if !is_mmc => Self::parse_v2(val),
Ok(SdCsdStructure::V3) if !is_mmc => Self::parse_v3(val),
_ if is_mmc => Self::parse_mmc(val),
_ => Err(Error::Invalid),
}
}
}
}
pub const fn bytes(&self) -> [u8; Self::LEN] {
match self {
Self::V1(csd) => csd.into_inner(),
Self::V2(csd) => csd.into_inner(),
Self::V3(csd) => csd.into_inner(),
Self::Mmc(csd) => csd.into_inner(),
}
}
pub const fn csd_structure(&self) -> Result<CsdStructure> {
match self {
Self::V1(csd) => match csd.csd_structure() {
Ok(c) => Ok(CsdStructure::Sd(c)),
Err(err) => Err(err),
},
Self::V2(csd) => match csd.csd_structure() {
Ok(c) => Ok(CsdStructure::Sd(c)),
Err(err) => Err(err),
},
Self::V3(csd) => match csd.csd_structure() {
Ok(c) => Ok(CsdStructure::Sd(c)),
Err(err) => Err(err),
},
Self::Mmc(csd) => Ok(CsdStructure::Mmc(csd.csd_structure())),
}
}
pub const fn taac(&self) -> Result<Taac> {
match self {
Self::V1(csd) => match csd.taac() {
Ok(taac) => Ok(Taac::V1(taac)),
Err(err) => Err(err),
},
Self::V2(csd) => match csd.taac() {
Ok(taac) => Ok(Taac::V2(taac)),
Err(err) => Err(err),
},
Self::V3(csd) => match csd.taac() {
Ok(taac) => Ok(Taac::V3(taac)),
Err(err) => Err(err),
},
Self::Mmc(csd) => match csd.taac() {
Ok(taac) => Ok(Taac::Mmc(taac)),
Err(err) => Err(err),
},
}
}
pub const fn nsac(&self) -> Result<NsAccessCycles> {
match self {
Self::V1(csd) => Ok(csd.nsac()),
Self::V2(csd) => csd.nsac(),
Self::V3(csd) => csd.nsac(),
Self::Mmc(csd) => Ok(csd.nsac()),
}
}
pub const fn tran_speed(&self) -> Result<TransferSpeed> {
match self {
Self::V1(csd) => csd.tran_speed(),
Self::V2(csd) => csd.tran_speed(),
Self::V3(csd) => csd.tran_speed(),
Self::Mmc(csd) => csd.tran_speed(),
}
}
pub const fn ccc(&self) -> CardCommandClass {
match self {
Self::V1(csd) => csd.ccc(),
Self::V2(csd) => csd.ccc(),
Self::V3(csd) => csd.ccc(),
Self::Mmc(csd) => csd.ccc(),
}
}
pub const fn c_size(&self) -> usize {
match self {
Self::V1(csd) => csd.c_size().size(),
Self::V2(csd) => csd.c_size().size(),
Self::V3(csd) => csd.c_size().size(),
Self::Mmc(csd) => csd.c_size().size(),
}
}
pub const fn c_size_mult(&self) -> usize {
match self {
Self::V1(csd) => csd.c_size_mult().mult(),
Self::V2(csd) => 1,
Self::V3(csd) => 1,
Self::Mmc(csd) => csd.c_size_mult().mult(),
}
}
pub const fn capacity(&self) -> Result<u64> {
match self {
Self::V1(csd) => match csd.capacity() {
Ok(c) => Ok(c as u64),
Err(err) => Err(err),
},
Self::V2(csd) => Ok(csd.capacity()),
Self::V3(csd) => Ok(csd.capacity()),
Self::Mmc(csd) => match csd.capacity() {
Ok(c) => Ok(c as u64),
Err(err) => Err(err),
},
}
}
pub const fn erase_size(&self) -> u32 {
match self {
Self::V1(_) => 1,
Self::V2(_) => 1,
Self::V3(_) => 1,
Self::Mmc(csd) => csd.erase_size() as u32,
}
}
pub const fn read_bl_len(&self) -> Result<BlockLength> {
match self {
Self::V1(csd) => csd.read_bl_len(),
Self::V2(csd) => csd.read_bl_len(),
Self::V3(csd) => csd.read_bl_len(),
Self::Mmc(csd) => csd.read_bl_len(),
}
}
pub const fn read_bl_partial(&self) -> ReadBlockPartial {
match self {
Self::V1(csd) => csd.read_bl_partial(),
Self::V2(csd) => csd.read_bl_partial(),
Self::V3(csd) => csd.read_bl_partial(),
Self::Mmc(csd) => csd.read_bl_partial(),
}
}
pub const fn read_blk_misalign(&self) -> ReadBlockMisalign {
match self {
Self::V1(csd) => csd.read_blk_misalign(),
Self::V2(csd) => csd.read_blk_misalign(),
Self::V3(csd) => csd.read_blk_misalign(),
Self::Mmc(csd) => csd.read_blk_misalign(),
}
}
pub const fn write_bl_len(&self) -> Result<BlockLength> {
match self {
Self::V1(csd) => csd.write_bl_len(),
Self::V2(csd) => csd.write_bl_len(),
Self::V3(csd) => csd.write_bl_len(),
Self::Mmc(csd) => csd.write_bl_len(),
}
}
pub const fn write_bl_partial(&self) -> WriteBlockPartial {
match self {
Self::V1(csd) => csd.write_bl_partial(),
Self::V2(csd) => csd.write_bl_partial(),
Self::V3(csd) => csd.write_bl_partial(),
Self::Mmc(csd) => csd.write_bl_partial(),
}
}
pub const fn write_blk_misalign(&self) -> WriteBlockMisalign {
match self {
Self::V1(csd) => csd.write_blk_misalign(),
Self::V2(csd) => csd.write_blk_misalign(),
Self::V3(csd) => csd.write_blk_misalign(),
Self::Mmc(csd) => csd.write_blk_misalign(),
}
}
pub const fn dsr_imp(&self) -> DsrImplemented {
match self {
Self::V1(csd) => csd.dsr_imp(),
Self::V2(csd) => csd.dsr_imp(),
Self::V3(csd) => csd.dsr_imp(),
Self::Mmc(csd) => csd.dsr_imp(),
}
}
pub const fn vdd_r_curr_min(&self) -> Result<VddCurrentMin> {
match self {
Self::V1(csd) => csd.vdd_r_curr_min(),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => csd.vdd_r_curr_min(),
}
}
pub const fn vdd_r_curr_max(&self) -> Result<VddCurrentMax> {
match self {
Self::V1(csd) => csd.vdd_r_curr_max(),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => csd.vdd_r_curr_max(),
}
}
pub const fn vdd_w_curr_min(&self) -> Result<VddCurrentMin> {
match self {
Self::V1(csd) => csd.vdd_w_curr_min(),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => csd.vdd_w_curr_min(),
}
}
pub const fn vdd_w_curr_max(&self) -> Result<VddCurrentMax> {
match self {
Self::V1(csd) => csd.vdd_w_curr_max(),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => csd.vdd_w_curr_max(),
}
}
pub const fn erase_blk_en(&self) -> Result<EraseBlockEnable> {
match self {
Self::V1(csd) => Ok(csd.erase_blk_en()),
Self::V2(csd) => Ok(csd.erase_blk_en()),
Self::V3(csd) => Ok(csd.erase_blk_en()),
Self::Mmc(csd) => Err(Error::unimplemented()),
}
}
pub const fn sector_size(&self) -> Result<SectorSize> {
match self {
Self::V1(csd) => Ok(csd.sector_size()),
Self::V2(csd) => csd.sector_size(),
Self::V3(csd) => csd.sector_size(),
Self::Mmc(csd) => Err(Error::unimplemented()),
}
}
pub const fn wp_grp_size(&self) -> usize {
match self {
Self::V1(csd) => csd.wp_grp_size().size(),
Self::V2(csd) => csd.wp_grp_size().size(),
Self::V3(csd) => csd.wp_grp_size().size(),
Self::Mmc(csd) => csd.wp_grp_size().size(),
}
}
pub const fn wp_grp_enable(&self) -> WriteProtectGroupEnable {
match self {
Self::V1(csd) => csd.wp_grp_enable(),
Self::V2(csd) => csd.wp_grp_enable(),
Self::V3(csd) => csd.wp_grp_enable(),
Self::Mmc(csd) => csd.wp_grp_enable(),
}
}
pub const fn default_ecc(&self) -> Result<Ecc> {
match self {
Self::V1(csd) => Err(Error::unimplemented()),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => csd.default_ecc(),
}
}
pub const fn r2w_factor(&self) -> Result<WriteSpeedFactor> {
match self {
Self::V1(csd) => csd.r2w_factor(),
Self::V2(csd) => csd.r2w_factor(),
Self::V3(csd) => csd.r2w_factor(),
Self::Mmc(csd) => csd.r2w_factor(),
}
}
pub const fn content_prot_app(&self) -> Result<ContentProtectionApp> {
match self {
Self::V1(csd) => Err(Error::unimplemented()),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => Ok(csd.content_prot_app()),
}
}
pub const fn file_format_grp(&self) -> FileFormatGroup {
match self {
Self::V1(csd) => csd.file_format_grp(),
Self::V2(csd) => csd.file_format_grp(),
Self::V3(csd) => csd.file_format_grp(),
Self::Mmc(csd) => csd.file_format_grp(),
}
}
pub const fn copy(&self) -> Copied {
match self {
Self::V1(csd) => csd.copy(),
Self::V2(csd) => csd.copy(),
Self::V3(csd) => csd.copy(),
Self::Mmc(csd) => csd.copy(),
}
}
pub const fn perm_write_protect(&self) -> PermanentWriteProtect {
match self {
Self::V1(csd) => csd.perm_write_protect(),
Self::V2(csd) => csd.perm_write_protect(),
Self::V3(csd) => csd.perm_write_protect(),
Self::Mmc(csd) => csd.perm_write_protect(),
}
}
pub const fn tmp_write_protect(&self) -> TemporaryWriteProtect {
match self {
Self::V1(csd) => csd.tmp_write_protect(),
Self::V2(csd) => csd.tmp_write_protect(),
Self::V3(csd) => csd.tmp_write_protect(),
Self::Mmc(csd) => csd.tmp_write_protect(),
}
}
pub const fn wp_upc(&self) -> Result<WriteProtectUntilPowerCycle> {
match self {
Self::V1(csd) => Ok(csd.wp_upc()),
Self::V2(csd) => Ok(csd.wp_upc()),
Self::V3(csd) => Ok(csd.wp_upc()),
Self::Mmc(csd) => Err(Error::unimplemented()),
}
}
pub const fn file_format(&self) -> Result<FileFormat> {
match self {
Self::V1(csd) => csd.file_format(),
Self::V2(csd) => csd.file_format(),
Self::V3(csd) => csd.file_format(),
Self::Mmc(csd) => csd.file_format(),
}
}
pub const fn ecc(&self) -> Result<Ecc> {
match self {
Self::V1(csd) => Err(Error::unimplemented()),
Self::V2(csd) => Err(Error::unimplemented()),
Self::V3(csd) => Err(Error::unimplemented()),
Self::Mmc(csd) => csd.ecc(),
}
}
pub const fn crc(&self) -> Crc7 {
match self {
Self::V1(csd) => csd.crc(),
Self::V2(csd) => csd.crc(),
Self::V3(csd) => csd.crc(),
Self::Mmc(csd) => csd.crc(),
}
}
}
impl Default for Csd {
fn default() -> Self {
Self::new()
}
}
impl TryFrom<&[u8]> for Csd {
type Error = Error;
fn try_from(val: &[u8]) -> Result<Csd> {
Csd::try_from_bytes(val)
}
}
impl From<Csd> for [u8; Csd::LEN] {
fn from(val: Csd) -> Self {
val.bytes()
}
}