use crate::crc::Crc7;
use crate::result::{Error, Result};
use crate::{lib_bitfield, response};
mod card_status;
pub use card_status::*;
pub const COMMAND_INDEX: u8 = 0b11;
lib_bitfield! {
pub R6(MSB0 [u8; 6]): u16 {
start_bit: 47;
direction: 46;
raw_command_index: 45, 40;
pub rca: 39, 24;
raw_card_status: 23, 8;
raw_crc: 7, 1;
end_bit: 0;
}
}
response! {
R6 {
response_mode: Sd,
}
}
impl R6 {
pub const LEN: usize = 6;
pub const DEFAULT: [u8; Self::LEN] = [COMMAND_INDEX, 0x00, 0x00, 0x00, 0x00, 0x45];
pub const fn new() -> Self {
Self(Self::DEFAULT)
}
pub const fn command_index(&self) -> u8 {
self.raw_command_index() as u8
}
pub const fn card_status(&self) -> Result<CardStatus> {
CardStatus::try_from_bits(self.raw_card_status())
}
pub fn set_card_status(&mut self, val: CardStatus) {
self.set_raw_card_status(val.bits());
}
pub const fn crc(&self) -> Crc7 {
Crc7::from_bits(self.raw_crc() as u8)
}
pub fn calculate_crc(&mut self) -> Crc7 {
let crc = Crc7::calculate(self.0[..Self::LEN - 1].as_ref());
self.set_raw_crc(crc.bits() as u16);
crc
}
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 crc = Crc7::calculate(&[val[0], val[1], val[2], val[3], val[4]]);
match R6([val[0], val[1], val[2], val[3], val[4], val[5]]) {
r6 if r6.start_bit() => Err(Error::invalid_field_variant("r6::start_bit", 1)),
r6 if r6.direction() => Err(Error::invalid_field_variant("r6::direction", 1)),
r6 if r6.command_index() != COMMAND_INDEX => Err(Error::invalid_field_variant(
"r6::command_index",
r6.command_index() as usize,
)),
r6 if r6.card_status().is_err() => Err(Error::invalid_field_variant(
"r6::card_status",
r6.raw_card_status() as usize,
)),
r6 if r6.raw_crc() as u8 != crc.bits() => {
Err(Error::invalid_crc7(r6.raw_crc() as u8, crc.bits()))
}
r6 if !r6.end_bit() => Err(Error::invalid_field_variant("r6::end_bit", 0)),
r6 => Ok(r6),
}
}
}
}
}
impl Default for R6 {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_field;
use crate::util::raw_with_crc;
#[test]
fn test_fields() {
let mut r6 = R6::new();
assert_eq!(r6.card_status(), Ok(CardStatus::new()));
let raw_cs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
raw_cs
.into_iter()
.zip([
CurrentState::Idle,
CurrentState::Ready,
CurrentState::Identification,
CurrentState::Standby,
CurrentState::Transfer,
CurrentState::Data,
CurrentState::Receive,
CurrentState::Program,
CurrentState::Disabled,
])
.for_each(|(cstate_raw, cstate)| {
assert_eq!(CurrentState::from_raw(cstate_raw), Ok(cstate));
let cs = CardStatus::try_from_bits((cstate_raw as u16) << 9).unwrap();
r6.set_card_status(cs);
assert_eq!(r6.card_status(), Ok(cs));
let (raw, _crc) = raw_with_crc([COMMAND_INDEX, 0, 0, cstate_raw << 1, 0, 0]);
let exp_r6 = R6(raw);
assert_eq!(R6::try_from_bytes(raw.as_ref()), Ok(exp_r6));
assert_eq!(exp_r6.card_status(), Ok(cs));
});
(0..=0xf)
.filter(|r| !raw_cs.iter().any(|cs| cs == r))
.for_each(|invalid_cs| {
let err_cs = u16::from_be_bytes([invalid_cs << 1, 0]);
assert_eq!(
R6::try_from_bytes(&[COMMAND_INDEX, 0, 0, invalid_cs << 1, 0, 0]),
Err(Error::invalid_field_variant(
"r6::card_status",
err_cs as usize
))
);
});
(1..=u16::BITS)
.map(|r| ((1u32 << r) - 1) as u16)
.for_each(|rca| {
let [rca0, rca1] = rca.to_be_bytes();
let (raw, _crc) = raw_with_crc([0x03, rca0, rca1, 0, 0, 0]);
let mut exp_r6 = R6(raw);
assert_eq!(R6::try_from_bytes(raw.as_ref()), Ok(exp_r6));
assert_eq!(exp_r6.rca(), rca);
exp_r6.set_rca(0);
assert_eq!(exp_r6.rca(), 0);
exp_r6.set_rca(rca);
assert_eq!(exp_r6.rca(), rca);
});
}
}