use crate::lib_bitfield;
use crate::result::{Error, Result};
mod current_state;
pub use current_state::*;
const CS_MASK: u32 = 0xfff9_ff68;
const CUR_STATE_MASK: u32 = 0x1d00;
const CUR_STATE_SHIFT: usize = 9;
lib_bitfield! {
pub CardStatus(u32): u8 {
pub out_of_range: 31;
pub address_error: 30;
pub block_len_error: 29;
pub erase_seq_error: 28;
pub erase_param: 27;
pub wp_violation: 26;
pub card_is_locked: 25;
pub lock_unlock_failed: 24;
pub crc_error: 23;
pub illegal_command: 22;
pub card_ecc_error: 21;
pub cc_error: 20;
pub error: 19;
pub csd_overwrite: 16;
pub wp_erase_skip: 15;
pub card_ecc_disabled: 14;
pub erase_reset: 13;
raw_current_state: 12, 9;
pub ready_for_data: 8;
pub fx_event: 6;
pub app_cmd: 5;
pub ake_seq_error: 3;
}
}
impl CardStatus {
pub const LEN: usize = 4;
pub const DEFAULT: u32 = 0;
pub const fn new() -> Self {
Self(Self::DEFAULT)
}
pub const fn current_state(&self) -> Result<CurrentState> {
CurrentState::from_raw(self.raw_current_state())
}
pub fn set_current_state(&mut self, val: CurrentState) {
self.set_raw_current_state(val.into_raw() as u32);
}
pub const fn try_from_bits(val: u32) -> Result<Self> {
match ((val & !CS_MASK), Self(val)) {
(0, cs) if cs.current_state().is_ok() => Ok(cs),
(_, cs) => Err(Error::invalid_field_variant("card_status", val as usize)),
}
}
pub const fn bytes(&self) -> [u8; Self::LEN] {
self.0.to_be_bytes()
}
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)),
_ => Self::try_from_bits(u32::from_be_bytes([val[0], val[1], val[2], val[3]])),
}
}
}
impl Default for CardStatus {
fn default() -> Self {
Self::new()
}
}
impl TryFrom<u32> for CardStatus {
type Error = Error;
fn try_from(val: u32) -> Result<Self> {
Self::try_from_bits(val)
}
}
impl From<CardStatus> for u32 {
fn from(val: CardStatus) -> Self {
val.bits()
}
}
impl TryFrom<&[u8]> for CardStatus {
type Error = Error;
fn try_from(val: &[u8]) -> Result<Self> {
Self::try_from_bytes(val)
}
}
impl<const N: usize> TryFrom<[u8; N]> for CardStatus {
type Error = Error;
fn try_from(val: [u8; N]) -> Result<Self> {
Self::try_from_bytes(val.as_ref())
}
}
impl<const N: usize> TryFrom<&[u8; N]> for CardStatus {
type Error = Error;
fn try_from(val: &[u8; N]) -> Result<Self> {
Self::try_from_bytes(val.as_ref())
}
}
impl From<CardStatus> for [u8; CardStatus::LEN] {
fn from(val: CardStatus) -> Self {
val.bytes()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_field;
#[test]
fn test_fields() {
const RESERVED: [u32; 7] = [0, 1, 2, 4, 7, 17, 18];
let mut cs = CardStatus::new();
test_field!(cs, ake_seq_error: 3);
test_field!(cs, app_cmd: 5);
test_field!(cs, fx_event: 6);
test_field!(cs, ready_for_data: 8);
test_field!(cs, erase_reset: 13);
test_field!(cs, card_ecc_disabled: 14);
test_field!(cs, wp_erase_skip: 15);
test_field!(cs, csd_overwrite: 16);
test_field!(cs, error: 19);
test_field!(cs, cc_error: 20);
test_field!(cs, card_ecc_error: 21);
test_field!(cs, illegal_command: 22);
test_field!(cs, crc_error: 23);
test_field!(cs, lock_unlock_failed: 24);
test_field!(cs, card_is_locked: 25);
test_field!(cs, wp_violation: 26);
test_field!(cs, erase_param: 27);
test_field!(cs, erase_seq_error: 28);
test_field!(cs, block_len_error: 29);
test_field!(cs, address_error: 30);
test_field!(cs, out_of_range: 31);
assert_eq!(cs.current_state(), Ok(CurrentState::new()));
(0..32)
.filter(|i| !RESERVED.iter().any(|r| r == i))
.for_each(|i| {
let raw_cs = 1u32 << i;
let exp_cs = CardStatus(raw_cs);
assert_eq!(CardStatus::try_from_bits(raw_cs), Ok(exp_cs));
assert_eq!(exp_cs.bits(), raw_cs);
assert_eq!(exp_cs.bytes(), raw_cs.to_be_bytes());
});
(0..32u32)
.chain([CS_MASK])
.filter(|i| RESERVED.iter().any(|r| r == i))
.for_each(|i| {
let res_bits = 1u32 << i;
assert_eq!(
CardStatus::try_from_bits(res_bits),
Err(Error::invalid_field_variant(
"card_status",
res_bits as usize
))
);
});
}
}