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