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 //-----------------------------------------------------------------------------
14 #include "../common/iso14443_crc.c"
16 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
17 #define BIT(x) GraphBuffer[x * clock]
18 #define BITS (GraphTraceLen / clock)
21 static int CmdHisamplest(char *str
, int nrlow
);
23 static void GetFromBigBuf(BYTE
*dest
, int bytes
)
28 PrintToScrollback("bad len in GetFromBigBuf");
33 for(i
= 0; i
< n
; i
+= 12) {
35 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
37 SendCommand(&c
, FALSE
);
39 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
40 PrintToScrollback("bad resp");
44 memcpy(dest
+(i
*4), c
.d
.asBytes
, 48);
48 static void CmdReset(char *str
)
51 c
.cmd
= CMD_HARDWARE_RESET
;
52 SendCommand(&c
, FALSE
);
55 static void CmdBuffClear(char *str
)
58 c
.cmd
= CMD_BUFF_CLEAR
;
59 SendCommand(&c
, FALSE
);
63 static void CmdQuit(char *str
)
68 static void CmdHIDdemodFSK(char *str
)
71 c
.cmd
= CMD_HID_DEMOD_FSK
;
72 SendCommand(&c
, FALSE
);
75 static void CmdTune(char *str
)
78 c
.cmd
= CMD_MEASURE_ANTENNA_TUNING
;
79 SendCommand(&c
, FALSE
);
82 static void CmdHi15read(char *str
)
85 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693
;
86 SendCommand(&c
, FALSE
);
89 static void CmdHi14read(char *str
)
92 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
94 SendCommand(&c
, FALSE
);
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/
102 static void CmdSri512read(char *str
)
105 c
.cmd
= CMD_READ_SRI512_TAG
;
107 SendCommand(&c
, FALSE
);
111 static void CmdHi14areader(char *str
)
114 c
.cmd
= CMD_READER_ISO_14443a
;
116 SendCommand(&c
, FALSE
);
120 static void CmdHi15reader(char *str
)
123 c
.cmd
= CMD_READER_ISO_15693
;
125 SendCommand(&c
, FALSE
);
129 static void CmdHi15tag(char *str
)
132 c
.cmd
= CMD_SIMTAG_ISO_15693
;
134 SendCommand(&c
, FALSE
);
137 static void CmdHi14read_sim(char *str
)
140 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM
;
142 SendCommand(&c
, FALSE
);
145 static void CmdHi14readt(char *str
)
148 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
150 SendCommand(&c
, FALSE
);
152 //CmdHisamplest(str);
153 while(CmdHisamplest(str
,atoi(str
))==0) {
154 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
156 SendCommand(&c
, FALSE
);
158 RepaintGraphWindow();
161 static void CmdHisimlisten(char *str
)
164 c
.cmd
= CMD_SIMULATE_TAG_HF_LISTEN
;
165 SendCommand(&c
, FALSE
);
168 static void CmdHi14sim(char *str
)
171 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443
;
172 SendCommand(&c
, FALSE
);
175 static void CmdHi14asim(char *str
) // ## simulate iso14443a tag
176 { // ## greg - added ability to specify tag UID
178 unsigned int hi
=0, lo
=0;
182 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
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
191 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi
, lo
);
192 SendCommand(&c
, FALSE
);
195 static void CmdHi14snoop(char *str
)
198 c
.cmd
= CMD_SNOOP_ISO_14443
;
199 SendCommand(&c
, FALSE
);
202 static void CmdHi14asnoop(char *str
)
205 c
.cmd
= CMD_SNOOP_ISO_14443a
;
206 SendCommand(&c
, FALSE
);
209 static void CmdFPGAOff(char *str
) // ## FPGA Control
212 c
.cmd
= CMD_FPGA_MAJOR_MODE_OFF
;
213 SendCommand(&c
, FALSE
);
216 /* clear out our graph window */
217 int CmdClearGraph(int redraw
)
219 int gtl
= GraphTraceLen
;
223 RepaintGraphWindow();
228 /* write a bit to the graph */
229 static void CmdAppendGraph(int redraw
, int clock
, int bit
)
233 for (i
= 0; i
< (int)(clock
/2); i
++)
234 GraphBuffer
[GraphTraceLen
++] = bit
^ 1;
236 for (i
= (int)(clock
/2); i
< clock
; i
++)
237 GraphBuffer
[GraphTraceLen
++] = bit
;
240 RepaintGraphWindow();
243 /* Function is equivalent of loread + losamples + em410xread
244 * looped until an EM410x tag is detected */
245 static void CmdEM410xwatch(char *str
)
259 /* Read the transmitted data of an EM4x50 tag
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
268 * LW <- Listen Window
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)).
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.
278 static void CmdEM4x50read(char *str
)
280 int i
, j
, startblock
, clock
, skip
, block
, start
, end
, low
, high
;
281 BOOL complete
= FALSE
;
282 int tmpbuff
[MAX_GRAPH_TRACE_LEN
/ 64];
288 /* first get high and low values */
289 for (i
= 0; i
< GraphTraceLen
; i
++)
291 if (GraphBuffer
[i
] > high
)
292 high
= GraphBuffer
[i
];
293 else if (GraphBuffer
[i
] < low
)
294 low
= GraphBuffer
[i
];
297 /* populate a buffer with pulse lengths */
300 while(i
< GraphTraceLen
)
302 // measure from low to low
303 while(GraphBuffer
[i
] > low
)
306 while(GraphBuffer
[i
] < high
)
308 while(GraphBuffer
[i
] > low
)
310 tmpbuff
[j
++]= i
- start
;
314 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
317 for (i
= 0; i
< j
- 4 ; ++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)
331 /* skip over the remainder of the LW */
332 skip
+= tmpbuff
[i
+1]+tmpbuff
[i
+2];
333 while(GraphBuffer
[skip
] > low
)
337 /* now do it again to find the end */
339 for (i
+= 3; i
< j
- 4 ; ++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)
353 PrintToScrollback("Found data at sample: %i",skip
);
356 PrintToScrollback("No data found!");
357 PrintToScrollback("Try again with more samples.");
363 PrintToScrollback("*** Warning!");
364 PrintToScrollback("Partial data - no end found!");
365 PrintToScrollback("Try again with more samples.");
368 /* get rid of leading crap */
369 sprintf(tmp
,"%i",skip
);
372 /* now work through remaining buffer printing out data blocks */
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");
382 /* look for LW before start of next block */
383 for ( ; i
< j
- 4 ; ++i
)
386 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
387 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
390 while(GraphBuffer
[skip
] > low
)
393 sprintf(tmp
,"%i",skip
);
401 /* Read the ID of an EM410x tag.
403 * 1111 1111 1 <-- standard non-repeatable header
404 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
406 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
407 * 0 <-- stop bit, end of tag
409 static void CmdEM410xread(char *str
)
411 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
415 int BitStream
[MAX_GRAPH_TRACE_LEN
];
418 /* Detect high and lows and clock */
419 for (i
= 0; i
< GraphTraceLen
; i
++)
421 if (GraphBuffer
[i
] > high
)
422 high
= GraphBuffer
[i
];
423 else if (GraphBuffer
[i
] < low
)
424 low
= GraphBuffer
[i
];
428 clock
= GetClock(str
, high
);
430 /* parity for our 4 columns */
431 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
434 /* manchester demodulate */
436 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
442 /* Find out if we hit both high and low peaks */
443 for (j
= 0; j
< clock
; j
++)
445 if (GraphBuffer
[(i
* clock
) + j
] == high
)
447 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
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;
457 if (hithigh
&& hitlow
)
461 /* If we didn't hit both high and low peaks, we had a bit transition */
462 if (!hithigh
|| !hitlow
)
465 BitStream
[bit2idx
++] = bit
;
469 /* We go till 5 before the graph ends because we'll get that far below */
470 for (i
= 1; i
< bit2idx
- 5; i
++)
472 /* Step 2: We have our header but need our tag ID */
473 if (header
== 9 && rows
< 10)
475 /* Confirm parity is correct */
476 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
478 /* Read another byte! */
479 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
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];
488 /* Move 4 bits ahead */
492 /* Damn, something wrong! reset */
495 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
497 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
498 i
-= 9 + (5 * rows
) - 5;
504 /* Step 3: Got our 40 bits! confirm column parity */
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] &&
513 PrintToScrollback("EM410x Tag ID: %s", id
);
520 /* Crap! Incorrect parity or no stop bit, start all over */
525 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
530 /* Step 1: get our header */
533 /* Need 9 consecutive 1's */
534 if (BitStream
[i
] == 1)
537 /* We don't have a header, not enough consecutive 1 bits */
543 /* if we've already retested after flipping bits, return */
547 /* if this didn't work, try flipping bits */
548 for (i
= 0; i
< bit2idx
; i
++)
554 /* emulate an EM410X tag
556 * 1111 1111 1 <-- standard non-repeatable header
557 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
559 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
560 * 0 <-- stop bit, end of tag
562 static void CmdEM410xsim(char *str
)
564 int i
, n
, j
, h
, binary
[4], parity
[4];
567 /* clock is 64 in EM410x tags */
570 /* clear our graph */
573 /* write it out a few times */
574 for (h
= 0; h
< 4; h
++)
576 /* write 9 start bits */
577 for (i
= 0; i
< 9; i
++)
578 CmdAppendGraph(0, clock
, 1);
580 /* for each hex char */
581 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
582 for (i
= 0; i
< 10; i
++)
584 /* read each hex char */
585 sscanf(&str
[i
], "%1x", &n
);
586 for (j
= 3; j
>= 0; j
--, n
/= 2)
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]);
595 /* append parity bit */
596 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
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];
606 CmdAppendGraph(0, clock
, parity
[0]);
607 CmdAppendGraph(0, clock
, parity
[1]);
608 CmdAppendGraph(0, clock
, parity
[2]);
609 CmdAppendGraph(0, clock
, parity
[3]);
612 CmdAppendGraph(0, clock
, 0);
615 /* modulate that biatch */
619 RepaintGraphWindow();
624 static void ChkBitstream(char *str
)
628 /* convert to bitstream if necessary */
629 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
631 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
639 static void CmdLosim(char *str
)
644 /* convert to bitstream if necessary */
647 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
650 for(j
= 0; j
< 48; j
++) {
651 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
653 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
655 SendCommand(&c
, FALSE
);
659 c
.cmd
= CMD_SIMULATE_TAG_125K
;
660 c
.ext1
= GraphTraceLen
;
661 SendCommand(&c
, FALSE
);
664 static void CmdLoread(char *str
)
667 // 'h' means higher-low-frequency, 134 kHz
670 } else if (*str
== '\0') {
673 PrintToScrollback("use 'loread' or 'loread h'");
676 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
677 SendCommand(&c
, FALSE
);
680 /* send a command before reading */
681 static void CmdLoCommandRead(char *str
)
683 static char dummy
[3];
688 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
689 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, &c
.d
.asBytes
,&dummy
+1);
690 // in case they specified 'h'
691 strcpy(&c
.d
.asBytes
+ strlen(c
.d
.asBytes
),dummy
);
692 SendCommand(&c
, FALSE
);
695 static void CmdLosamples(char *str
)
703 if (n
>16000) n
=16000;
705 for(i
= 0; i
< n
; i
+= 12) {
707 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
709 SendCommand(&c
, FALSE
);
711 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
713 PrintToScrollback("bad resp");
717 for(j
= 0; j
< 48; j
++) {
718 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
722 RepaintGraphWindow();
725 static void CmdBitsamples(char *str
)
732 for(i
= 0; i
< n
; i
+= 12) {
734 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
736 SendCommand(&c
, FALSE
);
738 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
739 PrintToScrollback("bad resp");
743 for(j
= 0; j
< 48; j
++) {
744 for(k
= 0; k
< 8; k
++) {
745 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
746 GraphBuffer
[cnt
++] = 1;
748 GraphBuffer
[cnt
++] = 0;
754 RepaintGraphWindow();
757 static void CmdHisamples(char *str
)
763 for(i
= 0; i
< n
; i
+= 12) {
765 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
767 SendCommand(&c
, FALSE
);
769 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
770 PrintToScrollback("bad resp");
774 for(j
= 0; j
< 48; j
++) {
775 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
780 RepaintGraphWindow();
784 static int CmdHisamplest(char *str
, int nrlow
)
796 for(i
= 0; i
< n
; i
+= 12) {
798 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
800 SendCommand(&c
, FALSE
);
802 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
803 PrintToScrollback("bad resp");
807 for(j
= 0; j
< 48; j
++) {
808 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
809 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
815 t1
= (t2
& 0x80) ^ (t2
& 0x20);
816 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
822 t2
= ((t2
<< 1) & 0x80);
828 t2
= ((t2
<< 1) & 0x20);
832 // both, but tag with other algorithm
833 t1
= (t2
& 0x80) ^ (t2
& 0x08);
834 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
838 GraphBuffer
[cnt
++] = t1
;
839 GraphBuffer
[cnt
++] = t2
;
844 if(hasbeennull
>nrlow
|| nrlow
==0) {
845 PrintToScrollback("hasbeennull=%d", hasbeennull
);
854 static void CmdHexsamples(char *str
)
865 for(i
= 0; i
< n
; i
+= 12) {
867 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
869 SendCommand(&c
, FALSE
);
871 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
872 PrintToScrollback("bad resp");
876 for(j
= 0; j
< 48; j
+= 8) {
877 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
892 static void CmdHisampless(char *str
)
904 for(i
= 0; i
< n
; i
+= 12) {
906 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
908 SendCommand(&c
, FALSE
);
910 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
911 PrintToScrollback("bad resp");
915 for(j
= 0; j
< 48; j
++) {
916 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
921 RepaintGraphWindow();
924 static WORD
Iso15693Crc(BYTE
*v
, int n
)
930 for(i
= 0; i
< n
; i
++) {
931 reg
= reg
^ ((DWORD
)v
[i
]);
932 for (j
= 0; j
< 8; j
++) {
934 reg
= (reg
>> 1) ^ 0x8408;
944 static void CmdHi14bdemod(char *str
)
949 BOOL negateI
, negateQ
;
954 // As received, the samples are pairs, correlations against I and Q
955 // square waves. So estimate angle of initial carrier (or just
956 // quadrant, actually), and then do the demod.
958 // First, estimate where the tag starts modulating.
959 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
960 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
964 if(i
>= GraphTraceLen
) {
965 PrintToScrollback("too weak to sync");
968 PrintToScrollback("out of weak at %d", i
);
971 // Now, estimate the phase in the initial modulation of the tag
974 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
975 isum
+= GraphBuffer
[i
+0];
976 qsum
+= GraphBuffer
[i
+1];
978 negateI
= (isum
< 0);
979 negateQ
= (qsum
< 0);
981 // Turn the correlation pairs into soft decisions on the bit.
983 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
984 int si
= GraphBuffer
[j
];
985 int sq
= GraphBuffer
[j
+1];
986 if(negateI
) si
= -si
;
987 if(negateQ
) sq
= -sq
;
988 GraphBuffer
[i
] = si
+ sq
;
994 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
996 if(i
>= GraphTraceLen
) goto demodError
;
999 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
1001 if(i
>= GraphTraceLen
) goto demodError
;
1002 if((i
- iold
) > 23) goto demodError
;
1004 PrintToScrollback("make it to demod loop");
1008 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
1010 if(i
>= GraphTraceLen
) goto demodError
;
1011 if((i
- iold
) > 6) goto demodError
;
1014 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
1016 for(j
= 0; j
< 10; j
++) {
1017 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
1019 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
1020 PrintToScrollback("weak bit");
1024 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
1031 if( (shiftReg
& 0x200) &&
1032 !(shiftReg
& 0x001))
1034 // valid data byte, start and stop bits okay
1035 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
1036 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
1037 if(dataLen
>= sizeof(data
)) {
1040 } else if(shiftReg
== 0x000) {
1049 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
1050 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
1051 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
1052 "ok" : "****FAIL****");
1054 RepaintGraphWindow();
1058 PrintToScrollback("demod error");
1059 RepaintGraphWindow();
1062 static void CmdHi14list(char *str
)
1065 GetFromBigBuf(got
, sizeof(got
));
1067 PrintToScrollback("recorded activity:");
1068 PrintToScrollback(" time :rssi: who bytes");
1069 PrintToScrollback("---------+----+----+-----------");
1080 int timestamp
= *((DWORD
*)(got
+i
));
1081 if(timestamp
& 0x80000000) {
1082 timestamp
&= 0x7fffffff;
1087 int metric
= *((DWORD
*)(got
+i
+4));
1094 if(i
+ len
>= 900) {
1098 BYTE
*frame
= (got
+i
+9);
1100 char line
[1000] = "";
1102 for(j
= 0; j
< len
; j
++) {
1103 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
1109 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
1110 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1111 crc
= "**FAIL CRC**";
1119 char metricString
[100];
1121 sprintf(metricString
, "%3d", metric
);
1123 strcpy(metricString
, " ");
1126 PrintToScrollback(" +%7d: %s: %s %s %s",
1127 (prev
< 0 ? 0 : timestamp
- prev
),
1129 (isResponse
? "TAG" : " "), line
, crc
);
1136 static void CmdHi14alist(char *str
)
1139 GetFromBigBuf(got
, sizeof(got
));
1141 PrintToScrollback("recorded activity:");
1142 PrintToScrollback(" ETU :rssi: who bytes");
1143 PrintToScrollback("---------+----+----+-----------");
1154 int timestamp
= *((DWORD
*)(got
+i
));
1155 if(timestamp
& 0x80000000) {
1156 timestamp
&= 0x7fffffff;
1163 int parityBits
= *((DWORD
*)(got
+i
+4));
1164 // 4 bytes of additional information...
1165 // maximum of 32 additional parity bit information
1168 // at each quarter bit period we can send power level (16 levels)
1169 // or each half bit period in 256 levels.
1177 if(i
+ len
>= 1900) {
1181 BYTE
*frame
= (got
+i
+9);
1183 // Break and stick with current result if buffer was not completely full
1184 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1186 char line
[1000] = "";
1188 for(j
= 0; j
< len
; j
++) {
1189 int oddparity
= 0x01;
1193 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1196 //if((parityBits >> (len - j - 1)) & 0x01) {
1197 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1198 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1201 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1209 for(j
= 0; j
< (len
- 1); j
++) {
1210 // gives problems... search for the reason..
1211 /*if(frame[j] == 0xAA) {
1212 switch(frame[j+1]) {
1214 crc = "[1] Two drops close after each other";
1217 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1220 crc = "[3] Segment Z after segment X is not possible";
1223 crc = "[4] Parity bit of a fully received byte was wrong";
1226 crc = "[?] Unknown error";
1233 if(strlen(crc
)==0) {
1234 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1235 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1236 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1245 char metricString
[100];
1247 sprintf(metricString
, "%3d", metric
);
1249 strcpy(metricString
, " ");
1252 PrintToScrollback(" +%7d: %s: %s %s %s",
1253 (prev
< 0 ? 0 : (timestamp
- prev
)),
1255 (isResponse
? "TAG" : " "), line
, crc
);
1260 CommandFinished
= 1;
1263 static void CmdHi15demod(char *str
)
1265 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1268 // 1) Unmodulated time of 56.64us
1269 // 2) 24 pulses of 423.75khz
1270 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1272 static const int FrameSOF
[] = {
1273 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1274 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1275 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1276 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1282 static const int Logic0
[] = {
1288 static const int Logic1
[] = {
1296 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1297 // 2) 24 pulses of 423.75khz
1298 // 3) Unmodulated time of 56.64us
1300 static const int FrameEOF
[] = {
1305 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1306 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1307 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1308 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1312 int max
= 0, maxPos
;
1316 if(GraphTraceLen
< 1000) return;
1318 // First, correlate for SOF
1319 for(i
= 0; i
< 100; i
++) {
1321 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1322 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1329 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1330 max
/(arraylen(FrameSOF
)/skip
));
1332 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1335 memset(outBuf
, 0, sizeof(outBuf
));
1338 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1339 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1340 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1342 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1343 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1345 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1346 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1348 // Even things out by the length of the target waveform.
1352 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1353 PrintToScrollback("EOF at %d", i
);
1355 } else if(corr1
> corr0
) {
1356 i
+= arraylen(Logic1
)/skip
;
1359 i
+= arraylen(Logic0
)/skip
;
1366 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1367 PrintToScrollback("ran off end!");
1372 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1373 PrintToScrollback(" mask=%02x", mask
);
1375 PrintToScrollback("%d octets", k
);
1377 for(i
= 0; i
< k
; i
++) {
1378 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1380 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1383 static void CmdTiread(char *str
)
1386 c
.cmd
= CMD_ACQUIRE_RAW_BITS_TI_TYPE
;
1387 SendCommand(&c
, FALSE
);
1390 static void CmdTibits(char *str
)
1394 for(i
= 0; i
< 1536; i
+= 12) {
1396 c
.cmd
= CMD_DOWNLOAD_RAW_BITS_TI_TYPE
;
1398 SendCommand(&c
, FALSE
);
1400 if(c
.cmd
!= CMD_DOWNLOADED_RAW_BITS_TI_TYPE
) {
1401 PrintToScrollback("bad resp");
1405 for(j
= 0; j
< 12; j
++) {
1407 for(k
= 31; k
>= 0; k
--) {
1408 if(c
.d
.asDwords
[j
] & (1 << k
)) {
1409 GraphBuffer
[cnt
++] = 1;
1411 GraphBuffer
[cnt
++] = -1;
1416 GraphTraceLen
= 1536*32;
1417 RepaintGraphWindow();
1420 static void CmdTidemod(char *cmdline
)
1422 /* MATLAB as follows:
1423 f_s = 2000000; % sampling frequency
1424 f_l = 123200; % low FSK tone
1425 f_h = 134200; % high FSK tone
1427 T_l = 119e-6; % low bit duration
1428 T_h = 130e-6; % high bit duration
1430 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1431 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1433 l = sign(sin(cumsum(l)));
1434 h = sign(sin(cumsum(h)));
1436 static const int LowTone
[] = {
1437 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,
1438 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1439 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
1440 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
1441 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,
1442 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
1443 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,
1444 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1445 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
1446 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,
1447 -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1448 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
1449 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
1451 static const int HighTone
[] = {
1452 1, 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,
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,
1458 -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,
1460 1, 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,
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, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1465 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,
1468 int convLen
= max(arraylen(HighTone
), arraylen(LowTone
));
1471 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1473 int lowSum
= 0, highSum
= 0;;
1474 int lowLen
= arraylen(LowTone
);
1475 int highLen
= arraylen(HighTone
);
1477 for(j
= 0; j
< lowLen
; j
++) {
1478 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1480 for(j
= 0; j
< highLen
; j
++) {
1481 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1483 lowSum
= abs((100*lowSum
) / lowLen
);
1484 highSum
= abs((100*highSum
) / highLen
);
1485 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1488 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1490 int lowTot
= 0, highTot
= 0;
1491 // 16 and 15 are f_s divided by f_l and f_h, rounded
1492 for(j
= 0; j
< 16; j
++) {
1493 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1495 for(j
= 0; j
< 15; j
++) {
1496 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1498 GraphBuffer
[i
] = lowTot
- highTot
;
1501 GraphTraceLen
-= (convLen
+ 16);
1503 RepaintGraphWindow();
1505 // Okay, so now we have unsliced soft decisions; find bit-sync, and then
1508 int max
= 0, maxPos
= 0;
1509 for(i
= 0; i
< 6000; i
++) {
1512 for(j
= 0; j
< 8*arraylen(LowTone
); j
++) {
1513 dec
-= GraphBuffer
[i
+j
];
1515 for(; j
< 8*arraylen(LowTone
) + 8*arraylen(HighTone
); j
++) {
1516 dec
+= GraphBuffer
[i
+j
];
1523 GraphBuffer
[maxPos
] = 800;
1524 GraphBuffer
[maxPos
+1] = -800;
1526 maxPos
+= 8*arraylen(LowTone
);
1527 GraphBuffer
[maxPos
] = 800;
1528 GraphBuffer
[maxPos
+1] = -800;
1529 maxPos
+= 8*arraylen(HighTone
);
1531 GraphBuffer
[maxPos
] = 800;
1532 GraphBuffer
[maxPos
+1] = -800;
1534 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1536 PrintToScrollback("length %d/%d", arraylen(HighTone
), arraylen(LowTone
));
1538 GraphBuffer
[maxPos
] = 800;
1539 GraphBuffer
[maxPos
+1] = -800;
1541 BYTE bits
[64+16+8+1];
1542 bits
[sizeof(bits
)-1] = '\0';
1544 for(i
= 0; i
< arraylen(bits
); i
++) {
1548 for(j
= 0; j
< arraylen(LowTone
); j
++) {
1549 low
-= GraphBuffer
[maxPos
+j
];
1551 for(j
= 0; j
< arraylen(HighTone
); j
++) {
1552 high
+= GraphBuffer
[maxPos
+j
];
1556 maxPos
+= arraylen(HighTone
);
1559 maxPos
+= arraylen(LowTone
);
1561 GraphBuffer
[maxPos
] = 800;
1562 GraphBuffer
[maxPos
+1] = -800;
1564 PrintToScrollback("bits: '%s'", bits
);
1567 for(i
= 0; i
< 32; i
++) {
1568 if(bits
[i
] == '1') {
1572 for(i
= 32; i
< 64; i
++) {
1573 if(bits
[i
] == '1') {
1577 PrintToScrollback("hex: %08x %08x", h
, l
);
1580 static void CmdNorm(char *str
)
1583 int max
= INT_MIN
, min
= INT_MAX
;
1584 for(i
= 10; i
< GraphTraceLen
; i
++) {
1585 if(GraphBuffer
[i
] > max
) {
1586 max
= GraphBuffer
[i
];
1588 if(GraphBuffer
[i
] < min
) {
1589 min
= GraphBuffer
[i
];
1593 for(i
= 0; i
< GraphTraceLen
; i
++) {
1594 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1598 RepaintGraphWindow();
1601 static void CmdDec(char *str
)
1604 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1605 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1608 PrintToScrollback("decimated by 2");
1609 RepaintGraphWindow();
1612 static void CmdHpf(char *str
)
1616 for(i
= 10; i
< GraphTraceLen
; i
++) {
1617 accum
+= GraphBuffer
[i
];
1619 accum
/= (GraphTraceLen
- 10);
1620 for(i
= 0; i
< GraphTraceLen
; i
++) {
1621 GraphBuffer
[i
] -= accum
;
1624 RepaintGraphWindow();
1627 static void CmdZerocrossings(char *str
)
1630 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1636 for(i
= 0; i
< GraphTraceLen
; i
++) {
1637 if(GraphBuffer
[i
]*sign
>= 0) {
1638 // No change in sign, reproduce the previous sample count.
1640 GraphBuffer
[i
] = lastZc
;
1642 // Change in sign, reset the sample count.
1644 GraphBuffer
[i
] = lastZc
;
1652 RepaintGraphWindow();
1655 static void CmdLtrim(char *str
)
1660 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1661 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1663 GraphTraceLen
-= ds
;
1665 RepaintGraphWindow();
1668 static void CmdAutoCorr(char *str
)
1670 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1672 int window
= atoi(str
);
1675 PrintToScrollback("needs a window");
1679 if(window
>= GraphTraceLen
) {
1680 PrintToScrollback("window must be smaller than trace (%d samples)",
1685 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1688 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1691 for(j
= 0; j
< window
; j
++) {
1692 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1694 CorrelBuffer
[i
] = sum
;
1696 GraphTraceLen
= GraphTraceLen
- window
;
1697 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1699 RepaintGraphWindow();
1702 static void CmdVchdemod(char *str
)
1704 // Is this the entire sync pattern, or does this also include some
1705 // data bits that happen to be the same everywhere? That would be
1707 static const int SyncPattern
[] = {
1708 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1709 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1710 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1711 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1712 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1713 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1714 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1715 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1716 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1717 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1720 // So first, we correlate for the sync pattern, and mark that.
1721 int bestCorrel
= 0, bestPos
= 0;
1723 // It does us no good to find the sync pattern, with fewer than
1724 // 2048 samples after it...
1725 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1728 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1729 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1731 if(sum
> bestCorrel
) {
1736 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
1741 int worst
= INT_MAX
;
1744 for(i
= 0; i
< 2048; i
+= 8) {
1747 for(j
= 0; j
< 8; j
++) {
1748 sum
+= GraphBuffer
[bestPos
+i
+j
];
1755 if(abs(sum
) < worst
) {
1760 PrintToScrollback("bits:");
1761 PrintToScrollback("%s", bits
);
1762 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
1764 if(strcmp(str
, "clone")==0) {
1767 for(s
= bits
; *s
; s
++) {
1769 for(j
= 0; j
< 16; j
++) {
1770 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
1773 RepaintGraphWindow();
1777 static void CmdIndalademod(char *str
)
1779 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
1784 // worst case with GraphTraceLen=64000 is < 4096
1785 // under normal conditions it's < 2048
1788 int worst
= 0, worstPos
= 0;
1789 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
1790 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
1792 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
1794 for(j
= 0; j
< count
- 8; j
+= 16) {
1795 rawbits
[rawbit
++] = 0;
1797 if ((abs(count
- j
)) > worst
) {
1798 worst
= abs(count
- j
);
1804 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
1806 for(j
= 0; j
< count
- 8; j
+= 16) {
1807 rawbits
[rawbit
++] = 1;
1809 if ((abs(count
- j
)) > worst
) {
1810 worst
= abs(count
- j
);
1818 PrintToScrollback("Recovered %d raw bits", rawbit
);
1819 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
1821 // Finding the start of a UID
1822 int uidlen
, long_wait
;
1823 if(strcmp(str
, "224") == 0) {
1832 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
1833 first
= rawbits
[start
];
1834 for(i
= start
; i
< start
+ long_wait
; i
++) {
1835 if(rawbits
[i
] != first
) {
1839 if(i
== (start
+ long_wait
)) {
1843 if(start
== rawbit
- uidlen
+ 1) {
1844 PrintToScrollback("nothing to wait for");
1848 // Inverting signal if needed
1850 for(i
= start
; i
< rawbit
; i
++) {
1851 rawbits
[i
] = !rawbits
[i
];
1858 showbits
[uidlen
]='\0';
1862 if(uidlen
> rawbit
) {
1863 PrintToScrollback("Warning: not enough raw bits to get a full UID");
1864 for(bit
= 0; bit
< rawbit
; bit
++) {
1865 bits
[bit
] = rawbits
[i
++];
1866 // As we cannot know the parity, let's use "." and "/"
1867 showbits
[bit
] = '.' + bits
[bit
];
1869 showbits
[bit
+1]='\0';
1870 PrintToScrollback("Partial UID=%s", showbits
);
1873 for(bit
= 0; bit
< uidlen
; bit
++) {
1874 bits
[bit
] = rawbits
[i
++];
1875 showbits
[bit
] = '0' + bits
[bit
];
1879 PrintToScrollback("UID=%s", showbits
);
1881 // Checking UID against next occurences
1882 for(; i
+ uidlen
<= rawbit
;) {
1884 for(bit
= 0; bit
< uidlen
; bit
++) {
1885 if(bits
[bit
] != rawbits
[i
++]) {
1895 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
1897 // Remodulating for tag cloning
1898 GraphTraceLen
= 32*uidlen
;
1901 for(bit
= 0; bit
< uidlen
; bit
++) {
1902 if(bits
[bit
] == 0) {
1908 for(j
= 0; j
< 32; j
++) {
1909 GraphBuffer
[i
++] = phase
;
1914 RepaintGraphWindow();
1917 static void CmdFlexdemod(char *str
)
1920 for(i
= 0; i
< GraphTraceLen
; i
++) {
1921 if(GraphBuffer
[i
] < 0) {
1922 GraphBuffer
[i
] = -1;
1928 #define LONG_WAIT 100
1930 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
1931 int first
= GraphBuffer
[start
];
1932 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
1933 if(GraphBuffer
[i
] != first
) {
1937 if(i
== (start
+ LONG_WAIT
)) {
1941 if(start
== GraphTraceLen
- LONG_WAIT
) {
1942 PrintToScrollback("nothing to wait for");
1946 GraphBuffer
[start
] = 2;
1947 GraphBuffer
[start
+1] = -2;
1953 for(bit
= 0; bit
< 64; bit
++) {
1956 for(j
= 0; j
< 16; j
++) {
1957 sum
+= GraphBuffer
[i
++];
1964 PrintToScrollback("bit %d sum %d", bit
, sum
);
1967 for(bit
= 0; bit
< 64; bit
++) {
1970 for(j
= 0; j
< 16; j
++) {
1971 sum
+= GraphBuffer
[i
++];
1973 if(sum
> 0 && bits
[bit
] != 1) {
1974 PrintToScrollback("oops1 at %d", bit
);
1976 if(sum
< 0 && bits
[bit
] != 0) {
1977 PrintToScrollback("oops2 at %d", bit
);
1981 GraphTraceLen
= 32*64;
1984 for(bit
= 0; bit
< 64; bit
++) {
1985 if(bits
[bit
] == 0) {
1991 for(j
= 0; j
< 32; j
++) {
1992 GraphBuffer
[i
++] = phase
;
1997 RepaintGraphWindow();
2001 * Generic command to demodulate ASK.
2003 * Argument is convention: positive or negative (High mod means zero
2004 * or high mod means one)
2006 * Updates the Graph trace with 0/1 values
2012 static void Cmdaskdemod(char *str
) {
2017 // TODO: complain if we do not give 2 arguments here !
2018 sscanf(str
, "%i", &c
);
2020 /* Detect high and lows and clock */
2021 for (i
= 0; i
< GraphTraceLen
; i
++)
2023 if (GraphBuffer
[i
] > high
)
2024 high
= GraphBuffer
[i
];
2025 else if (GraphBuffer
[i
] < low
)
2026 low
= GraphBuffer
[i
];
2029 if (GraphBuffer
[0] > 0) {
2030 GraphBuffer
[0] = 1-c
;
2034 for(i
=1;i
<GraphTraceLen
;i
++) {
2035 /* Transitions are detected at each peak
2036 * Transitions are either:
2037 * - we're low: transition if we hit a high
2038 * - we're high: transition if we hit a low
2039 * (we need to do it this way because some tags keep high or
2040 * low for long periods, others just reach the peak and go
2043 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
2045 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
2049 GraphBuffer
[i
] = GraphBuffer
[i
-1];
2052 RepaintGraphWindow();
2055 /* Print our clock rate */
2056 static void Cmddetectclockrate(char *str
)
2058 int clock
= detectclock(0);
2059 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2065 int detectclock(int peak
)
2071 /* Detect peak if we don't have one */
2073 for (i
= 0; i
< GraphTraceLen
; i
++)
2074 if (GraphBuffer
[i
] > peak
)
2075 peak
= GraphBuffer
[i
];
2077 for (i
= 1; i
< GraphTraceLen
; i
++)
2079 /* If this is the beginning of a peak */
2080 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
2082 /* Find lowest difference between peaks */
2083 if (lastpeak
&& i
- lastpeak
< clock
)
2085 clock
= i
- lastpeak
;
2094 /* Get or auto-detect clock rate */
2095 int GetClock(char *str
, int peak
)
2099 sscanf(str
, "%i", &clock
);
2100 if (!strcmp(str
, ""))
2103 /* Auto-detect clock */
2106 clock
= detectclock(peak
);
2108 /* Only print this message if we're not looping something */
2110 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2117 * Convert to a bitstream
2119 static void Cmdbitstream(char *str
) {
2126 int hithigh
, hitlow
, first
;
2128 /* Detect high and lows and clock */
2129 for (i
= 0; i
< GraphTraceLen
; i
++)
2131 if (GraphBuffer
[i
] > high
)
2132 high
= GraphBuffer
[i
];
2133 else if (GraphBuffer
[i
] < low
)
2134 low
= GraphBuffer
[i
];
2138 clock
= GetClock(str
, high
);
2140 gtl
= CmdClearGraph(0);
2143 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2149 /* Find out if we hit both high and low peaks */
2150 for (j
= 0; j
< clock
; j
++)
2152 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2154 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2157 /* it doesn't count if it's the first part of our read
2158 because it's really just trailing from the last sequence */
2159 if (first
&& (hithigh
|| hitlow
))
2160 hithigh
= hitlow
= 0;
2164 if (hithigh
&& hitlow
)
2168 /* If we didn't hit both high and low peaks, we had a bit transition */
2169 if (!hithigh
|| !hitlow
)
2172 CmdAppendGraph(0, clock
, bit
);
2173 // for (j = 0; j < (int)(clock/2); j++)
2174 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2175 // for (j = (int)(clock/2); j < clock; j++)
2176 // GraphBuffer[(i * clock) + j] = bit;
2179 RepaintGraphWindow();
2182 /* Modulate our data into manchester */
2183 static void Cmdmanchestermod(char *str
)
2187 int bit
, lastbit
, wave
;
2190 clock
= GetClock(str
, 0);
2194 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2196 bit
= GraphBuffer
[i
* clock
] ^ 1;
2198 for (j
= 0; j
< (int)(clock
/2); j
++)
2199 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2200 for (j
= (int)(clock
/2); j
< clock
; j
++)
2201 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2203 /* Keep track of how we start our wave and if we changed or not this time */
2204 wave
^= bit
^ lastbit
;
2208 RepaintGraphWindow();
2212 * Manchester demodulate a bitstream. The bitstream needs to be already in
2213 * the GraphBuffer as 0 and 1 values
2215 * Give the clock rate as argument in order to help the sync - the algorithm
2216 * resyncs at each pulse anyway.
2218 * Not optimized by any means, this is the 1st time I'm writing this type of
2219 * routine, feel free to improve...
2221 * 1st argument: clock rate (as number of samples per clock rate)
2222 * Typical values can be 64, 32, 128...
2224 static void Cmdmanchesterdemod(char *str
) {
2225 int i
, j
, invert
= 0;
2231 int hithigh
, hitlow
, first
;
2237 /* check if we're inverting output */
2240 PrintToScrollback("Inverting output");
2244 while(*str
== ' '); // in case a 2nd argument was given
2247 /* Holds the decoded bitstream: each clock period contains 2 bits */
2248 /* later simplified to 1 bit after manchester decoding. */
2249 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2250 /* int BitStream[GraphTraceLen*2/clock+10]; */
2252 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2254 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2256 /* Detect high and lows */
2257 for (i
= 0; i
< GraphTraceLen
; i
++)
2259 if (GraphBuffer
[i
] > high
)
2260 high
= GraphBuffer
[i
];
2261 else if (GraphBuffer
[i
] < low
)
2262 low
= GraphBuffer
[i
];
2266 clock
= GetClock(str
, high
);
2268 int tolerance
= clock
/4;
2270 /* Detect first transition */
2271 /* Lo-Hi (arbitrary) */
2272 for (i
= 0; i
< GraphTraceLen
; i
++)
2274 if (GraphBuffer
[i
] == low
)
2281 /* If we're not working with 1/0s, demod based off clock */
2284 bit
= 0; /* We assume the 1st bit is zero, it may not be
2285 * the case: this routine (I think) has an init problem.
2288 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2294 /* Find out if we hit both high and low peaks */
2295 for (j
= 0; j
< clock
; j
++)
2297 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2299 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2302 /* it doesn't count if it's the first part of our read
2303 because it's really just trailing from the last sequence */
2304 if (first
&& (hithigh
|| hitlow
))
2305 hithigh
= hitlow
= 0;
2309 if (hithigh
&& hitlow
)
2313 /* If we didn't hit both high and low peaks, we had a bit transition */
2314 if (!hithigh
|| !hitlow
)
2317 BitStream
[bit2idx
++] = bit
^ invert
;
2321 /* standard 1/0 bitstream */
2325 /* Then detect duration between 2 successive transitions */
2326 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2328 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2333 // Error check: if bitidx becomes too large, we do not
2334 // have a Manchester encoded bitstream or the clock is really
2336 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2337 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2340 // Then switch depending on lc length:
2341 // Tolerance is 1/4 of clock rate (arbitrary)
2342 if (abs(lc
-clock
/2) < tolerance
) {
2343 // Short pulse : either "1" or "0"
2344 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2345 } else if (abs(lc
-clock
) < tolerance
) {
2346 // Long pulse: either "11" or "00"
2347 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2348 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2352 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2353 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2357 PrintToScrollback("Error: too many detection errors, aborting.");
2364 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2365 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2366 // to stop output at the final bitidx2 value, not bitidx
2367 for (i
= 0; i
< bitidx
; i
+= 2) {
2368 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2369 BitStream
[bit2idx
++] = 1 ^ invert
;
2370 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2371 BitStream
[bit2idx
++] = 0 ^ invert
;
2373 // We cannot end up in this state, this means we are unsynchronized,
2377 PrintToScrollback("Unsynchronized, resync...");
2378 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2382 PrintToScrollback("Error: too many decode errors, aborting.");
2389 PrintToScrollback("Manchester decoded bitstream");
2390 // Now output the bitstream to the scrollback by line of 16 bits
2391 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2392 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2417 static void CmdHiddemod(char *str
)
2419 if(GraphTraceLen
< 4800) {
2420 PrintToScrollback("too short; need at least 4800 samples");
2424 GraphTraceLen
= 4800;
2426 for(i
= 0; i
< GraphTraceLen
; i
++) {
2427 if(GraphBuffer
[i
] < 0) {
2433 RepaintGraphWindow();
2436 static void CmdPlot(char *str
)
2441 static void CmdHide(char *str
)
2446 static void CmdScale(char *str
)
2448 CursorScaleFactor
= atoi(str
);
2449 if(CursorScaleFactor
== 0) {
2450 PrintToScrollback("bad, can't have zero scale");
2451 CursorScaleFactor
= 1;
2453 RepaintGraphWindow();
2456 static void CmdSave(char *str
)
2458 FILE *f
= fopen(str
, "w");
2460 PrintToScrollback("couldn't open '%s'", str
);
2464 for(i
= 0; i
< GraphTraceLen
; i
++) {
2465 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2468 PrintToScrollback("saved to '%s'", str
);
2471 static void CmdLoad(char *str
)
2473 FILE *f
= fopen(str
, "r");
2475 PrintToScrollback("couldn't open '%s'", str
);
2481 while(fgets(line
, sizeof(line
), f
)) {
2482 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2486 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2487 RepaintGraphWindow();
2490 static void CmdHIDsimTAG(char *str
)
2492 unsigned int hi
=0, lo
=0;
2496 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2497 hi
=(hi
<<4)|(lo
>>28);
2501 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2503 c
.cmd
= CMD_HID_SIM_TAG
;
2506 SendCommand(&c
, FALSE
);
2509 static void CmdLcdReset(char *str
)
2512 c
.cmd
= CMD_LCD_RESET
;
2514 SendCommand(&c
, FALSE
);
2517 static void CmdLcd(char *str
)
2522 sscanf(str
, "%x %d", &i
, &j
);
2525 SendCommand(&c
, FALSE
);
2531 static void CmdTest(char *str
)
2536 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2539 static void CmdSetDivisor(char *str
)
2542 c
.cmd
= CMD_SET_LF_DIVISOR
;
2544 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2545 PrintToScrollback("divisor must be between 19 and 255");
2547 SendCommand(&c
, FALSE
);
2548 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2552 static void CmdSweepLF(char *str
)
2555 c
.cmd
= CMD_SWEEP_LF
;
2556 SendCommand(&c
, FALSE
);
2560 typedef void HandlerFunction(char *cmdline
);
2562 /* in alphabetic order */
2565 HandlerFunction
*handler
;
2566 int offline
; // 1 if the command can be used when in offline mode
2568 } CommandTable
[] = {
2569 "askdemod", Cmdaskdemod
,1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags",
2570 "autocorr", CmdAutoCorr
,1, "<window length> -- Autocorrelation over window",
2571 "bitsamples", CmdBitsamples
,0, " Get raw samples as bitstring",
2572 "bitstream", Cmdbitstream
,1, "[clock rate] -- Convert waveform into a bitstream",
2573 "buffclear", CmdBuffClear
,0, " Clear sample buffer and graph window",
2574 "dec", CmdDec
,1, " Decimate samples",
2575 "detectclock", Cmddetectclockrate
,1, " Detect clock rate",
2576 "em410xsim", CmdEM410xsim
,1, "<UID> -- Simulate EM410x tag",
2577 "em410xread", CmdEM410xread
,1, "[clock rate] -- Extract ID from EM410x tag",
2578 "em410xwatch", CmdEM410xwatch
,0, " Watches for EM410x tags",
2579 "em4x50read", CmdEM4x50read
,1, " Extract data from EM4x50 tag",
2580 "exit", CmdQuit
,1, " Exit program",
2581 "flexdemod", CmdFlexdemod
,1, " Demodulate samples for FlexPass",
2582 "fpgaoff", CmdFPGAOff
,0, " Set FPGA off", // ## FPGA Control
2583 "hexsamples", CmdHexsamples
,0, "<blocks> -- Dump big buffer as hex bytes",
2584 "hi14alist", CmdHi14alist
,0, " List ISO 14443a history", // ## New list command
2585 "hi14areader", CmdHi14areader
,0, " Act like an ISO14443 Type A reader", // ## New reader command
2586 "hi14asim", CmdHi14asim
,0, "<UID> -- Fake ISO 14443a tag", // ## Simulate 14443a tag
2587 "hi14asnoop", CmdHi14asnoop
,0, " Eavesdrop ISO 14443 Type A", // ## New snoop command
2588 "hi14bdemod", CmdHi14bdemod
,1, " Demodulate ISO14443 Type B from tag",
2589 "hi14list", CmdHi14list
,0, " List ISO 14443 history",
2590 "hi14read", CmdHi14read
,0, " Read HF tag (ISO 14443)",
2591 "hi14sim", CmdHi14sim
,0, " Fake ISO 14443 tag",
2592 "hi14snoop", CmdHi14snoop
,0, " Eavesdrop ISO 14443",
2593 "hi15demod", CmdHi15demod
,1, " Demodulate ISO15693 from tag",
2594 "hi15read", CmdHi15read
,0, " Read HF tag (ISO 15693)",
2595 "hi15reader", CmdHi15reader
,0, " Act like an ISO15693 reader", // new command greg
2596 "hi15sim", CmdHi15tag
,0, " Fake an ISO15693 tag", // new command greg
2597 "hiddemod", CmdHiddemod
,1, " Demodulate HID Prox Card II (not optimal)",
2598 "hide", CmdHide
,1, " Hide graph window",
2599 "hidfskdemod", CmdHIDdemodFSK
,0, " Realtime HID FSK demodulator",
2600 "hidsimtag", CmdHIDsimTAG
,0, "<ID> -- HID tag simulator",
2601 "higet", CmdHi14read_sim
,0, "<samples> -- Get samples HF, 'analog'",
2602 "hisamples", CmdHisamples
,0, " Get raw samples for HF tag",
2603 "hisampless", CmdHisampless
,0, "<samples> -- Get signed raw samples, HF tag",
2604 "hisamplest", CmdHi14readt
,0, " Get samples HF, for testing",
2605 "hisimlisten", CmdHisimlisten
,0, " Get HF samples as fake tag",
2606 "hpf", CmdHpf
,1, " Remove DC offset from trace",
2607 "indalademod", CmdIndalademod
,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)",
2608 "lcd", CmdLcd
,0, "<HEX command> <count> -- Send command/data to LCD",
2609 "lcdreset", CmdLcdReset
,0, " Hardware reset LCD",
2610 "load", CmdLoad
,1, "<filename> -- Load trace (to graph window",
2611 "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)",
2612 "loread", CmdLoread
,0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)",
2613 "losamples", CmdLosamples
,0, "[128 - 16000] -- Get raw samples for LF tag",
2614 "losim", CmdLosim
,0, " Simulate LF tag",
2615 "ltrim", CmdLtrim
,1, "<samples> -- Trim samples from left of trace",
2616 "mandemod", Cmdmanchesterdemod
,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)",
2617 "manmod", Cmdmanchestermod
,1, "[clock rate] -- Manchester modulate a binary stream",
2618 "norm", CmdNorm
,1, " Normalize max/min to +/-500",
2619 "plot", CmdPlot
,1, " Show graph window",
2620 "quit", CmdQuit
,1, " Quit program",
2621 "reset", CmdReset
,0, " Reset the Proxmark3",
2622 "save", CmdSave
,1, "<filename> -- Save trace (from graph window)",
2623 "scale", CmdScale
,1, "<int> -- Set cursor display scale",
2624 "setlfdivisor", CmdSetDivisor
,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)",
2625 "sri512read", CmdSri512read
,0, "<int> -- Read contents of a SRI512 tag",
2626 "sweeplf", CmdSweepLF
,0, " Sweep through LF freq range and store results in buffer",
2627 "tibits", CmdTibits
,0, " Get raw bits for TI-type LF tag",
2628 "tidemod", CmdTidemod
,0, " Demodulate raw bits for TI-type LF tag",
2629 "tiread", CmdTiread
,0, " Read a TI-type 134 kHz tag",
2630 "tune", CmdTune
,0, " Measure antenna tuning",
2631 "vchdemod", CmdVchdemod
,0, "['clone'] -- Demodulate samples for VeriChip",
2632 "zerocrossings", CmdZerocrossings
,1, " Count time between zero-crossings",
2636 //-----------------------------------------------------------------------------
2637 // Entry point into our code: called whenever the user types a command and
2638 // then presses Enter, which the full command line that they typed.
2639 //-----------------------------------------------------------------------------
2640 void CommandReceived(char *cmd
)
2644 PrintToScrollback("> %s", cmd
);
2646 if(strcmp(cmd
, "help")==0) {
2647 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2648 PrintToScrollback("\r\nAvailable commands:");
2649 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2650 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2652 memset(line
, ' ', sizeof(line
));
2653 strcpy(line
+2, CommandTable
[i
].name
);
2654 line
[strlen(line
)] = ' ';
2655 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2656 PrintToScrollback("%s", line
);
2658 PrintToScrollback("");
2659 PrintToScrollback("and also: help, cls");
2663 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2664 char *name
= CommandTable
[i
].name
;
2665 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2666 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2668 cmd
+= strlen(name
);
2669 while(*cmd
== ' ') {
2672 if (offline
&& (CommandTable
[i
].offline
==0)) {
2673 PrintToScrollback("Offline mode, cannot use this command.");
2676 (CommandTable
[i
].handler
)(cmd
);
2680 PrintToScrollback(">> bad command '%s'", cmd
);
2683 //-----------------------------------------------------------------------------
2684 // Entry point into our code: called whenever we received a packet over USB
2685 // that we weren't necessarily expecting, for example a debug print.
2686 //-----------------------------------------------------------------------------
2687 void UsbCommandReceived(UsbCommand
*c
)
2690 case CMD_DEBUG_PRINT_STRING
: {
2692 if(c
->ext1
> 70 || c
->ext1
< 0) {
2695 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
2697 PrintToScrollback("#db# %s", s
);
2701 case CMD_DEBUG_PRINT_INTEGERS
:
2702 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
2705 case CMD_MEASURED_ANTENNA_TUNING
: {
2707 int vLf125
, vLf134
, vHf
;
2708 vLf125
= c
->ext1
& 0xffff;
2709 vLf134
= c
->ext1
>> 16;
2711 zLf
= c
->ext3
& 0xffff;
2712 zHf
= c
->ext3
>> 16;
2713 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",
2714 vLf125
/zLf
, vLf125
, zLf
);
2715 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",
2716 vLf134
/((zLf
*125)/134), vLf134
, (zLf
*125)/134);
2717 PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",
2722 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);