1use crate::crc::Crc7;
2use crate::result::{Error, Result};
3use crate::{lib_bitfield, response};
4
5mod card_status;
6
7pub use card_status::*;
8
9pub const COMMAND_INDEX: u8 = 0b11;
11
12lib_bitfield! {
13 pub R6(MSB0 [u8; 6]): u16 {
15 start_bit: 47;
16 direction: 46;
17 raw_command_index: 45, 40;
18 pub rca: 39, 24;
20 raw_card_status: 23, 8;
21 raw_crc: 7, 1;
22 end_bit: 0;
23 }
24}
25
26response! {
27 R6 {
28 response_mode: Sd,
29 }
30}
31
32impl R6 {
33 pub const LEN: usize = 6;
35 pub const DEFAULT: [u8; Self::LEN] = [COMMAND_INDEX, 0x00, 0x00, 0x00, 0x00, 0x45];
36
37 pub const fn new() -> Self {
39 Self(Self::DEFAULT)
40 }
41
42 pub const fn command_index(&self) -> u8 {
46 self.raw_command_index() as u8
47 }
48
49 pub const fn card_status(&self) -> Result<CardStatus> {
51 CardStatus::try_from_bits(self.raw_card_status())
52 }
53
54 pub fn set_card_status(&mut self, val: CardStatus) {
56 self.set_raw_card_status(val.bits());
57 }
58
59 pub const fn crc(&self) -> Crc7 {
61 Crc7::from_bits(self.raw_crc() as u8)
62 }
63
64 pub fn calculate_crc(&mut self) -> Crc7 {
68 let crc = Crc7::calculate(self.0[..Self::LEN - 1].as_ref());
69 self.set_raw_crc(crc.bits() as u16);
70 crc
71 }
72
73 pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
75 match val.len() {
76 len if len < Self::LEN => Err(Error::invalid_length(len, Self::LEN)),
77 _ => {
78 let crc = Crc7::calculate(&[val[0], val[1], val[2], val[3], val[4]]);
79
80 match R6([val[0], val[1], val[2], val[3], val[4], val[5]]) {
81 r6 if r6.start_bit() => Err(Error::invalid_field_variant("r6::start_bit", 1)),
82 r6 if r6.direction() => Err(Error::invalid_field_variant("r6::direction", 1)),
83 r6 if r6.command_index() != COMMAND_INDEX => Err(Error::invalid_field_variant(
84 "r6::command_index",
85 r6.command_index() as usize,
86 )),
87 r6 if r6.card_status().is_err() => Err(Error::invalid_field_variant(
88 "r6::card_status",
89 r6.raw_card_status() as usize,
90 )),
91 r6 if r6.raw_crc() as u8 != crc.bits() => {
92 Err(Error::invalid_crc7(r6.raw_crc() as u8, crc.bits()))
93 }
94 r6 if !r6.end_bit() => Err(Error::invalid_field_variant("r6::end_bit", 0)),
95 r6 => Ok(r6),
96 }
97 }
98 }
99 }
100}
101
102impl Default for R6 {
103 fn default() -> Self {
104 Self::new()
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::test_field;
112 use crate::util::raw_with_crc;
113
114 #[test]
115 fn test_fields() {
116 let mut r6 = R6::new();
117
118 assert_eq!(r6.card_status(), Ok(CardStatus::new()));
119
120 let raw_cs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
121
122 raw_cs
123 .into_iter()
124 .zip([
125 CurrentState::Idle,
126 CurrentState::Ready,
127 CurrentState::Identification,
128 CurrentState::Standby,
129 CurrentState::Transfer,
130 CurrentState::Data,
131 CurrentState::Receive,
132 CurrentState::Program,
133 CurrentState::Disabled,
134 ])
135 .for_each(|(cstate_raw, cstate)| {
136 assert_eq!(CurrentState::from_raw(cstate_raw), Ok(cstate));
137 let cs = CardStatus::try_from_bits((cstate_raw as u16) << 9).unwrap();
138
139 r6.set_card_status(cs);
140 assert_eq!(r6.card_status(), Ok(cs));
141
142 let (raw, _crc) = raw_with_crc([COMMAND_INDEX, 0, 0, cstate_raw << 1, 0, 0]);
143
144 let exp_r6 = R6(raw);
145 assert_eq!(R6::try_from_bytes(raw.as_ref()), Ok(exp_r6));
146
147 assert_eq!(exp_r6.card_status(), Ok(cs));
148 });
149
150 (0..=0xf)
151 .filter(|r| !raw_cs.iter().any(|cs| cs == r))
152 .for_each(|invalid_cs| {
153 let err_cs = u16::from_be_bytes([invalid_cs << 1, 0]);
154 assert_eq!(
155 R6::try_from_bytes(&[COMMAND_INDEX, 0, 0, invalid_cs << 1, 0, 0]),
156 Err(Error::invalid_field_variant(
157 "r6::card_status",
158 err_cs as usize
159 ))
160 );
161 });
162
163 (1..=u16::BITS)
164 .map(|r| ((1u32 << r) - 1) as u16)
165 .for_each(|rca| {
166 let [rca0, rca1] = rca.to_be_bytes();
167 let (raw, _crc) = raw_with_crc([0x03, rca0, rca1, 0, 0, 0]);
168 let mut exp_r6 = R6(raw);
169
170 assert_eq!(R6::try_from_bytes(raw.as_ref()), Ok(exp_r6));
171 assert_eq!(exp_r6.rca(), rca);
172
173 exp_r6.set_rca(0);
174 assert_eq!(exp_r6.rca(), 0);
175
176 exp_r6.set_rca(rca);
177 assert_eq!(exp_r6.rca(), rca);
178 });
179 }
180}