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