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