1 //-----------------------------------------------------------------------------
2 // The actual command interpeter for what the user types at the command line.
3 // Jonathan Westhues, Sept 2005
4 // Edits by Gerhard de Koning Gans, Sep 2007 (##)
5 //-----------------------------------------------------------------------------
14 #include "../common/iso14443_crc.c"
15 #include "../common/crc16.c"
17 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
18 #define BIT(x) GraphBuffer[x * clock]
19 #define BITS (GraphTraceLen / clock)
22 static int CmdHisamplest(char *str
, int nrlow
);
24 static void GetFromBigBuf(BYTE
*dest
, int bytes
)
29 PrintToScrollback("bad len in GetFromBigBuf");
34 for(i
= 0; i
< n
; i
+= 12) {
36 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
38 SendCommand(&c
, FALSE
);
40 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
41 PrintToScrollback("bad resp");
45 memcpy(dest
+(i
*4), c
.d
.asBytes
, 48);
49 static void CmdReset(char *str
)
52 c
.cmd
= CMD_HARDWARE_RESET
;
53 SendCommand(&c
, FALSE
);
56 static void CmdBuffClear(char *str
)
59 c
.cmd
= CMD_BUFF_CLEAR
;
60 SendCommand(&c
, FALSE
);
64 static void CmdQuit(char *str
)
69 static void CmdHIDdemodFSK(char *str
)
72 c
.cmd
= CMD_HID_DEMOD_FSK
;
73 SendCommand(&c
, FALSE
);
76 static void CmdTune(char *str
)
79 c
.cmd
= CMD_MEASURE_ANTENNA_TUNING
;
80 SendCommand(&c
, FALSE
);
83 static void CmdHi15read(char *str
)
86 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693
;
87 SendCommand(&c
, FALSE
);
90 static void CmdHi14read(char *str
)
93 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
95 SendCommand(&c
, FALSE
);
99 /* New command to read the contents of a SRI512 tag
100 * SRI512 tags are ISO14443-B modulated memory tags,
101 * this command just dumps the contents of the memory/
103 static void CmdSri512read(char *str
)
106 c
.cmd
= CMD_READ_SRI512_TAG
;
108 SendCommand(&c
, FALSE
);
112 static void CmdHi14areader(char *str
)
115 c
.cmd
= CMD_READER_ISO_14443a
;
117 SendCommand(&c
, FALSE
);
121 static void CmdHi15reader(char *str
)
124 c
.cmd
= CMD_READER_ISO_15693
;
126 SendCommand(&c
, FALSE
);
130 static void CmdHi15tag(char *str
)
133 c
.cmd
= CMD_SIMTAG_ISO_15693
;
135 SendCommand(&c
, FALSE
);
138 static void CmdHi14read_sim(char *str
)
141 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM
;
143 SendCommand(&c
, FALSE
);
146 static void CmdHi14readt(char *str
)
149 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
151 SendCommand(&c
, FALSE
);
153 //CmdHisamplest(str);
154 while(CmdHisamplest(str
,atoi(str
))==0) {
155 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443
;
157 SendCommand(&c
, FALSE
);
159 RepaintGraphWindow();
162 static void CmdHisimlisten(char *str
)
165 c
.cmd
= CMD_SIMULATE_TAG_HF_LISTEN
;
166 SendCommand(&c
, FALSE
);
169 static void CmdHi14sim(char *str
)
172 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443
;
173 SendCommand(&c
, FALSE
);
176 static void CmdHi14asim(char *str
) // ## simulate iso14443a tag
177 { // ## greg - added ability to specify tag UID
179 unsigned int hi
=0, lo
=0;
183 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
188 c
.cmd
= CMD_SIMULATE_TAG_ISO_14443a
;
189 // c.ext should be set to *str or convert *str to the correct format for a uid
192 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi
, lo
);
193 SendCommand(&c
, FALSE
);
196 static void CmdHi14snoop(char *str
)
199 c
.cmd
= CMD_SNOOP_ISO_14443
;
200 SendCommand(&c
, FALSE
);
203 static void CmdHi14asnoop(char *str
)
206 c
.cmd
= CMD_SNOOP_ISO_14443a
;
207 SendCommand(&c
, FALSE
);
210 static void CmdLegicRfSim(char *str
)
213 c
.cmd
= CMD_SIMULATE_TAG_LEGIC_RF
;
214 SendCommand(&c
, FALSE
);
217 static void CmdLegicRfRead(char *str
)
220 c
.cmd
= CMD_READER_LEGIC_RF
;
221 SendCommand(&c
, FALSE
);
224 static void CmdFPGAOff(char *str
) // ## FPGA Control
227 c
.cmd
= CMD_FPGA_MAJOR_MODE_OFF
;
228 SendCommand(&c
, FALSE
);
231 /* clear out our graph window */
232 int CmdClearGraph(int redraw
)
234 int gtl
= GraphTraceLen
;
238 RepaintGraphWindow();
243 /* write a bit to the graph */
244 static void CmdAppendGraph(int redraw
, int clock
, int bit
)
248 for (i
= 0; i
< (int)(clock
/2); i
++)
249 GraphBuffer
[GraphTraceLen
++] = bit
^ 1;
251 for (i
= (int)(clock
/2); i
< clock
; i
++)
252 GraphBuffer
[GraphTraceLen
++] = bit
;
255 RepaintGraphWindow();
258 /* Function is equivalent of loread + losamples + em410xread
259 * looped until an EM410x tag is detected */
260 static void CmdEM410xwatch(char *str
)
274 /* Read the transmitted data of an EM4x50 tag
277 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
278 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
279 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
280 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
281 * CCCCCCCC <- column parity bits
283 * LW <- Listen Window
285 * This pattern repeats for every block of data being transmitted.
286 * Transmission starts with two Listen Windows (LW - a modulated
287 * pattern of 320 cycles each (32/32/128/64/64)).
289 * Note that this data may or may not be the UID. It is whatever data
290 * is stored in the blocks defined in the control word First and Last
291 * Word Read values. UID is stored in block 32.
293 static void CmdEM4x50read(char *str
)
295 int i
, j
, startblock
, clock
, skip
, block
, start
, end
, low
, high
;
296 BOOL complete
= FALSE
;
297 int tmpbuff
[MAX_GRAPH_TRACE_LEN
/ 64];
303 /* first get high and low values */
304 for (i
= 0; i
< GraphTraceLen
; i
++)
306 if (GraphBuffer
[i
] > high
)
307 high
= GraphBuffer
[i
];
308 else if (GraphBuffer
[i
] < low
)
309 low
= GraphBuffer
[i
];
312 /* populate a buffer with pulse lengths */
315 while(i
< GraphTraceLen
)
317 // measure from low to low
318 while((GraphBuffer
[i
] > low
) && (i
<GraphTraceLen
))
321 while((GraphBuffer
[i
] < high
) && (i
<GraphTraceLen
))
323 while((GraphBuffer
[i
] > low
) && (i
<GraphTraceLen
))
325 if (j
>(MAX_GRAPH_TRACE_LEN
/64)) {
328 tmpbuff
[j
++]= i
- start
;
331 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
334 for (i
= 0; i
< j
- 4 ; ++i
)
337 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
338 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
339 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
340 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
348 /* skip over the remainder of the LW */
349 skip
+= tmpbuff
[i
+1]+tmpbuff
[i
+2];
350 while(skip
< MAX_GRAPH_TRACE_LEN
&& GraphBuffer
[skip
] > low
)
354 /* now do it again to find the end */
356 for (i
+= 3; i
< j
- 4 ; ++i
)
359 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
360 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
361 if (tmpbuff
[i
+2] >= 190 && tmpbuff
[i
+2] <= 194)
362 if (tmpbuff
[i
+3] >= 126 && tmpbuff
[i
+3] <= 130)
370 PrintToScrollback("Found data at sample: %i",skip
);
373 PrintToScrollback("No data found!");
374 PrintToScrollback("Try again with more samples.");
380 PrintToScrollback("*** Warning!");
381 PrintToScrollback("Partial data - no end found!");
382 PrintToScrollback("Try again with more samples.");
385 /* get rid of leading crap */
386 sprintf(tmp
,"%i",skip
);
389 /* now work through remaining buffer printing out data blocks */
394 PrintToScrollback("Block %i:", block
);
395 // mandemod routine needs to be split so we can call it for data
396 // just print for now for debugging
397 Cmdmanchesterdemod("i 64");
399 /* look for LW before start of next block */
400 for ( ; i
< j
- 4 ; ++i
)
403 if (tmpbuff
[i
] >= 190 && tmpbuff
[i
] <= 194)
404 if (tmpbuff
[i
+1] >= 126 && tmpbuff
[i
+1] <= 130)
407 while(GraphBuffer
[skip
] > low
)
410 sprintf(tmp
,"%i",skip
);
418 /* Read the ID of an EM410x tag.
420 * 1111 1111 1 <-- standard non-repeatable header
421 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
423 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
424 * 0 <-- stop bit, end of tag
426 static void CmdEM410xread(char *str
)
428 int i
, j
, clock
, header
, rows
, bit
, hithigh
, hitlow
, first
, bit2idx
, high
, low
;
432 int BitStream
[MAX_GRAPH_TRACE_LEN
];
435 /* Detect high and lows and clock */
436 for (i
= 0; i
< GraphTraceLen
; i
++)
438 if (GraphBuffer
[i
] > high
)
439 high
= GraphBuffer
[i
];
440 else if (GraphBuffer
[i
] < low
)
441 low
= GraphBuffer
[i
];
445 clock
= GetClock(str
, high
);
447 /* parity for our 4 columns */
448 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
451 /* manchester demodulate */
453 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
459 /* Find out if we hit both high and low peaks */
460 for (j
= 0; j
< clock
; j
++)
462 if (GraphBuffer
[(i
* clock
) + j
] == high
)
464 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
467 /* it doesn't count if it's the first part of our read
468 because it's really just trailing from the last sequence */
469 if (first
&& (hithigh
|| hitlow
))
470 hithigh
= hitlow
= 0;
474 if (hithigh
&& hitlow
)
478 /* If we didn't hit both high and low peaks, we had a bit transition */
479 if (!hithigh
|| !hitlow
)
482 BitStream
[bit2idx
++] = bit
;
486 /* We go till 5 before the graph ends because we'll get that far below */
487 for (i
= 1; i
< bit2idx
- 5; i
++)
489 /* Step 2: We have our header but need our tag ID */
490 if (header
== 9 && rows
< 10)
492 /* Confirm parity is correct */
493 if ((BitStream
[i
] ^ BitStream
[i
+1] ^ BitStream
[i
+2] ^ BitStream
[i
+3]) == BitStream
[i
+4])
495 /* Read another byte! */
496 sprintf(id
+rows
, "%x", (8 * BitStream
[i
]) + (4 * BitStream
[i
+1]) + (2 * BitStream
[i
+2]) + (1 * BitStream
[i
+3]));
499 /* Keep parity info */
500 parity
[0] ^= BitStream
[i
];
501 parity
[1] ^= BitStream
[i
+1];
502 parity
[2] ^= BitStream
[i
+2];
503 parity
[3] ^= BitStream
[i
+3];
505 /* Move 4 bits ahead */
509 /* Damn, something wrong! reset */
512 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows
+ 1, i
);
514 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
515 i
-= 9 + (5 * rows
) - 5;
521 /* Step 3: Got our 40 bits! confirm column parity */
524 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
525 if (BitStream
[i
] == parity
[0] && BitStream
[i
+1] == parity
[1] &&
526 BitStream
[i
+2] == parity
[2] && BitStream
[i
+3] == parity
[3] &&
530 PrintToScrollback("EM410x Tag ID: %s", id
);
537 /* Crap! Incorrect parity or no stop bit, start all over */
542 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
547 /* Step 1: get our header */
550 /* Need 9 consecutive 1's */
551 if (BitStream
[i
] == 1)
554 /* We don't have a header, not enough consecutive 1 bits */
560 /* if we've already retested after flipping bits, return */
564 /* if this didn't work, try flipping bits */
565 for (i
= 0; i
< bit2idx
; i
++)
571 /* emulate an EM410X tag
573 * 1111 1111 1 <-- standard non-repeatable header
574 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
576 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
577 * 0 <-- stop bit, end of tag
579 static void CmdEM410xsim(char *str
)
581 int i
, n
, j
, h
, binary
[4], parity
[4];
584 /* clock is 64 in EM410x tags */
587 /* clear our graph */
590 /* write it out a few times */
591 for (h
= 0; h
< 4; h
++)
593 /* write 9 start bits */
594 for (i
= 0; i
< 9; i
++)
595 CmdAppendGraph(0, clock
, 1);
597 /* for each hex char */
598 parity
[0] = parity
[1] = parity
[2] = parity
[3] = 0;
599 for (i
= 0; i
< 10; i
++)
601 /* read each hex char */
602 sscanf(&str
[i
], "%1x", &n
);
603 for (j
= 3; j
>= 0; j
--, n
/= 2)
606 /* append each bit */
607 CmdAppendGraph(0, clock
, binary
[0]);
608 CmdAppendGraph(0, clock
, binary
[1]);
609 CmdAppendGraph(0, clock
, binary
[2]);
610 CmdAppendGraph(0, clock
, binary
[3]);
612 /* append parity bit */
613 CmdAppendGraph(0, clock
, binary
[0] ^ binary
[1] ^ binary
[2] ^ binary
[3]);
615 /* keep track of column parity */
616 parity
[0] ^= binary
[0];
617 parity
[1] ^= binary
[1];
618 parity
[2] ^= binary
[2];
619 parity
[3] ^= binary
[3];
623 CmdAppendGraph(0, clock
, parity
[0]);
624 CmdAppendGraph(0, clock
, parity
[1]);
625 CmdAppendGraph(0, clock
, parity
[2]);
626 CmdAppendGraph(0, clock
, parity
[3]);
629 CmdAppendGraph(0, clock
, 0);
632 /* modulate that biatch */
636 RepaintGraphWindow();
641 static void ChkBitstream(char *str
)
645 /* convert to bitstream if necessary */
646 for (i
= 0; i
< (int)(GraphTraceLen
/ 2); i
++)
648 if (GraphBuffer
[i
] > 1 || GraphBuffer
[i
] < 0)
656 static void CmdLosim(char *str
)
660 /* convert to bitstream if necessary */
663 for (i
= 0; i
< GraphTraceLen
; i
+= 48) {
666 for(j
= 0; j
< 48; j
++) {
667 c
.d
.asBytes
[j
] = GraphBuffer
[i
+j
];
669 c
.cmd
= CMD_DOWNLOADED_SIM_SAMPLES_125K
;
671 SendCommand(&c
, FALSE
);
675 c
.cmd
= CMD_SIMULATE_TAG_125K
;
676 c
.ext1
= GraphTraceLen
;
677 SendCommand(&c
, FALSE
);
680 static void CmdLosimBidir(char *str
)
683 c
.cmd
= CMD_LF_SIMULATE_BIDIR
;
684 c
.ext1
= 47; /* Set ADC to twice the carrier for a slight supersampling */
686 SendCommand(&c
, FALSE
);
689 static void CmdLoread(char *str
)
692 // 'h' means higher-low-frequency, 134 kHz
695 } else if (*str
== '\0') {
698 PrintToScrollback("use 'loread' or 'loread h'");
701 c
.cmd
= CMD_ACQUIRE_RAW_ADC_SAMPLES_125K
;
702 SendCommand(&c
, FALSE
);
705 static void CmdDetectReader(char *str
)
708 // 'l' means LF - 125/134 kHz
711 } else if (*str
== 'h') {
713 } else if (*str
!= '\0') {
714 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");
717 c
.cmd
= CMD_LISTEN_READER_FIELD
;
718 SendCommand(&c
, FALSE
);
721 /* send a command before reading */
722 static void CmdLoCommandRead(char *str
)
724 static char dummy
[3];
729 c
.cmd
= CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K
;
730 sscanf(str
, "%i %i %i %s %s", &c
.ext1
, &c
.ext2
, &c
.ext3
, (char *) &c
.d
.asBytes
,(char *) &dummy
+1);
731 // in case they specified 'h'
732 strcpy((char *)&c
.d
.asBytes
+ strlen((char *)c
.d
.asBytes
), dummy
);
733 SendCommand(&c
, FALSE
);
736 static void CmdLosamples(char *str
)
744 if (n
>16000) n
=16000;
746 for(i
= 0; i
< n
; i
+= 12) {
748 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
750 SendCommand(&c
, FALSE
);
752 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
754 PrintToScrollback("bad resp");
758 for(j
= 0; j
< 48; j
++) {
759 GraphBuffer
[cnt
++] = ((int)c
.d
.asBytes
[j
]) - 128;
763 RepaintGraphWindow();
766 static void CmdBitsamples(char *str
)
773 for(i
= 0; i
< n
; i
+= 12) {
775 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
777 SendCommand(&c
, FALSE
);
779 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
780 PrintToScrollback("bad resp");
784 for(j
= 0; j
< 48; j
++) {
785 for(k
= 0; k
< 8; k
++) {
786 if(c
.d
.asBytes
[j
] & (1 << (7 - k
))) {
787 GraphBuffer
[cnt
++] = 1;
789 GraphBuffer
[cnt
++] = 0;
795 RepaintGraphWindow();
798 static void CmdHisamples(char *str
)
804 for(i
= 0; i
< n
; i
+= 12) {
806 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
808 SendCommand(&c
, FALSE
);
810 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
811 PrintToScrollback("bad resp");
815 for(j
= 0; j
< 48; j
++) {
816 GraphBuffer
[cnt
++] = (int)((BYTE
)c
.d
.asBytes
[j
]);
821 RepaintGraphWindow();
824 static int CmdHisamplest(char *str
, int nrlow
)
836 for(i
= 0; i
< n
; i
+= 12) {
838 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
840 SendCommand(&c
, FALSE
);
842 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
843 PrintToScrollback("bad resp");
847 for(j
= 0; j
< 48; j
++) {
848 t2
= (int)((BYTE
)c
.d
.asBytes
[j
]);
849 if((t2
^ 0xC0) & 0xC0) { hasbeennull
++; }
855 t1
= (t2
& 0x80) ^ (t2
& 0x20);
856 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x20);
862 t2
= ((t2
<< 1) & 0x80);
868 t2
= ((t2
<< 1) & 0x20);
872 // both, but tag with other algorithm
873 t1
= (t2
& 0x80) ^ (t2
& 0x08);
874 t2
= ((t2
<< 1) & 0x80) ^ ((t2
<< 1) & 0x08);
878 GraphBuffer
[cnt
++] = t1
;
879 GraphBuffer
[cnt
++] = t2
;
884 if(hasbeennull
>nrlow
|| nrlow
==0) {
885 PrintToScrollback("hasbeennull=%d", hasbeennull
);
894 static void CmdHexsamples(char *str
)
905 for(i
= 0; i
< n
; i
+= 12) {
907 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
909 SendCommand(&c
, FALSE
);
911 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
912 PrintToScrollback("bad resp");
916 for(j
= 0; j
< 48; j
+= 8) {
917 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",
932 static void CmdHisampless(char *str
)
944 for(i
= 0; i
< n
; i
+= 12) {
946 c
.cmd
= CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
;
948 SendCommand(&c
, FALSE
);
950 if(c
.cmd
!= CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) {
951 PrintToScrollback("bad resp");
955 for(j
= 0; j
< 48; j
++) {
956 GraphBuffer
[cnt
++] = (int)((signed char)c
.d
.asBytes
[j
]);
961 RepaintGraphWindow();
964 static WORD
Iso15693Crc(BYTE
*v
, int n
)
970 for(i
= 0; i
< n
; i
++) {
971 reg
= reg
^ ((DWORD
)v
[i
]);
972 for (j
= 0; j
< 8; j
++) {
974 reg
= (reg
>> 1) ^ 0x8408;
984 static void CmdHi14bdemod(char *str
)
989 BOOL negateI
, negateQ
;
994 // As received, the samples are pairs, correlations against I and Q
995 // square waves. So estimate angle of initial carrier (or just
996 // quadrant, actually), and then do the demod.
998 // First, estimate where the tag starts modulating.
999 for(i
= 0; i
< GraphTraceLen
; i
+= 2) {
1000 if(abs(GraphBuffer
[i
]) + abs(GraphBuffer
[i
+1]) > 40) {
1004 if(i
>= GraphTraceLen
) {
1005 PrintToScrollback("too weak to sync");
1008 PrintToScrollback("out of weak at %d", i
);
1011 // Now, estimate the phase in the initial modulation of the tag
1014 for(; i
< (outOfWeakAt
+ 16); i
+= 2) {
1015 isum
+= GraphBuffer
[i
+0];
1016 qsum
+= GraphBuffer
[i
+1];
1018 negateI
= (isum
< 0);
1019 negateQ
= (qsum
< 0);
1021 // Turn the correlation pairs into soft decisions on the bit.
1023 for(i
= 0; i
< GraphTraceLen
/2; i
++) {
1024 int si
= GraphBuffer
[j
];
1025 int sq
= GraphBuffer
[j
+1];
1026 if(negateI
) si
= -si
;
1027 if(negateQ
) sq
= -sq
;
1028 GraphBuffer
[i
] = si
+ sq
;
1034 while(GraphBuffer
[i
] > 0 && i
< GraphTraceLen
)
1036 if(i
>= GraphTraceLen
) goto demodError
;
1039 while(GraphBuffer
[i
] < 0 && i
< GraphTraceLen
)
1041 if(i
>= GraphTraceLen
) goto demodError
;
1042 if((i
- iold
) > 23) goto demodError
;
1044 PrintToScrollback("make it to demod loop");
1048 while(GraphBuffer
[i
] >= 0 && i
< GraphTraceLen
)
1050 if(i
>= GraphTraceLen
) goto demodError
;
1051 if((i
- iold
) > 6) goto demodError
;
1054 if(i
+ 20 >= GraphTraceLen
) goto demodError
;
1056 for(j
= 0; j
< 10; j
++) {
1057 int soft
= GraphBuffer
[i
] + GraphBuffer
[i
+1];
1059 if(abs(soft
) < ((abs(isum
) + abs(qsum
))/20)) {
1060 PrintToScrollback("weak bit");
1064 if(GraphBuffer
[i
] + GraphBuffer
[i
+1] >= 0) {
1071 if( (shiftReg
& 0x200) &&
1072 !(shiftReg
& 0x001))
1074 // valid data byte, start and stop bits okay
1075 PrintToScrollback(" %02x", (shiftReg
>> 1) & 0xff);
1076 data
[dataLen
++] = (shiftReg
>> 1) & 0xff;
1077 if(dataLen
>= sizeof(data
)) {
1080 } else if(shiftReg
== 0x000) {
1089 ComputeCrc14443(CRC_14443_B
, data
, dataLen
-2, &first
, &second
);
1090 PrintToScrollback("CRC: %02x %02x (%s)\n", first
, second
,
1091 (first
== data
[dataLen
-2] && second
== data
[dataLen
-1]) ?
1092 "ok" : "****FAIL****");
1094 RepaintGraphWindow();
1098 PrintToScrollback("demod error");
1099 RepaintGraphWindow();
1102 static void CmdHi14list(char *str
)
1105 GetFromBigBuf(got
, sizeof(got
));
1107 PrintToScrollback("recorded activity:");
1108 PrintToScrollback(" time :rssi: who bytes");
1109 PrintToScrollback("---------+----+----+-----------");
1120 int timestamp
= *((DWORD
*)(got
+i
));
1121 if(timestamp
& 0x80000000) {
1122 timestamp
&= 0x7fffffff;
1127 int metric
= *((DWORD
*)(got
+i
+4));
1134 if(i
+ len
>= 900) {
1138 BYTE
*frame
= (got
+i
+9);
1140 char line
[1000] = "";
1142 for(j
= 0; j
< len
; j
++) {
1143 sprintf(line
+(j
*3), "%02x ", frame
[j
]);
1149 ComputeCrc14443(CRC_14443_B
, frame
, len
-2, &b1
, &b2
);
1150 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1151 crc
= "**FAIL CRC**";
1159 char metricString
[100];
1161 sprintf(metricString
, "%3d", metric
);
1163 strcpy(metricString
, " ");
1166 PrintToScrollback(" +%7d: %s: %s %s %s",
1167 (prev
< 0 ? 0 : timestamp
- prev
),
1169 (isResponse
? "TAG" : " "), line
, crc
);
1176 static void CmdHi14alist(char *str
)
1179 GetFromBigBuf(got
, sizeof(got
));
1181 PrintToScrollback("recorded activity:");
1182 PrintToScrollback(" ETU :rssi: who bytes");
1183 PrintToScrollback("---------+----+----+-----------");
1194 int timestamp
= *((DWORD
*)(got
+i
));
1195 if(timestamp
& 0x80000000) {
1196 timestamp
&= 0x7fffffff;
1203 int parityBits
= *((DWORD
*)(got
+i
+4));
1204 // 4 bytes of additional information...
1205 // maximum of 32 additional parity bit information
1208 // at each quarter bit period we can send power level (16 levels)
1209 // or each half bit period in 256 levels.
1217 if(i
+ len
>= 1900) {
1221 BYTE
*frame
= (got
+i
+9);
1223 // Break and stick with current result if buffer was not completely full
1224 if(frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
1226 char line
[1000] = "";
1228 for(j
= 0; j
< len
; j
++) {
1229 int oddparity
= 0x01;
1233 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
1236 //if((parityBits >> (len - j - 1)) & 0x01) {
1237 if(isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
1238 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
1241 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
1249 for(j
= 0; j
< (len
- 1); j
++) {
1250 // gives problems... search for the reason..
1251 /*if(frame[j] == 0xAA) {
1252 switch(frame[j+1]) {
1254 crc = "[1] Two drops close after each other";
1257 crc = "[2] Potential SOC with a drop in second half of bitperiod";
1260 crc = "[3] Segment Z after segment X is not possible";
1263 crc = "[4] Parity bit of a fully received byte was wrong";
1266 crc = "[?] Unknown error";
1273 if(strlen(crc
)==0) {
1274 ComputeCrc14443(CRC_14443_A
, frame
, len
-2, &b1
, &b2
);
1275 if(b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
1276 crc
= (isResponse
& (len
< 6)) ? "" : " !crc";
1285 char metricString
[100];
1287 sprintf(metricString
, "%3d", metric
);
1289 strcpy(metricString
, " ");
1292 PrintToScrollback(" +%7d: %s: %s %s %s",
1293 (prev
< 0 ? 0 : (timestamp
- prev
)),
1295 (isResponse
? "TAG" : " "), line
, crc
);
1300 CommandFinished
= 1;
1303 static void CmdHi15demod(char *str
)
1305 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
1308 // 1) Unmodulated time of 56.64us
1309 // 2) 24 pulses of 423.75khz
1310 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
1312 static const int FrameSOF
[] = {
1313 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1314 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1315 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1316 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1322 static const int Logic0
[] = {
1328 static const int Logic1
[] = {
1336 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
1337 // 2) 24 pulses of 423.75khz
1338 // 3) Unmodulated time of 56.64us
1340 static const int FrameEOF
[] = {
1345 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1346 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1347 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1348 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1352 int max
= 0, maxPos
;
1356 if(GraphTraceLen
< 1000) return;
1358 // First, correlate for SOF
1359 for(i
= 0; i
< 100; i
++) {
1361 for(j
= 0; j
< arraylen(FrameSOF
); j
+= skip
) {
1362 corr
+= FrameSOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1369 PrintToScrollback("SOF at %d, correlation %d", maxPos
,
1370 max
/(arraylen(FrameSOF
)/skip
));
1372 i
= maxPos
+ arraylen(FrameSOF
)/skip
;
1375 memset(outBuf
, 0, sizeof(outBuf
));
1378 int corr0
= 0, corr1
= 0, corrEOF
= 0;
1379 for(j
= 0; j
< arraylen(Logic0
); j
+= skip
) {
1380 corr0
+= Logic0
[j
]*GraphBuffer
[i
+(j
/skip
)];
1382 for(j
= 0; j
< arraylen(Logic1
); j
+= skip
) {
1383 corr1
+= Logic1
[j
]*GraphBuffer
[i
+(j
/skip
)];
1385 for(j
= 0; j
< arraylen(FrameEOF
); j
+= skip
) {
1386 corrEOF
+= FrameEOF
[j
]*GraphBuffer
[i
+(j
/skip
)];
1388 // Even things out by the length of the target waveform.
1392 if(corrEOF
> corr1
&& corrEOF
> corr0
) {
1393 PrintToScrollback("EOF at %d", i
);
1395 } else if(corr1
> corr0
) {
1396 i
+= arraylen(Logic1
)/skip
;
1399 i
+= arraylen(Logic0
)/skip
;
1406 if((i
+(int)arraylen(FrameEOF
)) >= GraphTraceLen
) {
1407 PrintToScrollback("ran off end!");
1412 PrintToScrollback("error, uneven octet! (discard extra bits!)");
1413 PrintToScrollback(" mask=%02x", mask
);
1415 PrintToScrollback("%d octets", k
);
1417 for(i
= 0; i
< k
; i
++) {
1418 PrintToScrollback("# %2d: %02x ", i
, outBuf
[i
]);
1420 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf
, k
-2));
1423 static void CmdFSKdemod(char *cmdline
)
1425 static const int LowTone
[] = {
1426 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1427 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1428 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1429 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1430 1, 1, 1, 1, 1, -1, -1, -1, -1, -1
1432 static const int HighTone
[] = {
1433 1, 1, 1, 1, 1, -1, -1, -1, -1,
1434 1, 1, 1, 1, -1, -1, -1, -1,
1435 1, 1, 1, 1, -1, -1, -1, -1,
1436 1, 1, 1, 1, -1, -1, -1, -1,
1437 1, 1, 1, 1, -1, -1, -1, -1,
1438 1, 1, 1, 1, -1, -1, -1, -1, -1,
1441 int lowLen
= sizeof(LowTone
)/sizeof(int);
1442 int highLen
= sizeof(HighTone
)/sizeof(int);
1443 int convLen
= (highLen
>lowLen
)?highLen
:lowLen
;
1444 DWORD hi
= 0, lo
= 0;
1447 int minMark
=0, maxMark
=0;
1449 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1450 int lowSum
= 0, highSum
= 0;
1452 for(j
= 0; j
< lowLen
; j
++) {
1453 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1455 for(j
= 0; j
< highLen
; j
++) {
1456 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1458 lowSum
= abs((100*lowSum
) / lowLen
);
1459 highSum
= abs((100*highSum
) / highLen
);
1460 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1463 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1465 int lowTot
= 0, highTot
= 0;
1466 // 10 and 8 are f_s divided by f_l and f_h, rounded
1467 for(j
= 0; j
< 10; j
++) {
1468 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1470 for(j
= 0; j
< 8; j
++) {
1471 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1473 GraphBuffer
[i
] = lowTot
- highTot
;
1474 if (GraphBuffer
[i
]>maxMark
) maxMark
=GraphBuffer
[i
];
1475 if (GraphBuffer
[i
]<minMark
) minMark
=GraphBuffer
[i
];
1478 GraphTraceLen
-= (convLen
+ 16);
1480 RepaintGraphWindow();
1482 // Find bit-sync (3 lo followed by 3 high)
1483 int max
= 0, maxPos
= 0;
1484 for(i
= 0; i
< 6000; i
++) {
1486 for(j
= 0; j
< 3*lowLen
; j
++) {
1487 dec
-= GraphBuffer
[i
+j
];
1489 for(; j
< 3*(lowLen
+ highLen
); j
++) {
1490 dec
+= GraphBuffer
[i
+j
];
1498 // place start of bit sync marker in graph
1499 GraphBuffer
[maxPos
] = maxMark
;
1500 GraphBuffer
[maxPos
+1] = minMark
;
1504 // place end of bit sync marker in graph
1505 GraphBuffer
[maxPos
] = maxMark
;
1506 GraphBuffer
[maxPos
+1] = minMark
;
1508 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1509 PrintToScrollback("length %d/%d", highLen
, lowLen
);
1512 bits
[sizeof(bits
)-1] = '\0';
1514 // find bit pairs and manchester decode them
1515 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1517 for(j
= 0; j
< lowLen
; j
++) {
1518 dec
-= GraphBuffer
[maxPos
+j
];
1520 for(; j
< lowLen
+ highLen
; j
++) {
1521 dec
+= GraphBuffer
[maxPos
+j
];
1524 // place inter bit marker in graph
1525 GraphBuffer
[maxPos
] = maxMark
;
1526 GraphBuffer
[maxPos
+1] = minMark
;
1528 // hi and lo form a 64 bit pair
1529 hi
= (hi
<<1)|(lo
>>31);
1531 // store decoded bit as binary (in hi/lo) and text (in bits[])
1539 PrintToScrollback("bits: '%s'", bits
);
1540 PrintToScrollback("hex: %08x %08x", hi
, lo
);
1543 // read a TI tag and return its ID
1544 static void CmdTIRead(char *str
)
1547 c
.cmd
= CMD_READ_TI_TYPE
;
1548 SendCommand(&c
, FALSE
);
1551 // write new data to a r/w TI tag
1552 static void CmdTIWrite(char *str
)
1557 c
.cmd
= CMD_WRITE_TI_TYPE
;
1558 res
= sscanf(str
, "0x%x 0x%x 0x%x ", &c
.ext1
, &c
.ext2
, &c
.ext3
);
1559 if (res
== 2) c
.ext3
=0;
1561 PrintToScrollback("Please specify the data as two hex strings, optionally the CRC as a third");
1563 SendCommand(&c
, FALSE
);
1566 static void CmdTIDemod(char *cmdline
)
1568 /* MATLAB as follows:
1569 f_s = 2000000; % sampling frequency
1570 f_l = 123200; % low FSK tone
1571 f_h = 134200; % high FSK tone
1573 T_l = 119e-6; % low bit duration
1574 T_h = 130e-6; % high bit duration
1576 l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);
1577 h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
1579 l = sign(sin(cumsum(l)));
1580 h = sign(sin(cumsum(h)));
1583 // 2M*16/134.2k = 238
1584 static const int LowTone
[] = {
1585 1, 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,
1587 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1588 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1589 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1590 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1591 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1592 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1593 1, 1, 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, -1,
1595 1, 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, -1,
1597 1, 1, 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, -1,
1599 1, 1, 1, 1, 1, 1, 1, 1, -1, -1
1601 // 2M*16/123.2k = 260
1602 static const int HighTone
[] = {
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, -1, -1, -1, -1, -1, -1, -1,
1609 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1610 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1611 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1612 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1613 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1614 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1615 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1616 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1617 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1618 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
1619 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1620 1, 1, 1, 1, 1, 1, 1, 1
1622 int lowLen
= sizeof(LowTone
)/sizeof(int);
1623 int highLen
= sizeof(HighTone
)/sizeof(int);
1624 int convLen
= (highLen
>lowLen
)?highLen
:lowLen
;
1627 int lowSum
= 0, highSum
= 0;;
1628 int lowTot
= 0, highTot
= 0;
1630 for(i
= 0; i
< GraphTraceLen
- convLen
; i
++) {
1634 for(j
= 0; j
< lowLen
; j
++) {
1635 lowSum
+= LowTone
[j
]*GraphBuffer
[i
+j
];
1637 for(j
= 0; j
< highLen
; j
++) {
1638 highSum
+= HighTone
[j
]*GraphBuffer
[i
+j
];
1640 lowSum
= abs((100*lowSum
) / lowLen
);
1641 highSum
= abs((100*highSum
) / highLen
);
1642 lowSum
= (lowSum
<0)?-lowSum
:lowSum
;
1643 highSum
= (highSum
<0)?-highSum
:highSum
;
1645 GraphBuffer
[i
] = (highSum
<< 16) | lowSum
;
1648 for(i
= 0; i
< GraphTraceLen
- convLen
- 16; i
++) {
1651 // 16 and 15 are f_s divided by f_l and f_h, rounded
1652 for(j
= 0; j
< 16; j
++) {
1653 lowTot
+= (GraphBuffer
[i
+j
] & 0xffff);
1655 for(j
= 0; j
< 15; j
++) {
1656 highTot
+= (GraphBuffer
[i
+j
] >> 16);
1658 GraphBuffer
[i
] = lowTot
- highTot
;
1661 GraphTraceLen
-= (convLen
+ 16);
1663 RepaintGraphWindow();
1665 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,
1666 // 16 crc CCITT bits, 8 stop bits, 15 end bits
1668 // the 16 prebits are always low
1669 // the 8 start and stop bits of a tag must match
1670 // the start/stop prebits of a ro tag are 01111110
1671 // the start/stop prebits of a rw tag are 11111110
1672 // the 15 end bits of a ro tag are all low
1673 // the 15 end bits of a rw tag match bits 15-1 of the data bits
1675 // Okay, so now we have unsliced soft decisions;
1676 // find bit-sync, and then get some bits.
1677 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)
1678 int max
= 0, maxPos
= 0;
1679 for(i
= 0; i
< 6000; i
++) {
1682 // searching 17 consecutive lows
1683 for(j
= 0; j
< 17*lowLen
; j
++) {
1684 dec
-= GraphBuffer
[i
+j
];
1686 // searching 7 consecutive highs
1687 for(; j
< 17*lowLen
+ 6*highLen
; j
++) {
1688 dec
+= GraphBuffer
[i
+j
];
1696 // place a marker in the buffer to visually aid location
1697 // of the start of sync
1698 GraphBuffer
[maxPos
] = 800;
1699 GraphBuffer
[maxPos
+1] = -800;
1701 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)
1702 maxPos
+= 17*lowLen
;
1703 maxPos
+= 6*highLen
;
1705 // place a marker in the buffer to visually aid location
1706 // of the end of sync
1707 GraphBuffer
[maxPos
] = 800;
1708 GraphBuffer
[maxPos
+1] = -800;
1710 PrintToScrollback("actual data bits start at sample %d", maxPos
);
1712 PrintToScrollback("length %d/%d", highLen
, lowLen
);
1714 BYTE bits
[1+64+16+8+16];
1715 bits
[sizeof(bits
)-1] = '\0';
1717 DWORD shift3
= 0x7e000000, shift2
= 0, shift1
= 0, shift0
= 0;
1719 for(i
= 0; i
< arraylen(bits
)-1; i
++) {
1723 for(j
= 0; j
< lowLen
; j
++) {
1724 low
-= GraphBuffer
[maxPos
+j
];
1726 for(j
= 0; j
< highLen
; j
++) {
1727 high
+= GraphBuffer
[maxPos
+j
];
1733 // bitstream arrives lsb first so shift right
1740 // 128 bit right shift register
1741 shift0
= (shift0
>>1) | (shift1
<< 31);
1742 shift1
= (shift1
>>1) | (shift2
<< 31);
1743 shift2
= (shift2
>>1) | (shift3
<< 31);
1746 // place a marker in the buffer between bits to visually aid location
1747 GraphBuffer
[maxPos
] = 800;
1748 GraphBuffer
[maxPos
+1] = -800;
1750 PrintToScrollback("Info: raw tag bits = %s", bits
);
1752 TagType
= (shift3
>>8)&0xff;
1753 if ( TagType
!= ((shift0
>>16)&0xff) ) {
1754 PrintToScrollback("Error: start and stop bits do not match!");
1757 else if (TagType
== 0x7e) {
1758 PrintToScrollback("Info: Readonly TI tag detected.");
1761 else if (TagType
== 0xfe) {
1762 PrintToScrollback("Info: Rewriteable TI tag detected.");
1764 // put 64 bit data into shift1 and shift0
1765 shift0
= (shift0
>>24) | (shift1
<< 8);
1766 shift1
= (shift1
>>24) | (shift2
<< 8);
1768 // align 16 bit crc into lower half of shift2
1769 shift2
= ((shift2
>>24) | (shift3
<< 8)) & 0x0ffff;
1771 // align 16 bit "end bits" or "ident" into lower half of shift3
1774 // only 15 bits compare, last bit of ident is not valid
1775 if ( (shift3
^shift0
)&0x7fff ) {
1776 PrintToScrollback("Error: Ident mismatch!");
1778 // WARNING the order of the bytes in which we calc crc below needs checking
1779 // i'm 99% sure the crc algorithm is correct, but it may need to eat the
1780 // bytes in reverse or something
1783 crc
= update_crc16(crc
, (shift0
)&0xff);
1784 crc
= update_crc16(crc
, (shift0
>>8)&0xff);
1785 crc
= update_crc16(crc
, (shift0
>>16)&0xff);
1786 crc
= update_crc16(crc
, (shift0
>>24)&0xff);
1787 crc
= update_crc16(crc
, (shift1
)&0xff);
1788 crc
= update_crc16(crc
, (shift1
>>8)&0xff);
1789 crc
= update_crc16(crc
, (shift1
>>16)&0xff);
1790 crc
= update_crc16(crc
, (shift1
>>24)&0xff);
1791 PrintToScrollback("Info: Tag data = %08X%08X", shift1
, shift0
);
1792 if (crc
!= (shift2
&0xffff)) {
1793 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc
, shift2
&0xffff);
1795 PrintToScrollback("Info: CRC %04X is good", crc
);
1799 PrintToScrollback("Unknown tag type.");
1804 static void CmdNorm(char *str
)
1807 int max
= INT_MIN
, min
= INT_MAX
;
1808 for(i
= 10; i
< GraphTraceLen
; i
++) {
1809 if(GraphBuffer
[i
] > max
) {
1810 max
= GraphBuffer
[i
];
1812 if(GraphBuffer
[i
] < min
) {
1813 min
= GraphBuffer
[i
];
1817 for(i
= 0; i
< GraphTraceLen
; i
++) {
1818 GraphBuffer
[i
] = (GraphBuffer
[i
] - ((max
+ min
)/2))*1000/
1822 RepaintGraphWindow();
1825 static void CmdAmp(char *str
)
1827 int i
, rising
, falling
;
1828 int max
= INT_MIN
, min
= INT_MAX
;
1829 for(i
= 10; i
< GraphTraceLen
; i
++) {
1830 if(GraphBuffer
[i
] > max
) {
1831 max
= GraphBuffer
[i
];
1833 if(GraphBuffer
[i
] < min
) {
1834 min
= GraphBuffer
[i
];
1839 for(i
= 0; i
< GraphTraceLen
; i
++) {
1840 if(GraphBuffer
[i
+1] < GraphBuffer
[i
]) {
1842 GraphBuffer
[i
]= max
;
1847 if(GraphBuffer
[i
+1] > GraphBuffer
[i
]) {
1849 GraphBuffer
[i
]= min
;
1856 RepaintGraphWindow();
1859 static void CmdDec(char *str
)
1862 for(i
= 0; i
< (GraphTraceLen
/2); i
++) {
1863 GraphBuffer
[i
] = GraphBuffer
[i
*2];
1866 PrintToScrollback("decimated by 2");
1867 RepaintGraphWindow();
1870 static void CmdHpf(char *str
)
1874 for(i
= 10; i
< GraphTraceLen
; i
++) {
1875 accum
+= GraphBuffer
[i
];
1877 accum
/= (GraphTraceLen
- 10);
1878 for(i
= 0; i
< GraphTraceLen
; i
++) {
1879 GraphBuffer
[i
] -= accum
;
1882 RepaintGraphWindow();
1885 static void CmdZerocrossings(char *str
)
1888 // Zero-crossings aren't meaningful unless the signal is zero-mean.
1894 for(i
= 0; i
< GraphTraceLen
; i
++) {
1895 if(GraphBuffer
[i
]*sign
>= 0) {
1896 // No change in sign, reproduce the previous sample count.
1898 GraphBuffer
[i
] = lastZc
;
1900 // Change in sign, reset the sample count.
1902 GraphBuffer
[i
] = lastZc
;
1910 RepaintGraphWindow();
1913 static void CmdThreshold(char *str
)
1916 int threshold
= atoi(str
);
1918 for(i
= 0; i
< GraphTraceLen
; i
++) {
1919 if(GraphBuffer
[i
]>= threshold
)
1924 RepaintGraphWindow();
1927 static void CmdLtrim(char *str
)
1932 for(i
= ds
; i
< GraphTraceLen
; i
++) {
1933 GraphBuffer
[i
-ds
] = GraphBuffer
[i
];
1935 GraphTraceLen
-= ds
;
1937 RepaintGraphWindow();
1940 static void CmdAutoCorr(char *str
)
1942 static int CorrelBuffer
[MAX_GRAPH_TRACE_LEN
];
1944 int window
= atoi(str
);
1947 PrintToScrollback("needs a window");
1951 if(window
>= GraphTraceLen
) {
1952 PrintToScrollback("window must be smaller than trace (%d samples)",
1957 PrintToScrollback("performing %d correlations", GraphTraceLen
- window
);
1960 for(i
= 0; i
< GraphTraceLen
- window
; i
++) {
1963 for(j
= 0; j
< window
; j
++) {
1964 sum
+= (GraphBuffer
[j
]*GraphBuffer
[i
+j
]) / 256;
1966 CorrelBuffer
[i
] = sum
;
1968 GraphTraceLen
= GraphTraceLen
- window
;
1969 memcpy(GraphBuffer
, CorrelBuffer
, GraphTraceLen
*sizeof(int));
1971 RepaintGraphWindow();
1974 static void CmdVchdemod(char *str
)
1976 // Is this the entire sync pattern, or does this also include some
1977 // data bits that happen to be the same everywhere? That would be
1979 static const int SyncPattern
[] = {
1980 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1981 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1982 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1983 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1984 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1985 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1986 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1987 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1988 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1989 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1992 // So first, we correlate for the sync pattern, and mark that.
1993 int bestCorrel
= 0, bestPos
= 0;
1995 // It does us no good to find the sync pattern, with fewer than
1996 // 2048 samples after it...
1997 for(i
= 0; i
< (GraphTraceLen
-2048); i
++) {
2000 for(j
= 0; j
< arraylen(SyncPattern
); j
++) {
2001 sum
+= GraphBuffer
[i
+j
]*SyncPattern
[j
];
2003 if(sum
> bestCorrel
) {
2008 PrintToScrollback("best sync at %d [metric %d]", bestPos
, bestCorrel
);
2013 int worst
= INT_MAX
;
2016 for(i
= 0; i
< 2048; i
+= 8) {
2019 for(j
= 0; j
< 8; j
++) {
2020 sum
+= GraphBuffer
[bestPos
+i
+j
];
2027 if(abs(sum
) < worst
) {
2032 PrintToScrollback("bits:");
2033 PrintToScrollback("%s", bits
);
2034 PrintToScrollback("worst metric: %d at pos %d", worst
, worstPos
);
2036 if(strcmp(str
, "clone")==0) {
2039 for(s
= bits
; *s
; s
++) {
2041 for(j
= 0; j
< 16; j
++) {
2042 GraphBuffer
[GraphTraceLen
++] = (*s
== '1') ? 1 : 0;
2045 RepaintGraphWindow();
2049 static void CmdIndalademod(char *str
)
2051 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
2056 // worst case with GraphTraceLen=64000 is < 4096
2057 // under normal conditions it's < 2048
2060 int worst
= 0, worstPos
= 0;
2061 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen
/32);
2062 for(i
= 0; i
< GraphTraceLen
-1; i
+= 2) {
2064 if((GraphBuffer
[i
] > GraphBuffer
[i
+ 1]) && (state
!= 1)) {
2066 for(j
= 0; j
< count
- 8; j
+= 16) {
2067 rawbits
[rawbit
++] = 0;
2069 if ((abs(count
- j
)) > worst
) {
2070 worst
= abs(count
- j
);
2076 } else if((GraphBuffer
[i
] < GraphBuffer
[i
+ 1]) && (state
!= 0)) {
2078 for(j
= 0; j
< count
- 8; j
+= 16) {
2079 rawbits
[rawbit
++] = 1;
2081 if ((abs(count
- j
)) > worst
) {
2082 worst
= abs(count
- j
);
2090 PrintToScrollback("Recovered %d raw bits", rawbit
);
2091 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst
, worstPos
);
2093 // Finding the start of a UID
2094 int uidlen
, long_wait
;
2095 if(strcmp(str
, "224") == 0) {
2104 for(start
= 0; start
<= rawbit
- uidlen
; start
++) {
2105 first
= rawbits
[start
];
2106 for(i
= start
; i
< start
+ long_wait
; i
++) {
2107 if(rawbits
[i
] != first
) {
2111 if(i
== (start
+ long_wait
)) {
2115 if(start
== rawbit
- uidlen
+ 1) {
2116 PrintToScrollback("nothing to wait for");
2120 // Inverting signal if needed
2122 for(i
= start
; i
< rawbit
; i
++) {
2123 rawbits
[i
] = !rawbits
[i
];
2130 showbits
[uidlen
]='\0';
2134 if(uidlen
> rawbit
) {
2135 PrintToScrollback("Warning: not enough raw bits to get a full UID");
2136 for(bit
= 0; bit
< rawbit
; bit
++) {
2137 bits
[bit
] = rawbits
[i
++];
2138 // As we cannot know the parity, let's use "." and "/"
2139 showbits
[bit
] = '.' + bits
[bit
];
2141 showbits
[bit
+1]='\0';
2142 PrintToScrollback("Partial UID=%s", showbits
);
2145 for(bit
= 0; bit
< uidlen
; bit
++) {
2146 bits
[bit
] = rawbits
[i
++];
2147 showbits
[bit
] = '0' + bits
[bit
];
2151 PrintToScrollback("UID=%s", showbits
);
2153 // Checking UID against next occurences
2154 for(; i
+ uidlen
<= rawbit
;) {
2156 for(bit
= 0; bit
< uidlen
; bit
++) {
2157 if(bits
[bit
] != rawbits
[i
++]) {
2167 PrintToScrollback("Occurences: %d (expected %d)", times
, (rawbit
- start
) / uidlen
);
2169 // Remodulating for tag cloning
2170 GraphTraceLen
= 32*uidlen
;
2173 for(bit
= 0; bit
< uidlen
; bit
++) {
2174 if(bits
[bit
] == 0) {
2180 for(j
= 0; j
< 32; j
++) {
2181 GraphBuffer
[i
++] = phase
;
2186 RepaintGraphWindow();
2189 static void CmdFlexdemod(char *str
)
2192 for(i
= 0; i
< GraphTraceLen
; i
++) {
2193 if(GraphBuffer
[i
] < 0) {
2194 GraphBuffer
[i
] = -1;
2200 #define LONG_WAIT 100
2202 for(start
= 0; start
< GraphTraceLen
- LONG_WAIT
; start
++) {
2203 int first
= GraphBuffer
[start
];
2204 for(i
= start
; i
< start
+ LONG_WAIT
; i
++) {
2205 if(GraphBuffer
[i
] != first
) {
2209 if(i
== (start
+ LONG_WAIT
)) {
2213 if(start
== GraphTraceLen
- LONG_WAIT
) {
2214 PrintToScrollback("nothing to wait for");
2218 GraphBuffer
[start
] = 2;
2219 GraphBuffer
[start
+1] = -2;
2225 for(bit
= 0; bit
< 64; bit
++) {
2228 for(j
= 0; j
< 16; j
++) {
2229 sum
+= GraphBuffer
[i
++];
2236 PrintToScrollback("bit %d sum %d", bit
, sum
);
2239 for(bit
= 0; bit
< 64; bit
++) {
2242 for(j
= 0; j
< 16; j
++) {
2243 sum
+= GraphBuffer
[i
++];
2245 if(sum
> 0 && bits
[bit
] != 1) {
2246 PrintToScrollback("oops1 at %d", bit
);
2248 if(sum
< 0 && bits
[bit
] != 0) {
2249 PrintToScrollback("oops2 at %d", bit
);
2253 GraphTraceLen
= 32*64;
2256 for(bit
= 0; bit
< 64; bit
++) {
2257 if(bits
[bit
] == 0) {
2263 for(j
= 0; j
< 32; j
++) {
2264 GraphBuffer
[i
++] = phase
;
2269 RepaintGraphWindow();
2273 * Generic command to demodulate ASK.
2275 * Argument is convention: positive or negative (High mod means zero
2276 * or high mod means one)
2278 * Updates the Graph trace with 0/1 values
2284 static void Cmdaskdemod(char *str
) {
2286 int c
, high
= 0, low
= 0;
2288 // TODO: complain if we do not give 2 arguments here !
2289 // (AL - this doesn't make sense! we're only using one argument!!!)
2290 sscanf(str
, "%i", &c
);
2292 /* Detect high and lows and clock */
2294 for (i
= 0; i
< GraphTraceLen
; i
++)
2296 if (GraphBuffer
[i
] > high
)
2297 high
= GraphBuffer
[i
];
2298 else if (GraphBuffer
[i
] < low
)
2299 low
= GraphBuffer
[i
];
2301 if(c
!= 0 && c
!= 1) {
2302 PrintToScrollback("Invalid argument: %s",str
);
2306 if (GraphBuffer
[0] > 0) {
2307 GraphBuffer
[0] = 1-c
;
2311 for(i
=1;i
<GraphTraceLen
;i
++) {
2312 /* Transitions are detected at each peak
2313 * Transitions are either:
2314 * - we're low: transition if we hit a high
2315 * - we're high: transition if we hit a low
2316 * (we need to do it this way because some tags keep high or
2317 * low for long periods, others just reach the peak and go
2320 if ((GraphBuffer
[i
]==high
) && (GraphBuffer
[i
-1] == c
)) {
2322 } else if ((GraphBuffer
[i
]==low
) && (GraphBuffer
[i
-1] == (1-c
))){
2326 GraphBuffer
[i
] = GraphBuffer
[i
-1];
2329 RepaintGraphWindow();
2332 /* Print our clock rate */
2333 static void Cmddetectclockrate(char *str
)
2335 int clock
= detectclock(0);
2336 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2342 int detectclock(int peak
)
2348 /* Detect peak if we don't have one */
2350 for (i
= 0; i
< GraphTraceLen
; i
++)
2351 if (GraphBuffer
[i
] > peak
)
2352 peak
= GraphBuffer
[i
];
2354 for (i
= 1; i
< GraphTraceLen
; i
++)
2356 /* If this is the beginning of a peak */
2357 if (GraphBuffer
[i
-1] != GraphBuffer
[i
] && GraphBuffer
[i
] == peak
)
2359 /* Find lowest difference between peaks */
2360 if (lastpeak
&& i
- lastpeak
< clock
)
2362 clock
= i
- lastpeak
;
2371 /* Get or auto-detect clock rate */
2372 int GetClock(char *str
, int peak
)
2376 sscanf(str
, "%i", &clock
);
2377 if (!strcmp(str
, ""))
2380 /* Auto-detect clock */
2383 clock
= detectclock(peak
);
2385 /* Only print this message if we're not looping something */
2387 PrintToScrollback("Auto-detected clock rate: %d", clock
);
2394 * Convert to a bitstream
2396 static void Cmdbitstream(char *str
) {
2403 int hithigh
, hitlow
, first
;
2405 /* Detect high and lows and clock */
2406 for (i
= 0; i
< GraphTraceLen
; i
++)
2408 if (GraphBuffer
[i
] > high
)
2409 high
= GraphBuffer
[i
];
2410 else if (GraphBuffer
[i
] < low
)
2411 low
= GraphBuffer
[i
];
2415 clock
= GetClock(str
, high
);
2417 gtl
= CmdClearGraph(0);
2420 for (i
= 0; i
< (int)(gtl
/ clock
); i
++)
2426 /* Find out if we hit both high and low peaks */
2427 for (j
= 0; j
< clock
; j
++)
2429 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2431 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2434 /* it doesn't count if it's the first part of our read
2435 because it's really just trailing from the last sequence */
2436 if (first
&& (hithigh
|| hitlow
))
2437 hithigh
= hitlow
= 0;
2441 if (hithigh
&& hitlow
)
2445 /* If we didn't hit both high and low peaks, we had a bit transition */
2446 if (!hithigh
|| !hitlow
)
2449 CmdAppendGraph(0, clock
, bit
);
2450 // for (j = 0; j < (int)(clock/2); j++)
2451 // GraphBuffer[(i * clock) + j] = bit ^ 1;
2452 // for (j = (int)(clock/2); j < clock; j++)
2453 // GraphBuffer[(i * clock) + j] = bit;
2456 RepaintGraphWindow();
2459 /* Modulate our data into manchester */
2460 static void Cmdmanchestermod(char *str
)
2464 int bit
, lastbit
, wave
;
2467 clock
= GetClock(str
, 0);
2471 for (i
= 0; i
< (int)(GraphTraceLen
/ clock
); i
++)
2473 bit
= GraphBuffer
[i
* clock
] ^ 1;
2475 for (j
= 0; j
< (int)(clock
/2); j
++)
2476 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
;
2477 for (j
= (int)(clock
/2); j
< clock
; j
++)
2478 GraphBuffer
[(i
* clock
) + j
] = bit
^ lastbit
^ wave
^ 1;
2480 /* Keep track of how we start our wave and if we changed or not this time */
2481 wave
^= bit
^ lastbit
;
2485 RepaintGraphWindow();
2489 * Manchester demodulate a bitstream. The bitstream needs to be already in
2490 * the GraphBuffer as 0 and 1 values
2492 * Give the clock rate as argument in order to help the sync - the algorithm
2493 * resyncs at each pulse anyway.
2495 * Not optimized by any means, this is the 1st time I'm writing this type of
2496 * routine, feel free to improve...
2498 * 1st argument: clock rate (as number of samples per clock rate)
2499 * Typical values can be 64, 32, 128...
2501 static void Cmdmanchesterdemod(char *str
) {
2502 int i
, j
, invert
= 0;
2508 int hithigh
, hitlow
, first
;
2514 /* check if we're inverting output */
2517 PrintToScrollback("Inverting output");
2521 while(*str
== ' '); // in case a 2nd argument was given
2524 /* Holds the decoded bitstream: each clock period contains 2 bits */
2525 /* later simplified to 1 bit after manchester decoding. */
2526 /* Add 10 bits to allow for noisy / uncertain traces without aborting */
2527 /* int BitStream[GraphTraceLen*2/clock+10]; */
2529 /* But it does not work if compiling on WIndows: therefore we just allocate a */
2531 int BitStream
[MAX_GRAPH_TRACE_LEN
];
2533 /* Detect high and lows */
2534 for (i
= 0; i
< GraphTraceLen
; i
++)
2536 if (GraphBuffer
[i
] > high
)
2537 high
= GraphBuffer
[i
];
2538 else if (GraphBuffer
[i
] < low
)
2539 low
= GraphBuffer
[i
];
2543 clock
= GetClock(str
, high
);
2545 int tolerance
= clock
/4;
2547 /* Detect first transition */
2548 /* Lo-Hi (arbitrary) */
2549 /* skip to the first high */
2550 for (i
= 0; i
< GraphTraceLen
; i
++)
2551 if(GraphBuffer
[i
] == high
)
2553 /* now look for the first low */
2554 for (; i
< GraphTraceLen
; i
++)
2556 if (GraphBuffer
[i
] == low
)
2563 /* If we're not working with 1/0s, demod based off clock */
2566 bit
= 0; /* We assume the 1st bit is zero, it may not be
2567 * the case: this routine (I think) has an init problem.
2570 for (; i
< (int)(GraphTraceLen
/ clock
); i
++)
2576 /* Find out if we hit both high and low peaks */
2577 for (j
= 0; j
< clock
; j
++)
2579 if (GraphBuffer
[(i
* clock
) + j
] == high
)
2581 else if (GraphBuffer
[(i
* clock
) + j
] == low
)
2584 /* it doesn't count if it's the first part of our read
2585 because it's really just trailing from the last sequence */
2586 if (first
&& (hithigh
|| hitlow
))
2587 hithigh
= hitlow
= 0;
2591 if (hithigh
&& hitlow
)
2595 /* If we didn't hit both high and low peaks, we had a bit transition */
2596 if (!hithigh
|| !hitlow
)
2599 BitStream
[bit2idx
++] = bit
^ invert
;
2603 /* standard 1/0 bitstream */
2607 /* Then detect duration between 2 successive transitions */
2608 for (bitidx
= 1; i
< GraphTraceLen
; i
++)
2610 if (GraphBuffer
[i
-1] != GraphBuffer
[i
])
2615 // Error check: if bitidx becomes too large, we do not
2616 // have a Manchester encoded bitstream or the clock is really
2618 if (bitidx
> (GraphTraceLen
*2/clock
+8) ) {
2619 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
2622 // Then switch depending on lc length:
2623 // Tolerance is 1/4 of clock rate (arbitrary)
2624 if (abs(lc
-clock
/2) < tolerance
) {
2625 // Short pulse : either "1" or "0"
2626 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2627 } else if (abs(lc
-clock
) < tolerance
) {
2628 // Long pulse: either "11" or "00"
2629 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2630 BitStream
[bitidx
++]=GraphBuffer
[i
-1];
2634 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
2635 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
2639 PrintToScrollback("Error: too many detection errors, aborting.");
2646 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
2647 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
2648 // to stop output at the final bitidx2 value, not bitidx
2649 for (i
= 0; i
< bitidx
; i
+= 2) {
2650 if ((BitStream
[i
] == 0) && (BitStream
[i
+1] == 1)) {
2651 BitStream
[bit2idx
++] = 1 ^ invert
;
2652 } else if ((BitStream
[i
] == 1) && (BitStream
[i
+1] == 0)) {
2653 BitStream
[bit2idx
++] = 0 ^ invert
;
2655 // We cannot end up in this state, this means we are unsynchronized,
2659 PrintToScrollback("Unsynchronized, resync...");
2660 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
2664 PrintToScrollback("Error: too many decode errors, aborting.");
2671 PrintToScrollback("Manchester decoded bitstream");
2672 // Now output the bitstream to the scrollback by line of 16 bits
2673 for (i
= 0; i
< (bit2idx
-16); i
+=16) {
2674 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
2697 static void CmdHiddemod(char *str
)
2699 if(GraphTraceLen
< 4800) {
2700 PrintToScrollback("too short; need at least 4800 samples");
2704 GraphTraceLen
= 4800;
2706 for(i
= 0; i
< GraphTraceLen
; i
++) {
2707 if(GraphBuffer
[i
] < 0) {
2713 RepaintGraphWindow();
2716 static void CmdPlot(char *str
)
2721 static void CmdGrid(char *str
)
2723 sscanf(str
, "%i %i", &PlotGridX
, &PlotGridY
);
2724 RepaintGraphWindow();
2727 static void CmdHide(char *str
)
2732 static void CmdScale(char *str
)
2734 CursorScaleFactor
= atoi(str
);
2735 if(CursorScaleFactor
== 0) {
2736 PrintToScrollback("bad, can't have zero scale");
2737 CursorScaleFactor
= 1;
2739 RepaintGraphWindow();
2742 static void CmdSave(char *str
)
2744 FILE *f
= fopen(str
, "w");
2746 PrintToScrollback("couldn't open '%s'", str
);
2750 for(i
= 0; i
< GraphTraceLen
; i
++) {
2751 fprintf(f
, "%d\n", GraphBuffer
[i
]);
2754 PrintToScrollback("saved to '%s'", str
);
2757 static void CmdLoad(char *str
)
2759 FILE *f
= fopen(str
, "r");
2761 PrintToScrollback("couldn't open '%s'", str
);
2767 while(fgets(line
, sizeof(line
), f
)) {
2768 GraphBuffer
[GraphTraceLen
] = atoi(line
);
2772 PrintToScrollback("loaded %d samples", GraphTraceLen
);
2773 RepaintGraphWindow();
2776 static void CmdHIDsimTAG(char *str
)
2778 unsigned int hi
=0, lo
=0;
2782 while (sscanf(&str
[i
++], "%1x", &n
) == 1) {
2783 hi
=(hi
<<4)|(lo
>>28);
2787 PrintToScrollback("Emulating tag with ID %x%16x", hi
, lo
);
2789 c
.cmd
= CMD_HID_SIM_TAG
;
2792 SendCommand(&c
, FALSE
);
2795 static void CmdReadmem(char *str
)
2798 c
.cmd
= CMD_READ_MEM
;
2800 SendCommand(&c
, FALSE
);
2803 static void CmdVersion(char *str
)
2806 c
.cmd
= CMD_VERSION
;
2807 SendCommand(&c
, FALSE
);
2810 static void CmdLcdReset(char *str
)
2813 c
.cmd
= CMD_LCD_RESET
;
2815 SendCommand(&c
, FALSE
);
2818 static void CmdLcd(char *str
)
2823 sscanf(str
, "%x %d", &i
, &j
);
2826 SendCommand(&c
, FALSE
);
2831 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
2834 static void CmdSetDivisor(char *str
)
2837 c
.cmd
= CMD_SET_LF_DIVISOR
;
2839 if (( c
.ext1
<0) || (c
.ext1
>255)) {
2840 PrintToScrollback("divisor must be between 19 and 255");
2842 SendCommand(&c
, FALSE
);
2843 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c
.ext1
+1));
2847 static void CmdSetMux(char *str
)
2850 c
.cmd
= CMD_SET_ADC_MUX
;
2851 if(strcmp(str
, "lopkd") == 0) {
2853 } else if(strcmp(str
, "loraw") == 0) {
2855 } else if(strcmp(str
, "hipkd") == 0) {
2857 } else if(strcmp(str
, "hiraw") == 0) {
2860 SendCommand(&c
, FALSE
);
2863 typedef void HandlerFunction(char *cmdline
);
2865 /* in alphabetic order */
2868 HandlerFunction
*handler
;
2869 int offline
; // 1 if the command can be used when in offline mode
2871 } CommandTable
[] = {
2872 {"amp", CmdAmp
, 1, "Amplify peaks"},
2873 {"askdemod", Cmdaskdemod
, 1, "<0|1> -- Attempt to demodulate simple ASK tags"},
2874 {"autocorr", CmdAutoCorr
, 1, "<window length> -- Autocorrelation over window"},
2875 {"bitsamples", CmdBitsamples
, 0, "Get raw samples as bitstring"},
2876 {"bitstream", Cmdbitstream
, 1, "[clock rate] -- Convert waveform into a bitstream"},
2877 {"buffclear", CmdBuffClear
, 1, "Clear sample buffer and graph window"},
2878 {"dec", CmdDec
, 1, "Decimate samples"},
2879 {"detectclock", Cmddetectclockrate
, 1, "Detect clock rate"},
2880 {"detectreader", CmdDetectReader
, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
2881 {"em410xsim", CmdEM410xsim
, 1, "<UID> -- Simulate EM410x tag"},
2882 {"em410xread", CmdEM410xread
, 1, "[clock rate] -- Extract ID from EM410x tag"},
2883 {"em410xwatch", CmdEM410xwatch
, 0, "Watches for EM410x tags"},
2884 {"em4x50read", CmdEM4x50read
, 1, "Extract data from EM4x50 tag"},
2885 {"exit", CmdQuit
, 1, "Exit program"},
2886 {"flexdemod", CmdFlexdemod
, 1, "Demodulate samples for FlexPass"},
2887 {"fpgaoff", CmdFPGAOff
, 0, "Set FPGA off"},
2888 {"fskdemod", CmdFSKdemod
, 1, "Demodulate graph window as a HID FSK"},
2889 {"grid", CmdGrid
, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
2890 {"hexsamples", CmdHexsamples
, 0, "<blocks> -- Dump big buffer as hex bytes"},
2891 {"hi14alist", CmdHi14alist
, 0, "List ISO 14443a history"},
2892 {"hi14areader", CmdHi14areader
, 0, "Act like an ISO14443 Type A reader"},
2893 {"hi14asim", CmdHi14asim
, 0, "<UID> -- Fake ISO 14443a tag"},
2894 {"hi14asnoop", CmdHi14asnoop
, 0, "Eavesdrop ISO 14443 Type A"},
2895 {"hi14bdemod", CmdHi14bdemod
, 1, "Demodulate ISO14443 Type B from tag"},
2896 {"hi14list", CmdHi14list
, 0, "List ISO 14443 history"},
2897 {"hi14read", CmdHi14read
, 0, "Read HF tag (ISO 14443)"},
2898 {"hi14sim", CmdHi14sim
, 0, "Fake ISO 14443 tag"},
2899 {"hi14snoop", CmdHi14snoop
, 0, "Eavesdrop ISO 14443"},
2900 {"hi15demod", CmdHi15demod
, 1, "Demodulate ISO15693 from tag"},
2901 {"hi15read", CmdHi15read
, 0, "Read HF tag (ISO 15693)"},
2902 {"hi15reader", CmdHi15reader
, 0, "Act like an ISO15693 reader"},
2903 {"hi15sim", CmdHi15tag
, 0, "Fake an ISO15693 tag"},
2904 {"hiddemod", CmdHiddemod
, 1, "Demodulate HID Prox Card II (not optimal)"},
2905 {"hide", CmdHide
, 1, "Hide graph window"},
2906 {"hidfskdemod", CmdHIDdemodFSK
, 0, "Realtime HID FSK demodulator"},
2907 {"hidsimtag", CmdHIDsimTAG
, 0, "<ID> -- HID tag simulator"},
2908 {"higet", CmdHi14read_sim
, 0, "<samples> -- Get samples HF, 'analog'"},
2909 {"hisamples", CmdHisamples
, 0, "Get raw samples for HF tag"},
2910 {"hisampless", CmdHisampless
, 0, "<samples> -- Get signed raw samples, HF tag"},
2911 {"hisamplest", CmdHi14readt
, 0, "Get samples HF, for testing"},
2912 {"hisimlisten", CmdHisimlisten
, 0, "Get HF samples as fake tag"},
2913 {"hpf", CmdHpf
, 1, "Remove DC offset from trace"},
2914 {"indalademod", CmdIndalademod
, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
2915 {"lcd", CmdLcd
, 0, "<HEX command> <count> -- Send command/data to LCD"},
2916 {"lcdreset", CmdLcdReset
, 0, "Hardware reset LCD"},
2917 {"legicrfsim", CmdLegicRfSim
, 0, "Start the LEGIC RF tag simulator"},
2918 {"legicrfread", CmdLegicRfRead
, 0, "Start the LEGIC RF reader"},
2919 {"load", CmdLoad
, 1, "<filename> -- Load trace (to graph window"},
2920 {"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)"},
2921 {"loread", CmdLoread
, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
2922 {"losamples", CmdLosamples
, 0, "[128 - 16000] -- Get raw samples for LF tag"},
2923 {"losim", CmdLosim
, 0, "Simulate LF tag"},
2924 {"losimbidir", CmdLosimBidir
, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
2925 {"ltrim", CmdLtrim
, 1, "<samples> -- Trim samples from left of trace"},
2926 {"mandemod", Cmdmanchesterdemod
, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
2927 {"manmod", Cmdmanchestermod
, 1, "[clock rate] -- Manchester modulate a binary stream"},
2928 {"norm", CmdNorm
, 1, "Normalize max/min to +/-500"},
2929 {"plot", CmdPlot
, 1, "Show graph window"},
2930 {"quit", CmdQuit
, 1, "Quit program"},
2931 {"readmem", CmdReadmem
, 0, "[address] -- Read memory at decimal address from flash"},
2932 {"reset", CmdReset
, 0, "Reset the Proxmark3"},
2933 {"save", CmdSave
, 1, "<filename> -- Save trace (from graph window)"},
2934 {"scale", CmdScale
, 1, "<int> -- Set cursor display scale"},
2935 {"setlfdivisor", CmdSetDivisor
, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
2936 {"setmux", CmdSetMux
, 0, "<loraw|hiraw|lopkd|hipkd> -- Set the ADC mux to a specific value"},
2937 {"sri512read", CmdSri512read
, 0, "<int> -- Read contents of a SRI512 tag"},
2938 {"tidemod", CmdTIDemod
, 1, "Demodulate raw bits for TI-type LF tag"},
2939 {"tiread", CmdTIRead
, 0, "Read and decode a TI 134 kHz tag"},
2940 {"tiwrite", CmdTIWrite
, 0, "Write new data to a r/w TI 134 kHz tag"},
2941 {"threshold", CmdThreshold
, 1, "Maximize/minimize every value in the graph window depending on threshold"},
2942 {"tune", CmdTune
, 0, "Measure antenna tuning"},
2943 {"vchdemod", CmdVchdemod
, 0, "['clone'] -- Demodulate samples for VeriChip"},
2944 {"version", CmdVersion
, 0, "Show version inforation about the connected Proxmark"},
2945 {"zerocrossings", CmdZerocrossings
, 1, "Count time between zero-crossings"},
2953 } CommandExtendedHelp
[]= {
2954 {"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."},
2955 {"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."},
2958 //-----------------------------------------------------------------------------
2959 // Entry point into our code: called whenever the user types a command and
2960 // then presses Enter, which the full command line that they typed.
2961 //-----------------------------------------------------------------------------
2962 void CommandReceived(char *cmd
)
2967 PrintToScrollback("> %s", cmd
);
2969 if(strcmp(cmd
, "help") == 0 || strncmp(cmd
,"help ",strlen("help ")) == 0) {
2970 // check if we're doing extended help
2971 if(strlen(cmd
) > strlen("help ")) {
2972 cmd
+= strlen("help ");
2973 for(i
= 0; i
< sizeof(CommandExtendedHelp
) / sizeof(CommandExtendedHelp
[0]); i
++) {
2974 if(strcmp(CommandExtendedHelp
[i
].name
,cmd
) == 0) {
2975 PrintToScrollback("\nExtended help for '%s':\n", cmd
);
2976 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp
[i
].args
,CommandExtendedHelp
[i
].argshelp
);
2977 PrintToScrollback(CommandExtendedHelp
[i
].description
);
2978 PrintToScrollback("");
2982 PrintToScrollback("No extended help available for '%s'", cmd
);
2985 if (offline
) PrintToScrollback("Operating in OFFLINE mode (no device connected)");
2986 PrintToScrollback("\r\nAvailable commands:");
2987 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
2988 if (offline
&& (CommandTable
[i
].offline
==0)) continue;
2989 memset(line
, ' ', sizeof(line
));
2990 strcpy(line
+2, CommandTable
[i
].name
);
2991 line
[strlen(line
)] = ' ';
2992 sprintf(line
+15, " -- %s", CommandTable
[i
].docString
);
2993 PrintToScrollback("%s", line
);
2995 PrintToScrollback("");
2996 PrintToScrollback("'help <command>' for extended help on that command\n");
3000 for(i
= 0; i
< sizeof(CommandTable
) / sizeof(CommandTable
[0]); i
++) {
3001 char *name
= CommandTable
[i
].name
;
3002 if(memcmp(cmd
, name
, strlen(name
))==0 &&
3003 (cmd
[strlen(name
)] == ' ' || cmd
[strlen(name
)] == '\0'))
3005 cmd
+= strlen(name
);
3006 while(*cmd
== ' ') {
3009 if (offline
&& (CommandTable
[i
].offline
==0)) {
3010 PrintToScrollback("Offline mode, cannot use this command.");
3013 (CommandTable
[i
].handler
)(cmd
);
3017 PrintToScrollback(">> bad command '%s'", cmd
);
3020 //-----------------------------------------------------------------------------
3021 // Entry point into our code: called whenever we received a packet over USB
3022 // that we weren't necessarily expecting, for example a debug print.
3023 //-----------------------------------------------------------------------------
3024 void UsbCommandReceived(UsbCommand
*c
)
3027 case CMD_DEBUG_PRINT_STRING
: {
3029 if(c
->ext1
> 70 || c
->ext1
< 0) {
3032 memcpy(s
, c
->d
.asBytes
, c
->ext1
);
3034 PrintToScrollback("#db# %s", s
);
3038 case CMD_DEBUG_PRINT_INTEGERS
:
3039 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c
->ext1
, c
->ext2
, c
->ext3
);
3042 case CMD_MEASURED_ANTENNA_TUNING
: {
3044 int vLf125
, vLf134
, vHf
;
3045 vLf125
= c
->ext1
& 0xffff;
3046 vLf134
= c
->ext1
>> 16;
3047 vHf
= c
->ext2
& 0xffff;;
3048 peakf
= c
->ext3
& 0xffff;
3049 peakv
= c
->ext3
>> 16;
3050 PrintToScrollback("");
3051 PrintToScrollback("");
3052 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125
/1000.0);
3053 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134
/1000.0);
3054 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv
/1000.0, 12000.0/(peakf
+1));
3055 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf
/1000.0);
3057 PrintToScrollback("# Your LF antenna is unusable.");
3058 else if (peakv
<10000)
3059 PrintToScrollback("# Your LF antenna is marginal.");
3061 PrintToScrollback("# Your HF antenna is unusable.");
3063 PrintToScrollback("# Your HF antenna is marginal.");
3067 PrintToScrollback("unrecognized command %08x\n", c
->cmd
);