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 CmdLegicRfSim(char *str
)
213 c
.cmd
= CMD_SIMULATE_TAG_LEGIC_RF
;
214 SendCommand(&c
, FALSE
);
217 static void CmdFPGAOff(char *str
) // ## FPGA Control
220 c
.cmd
= CMD_FPGA_MAJOR_MODE_OFF
;
221 SendCommand(&c
, FALSE
);
224 /* clear out our graph window */
225 int CmdClearGraph(int redraw
)
227 int gtl
= GraphTraceLen
;
231 RepaintGraphWindow();
236 /* write a bit to the graph */
237 static void CmdAppendGraph(int redraw
, int clock
, int bit
)
241 for (i
= 0; i
< (int)(clock
/2); i
++)
242 GraphBuffer
[GraphTraceLen
++] = bit
^ 1;
244 for (i
= (int)(clock
/2); i
< clock
; i
++)
245 GraphBuffer
[GraphTraceLen
++] = bit
;
248 RepaintGraphWindow();
251 /* Function is equivalent of loread + losamples + em410xread
252 * looped until an EM410x tag is detected */
253 static void CmdEM410xwatch(char *str
)
267 /* Read the transmitted data of an EM4x50 tag
270 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
271 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
272 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
273 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
274 * CCCCCCCC <- column parity bits
276 * LW <- Listen Window
278 * This pattern repeats for every block of data being transmitted.
279 * Transmission starts with two Listen Windows (LW - a modulated
280 * pattern of 320 cycles each (32/32/128/64/64)).
282 * Note that this data may or may not be the UID. It is whatever data
283 * is stored in the blocks defined in the control word First and Last
284 * Word Read values. UID is stored in block 32.
286 static void CmdEM4x50read(char *str
)
288 int i
, j
, startblock
, clock
, skip
, block
, start
, end
, low
, high
;
289 BOOL complete
= FALSE
;
290 int tmpbuff
[MAX_GRAPH_TRACE_LEN
/ 64];
296 /* first get high and low values */
297 for (i
= 0; i
< GraphTraceLen
; i
++)
299 if (GraphBuffer
[i
] > high
)
300 high
= GraphBuffer
[i
];
301 else if (GraphBuffer
[i
] < low
)
302 low
= GraphBuffer
[i
];
305 /* populate a buffer with pulse lengths */
308 while(i
< GraphTraceLen
)
310 // measure from low to low
311 while((GraphBuffer
[i
] > low
) && (i
<GraphTraceLen
))
314 while((GraphBuffer
[i
] < high
) && (i
<GraphTraceLen
))
316 while((GraphBuffer
[i
] > low
) && (i
<GraphTraceLen
))
318 if (j
>(MAX_GRAPH_TRACE_LEN
/64)) {
321 tmpbuff
[j
++]= i
- start
;
324 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
327 for (i
= 0; i
< j
- 4 ; ++i
)
330 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
331 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
332 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
333 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
341 /* skip over the remainder of the LW */
342 skip
+= tmpbuff
[i
+1]+tmpbuff
[i
+2];
343 while(skip
< MAX_GRAPH_TRACE_LEN
&& GraphBuffer
[skip
] > low
)
347 /* now do it again to find the end */
349 for (i
+= 3; i
< j
- 4 ; ++i
)
352 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
353 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
354 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
355 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
363 PrintToScrollback("Found data at sample: %i",skip
);
366 PrintToScrollback("No data found!");
367 PrintToScrollback("Try again with more samples.");
373 PrintToScrollback("*** Warning!");
374 PrintToScrollback("Partial data - no end found!");
375 PrintToScrollback("Try again with more samples.");
378 /* get rid of leading crap */
379 sprintf(tmp
,"%i",skip
);
382 /* now work through remaining buffer printing out data blocks */
387 PrintToScrollback("Block %i:", block
);
388 // mandemod routine needs to be split so we can call it for data
389 // just print for now for debugging
390 Cmdmanchesterdemod("i 64");
392 /* look for LW before start of next block */
393 for ( ; i
< j
- 4 ; ++i
)
396 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
397 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
400 while(GraphBuffer
[skip
] > low
)
403 sprintf(tmp
,"%i",skip
);
411 /* Read the ID of an EM410x tag.
413 * 1111 1111 1 <-- standard non-repeatable header
414 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
416 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
417 * 0 <-- stop bit, end of tag
419 static void CmdEM410xread(char *str
)
421 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
425 int BitStream
[MAX_GRAPH_TRACE_LEN
];
428 /* Detect high and lows and clock */
429 for (i
= 0; i
< GraphTraceLen
; i
++)
431 if (GraphBuffer
[i
] > high
)
432 high
= GraphBuffer
[i
];
433 else if (GraphBuffer
[i
] < low
)
434 low
= GraphBuffer
[i
];
438 clock
= GetClock(str
, high
);
440 /* parity for our 4 columns */
441 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
444 /* manchester demodulate */
446 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
452 /* Find out if we hit both high and low peaks */
453 for (j
= 0; j
< clock
; j
++)
455 if (GraphBuffer
[(i
* clock
) + j
] == high
)
457 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
460 /* it doesn't count if it's the first part of our read
461 because it's really just trailing from the last sequence */
462 if (first
&& (hithigh
|| hitlow
))
463 hithigh
= hitlow
= 0;
467 if (hithigh
&& hitlow
)
471 /* If we didn't hit both high and low peaks, we had a bit transition */
472 if (!hithigh
|| !hitlow
)
475 BitStream
[bit2idx
++] = bit
;
479 /* We go till 5 before the graph ends because we'll get that far below */
480 for (i
= 1; i
< bit2idx
- 5; i
++)
482 /* Step 2: We have our header but need our tag ID */
483 if (header
== 9 && rows
< 10)
485 /* Confirm parity is correct */
486 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
488 /* Read another byte! */
489 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
492 /* Keep parity info */
493 parity
[0] ^= BitStream
[i
];
494 parity
[1] ^= BitStream
[i
+1];
495 parity
[2] ^= BitStream
[i
+2];
496 parity
[3] ^= BitStream
[i
+3];
498 /* Move 4 bits ahead */
502 /* Damn, something wrong! reset */
505 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
507 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
508 i
-= 9 + (5 * rows
) - 5;
514 /* Step 3: Got our 40 bits! confirm column parity */
517 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
518 if (BitStream
[i
] == parity
[0] && BitStream
[i
+1] == parity
[1] &&
519 BitStream
[i
+2] == parity
[2] && BitStream
[i
+3] == parity
[3] &&
523 PrintToScrollback("EM410x Tag ID: %s", id
);
530 /* Crap! Incorrect parity or no stop bit, start all over */
535 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
540 /* Step 1: get our header */
543 /* Need 9 consecutive 1's */
544 if (BitStream
[i
] == 1)
547 /* We don't have a header, not enough consecutive 1 bits */
553 /* if we've already retested after flipping bits, return */
557 /* if this didn't work, try flipping bits */
558 for (i
= 0; i
< bit2idx
; i
++)
564 /* emulate an EM410X tag
566 * 1111 1111 1 <-- standard non-repeatable header
567 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
569 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
570 * 0 <-- stop bit, end of tag
572 static void CmdEM410xsim(char *str
)
574 int i
, n
, j
, h
, binary
[4], parity
[4];
577 /* clock is 64 in EM410x tags */
580 /* clear our graph */
583 /* write it out a few times */
584 for (h
= 0; h
< 4; h
++)
586 /* write 9 start bits */
587 for (i
= 0; i
< 9; i
++)
588 CmdAppendGraph(0, clock
, 1);
590 /* for each hex char */
591 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
592 for (i
= 0; i
< 10; i
++)
594 /* read each hex char */
595 sscanf(&str
[i
], "%1x", &n
);
596 for (j
= 3; j
>= 0; j
--, n
/= 2)
599 /* append each bit */
600 CmdAppendGraph(0, clock
, binary
[0]);
601 CmdAppendGraph(0, clock
, binary
[1]);
602 CmdAppendGraph(0, clock
, binary
[2]);
603 CmdAppendGraph(0, clock
, binary
[3]);
605 /* append parity bit */
606 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
608 /* keep track of column parity */
609 parity
[0] ^= binary
[0];
610 parity
[1] ^= binary
[1];
611 parity
[2] ^= binary
[2];
612 parity
[3] ^= binary
[3];
616 CmdAppendGraph(0, clock
, parity
[0]);
617 CmdAppendGraph(0, clock
, parity
[1]);
618 CmdAppendGraph(0, clock
, parity
[2]);
619 CmdAppendGraph(0, clock
, parity
[3]);
622 CmdAppendGraph(0, clock
, 0);
625 /* modulate that biatch */
629 RepaintGraphWindow();
634 static void ChkBitstream(char *str
)
638 /* convert to bitstream if necessary */
639 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
641 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
649 static void CmdLosim(char *str
)
653 /* convert to bitstream if necessary */
656 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
659 for(j
= 0; j
< 48; j
++) {
660 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
662 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
664 SendCommand(&c
, FALSE
);
668 c
.cmd
= CMD_SIMULATE_TAG_125K
;
669 c
.ext1
= GraphTraceLen
;
670 SendCommand(&c
, FALSE
);
673 static void CmdLosimBidir(char *str
)
676 c
.cmd
= CMD_LF_SIMULATE_BIDIR
;
677 c
.ext1
= 47; /* Set ADC to twice the carrier for a slight supersampling */
679 SendCommand(&c
, FALSE
);
682 static void CmdLoread(char *str
)
685 // 'h' means higher-low-frequency, 134 kHz
688 } else if (*str
== '\0') {
691 PrintToScrollback("use 'loread' or 'loread h'");
694 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
695 SendCommand(&c
, FALSE
);
698 static void CmdDetectReader(char *str
)
701 // 'l' means LF - 125/134 kHz
704 } else if (*str
== 'h') {
706 } else if (*str
!= '\0') {
707 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");
710 c
.cmd
= CMD_LISTEN_READER_FIELD
;
711 SendCommand(&c
, FALSE
);
714 /* send a command before reading */
715 static void CmdLoCommandRead(char *str
)
717 static char dummy
[3];
722 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
723 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, (char *) &c
.d
.asBytes
,(char *) &dummy
+1);
724 // in case they specified 'h'
725 strcpy((char *)&c
.d
.asBytes
+ strlen((char *)c
.d
.asBytes
), dummy
);
726 SendCommand(&c
, FALSE
);
729 static void CmdLosamples(char *str
)
737 if (n
>16000) n
=16000;
739 for(i
= 0; i
< n
; i
+= 12) {
741 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
743 SendCommand(&c
, FALSE
);
745 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
747 PrintToScrollback("bad resp");
751 for(j
= 0; j
< 48; j
++) {
752 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
756 RepaintGraphWindow();
759 static void CmdBitsamples(char *str
)
766 for(i
= 0; i
< n
; i
+= 12) {
768 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
770 SendCommand(&c
, FALSE
);
772 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
773 PrintToScrollback("bad resp");
777 for(j
= 0; j
< 48; j
++) {
778 for(k
= 0; k
< 8; k
++) {
779 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
780 GraphBuffer
[cnt
++] = 1;
782 GraphBuffer
[cnt
++] = 0;
788 RepaintGraphWindow();
791 static void CmdHisamples(char *str
)
797 for(i
= 0; i
< n
; i
+= 12) {
799 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
801 SendCommand(&c
, FALSE
);
803 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
804 PrintToScrollback("bad resp");
808 for(j
= 0; j
< 48; j
++) {
809 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
814 RepaintGraphWindow();
817 static int CmdHisamplest(char *str
, int nrlow
)
829 for(i
= 0; i
< n
; i
+= 12) {
831 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
833 SendCommand(&c
, FALSE
);
835 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
836 PrintToScrollback("bad resp");
840 for(j
= 0; j
< 48; j
++) {
841 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
842 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
848 t1
= (t2
& 0x80) ^ (t2
& 0x20);
849 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
855 t2
= ((t2
<< 1) & 0x80);
861 t2
= ((t2
<< 1) & 0x20);
865 // both, but tag with other algorithm
866 t1
= (t2
& 0x80) ^ (t2
& 0x08);
867 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
871 GraphBuffer
[cnt
++] = t1
;
872 GraphBuffer
[cnt
++] = t2
;
877 if(hasbeennull
>nrlow
|| nrlow
==0) {
878 PrintToScrollback("hasbeennull=%d", hasbeennull
);
887 static void CmdHexsamples(char *str
)
898 for(i
= 0; i
< n
; i
+= 12) {
900 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
902 SendCommand(&c
, FALSE
);
904 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
905 PrintToScrollback("bad resp");
909 for(j
= 0; j
< 48; j
+= 8) {
910 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
925 static void CmdHisampless(char *str
)
937 for(i
= 0; i
< n
; i
+= 12) {
939 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
941 SendCommand(&c
, FALSE
);
943 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
944 PrintToScrollback("bad resp");
948 for(j
= 0; j
< 48; j
++) {
949 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
954 RepaintGraphWindow();
957 static WORD
Iso15693Crc(BYTE
*v
, int n
)
963 for(i
= 0; i
< n
; i
++) {
964 reg
= reg
^ ((DWORD
)v
[i
]);
965 for (j
= 0; j
< 8; j
++) {
967 reg
= (reg
>> 1) ^ 0x8408;
977 static void CmdHi14bdemod(char *str
)
982 BOOL negateI
, negateQ
;
987 // As received, the samples are pairs, correlations against I and Q
988 // square waves. So estimate angle of initial carrier (or just
989 // quadrant, actually), and then do the demod.
991 // First, estimate where the tag starts modulating.
992 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
993 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
997 if(i
>= GraphTraceLen
) {
998 PrintToScrollback("too weak to sync");
1001 PrintToScrollback("out of weak at %d", i
);
1004 // Now, estimate the phase in the initial modulation of the tag
1007 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
1008 isum
+= GraphBuffer
[i
+0];
1009 qsum
+= GraphBuffer
[i
+1];
1011 negateI
= (isum
< 0);
1012 negateQ
= (qsum
< 0);
1014 // Turn the correlation pairs into soft decisions on the bit.
1016 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
1017 int si
= GraphBuffer
[j
];
1018 int sq
= GraphBuffer
[j
+1];
1019 if(negateI
) si
= -si
;
1020 if(negateQ
) sq
= -sq
;
1021 GraphBuffer
[i
] = si
+ sq
;
1027 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
1029 if(i
>= GraphTraceLen
) goto demodError
;
1032 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
1034 if(i
>= GraphTraceLen
) goto demodError
;
1035 if((i
- iold
) > 23) goto demodError
;
1037 PrintToScrollback("make it to demod loop");
1041 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
1043 if(i
>= GraphTraceLen
) goto demodError
;
1044 if((i
- iold
) > 6) goto demodError
;
1047 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
1049 for(j
= 0; j
< 10; j
++) {
1050 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
1052 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
1053 PrintToScrollback("weak bit");
1057 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
1064 if( (shiftReg
& 0x200) &&
1065 !(shiftReg
& 0x001))
1067 // valid data byte, start and stop bits okay
1068 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
1069 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
1070 if(dataLen
>= sizeof(data
)) {
1073 } else if(shiftReg
== 0x000) {
1082 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
1083 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
1084 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
1085 "ok" : "****FAIL****");
1087 RepaintGraphWindow();
1091 PrintToScrollback("demod error");
1092 RepaintGraphWindow();
1095 static void CmdHi14list(char *str
)
1098 GetFromBigBuf(got
, sizeof(got
));
1100 PrintToScrollback("recorded activity:");
1101 PrintToScrollback(" time :rssi: who bytes");
1102 PrintToScrollback("---------+----+----+-----------");
1113 int timestamp
= *((DWORD
*)(got
+i
));
1114 if(timestamp
& 0x80000000) {
1115 timestamp
&= 0x7fffffff;
1120 int metric
= *((DWORD
*)(got
+i
+4));
1127 if(i
+ len
>= 900) {
1131 BYTE
*frame
= (got
+i
+9);
1133 char line
[1000] = "";
1135 for(j
= 0; j
< len
; j
++) {
1136 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
1142 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
1143 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1144 crc
= "**FAIL CRC**";
1152 char metricString
[100];
1154 sprintf(metricString
, "%3d", metric
);
1156 strcpy(metricString
, " ");
1159 PrintToScrollback(" +%7d: %s: %s %s %s",
1160 (prev
< 0 ? 0 : timestamp
- prev
),
1162 (isResponse
? "TAG" : " "), line
, crc
);
1169 static void CmdHi14alist(char *str
)
1172 GetFromBigBuf(got
, sizeof(got
));
1174 PrintToScrollback("recorded activity:");
1175 PrintToScrollback(" ETU :rssi: who bytes");
1176 PrintToScrollback("---------+----+----+-----------");
1187 int timestamp
= *((DWORD
*)(got
+i
));
1188 if(timestamp
& 0x80000000) {
1189 timestamp
&= 0x7fffffff;
1196 int parityBits
= *((DWORD
*)(got
+i
+4));
1197 // 4 bytes of additional information...
1198 // maximum of 32 additional parity bit information
1201 // at each quarter bit period we can send power level (16 levels)
1202 // or each half bit period in 256 levels.
1210 if(i
+ len
>= 1900) {
1214 BYTE
*frame
= (got
+i
+9);
1216 // Break and stick with current result if buffer was not completely full
1217 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1219 char line
[1000] = "";
1221 for(j
= 0; j
< len
; j
++) {
1222 int oddparity
= 0x01;
1226 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1229 //if((parityBits >> (len - j - 1)) & 0x01) {
1230 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1231 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1234 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1242 for(j
= 0; j
< (len
- 1); j
++) {
1243 // gives problems... search for the reason..
1244 /*if(frame[j] == 0xAA) {
1245 switch(frame[j+1]) {
1247 crc = "[1] Two drops close after each other";
1250 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1253 crc = "[3] Segment Z after segment X is not possible";
1256 crc = "[4] Parity bit of a fully received byte was wrong";
1259 crc = "[?] Unknown error";
1266 if(strlen(crc
)==0) {
1267 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1268 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1269 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1278 char metricString
[100];
1280 sprintf(metricString
, "%3d", metric
);
1282 strcpy(metricString
, " ");
1285 PrintToScrollback(" +%7d: %s: %s %s %s",
1286 (prev
< 0 ? 0 : (timestamp
- prev
)),
1288 (isResponse
? "TAG" : " "), line
, crc
);
1293 CommandFinished
= 1;
1296 static void CmdHi15demod(char *str
)
1298 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1301 // 1) Unmodulated time of 56.64us
1302 // 2) 24 pulses of 423.75khz
1303 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1305 static const int FrameSOF
[] = {
1306 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1307 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1308 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1309 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1315 static const int Logic0
[] = {
1321 static const int Logic1
[] = {
1329 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1330 // 2) 24 pulses of 423.75khz
1331 // 3) Unmodulated time of 56.64us
1333 static const int FrameEOF
[] = {
1338 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1339 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1340 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1341 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1345 int max
= 0, maxPos
;
1349 if(GraphTraceLen
< 1000) return;
1351 // First, correlate for SOF
1352 for(i
= 0; i
< 100; i
++) {
1354 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1355 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1362 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1363 max
/(arraylen(FrameSOF
)/skip
));
1365 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1368 memset(outBuf
, 0, sizeof(outBuf
));
1371 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1372 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1373 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1375 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1376 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1378 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1379 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1381 // Even things out by the length of the target waveform.
1385 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1386 PrintToScrollback("EOF at %d", i
);
1388 } else if(corr1
> corr0
) {
1389 i
+= arraylen(Logic1
)/skip
;
1392 i
+= arraylen(Logic0
)/skip
;
1399 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1400 PrintToScrollback("ran off end!");
1405 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1406 PrintToScrollback(" mask=%02x", mask
);
1408 PrintToScrollback("%d octets", k
);
1410 for(i
= 0; i
< k
; i
++) {
1411 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1413 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1416 static void CmdFSKdemod(char *cmdline
)
1418 static const int LowTone
[] = {
1419 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1420 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1421 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1422 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1423 1, 1, 1, 1, 1, -1, -1, -1, -1, -1
1425 static const int HighTone
[] = {
1426 1, 1, 1, 1, 1, -1, -1, -1, -1,
1427 1, 1, 1, 1, -1, -1, -1, -1,
1428 1, 1, 1, 1, -1, -1, -1, -1,
1429 1, 1, 1, 1, -1, -1, -1, -1,
1430 1, 1, 1, 1, -1, -1, -1, -1,
1431 1, 1, 1, 1, -1, -1, -1, -1, -1,
1434 int lowLen
= sizeof(LowTone
)/sizeof(int);
1435 int highLen
= sizeof(HighTone
)/sizeof(int);
1436 int convLen
= (highLen
>lowLen
)?highLen
:lowLen
;
1437 DWORD hi
= 0, lo
= 0;
1440 int minMark
=0, maxMark
=0;
1442 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1443 int lowSum
= 0, highSum
= 0;
1445 for(j
= 0; j
< lowLen
; j
++) {
1446 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1448 for(j
= 0; j
< highLen
; j
++) {
1449 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1451 lowSum
= abs((100*lowSum
) / lowLen
);
1452 highSum
= abs((100*highSum
) / highLen
);
1453 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1456 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1458 int lowTot
= 0, highTot
= 0;
1459 // 10 and 8 are f_s divided by f_l and f_h, rounded
1460 for(j
= 0; j
< 10; j
++) {
1461 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1463 for(j
= 0; j
< 8; j
++) {
1464 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1466 GraphBuffer
[i
] = lowTot
- highTot
;
1467 if (GraphBuffer
[i
]>maxMark
) maxMark
=GraphBuffer
[i
];
1468 if (GraphBuffer
[i
]<minMark
) minMark
=GraphBuffer
[i
];
1471 GraphTraceLen
-= (convLen
+ 16);
1473 RepaintGraphWindow();
1475 // Find bit-sync (3 lo followed by 3 high)
1476 int max
= 0, maxPos
= 0;
1477 for(i
= 0; i
< 6000; i
++) {
1479 for(j
= 0; j
< 3*lowLen
; j
++) {
1480 dec
-= GraphBuffer
[i
+j
];
1482 for(; j
< 3*(lowLen
+ highLen
); j
++) {
1483 dec
+= GraphBuffer
[i
+j
];
1491 // place start of bit sync marker in graph
1492 GraphBuffer
[maxPos
] = maxMark
;
1493 GraphBuffer
[maxPos
+1] = minMark
;
1497 // place end of bit sync marker in graph
1498 GraphBuffer
[maxPos
] = maxMark
;
1499 GraphBuffer
[maxPos
+1] = minMark
;
1501 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1502 PrintToScrollback("length %d/%d", highLen
, lowLen
);
1505 bits
[sizeof(bits
)-1] = '\0';
1507 // find bit pairs and manchester decode them
1508 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1510 for(j
= 0; j
< lowLen
; j
++) {
1511 dec
-= GraphBuffer
[maxPos
+j
];
1513 for(; j
< lowLen
+ highLen
; j
++) {
1514 dec
+= GraphBuffer
[maxPos
+j
];
1517 // place inter bit marker in graph
1518 GraphBuffer
[maxPos
] = maxMark
;
1519 GraphBuffer
[maxPos
+1] = minMark
;
1521 // hi and lo form a 64 bit pair
1522 hi
= (hi
<<1)|(lo
>>31);
1524 // store decoded bit as binary (in hi/lo) and text (in bits[])
1532 PrintToScrollback("bits: '%s'", bits
);
1533 PrintToScrollback("hex: %08x %08x", hi
, lo
);
1536 // read a TI tag and return its ID
1537 static void CmdTIRead(char *str
)
1540 c
.cmd
= CMD_READ_TI_TYPE
;
1541 SendCommand(&c
, FALSE
);
1544 // write new data to a r/w TI tag
1545 static void CmdTIWrite(char *str
)
1550 c
.cmd
= CMD_WRITE_TI_TYPE
;
1551 res
= sscanf(str
, "0x%x 0x%x 0x%x ", &c
.ext1
, &c
.ext2
, &c
.ext3
);
1552 if (res
== 2) c
.ext3
=0;
1554 PrintToScrollback("Please specify the data as two hex strings, optionally the CRC as a third");
1556 SendCommand(&c
, FALSE
);
1559 static void CmdTIDemod(char *cmdline
)
1561 /* MATLAB as follows:
1562 f_s = 2000000; % sampling frequency
1563 f_l = 123200; % low FSK tone
1564 f_h = 134200; % high FSK tone
1566 T_l = 119e-6; % low bit duration
1567 T_h = 130e-6; % high bit duration
1569 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1570 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1572 l = sign(sin(cumsum(l)));
1573 h = sign(sin(cumsum(h)));
1576 // 2M*16/134.2k = 238
1577 static const int LowTone
[] = {
1578 1, 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,
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, -1,
1583 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, -1, -1, -1, -1, -1, -1,
1586 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1587 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1588 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1589 1, 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, -1, -1,
1591 1, 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
1594 // 2M*16/123.2k = 260
1595 static const int HighTone
[] = {
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, -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,
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, -1,
1606 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1607 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1608 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1609 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1610 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1611 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1612 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1613 1, 1, 1, 1, 1, 1, 1, 1
1615 int lowLen
= sizeof(LowTone
)/sizeof(int);
1616 int highLen
= sizeof(HighTone
)/sizeof(int);
1617 int convLen
= (highLen
>lowLen
)?highLen
:lowLen
;
1620 int lowSum
= 0, highSum
= 0;;
1621 int lowTot
= 0, highTot
= 0;
1623 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1627 for(j
= 0; j
< lowLen
; j
++) {
1628 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1630 for(j
= 0; j
< highLen
; j
++) {
1631 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1633 lowSum
= abs((100*lowSum
) / lowLen
);
1634 highSum
= abs((100*highSum
) / highLen
);
1635 lowSum
= (lowSum
<0)?-lowSum
:lowSum
;
1636 highSum
= (highSum
<0)?-highSum
:highSum
;
1638 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1641 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1644 // 16 and 15 are f_s divided by f_l and f_h, rounded
1645 for(j
= 0; j
< 16; j
++) {
1646 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1648 for(j
= 0; j
< 15; j
++) {
1649 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1651 GraphBuffer
[i
] = lowTot
- highTot
;
1654 GraphTraceLen
-= (convLen
+ 16);
1656 RepaintGraphWindow();
1658 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,
1659 // 16 crc CCITT bits, 8 stop bits, 15 end bits
1661 // the 16 prebits are always low
1662 // the 8 start and stop bits of a tag must match
1663 // the start/stop prebits of a ro tag are 01111110
1664 // the start/stop prebits of a rw tag are 11111110
1665 // the 15 end bits of a ro tag are all low
1666 // the 15 end bits of a rw tag match bits 15-1 of the data bits
1668 // Okay, so now we have unsliced soft decisions;
1669 // find bit-sync, and then get some bits.
1670 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)
1671 int max
= 0, maxPos
= 0;
1672 for(i
= 0; i
< 6000; i
++) {
1675 // searching 17 consecutive lows
1676 for(j
= 0; j
< 17*lowLen
; j
++) {
1677 dec
-= GraphBuffer
[i
+j
];
1679 // searching 7 consecutive highs
1680 for(; j
< 17*lowLen
+ 6*highLen
; j
++) {
1681 dec
+= GraphBuffer
[i
+j
];
1689 // place a marker in the buffer to visually aid location
1690 // of the start of sync
1691 GraphBuffer
[maxPos
] = 800;
1692 GraphBuffer
[maxPos
+1] = -800;
1694 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)
1695 maxPos
+= 17*lowLen
;
1696 maxPos
+= 6*highLen
;
1698 // place a marker in the buffer to visually aid location
1699 // of the end of sync
1700 GraphBuffer
[maxPos
] = 800;
1701 GraphBuffer
[maxPos
+1] = -800;
1703 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1705 PrintToScrollback("length %d/%d", highLen
, lowLen
);
1707 BYTE bits
[1+64+16+8+16];
1708 bits
[sizeof(bits
)-1] = '\0';
1710 DWORD shift3
= 0x7e000000, shift2
= 0, shift1
= 0, shift0
= 0;
1712 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1716 for(j
= 0; j
< lowLen
; j
++) {
1717 low
-= GraphBuffer
[maxPos
+j
];
1719 for(j
= 0; j
< highLen
; j
++) {
1720 high
+= GraphBuffer
[maxPos
+j
];
1726 // bitstream arrives lsb first so shift right
1733 // 128 bit right shift register
1734 shift0
= (shift0
>>1) | (shift1
<< 31);
1735 shift1
= (shift1
>>1) | (shift2
<< 31);
1736 shift2
= (shift2
>>1) | (shift3
<< 31);
1739 // place a marker in the buffer between bits to visually aid location
1740 GraphBuffer
[maxPos
] = 800;
1741 GraphBuffer
[maxPos
+1] = -800;
1743 PrintToScrollback("Info: raw tag bits = %s", bits
);
1745 TagType
= (shift3
>>8)&0xff;
1746 if ( TagType
!= ((shift0
>>16)&0xff) ) {
1747 PrintToScrollback("Error: start and stop bits do not match!");
1750 else if (TagType
== 0x7e) {
1751 PrintToScrollback("Info: Readonly TI tag detected.");
1754 else if (TagType
== 0xfe) {
1755 PrintToScrollback("Info: Rewriteable TI tag detected.");
1757 // put 64 bit data into shift1 and shift0
1758 shift0
= (shift0
>>24) | (shift1
<< 8);
1759 shift1
= (shift1
>>24) | (shift2
<< 8);
1761 // align 16 bit crc into lower half of shift2
1762 shift2
= ((shift2
>>24) | (shift3
<< 8)) & 0x0ffff;
1764 // align 16 bit "end bits" or "ident" into lower half of shift3
1767 // only 15 bits compare, last bit of ident is not valid
1768 if ( (shift3
^shift0
)&0x7fff ) {
1769 PrintToScrollback("Error: Ident mismatch!");
1771 // WARNING the order of the bytes in which we calc crc below needs checking
1772 // i'm 99% sure the crc algorithm is correct, but it may need to eat the
1773 // bytes in reverse or something
1776 crc
= update_crc16(crc
, (shift0
)&0xff);
1777 crc
= update_crc16(crc
, (shift0
>>8)&0xff);
1778 crc
= update_crc16(crc
, (shift0
>>16)&0xff);
1779 crc
= update_crc16(crc
, (shift0
>>24)&0xff);
1780 crc
= update_crc16(crc
, (shift1
)&0xff);
1781 crc
= update_crc16(crc
, (shift1
>>8)&0xff);
1782 crc
= update_crc16(crc
, (shift1
>>16)&0xff);
1783 crc
= update_crc16(crc
, (shift1
>>24)&0xff);
1784 PrintToScrollback("Info: Tag data = %08X%08X", shift1
, shift0
);
1785 if (crc
!= (shift2
&0xffff)) {
1786 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc
, shift2
&0xffff);
1788 PrintToScrollback("Info: CRC %04X is good", crc
);
1792 PrintToScrollback("Unknown tag type.");
1797 static void CmdNorm(char *str
)
1800 int max
= INT_MIN
, min
= INT_MAX
;
1801 for(i
= 10; i
< GraphTraceLen
; i
++) {
1802 if(GraphBuffer
[i
] > max
) {
1803 max
= GraphBuffer
[i
];
1805 if(GraphBuffer
[i
] < min
) {
1806 min
= GraphBuffer
[i
];
1810 for(i
= 0; i
< GraphTraceLen
; i
++) {
1811 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1815 RepaintGraphWindow();
1818 static void CmdAmp(char *str
)
1820 int i
, rising
, falling
;
1821 int max
= INT_MIN
, min
= INT_MAX
;
1822 for(i
= 10; i
< GraphTraceLen
; i
++) {
1823 if(GraphBuffer
[i
] > max
) {
1824 max
= GraphBuffer
[i
];
1826 if(GraphBuffer
[i
] < min
) {
1827 min
= GraphBuffer
[i
];
1832 for(i
= 0; i
< GraphTraceLen
; i
++) {
1833 if(GraphBuffer
[i
+1] < GraphBuffer
[i
]) {
1835 GraphBuffer
[i
]= max
;
1840 if(GraphBuffer
[i
+1] > GraphBuffer
[i
]) {
1842 GraphBuffer
[i
]= min
;
1849 RepaintGraphWindow();
1852 static void CmdDec(char *str
)
1855 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1856 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1859 PrintToScrollback("decimated by 2");
1860 RepaintGraphWindow();
1863 static void CmdHpf(char *str
)
1867 for(i
= 10; i
< GraphTraceLen
; i
++) {
1868 accum
+= GraphBuffer
[i
];
1870 accum
/= (GraphTraceLen
- 10);
1871 for(i
= 0; i
< GraphTraceLen
; i
++) {
1872 GraphBuffer
[i
] -= accum
;
1875 RepaintGraphWindow();
1878 static void CmdZerocrossings(char *str
)
1881 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1887 for(i
= 0; i
< GraphTraceLen
; i
++) {
1888 if(GraphBuffer
[i
]*sign
>= 0) {
1889 // No change in sign, reproduce the previous sample count.
1891 GraphBuffer
[i
] = lastZc
;
1893 // Change in sign, reset the sample count.
1895 GraphBuffer
[i
] = lastZc
;
1903 RepaintGraphWindow();
1906 static void CmdThreshold(char *str
)
1909 int threshold
= atoi(str
);
1911 for(i
= 0; i
< GraphTraceLen
; i
++) {
1912 if(GraphBuffer
[i
]>= threshold
)
1917 RepaintGraphWindow();
1920 static void CmdLtrim(char *str
)
1925 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1926 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1928 GraphTraceLen
-= ds
;
1930 RepaintGraphWindow();
1933 static void CmdAutoCorr(char *str
)
1935 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1937 int window
= atoi(str
);
1940 PrintToScrollback("needs a window");
1944 if(window
>= GraphTraceLen
) {
1945 PrintToScrollback("window must be smaller than trace (%d samples)",
1950 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1953 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1956 for(j
= 0; j
< window
; j
++) {
1957 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1959 CorrelBuffer
[i
] = sum
;
1961 GraphTraceLen
= GraphTraceLen
- window
;
1962 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1964 RepaintGraphWindow();
1967 static void CmdVchdemod(char *str
)
1969 // Is this the entire sync pattern, or does this also include some
1970 // data bits that happen to be the same everywhere? That would be
1972 static const int SyncPattern
[] = {
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,
1976 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1977 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1978 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1979 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1980 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1981 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1982 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1985 // So first, we correlate for the sync pattern, and mark that.
1986 int bestCorrel
= 0, bestPos
= 0;
1988 // It does us no good to find the sync pattern, with fewer than
1989 // 2048 samples after it...
1990 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1993 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1994 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1996 if(sum
> bestCorrel
) {
2001 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
2006 int worst
= INT_MAX
;
2009 for(i
= 0; i
< 2048; i
+= 8) {
2012 for(j
= 0; j
< 8; j
++) {
2013 sum
+= GraphBuffer
[bestPos
+i
+j
];
2020 if(abs(sum
) < worst
) {
2025 PrintToScrollback("bits:");
2026 PrintToScrollback("%s", bits
);
2027 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
2029 if(strcmp(str
, "clone")==0) {
2032 for(s
= bits
; *s
; s
++) {
2034 for(j
= 0; j
< 16; j
++) {
2035 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
2038 RepaintGraphWindow();
2042 static void CmdIndalademod(char *str
)
2044 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
2049 // worst case with GraphTraceLen=64000 is < 4096
2050 // under normal conditions it's < 2048
2053 int worst
= 0, worstPos
= 0;
2054 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
2055 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
2057 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
2059 for(j
= 0; j
< count
- 8; j
+= 16) {
2060 rawbits
[rawbit
++] = 0;
2062 if ((abs(count
- j
)) > worst
) {
2063 worst
= abs(count
- j
);
2069 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
2071 for(j
= 0; j
< count
- 8; j
+= 16) {
2072 rawbits
[rawbit
++] = 1;
2074 if ((abs(count
- j
)) > worst
) {
2075 worst
= abs(count
- j
);
2083 PrintToScrollback("Recovered %d raw bits", rawbit
);
2084 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
2086 // Finding the start of a UID
2087 int uidlen
, long_wait
;
2088 if(strcmp(str
, "224") == 0) {
2097 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
2098 first
= rawbits
[start
];
2099 for(i
= start
; i
< start
+ long_wait
; i
++) {
2100 if(rawbits
[i
] != first
) {
2104 if(i
== (start
+ long_wait
)) {
2108 if(start
== rawbit
- uidlen
+ 1) {
2109 PrintToScrollback("nothing to wait for");
2113 // Inverting signal if needed
2115 for(i
= start
; i
< rawbit
; i
++) {
2116 rawbits
[i
] = !rawbits
[i
];
2123 showbits
[uidlen
]='\0';
2127 if(uidlen
> rawbit
) {
2128 PrintToScrollback("Warning: not enough raw bits to get a full UID");
2129 for(bit
= 0; bit
< rawbit
; bit
++) {
2130 bits
[bit
] = rawbits
[i
++];
2131 // As we cannot know the parity, let's use "." and "/"
2132 showbits
[bit
] = '.' + bits
[bit
];
2134 showbits
[bit
+1]='\0';
2135 PrintToScrollback("Partial UID=%s", showbits
);
2138 for(bit
= 0; bit
< uidlen
; bit
++) {
2139 bits
[bit
] = rawbits
[i
++];
2140 showbits
[bit
] = '0' + bits
[bit
];
2144 PrintToScrollback("UID=%s", showbits
);
2146 // Checking UID against next occurences
2147 for(; i
+ uidlen
<= rawbit
;) {
2149 for(bit
= 0; bit
< uidlen
; bit
++) {
2150 if(bits
[bit
] != rawbits
[i
++]) {
2160 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
2162 // Remodulating for tag cloning
2163 GraphTraceLen
= 32*uidlen
;
2166 for(bit
= 0; bit
< uidlen
; bit
++) {
2167 if(bits
[bit
] == 0) {
2173 for(j
= 0; j
< 32; j
++) {
2174 GraphBuffer
[i
++] = phase
;
2179 RepaintGraphWindow();
2182 static void CmdFlexdemod(char *str
)
2185 for(i
= 0; i
< GraphTraceLen
; i
++) {
2186 if(GraphBuffer
[i
] < 0) {
2187 GraphBuffer
[i
] = -1;
2193 #define LONG_WAIT 100
2195 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
2196 int first
= GraphBuffer
[start
];
2197 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
2198 if(GraphBuffer
[i
] != first
) {
2202 if(i
== (start
+ LONG_WAIT
)) {
2206 if(start
== GraphTraceLen
- LONG_WAIT
) {
2207 PrintToScrollback("nothing to wait for");
2211 GraphBuffer
[start
] = 2;
2212 GraphBuffer
[start
+1] = -2;
2218 for(bit
= 0; bit
< 64; bit
++) {
2221 for(j
= 0; j
< 16; j
++) {
2222 sum
+= GraphBuffer
[i
++];
2229 PrintToScrollback("bit %d sum %d", bit
, sum
);
2232 for(bit
= 0; bit
< 64; bit
++) {
2235 for(j
= 0; j
< 16; j
++) {
2236 sum
+= GraphBuffer
[i
++];
2238 if(sum
> 0 && bits
[bit
] != 1) {
2239 PrintToScrollback("oops1 at %d", bit
);
2241 if(sum
< 0 && bits
[bit
] != 0) {
2242 PrintToScrollback("oops2 at %d", bit
);
2246 GraphTraceLen
= 32*64;
2249 for(bit
= 0; bit
< 64; bit
++) {
2250 if(bits
[bit
] == 0) {
2256 for(j
= 0; j
< 32; j
++) {
2257 GraphBuffer
[i
++] = phase
;
2262 RepaintGraphWindow();
2266 * Generic command to demodulate ASK.
2268 * Argument is convention: positive or negative (High mod means zero
2269 * or high mod means one)
2271 * Updates the Graph trace with 0/1 values
2277 static void Cmdaskdemod(char *str
) {
2279 int c
, high
= 0, low
= 0;
2281 // TODO: complain if we do not give 2 arguments here !
2282 // (AL - this doesn't make sense! we're only using one argument!!!)
2283 sscanf(str
, "%i", &c
);
2285 /* Detect high and lows and clock */
2287 for (i
= 0; i
< GraphTraceLen
; i
++)
2289 if (GraphBuffer
[i
] > high
)
2290 high
= GraphBuffer
[i
];
2291 else if (GraphBuffer
[i
] < low
)
2292 low
= GraphBuffer
[i
];
2294 if(c
!= 0 && c
!= 1) {
2295 PrintToScrollback("Invalid argument: %s",str
);
2299 if (GraphBuffer
[0] > 0) {
2300 GraphBuffer
[0] = 1-c
;
2304 for(i
=1;i
<GraphTraceLen
;i
++) {
2305 /* Transitions are detected at each peak
2306 * Transitions are either:
2307 * - we're low: transition if we hit a high
2308 * - we're high: transition if we hit a low
2309 * (we need to do it this way because some tags keep high or
2310 * low for long periods, others just reach the peak and go
2313 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
2315 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
2319 GraphBuffer
[i
] = GraphBuffer
[i
-1];
2322 RepaintGraphWindow();
2325 /* Print our clock rate */
2326 static void Cmddetectclockrate(char *str
)
2328 int clock
= detectclock(0);
2329 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2335 int detectclock(int peak
)
2341 /* Detect peak if we don't have one */
2343 for (i
= 0; i
< GraphTraceLen
; i
++)
2344 if (GraphBuffer
[i
] > peak
)
2345 peak
= GraphBuffer
[i
];
2347 for (i
= 1; i
< GraphTraceLen
; i
++)
2349 /* If this is the beginning of a peak */
2350 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
2352 /* Find lowest difference between peaks */
2353 if (lastpeak
&& i
- lastpeak
< clock
)
2355 clock
= i
- lastpeak
;
2364 /* Get or auto-detect clock rate */
2365 int GetClock(char *str
, int peak
)
2369 sscanf(str
, "%i", &clock
);
2370 if (!strcmp(str
, ""))
2373 /* Auto-detect clock */
2376 clock
= detectclock(peak
);
2378 /* Only print this message if we're not looping something */
2380 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2387 * Convert to a bitstream
2389 static void Cmdbitstream(char *str
) {
2396 int hithigh
, hitlow
, first
;
2398 /* Detect high and lows and clock */
2399 for (i
= 0; i
< GraphTraceLen
; i
++)
2401 if (GraphBuffer
[i
] > high
)
2402 high
= GraphBuffer
[i
];
2403 else if (GraphBuffer
[i
] < low
)
2404 low
= GraphBuffer
[i
];
2408 clock
= GetClock(str
, high
);
2410 gtl
= CmdClearGraph(0);
2413 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2419 /* Find out if we hit both high and low peaks */
2420 for (j
= 0; j
< clock
; j
++)
2422 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2424 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2427 /* it doesn't count if it's the first part of our read
2428 because it's really just trailing from the last sequence */
2429 if (first
&& (hithigh
|| hitlow
))
2430 hithigh
= hitlow
= 0;
2434 if (hithigh
&& hitlow
)
2438 /* If we didn't hit both high and low peaks, we had a bit transition */
2439 if (!hithigh
|| !hitlow
)
2442 CmdAppendGraph(0, clock
, bit
);
2443 // for (j = 0; j < (int)(clock/2); j++)
2444 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2445 // for (j = (int)(clock/2); j < clock; j++)
2446 // GraphBuffer[(i * clock) + j] = bit;
2449 RepaintGraphWindow();
2452 /* Modulate our data into manchester */
2453 static void Cmdmanchestermod(char *str
)
2457 int bit
, lastbit
, wave
;
2460 clock
= GetClock(str
, 0);
2464 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2466 bit
= GraphBuffer
[i
* clock
] ^ 1;
2468 for (j
= 0; j
< (int)(clock
/2); j
++)
2469 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2470 for (j
= (int)(clock
/2); j
< clock
; j
++)
2471 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2473 /* Keep track of how we start our wave and if we changed or not this time */
2474 wave
^= bit
^ lastbit
;
2478 RepaintGraphWindow();
2482 * Manchester demodulate a bitstream. The bitstream needs to be already in
2483 * the GraphBuffer as 0 and 1 values
2485 * Give the clock rate as argument in order to help the sync - the algorithm
2486 * resyncs at each pulse anyway.
2488 * Not optimized by any means, this is the 1st time I'm writing this type of
2489 * routine, feel free to improve...
2491 * 1st argument: clock rate (as number of samples per clock rate)
2492 * Typical values can be 64, 32, 128...
2494 static void Cmdmanchesterdemod(char *str
) {
2495 int i
, j
, invert
= 0;
2501 int hithigh
, hitlow
, first
;
2507 /* check if we're inverting output */
2510 PrintToScrollback("Inverting output");
2514 while(*str
== ' '); // in case a 2nd argument was given
2517 /* Holds the decoded bitstream: each clock period contains 2 bits */
2518 /* later simplified to 1 bit after manchester decoding. */
2519 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2520 /* int BitStream[GraphTraceLen*2/clock+10]; */
2522 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2524 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2526 /* Detect high and lows */
2527 for (i
= 0; i
< GraphTraceLen
; i
++)
2529 if (GraphBuffer
[i
] > high
)
2530 high
= GraphBuffer
[i
];
2531 else if (GraphBuffer
[i
] < low
)
2532 low
= GraphBuffer
[i
];
2536 clock
= GetClock(str
, high
);
2538 int tolerance
= clock
/4;
2540 /* Detect first transition */
2541 /* Lo-Hi (arbitrary) */
2542 /* skip to the first high */
2543 for (i
= 0; i
< GraphTraceLen
; i
++)
2544 if(GraphBuffer
[i
] == high
)
2546 /* now look for the first low */
2547 for (; i
< GraphTraceLen
; i
++)
2549 if (GraphBuffer
[i
] == low
)
2556 /* If we're not working with 1/0s, demod based off clock */
2559 bit
= 0; /* We assume the 1st bit is zero, it may not be
2560 * the case: this routine (I think) has an init problem.
2563 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2569 /* Find out if we hit both high and low peaks */
2570 for (j
= 0; j
< clock
; j
++)
2572 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2574 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2577 /* it doesn't count if it's the first part of our read
2578 because it's really just trailing from the last sequence */
2579 if (first
&& (hithigh
|| hitlow
))
2580 hithigh
= hitlow
= 0;
2584 if (hithigh
&& hitlow
)
2588 /* If we didn't hit both high and low peaks, we had a bit transition */
2589 if (!hithigh
|| !hitlow
)
2592 BitStream
[bit2idx
++] = bit
^ invert
;
2596 /* standard 1/0 bitstream */
2600 /* Then detect duration between 2 successive transitions */
2601 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2603 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2608 // Error check: if bitidx becomes too large, we do not
2609 // have a Manchester encoded bitstream or the clock is really
2611 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2612 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2615 // Then switch depending on lc length:
2616 // Tolerance is 1/4 of clock rate (arbitrary)
2617 if (abs(lc
-clock
/2) < tolerance
) {
2618 // Short pulse : either "1" or "0"
2619 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2620 } else if (abs(lc
-clock
) < tolerance
) {
2621 // Long pulse: either "11" or "00"
2622 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2623 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2627 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2628 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2632 PrintToScrollback("Error: too many detection errors, aborting.");
2639 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2640 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2641 // to stop output at the final bitidx2 value, not bitidx
2642 for (i
= 0; i
< bitidx
; i
+= 2) {
2643 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2644 BitStream
[bit2idx
++] = 1 ^ invert
;
2645 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2646 BitStream
[bit2idx
++] = 0 ^ invert
;
2648 // We cannot end up in this state, this means we are unsynchronized,
2652 PrintToScrollback("Unsynchronized, resync...");
2653 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2657 PrintToScrollback("Error: too many decode errors, aborting.");
2664 PrintToScrollback("Manchester decoded bitstream");
2665 // Now output the bitstream to the scrollback by line of 16 bits
2666 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2667 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2690 static void CmdHiddemod(char *str
)
2692 if(GraphTraceLen
< 4800) {
2693 PrintToScrollback("too short; need at least 4800 samples");
2697 GraphTraceLen
= 4800;
2699 for(i
= 0; i
< GraphTraceLen
; i
++) {
2700 if(GraphBuffer
[i
] < 0) {
2706 RepaintGraphWindow();
2709 static void CmdPlot(char *str
)
2714 static void CmdGrid(char *str
)
2716 sscanf(str
, "%i %i", &PlotGridX
, &PlotGridY
);
2717 RepaintGraphWindow();
2720 static void CmdHide(char *str
)
2725 static void CmdScale(char *str
)
2727 CursorScaleFactor
= atoi(str
);
2728 if(CursorScaleFactor
== 0) {
2729 PrintToScrollback("bad, can't have zero scale");
2730 CursorScaleFactor
= 1;
2732 RepaintGraphWindow();
2735 static void CmdSave(char *str
)
2737 FILE *f
= fopen(str
, "w");
2739 PrintToScrollback("couldn't open '%s'", str
);
2743 for(i
= 0; i
< GraphTraceLen
; i
++) {
2744 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2747 PrintToScrollback("saved to '%s'", str
);
2750 static void CmdLoad(char *str
)
2752 FILE *f
= fopen(str
, "r");
2754 PrintToScrollback("couldn't open '%s'", str
);
2760 while(fgets(line
, sizeof(line
), f
)) {
2761 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2765 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2766 RepaintGraphWindow();
2769 static void CmdHIDsimTAG(char *str
)
2771 unsigned int hi
=0, lo
=0;
2775 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2776 hi
=(hi
<<4)|(lo
>>28);
2780 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2782 c
.cmd
= CMD_HID_SIM_TAG
;
2785 SendCommand(&c
, FALSE
);
2788 static void CmdReadmem(char *str
)
2791 c
.cmd
= CMD_READ_MEM
;
2793 SendCommand(&c
, FALSE
);
2796 static void CmdVersion(char *str
)
2799 c
.cmd
= CMD_VERSION
;
2800 SendCommand(&c
, FALSE
);
2803 static void CmdLcdReset(char *str
)
2806 c
.cmd
= CMD_LCD_RESET
;
2808 SendCommand(&c
, FALSE
);
2811 static void CmdLcd(char *str
)
2816 sscanf(str
, "%x %d", &i
, &j
);
2819 SendCommand(&c
, FALSE
);
2824 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2827 static void CmdSetDivisor(char *str
)
2830 c
.cmd
= CMD_SET_LF_DIVISOR
;
2832 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2833 PrintToScrollback("divisor must be between 19 and 255");
2835 SendCommand(&c
, FALSE
);
2836 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2840 static void CmdSetMux(char *str
)
2843 c
.cmd
= CMD_SET_ADC_MUX
;
2844 if(strcmp(str
, "lopkd") == 0) {
2846 } else if(strcmp(str
, "loraw") == 0) {
2848 } else if(strcmp(str
, "hipkd") == 0) {
2850 } else if(strcmp(str
, "hiraw") == 0) {
2853 SendCommand(&c
, FALSE
);
2856 typedef void HandlerFunction(char *cmdline
);
2858 /* in alphabetic order */
2861 HandlerFunction
*handler
;
2862 int offline
; // 1 if the command can be used when in offline mode
2864 } CommandTable
[] = {
2865 {"amp", CmdAmp
, 1, "Amplify peaks"},
2866 {"askdemod", Cmdaskdemod
, 1, "<0|1> -- Attempt to demodulate simple ASK tags"},
2867 {"autocorr", CmdAutoCorr
, 1, "<window length> -- Autocorrelation over window"},
2868 {"bitsamples", CmdBitsamples
, 0, "Get raw samples as bitstring"},
2869 {"bitstream", Cmdbitstream
, 1, "[clock rate] -- Convert waveform into a bitstream"},
2870 {"buffclear", CmdBuffClear
, 1, "Clear sample buffer and graph window"},
2871 {"dec", CmdDec
, 1, "Decimate samples"},
2872 {"detectclock", Cmddetectclockrate
, 1, "Detect clock rate"},
2873 {"detectreader", CmdDetectReader
, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
2874 {"em410xsim", CmdEM410xsim
, 1, "<UID> -- Simulate EM410x tag"},
2875 {"em410xread", CmdEM410xread
, 1, "[clock rate] -- Extract ID from EM410x tag"},
2876 {"em410xwatch", CmdEM410xwatch
, 0, "Watches for EM410x tags"},
2877 {"em4x50read", CmdEM4x50read
, 1, "Extract data from EM4x50 tag"},
2878 {"exit", CmdQuit
, 1, "Exit program"},
2879 {"flexdemod", CmdFlexdemod
, 1, "Demodulate samples for FlexPass"},
2880 {"fpgaoff", CmdFPGAOff
, 0, "Set FPGA off"},
2881 {"fskdemod", CmdFSKdemod
, 1, "Demodulate graph window as a HID FSK"},
2882 {"grid", CmdGrid
, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
2883 {"hexsamples", CmdHexsamples
, 0, "<blocks> -- Dump big buffer as hex bytes"},
2884 {"hi14alist", CmdHi14alist
, 0, "List ISO 14443a history"},
2885 {"hi14areader", CmdHi14areader
, 0, "Act like an ISO14443 Type A reader"},
2886 {"hi14asim", CmdHi14asim
, 0, "<UID> -- Fake ISO 14443a tag"},
2887 {"hi14asnoop", CmdHi14asnoop
, 0, "Eavesdrop ISO 14443 Type A"},
2888 {"hi14bdemod", CmdHi14bdemod
, 1, "Demodulate ISO14443 Type B from tag"},
2889 {"hi14list", CmdHi14list
, 0, "List ISO 14443 history"},
2890 {"hi14read", CmdHi14read
, 0, "Read HF tag (ISO 14443)"},
2891 {"hi14sim", CmdHi14sim
, 0, "Fake ISO 14443 tag"},
2892 {"hi14snoop", CmdHi14snoop
, 0, "Eavesdrop ISO 14443"},
2893 {"hi15demod", CmdHi15demod
, 1, "Demodulate ISO15693 from tag"},
2894 {"hi15read", CmdHi15read
, 0, "Read HF tag (ISO 15693)"},
2895 {"hi15reader", CmdHi15reader
, 0, "Act like an ISO15693 reader"},
2896 {"hi15sim", CmdHi15tag
, 0, "Fake an ISO15693 tag"},
2897 {"hiddemod", CmdHiddemod
, 1, "Demodulate HID Prox Card II (not optimal)"},
2898 {"hide", CmdHide
, 1, "Hide graph window"},
2899 {"hidfskdemod", CmdHIDdemodFSK
, 0, "Realtime HID FSK demodulator"},
2900 {"hidsimtag", CmdHIDsimTAG
, 0, "<ID> -- HID tag simulator"},
2901 {"higet", CmdHi14read_sim
, 0, "<samples> -- Get samples HF, 'analog'"},
2902 {"hisamples", CmdHisamples
, 0, "Get raw samples for HF tag"},
2903 {"hisampless", CmdHisampless
, 0, "<samples> -- Get signed raw samples, HF tag"},
2904 {"hisamplest", CmdHi14readt
, 0, "Get samples HF, for testing"},
2905 {"hisimlisten", CmdHisimlisten
, 0, "Get HF samples as fake tag"},
2906 {"hpf", CmdHpf
, 1, "Remove DC offset from trace"},
2907 {"indalademod", CmdIndalademod
, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
2908 {"lcd", CmdLcd
, 0, "<HEX command> <count> -- Send command/data to LCD"},
2909 {"lcdreset", CmdLcdReset
, 0, "Hardware reset LCD"},
2910 {"legicrfsim", CmdLegicRfSim
, 0, "Start the LEGIC RF tag simulator"},
2911 {"load", CmdLoad
, 1, "<filename> -- Load trace (to graph window"},
2912 {"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)"},
2913 {"loread", CmdLoread
, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
2914 {"losamples", CmdLosamples
, 0, "[128 - 16000] -- Get raw samples for LF tag"},
2915 {"losim", CmdLosim
, 0, "Simulate LF tag"},
2916 {"losimbidir", CmdLosimBidir
, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
2917 {"ltrim", CmdLtrim
, 1, "<samples> -- Trim samples from left of trace"},
2918 {"mandemod", Cmdmanchesterdemod
, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
2919 {"manmod", Cmdmanchestermod
, 1, "[clock rate] -- Manchester modulate a binary stream"},
2920 {"norm", CmdNorm
, 1, "Normalize max/min to +/-500"},
2921 {"plot", CmdPlot
, 1, "Show graph window"},
2922 {"quit", CmdQuit
, 1, "Quit program"},
2923 {"readmem", CmdReadmem
, 0, "[address] -- Read memory at decimal address from flash"},
2924 {"reset", CmdReset
, 0, "Reset the Proxmark3"},
2925 {"save", CmdSave
, 1, "<filename> -- Save trace (from graph window)"},
2926 {"scale", CmdScale
, 1, "<int> -- Set cursor display scale"},
2927 {"setlfdivisor", CmdSetDivisor
, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
2928 {"setmux", CmdSetMux
, 0, "<loraw|hiraw|lopkd|hipkd> -- Set the ADC mux to a specific value"},
2929 {"sri512read", CmdSri512read
, 0, "<int> -- Read contents of a SRI512 tag"},
2930 {"tidemod", CmdTIDemod
, 1, "Demodulate raw bits for TI-type LF tag"},
2931 {"tiread", CmdTIRead
, 0, "Read and decode a TI 134 kHz tag"},
2932 {"tiwrite", CmdTIWrite
, 0, "Write new data to a r/w TI 134 kHz tag"},
2933 {"threshold", CmdThreshold
, 1, "Maximize/minimize every value in the graph window depending on threshold"},
2934 {"tune", CmdTune
, 0, "Measure antenna tuning"},
2935 {"vchdemod", CmdVchdemod
, 0, "['clone'] -- Demodulate samples for VeriChip"},
2936 {"version", CmdVersion
, 0, "Show version inforation about the connected Proxmark"},
2937 {"zerocrossings", CmdZerocrossings
, 1, "Count time between zero-crossings"},
2945 } CommandExtendedHelp
[]= {
2946 {"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."},
2947 {"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."},
2950 //-----------------------------------------------------------------------------
2951 // Entry point into our code: called whenever the user types a command and
2952 // then presses Enter, which the full command line that they typed.
2953 //-----------------------------------------------------------------------------
2954 void CommandReceived(char *cmd
)
2959 PrintToScrollback("> %s", cmd
);
2961 if(strcmp(cmd
, "help") == 0 || strncmp(cmd
,"help ",strlen("help ")) == 0) {
2962 // check if we're doing extended help
2963 if(strlen(cmd
) > strlen("help ")) {
2964 cmd
+= strlen("help ");
2965 for(i
= 0; i
< sizeof(CommandExtendedHelp
) / sizeof(CommandExtendedHelp
[0]); i
++) {
2966 if(strcmp(CommandExtendedHelp
[i
].name
,cmd
) == 0) {
2967 PrintToScrollback("\nExtended help for '%s':\n", cmd
);
2968 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp
[i
].args
,CommandExtendedHelp
[i
].argshelp
);
2969 PrintToScrollback(CommandExtendedHelp
[i
].description
);
2970 PrintToScrollback("");
2974 PrintToScrollback("No extended help available for '%s'", cmd
);
2977 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2978 PrintToScrollback("\r\nAvailable commands:");
2979 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2980 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2981 memset(line
, ' ', sizeof(line
));
2982 strcpy(line
+2, CommandTable
[i
].name
);
2983 line
[strlen(line
)] = ' ';
2984 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2985 PrintToScrollback("%s", line
);
2987 PrintToScrollback("");
2988 PrintToScrollback("'help <command>' for extended help on that command\n");
2992 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2993 char *name
= CommandTable
[i
].name
;
2994 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2995 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2997 cmd
+= strlen(name
);
2998 while(*cmd
== ' ') {
3001 if (offline
&& (CommandTable
[i
].offline
==0)) {
3002 PrintToScrollback("Offline mode, cannot use this command.");
3005 (CommandTable
[i
].handler
)(cmd
);
3009 PrintToScrollback(">> bad command '%s'", cmd
);
3012 //-----------------------------------------------------------------------------
3013 // Entry point into our code: called whenever we received a packet over USB
3014 // that we weren't necessarily expecting, for example a debug print.
3015 //-----------------------------------------------------------------------------
3016 void UsbCommandReceived(UsbCommand
*c
)
3019 case CMD_DEBUG_PRINT_STRING
: {
3021 if(c
->ext1
> 70 || c
->ext1
< 0) {
3024 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
3026 PrintToScrollback("#db# %s", s
);
3030 case CMD_DEBUG_PRINT_INTEGERS
:
3031 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
3034 case CMD_MEASURED_ANTENNA_TUNING
: {
3036 int vLf125
, vLf134
, vHf
;
3037 vLf125
= c
->ext1
& 0xffff;
3038 vLf134
= c
->ext1
>> 16;
3039 vHf
= c
->ext2
& 0xffff;;
3040 peakf
= c
->ext3
& 0xffff;
3041 peakv
= c
->ext3
>> 16;
3042 PrintToScrollback("");
3043 PrintToScrollback("");
3044 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125
/1000.0);
3045 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134
/1000.0);
3046 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv
/1000.0, 12000.0/(peakf
+1));
3047 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf
/1000.0);
3049 PrintToScrollback("# Your LF antenna is unusable.");
3050 else if (peakv
<10000)
3051 PrintToScrollback("# Your LF antenna is marginal.");
3053 PrintToScrollback("# Your HF antenna is unusable.");
3055 PrintToScrollback("# Your HF antenna is marginal.");
3059 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);