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 /* send a command before reading */
539 static void CmdLoCommandRead(char *str
)
541 static char dummy
[3];
546 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
547 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, &c
.d
.asBytes
,&dummy
+1);
548 // in case they specified 'h'
549 strcpy(&c
.d
.asBytes
+ strlen(c
.d
.asBytes
),dummy
);
550 SendCommand(&c
, FALSE
);
553 static void CmdLosamples(char *str
)
561 if (n
>16000) n
=16000;
563 for(i
= 0; i
< n
; i
+= 12) {
565 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
567 SendCommand(&c
, FALSE
);
569 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
571 PrintToScrollback("bad resp");
575 for(j
= 0; j
< 48; j
++) {
576 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
580 RepaintGraphWindow();
583 static void CmdBitsamples(char *str
)
590 for(i
= 0; i
< n
; i
+= 12) {
592 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
594 SendCommand(&c
, FALSE
);
596 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
597 PrintToScrollback("bad resp");
601 for(j
= 0; j
< 48; j
++) {
602 for(k
= 0; k
< 8; k
++) {
603 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
604 GraphBuffer
[cnt
++] = 1;
606 GraphBuffer
[cnt
++] = 0;
612 RepaintGraphWindow();
615 static void CmdHisamples(char *str
)
621 for(i
= 0; i
< n
; i
+= 12) {
623 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
625 SendCommand(&c
, FALSE
);
627 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
628 PrintToScrollback("bad resp");
632 for(j
= 0; j
< 48; j
++) {
633 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
638 RepaintGraphWindow();
642 static int CmdHisamplest(char *str
, int nrlow
)
654 for(i
= 0; i
< n
; i
+= 12) {
656 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
658 SendCommand(&c
, FALSE
);
660 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
661 PrintToScrollback("bad resp");
665 for(j
= 0; j
< 48; j
++) {
666 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
667 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
673 t1
= (t2
& 0x80) ^ (t2
& 0x20);
674 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
680 t2
= ((t2
<< 1) & 0x80);
686 t2
= ((t2
<< 1) & 0x20);
690 // both, but tag with other algorithm
691 t1
= (t2
& 0x80) ^ (t2
& 0x08);
692 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
696 GraphBuffer
[cnt
++] = t1
;
697 GraphBuffer
[cnt
++] = t2
;
702 if(hasbeennull
>nrlow
|| nrlow
==0) {
703 PrintToScrollback("hasbeennull=%d", hasbeennull
);
712 static void CmdHexsamples(char *str
)
723 for(i
= 0; i
< n
; i
+= 12) {
725 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
727 SendCommand(&c
, FALSE
);
729 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
730 PrintToScrollback("bad resp");
734 for(j
= 0; j
< 48; j
+= 8) {
735 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
750 static void CmdHisampless(char *str
)
762 for(i
= 0; i
< n
; i
+= 12) {
764 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
766 SendCommand(&c
, FALSE
);
768 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
769 PrintToScrollback("bad resp");
773 for(j
= 0; j
< 48; j
++) {
774 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
779 RepaintGraphWindow();
782 static WORD
Iso15693Crc(BYTE
*v
, int n
)
788 for(i
= 0; i
< n
; i
++) {
789 reg
= reg
^ ((DWORD
)v
[i
]);
790 for (j
= 0; j
< 8; j
++) {
792 reg
= (reg
>> 1) ^ 0x8408;
802 static void CmdHi14bdemod(char *str
)
807 BOOL negateI
, negateQ
;
812 // As received, the samples are pairs, correlations against I and Q
813 // square waves. So estimate angle of initial carrier (or just
814 // quadrant, actually), and then do the demod.
816 // First, estimate where the tag starts modulating.
817 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
818 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
822 if(i
>= GraphTraceLen
) {
823 PrintToScrollback("too weak to sync");
826 PrintToScrollback("out of weak at %d", i
);
829 // Now, estimate the phase in the initial modulation of the tag
832 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
833 isum
+= GraphBuffer
[i
+0];
834 qsum
+= GraphBuffer
[i
+1];
836 negateI
= (isum
< 0);
837 negateQ
= (qsum
< 0);
839 // Turn the correlation pairs into soft decisions on the bit.
841 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
842 int si
= GraphBuffer
[j
];
843 int sq
= GraphBuffer
[j
+1];
844 if(negateI
) si
= -si
;
845 if(negateQ
) sq
= -sq
;
846 GraphBuffer
[i
] = si
+ sq
;
852 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
854 if(i
>= GraphTraceLen
) goto demodError
;
857 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
859 if(i
>= GraphTraceLen
) goto demodError
;
860 if((i
- iold
) > 23) goto demodError
;
862 PrintToScrollback("make it to demod loop");
866 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
868 if(i
>= GraphTraceLen
) goto demodError
;
869 if((i
- iold
) > 6) goto demodError
;
872 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
874 for(j
= 0; j
< 10; j
++) {
875 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
877 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
878 PrintToScrollback("weak bit");
882 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
889 if( (shiftReg
& 0x200) &&
892 // valid data byte, start and stop bits okay
893 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
894 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
895 if(dataLen
>= sizeof(data
)) {
898 } else if(shiftReg
== 0x000) {
907 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
908 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
909 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
910 "ok" : "****FAIL****");
912 RepaintGraphWindow();
916 PrintToScrollback("demod error");
917 RepaintGraphWindow();
920 static void CmdHi14list(char *str
)
923 GetFromBigBuf(got
, sizeof(got
));
925 PrintToScrollback("recorded activity:");
926 PrintToScrollback(" time :rssi: who bytes");
927 PrintToScrollback("---------+----+----+-----------");
938 int timestamp
= *((DWORD
*)(got
+i
));
939 if(timestamp
& 0x80000000) {
940 timestamp
&= 0x7fffffff;
945 int metric
= *((DWORD
*)(got
+i
+4));
956 BYTE
*frame
= (got
+i
+9);
958 char line
[1000] = "";
960 for(j
= 0; j
< len
; j
++) {
961 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
967 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
968 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
969 crc
= "**FAIL CRC**";
977 char metricString
[100];
979 sprintf(metricString
, "%3d", metric
);
981 strcpy(metricString
, " ");
984 PrintToScrollback(" +%7d: %s: %s %s %s",
985 (prev
< 0 ? 0 : timestamp
- prev
),
987 (isResponse
? "TAG" : " "), line
, crc
);
994 static void CmdHi14alist(char *str
)
997 GetFromBigBuf(got
, sizeof(got
));
999 PrintToScrollback("recorded activity:");
1000 PrintToScrollback(" ETU :rssi: who bytes");
1001 PrintToScrollback("---------+----+----+-----------");
1012 int timestamp
= *((DWORD
*)(got
+i
));
1013 if(timestamp
& 0x80000000) {
1014 timestamp
&= 0x7fffffff;
1021 int parityBits
= *((DWORD
*)(got
+i
+4));
1022 // 4 bytes of additional information...
1023 // maximum of 32 additional parity bit information
1026 // at each quarter bit period we can send power level (16 levels)
1027 // or each half bit period in 256 levels.
1035 if(i
+ len
>= 1900) {
1039 BYTE
*frame
= (got
+i
+9);
1041 // Break and stick with current result if buffer was not completely full
1042 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1044 char line
[1000] = "";
1046 for(j
= 0; j
< len
; j
++) {
1047 int oddparity
= 0x01;
1051 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1054 //if((parityBits >> (len - j - 1)) & 0x01) {
1055 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1056 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1059 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1067 for(j
= 0; j
< (len
- 1); j
++) {
1068 // gives problems... search for the reason..
1069 /*if(frame[j] == 0xAA) {
1070 switch(frame[j+1]) {
1072 crc = "[1] Two drops close after each other";
1075 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1078 crc = "[3] Segment Z after segment X is not possible";
1081 crc = "[4] Parity bit of a fully received byte was wrong";
1084 crc = "[?] Unknown error";
1091 if(strlen(crc
)==0) {
1092 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1093 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1094 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1103 char metricString
[100];
1105 sprintf(metricString
, "%3d", metric
);
1107 strcpy(metricString
, " ");
1110 PrintToScrollback(" +%7d: %s: %s %s %s",
1111 (prev
< 0 ? 0 : (timestamp
- prev
)),
1113 (isResponse
? "TAG" : " "), line
, crc
);
1118 CommandFinished
= 1;
1121 static void CmdHi15demod(char *str
)
1123 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1126 // 1) Unmodulated time of 56.64us
1127 // 2) 24 pulses of 423.75khz
1128 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1130 static const int FrameSOF
[] = {
1131 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1132 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1133 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1140 static const int Logic0
[] = {
1146 static const int Logic1
[] = {
1154 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1155 // 2) 24 pulses of 423.75khz
1156 // 3) Unmodulated time of 56.64us
1158 static const int FrameEOF
[] = {
1163 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1164 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1165 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1166 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1170 int max
= 0, maxPos
;
1174 if(GraphTraceLen
< 1000) return;
1176 // First, correlate for SOF
1177 for(i
= 0; i
< 100; i
++) {
1179 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1180 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1187 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1188 max
/(arraylen(FrameSOF
)/skip
));
1190 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1193 memset(outBuf
, 0, sizeof(outBuf
));
1196 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1197 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1198 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1200 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1201 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1203 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1204 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1206 // Even things out by the length of the target waveform.
1210 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1211 PrintToScrollback("EOF at %d", i
);
1213 } else if(corr1
> corr0
) {
1214 i
+= arraylen(Logic1
)/skip
;
1217 i
+= arraylen(Logic0
)/skip
;
1224 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1225 PrintToScrollback("ran off end!");
1230 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1231 PrintToScrollback(" mask=%02x", mask
);
1233 PrintToScrollback("%d octets", k
);
1235 for(i
= 0; i
< k
; i
++) {
1236 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1238 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1241 static void CmdTiread(char *str
)
1244 c
.cmd
= CMD_ACQUIRE_RAW_BITS_TI_TYPE
;
1245 SendCommand(&c
, FALSE
);
1248 static void CmdTibits(char *str
)
1252 for(i
= 0; i
< 1536; i
+= 12) {
1254 c
.cmd
= CMD_DOWNLOAD_RAW_BITS_TI_TYPE
;
1256 SendCommand(&c
, FALSE
);
1258 if(c
.cmd
!= CMD_DOWNLOADED_RAW_BITS_TI_TYPE
) {
1259 PrintToScrollback("bad resp");
1263 for(j
= 0; j
< 12; j
++) {
1265 for(k
= 31; k
>= 0; k
--) {
1266 if(c
.d
.asDwords
[j
] & (1 << k
)) {
1267 GraphBuffer
[cnt
++] = 1;
1269 GraphBuffer
[cnt
++] = -1;
1274 GraphTraceLen
= 1536*32;
1275 RepaintGraphWindow();
1278 static void CmdTidemod(char *cmdline
)
1280 /* MATLAB as follows:
1281 f_s = 2000000; % sampling frequency
1282 f_l = 123200; % low FSK tone
1283 f_h = 134200; % high FSK tone
1285 T_l = 119e-6; % low bit duration
1286 T_h = 130e-6; % high bit duration
1288 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1289 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1291 l = sign(sin(cumsum(l)));
1292 h = sign(sin(cumsum(h)));
1294 static const int LowTone
[] = {
1295 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, -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, 1,
1301 1, 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, 1,
1303 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, -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,
1309 static const int HighTone
[] = {
1310 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1311 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1312 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1313 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1314 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1315 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1316 -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1317 -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1318 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1319 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1320 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1321 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1322 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1323 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,
1326 int convLen
= max(arraylen(HighTone
), arraylen(LowTone
));
1329 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1331 int lowSum
= 0, highSum
= 0;;
1332 int lowLen
= arraylen(LowTone
);
1333 int highLen
= arraylen(HighTone
);
1335 for(j
= 0; j
< lowLen
; j
++) {
1336 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1338 for(j
= 0; j
< highLen
; j
++) {
1339 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1341 lowSum
= abs((100*lowSum
) / lowLen
);
1342 highSum
= abs((100*highSum
) / highLen
);
1343 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1346 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1348 int lowTot
= 0, highTot
= 0;
1349 // 16 and 15 are f_s divided by f_l and f_h, rounded
1350 for(j
= 0; j
< 16; j
++) {
1351 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1353 for(j
= 0; j
< 15; j
++) {
1354 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1356 GraphBuffer
[i
] = lowTot
- highTot
;
1359 GraphTraceLen
-= (convLen
+ 16);
1361 RepaintGraphWindow();
1363 // Okay, so now we have unsliced soft decisions; find bit-sync, and then
1366 int max
= 0, maxPos
= 0;
1367 for(i
= 0; i
< 6000; i
++) {
1370 for(j
= 0; j
< 8*arraylen(LowTone
); j
++) {
1371 dec
-= GraphBuffer
[i
+j
];
1373 for(; j
< 8*arraylen(LowTone
) + 8*arraylen(HighTone
); j
++) {
1374 dec
+= GraphBuffer
[i
+j
];
1381 GraphBuffer
[maxPos
] = 800;
1382 GraphBuffer
[maxPos
+1] = -800;
1384 maxPos
+= 8*arraylen(LowTone
);
1385 GraphBuffer
[maxPos
] = 800;
1386 GraphBuffer
[maxPos
+1] = -800;
1387 maxPos
+= 8*arraylen(HighTone
);
1389 GraphBuffer
[maxPos
] = 800;
1390 GraphBuffer
[maxPos
+1] = -800;
1392 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1394 PrintToScrollback("length %d/%d", arraylen(HighTone
), arraylen(LowTone
));
1396 GraphBuffer
[maxPos
] = 800;
1397 GraphBuffer
[maxPos
+1] = -800;
1399 BYTE bits
[64+16+8+1];
1400 bits
[sizeof(bits
)-1] = '\0';
1402 for(i
= 0; i
< arraylen(bits
); i
++) {
1406 for(j
= 0; j
< arraylen(LowTone
); j
++) {
1407 low
-= GraphBuffer
[maxPos
+j
];
1409 for(j
= 0; j
< arraylen(HighTone
); j
++) {
1410 high
+= GraphBuffer
[maxPos
+j
];
1414 maxPos
+= arraylen(HighTone
);
1417 maxPos
+= arraylen(LowTone
);
1419 GraphBuffer
[maxPos
] = 800;
1420 GraphBuffer
[maxPos
+1] = -800;
1422 PrintToScrollback("bits: '%s'", bits
);
1425 for(i
= 0; i
< 32; i
++) {
1426 if(bits
[i
] == '1') {
1430 for(i
= 32; i
< 64; i
++) {
1431 if(bits
[i
] == '1') {
1435 PrintToScrollback("hex: %08x %08x", h
, l
);
1438 static void CmdNorm(char *str
)
1441 int max
= INT_MIN
, min
= INT_MAX
;
1442 for(i
= 10; i
< GraphTraceLen
; i
++) {
1443 if(GraphBuffer
[i
] > max
) {
1444 max
= GraphBuffer
[i
];
1446 if(GraphBuffer
[i
] < min
) {
1447 min
= GraphBuffer
[i
];
1451 for(i
= 0; i
< GraphTraceLen
; i
++) {
1452 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1456 RepaintGraphWindow();
1459 static void CmdDec(char *str
)
1462 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1463 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1466 PrintToScrollback("decimated by 2");
1467 RepaintGraphWindow();
1470 static void CmdHpf(char *str
)
1474 for(i
= 10; i
< GraphTraceLen
; i
++) {
1475 accum
+= GraphBuffer
[i
];
1477 accum
/= (GraphTraceLen
- 10);
1478 for(i
= 0; i
< GraphTraceLen
; i
++) {
1479 GraphBuffer
[i
] -= accum
;
1482 RepaintGraphWindow();
1485 static void CmdZerocrossings(char *str
)
1488 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1494 for(i
= 0; i
< GraphTraceLen
; i
++) {
1495 if(GraphBuffer
[i
]*sign
>= 0) {
1496 // No change in sign, reproduce the previous sample count.
1498 GraphBuffer
[i
] = lastZc
;
1500 // Change in sign, reset the sample count.
1502 GraphBuffer
[i
] = lastZc
;
1510 RepaintGraphWindow();
1513 static void CmdLtrim(char *str
)
1518 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1519 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1521 GraphTraceLen
-= ds
;
1523 RepaintGraphWindow();
1526 static void CmdAutoCorr(char *str
)
1528 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1530 int window
= atoi(str
);
1533 PrintToScrollback("needs a window");
1537 if(window
>= GraphTraceLen
) {
1538 PrintToScrollback("window must be smaller than trace (%d samples)",
1543 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1546 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1549 for(j
= 0; j
< window
; j
++) {
1550 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1552 CorrelBuffer
[i
] = sum
;
1554 GraphTraceLen
= GraphTraceLen
- window
;
1555 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1557 RepaintGraphWindow();
1560 static void CmdVchdemod(char *str
)
1562 // Is this the entire sync pattern, or does this also include some
1563 // data bits that happen to be the same everywhere? That would be
1565 static const int SyncPattern
[] = {
1566 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1567 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1568 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1569 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1570 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1571 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1573 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1574 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1575 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1578 // So first, we correlate for the sync pattern, and mark that.
1579 int bestCorrel
= 0, bestPos
= 0;
1581 // It does us no good to find the sync pattern, with fewer than
1582 // 2048 samples after it...
1583 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1586 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1587 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1589 if(sum
> bestCorrel
) {
1594 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
1599 int worst
= INT_MAX
;
1602 for(i
= 0; i
< 2048; i
+= 8) {
1605 for(j
= 0; j
< 8; j
++) {
1606 sum
+= GraphBuffer
[bestPos
+i
+j
];
1613 if(abs(sum
) < worst
) {
1618 PrintToScrollback("bits:");
1619 PrintToScrollback("%s", bits
);
1620 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
1622 if(strcmp(str
, "clone")==0) {
1625 for(s
= bits
; *s
; s
++) {
1627 for(j
= 0; j
< 16; j
++) {
1628 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
1631 RepaintGraphWindow();
1635 static void CmdIndalademod(char *str
)
1637 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
1642 // worst case with GraphTraceLen=64000 is < 4096
1643 // under normal conditions it's < 2048
1646 int worst
= 0, worstPos
= 0;
1647 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
1648 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
1650 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
1652 for(j
= 0; j
< count
- 8; j
+= 16) {
1653 rawbits
[rawbit
++] = 0;
1655 if ((abs(count
- j
)) > worst
) {
1656 worst
= abs(count
- j
);
1662 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
1664 for(j
= 0; j
< count
- 8; j
+= 16) {
1665 rawbits
[rawbit
++] = 1;
1667 if ((abs(count
- j
)) > worst
) {
1668 worst
= abs(count
- j
);
1676 PrintToScrollback("Recovered %d raw bits", rawbit
);
1677 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
1679 // Finding the start of a UID
1680 int uidlen
, long_wait
;
1681 if(strcmp(str
, "224") == 0) {
1690 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
1691 first
= rawbits
[start
];
1692 for(i
= start
; i
< start
+ long_wait
; i
++) {
1693 if(rawbits
[i
] != first
) {
1697 if(i
== (start
+ long_wait
)) {
1701 if(start
== rawbit
- uidlen
+ 1) {
1702 PrintToScrollback("nothing to wait for");
1706 // Inverting signal if needed
1708 for(i
= start
; i
< rawbit
; i
++) {
1709 rawbits
[i
] = !rawbits
[i
];
1716 showbits
[uidlen
]='\0';
1720 if(uidlen
> rawbit
) {
1721 PrintToScrollback("Warning: not enough raw bits to get a full UID");
1722 for(bit
= 0; bit
< rawbit
; bit
++) {
1723 bits
[bit
] = rawbits
[i
++];
1724 // As we cannot know the parity, let's use "." and "/"
1725 showbits
[bit
] = '.' + bits
[bit
];
1727 showbits
[bit
+1]='\0';
1728 PrintToScrollback("Partial UID=%s", showbits
);
1731 for(bit
= 0; bit
< uidlen
; bit
++) {
1732 bits
[bit
] = rawbits
[i
++];
1733 showbits
[bit
] = '0' + bits
[bit
];
1737 PrintToScrollback("UID=%s", showbits
);
1739 // Checking UID against next occurences
1740 for(; i
+ uidlen
<= rawbit
;) {
1742 for(bit
= 0; bit
< uidlen
; bit
++) {
1743 if(bits
[bit
] != rawbits
[i
++]) {
1753 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
1755 // Remodulating for tag cloning
1756 GraphTraceLen
= 32*uidlen
;
1759 for(bit
= 0; bit
< uidlen
; bit
++) {
1760 if(bits
[bit
] == 0) {
1766 for(j
= 0; j
< 32; j
++) {
1767 GraphBuffer
[i
++] = phase
;
1772 RepaintGraphWindow();
1775 static void CmdFlexdemod(char *str
)
1778 for(i
= 0; i
< GraphTraceLen
; i
++) {
1779 if(GraphBuffer
[i
] < 0) {
1780 GraphBuffer
[i
] = -1;
1786 #define LONG_WAIT 100
1788 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
1789 int first
= GraphBuffer
[start
];
1790 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
1791 if(GraphBuffer
[i
] != first
) {
1795 if(i
== (start
+ LONG_WAIT
)) {
1799 if(start
== GraphTraceLen
- LONG_WAIT
) {
1800 PrintToScrollback("nothing to wait for");
1804 GraphBuffer
[start
] = 2;
1805 GraphBuffer
[start
+1] = -2;
1811 for(bit
= 0; bit
< 64; bit
++) {
1814 for(j
= 0; j
< 16; j
++) {
1815 sum
+= GraphBuffer
[i
++];
1822 PrintToScrollback("bit %d sum %d", bit
, sum
);
1825 for(bit
= 0; bit
< 64; bit
++) {
1828 for(j
= 0; j
< 16; j
++) {
1829 sum
+= GraphBuffer
[i
++];
1831 if(sum
> 0 && bits
[bit
] != 1) {
1832 PrintToScrollback("oops1 at %d", bit
);
1834 if(sum
< 0 && bits
[bit
] != 0) {
1835 PrintToScrollback("oops2 at %d", bit
);
1839 GraphTraceLen
= 32*64;
1842 for(bit
= 0; bit
< 64; bit
++) {
1843 if(bits
[bit
] == 0) {
1849 for(j
= 0; j
< 32; j
++) {
1850 GraphBuffer
[i
++] = phase
;
1855 RepaintGraphWindow();
1859 * Generic command to demodulate ASK.
1861 * Argument is convention: positive or negative (High mod means zero
1862 * or high mod means one)
1864 * Updates the Graph trace with 0/1 values
1870 static void Cmdaskdemod(char *str
) {
1875 // TODO: complain if we do not give 2 arguments here !
1876 sscanf(str
, "%i", &c
);
1878 /* Detect high and lows and clock */
1879 for (i
= 0; i
< GraphTraceLen
; i
++)
1881 if (GraphBuffer
[i
] > high
)
1882 high
= GraphBuffer
[i
];
1883 else if (GraphBuffer
[i
] < low
)
1884 low
= GraphBuffer
[i
];
1887 if (GraphBuffer
[0] > 0) {
1888 GraphBuffer
[0] = 1-c
;
1892 for(i
=1;i
<GraphTraceLen
;i
++) {
1893 /* Transitions are detected at each peak
1894 * Transitions are either:
1895 * - we're low: transition if we hit a high
1896 * - we're high: transition if we hit a low
1897 * (we need to do it this way because some tags keep high or
1898 * low for long periods, others just reach the peak and go
1901 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
1903 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
1907 GraphBuffer
[i
] = GraphBuffer
[i
-1];
1910 RepaintGraphWindow();
1913 /* Print our clock rate */
1914 static void Cmddetectclockrate(char *str
)
1916 int clock
= detectclock(0);
1917 PrintToScrollback("Auto-detected clock rate: %d", clock
);
1923 int detectclock(int peak
)
1929 /* Detect peak if we don't have one */
1931 for (i
= 0; i
< GraphTraceLen
; i
++)
1932 if (GraphBuffer
[i
] > peak
)
1933 peak
= GraphBuffer
[i
];
1935 for (i
= 1; i
< GraphTraceLen
; i
++)
1937 /* If this is the beginning of a peak */
1938 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
1940 /* Find lowest difference between peaks */
1941 if (lastpeak
&& i
- lastpeak
< clock
)
1943 clock
= i
- lastpeak
;
1952 /* Get or auto-detect clock rate */
1953 int GetClock(char *str
, int peak
)
1957 sscanf(str
, "%i", &clock
);
1958 if (!strcmp(str
, ""))
1961 /* Auto-detect clock */
1964 clock
= detectclock(peak
);
1966 /* Only print this message if we're not looping something */
1968 PrintToScrollback("Auto-detected clock rate: %d", clock
);
1975 * Convert to a bitstream
1977 static void Cmdbitstream(char *str
) {
1984 int hithigh
, hitlow
, first
;
1986 /* Detect high and lows and clock */
1987 for (i
= 0; i
< GraphTraceLen
; i
++)
1989 if (GraphBuffer
[i
] > high
)
1990 high
= GraphBuffer
[i
];
1991 else if (GraphBuffer
[i
] < low
)
1992 low
= GraphBuffer
[i
];
1996 clock
= GetClock(str
, high
);
1998 gtl
= CmdClearGraph(0);
2001 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2007 /* Find out if we hit both high and low peaks */
2008 for (j
= 0; j
< clock
; j
++)
2010 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2012 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2015 /* it doesn't count if it's the first part of our read
2016 because it's really just trailing from the last sequence */
2017 if (first
&& (hithigh
|| hitlow
))
2018 hithigh
= hitlow
= 0;
2022 if (hithigh
&& hitlow
)
2026 /* If we didn't hit both high and low peaks, we had a bit transition */
2027 if (!hithigh
|| !hitlow
)
2030 CmdAppendGraph(0, clock
, bit
);
2031 // for (j = 0; j < (int)(clock/2); j++)
2032 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2033 // for (j = (int)(clock/2); j < clock; j++)
2034 // GraphBuffer[(i * clock) + j] = bit;
2037 RepaintGraphWindow();
2040 /* Modulate our data into manchester */
2041 static void Cmdmanchestermod(char *str
)
2045 int bit
, lastbit
, wave
;
2048 clock
= GetClock(str
, 0);
2052 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2054 bit
= GraphBuffer
[i
* clock
] ^ 1;
2056 for (j
= 0; j
< (int)(clock
/2); j
++)
2057 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2058 for (j
= (int)(clock
/2); j
< clock
; j
++)
2059 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2061 /* Keep track of how we start our wave and if we changed or not this time */
2062 wave
^= bit
^ lastbit
;
2066 RepaintGraphWindow();
2070 * Manchester demodulate a bitstream. The bitstream needs to be already in
2071 * the GraphBuffer as 0 and 1 values
2073 * Give the clock rate as argument in order to help the sync - the algorithm
2074 * resyncs at each pulse anyway.
2076 * Not optimized by any means, this is the 1st time I'm writing this type of
2077 * routine, feel free to improve...
2079 * 1st argument: clock rate (as number of samples per clock rate)
2080 * Typical values can be 64, 32, 128...
2082 static void Cmdmanchesterdemod(char *str
) {
2083 int i
, j
, invert
= 0;
2089 int hithigh
, hitlow
, first
;
2095 /* check if we're inverting output */
2098 PrintToScrollback("Inverting output");
2102 while(*str
== ' '); // in case a 2nd argument was given
2105 /* Holds the decoded bitstream: each clock period contains 2 bits */
2106 /* later simplified to 1 bit after manchester decoding. */
2107 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2108 /* int BitStream[GraphTraceLen*2/clock+10]; */
2110 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2112 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2114 /* Detect high and lows */
2115 for (i
= 0; i
< GraphTraceLen
; i
++)
2117 if (GraphBuffer
[i
] > high
)
2118 high
= GraphBuffer
[i
];
2119 else if (GraphBuffer
[i
] < low
)
2120 low
= GraphBuffer
[i
];
2124 clock
= GetClock(str
, high
);
2126 int tolerance
= clock
/4;
2128 /* Detect first transition */
2129 /* Lo-Hi (arbitrary) */
2130 for (i
= 0; i
< GraphTraceLen
; i
++)
2132 if (GraphBuffer
[i
] == low
)
2139 /* If we're not working with 1/0s, demod based off clock */
2142 bit
= 0; /* We assume the 1st bit is zero, it may not be
2143 * the case: this routine (I think) has an init problem.
2146 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2152 /* Find out if we hit both high and low peaks */
2153 for (j
= 0; j
< clock
; j
++)
2155 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2157 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2160 /* it doesn't count if it's the first part of our read
2161 because it's really just trailing from the last sequence */
2162 if (first
&& (hithigh
|| hitlow
))
2163 hithigh
= hitlow
= 0;
2167 if (hithigh
&& hitlow
)
2171 /* If we didn't hit both high and low peaks, we had a bit transition */
2172 if (!hithigh
|| !hitlow
)
2175 BitStream
[bit2idx
++] = bit
^ invert
;
2179 /* standard 1/0 bitstream */
2183 /* Then detect duration between 2 successive transitions */
2184 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2186 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2191 // Error check: if bitidx becomes too large, we do not
2192 // have a Manchester encoded bitstream or the clock is really
2194 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2195 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2198 // Then switch depending on lc length:
2199 // Tolerance is 1/4 of clock rate (arbitrary)
2200 if (abs(lc
-clock
/2) < tolerance
) {
2201 // Short pulse : either "1" or "0"
2202 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2203 } else if (abs(lc
-clock
) < tolerance
) {
2204 // Long pulse: either "11" or "00"
2205 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2206 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2210 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2211 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2215 PrintToScrollback("Error: too many detection errors, aborting.");
2222 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2223 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2224 // to stop output at the final bitidx2 value, not bitidx
2225 for (i
= 0; i
< bitidx
; i
+= 2) {
2226 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2227 BitStream
[bit2idx
++] = 1 ^ invert
;
2228 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2229 BitStream
[bit2idx
++] = 0 ^ invert
;
2231 // We cannot end up in this state, this means we are unsynchronized,
2235 PrintToScrollback("Unsynchronized, resync...");
2236 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2240 PrintToScrollback("Error: too many decode errors, aborting.");
2247 PrintToScrollback("Manchester decoded bitstream");
2248 // Now output the bitstream to the scrollback by line of 16 bits
2249 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2250 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2275 static void CmdHiddemod(char *str
)
2277 if(GraphTraceLen
< 4800) {
2278 PrintToScrollback("too short; need at least 4800 samples");
2282 GraphTraceLen
= 4800;
2284 for(i
= 0; i
< GraphTraceLen
; i
++) {
2285 if(GraphBuffer
[i
] < 0) {
2291 RepaintGraphWindow();
2294 static void CmdPlot(char *str
)
2299 static void CmdHide(char *str
)
2304 static void CmdScale(char *str
)
2306 CursorScaleFactor
= atoi(str
);
2307 if(CursorScaleFactor
== 0) {
2308 PrintToScrollback("bad, can't have zero scale");
2309 CursorScaleFactor
= 1;
2311 RepaintGraphWindow();
2314 static void CmdSave(char *str
)
2316 FILE *f
= fopen(str
, "w");
2318 PrintToScrollback("couldn't open '%s'", str
);
2322 for(i
= 0; i
< GraphTraceLen
; i
++) {
2323 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2326 PrintToScrollback("saved to '%s'", str
);
2329 static void CmdLoad(char *str
)
2331 FILE *f
= fopen(str
, "r");
2333 PrintToScrollback("couldn't open '%s'", str
);
2339 while(fgets(line
, sizeof(line
), f
)) {
2340 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2344 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2345 RepaintGraphWindow();
2348 static void CmdHIDsimTAG(char *str
)
2350 unsigned int hi
=0, lo
=0;
2354 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2355 hi
=(hi
<<4)|(lo
>>28);
2359 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2361 c
.cmd
= CMD_HID_SIM_TAG
;
2364 SendCommand(&c
, FALSE
);
2367 static void CmdLcdReset(char *str
)
2370 c
.cmd
= CMD_LCD_RESET
;
2372 SendCommand(&c
, FALSE
);
2375 static void CmdLcd(char *str
)
2380 sscanf(str
, "%x %d", &i
, &j
);
2383 SendCommand(&c
, FALSE
);
2389 static void CmdTest(char *str
)
2394 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2397 static void CmdSetDivisor(char *str
)
2400 c
.cmd
= CMD_SET_LF_DIVISOR
;
2402 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2403 PrintToScrollback("divisor must be between 19 and 255");
2405 SendCommand(&c
, FALSE
);
2406 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2410 static void CmdSweepLF(char *str
)
2413 c
.cmd
= CMD_SWEEP_LF
;
2414 SendCommand(&c
, FALSE
);
2418 typedef void HandlerFunction(char *cmdline
);
2420 /* in alphabetic order */
2423 HandlerFunction
*handler
;
2424 int offline
; // 1 if the command can be used when in offline mode
2426 } CommandTable
[] = {
2427 "askdemod", Cmdaskdemod
,1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags",
2428 "autocorr", CmdAutoCorr
,1, "<window length> -- Autocorrelation over window",
2429 "bitsamples", CmdBitsamples
,0, " Get raw samples as bitstring",
2430 "bitstream", Cmdbitstream
,1, "[clock rate] -- Convert waveform into a bitstream",
2431 "buffclear", CmdBuffClear
,0, " Clear sample buffer and graph window",
2432 "dec", CmdDec
,1, " Decimate samples",
2433 "detectclock", Cmddetectclockrate
,1, " Detect clock rate",
2434 "em410xsim", CmdEM410xsim
,1, "<UID> -- Simulate EM410x tag",
2435 "em410xread", CmdEM410xread
,1, "[clock rate] -- Extract ID from EM410x tag",
2436 "em410xwatch", CmdEM410xwatch
,0, " Watches for EM410x tags",
2437 "exit", CmdQuit
,1, " Exit program",
2438 "flexdemod", CmdFlexdemod
,1, " Demodulate samples for FlexPass",
2439 "fpgaoff", CmdFPGAOff
,0, " Set FPGA off", // ## FPGA Control
2440 "hexsamples", CmdHexsamples
,0, "<blocks> -- Dump big buffer as hex bytes",
2441 "hi14alist", CmdHi14alist
,0, " List ISO 14443a history", // ## New list command
2442 "hi14areader", CmdHi14areader
,0, " Act like an ISO14443 Type A reader", // ## New reader command
2443 "hi14asim", CmdHi14asim
,0, "<UID> -- Fake ISO 14443a tag", // ## Simulate 14443a tag
2444 "hi14asnoop", CmdHi14asnoop
,0, " Eavesdrop ISO 14443 Type A", // ## New snoop command
2445 "hi14bdemod", CmdHi14bdemod
,1, " Demodulate ISO14443 Type B from tag",
2446 "hi14list", CmdHi14list
,0, " List ISO 14443 history",
2447 "hi14read", CmdHi14read
,0, " Read HF tag (ISO 14443)",
2448 "hi14sim", CmdHi14sim
,0, " Fake ISO 14443 tag",
2449 "hi14snoop", CmdHi14snoop
,0, " Eavesdrop ISO 14443",
2450 "hi15demod", CmdHi15demod
,1, " Demodulate ISO15693 from tag",
2451 "hi15read", CmdHi15read
,0, " Read HF tag (ISO 15693)",
2452 "hi15reader", CmdHi15reader
,0, " Act like an ISO15693 reader", // new command greg
2453 "hi15sim", CmdHi15tag
,0, " Fake an ISO15693 tag", // new command greg
2454 "hiddemod", CmdHiddemod
,1, " Demodulate HID Prox Card II (not optimal)",
2455 "hide", CmdHide
,1, " Hide graph window",
2456 "hidfskdemod", CmdHIDdemodFSK
,0, " Realtime HID FSK demodulator",
2457 "hidsimtag", CmdHIDsimTAG
,0, "<ID> -- HID tag simulator",
2458 "higet", CmdHi14read_sim
,0, "<samples> -- Get samples HF, 'analog'",
2459 "hisamples", CmdHisamples
,0, " Get raw samples for HF tag",
2460 "hisampless", CmdHisampless
,0, "<samples> -- Get signed raw samples, HF tag",
2461 "hisamplest", CmdHi14readt
,0, " Get samples HF, for testing",
2462 "hisimlisten", CmdHisimlisten
,0, " Get HF samples as fake tag",
2463 "hpf", CmdHpf
,1, " Remove DC offset from trace",
2464 "indalademod", CmdIndalademod
,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)",
2465 "lcd", CmdLcd
,0, "<HEX command> <count> -- Send command/data to LCD",
2466 "lcdreset", CmdLcdReset
,0, " Hardware reset LCD",
2467 "load", CmdLoad
,1, "<filename> -- Load trace (to graph window",
2468 "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)",
2469 "loread", CmdLoread
,0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)",
2470 "losamples", CmdLosamples
,0, "[128 - 16000] -- Get raw samples for LF tag",
2471 "losim", CmdLosim
,0, " Simulate LF tag",
2472 "ltrim", CmdLtrim
,1, "<samples> -- Trim samples from left of trace",
2473 "mandemod", Cmdmanchesterdemod
,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)",
2474 "manmod", Cmdmanchestermod
,1, "[clock rate] -- Manchester modulate a binary stream",
2475 "norm", CmdNorm
,1, " Normalize max/min to +/-500",
2476 "plot", CmdPlot
,1, " Show graph window",
2477 "quit", CmdQuit
,1, " Quit program",
2478 "reset", CmdReset
,0, " Reset the Proxmark3",
2479 "save", CmdSave
,1, "<filename> -- Save trace (from graph window)",
2480 "scale", CmdScale
,1, "<int> -- Set cursor display scale",
2481 "setlfdivisor", CmdSetDivisor
,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)",
2482 "sri512read", CmdSri512read
,0, "<int> -- Read contents of a SRI512 tag",
2483 "sweeplf", CmdSweepLF
,0, " Sweep through LF freq range and store results in buffer",
2484 "tibits", CmdTibits
,0, " Get raw bits for TI-type LF tag",
2485 "tidemod", CmdTidemod
,0, " Demodulate raw bits for TI-type LF tag",
2486 "tiread", CmdTiread
,0, " Read a TI-type 134 kHz tag",
2487 "tune", CmdTune
,0, " Measure antenna tuning",
2488 "vchdemod", CmdVchdemod
,0, "['clone'] -- Demodulate samples for VeriChip",
2489 "zerocrossings", CmdZerocrossings
,1, " Count time between zero-crossings",
2493 //-----------------------------------------------------------------------------
2494 // Entry point into our code: called whenever the user types a command and
2495 // then presses Enter, which the full command line that they typed.
2496 //-----------------------------------------------------------------------------
2497 void CommandReceived(char *cmd
)
2501 PrintToScrollback("> %s", cmd
);
2503 if(strcmp(cmd
, "help")==0) {
2504 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2505 PrintToScrollback("\r\nAvailable commands:");
2506 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2507 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2509 memset(line
, ' ', sizeof(line
));
2510 strcpy(line
+2, CommandTable
[i
].name
);
2511 line
[strlen(line
)] = ' ';
2512 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2513 PrintToScrollback("%s", line
);
2515 PrintToScrollback("");
2516 PrintToScrollback("and also: help, cls");
2520 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2521 char *name
= CommandTable
[i
].name
;
2522 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2523 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2525 cmd
+= strlen(name
);
2526 while(*cmd
== ' ') {
2529 if (offline
&& (CommandTable
[i
].offline
==0)) {
2530 PrintToScrollback("Offline mode, cannot use this command.");
2533 (CommandTable
[i
].handler
)(cmd
);
2537 PrintToScrollback(">> bad command '%s'", cmd
);
2540 //-----------------------------------------------------------------------------
2541 // Entry point into our code: called whenever we received a packet over USB
2542 // that we weren't necessarily expecting, for example a debug print.
2543 //-----------------------------------------------------------------------------
2544 void UsbCommandReceived(UsbCommand
*c
)
2547 case CMD_DEBUG_PRINT_STRING
: {
2549 if(c
->ext1
> 70 || c
->ext1
< 0) {
2552 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
2554 PrintToScrollback("#db# %s", s
);
2558 case CMD_DEBUG_PRINT_INTEGERS
:
2559 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
2562 case CMD_MEASURED_ANTENNA_TUNING
: {
2564 int vLf125
, vLf134
, vHf
;
2565 vLf125
= c
->ext1
& 0xffff;
2566 vLf134
= c
->ext1
>> 16;
2568 zLf
= c
->ext3
& 0xffff;
2569 zHf
= c
->ext3
>> 16;
2570 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",
2571 vLf125
/zLf
, vLf125
, zLf
);
2572 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",
2573 vLf134
/((zLf
*125)/134), vLf134
, (zLf
*125)/134);
2574 PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",
2579 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);