]>
Commit | Line | Data |
---|---|---|
6658905f | 1 | //-----------------------------------------------------------------------------\r |
2 | // Routines to support ISO 14443. This includes both the reader software and\r | |
3 | // the `fake tag' modes. At the moment only the Type B modulation is\r | |
4 | // supported.\r | |
5 | // Jonathan Westhues, split Nov 2006\r | |
6 | //-----------------------------------------------------------------------------\r | |
7 | #include <proxmark3.h>\r | |
8 | #include "apps.h"\r | |
30f2a7d3 | 9 | #include "../common/iso14443_crc.c"\r |
6658905f | 10 | \r |
11 | \r | |
12 | //static void GetSamplesFor14443(BOOL weTx, int n);\r | |
13 | \r | |
14 | #define DMA_BUFFER_SIZE 256\r | |
15 | \r | |
16 | //=============================================================================\r | |
17 | // An ISO 14443 Type B tag. We listen for commands from the reader, using\r | |
18 | // a UART kind of thing that's implemented in software. When we get a\r | |
19 | // frame (i.e., a group of bytes between SOF and EOF), we check the CRC.\r | |
20 | // If it's good, then we can do something appropriate with it, and send\r | |
21 | // a response.\r | |
22 | //=============================================================================\r | |
23 | \r | |
24 | //-----------------------------------------------------------------------------\r | |
25 | // Code up a string of octets at layer 2 (including CRC, we don't generate\r | |
26 | // that here) so that they can be transmitted to the reader. Doesn't transmit\r | |
27 | // them yet, just leaves them ready to send in ToSend[].\r | |
28 | //-----------------------------------------------------------------------------\r | |
29 | static void CodeIso14443bAsTag(const BYTE *cmd, int len)\r | |
30 | {\r | |
31 | int i;\r | |
32 | \r | |
33 | ToSendReset();\r | |
34 | \r | |
35 | // Transmit a burst of ones, as the initial thing that lets the\r | |
36 | // reader get phase sync. This (TR1) must be > 80/fs, per spec,\r | |
37 | // but tag that I've tried (a Paypass) exceeds that by a fair bit,\r | |
38 | // so I will too.\r | |
39 | for(i = 0; i < 20; i++) {\r | |
40 | ToSendStuffBit(1);\r | |
41 | ToSendStuffBit(1);\r | |
42 | ToSendStuffBit(1);\r | |
43 | ToSendStuffBit(1);\r | |
44 | }\r | |
45 | \r | |
46 | // Send SOF.\r | |
47 | for(i = 0; i < 10; i++) {\r | |
48 | ToSendStuffBit(0);\r | |
49 | ToSendStuffBit(0);\r | |
50 | ToSendStuffBit(0);\r | |
51 | ToSendStuffBit(0);\r | |
52 | }\r | |
53 | for(i = 0; i < 2; i++) {\r | |
54 | ToSendStuffBit(1);\r | |
55 | ToSendStuffBit(1);\r | |
56 | ToSendStuffBit(1);\r | |
57 | ToSendStuffBit(1);\r | |
58 | }\r | |
59 | \r | |
60 | for(i = 0; i < len; i++) {\r | |
61 | int j;\r | |
62 | BYTE b = cmd[i];\r | |
63 | \r | |
64 | // Start bit\r | |
65 | ToSendStuffBit(0);\r | |
66 | ToSendStuffBit(0);\r | |
67 | ToSendStuffBit(0);\r | |
68 | ToSendStuffBit(0);\r | |
69 | \r | |
70 | // Data bits\r | |
71 | for(j = 0; j < 8; j++) {\r | |
72 | if(b & 1) {\r | |
73 | ToSendStuffBit(1);\r | |
74 | ToSendStuffBit(1);\r | |
75 | ToSendStuffBit(1);\r | |
76 | ToSendStuffBit(1);\r | |
77 | } else {\r | |
78 | ToSendStuffBit(0);\r | |
79 | ToSendStuffBit(0);\r | |
80 | ToSendStuffBit(0);\r | |
81 | ToSendStuffBit(0);\r | |
82 | }\r | |
83 | b >>= 1;\r | |
84 | }\r | |
85 | \r | |
86 | // Stop bit\r | |
87 | ToSendStuffBit(1);\r | |
88 | ToSendStuffBit(1);\r | |
89 | ToSendStuffBit(1);\r | |
90 | ToSendStuffBit(1);\r | |
91 | }\r | |
92 | \r | |
93 | // Send SOF.\r | |
94 | for(i = 0; i < 10; i++) {\r | |
95 | ToSendStuffBit(0);\r | |
96 | ToSendStuffBit(0);\r | |
97 | ToSendStuffBit(0);\r | |
98 | ToSendStuffBit(0);\r | |
99 | }\r | |
100 | for(i = 0; i < 10; i++) {\r | |
101 | ToSendStuffBit(1);\r | |
102 | ToSendStuffBit(1);\r | |
103 | ToSendStuffBit(1);\r | |
104 | ToSendStuffBit(1);\r | |
105 | }\r | |
106 | \r | |
107 | // Convert from last byte pos to length\r | |
108 | ToSendMax++;\r | |
109 | \r | |
110 | // Add a few more for slop\r | |
111 | ToSendMax += 2;\r | |
112 | }\r | |
113 | \r | |
114 | //-----------------------------------------------------------------------------\r | |
115 | // The software UART that receives commands from the reader, and its state\r | |
116 | // variables.\r | |
117 | //-----------------------------------------------------------------------------\r | |
118 | static struct {\r | |
119 | enum {\r | |
120 | STATE_UNSYNCD,\r | |
121 | STATE_GOT_FALLING_EDGE_OF_SOF,\r | |
122 | STATE_AWAITING_START_BIT,\r | |
123 | STATE_RECEIVING_DATA,\r | |
124 | STATE_ERROR_WAIT\r | |
125 | } state;\r | |
126 | WORD shiftReg;\r | |
127 | int bitCnt;\r | |
128 | int byteCnt;\r | |
129 | int byteCntMax;\r | |
130 | int posCnt;\r | |
131 | BYTE *output;\r | |
132 | } Uart;\r | |
133 | \r | |
0e25ae11 | 134 | /* Receive & handle a bit coming from the reader.\r |
135 | *\r | |
136 | * LED handling:\r | |
137 | * LED A -> ON once we have received the SOF and are expecting the rest.\r | |
138 | * LED A -> OFF once we have received EOF or are in error state or unsynced\r | |
139 | *\r | |
140 | * Returns: true if we received a EOF\r | |
141 | * false if we are still waiting for some more\r | |
142 | */\r | |
6658905f | 143 | static BOOL Handle14443UartBit(int bit)\r |
144 | {\r | |
145 | switch(Uart.state) {\r | |
146 | case STATE_UNSYNCD:\r | |
0e25ae11 | 147 | LED_A_OFF();\r |
6658905f | 148 | if(!bit) {\r |
149 | // we went low, so this could be the beginning\r | |
150 | // of an SOF\r | |
151 | Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;\r | |
152 | Uart.posCnt = 0;\r | |
153 | Uart.bitCnt = 0;\r | |
154 | }\r | |
155 | break;\r | |
156 | \r | |
157 | case STATE_GOT_FALLING_EDGE_OF_SOF:\r | |
158 | Uart.posCnt++;\r | |
159 | if(Uart.posCnt == 2) {\r | |
160 | if(bit) {\r | |
161 | if(Uart.bitCnt >= 10) {\r | |
162 | // we've seen enough consecutive\r | |
163 | // zeros that it's a valid SOF\r | |
164 | Uart.posCnt = 0;\r | |
165 | Uart.byteCnt = 0;\r | |
166 | Uart.state = STATE_AWAITING_START_BIT;\r | |
0e25ae11 | 167 | LED_A_ON(); // Indicate we got a valid SOF\r |
6658905f | 168 | } else {\r |
169 | // didn't stay down long enough\r | |
170 | // before going high, error\r | |
171 | Uart.state = STATE_ERROR_WAIT;\r | |
172 | }\r | |
173 | } else {\r | |
174 | // do nothing, keep waiting\r | |
175 | }\r | |
176 | Uart.bitCnt++;\r | |
177 | }\r | |
178 | if(Uart.posCnt >= 4) Uart.posCnt = 0;\r | |
179 | if(Uart.bitCnt > 14) {\r | |
180 | // Give up if we see too many zeros without\r | |
181 | // a one, too.\r | |
182 | Uart.state = STATE_ERROR_WAIT;\r | |
183 | }\r | |
184 | break;\r | |
185 | \r | |
186 | case STATE_AWAITING_START_BIT:\r | |
187 | Uart.posCnt++;\r | |
188 | if(bit) {\r | |
189 | if(Uart.posCnt > 25) {\r | |
190 | // stayed high for too long between\r | |
191 | // characters, error\r | |
192 | Uart.state = STATE_ERROR_WAIT;\r | |
193 | }\r | |
194 | } else {\r | |
195 | // falling edge, this starts the data byte\r | |
196 | Uart.posCnt = 0;\r | |
197 | Uart.bitCnt = 0;\r | |
198 | Uart.shiftReg = 0;\r | |
199 | Uart.state = STATE_RECEIVING_DATA;\r | |
0e25ae11 | 200 | LED_A_ON(); // Indicate we're receiving\r |
6658905f | 201 | }\r |
202 | break;\r | |
203 | \r | |
204 | case STATE_RECEIVING_DATA:\r | |
205 | Uart.posCnt++;\r | |
206 | if(Uart.posCnt == 2) {\r | |
207 | // time to sample a bit\r | |
208 | Uart.shiftReg >>= 1;\r | |
209 | if(bit) {\r | |
210 | Uart.shiftReg |= 0x200;\r | |
211 | }\r | |
212 | Uart.bitCnt++;\r | |
213 | }\r | |
214 | if(Uart.posCnt >= 4) {\r | |
215 | Uart.posCnt = 0;\r | |
216 | }\r | |
217 | if(Uart.bitCnt == 10) {\r | |
218 | if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))\r | |
219 | {\r | |
220 | // this is a data byte, with correct\r | |
221 | // start and stop bits\r | |
222 | Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;\r | |
223 | Uart.byteCnt++;\r | |
224 | \r | |
225 | if(Uart.byteCnt >= Uart.byteCntMax) {\r | |
226 | // Buffer overflowed, give up\r | |
227 | Uart.posCnt = 0;\r | |
228 | Uart.state = STATE_ERROR_WAIT;\r | |
229 | } else {\r | |
230 | // so get the next byte now\r | |
231 | Uart.posCnt = 0;\r | |
232 | Uart.state = STATE_AWAITING_START_BIT;\r | |
233 | }\r | |
234 | } else if(Uart.shiftReg == 0x000) {\r | |
235 | // this is an EOF byte\r | |
0e25ae11 | 236 | LED_A_OFF(); // Finished receiving\r |
6658905f | 237 | return TRUE;\r |
238 | } else {\r | |
239 | // this is an error\r | |
240 | Uart.posCnt = 0;\r | |
241 | Uart.state = STATE_ERROR_WAIT;\r | |
242 | }\r | |
243 | }\r | |
244 | break;\r | |
245 | \r | |
246 | case STATE_ERROR_WAIT:\r | |
247 | // We're all screwed up, so wait a little while\r | |
248 | // for whatever went wrong to finish, and then\r | |
249 | // start over.\r | |
250 | Uart.posCnt++;\r | |
251 | if(Uart.posCnt > 10) {\r | |
252 | Uart.state = STATE_UNSYNCD;\r | |
253 | }\r | |
254 | break;\r | |
255 | \r | |
256 | default:\r | |
257 | Uart.state = STATE_UNSYNCD;\r | |
258 | break;\r | |
259 | }\r | |
260 | \r | |
0e25ae11 | 261 | if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error\r |
262 | \r | |
6658905f | 263 | return FALSE;\r |
264 | }\r | |
265 | \r | |
266 | //-----------------------------------------------------------------------------\r | |
267 | // Receive a command (from the reader to us, where we are the simulated tag),\r | |
268 | // and store it in the given buffer, up to the given maximum length. Keeps\r | |
269 | // spinning, waiting for a well-framed command, until either we get one\r | |
270 | // (returns TRUE) or someone presses the pushbutton on the board (FALSE).\r | |
271 | //\r | |
272 | // Assume that we're called with the SSC (to the FPGA) and ADC path set\r | |
273 | // correctly.\r | |
274 | //-----------------------------------------------------------------------------\r | |
275 | static BOOL GetIso14443CommandFromReader(BYTE *received, int *len, int maxLen)\r | |
276 | {\r | |
277 | BYTE mask;\r | |
278 | int i, bit;\r | |
279 | \r | |
280 | // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen\r | |
281 | // only, since we are receiving, not transmitting).\r | |
0e25ae11 | 282 | // Signal field is off with the appropriate LED\r |
283 | LED_D_OFF();\r | |
6658905f | 284 | FpgaWriteConfWord(\r |
285 | FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);\r | |
286 | \r | |
287 | \r | |
288 | // Now run a `software UART' on the stream of incoming samples.\r | |
289 | Uart.output = received;\r | |
290 | Uart.byteCntMax = maxLen;\r | |
291 | Uart.state = STATE_UNSYNCD;\r | |
292 | \r | |
293 | for(;;) {\r | |
294 | WDT_HIT();\r | |
295 | \r | |
296 | if(BUTTON_PRESS()) return FALSE;\r | |
297 | \r | |
6949aca9 | 298 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r |
299 | AT91C_BASE_SSC->SSC_THR = 0x00;\r | |
6658905f | 300 | }\r |
6949aca9 | 301 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r |
302 | BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r | |
6658905f | 303 | \r |
304 | mask = 0x80;\r | |
305 | for(i = 0; i < 8; i++, mask >>= 1) {\r | |
306 | bit = (b & mask);\r | |
307 | if(Handle14443UartBit(bit)) {\r | |
308 | *len = Uart.byteCnt;\r | |
309 | return TRUE;\r | |
310 | }\r | |
311 | }\r | |
312 | }\r | |
313 | }\r | |
314 | }\r | |
315 | \r | |
316 | //-----------------------------------------------------------------------------\r | |
317 | // Main loop of simulated tag: receive commands from reader, decide what\r | |
318 | // response to send, and send it.\r | |
319 | //-----------------------------------------------------------------------------\r | |
320 | void SimulateIso14443Tag(void)\r | |
321 | {\r | |
322 | static const BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r | |
323 | static const BYTE response1[] = {\r | |
324 | 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,\r | |
325 | 0x00, 0x21, 0x85, 0x5e, 0xd7\r | |
326 | };\r | |
327 | \r | |
328 | BYTE *resp;\r | |
329 | int respLen;\r | |
330 | \r | |
331 | BYTE *resp1 = (((BYTE *)BigBuf) + 800);\r | |
332 | int resp1Len;\r | |
333 | \r | |
334 | BYTE *receivedCmd = (BYTE *)BigBuf;\r | |
335 | int len;\r | |
336 | \r | |
337 | int i;\r | |
338 | \r | |
339 | int cmdsRecvd = 0;\r | |
340 | \r | |
341 | memset(receivedCmd, 0x44, 400);\r | |
342 | \r | |
343 | CodeIso14443bAsTag(response1, sizeof(response1));\r | |
344 | memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;\r | |
345 | \r | |
346 | // We need to listen to the high-frequency, peak-detected path.\r | |
347 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
348 | FpgaSetupSsc();\r | |
349 | \r | |
350 | cmdsRecvd = 0;\r | |
351 | \r | |
352 | for(;;) {\r | |
353 | BYTE b1, b2;\r | |
354 | \r | |
355 | if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {\r | |
850427c8 | 356 | Dbprintf("button pressed, received %d commands", cmdsRecvd);\r |
357 | break;\r | |
6658905f | 358 | }\r |
359 | \r | |
360 | // Good, look at the command now.\r | |
361 | \r | |
362 | if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {\r | |
363 | resp = resp1; respLen = resp1Len;\r | |
364 | } else {\r | |
850427c8 | 365 | Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd);\r |
6658905f | 366 | // And print whether the CRC fails, just for good measure\r |
367 | ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);\r | |
368 | if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {\r | |
369 | // Not so good, try again.\r | |
370 | DbpString("+++CRC fail");\r | |
371 | } else {\r | |
372 | DbpString("CRC passes");\r | |
373 | }\r | |
374 | break;\r | |
375 | }\r | |
376 | \r | |
377 | memset(receivedCmd, 0x44, 32);\r | |
378 | \r | |
379 | cmdsRecvd++;\r | |
380 | \r | |
381 | if(cmdsRecvd > 0x30) {\r | |
382 | DbpString("many commands later...");\r | |
383 | break;\r | |
384 | }\r | |
385 | \r | |
386 | if(respLen <= 0) continue;\r | |
387 | \r | |
388 | // Modulate BPSK\r | |
0e25ae11 | 389 | // Signal field is off with the appropriate LED\r |
390 | LED_D_OFF();\r | |
6658905f | 391 | FpgaWriteConfWord(\r |
392 | FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);\r | |
6949aca9 | 393 | AT91C_BASE_SSC->SSC_THR = 0xff;\r |
6658905f | 394 | FpgaSetupSsc();\r |
395 | \r | |
396 | // Transmit the response.\r | |
397 | i = 0;\r | |
398 | for(;;) {\r | |
6949aca9 | 399 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r |
6658905f | 400 | BYTE b = resp[i];\r |
401 | \r | |
6949aca9 | 402 | AT91C_BASE_SSC->SSC_THR = b;\r |
6658905f | 403 | \r |
404 | i++;\r | |
405 | if(i > respLen) {\r | |
406 | break;\r | |
407 | }\r | |
408 | }\r | |
6949aca9 | 409 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r |
410 | volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r | |
6658905f | 411 | (void)b;\r |
412 | }\r | |
413 | }\r | |
414 | }\r | |
415 | }\r | |
416 | \r | |
417 | //=============================================================================\r | |
418 | // An ISO 14443 Type B reader. We take layer two commands, code them\r | |
419 | // appropriately, and then send them to the tag. We then listen for the\r | |
420 | // tag's response, which we leave in the buffer to be demodulated on the\r | |
421 | // PC side.\r | |
422 | //=============================================================================\r | |
423 | \r | |
424 | static struct {\r | |
425 | enum {\r | |
426 | DEMOD_UNSYNCD,\r | |
427 | DEMOD_PHASE_REF_TRAINING,\r | |
428 | DEMOD_AWAITING_FALLING_EDGE_OF_SOF,\r | |
429 | DEMOD_GOT_FALLING_EDGE_OF_SOF,\r | |
430 | DEMOD_AWAITING_START_BIT,\r | |
431 | DEMOD_RECEIVING_DATA,\r | |
432 | DEMOD_ERROR_WAIT\r | |
433 | } state;\r | |
434 | int bitCount;\r | |
435 | int posCount;\r | |
436 | int thisBit;\r | |
437 | int metric;\r | |
438 | int metricN;\r | |
439 | WORD shiftReg;\r | |
440 | BYTE *output;\r | |
441 | int len;\r | |
442 | int sumI;\r | |
443 | int sumQ;\r | |
444 | } Demod;\r | |
445 | \r | |
0e25ae11 | 446 | /*\r |
447 | * Handles reception of a bit from the tag\r | |
448 | *\r | |
449 | * LED handling:\r | |
450 | * LED C -> ON once we have received the SOF and are expecting the rest.\r | |
451 | * LED C -> OFF once we have received EOF or are unsynced\r | |
452 | *\r | |
453 | * Returns: true if we received a EOF\r | |
454 | * false if we are still waiting for some more\r | |
6949aca9 | 455 | *\r |
0e25ae11 | 456 | */\r |
6658905f | 457 | static BOOL Handle14443SamplesDemod(int ci, int cq)\r |
458 | {\r | |
459 | int v;\r | |
460 | \r | |
461 | // The soft decision on the bit uses an estimate of just the\r | |
462 | // quadrant of the reference angle, not the exact angle.\r | |
463 | #define MAKE_SOFT_DECISION() { \\r | |
464 | if(Demod.sumI > 0) { \\r | |
465 | v = ci; \\r | |
466 | } else { \\r | |
467 | v = -ci; \\r | |
468 | } \\r | |
469 | if(Demod.sumQ > 0) { \\r | |
470 | v += cq; \\r | |
471 | } else { \\r | |
472 | v -= cq; \\r | |
473 | } \\r | |
474 | }\r | |
475 | \r | |
476 | switch(Demod.state) {\r | |
477 | case DEMOD_UNSYNCD:\r | |
478 | v = ci;\r | |
479 | if(v < 0) v = -v;\r | |
480 | if(cq > 0) {\r | |
481 | v += cq;\r | |
482 | } else {\r | |
483 | v -= cq;\r | |
484 | }\r | |
485 | if(v > 40) {\r | |
486 | Demod.posCount = 0;\r | |
487 | Demod.state = DEMOD_PHASE_REF_TRAINING;\r | |
488 | Demod.sumI = 0;\r | |
489 | Demod.sumQ = 0;\r | |
490 | }\r | |
491 | break;\r | |
492 | \r | |
493 | case DEMOD_PHASE_REF_TRAINING:\r | |
494 | if(Demod.posCount < 8) {\r | |
495 | Demod.sumI += ci;\r | |
496 | Demod.sumQ += cq;\r | |
497 | } else if(Demod.posCount > 100) {\r | |
498 | // error, waited too long\r | |
499 | Demod.state = DEMOD_UNSYNCD;\r | |
500 | } else {\r | |
501 | MAKE_SOFT_DECISION();\r | |
502 | if(v < 0) {\r | |
503 | Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;\r | |
504 | Demod.posCount = 0;\r | |
505 | }\r | |
506 | }\r | |
507 | Demod.posCount++;\r | |
508 | break;\r | |
509 | \r | |
510 | case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:\r | |
511 | MAKE_SOFT_DECISION();\r | |
512 | if(v < 0) {\r | |
513 | Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;\r | |
514 | Demod.posCount = 0;\r | |
515 | } else {\r | |
516 | if(Demod.posCount > 100) {\r | |
517 | Demod.state = DEMOD_UNSYNCD;\r | |
518 | }\r | |
519 | }\r | |
520 | Demod.posCount++;\r | |
521 | break;\r | |
522 | \r | |
523 | case DEMOD_GOT_FALLING_EDGE_OF_SOF:\r | |
524 | MAKE_SOFT_DECISION();\r | |
525 | if(v > 0) {\r | |
526 | if(Demod.posCount < 12) {\r | |
527 | Demod.state = DEMOD_UNSYNCD;\r | |
528 | } else {\r | |
0e25ae11 | 529 | LED_C_ON(); // Got SOF\r |
6658905f | 530 | Demod.state = DEMOD_AWAITING_START_BIT;\r |
531 | Demod.posCount = 0;\r | |
532 | Demod.len = 0;\r | |
533 | Demod.metricN = 0;\r | |
534 | Demod.metric = 0;\r | |
535 | }\r | |
536 | } else {\r | |
537 | if(Demod.posCount > 100) {\r | |
538 | Demod.state = DEMOD_UNSYNCD;\r | |
539 | }\r | |
540 | }\r | |
541 | Demod.posCount++;\r | |
542 | break;\r | |
543 | \r | |
544 | case DEMOD_AWAITING_START_BIT:\r | |
545 | MAKE_SOFT_DECISION();\r | |
546 | if(v > 0) {\r | |
547 | if(Demod.posCount > 10) {\r | |
548 | Demod.state = DEMOD_UNSYNCD;\r | |
549 | }\r | |
550 | } else {\r | |
551 | Demod.bitCount = 0;\r | |
552 | Demod.posCount = 1;\r | |
553 | Demod.thisBit = v;\r | |
554 | Demod.shiftReg = 0;\r | |
555 | Demod.state = DEMOD_RECEIVING_DATA;\r | |
556 | }\r | |
557 | break;\r | |
558 | \r | |
559 | case DEMOD_RECEIVING_DATA:\r | |
560 | MAKE_SOFT_DECISION();\r | |
561 | if(Demod.posCount == 0) {\r | |
562 | Demod.thisBit = v;\r | |
563 | Demod.posCount = 1;\r | |
564 | } else {\r | |
565 | Demod.thisBit += v;\r | |
566 | \r | |
567 | if(Demod.thisBit > 0) {\r | |
568 | Demod.metric += Demod.thisBit;\r | |
569 | } else {\r | |
570 | Demod.metric -= Demod.thisBit;\r | |
571 | }\r | |
572 | (Demod.metricN)++;\r | |
573 | \r | |
574 | Demod.shiftReg >>= 1;\r | |
575 | if(Demod.thisBit > 0) {\r | |
576 | Demod.shiftReg |= 0x200;\r | |
577 | }\r | |
578 | \r | |
579 | Demod.bitCount++;\r | |
580 | if(Demod.bitCount == 10) {\r | |
581 | WORD s = Demod.shiftReg;\r | |
582 | if((s & 0x200) && !(s & 0x001)) {\r | |
583 | BYTE b = (s >> 1);\r | |
584 | Demod.output[Demod.len] = b;\r | |
585 | Demod.len++;\r | |
586 | Demod.state = DEMOD_AWAITING_START_BIT;\r | |
587 | } else if(s == 0x000) {\r | |
588 | // This is EOF\r | |
0e25ae11 | 589 | LED_C_OFF();\r |
6658905f | 590 | return TRUE;\r |
591 | Demod.state = DEMOD_UNSYNCD;\r | |
592 | } else {\r | |
593 | Demod.state = DEMOD_UNSYNCD;\r | |
594 | }\r | |
595 | }\r | |
596 | Demod.posCount = 0;\r | |
597 | }\r | |
598 | break;\r | |
599 | \r | |
600 | default:\r | |
601 | Demod.state = DEMOD_UNSYNCD;\r | |
602 | break;\r | |
603 | }\r | |
604 | \r | |
0e25ae11 | 605 | if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized...\r |
6658905f | 606 | return FALSE;\r |
607 | }\r | |
608 | \r | |
0e25ae11 | 609 | /*\r |
610 | * Demodulate the samples we received from the tag\r | |
611 | * weTx: set to 'TRUE' if we behave like a reader\r | |
612 | * set to 'FALSE' if we behave like a snooper\r | |
6949aca9 | 613 | * quiet: set to 'TRUE' to disable debug output\r |
0e25ae11 | 614 | */\r |
fb25b483 | 615 | static void GetSamplesFor14443Demod(BOOL weTx, int n, BOOL quiet)\r |
6658905f | 616 | {\r |
617 | int max = 0;\r | |
618 | BOOL gotFrame = FALSE;\r | |
619 | \r | |
620 | //# define DMA_BUFFER_SIZE 8\r | |
621 | SBYTE *dmaBuf;\r | |
622 | \r | |
623 | int lastRxCounter;\r | |
624 | SBYTE *upTo;\r | |
625 | \r | |
626 | int ci, cq;\r | |
627 | \r | |
628 | int samples = 0;\r | |
629 | \r | |
630 | // Clear out the state of the "UART" that receives from the tag.\r | |
631 | memset(BigBuf, 0x44, 400);\r | |
632 | Demod.output = (BYTE *)BigBuf;\r | |
633 | Demod.len = 0;\r | |
634 | Demod.state = DEMOD_UNSYNCD;\r | |
635 | \r | |
636 | // And the UART that receives from the reader\r | |
637 | Uart.output = (((BYTE *)BigBuf) + 1024);\r | |
638 | Uart.byteCntMax = 100;\r | |
639 | Uart.state = STATE_UNSYNCD;\r | |
640 | \r | |
641 | // Setup for the DMA.\r | |
642 | dmaBuf = (SBYTE *)(BigBuf + 32);\r | |
643 | upTo = dmaBuf;\r | |
644 | lastRxCounter = DMA_BUFFER_SIZE;\r | |
645 | FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r | |
646 | \r | |
0e25ae11 | 647 | // Signal field is ON with the appropriate LED:\r |
648 | if (weTx) LED_D_ON(); else LED_D_OFF();\r | |
6658905f | 649 | // And put the FPGA in the appropriate mode\r |
650 | FpgaWriteConfWord(\r | |
651 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r | |
652 | (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r | |
653 | \r | |
654 | for(;;) {\r | |
6949aca9 | 655 | int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;\r |
6658905f | 656 | if(behindBy > max) max = behindBy;\r |
657 | \r | |
6949aca9 | 658 | while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1))\r |
6658905f | 659 | > 2)\r |
660 | {\r | |
661 | ci = upTo[0];\r | |
662 | cq = upTo[1];\r | |
663 | upTo += 2;\r | |
664 | if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r | |
665 | upTo -= DMA_BUFFER_SIZE;\r | |
6949aca9 | 666 | AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo;\r |
667 | AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r | |
6658905f | 668 | }\r |
669 | lastRxCounter -= 2;\r | |
670 | if(lastRxCounter <= 0) {\r | |
671 | lastRxCounter += DMA_BUFFER_SIZE;\r | |
672 | }\r | |
673 | \r | |
674 | samples += 2;\r | |
675 | \r | |
676 | Handle14443UartBit(1);\r | |
677 | Handle14443UartBit(1);\r | |
678 | \r | |
679 | if(Handle14443SamplesDemod(ci, cq)) {\r | |
680 | gotFrame = 1;\r | |
681 | }\r | |
682 | }\r | |
6658905f | 683 | \r |
684 | if(samples > 2000) {\r | |
685 | break;\r | |
686 | }\r | |
687 | }\r | |
6949aca9 | 688 | AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r |
850427c8 | 689 | if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len);\r |
6658905f | 690 | }\r |
691 | \r | |
692 | //-----------------------------------------------------------------------------\r | |
693 | // Read the tag's response. We just receive a stream of slightly-processed\r | |
694 | // samples from the FPGA, which we will later do some signal processing on,\r | |
695 | // to get the bits.\r | |
696 | //-----------------------------------------------------------------------------\r | |
697 | /*static void GetSamplesFor14443(BOOL weTx, int n)\r | |
698 | {\r | |
699 | BYTE *dest = (BYTE *)BigBuf;\r | |
700 | int c;\r | |
701 | \r | |
702 | FpgaWriteConfWord(\r | |
703 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r | |
704 | (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r | |
705 | \r | |
706 | c = 0;\r | |
707 | for(;;) {\r | |
6949aca9 | 708 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r |
709 | AT91C_BASE_SSC->SSC_THR = 0x43;\r | |
6658905f | 710 | }\r |
6949aca9 | 711 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r |
6658905f | 712 | SBYTE b;\r |
6949aca9 | 713 | b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;\r |
6658905f | 714 | \r |
715 | dest[c++] = (BYTE)b;\r | |
716 | \r | |
717 | if(c >= n) {\r | |
718 | break;\r | |
719 | }\r | |
720 | }\r | |
721 | }\r | |
722 | }*/\r | |
723 | \r | |
724 | //-----------------------------------------------------------------------------\r | |
725 | // Transmit the command (to the tag) that was placed in ToSend[].\r | |
726 | //-----------------------------------------------------------------------------\r | |
727 | static void TransmitFor14443(void)\r | |
728 | {\r | |
729 | int c;\r | |
730 | \r | |
731 | FpgaSetupSsc();\r | |
732 | \r | |
6949aca9 | 733 | while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r |
734 | AT91C_BASE_SSC->SSC_THR = 0xff;\r | |
6658905f | 735 | }\r |
736 | \r | |
0e25ae11 | 737 | // Signal field is ON with the appropriate Red LED\r |
738 | LED_D_ON();\r | |
739 | // Signal we are transmitting with the Green LED\r | |
740 | LED_B_ON();\r | |
741 | FpgaWriteConfWord(\r | |
6658905f | 742 | FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);\r |
743 | \r | |
744 | for(c = 0; c < 10;) {\r | |
6949aca9 | 745 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r |
746 | AT91C_BASE_SSC->SSC_THR = 0xff;\r | |
6658905f | 747 | c++;\r |
748 | }\r | |
6949aca9 | 749 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r |
750 | volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r | |
6658905f | 751 | (void)r;\r |
752 | }\r | |
753 | WDT_HIT();\r | |
754 | }\r | |
755 | \r | |
756 | c = 0;\r | |
757 | for(;;) {\r | |
6949aca9 | 758 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r |
759 | AT91C_BASE_SSC->SSC_THR = ToSend[c];\r | |
6658905f | 760 | c++;\r |
761 | if(c >= ToSendMax) {\r | |
762 | break;\r | |
763 | }\r | |
764 | }\r | |
6949aca9 | 765 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r |
766 | volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r | |
6658905f | 767 | (void)r;\r |
768 | }\r | |
769 | WDT_HIT();\r | |
770 | }\r | |
0e25ae11 | 771 | LED_B_OFF(); // Finished sending\r |
6658905f | 772 | }\r |
773 | \r | |
774 | //-----------------------------------------------------------------------------\r | |
775 | // Code a layer 2 command (string of octets, including CRC) into ToSend[],\r | |
776 | // so that it is ready to transmit to the tag using TransmitFor14443().\r | |
777 | //-----------------------------------------------------------------------------\r | |
778 | void CodeIso14443bAsReader(const BYTE *cmd, int len)\r | |
779 | {\r | |
780 | int i, j;\r | |
781 | BYTE b;\r | |
782 | \r | |
783 | ToSendReset();\r | |
784 | \r | |
785 | // Establish initial reference level\r | |
786 | for(i = 0; i < 40; i++) {\r | |
787 | ToSendStuffBit(1);\r | |
788 | }\r | |
789 | // Send SOF\r | |
790 | for(i = 0; i < 10; i++) {\r | |
791 | ToSendStuffBit(0);\r | |
792 | }\r | |
793 | \r | |
794 | for(i = 0; i < len; i++) {\r | |
795 | // Stop bits/EGT\r | |
796 | ToSendStuffBit(1);\r | |
797 | ToSendStuffBit(1);\r | |
798 | // Start bit\r | |
799 | ToSendStuffBit(0);\r | |
800 | // Data bits\r | |
801 | b = cmd[i];\r | |
802 | for(j = 0; j < 8; j++) {\r | |
803 | if(b & 1) {\r | |
804 | ToSendStuffBit(1);\r | |
805 | } else {\r | |
806 | ToSendStuffBit(0);\r | |
807 | }\r | |
808 | b >>= 1;\r | |
809 | }\r | |
810 | }\r | |
811 | // Send EOF\r | |
812 | ToSendStuffBit(1);\r | |
813 | for(i = 0; i < 10; i++) {\r | |
814 | ToSendStuffBit(0);\r | |
815 | }\r | |
816 | for(i = 0; i < 8; i++) {\r | |
817 | ToSendStuffBit(1);\r | |
818 | }\r | |
819 | \r | |
820 | // And then a little more, to make sure that the last character makes\r | |
821 | // it out before we switch to rx mode.\r | |
822 | for(i = 0; i < 24; i++) {\r | |
823 | ToSendStuffBit(1);\r | |
824 | }\r | |
825 | \r | |
826 | // Convert from last character reference to length\r | |
827 | ToSendMax++;\r | |
828 | }\r | |
829 | \r | |
830 | //-----------------------------------------------------------------------------\r | |
831 | // Read an ISO 14443 tag. We send it some set of commands, and record the\r | |
6949aca9 | 832 | // responses.\r |
833 | // The command name is misleading, it actually decodes the reponse in HEX\r | |
fb25b483 | 834 | // into the output buffer (read the result using hexsamples, not hisamples)\r |
6658905f | 835 | //-----------------------------------------------------------------------------\r |
836 | void AcquireRawAdcSamplesIso14443(DWORD parameter)\r | |
837 | {\r | |
6658905f | 838 | BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r |
839 | \r | |
840 | // Make sure that we start from off, since the tags are stateful;\r | |
841 | // confusing things will happen if we don't reset them between reads.\r | |
6658905f | 842 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r |
0e25ae11 | 843 | LED_D_OFF();\r |
6658905f | 844 | SpinDelay(200);\r |
845 | \r | |
846 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
847 | FpgaSetupSsc();\r | |
848 | \r | |
849 | // Now give it time to spin up.\r | |
0e25ae11 | 850 | // Signal field is on with the appropriate LED\r |
851 | LED_D_ON();\r | |
6658905f | 852 | FpgaWriteConfWord(\r |
853 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r | |
854 | SpinDelay(200);\r | |
855 | \r | |
856 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
857 | TransmitFor14443();\r | |
0e25ae11 | 858 | // LED_A_ON();\r |
fb25b483 | 859 | GetSamplesFor14443Demod(TRUE, 2000, FALSE);\r |
0e25ae11 | 860 | // LED_A_OFF();\r |
6658905f | 861 | }\r |
6949aca9 | 862 | \r |
fb25b483 | 863 | //-----------------------------------------------------------------------------\r |
864 | // Read a SRI512 ISO 14443 tag.\r | |
6949aca9 | 865 | //\r |
866 | // SRI512 tags are just simple memory tags, here we're looking at making a dump\r | |
867 | // of the contents of the memory. No anticollision algorithm is done, we assume\r | |
868 | // we have a single tag in the field.\r | |
869 | //\r | |
fb25b483 | 870 | // I tried to be systematic and check every answer of the tag, every CRC, etc...\r |
871 | //-----------------------------------------------------------------------------\r | |
872 | void ReadSRI512Iso14443(DWORD parameter)\r | |
873 | {\r | |
850427c8 | 874 | ReadSTMemoryIso14443(parameter,0x0F);\r |
875 | }\r | |
876 | void ReadSRIX4KIso14443(DWORD parameter)\r | |
877 | {\r | |
878 | ReadSTMemoryIso14443(parameter,0x7F);\r | |
879 | }\r | |
880 | \r | |
881 | void ReadSTMemoryIso14443(DWORD parameter,DWORD dwLast)\r | |
882 | {\r | |
6949aca9 | 883 | BYTE i = 0x00;\r |
fb25b483 | 884 | \r |
885 | // Make sure that we start from off, since the tags are stateful;\r | |
886 | // confusing things will happen if we don't reset them between reads.\r | |
887 | LED_D_OFF();\r | |
888 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r | |
889 | SpinDelay(200);\r | |
890 | \r | |
891 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
892 | FpgaSetupSsc();\r | |
893 | \r | |
894 | // Now give it time to spin up.\r | |
0e25ae11 | 895 | // Signal field is on with the appropriate LED\r |
896 | LED_D_ON();\r | |
fb25b483 | 897 | FpgaWriteConfWord(\r |
898 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r | |
899 | SpinDelay(200);\r | |
6949aca9 | 900 | \r |
fb25b483 | 901 | // First command: wake up the tag using the INITIATE command\r |
902 | BYTE cmd1[] = { 0x06, 0x00, 0x97, 0x5b};\r | |
903 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
904 | TransmitFor14443();\r | |
0e25ae11 | 905 | // LED_A_ON();\r |
fb25b483 | 906 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r |
0e25ae11 | 907 | // LED_A_OFF();\r |
6949aca9 | 908 | \r |
909 | if (Demod.len == 0) {\r | |
910 | DbpString("No response from tag");\r | |
911 | return;\r | |
912 | } else {\r | |
850427c8 | 913 | Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x",\r |
914 | Demod.output[0], Demod.output[1],Demod.output[2]);\r | |
6949aca9 | 915 | }\r |
916 | // There is a response, SELECT the uid\r | |
917 | DbpString("Now SELECT tag:");\r | |
918 | cmd1[0] = 0x0E; // 0x0E is SELECT\r | |
919 | cmd1[1] = Demod.output[0];\r | |
fb25b483 | 920 | ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);\r |
921 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
922 | TransmitFor14443();\r | |
0e25ae11 | 923 | // LED_A_ON();\r |
fb25b483 | 924 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r |
0e25ae11 | 925 | // LED_A_OFF();\r |
6949aca9 | 926 | if (Demod.len != 3) {\r |
850427c8 | 927 | Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);\r |
6949aca9 | 928 | return;\r |
929 | }\r | |
930 | // Check the CRC of the answer:\r | |
fb25b483 | 931 | ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);\r |
932 | if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {\r | |
6949aca9 | 933 | DbpString("CRC Error reading select response.");\r |
934 | return;\r | |
935 | }\r | |
936 | // Check response from the tag: should be the same UID as the command we just sent:\r | |
937 | if (cmd1[1] != Demod.output[0]) {\r | |
850427c8 | 938 | Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]);\r |
6949aca9 | 939 | return;\r |
940 | }\r | |
941 | // Tag is now selected,\r | |
942 | // First get the tag's UID:\r | |
943 | cmd1[0] = 0x0B;\r | |
944 | ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);\r | |
1a093c19 | 945 | CodeIso14443bAsReader(cmd1, 3); // Only first three bytes for this one\r |
946 | TransmitFor14443();\r | |
0e25ae11 | 947 | // LED_A_ON();\r |
1a093c19 | 948 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r |
0e25ae11 | 949 | // LED_A_OFF();\r |
6949aca9 | 950 | if (Demod.len != 10) {\r |
850427c8 | 951 | Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);\r |
6949aca9 | 952 | return;\r |
953 | }\r | |
954 | // The check the CRC of the answer (use cmd1 as temporary variable):\r | |
1a093c19 | 955 | ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]);\r |
956 | if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) {\r | |
850427c8 | 957 | Dbprintf("CRC Error reading block! - Below: expected, got %x %x",\r |
958 | (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]);\r | |
6949aca9 | 959 | // Do not return;, let's go on... (we should retry, maybe ?)\r |
960 | }\r | |
850427c8 | 961 | Dbprintf("Tag UID (64 bits): %08x %08x",\r |
962 | (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4],\r | |
963 | (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]);\r | |
6949aca9 | 964 | \r |
965 | // Now loop to read all 16 blocks, address from 0 to 15\r | |
966 | DbpString("Tag memory dump, block 0 to 15");\r | |
967 | cmd1[0] = 0x08;\r | |
968 | i = 0x00;\r | |
850427c8 | 969 | dwLast++;\r |
6949aca9 | 970 | for (;;) {\r |
850427c8 | 971 | if (i == dwLast) {\r |
6949aca9 | 972 | DbpString("System area block (0xff):");\r |
973 | i = 0xff;\r | |
974 | }\r | |
975 | cmd1[1] = i;\r | |
fb25b483 | 976 | ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);\r |
977 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
978 | TransmitFor14443();\r | |
0e25ae11 | 979 | // LED_A_ON();\r |
fb25b483 | 980 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r |
6949aca9 | 981 | // LED_A_OFF();\r |
982 | if (Demod.len != 6) { // Check if we got an answer from the tag\r | |
983 | DbpString("Expected 6 bytes from tag, got less...");\r | |
984 | return;\r | |
985 | }\r | |
986 | // The check the CRC of the answer (use cmd1 as temporary variable):\r | |
fb25b483 | 987 | ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]);\r |
988 | if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) {\r | |
850427c8 | 989 | Dbprintf("CRC Error reading block! - Below: expected, got %x %x",\r |
990 | (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]);\r | |
6949aca9 | 991 | // Do not return;, let's go on... (we should retry, maybe ?)\r |
992 | }\r | |
993 | // Now print out the memory location:\r | |
850427c8 | 994 | Dbprintf("Address=%x, Contents=%x, CRC=%x", i,\r |
995 | (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0],\r | |
996 | (Demod.output[4]<<8)+Demod.output[5]);\r | |
6949aca9 | 997 | if (i == 0xff) {\r |
998 | break;\r | |
999 | }\r | |
1000 | i++;\r | |
1001 | }\r | |
fb25b483 | 1002 | }\r |
6949aca9 | 1003 | \r |
6658905f | 1004 | \r |
1005 | //=============================================================================\r | |
1006 | // Finally, the `sniffer' combines elements from both the reader and\r | |
1007 | // simulated tag, to show both sides of the conversation.\r | |
1008 | //=============================================================================\r | |
1009 | \r | |
1010 | //-----------------------------------------------------------------------------\r | |
1011 | // Record the sequence of commands sent by the reader to the tag, with\r | |
1012 | // triggering so that we start recording at the point that the tag is moved\r | |
1013 | // near the reader.\r | |
1014 | //-----------------------------------------------------------------------------\r | |
0e25ae11 | 1015 | /*\r |
1016 | * Memory usage for this function, (within BigBuf)\r | |
1017 | * 0-1023 : Demodulated samples receive (1024 bytes)\r | |
1018 | * 1024-1535 : Last Received command, 512 bytes (reader->tag)\r | |
1019 | * 1536-2047 : Last Received command, 512 bytes(tag->reader)\r | |
6949aca9 | 1020 | * 2048-2304 : DMA Buffer, 256 bytes (samples)\r |
0e25ae11 | 1021 | */\r |
6658905f | 1022 | void SnoopIso14443(void)\r |
1023 | {\r | |
1024 | // We won't start recording the frames that we acquire until we trigger;\r | |
1025 | // a good trigger condition to get started is probably when we see a\r | |
1026 | // response from the tag.\r | |
1027 | BOOL triggered = FALSE;\r | |
1028 | \r | |
1029 | // The command (reader -> tag) that we're working on receiving.\r | |
0e25ae11 | 1030 | BYTE *receivedCmd = (BYTE *)(BigBuf) + 1024;\r |
6658905f | 1031 | // The response (tag -> reader) that we're working on receiving.\r |
0e25ae11 | 1032 | BYTE *receivedResponse = (BYTE *)(BigBuf) + 1536;\r |
6658905f | 1033 | \r |
1034 | // As we receive stuff, we copy it from receivedCmd or receivedResponse\r | |
1035 | // into trace, along with its length and other annotations.\r | |
1036 | BYTE *trace = (BYTE *)BigBuf;\r | |
1037 | int traceLen = 0;\r | |
1038 | \r | |
1039 | // The DMA buffer, used to stream samples from the FPGA.\r | |
0e25ae11 | 1040 | SBYTE *dmaBuf = (SBYTE *)(BigBuf) + 2048;\r |
6658905f | 1041 | int lastRxCounter;\r |
1042 | SBYTE *upTo;\r | |
1043 | int ci, cq;\r | |
1044 | int maxBehindBy = 0;\r | |
1045 | \r | |
1046 | // Count of samples received so far, so that we can include timing\r | |
1047 | // information in the trace buffer.\r | |
1048 | int samples = 0;\r | |
1049 | \r | |
0e25ae11 | 1050 | // Initialize the trace buffer\r |
1051 | memset(trace, 0x44, 1024);\r | |
6658905f | 1052 | \r |
1053 | // Set up the demodulator for tag -> reader responses.\r | |
1054 | Demod.output = receivedResponse;\r | |
1055 | Demod.len = 0;\r | |
1056 | Demod.state = DEMOD_UNSYNCD;\r | |
1057 | \r | |
1058 | // And the reader -> tag commands\r | |
1059 | memset(&Uart, 0, sizeof(Uart));\r | |
1060 | Uart.output = receivedCmd;\r | |
1061 | Uart.byteCntMax = 100;\r | |
1062 | Uart.state = STATE_UNSYNCD;\r | |
1063 | \r | |
1064 | // And put the FPGA in the appropriate mode\r | |
0e25ae11 | 1065 | // Signal field is off with the appropriate LED\r |
1066 | LED_D_OFF();\r | |
6658905f | 1067 | FpgaWriteConfWord(\r |
1068 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r | |
1069 | FPGA_HF_READER_RX_XCORR_SNOOP);\r | |
1070 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
1071 | \r | |
1072 | // Setup for the DMA.\r | |
1073 | FpgaSetupSsc();\r | |
1074 | upTo = dmaBuf;\r | |
1075 | lastRxCounter = DMA_BUFFER_SIZE;\r | |
1076 | FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r | |
6658905f | 1077 | // And now we loop, receiving samples.\r |
1078 | for(;;) {\r | |
6949aca9 | 1079 | int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &\r |
6658905f | 1080 | (DMA_BUFFER_SIZE-1);\r |
1081 | if(behindBy > maxBehindBy) {\r | |
1082 | maxBehindBy = behindBy;\r | |
0e25ae11 | 1083 | if(behindBy > (DMA_BUFFER_SIZE-2)) { // TODO: understand whether we can increase/decrease as we want or not?\r |
850427c8 | 1084 | Dbprintf("blew circular buffer! behindBy=%x", behindBy);\r |
6658905f | 1085 | goto done;\r |
1086 | }\r | |
1087 | }\r | |
1088 | if(behindBy < 2) continue;\r | |
1089 | \r | |
1090 | ci = upTo[0];\r | |
1091 | cq = upTo[1];\r | |
1092 | upTo += 2;\r | |
1093 | lastRxCounter -= 2;\r | |
1094 | if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r | |
1095 | upTo -= DMA_BUFFER_SIZE;\r | |
1096 | lastRxCounter += DMA_BUFFER_SIZE;\r | |
6949aca9 | 1097 | AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD) upTo;\r |
1098 | AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r | |
6658905f | 1099 | }\r |
1100 | \r | |
1101 | samples += 2;\r | |
1102 | \r | |
1103 | #define HANDLE_BIT_IF_BODY \\r | |
1104 | if(triggered) { \\r | |
1105 | trace[traceLen++] = ((samples >> 0) & 0xff); \\r | |
1106 | trace[traceLen++] = ((samples >> 8) & 0xff); \\r | |
1107 | trace[traceLen++] = ((samples >> 16) & 0xff); \\r | |
1108 | trace[traceLen++] = ((samples >> 24) & 0xff); \\r | |
1109 | trace[traceLen++] = 0; \\r | |
1110 | trace[traceLen++] = 0; \\r | |
1111 | trace[traceLen++] = 0; \\r | |
1112 | trace[traceLen++] = 0; \\r | |
1113 | trace[traceLen++] = Uart.byteCnt; \\r | |
1114 | memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \\r | |
1115 | traceLen += Uart.byteCnt; \\r | |
1116 | if(traceLen > 1000) break; \\r | |
1117 | } \\r | |
1118 | /* And ready to receive another command. */ \\r | |
1119 | memset(&Uart, 0, sizeof(Uart)); \\r | |
1120 | Uart.output = receivedCmd; \\r | |
1121 | Uart.byteCntMax = 100; \\r | |
1122 | Uart.state = STATE_UNSYNCD; \\r | |
1123 | /* And also reset the demod code, which might have been */ \\r | |
1124 | /* false-triggered by the commands from the reader. */ \\r | |
1125 | memset(&Demod, 0, sizeof(Demod)); \\r | |
1126 | Demod.output = receivedResponse; \\r | |
1127 | Demod.state = DEMOD_UNSYNCD; \\r | |
1128 | \r | |
1129 | if(Handle14443UartBit(ci & 1)) {\r | |
1130 | HANDLE_BIT_IF_BODY\r | |
1131 | }\r | |
1132 | if(Handle14443UartBit(cq & 1)) {\r | |
1133 | HANDLE_BIT_IF_BODY\r | |
1134 | }\r | |
1135 | \r | |
1136 | if(Handle14443SamplesDemod(ci, cq)) {\r | |
1137 | // timestamp, as a count of samples\r | |
1138 | trace[traceLen++] = ((samples >> 0) & 0xff);\r | |
1139 | trace[traceLen++] = ((samples >> 8) & 0xff);\r | |
1140 | trace[traceLen++] = ((samples >> 16) & 0xff);\r | |
1141 | trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff);\r | |
1142 | // correlation metric (~signal strength estimate)\r | |
1143 | if(Demod.metricN != 0) {\r | |
1144 | Demod.metric /= Demod.metricN;\r | |
1145 | }\r | |
1146 | trace[traceLen++] = ((Demod.metric >> 0) & 0xff);\r | |
1147 | trace[traceLen++] = ((Demod.metric >> 8) & 0xff);\r | |
1148 | trace[traceLen++] = ((Demod.metric >> 16) & 0xff);\r | |
1149 | trace[traceLen++] = ((Demod.metric >> 24) & 0xff);\r | |
1150 | // length\r | |
1151 | trace[traceLen++] = Demod.len;\r | |
1152 | memcpy(trace+traceLen, receivedResponse, Demod.len);\r | |
1153 | traceLen += Demod.len;\r | |
1154 | if(traceLen > 1000) break;\r | |
1155 | \r | |
1156 | triggered = TRUE;\r | |
6658905f | 1157 | \r |
1158 | // And ready to receive another response.\r | |
1159 | memset(&Demod, 0, sizeof(Demod));\r | |
1160 | Demod.output = receivedResponse;\r | |
1161 | Demod.state = DEMOD_UNSYNCD;\r | |
1162 | }\r | |
0e25ae11 | 1163 | WDT_HIT();\r |
6658905f | 1164 | \r |
1165 | if(BUTTON_PRESS()) {\r | |
1166 | DbpString("cancelled");\r | |
1167 | goto done;\r | |
1168 | }\r | |
1169 | }\r | |
1170 | \r | |
1171 | DbpString("in done pt");\r | |
850427c8 | 1172 | Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);\r |
1173 | Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, 0x23);\r | |
6658905f | 1174 | \r |
1175 | done:\r | |
0e25ae11 | 1176 | LED_D_OFF();\r |
6949aca9 | 1177 | AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r |
6658905f | 1178 | }\r |