]> git.zerfleddert.de Git - proxmark3-svn/blob - winsrc/command.cpp
a02803db0da870b274571bc0397536cfd7a8d301
[proxmark3-svn] / winsrc / command.cpp
1 //-----------------------------------------------------------------------------
2 // The actual command interpeter for what the user types at the command line.
3 // Jonathan Westhues, Sept 2005
4 // Edits by Gerhard de Koning Gans, Sep 2007 (##)
5 //-----------------------------------------------------------------------------
6 #include <windows.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <limits.h>
11 #include <math.h>
12
13 #include "prox.h"
14 #include "../common/iso14443_crc.c"
15
16 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
17
18 static int CmdHisamplest(char *str, int nrlow);
19
20 static void GetFromBigBuf(BYTE *dest, int bytes)
21 {
22 int n = bytes/4;
23
24 if(n % 48 != 0) {
25 PrintToScrollback("bad len in GetFromBigBuf");
26 return;
27 }
28
29 int i;
30 for(i = 0; i < n; i += 12) {
31 UsbCommand c;
32 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
33 c.ext1 = i;
34 SendCommand(&c, FALSE);
35 ReceiveCommand(&c);
36 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
37 PrintToScrollback("bad resp\n");
38 return;
39 }
40
41 memcpy(dest+(i*4), c.d.asBytes, 48);
42 }
43 }
44
45 static void CmdReset(char *str)
46 {
47 UsbCommand c;
48 c.cmd = CMD_HARDWARE_RESET;
49 SendCommand(&c, FALSE);
50 }
51
52
53 static void CmdQuit(char *str)
54 {
55 exit(0);
56 }
57
58 static void CmdHIDdemodFSK(char *str)
59 {
60 UsbCommand c;
61 c.cmd = CMD_HID_DEMOD_FSK;
62 SendCommand(&c, FALSE);
63 }
64
65 static void CmdTune(char *str)
66 {
67 UsbCommand c;
68 c.cmd = CMD_MEASURE_ANTENNA_TUNING;
69 SendCommand(&c, FALSE);
70 }
71
72 static void CmdHi15read(char *str)
73 {
74 UsbCommand c;
75 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;
76 SendCommand(&c, FALSE);
77 }
78
79 static void CmdHi14read(char *str)
80 {
81 UsbCommand c;
82 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;
83 c.ext1 = atoi(str);
84 SendCommand(&c, FALSE);
85 }
86
87
88 /* New command to read the contents of a SRI512 tag
89 * SRI512 tags are ISO14443-B modulated memory tags,
90 * this command just dumps the contents of the memory/
91 */
92 static void CmdSri512read(char *str)
93 {
94 UsbCommand c;
95 c.cmd = CMD_READ_SRI512_TAG;
96 c.ext1 = atoi(str);
97 SendCommand(&c, FALSE);
98 }
99
100 // ## New command
101 static void CmdHi14areader(char *str)
102 {
103 UsbCommand c;
104 c.cmd = CMD_READER_ISO_14443a;
105 c.ext1 = atoi(str);
106 SendCommand(&c, FALSE);
107 }
108
109 // ## New command
110 static void CmdHi15reader(char *str)
111 {
112 UsbCommand c;
113 c.cmd = CMD_READER_ISO_15693;
114 c.ext1 = atoi(str);
115 SendCommand(&c, FALSE);
116 }
117
118 // ## New command
119 static void CmdHi15tag(char *str)
120 {
121 UsbCommand c;
122 c.cmd = CMD_SIMTAG_ISO_15693;
123 c.ext1 = atoi(str);
124 SendCommand(&c, FALSE);
125 }
126
127 static void CmdHi14read_sim(char *str)
128 {
129 UsbCommand c;
130 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM;
131 c.ext1 = atoi(str);
132 SendCommand(&c, FALSE);
133 }
134
135 static void CmdHi14readt(char *str)
136 {
137 UsbCommand c;
138 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;
139 c.ext1 = atoi(str);
140 SendCommand(&c, FALSE);
141
142 //CmdHisamplest(str);
143 while(CmdHisamplest(str,atoi(str))==0) {
144 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;
145 c.ext1 = atoi(str);
146 SendCommand(&c, FALSE);
147 }
148 RepaintGraphWindow();
149 }
150
151 static void CmdHisimlisten(char *str)
152 {
153 UsbCommand c;
154 c.cmd = CMD_SIMULATE_TAG_HF_LISTEN;
155 SendCommand(&c, FALSE);
156 }
157
158 static void CmdHi14sim(char *str)
159 {
160 UsbCommand c;
161 c.cmd = CMD_SIMULATE_TAG_ISO_14443;
162 SendCommand(&c, FALSE);
163 }
164
165
166
167 static void CmdHi14asim(char *str) // ## simulate iso14443a tag
168 { // ## greg - added ability to specify tag UID
169
170 unsigned int hi=0, lo=0;
171 int n=0, i=0;
172 UsbCommand c;
173
174 while (sscanf(&str[i++], "%1x", &n ) == 1) {
175 hi=(hi<<4)|(lo>>28);
176 lo=(lo<<4)|(n&0xf);
177 }
178
179 c.cmd = CMD_SIMULATE_TAG_ISO_14443a;
180 // c.ext should be set to *str or convert *str to the correct format for a uid
181 c.ext1 = hi;
182 c.ext2 = lo;
183 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi, lo);
184 SendCommand(&c, FALSE);
185 }
186
187 static void CmdHi14snoop(char *str)
188 {
189 UsbCommand c;
190 c.cmd = CMD_SNOOP_ISO_14443;
191 SendCommand(&c, FALSE);
192 }
193
194 static void CmdHi14asnoop(char *str)
195 {
196 UsbCommand c;
197 c.cmd = CMD_SNOOP_ISO_14443a;
198 SendCommand(&c, FALSE);
199 }
200
201 static void CmdFPGAOff(char *str) // ## FPGA Control
202 {
203 UsbCommand c;
204 c.cmd = CMD_FPGA_MAJOR_MODE_OFF;
205 SendCommand(&c, FALSE);
206 }
207
208 static void CmdLosim(char *str)
209 {
210 int i;
211
212 for(i = 0; i < GraphTraceLen; i += 48) {
213 UsbCommand c;
214 int j;
215 for(j = 0; j < 48; j++) {
216 c.d.asBytes[j] = GraphBuffer[i+j];
217 }
218 c.cmd = CMD_DOWNLOADED_SIM_SAMPLES_125K;
219 c.ext1 = i;
220 SendCommand(&c, FALSE);
221 }
222
223 UsbCommand c;
224 c.cmd = CMD_SIMULATE_TAG_125K;
225 c.ext1 = GraphTraceLen;
226 SendCommand(&c, FALSE);
227 }
228
229 static void CmdLoread(char *str)
230 {
231 UsbCommand c;
232 // 'h' means higher-low-frequency, 134 kHz
233 if(*str == 'h') {
234 c.ext1 = 1;
235 } else if (*str == '\0') {
236 c.ext1 = 0;
237 } else {
238 PrintToScrollback("use 'loread' or 'loread h'");
239 return;
240 }
241 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_125K;
242 SendCommand(&c, FALSE);
243 }
244
245 static void CmdLosamples(char *str)
246 {
247 int cnt = 0;
248 int i;
249 int n;
250
251 n=atoi(str);
252 if (n==0) n=128;
253 if (n>16000) n=16000;
254
255 for(i = 0; i < n; i += 12) {
256 UsbCommand c;
257 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
258 c.ext1 = i;
259 SendCommand(&c, FALSE);
260 ReceiveCommand(&c);
261 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
262 PrintToScrollback("bad resp\n");
263 return;
264 }
265 int j;
266 for(j = 0; j < 48; j++) {
267 GraphBuffer[cnt++] = ((int)c.d.asBytes[j]) - 128;
268 }
269 }
270 GraphTraceLen = n*4;
271 RepaintGraphWindow();
272 }
273
274 static void CmdBitsamples(char *str)
275 {
276 int cnt = 0;
277 int i;
278 int n;
279
280 n = 3072;
281 for(i = 0; i < n; i += 12) {
282 UsbCommand c;
283 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
284 c.ext1 = i;
285 SendCommand(&c, FALSE);
286 ReceiveCommand(&c);
287 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
288 PrintToScrollback("bad resp\n");
289 return;
290 }
291 int j, k;
292 for(j = 0; j < 48; j++) {
293 for(k = 0; k < 8; k++) {
294 if(c.d.asBytes[j] & (1 << (7 - k))) {
295 GraphBuffer[cnt++] = 1;
296 } else {
297 GraphBuffer[cnt++] = 0;
298 }
299 }
300 }
301 }
302 GraphTraceLen = cnt;
303 RepaintGraphWindow();
304 }
305
306 static void CmdHisamples(char *str)
307 {
308 int cnt = 0;
309 int i;
310 int n;
311 n = 1000;
312 for(i = 0; i < n; i += 12) {
313 UsbCommand c;
314 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
315 c.ext1 = i;
316 SendCommand(&c, FALSE);
317 ReceiveCommand(&c);
318 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
319 PrintToScrollback("bad resp\n");
320 return;
321 }
322 int j;
323 for(j = 0; j < 48; j++) {
324 GraphBuffer[cnt++] = (int)((BYTE)c.d.asBytes[j]);
325 }
326 }
327 GraphTraceLen = n*4;
328
329 RepaintGraphWindow();
330 }
331
332
333 static int CmdHisamplest(char *str, int nrlow)
334 {
335 int cnt = 0;
336 int t1, t2;
337 int i;
338 int n;
339 int hasbeennull;
340 int show;
341
342
343 n = 1000;
344 hasbeennull = 0;
345 for(i = 0; i < n; i += 12) {
346 UsbCommand c;
347 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
348 c.ext1 = i;
349 SendCommand(&c, FALSE);
350 ReceiveCommand(&c);
351 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
352 PrintToScrollback("bad resp\n");
353 return 0;
354 }
355 int j;
356 for(j = 0; j < 48; j++) {
357 t2 = (int)((BYTE)c.d.asBytes[j]);
358 if((t2 ^ 0xC0) & 0xC0) { hasbeennull++; }
359
360 show = 0;
361 switch(show) {
362 case 0:
363 // combined
364 t1 = (t2 & 0x80) ^ (t2 & 0x20);
365 t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x20);
366 break;
367
368 case 1:
369 // only reader
370 t1 = (t2 & 0x80);
371 t2 = ((t2 << 1) & 0x80);
372 break;
373
374 case 2:
375 // only tag
376 t1 = (t2 & 0x20);
377 t2 = ((t2 << 1) & 0x20);
378 break;
379
380 case 3:
381 // both, but tag with other algorithm
382 t1 = (t2 & 0x80) ^ (t2 & 0x08);
383 t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x08);
384 break;
385 }
386
387 GraphBuffer[cnt++] = t1;
388 GraphBuffer[cnt++] = t2;
389 }
390 }
391 GraphTraceLen = n*4;
392 // 1130
393 if(hasbeennull>nrlow || nrlow==0) {
394 PrintToScrollback("hasbeennull=%d", hasbeennull);
395 return 1;
396 }
397 else {
398 return 0;
399 }
400 }
401
402
403 static void CmdHexsamples(char *str)
404 {
405 int i;
406 int n;
407
408 if(atoi(str) == 0) {
409 n = 12;
410 } else {
411 n = atoi(str)/4;
412 }
413
414 for(i = 0; i < n; i += 12) {
415 UsbCommand c;
416 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
417 c.ext1 = i;
418 SendCommand(&c, FALSE);
419 ReceiveCommand(&c);
420 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
421 PrintToScrollback("bad resp\n");
422 return;
423 }
424 int j;
425 for(j = 0; j < 48; j += 8) {
426 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
427 c.d.asBytes[j+0],
428 c.d.asBytes[j+1],
429 c.d.asBytes[j+2],
430 c.d.asBytes[j+3],
431 c.d.asBytes[j+4],
432 c.d.asBytes[j+5],
433 c.d.asBytes[j+6],
434 c.d.asBytes[j+7],
435 c.d.asBytes[j+8]
436 );
437 }
438 }
439 }
440
441 static void CmdHisampless(char *str)
442 {
443 int cnt = 0;
444 int i;
445 int n;
446
447 if(atoi(str) == 0) {
448 n = 1000;
449 } else {
450 n = atoi(str)/4;
451 }
452
453 for(i = 0; i < n; i += 12) {
454 UsbCommand c;
455 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;
456 c.ext1 = i;
457 SendCommand(&c, FALSE);
458 ReceiveCommand(&c);
459 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
460 PrintToScrollback("bad resp\n");
461 return;
462 }
463 int j;
464 for(j = 0; j < 48; j++) {
465 GraphBuffer[cnt++] = (int)((signed char)c.d.asBytes[j]);
466 }
467 }
468 GraphTraceLen = cnt;
469
470 RepaintGraphWindow();
471 }
472
473 static WORD Iso15693Crc(BYTE *v, int n)
474 {
475 DWORD reg;
476 int i, j;
477
478 reg = 0xffff;
479 for(i = 0; i < n; i++) {
480 reg = reg ^ ((DWORD)v[i]);
481 for (j = 0; j < 8; j++) {
482 if (reg & 0x0001) {
483 reg = (reg >> 1) ^ 0x8408;
484 } else {
485 reg = (reg >> 1);
486 }
487 }
488 }
489
490 return (WORD)~reg;
491 }
492
493 static void CmdHi14bdemod(char *str)
494 {
495 int i, j, iold;
496 int isum, qsum;
497 int outOfWeakAt;
498 BOOL negateI, negateQ;
499
500 BYTE data[256];
501 int dataLen=0;
502
503 // As received, the samples are pairs, correlations against I and Q
504 // square waves. So estimate angle of initial carrier (or just
505 // quadrant, actually), and then do the demod.
506
507 // First, estimate where the tag starts modulating.
508 for(i = 0; i < GraphTraceLen; i += 2) {
509 if(abs(GraphBuffer[i]) + abs(GraphBuffer[i+1]) > 40) {
510 break;
511 }
512 }
513 if(i >= GraphTraceLen) {
514 PrintToScrollback("too weak to sync");
515 return;
516 }
517 PrintToScrollback("out of weak at %d", i);
518 outOfWeakAt = i;
519
520 // Now, estimate the phase in the initial modulation of the tag
521 isum = 0;
522 qsum = 0;
523 for(; i < (outOfWeakAt + 16); i += 2) {
524 isum += GraphBuffer[i+0];
525 qsum += GraphBuffer[i+1];
526 }
527 negateI = (isum < 0);
528 negateQ = (qsum < 0);
529
530 // Turn the correlation pairs into soft decisions on the bit.
531 j = 0;
532 for(i = 0; i < GraphTraceLen/2; i++) {
533 int si = GraphBuffer[j];
534 int sq = GraphBuffer[j+1];
535 if(negateI) si = -si;
536 if(negateQ) sq = -sq;
537 GraphBuffer[i] = si + sq;
538 j += 2;
539 }
540 GraphTraceLen = i;
541
542 i = outOfWeakAt/2;
543 while(GraphBuffer[i] > 0 && i < GraphTraceLen)
544 i++;
545 if(i >= GraphTraceLen) goto demodError;
546
547 iold = i;
548 while(GraphBuffer[i] < 0 && i < GraphTraceLen)
549 i++;
550 if(i >= GraphTraceLen) goto demodError;
551 if((i - iold) > 23) goto demodError;
552
553 PrintToScrollback("make it to demod loop");
554
555 for(;;) {
556 iold = i;
557 while(GraphBuffer[i] >= 0 && i < GraphTraceLen)
558 i++;
559 if(i >= GraphTraceLen) goto demodError;
560 if((i - iold) > 6) goto demodError;
561
562 WORD shiftReg = 0;
563 if(i + 20 >= GraphTraceLen) goto demodError;
564
565 for(j = 0; j < 10; j++) {
566 int soft = GraphBuffer[i] + GraphBuffer[i+1];
567
568 if(abs(soft) < ((abs(isum) + abs(qsum))/20)) {
569 PrintToScrollback("weak bit");
570 }
571
572 shiftReg >>= 1;
573 if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {
574 shiftReg |= 0x200;
575 }
576
577 i+= 2;
578 }
579
580 if( (shiftReg & 0x200) &&
581 !(shiftReg & 0x001))
582 {
583 // valid data byte, start and stop bits okay
584 PrintToScrollback(" %02x", (shiftReg >> 1) & 0xff);
585 data[dataLen++] = (shiftReg >> 1) & 0xff;
586 if(dataLen >= sizeof(data)) {
587 return;
588 }
589 } else if(shiftReg == 0x000) {
590 // this is EOF
591 break;
592 } else {
593 goto demodError;
594 }
595 }
596
597 BYTE first, second;
598 ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);
599 PrintToScrollback("CRC: %02x %02x (%s)\n", first, second,
600 (first == data[dataLen-2] && second == data[dataLen-1]) ?
601 "ok" : "****FAIL****");
602
603 RepaintGraphWindow();
604 return;
605
606 demodError:
607 PrintToScrollback("demod error");
608 RepaintGraphWindow();
609 }
610
611 static void CmdHi14list(char *str)
612 {
613 BYTE got[960];
614 GetFromBigBuf(got, sizeof(got));
615
616 PrintToScrollback("recorded activity:");
617 PrintToScrollback(" time :rssi: who bytes");
618 PrintToScrollback("---------+----+----+-----------");
619
620 int i = 0;
621 int prev = -1;
622
623 for(;;) {
624 if(i >= 900) {
625 break;
626 }
627
628 BOOL isResponse;
629 int timestamp = *((DWORD *)(got+i));
630 if(timestamp & 0x80000000) {
631 timestamp &= 0x7fffffff;
632 isResponse = 1;
633 } else {
634 isResponse = 0;
635 }
636 int metric = *((DWORD *)(got+i+4));
637
638 int len = got[i+8];
639
640 if(len > 100) {
641 break;
642 }
643 if(i + len >= 900) {
644 break;
645 }
646
647 BYTE *frame = (got+i+9);
648
649 char line[1000] = "";
650 int j;
651 for(j = 0; j < len; j++) {
652 sprintf(line+(j*3), "%02x ", frame[j]);
653 }
654
655 char *crc;
656 if(len > 2) {
657 BYTE b1, b2;
658 ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2);
659 if(b1 != frame[len-2] || b2 != frame[len-1]) {
660 crc = "**FAIL CRC**";
661 } else {
662 crc = "";
663 }
664 } else {
665 crc = "(SHORT)";
666 }
667
668 char metricString[100];
669 if(isResponse) {
670 sprintf(metricString, "%3d", metric);
671 } else {
672 strcpy(metricString, " ");
673 }
674
675 PrintToScrollback(" +%7d: %s: %s %s %s",
676 (prev < 0 ? 0 : timestamp - prev),
677 metricString,
678 (isResponse ? "TAG" : " "), line, crc);
679
680 prev = timestamp;
681 i += (len + 9);
682 }
683 }
684
685 static void CmdHi14alist(char *str)
686 {
687 BYTE got[1920];
688 GetFromBigBuf(got, sizeof(got));
689
690 PrintToScrollback("recorded activity:");
691 PrintToScrollback(" ETU :rssi: who bytes");
692 PrintToScrollback("---------+----+----+-----------");
693
694 int i = 0;
695 int prev = -1;
696
697 for(;;) {
698 if(i >= 1900) {
699 break;
700 }
701
702 BOOL isResponse;
703 int timestamp = *((DWORD *)(got+i));
704 if(timestamp & 0x80000000) {
705 timestamp &= 0x7fffffff;
706 isResponse = 1;
707 } else {
708 isResponse = 0;
709 }
710
711 int metric = 0;
712 int parityBits = *((DWORD *)(got+i+4));
713 // 4 bytes of additional information...
714 // maximum of 32 additional parity bit information
715 //
716 // TODO:
717 // at each quarter bit period we can send power level (16 levels)
718 // or each half bit period in 256 levels.
719
720
721 int len = got[i+8];
722
723 if(len > 100) {
724 break;
725 }
726 if(i + len >= 1900) {
727 break;
728 }
729
730 BYTE *frame = (got+i+9);
731
732 // Break and stick with current result if buffer was not completely full
733 if(frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }
734
735 char line[1000] = "";
736 int j;
737 for(j = 0; j < len; j++) {
738 int oddparity = 0x01;
739 int k;
740
741 for(k=0;k<8;k++) {
742 oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
743 }
744
745 //if((parityBits >> (len - j - 1)) & 0x01) {
746 if(isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {
747 sprintf(line+(j*4), "%02x! ", frame[j]);
748 }
749 else {
750 sprintf(line+(j*4), "%02x ", frame[j]);
751 }
752 }
753
754 char *crc;
755 crc = "";
756 if(len > 2) {
757 BYTE b1, b2;
758 for(j = 0; j < (len - 1); j++) {
759 // gives problems... search for the reason..
760 /*if(frame[j] == 0xAA) {
761 switch(frame[j+1]) {
762 case 0x01:
763 crc = "[1] Two drops close after each other";
764 break;
765 case 0x02:
766 crc = "[2] Potential SOC with a drop in second half of bitperiod";
767 break;
768 case 0x03:
769 crc = "[3] Segment Z after segment X is not possible";
770 break;
771 case 0x04:
772 crc = "[4] Parity bit of a fully received byte was wrong";
773 break;
774 default:
775 crc = "[?] Unknown error";
776 break;
777 }
778 break;
779 }*/
780 }
781
782 if(strlen(crc)==0) {
783 ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2);
784 if(b1 != frame[len-2] || b2 != frame[len-1]) {
785 crc = (isResponse & (len < 6)) ? "" : " !crc";
786 } else {
787 crc = "";
788 }
789 }
790 } else {
791 crc = ""; // SHORT
792 }
793
794 char metricString[100];
795 if(isResponse) {
796 sprintf(metricString, "%3d", metric);
797 } else {
798 strcpy(metricString, " ");
799 }
800
801 PrintToScrollback(" +%7d: %s: %s %s %s",
802 (prev < 0 ? 0 : (timestamp - prev)),
803 metricString,
804 (isResponse ? "TAG" : " "), line, crc);
805
806 prev = timestamp;
807 i += (len + 9);
808 }
809 CommandFinished = 1;
810 }
811
812 static void CmdHi15demod(char *str)
813 {
814 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
815
816 // SOF defined as
817 // 1) Unmodulated time of 56.64us
818 // 2) 24 pulses of 423.75khz
819 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
820
821 static const int FrameSOF[] = {
822 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
823 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
824 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
825 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
826 -1, -1, -1, -1,
827 -1, -1, -1, -1,
828 1, 1, 1, 1,
829 1, 1, 1, 1
830 };
831 static const int Logic0[] = {
832 1, 1, 1, 1,
833 1, 1, 1, 1,
834 -1, -1, -1, -1,
835 -1, -1, -1, -1
836 };
837 static const int Logic1[] = {
838 -1, -1, -1, -1,
839 -1, -1, -1, -1,
840 1, 1, 1, 1,
841 1, 1, 1, 1
842 };
843
844 // EOF defined as
845 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
846 // 2) 24 pulses of 423.75khz
847 // 3) Unmodulated time of 56.64us
848
849 static const int FrameEOF[] = {
850 1, 1, 1, 1,
851 1, 1, 1, 1,
852 -1, -1, -1, -1,
853 -1, -1, -1, -1,
854 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
855 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
856 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
857 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
858 };
859
860 int i, j;
861 int max = 0, maxPos;
862
863 int skip = 4;
864
865 if(GraphTraceLen < 1000) return;
866
867 // First, correlate for SOF
868 for(i = 0; i < 100; i++) {
869 int corr = 0;
870 for(j = 0; j < arraylen(FrameSOF); j += skip) {
871 corr += FrameSOF[j]*GraphBuffer[i+(j/skip)];
872 }
873 if(corr > max) {
874 max = corr;
875 maxPos = i;
876 }
877 }
878 PrintToScrollback("SOF at %d, correlation %d", maxPos,
879 max/(arraylen(FrameSOF)/skip));
880
881 i = maxPos + arraylen(FrameSOF)/skip;
882 int k = 0;
883 BYTE outBuf[20];
884 memset(outBuf, 0, sizeof(outBuf));
885 BYTE mask = 0x01;
886 for(;;) {
887 int corr0 = 0, corr1 = 0, corrEOF = 0;
888 for(j = 0; j < arraylen(Logic0); j += skip) {
889 corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];
890 }
891 for(j = 0; j < arraylen(Logic1); j += skip) {
892 corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];
893 }
894 for(j = 0; j < arraylen(FrameEOF); j += skip) {
895 corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];
896 }
897 // Even things out by the length of the target waveform.
898 corr0 *= 4;
899 corr1 *= 4;
900
901 if(corrEOF > corr1 && corrEOF > corr0) {
902 PrintToScrollback("EOF at %d", i);
903 break;
904 } else if(corr1 > corr0) {
905 i += arraylen(Logic1)/skip;
906 outBuf[k] |= mask;
907 } else {
908 i += arraylen(Logic0)/skip;
909 }
910 mask <<= 1;
911 if(mask == 0) {
912 k++;
913 mask = 0x01;
914 }
915 if((i+(int)arraylen(FrameEOF)) >= GraphTraceLen) {
916 PrintToScrollback("ran off end!");
917 break;
918 }
919 }
920 if(mask != 0x01) {
921 PrintToScrollback("error, uneven octet! (discard extra bits!)");
922 PrintToScrollback(" mask=%02x", mask);
923 }
924 PrintToScrollback("%d octets", k);
925
926 for(i = 0; i < k; i++) {
927 PrintToScrollback("# %2d: %02x ", i, outBuf[i]);
928 }
929 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));
930 }
931
932 static void CmdTiread(char *str)
933 {
934 UsbCommand c;
935 c.cmd = CMD_ACQUIRE_RAW_BITS_TI_TYPE;
936 SendCommand(&c, FALSE);
937 }
938
939 static void CmdTibits(char *str)
940 {
941 int cnt = 0;
942 int i;
943 for(i = 0; i < 1536; i += 12) {
944 UsbCommand c;
945 c.cmd = CMD_DOWNLOAD_RAW_BITS_TI_TYPE;
946 c.ext1 = i;
947 SendCommand(&c, FALSE);
948 ReceiveCommand(&c);
949 if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {
950 PrintToScrollback("bad resp\n");
951 return;
952 }
953 int j;
954 for(j = 0; j < 12; j++) {
955 int k;
956 for(k = 31; k >= 0; k--) {
957 if(c.d.asDwords[j] & (1 << k)) {
958 GraphBuffer[cnt++] = 1;
959 } else {
960 GraphBuffer[cnt++] = -1;
961 }
962 }
963 }
964 }
965 GraphTraceLen = 1536*32;
966 RepaintGraphWindow();
967 }
968
969 static void CmdTidemod(char *cmdline)
970 {
971 /* MATLAB as follows:
972 f_s = 2000000; % sampling frequency
973 f_l = 123200; % low FSK tone
974 f_h = 134200; % high FSK tone
975
976 T_l = 119e-6; % low bit duration
977 T_h = 130e-6; % high bit duration
978
979 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
980 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
981
982 l = sign(sin(cumsum(l)));
983 h = sign(sin(cumsum(h)));
984 */
985 static const int LowTone[] = {
986 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,
987 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
988 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
989 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
990 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,
991 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
992 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,
993 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
994 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
995 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,
996 -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
997 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
998 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
999 };
1000 static const int HighTone[] = {
1001 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1002 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1003 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1004 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1005 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1006 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1007 -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1008 -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1009 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1010 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1011 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1012 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1013 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1014 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,
1015 };
1016
1017 int convLen = max(arraylen(HighTone), arraylen(LowTone));
1018
1019 int i;
1020 for(i = 0; i < GraphTraceLen - convLen; i++) {
1021 int j;
1022 int lowSum = 0, highSum = 0;;
1023 int lowLen = arraylen(LowTone);
1024 int highLen = arraylen(HighTone);
1025
1026 for(j = 0; j < lowLen; j++) {
1027 lowSum += LowTone[j]*GraphBuffer[i+j];
1028 }
1029 for(j = 0; j < highLen; j++) {
1030 highSum += HighTone[j]*GraphBuffer[i+j];
1031 }
1032 lowSum = abs((100*lowSum) / lowLen);
1033 highSum = abs((100*highSum) / highLen);
1034 GraphBuffer[i] = (highSum << 16) | lowSum;
1035 }
1036
1037 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {
1038 int j;
1039 int lowTot = 0, highTot = 0;
1040 // 16 and 15 are f_s divided by f_l and f_h, rounded
1041 for(j = 0; j < 16; j++) {
1042 lowTot += (GraphBuffer[i+j] & 0xffff);
1043 }
1044 for(j = 0; j < 15; j++) {
1045 highTot += (GraphBuffer[i+j] >> 16);
1046 }
1047 GraphBuffer[i] = lowTot - highTot;
1048 }
1049
1050 GraphTraceLen -= (convLen + 16);
1051
1052 RepaintGraphWindow();
1053
1054 // Okay, so now we have unsliced soft decisions; find bit-sync, and then
1055 // get some bits.
1056
1057 int max = 0, maxPos = 0;
1058 for(i = 0; i < 6000; i++) {
1059 int j;
1060 int dec = 0;
1061 for(j = 0; j < 8*arraylen(LowTone); j++) {
1062 dec -= GraphBuffer[i+j];
1063 }
1064 for(; j < 8*arraylen(LowTone) + 8*arraylen(HighTone); j++) {
1065 dec += GraphBuffer[i+j];
1066 }
1067 if(dec > max) {
1068 max = dec;
1069 maxPos = i;
1070 }
1071 }
1072 GraphBuffer[maxPos] = 800;
1073 GraphBuffer[maxPos+1] = -800;
1074
1075 maxPos += 8*arraylen(LowTone);
1076 GraphBuffer[maxPos] = 800;
1077 GraphBuffer[maxPos+1] = -800;
1078 maxPos += 8*arraylen(HighTone);
1079
1080 GraphBuffer[maxPos] = 800;
1081 GraphBuffer[maxPos+1] = -800;
1082
1083 PrintToScrollback("actual data bits start at sample %d", maxPos);
1084
1085 PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));
1086
1087 GraphBuffer[maxPos] = 800;
1088 GraphBuffer[maxPos+1] = -800;
1089
1090 BYTE bits[64+16+8+1];
1091 bits[sizeof(bits)-1] = '\0';
1092
1093 for(i = 0; i < arraylen(bits); i++) {
1094 int high = 0;
1095 int low = 0;
1096 int j;
1097 for(j = 0; j < arraylen(LowTone); j++) {
1098 low -= GraphBuffer[maxPos+j];
1099 }
1100 for(j = 0; j < arraylen(HighTone); j++) {
1101 high += GraphBuffer[maxPos+j];
1102 }
1103 if(high > low) {
1104 bits[i] = '1';
1105 maxPos += arraylen(HighTone);
1106 } else {
1107 bits[i] = '.';
1108 maxPos += arraylen(LowTone);
1109 }
1110 GraphBuffer[maxPos] = 800;
1111 GraphBuffer[maxPos+1] = -800;
1112 }
1113 PrintToScrollback("bits: '%s'", bits);
1114
1115 DWORD h = 0, l = 0;
1116 for(i = 0; i < 32; i++) {
1117 if(bits[i] == '1') {
1118 l |= (1<<i);
1119 }
1120 }
1121 for(i = 32; i < 64; i++) {
1122 if(bits[i] == '1') {
1123 h |= (1<<(i-32));
1124 }
1125 }
1126 PrintToScrollback("hex: %08x %08x", h, l);
1127 }
1128
1129 static void CmdNorm(char *str)
1130 {
1131 int i;
1132 int max = INT_MIN, min = INT_MAX;
1133 for(i = 10; i < GraphTraceLen; i++) {
1134 if(GraphBuffer[i] > max) {
1135 max = GraphBuffer[i];
1136 }
1137 if(GraphBuffer[i] < min) {
1138 min = GraphBuffer[i];
1139 }
1140 }
1141 if(max != min) {
1142 for(i = 0; i < GraphTraceLen; i++) {
1143 GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/
1144 (max - min);
1145 }
1146 }
1147 RepaintGraphWindow();
1148 }
1149
1150 static void CmdDec(char *str)
1151 {
1152 int i;
1153 for(i = 0; i < (GraphTraceLen/2); i++) {
1154 GraphBuffer[i] = GraphBuffer[i*2];
1155 }
1156 GraphTraceLen /= 2;
1157 PrintToScrollback("decimated by 2");
1158 RepaintGraphWindow();
1159 }
1160
1161 static void CmdHpf(char *str)
1162 {
1163 int i;
1164 int accum = 0;
1165 for(i = 10; i < GraphTraceLen; i++) {
1166 accum += GraphBuffer[i];
1167 }
1168 accum /= (GraphTraceLen - 10);
1169 for(i = 0; i < GraphTraceLen; i++) {
1170 GraphBuffer[i] -= accum;
1171 }
1172
1173 RepaintGraphWindow();
1174 }
1175
1176 static void CmdZerocrossings(char *str)
1177 {
1178 int i;
1179 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1180 CmdHpf("");
1181
1182 int sign = 1;
1183 int zc = 0;
1184 int lastZc = 0;
1185 for(i = 0; i < GraphTraceLen; i++) {
1186 if(GraphBuffer[i]*sign >= 0) {
1187 // No change in sign, reproduce the previous sample count.
1188 zc++;
1189 GraphBuffer[i] = lastZc;
1190 } else {
1191 // Change in sign, reset the sample count.
1192 sign = -sign;
1193 GraphBuffer[i] = lastZc;
1194 if(sign > 0) {
1195 lastZc = zc;
1196 zc = 0;
1197 }
1198 }
1199 }
1200
1201 RepaintGraphWindow();
1202 }
1203
1204 static void CmdLtrim(char *str)
1205 {
1206 int i;
1207 int ds = atoi(str);
1208
1209 for(i = ds; i < GraphTraceLen; i++) {
1210 GraphBuffer[i-ds] = GraphBuffer[i];
1211 }
1212 GraphTraceLen -= ds;
1213
1214 RepaintGraphWindow();
1215 }
1216
1217 static void CmdAutoCorr(char *str)
1218 {
1219 static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];
1220
1221 int window = atoi(str);
1222
1223 if(window == 0) {
1224 PrintToScrollback("needs a window");
1225 return;
1226 }
1227
1228 if(window >= GraphTraceLen) {
1229 PrintToScrollback("window must be smaller than trace (%d samples)",
1230 GraphTraceLen);
1231 return;
1232 }
1233
1234 PrintToScrollback("performing %d correlations", GraphTraceLen - window);
1235
1236 int i;
1237 for(i = 0; i < GraphTraceLen - window; i++) {
1238 int sum = 0;
1239 int j;
1240 for(j = 0; j < window; j++) {
1241 sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;
1242 }
1243 CorrelBuffer[i] = sum;
1244 }
1245 GraphTraceLen = GraphTraceLen - window;
1246 memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));
1247
1248 RepaintGraphWindow();
1249 }
1250
1251 static void CmdVchdemod(char *str)
1252 {
1253 // Is this the entire sync pattern, or does this also include some
1254 // data bits that happen to be the same everywhere? That would be
1255 // lovely to know.
1256 static const int SyncPattern[] = {
1257 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1258 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1259 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1260 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1261 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1262 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1263 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1264 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1265 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1266 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1267 };
1268
1269 // So first, we correlate for the sync pattern, and mark that.
1270 int bestCorrel = 0, bestPos = 0;
1271 int i;
1272 // It does us no good to find the sync pattern, with fewer than
1273 // 2048 samples after it...
1274 for(i = 0; i < (GraphTraceLen-2048); i++) {
1275 int sum = 0;
1276 int j;
1277 for(j = 0; j < arraylen(SyncPattern); j++) {
1278 sum += GraphBuffer[i+j]*SyncPattern[j];
1279 }
1280 if(sum > bestCorrel) {
1281 bestCorrel = sum;
1282 bestPos = i;
1283 }
1284 }
1285 PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);
1286
1287 char bits[257];
1288 bits[256] = '\0';
1289
1290 int worst = INT_MAX;
1291 int worstPos;
1292
1293 for(i = 0; i < 2048; i += 8) {
1294 int sum = 0;
1295 int j;
1296 for(j = 0; j < 8; j++) {
1297 sum += GraphBuffer[bestPos+i+j];
1298 }
1299 if(sum < 0) {
1300 bits[i/8] = '.';
1301 } else {
1302 bits[i/8] = '1';
1303 }
1304 if(abs(sum) < worst) {
1305 worst = abs(sum);
1306 worstPos = i;
1307 }
1308 }
1309 PrintToScrollback("bits:");
1310 PrintToScrollback("%s", bits);
1311 PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);
1312
1313 if(strcmp(str, "clone")==0) {
1314 GraphTraceLen = 0;
1315 char *s;
1316 for(s = bits; *s; s++) {
1317 int j;
1318 for(j = 0; j < 16; j++) {
1319 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
1320 }
1321 }
1322 RepaintGraphWindow();
1323 }
1324 }
1325
1326 static void CmdIndalademod(char *str)
1327 {
1328 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
1329
1330 int state = -1;
1331 int count = 0;
1332 int i, j;
1333 // worst case with GraphTraceLen=64000 is < 4096
1334 // under normal conditions it's < 2048
1335 BYTE rawbits[4096];
1336 int rawbit = 0;
1337 int worst = 0, worstPos = 0;
1338 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen/32);
1339 for(i = 0; i < GraphTraceLen-1; i += 2) {
1340 count+=1;
1341 if((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
1342 if (state == 0) {
1343 for(j = 0; j < count - 8; j += 16) {
1344 rawbits[rawbit++] = 0;
1345 }
1346 if ((abs(count - j)) > worst) {
1347 worst = abs(count - j);
1348 worstPos = i;
1349 }
1350 }
1351 state = 1;
1352 count=0;
1353 } else if((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
1354 if (state == 1) {
1355 for(j = 0; j < count - 8; j += 16) {
1356 rawbits[rawbit++] = 1;
1357 }
1358 if ((abs(count - j)) > worst) {
1359 worst = abs(count - j);
1360 worstPos = i;
1361 }
1362 }
1363 state = 0;
1364 count=0;
1365 }
1366 }
1367 PrintToScrollback("Recovered %d raw bits", rawbit);
1368 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
1369
1370 // Finding the start of a UID
1371 int uidlen, long_wait;
1372 if(strcmp(str, "224") == 0) {
1373 uidlen=224;
1374 long_wait=30;
1375 } else {
1376 uidlen=64;
1377 long_wait=29;
1378 }
1379 int start;
1380 int first = 0;
1381 for(start = 0; start <= rawbit - uidlen; start++) {
1382 first = rawbits[start];
1383 for(i = start; i < start + long_wait; i++) {
1384 if(rawbits[i] != first) {
1385 break;
1386 }
1387 }
1388 if(i == (start + long_wait)) {
1389 break;
1390 }
1391 }
1392 if(start == rawbit - uidlen + 1) {
1393 PrintToScrollback("nothing to wait for");
1394 return;
1395 }
1396
1397 // Inverting signal if needed
1398 if(first == 1) {
1399 for(i = start; i < rawbit; i++) {
1400 rawbits[i] = !rawbits[i];
1401 }
1402 }
1403
1404 // Dumping UID
1405 BYTE bits[224];
1406 char showbits[225];
1407 showbits[uidlen]='\0';
1408 int bit;
1409 i = start;
1410 int times = 0;
1411 if(uidlen > rawbit) {
1412 PrintToScrollback("Warning: not enough raw bits to get a full UID");
1413 for(bit = 0; bit < rawbit; bit++) {
1414 bits[bit] = rawbits[i++];
1415 // As we cannot know the parity, let's use "." and "/"
1416 showbits[bit] = '.' + bits[bit];
1417 }
1418 showbits[bit+1]='\0';
1419 PrintToScrollback("Partial UID=%s", showbits);
1420 return;
1421 } else {
1422 for(bit = 0; bit < uidlen; bit++) {
1423 bits[bit] = rawbits[i++];
1424 showbits[bit] = '0' + bits[bit];
1425 }
1426 times = 1;
1427 }
1428 PrintToScrollback("UID=%s", showbits);
1429
1430 // Checking UID against next occurences
1431 for(; i + uidlen <= rawbit;) {
1432 int failed = 0;
1433 for(bit = 0; bit < uidlen; bit++) {
1434 if(bits[bit] != rawbits[i++]) {
1435 failed = 1;
1436 break;
1437 }
1438 }
1439 if (failed == 1) {
1440 break;
1441 }
1442 times += 1;
1443 }
1444 PrintToScrollback("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);
1445
1446 // Remodulating for tag cloning
1447 GraphTraceLen = 32*uidlen;
1448 i = 0;
1449 int phase = 0;
1450 for(bit = 0; bit < uidlen; bit++) {
1451 if(bits[bit] == 0) {
1452 phase = 0;
1453 } else {
1454 phase = 1;
1455 }
1456 int j;
1457 for(j = 0; j < 32; j++) {
1458 GraphBuffer[i++] = phase;
1459 phase = !phase;
1460 }
1461 }
1462
1463 RepaintGraphWindow();
1464 }
1465
1466 static void CmdFlexdemod(char *str)
1467 {
1468 int i;
1469 for(i = 0; i < GraphTraceLen; i++) {
1470 if(GraphBuffer[i] < 0) {
1471 GraphBuffer[i] = -1;
1472 } else {
1473 GraphBuffer[i] = 1;
1474 }
1475 }
1476
1477 #define LONG_WAIT 100
1478 int start;
1479 for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
1480 int first = GraphBuffer[start];
1481 for(i = start; i < start + LONG_WAIT; i++) {
1482 if(GraphBuffer[i] != first) {
1483 break;
1484 }
1485 }
1486 if(i == (start + LONG_WAIT)) {
1487 break;
1488 }
1489 }
1490 if(start == GraphTraceLen - LONG_WAIT) {
1491 PrintToScrollback("nothing to wait for");
1492 return;
1493 }
1494
1495 GraphBuffer[start] = 2;
1496 GraphBuffer[start+1] = -2;
1497
1498 BYTE bits[64];
1499
1500 int bit;
1501 i = start;
1502 for(bit = 0; bit < 64; bit++) {
1503 int j;
1504 int sum = 0;
1505 for(j = 0; j < 16; j++) {
1506 sum += GraphBuffer[i++];
1507 }
1508 if(sum > 0) {
1509 bits[bit] = 1;
1510 } else {
1511 bits[bit] = 0;
1512 }
1513 PrintToScrollback("bit %d sum %d", bit, sum);
1514 }
1515
1516 for(bit = 0; bit < 64; bit++) {
1517 int j;
1518 int sum = 0;
1519 for(j = 0; j < 16; j++) {
1520 sum += GraphBuffer[i++];
1521 }
1522 if(sum > 0 && bits[bit] != 1) {
1523 PrintToScrollback("oops1 at %d", bit);
1524 }
1525 if(sum < 0 && bits[bit] != 0) {
1526 PrintToScrollback("oops2 at %d", bit);
1527 }
1528 }
1529
1530 GraphTraceLen = 32*64;
1531 i = 0;
1532 int phase = 0;
1533 for(bit = 0; bit < 64; bit++) {
1534 if(bits[bit] == 0) {
1535 phase = 0;
1536 } else {
1537 phase = 1;
1538 }
1539 int j;
1540 for(j = 0; j < 32; j++) {
1541 GraphBuffer[i++] = phase;
1542 phase = !phase;
1543 }
1544 }
1545
1546 RepaintGraphWindow();
1547 }
1548
1549 /*
1550 * Generic command to demodulate ASK. bit length in argument.
1551 * Giving the bit length helps discriminate ripple effects
1552 * upon zero crossing for noisy traces.
1553 *
1554 * Second is convention: positive or negative (High mod means zero
1555 * or high mod means one)
1556 *
1557 * Updates the Graph trace with 0/1 values
1558 *
1559 * Arguments:
1560 * sl : bit length in terms of number of samples per bit
1561 * (use yellow/purple markers to compute).
1562 * c : 0 or 1
1563 */
1564
1565 static void Cmdaskdemod(char *str) {
1566 int i;
1567 int sign = 1;
1568 int n = 0;
1569 int c = 0;
1570 int t1 = 0;
1571
1572 // TODO: complain if we do not give 2 arguments here !
1573 sscanf(str, "%i %i", &n, &c);
1574 if (c == 0) {
1575 c = 1 ;
1576 } else {
1577 c = -1;
1578 }
1579
1580 if (GraphBuffer[0]*c > 0) {
1581 GraphBuffer[0] = 1;
1582 } else {
1583 GraphBuffer[0] = 0;
1584 }
1585 for(i=1;i<GraphTraceLen;i++) {
1586 /* Analyse signal within the symbol length */
1587 /* Decide if we crossed a zero */
1588 if (GraphBuffer[i]*sign < 0) {
1589 /* Crossed a zero, check if this is a ripple or not */
1590 if ( (i-t1) > n/4 ) {
1591 sign = -sign;
1592 t1=i;
1593 if (GraphBuffer[i]*c > 0){
1594 GraphBuffer[i]=1;
1595 } else {
1596 GraphBuffer[i]=0;
1597 }
1598 } else {
1599 /* This is a ripple, set the current sample value
1600 to the same as previous */
1601 GraphBuffer[i] = GraphBuffer[i-1];
1602 }
1603 } else {
1604 GraphBuffer[i] = GraphBuffer[i-1];
1605 }
1606 }
1607 RepaintGraphWindow();
1608 }
1609
1610
1611 /*
1612 * Manchester demodulate a bitstream. The bitstream needs to be already in
1613 * the GraphBuffer as 0 and 1 values
1614 *
1615 * Give the clock rate as argument in order to help the sync - the algorithm
1616 * resyncs at each pulse anyway.
1617 *
1618 * Not optimized by any means, this is the 1st time I'm writing this type of
1619 * routine, feel free to improve...
1620 *
1621 * 1st argument: clock rate (as number of samples per clock rate)
1622 * Typical values can be 64, 32, 128...
1623 */
1624 static void Cmdmanchesterdemod(char *str) {
1625 int i, j;
1626 int bit;
1627 int clock;
1628 int lastval;
1629 int low = 0;
1630 int high = 0;
1631 int hithigh, hitlow, first;
1632 int lc = 0;
1633 int bitidx = 0;
1634 int bit2idx = 0;
1635 int warnings = 0;
1636
1637 sscanf(str, "%i", &clock);
1638 if (!clock)
1639 {
1640 PrintToScrollback("You must provide a clock rate.");
1641 return;
1642 }
1643
1644 int tolerance = clock/4;
1645 /* Holds the decoded bitstream: each clock period contains 2 bits */
1646 /* later simplified to 1 bit after manchester decoding. */
1647 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
1648 /* int BitStream[GraphTraceLen*2/clock+10]; */
1649
1650 /* But it does not work if compiling on WIndows: therefore we just allocate a */
1651 /* large array */
1652 int BitStream[MAX_GRAPH_TRACE_LEN];
1653
1654 /* Detect high and lows */
1655 for (i = 0; i < GraphTraceLen; i++)
1656 {
1657 if (GraphBuffer[i] > high)
1658 high = GraphBuffer[i];
1659 else if (GraphBuffer[i] < low)
1660 low = GraphBuffer[i];
1661 }
1662
1663 /* Detect first transition */
1664 /* Lo-Hi (arbitrary) */
1665 for (i = 0; i < GraphTraceLen; i++)
1666 {
1667 if (GraphBuffer[i] == low)
1668 {
1669 // BitStream[0]=0; // Previous state = 0;
1670 lastval = i;
1671 break;
1672 }
1673 }
1674 //PrintToScrollback("cool %d %d %d %d", low, high, lastval, GraphBuffer[i]);
1675
1676 /* If we're not working with 1/0s, demod based off clock */
1677 if (high != 1)
1678 {
1679 bit = 0;
1680 for (i = 0; i < (GraphTraceLen / clock); i++)
1681 {
1682 hithigh = 0;
1683 hitlow = 0;
1684 first = 1;
1685
1686 /* Find out if we hit both high and low peaks */
1687 for (j = 0; j < clock; j++)
1688 {
1689 if (GraphBuffer[(i * clock) + j] == high)
1690 hithigh = 1;
1691 else if (GraphBuffer[(i * clock) + j] == low)
1692 hitlow = 1;
1693
1694 /* it doesn't count if it's the first part of our read
1695 because it's really just trailing from the last sequence */
1696 if (first && (hithigh || hitlow))
1697 hithigh = hitlow = 0;
1698 else
1699 first = 0;
1700
1701 if (hithigh && hitlow)
1702 break;
1703 }
1704
1705 /* If we didn't hit both high and low peaks, we had a bit transition */
1706 if (!hithigh || !hitlow)
1707 bit ^= 1;
1708
1709 BitStream[bit2idx++] = bit;
1710 }
1711 }
1712
1713 /* standard 1/0 bitstream */
1714 else
1715 {
1716
1717 /* Then detect duration between 2 successive transitions */
1718 for (bitidx = 1; i < GraphTraceLen; i++)
1719 {
1720 if (GraphBuffer[i-1] != GraphBuffer[i])
1721 {
1722 lc = i-lastval;
1723 lastval = i;
1724
1725 // Error check: if bitidx becomes too large, we do not
1726 // have a Manchester encoded bitstream or the clock is really
1727 // wrong!
1728 if (bitidx > (GraphTraceLen*2/clock+8) ) {
1729 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
1730 return;
1731 }
1732 // Then switch depending on lc length:
1733 // Tolerance is 1/4 of clock rate (arbitrary)
1734 if (abs(lc-clock/2) < tolerance) {
1735 // Short pulse : either "1" or "0"
1736 BitStream[bitidx++]=GraphBuffer[i-1];
1737 } else if (abs(lc-clock) < tolerance) {
1738 // Long pulse: either "11" or "00"
1739 BitStream[bitidx++]=GraphBuffer[i-1];
1740 BitStream[bitidx++]=GraphBuffer[i-1];
1741 } else {
1742 // Error
1743 warnings++;
1744 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
1745 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
1746
1747 if (warnings > 100)
1748 {
1749 PrintToScrollback("Error: too many detection errors, aborting.");
1750 return;
1751 }
1752 }
1753 }
1754 }
1755
1756 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
1757 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
1758 // to stop output at the final bitidx2 value, not bitidx
1759 for (i = 0; i < bitidx; i += 2) {
1760 if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {
1761 BitStream[bit2idx++] = 1;
1762 } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {
1763 BitStream[bit2idx++] = 0;
1764 } else {
1765 // We cannot end up in this state, this means we are unsynchronized,
1766 // move up 1 bit:
1767 i++;
1768 warnings++;
1769 PrintToScrollback("Unsynchronized, resync...");
1770 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
1771
1772 if (warnings > 100)
1773 {
1774 PrintToScrollback("Error: too many decode errors, aborting.");
1775 return;
1776 }
1777 }
1778 }
1779 }
1780
1781 PrintToScrollback("Manchester decoded bitstream");
1782 // Now output the bitstream to the scrollback by line of 16 bits
1783 for (i = 0; i < (bit2idx-16); i+=16) {
1784 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
1785 BitStream[i],
1786 BitStream[i+1],
1787 BitStream[i+2],
1788 BitStream[i+3],
1789 BitStream[i+4],
1790 BitStream[i+5],
1791 BitStream[i+6],
1792 BitStream[i+7],
1793 BitStream[i+8],
1794 BitStream[i+9],
1795 BitStream[i+10],
1796 BitStream[i+11],
1797 BitStream[i+12],
1798 BitStream[i+13],
1799 BitStream[i+14],
1800 BitStream[i+15]);
1801 }
1802 }
1803
1804
1805
1806 /*
1807 * Usage ???
1808 */
1809 static void CmdHiddemod(char *str)
1810 {
1811 if(GraphTraceLen < 4800) {
1812 PrintToScrollback("too short; need at least 4800 samples");
1813 return;
1814 }
1815
1816 GraphTraceLen = 4800;
1817 int i;
1818 for(i = 0; i < GraphTraceLen; i++) {
1819 if(GraphBuffer[i] < 0) {
1820 GraphBuffer[i] = 0;
1821 } else {
1822 GraphBuffer[i] = 1;
1823 }
1824 }
1825 RepaintGraphWindow();
1826 }
1827
1828 static void CmdPlot(char *str)
1829 {
1830 ShowGraphWindow();
1831 }
1832
1833 static void CmdHide(char *str)
1834 {
1835 HideGraphWindow();
1836 }
1837
1838 static void CmdScale(char *str)
1839 {
1840 CursorScaleFactor = atoi(str);
1841 if(CursorScaleFactor == 0) {
1842 PrintToScrollback("bad, can't have zero scale");
1843 CursorScaleFactor = 1;
1844 }
1845 RepaintGraphWindow();
1846 }
1847
1848 static void CmdSave(char *str)
1849 {
1850 FILE *f = fopen(str, "w");
1851 if(!f) {
1852 PrintToScrollback("couldn't open '%s'", str);
1853 return;
1854 }
1855 int i;
1856 for(i = 0; i < GraphTraceLen; i++) {
1857 fprintf(f, "%d\n", GraphBuffer[i]);
1858 }
1859 fclose(f);
1860 PrintToScrollback("saved to '%s'", str);
1861 }
1862
1863 static void CmdLoad(char *str)
1864 {
1865 FILE *f = fopen(str, "r");
1866 if(!f) {
1867 PrintToScrollback("couldn't open '%s'", str);
1868 return;
1869 }
1870
1871 GraphTraceLen = 0;
1872 char line[80];
1873 while(fgets(line, sizeof(line), f)) {
1874 GraphBuffer[GraphTraceLen] = atoi(line);
1875 GraphTraceLen++;
1876 }
1877 fclose(f);
1878 PrintToScrollback("loaded %d samples", GraphTraceLen);
1879 RepaintGraphWindow();
1880 }
1881
1882 static void CmdHIDsimTAG(char *str)
1883 {
1884 unsigned int hi=0, lo=0;
1885 int n=0, i=0;
1886 UsbCommand c;
1887
1888 while (sscanf(&str[i++], "%1x", &n ) == 1) {
1889 hi=(hi<<4)|(lo>>28);
1890 lo=(lo<<4)|(n&0xf);
1891 }
1892
1893 PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);
1894
1895 c.cmd = CMD_HID_SIM_TAG;
1896 c.ext1 = hi;
1897 c.ext2 = lo;
1898 SendCommand(&c, FALSE);
1899 }
1900
1901 static void CmdLcdReset(char *str)
1902 {
1903 UsbCommand c;
1904 c.cmd = CMD_LCD_RESET;
1905 c.ext1 = atoi(str);
1906 SendCommand(&c, FALSE);
1907 }
1908
1909 static void CmdLcd(char *str)
1910 {
1911 int i, j;
1912 UsbCommand c;
1913 c.cmd = CMD_LCD;
1914 sscanf(str, "%x %d", &i, &j);
1915 while (j--) {
1916 c.ext1 = i&0x1ff;
1917 SendCommand(&c, FALSE);
1918 }
1919 }
1920
1921
1922
1923 static void CmdTest(char *str)
1924 {
1925 }
1926
1927 /*
1928 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
1929 * 600kHz.
1930 */
1931 static void CmdSetDivisor(char *str)
1932 {
1933 UsbCommand c;
1934 c.cmd = CMD_SET_LF_DIVISOR;
1935 c.ext1 = atoi(str);
1936 if (( c.ext1<0) || (c.ext1>255)) {
1937 PrintToScrollback("divisor must be between 19 and 255");
1938 } else {
1939 SendCommand(&c, FALSE);
1940 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c.ext1+1));
1941 }
1942 }
1943
1944 static void CmdSweepLF(char *str)
1945 {
1946 UsbCommand c;
1947 c.cmd = CMD_SWEEP_LF;
1948 SendCommand(&c, FALSE);
1949 }
1950
1951
1952 typedef void HandlerFunction(char *cmdline);
1953
1954 static struct {
1955 char *name;
1956 HandlerFunction *handler;
1957 int offline; // 1 if the command can be used when in offline mode
1958 char *docString;
1959 } CommandTable[] = {
1960 "tune", CmdTune,0, "measure antenna tuning",
1961 "tiread", CmdTiread,0, "read a TI-type 134 kHz tag",
1962 "tibits", CmdTibits,0, "get raw bits for TI-type LF tag",
1963 "tidemod", CmdTidemod,0, "demod raw bits for TI-type LF tag",
1964 "vchdemod", CmdVchdemod,0, "demod samples for VeriChip",
1965 "plot", CmdPlot,1, "show graph window",
1966 "hide", CmdHide,1, "hide graph window",
1967 "losim", CmdLosim,0, "simulate LF tag",
1968 "loread", CmdLoread,0, "read (125/134 kHz) LF ID-only tag",
1969 "losamples", CmdLosamples,0, "get raw samples for LF tag",
1970 "hisamples", CmdHisamples,0, "get raw samples for HF tag",
1971 "hisampless", CmdHisampless,0, "get signed raw samples, HF tag",
1972 "hisamplest", CmdHi14readt,0, "get samples HF, for testing",
1973 "higet", CmdHi14read_sim,0, "get samples HF, 'analog'",
1974 "bitsamples", CmdBitsamples,0, "get raw samples as bitstring",
1975 "hexsamples", CmdHexsamples,0, "dump big buffer as hex bytes",
1976 "hi15read", CmdHi15read,0, "read HF tag (ISO 15693)",
1977 "hi15reader", CmdHi15reader,0, "act like an ISO15693 reader", // new command greg
1978 "hi15sim", CmdHi15tag,0, "fake an ISO15693 tag", // new command greg
1979 "hi14read", CmdHi14read,0, "read HF tag (ISO 14443)",
1980 "sri512read", CmdSri512read,0, "Read contents of a SRI512 tag",
1981 "hi14areader", CmdHi14areader,0, "act like an ISO14443 Type A reader", // ## New reader command
1982 "hi15demod", CmdHi15demod,1, "demod ISO15693 from tag",
1983 "hi14bdemod", CmdHi14bdemod,1, "demod ISO14443 Type B from tag",
1984 "autocorr", CmdAutoCorr,1, "autocorrelation over window",
1985 "norm", CmdNorm,1, "normalize max/min to +/-500",
1986 "dec", CmdDec,1, "decimate",
1987 "hpf", CmdHpf,1, "remove DC offset from trace",
1988 "zerocrossings", CmdZerocrossings,1, "count time between zero-crossings",
1989 "ltrim", CmdLtrim,1, "trim from left of trace",
1990 "scale", CmdScale,1, "set cursor display scale",
1991 "flexdemod", CmdFlexdemod,1, "demod samples for FlexPass",
1992 "save", CmdSave,1, "save trace (from graph window)",
1993 "load", CmdLoad,1, "load trace (to graph window",
1994 "hisimlisten", CmdHisimlisten,0, "get HF samples as fake tag",
1995 "hi14sim", CmdHi14sim,0, "fake ISO 14443 tag",
1996 "hi14asim", CmdHi14asim,0, "fake ISO 14443a tag", // ## Simulate 14443a tag
1997 "hi14snoop", CmdHi14snoop,0, "eavesdrop ISO 14443",
1998 "hi14asnoop", CmdHi14asnoop,0, "eavesdrop ISO 14443 Type A", // ## New snoop command
1999 "hi14list", CmdHi14list,0, "list ISO 14443 history",
2000 "hi14alist", CmdHi14alist,0, "list ISO 14443a history", // ## New list command
2001 "hiddemod", CmdHiddemod,1, "HID Prox Card II (not optimal)",
2002 "hidfskdemod", CmdHIDdemodFSK,0, "HID FSK demodulator",
2003 "indalademod", CmdIndalademod,0, "demod samples for Indala",
2004 "askdemod", Cmdaskdemod,1, "Attempt to demodulate simple ASK tags",
2005 "hidsimtag", CmdHIDsimTAG,0, "HID tag simulator",
2006 "mandemod", Cmdmanchesterdemod,1, "Try a Manchester demodulation on a binary stream",
2007 "fpgaoff", CmdFPGAOff,0, "set FPGA off", // ## FPGA Control
2008 "lcdreset", CmdLcdReset,0, "Hardware reset LCD",
2009 "lcd", CmdLcd,0, "Send command/data to LCD",
2010 "setlfdivisor", CmdSetDivisor,0, "Drive LF antenna at 12Mhz/(divisor+1)",
2011 "sweeplf", CmdSweepLF,0, "Sweep through LF freq range and store results in buffer",
2012 "reset", CmdReset,0, "Reset the Proxmark3",
2013 "quit", CmdQuit,1, "quit program"
2014 };
2015
2016
2017 //-----------------------------------------------------------------------------
2018 // Entry point into our code: called whenever the user types a command and
2019 // then presses Enter, which the full command line that they typed.
2020 //-----------------------------------------------------------------------------
2021 void CommandReceived(char *cmd)
2022 {
2023 int i;
2024
2025 PrintToScrollback("> %s", cmd);
2026
2027 if(strcmp(cmd, "help")==0) {
2028 if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2029 PrintToScrollback("\r\nAvailable commands:");
2030 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {
2031 if (offline && (CommandTable[i].offline==0)) continue;
2032 char line[256];
2033 memset(line, ' ', sizeof(line));
2034 strcpy(line+2, CommandTable[i].name);
2035 line[strlen(line)] = ' ';
2036 sprintf(line+15, " -- %s", CommandTable[i].docString);
2037 PrintToScrollback("%s", line);
2038 }
2039 PrintToScrollback("");
2040 PrintToScrollback("and also: help, cls");
2041 return;
2042 }
2043
2044 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {
2045 char *name = CommandTable[i].name;
2046 if(memcmp(cmd, name, strlen(name))==0 &&
2047 (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))
2048 {
2049 cmd += strlen(name);
2050 while(*cmd == ' ') {
2051 cmd++;
2052 }
2053 if (offline && (CommandTable[i].offline==0)) {
2054 PrintToScrollback("Offline mode, cannot use this command.");
2055 return;
2056 }
2057 (CommandTable[i].handler)(cmd);
2058 return;
2059 }
2060 }
2061 PrintToScrollback(">> bad command '%s'", cmd);
2062 }
2063
2064 //-----------------------------------------------------------------------------
2065 // Entry point into our code: called whenever we received a packet over USB
2066 // that we weren't necessarily expecting, for example a debug print.
2067 //-----------------------------------------------------------------------------
2068 void UsbCommandReceived(UsbCommand *c)
2069 {
2070 switch(c->cmd) {
2071 case CMD_DEBUG_PRINT_STRING: {
2072 char s[100];
2073 if(c->ext1 > 70 || c->ext1 < 0) {
2074 c->ext1 = 0;
2075 }
2076 memcpy(s, c->d.asBytes, c->ext1);
2077 s[c->ext1] = '\0';
2078 PrintToScrollback("#db# %s", s);
2079 break;
2080 }
2081
2082 case CMD_DEBUG_PRINT_INTEGERS:
2083 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);
2084 break;
2085
2086 case CMD_MEASURED_ANTENNA_TUNING: {
2087 int zLf, zHf;
2088 int vLf125, vLf134, vHf;
2089 vLf125 = c->ext1 & 0xffff;
2090 vLf134 = c->ext1 >> 16;
2091 vHf = c->ext2;
2092 zLf = c->ext3 & 0xffff;
2093 zHf = c->ext3 >> 16;
2094 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",
2095 vLf125/zLf, vLf125, zLf);
2096 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",
2097 vLf134/((zLf*125)/134), vLf134, (zLf*125)/134);
2098 PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",
2099 vHf/zHf, vHf, zHf);
2100 break;
2101 }
2102 default:
2103 PrintToScrollback("unrecognized command %08x\n", c->cmd);
2104 break;
2105 }
2106 }
Impressum, Datenschutz