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