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 ID of an EM410x tag.
261 * 1111 1111 1 <-- standard non-repeatable header
262 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
264 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
265 * 0 <-- stop bit, end of tag
267 static void CmdEM410xread(char *str
)
269 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
273 int BitStream
[MAX_GRAPH_TRACE_LEN
];
276 /* Detect high and lows and clock */
277 for (i
= 0; i
< GraphTraceLen
; i
++)
279 if (GraphBuffer
[i
] > high
)
280 high
= GraphBuffer
[i
];
281 else if (GraphBuffer
[i
] < low
)
282 low
= GraphBuffer
[i
];
286 clock
= GetClock(str
, high
);
288 /* parity for our 4 columns */
289 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
292 /* manchester demodulate */
294 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
300 /* Find out if we hit both high and low peaks */
301 for (j
= 0; j
< clock
; j
++)
303 if (GraphBuffer
[(i
* clock
) + j
] == high
)
305 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
308 /* it doesn't count if it's the first part of our read
309 because it's really just trailing from the last sequence */
310 if (first
&& (hithigh
|| hitlow
))
311 hithigh
= hitlow
= 0;
315 if (hithigh
&& hitlow
)
319 /* If we didn't hit both high and low peaks, we had a bit transition */
320 if (!hithigh
|| !hitlow
)
323 BitStream
[bit2idx
++] = bit
;
327 /* We go till 5 before the graph ends because we'll get that far below */
328 for (i
= 1; i
< bit2idx
- 5; i
++)
330 /* Step 2: We have our header but need our tag ID */
331 if (header
== 9 && rows
< 10)
333 /* Confirm parity is correct */
334 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
336 /* Read another byte! */
337 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
340 /* Keep parity info */
341 parity
[0] ^= BitStream
[i
];
342 parity
[1] ^= BitStream
[i
+1];
343 parity
[2] ^= BitStream
[i
+2];
344 parity
[3] ^= BitStream
[i
+3];
346 /* Move 4 bits ahead */
350 /* Damn, something wrong! reset */
353 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
355 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
356 i
-= 9 + (5 * rows
) - 5;
362 /* Step 3: Got our 40 bits! confirm column parity */
365 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
366 if (BitStream
[i
] == parity
[0] && BitStream
[i
+1] == parity
[1] &&
367 BitStream
[i
+2] == parity
[2] && BitStream
[i
+3] == parity
[3] &&
371 PrintToScrollback("EM410x Tag ID: %s", id
);
378 /* Crap! Incorrect parity or no stop bit, start all over */
383 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
388 /* Step 1: get our header */
391 /* Need 9 consecutive 1's */
392 if (BitStream
[i
] == 1)
395 /* We don't have a header, not enough consecutive 1 bits */
401 /* if we've already retested after flipping bits, return */
405 /* if this didn't work, try flipping bits */
406 for (i
= 0; i
< bit2idx
; i
++)
412 /* emulate an EM410X tag
414 * 1111 1111 1 <-- standard non-repeatable header
415 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
417 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
418 * 0 <-- stop bit, end of tag
420 static void CmdEM410xsim(char *str
)
422 int i
, n
, j
, h
, binary
[4], parity
[4];
425 /* clock is 64 in EM410x tags */
428 /* clear our graph */
431 /* write it out a few times */
432 for (h
= 0; h
< 4; h
++)
434 /* write 9 start bits */
435 for (i
= 0; i
< 9; i
++)
436 CmdAppendGraph(0, clock
, 1);
438 /* for each hex char */
439 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
440 for (i
= 0; i
< 10; i
++)
442 /* read each hex char */
443 sscanf(&str
[i
], "%1x", &n
);
444 for (j
= 3; j
>= 0; j
--, n
/= 2)
447 /* append each bit */
448 CmdAppendGraph(0, clock
, binary
[0]);
449 CmdAppendGraph(0, clock
, binary
[1]);
450 CmdAppendGraph(0, clock
, binary
[2]);
451 CmdAppendGraph(0, clock
, binary
[3]);
453 /* append parity bit */
454 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
456 /* keep track of column parity */
457 parity
[0] ^= binary
[0];
458 parity
[1] ^= binary
[1];
459 parity
[2] ^= binary
[2];
460 parity
[3] ^= binary
[3];
464 CmdAppendGraph(0, clock
, parity
[0]);
465 CmdAppendGraph(0, clock
, parity
[1]);
466 CmdAppendGraph(0, clock
, parity
[2]);
467 CmdAppendGraph(0, clock
, parity
[3]);
470 CmdAppendGraph(0, clock
, 0);
473 /* modulate that biatch */
477 RepaintGraphWindow();
482 static void ChkBitstream(char *str
)
486 /* convert to bitstream if necessary */
487 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
489 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
497 static void CmdLosim(char *str
)
502 /* convert to bitstream if necessary */
505 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
508 for(j
= 0; j
< 48; j
++) {
509 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
511 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
513 SendCommand(&c
, FALSE
);
517 c
.cmd
= CMD_SIMULATE_TAG_125K
;
518 c
.ext1
= GraphTraceLen
;
519 SendCommand(&c
, FALSE
);
522 static void CmdLoread(char *str
)
525 // 'h' means higher-low-frequency, 134 kHz
528 } else if (*str
== '\0') {
531 PrintToScrollback("use 'loread' or 'loread h'");
534 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
535 SendCommand(&c
, FALSE
);
538 static void CmdLosamples(char *str
)
546 if (n
>16000) n
=16000;
548 for(i
= 0; i
< n
; i
+= 12) {
550 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
552 SendCommand(&c
, FALSE
);
554 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
556 PrintToScrollback("bad resp");
560 for(j
= 0; j
< 48; j
++) {
561 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
565 RepaintGraphWindow();
568 static void CmdBitsamples(char *str
)
575 for(i
= 0; i
< n
; i
+= 12) {
577 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
579 SendCommand(&c
, FALSE
);
581 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
582 PrintToScrollback("bad resp");
586 for(j
= 0; j
< 48; j
++) {
587 for(k
= 0; k
< 8; k
++) {
588 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
589 GraphBuffer
[cnt
++] = 1;
591 GraphBuffer
[cnt
++] = 0;
597 RepaintGraphWindow();
600 static void CmdHisamples(char *str
)
606 for(i
= 0; i
< n
; i
+= 12) {
608 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
610 SendCommand(&c
, FALSE
);
612 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
613 PrintToScrollback("bad resp");
617 for(j
= 0; j
< 48; j
++) {
618 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
623 RepaintGraphWindow();
627 static int CmdHisamplest(char *str
, int nrlow
)
639 for(i
= 0; i
< n
; i
+= 12) {
641 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
643 SendCommand(&c
, FALSE
);
645 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
646 PrintToScrollback("bad resp");
650 for(j
= 0; j
< 48; j
++) {
651 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
652 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
658 t1
= (t2
& 0x80) ^ (t2
& 0x20);
659 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
665 t2
= ((t2
<< 1) & 0x80);
671 t2
= ((t2
<< 1) & 0x20);
675 // both, but tag with other algorithm
676 t1
= (t2
& 0x80) ^ (t2
& 0x08);
677 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
681 GraphBuffer
[cnt
++] = t1
;
682 GraphBuffer
[cnt
++] = t2
;
687 if(hasbeennull
>nrlow
|| nrlow
==0) {
688 PrintToScrollback("hasbeennull=%d", hasbeennull
);
697 static void CmdHexsamples(char *str
)
708 for(i
= 0; i
< n
; i
+= 12) {
710 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
712 SendCommand(&c
, FALSE
);
714 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
715 PrintToScrollback("bad resp");
719 for(j
= 0; j
< 48; j
+= 8) {
720 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
735 static void CmdHisampless(char *str
)
747 for(i
= 0; i
< n
; i
+= 12) {
749 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
751 SendCommand(&c
, FALSE
);
753 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
754 PrintToScrollback("bad resp");
758 for(j
= 0; j
< 48; j
++) {
759 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
764 RepaintGraphWindow();
767 static WORD
Iso15693Crc(BYTE
*v
, int n
)
773 for(i
= 0; i
< n
; i
++) {
774 reg
= reg
^ ((DWORD
)v
[i
]);
775 for (j
= 0; j
< 8; j
++) {
777 reg
= (reg
>> 1) ^ 0x8408;
787 static void CmdHi14bdemod(char *str
)
792 BOOL negateI
, negateQ
;
797 // As received, the samples are pairs, correlations against I and Q
798 // square waves. So estimate angle of initial carrier (or just
799 // quadrant, actually), and then do the demod.
801 // First, estimate where the tag starts modulating.
802 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
803 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
807 if(i
>= GraphTraceLen
) {
808 PrintToScrollback("too weak to sync");
811 PrintToScrollback("out of weak at %d", i
);
814 // Now, estimate the phase in the initial modulation of the tag
817 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
818 isum
+= GraphBuffer
[i
+0];
819 qsum
+= GraphBuffer
[i
+1];
821 negateI
= (isum
< 0);
822 negateQ
= (qsum
< 0);
824 // Turn the correlation pairs into soft decisions on the bit.
826 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
827 int si
= GraphBuffer
[j
];
828 int sq
= GraphBuffer
[j
+1];
829 if(negateI
) si
= -si
;
830 if(negateQ
) sq
= -sq
;
831 GraphBuffer
[i
] = si
+ sq
;
837 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
839 if(i
>= GraphTraceLen
) goto demodError
;
842 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
844 if(i
>= GraphTraceLen
) goto demodError
;
845 if((i
- iold
) > 23) goto demodError
;
847 PrintToScrollback("make it to demod loop");
851 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
853 if(i
>= GraphTraceLen
) goto demodError
;
854 if((i
- iold
) > 6) goto demodError
;
857 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
859 for(j
= 0; j
< 10; j
++) {
860 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
862 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
863 PrintToScrollback("weak bit");
867 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
874 if( (shiftReg
& 0x200) &&
877 // valid data byte, start and stop bits okay
878 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
879 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
880 if(dataLen
>= sizeof(data
)) {
883 } else if(shiftReg
== 0x000) {
892 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
893 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
894 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
895 "ok" : "****FAIL****");
897 RepaintGraphWindow();
901 PrintToScrollback("demod error");
902 RepaintGraphWindow();
905 static void CmdHi14list(char *str
)
908 GetFromBigBuf(got
, sizeof(got
));
910 PrintToScrollback("recorded activity:");
911 PrintToScrollback(" time :rssi: who bytes");
912 PrintToScrollback("---------+----+----+-----------");
923 int timestamp
= *((DWORD
*)(got
+i
));
924 if(timestamp
& 0x80000000) {
925 timestamp
&= 0x7fffffff;
930 int metric
= *((DWORD
*)(got
+i
+4));
941 BYTE
*frame
= (got
+i
+9);
943 char line
[1000] = "";
945 for(j
= 0; j
< len
; j
++) {
946 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
952 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
953 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
954 crc
= "**FAIL CRC**";
962 char metricString
[100];
964 sprintf(metricString
, "%3d", metric
);
966 strcpy(metricString
, " ");
969 PrintToScrollback(" +%7d: %s: %s %s %s",
970 (prev
< 0 ? 0 : timestamp
- prev
),
972 (isResponse
? "TAG" : " "), line
, crc
);
979 static void CmdHi14alist(char *str
)
982 GetFromBigBuf(got
, sizeof(got
));
984 PrintToScrollback("recorded activity:");
985 PrintToScrollback(" ETU :rssi: who bytes");
986 PrintToScrollback("---------+----+----+-----------");
997 int timestamp
= *((DWORD
*)(got
+i
));
998 if(timestamp
& 0x80000000) {
999 timestamp
&= 0x7fffffff;
1006 int parityBits
= *((DWORD
*)(got
+i
+4));
1007 // 4 bytes of additional information...
1008 // maximum of 32 additional parity bit information
1011 // at each quarter bit period we can send power level (16 levels)
1012 // or each half bit period in 256 levels.
1020 if(i
+ len
>= 1900) {
1024 BYTE
*frame
= (got
+i
+9);
1026 // Break and stick with current result if buffer was not completely full
1027 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1029 char line
[1000] = "";
1031 for(j
= 0; j
< len
; j
++) {
1032 int oddparity
= 0x01;
1036 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1039 //if((parityBits >> (len - j - 1)) & 0x01) {
1040 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1041 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1044 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1052 for(j
= 0; j
< (len
- 1); j
++) {
1053 // gives problems... search for the reason..
1054 /*if(frame[j] == 0xAA) {
1055 switch(frame[j+1]) {
1057 crc = "[1] Two drops close after each other";
1060 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1063 crc = "[3] Segment Z after segment X is not possible";
1066 crc = "[4] Parity bit of a fully received byte was wrong";
1069 crc = "[?] Unknown error";
1076 if(strlen(crc
)==0) {
1077 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1078 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1079 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1088 char metricString
[100];
1090 sprintf(metricString
, "%3d", metric
);
1092 strcpy(metricString
, " ");
1095 PrintToScrollback(" +%7d: %s: %s %s %s",
1096 (prev
< 0 ? 0 : (timestamp
- prev
)),
1098 (isResponse
? "TAG" : " "), line
, crc
);
1103 CommandFinished
= 1;
1106 static void CmdHi15demod(char *str
)
1108 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1111 // 1) Unmodulated time of 56.64us
1112 // 2) 24 pulses of 423.75khz
1113 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1115 static const int FrameSOF
[] = {
1116 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1117 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1118 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1119 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1125 static const int Logic0
[] = {
1131 static const int Logic1
[] = {
1139 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1140 // 2) 24 pulses of 423.75khz
1141 // 3) Unmodulated time of 56.64us
1143 static const int FrameEOF
[] = {
1148 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1149 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1151 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1155 int max
= 0, maxPos
;
1159 if(GraphTraceLen
< 1000) return;
1161 // First, correlate for SOF
1162 for(i
= 0; i
< 100; i
++) {
1164 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1165 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1172 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1173 max
/(arraylen(FrameSOF
)/skip
));
1175 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1178 memset(outBuf
, 0, sizeof(outBuf
));
1181 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1182 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1183 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1185 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1186 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1188 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1189 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1191 // Even things out by the length of the target waveform.
1195 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1196 PrintToScrollback("EOF at %d", i
);
1198 } else if(corr1
> corr0
) {
1199 i
+= arraylen(Logic1
)/skip
;
1202 i
+= arraylen(Logic0
)/skip
;
1209 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1210 PrintToScrollback("ran off end!");
1215 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1216 PrintToScrollback(" mask=%02x", mask
);
1218 PrintToScrollback("%d octets", k
);
1220 for(i
= 0; i
< k
; i
++) {
1221 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1223 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1226 static void CmdTiread(char *str
)
1229 c
.cmd
= CMD_ACQUIRE_RAW_BITS_TI_TYPE
;
1230 SendCommand(&c
, FALSE
);
1233 static void CmdTibits(char *str
)
1237 for(i
= 0; i
< 1536; i
+= 12) {
1239 c
.cmd
= CMD_DOWNLOAD_RAW_BITS_TI_TYPE
;
1241 SendCommand(&c
, FALSE
);
1243 if(c
.cmd
!= CMD_DOWNLOADED_RAW_BITS_TI_TYPE
) {
1244 PrintToScrollback("bad resp");
1248 for(j
= 0; j
< 12; j
++) {
1250 for(k
= 31; k
>= 0; k
--) {
1251 if(c
.d
.asDwords
[j
] & (1 << k
)) {
1252 GraphBuffer
[cnt
++] = 1;
1254 GraphBuffer
[cnt
++] = -1;
1259 GraphTraceLen
= 1536*32;
1260 RepaintGraphWindow();
1263 static void CmdTidemod(char *cmdline
)
1265 /* MATLAB as follows:
1266 f_s = 2000000; % sampling frequency
1267 f_l = 123200; % low FSK tone
1268 f_h = 134200; % high FSK tone
1270 T_l = 119e-6; % low bit duration
1271 T_h = 130e-6; % high bit duration
1273 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1274 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1276 l = sign(sin(cumsum(l)));
1277 h = sign(sin(cumsum(h)));
1279 static const int LowTone
[] = {
1280 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,
1281 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1282 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
1283 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
1284 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,
1285 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
1286 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,
1287 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1288 1, 1, -1, -1, -1, -1, -1, -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, 1, 1, 1, -1, -1, -1, -1,
1290 -1, -1, -1, -1, 1, 1, 1, 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, -1, -1, -1, -1, -1, -1, 1,
1292 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
1294 static const int HighTone
[] = {
1295 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1296 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1297 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1298 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1299 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1300 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1301 -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1302 -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1303 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1304 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1305 -1, -1, -1, -1, -1, 1, 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, -1, -1, -1, -1, -1, 1, 1,
1307 1, 1, 1, 1, 1, -1, -1, -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, 1, 1, 1, 1,
1311 int convLen
= max(arraylen(HighTone
), arraylen(LowTone
));
1314 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1316 int lowSum
= 0, highSum
= 0;;
1317 int lowLen
= arraylen(LowTone
);
1318 int highLen
= arraylen(HighTone
);
1320 for(j
= 0; j
< lowLen
; j
++) {
1321 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1323 for(j
= 0; j
< highLen
; j
++) {
1324 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1326 lowSum
= abs((100*lowSum
) / lowLen
);
1327 highSum
= abs((100*highSum
) / highLen
);
1328 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1331 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1333 int lowTot
= 0, highTot
= 0;
1334 // 16 and 15 are f_s divided by f_l and f_h, rounded
1335 for(j
= 0; j
< 16; j
++) {
1336 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1338 for(j
= 0; j
< 15; j
++) {
1339 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1341 GraphBuffer
[i
] = lowTot
- highTot
;
1344 GraphTraceLen
-= (convLen
+ 16);
1346 RepaintGraphWindow();
1348 // Okay, so now we have unsliced soft decisions; find bit-sync, and then
1351 int max
= 0, maxPos
= 0;
1352 for(i
= 0; i
< 6000; i
++) {
1355 for(j
= 0; j
< 8*arraylen(LowTone
); j
++) {
1356 dec
-= GraphBuffer
[i
+j
];
1358 for(; j
< 8*arraylen(LowTone
) + 8*arraylen(HighTone
); j
++) {
1359 dec
+= GraphBuffer
[i
+j
];
1366 GraphBuffer
[maxPos
] = 800;
1367 GraphBuffer
[maxPos
+1] = -800;
1369 maxPos
+= 8*arraylen(LowTone
);
1370 GraphBuffer
[maxPos
] = 800;
1371 GraphBuffer
[maxPos
+1] = -800;
1372 maxPos
+= 8*arraylen(HighTone
);
1374 GraphBuffer
[maxPos
] = 800;
1375 GraphBuffer
[maxPos
+1] = -800;
1377 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1379 PrintToScrollback("length %d/%d", arraylen(HighTone
), arraylen(LowTone
));
1381 GraphBuffer
[maxPos
] = 800;
1382 GraphBuffer
[maxPos
+1] = -800;
1384 BYTE bits
[64+16+8+1];
1385 bits
[sizeof(bits
)-1] = '\0';
1387 for(i
= 0; i
< arraylen(bits
); i
++) {
1391 for(j
= 0; j
< arraylen(LowTone
); j
++) {
1392 low
-= GraphBuffer
[maxPos
+j
];
1394 for(j
= 0; j
< arraylen(HighTone
); j
++) {
1395 high
+= GraphBuffer
[maxPos
+j
];
1399 maxPos
+= arraylen(HighTone
);
1402 maxPos
+= arraylen(LowTone
);
1404 GraphBuffer
[maxPos
] = 800;
1405 GraphBuffer
[maxPos
+1] = -800;
1407 PrintToScrollback("bits: '%s'", bits
);
1410 for(i
= 0; i
< 32; i
++) {
1411 if(bits
[i
] == '1') {
1415 for(i
= 32; i
< 64; i
++) {
1416 if(bits
[i
] == '1') {
1420 PrintToScrollback("hex: %08x %08x", h
, l
);
1423 static void CmdNorm(char *str
)
1426 int max
= INT_MIN
, min
= INT_MAX
;
1427 for(i
= 10; i
< GraphTraceLen
; i
++) {
1428 if(GraphBuffer
[i
] > max
) {
1429 max
= GraphBuffer
[i
];
1431 if(GraphBuffer
[i
] < min
) {
1432 min
= GraphBuffer
[i
];
1436 for(i
= 0; i
< GraphTraceLen
; i
++) {
1437 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1441 RepaintGraphWindow();
1444 static void CmdDec(char *str
)
1447 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1448 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1451 PrintToScrollback("decimated by 2");
1452 RepaintGraphWindow();
1455 static void CmdHpf(char *str
)
1459 for(i
= 10; i
< GraphTraceLen
; i
++) {
1460 accum
+= GraphBuffer
[i
];
1462 accum
/= (GraphTraceLen
- 10);
1463 for(i
= 0; i
< GraphTraceLen
; i
++) {
1464 GraphBuffer
[i
] -= accum
;
1467 RepaintGraphWindow();
1470 static void CmdZerocrossings(char *str
)
1473 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1479 for(i
= 0; i
< GraphTraceLen
; i
++) {
1480 if(GraphBuffer
[i
]*sign
>= 0) {
1481 // No change in sign, reproduce the previous sample count.
1483 GraphBuffer
[i
] = lastZc
;
1485 // Change in sign, reset the sample count.
1487 GraphBuffer
[i
] = lastZc
;
1495 RepaintGraphWindow();
1498 static void CmdLtrim(char *str
)
1503 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1504 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1506 GraphTraceLen
-= ds
;
1508 RepaintGraphWindow();
1511 static void CmdAutoCorr(char *str
)
1513 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1515 int window
= atoi(str
);
1518 PrintToScrollback("needs a window");
1522 if(window
>= GraphTraceLen
) {
1523 PrintToScrollback("window must be smaller than trace (%d samples)",
1528 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1531 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1534 for(j
= 0; j
< window
; j
++) {
1535 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1537 CorrelBuffer
[i
] = sum
;
1539 GraphTraceLen
= GraphTraceLen
- window
;
1540 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1542 RepaintGraphWindow();
1545 static void CmdVchdemod(char *str
)
1547 // Is this the entire sync pattern, or does this also include some
1548 // data bits that happen to be the same everywhere? That would be
1550 static const int SyncPattern
[] = {
1551 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1552 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1553 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1554 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1555 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1556 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1557 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1558 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1559 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1560 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1563 // So first, we correlate for the sync pattern, and mark that.
1564 int bestCorrel
= 0, bestPos
= 0;
1566 // It does us no good to find the sync pattern, with fewer than
1567 // 2048 samples after it...
1568 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1571 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1572 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1574 if(sum
> bestCorrel
) {
1579 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
1584 int worst
= INT_MAX
;
1587 for(i
= 0; i
< 2048; i
+= 8) {
1590 for(j
= 0; j
< 8; j
++) {
1591 sum
+= GraphBuffer
[bestPos
+i
+j
];
1598 if(abs(sum
) < worst
) {
1603 PrintToScrollback("bits:");
1604 PrintToScrollback("%s", bits
);
1605 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
1607 if(strcmp(str
, "clone")==0) {
1610 for(s
= bits
; *s
; s
++) {
1612 for(j
= 0; j
< 16; j
++) {
1613 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
1616 RepaintGraphWindow();
1620 static void CmdIndalademod(char *str
)
1622 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
1627 // worst case with GraphTraceLen=64000 is < 4096
1628 // under normal conditions it's < 2048
1631 int worst
= 0, worstPos
= 0;
1632 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
1633 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
1635 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
1637 for(j
= 0; j
< count
- 8; j
+= 16) {
1638 rawbits
[rawbit
++] = 0;
1640 if ((abs(count
- j
)) > worst
) {
1641 worst
= abs(count
- j
);
1647 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
1649 for(j
= 0; j
< count
- 8; j
+= 16) {
1650 rawbits
[rawbit
++] = 1;
1652 if ((abs(count
- j
)) > worst
) {
1653 worst
= abs(count
- j
);
1661 PrintToScrollback("Recovered %d raw bits", rawbit
);
1662 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
1664 // Finding the start of a UID
1665 int uidlen
, long_wait
;
1666 if(strcmp(str
, "224") == 0) {
1675 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
1676 first
= rawbits
[start
];
1677 for(i
= start
; i
< start
+ long_wait
; i
++) {
1678 if(rawbits
[i
] != first
) {
1682 if(i
== (start
+ long_wait
)) {
1686 if(start
== rawbit
- uidlen
+ 1) {
1687 PrintToScrollback("nothing to wait for");
1691 // Inverting signal if needed
1693 for(i
= start
; i
< rawbit
; i
++) {
1694 rawbits
[i
] = !rawbits
[i
];
1701 showbits
[uidlen
]='\0';
1705 if(uidlen
> rawbit
) {
1706 PrintToScrollback("Warning: not enough raw bits to get a full UID");
1707 for(bit
= 0; bit
< rawbit
; bit
++) {
1708 bits
[bit
] = rawbits
[i
++];
1709 // As we cannot know the parity, let's use "." and "/"
1710 showbits
[bit
] = '.' + bits
[bit
];
1712 showbits
[bit
+1]='\0';
1713 PrintToScrollback("Partial UID=%s", showbits
);
1716 for(bit
= 0; bit
< uidlen
; bit
++) {
1717 bits
[bit
] = rawbits
[i
++];
1718 showbits
[bit
] = '0' + bits
[bit
];
1722 PrintToScrollback("UID=%s", showbits
);
1724 // Checking UID against next occurences
1725 for(; i
+ uidlen
<= rawbit
;) {
1727 for(bit
= 0; bit
< uidlen
; bit
++) {
1728 if(bits
[bit
] != rawbits
[i
++]) {
1738 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
1740 // Remodulating for tag cloning
1741 GraphTraceLen
= 32*uidlen
;
1744 for(bit
= 0; bit
< uidlen
; bit
++) {
1745 if(bits
[bit
] == 0) {
1751 for(j
= 0; j
< 32; j
++) {
1752 GraphBuffer
[i
++] = phase
;
1757 RepaintGraphWindow();
1760 static void CmdFlexdemod(char *str
)
1763 for(i
= 0; i
< GraphTraceLen
; i
++) {
1764 if(GraphBuffer
[i
] < 0) {
1765 GraphBuffer
[i
] = -1;
1771 #define LONG_WAIT 100
1773 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
1774 int first
= GraphBuffer
[start
];
1775 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
1776 if(GraphBuffer
[i
] != first
) {
1780 if(i
== (start
+ LONG_WAIT
)) {
1784 if(start
== GraphTraceLen
- LONG_WAIT
) {
1785 PrintToScrollback("nothing to wait for");
1789 GraphBuffer
[start
] = 2;
1790 GraphBuffer
[start
+1] = -2;
1796 for(bit
= 0; bit
< 64; bit
++) {
1799 for(j
= 0; j
< 16; j
++) {
1800 sum
+= GraphBuffer
[i
++];
1807 PrintToScrollback("bit %d sum %d", bit
, sum
);
1810 for(bit
= 0; bit
< 64; bit
++) {
1813 for(j
= 0; j
< 16; j
++) {
1814 sum
+= GraphBuffer
[i
++];
1816 if(sum
> 0 && bits
[bit
] != 1) {
1817 PrintToScrollback("oops1 at %d", bit
);
1819 if(sum
< 0 && bits
[bit
] != 0) {
1820 PrintToScrollback("oops2 at %d", bit
);
1824 GraphTraceLen
= 32*64;
1827 for(bit
= 0; bit
< 64; bit
++) {
1828 if(bits
[bit
] == 0) {
1834 for(j
= 0; j
< 32; j
++) {
1835 GraphBuffer
[i
++] = phase
;
1840 RepaintGraphWindow();
1844 * Generic command to demodulate ASK.
1846 * Argument is convention: positive or negative (High mod means zero
1847 * or high mod means one)
1849 * Updates the Graph trace with 0/1 values
1855 static void Cmdaskdemod(char *str
) {
1860 // TODO: complain if we do not give 2 arguments here !
1861 sscanf(str
, "%i", &c
);
1863 /* Detect high and lows and clock */
1864 for (i
= 0; i
< GraphTraceLen
; i
++)
1866 if (GraphBuffer
[i
] > high
)
1867 high
= GraphBuffer
[i
];
1868 else if (GraphBuffer
[i
] < low
)
1869 low
= GraphBuffer
[i
];
1872 if (GraphBuffer
[0] > 0) {
1873 GraphBuffer
[0] = 1-c
;
1877 for(i
=1;i
<GraphTraceLen
;i
++) {
1878 /* Transitions are detected at each peak
1879 * Transitions are either:
1880 * - we're low: transition if we hit a high
1881 * - we're high: transition if we hit a low
1882 * (we need to do it this way because some tags keep high or
1883 * low for long periods, others just reach the peak and go
1886 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
1888 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
1892 GraphBuffer
[i
] = GraphBuffer
[i
-1];
1895 RepaintGraphWindow();
1898 /* Print our clock rate */
1899 static void Cmddetectclockrate(char *str
)
1901 int clock
= detectclock(0);
1902 PrintToScrollback("Auto-detected clock rate: %d", clock
);
1908 int detectclock(int peak
)
1914 /* Detect peak if we don't have one */
1916 for (i
= 0; i
< GraphTraceLen
; i
++)
1917 if (GraphBuffer
[i
] > peak
)
1918 peak
= GraphBuffer
[i
];
1920 for (i
= 1; i
< GraphTraceLen
; i
++)
1922 /* If this is the beginning of a peak */
1923 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
1925 /* Find lowest difference between peaks */
1926 if (lastpeak
&& i
- lastpeak
< clock
)
1928 clock
= i
- lastpeak
;
1937 /* Get or auto-detect clock rate */
1938 int GetClock(char *str
, int peak
)
1942 sscanf(str
, "%i", &clock
);
1943 if (!strcmp(str
, ""))
1946 /* Auto-detect clock */
1949 clock
= detectclock(peak
);
1951 /* Only print this message if we're not looping something */
1953 PrintToScrollback("Auto-detected clock rate: %d", clock
);
1960 * Convert to a bitstream
1962 static void Cmdbitstream(char *str
) {
1969 int hithigh
, hitlow
, first
;
1971 /* Detect high and lows and clock */
1972 for (i
= 0; i
< GraphTraceLen
; i
++)
1974 if (GraphBuffer
[i
] > high
)
1975 high
= GraphBuffer
[i
];
1976 else if (GraphBuffer
[i
] < low
)
1977 low
= GraphBuffer
[i
];
1981 clock
= GetClock(str
, high
);
1983 gtl
= CmdClearGraph(0);
1986 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
1992 /* Find out if we hit both high and low peaks */
1993 for (j
= 0; j
< clock
; j
++)
1995 if (GraphBuffer
[(i
* clock
) + j
] == high
)
1997 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2000 /* it doesn't count if it's the first part of our read
2001 because it's really just trailing from the last sequence */
2002 if (first
&& (hithigh
|| hitlow
))
2003 hithigh
= hitlow
= 0;
2007 if (hithigh
&& hitlow
)
2011 /* If we didn't hit both high and low peaks, we had a bit transition */
2012 if (!hithigh
|| !hitlow
)
2015 CmdAppendGraph(0, clock
, bit
);
2016 // for (j = 0; j < (int)(clock/2); j++)
2017 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2018 // for (j = (int)(clock/2); j < clock; j++)
2019 // GraphBuffer[(i * clock) + j] = bit;
2022 RepaintGraphWindow();
2025 /* Modulate our data into manchester */
2026 static void Cmdmanchestermod(char *str
)
2030 int bit
, lastbit
, wave
;
2033 clock
= GetClock(str
, 0);
2037 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2039 bit
= GraphBuffer
[i
* clock
] ^ 1;
2041 for (j
= 0; j
< (int)(clock
/2); j
++)
2042 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2043 for (j
= (int)(clock
/2); j
< clock
; j
++)
2044 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2046 /* Keep track of how we start our wave and if we changed or not this time */
2047 wave
^= bit
^ lastbit
;
2051 RepaintGraphWindow();
2055 * Manchester demodulate a bitstream. The bitstream needs to be already in
2056 * the GraphBuffer as 0 and 1 values
2058 * Give the clock rate as argument in order to help the sync - the algorithm
2059 * resyncs at each pulse anyway.
2061 * Not optimized by any means, this is the 1st time I'm writing this type of
2062 * routine, feel free to improve...
2064 * 1st argument: clock rate (as number of samples per clock rate)
2065 * Typical values can be 64, 32, 128...
2067 static void Cmdmanchesterdemod(char *str
) {
2074 int hithigh
, hitlow
, first
;
2080 /* Holds the decoded bitstream: each clock period contains 2 bits */
2081 /* later simplified to 1 bit after manchester decoding. */
2082 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2083 /* int BitStream[GraphTraceLen*2/clock+10]; */
2085 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2087 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2089 /* Detect high and lows */
2090 for (i
= 0; i
< GraphTraceLen
; i
++)
2092 if (GraphBuffer
[i
] > high
)
2093 high
= GraphBuffer
[i
];
2094 else if (GraphBuffer
[i
] < low
)
2095 low
= GraphBuffer
[i
];
2099 clock
= GetClock(str
, high
);
2101 int tolerance
= clock
/4;
2103 /* Detect first transition */
2104 /* Lo-Hi (arbitrary) */
2105 for (i
= 0; i
< GraphTraceLen
; i
++)
2107 if (GraphBuffer
[i
] == low
)
2114 /* If we're not working with 1/0s, demod based off clock */
2117 bit
= 0; /* We assume the 1st bit is zero, it may not be
2118 * the case: this routine (I think) has an init problem.
2121 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2127 /* Find out if we hit both high and low peaks */
2128 for (j
= 0; j
< clock
; j
++)
2130 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2132 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2135 /* it doesn't count if it's the first part of our read
2136 because it's really just trailing from the last sequence */
2137 if (first
&& (hithigh
|| hitlow
))
2138 hithigh
= hitlow
= 0;
2142 if (hithigh
&& hitlow
)
2146 /* If we didn't hit both high and low peaks, we had a bit transition */
2147 if (!hithigh
|| !hitlow
)
2150 BitStream
[bit2idx
++] = bit
;
2154 /* standard 1/0 bitstream */
2158 /* Then detect duration between 2 successive transitions */
2159 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2161 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2166 // Error check: if bitidx becomes too large, we do not
2167 // have a Manchester encoded bitstream or the clock is really
2169 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2170 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2173 // Then switch depending on lc length:
2174 // Tolerance is 1/4 of clock rate (arbitrary)
2175 if (abs(lc
-clock
/2) < tolerance
) {
2176 // Short pulse : either "1" or "0"
2177 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2178 } else if (abs(lc
-clock
) < tolerance
) {
2179 // Long pulse: either "11" or "00"
2180 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2181 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2185 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2186 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2190 PrintToScrollback("Error: too many detection errors, aborting.");
2197 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2198 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2199 // to stop output at the final bitidx2 value, not bitidx
2200 for (i
= 0; i
< bitidx
; i
+= 2) {
2201 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2202 BitStream
[bit2idx
++] = 1;
2203 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2204 BitStream
[bit2idx
++] = 0;
2206 // We cannot end up in this state, this means we are unsynchronized,
2210 PrintToScrollback("Unsynchronized, resync...");
2211 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2215 PrintToScrollback("Error: too many decode errors, aborting.");
2222 PrintToScrollback("Manchester decoded bitstream");
2223 // Now output the bitstream to the scrollback by line of 16 bits
2224 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2225 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2250 static void CmdHiddemod(char *str
)
2252 if(GraphTraceLen
< 4800) {
2253 PrintToScrollback("too short; need at least 4800 samples");
2257 GraphTraceLen
= 4800;
2259 for(i
= 0; i
< GraphTraceLen
; i
++) {
2260 if(GraphBuffer
[i
] < 0) {
2266 RepaintGraphWindow();
2269 static void CmdPlot(char *str
)
2274 static void CmdHide(char *str
)
2279 static void CmdScale(char *str
)
2281 CursorScaleFactor
= atoi(str
);
2282 if(CursorScaleFactor
== 0) {
2283 PrintToScrollback("bad, can't have zero scale");
2284 CursorScaleFactor
= 1;
2286 RepaintGraphWindow();
2289 static void CmdSave(char *str
)
2291 FILE *f
= fopen(str
, "w");
2293 PrintToScrollback("couldn't open '%s'", str
);
2297 for(i
= 0; i
< GraphTraceLen
; i
++) {
2298 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2301 PrintToScrollback("saved to '%s'", str
);
2304 static void CmdLoad(char *str
)
2306 FILE *f
= fopen(str
, "r");
2308 PrintToScrollback("couldn't open '%s'", str
);
2314 while(fgets(line
, sizeof(line
), f
)) {
2315 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2319 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2320 RepaintGraphWindow();
2323 static void CmdHIDsimTAG(char *str
)
2325 unsigned int hi
=0, lo
=0;
2329 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2330 hi
=(hi
<<4)|(lo
>>28);
2334 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2336 c
.cmd
= CMD_HID_SIM_TAG
;
2339 SendCommand(&c
, FALSE
);
2342 static void CmdLcdReset(char *str
)
2345 c
.cmd
= CMD_LCD_RESET
;
2347 SendCommand(&c
, FALSE
);
2350 static void CmdLcd(char *str
)
2355 sscanf(str
, "%x %d", &i
, &j
);
2358 SendCommand(&c
, FALSE
);
2364 static void CmdTest(char *str
)
2369 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2372 static void CmdSetDivisor(char *str
)
2375 c
.cmd
= CMD_SET_LF_DIVISOR
;
2377 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2378 PrintToScrollback("divisor must be between 19 and 255");
2380 SendCommand(&c
, FALSE
);
2381 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2385 static void CmdSweepLF(char *str
)
2388 c
.cmd
= CMD_SWEEP_LF
;
2389 SendCommand(&c
, FALSE
);
2393 typedef void HandlerFunction(char *cmdline
);
2395 /* in alphabetic order */
2398 HandlerFunction
*handler
;
2399 int offline
; // 1 if the command can be used when in offline mode
2401 } CommandTable
[] = {
2402 "askdemod", Cmdaskdemod
,1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags",
2403 "autocorr", CmdAutoCorr
,1, "<window length> -- Autocorrelation over window",
2404 "bitsamples", CmdBitsamples
,0, " Get raw samples as bitstring",
2405 "bitstream", Cmdbitstream
,1, "[clock rate] -- Convert waveform into a bitstream",
2406 "buffclear", CmdBuffClear
,0, " Clear sample buffer and graph window",
2407 "dec", CmdDec
,1, " Decimate samples",
2408 "detectclock", Cmddetectclockrate
,1, " Detect clock rate",
2409 "em410xsim", CmdEM410xsim
,1, "<UID> -- Simulate EM410x tag",
2410 "em410xread", CmdEM410xread
,1, "[clock rate] -- Extract ID from EM410x tag",
2411 "em410xwatch", CmdEM410xwatch
,0, " Watches for EM410x tags",
2412 "exit", CmdQuit
,1, " Exit program",
2413 "flexdemod", CmdFlexdemod
,1, " Demodulate samples for FlexPass",
2414 "fpgaoff", CmdFPGAOff
,0, " Set FPGA off", // ## FPGA Control
2415 "hexsamples", CmdHexsamples
,0, "<blocks> -- Dump big buffer as hex bytes",
2416 "hi14alist", CmdHi14alist
,0, " List ISO 14443a history", // ## New list command
2417 "hi14areader", CmdHi14areader
,0, " Act like an ISO14443 Type A reader", // ## New reader command
2418 "hi14asim", CmdHi14asim
,0, "<UID> -- Fake ISO 14443a tag", // ## Simulate 14443a tag
2419 "hi14asnoop", CmdHi14asnoop
,0, " Eavesdrop ISO 14443 Type A", // ## New snoop command
2420 "hi14bdemod", CmdHi14bdemod
,1, " Demodulate ISO14443 Type B from tag",
2421 "hi14list", CmdHi14list
,0, " List ISO 14443 history",
2422 "hi14read", CmdHi14read
,0, " Read HF tag (ISO 14443)",
2423 "hi14sim", CmdHi14sim
,0, " Fake ISO 14443 tag",
2424 "hi14snoop", CmdHi14snoop
,0, " Eavesdrop ISO 14443",
2425 "hi15demod", CmdHi15demod
,1, " Demodulate ISO15693 from tag",
2426 "hi15read", CmdHi15read
,0, " Read HF tag (ISO 15693)",
2427 "hi15reader", CmdHi15reader
,0, " Act like an ISO15693 reader", // new command greg
2428 "hi15sim", CmdHi15tag
,0, " Fake an ISO15693 tag", // new command greg
2429 "hiddemod", CmdHiddemod
,1, " Demodulate HID Prox Card II (not optimal)",
2430 "hide", CmdHide
,1, " Hide graph window",
2431 "hidfskdemod", CmdHIDdemodFSK
,0, " Realtime HID FSK demodulator",
2432 "hidsimtag", CmdHIDsimTAG
,0, "<ID> -- HID tag simulator",
2433 "higet", CmdHi14read_sim
,0, "<samples> -- Get samples HF, 'analog'",
2434 "hisamples", CmdHisamples
,0, " Get raw samples for HF tag",
2435 "hisampless", CmdHisampless
,0, "<samples> -- Get signed raw samples, HF tag",
2436 "hisamplest", CmdHi14readt
,0, " Get samples HF, for testing",
2437 "hisimlisten", CmdHisimlisten
,0, " Get HF samples as fake tag",
2438 "hpf", CmdHpf
,1, " Remove DC offset from trace",
2439 "indalademod", CmdIndalademod
,0, "['224'] -- Demodulate samples for Indala",
2440 "lcd", CmdLcd
,0, "<HEX command> <count> -- Send command/data to LCD",
2441 "lcdreset", CmdLcdReset
,0, " Hardware reset LCD",
2442 "load", CmdLoad
,1, "<filename> -- Load trace (to graph window",
2443 "loread", CmdLoread
,0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)",
2444 "losamples", CmdLosamples
,0, "[128 - 16000] -- Get raw samples for LF tag",
2445 "losim", CmdLosim
,0, " Simulate LF tag",
2446 "ltrim", CmdLtrim
,1, "<samples> -- Trim samples from left of trace",
2447 "mandemod", Cmdmanchesterdemod
,1, "[clock rate] -- Try a Manchester demodulation on a binary stream",
2448 "manmod", Cmdmanchestermod
,1, "[clock rate] -- Manchester modulate a binary stream",
2449 "norm", CmdNorm
,1, " Normalize max/min to +/-500",
2450 "plot", CmdPlot
,1, " Show graph window",
2451 "quit", CmdQuit
,1, " Quit program",
2452 "reset", CmdReset
,0, " Reset the Proxmark3",
2453 "save", CmdSave
,1, "<filename> -- Save trace (from graph window)",
2454 "scale", CmdScale
,1, "<int> -- Set cursor display scale",
2455 "setlfdivisor", CmdSetDivisor
,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)",
2456 "sri512read", CmdSri512read
,0, "<int> -- Read contents of a SRI512 tag",
2457 "sweeplf", CmdSweepLF
,0, " Sweep through LF freq range and store results in buffer",
2458 "tibits", CmdTibits
,0, " Get raw bits for TI-type LF tag",
2459 "tidemod", CmdTidemod
,0, " Demodulate raw bits for TI-type LF tag",
2460 "tiread", CmdTiread
,0, " Read a TI-type 134 kHz tag",
2461 "tune", CmdTune
,0, " Measure antenna tuning",
2462 "vchdemod", CmdVchdemod
,0, "['clone'] -- Demodulate samples for VeriChip",
2463 "zerocrossings", CmdZerocrossings
,1, " Count time between zero-crossings",
2467 //-----------------------------------------------------------------------------
2468 // Entry point into our code: called whenever the user types a command and
2469 // then presses Enter, which the full command line that they typed.
2470 //-----------------------------------------------------------------------------
2471 void CommandReceived(char *cmd
)
2475 PrintToScrollback("> %s", cmd
);
2477 if(strcmp(cmd
, "help")==0) {
2478 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2479 PrintToScrollback("\r\nAvailable commands:");
2480 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2481 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2483 memset(line
, ' ', sizeof(line
));
2484 strcpy(line
+2, CommandTable
[i
].name
);
2485 line
[strlen(line
)] = ' ';
2486 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2487 PrintToScrollback("%s", line
);
2489 PrintToScrollback("");
2490 PrintToScrollback("and also: help, cls");
2494 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2495 char *name
= CommandTable
[i
].name
;
2496 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2497 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2499 cmd
+= strlen(name
);
2500 while(*cmd
== ' ') {
2503 if (offline
&& (CommandTable
[i
].offline
==0)) {
2504 PrintToScrollback("Offline mode, cannot use this command.");
2507 (CommandTable
[i
].handler
)(cmd
);
2511 PrintToScrollback(">> bad command '%s'", cmd
);
2514 //-----------------------------------------------------------------------------
2515 // Entry point into our code: called whenever we received a packet over USB
2516 // that we weren't necessarily expecting, for example a debug print.
2517 //-----------------------------------------------------------------------------
2518 void UsbCommandReceived(UsbCommand
*c
)
2521 case CMD_DEBUG_PRINT_STRING
: {
2523 if(c
->ext1
> 70 || c
->ext1
< 0) {
2526 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
2528 PrintToScrollback("#db# %s", s
);
2532 case CMD_DEBUG_PRINT_INTEGERS
:
2533 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
2536 case CMD_MEASURED_ANTENNA_TUNING
: {
2538 int vLf125
, vLf134
, vHf
;
2539 vLf125
= c
->ext1
& 0xffff;
2540 vLf134
= c
->ext1
>> 16;
2542 zLf
= c
->ext3
& 0xffff;
2543 zHf
= c
->ext3
>> 16;
2544 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",
2545 vLf125
/zLf
, vLf125
, zLf
);
2546 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",
2547 vLf134
/((zLf
*125)/134), vLf134
, (zLf
*125)/134);
2548 PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",
2553 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);