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