]> git.zerfleddert.de Git - proxmark3-svn/blame - winsrc/command.cpp
em4x50read (work in progress)
[proxmark3-svn] / winsrc / command.cpp
CommitLineData
6658905f 1//-----------------------------------------------------------------------------\r
2// The actual command interpeter for what the user types at the command line.\r
3// Jonathan Westhues, Sept 2005\r
4// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
5//-----------------------------------------------------------------------------\r
6#include <windows.h>\r
7#include <stdlib.h>\r
8#include <string.h>\r
9#include <stdio.h>\r
10#include <limits.h>\r
11#include <math.h>\r
12\r
13#include "prox.h"\r
14#include "../common/iso14443_crc.c"\r
15\r
16#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
9760414b 17#define BIT(x) GraphBuffer[x * clock]\r
18#define BITS (GraphTraceLen / clock)\r
6658905f 19\r
9760414b 20int go = 0;\r
6658905f 21static int CmdHisamplest(char *str, int nrlow);\r
22\r
23static void GetFromBigBuf(BYTE *dest, int bytes)\r
24{\r
25 int n = bytes/4;\r
26\r
27 if(n % 48 != 0) {\r
28 PrintToScrollback("bad len in GetFromBigBuf");\r
29 return;\r
30 }\r
31\r
32 int i;\r
33 for(i = 0; i < n; i += 12) {\r
34 UsbCommand c;\r
35 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
36 c.ext1 = i;\r
37 SendCommand(&c, FALSE);\r
38 ReceiveCommand(&c);\r
39 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 40 PrintToScrollback("bad resp");\r
6658905f 41 return;\r
42 }\r
43\r
44 memcpy(dest+(i*4), c.d.asBytes, 48);\r
45 }\r
46}\r
47\r
d722c4ce 48static void CmdReset(char *str)\r
49{\r
50 UsbCommand c;\r
51 c.cmd = CMD_HARDWARE_RESET;\r
52 SendCommand(&c, FALSE);\r
53}\r
54\r
f23e056d 55static void CmdBuffClear(char *str)\r
56{\r
57 UsbCommand c;\r
58 c.cmd = CMD_BUFF_CLEAR;\r
59 SendCommand(&c, FALSE);\r
60 CmdClearGraph(TRUE);\r
61}\r
d722c4ce 62\r
6658905f 63static void CmdQuit(char *str)\r
64{\r
65 exit(0);\r
66}\r
67\r
68static void CmdHIDdemodFSK(char *str)\r
69{\r
70 UsbCommand c;\r
71 c.cmd = CMD_HID_DEMOD_FSK;\r
72 SendCommand(&c, FALSE);\r
73}\r
74\r
75static void CmdTune(char *str)\r
76{\r
77 UsbCommand c;\r
78 c.cmd = CMD_MEASURE_ANTENNA_TUNING;\r
79 SendCommand(&c, FALSE);\r
80}\r
81\r
82static void CmdHi15read(char *str)\r
83{\r
84 UsbCommand c;\r
85 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;\r
86 SendCommand(&c, FALSE);\r
87}\r
88\r
89static void CmdHi14read(char *str)\r
90{\r
91 UsbCommand c;\r
92 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
93 c.ext1 = atoi(str);\r
94 SendCommand(&c, FALSE);\r
95}\r
9760414b 96\r
97\r
98/* New command to read the contents of a SRI512 tag\r
99 * SRI512 tags are ISO14443-B modulated memory tags,\r
100 * this command just dumps the contents of the memory/\r
101 */\r
102static void CmdSri512read(char *str)\r
103{\r
fb25b483 104 UsbCommand c;\r
105 c.cmd = CMD_READ_SRI512_TAG;\r
106 c.ext1 = atoi(str);\r
9760414b 107 SendCommand(&c, FALSE);\r
108}\r
6658905f 109\r
110// ## New command\r
111static void CmdHi14areader(char *str)\r
112{\r
113 UsbCommand c;\r
114 c.cmd = CMD_READER_ISO_14443a;\r
115 c.ext1 = atoi(str);\r
116 SendCommand(&c, FALSE);\r
117}\r
118\r
119// ## New command\r
120static void CmdHi15reader(char *str)\r
121{\r
122 UsbCommand c;\r
123 c.cmd = CMD_READER_ISO_15693;\r
124 c.ext1 = atoi(str);\r
125 SendCommand(&c, FALSE);\r
126}\r
127\r
128// ## New command\r
129static void CmdHi15tag(char *str)\r
130{\r
131 UsbCommand c;\r
132 c.cmd = CMD_SIMTAG_ISO_15693;\r
133 c.ext1 = atoi(str);\r
134 SendCommand(&c, FALSE);\r
135}\r
136\r
137static void CmdHi14read_sim(char *str)\r
138{\r
139 UsbCommand c;\r
140 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM;\r
141 c.ext1 = atoi(str);\r
142 SendCommand(&c, FALSE);\r
143}\r
144\r
145static void CmdHi14readt(char *str)\r
146{\r
147 UsbCommand c;\r
148 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
149 c.ext1 = atoi(str);\r
150 SendCommand(&c, FALSE);\r
151\r
152 //CmdHisamplest(str);\r
153 while(CmdHisamplest(str,atoi(str))==0) {\r
154 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
155 c.ext1 = atoi(str);\r
156 SendCommand(&c, FALSE);\r
157 }\r
158 RepaintGraphWindow();\r
159}\r
160\r
161static void CmdHisimlisten(char *str)\r
162{\r
163 UsbCommand c;\r
164 c.cmd = CMD_SIMULATE_TAG_HF_LISTEN;\r
165 SendCommand(&c, FALSE);\r
166}\r
167\r
168static void CmdHi14sim(char *str)\r
169{\r
170 UsbCommand c;\r
171 c.cmd = CMD_SIMULATE_TAG_ISO_14443;\r
172 SendCommand(&c, FALSE);\r
173}\r
6658905f 174\r
175static void CmdHi14asim(char *str) // ## simulate iso14443a tag\r
176{ // ## greg - added ability to specify tag UID\r
177\r
178 unsigned int hi=0, lo=0;\r
179 int n=0, i=0;\r
180 UsbCommand c;\r
181\r
182 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
183 hi=(hi<<4)|(lo>>28);\r
184 lo=(lo<<4)|(n&0xf);\r
185 }\r
186\r
187 c.cmd = CMD_SIMULATE_TAG_ISO_14443a;\r
188 // c.ext should be set to *str or convert *str to the correct format for a uid\r
189 c.ext1 = hi;\r
190 c.ext2 = lo;\r
191 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi, lo);\r
192 SendCommand(&c, FALSE);\r
193}\r
194\r
195static void CmdHi14snoop(char *str)\r
196{\r
197 UsbCommand c;\r
198 c.cmd = CMD_SNOOP_ISO_14443;\r
199 SendCommand(&c, FALSE);\r
200}\r
201\r
202static void CmdHi14asnoop(char *str)\r
203{\r
204 UsbCommand c;\r
205 c.cmd = CMD_SNOOP_ISO_14443a;\r
206 SendCommand(&c, FALSE);\r
207}\r
208\r
209static void CmdFPGAOff(char *str) // ## FPGA Control\r
210{\r
211 UsbCommand c;\r
212 c.cmd = CMD_FPGA_MAJOR_MODE_OFF;\r
213 SendCommand(&c, FALSE);\r
214}\r
215\r
9760414b 216/* clear out our graph window */\r
217int CmdClearGraph(int redraw)\r
218{\r
219 int gtl = GraphTraceLen;\r
220 GraphTraceLen = 0;\r
15db5fb7 221\r
9760414b 222 if (redraw)\r
223 RepaintGraphWindow();\r
15db5fb7 224\r
9760414b 225 return gtl;\r
226}\r
227\r
228/* write a bit to the graph */\r
229static void CmdAppendGraph(int redraw, int clock, int bit)\r
6658905f 230{\r
231 int i;\r
232\r
9760414b 233 for (i = 0; i < (int)(clock/2); i++)\r
234 GraphBuffer[GraphTraceLen++] = bit ^ 1;\r
15db5fb7 235\r
236 for (i = (int)(clock/2); i < clock; i++)\r
9760414b 237 GraphBuffer[GraphTraceLen++] = bit;\r
238\r
239 if (redraw)\r
240 RepaintGraphWindow();\r
241}\r
242\r
243/* Function is equivalent of loread + losamples + em410xread\r
244 * looped until an EM410x tag is detected */\r
245static void CmdEM410xwatch(char *str)\r
246{\r
247 char *zero = "";\r
248 char *twok = "2000";\r
249 go = 1;\r
15db5fb7 250\r
9760414b 251 do\r
252 {\r
253 CmdLoread(zero);\r
254 CmdLosamples(twok);\r
255 CmdEM410xread(zero);\r
256 } while (go);\r
257}\r
258\r
955aa93f 259/* Read the transmitted data of an EM4x50 tag\r
260 * Format:\r
261 *\r
262 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
263 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
264 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
265 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
266 * CCCCCCCC <- column parity bits\r
267 * 0 <- stop bit\r
268 * LW <- Listen Window\r
269 *\r
270 * This pattern repeats for every block of data being transmitted.\r
271 * Transmission starts with two Listen Windows (LW - a modulated\r
272 * pattern of 320 cycles each (32/32/128/64/64)).\r
273 *\r
274 * Note that this data may or may not be the UID. It is whatever data\r
275 * is stored in the blocks defined in the control word First and Last \r
276 * Word Read values. UID is stored in block 32.\r
277 */ \r
278static void CmdEM4x50read(char *str)\r
279{\r
280 int i, j, startblock, clock, skip, block, start, end, low, high;\r
281 BOOL complete= FALSE;\r
282 int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];\r
283 char tmp[6];\r
284\r
285 high= low= 0;\r
286 clock= 64;\r
287\r
288 /* first get high and low values */\r
289 for (i = 0; i < GraphTraceLen; i++)\r
290 {\r
291 if (GraphBuffer[i] > high) \r
292 high = GraphBuffer[i];\r
293 else if (GraphBuffer[i] < low)\r
294 low = GraphBuffer[i];\r
295 }\r
296\r
297 /* populate a buffer with pulse lengths */\r
298 i= 0;\r
299 j= 0;\r
300 while(i < GraphTraceLen)\r
301 {\r
302 // measure from low to low\r
303 while(GraphBuffer[i] > low)\r
304 ++i;\r
305 start= i;\r
306 while(GraphBuffer[i] < high)\r
307 ++i;\r
308 while(GraphBuffer[i] > low)\r
309 ++i;\r
310 tmpbuff[j++]= i - start;\r
311 }\r
312\r
313 \r
314 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */\r
315 start= -1;\r
316 skip= 0;\r
317 for (i= 0; i < j - 4 ; ++i)\r
318 {\r
319 skip += tmpbuff[i];\r
320 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
321 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
322 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
323 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
324 {\r
325 start= i + 3;\r
326 break;\r
327 }\r
328 }\r
329 startblock= i + 3;\r
330\r
331 /* skip over the remainder of the LW */\r
332 skip += tmpbuff[i+1]+tmpbuff[i+2];\r
333 while(GraphBuffer[skip] > low)\r
334 ++skip;\r
335 skip += 8;\r
336\r
337 /* now do it again to find the end */\r
338 end= start;\r
339 for (i += 3; i < j - 4 ; ++i)\r
340 {\r
341 end += tmpbuff[i];\r
342 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
343 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
344 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
345 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
346 {\r
347 complete= TRUE;\r
348 break;\r
349 }\r
350 }\r
351\r
352 if (start >= 0)\r
353 PrintToScrollback("Found data at sample: %i",skip);\r
354 else\r
355 {\r
356 PrintToScrollback("No data found!");\r
357 PrintToScrollback("Try again with more samples.");\r
358 return;\r
359 }\r
360\r
361 if (!complete)\r
362 {\r
363 PrintToScrollback("*** Warning!");\r
364 PrintToScrollback("Partial data - no end found!");\r
365 PrintToScrollback("Try again with more samples.");\r
366 }\r
367\r
368 /* get rid of leading crap */\r
369 sprintf(tmp,"%i",skip);\r
370 CmdLtrim(tmp);\r
371\r
372 /* now work through remaining buffer printing out data blocks */\r
373 block= 0;\r
374 i= startblock;\r
375 while(block < 6)\r
376 {\r
377 PrintToScrollback("Block %i:", block);\r
378 // mandemod routine needs to be split so we can call it for data\r
379 // just print for now for debugging\r
380 Cmdmanchesterdemod("i 64");\r
381 skip= 0;\r
382 /* look for LW before start of next block */\r
383 for ( ; i < j - 4 ; ++i)\r
384 {\r
385 skip += tmpbuff[i];\r
386 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
387 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
388 break;\r
389 }\r
390 while(GraphBuffer[skip] > low)\r
391 ++skip;\r
392 skip += 8;\r
393 sprintf(tmp,"%i",skip);\r
394 CmdLtrim(tmp);\r
395 start += skip;\r
396 block++;\r
397 }\r
398}\r
399\r
400\r
9760414b 401/* Read the ID of an EM410x tag.\r
402 * Format:\r
403 * 1111 1111 1 <-- standard non-repeatable header\r
404 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
405 * ....\r
406 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column\r
407 * 0 <-- stop bit, end of tag\r
408 */\r
409static void CmdEM410xread(char *str)\r
410{\r
411 int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low;\r
412 int parity[4];\r
413 char id[11];\r
a91ff4c8 414 int retested = 0;\r
9760414b 415 int BitStream[MAX_GRAPH_TRACE_LEN];\r
416 high = low = 0;\r
15db5fb7 417\r
9760414b 418 /* Detect high and lows and clock */\r
419 for (i = 0; i < GraphTraceLen; i++)\r
420 {\r
421 if (GraphBuffer[i] > high)\r
422 high = GraphBuffer[i];\r
423 else if (GraphBuffer[i] < low)\r
424 low = GraphBuffer[i];\r
15db5fb7 425 }\r
426\r
9760414b 427 /* get clock */\r
428 clock = GetClock(str, high);\r
15db5fb7 429\r
9760414b 430 /* parity for our 4 columns */\r
431 parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
432 header = rows = 0;\r
15db5fb7 433\r
9760414b 434 /* manchester demodulate */\r
435 bit = bit2idx = 0;\r
436 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
437 {\r
438 hithigh = 0;\r
439 hitlow = 0;\r
440 first = 1;\r
15db5fb7 441\r
9760414b 442 /* Find out if we hit both high and low peaks */\r
443 for (j = 0; j < clock; j++)\r
444 {\r
445 if (GraphBuffer[(i * clock) + j] == high)\r
446 hithigh = 1;\r
447 else if (GraphBuffer[(i * clock) + j] == low)\r
448 hitlow = 1;\r
15db5fb7 449\r
9760414b 450 /* it doesn't count if it's the first part of our read\r
451 because it's really just trailing from the last sequence */\r
452 if (first && (hithigh || hitlow))\r
453 hithigh = hitlow = 0;\r
454 else\r
455 first = 0;\r
15db5fb7 456\r
9760414b 457 if (hithigh && hitlow)\r
458 break;\r
459 }\r
a91ff4c8 460 \r
9760414b 461 /* If we didn't hit both high and low peaks, we had a bit transition */\r
462 if (!hithigh || !hitlow)\r
463 bit ^= 1;\r
a91ff4c8 464 \r
9760414b 465 BitStream[bit2idx++] = bit;\r
466 }\r
a91ff4c8 467 \r
468retest:\r
9760414b 469 /* We go till 5 before the graph ends because we'll get that far below */\r
470 for (i = 1; i < bit2idx - 5; i++)\r
471 {\r
472 /* Step 2: We have our header but need our tag ID */\r
473 if (header == 9 && rows < 10)\r
474 {\r
475 /* Confirm parity is correct */\r
476 if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4])\r
477 {\r
478 /* Read another byte! */\r
479 sprintf(id+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3]));\r
480 rows++;\r
15db5fb7 481\r
9760414b 482 /* Keep parity info */\r
483 parity[0] ^= BitStream[i];\r
484 parity[1] ^= BitStream[i+1];\r
485 parity[2] ^= BitStream[i+2];\r
486 parity[3] ^= BitStream[i+3];\r
15db5fb7 487\r
9760414b 488 /* Move 4 bits ahead */\r
489 i += 4;\r
490 }\r
15db5fb7 491\r
9760414b 492 /* Damn, something wrong! reset */\r
493 else\r
494 {\r
495 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i);\r
15db5fb7 496\r
9760414b 497 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */\r
498 i -= 9 + (5 * rows) - 5;\r
499\r
500 rows = header = 0;\r
501 }\r
502 }\r
15db5fb7 503\r
9760414b 504 /* Step 3: Got our 40 bits! confirm column parity */\r
505 else if (rows == 10)\r
506 {\r
507 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */\r
508 if (BitStream[i] == parity[0] && BitStream[i+1] == parity[1] &&\r
509 BitStream[i+2] == parity[2] && BitStream[i+3] == parity[3] &&\r
510 BitStream[i+4] == 0)\r
511 {\r
512 /* Sweet! */\r
513 PrintToScrollback("EM410x Tag ID: %s", id);\r
15db5fb7 514\r
9760414b 515 /* Stop any loops */\r
516 go = 0;\r
a91ff4c8 517 return;\r
9760414b 518 }\r
15db5fb7 519\r
9760414b 520 /* Crap! Incorrect parity or no stop bit, start all over */\r
521 else\r
522 {\r
523 rows = header = 0;\r
15db5fb7 524\r
9760414b 525 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */\r
526 i -= 59;\r
527 }\r
528 }\r
15db5fb7 529\r
9760414b 530 /* Step 1: get our header */\r
531 else if (header < 9)\r
532 {\r
533 /* Need 9 consecutive 1's */\r
534 if (BitStream[i] == 1)\r
535 header++;\r
15db5fb7 536\r
9760414b 537 /* We don't have a header, not enough consecutive 1 bits */\r
538 else\r
539 header = 0;\r
540 }\r
541 }\r
a91ff4c8 542 \r
543 /* if we've already retested after flipping bits, return */\r
544 if (retested++)\r
545 return;\r
546\r
547 /* if this didn't work, try flipping bits */\r
548 for (i = 0; i < bit2idx; i++)\r
549 BitStream[i] ^= 1;\r
550\r
551 goto retest;\r
9760414b 552}\r
553\r
554/* emulate an EM410X tag\r
555 * Format:\r
556 * 1111 1111 1 <-- standard non-repeatable header\r
557 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
558 * ....\r
559 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column\r
560 * 0 <-- stop bit, end of tag\r
561 */\r
562static void CmdEM410xsim(char *str)\r
563{\r
564 int i, n, j, h, binary[4], parity[4];\r
565 char *s = "0";\r
15db5fb7 566\r
9760414b 567 /* clock is 64 in EM410x tags */\r
568 int clock = 64;\r
15db5fb7 569\r
9760414b 570 /* clear our graph */\r
571 CmdClearGraph(0);\r
15db5fb7 572\r
9760414b 573 /* write it out a few times */\r
574 for (h = 0; h < 4; h++)\r
575 {\r
576 /* write 9 start bits */\r
577 for (i = 0; i < 9; i++)\r
578 CmdAppendGraph(0, clock, 1);\r
15db5fb7 579\r
9760414b 580 /* for each hex char */\r
581 parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
582 for (i = 0; i < 10; i++)\r
583 {\r
584 /* read each hex char */\r
585 sscanf(&str[i], "%1x", &n);\r
586 for (j = 3; j >= 0; j--, n/= 2)\r
587 binary[j] = n % 2;\r
15db5fb7 588\r
9760414b 589 /* append each bit */\r
590 CmdAppendGraph(0, clock, binary[0]);\r
591 CmdAppendGraph(0, clock, binary[1]);\r
592 CmdAppendGraph(0, clock, binary[2]);\r
593 CmdAppendGraph(0, clock, binary[3]);\r
15db5fb7 594\r
9760414b 595 /* append parity bit */\r
596 CmdAppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);\r
15db5fb7 597\r
9760414b 598 /* keep track of column parity */\r
599 parity[0] ^= binary[0];\r
600 parity[1] ^= binary[1];\r
601 parity[2] ^= binary[2];\r
602 parity[3] ^= binary[3];\r
603 }\r
15db5fb7 604\r
9760414b 605 /* parity columns */\r
606 CmdAppendGraph(0, clock, parity[0]);\r
607 CmdAppendGraph(0, clock, parity[1]);\r
608 CmdAppendGraph(0, clock, parity[2]);\r
609 CmdAppendGraph(0, clock, parity[3]);\r
15db5fb7 610\r
9760414b 611 /* stop bit */\r
612 CmdAppendGraph(0, clock, 0);\r
613 }\r
15db5fb7 614\r
9760414b 615 /* modulate that biatch */\r
616 Cmdmanchestermod(s);\r
15db5fb7 617\r
9760414b 618 /* booyah! */\r
619 RepaintGraphWindow();\r
620\r
621 CmdLosim(s);\r
622}\r
623\r
624static void ChkBitstream(char *str)\r
625{\r
626 int i;\r
15db5fb7 627\r
9760414b 628 /* convert to bitstream if necessary */\r
629 for (i = 0; i < (int)(GraphTraceLen / 2); i++)\r
630 {\r
631 if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)\r
632 {\r
633 Cmdbitstream(str);\r
634 break;\r
635 }\r
636 }\r
637}\r
638\r
639static void CmdLosim(char *str)\r
640{\r
641 int i;\r
642 char *zero = "0";\r
15db5fb7 643\r
9760414b 644 /* convert to bitstream if necessary */\r
645 ChkBitstream(str);\r
15db5fb7 646\r
9760414b 647 for (i = 0; i < GraphTraceLen; i += 48) {\r
6658905f 648 UsbCommand c;\r
649 int j;\r
650 for(j = 0; j < 48; j++) {\r
651 c.d.asBytes[j] = GraphBuffer[i+j];\r
652 }\r
653 c.cmd = CMD_DOWNLOADED_SIM_SAMPLES_125K;\r
654 c.ext1 = i;\r
655 SendCommand(&c, FALSE);\r
656 }\r
657\r
658 UsbCommand c;\r
659 c.cmd = CMD_SIMULATE_TAG_125K;\r
660 c.ext1 = GraphTraceLen;\r
661 SendCommand(&c, FALSE);\r
662}\r
663\r
664static void CmdLoread(char *str)\r
665{\r
666 UsbCommand c;\r
667 // 'h' means higher-low-frequency, 134 kHz\r
668 if(*str == 'h') {\r
669 c.ext1 = 1;\r
670 } else if (*str == '\0') {\r
671 c.ext1 = 0;\r
672 } else {\r
673 PrintToScrollback("use 'loread' or 'loread h'");\r
674 return;\r
675 }\r
676 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
677 SendCommand(&c, FALSE);\r
678}\r
679\r
959baa89 680/* send a command before reading */\r
681static void CmdLoCommandRead(char *str)\r
682{\r
683 static char dummy[3];\r
684\r
685 dummy[0]= ' ';\r
686 \r
687 UsbCommand c;\r
688 c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
689 sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, &c.d.asBytes,&dummy+1);\r
690 // in case they specified 'h'\r
691 strcpy(&c.d.asBytes + strlen(c.d.asBytes),dummy);\r
692 SendCommand(&c, FALSE);\r
693}\r
694\r
6658905f 695static void CmdLosamples(char *str)\r
696{\r
697 int cnt = 0;\r
698 int i;\r
699 int n;\r
700\r
701 n=atoi(str);\r
702 if (n==0) n=128;\r
703 if (n>16000) n=16000;\r
704\r
705 for(i = 0; i < n; i += 12) {\r
706 UsbCommand c;\r
707 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
708 c.ext1 = i;\r
709 SendCommand(&c, FALSE);\r
710 ReceiveCommand(&c);\r
711 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 712 if (!go)\r
713 PrintToScrollback("bad resp");\r
6658905f 714 return;\r
715 }\r
716 int j;\r
717 for(j = 0; j < 48; j++) {\r
718 GraphBuffer[cnt++] = ((int)c.d.asBytes[j]) - 128;\r
719 }\r
720 }\r
721 GraphTraceLen = n*4;\r
722 RepaintGraphWindow();\r
723}\r
724\r
725static void CmdBitsamples(char *str)\r
726{\r
727 int cnt = 0;\r
728 int i;\r
729 int n;\r
730\r
731 n = 3072;\r
732 for(i = 0; i < n; i += 12) {\r
733 UsbCommand c;\r
734 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
735 c.ext1 = i;\r
736 SendCommand(&c, FALSE);\r
737 ReceiveCommand(&c);\r
738 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 739 PrintToScrollback("bad resp");\r
6658905f 740 return;\r
741 }\r
742 int j, k;\r
743 for(j = 0; j < 48; j++) {\r
744 for(k = 0; k < 8; k++) {\r
745 if(c.d.asBytes[j] & (1 << (7 - k))) {\r
746 GraphBuffer[cnt++] = 1;\r
747 } else {\r
748 GraphBuffer[cnt++] = 0;\r
749 }\r
750 }\r
751 }\r
752 }\r
753 GraphTraceLen = cnt;\r
754 RepaintGraphWindow();\r
755}\r
756\r
757static void CmdHisamples(char *str)\r
758{\r
759 int cnt = 0;\r
760 int i;\r
761 int n;\r
762 n = 1000;\r
763 for(i = 0; i < n; i += 12) {\r
764 UsbCommand c;\r
765 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
766 c.ext1 = i;\r
767 SendCommand(&c, FALSE);\r
768 ReceiveCommand(&c);\r
769 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 770 PrintToScrollback("bad resp");\r
6658905f 771 return;\r
772 }\r
773 int j;\r
774 for(j = 0; j < 48; j++) {\r
775 GraphBuffer[cnt++] = (int)((BYTE)c.d.asBytes[j]);\r
776 }\r
777 }\r
778 GraphTraceLen = n*4;\r
779\r
780 RepaintGraphWindow();\r
781}\r
782\r
783\r
784static int CmdHisamplest(char *str, int nrlow)\r
785{\r
786 int cnt = 0;\r
787 int t1, t2;\r
788 int i;\r
789 int n;\r
790 int hasbeennull;\r
791 int show;\r
792\r
793\r
794 n = 1000;\r
795 hasbeennull = 0;\r
796 for(i = 0; i < n; i += 12) {\r
797 UsbCommand c;\r
798 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
799 c.ext1 = i;\r
800 SendCommand(&c, FALSE);\r
801 ReceiveCommand(&c);\r
802 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 803 PrintToScrollback("bad resp");\r
6658905f 804 return 0;\r
805 }\r
806 int j;\r
807 for(j = 0; j < 48; j++) {\r
808 t2 = (int)((BYTE)c.d.asBytes[j]);\r
809 if((t2 ^ 0xC0) & 0xC0) { hasbeennull++; }\r
810\r
811 show = 0;\r
812 switch(show) {\r
813 case 0:\r
814 // combined\r
815 t1 = (t2 & 0x80) ^ (t2 & 0x20);\r
816 t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x20);\r
817 break;\r
818\r
819 case 1:\r
820 // only reader\r
821 t1 = (t2 & 0x80);\r
822 t2 = ((t2 << 1) & 0x80);\r
823 break;\r
824\r
825 case 2:\r
826 // only tag\r
827 t1 = (t2 & 0x20);\r
828 t2 = ((t2 << 1) & 0x20);\r
829 break;\r
830\r
831 case 3:\r
832 // both, but tag with other algorithm\r
833 t1 = (t2 & 0x80) ^ (t2 & 0x08);\r
834 t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x08);\r
835 break;\r
836 }\r
837\r
838 GraphBuffer[cnt++] = t1;\r
839 GraphBuffer[cnt++] = t2;\r
840 }\r
841 }\r
842 GraphTraceLen = n*4;\r
843// 1130\r
844 if(hasbeennull>nrlow || nrlow==0) {\r
845 PrintToScrollback("hasbeennull=%d", hasbeennull);\r
846 return 1;\r
847 }\r
848 else {\r
849 return 0;\r
850 }\r
851}\r
852\r
853\r
854static void CmdHexsamples(char *str)\r
855{\r
856 int i;\r
857 int n;\r
858\r
859 if(atoi(str) == 0) {\r
860 n = 12;\r
861 } else {\r
862 n = atoi(str)/4;\r
863 }\r
864\r
865 for(i = 0; i < n; i += 12) {\r
866 UsbCommand c;\r
867 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
868 c.ext1 = i;\r
869 SendCommand(&c, FALSE);\r
870 ReceiveCommand(&c);\r
871 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 872 PrintToScrollback("bad resp");\r
6658905f 873 return;\r
874 }\r
875 int j;\r
876 for(j = 0; j < 48; j += 8) {\r
877 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",\r
878 c.d.asBytes[j+0],\r
879 c.d.asBytes[j+1],\r
880 c.d.asBytes[j+2],\r
881 c.d.asBytes[j+3],\r
882 c.d.asBytes[j+4],\r
883 c.d.asBytes[j+5],\r
884 c.d.asBytes[j+6],\r
885 c.d.asBytes[j+7],\r
886 c.d.asBytes[j+8]\r
887 );\r
888 }\r
889 }\r
890}\r
891\r
892static void CmdHisampless(char *str)\r
893{\r
894 int cnt = 0;\r
895 int i;\r
896 int n;\r
897\r
898 if(atoi(str) == 0) {\r
899 n = 1000;\r
900 } else {\r
901 n = atoi(str)/4;\r
902 }\r
903\r
904 for(i = 0; i < n; i += 12) {\r
905 UsbCommand c;\r
906 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
907 c.ext1 = i;\r
908 SendCommand(&c, FALSE);\r
909 ReceiveCommand(&c);\r
910 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 911 PrintToScrollback("bad resp");\r
6658905f 912 return;\r
913 }\r
914 int j;\r
915 for(j = 0; j < 48; j++) {\r
916 GraphBuffer[cnt++] = (int)((signed char)c.d.asBytes[j]);\r
917 }\r
918 }\r
919 GraphTraceLen = cnt;\r
920\r
921 RepaintGraphWindow();\r
922}\r
923\r
924static WORD Iso15693Crc(BYTE *v, int n)\r
925{\r
926 DWORD reg;\r
927 int i, j;\r
928\r
929 reg = 0xffff;\r
930 for(i = 0; i < n; i++) {\r
931 reg = reg ^ ((DWORD)v[i]);\r
932 for (j = 0; j < 8; j++) {\r
933 if (reg & 0x0001) {\r
934 reg = (reg >> 1) ^ 0x8408;\r
935 } else {\r
936 reg = (reg >> 1);\r
937 }\r
938 }\r
939 }\r
940\r
941 return (WORD)~reg;\r
942}\r
943\r
944static void CmdHi14bdemod(char *str)\r
945{\r
946 int i, j, iold;\r
947 int isum, qsum;\r
948 int outOfWeakAt;\r
949 BOOL negateI, negateQ;\r
950\r
951 BYTE data[256];\r
952 int dataLen=0;\r
953\r
954 // As received, the samples are pairs, correlations against I and Q\r
955 // square waves. So estimate angle of initial carrier (or just\r
956 // quadrant, actually), and then do the demod.\r
957\r
958 // First, estimate where the tag starts modulating.\r
959 for(i = 0; i < GraphTraceLen; i += 2) {\r
960 if(abs(GraphBuffer[i]) + abs(GraphBuffer[i+1]) > 40) {\r
961 break;\r
962 }\r
963 }\r
964 if(i >= GraphTraceLen) {\r
965 PrintToScrollback("too weak to sync");\r
966 return;\r
967 }\r
968 PrintToScrollback("out of weak at %d", i);\r
969 outOfWeakAt = i;\r
970\r
971 // Now, estimate the phase in the initial modulation of the tag\r
972 isum = 0;\r
973 qsum = 0;\r
974 for(; i < (outOfWeakAt + 16); i += 2) {\r
975 isum += GraphBuffer[i+0];\r
976 qsum += GraphBuffer[i+1];\r
977 }\r
978 negateI = (isum < 0);\r
979 negateQ = (qsum < 0);\r
980\r
981 // Turn the correlation pairs into soft decisions on the bit.\r
982 j = 0;\r
983 for(i = 0; i < GraphTraceLen/2; i++) {\r
984 int si = GraphBuffer[j];\r
985 int sq = GraphBuffer[j+1];\r
986 if(negateI) si = -si;\r
987 if(negateQ) sq = -sq;\r
988 GraphBuffer[i] = si + sq;\r
989 j += 2;\r
990 }\r
991 GraphTraceLen = i;\r
992\r
993 i = outOfWeakAt/2;\r
994 while(GraphBuffer[i] > 0 && i < GraphTraceLen)\r
995 i++;\r
996 if(i >= GraphTraceLen) goto demodError;\r
997\r
998 iold = i;\r
999 while(GraphBuffer[i] < 0 && i < GraphTraceLen)\r
1000 i++;\r
1001 if(i >= GraphTraceLen) goto demodError;\r
1002 if((i - iold) > 23) goto demodError;\r
1003\r
1004 PrintToScrollback("make it to demod loop");\r
1005\r
1006 for(;;) {\r
1007 iold = i;\r
1008 while(GraphBuffer[i] >= 0 && i < GraphTraceLen)\r
1009 i++;\r
1010 if(i >= GraphTraceLen) goto demodError;\r
1011 if((i - iold) > 6) goto demodError;\r
1012\r
1013 WORD shiftReg = 0;\r
1014 if(i + 20 >= GraphTraceLen) goto demodError;\r
1015\r
1016 for(j = 0; j < 10; j++) {\r
1017 int soft = GraphBuffer[i] + GraphBuffer[i+1];\r
1018\r
1019 if(abs(soft) < ((abs(isum) + abs(qsum))/20)) {\r
1020 PrintToScrollback("weak bit");\r
1021 }\r
1022\r
1023 shiftReg >>= 1;\r
1024 if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {\r
1025 shiftReg |= 0x200;\r
1026 }\r
1027\r
1028 i+= 2;\r
1029 }\r
1030\r
1031 if( (shiftReg & 0x200) &&\r
1032 !(shiftReg & 0x001))\r
1033 {\r
1034 // valid data byte, start and stop bits okay\r
1035 PrintToScrollback(" %02x", (shiftReg >> 1) & 0xff);\r
1036 data[dataLen++] = (shiftReg >> 1) & 0xff;\r
1037 if(dataLen >= sizeof(data)) {\r
1038 return;\r
1039 }\r
1040 } else if(shiftReg == 0x000) {\r
1041 // this is EOF\r
1042 break;\r
1043 } else {\r
1044 goto demodError;\r
1045 }\r
1046 }\r
1047\r
1048 BYTE first, second;\r
1049 ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);\r
1050 PrintToScrollback("CRC: %02x %02x (%s)\n", first, second,\r
1051 (first == data[dataLen-2] && second == data[dataLen-1]) ?\r
1052 "ok" : "****FAIL****");\r
1053\r
1054 RepaintGraphWindow();\r
1055 return;\r
1056\r
1057demodError:\r
1058 PrintToScrollback("demod error");\r
1059 RepaintGraphWindow();\r
1060}\r
1061\r
1062static void CmdHi14list(char *str)\r
1063{\r
1064 BYTE got[960];\r
1065 GetFromBigBuf(got, sizeof(got));\r
1066\r
1067 PrintToScrollback("recorded activity:");\r
1068 PrintToScrollback(" time :rssi: who bytes");\r
1069 PrintToScrollback("---------+----+----+-----------");\r
1070\r
1071 int i = 0;\r
1072 int prev = -1;\r
1073\r
1074 for(;;) {\r
1075 if(i >= 900) {\r
1076 break;\r
1077 }\r
1078\r
1079 BOOL isResponse;\r
1080 int timestamp = *((DWORD *)(got+i));\r
1081 if(timestamp & 0x80000000) {\r
1082 timestamp &= 0x7fffffff;\r
1083 isResponse = 1;\r
1084 } else {\r
1085 isResponse = 0;\r
1086 }\r
1087 int metric = *((DWORD *)(got+i+4));\r
1088\r
1089 int len = got[i+8];\r
1090\r
1091 if(len > 100) {\r
1092 break;\r
1093 }\r
1094 if(i + len >= 900) {\r
1095 break;\r
1096 }\r
1097\r
1098 BYTE *frame = (got+i+9);\r
1099\r
1100 char line[1000] = "";\r
1101 int j;\r
1102 for(j = 0; j < len; j++) {\r
1103 sprintf(line+(j*3), "%02x ", frame[j]);\r
1104 }\r
1105\r
1106 char *crc;\r
1107 if(len > 2) {\r
1108 BYTE b1, b2;\r
1109 ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2);\r
1110 if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
1111 crc = "**FAIL CRC**";\r
1112 } else {\r
1113 crc = "";\r
1114 }\r
1115 } else {\r
1116 crc = "(SHORT)";\r
1117 }\r
1118\r
1119 char metricString[100];\r
1120 if(isResponse) {\r
1121 sprintf(metricString, "%3d", metric);\r
1122 } else {\r
1123 strcpy(metricString, " ");\r
1124 }\r
1125\r
1126 PrintToScrollback(" +%7d: %s: %s %s %s",\r
1127 (prev < 0 ? 0 : timestamp - prev),\r
1128 metricString,\r
1129 (isResponse ? "TAG" : " "), line, crc);\r
1130\r
1131 prev = timestamp;\r
1132 i += (len + 9);\r
1133 }\r
1134}\r
1135\r
1136static void CmdHi14alist(char *str)\r
1137{\r
1138 BYTE got[1920];\r
1139 GetFromBigBuf(got, sizeof(got));\r
1140\r
1141 PrintToScrollback("recorded activity:");\r
1142 PrintToScrollback(" ETU :rssi: who bytes");\r
1143 PrintToScrollback("---------+----+----+-----------");\r
1144\r
1145 int i = 0;\r
1146 int prev = -1;\r
1147\r
1148 for(;;) {\r
1149 if(i >= 1900) {\r
1150 break;\r
1151 }\r
1152\r
1153 BOOL isResponse;\r
1154 int timestamp = *((DWORD *)(got+i));\r
1155 if(timestamp & 0x80000000) {\r
1156 timestamp &= 0x7fffffff;\r
1157 isResponse = 1;\r
1158 } else {\r
1159 isResponse = 0;\r
1160 }\r
1161\r
1162 int metric = 0;\r
1163 int parityBits = *((DWORD *)(got+i+4));\r
1164 // 4 bytes of additional information...\r
1165 // maximum of 32 additional parity bit information\r
1166 //\r
1167 // TODO:\r
1168 // at each quarter bit period we can send power level (16 levels)\r
1169 // or each half bit period in 256 levels.\r
1170\r
1171\r
1172 int len = got[i+8];\r
1173\r
1174 if(len > 100) {\r
1175 break;\r
1176 }\r
1177 if(i + len >= 1900) {\r
1178 break;\r
1179 }\r
1180\r
1181 BYTE *frame = (got+i+9);\r
1182\r
1183 // Break and stick with current result if buffer was not completely full\r
1184 if(frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }\r
1185\r
1186 char line[1000] = "";\r
1187 int j;\r
1188 for(j = 0; j < len; j++) {\r
1189 int oddparity = 0x01;\r
1190 int k;\r
1191\r
1192 for(k=0;k<8;k++) {\r
1193 oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);\r
1194 }\r
1195\r
1196 //if((parityBits >> (len - j - 1)) & 0x01) {\r
1197 if(isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {\r
1198 sprintf(line+(j*4), "%02x! ", frame[j]);\r
1199 }\r
1200 else {\r
1201 sprintf(line+(j*4), "%02x ", frame[j]);\r
1202 }\r
1203 }\r
1204\r
1205 char *crc;\r
1206 crc = "";\r
1207 if(len > 2) {\r
1208 BYTE b1, b2;\r
1209 for(j = 0; j < (len - 1); j++) {\r
1210 // gives problems... search for the reason..\r
1211 /*if(frame[j] == 0xAA) {\r
1212 switch(frame[j+1]) {\r
1213 case 0x01:\r
1214 crc = "[1] Two drops close after each other";\r
1215 break;\r
1216 case 0x02:\r
1217 crc = "[2] Potential SOC with a drop in second half of bitperiod";\r
1218 break;\r
1219 case 0x03:\r
1220 crc = "[3] Segment Z after segment X is not possible";\r
1221 break;\r
1222 case 0x04:\r
1223 crc = "[4] Parity bit of a fully received byte was wrong";\r
1224 break;\r
1225 default:\r
1226 crc = "[?] Unknown error";\r
1227 break;\r
1228 }\r
1229 break;\r
1230 }*/\r
1231 }\r
1232\r
1233 if(strlen(crc)==0) {\r
1234 ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2);\r
1235 if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
1236 crc = (isResponse & (len < 6)) ? "" : " !crc";\r
1237 } else {\r
1238 crc = "";\r
1239 }\r
1240 }\r
1241 } else {\r
1242 crc = ""; // SHORT\r
1243 }\r
1244\r
1245 char metricString[100];\r
1246 if(isResponse) {\r
1247 sprintf(metricString, "%3d", metric);\r
1248 } else {\r
1249 strcpy(metricString, " ");\r
1250 }\r
1251\r
1252 PrintToScrollback(" +%7d: %s: %s %s %s",\r
1253 (prev < 0 ? 0 : (timestamp - prev)),\r
1254 metricString,\r
1255 (isResponse ? "TAG" : " "), line, crc);\r
1256\r
1257 prev = timestamp;\r
1258 i += (len + 9);\r
1259 }\r
1260 CommandFinished = 1;\r
1261}\r
1262\r
1263static void CmdHi15demod(char *str)\r
1264{\r
1265 // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
1266\r
0e25ae11 1267 // SOF defined as\r
6658905f 1268 // 1) Unmodulated time of 56.64us\r
1269 // 2) 24 pulses of 423.75khz\r
1270 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
1271\r
1272 static const int FrameSOF[] = {\r
1273 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1274 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1275 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1276 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1277 -1, -1, -1, -1,\r
1278 -1, -1, -1, -1,\r
1279 1, 1, 1, 1,\r
1280 1, 1, 1, 1\r
1281 };\r
1282 static const int Logic0[] = {\r
1283 1, 1, 1, 1,\r
1284 1, 1, 1, 1,\r
1285 -1, -1, -1, -1,\r
1286 -1, -1, -1, -1\r
1287 };\r
1288 static const int Logic1[] = {\r
1289 -1, -1, -1, -1,\r
1290 -1, -1, -1, -1,\r
1291 1, 1, 1, 1,\r
1292 1, 1, 1, 1\r
1293 };\r
1294\r
0e25ae11 1295 // EOF defined as\r
6658905f 1296 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
1297 // 2) 24 pulses of 423.75khz\r
1298 // 3) Unmodulated time of 56.64us\r
1299\r
1300 static const int FrameEOF[] = {\r
1301 1, 1, 1, 1,\r
1302 1, 1, 1, 1,\r
1303 -1, -1, -1, -1,\r
1304 -1, -1, -1, -1,\r
1305 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1306 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1307 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1308 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
1309 };\r
1310\r
1311 int i, j;\r
1312 int max = 0, maxPos;\r
1313\r
1314 int skip = 4;\r
1315\r
1316 if(GraphTraceLen < 1000) return;\r
1317\r
1318 // First, correlate for SOF\r
1319 for(i = 0; i < 100; i++) {\r
1320 int corr = 0;\r
1321 for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
1322 corr += FrameSOF[j]*GraphBuffer[i+(j/skip)];\r
1323 }\r
1324 if(corr > max) {\r
1325 max = corr;\r
1326 maxPos = i;\r
1327 }\r
1328 }\r
1329 PrintToScrollback("SOF at %d, correlation %d", maxPos,\r
1330 max/(arraylen(FrameSOF)/skip));\r
1331\r
1332 i = maxPos + arraylen(FrameSOF)/skip;\r
1333 int k = 0;\r
1334 BYTE outBuf[20];\r
1335 memset(outBuf, 0, sizeof(outBuf));\r
1336 BYTE mask = 0x01;\r
1337 for(;;) {\r
1338 int corr0 = 0, corr1 = 0, corrEOF = 0;\r
1339 for(j = 0; j < arraylen(Logic0); j += skip) {\r
1340 corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];\r
1341 }\r
1342 for(j = 0; j < arraylen(Logic1); j += skip) {\r
1343 corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];\r
1344 }\r
1345 for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
1346 corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];\r
1347 }\r
1348 // Even things out by the length of the target waveform.\r
1349 corr0 *= 4;\r
1350 corr1 *= 4;\r
1351\r
1352 if(corrEOF > corr1 && corrEOF > corr0) {\r
1353 PrintToScrollback("EOF at %d", i);\r
1354 break;\r
1355 } else if(corr1 > corr0) {\r
1356 i += arraylen(Logic1)/skip;\r
1357 outBuf[k] |= mask;\r
1358 } else {\r
1359 i += arraylen(Logic0)/skip;\r
1360 }\r
1361 mask <<= 1;\r
1362 if(mask == 0) {\r
1363 k++;\r
1364 mask = 0x01;\r
1365 }\r
1366 if((i+(int)arraylen(FrameEOF)) >= GraphTraceLen) {\r
1367 PrintToScrollback("ran off end!");\r
1368 break;\r
1369 }\r
1370 }\r
1371 if(mask != 0x01) {\r
1372 PrintToScrollback("error, uneven octet! (discard extra bits!)");\r
1373 PrintToScrollback(" mask=%02x", mask);\r
1374 }\r
1375 PrintToScrollback("%d octets", k);\r
1376\r
1377 for(i = 0; i < k; i++) {\r
1378 PrintToScrollback("# %2d: %02x ", i, outBuf[i]);\r
1379 }\r
1380 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
1381}\r
1382\r
1383static void CmdTiread(char *str)\r
1384{\r
1385 UsbCommand c;\r
1386 c.cmd = CMD_ACQUIRE_RAW_BITS_TI_TYPE;\r
1387 SendCommand(&c, FALSE);\r
1388}\r
1389\r
1390static void CmdTibits(char *str)\r
1391{\r
1392 int cnt = 0;\r
1393 int i;\r
1394 for(i = 0; i < 1536; i += 12) {\r
1395 UsbCommand c;\r
1396 c.cmd = CMD_DOWNLOAD_RAW_BITS_TI_TYPE;\r
1397 c.ext1 = i;\r
1398 SendCommand(&c, FALSE);\r
1399 ReceiveCommand(&c);\r
1400 if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {\r
9760414b 1401 PrintToScrollback("bad resp");\r
6658905f 1402 return;\r
1403 }\r
1404 int j;\r
1405 for(j = 0; j < 12; j++) {\r
1406 int k;\r
1407 for(k = 31; k >= 0; k--) {\r
1408 if(c.d.asDwords[j] & (1 << k)) {\r
1409 GraphBuffer[cnt++] = 1;\r
1410 } else {\r
1411 GraphBuffer[cnt++] = -1;\r
1412 }\r
1413 }\r
1414 }\r
1415 }\r
1416 GraphTraceLen = 1536*32;\r
1417 RepaintGraphWindow();\r
1418}\r
1419\r
1420static void CmdTidemod(char *cmdline)\r
1421{\r
1422 /* MATLAB as follows:\r
1423f_s = 2000000; % sampling frequency\r
1424f_l = 123200; % low FSK tone\r
1425f_h = 134200; % high FSK tone\r
1426\r
1427T_l = 119e-6; % low bit duration\r
1428T_h = 130e-6; % high bit duration\r
1429\r
1430l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);\r
1431h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);\r
1432\r
1433l = sign(sin(cumsum(l)));\r
1434h = sign(sin(cumsum(h)));\r
1435 */\r
1436 static const int LowTone[] = {\r
1437 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,\r
1438 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
1439 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,\r
1440 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
1441 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,\r
1442 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,\r
1443 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,\r
1444 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
1445 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,\r
1446 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,\r
1447 -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1448 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,\r
1449 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
1450 };\r
1451 static const int HighTone[] = {\r
1452 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
1453 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
1454 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1455 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,\r
1456 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
1457 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
1458 -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1459 -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1460 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
1461 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
1462 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1463 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,\r
1464 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
1465 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,\r
1466 };\r
1467\r
1468 int convLen = max(arraylen(HighTone), arraylen(LowTone));\r
1469\r
1470 int i;\r
1471 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
1472 int j;\r
1473 int lowSum = 0, highSum = 0;;\r
1474 int lowLen = arraylen(LowTone);\r
1475 int highLen = arraylen(HighTone);\r
1476\r
1477 for(j = 0; j < lowLen; j++) {\r
1478 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1479 }\r
1480 for(j = 0; j < highLen; j++) {\r
1481 highSum += HighTone[j]*GraphBuffer[i+j];\r
1482 }\r
1483 lowSum = abs((100*lowSum) / lowLen);\r
1484 highSum = abs((100*highSum) / highLen);\r
1485 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1486 }\r
1487\r
1488 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
1489 int j;\r
1490 int lowTot = 0, highTot = 0;\r
1491 // 16 and 15 are f_s divided by f_l and f_h, rounded\r
1492 for(j = 0; j < 16; j++) {\r
1493 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1494 }\r
1495 for(j = 0; j < 15; j++) {\r
1496 highTot += (GraphBuffer[i+j] >> 16);\r
1497 }\r
1498 GraphBuffer[i] = lowTot - highTot;\r
1499 }\r
1500\r
1501 GraphTraceLen -= (convLen + 16);\r
1502\r
1503 RepaintGraphWindow();\r
1504\r
1505 // Okay, so now we have unsliced soft decisions; find bit-sync, and then\r
1506 // get some bits.\r
1507\r
1508 int max = 0, maxPos = 0;\r
1509 for(i = 0; i < 6000; i++) {\r
1510 int j;\r
1511 int dec = 0;\r
1512 for(j = 0; j < 8*arraylen(LowTone); j++) {\r
1513 dec -= GraphBuffer[i+j];\r
1514 }\r
1515 for(; j < 8*arraylen(LowTone) + 8*arraylen(HighTone); j++) {\r
1516 dec += GraphBuffer[i+j];\r
1517 }\r
1518 if(dec > max) {\r
1519 max = dec;\r
1520 maxPos = i;\r
1521 }\r
1522 }\r
1523 GraphBuffer[maxPos] = 800;\r
1524 GraphBuffer[maxPos+1] = -800;\r
1525\r
1526 maxPos += 8*arraylen(LowTone);\r
1527 GraphBuffer[maxPos] = 800;\r
1528 GraphBuffer[maxPos+1] = -800;\r
1529 maxPos += 8*arraylen(HighTone);\r
1530\r
1531 GraphBuffer[maxPos] = 800;\r
1532 GraphBuffer[maxPos+1] = -800;\r
1533\r
1534 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
1535\r
1536 PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));\r
1537\r
1538 GraphBuffer[maxPos] = 800;\r
1539 GraphBuffer[maxPos+1] = -800;\r
1540\r
1541 BYTE bits[64+16+8+1];\r
1542 bits[sizeof(bits)-1] = '\0';\r
1543\r
1544 for(i = 0; i < arraylen(bits); i++) {\r
1545 int high = 0;\r
1546 int low = 0;\r
1547 int j;\r
1548 for(j = 0; j < arraylen(LowTone); j++) {\r
1549 low -= GraphBuffer[maxPos+j];\r
1550 }\r
1551 for(j = 0; j < arraylen(HighTone); j++) {\r
1552 high += GraphBuffer[maxPos+j];\r
1553 }\r
1554 if(high > low) {\r
1555 bits[i] = '1';\r
1556 maxPos += arraylen(HighTone);\r
1557 } else {\r
1558 bits[i] = '.';\r
1559 maxPos += arraylen(LowTone);\r
1560 }\r
1561 GraphBuffer[maxPos] = 800;\r
1562 GraphBuffer[maxPos+1] = -800;\r
1563 }\r
1564 PrintToScrollback("bits: '%s'", bits);\r
1565\r
1566 DWORD h = 0, l = 0;\r
1567 for(i = 0; i < 32; i++) {\r
1568 if(bits[i] == '1') {\r
1569 l |= (1<<i);\r
1570 }\r
1571 }\r
1572 for(i = 32; i < 64; i++) {\r
1573 if(bits[i] == '1') {\r
1574 h |= (1<<(i-32));\r
1575 }\r
1576 }\r
1577 PrintToScrollback("hex: %08x %08x", h, l);\r
1578}\r
1579\r
1580static void CmdNorm(char *str)\r
1581{\r
1582 int i;\r
1583 int max = INT_MIN, min = INT_MAX;\r
1584 for(i = 10; i < GraphTraceLen; i++) {\r
1585 if(GraphBuffer[i] > max) {\r
1586 max = GraphBuffer[i];\r
1587 }\r
1588 if(GraphBuffer[i] < min) {\r
1589 min = GraphBuffer[i];\r
1590 }\r
1591 }\r
1592 if(max != min) {\r
1593 for(i = 0; i < GraphTraceLen; i++) {\r
1594 GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/\r
1595 (max - min);\r
1596 }\r
1597 }\r
1598 RepaintGraphWindow();\r
1599}\r
1600\r
1601static void CmdDec(char *str)\r
1602{\r
1603 int i;\r
1604 for(i = 0; i < (GraphTraceLen/2); i++) {\r
1605 GraphBuffer[i] = GraphBuffer[i*2];\r
1606 }\r
1607 GraphTraceLen /= 2;\r
1608 PrintToScrollback("decimated by 2");\r
1609 RepaintGraphWindow();\r
1610}\r
1611\r
1612static void CmdHpf(char *str)\r
1613{\r
1614 int i;\r
1615 int accum = 0;\r
1616 for(i = 10; i < GraphTraceLen; i++) {\r
1617 accum += GraphBuffer[i];\r
1618 }\r
1619 accum /= (GraphTraceLen - 10);\r
1620 for(i = 0; i < GraphTraceLen; i++) {\r
1621 GraphBuffer[i] -= accum;\r
1622 }\r
1623\r
1624 RepaintGraphWindow();\r
1625}\r
1626\r
1627static void CmdZerocrossings(char *str)\r
1628{\r
1629 int i;\r
1630 // Zero-crossings aren't meaningful unless the signal is zero-mean.\r
1631 CmdHpf("");\r
1632\r
1633 int sign = 1;\r
1634 int zc = 0;\r
1635 int lastZc = 0;\r
1636 for(i = 0; i < GraphTraceLen; i++) {\r
1637 if(GraphBuffer[i]*sign >= 0) {\r
1638 // No change in sign, reproduce the previous sample count.\r
1639 zc++;\r
1640 GraphBuffer[i] = lastZc;\r
1641 } else {\r
1642 // Change in sign, reset the sample count.\r
1643 sign = -sign;\r
1644 GraphBuffer[i] = lastZc;\r
1645 if(sign > 0) {\r
1646 lastZc = zc;\r
1647 zc = 0;\r
1648 }\r
1649 }\r
1650 }\r
1651\r
1652 RepaintGraphWindow();\r
1653}\r
1654\r
1655static void CmdLtrim(char *str)\r
1656{\r
1657 int i;\r
1658 int ds = atoi(str);\r
1659\r
1660 for(i = ds; i < GraphTraceLen; i++) {\r
1661 GraphBuffer[i-ds] = GraphBuffer[i];\r
1662 }\r
1663 GraphTraceLen -= ds;\r
1664\r
1665 RepaintGraphWindow();\r
1666}\r
1667\r
1668static void CmdAutoCorr(char *str)\r
1669{\r
1670 static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];\r
1671\r
1672 int window = atoi(str);\r
1673\r
1674 if(window == 0) {\r
1675 PrintToScrollback("needs a window");\r
1676 return;\r
1677 }\r
1678\r
1679 if(window >= GraphTraceLen) {\r
1680 PrintToScrollback("window must be smaller than trace (%d samples)",\r
1681 GraphTraceLen);\r
1682 return;\r
1683 }\r
1684\r
1685 PrintToScrollback("performing %d correlations", GraphTraceLen - window);\r
1686\r
1687 int i;\r
1688 for(i = 0; i < GraphTraceLen - window; i++) {\r
1689 int sum = 0;\r
1690 int j;\r
1691 for(j = 0; j < window; j++) {\r
1692 sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;\r
1693 }\r
1694 CorrelBuffer[i] = sum;\r
1695 }\r
1696 GraphTraceLen = GraphTraceLen - window;\r
1697 memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));\r
1698\r
1699 RepaintGraphWindow();\r
1700}\r
1701\r
1702static void CmdVchdemod(char *str)\r
1703{\r
1704 // Is this the entire sync pattern, or does this also include some\r
1705 // data bits that happen to be the same everywhere? That would be\r
1706 // lovely to know.\r
1707 static const int SyncPattern[] = {\r
1708 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1709 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1710 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1711 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1712 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1713 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1714 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1715 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1716 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1717 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1718 };\r
1719\r
1720 // So first, we correlate for the sync pattern, and mark that.\r
1721 int bestCorrel = 0, bestPos = 0;\r
1722 int i;\r
1723 // It does us no good to find the sync pattern, with fewer than\r
1724 // 2048 samples after it...\r
1725 for(i = 0; i < (GraphTraceLen-2048); i++) {\r
1726 int sum = 0;\r
1727 int j;\r
1728 for(j = 0; j < arraylen(SyncPattern); j++) {\r
1729 sum += GraphBuffer[i+j]*SyncPattern[j];\r
1730 }\r
1731 if(sum > bestCorrel) {\r
1732 bestCorrel = sum;\r
1733 bestPos = i;\r
1734 }\r
1735 }\r
1736 PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);\r
1737\r
1738 char bits[257];\r
1739 bits[256] = '\0';\r
1740\r
1741 int worst = INT_MAX;\r
1742 int worstPos;\r
1743\r
1744 for(i = 0; i < 2048; i += 8) {\r
1745 int sum = 0;\r
1746 int j;\r
1747 for(j = 0; j < 8; j++) {\r
1748 sum += GraphBuffer[bestPos+i+j];\r
1749 }\r
1750 if(sum < 0) {\r
1751 bits[i/8] = '.';\r
1752 } else {\r
1753 bits[i/8] = '1';\r
1754 }\r
1755 if(abs(sum) < worst) {\r
1756 worst = abs(sum);\r
1757 worstPos = i;\r
1758 }\r
1759 }\r
1760 PrintToScrollback("bits:");\r
1761 PrintToScrollback("%s", bits);\r
1762 PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);\r
1763\r
1764 if(strcmp(str, "clone")==0) {\r
1765 GraphTraceLen = 0;\r
1766 char *s;\r
1767 for(s = bits; *s; s++) {\r
1768 int j;\r
1769 for(j = 0; j < 16; j++) {\r
1770 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;\r
1771 }\r
1772 }\r
1773 RepaintGraphWindow();\r
1774 }\r
1775}\r
1776\r
a60612db 1777static void CmdIndalademod(char *str)\r
1778{\r
1779 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID\r
1780\r
1781 int state = -1;\r
1782 int count = 0;\r
1783 int i, j;\r
1784 // worst case with GraphTraceLen=64000 is < 4096\r
1785 // under normal conditions it's < 2048\r
1786 BYTE rawbits[4096];\r
1787 int rawbit = 0;\r
1788 int worst = 0, worstPos = 0;\r
1789 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen/32);\r
1790 for(i = 0; i < GraphTraceLen-1; i += 2) {\r
1791 count+=1;\r
1792 if((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {\r
1793 if (state == 0) {\r
1794 for(j = 0; j < count - 8; j += 16) {\r
1795 rawbits[rawbit++] = 0;\r
1796 }\r
1797 if ((abs(count - j)) > worst) {\r
1798 worst = abs(count - j);\r
1799 worstPos = i;\r
1800 }\r
1801 }\r
1802 state = 1;\r
1803 count=0;\r
1804 } else if((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {\r
1805 if (state == 1) {\r
1806 for(j = 0; j < count - 8; j += 16) {\r
1807 rawbits[rawbit++] = 1;\r
1808 }\r
1809 if ((abs(count - j)) > worst) {\r
1810 worst = abs(count - j);\r
1811 worstPos = i;\r
1812 }\r
1813 }\r
1814 state = 0;\r
1815 count=0;\r
1816 }\r
1817 }\r
1818 PrintToScrollback("Recovered %d raw bits", rawbit);\r
1819 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);\r
1820\r
1821 // Finding the start of a UID\r
1822 int uidlen, long_wait;\r
1823 if(strcmp(str, "224") == 0) {\r
1824 uidlen=224;\r
1825 long_wait=30;\r
1826 } else {\r
1827 uidlen=64;\r
1828 long_wait=29;\r
1829 }\r
1830 int start;\r
1831 int first = 0;\r
1832 for(start = 0; start <= rawbit - uidlen; start++) {\r
1833 first = rawbits[start];\r
1834 for(i = start; i < start + long_wait; i++) {\r
1835 if(rawbits[i] != first) {\r
1836 break;\r
1837 }\r
1838 }\r
1839 if(i == (start + long_wait)) {\r
1840 break;\r
1841 }\r
1842 }\r
1843 if(start == rawbit - uidlen + 1) {\r
1844 PrintToScrollback("nothing to wait for");\r
1845 return;\r
1846 }\r
1847\r
1848 // Inverting signal if needed\r
1849 if(first == 1) {\r
1850 for(i = start; i < rawbit; i++) {\r
1851 rawbits[i] = !rawbits[i];\r
1852 }\r
1853 }\r
1854\r
1855 // Dumping UID\r
1856 BYTE bits[224];\r
1857 char showbits[225];\r
1858 showbits[uidlen]='\0';\r
1859 int bit;\r
1860 i = start;\r
1861 int times = 0;\r
1862 if(uidlen > rawbit) {\r
1863 PrintToScrollback("Warning: not enough raw bits to get a full UID");\r
1864 for(bit = 0; bit < rawbit; bit++) {\r
1865 bits[bit] = rawbits[i++];\r
1866 // As we cannot know the parity, let's use "." and "/"\r
1867 showbits[bit] = '.' + bits[bit];\r
1868 }\r
1869 showbits[bit+1]='\0';\r
1870 PrintToScrollback("Partial UID=%s", showbits);\r
1871 return;\r
1872 } else {\r
1873 for(bit = 0; bit < uidlen; bit++) {\r
1874 bits[bit] = rawbits[i++];\r
1875 showbits[bit] = '0' + bits[bit];\r
1876 }\r
1877 times = 1;\r
1878 }\r
1879 PrintToScrollback("UID=%s", showbits);\r
1880\r
1881 // Checking UID against next occurences\r
1882 for(; i + uidlen <= rawbit;) {\r
1883 int failed = 0;\r
1884 for(bit = 0; bit < uidlen; bit++) {\r
1885 if(bits[bit] != rawbits[i++]) {\r
1886 failed = 1;\r
1887 break;\r
1888 }\r
1889 }\r
1890 if (failed == 1) {\r
1891 break;\r
1892 }\r
1893 times += 1;\r
1894 }\r
1895 PrintToScrollback("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);\r
1896\r
1897 // Remodulating for tag cloning\r
1898 GraphTraceLen = 32*uidlen;\r
1899 i = 0;\r
1900 int phase = 0;\r
1901 for(bit = 0; bit < uidlen; bit++) {\r
1902 if(bits[bit] == 0) {\r
1903 phase = 0;\r
1904 } else {\r
1905 phase = 1;\r
1906 }\r
1907 int j;\r
1908 for(j = 0; j < 32; j++) {\r
1909 GraphBuffer[i++] = phase;\r
1910 phase = !phase;\r
1911 }\r
1912 }\r
1913\r
1914 RepaintGraphWindow();\r
1915}\r
1916\r
6658905f 1917static void CmdFlexdemod(char *str)\r
1918{\r
1919 int i;\r
1920 for(i = 0; i < GraphTraceLen; i++) {\r
1921 if(GraphBuffer[i] < 0) {\r
1922 GraphBuffer[i] = -1;\r
1923 } else {\r
1924 GraphBuffer[i] = 1;\r
1925 }\r
1926 }\r
1927\r
1928#define LONG_WAIT 100\r
1929 int start;\r
1930 for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {\r
1931 int first = GraphBuffer[start];\r
1932 for(i = start; i < start + LONG_WAIT; i++) {\r
1933 if(GraphBuffer[i] != first) {\r
1934 break;\r
1935 }\r
1936 }\r
1937 if(i == (start + LONG_WAIT)) {\r
1938 break;\r
1939 }\r
1940 }\r
1941 if(start == GraphTraceLen - LONG_WAIT) {\r
1942 PrintToScrollback("nothing to wait for");\r
1943 return;\r
1944 }\r
1945\r
1946 GraphBuffer[start] = 2;\r
1947 GraphBuffer[start+1] = -2;\r
1948\r
1949 BYTE bits[64];\r
1950\r
1951 int bit;\r
1952 i = start;\r
1953 for(bit = 0; bit < 64; bit++) {\r
1954 int j;\r
1955 int sum = 0;\r
1956 for(j = 0; j < 16; j++) {\r
1957 sum += GraphBuffer[i++];\r
1958 }\r
1959 if(sum > 0) {\r
1960 bits[bit] = 1;\r
1961 } else {\r
1962 bits[bit] = 0;\r
1963 }\r
1964 PrintToScrollback("bit %d sum %d", bit, sum);\r
1965 }\r
1966\r
1967 for(bit = 0; bit < 64; bit++) {\r
1968 int j;\r
1969 int sum = 0;\r
1970 for(j = 0; j < 16; j++) {\r
1971 sum += GraphBuffer[i++];\r
1972 }\r
1973 if(sum > 0 && bits[bit] != 1) {\r
1974 PrintToScrollback("oops1 at %d", bit);\r
1975 }\r
1976 if(sum < 0 && bits[bit] != 0) {\r
1977 PrintToScrollback("oops2 at %d", bit);\r
1978 }\r
1979 }\r
1980\r
1981 GraphTraceLen = 32*64;\r
1982 i = 0;\r
1983 int phase = 0;\r
1984 for(bit = 0; bit < 64; bit++) {\r
1985 if(bits[bit] == 0) {\r
1986 phase = 0;\r
1987 } else {\r
1988 phase = 1;\r
1989 }\r
1990 int j;\r
1991 for(j = 0; j < 32; j++) {\r
1992 GraphBuffer[i++] = phase;\r
1993 phase = !phase;\r
1994 }\r
1995 }\r
1996\r
1997 RepaintGraphWindow();\r
1998}\r
9760414b 1999\r
2000/*\r
15db5fb7 2001 * Generic command to demodulate ASK.\r
9760414b 2002 *\r
15db5fb7 2003 * Argument is convention: positive or negative (High mod means zero\r
9760414b 2004 * or high mod means one)\r
2005 *\r
2006 * Updates the Graph trace with 0/1 values\r
2007 *\r
2008 * Arguments:\r
9760414b 2009 * c : 0 or 1\r
2010 */\r
2011\r
2012static void Cmdaskdemod(char *str) {\r
2013 int i;\r
9760414b 2014 int n = 0;\r
15db5fb7 2015 int c,high,low = 0;\r
9760414b 2016\r
2017 // TODO: complain if we do not give 2 arguments here !\r
15db5fb7 2018 sscanf(str, "%i", &c);\r
2019\r
2020 /* Detect high and lows and clock */\r
2021 for (i = 0; i < GraphTraceLen; i++)\r
2022 {\r
2023 if (GraphBuffer[i] > high)\r
2024 high = GraphBuffer[i];\r
2025 else if (GraphBuffer[i] < low)\r
2026 low = GraphBuffer[i];\r
9760414b 2027 }\r
2028\r
15db5fb7 2029 if (GraphBuffer[0] > 0) {\r
2030 GraphBuffer[0] = 1-c;\r
9760414b 2031 } else {\r
15db5fb7 2032 GraphBuffer[0] = c;\r
9760414b 2033 }\r
2034 for(i=1;i<GraphTraceLen;i++) {\r
15db5fb7 2035 /* Transitions are detected at each peak\r
2036 * Transitions are either:\r
2037 * - we're low: transition if we hit a high\r
2038 * - we're high: transition if we hit a low\r
2039 * (we need to do it this way because some tags keep high or\r
2040 * low for long periods, others just reach the peak and go\r
a91ff4c8 2041 * down)\r
15db5fb7 2042 */\r
2043 if ((GraphBuffer[i]==high) && (GraphBuffer[i-1] == c)) {\r
2044 GraphBuffer[i]=1-c;\r
2045 } else if ((GraphBuffer[i]==low) && (GraphBuffer[i-1] == (1-c))){\r
2046 GraphBuffer[i] = c;\r
9760414b 2047 } else {\r
15db5fb7 2048 /* No transition */\r
9760414b 2049 GraphBuffer[i] = GraphBuffer[i-1];\r
2050 }\r
2051 }\r
2052 RepaintGraphWindow();\r
2053}\r
2054\r
2055/* Print our clock rate */\r
2056static void Cmddetectclockrate(char *str)\r
2057{\r
2058 int clock = detectclock(0);\r
2059 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2060}\r
2061\r
2062/*\r
2063 * Detect clock rate\r
2064 */\r
2065int detectclock(int peak)\r
2066{\r
2067 int i;\r
2068 int clock = 0xFFFF;\r
2069 int lastpeak = 0;\r
2070\r
2071 /* Detect peak if we don't have one */\r
2072 if (!peak)\r
2073 for (i = 0; i < GraphTraceLen; i++)\r
2074 if (GraphBuffer[i] > peak)\r
2075 peak = GraphBuffer[i];\r
2076\r
2077 for (i = 1; i < GraphTraceLen; i++)\r
2078 {\r
2079 /* If this is the beginning of a peak */\r
2080 if (GraphBuffer[i-1] != GraphBuffer[i] && GraphBuffer[i] == peak)\r
2081 {\r
2082 /* Find lowest difference between peaks */\r
2083 if (lastpeak && i - lastpeak < clock)\r
2084 {\r
2085 clock = i - lastpeak;\r
2086 }\r
2087 lastpeak = i;\r
2088 }\r
2089 }\r
15db5fb7 2090\r
9760414b 2091 return clock;\r
2092}\r
2093\r
2094/* Get or auto-detect clock rate */\r
2095int GetClock(char *str, int peak)\r
2096{\r
2097 int clock;\r
15db5fb7 2098\r
9760414b 2099 sscanf(str, "%i", &clock);\r
2100 if (!strcmp(str, ""))\r
2101 clock = 0;\r
2102\r
2103 /* Auto-detect clock */\r
2104 if (!clock)\r
2105 {\r
2106 clock = detectclock(peak);\r
15db5fb7 2107\r
9760414b 2108 /* Only print this message if we're not looping something */\r
2109 if (!go)\r
2110 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2111 }\r
15db5fb7 2112\r
9760414b 2113 return clock;\r
2114}\r
2115\r
2116/*\r
2117 * Convert to a bitstream\r
2118 */\r
2119static void Cmdbitstream(char *str) {\r
c9f99c01 2120 int i, j;\r
2121 int bit;\r
9760414b 2122 int gtl;\r
2123 int clock;\r
c9f99c01 2124 int low = 0;\r
2125 int high = 0;\r
2126 int hithigh, hitlow, first;\r
9760414b 2127\r
2128 /* Detect high and lows and clock */\r
2129 for (i = 0; i < GraphTraceLen; i++)\r
c9f99c01 2130 {\r
9760414b 2131 if (GraphBuffer[i] > high)\r
2132 high = GraphBuffer[i];\r
2133 else if (GraphBuffer[i] < low)\r
2134 low = GraphBuffer[i];\r
c9f99c01 2135 }\r
9760414b 2136\r
2137 /* Get our clock */\r
2138 clock = GetClock(str, high);\r
15db5fb7 2139\r
9760414b 2140 gtl = CmdClearGraph(0);\r
15db5fb7 2141\r
9760414b 2142 bit = 0;\r
2143 for (i = 0; i < (int)(gtl / clock); i++)\r
2144 {\r
2145 hithigh = 0;\r
2146 hitlow = 0;\r
2147 first = 1;\r
15db5fb7 2148\r
9760414b 2149 /* Find out if we hit both high and low peaks */\r
2150 for (j = 0; j < clock; j++)\r
2151 {\r
2152 if (GraphBuffer[(i * clock) + j] == high)\r
2153 hithigh = 1;\r
2154 else if (GraphBuffer[(i * clock) + j] == low)\r
2155 hitlow = 1;\r
15db5fb7 2156\r
9760414b 2157 /* it doesn't count if it's the first part of our read\r
2158 because it's really just trailing from the last sequence */\r
2159 if (first && (hithigh || hitlow))\r
2160 hithigh = hitlow = 0;\r
2161 else\r
2162 first = 0;\r
15db5fb7 2163\r
9760414b 2164 if (hithigh && hitlow)\r
2165 break;\r
2166 }\r
15db5fb7 2167\r
9760414b 2168 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2169 if (!hithigh || !hitlow)\r
2170 bit ^= 1;\r
2171\r
2172 CmdAppendGraph(0, clock, bit);\r
2173// for (j = 0; j < (int)(clock/2); j++)\r
2174// GraphBuffer[(i * clock) + j] = bit ^ 1;\r
2175// for (j = (int)(clock/2); j < clock; j++)\r
2176// GraphBuffer[(i * clock) + j] = bit;\r
2177 }\r
2178\r
2179 RepaintGraphWindow();\r
2180}\r
2181\r
2182/* Modulate our data into manchester */\r
2183static void Cmdmanchestermod(char *str)\r
2184{\r
2185 int i, j;\r
2186 int clock;\r
2187 int bit, lastbit, wave;\r
15db5fb7 2188\r
9760414b 2189 /* Get our clock */\r
2190 clock = GetClock(str, 0);\r
2191\r
2192 wave = 0;\r
2193 lastbit = 1;\r
2194 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
2195 {\r
2196 bit = GraphBuffer[i * clock] ^ 1;\r
15db5fb7 2197\r
9760414b 2198 for (j = 0; j < (int)(clock/2); j++)\r
2199 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave;\r
2200 for (j = (int)(clock/2); j < clock; j++)\r
2201 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1;\r
15db5fb7 2202\r
9760414b 2203 /* Keep track of how we start our wave and if we changed or not this time */\r
2204 wave ^= bit ^ lastbit;\r
2205 lastbit = bit;\r
2206 }\r
15db5fb7 2207\r
9760414b 2208 RepaintGraphWindow();\r
2209}\r
2210\r
2211/*\r
2212 * Manchester demodulate a bitstream. The bitstream needs to be already in\r
2213 * the GraphBuffer as 0 and 1 values\r
2214 *\r
2215 * Give the clock rate as argument in order to help the sync - the algorithm\r
2216 * resyncs at each pulse anyway.\r
2217 *\r
2218 * Not optimized by any means, this is the 1st time I'm writing this type of\r
2219 * routine, feel free to improve...\r
2220 *\r
2221 * 1st argument: clock rate (as number of samples per clock rate)\r
2222 * Typical values can be 64, 32, 128...\r
2223 */\r
2224static void Cmdmanchesterdemod(char *str) {\r
736aea60 2225 int i, j, invert= 0;\r
9760414b 2226 int bit;\r
2227 int clock;\r
2228 int lastval;\r
2229 int low = 0;\r
2230 int high = 0;\r
2231 int hithigh, hitlow, first;\r
2232 int lc = 0;\r
2233 int bitidx = 0;\r
2234 int bit2idx = 0;\r
2235 int warnings = 0;\r
2236\r
736aea60 2237 /* check if we're inverting output */\r
2238 if(*str == 'i')\r
2239 {\r
2240 PrintToScrollback("Inverting output");\r
2241 invert= 1;\r
2242 do\r
2243 ++str;\r
2244 while(*str == ' '); // in case a 2nd argument was given\r
2245 }\r
2246\r
9760414b 2247 /* Holds the decoded bitstream: each clock period contains 2 bits */\r
2248 /* later simplified to 1 bit after manchester decoding. */\r
2249 /* Add 10 bits to allow for noisy / uncertain traces without aborting */\r
2250 /* int BitStream[GraphTraceLen*2/clock+10]; */\r
2251\r
2252 /* But it does not work if compiling on WIndows: therefore we just allocate a */\r
2253 /* large array */\r
2254 int BitStream[MAX_GRAPH_TRACE_LEN];\r
2255\r
c9f99c01 2256 /* Detect high and lows */\r
2257 for (i = 0; i < GraphTraceLen; i++)\r
2258 {\r
2259 if (GraphBuffer[i] > high)\r
2260 high = GraphBuffer[i];\r
2261 else if (GraphBuffer[i] < low)\r
2262 low = GraphBuffer[i];\r
2263 }\r
2264\r
9760414b 2265 /* Get our clock */\r
2266 clock = GetClock(str, high);\r
15db5fb7 2267\r
9760414b 2268 int tolerance = clock/4;\r
15db5fb7 2269\r
9760414b 2270 /* Detect first transition */\r
2271 /* Lo-Hi (arbitrary) */\r
c9f99c01 2272 for (i = 0; i < GraphTraceLen; i++)\r
2273 {\r
2274 if (GraphBuffer[i] == low)\r
2275 {\r
9760414b 2276 lastval = i;\r
2277 break;\r
2278 }\r
2279 }\r
c9f99c01 2280\r
2281 /* If we're not working with 1/0s, demod based off clock */\r
2282 if (high != 1)\r
2283 {\r
15db5fb7 2284 bit = 0; /* We assume the 1st bit is zero, it may not be\r
2285 * the case: this routine (I think) has an init problem.\r
2286 * Ed.\r
2287 */\r
2288 for (; i < (int)(GraphTraceLen / clock); i++)\r
c9f99c01 2289 {\r
2290 hithigh = 0;\r
2291 hitlow = 0;\r
2292 first = 1;\r
2293\r
2294 /* Find out if we hit both high and low peaks */\r
2295 for (j = 0; j < clock; j++)\r
2296 {\r
2297 if (GraphBuffer[(i * clock) + j] == high)\r
2298 hithigh = 1;\r
2299 else if (GraphBuffer[(i * clock) + j] == low)\r
2300 hitlow = 1;\r
2301\r
2302 /* it doesn't count if it's the first part of our read\r
2303 because it's really just trailing from the last sequence */\r
2304 if (first && (hithigh || hitlow))\r
2305 hithigh = hitlow = 0;\r
2306 else\r
2307 first = 0;\r
2308\r
2309 if (hithigh && hitlow)\r
2310 break;\r
2311 }\r
2312\r
2313 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2314 if (!hithigh || !hitlow)\r
2315 bit ^= 1;\r
2316\r
736aea60 2317 BitStream[bit2idx++] = bit ^ invert;\r
c9f99c01 2318 }\r
2319 }\r
2320\r
2321 /* standard 1/0 bitstream */\r
2322 else\r
2323 {\r
9760414b 2324\r
736aea60 2325 /* Then detect duration between 2 successive transitions */\r
c9f99c01 2326 for (bitidx = 1; i < GraphTraceLen; i++)\r
2327 {\r
2328 if (GraphBuffer[i-1] != GraphBuffer[i])\r
2329 {\r
9760414b 2330 lc = i-lastval;\r
2331 lastval = i;\r
2332\r
2333 // Error check: if bitidx becomes too large, we do not\r
2334 // have a Manchester encoded bitstream or the clock is really\r
2335 // wrong!\r
2336 if (bitidx > (GraphTraceLen*2/clock+8) ) {\r
2337 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");\r
2338 return;\r
2339 }\r
2340 // Then switch depending on lc length:\r
2341 // Tolerance is 1/4 of clock rate (arbitrary)\r
2342 if (abs(lc-clock/2) < tolerance) {\r
2343 // Short pulse : either "1" or "0"\r
2344 BitStream[bitidx++]=GraphBuffer[i-1];\r
2345 } else if (abs(lc-clock) < tolerance) {\r
2346 // Long pulse: either "11" or "00"\r
2347 BitStream[bitidx++]=GraphBuffer[i-1];\r
2348 BitStream[bitidx++]=GraphBuffer[i-1];\r
2349 } else {\r
2350 // Error\r
c9f99c01 2351 warnings++;\r
9760414b 2352 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");\r
2353 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");\r
c9f99c01 2354\r
2355 if (warnings > 100)\r
2356 {\r
2357 PrintToScrollback("Error: too many detection errors, aborting.");\r
2358 return;\r
2359 }\r
736aea60 2360 }\r
9760414b 2361 }\r
2362 }\r
9760414b 2363\r
736aea60 2364 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream\r
2365 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful\r
2366 // to stop output at the final bitidx2 value, not bitidx\r
2367 for (i = 0; i < bitidx; i += 2) {\r
2368 if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {\r
2369 BitStream[bit2idx++] = 1 ^ invert;\r
9760414b 2370 } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {\r
736aea60 2371 BitStream[bit2idx++] = 0 ^ invert;\r
9760414b 2372 } else {\r
2373 // We cannot end up in this state, this means we are unsynchronized,\r
2374 // move up 1 bit:\r
2375 i++;\r
c9f99c01 2376 warnings++;\r
9760414b 2377 PrintToScrollback("Unsynchronized, resync...");\r
2378 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");\r
c9f99c01 2379\r
2380 if (warnings > 100)\r
2381 {\r
2382 PrintToScrollback("Error: too many decode errors, aborting.");\r
2383 return;\r
2384 }\r
736aea60 2385 }\r
2386 } \r
c9f99c01 2387 }\r
2388\r
2389 PrintToScrollback("Manchester decoded bitstream");\r
9760414b 2390 // Now output the bitstream to the scrollback by line of 16 bits\r
2391 for (i = 0; i < (bit2idx-16); i+=16) {\r
2392 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",\r
2393 BitStream[i],\r
2394 BitStream[i+1],\r
2395 BitStream[i+2],\r
2396 BitStream[i+3],\r
2397 BitStream[i+4],\r
2398 BitStream[i+5],\r
2399 BitStream[i+6],\r
2400 BitStream[i+7],\r
2401 BitStream[i+8],\r
2402 BitStream[i+9],\r
2403 BitStream[i+10],\r
2404 BitStream[i+11],\r
2405 BitStream[i+12],\r
2406 BitStream[i+13],\r
2407 BitStream[i+14],\r
2408 BitStream[i+15]);\r
2409 }\r
2410}\r
2411\r
2412\r
2413\r
2414/*\r
2415 * Usage ???\r
6658905f 2416 */\r
2417static void CmdHiddemod(char *str)\r
2418{\r
2419 if(GraphTraceLen < 4800) {\r
2420 PrintToScrollback("too short; need at least 4800 samples");\r
2421 return;\r
2422 }\r
2423\r
2424 GraphTraceLen = 4800;\r
2425 int i;\r
2426 for(i = 0; i < GraphTraceLen; i++) {\r
2427 if(GraphBuffer[i] < 0) {\r
2428 GraphBuffer[i] = 0;\r
2429 } else {\r
2430 GraphBuffer[i] = 1;\r
2431 }\r
2432 }\r
2433 RepaintGraphWindow();\r
2434}\r
2435\r
2436static void CmdPlot(char *str)\r
2437{\r
2438 ShowGraphWindow();\r
2439}\r
2440\r
2441static void CmdHide(char *str)\r
2442{\r
2443 HideGraphWindow();\r
2444}\r
2445\r
2446static void CmdScale(char *str)\r
2447{\r
2448 CursorScaleFactor = atoi(str);\r
2449 if(CursorScaleFactor == 0) {\r
2450 PrintToScrollback("bad, can't have zero scale");\r
2451 CursorScaleFactor = 1;\r
2452 }\r
2453 RepaintGraphWindow();\r
2454}\r
2455\r
2456static void CmdSave(char *str)\r
2457{\r
2458 FILE *f = fopen(str, "w");\r
2459 if(!f) {\r
2460 PrintToScrollback("couldn't open '%s'", str);\r
2461 return;\r
2462 }\r
2463 int i;\r
2464 for(i = 0; i < GraphTraceLen; i++) {\r
2465 fprintf(f, "%d\n", GraphBuffer[i]);\r
2466 }\r
2467 fclose(f);\r
2468 PrintToScrollback("saved to '%s'", str);\r
2469}\r
2470\r
2471static void CmdLoad(char *str)\r
2472{\r
2473 FILE *f = fopen(str, "r");\r
2474 if(!f) {\r
2475 PrintToScrollback("couldn't open '%s'", str);\r
2476 return;\r
2477 }\r
2478\r
2479 GraphTraceLen = 0;\r
2480 char line[80];\r
2481 while(fgets(line, sizeof(line), f)) {\r
2482 GraphBuffer[GraphTraceLen] = atoi(line);\r
2483 GraphTraceLen++;\r
2484 }\r
2485 fclose(f);\r
2486 PrintToScrollback("loaded %d samples", GraphTraceLen);\r
2487 RepaintGraphWindow();\r
2488}\r
2489\r
2490static void CmdHIDsimTAG(char *str)\r
2491{\r
2492 unsigned int hi=0, lo=0;\r
2493 int n=0, i=0;\r
2494 UsbCommand c;\r
2495\r
2496 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
2497 hi=(hi<<4)|(lo>>28);\r
2498 lo=(lo<<4)|(n&0xf);\r
2499 }\r
2500\r
2501 PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);\r
2502\r
2503 c.cmd = CMD_HID_SIM_TAG;\r
2504 c.ext1 = hi;\r
2505 c.ext2 = lo;\r
2506 SendCommand(&c, FALSE);\r
2507}\r
2508\r
2509static void CmdLcdReset(char *str)\r
2510{\r
2511 UsbCommand c;\r
2512 c.cmd = CMD_LCD_RESET;\r
2513 c.ext1 = atoi(str);\r
2514 SendCommand(&c, FALSE);\r
2515}\r
2516\r
2517static void CmdLcd(char *str)\r
2518{\r
2519 int i, j;\r
2520 UsbCommand c;\r
2521 c.cmd = CMD_LCD;\r
2522 sscanf(str, "%x %d", &i, &j);\r
2523 while (j--) {\r
2524 c.ext1 = i&0x1ff;\r
2525 SendCommand(&c, FALSE);\r
2526 }\r
2527}\r
2528\r
d722c4ce 2529\r
2530\r
6658905f 2531static void CmdTest(char *str)\r
2532{\r
2533}\r
9760414b 2534\r
2535/*\r
2536 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below\r
2537 * 600kHz.\r
2538 */\r
30f2a7d3 2539static void CmdSetDivisor(char *str)\r
2540{\r
2541 UsbCommand c;\r
2542 c.cmd = CMD_SET_LF_DIVISOR;\r
2543 c.ext1 = atoi(str);\r
2544 if (( c.ext1<0) || (c.ext1>255)) {\r
2545 PrintToScrollback("divisor must be between 19 and 255");\r
2546 } else {\r
2547 SendCommand(&c, FALSE);\r
2548 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c.ext1+1));\r
2549 }\r
2550}\r
2551\r
2552static void CmdSweepLF(char *str)\r
2553{\r
2554 UsbCommand c;\r
2555 c.cmd = CMD_SWEEP_LF;\r
2556 SendCommand(&c, FALSE);\r
2557}\r
9760414b 2558\r
2559\r
6658905f 2560typedef void HandlerFunction(char *cmdline);\r
2561\r
3f030abe 2562/* in alphabetic order */\r
6658905f 2563static struct {\r
fb25b483 2564 char *name;\r
2565 HandlerFunction *handler;\r
2566 int offline; // 1 if the command can be used when in offline mode\r
9760414b 2567 char *docString;\r
6658905f 2568} CommandTable[] = {\r
3f030abe 2569 "askdemod", Cmdaskdemod,1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags",\r
2570 "autocorr", CmdAutoCorr,1, "<window length> -- Autocorrelation over window",\r
2571 "bitsamples", CmdBitsamples,0, " Get raw samples as bitstring",\r
2572 "bitstream", Cmdbitstream,1, "[clock rate] -- Convert waveform into a bitstream",\r
f23e056d 2573 "buffclear", CmdBuffClear,0, " Clear sample buffer and graph window",\r
3f030abe 2574 "dec", CmdDec,1, " Decimate samples",\r
2575 "detectclock", Cmddetectclockrate,1, " Detect clock rate",\r
2576 "em410xsim", CmdEM410xsim,1, "<UID> -- Simulate EM410x tag",\r
2577 "em410xread", CmdEM410xread,1, "[clock rate] -- Extract ID from EM410x tag",\r
2578 "em410xwatch", CmdEM410xwatch,0, " Watches for EM410x tags",\r
955aa93f 2579 "em4x50read", CmdEM4x50read,1, " Extract data from EM4x50 tag",\r
3f030abe 2580 "exit", CmdQuit,1, " Exit program",\r
2581 "flexdemod", CmdFlexdemod,1, " Demodulate samples for FlexPass",\r
2582 "fpgaoff", CmdFPGAOff,0, " Set FPGA off", // ## FPGA Control\r
2583 "hexsamples", CmdHexsamples,0, "<blocks> -- Dump big buffer as hex bytes",\r
2584 "hi14alist", CmdHi14alist,0, " List ISO 14443a history", // ## New list command\r
2585 "hi14areader", CmdHi14areader,0, " Act like an ISO14443 Type A reader", // ## New reader command\r
2586 "hi14asim", CmdHi14asim,0, "<UID> -- Fake ISO 14443a tag", // ## Simulate 14443a tag\r
2587 "hi14asnoop", CmdHi14asnoop,0, " Eavesdrop ISO 14443 Type A", // ## New snoop command\r
2588 "hi14bdemod", CmdHi14bdemod,1, " Demodulate ISO14443 Type B from tag",\r
2589 "hi14list", CmdHi14list,0, " List ISO 14443 history",\r
2590 "hi14read", CmdHi14read,0, " Read HF tag (ISO 14443)",\r
2591 "hi14sim", CmdHi14sim,0, " Fake ISO 14443 tag",\r
2592 "hi14snoop", CmdHi14snoop,0, " Eavesdrop ISO 14443",\r
2593 "hi15demod", CmdHi15demod,1, " Demodulate ISO15693 from tag",\r
2594 "hi15read", CmdHi15read,0, " Read HF tag (ISO 15693)",\r
2595 "hi15reader", CmdHi15reader,0, " Act like an ISO15693 reader", // new command greg\r
2596 "hi15sim", CmdHi15tag,0, " Fake an ISO15693 tag", // new command greg\r
2597 "hiddemod", CmdHiddemod,1, " Demodulate HID Prox Card II (not optimal)",\r
2598 "hide", CmdHide,1, " Hide graph window",\r
2599 "hidfskdemod", CmdHIDdemodFSK,0, " Realtime HID FSK demodulator",\r
2600 "hidsimtag", CmdHIDsimTAG,0, "<ID> -- HID tag simulator",\r
2601 "higet", CmdHi14read_sim,0, "<samples> -- Get samples HF, 'analog'",\r
2602 "hisamples", CmdHisamples,0, " Get raw samples for HF tag",\r
2603 "hisampless", CmdHisampless,0, "<samples> -- Get signed raw samples, HF tag",\r
2604 "hisamplest", CmdHi14readt,0, " Get samples HF, for testing",\r
2605 "hisimlisten", CmdHisimlisten,0, " Get HF samples as fake tag",\r
2606 "hpf", CmdHpf,1, " Remove DC offset from trace",\r
736aea60 2607 "indalademod", CmdIndalademod,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)",\r
3f030abe 2608 "lcd", CmdLcd,0, "<HEX command> <count> -- Send command/data to LCD",\r
2609 "lcdreset", CmdLcdReset,0, " Hardware reset LCD",\r
2610 "load", CmdLoad,1, "<filename> -- Load trace (to graph window",\r
1de3416e 2611 "locomread", CmdLoCommandRead,0, "<off period> <'0' period> <'1' period> <command> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)",\r
3f030abe 2612 "loread", CmdLoread,0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)",\r
2613 "losamples", CmdLosamples,0, "[128 - 16000] -- Get raw samples for LF tag",\r
2614 "losim", CmdLosim,0, " Simulate LF tag",\r
2615 "ltrim", CmdLtrim,1, "<samples> -- Trim samples from left of trace",\r
736aea60 2616 "mandemod", Cmdmanchesterdemod,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)",\r
3f030abe 2617 "manmod", Cmdmanchestermod,1, "[clock rate] -- Manchester modulate a binary stream",\r
2618 "norm", CmdNorm,1, " Normalize max/min to +/-500",\r
2619 "plot", CmdPlot,1, " Show graph window",\r
2620 "quit", CmdQuit,1, " Quit program",\r
2621 "reset", CmdReset,0, " Reset the Proxmark3",\r
2622 "save", CmdSave,1, "<filename> -- Save trace (from graph window)",\r
2623 "scale", CmdScale,1, "<int> -- Set cursor display scale",\r
2624 "setlfdivisor", CmdSetDivisor,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)",\r
2625 "sri512read", CmdSri512read,0, "<int> -- Read contents of a SRI512 tag",\r
2626 "sweeplf", CmdSweepLF,0, " Sweep through LF freq range and store results in buffer",\r
2627 "tibits", CmdTibits,0, " Get raw bits for TI-type LF tag",\r
2628 "tidemod", CmdTidemod,0, " Demodulate raw bits for TI-type LF tag",\r
2629 "tiread", CmdTiread,0, " Read a TI-type 134 kHz tag",\r
2630 "tune", CmdTune,0, " Measure antenna tuning",\r
2631 "vchdemod", CmdVchdemod,0, "['clone'] -- Demodulate samples for VeriChip",\r
2632 "zerocrossings", CmdZerocrossings,1, " Count time between zero-crossings",\r
6658905f 2633};\r
2634\r
fb25b483 2635\r
6658905f 2636//-----------------------------------------------------------------------------\r
2637// Entry point into our code: called whenever the user types a command and\r
2638// then presses Enter, which the full command line that they typed.\r
2639//-----------------------------------------------------------------------------\r
2640void CommandReceived(char *cmd)\r
2641{\r
2642 int i;\r
2643\r
2644 PrintToScrollback("> %s", cmd);\r
2645\r
2646 if(strcmp(cmd, "help")==0) {\r
d722c4ce 2647 if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");\r
6658905f 2648 PrintToScrollback("\r\nAvailable commands:");\r
2649 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
d722c4ce 2650 if (offline && (CommandTable[i].offline==0)) continue;\r
6658905f 2651 char line[256];\r
2652 memset(line, ' ', sizeof(line));\r
2653 strcpy(line+2, CommandTable[i].name);\r
2654 line[strlen(line)] = ' ';\r
2655 sprintf(line+15, " -- %s", CommandTable[i].docString);\r
2656 PrintToScrollback("%s", line);\r
2657 }\r
2658 PrintToScrollback("");\r
2659 PrintToScrollback("and also: help, cls");\r
2660 return;\r
2661 }\r
2662\r
2663 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
2664 char *name = CommandTable[i].name;\r
2665 if(memcmp(cmd, name, strlen(name))==0 &&\r
2666 (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
2667 {\r
2668 cmd += strlen(name);\r
2669 while(*cmd == ' ') {\r
2670 cmd++;\r
2671 }\r
d722c4ce 2672 if (offline && (CommandTable[i].offline==0)) {\r
2673 PrintToScrollback("Offline mode, cannot use this command.");\r
2674 return;\r
2675 }\r
6658905f 2676 (CommandTable[i].handler)(cmd);\r
2677 return;\r
2678 }\r
2679 }\r
2680 PrintToScrollback(">> bad command '%s'", cmd);\r
2681}\r
2682\r
2683//-----------------------------------------------------------------------------\r
2684// Entry point into our code: called whenever we received a packet over USB\r
2685// that we weren't necessarily expecting, for example a debug print.\r
2686//-----------------------------------------------------------------------------\r
2687void UsbCommandReceived(UsbCommand *c)\r
2688{\r
2689 switch(c->cmd) {\r
2690 case CMD_DEBUG_PRINT_STRING: {\r
2691 char s[100];\r
2692 if(c->ext1 > 70 || c->ext1 < 0) {\r
2693 c->ext1 = 0;\r
2694 }\r
2695 memcpy(s, c->d.asBytes, c->ext1);\r
2696 s[c->ext1] = '\0';\r
2697 PrintToScrollback("#db# %s", s);\r
9760414b 2698 break;\r
6658905f 2699 }\r
2700\r
2701 case CMD_DEBUG_PRINT_INTEGERS:\r
2702 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
2703 break;\r
2704\r
2705 case CMD_MEASURED_ANTENNA_TUNING: {\r
2706 int zLf, zHf;\r
2707 int vLf125, vLf134, vHf;\r
2708 vLf125 = c->ext1 & 0xffff;\r
2709 vLf134 = c->ext1 >> 16;\r
2710 vHf = c->ext2;\r
2711 zLf = c->ext3 & 0xffff;\r
2712 zHf = c->ext3 >> 16;\r
2713 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",\r
2714 vLf125/zLf, vLf125, zLf);\r
2715 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",\r
2716 vLf134/((zLf*125)/134), vLf134, (zLf*125)/134);\r
2717 PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",\r
2718 vHf/zHf, vHf, zHf);\r
2719 break;\r
2720 }\r
2721 default:\r
2722 PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
2723 break;\r
2724 }\r
2725}\r
Impressum, Datenschutz