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
)
307 while(GraphBuffer
[i
] < high
)
309 while(GraphBuffer
[i
] > low
)
311 tmpbuff
[j
++]= i
- start
;
315 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
318 for (i
= 0; i
< j
- 4 ; ++i
)
321 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
322 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
323 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
324 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
332 /* skip over the remainder of the LW */
333 skip
+= tmpbuff
[i
+1]+tmpbuff
[i
+2];
334 while(GraphBuffer
[skip
] > low
)
338 /* now do it again to find the end */
340 for (i
+= 3; i
< j
- 4 ; ++i
)
343 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
344 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
345 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
346 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
354 PrintToScrollback("Found data at sample: %i",skip
);
357 PrintToScrollback("No data found!");
358 PrintToScrollback("Try again with more samples.");
364 PrintToScrollback("*** Warning!");
365 PrintToScrollback("Partial data - no end found!");
366 PrintToScrollback("Try again with more samples.");
369 /* get rid of leading crap */
370 sprintf(tmp
,"%i",skip
);
373 /* now work through remaining buffer printing out data blocks */
378 PrintToScrollback("Block %i:", block
);
379 // mandemod routine needs to be split so we can call it for data
380 // just print for now for debugging
381 Cmdmanchesterdemod("i 64");
383 /* look for LW before start of next block */
384 for ( ; i
< j
- 4 ; ++i
)
387 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
388 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
391 while(GraphBuffer
[skip
] > low
)
394 sprintf(tmp
,"%i",skip
);
402 /* Read the ID of an EM410x tag.
404 * 1111 1111 1 <-- standard non-repeatable header
405 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
407 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
408 * 0 <-- stop bit, end of tag
410 static void CmdEM410xread(char *str
)
412 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
416 int BitStream
[MAX_GRAPH_TRACE_LEN
];
419 /* Detect high and lows and clock */
420 for (i
= 0; i
< GraphTraceLen
; i
++)
422 if (GraphBuffer
[i
] > high
)
423 high
= GraphBuffer
[i
];
424 else if (GraphBuffer
[i
] < low
)
425 low
= GraphBuffer
[i
];
429 clock
= GetClock(str
, high
);
431 /* parity for our 4 columns */
432 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
435 /* manchester demodulate */
437 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
443 /* Find out if we hit both high and low peaks */
444 for (j
= 0; j
< clock
; j
++)
446 if (GraphBuffer
[(i
* clock
) + j
] == high
)
448 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
451 /* it doesn't count if it's the first part of our read
452 because it's really just trailing from the last sequence */
453 if (first
&& (hithigh
|| hitlow
))
454 hithigh
= hitlow
= 0;
458 if (hithigh
&& hitlow
)
462 /* If we didn't hit both high and low peaks, we had a bit transition */
463 if (!hithigh
|| !hitlow
)
466 BitStream
[bit2idx
++] = bit
;
470 /* We go till 5 before the graph ends because we'll get that far below */
471 for (i
= 1; i
< bit2idx
- 5; i
++)
473 /* Step 2: We have our header but need our tag ID */
474 if (header
== 9 && rows
< 10)
476 /* Confirm parity is correct */
477 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
479 /* Read another byte! */
480 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
483 /* Keep parity info */
484 parity
[0] ^= BitStream
[i
];
485 parity
[1] ^= BitStream
[i
+1];
486 parity
[2] ^= BitStream
[i
+2];
487 parity
[3] ^= BitStream
[i
+3];
489 /* Move 4 bits ahead */
493 /* Damn, something wrong! reset */
496 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
498 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
499 i
-= 9 + (5 * rows
) - 5;
505 /* Step 3: Got our 40 bits! confirm column parity */
508 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
509 if (BitStream
[i
] == parity
[0] && BitStream
[i
+1] == parity
[1] &&
510 BitStream
[i
+2] == parity
[2] && BitStream
[i
+3] == parity
[3] &&
514 PrintToScrollback("EM410x Tag ID: %s", id
);
521 /* Crap! Incorrect parity or no stop bit, start all over */
526 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
531 /* Step 1: get our header */
534 /* Need 9 consecutive 1's */
535 if (BitStream
[i
] == 1)
538 /* We don't have a header, not enough consecutive 1 bits */
544 /* if we've already retested after flipping bits, return */
548 /* if this didn't work, try flipping bits */
549 for (i
= 0; i
< bit2idx
; i
++)
555 /* emulate an EM410X tag
557 * 1111 1111 1 <-- standard non-repeatable header
558 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
560 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
561 * 0 <-- stop bit, end of tag
563 static void CmdEM410xsim(char *str
)
565 int i
, n
, j
, h
, binary
[4], parity
[4];
568 /* clock is 64 in EM410x tags */
571 /* clear our graph */
574 /* write it out a few times */
575 for (h
= 0; h
< 4; h
++)
577 /* write 9 start bits */
578 for (i
= 0; i
< 9; i
++)
579 CmdAppendGraph(0, clock
, 1);
581 /* for each hex char */
582 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
583 for (i
= 0; i
< 10; i
++)
585 /* read each hex char */
586 sscanf(&str
[i
], "%1x", &n
);
587 for (j
= 3; j
>= 0; j
--, n
/= 2)
590 /* append each bit */
591 CmdAppendGraph(0, clock
, binary
[0]);
592 CmdAppendGraph(0, clock
, binary
[1]);
593 CmdAppendGraph(0, clock
, binary
[2]);
594 CmdAppendGraph(0, clock
, binary
[3]);
596 /* append parity bit */
597 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
599 /* keep track of column parity */
600 parity
[0] ^= binary
[0];
601 parity
[1] ^= binary
[1];
602 parity
[2] ^= binary
[2];
603 parity
[3] ^= binary
[3];
607 CmdAppendGraph(0, clock
, parity
[0]);
608 CmdAppendGraph(0, clock
, parity
[1]);
609 CmdAppendGraph(0, clock
, parity
[2]);
610 CmdAppendGraph(0, clock
, parity
[3]);
613 CmdAppendGraph(0, clock
, 0);
616 /* modulate that biatch */
620 RepaintGraphWindow();
625 static void ChkBitstream(char *str
)
629 /* convert to bitstream if necessary */
630 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
632 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
640 static void CmdLosim(char *str
)
644 /* convert to bitstream if necessary */
647 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
650 for(j
= 0; j
< 48; j
++) {
651 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
653 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
655 SendCommand(&c
, FALSE
);
659 c
.cmd
= CMD_SIMULATE_TAG_125K
;
660 c
.ext1
= GraphTraceLen
;
661 SendCommand(&c
, FALSE
);
664 static void CmdLoread(char *str
)
667 // 'h' means higher-low-frequency, 134 kHz
670 } else if (*str
== '\0') {
673 PrintToScrollback("use 'loread' or 'loread h'");
676 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
677 SendCommand(&c
, FALSE
);
680 static void CmdDetectReader(char *str
)
683 // 'l' means LF - 125/134 kHz
686 } else if (*str
== 'h') {
688 } else if (*str
!= '\0') {
689 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");
692 c
.cmd
= CMD_LISTEN_READER_FIELD
;
693 SendCommand(&c
, FALSE
);
696 /* send a command before reading */
697 static void CmdLoCommandRead(char *str
)
699 static char dummy
[3];
704 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
705 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, (char *) &c
.d
.asBytes
,(char *) &dummy
+1);
706 // in case they specified 'h'
707 strcpy((char *)&c
.d
.asBytes
+ strlen((char *)c
.d
.asBytes
), dummy
);
708 SendCommand(&c
, FALSE
);
711 static void CmdLosamples(char *str
)
719 if (n
>16000) n
=16000;
721 for(i
= 0; i
< n
; i
+= 12) {
723 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
725 SendCommand(&c
, FALSE
);
727 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
729 PrintToScrollback("bad resp");
733 for(j
= 0; j
< 48; j
++) {
734 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
738 RepaintGraphWindow();
741 static void CmdBitsamples(char *str
)
748 for(i
= 0; i
< n
; i
+= 12) {
750 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
752 SendCommand(&c
, FALSE
);
754 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
755 PrintToScrollback("bad resp");
759 for(j
= 0; j
< 48; j
++) {
760 for(k
= 0; k
< 8; k
++) {
761 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
762 GraphBuffer
[cnt
++] = 1;
764 GraphBuffer
[cnt
++] = 0;
770 RepaintGraphWindow();
773 static void CmdHisamples(char *str
)
779 for(i
= 0; i
< n
; i
+= 12) {
781 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
783 SendCommand(&c
, FALSE
);
785 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
786 PrintToScrollback("bad resp");
790 for(j
= 0; j
< 48; j
++) {
791 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
796 RepaintGraphWindow();
799 static int CmdHisamplest(char *str
, int nrlow
)
811 for(i
= 0; i
< n
; i
+= 12) {
813 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
815 SendCommand(&c
, FALSE
);
817 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
818 PrintToScrollback("bad resp");
822 for(j
= 0; j
< 48; j
++) {
823 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
824 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
830 t1
= (t2
& 0x80) ^ (t2
& 0x20);
831 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
837 t2
= ((t2
<< 1) & 0x80);
843 t2
= ((t2
<< 1) & 0x20);
847 // both, but tag with other algorithm
848 t1
= (t2
& 0x80) ^ (t2
& 0x08);
849 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
853 GraphBuffer
[cnt
++] = t1
;
854 GraphBuffer
[cnt
++] = t2
;
859 if(hasbeennull
>nrlow
|| nrlow
==0) {
860 PrintToScrollback("hasbeennull=%d", hasbeennull
);
869 static void CmdHexsamples(char *str
)
880 for(i
= 0; i
< n
; i
+= 12) {
882 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
884 SendCommand(&c
, FALSE
);
886 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
887 PrintToScrollback("bad resp");
891 for(j
= 0; j
< 48; j
+= 8) {
892 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
907 static void CmdHisampless(char *str
)
919 for(i
= 0; i
< n
; i
+= 12) {
921 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
923 SendCommand(&c
, FALSE
);
925 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
926 PrintToScrollback("bad resp");
930 for(j
= 0; j
< 48; j
++) {
931 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
936 RepaintGraphWindow();
939 static WORD
Iso15693Crc(BYTE
*v
, int n
)
945 for(i
= 0; i
< n
; i
++) {
946 reg
= reg
^ ((DWORD
)v
[i
]);
947 for (j
= 0; j
< 8; j
++) {
949 reg
= (reg
>> 1) ^ 0x8408;
959 static void CmdHi14bdemod(char *str
)
964 BOOL negateI
, negateQ
;
969 // As received, the samples are pairs, correlations against I and Q
970 // square waves. So estimate angle of initial carrier (or just
971 // quadrant, actually), and then do the demod.
973 // First, estimate where the tag starts modulating.
974 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
975 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
979 if(i
>= GraphTraceLen
) {
980 PrintToScrollback("too weak to sync");
983 PrintToScrollback("out of weak at %d", i
);
986 // Now, estimate the phase in the initial modulation of the tag
989 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
990 isum
+= GraphBuffer
[i
+0];
991 qsum
+= GraphBuffer
[i
+1];
993 negateI
= (isum
< 0);
994 negateQ
= (qsum
< 0);
996 // Turn the correlation pairs into soft decisions on the bit.
998 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
999 int si
= GraphBuffer
[j
];
1000 int sq
= GraphBuffer
[j
+1];
1001 if(negateI
) si
= -si
;
1002 if(negateQ
) sq
= -sq
;
1003 GraphBuffer
[i
] = si
+ sq
;
1009 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
1011 if(i
>= GraphTraceLen
) goto demodError
;
1014 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
1016 if(i
>= GraphTraceLen
) goto demodError
;
1017 if((i
- iold
) > 23) goto demodError
;
1019 PrintToScrollback("make it to demod loop");
1023 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
1025 if(i
>= GraphTraceLen
) goto demodError
;
1026 if((i
- iold
) > 6) goto demodError
;
1029 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
1031 for(j
= 0; j
< 10; j
++) {
1032 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
1034 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
1035 PrintToScrollback("weak bit");
1039 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
1046 if( (shiftReg
& 0x200) &&
1047 !(shiftReg
& 0x001))
1049 // valid data byte, start and stop bits okay
1050 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
1051 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
1052 if(dataLen
>= sizeof(data
)) {
1055 } else if(shiftReg
== 0x000) {
1064 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
1065 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
1066 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
1067 "ok" : "****FAIL****");
1069 RepaintGraphWindow();
1073 PrintToScrollback("demod error");
1074 RepaintGraphWindow();
1077 static void CmdHi14list(char *str
)
1080 GetFromBigBuf(got
, sizeof(got
));
1082 PrintToScrollback("recorded activity:");
1083 PrintToScrollback(" time :rssi: who bytes");
1084 PrintToScrollback("---------+----+----+-----------");
1095 int timestamp
= *((DWORD
*)(got
+i
));
1096 if(timestamp
& 0x80000000) {
1097 timestamp
&= 0x7fffffff;
1102 int metric
= *((DWORD
*)(got
+i
+4));
1109 if(i
+ len
>= 900) {
1113 BYTE
*frame
= (got
+i
+9);
1115 char line
[1000] = "";
1117 for(j
= 0; j
< len
; j
++) {
1118 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
1124 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
1125 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1126 crc
= "**FAIL CRC**";
1134 char metricString
[100];
1136 sprintf(metricString
, "%3d", metric
);
1138 strcpy(metricString
, " ");
1141 PrintToScrollback(" +%7d: %s: %s %s %s",
1142 (prev
< 0 ? 0 : timestamp
- prev
),
1144 (isResponse
? "TAG" : " "), line
, crc
);
1151 static void CmdHi14alist(char *str
)
1154 GetFromBigBuf(got
, sizeof(got
));
1156 PrintToScrollback("recorded activity:");
1157 PrintToScrollback(" ETU :rssi: who bytes");
1158 PrintToScrollback("---------+----+----+-----------");
1169 int timestamp
= *((DWORD
*)(got
+i
));
1170 if(timestamp
& 0x80000000) {
1171 timestamp
&= 0x7fffffff;
1178 int parityBits
= *((DWORD
*)(got
+i
+4));
1179 // 4 bytes of additional information...
1180 // maximum of 32 additional parity bit information
1183 // at each quarter bit period we can send power level (16 levels)
1184 // or each half bit period in 256 levels.
1192 if(i
+ len
>= 1900) {
1196 BYTE
*frame
= (got
+i
+9);
1198 // Break and stick with current result if buffer was not completely full
1199 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1201 char line
[1000] = "";
1203 for(j
= 0; j
< len
; j
++) {
1204 int oddparity
= 0x01;
1208 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1211 //if((parityBits >> (len - j - 1)) & 0x01) {
1212 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1213 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1216 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1224 for(j
= 0; j
< (len
- 1); j
++) {
1225 // gives problems... search for the reason..
1226 /*if(frame[j] == 0xAA) {
1227 switch(frame[j+1]) {
1229 crc = "[1] Two drops close after each other";
1232 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1235 crc = "[3] Segment Z after segment X is not possible";
1238 crc = "[4] Parity bit of a fully received byte was wrong";
1241 crc = "[?] Unknown error";
1248 if(strlen(crc
)==0) {
1249 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1250 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1251 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1260 char metricString
[100];
1262 sprintf(metricString
, "%3d", metric
);
1264 strcpy(metricString
, " ");
1267 PrintToScrollback(" +%7d: %s: %s %s %s",
1268 (prev
< 0 ? 0 : (timestamp
- prev
)),
1270 (isResponse
? "TAG" : " "), line
, crc
);
1275 CommandFinished
= 1;
1278 static void CmdHi15demod(char *str
)
1280 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1283 // 1) Unmodulated time of 56.64us
1284 // 2) 24 pulses of 423.75khz
1285 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1287 static const int FrameSOF
[] = {
1288 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1289 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1290 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1291 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1297 static const int Logic0
[] = {
1303 static const int Logic1
[] = {
1311 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1312 // 2) 24 pulses of 423.75khz
1313 // 3) Unmodulated time of 56.64us
1315 static const int FrameEOF
[] = {
1320 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1321 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1322 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1323 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1327 int max
= 0, maxPos
;
1331 if(GraphTraceLen
< 1000) return;
1333 // First, correlate for SOF
1334 for(i
= 0; i
< 100; i
++) {
1336 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1337 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1344 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1345 max
/(arraylen(FrameSOF
)/skip
));
1347 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1350 memset(outBuf
, 0, sizeof(outBuf
));
1353 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1354 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1355 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1357 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1358 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1360 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1361 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1363 // Even things out by the length of the target waveform.
1367 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1368 PrintToScrollback("EOF at %d", i
);
1370 } else if(corr1
> corr0
) {
1371 i
+= arraylen(Logic1
)/skip
;
1374 i
+= arraylen(Logic0
)/skip
;
1381 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1382 PrintToScrollback("ran off end!");
1387 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1388 PrintToScrollback(" mask=%02x", mask
);
1390 PrintToScrollback("%d octets", k
);
1392 for(i
= 0; i
< k
; i
++) {
1393 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1395 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1398 static void CmdTiread(char *str
)
1401 c
.cmd
= CMD_ACQUIRE_RAW_BITS_TI_TYPE
;
1402 SendCommand(&c
, FALSE
);
1405 static void CmdTibits(char *str
)
1409 // for(i = 0; i < 1536; i += 12) {
1410 for(i
= 0; i
< 4000; i
+= 12) {
1412 c
.cmd
= CMD_DOWNLOAD_RAW_BITS_TI_TYPE
;
1414 SendCommand(&c
, FALSE
);
1416 if(c
.cmd
!= CMD_DOWNLOADED_RAW_BITS_TI_TYPE
) {
1417 PrintToScrollback("bad resp");
1421 for(j
= 0; j
< 12; j
++) {
1423 for(k
= 31; k
>= 0; k
--) {
1424 if(c
.d
.asDwords
[j
] & (1 << k
)) {
1425 GraphBuffer
[cnt
++] = 1;
1427 GraphBuffer
[cnt
++] = -1;
1432 // GraphTraceLen = 1536*32;
1433 GraphTraceLen
= 4000*32;
1434 RepaintGraphWindow();
1437 static void CmdFSKdemod(char *cmdline
)
1439 static const int LowTone
[] = {
1440 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1441 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1442 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1443 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1444 1, 1, 1, 1, 1, -1, -1, -1, -1, -1
1446 static const int HighTone
[] = {
1447 1, 1, 1, 1, 1, -1, -1, -1, -1,
1448 1, 1, 1, 1, -1, -1, -1, -1,
1449 1, 1, 1, 1, -1, -1, -1, -1,
1450 1, 1, 1, 1, -1, -1, -1, -1,
1451 1, 1, 1, 1, -1, -1, -1, -1,
1452 1, 1, 1, 1, -1, -1, -1, -1, -1,
1455 int convLen
= max(arraylen(HighTone
), arraylen(LowTone
));
1456 DWORD hi
= 0, lo
= 0;
1459 int minMark
=0, maxMark
=0;
1460 int lowLen
= arraylen(LowTone
);
1461 int highLen
= arraylen(HighTone
);
1463 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1464 int lowSum
= 0, highSum
= 0;
1466 for(j
= 0; j
< lowLen
; j
++) {
1467 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1469 for(j
= 0; j
< highLen
; j
++) {
1470 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1472 lowSum
= abs((100*lowSum
) / lowLen
);
1473 highSum
= abs((100*highSum
) / highLen
);
1474 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1477 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1479 int lowTot
= 0, highTot
= 0;
1480 // 10 and 8 are f_s divided by f_l and f_h, rounded
1481 for(j
= 0; j
< 10; j
++) {
1482 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1484 for(j
= 0; j
< 8; j
++) {
1485 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1487 GraphBuffer
[i
] = lowTot
- highTot
;
1488 if (GraphBuffer
[i
]>maxMark
) maxMark
=GraphBuffer
[i
];
1489 if (GraphBuffer
[i
]<minMark
) minMark
=GraphBuffer
[i
];
1492 GraphTraceLen
-= (convLen
+ 16);
1494 RepaintGraphWindow();
1496 // Find bit-sync (3 lo followed by 3 high)
1497 int max
= 0, maxPos
= 0;
1498 for(i
= 0; i
< 6000; i
++) {
1500 for(j
= 0; j
< 3*arraylen(LowTone
); j
++) {
1501 dec
-= GraphBuffer
[i
+j
];
1503 for(; j
< 3*(arraylen(LowTone
) + arraylen(HighTone
) ); j
++) {
1504 dec
+= GraphBuffer
[i
+j
];
1512 // place start of bit sync marker in graph
1513 GraphBuffer
[maxPos
] = maxMark
;
1514 GraphBuffer
[maxPos
+1] = minMark
;
1518 // place end of bit sync marker in graph
1519 GraphBuffer
[maxPos
] = maxMark
;
1520 GraphBuffer
[maxPos
+1] = minMark
;
1522 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1523 PrintToScrollback("length %d/%d", arraylen(HighTone
), arraylen(LowTone
));
1526 bits
[sizeof(bits
)-1] = '\0';
1528 // find bit pairs and manchester decode them
1529 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1531 for(j
= 0; j
< arraylen(LowTone
); j
++) {
1532 dec
-= GraphBuffer
[maxPos
+j
];
1534 for(; j
< arraylen(LowTone
) + arraylen(HighTone
); j
++) {
1535 dec
+= GraphBuffer
[maxPos
+j
];
1538 // place inter bit marker in graph
1539 GraphBuffer
[maxPos
] = maxMark
;
1540 GraphBuffer
[maxPos
+1] = minMark
;
1542 // hi and lo form a 64 bit pair
1543 hi
= (hi
<<1)|(lo
>>31);
1545 // store decoded bit as binary (in hi/lo) and text (in bits[])
1553 PrintToScrollback("bits: '%s'", bits
);
1554 PrintToScrollback("hex: %08x %08x", hi
, lo
);
1557 static void CmdTidemod(char *cmdline
)
1559 /* MATLAB as follows:
1560 f_s = 2000000; % sampling frequency
1561 f_l = 123200; % low FSK tone
1562 f_h = 134200; % high FSK tone
1564 T_l = 119e-6; % low bit duration
1565 T_h = 130e-6; % high bit duration
1567 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1568 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1570 l = sign(sin(cumsum(l)));
1571 h = sign(sin(cumsum(h)));
1573 static const int LowTone
[] = {
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,
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, -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,
1590 static const int HighTone
[] = {
1591 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, -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, -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, -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,
1611 int convLen
= max(arraylen(HighTone
), arraylen(LowTone
));
1614 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1616 int lowSum
= 0, highSum
= 0;;
1617 int lowLen
= arraylen(LowTone
);
1618 int highLen
= arraylen(HighTone
);
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 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1631 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1633 int lowTot
= 0, highTot
= 0;
1634 // 16 and 15 are f_s divided by f_l and f_h, rounded
1635 for(j
= 0; j
< 16; j
++) {
1636 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1638 for(j
= 0; j
< 15; j
++) {
1639 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1641 GraphBuffer
[i
] = lowTot
- highTot
;
1644 GraphTraceLen
-= (convLen
+ 16);
1646 RepaintGraphWindow();
1648 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,
1649 // 16 crc CCITT bits, 8 stop bits, 15 end bits
1651 // the 16 prebits are always low
1652 // the 8 start and stop bits of a tag must match
1653 // the start/stop prebits of a ro tag are 01111110
1654 // the start/stop prebits of a rw tag are 11111110
1655 // the 15 end bits of a ro tag are all low
1656 // the 15 end bits of a rw tag match bits 15-1 of the data bits
1658 // Okay, so now we have unsliced soft decisions;
1659 // find bit-sync, and then get some bits.
1660 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)
1661 int max
= 0, maxPos
= 0;
1662 for(i
= 0; i
< 6000; i
++) {
1665 // searching 17 consecutive lows
1666 for(j
= 0; j
< 17*arraylen(LowTone
); j
++) {
1667 dec
-= GraphBuffer
[i
+j
];
1669 // searching 7 consecutive highs
1670 for(; j
< 17*arraylen(LowTone
) + 6*arraylen(HighTone
); j
++) {
1671 dec
+= GraphBuffer
[i
+j
];
1679 // place a marker in the buffer to visually aid location
1680 // of the start of sync
1681 GraphBuffer
[maxPos
] = 800;
1682 GraphBuffer
[maxPos
+1] = -800;
1684 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)
1685 maxPos
+= 17*arraylen(LowTone
);
1686 maxPos
+= 6*arraylen(HighTone
);
1688 // place a marker in the buffer to visually aid location
1689 // of the end of sync
1690 GraphBuffer
[maxPos
] = 800;
1691 GraphBuffer
[maxPos
+1] = -800;
1693 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1695 PrintToScrollback("length %d/%d", arraylen(HighTone
), arraylen(LowTone
));
1697 BYTE bits
[1+64+16+8+16];
1698 bits
[sizeof(bits
)-1] = '\0';
1700 DWORD shift3
= 0x7e000000, shift2
= 0, shift1
= 0, shift0
= 0;
1702 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1706 for(j
= 0; j
< arraylen(LowTone
); j
++) {
1707 low
-= GraphBuffer
[maxPos
+j
];
1709 for(j
= 0; j
< arraylen(HighTone
); j
++) {
1710 high
+= GraphBuffer
[maxPos
+j
];
1715 maxPos
+= arraylen(HighTone
);
1716 // bitstream arrives lsb first so shift right
1720 maxPos
+= arraylen(LowTone
);
1723 // 128 bit right shift register
1724 shift0
= (shift0
>>1) | (shift1
<< 31);
1725 shift1
= (shift1
>>1) | (shift2
<< 31);
1726 shift2
= (shift2
>>1) | (shift3
<< 31);
1729 // place a marker in the buffer between bits to visually aid location
1730 GraphBuffer
[maxPos
] = 800;
1731 GraphBuffer
[maxPos
+1] = -800;
1733 PrintToScrollback("Info: raw tag bits = %s", bits
);
1735 TagType
= (shift3
>>8)&0xff;
1736 if ( TagType
!= ((shift0
>>16)&0xff) ) {
1737 PrintToScrollback("Error: start and stop bits do not match!");
1740 else if (TagType
== 0x7e) {
1741 PrintToScrollback("Info: Readonly TI tag detected.");
1744 else if (TagType
== 0xfe) {
1745 PrintToScrollback("Info: Rewriteable TI tag detected.");
1747 // put 64 bit data into shift1 and shift0
1748 shift0
= (shift0
>>24) | (shift1
<< 8);
1749 shift1
= (shift1
>>24) | (shift2
<< 8);
1751 // align 16 bit crc into lower half of shift2
1752 shift2
= ((shift2
>>24) | (shift3
<< 8)) & 0x0ffff;
1754 // align 16 bit "end bits" or "ident" into lower half of shift3
1757 if ( (shift3
^shift0
)&0xffff ) {
1758 PrintToScrollback("Error: Ident mismatch!");
1762 crc
= update_crc16(crc
, (shift0
)&0xff);
1763 crc
= update_crc16(crc
, (shift0
>>8)&0xff);
1764 crc
= update_crc16(crc
, (shift0
>>16)&0xff);
1765 crc
= update_crc16(crc
, (shift0
>>24)&0xff);
1766 crc
= update_crc16(crc
, (shift1
)&0xff);
1767 crc
= update_crc16(crc
, (shift1
>>8)&0xff);
1768 crc
= update_crc16(crc
, (shift1
>>16)&0xff);
1769 crc
= update_crc16(crc
, (shift1
>>24)&0xff);
1770 PrintToScrollback("Info: Tag data = %08X%08X", shift1
, shift0
);
1771 if (crc
!= (shift2
&0xffff)) {
1772 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc
, shift2
&0xffff);
1774 PrintToScrollback("Info: CRC %04X is good", crc
);
1778 PrintToScrollback("Unknown tag type.");
1783 static void CmdNorm(char *str
)
1786 int max
= INT_MIN
, min
= INT_MAX
;
1787 for(i
= 10; i
< GraphTraceLen
; i
++) {
1788 if(GraphBuffer
[i
] > max
) {
1789 max
= GraphBuffer
[i
];
1791 if(GraphBuffer
[i
] < min
) {
1792 min
= GraphBuffer
[i
];
1796 for(i
= 0; i
< GraphTraceLen
; i
++) {
1797 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1801 RepaintGraphWindow();
1804 static void CmdDec(char *str
)
1807 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1808 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1811 PrintToScrollback("decimated by 2");
1812 RepaintGraphWindow();
1815 static void CmdHpf(char *str
)
1819 for(i
= 10; i
< GraphTraceLen
; i
++) {
1820 accum
+= GraphBuffer
[i
];
1822 accum
/= (GraphTraceLen
- 10);
1823 for(i
= 0; i
< GraphTraceLen
; i
++) {
1824 GraphBuffer
[i
] -= accum
;
1827 RepaintGraphWindow();
1830 static void CmdZerocrossings(char *str
)
1833 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1839 for(i
= 0; i
< GraphTraceLen
; i
++) {
1840 if(GraphBuffer
[i
]*sign
>= 0) {
1841 // No change in sign, reproduce the previous sample count.
1843 GraphBuffer
[i
] = lastZc
;
1845 // Change in sign, reset the sample count.
1847 GraphBuffer
[i
] = lastZc
;
1855 RepaintGraphWindow();
1858 static void CmdThreshold(char *str
)
1861 int threshold
= atoi(str
);
1863 for(i
= 0; i
< GraphTraceLen
; i
++) {
1864 if(GraphBuffer
[i
]>= threshold
)
1869 RepaintGraphWindow();
1872 static void CmdLtrim(char *str
)
1877 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1878 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1880 GraphTraceLen
-= ds
;
1882 RepaintGraphWindow();
1885 static void CmdAutoCorr(char *str
)
1887 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1889 int window
= atoi(str
);
1892 PrintToScrollback("needs a window");
1896 if(window
>= GraphTraceLen
) {
1897 PrintToScrollback("window must be smaller than trace (%d samples)",
1902 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1905 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1908 for(j
= 0; j
< window
; j
++) {
1909 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1911 CorrelBuffer
[i
] = sum
;
1913 GraphTraceLen
= GraphTraceLen
- window
;
1914 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1916 RepaintGraphWindow();
1919 static void CmdVchdemod(char *str
)
1921 // Is this the entire sync pattern, or does this also include some
1922 // data bits that happen to be the same everywhere? That would be
1924 static const int SyncPattern
[] = {
1925 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1926 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1927 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1928 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1929 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1930 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1931 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1932 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1933 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1934 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1937 // So first, we correlate for the sync pattern, and mark that.
1938 int bestCorrel
= 0, bestPos
= 0;
1940 // It does us no good to find the sync pattern, with fewer than
1941 // 2048 samples after it...
1942 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1945 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1946 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1948 if(sum
> bestCorrel
) {
1953 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
1958 int worst
= INT_MAX
;
1961 for(i
= 0; i
< 2048; i
+= 8) {
1964 for(j
= 0; j
< 8; j
++) {
1965 sum
+= GraphBuffer
[bestPos
+i
+j
];
1972 if(abs(sum
) < worst
) {
1977 PrintToScrollback("bits:");
1978 PrintToScrollback("%s", bits
);
1979 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
1981 if(strcmp(str
, "clone")==0) {
1984 for(s
= bits
; *s
; s
++) {
1986 for(j
= 0; j
< 16; j
++) {
1987 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
1990 RepaintGraphWindow();
1994 static void CmdIndalademod(char *str
)
1996 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
2001 // worst case with GraphTraceLen=64000 is < 4096
2002 // under normal conditions it's < 2048
2005 int worst
= 0, worstPos
= 0;
2006 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
2007 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
2009 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
2011 for(j
= 0; j
< count
- 8; j
+= 16) {
2012 rawbits
[rawbit
++] = 0;
2014 if ((abs(count
- j
)) > worst
) {
2015 worst
= abs(count
- j
);
2021 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
2023 for(j
= 0; j
< count
- 8; j
+= 16) {
2024 rawbits
[rawbit
++] = 1;
2026 if ((abs(count
- j
)) > worst
) {
2027 worst
= abs(count
- j
);
2035 PrintToScrollback("Recovered %d raw bits", rawbit
);
2036 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
2038 // Finding the start of a UID
2039 int uidlen
, long_wait
;
2040 if(strcmp(str
, "224") == 0) {
2049 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
2050 first
= rawbits
[start
];
2051 for(i
= start
; i
< start
+ long_wait
; i
++) {
2052 if(rawbits
[i
] != first
) {
2056 if(i
== (start
+ long_wait
)) {
2060 if(start
== rawbit
- uidlen
+ 1) {
2061 PrintToScrollback("nothing to wait for");
2065 // Inverting signal if needed
2067 for(i
= start
; i
< rawbit
; i
++) {
2068 rawbits
[i
] = !rawbits
[i
];
2075 showbits
[uidlen
]='\0';
2079 if(uidlen
> rawbit
) {
2080 PrintToScrollback("Warning: not enough raw bits to get a full UID");
2081 for(bit
= 0; bit
< rawbit
; bit
++) {
2082 bits
[bit
] = rawbits
[i
++];
2083 // As we cannot know the parity, let's use "." and "/"
2084 showbits
[bit
] = '.' + bits
[bit
];
2086 showbits
[bit
+1]='\0';
2087 PrintToScrollback("Partial UID=%s", showbits
);
2090 for(bit
= 0; bit
< uidlen
; bit
++) {
2091 bits
[bit
] = rawbits
[i
++];
2092 showbits
[bit
] = '0' + bits
[bit
];
2096 PrintToScrollback("UID=%s", showbits
);
2098 // Checking UID against next occurences
2099 for(; i
+ uidlen
<= rawbit
;) {
2101 for(bit
= 0; bit
< uidlen
; bit
++) {
2102 if(bits
[bit
] != rawbits
[i
++]) {
2112 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
2114 // Remodulating for tag cloning
2115 GraphTraceLen
= 32*uidlen
;
2118 for(bit
= 0; bit
< uidlen
; bit
++) {
2119 if(bits
[bit
] == 0) {
2125 for(j
= 0; j
< 32; j
++) {
2126 GraphBuffer
[i
++] = phase
;
2131 RepaintGraphWindow();
2134 static void CmdFlexdemod(char *str
)
2137 for(i
= 0; i
< GraphTraceLen
; i
++) {
2138 if(GraphBuffer
[i
] < 0) {
2139 GraphBuffer
[i
] = -1;
2145 #define LONG_WAIT 100
2147 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
2148 int first
= GraphBuffer
[start
];
2149 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
2150 if(GraphBuffer
[i
] != first
) {
2154 if(i
== (start
+ LONG_WAIT
)) {
2158 if(start
== GraphTraceLen
- LONG_WAIT
) {
2159 PrintToScrollback("nothing to wait for");
2163 GraphBuffer
[start
] = 2;
2164 GraphBuffer
[start
+1] = -2;
2170 for(bit
= 0; bit
< 64; bit
++) {
2173 for(j
= 0; j
< 16; j
++) {
2174 sum
+= GraphBuffer
[i
++];
2181 PrintToScrollback("bit %d sum %d", bit
, sum
);
2184 for(bit
= 0; bit
< 64; bit
++) {
2187 for(j
= 0; j
< 16; j
++) {
2188 sum
+= GraphBuffer
[i
++];
2190 if(sum
> 0 && bits
[bit
] != 1) {
2191 PrintToScrollback("oops1 at %d", bit
);
2193 if(sum
< 0 && bits
[bit
] != 0) {
2194 PrintToScrollback("oops2 at %d", bit
);
2198 GraphTraceLen
= 32*64;
2201 for(bit
= 0; bit
< 64; bit
++) {
2202 if(bits
[bit
] == 0) {
2208 for(j
= 0; j
< 32; j
++) {
2209 GraphBuffer
[i
++] = phase
;
2214 RepaintGraphWindow();
2218 * Generic command to demodulate ASK.
2220 * Argument is convention: positive or negative (High mod means zero
2221 * or high mod means one)
2223 * Updates the Graph trace with 0/1 values
2229 static void Cmdaskdemod(char *str
) {
2231 int c
, high
= 0, low
= 0;
2233 // TODO: complain if we do not give 2 arguments here !
2234 sscanf(str
, "%i", &c
);
2236 /* Detect high and lows and clock */
2237 for (i
= 0; i
< GraphTraceLen
; i
++)
2239 if (GraphBuffer
[i
] > high
)
2240 high
= GraphBuffer
[i
];
2241 else if (GraphBuffer
[i
] < low
)
2242 low
= GraphBuffer
[i
];
2245 if (GraphBuffer
[0] > 0) {
2246 GraphBuffer
[0] = 1-c
;
2250 for(i
=1;i
<GraphTraceLen
;i
++) {
2251 /* Transitions are detected at each peak
2252 * Transitions are either:
2253 * - we're low: transition if we hit a high
2254 * - we're high: transition if we hit a low
2255 * (we need to do it this way because some tags keep high or
2256 * low for long periods, others just reach the peak and go
2259 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
2261 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
2265 GraphBuffer
[i
] = GraphBuffer
[i
-1];
2268 RepaintGraphWindow();
2271 /* Print our clock rate */
2272 static void Cmddetectclockrate(char *str
)
2274 int clock
= detectclock(0);
2275 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2281 int detectclock(int peak
)
2287 /* Detect peak if we don't have one */
2289 for (i
= 0; i
< GraphTraceLen
; i
++)
2290 if (GraphBuffer
[i
] > peak
)
2291 peak
= GraphBuffer
[i
];
2293 for (i
= 1; i
< GraphTraceLen
; i
++)
2295 /* If this is the beginning of a peak */
2296 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
2298 /* Find lowest difference between peaks */
2299 if (lastpeak
&& i
- lastpeak
< clock
)
2301 clock
= i
- lastpeak
;
2310 /* Get or auto-detect clock rate */
2311 int GetClock(char *str
, int peak
)
2315 sscanf(str
, "%i", &clock
);
2316 if (!strcmp(str
, ""))
2319 /* Auto-detect clock */
2322 clock
= detectclock(peak
);
2324 /* Only print this message if we're not looping something */
2326 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2333 * Convert to a bitstream
2335 static void Cmdbitstream(char *str
) {
2342 int hithigh
, hitlow
, first
;
2344 /* Detect high and lows and clock */
2345 for (i
= 0; i
< GraphTraceLen
; i
++)
2347 if (GraphBuffer
[i
] > high
)
2348 high
= GraphBuffer
[i
];
2349 else if (GraphBuffer
[i
] < low
)
2350 low
= GraphBuffer
[i
];
2354 clock
= GetClock(str
, high
);
2356 gtl
= CmdClearGraph(0);
2359 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2365 /* Find out if we hit both high and low peaks */
2366 for (j
= 0; j
< clock
; j
++)
2368 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2370 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2373 /* it doesn't count if it's the first part of our read
2374 because it's really just trailing from the last sequence */
2375 if (first
&& (hithigh
|| hitlow
))
2376 hithigh
= hitlow
= 0;
2380 if (hithigh
&& hitlow
)
2384 /* If we didn't hit both high and low peaks, we had a bit transition */
2385 if (!hithigh
|| !hitlow
)
2388 CmdAppendGraph(0, clock
, bit
);
2389 // for (j = 0; j < (int)(clock/2); j++)
2390 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2391 // for (j = (int)(clock/2); j < clock; j++)
2392 // GraphBuffer[(i * clock) + j] = bit;
2395 RepaintGraphWindow();
2398 /* Modulate our data into manchester */
2399 static void Cmdmanchestermod(char *str
)
2403 int bit
, lastbit
, wave
;
2406 clock
= GetClock(str
, 0);
2410 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2412 bit
= GraphBuffer
[i
* clock
] ^ 1;
2414 for (j
= 0; j
< (int)(clock
/2); j
++)
2415 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2416 for (j
= (int)(clock
/2); j
< clock
; j
++)
2417 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2419 /* Keep track of how we start our wave and if we changed or not this time */
2420 wave
^= bit
^ lastbit
;
2424 RepaintGraphWindow();
2428 * Manchester demodulate a bitstream. The bitstream needs to be already in
2429 * the GraphBuffer as 0 and 1 values
2431 * Give the clock rate as argument in order to help the sync - the algorithm
2432 * resyncs at each pulse anyway.
2434 * Not optimized by any means, this is the 1st time I'm writing this type of
2435 * routine, feel free to improve...
2437 * 1st argument: clock rate (as number of samples per clock rate)
2438 * Typical values can be 64, 32, 128...
2440 static void Cmdmanchesterdemod(char *str
) {
2441 int i
, j
, invert
= 0;
2447 int hithigh
, hitlow
, first
;
2453 /* check if we're inverting output */
2456 PrintToScrollback("Inverting output");
2460 while(*str
== ' '); // in case a 2nd argument was given
2463 /* Holds the decoded bitstream: each clock period contains 2 bits */
2464 /* later simplified to 1 bit after manchester decoding. */
2465 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2466 /* int BitStream[GraphTraceLen*2/clock+10]; */
2468 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2470 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2472 /* Detect high and lows */
2473 for (i
= 0; i
< GraphTraceLen
; i
++)
2475 if (GraphBuffer
[i
] > high
)
2476 high
= GraphBuffer
[i
];
2477 else if (GraphBuffer
[i
] < low
)
2478 low
= GraphBuffer
[i
];
2482 clock
= GetClock(str
, high
);
2484 int tolerance
= clock
/4;
2486 /* Detect first transition */
2487 /* Lo-Hi (arbitrary) */
2488 for (i
= 0; i
< GraphTraceLen
; i
++)
2490 if (GraphBuffer
[i
] == low
)
2497 /* If we're not working with 1/0s, demod based off clock */
2500 bit
= 0; /* We assume the 1st bit is zero, it may not be
2501 * the case: this routine (I think) has an init problem.
2504 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2510 /* Find out if we hit both high and low peaks */
2511 for (j
= 0; j
< clock
; j
++)
2513 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2515 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2518 /* it doesn't count if it's the first part of our read
2519 because it's really just trailing from the last sequence */
2520 if (first
&& (hithigh
|| hitlow
))
2521 hithigh
= hitlow
= 0;
2525 if (hithigh
&& hitlow
)
2529 /* If we didn't hit both high and low peaks, we had a bit transition */
2530 if (!hithigh
|| !hitlow
)
2533 BitStream
[bit2idx
++] = bit
^ invert
;
2537 /* standard 1/0 bitstream */
2541 /* Then detect duration between 2 successive transitions */
2542 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2544 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2549 // Error check: if bitidx becomes too large, we do not
2550 // have a Manchester encoded bitstream or the clock is really
2552 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2553 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2556 // Then switch depending on lc length:
2557 // Tolerance is 1/4 of clock rate (arbitrary)
2558 if (abs(lc
-clock
/2) < tolerance
) {
2559 // Short pulse : either "1" or "0"
2560 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2561 } else if (abs(lc
-clock
) < tolerance
) {
2562 // Long pulse: either "11" or "00"
2563 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2564 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2568 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2569 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2573 PrintToScrollback("Error: too many detection errors, aborting.");
2580 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2581 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2582 // to stop output at the final bitidx2 value, not bitidx
2583 for (i
= 0; i
< bitidx
; i
+= 2) {
2584 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2585 BitStream
[bit2idx
++] = 1 ^ invert
;
2586 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2587 BitStream
[bit2idx
++] = 0 ^ invert
;
2589 // We cannot end up in this state, this means we are unsynchronized,
2593 PrintToScrollback("Unsynchronized, resync...");
2594 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2598 PrintToScrollback("Error: too many decode errors, aborting.");
2605 PrintToScrollback("Manchester decoded bitstream");
2606 // Now output the bitstream to the scrollback by line of 16 bits
2607 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2608 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2631 static void CmdHiddemod(char *str
)
2633 if(GraphTraceLen
< 4800) {
2634 PrintToScrollback("too short; need at least 4800 samples");
2638 GraphTraceLen
= 4800;
2640 for(i
= 0; i
< GraphTraceLen
; i
++) {
2641 if(GraphBuffer
[i
] < 0) {
2647 RepaintGraphWindow();
2650 static void CmdPlot(char *str
)
2655 static void CmdGrid(char *str
)
2657 sscanf(str
, "%i %i", &PlotGridX
, &PlotGridY
);
2658 RepaintGraphWindow();
2661 static void CmdHide(char *str
)
2666 static void CmdScale(char *str
)
2668 CursorScaleFactor
= atoi(str
);
2669 if(CursorScaleFactor
== 0) {
2670 PrintToScrollback("bad, can't have zero scale");
2671 CursorScaleFactor
= 1;
2673 RepaintGraphWindow();
2676 static void CmdSave(char *str
)
2678 FILE *f
= fopen(str
, "w");
2680 PrintToScrollback("couldn't open '%s'", str
);
2684 for(i
= 0; i
< GraphTraceLen
; i
++) {
2685 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2688 PrintToScrollback("saved to '%s'", str
);
2691 static void CmdLoad(char *str
)
2693 FILE *f
= fopen(str
, "r");
2695 PrintToScrollback("couldn't open '%s'", str
);
2701 while(fgets(line
, sizeof(line
), f
)) {
2702 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2706 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2707 RepaintGraphWindow();
2710 static void CmdHIDsimTAG(char *str
)
2712 unsigned int hi
=0, lo
=0;
2716 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2717 hi
=(hi
<<4)|(lo
>>28);
2721 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2723 c
.cmd
= CMD_HID_SIM_TAG
;
2726 SendCommand(&c
, FALSE
);
2729 static void CmdReadmem(char *str
)
2732 c
.cmd
= CMD_READ_MEM
;
2734 SendCommand(&c
, FALSE
);
2737 static void CmdLcdReset(char *str
)
2740 c
.cmd
= CMD_LCD_RESET
;
2742 SendCommand(&c
, FALSE
);
2745 static void CmdLcd(char *str
)
2750 sscanf(str
, "%x %d", &i
, &j
);
2753 SendCommand(&c
, FALSE
);
2758 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2761 static void CmdSetDivisor(char *str
)
2764 c
.cmd
= CMD_SET_LF_DIVISOR
;
2766 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2767 PrintToScrollback("divisor must be between 19 and 255");
2769 SendCommand(&c
, FALSE
);
2770 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2774 typedef void HandlerFunction(char *cmdline
);
2776 /* in alphabetic order */
2779 HandlerFunction
*handler
;
2780 int offline
; // 1 if the command can be used when in offline mode
2782 } CommandTable
[] = {
2783 {"askdemod", Cmdaskdemod
, 1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags"},
2784 {"autocorr", CmdAutoCorr
, 1, "<window length> -- Autocorrelation over window"},
2785 {"bitsamples", CmdBitsamples
, 0, "Get raw samples as bitstring"},
2786 {"bitstream", Cmdbitstream
, 1, "[clock rate] -- Convert waveform into a bitstream"},
2787 {"buffclear", CmdBuffClear
, 1, "Clear sample buffer and graph window"},
2788 {"dec", CmdDec
, 1, "Decimate samples"},
2789 {"detectclock", Cmddetectclockrate
, 1, "Detect clock rate"},
2790 {"detectreader", CmdDetectReader
, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
2791 {"em410xsim", CmdEM410xsim
, 1, "<UID> -- Simulate EM410x tag"},
2792 {"em410xread", CmdEM410xread
, 1, "[clock rate] -- Extract ID from EM410x tag"},
2793 {"em410xwatch", CmdEM410xwatch
, 0, "Watches for EM410x tags"},
2794 {"em4x50read", CmdEM4x50read
, 1, "Extract data from EM4x50 tag"},
2795 {"exit", CmdQuit
, 1, "Exit program"},
2796 {"flexdemod", CmdFlexdemod
, 1, "Demodulate samples for FlexPass"},
2797 {"fpgaoff", CmdFPGAOff
, 0, "Set FPGA off"},
2798 {"fskdemod", CmdFSKdemod
, 1, "Demodulate graph window as a HID FSK"},
2799 {"grid", CmdGrid
, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
2800 {"hexsamples", CmdHexsamples
, 0, "<blocks> -- Dump big buffer as hex bytes"},
2801 {"hi14alist", CmdHi14alist
, 0, "List ISO 14443a history"},
2802 {"hi14areader", CmdHi14areader
, 0, "Act like an ISO14443 Type A reader"},
2803 {"hi14asim", CmdHi14asim
, 0, "<UID> -- Fake ISO 14443a tag"},
2804 {"hi14asnoop", CmdHi14asnoop
, 0, "Eavesdrop ISO 14443 Type A"},
2805 {"hi14bdemod", CmdHi14bdemod
, 1, "Demodulate ISO14443 Type B from tag"},
2806 {"hi14list", CmdHi14list
, 0, "List ISO 14443 history"},
2807 {"hi14read", CmdHi14read
, 0, "Read HF tag (ISO 14443)"},
2808 {"hi14sim", CmdHi14sim
, 0, "Fake ISO 14443 tag"},
2809 {"hi14snoop", CmdHi14snoop
, 0, "Eavesdrop ISO 14443"},
2810 {"hi15demod", CmdHi15demod
, 1, "Demodulate ISO15693 from tag"},
2811 {"hi15read", CmdHi15read
, 0, "Read HF tag (ISO 15693)"},
2812 {"hi15reader", CmdHi15reader
, 0, "Act like an ISO15693 reader"},
2813 {"hi15sim", CmdHi15tag
, 0, "Fake an ISO15693 tag"},
2814 {"hiddemod", CmdHiddemod
, 1, "Demodulate HID Prox Card II (not optimal)"},
2815 {"hide", CmdHide
, 1, "Hide graph window"},
2816 {"hidfskdemod", CmdHIDdemodFSK
, 0, "Realtime HID FSK demodulator"},
2817 {"hidsimtag", CmdHIDsimTAG
, 0, "<ID> -- HID tag simulator"},
2818 {"higet", CmdHi14read_sim
, 0, "<samples> -- Get samples HF, 'analog'"},
2819 {"hisamples", CmdHisamples
, 0, "Get raw samples for HF tag"},
2820 {"hisampless", CmdHisampless
, 0, "<samples> -- Get signed raw samples, HF tag"},
2821 {"hisamplest", CmdHi14readt
, 0, "Get samples HF, for testing"},
2822 {"hisimlisten", CmdHisimlisten
, 0, "Get HF samples as fake tag"},
2823 {"hpf", CmdHpf
, 1, "Remove DC offset from trace"},
2824 {"indalademod", CmdIndalademod
, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
2825 {"lcd", CmdLcd
, 0, "<HEX command> <count> -- Send command/data to LCD"},
2826 {"lcdreset", CmdLcdReset
, 0, "Hardware reset LCD"},
2827 {"load", CmdLoad
, 1, "<filename> -- Load trace (to graph window"},
2828 {"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)"},
2829 {"loread", CmdLoread
, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
2830 {"losamples", CmdLosamples
, 0, "[128 - 16000] -- Get raw samples for LF tag"},
2831 {"losim", CmdLosim
, 0, "Simulate LF tag"},
2832 {"ltrim", CmdLtrim
, 1, "<samples> -- Trim samples from left of trace"},
2833 {"mandemod", Cmdmanchesterdemod
, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
2834 {"manmod", Cmdmanchestermod
, 1, "[clock rate] -- Manchester modulate a binary stream"},
2835 {"norm", CmdNorm
, 1, "Normalize max/min to +/-500"},
2836 {"plot", CmdPlot
, 1, "Show graph window"},
2837 {"quit", CmdQuit
, 1, "Quit program"},
2838 {"readmem", CmdReadmem
, 0, "[address] -- Read memory at decimal address from flash"},
2839 {"reset", CmdReset
, 0, "Reset the Proxmark3"},
2840 {"save", CmdSave
, 1, "<filename> -- Save trace (from graph window)"},
2841 {"scale", CmdScale
, 1, "<int> -- Set cursor display scale"},
2842 {"setlfdivisor", CmdSetDivisor
, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
2843 {"sri512read", CmdSri512read
, 0, "<int> -- Read contents of a SRI512 tag"},
2844 {"tibits", CmdTibits
, 0, "Get raw bits for TI-type LF tag"},
2845 {"tidemod", CmdTidemod
, 1, "Demodulate raw bits for TI-type LF tag"},
2846 {"tiread", CmdTiread
, 0, "Read a TI-type 134 kHz tag"},
2847 {"threshold", CmdThreshold
, 1, "Maximize/minimize every value in the graph window depending on threshold"},
2848 {"tune", CmdTune
, 0, "Measure antenna tuning"},
2849 {"vchdemod", CmdVchdemod
, 0, "['clone'] -- Demodulate samples for VeriChip"},
2850 {"zerocrossings", CmdZerocrossings
, 1, "Count time between zero-crossings"},
2858 } CommandExtendedHelp
[]= {
2859 {"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."},
2860 {"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."},
2863 //-----------------------------------------------------------------------------
2864 // Entry point into our code: called whenever the user types a command and
2865 // then presses Enter, which the full command line that they typed.
2866 //-----------------------------------------------------------------------------
2867 void CommandReceived(char *cmd
)
2872 PrintToScrollback("> %s", cmd
);
2874 if(strcmp(cmd
, "help") == 0 || strncmp(cmd
,"help ",strlen("help ")) == 0) {
2875 // check if we're doing extended help
2876 if(strlen(cmd
) > strlen("help ")) {
2877 cmd
+= strlen("help ");
2878 for(i
= 0; i
< sizeof(CommandExtendedHelp
) / sizeof(CommandExtendedHelp
[0]); i
++) {
2879 if(strcmp(CommandExtendedHelp
[i
].name
,cmd
) == 0) {
2880 PrintToScrollback("\nExtended help for '%s':\n", cmd
);
2881 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp
[i
].args
,CommandExtendedHelp
[i
].argshelp
);
2882 PrintToScrollback(CommandExtendedHelp
[i
].description
);
2883 PrintToScrollback("");
2887 PrintToScrollback("No extended help available for '%s'", cmd
);
2890 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2891 PrintToScrollback("\r\nAvailable commands:");
2892 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2893 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2894 memset(line
, ' ', sizeof(line
));
2895 strcpy(line
+2, CommandTable
[i
].name
);
2896 line
[strlen(line
)] = ' ';
2897 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2898 PrintToScrollback("%s", line
);
2900 PrintToScrollback("");
2901 PrintToScrollback("'help <command>' for extended help on that command\n");
2905 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2906 char *name
= CommandTable
[i
].name
;
2907 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2908 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2910 cmd
+= strlen(name
);
2911 while(*cmd
== ' ') {
2914 if (offline
&& (CommandTable
[i
].offline
==0)) {
2915 PrintToScrollback("Offline mode, cannot use this command.");
2918 (CommandTable
[i
].handler
)(cmd
);
2922 PrintToScrollback(">> bad command '%s'", cmd
);
2925 //-----------------------------------------------------------------------------
2926 // Entry point into our code: called whenever we received a packet over USB
2927 // that we weren't necessarily expecting, for example a debug print.
2928 //-----------------------------------------------------------------------------
2929 void UsbCommandReceived(UsbCommand
*c
)
2932 case CMD_DEBUG_PRINT_STRING
: {
2934 if(c
->ext1
> 70 || c
->ext1
< 0) {
2937 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
2939 PrintToScrollback("#db# %s", s
);
2943 case CMD_DEBUG_PRINT_INTEGERS
:
2944 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
2947 case CMD_MEASURED_ANTENNA_TUNING
: {
2949 int vLf125
, vLf134
, vHf
;
2950 vLf125
= c
->ext1
& 0xffff;
2951 vLf134
= c
->ext1
>> 16;
2952 vHf
= c
->ext2
& 0xffff;;
2953 peakf
= c
->ext3
& 0xffff;
2954 peakv
= c
->ext3
>> 16;
2955 PrintToScrollback("");
2956 PrintToScrollback("");
2957 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125
/1000.0);
2958 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134
/1000.0);
2959 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv
/1000.0, 12000.0/(peakf
+1));
2960 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf
/1000.0);
2962 PrintToScrollback("# Your LF antenna is unusable.");
2963 else if (peakv
<10000)
2964 PrintToScrollback("# Your LF antenna is marginal.");
2966 PrintToScrollback("# Your HF antenna is unusable.");
2968 PrintToScrollback("# Your HF antenna is marginal.");
2972 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);