]> git.zerfleddert.de Git - proxmark3-svn/blame - winsrc/command.cpp
Added the new SRIX4K reading routine, thanks to jonor. Regression tested against...
[proxmark3-svn] / winsrc / command.cpp
CommitLineData
6658905f 1//-----------------------------------------------------------------------------\r
2// The actual command interpeter for what the user types at the command line.\r
3// Jonathan Westhues, Sept 2005\r
4// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
5//-----------------------------------------------------------------------------\r
6#include <windows.h>\r
7#include <stdlib.h>\r
8#include <string.h>\r
9#include <stdio.h>\r
10#include <limits.h>\r
11#include <math.h>\r
12\r
13#include "prox.h"\r
14#include "../common/iso14443_crc.c"\r
0c2ed92d 15#include "../common/crc16.c"\r
6658905f 16\r
17#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
9760414b 18#define BIT(x) GraphBuffer[x * clock]\r
19#define BITS (GraphTraceLen / clock)\r
6658905f 20\r
9760414b 21int go = 0;\r
6658905f 22static int CmdHisamplest(char *str, int nrlow);\r
23\r
24static void GetFromBigBuf(BYTE *dest, int bytes)\r
25{\r
26 int n = bytes/4;\r
27\r
28 if(n % 48 != 0) {\r
29 PrintToScrollback("bad len in GetFromBigBuf");\r
30 return;\r
31 }\r
32\r
33 int i;\r
34 for(i = 0; i < n; i += 12) {\r
35 UsbCommand c;\r
36 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
37 c.ext1 = i;\r
38 SendCommand(&c, FALSE);\r
39 ReceiveCommand(&c);\r
40 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 41 PrintToScrollback("bad resp");\r
6658905f 42 return;\r
43 }\r
44\r
45 memcpy(dest+(i*4), c.d.asBytes, 48);\r
46 }\r
47}\r
48\r
d722c4ce 49static void CmdReset(char *str)\r
50{\r
51 UsbCommand c;\r
52 c.cmd = CMD_HARDWARE_RESET;\r
53 SendCommand(&c, FALSE);\r
54}\r
55\r
f23e056d 56static void CmdBuffClear(char *str)\r
57{\r
58 UsbCommand c;\r
59 c.cmd = CMD_BUFF_CLEAR;\r
60 SendCommand(&c, FALSE);\r
61 CmdClearGraph(TRUE);\r
62}\r
d722c4ce 63\r
6658905f 64static void CmdQuit(char *str)\r
65{\r
66 exit(0);\r
67}\r
68\r
69static void CmdHIDdemodFSK(char *str)\r
70{\r
71 UsbCommand c;\r
72 c.cmd = CMD_HID_DEMOD_FSK;\r
73 SendCommand(&c, FALSE);\r
74}\r
75\r
76static void CmdTune(char *str)\r
77{\r
78 UsbCommand c;\r
79 c.cmd = CMD_MEASURE_ANTENNA_TUNING;\r
80 SendCommand(&c, FALSE);\r
81}\r
82\r
83static void CmdHi15read(char *str)\r
84{\r
85 UsbCommand c;\r
86 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;\r
87 SendCommand(&c, FALSE);\r
88}\r
89\r
90static void CmdHi14read(char *str)\r
91{\r
92 UsbCommand c;\r
93 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
94 c.ext1 = atoi(str);\r
95 SendCommand(&c, FALSE);\r
96}\r
9760414b 97\r
98\r
99/* New command to read the contents of a SRI512 tag\r
100 * SRI512 tags are ISO14443-B modulated memory tags,\r
101 * this command just dumps the contents of the memory/\r
102 */\r
103static void CmdSri512read(char *str)\r
104{\r
fb25b483 105 UsbCommand c;\r
106 c.cmd = CMD_READ_SRI512_TAG;\r
107 c.ext1 = atoi(str);\r
9760414b 108 SendCommand(&c, FALSE);\r
109}\r
c86cc308 110
111/* New command to read the contents of a SRIX4K tag
112 * SRIX4K tags are ISO14443-B modulated memory tags,
113 * this command just dumps the contents of the memory/
114 */
115static void CmdSrix4kread(char *str)
116{
117 UsbCommand c;
118 c.cmd = CMD_READ_SRIX4K_TAG;
119 c.ext1 = atoi(str);
120 SendCommand(&c, FALSE);
121}
122
123
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
130 c.ext1 = atoi(str);\r
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
139 c.ext1 = atoi(str);\r
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
148 c.ext1 = atoi(str);\r
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
156 c.ext1 = atoi(str);\r
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
164 c.ext1 = atoi(str);\r
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
170 c.ext1 = atoi(str);\r
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
204 c.ext1 = hi;\r
205 c.ext2 = lo;\r
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
684 c.ext1 = i;\r
685 SendCommand(&c, FALSE);\r
686 }\r
687\r
688 UsbCommand c;\r
689 c.cmd = CMD_SIMULATE_TAG_125K;\r
690 c.ext1 = GraphTraceLen;\r
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
698 c.ext1 = 47; /* Set ADC to twice the carrier for a slight supersampling */\r
699 c.ext2 = 384;\r
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
708 c.ext1 = 1;\r
709 } else if (*str == '\0') {\r
710 c.ext1 = 0;\r
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
724 c.ext1 = 1;\r
725 } else if (*str == 'h') {\r
726 c.ext1 = 2;\r
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
1dd23352 744 sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, (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
763 c.ext1 = i;\r
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
790 c.ext1 = i;\r
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
821 c.ext1 = i;\r
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
853 c.ext1 = i;\r
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
912\r
913 if(atoi(str) == 0) {\r
914 n = 12;\r
915 } else {\r
916 n = atoi(str)/4;\r
917 }\r
918\r
919 for(i = 0; i < n; i += 12) {\r
920 UsbCommand c;\r
921 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
922 c.ext1 = i;\r
923 SendCommand(&c, FALSE);\r
924 ReceiveCommand(&c);\r
925 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 926 PrintToScrollback("bad resp");\r
6658905f 927 return;\r
928 }\r
929 int j;\r
930 for(j = 0; j < 48; j += 8) {\r
931 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",\r
932 c.d.asBytes[j+0],\r
933 c.d.asBytes[j+1],\r
934 c.d.asBytes[j+2],\r
935 c.d.asBytes[j+3],\r
936 c.d.asBytes[j+4],\r
937 c.d.asBytes[j+5],\r
938 c.d.asBytes[j+6],\r
939 c.d.asBytes[j+7],\r
940 c.d.asBytes[j+8]\r
941 );\r
942 }\r
943 }\r
944}\r
945\r
946static void CmdHisampless(char *str)\r
947{\r
948 int cnt = 0;\r
949 int i;\r
950 int n;\r
951\r
952 if(atoi(str) == 0) {\r
953 n = 1000;\r
954 } else {\r
955 n = atoi(str)/4;\r
956 }\r
957\r
958 for(i = 0; i < n; i += 12) {\r
959 UsbCommand c;\r
960 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
961 c.ext1 = i;\r
962 SendCommand(&c, FALSE);\r
963 ReceiveCommand(&c);\r
964 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 965 PrintToScrollback("bad resp");\r
6658905f 966 return;\r
967 }\r
968 int j;\r
969 for(j = 0; j < 48; j++) {\r
970 GraphBuffer[cnt++] = (int)((signed char)c.d.asBytes[j]);\r
971 }\r
972 }\r
973 GraphTraceLen = cnt;\r
974\r
975 RepaintGraphWindow();\r
976}\r
977\r
978static WORD Iso15693Crc(BYTE *v, int n)\r
979{\r
980 DWORD reg;\r
981 int i, j;\r
982\r
983 reg = 0xffff;\r
984 for(i = 0; i < n; i++) {\r
985 reg = reg ^ ((DWORD)v[i]);\r
986 for (j = 0; j < 8; j++) {\r
987 if (reg & 0x0001) {\r
988 reg = (reg >> 1) ^ 0x8408;\r
989 } else {\r
990 reg = (reg >> 1);\r
991 }\r
992 }\r
993 }\r
994\r
995 return (WORD)~reg;\r
996}\r
997\r
998static void CmdHi14bdemod(char *str)\r
999{\r
1000 int i, j, iold;\r
1001 int isum, qsum;\r
1002 int outOfWeakAt;\r
1003 BOOL negateI, negateQ;\r
1004\r
1005 BYTE data[256];\r
1006 int dataLen=0;\r
1007\r
1008 // As received, the samples are pairs, correlations against I and Q\r
1009 // square waves. So estimate angle of initial carrier (or just\r
1010 // quadrant, actually), and then do the demod.\r
1011\r
1012 // First, estimate where the tag starts modulating.\r
1013 for(i = 0; i < GraphTraceLen; i += 2) {\r
1014 if(abs(GraphBuffer[i]) + abs(GraphBuffer[i+1]) > 40) {\r
1015 break;\r
1016 }\r
1017 }\r
1018 if(i >= GraphTraceLen) {\r
1019 PrintToScrollback("too weak to sync");\r
1020 return;\r
1021 }\r
1022 PrintToScrollback("out of weak at %d", i);\r
1023 outOfWeakAt = i;\r
1024\r
1025 // Now, estimate the phase in the initial modulation of the tag\r
1026 isum = 0;\r
1027 qsum = 0;\r
1028 for(; i < (outOfWeakAt + 16); i += 2) {\r
1029 isum += GraphBuffer[i+0];\r
1030 qsum += GraphBuffer[i+1];\r
1031 }\r
1032 negateI = (isum < 0);\r
1033 negateQ = (qsum < 0);\r
1034\r
1035 // Turn the correlation pairs into soft decisions on the bit.\r
1036 j = 0;\r
1037 for(i = 0; i < GraphTraceLen/2; i++) {\r
1038 int si = GraphBuffer[j];\r
1039 int sq = GraphBuffer[j+1];\r
1040 if(negateI) si = -si;\r
1041 if(negateQ) sq = -sq;\r
1042 GraphBuffer[i] = si + sq;\r
1043 j += 2;\r
1044 }\r
1045 GraphTraceLen = i;\r
1046\r
1047 i = outOfWeakAt/2;\r
1048 while(GraphBuffer[i] > 0 && i < GraphTraceLen)\r
1049 i++;\r
1050 if(i >= GraphTraceLen) goto demodError;\r
1051\r
1052 iold = i;\r
1053 while(GraphBuffer[i] < 0 && i < GraphTraceLen)\r
1054 i++;\r
1055 if(i >= GraphTraceLen) goto demodError;\r
1056 if((i - iold) > 23) goto demodError;\r
1057\r
1058 PrintToScrollback("make it to demod loop");\r
1059\r
1060 for(;;) {\r
1061 iold = i;\r
1062 while(GraphBuffer[i] >= 0 && i < GraphTraceLen)\r
1063 i++;\r
1064 if(i >= GraphTraceLen) goto demodError;\r
1065 if((i - iold) > 6) goto demodError;\r
1066\r
1067 WORD shiftReg = 0;\r
1068 if(i + 20 >= GraphTraceLen) goto demodError;\r
1069\r
1070 for(j = 0; j < 10; j++) {\r
1071 int soft = GraphBuffer[i] + GraphBuffer[i+1];\r
1072\r
1073 if(abs(soft) < ((abs(isum) + abs(qsum))/20)) {\r
1074 PrintToScrollback("weak bit");\r
1075 }\r
1076\r
1077 shiftReg >>= 1;\r
1078 if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {\r
1079 shiftReg |= 0x200;\r
1080 }\r
1081\r
1082 i+= 2;\r
1083 }\r
1084\r
1085 if( (shiftReg & 0x200) &&\r
1086 !(shiftReg & 0x001))\r
1087 {\r
1088 // valid data byte, start and stop bits okay\r
1089 PrintToScrollback(" %02x", (shiftReg >> 1) & 0xff);\r
1090 data[dataLen++] = (shiftReg >> 1) & 0xff;\r
1091 if(dataLen >= sizeof(data)) {\r
1092 return;\r
1093 }\r
1094 } else if(shiftReg == 0x000) {\r
1095 // this is EOF\r
1096 break;\r
1097 } else {\r
1098 goto demodError;\r
1099 }\r
1100 }\r
1101\r
1102 BYTE first, second;\r
1103 ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);\r
1104 PrintToScrollback("CRC: %02x %02x (%s)\n", first, second,\r
1105 (first == data[dataLen-2] && second == data[dataLen-1]) ?\r
1106 "ok" : "****FAIL****");\r
1107\r
1108 RepaintGraphWindow();\r
1109 return;\r
1110\r
1111demodError:\r
1112 PrintToScrollback("demod error");\r
1113 RepaintGraphWindow();\r
1114}\r
1115\r
1116static void CmdHi14list(char *str)\r
1117{\r
1118 BYTE got[960];\r
1119 GetFromBigBuf(got, sizeof(got));\r
1120\r
1121 PrintToScrollback("recorded activity:");\r
1122 PrintToScrollback(" time :rssi: who bytes");\r
1123 PrintToScrollback("---------+----+----+-----------");\r
1124\r
1125 int i = 0;\r
1126 int prev = -1;\r
1127\r
1128 for(;;) {\r
1129 if(i >= 900) {\r
1130 break;\r
1131 }\r
1132\r
1133 BOOL isResponse;\r
1134 int timestamp = *((DWORD *)(got+i));\r
1135 if(timestamp & 0x80000000) {\r
1136 timestamp &= 0x7fffffff;\r
1137 isResponse = 1;\r
1138 } else {\r
1139 isResponse = 0;\r
1140 }\r
1141 int metric = *((DWORD *)(got+i+4));\r
1142\r
1143 int len = got[i+8];\r
1144\r
1145 if(len > 100) {\r
1146 break;\r
1147 }\r
1148 if(i + len >= 900) {\r
1149 break;\r
1150 }\r
1151\r
1152 BYTE *frame = (got+i+9);\r
1153\r
1154 char line[1000] = "";\r
1155 int j;\r
1156 for(j = 0; j < len; j++) {\r
1157 sprintf(line+(j*3), "%02x ", frame[j]);\r
1158 }\r
1159\r
1160 char *crc;\r
1161 if(len > 2) {\r
1162 BYTE b1, b2;\r
1163 ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2);\r
1164 if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
1165 crc = "**FAIL CRC**";\r
1166 } else {\r
1167 crc = "";\r
1168 }\r
1169 } else {\r
1170 crc = "(SHORT)";\r
1171 }\r
1172\r
1173 char metricString[100];\r
1174 if(isResponse) {\r
1175 sprintf(metricString, "%3d", metric);\r
1176 } else {\r
1177 strcpy(metricString, " ");\r
1178 }\r
1179\r
1180 PrintToScrollback(" +%7d: %s: %s %s %s",\r
1181 (prev < 0 ? 0 : timestamp - prev),\r
1182 metricString,\r
1183 (isResponse ? "TAG" : " "), line, crc);\r
1184\r
1185 prev = timestamp;\r
1186 i += (len + 9);\r
1187 }\r
1188}\r
1189\r
1190static void CmdHi14alist(char *str)\r
1191{\r
1192 BYTE got[1920];\r
1193 GetFromBigBuf(got, sizeof(got));\r
1194\r
1195 PrintToScrollback("recorded activity:");\r
1196 PrintToScrollback(" ETU :rssi: who bytes");\r
1197 PrintToScrollback("---------+----+----+-----------");\r
1198\r
1199 int i = 0;\r
1200 int prev = -1;\r
1201\r
1202 for(;;) {\r
1203 if(i >= 1900) {\r
1204 break;\r
1205 }\r
1206\r
1207 BOOL isResponse;\r
1208 int timestamp = *((DWORD *)(got+i));\r
1209 if(timestamp & 0x80000000) {\r
1210 timestamp &= 0x7fffffff;\r
1211 isResponse = 1;\r
1212 } else {\r
1213 isResponse = 0;\r
1214 }\r
1215\r
1216 int metric = 0;\r
1217 int parityBits = *((DWORD *)(got+i+4));\r
1218 // 4 bytes of additional information...\r
1219 // maximum of 32 additional parity bit information\r
1220 //\r
1221 // TODO:\r
1222 // at each quarter bit period we can send power level (16 levels)\r
1223 // or each half bit period in 256 levels.\r
1224\r
1225\r
1226 int len = got[i+8];\r
1227\r
1228 if(len > 100) {\r
1229 break;\r
1230 }\r
1231 if(i + len >= 1900) {\r
1232 break;\r
1233 }\r
1234\r
1235 BYTE *frame = (got+i+9);\r
1236\r
1237 // Break and stick with current result if buffer was not completely full\r
1238 if(frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }\r
1239\r
1240 char line[1000] = "";\r
1241 int j;\r
1242 for(j = 0; j < len; j++) {\r
1243 int oddparity = 0x01;\r
1244 int k;\r
1245\r
1246 for(k=0;k<8;k++) {\r
1247 oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);\r
1248 }\r
1249\r
1250 //if((parityBits >> (len - j - 1)) & 0x01) {\r
1251 if(isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {\r
1252 sprintf(line+(j*4), "%02x! ", frame[j]);\r
1253 }\r
1254 else {\r
1255 sprintf(line+(j*4), "%02x ", frame[j]);\r
1256 }\r
1257 }\r
1258\r
1259 char *crc;\r
1260 crc = "";\r
1261 if(len > 2) {\r
1262 BYTE b1, b2;\r
1263 for(j = 0; j < (len - 1); j++) {\r
1264 // gives problems... search for the reason..\r
1265 /*if(frame[j] == 0xAA) {\r
1266 switch(frame[j+1]) {\r
1267 case 0x01:\r
1268 crc = "[1] Two drops close after each other";\r
1269 break;\r
1270 case 0x02:\r
1271 crc = "[2] Potential SOC with a drop in second half of bitperiod";\r
1272 break;\r
1273 case 0x03:\r
1274 crc = "[3] Segment Z after segment X is not possible";\r
1275 break;\r
1276 case 0x04:\r
1277 crc = "[4] Parity bit of a fully received byte was wrong";\r
1278 break;\r
1279 default:\r
1280 crc = "[?] Unknown error";\r
1281 break;\r
1282 }\r
1283 break;\r
1284 }*/\r
1285 }\r
1286\r
1287 if(strlen(crc)==0) {\r
1288 ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2);\r
1289 if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
1290 crc = (isResponse & (len < 6)) ? "" : " !crc";\r
1291 } else {\r
1292 crc = "";\r
1293 }\r
1294 }\r
1295 } else {\r
1296 crc = ""; // SHORT\r
1297 }\r
1298\r
1299 char metricString[100];\r
1300 if(isResponse) {\r
1301 sprintf(metricString, "%3d", metric);\r
1302 } else {\r
1303 strcpy(metricString, " ");\r
1304 }\r
1305\r
1306 PrintToScrollback(" +%7d: %s: %s %s %s",\r
1307 (prev < 0 ? 0 : (timestamp - prev)),\r
1308 metricString,\r
1309 (isResponse ? "TAG" : " "), line, crc);\r
1310\r
1311 prev = timestamp;\r
1312 i += (len + 9);\r
1313 }\r
1314 CommandFinished = 1;\r
1315}\r
1316\r
1317static void CmdHi15demod(char *str)\r
1318{\r
1319 // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
1320\r
0e25ae11 1321 // SOF defined as\r
6658905f 1322 // 1) Unmodulated time of 56.64us\r
1323 // 2) 24 pulses of 423.75khz\r
1324 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
1325\r
1326 static const int FrameSOF[] = {\r
1327 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1328 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1329 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1330 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1331 -1, -1, -1, -1,\r
1332 -1, -1, -1, -1,\r
1333 1, 1, 1, 1,\r
1334 1, 1, 1, 1\r
1335 };\r
1336 static const int Logic0[] = {\r
1337 1, 1, 1, 1,\r
1338 1, 1, 1, 1,\r
1339 -1, -1, -1, -1,\r
1340 -1, -1, -1, -1\r
1341 };\r
1342 static const int Logic1[] = {\r
1343 -1, -1, -1, -1,\r
1344 -1, -1, -1, -1,\r
1345 1, 1, 1, 1,\r
1346 1, 1, 1, 1\r
1347 };\r
1348\r
0e25ae11 1349 // EOF defined as\r
6658905f 1350 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
1351 // 2) 24 pulses of 423.75khz\r
1352 // 3) Unmodulated time of 56.64us\r
1353\r
1354 static const int FrameEOF[] = {\r
1355 1, 1, 1, 1,\r
1356 1, 1, 1, 1,\r
1357 -1, -1, -1, -1,\r
1358 -1, -1, -1, -1,\r
1359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1361 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1362 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
1363 };\r
1364\r
1365 int i, j;\r
1366 int max = 0, maxPos;\r
1367\r
1368 int skip = 4;\r
1369\r
1370 if(GraphTraceLen < 1000) return;\r
1371\r
1372 // First, correlate for SOF\r
1373 for(i = 0; i < 100; i++) {\r
1374 int corr = 0;\r
1375 for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
1376 corr += FrameSOF[j]*GraphBuffer[i+(j/skip)];\r
1377 }\r
1378 if(corr > max) {\r
1379 max = corr;\r
1380 maxPos = i;\r
1381 }\r
1382 }\r
1383 PrintToScrollback("SOF at %d, correlation %d", maxPos,\r
1384 max/(arraylen(FrameSOF)/skip));\r
1385\r
1386 i = maxPos + arraylen(FrameSOF)/skip;\r
1387 int k = 0;\r
1388 BYTE outBuf[20];\r
1389 memset(outBuf, 0, sizeof(outBuf));\r
1390 BYTE mask = 0x01;\r
1391 for(;;) {\r
1392 int corr0 = 0, corr1 = 0, corrEOF = 0;\r
1393 for(j = 0; j < arraylen(Logic0); j += skip) {\r
1394 corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];\r
1395 }\r
1396 for(j = 0; j < arraylen(Logic1); j += skip) {\r
1397 corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];\r
1398 }\r
1399 for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
1400 corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];\r
1401 }\r
1402 // Even things out by the length of the target waveform.\r
1403 corr0 *= 4;\r
1404 corr1 *= 4;\r
1405\r
1406 if(corrEOF > corr1 && corrEOF > corr0) {\r
1407 PrintToScrollback("EOF at %d", i);\r
1408 break;\r
1409 } else if(corr1 > corr0) {\r
1410 i += arraylen(Logic1)/skip;\r
1411 outBuf[k] |= mask;\r
1412 } else {\r
1413 i += arraylen(Logic0)/skip;\r
1414 }\r
1415 mask <<= 1;\r
1416 if(mask == 0) {\r
1417 k++;\r
1418 mask = 0x01;\r
1419 }\r
1420 if((i+(int)arraylen(FrameEOF)) >= GraphTraceLen) {\r
1421 PrintToScrollback("ran off end!");\r
1422 break;\r
1423 }\r
1424 }\r
1425 if(mask != 0x01) {\r
1426 PrintToScrollback("error, uneven octet! (discard extra bits!)");\r
1427 PrintToScrollback(" mask=%02x", mask);\r
1428 }\r
1429 PrintToScrollback("%d octets", k);\r
1430\r
1431 for(i = 0; i < k; i++) {\r
1432 PrintToScrollback("# %2d: %02x ", i, outBuf[i]);\r
1433 }\r
1434 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
1435}\r
1436\r
67853904 1437static void CmdFSKdemod(char *cmdline)\r
1438{\r
1439 static const int LowTone[] = {\r
1440 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1441 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1442 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1443 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1444 1, 1, 1, 1, 1, -1, -1, -1, -1, -1\r
1445 };\r
1446 static const int HighTone[] = {\r
1447 1, 1, 1, 1, 1, -1, -1, -1, -1,\r
1448 1, 1, 1, 1, -1, -1, -1, -1,\r
1449 1, 1, 1, 1, -1, -1, -1, -1,\r
1450 1, 1, 1, 1, -1, -1, -1, -1,\r
1451 1, 1, 1, 1, -1, -1, -1, -1,\r
1452 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1453 };\r
1454\r
7381e8f2 1455 int lowLen = sizeof(LowTone)/sizeof(int);\r
1456 int highLen = sizeof(HighTone)/sizeof(int);\r
1457 int convLen = (highLen>lowLen)?highLen:lowLen;\r
67853904 1458 DWORD hi = 0, lo = 0;\r
1459\r
1460 int i, j;\r
1461 int minMark=0, maxMark=0;\r
67853904 1462\r
1463 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
1464 int lowSum = 0, highSum = 0;\r
1465\r
1466 for(j = 0; j < lowLen; j++) {\r
1467 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1468 }\r
1469 for(j = 0; j < highLen; j++) {\r
1470 highSum += HighTone[j]*GraphBuffer[i+j];\r
1471 }\r
1472 lowSum = abs((100*lowSum) / lowLen);\r
1473 highSum = abs((100*highSum) / highLen);\r
1474 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1475 }\r
1476\r
1477 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
1478 int j;\r
1479 int lowTot = 0, highTot = 0;\r
1480 // 10 and 8 are f_s divided by f_l and f_h, rounded\r
1481 for(j = 0; j < 10; j++) {\r
1482 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1483 }\r
1484 for(j = 0; j < 8; j++) {\r
1485 highTot += (GraphBuffer[i+j] >> 16);\r
1486 }\r
1487 GraphBuffer[i] = lowTot - highTot;\r
1488 if (GraphBuffer[i]>maxMark) maxMark=GraphBuffer[i];\r
1489 if (GraphBuffer[i]<minMark) minMark=GraphBuffer[i];\r
1490 }\r
1491\r
1492 GraphTraceLen -= (convLen + 16);\r
1493\r
1494 RepaintGraphWindow();\r
1495\r
1496 // Find bit-sync (3 lo followed by 3 high)\r
1497 int max = 0, maxPos = 0;\r
1498 for(i = 0; i < 6000; i++) {\r
1499 int dec = 0;\r
7381e8f2 1500 for(j = 0; j < 3*lowLen; j++) {\r
67853904 1501 dec -= GraphBuffer[i+j];\r
1502 }\r
7381e8f2 1503 for(; j < 3*(lowLen + highLen ); j++) {\r
67853904 1504 dec += GraphBuffer[i+j];\r
1505 }\r
1506 if(dec > max) {\r
1507 max = dec;\r
1508 maxPos = i;\r
1509 }\r
1510 }\r
1511\r
1512 // place start of bit sync marker in graph\r
1513 GraphBuffer[maxPos] = maxMark;\r
1514 GraphBuffer[maxPos+1] = minMark;\r
1515\r
1516 maxPos += j;\r
1517\r
1518 // place end of bit sync marker in graph\r
1519 GraphBuffer[maxPos] = maxMark;\r
1520 GraphBuffer[maxPos+1] = minMark;\r
1521\r
1522 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
7381e8f2 1523 PrintToScrollback("length %d/%d", highLen, lowLen);\r
67853904 1524\r
1525 BYTE bits[46];\r
1526 bits[sizeof(bits)-1] = '\0';\r
1527\r
1528 // find bit pairs and manchester decode them\r
1529 for(i = 0; i < arraylen(bits)-1; i++) {\r
1530 int dec = 0;\r
7381e8f2 1531 for(j = 0; j < lowLen; j++) {\r
67853904 1532 dec -= GraphBuffer[maxPos+j];\r
1533 }\r
7381e8f2 1534 for(; j < lowLen + highLen; j++) {\r
67853904 1535 dec += GraphBuffer[maxPos+j];\r
1536 }\r
1537 maxPos += j;\r
1538 // place inter bit marker in graph\r
1539 GraphBuffer[maxPos] = maxMark;\r
1540 GraphBuffer[maxPos+1] = minMark;\r
1541\r
1542 // hi and lo form a 64 bit pair\r
1543 hi = (hi<<1)|(lo>>31);\r
1544 lo = (lo<<1);\r
1545 // store decoded bit as binary (in hi/lo) and text (in bits[])\r
1546 if(dec<0) {\r
1547 bits[i] = '1';\r
1548 lo|=1;\r
1549 } else {\r
1550 bits[i] = '0';\r
1551 }\r
1552 }\r
1553 PrintToScrollback("bits: '%s'", bits);\r
1554 PrintToScrollback("hex: %08x %08x", hi, lo);\r
1555}\r
1556\r
9bea179a 1557// read a TI tag and return its ID\r
1558static void CmdTIRead(char *str)\r
1559{\r
1560 UsbCommand c;\r
1561 c.cmd = CMD_READ_TI_TYPE;\r
1562 SendCommand(&c, FALSE);\r
1563}\r
1564\r
1565// write new data to a r/w TI tag\r
1566static void CmdTIWrite(char *str)\r
1567{\r
1568 UsbCommand c;\r
1569 int res=0;\r
1570\r
1571 c.cmd = CMD_WRITE_TI_TYPE;\r
1572 res = sscanf(str, "0x%x 0x%x 0x%x ", &c.ext1, &c.ext2, &c.ext3);\r
1573 if (res == 2) c.ext3=0;\r
1574 if (res<2)\r
7381e8f2 1575 PrintToScrollback("Please specify the data as two hex strings, optionally the CRC as a third");\r
3628c318 1576 else\r
9bea179a 1577 SendCommand(&c, FALSE);\r
1578}\r
1579\r
1580static void CmdTIDemod(char *cmdline)\r
6658905f 1581{\r
1582 /* MATLAB as follows:\r
1583f_s = 2000000; % sampling frequency\r
1584f_l = 123200; % low FSK tone\r
1585f_h = 134200; % high FSK tone\r
1586\r
1587T_l = 119e-6; % low bit duration\r
1588T_h = 130e-6; % high bit duration\r
1589\r
1590l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);\r
1591h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);\r
1592\r
1593l = sign(sin(cumsum(l)));\r
1594h = sign(sin(cumsum(h)));\r
1595 */\r
7381e8f2 1596\r
1597// 2M*16/134.2k = 238\r
67853904 1598 static const int LowTone[] = {\r
7381e8f2 1599 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1600 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1601 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1602 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1603 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1604 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1605 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1606 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
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\r
67853904 1614 };\r
7381e8f2 1615// 2M*16/123.2k = 260\r
67853904 1616 static const int HighTone[] = {\r
7381e8f2 1617 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1618 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1619 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1620 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, -1, -1, -1, -1, -1,\r
1622 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1623 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1624 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
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,\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, -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,\r
1634 1, 1, 1, 1, 1, 1, 1, 1\r
67853904 1635 };\r
7381e8f2 1636 int lowLen = sizeof(LowTone)/sizeof(int);\r
1637 int highLen = sizeof(HighTone)/sizeof(int);\r
1638 int convLen = (highLen>lowLen)?highLen:lowLen;\r
0c2ed92d 1639 WORD crc;\r
7381e8f2 1640 int i, j, TagType;\r
1641 int lowSum = 0, highSum = 0;;\r
1642 int lowTot = 0, highTot = 0;\r
1643\r
6658905f 1644 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
7381e8f2 1645 lowSum = 0;\r
1646 highSum = 0;;\r
6658905f 1647\r
1648 for(j = 0; j < lowLen; j++) {\r
1649 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1650 }\r
1651 for(j = 0; j < highLen; j++) {\r
1652 highSum += HighTone[j]*GraphBuffer[i+j];\r
1653 }\r
1654 lowSum = abs((100*lowSum) / lowLen);\r
1655 highSum = abs((100*highSum) / highLen);\r
7381e8f2 1656 lowSum = (lowSum<0)?-lowSum:lowSum;\r
1657 highSum = (highSum<0)?-highSum:highSum;\r
1658\r
6658905f 1659 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1660 }\r
1661\r
1662 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
7381e8f2 1663 lowTot = 0;\r
1664 highTot = 0;\r
6658905f 1665 // 16 and 15 are f_s divided by f_l and f_h, rounded\r
1666 for(j = 0; j < 16; j++) {\r
1667 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1668 }\r
1669 for(j = 0; j < 15; j++) {\r
1670 highTot += (GraphBuffer[i+j] >> 16);\r
1671 }\r
1672 GraphBuffer[i] = lowTot - highTot;\r
1673 }\r
1674\r
1675 GraphTraceLen -= (convLen + 16);\r
1676\r
1677 RepaintGraphWindow();\r
1678\r
0c2ed92d 1679 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,\r
1680 // 16 crc CCITT bits, 8 stop bits, 15 end bits\r
1681\r
1682 // the 16 prebits are always low\r
1683 // the 8 start and stop bits of a tag must match\r
1684 // the start/stop prebits of a ro tag are 01111110\r
1685 // the start/stop prebits of a rw tag are 11111110\r
1686 // the 15 end bits of a ro tag are all low\r
1687 // the 15 end bits of a rw tag match bits 15-1 of the data bits\r
6658905f 1688\r
0c2ed92d 1689 // Okay, so now we have unsliced soft decisions;\r
1690 // find bit-sync, and then get some bits.\r
1691 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)\r
6658905f 1692 int max = 0, maxPos = 0;\r
1693 for(i = 0; i < 6000; i++) {\r
1694 int j;\r
1695 int dec = 0;\r
0c2ed92d 1696 // searching 17 consecutive lows\r
7381e8f2 1697 for(j = 0; j < 17*lowLen; j++) {\r
6658905f 1698 dec -= GraphBuffer[i+j];\r
1699 }\r
0c2ed92d 1700 // searching 7 consecutive highs\r
7381e8f2 1701 for(; j < 17*lowLen + 6*highLen; j++) {\r
6658905f 1702 dec += GraphBuffer[i+j];\r
1703 }\r
1704 if(dec > max) {\r
1705 max = dec;\r
1706 maxPos = i;\r
1707 }\r
1708 }\r
6658905f 1709\r
0c2ed92d 1710 // place a marker in the buffer to visually aid location\r
1711 // of the start of sync\r
6658905f 1712 GraphBuffer[maxPos] = 800;\r
1713 GraphBuffer[maxPos+1] = -800;\r
6658905f 1714\r
0c2ed92d 1715 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)\r
7381e8f2 1716 maxPos += 17*lowLen;\r
1717 maxPos += 6*highLen;\r
0c2ed92d 1718\r
1719 // place a marker in the buffer to visually aid location\r
1720 // of the end of sync\r
6658905f 1721 GraphBuffer[maxPos] = 800;\r
1722 GraphBuffer[maxPos+1] = -800;\r
1723\r
1724 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
1725\r
7381e8f2 1726 PrintToScrollback("length %d/%d", highLen, lowLen);\r
6658905f 1727\r
0c2ed92d 1728 BYTE bits[1+64+16+8+16];\r
6658905f 1729 bits[sizeof(bits)-1] = '\0';\r
1730\r
0c2ed92d 1731 DWORD shift3 = 0x7e000000, shift2 = 0, shift1 = 0, shift0 = 0;\r
1732\r
1733 for(i = 0; i < arraylen(bits)-1; i++) {\r
6658905f 1734 int high = 0;\r
1735 int low = 0;\r
1736 int j;\r
7381e8f2 1737 for(j = 0; j < lowLen; j++) {\r
6658905f 1738 low -= GraphBuffer[maxPos+j];\r
1739 }\r
7381e8f2 1740 for(j = 0; j < highLen; j++) {\r
6658905f 1741 high += GraphBuffer[maxPos+j];\r
1742 }\r
0c2ed92d 1743\r
6658905f 1744 if(high > low) {\r
1745 bits[i] = '1';\r
7381e8f2 1746 maxPos += highLen;\r
0c2ed92d 1747 // bitstream arrives lsb first so shift right\r
1748 shift3 |= (1<<31);\r
6658905f 1749 } else {\r
1750 bits[i] = '.';\r
7381e8f2 1751 maxPos += lowLen;\r
6658905f 1752 }\r
0c2ed92d 1753\r
1754 // 128 bit right shift register\r
1755 shift0 = (shift0>>1) | (shift1 << 31);\r
1756 shift1 = (shift1>>1) | (shift2 << 31);\r
1757 shift2 = (shift2>>1) | (shift3 << 31);\r
1758 shift3 >>= 1;\r
1759\r
1760 // place a marker in the buffer between bits to visually aid location\r
6658905f 1761 GraphBuffer[maxPos] = 800;\r
1762 GraphBuffer[maxPos+1] = -800;\r
1763 }\r
0c2ed92d 1764 PrintToScrollback("Info: raw tag bits = %s", bits);\r
6658905f 1765\r
0c2ed92d 1766 TagType = (shift3>>8)&0xff;\r
1767 if ( TagType != ((shift0>>16)&0xff) ) {\r
1768 PrintToScrollback("Error: start and stop bits do not match!");\r
1769 return;\r
1770 }\r
1771 else if (TagType == 0x7e) {\r
1772 PrintToScrollback("Info: Readonly TI tag detected.");\r
1773 return;\r
6658905f 1774 }\r
0c2ed92d 1775 else if (TagType == 0xfe) {\r
1776 PrintToScrollback("Info: Rewriteable TI tag detected.");\r
1777\r
1778 // put 64 bit data into shift1 and shift0\r
1779 shift0 = (shift0>>24) | (shift1 << 8);\r
1780 shift1 = (shift1>>24) | (shift2 << 8);\r
1781\r
1782 // align 16 bit crc into lower half of shift2\r
1783 shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;\r
1784\r
1785 // align 16 bit "end bits" or "ident" into lower half of shift3\r
1786 shift3 >>= 16;\r
1787\r
9bea179a 1788 // only 15 bits compare, last bit of ident is not valid\r
1789 if ( (shift3^shift0)&0x7fff ) {\r
0c2ed92d 1790 PrintToScrollback("Error: Ident mismatch!");\r
1791 }\r
9bea179a 1792 // WARNING the order of the bytes in which we calc crc below needs checking\r
1793 // i'm 99% sure the crc algorithm is correct, but it may need to eat the\r
1794 // bytes in reverse or something\r
0c2ed92d 1795 // calculate CRC\r
1796 crc=0;\r
1797 crc = update_crc16(crc, (shift0)&0xff);\r
1798 crc = update_crc16(crc, (shift0>>8)&0xff);\r
1799 crc = update_crc16(crc, (shift0>>16)&0xff);\r
1800 crc = update_crc16(crc, (shift0>>24)&0xff);\r
1801 crc = update_crc16(crc, (shift1)&0xff);\r
1802 crc = update_crc16(crc, (shift1>>8)&0xff);\r
1803 crc = update_crc16(crc, (shift1>>16)&0xff);\r
1804 crc = update_crc16(crc, (shift1>>24)&0xff);\r
1805 PrintToScrollback("Info: Tag data = %08X%08X", shift1, shift0);\r
1806 if (crc != (shift2&0xffff)) {\r
1807 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc, shift2&0xffff);\r
1808 } else {\r
1809 PrintToScrollback("Info: CRC %04X is good", crc);\r
6658905f 1810 }\r
1811 }\r
0c2ed92d 1812 else {\r
1813 PrintToScrollback("Unknown tag type.");\r
1814 return;\r
1815 }\r
6658905f 1816}\r
1817\r
1818static void CmdNorm(char *str)\r
1819{\r
1820 int i;\r
1821 int max = INT_MIN, min = INT_MAX;\r
1822 for(i = 10; i < GraphTraceLen; i++) {\r
1823 if(GraphBuffer[i] > max) {\r
1824 max = GraphBuffer[i];\r
1825 }\r
1826 if(GraphBuffer[i] < min) {\r
1827 min = GraphBuffer[i];\r
1828 }\r
1829 }\r
1830 if(max != min) {\r
1831 for(i = 0; i < GraphTraceLen; i++) {\r
1832 GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/\r
1833 (max - min);\r
1834 }\r
1835 }\r
1836 RepaintGraphWindow();\r
1837}\r
1838\r
523f4c90 1839static void CmdAmp(char *str)\r
1840{\r
1841 int i, rising, falling;\r
1842 int max = INT_MIN, min = INT_MAX;\r
1843 for(i = 10; i < GraphTraceLen; i++) {\r
1844 if(GraphBuffer[i] > max) {\r
1845 max = GraphBuffer[i];\r
1846 }\r
1847 if(GraphBuffer[i] < min) {\r
1848 min = GraphBuffer[i];\r
1849 }\r
1850 }\r
1851 if(max != min) {\r
1852 rising= falling= 0;\r
1853 for(i = 0; i < GraphTraceLen; i++) {\r
1854 if(GraphBuffer[i+1] < GraphBuffer[i]) {\r
1855 if(rising) {\r
1856 GraphBuffer[i]= max;\r
1857 rising= 0;\r
1858 }\r
1859 falling= 1;\r
1860 }\r
1861 if(GraphBuffer[i+1] > GraphBuffer[i]) {\r
1862 if(falling) {\r
1863 GraphBuffer[i]= min;\r
1864 falling= 0;\r
1865 }\r
1866 rising= 1;\r
1867 }\r
1868 }\r
1869 }\r
1870 RepaintGraphWindow();\r
1871}\r
1872\r
6658905f 1873static void CmdDec(char *str)\r
1874{\r
1875 int i;\r
1876 for(i = 0; i < (GraphTraceLen/2); i++) {\r
1877 GraphBuffer[i] = GraphBuffer[i*2];\r
1878 }\r
1879 GraphTraceLen /= 2;\r
1880 PrintToScrollback("decimated by 2");\r
1881 RepaintGraphWindow();\r
1882}\r
1883\r
1884static void CmdHpf(char *str)\r
1885{\r
1886 int i;\r
1887 int accum = 0;\r
1888 for(i = 10; i < GraphTraceLen; i++) {\r
1889 accum += GraphBuffer[i];\r
1890 }\r
1891 accum /= (GraphTraceLen - 10);\r
1892 for(i = 0; i < GraphTraceLen; i++) {\r
1893 GraphBuffer[i] -= accum;\r
1894 }\r
1895\r
1896 RepaintGraphWindow();\r
1897}\r
1898\r
1899static void CmdZerocrossings(char *str)\r
1900{\r
1901 int i;\r
1902 // Zero-crossings aren't meaningful unless the signal is zero-mean.\r
1903 CmdHpf("");\r
1904\r
1905 int sign = 1;\r
1906 int zc = 0;\r
1907 int lastZc = 0;\r
1908 for(i = 0; i < GraphTraceLen; i++) {\r
1909 if(GraphBuffer[i]*sign >= 0) {\r
1910 // No change in sign, reproduce the previous sample count.\r
1911 zc++;\r
1912 GraphBuffer[i] = lastZc;\r
1913 } else {\r
1914 // Change in sign, reset the sample count.\r
1915 sign = -sign;\r
1916 GraphBuffer[i] = lastZc;\r
1917 if(sign > 0) {\r
1918 lastZc = zc;\r
1919 zc = 0;\r
1920 }\r
1921 }\r
1922 }\r
1923\r
1924 RepaintGraphWindow();\r
1925}\r
1926\r
67853904 1927static void CmdThreshold(char *str)\r
1928{\r
1929 int i;\r
1930 int threshold = atoi(str);\r
1931\r
1932 for(i = 0; i < GraphTraceLen; i++) {\r
1933 if(GraphBuffer[i]>= threshold)\r
bd4cc2c9 1934 GraphBuffer[i]=1;\r
67853904 1935 else\r
bd4cc2c9 1936 GraphBuffer[i]=-1;\r
67853904 1937 }\r
1938 RepaintGraphWindow();\r
1939}\r
1940\r
6658905f 1941static void CmdLtrim(char *str)\r
1942{\r
1943 int i;\r
1944 int ds = atoi(str);\r
1945\r
1946 for(i = ds; i < GraphTraceLen; i++) {\r
1947 GraphBuffer[i-ds] = GraphBuffer[i];\r
1948 }\r
1949 GraphTraceLen -= ds;\r
1950\r
1951 RepaintGraphWindow();\r
1952}\r
1953\r
1954static void CmdAutoCorr(char *str)\r
1955{\r
1956 static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];\r
1957\r
1958 int window = atoi(str);\r
1959\r
1960 if(window == 0) {\r
1961 PrintToScrollback("needs a window");\r
1962 return;\r
1963 }\r
1964\r
1965 if(window >= GraphTraceLen) {\r
1966 PrintToScrollback("window must be smaller than trace (%d samples)",\r
1967 GraphTraceLen);\r
1968 return;\r
1969 }\r
1970\r
1971 PrintToScrollback("performing %d correlations", GraphTraceLen - window);\r
1972\r
1973 int i;\r
1974 for(i = 0; i < GraphTraceLen - window; i++) {\r
1975 int sum = 0;\r
1976 int j;\r
1977 for(j = 0; j < window; j++) {\r
1978 sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;\r
1979 }\r
1980 CorrelBuffer[i] = sum;\r
1981 }\r
1982 GraphTraceLen = GraphTraceLen - window;\r
1983 memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));\r
1984\r
1985 RepaintGraphWindow();\r
1986}\r
1987\r
1988static void CmdVchdemod(char *str)\r
1989{\r
1990 // Is this the entire sync pattern, or does this also include some\r
1991 // data bits that happen to be the same everywhere? That would be\r
1992 // lovely to know.\r
1993 static const int SyncPattern[] = {\r
1994 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1995 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1996 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1997 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1998 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1999 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
2000 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
2001 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\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 };\r
2005\r
2006 // So first, we correlate for the sync pattern, and mark that.\r
2007 int bestCorrel = 0, bestPos = 0;\r
2008 int i;\r
2009 // It does us no good to find the sync pattern, with fewer than\r
2010 // 2048 samples after it...\r
2011 for(i = 0; i < (GraphTraceLen-2048); i++) {\r
2012 int sum = 0;\r
2013 int j;\r
2014 for(j = 0; j < arraylen(SyncPattern); j++) {\r
2015 sum += GraphBuffer[i+j]*SyncPattern[j];\r
2016 }\r
2017 if(sum > bestCorrel) {\r
2018 bestCorrel = sum;\r
2019 bestPos = i;\r
2020 }\r
2021 }\r
2022 PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);\r
2023\r
2024 char bits[257];\r
2025 bits[256] = '\0';\r
2026\r
2027 int worst = INT_MAX;\r
2028 int worstPos;\r
2029\r
2030 for(i = 0; i < 2048; i += 8) {\r
2031 int sum = 0;\r
2032 int j;\r
2033 for(j = 0; j < 8; j++) {\r
2034 sum += GraphBuffer[bestPos+i+j];\r
2035 }\r
2036 if(sum < 0) {\r
2037 bits[i/8] = '.';\r
2038 } else {\r
2039 bits[i/8] = '1';\r
2040 }\r
2041 if(abs(sum) < worst) {\r
2042 worst = abs(sum);\r
2043 worstPos = i;\r
2044 }\r
2045 }\r
2046 PrintToScrollback("bits:");\r
2047 PrintToScrollback("%s", bits);\r
2048 PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);\r
2049\r
2050 if(strcmp(str, "clone")==0) {\r
2051 GraphTraceLen = 0;\r
2052 char *s;\r
2053 for(s = bits; *s; s++) {\r
2054 int j;\r
2055 for(j = 0; j < 16; j++) {\r
2056 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;\r
2057 }\r
2058 }\r
2059 RepaintGraphWindow();\r
2060 }\r
2061}\r
2062\r
a60612db 2063static void CmdIndalademod(char *str)\r
2064{\r
2065 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID\r
2066\r
2067 int state = -1;\r
2068 int count = 0;\r
2069 int i, j;\r
2070 // worst case with GraphTraceLen=64000 is < 4096\r
2071 // under normal conditions it's < 2048\r
2072 BYTE rawbits[4096];\r
2073 int rawbit = 0;\r
2074 int worst = 0, worstPos = 0;\r
2075 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen/32);\r
2076 for(i = 0; i < GraphTraceLen-1; i += 2) {\r
2077 count+=1;\r
2078 if((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {\r
2079 if (state == 0) {\r
2080 for(j = 0; j < count - 8; j += 16) {\r
2081 rawbits[rawbit++] = 0;\r
2082 }\r
2083 if ((abs(count - j)) > worst) {\r
2084 worst = abs(count - j);\r
2085 worstPos = i;\r
2086 }\r
2087 }\r
2088 state = 1;\r
2089 count=0;\r
2090 } else if((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {\r
2091 if (state == 1) {\r
2092 for(j = 0; j < count - 8; j += 16) {\r
2093 rawbits[rawbit++] = 1;\r
2094 }\r
2095 if ((abs(count - j)) > worst) {\r
2096 worst = abs(count - j);\r
2097 worstPos = i;\r
2098 }\r
2099 }\r
2100 state = 0;\r
2101 count=0;\r
2102 }\r
2103 }\r
2104 PrintToScrollback("Recovered %d raw bits", rawbit);\r
2105 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);\r
2106\r
2107 // Finding the start of a UID\r
2108 int uidlen, long_wait;\r
2109 if(strcmp(str, "224") == 0) {\r
2110 uidlen=224;\r
2111 long_wait=30;\r
2112 } else {\r
2113 uidlen=64;\r
2114 long_wait=29;\r
2115 }\r
2116 int start;\r
2117 int first = 0;\r
2118 for(start = 0; start <= rawbit - uidlen; start++) {\r
2119 first = rawbits[start];\r
2120 for(i = start; i < start + long_wait; i++) {\r
2121 if(rawbits[i] != first) {\r
2122 break;\r
2123 }\r
2124 }\r
2125 if(i == (start + long_wait)) {\r
2126 break;\r
2127 }\r
2128 }\r
2129 if(start == rawbit - uidlen + 1) {\r
2130 PrintToScrollback("nothing to wait for");\r
2131 return;\r
2132 }\r
2133\r
2134 // Inverting signal if needed\r
2135 if(first == 1) {\r
2136 for(i = start; i < rawbit; i++) {\r
2137 rawbits[i] = !rawbits[i];\r
2138 }\r
2139 }\r
2140\r
2141 // Dumping UID\r
2142 BYTE bits[224];\r
2143 char showbits[225];\r
2144 showbits[uidlen]='\0';\r
2145 int bit;\r
2146 i = start;\r
2147 int times = 0;\r
2148 if(uidlen > rawbit) {\r
2149 PrintToScrollback("Warning: not enough raw bits to get a full UID");\r
2150 for(bit = 0; bit < rawbit; bit++) {\r
2151 bits[bit] = rawbits[i++];\r
2152 // As we cannot know the parity, let's use "." and "/"\r
2153 showbits[bit] = '.' + bits[bit];\r
2154 }\r
2155 showbits[bit+1]='\0';\r
2156 PrintToScrollback("Partial UID=%s", showbits);\r
2157 return;\r
2158 } else {\r
2159 for(bit = 0; bit < uidlen; bit++) {\r
2160 bits[bit] = rawbits[i++];\r
2161 showbits[bit] = '0' + bits[bit];\r
2162 }\r
2163 times = 1;\r
2164 }\r
2165 PrintToScrollback("UID=%s", showbits);\r
2166\r
2167 // Checking UID against next occurences\r
2168 for(; i + uidlen <= rawbit;) {\r
2169 int failed = 0;\r
2170 for(bit = 0; bit < uidlen; bit++) {\r
2171 if(bits[bit] != rawbits[i++]) {\r
2172 failed = 1;\r
2173 break;\r
2174 }\r
2175 }\r
2176 if (failed == 1) {\r
2177 break;\r
2178 }\r
2179 times += 1;\r
2180 }\r
2181 PrintToScrollback("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);\r
2182\r
2183 // Remodulating for tag cloning\r
2184 GraphTraceLen = 32*uidlen;\r
2185 i = 0;\r
2186 int phase = 0;\r
2187 for(bit = 0; bit < uidlen; bit++) {\r
2188 if(bits[bit] == 0) {\r
2189 phase = 0;\r
2190 } else {\r
2191 phase = 1;\r
2192 }\r
2193 int j;\r
2194 for(j = 0; j < 32; j++) {\r
2195 GraphBuffer[i++] = phase;\r
2196 phase = !phase;\r
2197 }\r
2198 }\r
2199\r
2200 RepaintGraphWindow();\r
2201}\r
2202\r
6658905f 2203static void CmdFlexdemod(char *str)\r
2204{\r
2205 int i;\r
2206 for(i = 0; i < GraphTraceLen; i++) {\r
2207 if(GraphBuffer[i] < 0) {\r
2208 GraphBuffer[i] = -1;\r
2209 } else {\r
2210 GraphBuffer[i] = 1;\r
2211 }\r
2212 }\r
2213\r
2214#define LONG_WAIT 100\r
2215 int start;\r
2216 for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {\r
2217 int first = GraphBuffer[start];\r
2218 for(i = start; i < start + LONG_WAIT; i++) {\r
2219 if(GraphBuffer[i] != first) {\r
2220 break;\r
2221 }\r
2222 }\r
2223 if(i == (start + LONG_WAIT)) {\r
2224 break;\r
2225 }\r
2226 }\r
2227 if(start == GraphTraceLen - LONG_WAIT) {\r
2228 PrintToScrollback("nothing to wait for");\r
2229 return;\r
2230 }\r
2231\r
2232 GraphBuffer[start] = 2;\r
2233 GraphBuffer[start+1] = -2;\r
2234\r
2235 BYTE bits[64];\r
2236\r
2237 int bit;\r
2238 i = start;\r
2239 for(bit = 0; bit < 64; bit++) {\r
2240 int j;\r
2241 int sum = 0;\r
2242 for(j = 0; j < 16; j++) {\r
2243 sum += GraphBuffer[i++];\r
2244 }\r
2245 if(sum > 0) {\r
2246 bits[bit] = 1;\r
2247 } else {\r
2248 bits[bit] = 0;\r
2249 }\r
2250 PrintToScrollback("bit %d sum %d", bit, sum);\r
2251 }\r
2252\r
2253 for(bit = 0; bit < 64; bit++) {\r
2254 int j;\r
2255 int sum = 0;\r
2256 for(j = 0; j < 16; j++) {\r
2257 sum += GraphBuffer[i++];\r
2258 }\r
2259 if(sum > 0 && bits[bit] != 1) {\r
2260 PrintToScrollback("oops1 at %d", bit);\r
2261 }\r
2262 if(sum < 0 && bits[bit] != 0) {\r
2263 PrintToScrollback("oops2 at %d", bit);\r
2264 }\r
2265 }\r
2266\r
2267 GraphTraceLen = 32*64;\r
2268 i = 0;\r
2269 int phase = 0;\r
2270 for(bit = 0; bit < 64; bit++) {\r
2271 if(bits[bit] == 0) {\r
2272 phase = 0;\r
2273 } else {\r
2274 phase = 1;\r
2275 }\r
2276 int j;\r
2277 for(j = 0; j < 32; j++) {\r
2278 GraphBuffer[i++] = phase;\r
2279 phase = !phase;\r
2280 }\r
2281 }\r
2282\r
2283 RepaintGraphWindow();\r
2284}\r
9760414b 2285\r
2286/*\r
15db5fb7 2287 * Generic command to demodulate ASK.\r
9760414b 2288 *\r
15db5fb7 2289 * Argument is convention: positive or negative (High mod means zero\r
9760414b 2290 * or high mod means one)\r
2291 *\r
2292 * Updates the Graph trace with 0/1 values\r
2293 *\r
2294 * Arguments:\r
9760414b 2295 * c : 0 or 1\r
2296 */\r
2297\r
2298static void Cmdaskdemod(char *str) {\r
2299 int i;\r
8172fb35 2300 int c, high = 0, low = 0;\r
9760414b 2301\r
2302 // TODO: complain if we do not give 2 arguments here !\r
c2c80de8 2303 // (AL - this doesn't make sense! we're only using one argument!!!)\r
15db5fb7 2304 sscanf(str, "%i", &c);\r
2305\r
2306 /* Detect high and lows and clock */\r
c2c80de8 2307 // (AL - clock???)\r
15db5fb7 2308 for (i = 0; i < GraphTraceLen; i++)\r
2309 {\r
2310 if (GraphBuffer[i] > high)\r
2311 high = GraphBuffer[i];\r
2312 else if (GraphBuffer[i] < low)\r
2313 low = GraphBuffer[i];\r
9760414b 2314 }\r
c2c80de8 2315 if(c != 0 && c != 1) {\r
2316 PrintToScrollback("Invalid argument: %s",str);\r
2317 return;\r
2318 }\r
9760414b 2319\r
15db5fb7 2320 if (GraphBuffer[0] > 0) {\r
2321 GraphBuffer[0] = 1-c;\r
9760414b 2322 } else {\r
15db5fb7 2323 GraphBuffer[0] = c;\r
9760414b 2324 }\r
2325 for(i=1;i<GraphTraceLen;i++) {\r
15db5fb7 2326 /* Transitions are detected at each peak\r
2327 * Transitions are either:\r
2328 * - we're low: transition if we hit a high\r
2329 * - we're high: transition if we hit a low\r
2330 * (we need to do it this way because some tags keep high or\r
2331 * low for long periods, others just reach the peak and go\r
a91ff4c8 2332 * down)\r
15db5fb7 2333 */\r
2334 if ((GraphBuffer[i]==high) && (GraphBuffer[i-1] == c)) {\r
2335 GraphBuffer[i]=1-c;\r
2336 } else if ((GraphBuffer[i]==low) && (GraphBuffer[i-1] == (1-c))){\r
2337 GraphBuffer[i] = c;\r
9760414b 2338 } else {\r
15db5fb7 2339 /* No transition */\r
9760414b 2340 GraphBuffer[i] = GraphBuffer[i-1];\r
2341 }\r
2342 }\r
2343 RepaintGraphWindow();\r
2344}\r
2345\r
2346/* Print our clock rate */\r
2347static void Cmddetectclockrate(char *str)\r
2348{\r
2349 int clock = detectclock(0);\r
2350 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2351}\r
2352\r
2353/*\r
2354 * Detect clock rate\r
2355 */\r
2356int detectclock(int peak)\r
2357{\r
2358 int i;\r
2359 int clock = 0xFFFF;\r
2360 int lastpeak = 0;\r
2361\r
2362 /* Detect peak if we don't have one */\r
2363 if (!peak)\r
2364 for (i = 0; i < GraphTraceLen; i++)\r
2365 if (GraphBuffer[i] > peak)\r
2366 peak = GraphBuffer[i];\r
2367\r
2368 for (i = 1; i < GraphTraceLen; i++)\r
2369 {\r
2370 /* If this is the beginning of a peak */\r
2371 if (GraphBuffer[i-1] != GraphBuffer[i] && GraphBuffer[i] == peak)\r
2372 {\r
2373 /* Find lowest difference between peaks */\r
2374 if (lastpeak && i - lastpeak < clock)\r
2375 {\r
2376 clock = i - lastpeak;\r
2377 }\r
2378 lastpeak = i;\r
2379 }\r
2380 }\r
15db5fb7 2381\r
9760414b 2382 return clock;\r
2383}\r
2384\r
2385/* Get or auto-detect clock rate */\r
2386int GetClock(char *str, int peak)\r
2387{\r
2388 int clock;\r
15db5fb7 2389\r
9760414b 2390 sscanf(str, "%i", &clock);\r
2391 if (!strcmp(str, ""))\r
2392 clock = 0;\r
2393\r
2394 /* Auto-detect clock */\r
2395 if (!clock)\r
2396 {\r
2397 clock = detectclock(peak);\r
15db5fb7 2398\r
9760414b 2399 /* Only print this message if we're not looping something */\r
2400 if (!go)\r
2401 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2402 }\r
15db5fb7 2403\r
9760414b 2404 return clock;\r
2405}\r
2406\r
2407/*\r
2408 * Convert to a bitstream\r
2409 */\r
2410static void Cmdbitstream(char *str) {\r
c9f99c01 2411 int i, j;\r
2412 int bit;\r
9760414b 2413 int gtl;\r
2414 int clock;\r
c9f99c01 2415 int low = 0;\r
2416 int high = 0;\r
2417 int hithigh, hitlow, first;\r
9760414b 2418\r
2419 /* Detect high and lows and clock */\r
2420 for (i = 0; i < GraphTraceLen; i++)\r
c9f99c01 2421 {\r
9760414b 2422 if (GraphBuffer[i] > high)\r
2423 high = GraphBuffer[i];\r
2424 else if (GraphBuffer[i] < low)\r
2425 low = GraphBuffer[i];\r
c9f99c01 2426 }\r
9760414b 2427\r
2428 /* Get our clock */\r
2429 clock = GetClock(str, high);\r
15db5fb7 2430\r
9760414b 2431 gtl = CmdClearGraph(0);\r
15db5fb7 2432\r
9760414b 2433 bit = 0;\r
2434 for (i = 0; i < (int)(gtl / clock); i++)\r
2435 {\r
2436 hithigh = 0;\r
2437 hitlow = 0;\r
2438 first = 1;\r
15db5fb7 2439\r
9760414b 2440 /* Find out if we hit both high and low peaks */\r
2441 for (j = 0; j < clock; j++)\r
2442 {\r
2443 if (GraphBuffer[(i * clock) + j] == high)\r
2444 hithigh = 1;\r
2445 else if (GraphBuffer[(i * clock) + j] == low)\r
2446 hitlow = 1;\r
15db5fb7 2447\r
9760414b 2448 /* it doesn't count if it's the first part of our read\r
2449 because it's really just trailing from the last sequence */\r
2450 if (first && (hithigh || hitlow))\r
2451 hithigh = hitlow = 0;\r
2452 else\r
2453 first = 0;\r
15db5fb7 2454\r
9760414b 2455 if (hithigh && hitlow)\r
2456 break;\r
2457 }\r
15db5fb7 2458\r
9760414b 2459 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2460 if (!hithigh || !hitlow)\r
2461 bit ^= 1;\r
2462\r
2463 CmdAppendGraph(0, clock, bit);\r
2464// for (j = 0; j < (int)(clock/2); j++)\r
2465// GraphBuffer[(i * clock) + j] = bit ^ 1;\r
2466// for (j = (int)(clock/2); j < clock; j++)\r
2467// GraphBuffer[(i * clock) + j] = bit;\r
2468 }\r
2469\r
2470 RepaintGraphWindow();\r
2471}\r
2472\r
2473/* Modulate our data into manchester */\r
2474static void Cmdmanchestermod(char *str)\r
2475{\r
2476 int i, j;\r
2477 int clock;\r
2478 int bit, lastbit, wave;\r
15db5fb7 2479\r
9760414b 2480 /* Get our clock */\r
2481 clock = GetClock(str, 0);\r
2482\r
2483 wave = 0;\r
2484 lastbit = 1;\r
2485 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
2486 {\r
2487 bit = GraphBuffer[i * clock] ^ 1;\r
15db5fb7 2488\r
9760414b 2489 for (j = 0; j < (int)(clock/2); j++)\r
2490 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave;\r
2491 for (j = (int)(clock/2); j < clock; j++)\r
2492 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1;\r
15db5fb7 2493\r
9760414b 2494 /* Keep track of how we start our wave and if we changed or not this time */\r
2495 wave ^= bit ^ lastbit;\r
2496 lastbit = bit;\r
2497 }\r
15db5fb7 2498\r
9760414b 2499 RepaintGraphWindow();\r
2500}\r
2501\r
2502/*\r
2503 * Manchester demodulate a bitstream. The bitstream needs to be already in\r
2504 * the GraphBuffer as 0 and 1 values\r
2505 *\r
2506 * Give the clock rate as argument in order to help the sync - the algorithm\r
2507 * resyncs at each pulse anyway.\r
2508 *\r
2509 * Not optimized by any means, this is the 1st time I'm writing this type of\r
2510 * routine, feel free to improve...\r
2511 *\r
2512 * 1st argument: clock rate (as number of samples per clock rate)\r
2513 * Typical values can be 64, 32, 128...\r
2514 */\r
2515static void Cmdmanchesterdemod(char *str) {\r
736aea60 2516 int i, j, invert= 0;\r
9760414b 2517 int bit;\r
2518 int clock;\r
2519 int lastval;\r
2520 int low = 0;\r
2521 int high = 0;\r
2522 int hithigh, hitlow, first;\r
2523 int lc = 0;\r
2524 int bitidx = 0;\r
2525 int bit2idx = 0;\r
2526 int warnings = 0;\r
2527\r
736aea60 2528 /* check if we're inverting output */\r
2529 if(*str == 'i')\r
2530 {\r
2531 PrintToScrollback("Inverting output");\r
2532 invert= 1;\r
2533 do\r
2534 ++str;\r
2535 while(*str == ' '); // in case a 2nd argument was given\r
2536 }\r
2537\r
9760414b 2538 /* Holds the decoded bitstream: each clock period contains 2 bits */\r
2539 /* later simplified to 1 bit after manchester decoding. */\r
2540 /* Add 10 bits to allow for noisy / uncertain traces without aborting */\r
2541 /* int BitStream[GraphTraceLen*2/clock+10]; */\r
2542\r
2543 /* But it does not work if compiling on WIndows: therefore we just allocate a */\r
2544 /* large array */\r
2545 int BitStream[MAX_GRAPH_TRACE_LEN];\r
2546\r
c9f99c01 2547 /* Detect high and lows */\r
2548 for (i = 0; i < GraphTraceLen; i++)\r
2549 {\r
2550 if (GraphBuffer[i] > high)\r
2551 high = GraphBuffer[i];\r
2552 else if (GraphBuffer[i] < low)\r
2553 low = GraphBuffer[i];\r
2554 }\r
2555\r
9760414b 2556 /* Get our clock */\r
2557 clock = GetClock(str, high);\r
15db5fb7 2558\r
9760414b 2559 int tolerance = clock/4;\r
15db5fb7 2560\r
9760414b 2561 /* Detect first transition */\r
2562 /* Lo-Hi (arbitrary) */\r
ac86b656 2563 /* skip to the first high */\r
2564 for (i= 0; i < GraphTraceLen; i++)\r
2565 if(GraphBuffer[i] == high)\r
2566 break;\r
2567 /* now look for the first low */\r
2568 for (; i < GraphTraceLen; i++)\r
c9f99c01 2569 {\r
2570 if (GraphBuffer[i] == low)\r
2571 {\r
9760414b 2572 lastval = i;\r
2573 break;\r
2574 }\r
2575 }\r
c9f99c01 2576\r
2577 /* If we're not working with 1/0s, demod based off clock */\r
2578 if (high != 1)\r
2579 {\r
15db5fb7 2580 bit = 0; /* We assume the 1st bit is zero, it may not be\r
2581 * the case: this routine (I think) has an init problem.\r
2582 * Ed.\r
2583 */\r
2584 for (; i < (int)(GraphTraceLen / clock); i++)\r
c9f99c01 2585 {\r
2586 hithigh = 0;\r
2587 hitlow = 0;\r
2588 first = 1;\r
2589\r
2590 /* Find out if we hit both high and low peaks */\r
2591 for (j = 0; j < clock; j++)\r
2592 {\r
2593 if (GraphBuffer[(i * clock) + j] == high)\r
2594 hithigh = 1;\r
2595 else if (GraphBuffer[(i * clock) + j] == low)\r
2596 hitlow = 1;\r
2597\r
2598 /* it doesn't count if it's the first part of our read\r
2599 because it's really just trailing from the last sequence */\r
2600 if (first && (hithigh || hitlow))\r
2601 hithigh = hitlow = 0;\r
2602 else\r
2603 first = 0;\r
2604\r
2605 if (hithigh && hitlow)\r
2606 break;\r
2607 }\r
2608\r
2609 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2610 if (!hithigh || !hitlow)\r
2611 bit ^= 1;\r
2612\r
736aea60 2613 BitStream[bit2idx++] = bit ^ invert;\r
c9f99c01 2614 }\r
2615 }\r
2616\r
2617 /* standard 1/0 bitstream */\r
2618 else\r
2619 {\r
9760414b 2620\r
736aea60 2621 /* Then detect duration between 2 successive transitions */\r
c9f99c01 2622 for (bitidx = 1; i < GraphTraceLen; i++)\r
2623 {\r
2624 if (GraphBuffer[i-1] != GraphBuffer[i])\r
2625 {\r
9760414b 2626 lc = i-lastval;\r
2627 lastval = i;\r
2628\r
2629 // Error check: if bitidx becomes too large, we do not\r
2630 // have a Manchester encoded bitstream or the clock is really\r
2631 // wrong!\r
2632 if (bitidx > (GraphTraceLen*2/clock+8) ) {\r
2633 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");\r
2634 return;\r
2635 }\r
2636 // Then switch depending on lc length:\r
2637 // Tolerance is 1/4 of clock rate (arbitrary)\r
2638 if (abs(lc-clock/2) < tolerance) {\r
2639 // Short pulse : either "1" or "0"\r
2640 BitStream[bitidx++]=GraphBuffer[i-1];\r
2641 } else if (abs(lc-clock) < tolerance) {\r
2642 // Long pulse: either "11" or "00"\r
2643 BitStream[bitidx++]=GraphBuffer[i-1];\r
2644 BitStream[bitidx++]=GraphBuffer[i-1];\r
2645 } else {\r
2646 // Error\r
c9f99c01 2647 warnings++;\r
9760414b 2648 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");\r
2649 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");\r
c9f99c01 2650\r
2651 if (warnings > 100)\r
2652 {\r
2653 PrintToScrollback("Error: too many detection errors, aborting.");\r
2654 return;\r
2655 }\r
736aea60 2656 }\r
9760414b 2657 }\r
2658 }\r
9760414b 2659\r
736aea60 2660 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream\r
2661 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful\r
2662 // to stop output at the final bitidx2 value, not bitidx\r
2663 for (i = 0; i < bitidx; i += 2) {\r
2664 if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {\r
2665 BitStream[bit2idx++] = 1 ^ invert;\r
9760414b 2666 } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {\r
736aea60 2667 BitStream[bit2idx++] = 0 ^ invert;\r
9760414b 2668 } else {\r
2669 // We cannot end up in this state, this means we are unsynchronized,\r
2670 // move up 1 bit:\r
2671 i++;\r
c9f99c01 2672 warnings++;\r
9760414b 2673 PrintToScrollback("Unsynchronized, resync...");\r
2674 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");\r
c9f99c01 2675\r
2676 if (warnings > 100)\r
2677 {\r
2678 PrintToScrollback("Error: too many decode errors, aborting.");\r
2679 return;\r
2680 }\r
736aea60 2681 }\r
67853904 2682 }\r
c9f99c01 2683 }\r
2684\r
2685 PrintToScrollback("Manchester decoded bitstream");\r
9760414b 2686 // Now output the bitstream to the scrollback by line of 16 bits\r
2687 for (i = 0; i < (bit2idx-16); i+=16) {\r
2688 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",\r
2689 BitStream[i],\r
2690 BitStream[i+1],\r
2691 BitStream[i+2],\r
2692 BitStream[i+3],\r
2693 BitStream[i+4],\r
2694 BitStream[i+5],\r
2695 BitStream[i+6],\r
2696 BitStream[i+7],\r
2697 BitStream[i+8],\r
2698 BitStream[i+9],\r
2699 BitStream[i+10],\r
2700 BitStream[i+11],\r
2701 BitStream[i+12],\r
2702 BitStream[i+13],\r
2703 BitStream[i+14],\r
2704 BitStream[i+15]);\r
2705 }\r
2706}\r
2707\r
9760414b 2708/*\r
2709 * Usage ???\r
6658905f 2710 */\r
2711static void CmdHiddemod(char *str)\r
2712{\r
2713 if(GraphTraceLen < 4800) {\r
2714 PrintToScrollback("too short; need at least 4800 samples");\r
2715 return;\r
2716 }\r
2717\r
2718 GraphTraceLen = 4800;\r
2719 int i;\r
2720 for(i = 0; i < GraphTraceLen; i++) {\r
2721 if(GraphBuffer[i] < 0) {\r
2722 GraphBuffer[i] = 0;\r
2723 } else {\r
2724 GraphBuffer[i] = 1;\r
2725 }\r
2726 }\r
2727 RepaintGraphWindow();\r
2728}\r
2729\r
2730static void CmdPlot(char *str)\r
2731{\r
2732 ShowGraphWindow();\r
2733}\r
2734\r
bd4cc2c9 2735static void CmdGrid(char *str)\r
2736{\r
f4434ad2 2737 sscanf(str, "%i %i", &PlotGridX, &PlotGridY);\r
bd4cc2c9 2738 RepaintGraphWindow();\r
2739}\r
2740\r
6658905f 2741static void CmdHide(char *str)\r
2742{\r
2743 HideGraphWindow();\r
2744}\r
2745\r
2746static void CmdScale(char *str)\r
2747{\r
2748 CursorScaleFactor = atoi(str);\r
2749 if(CursorScaleFactor == 0) {\r
2750 PrintToScrollback("bad, can't have zero scale");\r
2751 CursorScaleFactor = 1;\r
2752 }\r
2753 RepaintGraphWindow();\r
2754}\r
2755\r
2756static void CmdSave(char *str)\r
2757{\r
2758 FILE *f = fopen(str, "w");\r
2759 if(!f) {\r
2760 PrintToScrollback("couldn't open '%s'", str);\r
2761 return;\r
2762 }\r
2763 int i;\r
2764 for(i = 0; i < GraphTraceLen; i++) {\r
2765 fprintf(f, "%d\n", GraphBuffer[i]);\r
2766 }\r
2767 fclose(f);\r
2768 PrintToScrollback("saved to '%s'", str);\r
2769}\r
2770\r
2771static void CmdLoad(char *str)\r
2772{\r
2773 FILE *f = fopen(str, "r");\r
2774 if(!f) {\r
2775 PrintToScrollback("couldn't open '%s'", str);\r
2776 return;\r
2777 }\r
2778\r
2779 GraphTraceLen = 0;\r
2780 char line[80];\r
2781 while(fgets(line, sizeof(line), f)) {\r
2782 GraphBuffer[GraphTraceLen] = atoi(line);\r
2783 GraphTraceLen++;\r
2784 }\r
2785 fclose(f);\r
2786 PrintToScrollback("loaded %d samples", GraphTraceLen);\r
2787 RepaintGraphWindow();\r
2788}\r
2789\r
2790static void CmdHIDsimTAG(char *str)\r
2791{\r
2792 unsigned int hi=0, lo=0;\r
2793 int n=0, i=0;\r
2794 UsbCommand c;\r
2795\r
2796 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
2797 hi=(hi<<4)|(lo>>28);\r
2798 lo=(lo<<4)|(n&0xf);\r
2799 }\r
2800\r
2801 PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);\r
2802\r
2803 c.cmd = CMD_HID_SIM_TAG;\r
2804 c.ext1 = hi;\r
2805 c.ext2 = lo;\r
2806 SendCommand(&c, FALSE);\r
2807}\r
2808\r
1dff8c42 2809static void CmdReadmem(char *str)\r
2810{\r
2811 UsbCommand c;\r
2812 c.cmd = CMD_READ_MEM;\r
2813 c.ext1 = atoi(str);\r
2814 SendCommand(&c, FALSE);\r
2815}\r
2816\r
ba8a80b3 2817static void CmdVersion(char *str)\r
2818{\r
2819 UsbCommand c;\r
2820 c.cmd = CMD_VERSION;\r
2821 SendCommand(&c, FALSE);\r
2822}\r
2823\r
6658905f 2824static void CmdLcdReset(char *str)\r
2825{\r
2826 UsbCommand c;\r
2827 c.cmd = CMD_LCD_RESET;\r
2828 c.ext1 = atoi(str);\r
2829 SendCommand(&c, FALSE);\r
2830}\r
2831\r
2832static void CmdLcd(char *str)\r
2833{\r
2834 int i, j;\r
2835 UsbCommand c;\r
2836 c.cmd = CMD_LCD;\r
2837 sscanf(str, "%x %d", &i, &j);\r
2838 while (j--) {\r
2839 c.ext1 = i&0x1ff;\r
2840 SendCommand(&c, FALSE);\r
2841 }\r
2842}\r
2843\r
9760414b 2844/*\r
2845 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below\r
2846 * 600kHz.\r
2847 */\r
30f2a7d3 2848static void CmdSetDivisor(char *str)\r
2849{\r
2850 UsbCommand c;\r
2851 c.cmd = CMD_SET_LF_DIVISOR;\r
2852 c.ext1 = atoi(str);\r
2853 if (( c.ext1<0) || (c.ext1>255)) {\r
2854 PrintToScrollback("divisor must be between 19 and 255");\r
2855 } else {\r
2856 SendCommand(&c, FALSE);\r
2857 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c.ext1+1));\r
2858 }\r
2859}\r
2860\r
5fc8250f 2861static void CmdSetMux(char *str)\r
2862{\r
2863 UsbCommand c;\r
2864 c.cmd = CMD_SET_ADC_MUX;\r
ec81f90e 2865 if(strcmp(str, "lopkd") == 0) {\r
5fc8250f 2866 c.ext1 = 0;\r
ec81f90e 2867 } else if(strcmp(str, "loraw") == 0) {\r
5fc8250f 2868 c.ext1 = 1;\r
ec81f90e 2869 } else if(strcmp(str, "hipkd") == 0) {\r
5fc8250f 2870 c.ext1 = 2;\r
ec81f90e 2871 } else if(strcmp(str, "hiraw") == 0) {\r
5fc8250f 2872 c.ext1 = 3;\r
2873 }\r
2874 SendCommand(&c, FALSE);\r
2875}\r
2876\r
6658905f 2877typedef void HandlerFunction(char *cmdline);\r
2878\r
3f030abe 2879/* in alphabetic order */\r
6658905f 2880static struct {\r
fb25b483 2881 char *name;\r
2882 HandlerFunction *handler;\r
2883 int offline; // 1 if the command can be used when in offline mode\r
9760414b 2884 char *docString;\r
6658905f 2885} CommandTable[] = {\r
523f4c90 2886 {"amp", CmdAmp, 1, "Amplify peaks"},\r
c2c80de8 2887 {"askdemod", Cmdaskdemod, 1, "<0|1> -- Attempt to demodulate simple ASK tags"},\r
bd4cc2c9 2888 {"autocorr", CmdAutoCorr, 1, "<window length> -- Autocorrelation over window"},\r
2889 {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"},\r
2890 {"bitstream", Cmdbitstream, 1, "[clock rate] -- Convert waveform into a bitstream"},\r
1569d977 2891 {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"},\r
bd4cc2c9 2892 {"dec", CmdDec, 1, "Decimate samples"},\r
2893 {"detectclock", Cmddetectclockrate, 1, "Detect clock rate"},\r
2894 {"detectreader", CmdDetectReader, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},\r
2895 {"em410xsim", CmdEM410xsim, 1, "<UID> -- Simulate EM410x tag"},\r
2896 {"em410xread", CmdEM410xread, 1, "[clock rate] -- Extract ID from EM410x tag"},\r
2897 {"em410xwatch", CmdEM410xwatch, 0, "Watches for EM410x tags"},\r
2898 {"em4x50read", CmdEM4x50read, 1, "Extract data from EM4x50 tag"},\r
2899 {"exit", CmdQuit, 1, "Exit program"},\r
2900 {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},\r
2901 {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"},\r
2902 {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"},\r
f4434ad2 2903 {"grid", CmdGrid, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},\r
bd4cc2c9 2904 {"hexsamples", CmdHexsamples, 0, "<blocks> -- Dump big buffer as hex bytes"},\r
2905 {"hi14alist", CmdHi14alist, 0, "List ISO 14443a history"},\r
2906 {"hi14areader", CmdHi14areader, 0, "Act like an ISO14443 Type A reader"},\r
2907 {"hi14asim", CmdHi14asim, 0, "<UID> -- Fake ISO 14443a tag"},\r
2908 {"hi14asnoop", CmdHi14asnoop, 0, "Eavesdrop ISO 14443 Type A"},\r
2909 {"hi14bdemod", CmdHi14bdemod, 1, "Demodulate ISO14443 Type B from tag"},\r
2910 {"hi14list", CmdHi14list, 0, "List ISO 14443 history"},\r
2911 {"hi14read", CmdHi14read, 0, "Read HF tag (ISO 14443)"},\r
2912 {"hi14sim", CmdHi14sim, 0, "Fake ISO 14443 tag"},\r
2913 {"hi14snoop", CmdHi14snoop, 0, "Eavesdrop ISO 14443"},\r
2914 {"hi15demod", CmdHi15demod, 1, "Demodulate ISO15693 from tag"},\r
2915 {"hi15read", CmdHi15read, 0, "Read HF tag (ISO 15693)"},\r
2916 {"hi15reader", CmdHi15reader, 0, "Act like an ISO15693 reader"},\r
2917 {"hi15sim", CmdHi15tag, 0, "Fake an ISO15693 tag"},\r
2918 {"hiddemod", CmdHiddemod, 1, "Demodulate HID Prox Card II (not optimal)"},\r
2919 {"hide", CmdHide, 1, "Hide graph window"},\r
2920 {"hidfskdemod", CmdHIDdemodFSK, 0, "Realtime HID FSK demodulator"},\r
2921 {"hidsimtag", CmdHIDsimTAG, 0, "<ID> -- HID tag simulator"},\r
2922 {"higet", CmdHi14read_sim, 0, "<samples> -- Get samples HF, 'analog'"},\r
2923 {"hisamples", CmdHisamples, 0, "Get raw samples for HF tag"},\r
2924 {"hisampless", CmdHisampless, 0, "<samples> -- Get signed raw samples, HF tag"},\r
2925 {"hisamplest", CmdHi14readt, 0, "Get samples HF, for testing"},\r
2926 {"hisimlisten", CmdHisimlisten, 0, "Get HF samples as fake tag"},\r
2927 {"hpf", CmdHpf, 1, "Remove DC offset from trace"},\r
2928 {"indalademod", CmdIndalademod, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},\r
2929 {"lcd", CmdLcd, 0, "<HEX command> <count> -- Send command/data to LCD"},\r
2930 {"lcdreset", CmdLcdReset, 0, "Hardware reset LCD"},\r
a7247d85 2931 {"legicrfsim", CmdLegicRfSim, 0, "Start the LEGIC RF tag simulator"},\r
dcc10e5e 2932 {"legicrfread", CmdLegicRfRead, 0, "Start the LEGIC RF reader"},\r
bd4cc2c9 2933 {"load", CmdLoad, 1, "<filename> -- Load trace (to graph window"},\r
2934 {"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
2935 {"loread", CmdLoread, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},\r
2936 {"losamples", CmdLosamples, 0, "[128 - 16000] -- Get raw samples for LF tag"},\r
2937 {"losim", CmdLosim, 0, "Simulate LF tag"},\r
0fa9ca5b 2938 {"losimbidir", CmdLosimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},\r
bd4cc2c9 2939 {"ltrim", CmdLtrim, 1, "<samples> -- Trim samples from left of trace"},\r
2940 {"mandemod", Cmdmanchesterdemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},\r
2941 {"manmod", Cmdmanchestermod, 1, "[clock rate] -- Manchester modulate a binary stream"},\r
2942 {"norm", CmdNorm, 1, "Normalize max/min to +/-500"},\r
2943 {"plot", CmdPlot, 1, "Show graph window"},\r
2944 {"quit", CmdQuit, 1, "Quit program"},\r
2945 {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"},\r
2946 {"reset", CmdReset, 0, "Reset the Proxmark3"},\r
2947 {"save", CmdSave, 1, "<filename> -- Save trace (from graph window)"},\r
2948 {"scale", CmdScale, 1, "<int> -- Set cursor display scale"},\r
2949 {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},\r
5fc8250f 2950 {"setmux", CmdSetMux, 0, "<loraw|hiraw|lopkd|hipkd> -- Set the ADC mux to a specific value"},\r
bd4cc2c9 2951 {"sri512read", CmdSri512read, 0, "<int> -- Read contents of a SRI512 tag"},\r
c86cc308 2952 {"srix4kread", CmdSrix4kread, 0, "<int> -- Read contents of a SRIX4K tag"},
9bea179a 2953 {"tidemod", CmdTIDemod, 1, "Demodulate raw bits for TI-type LF tag"},\r
9bea179a 2954 {"tiread", CmdTIRead, 0, "Read and decode a TI 134 kHz tag"},\r
2955 {"tiwrite", CmdTIWrite, 0, "Write new data to a r/w TI 134 kHz tag"},\r
bd4cc2c9 2956 {"threshold", CmdThreshold, 1, "Maximize/minimize every value in the graph window depending on threshold"},\r
2957 {"tune", CmdTune, 0, "Measure antenna tuning"},\r
2958 {"vchdemod", CmdVchdemod, 0, "['clone'] -- Demodulate samples for VeriChip"},\r
269a820f 2959 {"version", CmdVersion, 0, "Show version inforation about the connected Proxmark"},\r
bd4cc2c9 2960 {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"},\r
6658905f 2961};\r
2962\r
7f93ef2c 2963static struct {\r
2964 char *name;\r
2965 char *args;\r
2966 char *argshelp;\r
2967 char *description;\r
2968 } CommandExtendedHelp[]= {\r
a52a7d19 2969 {"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 2970 {"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 2971 };\r
fb25b483 2972\r
6658905f 2973//-----------------------------------------------------------------------------\r
2974// Entry point into our code: called whenever the user types a command and\r
2975// then presses Enter, which the full command line that they typed.\r
2976//-----------------------------------------------------------------------------\r
2977void CommandReceived(char *cmd)\r
2978{\r
2979 int i;\r
7f93ef2c 2980 char line[256];\r
6658905f 2981\r
2982 PrintToScrollback("> %s", cmd);\r
2983\r
7f93ef2c 2984 if(strcmp(cmd, "help") == 0 || strncmp(cmd,"help ",strlen("help ")) == 0) {\r
2985 // check if we're doing extended help\r
2986 if(strlen(cmd) > strlen("help ")) {\r
2987 cmd += strlen("help ");\r
2988 for(i = 0; i < sizeof(CommandExtendedHelp) / sizeof(CommandExtendedHelp[0]); i++) {\r
2989 if(strcmp(CommandExtendedHelp[i].name,cmd) == 0) {\r
2990 PrintToScrollback("\nExtended help for '%s':\n", cmd);\r
2991 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp[i].args,CommandExtendedHelp[i].argshelp);\r
2992 PrintToScrollback(CommandExtendedHelp[i].description);\r
a52a7d19 2993 PrintToScrollback("");\r
7f93ef2c 2994 return;\r
2995 }\r
2996 }\r
2997 PrintToScrollback("No extended help available for '%s'", cmd);\r
2998 return;\r
2999 }\r
d722c4ce 3000 if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");\r
6658905f 3001 PrintToScrollback("\r\nAvailable commands:");\r
3002 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
d722c4ce 3003 if (offline && (CommandTable[i].offline==0)) continue;\r
6658905f 3004 memset(line, ' ', sizeof(line));\r
3005 strcpy(line+2, CommandTable[i].name);\r
3006 line[strlen(line)] = ' ';\r
3007 sprintf(line+15, " -- %s", CommandTable[i].docString);\r
3008 PrintToScrollback("%s", line);\r
3009 }\r
3010 PrintToScrollback("");\r
a52a7d19 3011 PrintToScrollback("'help <command>' for extended help on that command\n");\r
6658905f 3012 return;\r
3013 }\r
3014\r
3015 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
3016 char *name = CommandTable[i].name;\r
3017 if(memcmp(cmd, name, strlen(name))==0 &&\r
3018 (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
3019 {\r
3020 cmd += strlen(name);\r
3021 while(*cmd == ' ') {\r
3022 cmd++;\r
3023 }\r
d722c4ce 3024 if (offline && (CommandTable[i].offline==0)) {\r
3025 PrintToScrollback("Offline mode, cannot use this command.");\r
3026 return;\r
3027 }\r
6658905f 3028 (CommandTable[i].handler)(cmd);\r
3029 return;\r
3030 }\r
3031 }\r
3032 PrintToScrollback(">> bad command '%s'", cmd);\r
3033}\r
3034\r
3035//-----------------------------------------------------------------------------\r
3036// Entry point into our code: called whenever we received a packet over USB\r
3037// that we weren't necessarily expecting, for example a debug print.\r
3038//-----------------------------------------------------------------------------\r
3039void UsbCommandReceived(UsbCommand *c)\r
3040{\r
3041 switch(c->cmd) {\r
3042 case CMD_DEBUG_PRINT_STRING: {\r
3043 char s[100];\r
3044 if(c->ext1 > 70 || c->ext1 < 0) {\r
3045 c->ext1 = 0;\r
3046 }\r
3047 memcpy(s, c->d.asBytes, c->ext1);\r
3048 s[c->ext1] = '\0';\r
3049 PrintToScrollback("#db# %s", s);\r
9760414b 3050 break;\r
6658905f 3051 }\r
3052\r
3053 case CMD_DEBUG_PRINT_INTEGERS:\r
3054 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
3055 break;\r
3056\r
3057 case CMD_MEASURED_ANTENNA_TUNING: {\r
e7aee94e 3058 int peakv, peakf;\r
6658905f 3059 int vLf125, vLf134, vHf;\r
3060 vLf125 = c->ext1 & 0xffff;\r
3061 vLf134 = c->ext1 >> 16;\r
e7aee94e 3062 vHf = c->ext2 & 0xffff;;\r
3063 peakf = c->ext3 & 0xffff;\r
3064 peakv = c->ext3 >> 16;\r
ad2a9782 3065 PrintToScrollback("");\r
3066 PrintToScrollback("");\r
3067 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0);\r
3068 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0);\r
3069 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1));\r
3070 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0);\r
e7aee94e 3071 if (peakv<2000)\r
67853904 3072 PrintToScrollback("# Your LF antenna is unusable.");\r
e7aee94e 3073 else if (peakv<10000)\r
3074 PrintToScrollback("# Your LF antenna is marginal.");\r
3075 if (vHf<2000)\r
67853904 3076 PrintToScrollback("# Your HF antenna is unusable.");\r
e7aee94e 3077 else if (vHf<5000)\r
3078 PrintToScrollback("# Your HF antenna is marginal.");\r
6658905f 3079 break;\r
3080 }\r
3081 default:\r
3082 PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
3083 break;\r
3084 }\r
3085}\r
Impressum, Datenschutz