1use core::fmt::Write;
2
3use crate::{
4 MFRC522, MfrcDriver,
5 consts::{PCDErrorCode, PICCCommand, PICCType, Uid},
6};
7use heapless::String;
8
9#[allow(async_fn_in_trait)]
10pub trait MFRC522Debug {
11 async fn debug_dump_card(&mut self, uid: &Uid) -> Result<(), PCDErrorCode>;
12 async fn debug_dump_card_memory(&mut self, uid: &Uid) -> Result<(), PCDErrorCode>;
13 async fn debug_dump_card_details(&mut self, uid: &Uid) -> Result<(), PCDErrorCode>;
14}
15
16impl<D> MFRC522<D>
17where
18 D: MfrcDriver,
19{
20 pub async fn test(&mut self) {}
21}
22
23#[allow(unused)]
24impl<D> MFRC522<D>
25where
26 D: MfrcDriver,
27{
28 pub async fn debug_dump_card(&mut self, uid: &Uid) -> Result<(), PCDErrorCode> {
29 self.debug_dump_card_details(uid).await?;
30 log::debug!("");
31 self.debug_dump_card_memory(uid).await?;
32
33 Ok(())
34 }
35
36 pub async fn debug_dump_card_memory(&mut self, uid: &Uid) -> Result<(), PCDErrorCode> {
37 let picc_type = PICCType::from_sak(uid.sak);
38
39 match picc_type {
40 PICCType::PiccTypeMifare1K
41 | PICCType::PiccTypeMifare4K
42 | PICCType::PiccTypeMifareMini => {
43 let mifare_key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
44 let res = dump_mifare_classic(self, uid, &mifare_key, picc_type).await;
45 if let Err(e) = res {
46 log::error!("Dump mifare classic failed: {e:?}");
47 }
48 }
49 PICCType::PiccTypeMifareUL => {
50 let res = dump_mifare_ultralight(self).await;
51 if let Err(e) = res {
52 log::error!("Dump mifare ultralight failed: {e:?}");
53 }
54 }
55 PICCType::PiccTypeUnknown | PICCType::PiccTypeNotComplete => {
56 return Ok(());
57 }
58 _ => {
59 log::warn!("Dumping memory not implemented for: {:?}", picc_type);
60 }
61 }
62
63 self.picc_halta().await?;
64 Ok(())
65 }
66
67 pub async fn debug_dump_card_details(&mut self, uid: &Uid) -> Result<(), PCDErrorCode> {
68 let mut dbg_line_buff: String<32> = String::new();
69 for i in 0..uid.size {
70 _ = dbg_line_buff.write_fmt(format_args!(" {:02X}", uid.uid_bytes[i as usize]));
71 }
72
73 log::debug!("Card UID:{dbg_line_buff}");
74 log::debug!("Card SAK: 0x{:02X}", uid.sak);
75 log::debug!("PICC Type: {:?}", PICCType::from_sak(uid.sak));
76
77 Ok(())
78 }
79}
80
81async fn dump_mifare_classic<D: MfrcDriver>(
82 mfrc522: &mut MFRC522<D>,
83 uid: &Uid,
84 key: &[u8],
85 picc_type: PICCType,
86) -> Result<(), PCDErrorCode> {
87 let sectors_count = match picc_type {
88 PICCType::PiccTypeMifareMini => 5,
89 PICCType::PiccTypeMifare1K => 16,
90 PICCType::PiccTypeMifare4K => 40,
91 _ => unreachable!(),
92 };
93
94 log::debug!("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits");
95 for i in (0..sectors_count).rev() {
96 let res = dump_mifare_classic_sector(mfrc522, uid, key, i).await;
97 if let Err(e) = res {
98 log::error!("Sector dump error ({i}): {e:?}");
99 }
100 }
101
102 mfrc522.picc_halta().await?;
103 mfrc522.pcd_stop_crypto1().await?;
104 Ok(())
105}
106
107async fn dump_mifare_classic_sector<D: MfrcDriver>(
108 mfrc522: &mut MFRC522<D>,
109 uid: &Uid,
110 key: &[u8],
111 sector: u8,
112) -> Result<(), PCDErrorCode> {
113 let mut groups = [0; 4];
114 let mut inverted_error = false;
115
116 let first_block;
117 let no_of_blocks;
118 if sector < 32 {
119 no_of_blocks = 4;
120 first_block = sector * no_of_blocks;
121 } else if sector < 40 {
122 no_of_blocks = 16;
123 first_block = 128 + (sector - 32) * no_of_blocks;
124 } else {
125 return Err(PCDErrorCode::Invalid);
126 }
127
128 let mut is_sector_trailer = true;
129 let mut buff = [0; 18];
130
131 let mut dbg_line_buff: String<128> = String::new();
132 for block_offset in (0..no_of_blocks).rev() {
133 dbg_line_buff.clear();
134
135 let block_addr = first_block + block_offset;
136 if is_sector_trailer {
137 mfrc522
138 .pcd_authenticate(PICCCommand::PICC_CMD_MF_AUTH_KEY_A, first_block, key, uid)
139 .await?;
140
141 _ = dbg_line_buff.write_fmt(format_args!(" {sector: >2} "));
142 } else {
143 _ = dbg_line_buff.push_str(" ");
144 }
145
146 _ = dbg_line_buff.write_fmt(format_args!("{block_addr: >3} "));
147
148 let mut byte_count = 18;
149 mfrc522
150 .mifare_read(block_addr, &mut buff, &mut byte_count)
151 .await?;
152
153 for (i, buffi) in buff.iter().enumerate().take(16) {
154 _ = dbg_line_buff.write_fmt(format_args!("{:02X} ", buffi));
155 if i % 4 == 3 {
156 _ = dbg_line_buff.push(' ');
157 }
158 }
159
160 if is_sector_trailer {
161 let c1 = buff[7] >> 4;
162 let c2 = buff[8] & 0xF;
163 let c3 = buff[8] >> 4;
164 let c1_ = buff[6] & 0xF;
165 let c2_ = buff[6] >> 4;
166 let c3_ = buff[7] & 0xF;
167
168 inverted_error = (c1 != (!c1_ & 0xF)) || (c2 != (!c2_ & 0xF)) || (c3 != (!c3_ & 0xF));
169 groups[0] = ((c1 & 1) << 2) | ((c2 & 1) << 1) | (c3 & 1);
170 groups[1] = ((c1 & 2) << 1) | (c2 & 2) | ((c3 & 2) >> 1);
171 groups[2] = (c1 & 4) | ((c2 & 4) >> 1) | ((c3 & 4) >> 2);
172 groups[3] = ((c1 & 8) >> 1) | ((c2 & 8) >> 2) | ((c3 & 8) >> 3);
173
174 is_sector_trailer = false;
175 }
176
177 let first_in_group;
178 let group;
179
180 if no_of_blocks == 4 {
181 group = block_offset;
182 first_in_group = true;
183 } else {
184 group = block_offset / 5;
185 first_in_group = (group == 3) || (group != (block_offset + 1) / 5);
186 }
187
188 if first_in_group {
189 let (g1, g2, g3) = (
190 (groups[group as usize] >> 2) & 1,
191 (groups[group as usize] >> 1) & 1,
192 groups[group as usize] & 1,
193 );
194
195 _ = core::fmt::write(&mut dbg_line_buff, format_args!("[ {g1} {g2} {g3} ]"));
196 if inverted_error {
197 _ = dbg_line_buff.push_str(" Inverted access bits did not match! ");
198 }
199 }
200
201 if group != 3 && (groups[group as usize] == 1 || groups[group as usize] == 6) {
202 let val = ((buff[3] as i32) << 24)
203 | ((buff[2] as i32) << 16)
204 | ((buff[1] as i32) << 8)
205 | (buff[0] as i32);
206
207 _ = dbg_line_buff.write_fmt(format_args!(" Value=0x{val:X} Adr=0x{:X}", buff[12]));
208 }
209
210 log::debug!("{}", dbg_line_buff);
211 }
212
213 Ok(())
214}
215
216async fn dump_mifare_ultralight<D: MfrcDriver>(
217 mfrc522: &mut MFRC522<D>,
218) -> Result<(), PCDErrorCode> {
219 let mut buff = [0; 18];
220 let mut i;
221
222 log::debug!("Page 0 1 2 3");
223 let mut dbg_line_buff: String<128> = String::new();
224 for page in (0..16).step_by(4) {
225 dbg_line_buff.clear();
226
227 let mut bytes_count = 18;
228 mfrc522
229 .mifare_read(page, &mut buff, &mut bytes_count)
230 .await?;
231
232 for offset in 0..4 {
233 i = page + offset;
234 _ = dbg_line_buff.write_fmt(format_args!(" {i: >2} "));
235
236 for index in 0..4 {
237 i = 4 * offset + index;
238 _ = dbg_line_buff.write_fmt(format_args!(" {i:02X} "));
239 }
240 }
241
242 log::debug!("{}", dbg_line_buff);
243 }
244
245 Ok(())
246}