1 //-----------------------------------------------------------------------------
2 // The actual command interpeter for what the user types at the command line.
3 // Jonathan Westhues, Sept 2005
4 // Edits by Gerhard de Koning Gans, Sep 2007 (##)
5 //-----------------------------------------------------------------------------
14 #include "../common/iso14443_crc.c"
16 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
17 #define BIT(x) GraphBuffer[x * clock]
18 #define BITS (GraphTraceLen / clock)
21 static int CmdHisamplest(char *str
, int nrlow
);
23 static void GetFromBigBuf(BYTE
*dest
, int bytes
)
28 PrintToScrollback("bad len in GetFromBigBuf");
33 for(i
= 0; i
< n
; i
+= 12) {
35 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
37 SendCommand(&c
, FALSE
);
39 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
40 PrintToScrollback("bad resp");
44 memcpy(dest
+(i
*4), c
.d
.asBytes
, 48);
48 static void CmdReset(char *str
)
51 c
.cmd
= CMD_HARDWARE_RESET
;
52 SendCommand(&c
, FALSE
);
55 static void CmdBuffClear(char *str
)
58 c
.cmd
= CMD_BUFF_CLEAR
;
59 SendCommand(&c
, FALSE
);
63 static void CmdQuit(char *str
)
68 static void CmdHIDdemodFSK(char *str
)
71 c
.cmd
= CMD_HID_DEMOD_FSK
;
72 SendCommand(&c
, FALSE
);
75 static void CmdTune(char *str
)
78 c
.cmd
= CMD_MEASURE_ANTENNA_TUNING
;
79 SendCommand(&c
, FALSE
);
82 static void CmdHi15read(char *str
)
85 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693
;
86 SendCommand(&c
, FALSE
);
89 static void CmdHi14read(char *str
)
92 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
94 SendCommand(&c
, FALSE
);
98 /* New command to read the contents of a SRI512 tag
99 * SRI512 tags are ISO14443-B modulated memory tags,
100 * this command just dumps the contents of the memory/
102 static void CmdSri512read(char *str
)
105 c
.cmd
= CMD_READ_SRI512_TAG
;
107 SendCommand(&c
, FALSE
);
111 static void CmdHi14areader(char *str
)
114 c
.cmd
= CMD_READER_ISO_14443a
;
116 SendCommand(&c
, FALSE
);
120 static void CmdHi15reader(char *str
)
123 c
.cmd
= CMD_READER_ISO_15693
;
125 SendCommand(&c
, FALSE
);
129 static void CmdHi15tag(char *str
)
132 c
.cmd
= CMD_SIMTAG_ISO_15693
;
134 SendCommand(&c
, FALSE
);
137 static void CmdHi14read_sim(char *str
)
140 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM
;
142 SendCommand(&c
, FALSE
);
145 static void CmdHi14readt(char *str
)
148 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
150 SendCommand(&c
, FALSE
);
152 //CmdHisamplest(str);
153 while(CmdHisamplest(str
,atoi(str
))==0) {
154 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
156 SendCommand(&c
, FALSE
);
158 RepaintGraphWindow();
161 static void CmdHisimlisten(char *str
)
164 c
.cmd
= CMD_SIMULATE_TAG_HF_LISTEN
;
165 SendCommand(&c
, FALSE
);
168 static void CmdHi14sim(char *str
)
171 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443
;
172 SendCommand(&c
, FALSE
);
175 static void CmdHi14asim(char *str
) // ## simulate iso14443a tag
176 { // ## greg - added ability to specify tag UID
178 unsigned int hi
=0, lo
=0;
182 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
187 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443a
;
188 // c.ext should be set to *str or convert *str to the correct format for a uid
191 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi
, lo
);
192 SendCommand(&c
, FALSE
);
195 static void CmdHi14snoop(char *str
)
198 c
.cmd
= CMD_SNOOP_ISO_14443
;
199 SendCommand(&c
, FALSE
);
202 static void CmdHi14asnoop(char *str
)
205 c
.cmd
= CMD_SNOOP_ISO_14443a
;
206 SendCommand(&c
, FALSE
);
209 static void CmdFPGAOff(char *str
) // ## FPGA Control
212 c
.cmd
= CMD_FPGA_MAJOR_MODE_OFF
;
213 SendCommand(&c
, FALSE
);
216 /* clear out our graph window */
217 int CmdClearGraph(int redraw
)
219 int gtl
= GraphTraceLen
;
223 RepaintGraphWindow();
228 /* write a bit to the graph */
229 static void CmdAppendGraph(int redraw
, int clock
, int bit
)
233 for (i
= 0; i
< (int)(clock
/2); i
++)
234 GraphBuffer
[GraphTraceLen
++] = bit
^ 1;
236 for (i
= (int)(clock
/2); i
< clock
; i
++)
237 GraphBuffer
[GraphTraceLen
++] = bit
;
240 RepaintGraphWindow();
243 /* Function is equivalent of loread + losamples + em410xread
244 * looped until an EM410x tag is detected */
245 static void CmdEM410xwatch(char *str
)
259 /* Read the transmitted data of an EM4x50 tag
262 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
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 * CCCCCCCC <- column parity bits
268 * LW <- Listen Window
270 * This pattern repeats for every block of data being transmitted.
271 * Transmission starts with two Listen Windows (LW - a modulated
272 * pattern of 320 cycles each (32/32/128/64/64)).
274 * Note that this data may or may not be the UID. It is whatever data
275 * is stored in the blocks defined in the control word First and Last
276 * Word Read values. UID is stored in block 32.
278 static void CmdEM4x50read(char *str
)
280 int i
, j
, startblock
, clock
, skip
, block
, start
, end
, low
, high
;
281 BOOL complete
= FALSE
;
282 int tmpbuff
[MAX_GRAPH_TRACE_LEN
/ 64];
288 /* first get high and low values */
289 for (i
= 0; i
< GraphTraceLen
; i
++)
291 if (GraphBuffer
[i
] > high
)
292 high
= GraphBuffer
[i
];
293 else if (GraphBuffer
[i
] < low
)
294 low
= GraphBuffer
[i
];
297 /* populate a buffer with pulse lengths */
300 while(i
< GraphTraceLen
)
302 // measure from low to low
303 while(GraphBuffer
[i
] > low
)
306 while(GraphBuffer
[i
] < high
)
308 while(GraphBuffer
[i
] > low
)
310 tmpbuff
[j
++]= i
- start
;
314 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
317 for (i
= 0; i
< j
- 4 ; ++i
)
320 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
321 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
322 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
323 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
331 /* skip over the remainder of the LW */
332 skip
+= tmpbuff
[i
+1]+tmpbuff
[i
+2];
333 while(GraphBuffer
[skip
] > low
)
337 /* now do it again to find the end */
339 for (i
+= 3; i
< j
- 4 ; ++i
)
342 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
343 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
344 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
345 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
353 PrintToScrollback("Found data at sample: %i",skip
);
356 PrintToScrollback("No data found!");
357 PrintToScrollback("Try again with more samples.");
363 PrintToScrollback("*** Warning!");
364 PrintToScrollback("Partial data - no end found!");
365 PrintToScrollback("Try again with more samples.");
368 /* get rid of leading crap */
369 sprintf(tmp
,"%i",skip
);
372 /* now work through remaining buffer printing out data blocks */
377 PrintToScrollback("Block %i:", block
);
378 // mandemod routine needs to be split so we can call it for data
379 // just print for now for debugging
380 Cmdmanchesterdemod("i 64");
382 /* look for LW before start of next block */
383 for ( ; i
< j
- 4 ; ++i
)
386 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
387 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
390 while(GraphBuffer
[skip
] > low
)
393 sprintf(tmp
,"%i",skip
);
401 /* Read the ID of an EM410x tag.
403 * 1111 1111 1 <-- standard non-repeatable header
404 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
406 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
407 * 0 <-- stop bit, end of tag
409 static void CmdEM410xread(char *str
)
411 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
415 int BitStream
[MAX_GRAPH_TRACE_LEN
];
418 /* Detect high and lows and clock */
419 for (i
= 0; i
< GraphTraceLen
; i
++)
421 if (GraphBuffer
[i
] > high
)
422 high
= GraphBuffer
[i
];
423 else if (GraphBuffer
[i
] < low
)
424 low
= GraphBuffer
[i
];
428 clock
= GetClock(str
, high
);
430 /* parity for our 4 columns */
431 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
434 /* manchester demodulate */
436 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
442 /* Find out if we hit both high and low peaks */
443 for (j
= 0; j
< clock
; j
++)
445 if (GraphBuffer
[(i
* clock
) + j
] == high
)
447 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
450 /* it doesn't count if it's the first part of our read
451 because it's really just trailing from the last sequence */
452 if (first
&& (hithigh
|| hitlow
))
453 hithigh
= hitlow
= 0;
457 if (hithigh
&& hitlow
)
461 /* If we didn't hit both high and low peaks, we had a bit transition */
462 if (!hithigh
|| !hitlow
)
465 BitStream
[bit2idx
++] = bit
;
469 /* We go till 5 before the graph ends because we'll get that far below */
470 for (i
= 1; i
< bit2idx
- 5; i
++)
472 /* Step 2: We have our header but need our tag ID */
473 if (header
== 9 && rows
< 10)
475 /* Confirm parity is correct */
476 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
478 /* Read another byte! */
479 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
482 /* Keep parity info */
483 parity
[0] ^= BitStream
[i
];
484 parity
[1] ^= BitStream
[i
+1];
485 parity
[2] ^= BitStream
[i
+2];
486 parity
[3] ^= BitStream
[i
+3];
488 /* Move 4 bits ahead */
492 /* Damn, something wrong! reset */
495 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
497 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
498 i
-= 9 + (5 * rows
) - 5;
504 /* Step 3: Got our 40 bits! confirm column parity */
507 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
508 if (BitStream
[i
] == parity
[0] && BitStream
[i
+1] == parity
[1] &&
509 BitStream
[i
+2] == parity
[2] && BitStream
[i
+3] == parity
[3] &&
513 PrintToScrollback("EM410x Tag ID: %s", id
);
520 /* Crap! Incorrect parity or no stop bit, start all over */
525 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
530 /* Step 1: get our header */
533 /* Need 9 consecutive 1's */
534 if (BitStream
[i
] == 1)
537 /* We don't have a header, not enough consecutive 1 bits */
543 /* if we've already retested after flipping bits, return */
547 /* if this didn't work, try flipping bits */
548 for (i
= 0; i
< bit2idx
; i
++)
554 /* emulate an EM410X tag
556 * 1111 1111 1 <-- standard non-repeatable header
557 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
559 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
560 * 0 <-- stop bit, end of tag
562 static void CmdEM410xsim(char *str
)
564 int i
, n
, j
, h
, binary
[4], parity
[4];
567 /* clock is 64 in EM410x tags */
570 /* clear our graph */
573 /* write it out a few times */
574 for (h
= 0; h
< 4; h
++)
576 /* write 9 start bits */
577 for (i
= 0; i
< 9; i
++)
578 CmdAppendGraph(0, clock
, 1);
580 /* for each hex char */
581 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
582 for (i
= 0; i
< 10; i
++)
584 /* read each hex char */
585 sscanf(&str
[i
], "%1x", &n
);
586 for (j
= 3; j
>= 0; j
--, n
/= 2)
589 /* append each bit */
590 CmdAppendGraph(0, clock
, binary
[0]);
591 CmdAppendGraph(0, clock
, binary
[1]);
592 CmdAppendGraph(0, clock
, binary
[2]);
593 CmdAppendGraph(0, clock
, binary
[3]);
595 /* append parity bit */
596 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
598 /* keep track of column parity */
599 parity
[0] ^= binary
[0];
600 parity
[1] ^= binary
[1];
601 parity
[2] ^= binary
[2];
602 parity
[3] ^= binary
[3];
606 CmdAppendGraph(0, clock
, parity
[0]);
607 CmdAppendGraph(0, clock
, parity
[1]);
608 CmdAppendGraph(0, clock
, parity
[2]);
609 CmdAppendGraph(0, clock
, parity
[3]);
612 CmdAppendGraph(0, clock
, 0);
615 /* modulate that biatch */
619 RepaintGraphWindow();
624 static void ChkBitstream(char *str
)
628 /* convert to bitstream if necessary */
629 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
631 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
639 static void CmdLosim(char *str
)
643 /* convert to bitstream if necessary */
646 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
649 for(j
= 0; j
< 48; j
++) {
650 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
652 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
654 SendCommand(&c
, FALSE
);
658 c
.cmd
= CMD_SIMULATE_TAG_125K
;
659 c
.ext1
= GraphTraceLen
;
660 SendCommand(&c
, FALSE
);
663 static void CmdLoread(char *str
)
666 // 'h' means higher-low-frequency, 134 kHz
669 } else if (*str
== '\0') {
672 PrintToScrollback("use 'loread' or 'loread h'");
675 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
676 SendCommand(&c
, FALSE
);
679 static void CmdDetectReader(char *str
)
682 // 'l' means LF - 125/134 kHz
685 } else if (*str
== 'h') {
687 } else if (*str
!= '\0') {
688 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");
691 c
.cmd
= CMD_LISTEN_READER_FIELD
;
692 SendCommand(&c
, FALSE
);
695 /* send a command before reading */
696 static void CmdLoCommandRead(char *str
)
698 static char dummy
[3];
703 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
704 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, (char *) &c
.d
.asBytes
,(char *) &dummy
+1);
705 // in case they specified 'h'
706 strcpy((char *)&c
.d
.asBytes
+ strlen((char *)c
.d
.asBytes
), dummy
);
707 SendCommand(&c
, FALSE
);
710 static void CmdLosamples(char *str
)
718 if (n
>16000) n
=16000;
720 for(i
= 0; i
< n
; i
+= 12) {
722 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
724 SendCommand(&c
, FALSE
);
726 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
728 PrintToScrollback("bad resp");
732 for(j
= 0; j
< 48; j
++) {
733 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
737 RepaintGraphWindow();
740 static void CmdBitsamples(char *str
)
747 for(i
= 0; i
< n
; i
+= 12) {
749 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
751 SendCommand(&c
, FALSE
);
753 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
754 PrintToScrollback("bad resp");
758 for(j
= 0; j
< 48; j
++) {
759 for(k
= 0; k
< 8; k
++) {
760 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
761 GraphBuffer
[cnt
++] = 1;
763 GraphBuffer
[cnt
++] = 0;
769 RepaintGraphWindow();
772 static void CmdHisamples(char *str
)
778 for(i
= 0; i
< n
; i
+= 12) {
780 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
782 SendCommand(&c
, FALSE
);
784 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
785 PrintToScrollback("bad resp");
789 for(j
= 0; j
< 48; j
++) {
790 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
795 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) {
1411 c
.cmd
= CMD_DOWNLOAD_RAW_BITS_TI_TYPE
;
1413 SendCommand(&c
, FALSE
);
1415 if(c
.cmd
!= CMD_DOWNLOADED_RAW_BITS_TI_TYPE
) {
1416 PrintToScrollback("bad resp");
1420 for(j
= 0; j
< 12; j
++) {
1422 for(k
= 31; k
>= 0; k
--) {
1423 if(c
.d
.asDwords
[j
] & (1 << k
)) {
1424 GraphBuffer
[cnt
++] = 1;
1426 GraphBuffer
[cnt
++] = -1;
1431 GraphTraceLen
= 1536*32;
1432 RepaintGraphWindow();
1435 static void CmdTidemod(char *cmdline
)
1437 /* MATLAB as follows:
1438 f_s = 2000000; % sampling frequency
1439 f_l = 123200; % low FSK tone
1440 f_h = 134200; % high FSK tone
1442 T_l = 119e-6; % low bit duration
1443 T_h = 130e-6; % high bit duration
1445 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1446 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1448 l = sign(sin(cumsum(l)));
1449 h = sign(sin(cumsum(h)));
1451 static const int LowTone
[] = {
1452 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,
1453 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1454 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
1455 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
1456 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,
1457 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
1458 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,
1459 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1460 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
1461 -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,
1462 -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1463 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
1464 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
1466 static const int HighTone
[] = {
1467 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1468 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1469 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1470 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1471 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1472 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1473 -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1474 -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1475 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1476 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
1477 -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1478 -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
1479 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
1480 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,
1483 int convLen
= max(arraylen(HighTone
), arraylen(LowTone
));
1486 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1488 int lowSum
= 0, highSum
= 0;;
1489 int lowLen
= arraylen(LowTone
);
1490 int highLen
= arraylen(HighTone
);
1492 for(j
= 0; j
< lowLen
; j
++) {
1493 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1495 for(j
= 0; j
< highLen
; j
++) {
1496 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1498 lowSum
= abs((100*lowSum
) / lowLen
);
1499 highSum
= abs((100*highSum
) / highLen
);
1500 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1503 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1505 int lowTot
= 0, highTot
= 0;
1506 // 16 and 15 are f_s divided by f_l and f_h, rounded
1507 for(j
= 0; j
< 16; j
++) {
1508 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1510 for(j
= 0; j
< 15; j
++) {
1511 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1513 GraphBuffer
[i
] = lowTot
- highTot
;
1516 GraphTraceLen
-= (convLen
+ 16);
1518 RepaintGraphWindow();
1520 // Okay, so now we have unsliced soft decisions; find bit-sync, and then
1523 int max
= 0, maxPos
= 0;
1524 for(i
= 0; i
< 6000; i
++) {
1527 for(j
= 0; j
< 8*arraylen(LowTone
); j
++) {
1528 dec
-= GraphBuffer
[i
+j
];
1530 for(; j
< 8*arraylen(LowTone
) + 8*arraylen(HighTone
); j
++) {
1531 dec
+= GraphBuffer
[i
+j
];
1538 GraphBuffer
[maxPos
] = 800;
1539 GraphBuffer
[maxPos
+1] = -800;
1541 maxPos
+= 8*arraylen(LowTone
);
1542 GraphBuffer
[maxPos
] = 800;
1543 GraphBuffer
[maxPos
+1] = -800;
1544 maxPos
+= 8*arraylen(HighTone
);
1546 GraphBuffer
[maxPos
] = 800;
1547 GraphBuffer
[maxPos
+1] = -800;
1549 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1551 PrintToScrollback("length %d/%d", arraylen(HighTone
), arraylen(LowTone
));
1553 GraphBuffer
[maxPos
] = 800;
1554 GraphBuffer
[maxPos
+1] = -800;
1556 BYTE bits
[64+16+8+1];
1557 bits
[sizeof(bits
)-1] = '\0';
1559 for(i
= 0; i
< arraylen(bits
); i
++) {
1563 for(j
= 0; j
< arraylen(LowTone
); j
++) {
1564 low
-= GraphBuffer
[maxPos
+j
];
1566 for(j
= 0; j
< arraylen(HighTone
); j
++) {
1567 high
+= GraphBuffer
[maxPos
+j
];
1571 maxPos
+= arraylen(HighTone
);
1574 maxPos
+= arraylen(LowTone
);
1576 GraphBuffer
[maxPos
] = 800;
1577 GraphBuffer
[maxPos
+1] = -800;
1579 PrintToScrollback("bits: '%s'", bits
);
1582 for(i
= 0; i
< 32; i
++) {
1583 if(bits
[i
] == '1') {
1587 for(i
= 32; i
< 64; i
++) {
1588 if(bits
[i
] == '1') {
1592 PrintToScrollback("hex: %08x %08x", h
, l
);
1595 static void CmdNorm(char *str
)
1598 int max
= INT_MIN
, min
= INT_MAX
;
1599 for(i
= 10; i
< GraphTraceLen
; i
++) {
1600 if(GraphBuffer
[i
] > max
) {
1601 max
= GraphBuffer
[i
];
1603 if(GraphBuffer
[i
] < min
) {
1604 min
= GraphBuffer
[i
];
1608 for(i
= 0; i
< GraphTraceLen
; i
++) {
1609 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1613 RepaintGraphWindow();
1616 static void CmdDec(char *str
)
1619 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1620 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1623 PrintToScrollback("decimated by 2");
1624 RepaintGraphWindow();
1627 static void CmdHpf(char *str
)
1631 for(i
= 10; i
< GraphTraceLen
; i
++) {
1632 accum
+= GraphBuffer
[i
];
1634 accum
/= (GraphTraceLen
- 10);
1635 for(i
= 0; i
< GraphTraceLen
; i
++) {
1636 GraphBuffer
[i
] -= accum
;
1639 RepaintGraphWindow();
1642 static void CmdZerocrossings(char *str
)
1645 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1651 for(i
= 0; i
< GraphTraceLen
; i
++) {
1652 if(GraphBuffer
[i
]*sign
>= 0) {
1653 // No change in sign, reproduce the previous sample count.
1655 GraphBuffer
[i
] = lastZc
;
1657 // Change in sign, reset the sample count.
1659 GraphBuffer
[i
] = lastZc
;
1667 RepaintGraphWindow();
1670 static void CmdLtrim(char *str
)
1675 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1676 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1678 GraphTraceLen
-= ds
;
1680 RepaintGraphWindow();
1683 static void CmdAutoCorr(char *str
)
1685 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1687 int window
= atoi(str
);
1690 PrintToScrollback("needs a window");
1694 if(window
>= GraphTraceLen
) {
1695 PrintToScrollback("window must be smaller than trace (%d samples)",
1700 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1703 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1706 for(j
= 0; j
< window
; j
++) {
1707 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1709 CorrelBuffer
[i
] = sum
;
1711 GraphTraceLen
= GraphTraceLen
- window
;
1712 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1714 RepaintGraphWindow();
1717 static void CmdVchdemod(char *str
)
1719 // Is this the entire sync pattern, or does this also include some
1720 // data bits that happen to be the same everywhere? That would be
1722 static const int SyncPattern
[] = {
1723 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1724 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1725 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1726 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1727 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1728 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1729 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1730 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1731 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1732 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1735 // So first, we correlate for the sync pattern, and mark that.
1736 int bestCorrel
= 0, bestPos
= 0;
1738 // It does us no good to find the sync pattern, with fewer than
1739 // 2048 samples after it...
1740 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
1743 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
1744 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
1746 if(sum
> bestCorrel
) {
1751 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
1756 int worst
= INT_MAX
;
1759 for(i
= 0; i
< 2048; i
+= 8) {
1762 for(j
= 0; j
< 8; j
++) {
1763 sum
+= GraphBuffer
[bestPos
+i
+j
];
1770 if(abs(sum
) < worst
) {
1775 PrintToScrollback("bits:");
1776 PrintToScrollback("%s", bits
);
1777 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
1779 if(strcmp(str
, "clone")==0) {
1782 for(s
= bits
; *s
; s
++) {
1784 for(j
= 0; j
< 16; j
++) {
1785 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
1788 RepaintGraphWindow();
1792 static void CmdIndalademod(char *str
)
1794 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
1799 // worst case with GraphTraceLen=64000 is < 4096
1800 // under normal conditions it's < 2048
1803 int worst
= 0, worstPos
= 0;
1804 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
1805 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
1807 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
1809 for(j
= 0; j
< count
- 8; j
+= 16) {
1810 rawbits
[rawbit
++] = 0;
1812 if ((abs(count
- j
)) > worst
) {
1813 worst
= abs(count
- j
);
1819 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
1821 for(j
= 0; j
< count
- 8; j
+= 16) {
1822 rawbits
[rawbit
++] = 1;
1824 if ((abs(count
- j
)) > worst
) {
1825 worst
= abs(count
- j
);
1833 PrintToScrollback("Recovered %d raw bits", rawbit
);
1834 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
1836 // Finding the start of a UID
1837 int uidlen
, long_wait
;
1838 if(strcmp(str
, "224") == 0) {
1847 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
1848 first
= rawbits
[start
];
1849 for(i
= start
; i
< start
+ long_wait
; i
++) {
1850 if(rawbits
[i
] != first
) {
1854 if(i
== (start
+ long_wait
)) {
1858 if(start
== rawbit
- uidlen
+ 1) {
1859 PrintToScrollback("nothing to wait for");
1863 // Inverting signal if needed
1865 for(i
= start
; i
< rawbit
; i
++) {
1866 rawbits
[i
] = !rawbits
[i
];
1873 showbits
[uidlen
]='\0';
1877 if(uidlen
> rawbit
) {
1878 PrintToScrollback("Warning: not enough raw bits to get a full UID");
1879 for(bit
= 0; bit
< rawbit
; bit
++) {
1880 bits
[bit
] = rawbits
[i
++];
1881 // As we cannot know the parity, let's use "." and "/"
1882 showbits
[bit
] = '.' + bits
[bit
];
1884 showbits
[bit
+1]='\0';
1885 PrintToScrollback("Partial UID=%s", showbits
);
1888 for(bit
= 0; bit
< uidlen
; bit
++) {
1889 bits
[bit
] = rawbits
[i
++];
1890 showbits
[bit
] = '0' + bits
[bit
];
1894 PrintToScrollback("UID=%s", showbits
);
1896 // Checking UID against next occurences
1897 for(; i
+ uidlen
<= rawbit
;) {
1899 for(bit
= 0; bit
< uidlen
; bit
++) {
1900 if(bits
[bit
] != rawbits
[i
++]) {
1910 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
1912 // Remodulating for tag cloning
1913 GraphTraceLen
= 32*uidlen
;
1916 for(bit
= 0; bit
< uidlen
; bit
++) {
1917 if(bits
[bit
] == 0) {
1923 for(j
= 0; j
< 32; j
++) {
1924 GraphBuffer
[i
++] = phase
;
1929 RepaintGraphWindow();
1932 static void CmdFlexdemod(char *str
)
1935 for(i
= 0; i
< GraphTraceLen
; i
++) {
1936 if(GraphBuffer
[i
] < 0) {
1937 GraphBuffer
[i
] = -1;
1943 #define LONG_WAIT 100
1945 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
1946 int first
= GraphBuffer
[start
];
1947 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
1948 if(GraphBuffer
[i
] != first
) {
1952 if(i
== (start
+ LONG_WAIT
)) {
1956 if(start
== GraphTraceLen
- LONG_WAIT
) {
1957 PrintToScrollback("nothing to wait for");
1961 GraphBuffer
[start
] = 2;
1962 GraphBuffer
[start
+1] = -2;
1968 for(bit
= 0; bit
< 64; bit
++) {
1971 for(j
= 0; j
< 16; j
++) {
1972 sum
+= GraphBuffer
[i
++];
1979 PrintToScrollback("bit %d sum %d", bit
, sum
);
1982 for(bit
= 0; bit
< 64; bit
++) {
1985 for(j
= 0; j
< 16; j
++) {
1986 sum
+= GraphBuffer
[i
++];
1988 if(sum
> 0 && bits
[bit
] != 1) {
1989 PrintToScrollback("oops1 at %d", bit
);
1991 if(sum
< 0 && bits
[bit
] != 0) {
1992 PrintToScrollback("oops2 at %d", bit
);
1996 GraphTraceLen
= 32*64;
1999 for(bit
= 0; bit
< 64; bit
++) {
2000 if(bits
[bit
] == 0) {
2006 for(j
= 0; j
< 32; j
++) {
2007 GraphBuffer
[i
++] = phase
;
2012 RepaintGraphWindow();
2016 * Generic command to demodulate ASK.
2018 * Argument is convention: positive or negative (High mod means zero
2019 * or high mod means one)
2021 * Updates the Graph trace with 0/1 values
2027 static void Cmdaskdemod(char *str
) {
2029 int c
, high
= 0, low
= 0;
2031 // TODO: complain if we do not give 2 arguments here !
2032 sscanf(str
, "%i", &c
);
2034 /* Detect high and lows and clock */
2035 for (i
= 0; i
< GraphTraceLen
; i
++)
2037 if (GraphBuffer
[i
] > high
)
2038 high
= GraphBuffer
[i
];
2039 else if (GraphBuffer
[i
] < low
)
2040 low
= GraphBuffer
[i
];
2043 if (GraphBuffer
[0] > 0) {
2044 GraphBuffer
[0] = 1-c
;
2048 for(i
=1;i
<GraphTraceLen
;i
++) {
2049 /* Transitions are detected at each peak
2050 * Transitions are either:
2051 * - we're low: transition if we hit a high
2052 * - we're high: transition if we hit a low
2053 * (we need to do it this way because some tags keep high or
2054 * low for long periods, others just reach the peak and go
2057 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
2059 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
2063 GraphBuffer
[i
] = GraphBuffer
[i
-1];
2066 RepaintGraphWindow();
2069 /* Print our clock rate */
2070 static void Cmddetectclockrate(char *str
)
2072 int clock
= detectclock(0);
2073 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2079 int detectclock(int peak
)
2085 /* Detect peak if we don't have one */
2087 for (i
= 0; i
< GraphTraceLen
; i
++)
2088 if (GraphBuffer
[i
] > peak
)
2089 peak
= GraphBuffer
[i
];
2091 for (i
= 1; i
< GraphTraceLen
; i
++)
2093 /* If this is the beginning of a peak */
2094 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
2096 /* Find lowest difference between peaks */
2097 if (lastpeak
&& i
- lastpeak
< clock
)
2099 clock
= i
- lastpeak
;
2108 /* Get or auto-detect clock rate */
2109 int GetClock(char *str
, int peak
)
2113 sscanf(str
, "%i", &clock
);
2114 if (!strcmp(str
, ""))
2117 /* Auto-detect clock */
2120 clock
= detectclock(peak
);
2122 /* Only print this message if we're not looping something */
2124 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2131 * Convert to a bitstream
2133 static void Cmdbitstream(char *str
) {
2140 int hithigh
, hitlow
, first
;
2142 /* Detect high and lows and clock */
2143 for (i
= 0; i
< GraphTraceLen
; i
++)
2145 if (GraphBuffer
[i
] > high
)
2146 high
= GraphBuffer
[i
];
2147 else if (GraphBuffer
[i
] < low
)
2148 low
= GraphBuffer
[i
];
2152 clock
= GetClock(str
, high
);
2154 gtl
= CmdClearGraph(0);
2157 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2163 /* Find out if we hit both high and low peaks */
2164 for (j
= 0; j
< clock
; j
++)
2166 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2168 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2171 /* it doesn't count if it's the first part of our read
2172 because it's really just trailing from the last sequence */
2173 if (first
&& (hithigh
|| hitlow
))
2174 hithigh
= hitlow
= 0;
2178 if (hithigh
&& hitlow
)
2182 /* If we didn't hit both high and low peaks, we had a bit transition */
2183 if (!hithigh
|| !hitlow
)
2186 CmdAppendGraph(0, clock
, bit
);
2187 // for (j = 0; j < (int)(clock/2); j++)
2188 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2189 // for (j = (int)(clock/2); j < clock; j++)
2190 // GraphBuffer[(i * clock) + j] = bit;
2193 RepaintGraphWindow();
2196 /* Modulate our data into manchester */
2197 static void Cmdmanchestermod(char *str
)
2201 int bit
, lastbit
, wave
;
2204 clock
= GetClock(str
, 0);
2208 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2210 bit
= GraphBuffer
[i
* clock
] ^ 1;
2212 for (j
= 0; j
< (int)(clock
/2); j
++)
2213 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2214 for (j
= (int)(clock
/2); j
< clock
; j
++)
2215 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2217 /* Keep track of how we start our wave and if we changed or not this time */
2218 wave
^= bit
^ lastbit
;
2222 RepaintGraphWindow();
2226 * Manchester demodulate a bitstream. The bitstream needs to be already in
2227 * the GraphBuffer as 0 and 1 values
2229 * Give the clock rate as argument in order to help the sync - the algorithm
2230 * resyncs at each pulse anyway.
2232 * Not optimized by any means, this is the 1st time I'm writing this type of
2233 * routine, feel free to improve...
2235 * 1st argument: clock rate (as number of samples per clock rate)
2236 * Typical values can be 64, 32, 128...
2238 static void Cmdmanchesterdemod(char *str
) {
2239 int i
, j
, invert
= 0;
2245 int hithigh
, hitlow
, first
;
2251 /* check if we're inverting output */
2254 PrintToScrollback("Inverting output");
2258 while(*str
== ' '); // in case a 2nd argument was given
2261 /* Holds the decoded bitstream: each clock period contains 2 bits */
2262 /* later simplified to 1 bit after manchester decoding. */
2263 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2264 /* int BitStream[GraphTraceLen*2/clock+10]; */
2266 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2268 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2270 /* Detect high and lows */
2271 for (i
= 0; i
< GraphTraceLen
; i
++)
2273 if (GraphBuffer
[i
] > high
)
2274 high
= GraphBuffer
[i
];
2275 else if (GraphBuffer
[i
] < low
)
2276 low
= GraphBuffer
[i
];
2280 clock
= GetClock(str
, high
);
2282 int tolerance
= clock
/4;
2284 /* Detect first transition */
2285 /* Lo-Hi (arbitrary) */
2286 for (i
= 0; i
< GraphTraceLen
; i
++)
2288 if (GraphBuffer
[i
] == low
)
2295 /* If we're not working with 1/0s, demod based off clock */
2298 bit
= 0; /* We assume the 1st bit is zero, it may not be
2299 * the case: this routine (I think) has an init problem.
2302 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2308 /* Find out if we hit both high and low peaks */
2309 for (j
= 0; j
< clock
; j
++)
2311 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2313 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2316 /* it doesn't count if it's the first part of our read
2317 because it's really just trailing from the last sequence */
2318 if (first
&& (hithigh
|| hitlow
))
2319 hithigh
= hitlow
= 0;
2323 if (hithigh
&& hitlow
)
2327 /* If we didn't hit both high and low peaks, we had a bit transition */
2328 if (!hithigh
|| !hitlow
)
2331 BitStream
[bit2idx
++] = bit
^ invert
;
2335 /* standard 1/0 bitstream */
2339 /* Then detect duration between 2 successive transitions */
2340 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2342 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2347 // Error check: if bitidx becomes too large, we do not
2348 // have a Manchester encoded bitstream or the clock is really
2350 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2351 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2354 // Then switch depending on lc length:
2355 // Tolerance is 1/4 of clock rate (arbitrary)
2356 if (abs(lc
-clock
/2) < tolerance
) {
2357 // Short pulse : either "1" or "0"
2358 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2359 } else if (abs(lc
-clock
) < tolerance
) {
2360 // Long pulse: either "11" or "00"
2361 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2362 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2366 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2367 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2371 PrintToScrollback("Error: too many detection errors, aborting.");
2378 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2379 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2380 // to stop output at the final bitidx2 value, not bitidx
2381 for (i
= 0; i
< bitidx
; i
+= 2) {
2382 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2383 BitStream
[bit2idx
++] = 1 ^ invert
;
2384 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2385 BitStream
[bit2idx
++] = 0 ^ invert
;
2387 // We cannot end up in this state, this means we are unsynchronized,
2391 PrintToScrollback("Unsynchronized, resync...");
2392 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2396 PrintToScrollback("Error: too many decode errors, aborting.");
2403 PrintToScrollback("Manchester decoded bitstream");
2404 // Now output the bitstream to the scrollback by line of 16 bits
2405 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2406 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2431 static void CmdHiddemod(char *str
)
2433 if(GraphTraceLen
< 4800) {
2434 PrintToScrollback("too short; need at least 4800 samples");
2438 GraphTraceLen
= 4800;
2440 for(i
= 0; i
< GraphTraceLen
; i
++) {
2441 if(GraphBuffer
[i
] < 0) {
2447 RepaintGraphWindow();
2450 static void CmdPlot(char *str
)
2455 static void CmdHide(char *str
)
2460 static void CmdScale(char *str
)
2462 CursorScaleFactor
= atoi(str
);
2463 if(CursorScaleFactor
== 0) {
2464 PrintToScrollback("bad, can't have zero scale");
2465 CursorScaleFactor
= 1;
2467 RepaintGraphWindow();
2470 static void CmdSave(char *str
)
2472 FILE *f
= fopen(str
, "w");
2474 PrintToScrollback("couldn't open '%s'", str
);
2478 for(i
= 0; i
< GraphTraceLen
; i
++) {
2479 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2482 PrintToScrollback("saved to '%s'", str
);
2485 static void CmdLoad(char *str
)
2487 FILE *f
= fopen(str
, "r");
2489 PrintToScrollback("couldn't open '%s'", str
);
2495 while(fgets(line
, sizeof(line
), f
)) {
2496 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2500 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2501 RepaintGraphWindow();
2504 static void CmdHIDsimTAG(char *str
)
2506 unsigned int hi
=0, lo
=0;
2510 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2511 hi
=(hi
<<4)|(lo
>>28);
2515 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2517 c
.cmd
= CMD_HID_SIM_TAG
;
2520 SendCommand(&c
, FALSE
);
2523 static void CmdReadmem(char *str
)
2526 c
.cmd
= CMD_READ_MEM
;
2528 SendCommand(&c
, FALSE
);
2531 static void CmdLcdReset(char *str
)
2534 c
.cmd
= CMD_LCD_RESET
;
2536 SendCommand(&c
, FALSE
);
2539 static void CmdLcd(char *str
)
2544 sscanf(str
, "%x %d", &i
, &j
);
2547 SendCommand(&c
, FALSE
);
2553 static void CmdTest(char *str
)
2558 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2561 static void CmdSetDivisor(char *str
)
2564 c
.cmd
= CMD_SET_LF_DIVISOR
;
2566 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2567 PrintToScrollback("divisor must be between 19 and 255");
2569 SendCommand(&c
, FALSE
);
2570 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2574 typedef void HandlerFunction(char *cmdline
);
2576 /* in alphabetic order */
2579 HandlerFunction
*handler
;
2580 int offline
; // 1 if the command can be used when in offline mode
2582 } CommandTable
[] = {
2583 {"askdemod", Cmdaskdemod
,1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags"},
2584 {"autocorr", CmdAutoCorr
,1, "<window length> -- Autocorrelation over window"},
2585 {"bitsamples", CmdBitsamples
,0, " Get raw samples as bitstring"},
2586 {"bitstream", Cmdbitstream
,1, "[clock rate] -- Convert waveform into a bitstream"},
2587 {"buffclear", CmdBuffClear
,0, " Clear sample buffer and graph window"},
2588 {"dec", CmdDec
,1, " Decimate samples"},
2589 {"detectclock", Cmddetectclockrate
,1, " Detect clock rate"},
2590 {"detectreader", CmdDetectReader
,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
2591 {"em410xsim", CmdEM410xsim
,1, "<UID> -- Simulate EM410x tag"},
2592 {"em410xread", CmdEM410xread
,1, "[clock rate] -- Extract ID from EM410x tag"},
2593 {"em410xwatch", CmdEM410xwatch
,0, " Watches for EM410x tags"},
2594 {"em4x50read", CmdEM4x50read
,1, " Extract data from EM4x50 tag"},
2595 {"exit", CmdQuit
,1, " Exit program"},
2596 {"flexdemod", CmdFlexdemod
,1, " Demodulate samples for FlexPass"},
2597 {"fpgaoff", CmdFPGAOff
,0, " Set FPGA off"}, // ## FPGA Control
2598 {"hexsamples", CmdHexsamples
,0, "<blocks> -- Dump big buffer as hex bytes"},
2599 {"hi14alist", CmdHi14alist
,0, " List ISO 14443a history"}, // ## New list command
2600 {"hi14areader", CmdHi14areader
,0, " Act like an ISO14443 Type A reader"}, // ## New reader command
2601 {"hi14asim", CmdHi14asim
,0, "<UID> -- Fake ISO 14443a tag"}, // ## Simulate 14443a tag
2602 {"hi14asnoop", CmdHi14asnoop
,0, " Eavesdrop ISO 14443 Type A"}, // ## New snoop command
2603 {"hi14bdemod", CmdHi14bdemod
,1, " Demodulate ISO14443 Type B from tag"},
2604 {"hi14list", CmdHi14list
,0, " List ISO 14443 history"},
2605 {"hi14read", CmdHi14read
,0, " Read HF tag (ISO 14443)"},
2606 {"hi14sim", CmdHi14sim
,0, " Fake ISO 14443 tag"},
2607 {"hi14snoop", CmdHi14snoop
,0, " Eavesdrop ISO 14443"},
2608 {"hi15demod", CmdHi15demod
,1, " Demodulate ISO15693 from tag"},
2609 {"hi15read", CmdHi15read
,0, " Read HF tag (ISO 15693)"},
2610 {"hi15reader", CmdHi15reader
,0, " Act like an ISO15693 reader"}, // new command greg
2611 {"hi15sim", CmdHi15tag
,0, " Fake an ISO15693 tag"}, // new command greg
2612 {"hiddemod", CmdHiddemod
,1, " Demodulate HID Prox Card II (not optimal)"},
2613 {"hide", CmdHide
,1, " Hide graph window"},
2614 {"hidfskdemod", CmdHIDdemodFSK
,0, " Realtime HID FSK demodulator"},
2615 {"hidsimtag", CmdHIDsimTAG
,0, "<ID> -- HID tag simulator"},
2616 {"higet", CmdHi14read_sim
,0, "<samples> -- Get samples HF, 'analog'"},
2617 {"hisamples", CmdHisamples
,0, " Get raw samples for HF tag"},
2618 {"hisampless", CmdHisampless
,0, "<samples> -- Get signed raw samples, HF tag"},
2619 {"hisamplest", CmdHi14readt
,0, " Get samples HF, for testing"},
2620 {"hisimlisten", CmdHisimlisten
,0, " Get HF samples as fake tag"},
2621 {"hpf", CmdHpf
,1, " Remove DC offset from trace"},
2622 {"indalademod", CmdIndalademod
,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
2623 {"lcd", CmdLcd
,0, "<HEX command> <count> -- Send command/data to LCD"},
2624 {"lcdreset", CmdLcdReset
,0, " Hardware reset LCD"},
2625 {"load", CmdLoad
,1, "<filename> -- Load trace (to graph window"},
2626 {"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)"},
2627 {"loread", CmdLoread
,0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
2628 {"losamples", CmdLosamples
,0, "[128 - 16000] -- Get raw samples for LF tag"},
2629 {"losim", CmdLosim
,0, " Simulate LF tag"},
2630 {"ltrim", CmdLtrim
,1, "<samples> -- Trim samples from left of trace"},
2631 {"mandemod", Cmdmanchesterdemod
,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
2632 {"manmod", Cmdmanchestermod
,1, "[clock rate] -- Manchester modulate a binary stream"},
2633 {"norm", CmdNorm
,1, " Normalize max/min to +/-500"},
2634 {"plot", CmdPlot
,1, " Show graph window"},
2635 {"quit", CmdQuit
,1, " Quit program"},
2636 {"readmem", CmdReadmem
,0, " [address] -- Read memory at decimal address from flash"},
2637 {"reset", CmdReset
,0, " Reset the Proxmark3"},
2638 {"save", CmdSave
,1, "<filename> -- Save trace (from graph window)"},
2639 {"scale", CmdScale
,1, "<int> -- Set cursor display scale"},
2640 {"setlfdivisor", CmdSetDivisor
,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
2641 {"sri512read", CmdSri512read
,0, "<int> -- Read contents of a SRI512 tag"},
2642 {"tibits", CmdTibits
,0, " Get raw bits for TI-type LF tag"},
2643 {"tidemod", CmdTidemod
,0, " Demodulate raw bits for TI-type LF tag"},
2644 {"tiread", CmdTiread
,0, " Read a TI-type 134 kHz tag"},
2645 {"tune", CmdTune
,0, " Measure antenna tuning"},
2646 {"vchdemod", CmdVchdemod
,0, "['clone'] -- Demodulate samples for VeriChip"},
2647 {"zerocrossings", CmdZerocrossings
,1, " Count time between zero-crossings"},
2655 } CommandExtendedHelp
[]= {
2656 {"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."},
2657 {"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."},
2660 //-----------------------------------------------------------------------------
2661 // Entry point into our code: called whenever the user types a command and
2662 // then presses Enter, which the full command line that they typed.
2663 //-----------------------------------------------------------------------------
2664 void CommandReceived(char *cmd
)
2669 PrintToScrollback("> %s", cmd
);
2671 if(strcmp(cmd
, "help") == 0 || strncmp(cmd
,"help ",strlen("help ")) == 0) {
2672 // check if we're doing extended help
2673 if(strlen(cmd
) > strlen("help ")) {
2674 cmd
+= strlen("help ");
2675 for(i
= 0; i
< sizeof(CommandExtendedHelp
) / sizeof(CommandExtendedHelp
[0]); i
++) {
2676 if(strcmp(CommandExtendedHelp
[i
].name
,cmd
) == 0) {
2677 PrintToScrollback("\nExtended help for '%s':\n", cmd
);
2678 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp
[i
].args
,CommandExtendedHelp
[i
].argshelp
);
2679 PrintToScrollback(CommandExtendedHelp
[i
].description
);
2680 PrintToScrollback("");
2684 PrintToScrollback("No extended help available for '%s'", cmd
);
2687 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2688 PrintToScrollback("\r\nAvailable commands:");
2689 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2690 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2691 memset(line
, ' ', sizeof(line
));
2692 strcpy(line
+2, CommandTable
[i
].name
);
2693 line
[strlen(line
)] = ' ';
2694 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2695 PrintToScrollback("%s", line
);
2697 PrintToScrollback("");
2698 PrintToScrollback("'help <command>' for extended help on that command\n");
2702 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2703 char *name
= CommandTable
[i
].name
;
2704 if(memcmp(cmd
, name
, strlen(name
))==0 &&
2705 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
2707 cmd
+= strlen(name
);
2708 while(*cmd
== ' ') {
2711 if (offline
&& (CommandTable
[i
].offline
==0)) {
2712 PrintToScrollback("Offline mode, cannot use this command.");
2715 (CommandTable
[i
].handler
)(cmd
);
2719 PrintToScrollback(">> bad command '%s'", cmd
);
2722 //-----------------------------------------------------------------------------
2723 // Entry point into our code: called whenever we received a packet over USB
2724 // that we weren't necessarily expecting, for example a debug print.
2725 //-----------------------------------------------------------------------------
2726 void UsbCommandReceived(UsbCommand
*c
)
2729 case CMD_DEBUG_PRINT_STRING
: {
2731 if(c
->ext1
> 70 || c
->ext1
< 0) {
2734 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
2736 PrintToScrollback("#db# %s", s
);
2740 case CMD_DEBUG_PRINT_INTEGERS
:
2741 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
2744 case CMD_MEASURED_ANTENNA_TUNING
: {
2746 int vLf125
, vLf134
, vHf
;
2747 vLf125
= c
->ext1
& 0xffff;
2748 vLf134
= c
->ext1
>> 16;
2749 vHf
= c
->ext2
& 0xffff;;
2750 peakf
= c
->ext3
& 0xffff;
2751 peakv
= c
->ext3
>> 16;
2752 PrintToScrollback("");
2753 PrintToScrollback("");
2754 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125
/1000.0);
2755 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134
/1000.0);
2756 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv
/1000.0, 12000.0/(peakf
+1));
2757 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf
/1000.0);
2759 PrintToScrollback("# Your LF antenna is unusable.");
2760 else if (peakv
<10000)
2761 PrintToScrollback("# Your LF antenna is marginal.");
2763 PrintToScrollback("# Your HF antenna is unusable.");
2765 PrintToScrollback("# Your HF antenna is marginal.");
2769 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);