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"
15 #include "../common/crc16.c"
17 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
18 #define BIT(x) GraphBuffer[x * clock]
19 #define BITS (GraphTraceLen / clock)
22 static int CmdHisamplest(char *str
, int nrlow
);
24 static void GetFromBigBuf(BYTE
*dest
, int bytes
)
29 PrintToScrollback("bad len in GetFromBigBuf");
34 for(i
= 0; i
< n
; i
+= 12) {
36 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
38 SendCommand(&c
, FALSE
);
40 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
41 PrintToScrollback("bad resp");
45 memcpy(dest
+(i
*4), c
.d
.asBytes
, 48);
49 static void CmdReset(char *str
)
52 c
.cmd
= CMD_HARDWARE_RESET
;
53 SendCommand(&c
, FALSE
);
56 static void CmdBuffClear(char *str
)
59 c
.cmd
= CMD_BUFF_CLEAR
;
60 SendCommand(&c
, FALSE
);
64 static void CmdQuit(char *str
)
69 static void CmdHIDdemodFSK(char *str
)
72 c
.cmd
= CMD_HID_DEMOD_FSK
;
73 SendCommand(&c
, FALSE
);
76 static void CmdTune(char *str
)
79 c
.cmd
= CMD_MEASURE_ANTENNA_TUNING
;
80 SendCommand(&c
, FALSE
);
83 static void CmdHi15read(char *str
)
86 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693
;
87 SendCommand(&c
, FALSE
);
90 static void CmdHi14read(char *str
)
93 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
95 SendCommand(&c
, FALSE
);
99 /* New command to read the contents of a SRI512 tag
100 * SRI512 tags are ISO14443-B modulated memory tags,
101 * this command just dumps the contents of the memory/
103 static void CmdSri512read(char *str
)
106 c
.cmd
= CMD_READ_SRI512_TAG
;
108 SendCommand(&c
, FALSE
);
112 static void CmdHi14areader(char *str
)
115 c
.cmd
= CMD_READER_ISO_14443a
;
117 SendCommand(&c
, FALSE
);
121 static void CmdHi15reader(char *str
)
124 c
.cmd
= CMD_READER_ISO_15693
;
126 SendCommand(&c
, FALSE
);
130 static void CmdHi15tag(char *str
)
133 c
.cmd
= CMD_SIMTAG_ISO_15693
;
135 SendCommand(&c
, FALSE
);
138 static void CmdHi14read_sim(char *str
)
141 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM
;
143 SendCommand(&c
, FALSE
);
146 static void CmdHi14readt(char *str
)
149 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
151 SendCommand(&c
, FALSE
);
153 //CmdHisamplest(str);
154 while(CmdHisamplest(str
,atoi(str
))==0) {
155 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
157 SendCommand(&c
, FALSE
);
159 RepaintGraphWindow();
162 static void CmdHisimlisten(char *str
)
165 c
.cmd
= CMD_SIMULATE_TAG_HF_LISTEN
;
166 SendCommand(&c
, FALSE
);
169 static void CmdHi14sim(char *str
)
172 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443
;
173 SendCommand(&c
, FALSE
);
176 static void CmdHi14asim(char *str
) // ## simulate iso14443a tag
177 { // ## greg - added ability to specify tag UID
179 unsigned int hi
=0, lo
=0;
183 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
188 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443a
;
189 // c.ext should be set to *str or convert *str to the correct format for a uid
192 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi
, lo
);
193 SendCommand(&c
, FALSE
);
196 static void CmdHi14snoop(char *str
)
199 c
.cmd
= CMD_SNOOP_ISO_14443
;
200 SendCommand(&c
, FALSE
);
203 static void CmdHi14asnoop(char *str
)
206 c
.cmd
= CMD_SNOOP_ISO_14443a
;
207 SendCommand(&c
, FALSE
);
210 static void CmdFPGAOff(char *str
) // ## FPGA Control
213 c
.cmd
= CMD_FPGA_MAJOR_MODE_OFF
;
214 SendCommand(&c
, FALSE
);
217 /* clear out our graph window */
218 int CmdClearGraph(int redraw
)
220 int gtl
= GraphTraceLen
;
224 RepaintGraphWindow();
229 /* write a bit to the graph */
230 static void CmdAppendGraph(int redraw
, int clock
, int bit
)
234 for (i
= 0; i
< (int)(clock
/2); i
++)
235 GraphBuffer
[GraphTraceLen
++] = bit
^ 1;
237 for (i
= (int)(clock
/2); i
< clock
; i
++)
238 GraphBuffer
[GraphTraceLen
++] = bit
;
241 RepaintGraphWindow();
244 /* Function is equivalent of loread + losamples + em410xread
245 * looped until an EM410x tag is detected */
246 static void CmdEM410xwatch(char *str
)
260 /* Read the transmitted data of an EM4x50 tag
263 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
264 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
265 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
266 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
267 * CCCCCCCC <- column parity bits
269 * LW <- Listen Window
271 * This pattern repeats for every block of data being transmitted.
272 * Transmission starts with two Listen Windows (LW - a modulated
273 * pattern of 320 cycles each (32/32/128/64/64)).
275 * Note that this data may or may not be the UID. It is whatever data
276 * is stored in the blocks defined in the control word First and Last
277 * Word Read values. UID is stored in block 32.
279 static void CmdEM4x50read(char *str
)
281 int i
, j
, startblock
, clock
, skip
, block
, start
, end
, low
, high
;
282 BOOL complete
= FALSE
;
283 int tmpbuff
[MAX_GRAPH_TRACE_LEN
/ 64];
289 /* first get high and low values */
290 for (i
= 0; i
< GraphTraceLen
; i
++)
292 if (GraphBuffer
[i
] > high
)
293 high
= GraphBuffer
[i
];
294 else if (GraphBuffer
[i
] < low
)
295 low
= GraphBuffer
[i
];
298 /* populate a buffer with pulse lengths */
301 while(i
< GraphTraceLen
)
303 // measure from low to low
304 while((GraphBuffer
[i
] > low
) && (i
<GraphTraceLen
))
307 while((GraphBuffer
[i
] < high
) && (i
<GraphTraceLen
))
309 while((GraphBuffer
[i
] > low
) && (i
<GraphTraceLen
))
311 if (j
>(MAX_GRAPH_TRACE_LEN
/64)) {
314 tmpbuff
[j
++]= i
- start
;
317 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
320 for (i
= 0; i
< j
- 4 ; ++i
)
323 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
324 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
325 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
326 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
334 /* skip over the remainder of the LW */
335 skip
+= tmpbuff
[i
+1]+tmpbuff
[i
+2];
336 while(skip
< MAX_GRAPH_TRACE_LEN
&& GraphBuffer
[skip
] > low
)
340 /* now do it again to find the end */
342 for (i
+= 3; i
< j
- 4 ; ++i
)
345 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
346 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
347 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
348 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
356 PrintToScrollback("Found data at sample: %i",skip
);
359 PrintToScrollback("No data found!");
360 PrintToScrollback("Try again with more samples.");
366 PrintToScrollback("*** Warning!");
367 PrintToScrollback("Partial data - no end found!");
368 PrintToScrollback("Try again with more samples.");
371 /* get rid of leading crap */
372 sprintf(tmp
,"%i",skip
);
375 /* now work through remaining buffer printing out data blocks */
380 PrintToScrollback("Block %i:", block
);
381 // mandemod routine needs to be split so we can call it for data
382 // just print for now for debugging
383 Cmdmanchesterdemod("i 64");
385 /* look for LW before start of next block */
386 for ( ; i
< j
- 4 ; ++i
)
389 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
390 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
393 while(GraphBuffer
[skip
] > low
)
396 sprintf(tmp
,"%i",skip
);
404 /* Read the ID of an EM410x tag.
406 * 1111 1111 1 <-- standard non-repeatable header
407 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
409 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
410 * 0 <-- stop bit, end of tag
412 static void CmdEM410xread(char *str
)
414 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
418 int BitStream
[MAX_GRAPH_TRACE_LEN
];
421 /* Detect high and lows and clock */
422 for (i
= 0; i
< GraphTraceLen
; i
++)
424 if (GraphBuffer
[i
] > high
)
425 high
= GraphBuffer
[i
];
426 else if (GraphBuffer
[i
] < low
)
427 low
= GraphBuffer
[i
];
431 clock
= GetClock(str
, high
);
433 /* parity for our 4 columns */
434 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
437 /* manchester demodulate */
439 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
445 /* Find out if we hit both high and low peaks */
446 for (j
= 0; j
< clock
; j
++)
448 if (GraphBuffer
[(i
* clock
) + j
] == high
)
450 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
453 /* it doesn't count if it's the first part of our read
454 because it's really just trailing from the last sequence */
455 if (first
&& (hithigh
|| hitlow
))
456 hithigh
= hitlow
= 0;
460 if (hithigh
&& hitlow
)
464 /* If we didn't hit both high and low peaks, we had a bit transition */
465 if (!hithigh
|| !hitlow
)
468 BitStream
[bit2idx
++] = bit
;
472 /* We go till 5 before the graph ends because we'll get that far below */
473 for (i
= 1; i
< bit2idx
- 5; i
++)
475 /* Step 2: We have our header but need our tag ID */
476 if (header
== 9 && rows
< 10)
478 /* Confirm parity is correct */
479 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
481 /* Read another byte! */
482 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
485 /* Keep parity info */
486 parity
[0] ^= BitStream
[i
];
487 parity
[1] ^= BitStream
[i
+1];
488 parity
[2] ^= BitStream
[i
+2];
489 parity
[3] ^= BitStream
[i
+3];
491 /* Move 4 bits ahead */
495 /* Damn, something wrong! reset */
498 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
500 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
501 i
-= 9 + (5 * rows
) - 5;
507 /* Step 3: Got our 40 bits! confirm column parity */
510 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
511 if (BitStream
[i
] == parity
[0] && BitStream
[i
+1] == parity
[1] &&
512 BitStream
[i
+2] == parity
[2] && BitStream
[i
+3] == parity
[3] &&
516 PrintToScrollback("EM410x Tag ID: %s", id
);
523 /* Crap! Incorrect parity or no stop bit, start all over */
528 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
533 /* Step 1: get our header */
536 /* Need 9 consecutive 1's */
537 if (BitStream
[i
] == 1)
540 /* We don't have a header, not enough consecutive 1 bits */
546 /* if we've already retested after flipping bits, return */
550 /* if this didn't work, try flipping bits */
551 for (i
= 0; i
< bit2idx
; i
++)
557 /* emulate an EM410X tag
559 * 1111 1111 1 <-- standard non-repeatable header
560 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
562 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
563 * 0 <-- stop bit, end of tag
565 static void CmdEM410xsim(char *str
)
567 int i
, n
, j
, h
, binary
[4], parity
[4];
570 /* clock is 64 in EM410x tags */
573 /* clear our graph */
576 /* write it out a few times */
577 for (h
= 0; h
< 4; h
++)
579 /* write 9 start bits */
580 for (i
= 0; i
< 9; i
++)
581 CmdAppendGraph(0, clock
, 1);
583 /* for each hex char */
584 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
585 for (i
= 0; i
< 10; i
++)
587 /* read each hex char */
588 sscanf(&str
[i
], "%1x", &n
);
589 for (j
= 3; j
>= 0; j
--, n
/= 2)
592 /* append each bit */
593 CmdAppendGraph(0, clock
, binary
[0]);
594 CmdAppendGraph(0, clock
, binary
[1]);
595 CmdAppendGraph(0, clock
, binary
[2]);
596 CmdAppendGraph(0, clock
, binary
[3]);
598 /* append parity bit */
599 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
601 /* keep track of column parity */
602 parity
[0] ^= binary
[0];
603 parity
[1] ^= binary
[1];
604 parity
[2] ^= binary
[2];
605 parity
[3] ^= binary
[3];
609 CmdAppendGraph(0, clock
, parity
[0]);
610 CmdAppendGraph(0, clock
, parity
[1]);
611 CmdAppendGraph(0, clock
, parity
[2]);
612 CmdAppendGraph(0, clock
, parity
[3]);
615 CmdAppendGraph(0, clock
, 0);
618 /* modulate that biatch */
622 RepaintGraphWindow();
627 static void ChkBitstream(char *str
)
631 /* convert to bitstream if necessary */
632 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
634 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
642 static void CmdLosim(char *str
)
646 /* convert to bitstream if necessary */
649 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
652 for(j
= 0; j
< 48; j
++) {
653 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
655 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
657 SendCommand(&c
, FALSE
);
661 c
.cmd
= CMD_SIMULATE_TAG_125K
;
662 c
.ext1
= GraphTraceLen
;
663 SendCommand(&c
, FALSE
);
666 static void CmdLosimBidir(char *str
)
669 c
.cmd
= CMD_LF_SIMULATE_BIDIR
;
670 c
.ext1
= 47; /* Set ADC to twice the carrier for a slight supersampling */
672 SendCommand(&c
, FALSE
);
675 static void CmdLoread(char *str
)
678 // 'h' means higher-low-frequency, 134 kHz
681 } else if (*str
== '\0') {
684 PrintToScrollback("use 'loread' or 'loread h'");
687 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
688 SendCommand(&c
, FALSE
);
691 static void CmdDetectReader(char *str
)
694 // 'l' means LF - 125/134 kHz
697 } else if (*str
== 'h') {
699 } else if (*str
!= '\0') {
700 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");
703 c
.cmd
= CMD_LISTEN_READER_FIELD
;
704 SendCommand(&c
, FALSE
);
707 /* send a command before reading */
708 static void CmdLoCommandRead(char *str
)
710 static char dummy
[3];
715 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
716 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, (char *) &c
.d
.asBytes
,(char *) &dummy
+1);
717 // in case they specified 'h'
718 strcpy((char *)&c
.d
.asBytes
+ strlen((char *)c
.d
.asBytes
), dummy
);
719 SendCommand(&c
, FALSE
);
722 static void CmdLosamples(char *str
)
730 if (n
>16000) n
=16000;
732 for(i
= 0; i
< n
; i
+= 12) {
734 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
736 SendCommand(&c
, FALSE
);
738 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
740 PrintToScrollback("bad resp");
744 for(j
= 0; j
< 48; j
++) {
745 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
749 RepaintGraphWindow();
752 static void CmdBitsamples(char *str
)
759 for(i
= 0; i
< n
; i
+= 12) {
761 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
763 SendCommand(&c
, FALSE
);
765 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
766 PrintToScrollback("bad resp");
770 for(j
= 0; j
< 48; j
++) {
771 for(k
= 0; k
< 8; k
++) {
772 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
773 GraphBuffer
[cnt
++] = 1;
775 GraphBuffer
[cnt
++] = 0;
781 RepaintGraphWindow();
784 static void CmdHisamples(char *str
)
790 for(i
= 0; i
< n
; i
+= 12) {
792 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
794 SendCommand(&c
, FALSE
);
796 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
797 PrintToScrollback("bad resp");
801 for(j
= 0; j
< 48; j
++) {
802 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
807 RepaintGraphWindow();
810 static int CmdHisamplest(char *str
, int nrlow
)
822 for(i
= 0; i
< n
; i
+= 12) {
824 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
826 SendCommand(&c
, FALSE
);
828 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
829 PrintToScrollback("bad resp");
833 for(j
= 0; j
< 48; j
++) {
834 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
835 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
841 t1
= (t2
& 0x80) ^ (t2
& 0x20);
842 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
848 t2
= ((t2
<< 1) & 0x80);
854 t2
= ((t2
<< 1) & 0x20);
858 // both, but tag with other algorithm
859 t1
= (t2
& 0x80) ^ (t2
& 0x08);
860 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
864 GraphBuffer
[cnt
++] = t1
;
865 GraphBuffer
[cnt
++] = t2
;
870 if(hasbeennull
>nrlow
|| nrlow
==0) {
871 PrintToScrollback("hasbeennull=%d", hasbeennull
);
880 static void CmdHexsamples(char *str
)
891 for(i
= 0; i
< n
; i
+= 12) {
893 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
895 SendCommand(&c
, FALSE
);
897 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
898 PrintToScrollback("bad resp");
902 for(j
= 0; j
< 48; j
+= 8) {
903 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
918 static void CmdHisampless(char *str
)
930 for(i
= 0; i
< n
; i
+= 12) {
932 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
934 SendCommand(&c
, FALSE
);
936 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
937 PrintToScrollback("bad resp");
941 for(j
= 0; j
< 48; j
++) {
942 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
947 RepaintGraphWindow();
950 static WORD
Iso15693Crc(BYTE
*v
, int n
)
956 for(i
= 0; i
< n
; i
++) {
957 reg
= reg
^ ((DWORD
)v
[i
]);
958 for (j
= 0; j
< 8; j
++) {
960 reg
= (reg
>> 1) ^ 0x8408;
970 static void CmdHi14bdemod(char *str
)
975 BOOL negateI
, negateQ
;
980 // As received, the samples are pairs, correlations against I and Q
981 // square waves. So estimate angle of initial carrier (or just
982 // quadrant, actually), and then do the demod.
984 // First, estimate where the tag starts modulating.
985 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
986 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
990 if(i
>= GraphTraceLen
) {
991 PrintToScrollback("too weak to sync");
994 PrintToScrollback("out of weak at %d", i
);
997 // Now, estimate the phase in the initial modulation of the tag
1000 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
1001 isum
+= GraphBuffer
[i
+0];
1002 qsum
+= GraphBuffer
[i
+1];
1004 negateI
= (isum
< 0);
1005 negateQ
= (qsum
< 0);
1007 // Turn the correlation pairs into soft decisions on the bit.
1009 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
1010 int si
= GraphBuffer
[j
];
1011 int sq
= GraphBuffer
[j
+1];
1012 if(negateI
) si
= -si
;
1013 if(negateQ
) sq
= -sq
;
1014 GraphBuffer
[i
] = si
+ sq
;
1020 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
1022 if(i
>= GraphTraceLen
) goto demodError
;
1025 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
1027 if(i
>= GraphTraceLen
) goto demodError
;
1028 if((i
- iold
) > 23) goto demodError
;
1030 PrintToScrollback("make it to demod loop");
1034 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
1036 if(i
>= GraphTraceLen
) goto demodError
;
1037 if((i
- iold
) > 6) goto demodError
;
1040 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
1042 for(j
= 0; j
< 10; j
++) {
1043 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
1045 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
1046 PrintToScrollback("weak bit");
1050 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
1057 if( (shiftReg
& 0x200) &&
1058 !(shiftReg
& 0x001))
1060 // valid data byte, start and stop bits okay
1061 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
1062 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
1063 if(dataLen
>= sizeof(data
)) {
1066 } else if(shiftReg
== 0x000) {
1075 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
1076 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
1077 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
1078 "ok" : "****FAIL****");
1080 RepaintGraphWindow();
1084 PrintToScrollback("demod error");
1085 RepaintGraphWindow();
1088 static void CmdHi14list(char *str
)
1091 GetFromBigBuf(got
, sizeof(got
));
1093 PrintToScrollback("recorded activity:");
1094 PrintToScrollback(" time :rssi: who bytes");
1095 PrintToScrollback("---------+----+----+-----------");
1106 int timestamp
= *((DWORD
*)(got
+i
));
1107 if(timestamp
& 0x80000000) {
1108 timestamp
&= 0x7fffffff;
1113 int metric
= *((DWORD
*)(got
+i
+4));
1120 if(i
+ len
>= 900) {
1124 BYTE
*frame
= (got
+i
+9);
1126 char line
[1000] = "";
1128 for(j
= 0; j
< len
; j
++) {
1129 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
1135 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
1136 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1137 crc
= "**FAIL CRC**";
1145 char metricString
[100];
1147 sprintf(metricString
, "%3d", metric
);
1149 strcpy(metricString
, " ");
1152 PrintToScrollback(" +%7d: %s: %s %s %s",
1153 (prev
< 0 ? 0 : timestamp
- prev
),
1155 (isResponse
? "TAG" : " "), line
, crc
);
1162 static void CmdHi14alist(char *str
)
1165 GetFromBigBuf(got
, sizeof(got
));
1167 PrintToScrollback("recorded activity:");
1168 PrintToScrollback(" ETU :rssi: who bytes");
1169 PrintToScrollback("---------+----+----+-----------");
1180 int timestamp
= *((DWORD
*)(got
+i
));
1181 if(timestamp
& 0x80000000) {
1182 timestamp
&= 0x7fffffff;
1189 int parityBits
= *((DWORD
*)(got
+i
+4));
1190 // 4 bytes of additional information...
1191 // maximum of 32 additional parity bit information
1194 // at each quarter bit period we can send power level (16 levels)
1195 // or each half bit period in 256 levels.
1203 if(i
+ len
>= 1900) {
1207 BYTE
*frame
= (got
+i
+9);
1209 // Break and stick with current result if buffer was not completely full
1210 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1212 char line
[1000] = "";
1214 for(j
= 0; j
< len
; j
++) {
1215 int oddparity
= 0x01;
1219 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1222 //if((parityBits >> (len - j - 1)) & 0x01) {
1223 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1224 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1227 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1235 for(j
= 0; j
< (len
- 1); j
++) {
1236 // gives problems... search for the reason..
1237 /*if(frame[j] == 0xAA) {
1238 switch(frame[j+1]) {
1240 crc = "[1] Two drops close after each other";
1243 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1246 crc = "[3] Segment Z after segment X is not possible";
1249 crc = "[4] Parity bit of a fully received byte was wrong";
1252 crc = "[?] Unknown error";
1259 if(strlen(crc
)==0) {
1260 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1261 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1262 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1271 char metricString
[100];
1273 sprintf(metricString
, "%3d", metric
);
1275 strcpy(metricString
, " ");
1278 PrintToScrollback(" +%7d: %s: %s %s %s",
1279 (prev
< 0 ? 0 : (timestamp
- prev
)),
1281 (isResponse
? "TAG" : " "), line
, crc
);
1286 CommandFinished
= 1;
1289 static void CmdHi15demod(char *str
)
1291 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1294 // 1) Unmodulated time of 56.64us
1295 // 2) 24 pulses of 423.75khz
1296 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1298 static const int FrameSOF
[] = {
1299 -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,
1301 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,
1308 static const int Logic0
[] = {
1314 static const int Logic1
[] = {
1322 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1323 // 2) 24 pulses of 423.75khz
1324 // 3) Unmodulated time of 56.64us
1326 static const int FrameEOF
[] = {
1331 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1332 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1333 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1334 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1338 int max
= 0, maxPos
;
1342 if(GraphTraceLen
< 1000) return;
1344 // First, correlate for SOF
1345 for(i
= 0; i
< 100; i
++) {
1347 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1348 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1355 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1356 max
/(arraylen(FrameSOF
)/skip
));
1358 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1361 memset(outBuf
, 0, sizeof(outBuf
));
1364 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1365 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1366 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1368 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1369 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1371 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1372 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1374 // Even things out by the length of the target waveform.
1378 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1379 PrintToScrollback("EOF at %d", i
);
1381 } else if(corr1
> corr0
) {
1382 i
+= arraylen(Logic1
)/skip
;
1385 i
+= arraylen(Logic0
)/skip
;
1392 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1393 PrintToScrollback("ran off end!");
1398 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1399 PrintToScrollback(" mask=%02x", mask
);
1401 PrintToScrollback("%d octets", k
);
1403 for(i
= 0; i
< k
; i
++) {
1404 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1406 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1409 static void CmdFSKdemod(char *cmdline
)
1411 static const int LowTone
[] = {
1412 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1413 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1414 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1415 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1416 1, 1, 1, 1, 1, -1, -1, -1, -1, -1
1418 static const int HighTone
[] = {
1419 1, 1, 1, 1, 1, -1, -1, -1, -1,
1420 1, 1, 1, 1, -1, -1, -1, -1,
1421 1, 1, 1, 1, -1, -1, -1, -1,
1422 1, 1, 1, 1, -1, -1, -1, -1,
1423 1, 1, 1, 1, -1, -1, -1, -1,
1424 1, 1, 1, 1, -1, -1, -1, -1, -1,
1427 int lowLen
= sizeof(LowTone
)/sizeof(int);
1428 int highLen
= sizeof(HighTone
)/sizeof(int);
1429 int convLen
= (highLen
>lowLen
)?highLen
:lowLen
;
1430 DWORD hi
= 0, lo
= 0;
1433 int minMark
=0, maxMark
=0;
1435 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1436 int lowSum
= 0, highSum
= 0;
1438 for(j
= 0; j
< lowLen
; j
++) {
1439 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1441 for(j
= 0; j
< highLen
; j
++) {
1442 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1444 lowSum
= abs((100*lowSum
) / lowLen
);
1445 highSum
= abs((100*highSum
) / highLen
);
1446 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1449 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1451 int lowTot
= 0, highTot
= 0;
1452 // 10 and 8 are f_s divided by f_l and f_h, rounded
1453 for(j
= 0; j
< 10; j
++) {
1454 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1456 for(j
= 0; j
< 8; j
++) {
1457 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1459 GraphBuffer
[i
] = lowTot
- highTot
;
1460 if (GraphBuffer
[i
]>maxMark
) maxMark
=GraphBuffer
[i
];
1461 if (GraphBuffer
[i
]<minMark
) minMark
=GraphBuffer
[i
];
1464 GraphTraceLen
-= (convLen
+ 16);
1466 RepaintGraphWindow();
1468 // Find bit-sync (3 lo followed by 3 high)
1469 int max
= 0, maxPos
= 0;
1470 for(i
= 0; i
< 6000; i
++) {
1472 for(j
= 0; j
< 3*lowLen
; j
++) {
1473 dec
-= GraphBuffer
[i
+j
];
1475 for(; j
< 3*(lowLen
+ highLen
); j
++) {
1476 dec
+= GraphBuffer
[i
+j
];
1484 // place start of bit sync marker in graph
1485 GraphBuffer
[maxPos
] = maxMark
;
1486 GraphBuffer
[maxPos
+1] = minMark
;
1490 // place end of bit sync marker in graph
1491 GraphBuffer
[maxPos
] = maxMark
;
1492 GraphBuffer
[maxPos
+1] = minMark
;
1494 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1495 PrintToScrollback("length %d/%d", highLen
, lowLen
);
1498 bits
[sizeof(bits
)-1] = '\0';
1500 // find bit pairs and manchester decode them
1501 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1503 for(j
= 0; j
< lowLen
; j
++) {
1504 dec
-= GraphBuffer
[maxPos
+j
];
1506 for(; j
< lowLen
+ highLen
; j
++) {
1507 dec
+= GraphBuffer
[maxPos
+j
];
1510 // place inter bit marker in graph
1511 GraphBuffer
[maxPos
] = maxMark
;
1512 GraphBuffer
[maxPos
+1] = minMark
;
1514 // hi and lo form a 64 bit pair
1515 hi
= (hi
<<1)|(lo
>>31);
1517 // store decoded bit as binary (in hi/lo) and text (in bits[])
1525 PrintToScrollback("bits: '%s'", bits
);
1526 PrintToScrollback("hex: %08x %08x", hi
, lo
);
1529 // read a TI tag and return its ID
1530 static void CmdTIRead(char *str
)
1533 c
.cmd
= CMD_READ_TI_TYPE
;
1534 SendCommand(&c
, FALSE
);
1537 // write new data to a r/w TI tag
1538 static void CmdTIWrite(char *str
)
1543 c
.cmd
= CMD_WRITE_TI_TYPE
;
1544 res
= sscanf(str
, "0x%x 0x%x 0x%x ", &c
.ext1
, &c
.ext2
, &c
.ext3
);
1545 if (res
== 2) c
.ext3
=0;
1547 PrintToScrollback("Please specify the data as two hex strings, optionally the CRC as a third");
1549 SendCommand(&c
, FALSE
);
1552 static void CmdTIDemod(char *cmdline
)
1554 /* MATLAB as follows:
1555 f_s = 2000000; % sampling frequency
1556 f_l = 123200; % low FSK tone
1557 f_h = 134200; % high FSK tone
1559 T_l = 119e-6; % low bit duration
1560 T_h = 130e-6; % high bit duration
1562 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1563 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1565 l = sign(sin(cumsum(l)));
1566 h = sign(sin(cumsum(h)));
1569 // 2M*16/134.2k = 238
1570 static const int LowTone
[] = {
1571 1, 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, -1,
1576 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1577 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1578 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1579 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1580 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1581 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1582 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1583 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1584 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1585 1, 1, 1, 1, 1, 1, 1, 1, -1, -1
1587 // 2M*16/123.2k = 260
1588 static const int HighTone
[] = {
1589 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1590 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1591 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1592 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1593 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1594 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1595 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1596 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1597 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1598 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1599 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1600 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1601 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1602 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1603 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1604 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1605 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1606 1, 1, 1, 1, 1, 1, 1, 1
1608 int lowLen
= sizeof(LowTone
)/sizeof(int);
1609 int highLen
= sizeof(HighTone
)/sizeof(int);
1610 int convLen
= (highLen
>lowLen
)?highLen
:lowLen
;
1613 int lowSum
= 0, highSum
= 0;;
1614 int lowTot
= 0, highTot
= 0;
1616 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1620 for(j
= 0; j
< lowLen
; j
++) {
1621 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1623 for(j
= 0; j
< highLen
; j
++) {
1624 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1626 lowSum
= abs((100*lowSum
) / lowLen
);
1627 highSum
= abs((100*highSum
) / highLen
);
1628 lowSum
= (lowSum
<0)?-lowSum
:lowSum
;
1629 highSum
= (highSum
<0)?-highSum
:highSum
;
1631 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1634 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1637 // 16 and 15 are f_s divided by f_l and f_h, rounded
1638 for(j
= 0; j
< 16; j
++) {
1639 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1641 for(j
= 0; j
< 15; j
++) {
1642 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1644 GraphBuffer
[i
] = lowTot
- highTot
;
1647 GraphTraceLen
-= (convLen
+ 16);
1649 RepaintGraphWindow();
1651 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,
1652 // 16 crc CCITT bits, 8 stop bits, 15 end bits
1654 // the 16 prebits are always low
1655 // the 8 start and stop bits of a tag must match
1656 // the start/stop prebits of a ro tag are 01111110
1657 // the start/stop prebits of a rw tag are 11111110
1658 // the 15 end bits of a ro tag are all low
1659 // the 15 end bits of a rw tag match bits 15-1 of the data bits
1661 // Okay, so now we have unsliced soft decisions;
1662 // find bit-sync, and then get some bits.
1663 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)
1664 int max
= 0, maxPos
= 0;
1665 for(i
= 0; i
< 6000; i
++) {
1668 // searching 17 consecutive lows
1669 for(j
= 0; j
< 17*lowLen
; j
++) {
1670 dec
-= GraphBuffer
[i
+j
];
1672 // searching 7 consecutive highs
1673 for(; j
< 17*lowLen
+ 6*highLen
; j
++) {
1674 dec
+= GraphBuffer
[i
+j
];
1682 // place a marker in the buffer to visually aid location
1683 // of the start of sync
1684 GraphBuffer
[maxPos
] = 800;
1685 GraphBuffer
[maxPos
+1] = -800;
1687 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)
1688 maxPos
+= 17*lowLen
;
1689 maxPos
+= 6*highLen
;
1691 // place a marker in the buffer to visually aid location
1692 // of the end of sync
1693 GraphBuffer
[maxPos
] = 800;
1694 GraphBuffer
[maxPos
+1] = -800;
1696 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1698 PrintToScrollback("length %d/%d", highLen
, lowLen
);
1700 BYTE bits
[1+64+16+8+16];
1701 bits
[sizeof(bits
)-1] = '\0';
1703 DWORD shift3
= 0x7e000000, shift2
= 0, shift1
= 0, shift0
= 0;
1705 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1709 for(j
= 0; j
< lowLen
; j
++) {
1710 low
-= GraphBuffer
[maxPos
+j
];
1712 for(j
= 0; j
< highLen
; j
++) {
1713 high
+= GraphBuffer
[maxPos
+j
];
1719 // bitstream arrives lsb first so shift right
1726 // 128 bit right shift register
1727 shift0
= (shift0
>>1) | (shift1
<< 31);
1728 shift1
= (shift1
>>1) | (shift2
<< 31);
1729 shift2
= (shift2
>>1) | (shift3
<< 31);
1732 // place a marker in the buffer between bits to visually aid location
1733 GraphBuffer
[maxPos
] = 800;
1734 GraphBuffer
[maxPos
+1] = -800;
1736 PrintToScrollback("Info: raw tag bits = %s", bits
);
1738 TagType
= (shift3
>>8)&0xff;
1739 if ( TagType
!= ((shift0
>>16)&0xff) ) {
1740 PrintToScrollback("Error: start and stop bits do not match!");
1743 else if (TagType
== 0x7e) {
1744 PrintToScrollback("Info: Readonly TI tag detected.");
1747 else if (TagType
== 0xfe) {
1748 PrintToScrollback("Info: Rewriteable TI tag detected.");
1750 // put 64 bit data into shift1 and shift0
1751 shift0
= (shift0
>>24) | (shift1
<< 8);
1752 shift1
= (shift1
>>24) | (shift2
<< 8);
1754 // align 16 bit crc into lower half of shift2
1755 shift2
= ((shift2
>>24) | (shift3
<< 8)) & 0x0ffff;
1757 // align 16 bit "end bits" or "ident" into lower half of shift3
1760 // only 15 bits compare, last bit of ident is not valid
1761 if ( (shift3
^shift0
)&0x7fff ) {
1762 PrintToScrollback("Error: Ident mismatch!");
1764 // WARNING the order of the bytes in which we calc crc below needs checking
1765 // i'm 99% sure the crc algorithm is correct, but it may need to eat the
1766 // bytes in reverse or something
1769 crc
= update_crc16(crc
, (shift0
)&0xff);
1770 crc
= update_crc16(crc
, (shift0
>>8)&0xff);
1771 crc
= update_crc16(crc
, (shift0
>>16)&0xff);
1772 crc
= update_crc16(crc
, (shift0
>>24)&0xff);
1773 crc
= update_crc16(crc
, (shift1
)&0xff);
1774 crc
= update_crc16(crc
, (shift1
>>8)&0xff);
1775 crc
= update_crc16(crc
, (shift1
>>16)&0xff);
1776 crc
= update_crc16(crc
, (shift1
>>24)&0xff);
1777 PrintToScrollback("Info: Tag data = %08X%08X", shift1
, shift0
);
1778 if (crc
!= (shift2
&0xffff)) {
1779 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc
, shift2
&0xffff);
1781 PrintToScrollback("Info: CRC %04X is good", crc
);
1785 PrintToScrollback("Unknown tag type.");
1790 static void CmdNorm(char *str
)
1793 int max
= INT_MIN
, min
= INT_MAX
;
1794 for(i
= 10; i
< GraphTraceLen
; i
++) {
1795 if(GraphBuffer
[i
] > max
) {
1796 max
= GraphBuffer
[i
];
1798 if(GraphBuffer
[i
] < min
) {
1799 min
= GraphBuffer
[i
];
1803 for(i
= 0; i
< GraphTraceLen
; i
++) {
1804 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1808 RepaintGraphWindow();
1811 static void CmdAmp(char *str
)
1813 int i
, rising
, falling
;
1814 int max
= INT_MIN
, min
= INT_MAX
;
1815 for(i
= 10; i
< GraphTraceLen
; i
++) {
1816 if(GraphBuffer
[i
] > max
) {
1817 max
= GraphBuffer
[i
];
1819 if(GraphBuffer
[i
] < min
) {
1820 min
= GraphBuffer
[i
];
1825 for(i
= 0; i
< GraphTraceLen
; i
++) {
1826 if(GraphBuffer
[i
+1] < GraphBuffer
[i
]) {
1828 GraphBuffer
[i
]= max
;
1833 if(GraphBuffer
[i
+1] > GraphBuffer
[i
]) {
1835 GraphBuffer
[i
]= min
;
1842 RepaintGraphWindow();
1845 static void CmdDec(char *str
)
1848 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1849 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1852 PrintToScrollback("decimated by 2");
1853 RepaintGraphWindow();
1856 static void CmdHpf(char *str
)
1860 for(i
= 10; i
< GraphTraceLen
; i
++) {
1861 accum
+= GraphBuffer
[i
];
1863 accum
/= (GraphTraceLen
- 10);
1864 for(i
= 0; i
< GraphTraceLen
; i
++) {
1865 GraphBuffer
[i
] -= accum
;
1868 RepaintGraphWindow();
1871 static void CmdZerocrossings(char *str
)
1874 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1880 for(i
= 0; i
< GraphTraceLen
; i
++) {
1881 if(GraphBuffer
[i
]*sign
>= 0) {
1882 // No change in sign, reproduce the previous sample count.
1884 GraphBuffer
[i
] = lastZc
;
1886 // Change in sign, reset the sample count.
1888 GraphBuffer
[i
] = lastZc
;
1896 RepaintGraphWindow();
1899 static void CmdThreshold(char *str
)
1902 int threshold
= atoi(str
);
1904 for(i
= 0; i
< GraphTraceLen
; i
++) {
1905 if(GraphBuffer
[i
]>= threshold
)
1910 RepaintGraphWindow();
1913 static void CmdLtrim(char *str
)
1918 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1919 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1921 GraphTraceLen
-= ds
;
1923 RepaintGraphWindow();
1926 static void CmdAutoCorr(char *str
)
1928 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1930 int window
= atoi(str
);
1933 PrintToScrollback("needs a window");
1937 if(window
>= GraphTraceLen
) {
1938 PrintToScrollback("window must be smaller than trace (%d samples)",
1943 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1946 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1949 for(j
= 0; j
< window
; j
++) {
1950 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1952 CorrelBuffer
[i
] = sum
;
1954 GraphTraceLen
= GraphTraceLen
- window
;
1955 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1957 RepaintGraphWindow();
1960 static void CmdVchdemod(char *str
)
1962 // Is this the entire sync pattern, or does this also include some
1963 // data bits that happen to be the same everywhere? That would be
1965 static const int SyncPattern
[] = {
1966 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1967 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1968 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1969 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1970 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1971 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1972 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1973 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1974 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1975 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1978 // So first, we correlate for the sync pattern, and mark that.
1979 int bestCorrel
= 0, bestPos
= 0;
1981 // It does us no good to find the sync pattern, with fewer than
1982 // 2048 samples after it...
1983 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1986 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1987 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1989 if(sum
> bestCorrel
) {
1994 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
1999 int worst
= INT_MAX
;
2002 for(i
= 0; i
< 2048; i
+= 8) {
2005 for(j
= 0; j
< 8; j
++) {
2006 sum
+= GraphBuffer
[bestPos
+i
+j
];
2013 if(abs(sum
) < worst
) {
2018 PrintToScrollback("bits:");
2019 PrintToScrollback("%s", bits
);
2020 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
2022 if(strcmp(str
, "clone")==0) {
2025 for(s
= bits
; *s
; s
++) {
2027 for(j
= 0; j
< 16; j
++) {
2028 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
2031 RepaintGraphWindow();
2035 static void CmdIndalademod(char *str
)
2037 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
2042 // worst case with GraphTraceLen=64000 is < 4096
2043 // under normal conditions it's < 2048
2046 int worst
= 0, worstPos
= 0;
2047 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
2048 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
2050 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
2052 for(j
= 0; j
< count
- 8; j
+= 16) {
2053 rawbits
[rawbit
++] = 0;
2055 if ((abs(count
- j
)) > worst
) {
2056 worst
= abs(count
- j
);
2062 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
2064 for(j
= 0; j
< count
- 8; j
+= 16) {
2065 rawbits
[rawbit
++] = 1;
2067 if ((abs(count
- j
)) > worst
) {
2068 worst
= abs(count
- j
);
2076 PrintToScrollback("Recovered %d raw bits", rawbit
);
2077 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
2079 // Finding the start of a UID
2080 int uidlen
, long_wait
;
2081 if(strcmp(str
, "224") == 0) {
2090 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
2091 first
= rawbits
[start
];
2092 for(i
= start
; i
< start
+ long_wait
; i
++) {
2093 if(rawbits
[i
] != first
) {
2097 if(i
== (start
+ long_wait
)) {
2101 if(start
== rawbit
- uidlen
+ 1) {
2102 PrintToScrollback("nothing to wait for");
2106 // Inverting signal if needed
2108 for(i
= start
; i
< rawbit
; i
++) {
2109 rawbits
[i
] = !rawbits
[i
];
2116 showbits
[uidlen
]='\0';
2120 if(uidlen
> rawbit
) {
2121 PrintToScrollback("Warning: not enough raw bits to get a full UID");
2122 for(bit
= 0; bit
< rawbit
; bit
++) {
2123 bits
[bit
] = rawbits
[i
++];
2124 // As we cannot know the parity, let's use "." and "/"
2125 showbits
[bit
] = '.' + bits
[bit
];
2127 showbits
[bit
+1]='\0';
2128 PrintToScrollback("Partial UID=%s", showbits
);
2131 for(bit
= 0; bit
< uidlen
; bit
++) {
2132 bits
[bit
] = rawbits
[i
++];
2133 showbits
[bit
] = '0' + bits
[bit
];
2137 PrintToScrollback("UID=%s", showbits
);
2139 // Checking UID against next occurences
2140 for(; i
+ uidlen
<= rawbit
;) {
2142 for(bit
= 0; bit
< uidlen
; bit
++) {
2143 if(bits
[bit
] != rawbits
[i
++]) {
2153 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
2155 // Remodulating for tag cloning
2156 GraphTraceLen
= 32*uidlen
;
2159 for(bit
= 0; bit
< uidlen
; bit
++) {
2160 if(bits
[bit
] == 0) {
2166 for(j
= 0; j
< 32; j
++) {
2167 GraphBuffer
[i
++] = phase
;
2172 RepaintGraphWindow();
2175 static void CmdFlexdemod(char *str
)
2178 for(i
= 0; i
< GraphTraceLen
; i
++) {
2179 if(GraphBuffer
[i
] < 0) {
2180 GraphBuffer
[i
] = -1;
2186 #define LONG_WAIT 100
2188 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
2189 int first
= GraphBuffer
[start
];
2190 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
2191 if(GraphBuffer
[i
] != first
) {
2195 if(i
== (start
+ LONG_WAIT
)) {
2199 if(start
== GraphTraceLen
- LONG_WAIT
) {
2200 PrintToScrollback("nothing to wait for");
2204 GraphBuffer
[start
] = 2;
2205 GraphBuffer
[start
+1] = -2;
2211 for(bit
= 0; bit
< 64; bit
++) {
2214 for(j
= 0; j
< 16; j
++) {
2215 sum
+= GraphBuffer
[i
++];
2222 PrintToScrollback("bit %d sum %d", bit
, sum
);
2225 for(bit
= 0; bit
< 64; bit
++) {
2228 for(j
= 0; j
< 16; j
++) {
2229 sum
+= GraphBuffer
[i
++];
2231 if(sum
> 0 && bits
[bit
] != 1) {
2232 PrintToScrollback("oops1 at %d", bit
);
2234 if(sum
< 0 && bits
[bit
] != 0) {
2235 PrintToScrollback("oops2 at %d", bit
);
2239 GraphTraceLen
= 32*64;
2242 for(bit
= 0; bit
< 64; bit
++) {
2243 if(bits
[bit
] == 0) {
2249 for(j
= 0; j
< 32; j
++) {
2250 GraphBuffer
[i
++] = phase
;
2255 RepaintGraphWindow();
2259 * Generic command to demodulate ASK.
2261 * Argument is convention: positive or negative (High mod means zero
2262 * or high mod means one)
2264 * Updates the Graph trace with 0/1 values
2270 static void Cmdaskdemod(char *str
) {
2272 int c
, high
= 0, low
= 0;
2274 // TODO: complain if we do not give 2 arguments here !
2275 // (AL - this doesn't make sense! we're only using one argument!!!)
2276 sscanf(str
, "%i", &c
);
2278 /* Detect high and lows and clock */
2280 for (i
= 0; i
< GraphTraceLen
; i
++)
2282 if (GraphBuffer
[i
] > high
)
2283 high
= GraphBuffer
[i
];
2284 else if (GraphBuffer
[i
] < low
)
2285 low
= GraphBuffer
[i
];
2287 if(c
!= 0 && c
!= 1) {
2288 PrintToScrollback("Invalid argument: %s",str
);
2292 if (GraphBuffer
[0] > 0) {
2293 GraphBuffer
[0] = 1-c
;
2297 for(i
=1;i
<GraphTraceLen
;i
++) {
2298 /* Transitions are detected at each peak
2299 * Transitions are either:
2300 * - we're low: transition if we hit a high
2301 * - we're high: transition if we hit a low
2302 * (we need to do it this way because some tags keep high or
2303 * low for long periods, others just reach the peak and go
2306 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
2308 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
2312 GraphBuffer
[i
] = GraphBuffer
[i
-1];
2315 RepaintGraphWindow();
2318 /* Print our clock rate */
2319 static void Cmddetectclockrate(char *str
)
2321 int clock
= detectclock(0);
2322 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2328 int detectclock(int peak
)
2334 /* Detect peak if we don't have one */
2336 for (i
= 0; i
< GraphTraceLen
; i
++)
2337 if (GraphBuffer
[i
] > peak
)
2338 peak
= GraphBuffer
[i
];
2340 for (i
= 1; i
< GraphTraceLen
; i
++)
2342 /* If this is the beginning of a peak */
2343 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
2345 /* Find lowest difference between peaks */
2346 if (lastpeak
&& i
- lastpeak
< clock
)
2348 clock
= i
- lastpeak
;
2357 /* Get or auto-detect clock rate */
2358 int GetClock(char *str
, int peak
)
2362 sscanf(str
, "%i", &clock
);
2363 if (!strcmp(str
, ""))
2366 /* Auto-detect clock */
2369 clock
= detectclock(peak
);
2371 /* Only print this message if we're not looping something */
2373 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2380 * Convert to a bitstream
2382 static void Cmdbitstream(char *str
) {
2389 int hithigh
, hitlow
, first
;
2391 /* Detect high and lows and clock */
2392 for (i
= 0; i
< GraphTraceLen
; i
++)
2394 if (GraphBuffer
[i
] > high
)
2395 high
= GraphBuffer
[i
];
2396 else if (GraphBuffer
[i
] < low
)
2397 low
= GraphBuffer
[i
];
2401 clock
= GetClock(str
, high
);
2403 gtl
= CmdClearGraph(0);
2406 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2412 /* Find out if we hit both high and low peaks */
2413 for (j
= 0; j
< clock
; j
++)
2415 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2417 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2420 /* it doesn't count if it's the first part of our read
2421 because it's really just trailing from the last sequence */
2422 if (first
&& (hithigh
|| hitlow
))
2423 hithigh
= hitlow
= 0;
2427 if (hithigh
&& hitlow
)
2431 /* If we didn't hit both high and low peaks, we had a bit transition */
2432 if (!hithigh
|| !hitlow
)
2435 CmdAppendGraph(0, clock
, bit
);
2436 // for (j = 0; j < (int)(clock/2); j++)
2437 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2438 // for (j = (int)(clock/2); j < clock; j++)
2439 // GraphBuffer[(i * clock) + j] = bit;
2442 RepaintGraphWindow();
2445 /* Modulate our data into manchester */
2446 static void Cmdmanchestermod(char *str
)
2450 int bit
, lastbit
, wave
;
2453 clock
= GetClock(str
, 0);
2457 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2459 bit
= GraphBuffer
[i
* clock
] ^ 1;
2461 for (j
= 0; j
< (int)(clock
/2); j
++)
2462 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2463 for (j
= (int)(clock
/2); j
< clock
; j
++)
2464 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2466 /* Keep track of how we start our wave and if we changed or not this time */
2467 wave
^= bit
^ lastbit
;
2471 RepaintGraphWindow();
2475 * Manchester demodulate a bitstream. The bitstream needs to be already in
2476 * the GraphBuffer as 0 and 1 values
2478 * Give the clock rate as argument in order to help the sync - the algorithm
2479 * resyncs at each pulse anyway.
2481 * Not optimized by any means, this is the 1st time I'm writing this type of
2482 * routine, feel free to improve...
2484 * 1st argument: clock rate (as number of samples per clock rate)
2485 * Typical values can be 64, 32, 128...
2487 static void Cmdmanchesterdemod(char *str
) {
2488 int i
, j
, invert
= 0;
2494 int hithigh
, hitlow
, first
;
2500 /* check if we're inverting output */
2503 PrintToScrollback("Inverting output");
2507 while(*str
== ' '); // in case a 2nd argument was given
2510 /* Holds the decoded bitstream: each clock period contains 2 bits */
2511 /* later simplified to 1 bit after manchester decoding. */
2512 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2513 /* int BitStream[GraphTraceLen*2/clock+10]; */
2515 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2517 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2519 /* Detect high and lows */
2520 for (i
= 0; i
< GraphTraceLen
; i
++)
2522 if (GraphBuffer
[i
] > high
)
2523 high
= GraphBuffer
[i
];
2524 else if (GraphBuffer
[i
] < low
)
2525 low
= GraphBuffer
[i
];
2529 clock
= GetClock(str
, high
);
2531 int tolerance
= clock
/4;
2533 /* Detect first transition */
2534 /* Lo-Hi (arbitrary) */
2535 for (i
= 0; i
< GraphTraceLen
; i
++)
2537 if (GraphBuffer
[i
] == low
)
2544 /* If we're not working with 1/0s, demod based off clock */
2547 bit
= 0; /* We assume the 1st bit is zero, it may not be
2548 * the case: this routine (I think) has an init problem.
2551 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2557 /* Find out if we hit both high and low peaks */
2558 for (j
= 0; j
< clock
; j
++)
2560 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2562 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2565 /* it doesn't count if it's the first part of our read
2566 because it's really just trailing from the last sequence */
2567 if (first
&& (hithigh
|| hitlow
))
2568 hithigh
= hitlow
= 0;
2572 if (hithigh
&& hitlow
)
2576 /* If we didn't hit both high and low peaks, we had a bit transition */
2577 if (!hithigh
|| !hitlow
)
2580 BitStream
[bit2idx
++] = bit
^ invert
;
2584 /* standard 1/0 bitstream */
2588 /* Then detect duration between 2 successive transitions */
2589 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2591 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2596 // Error check: if bitidx becomes too large, we do not
2597 // have a Manchester encoded bitstream or the clock is really
2599 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2600 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2603 // Then switch depending on lc length:
2604 // Tolerance is 1/4 of clock rate (arbitrary)
2605 if (abs(lc
-clock
/2) < tolerance
) {
2606 // Short pulse : either "1" or "0"
2607 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2608 } else if (abs(lc
-clock
) < tolerance
) {
2609 // Long pulse: either "11" or "00"
2610 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2611 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2615 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2616 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2620 PrintToScrollback("Error: too many detection errors, aborting.");
2627 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2628 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2629 // to stop output at the final bitidx2 value, not bitidx
2630 for (i
= 0; i
< bitidx
; i
+= 2) {
2631 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2632 BitStream
[bit2idx
++] = 1 ^ invert
;
2633 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2634 BitStream
[bit2idx
++] = 0 ^ invert
;
2636 // We cannot end up in this state, this means we are unsynchronized,
2640 PrintToScrollback("Unsynchronized, resync...");
2641 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2645 PrintToScrollback("Error: too many decode errors, aborting.");
2652 PrintToScrollback("Manchester decoded bitstream");
2653 // Now output the bitstream to the scrollback by line of 16 bits
2654 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2655 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2678 static void CmdHiddemod(char *str
)
2680 if(GraphTraceLen
< 4800) {
2681 PrintToScrollback("too short; need at least 4800 samples");
2685 GraphTraceLen
= 4800;
2687 for(i
= 0; i
< GraphTraceLen
; i
++) {
2688 if(GraphBuffer
[i
] < 0) {
2694 RepaintGraphWindow();
2697 static void CmdPlot(char *str
)
2702 static void CmdGrid(char *str
)
2704 sscanf(str
, "%i %i", &PlotGridX
, &PlotGridY
);
2705 RepaintGraphWindow();
2708 static void CmdHide(char *str
)
2713 static void CmdScale(char *str
)
2715 CursorScaleFactor
= atoi(str
);
2716 if(CursorScaleFactor
== 0) {
2717 PrintToScrollback("bad, can't have zero scale");
2718 CursorScaleFactor
= 1;
2720 RepaintGraphWindow();
2723 static void CmdSave(char *str
)
2725 FILE *f
= fopen(str
, "w");
2727 PrintToScrollback("couldn't open '%s'", str
);
2731 for(i
= 0; i
< GraphTraceLen
; i
++) {
2732 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2735 PrintToScrollback("saved to '%s'", str
);
2738 static void CmdLoad(char *str
)
2740 FILE *f
= fopen(str
, "r");
2742 PrintToScrollback("couldn't open '%s'", str
);
2748 while(fgets(line
, sizeof(line
), f
)) {
2749 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2753 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2754 RepaintGraphWindow();
2757 static void CmdHIDsimTAG(char *str
)
2759 unsigned int hi
=0, lo
=0;
2763 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2764 hi
=(hi
<<4)|(lo
>>28);
2768 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2770 c
.cmd
= CMD_HID_SIM_TAG
;
2773 SendCommand(&c
, FALSE
);
2776 static void CmdReadmem(char *str
)
2779 c
.cmd
= CMD_READ_MEM
;
2781 SendCommand(&c
, FALSE
);
2784 static void CmdVersion(char *str
)
2787 c
.cmd
= CMD_VERSION
;
2788 SendCommand(&c
, FALSE
);
2791 static void CmdLcdReset(char *str
)
2794 c
.cmd
= CMD_LCD_RESET
;
2796 SendCommand(&c
, FALSE
);
2799 static void CmdLcd(char *str
)
2804 sscanf(str
, "%x %d", &i
, &j
);
2807 SendCommand(&c
, FALSE
);
2812 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2815 static void CmdSetDivisor(char *str
)
2818 c
.cmd
= CMD_SET_LF_DIVISOR
;
2820 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2821 PrintToScrollback("divisor must be between 19 and 255");
2823 SendCommand(&c
, FALSE
);
2824 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2828 typedef void HandlerFunction(char *cmdline
);
2830 /* in alphabetic order */
2833 HandlerFunction
*handler
;
2834 int offline
; // 1 if the command can be used when in offline mode
2836 } CommandTable
[] = {
2837 {"amp", CmdAmp
, 1, "Amplify peaks"},
2838 {"askdemod", Cmdaskdemod
, 1, "<0|1> -- Attempt to demodulate simple ASK tags"},
2839 {"autocorr", CmdAutoCorr
, 1, "<window length> -- Autocorrelation over window"},
2840 {"bitsamples", CmdBitsamples
, 0, "Get raw samples as bitstring"},
2841 {"bitstream", Cmdbitstream
, 1, "[clock rate] -- Convert waveform into a bitstream"},
2842 {"buffclear", CmdBuffClear
, 1, "Clear sample buffer and graph window"},
2843 {"dec", CmdDec
, 1, "Decimate samples"},
2844 {"detectclock", Cmddetectclockrate
, 1, "Detect clock rate"},
2845 {"detectreader", CmdDetectReader
, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
2846 {"em410xsim", CmdEM410xsim
, 1, "<UID> -- Simulate EM410x tag"},
2847 {"em410xread", CmdEM410xread
, 1, "[clock rate] -- Extract ID from EM410x tag"},
2848 {"em410xwatch", CmdEM410xwatch
, 0, "Watches for EM410x tags"},
2849 {"em4x50read", CmdEM4x50read
, 1, "Extract data from EM4x50 tag"},
2850 {"exit", CmdQuit
, 1, "Exit program"},
2851 {"flexdemod", CmdFlexdemod
, 1, "Demodulate samples for FlexPass"},
2852 {"fpgaoff", CmdFPGAOff
, 0, "Set FPGA off"},
2853 {"fskdemod", CmdFSKdemod
, 1, "Demodulate graph window as a HID FSK"},
2854 {"grid", CmdGrid
, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
2855 {"hexsamples", CmdHexsamples
, 0, "<blocks> -- Dump big buffer as hex bytes"},
2856 {"hi14alist", CmdHi14alist
, 0, "List ISO 14443a history"},
2857 {"hi14areader", CmdHi14areader
, 0, "Act like an ISO14443 Type A reader"},
2858 {"hi14asim", CmdHi14asim
, 0, "<UID> -- Fake ISO 14443a tag"},
2859 {"hi14asnoop", CmdHi14asnoop
, 0, "Eavesdrop ISO 14443 Type A"},
2860 {"hi14bdemod", CmdHi14bdemod
, 1, "Demodulate ISO14443 Type B from tag"},
2861 {"hi14list", CmdHi14list
, 0, "List ISO 14443 history"},
2862 {"hi14read", CmdHi14read
, 0, "Read HF tag (ISO 14443)"},
2863 {"hi14sim", CmdHi14sim
, 0, "Fake ISO 14443 tag"},
2864 {"hi14snoop", CmdHi14snoop
, 0, "Eavesdrop ISO 14443"},
2865 {"hi15demod", CmdHi15demod
, 1, "Demodulate ISO15693 from tag"},
2866 {"hi15read", CmdHi15read
, 0, "Read HF tag (ISO 15693)"},
2867 {"hi15reader", CmdHi15reader
, 0, "Act like an ISO15693 reader"},
2868 {"hi15sim", CmdHi15tag
, 0, "Fake an ISO15693 tag"},
2869 {"hiddemod", CmdHiddemod
, 1, "Demodulate HID Prox Card II (not optimal)"},
2870 {"hide", CmdHide
, 1, "Hide graph window"},
2871 {"hidfskdemod", CmdHIDdemodFSK
, 0, "Realtime HID FSK demodulator"},
2872 {"hidsimtag", CmdHIDsimTAG
, 0, "<ID> -- HID tag simulator"},
2873 {"higet", CmdHi14read_sim
, 0, "<samples> -- Get samples HF, 'analog'"},
2874 {"hisamples", CmdHisamples
, 0, "Get raw samples for HF tag"},
2875 {"hisampless", CmdHisampless
, 0, "<samples> -- Get signed raw samples, HF tag"},
2876 {"hisamplest", CmdHi14readt
, 0, "Get samples HF, for testing"},
2877 {"hisimlisten", CmdHisimlisten
, 0, "Get HF samples as fake tag"},
2878 {"hpf", CmdHpf
, 1, "Remove DC offset from trace"},
2879 {"indalademod", CmdIndalademod
, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
2880 {"lcd", CmdLcd
, 0, "<HEX command> <count> -- Send command/data to LCD"},
2881 {"lcdreset", CmdLcdReset
, 0, "Hardware reset LCD"},
2882 {"load", CmdLoad
, 1, "<filename> -- Load trace (to graph window"},
2883 {"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)"},
2884 {"loread", CmdLoread
, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
2885 {"losamples", CmdLosamples
, 0, "[128 - 16000] -- Get raw samples for LF tag"},
2886 {"losim", CmdLosim
, 0, "Simulate LF tag"},
2887 {"losimbidir", CmdLosimBidir
, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
2888 {"ltrim", CmdLtrim
, 1, "<samples> -- Trim samples from left of trace"},
2889 {"mandemod", Cmdmanchesterdemod
, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
2890 {"manmod", Cmdmanchestermod
, 1, "[clock rate] -- Manchester modulate a binary stream"},
2891 {"norm", CmdNorm
, 1, "Normalize max/min to +/-500"},
2892 {"plot", CmdPlot
, 1, "Show graph window"},
2893 {"quit", CmdQuit
, 1, "Quit program"},
2894 {"readmem", CmdReadmem
, 0, "[address] -- Read memory at decimal address from flash"},
2895 {"reset", CmdReset
, 0, "Reset the Proxmark3"},
2896 {"save", CmdSave
, 1, "<filename> -- Save trace (from graph window)"},
2897 {"scale", CmdScale
, 1, "<int> -- Set cursor display scale"},
2898 {"setlfdivisor", CmdSetDivisor
, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
2899 {"sri512read", CmdSri512read
, 0, "<int> -- Read contents of a SRI512 tag"},
2900 {"tidemod", CmdTIDemod
, 1, "Demodulate raw bits for TI-type LF tag"},
2901 {"tiread", CmdTIRead
, 0, "Read and decode a TI 134 kHz tag"},
2902 {"tiwrite", CmdTIWrite
, 0, "Write new data to a r/w TI 134 kHz tag"},
2903 {"threshold", CmdThreshold
, 1, "Maximize/minimize every value in the graph window depending on threshold"},
2904 {"tune", CmdTune
, 0, "Measure antenna tuning"},
2905 {"vchdemod", CmdVchdemod
, 0, "['clone'] -- Demodulate samples for VeriChip"},
2906 {"version", CmdVersion
, 0, "Show version inforation about the connected Proxmark"},
2907 {"zerocrossings", CmdZerocrossings
, 1, "Count time between zero-crossings"},
2915 } CommandExtendedHelp
[]= {
2916 {"detectreader","'l'|'h'","'l' specifies LF antenna scan only, 'h' specifies HF antenna scan only.","Monitor antenna for changes in voltage. Output is in three fields: CHANGED, CURRENT, PERIOD,\nwhere CHANGED is the value just changed from, CURRENT is the current value and PERIOD is the\nnumber of program loops since the last change.\n\nThe RED LED indicates LF field detected, and the GREEN LED indicates HF field detected."},
2917 {"tune","","","Drive LF antenna at all divisor range values (19 - 255) and store the results in the output\nbuffer. Issuing 'losamples' and then 'plot' commands will display the resulting peak. 12MHz\ndivided by the peak's position plus one gives the antenna's resonant frequency. For convenience,\nthis value is also printed out by the command."},
2920 //-----------------------------------------------------------------------------
2921 // Entry point into our code: called whenever the user types a command and
2922 // then presses Enter, which the full command line that they typed.
2923 //-----------------------------------------------------------------------------
2924 void CommandReceived(char *cmd
)
2929 PrintToScrollback("> %s", cmd
);
2931 if(strcmp(cmd
, "help") == 0 || strncmp(cmd
,"help ",strlen("help ")) == 0) {
2932 // check if we're doing extended help
2933 if(strlen(cmd
) > strlen("help ")) {
2934 cmd
+= strlen("help ");
2935 for(i
= 0; i
< sizeof(CommandExtendedHelp
) / sizeof(CommandExtendedHelp
[0]); i
++) {
2936 if(strcmp(CommandExtendedHelp
[i
].name
,cmd
) == 0) {
2937 PrintToScrollback("\nExtended help for '%s':\n", cmd
);
2938 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp
[i
].args
,CommandExtendedHelp
[i
].argshelp
);
2939 PrintToScrollback(CommandExtendedHelp
[i
].description
);
2940 PrintToScrollback("");
2944 PrintToScrollback("No extended help available for '%s'", cmd
);
2947 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2948 PrintToScrollback("\r\nAvailable commands:");
2949 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2950 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2951 memset(line
, ' ', sizeof(line
));
2952 strcpy(line
+2, CommandTable
[i
].name
);
2953 line
[strlen(line
)] = ' ';
2954 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2955 PrintToScrollback("%s", line
);
2957 PrintToScrollback("");
2958 PrintToScrollback("'help <command>' for extended help on that command\n");
2962 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2963 char *name
= CommandTable
[i
].name
;
2964 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2965 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2967 cmd
+= strlen(name
);
2968 while(*cmd
== ' ') {
2971 if (offline
&& (CommandTable
[i
].offline
==0)) {
2972 PrintToScrollback("Offline mode, cannot use this command.");
2975 (CommandTable
[i
].handler
)(cmd
);
2979 PrintToScrollback(">> bad command '%s'", cmd
);
2982 //-----------------------------------------------------------------------------
2983 // Entry point into our code: called whenever we received a packet over USB
2984 // that we weren't necessarily expecting, for example a debug print.
2985 //-----------------------------------------------------------------------------
2986 void UsbCommandReceived(UsbCommand
*c
)
2989 case CMD_DEBUG_PRINT_STRING
: {
2991 if(c
->ext1
> 70 || c
->ext1
< 0) {
2994 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
2996 PrintToScrollback("#db# %s", s
);
3000 case CMD_DEBUG_PRINT_INTEGERS
:
3001 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
3004 case CMD_MEASURED_ANTENNA_TUNING
: {
3006 int vLf125
, vLf134
, vHf
;
3007 vLf125
= c
->ext1
& 0xffff;
3008 vLf134
= c
->ext1
>> 16;
3009 vHf
= c
->ext2
& 0xffff;;
3010 peakf
= c
->ext3
& 0xffff;
3011 peakv
= c
->ext3
>> 16;
3012 PrintToScrollback("");
3013 PrintToScrollback("");
3014 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125
/1000.0);
3015 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134
/1000.0);
3016 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv
/1000.0, 12000.0/(peakf
+1));
3017 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf
/1000.0);
3019 PrintToScrollback("# Your LF antenna is unusable.");
3020 else if (peakv
<10000)
3021 PrintToScrollback("# Your LF antenna is marginal.");
3023 PrintToScrollback("# Your HF antenna is unusable.");
3025 PrintToScrollback("# Your HF antenna is marginal.");
3029 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);