]>
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 "../common/iso14443_crc.c"\r | |
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 | |
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 | |
143 | static BOOL Handle14443UartBit(int bit)\r | |
144 | {\r | |
145 | switch(Uart.state) {\r | |
146 | case STATE_UNSYNCD:\r | |
147 | LED_A_OFF();\r | |
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 | |
167 | LED_A_ON(); // Indicate we got a valid SOF\r | |
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 | |
200 | LED_A_ON(); // Indicate we're receiving\r | |
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 | |
236 | LED_A_OFF(); // Finished receiving\r | |
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 | |
261 | if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error\r | |
262 | \r | |
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 | |
282 | // Signal field is off with the appropriate LED\r | |
283 | LED_D_OFF();\r | |
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 | |
298 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r | |
299 | AT91C_BASE_SSC->SSC_THR = 0x00;\r | |
300 | }\r | |
301 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r | |
302 | BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r | |
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 | |
356 | DbpIntegers(cmdsRecvd, 0, 0);\r | |
357 | DbpString("button press");\r | |
358 | break;\r | |
359 | }\r | |
360 | \r | |
361 | // Good, look at the command now.\r | |
362 | \r | |
363 | if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {\r | |
364 | resp = resp1; respLen = resp1Len;\r | |
365 | } else {\r | |
366 | DbpString("new cmd from reader:");\r | |
367 | DbpIntegers(len, 0x1234, cmdsRecvd);\r | |
368 | // And print whether the CRC fails, just for good measure\r | |
369 | ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);\r | |
370 | if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {\r | |
371 | // Not so good, try again.\r | |
372 | DbpString("+++CRC fail");\r | |
373 | } else {\r | |
374 | DbpString("CRC passes");\r | |
375 | }\r | |
376 | break;\r | |
377 | }\r | |
378 | \r | |
379 | memset(receivedCmd, 0x44, 32);\r | |
380 | \r | |
381 | cmdsRecvd++;\r | |
382 | \r | |
383 | if(cmdsRecvd > 0x30) {\r | |
384 | DbpString("many commands later...");\r | |
385 | break;\r | |
386 | }\r | |
387 | \r | |
388 | if(respLen <= 0) continue;\r | |
389 | \r | |
390 | // Modulate BPSK\r | |
391 | // Signal field is off with the appropriate LED\r | |
392 | LED_D_OFF();\r | |
393 | FpgaWriteConfWord(\r | |
394 | FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);\r | |
395 | AT91C_BASE_SSC->SSC_THR = 0xff;\r | |
396 | FpgaSetupSsc();\r | |
397 | \r | |
398 | // Transmit the response.\r | |
399 | i = 0;\r | |
400 | for(;;) {\r | |
401 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r | |
402 | BYTE b = resp[i];\r | |
403 | \r | |
404 | AT91C_BASE_SSC->SSC_THR = b;\r | |
405 | \r | |
406 | i++;\r | |
407 | if(i > respLen) {\r | |
408 | break;\r | |
409 | }\r | |
410 | }\r | |
411 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r | |
412 | volatile BYTE b = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r | |
413 | (void)b;\r | |
414 | }\r | |
415 | }\r | |
416 | }\r | |
417 | }\r | |
418 | \r | |
419 | //=============================================================================\r | |
420 | // An ISO 14443 Type B reader. We take layer two commands, code them\r | |
421 | // appropriately, and then send them to the tag. We then listen for the\r | |
422 | // tag's response, which we leave in the buffer to be demodulated on the\r | |
423 | // PC side.\r | |
424 | //=============================================================================\r | |
425 | \r | |
426 | static struct {\r | |
427 | enum {\r | |
428 | DEMOD_UNSYNCD,\r | |
429 | DEMOD_PHASE_REF_TRAINING,\r | |
430 | DEMOD_AWAITING_FALLING_EDGE_OF_SOF,\r | |
431 | DEMOD_GOT_FALLING_EDGE_OF_SOF,\r | |
432 | DEMOD_AWAITING_START_BIT,\r | |
433 | DEMOD_RECEIVING_DATA,\r | |
434 | DEMOD_ERROR_WAIT\r | |
435 | } state;\r | |
436 | int bitCount;\r | |
437 | int posCount;\r | |
438 | int thisBit;\r | |
439 | int metric;\r | |
440 | int metricN;\r | |
441 | WORD shiftReg;\r | |
442 | BYTE *output;\r | |
443 | int len;\r | |
444 | int sumI;\r | |
445 | int sumQ;\r | |
446 | } Demod;\r | |
447 | \r | |
448 | /*\r | |
449 | * Handles reception of a bit from the tag\r | |
450 | *\r | |
451 | * LED handling:\r | |
452 | * LED C -> ON once we have received the SOF and are expecting the rest.\r | |
453 | * LED C -> OFF once we have received EOF or are unsynced\r | |
454 | *\r | |
455 | * Returns: true if we received a EOF\r | |
456 | * false if we are still waiting for some more\r | |
457 | *\r | |
458 | */\r | |
459 | static BOOL Handle14443SamplesDemod(int ci, int cq)\r | |
460 | {\r | |
461 | int v;\r | |
462 | \r | |
463 | // The soft decision on the bit uses an estimate of just the\r | |
464 | // quadrant of the reference angle, not the exact angle.\r | |
465 | #define MAKE_SOFT_DECISION() { \\r | |
466 | if(Demod.sumI > 0) { \\r | |
467 | v = ci; \\r | |
468 | } else { \\r | |
469 | v = -ci; \\r | |
470 | } \\r | |
471 | if(Demod.sumQ > 0) { \\r | |
472 | v += cq; \\r | |
473 | } else { \\r | |
474 | v -= cq; \\r | |
475 | } \\r | |
476 | }\r | |
477 | \r | |
478 | switch(Demod.state) {\r | |
479 | case DEMOD_UNSYNCD:\r | |
480 | v = ci;\r | |
481 | if(v < 0) v = -v;\r | |
482 | if(cq > 0) {\r | |
483 | v += cq;\r | |
484 | } else {\r | |
485 | v -= cq;\r | |
486 | }\r | |
487 | if(v > 40) {\r | |
488 | Demod.posCount = 0;\r | |
489 | Demod.state = DEMOD_PHASE_REF_TRAINING;\r | |
490 | Demod.sumI = 0;\r | |
491 | Demod.sumQ = 0;\r | |
492 | }\r | |
493 | break;\r | |
494 | \r | |
495 | case DEMOD_PHASE_REF_TRAINING:\r | |
496 | if(Demod.posCount < 8) {\r | |
497 | Demod.sumI += ci;\r | |
498 | Demod.sumQ += cq;\r | |
499 | } else if(Demod.posCount > 100) {\r | |
500 | // error, waited too long\r | |
501 | Demod.state = DEMOD_UNSYNCD;\r | |
502 | } else {\r | |
503 | MAKE_SOFT_DECISION();\r | |
504 | if(v < 0) {\r | |
505 | Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;\r | |
506 | Demod.posCount = 0;\r | |
507 | }\r | |
508 | }\r | |
509 | Demod.posCount++;\r | |
510 | break;\r | |
511 | \r | |
512 | case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:\r | |
513 | MAKE_SOFT_DECISION();\r | |
514 | if(v < 0) {\r | |
515 | Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;\r | |
516 | Demod.posCount = 0;\r | |
517 | } else {\r | |
518 | if(Demod.posCount > 100) {\r | |
519 | Demod.state = DEMOD_UNSYNCD;\r | |
520 | }\r | |
521 | }\r | |
522 | Demod.posCount++;\r | |
523 | break;\r | |
524 | \r | |
525 | case DEMOD_GOT_FALLING_EDGE_OF_SOF:\r | |
526 | MAKE_SOFT_DECISION();\r | |
527 | if(v > 0) {\r | |
528 | if(Demod.posCount < 12) {\r | |
529 | Demod.state = DEMOD_UNSYNCD;\r | |
530 | } else {\r | |
531 | LED_C_ON(); // Got SOF\r | |
532 | Demod.state = DEMOD_AWAITING_START_BIT;\r | |
533 | Demod.posCount = 0;\r | |
534 | Demod.len = 0;\r | |
535 | Demod.metricN = 0;\r | |
536 | Demod.metric = 0;\r | |
537 | }\r | |
538 | } else {\r | |
539 | if(Demod.posCount > 100) {\r | |
540 | Demod.state = DEMOD_UNSYNCD;\r | |
541 | }\r | |
542 | }\r | |
543 | Demod.posCount++;\r | |
544 | break;\r | |
545 | \r | |
546 | case DEMOD_AWAITING_START_BIT:\r | |
547 | MAKE_SOFT_DECISION();\r | |
548 | if(v > 0) {\r | |
549 | if(Demod.posCount > 10) {\r | |
550 | Demod.state = DEMOD_UNSYNCD;\r | |
551 | }\r | |
552 | } else {\r | |
553 | Demod.bitCount = 0;\r | |
554 | Demod.posCount = 1;\r | |
555 | Demod.thisBit = v;\r | |
556 | Demod.shiftReg = 0;\r | |
557 | Demod.state = DEMOD_RECEIVING_DATA;\r | |
558 | }\r | |
559 | break;\r | |
560 | \r | |
561 | case DEMOD_RECEIVING_DATA:\r | |
562 | MAKE_SOFT_DECISION();\r | |
563 | if(Demod.posCount == 0) {\r | |
564 | Demod.thisBit = v;\r | |
565 | Demod.posCount = 1;\r | |
566 | } else {\r | |
567 | Demod.thisBit += v;\r | |
568 | \r | |
569 | if(Demod.thisBit > 0) {\r | |
570 | Demod.metric += Demod.thisBit;\r | |
571 | } else {\r | |
572 | Demod.metric -= Demod.thisBit;\r | |
573 | }\r | |
574 | (Demod.metricN)++;\r | |
575 | \r | |
576 | Demod.shiftReg >>= 1;\r | |
577 | if(Demod.thisBit > 0) {\r | |
578 | Demod.shiftReg |= 0x200;\r | |
579 | }\r | |
580 | \r | |
581 | Demod.bitCount++;\r | |
582 | if(Demod.bitCount == 10) {\r | |
583 | WORD s = Demod.shiftReg;\r | |
584 | if((s & 0x200) && !(s & 0x001)) {\r | |
585 | BYTE b = (s >> 1);\r | |
586 | Demod.output[Demod.len] = b;\r | |
587 | Demod.len++;\r | |
588 | Demod.state = DEMOD_AWAITING_START_BIT;\r | |
589 | } else if(s == 0x000) {\r | |
590 | // This is EOF\r | |
591 | LED_C_OFF();\r | |
592 | return TRUE;\r | |
593 | Demod.state = DEMOD_UNSYNCD;\r | |
594 | } else {\r | |
595 | Demod.state = DEMOD_UNSYNCD;\r | |
596 | }\r | |
597 | }\r | |
598 | Demod.posCount = 0;\r | |
599 | }\r | |
600 | break;\r | |
601 | \r | |
602 | default:\r | |
603 | Demod.state = DEMOD_UNSYNCD;\r | |
604 | break;\r | |
605 | }\r | |
606 | \r | |
607 | if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized...\r | |
608 | return FALSE;\r | |
609 | }\r | |
610 | \r | |
611 | /*\r | |
612 | * Demodulate the samples we received from the tag\r | |
613 | * weTx: set to 'TRUE' if we behave like a reader\r | |
614 | * set to 'FALSE' if we behave like a snooper\r | |
615 | * quiet: set to 'TRUE' to disable debug output\r | |
616 | */\r | |
617 | static void GetSamplesFor14443Demod(BOOL weTx, int n, BOOL quiet)\r | |
618 | {\r | |
619 | int max = 0;\r | |
620 | BOOL gotFrame = FALSE;\r | |
621 | \r | |
622 | //# define DMA_BUFFER_SIZE 8\r | |
623 | SBYTE *dmaBuf;\r | |
624 | \r | |
625 | int lastRxCounter;\r | |
626 | SBYTE *upTo;\r | |
627 | \r | |
628 | int ci, cq;\r | |
629 | \r | |
630 | int samples = 0;\r | |
631 | \r | |
632 | // Clear out the state of the "UART" that receives from the tag.\r | |
633 | memset(BigBuf, 0x44, 400);\r | |
634 | Demod.output = (BYTE *)BigBuf;\r | |
635 | Demod.len = 0;\r | |
636 | Demod.state = DEMOD_UNSYNCD;\r | |
637 | \r | |
638 | // And the UART that receives from the reader\r | |
639 | Uart.output = (((BYTE *)BigBuf) + 1024);\r | |
640 | Uart.byteCntMax = 100;\r | |
641 | Uart.state = STATE_UNSYNCD;\r | |
642 | \r | |
643 | // Setup for the DMA.\r | |
644 | dmaBuf = (SBYTE *)(BigBuf + 32);\r | |
645 | upTo = dmaBuf;\r | |
646 | lastRxCounter = DMA_BUFFER_SIZE;\r | |
647 | FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r | |
648 | \r | |
649 | // Signal field is ON with the appropriate LED:\r | |
650 | if (weTx) LED_D_ON(); else LED_D_OFF();\r | |
651 | // And put the FPGA in the appropriate mode\r | |
652 | FpgaWriteConfWord(\r | |
653 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r | |
654 | (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r | |
655 | \r | |
656 | for(;;) {\r | |
657 | int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;\r | |
658 | if(behindBy > max) max = behindBy;\r | |
659 | \r | |
660 | while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1))\r | |
661 | > 2)\r | |
662 | {\r | |
663 | ci = upTo[0];\r | |
664 | cq = upTo[1];\r | |
665 | upTo += 2;\r | |
666 | if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r | |
667 | upTo -= DMA_BUFFER_SIZE;\r | |
668 | AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)upTo;\r | |
669 | AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r | |
670 | }\r | |
671 | lastRxCounter -= 2;\r | |
672 | if(lastRxCounter <= 0) {\r | |
673 | lastRxCounter += DMA_BUFFER_SIZE;\r | |
674 | }\r | |
675 | \r | |
676 | samples += 2;\r | |
677 | \r | |
678 | Handle14443UartBit(1);\r | |
679 | Handle14443UartBit(1);\r | |
680 | \r | |
681 | if(Handle14443SamplesDemod(ci, cq)) {\r | |
682 | gotFrame = 1;\r | |
683 | }\r | |
684 | }\r | |
685 | \r | |
686 | if(samples > 2000) {\r | |
687 | break;\r | |
688 | }\r | |
689 | }\r | |
690 | AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r | |
691 | if (!quiet) DbpIntegers(max, gotFrame, Demod.len);\r | |
692 | }\r | |
693 | \r | |
694 | //-----------------------------------------------------------------------------\r | |
695 | // Read the tag's response. We just receive a stream of slightly-processed\r | |
696 | // samples from the FPGA, which we will later do some signal processing on,\r | |
697 | // to get the bits.\r | |
698 | //-----------------------------------------------------------------------------\r | |
699 | /*static void GetSamplesFor14443(BOOL weTx, int n)\r | |
700 | {\r | |
701 | BYTE *dest = (BYTE *)BigBuf;\r | |
702 | int c;\r | |
703 | \r | |
704 | FpgaWriteConfWord(\r | |
705 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r | |
706 | (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r | |
707 | \r | |
708 | c = 0;\r | |
709 | for(;;) {\r | |
710 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r | |
711 | AT91C_BASE_SSC->SSC_THR = 0x43;\r | |
712 | }\r | |
713 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r | |
714 | SBYTE b;\r | |
715 | b = (SBYTE)AT91C_BASE_SSC->SSC_RHR;\r | |
716 | \r | |
717 | dest[c++] = (BYTE)b;\r | |
718 | \r | |
719 | if(c >= n) {\r | |
720 | break;\r | |
721 | }\r | |
722 | }\r | |
723 | }\r | |
724 | }*/\r | |
725 | \r | |
726 | //-----------------------------------------------------------------------------\r | |
727 | // Transmit the command (to the tag) that was placed in ToSend[].\r | |
728 | //-----------------------------------------------------------------------------\r | |
729 | static void TransmitFor14443(void)\r | |
730 | {\r | |
731 | int c;\r | |
732 | \r | |
733 | FpgaSetupSsc();\r | |
734 | \r | |
735 | while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r | |
736 | AT91C_BASE_SSC->SSC_THR = 0xff;\r | |
737 | }\r | |
738 | \r | |
739 | // Signal field is ON with the appropriate Red LED\r | |
740 | LED_D_ON();\r | |
741 | // Signal we are transmitting with the Green LED\r | |
742 | LED_B_ON();\r | |
743 | FpgaWriteConfWord(\r | |
744 | FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);\r | |
745 | \r | |
746 | for(c = 0; c < 10;) {\r | |
747 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r | |
748 | AT91C_BASE_SSC->SSC_THR = 0xff;\r | |
749 | c++;\r | |
750 | }\r | |
751 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r | |
752 | volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r | |
753 | (void)r;\r | |
754 | }\r | |
755 | WDT_HIT();\r | |
756 | }\r | |
757 | \r | |
758 | c = 0;\r | |
759 | for(;;) {\r | |
760 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r | |
761 | AT91C_BASE_SSC->SSC_THR = ToSend[c];\r | |
762 | c++;\r | |
763 | if(c >= ToSendMax) {\r | |
764 | break;\r | |
765 | }\r | |
766 | }\r | |
767 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r | |
768 | volatile DWORD r = AT91C_BASE_SSC->SSC_RHR;\r | |
769 | (void)r;\r | |
770 | }\r | |
771 | WDT_HIT();\r | |
772 | }\r | |
773 | LED_B_OFF(); // Finished sending\r | |
774 | }\r | |
775 | \r | |
776 | //-----------------------------------------------------------------------------\r | |
777 | // Code a layer 2 command (string of octets, including CRC) into ToSend[],\r | |
778 | // so that it is ready to transmit to the tag using TransmitFor14443().\r | |
779 | //-----------------------------------------------------------------------------\r | |
780 | void CodeIso14443bAsReader(const BYTE *cmd, int len)\r | |
781 | {\r | |
782 | int i, j;\r | |
783 | BYTE b;\r | |
784 | \r | |
785 | ToSendReset();\r | |
786 | \r | |
787 | // Establish initial reference level\r | |
788 | for(i = 0; i < 40; i++) {\r | |
789 | ToSendStuffBit(1);\r | |
790 | }\r | |
791 | // Send SOF\r | |
792 | for(i = 0; i < 10; i++) {\r | |
793 | ToSendStuffBit(0);\r | |
794 | }\r | |
795 | \r | |
796 | for(i = 0; i < len; i++) {\r | |
797 | // Stop bits/EGT\r | |
798 | ToSendStuffBit(1);\r | |
799 | ToSendStuffBit(1);\r | |
800 | // Start bit\r | |
801 | ToSendStuffBit(0);\r | |
802 | // Data bits\r | |
803 | b = cmd[i];\r | |
804 | for(j = 0; j < 8; j++) {\r | |
805 | if(b & 1) {\r | |
806 | ToSendStuffBit(1);\r | |
807 | } else {\r | |
808 | ToSendStuffBit(0);\r | |
809 | }\r | |
810 | b >>= 1;\r | |
811 | }\r | |
812 | }\r | |
813 | // Send EOF\r | |
814 | ToSendStuffBit(1);\r | |
815 | for(i = 0; i < 10; i++) {\r | |
816 | ToSendStuffBit(0);\r | |
817 | }\r | |
818 | for(i = 0; i < 8; i++) {\r | |
819 | ToSendStuffBit(1);\r | |
820 | }\r | |
821 | \r | |
822 | // And then a little more, to make sure that the last character makes\r | |
823 | // it out before we switch to rx mode.\r | |
824 | for(i = 0; i < 24; i++) {\r | |
825 | ToSendStuffBit(1);\r | |
826 | }\r | |
827 | \r | |
828 | // Convert from last character reference to length\r | |
829 | ToSendMax++;\r | |
830 | }\r | |
831 | \r | |
832 | //-----------------------------------------------------------------------------\r | |
833 | // Read an ISO 14443 tag. We send it some set of commands, and record the\r | |
834 | // responses.\r | |
835 | // The command name is misleading, it actually decodes the reponse in HEX\r | |
836 | // into the output buffer (read the result using hexsamples, not hisamples)\r | |
837 | //-----------------------------------------------------------------------------\r | |
838 | void AcquireRawAdcSamplesIso14443(DWORD parameter)\r | |
839 | {\r | |
840 | BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r | |
841 | \r | |
842 | // Make sure that we start from off, since the tags are stateful;\r | |
843 | // confusing things will happen if we don't reset them between reads.\r | |
844 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r | |
845 | LED_D_OFF();\r | |
846 | SpinDelay(200);\r | |
847 | \r | |
848 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
849 | FpgaSetupSsc();\r | |
850 | \r | |
851 | // Now give it time to spin up.\r | |
852 | // Signal field is on with the appropriate LED\r | |
853 | LED_D_ON();\r | |
854 | FpgaWriteConfWord(\r | |
855 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r | |
856 | SpinDelay(200);\r | |
857 | \r | |
858 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
859 | TransmitFor14443();\r | |
860 | // LED_A_ON();\r | |
861 | GetSamplesFor14443Demod(TRUE, 2000, FALSE);\r | |
862 | // LED_A_OFF();\r | |
863 | }\r | |
864 | \r | |
865 | //-----------------------------------------------------------------------------\r | |
866 | // Read a SRI512 ISO 14443 tag.\r | |
867 | //\r | |
868 | // SRI512 tags are just simple memory tags, here we're looking at making a dump\r | |
869 | // of the contents of the memory. No anticollision algorithm is done, we assume\r | |
870 | // we have a single tag in the field.\r | |
871 | //\r | |
872 | // I tried to be systematic and check every answer of the tag, every CRC, etc...\r | |
873 | //-----------------------------------------------------------------------------\r | |
874 | void ReadSRI512Iso14443(DWORD parameter)\r | |
875 | {\r | |
876 | ReadSTMemoryIso14443(parameter,0x0F); | |
877 | } | |
878 | void ReadSRIX4KIso14443(DWORD parameter) | |
879 | { | |
880 | ReadSTMemoryIso14443(parameter,0x7F); | |
881 | } | |
882 | ||
883 | void ReadSTMemoryIso14443(DWORD parameter,DWORD dwLast) | |
884 | { | |
885 | BYTE i = 0x00;\r | |
886 | \r | |
887 | // Make sure that we start from off, since the tags are stateful;\r | |
888 | // confusing things will happen if we don't reset them between reads.\r | |
889 | LED_D_OFF();\r | |
890 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r | |
891 | SpinDelay(200);\r | |
892 | \r | |
893 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
894 | FpgaSetupSsc();\r | |
895 | \r | |
896 | // Now give it time to spin up.\r | |
897 | // Signal field is on with the appropriate LED\r | |
898 | LED_D_ON();\r | |
899 | FpgaWriteConfWord(\r | |
900 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r | |
901 | SpinDelay(200);\r | |
902 | \r | |
903 | // First command: wake up the tag using the INITIATE command\r | |
904 | BYTE cmd1[] = { 0x06, 0x00, 0x97, 0x5b};\r | |
905 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
906 | TransmitFor14443();\r | |
907 | // LED_A_ON();\r | |
908 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r | |
909 | // LED_A_OFF();\r | |
910 | \r | |
911 | if (Demod.len == 0) {\r | |
912 | DbpString("No response from tag");\r | |
913 | return;\r | |
914 | } else {\r | |
915 | DbpString("Randomly generated UID from tag (+ 2 byte CRC):");\r | |
916 | DbpIntegers(Demod.output[0], Demod.output[1],Demod.output[2]);\r | |
917 | }\r | |
918 | // There is a response, SELECT the uid\r | |
919 | DbpString("Now SELECT tag:");\r | |
920 | cmd1[0] = 0x0E; // 0x0E is SELECT\r | |
921 | cmd1[1] = Demod.output[0];\r | |
922 | ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);\r | |
923 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
924 | TransmitFor14443();\r | |
925 | // LED_A_ON();\r | |
926 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r | |
927 | // LED_A_OFF();\r | |
928 | if (Demod.len != 3) {\r | |
929 | DbpString("Expected 3 bytes from tag, got:");\r | |
930 | DbpIntegers(Demod.len,0x0,0x0);\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 | DbpString("Bad response to SELECT from Tag, aborting:");\r | |
942 | DbpIntegers(cmd1[1],Demod.output[0],0x0);\r | |
943 | return;\r | |
944 | }\r | |
945 | // Tag is now selected,\r | |
946 | // First get the tag's UID:\r | |
947 | cmd1[0] = 0x0B;\r | |
948 | ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);\r | |
949 | CodeIso14443bAsReader(cmd1, 3); // Only first three bytes for this one\r | |
950 | TransmitFor14443();\r | |
951 | // LED_A_ON();\r | |
952 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r | |
953 | // LED_A_OFF();\r | |
954 | if (Demod.len != 10) {\r | |
955 | DbpString("Expected 10 bytes from tag, got:");\r | |
956 | DbpIntegers(Demod.len,0x0,0x0);\r | |
957 | return;\r | |
958 | }\r | |
959 | // The check the CRC of the answer (use cmd1 as temporary variable):\r | |
960 | ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]);\r | |
961 | if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) {\r | |
962 | DbpString("CRC Error reading block! - Below: expected, got");\r | |
963 | DbpIntegers( (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9],0);\r | |
964 | // Do not return;, let's go on... (we should retry, maybe ?)\r | |
965 | }\r | |
966 | DbpString("Tag UID (64 bits):");\r | |
967 | DbpIntegers((Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], 0);\r | |
968 | \r | |
969 | // Now loop to read all 16 blocks, address from 0 to 15\r | |
970 | DbpString("Tag memory dump, block 0 to 15");\r | |
971 | cmd1[0] = 0x08;\r | |
972 | i = 0x00;\r | |
973 | dwLast++; | |
974 | for (;;) {\r | |
975 | if (i == dwLast) { | |
976 | DbpString("System area block (0xff):");\r | |
977 | i = 0xff;\r | |
978 | }\r | |
979 | cmd1[1] = i;\r | |
980 | ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);\r | |
981 | CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r | |
982 | TransmitFor14443();\r | |
983 | // LED_A_ON();\r | |
984 | GetSamplesFor14443Demod(TRUE, 2000,TRUE);\r | |
985 | // LED_A_OFF();\r | |
986 | if (Demod.len != 6) { // Check if we got an answer from the tag\r | |
987 | DbpString("Expected 6 bytes from tag, got less...");\r | |
988 | return;\r | |
989 | }\r | |
990 | // The check the CRC of the answer (use cmd1 as temporary variable):\r | |
991 | ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]);\r | |
992 | if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) {\r | |
993 | DbpString("CRC Error reading block! - Below: expected, got");\r | |
994 | DbpIntegers( (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5],0);\r | |
995 | // Do not return;, let's go on... (we should retry, maybe ?)\r | |
996 | }\r | |
997 | // Now print out the memory location:\r | |
998 | DbpString("Address , Contents, CRC");\r | |
999 | DbpIntegers(i, (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], (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-1023 : Demodulated samples receive (1024 bytes)\r | |
1021 | * 1024-1535 : Last Received command, 512 bytes (reader->tag)\r | |
1022 | * 1536-2047 : Last Received command, 512 bytes(tag->reader)\r | |
1023 | * 2048-2304 : DMA Buffer, 256 bytes (samples)\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) + 1024;\r | |
1034 | // The response (tag -> reader) that we're working on receiving.\r | |
1035 | BYTE *receivedResponse = (BYTE *)(BigBuf) + 1536;\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) + 2048;\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, 1024);\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 | // And put the FPGA in the appropriate mode\r | |
1068 | // Signal field is off with the appropriate LED\r | |
1069 | LED_D_OFF();\r | |
1070 | FpgaWriteConfWord(\r | |
1071 | FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r | |
1072 | FPGA_HF_READER_RX_XCORR_SNOOP);\r | |
1073 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r | |
1074 | \r | |
1075 | // Setup for the DMA.\r | |
1076 | FpgaSetupSsc();\r | |
1077 | upTo = dmaBuf;\r | |
1078 | lastRxCounter = DMA_BUFFER_SIZE;\r | |
1079 | FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r | |
1080 | // And now we loop, receiving samples.\r | |
1081 | for(;;) {\r | |
1082 | int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &\r | |
1083 | (DMA_BUFFER_SIZE-1);\r | |
1084 | if(behindBy > maxBehindBy) {\r | |
1085 | maxBehindBy = behindBy;\r | |
1086 | if(behindBy > (DMA_BUFFER_SIZE-2)) { // TODO: understand whether we can increase/decrease as we want or not?\r | |
1087 | DbpString("blew circular buffer!");\r | |
1088 | DbpIntegers(behindBy,0,0);\r | |
1089 | goto done;\r | |
1090 | }\r | |
1091 | }\r | |
1092 | if(behindBy < 2) continue;\r | |
1093 | \r | |
1094 | ci = upTo[0];\r | |
1095 | cq = upTo[1];\r | |
1096 | upTo += 2;\r | |
1097 | lastRxCounter -= 2;\r | |
1098 | if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r | |
1099 | upTo -= DMA_BUFFER_SIZE;\r | |
1100 | lastRxCounter += DMA_BUFFER_SIZE;\r | |
1101 | AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD) upTo;\r | |
1102 | AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;\r | |
1103 | }\r | |
1104 | \r | |
1105 | samples += 2;\r | |
1106 | \r | |
1107 | #define HANDLE_BIT_IF_BODY \\r | |
1108 | if(triggered) { \\r | |
1109 | trace[traceLen++] = ((samples >> 0) & 0xff); \\r | |
1110 | trace[traceLen++] = ((samples >> 8) & 0xff); \\r | |
1111 | trace[traceLen++] = ((samples >> 16) & 0xff); \\r | |
1112 | trace[traceLen++] = ((samples >> 24) & 0xff); \\r | |
1113 | trace[traceLen++] = 0; \\r | |
1114 | trace[traceLen++] = 0; \\r | |
1115 | trace[traceLen++] = 0; \\r | |
1116 | trace[traceLen++] = 0; \\r | |
1117 | trace[traceLen++] = Uart.byteCnt; \\r | |
1118 | memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \\r | |
1119 | traceLen += Uart.byteCnt; \\r | |
1120 | if(traceLen > 1000) break; \\r | |
1121 | } \\r | |
1122 | /* And ready to receive another command. */ \\r | |
1123 | memset(&Uart, 0, sizeof(Uart)); \\r | |
1124 | Uart.output = receivedCmd; \\r | |
1125 | Uart.byteCntMax = 100; \\r | |
1126 | Uart.state = STATE_UNSYNCD; \\r | |
1127 | /* And also reset the demod code, which might have been */ \\r | |
1128 | /* false-triggered by the commands from the reader. */ \\r | |
1129 | memset(&Demod, 0, sizeof(Demod)); \\r | |
1130 | Demod.output = receivedResponse; \\r | |
1131 | Demod.state = DEMOD_UNSYNCD; \\r | |
1132 | \r | |
1133 | if(Handle14443UartBit(ci & 1)) {\r | |
1134 | HANDLE_BIT_IF_BODY\r | |
1135 | }\r | |
1136 | if(Handle14443UartBit(cq & 1)) {\r | |
1137 | HANDLE_BIT_IF_BODY\r | |
1138 | }\r | |
1139 | \r | |
1140 | if(Handle14443SamplesDemod(ci, cq)) {\r | |
1141 | // timestamp, as a count of samples\r | |
1142 | trace[traceLen++] = ((samples >> 0) & 0xff);\r | |
1143 | trace[traceLen++] = ((samples >> 8) & 0xff);\r | |
1144 | trace[traceLen++] = ((samples >> 16) & 0xff);\r | |
1145 | trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff);\r | |
1146 | // correlation metric (~signal strength estimate)\r | |
1147 | if(Demod.metricN != 0) {\r | |
1148 | Demod.metric /= Demod.metricN;\r | |
1149 | }\r | |
1150 | trace[traceLen++] = ((Demod.metric >> 0) & 0xff);\r | |
1151 | trace[traceLen++] = ((Demod.metric >> 8) & 0xff);\r | |
1152 | trace[traceLen++] = ((Demod.metric >> 16) & 0xff);\r | |
1153 | trace[traceLen++] = ((Demod.metric >> 24) & 0xff);\r | |
1154 | // length\r | |
1155 | trace[traceLen++] = Demod.len;\r | |
1156 | memcpy(trace+traceLen, receivedResponse, Demod.len);\r | |
1157 | traceLen += Demod.len;\r | |
1158 | if(traceLen > 1000) break;\r | |
1159 | \r | |
1160 | triggered = TRUE;\r | |
1161 | \r | |
1162 | // And ready to receive another response.\r | |
1163 | memset(&Demod, 0, sizeof(Demod));\r | |
1164 | Demod.output = receivedResponse;\r | |
1165 | Demod.state = DEMOD_UNSYNCD;\r | |
1166 | }\r | |
1167 | WDT_HIT();\r | |
1168 | \r | |
1169 | if(BUTTON_PRESS()) {\r | |
1170 | DbpString("cancelled");\r | |
1171 | goto done;\r | |
1172 | }\r | |
1173 | }\r | |
1174 | \r | |
1175 | DbpString("in done pt");\r | |
1176 | \r | |
1177 | DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt);\r | |
1178 | DbpIntegers(Uart.byteCntMax, traceLen, 0x23);\r | |
1179 | \r | |
1180 | done:\r | |
1181 | LED_D_OFF();\r | |
1182 | AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;\r | |
1183 | }\r |