]> git.zerfleddert.de Git - proxmark3-svn/blame - winsrc/command.cpp
fix mandemod initialisation and add Transit tag trace
[proxmark3-svn] / winsrc / command.cpp
CommitLineData
6658905f 1//-----------------------------------------------------------------------------\r
2// The actual command interpeter for what the user types at the command line.\r
3// Jonathan Westhues, Sept 2005\r
4// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
5//-----------------------------------------------------------------------------\r
6#include <windows.h>\r
7#include <stdlib.h>\r
8#include <string.h>\r
9#include <stdio.h>\r
10#include <limits.h>\r
11#include <math.h>\r
12\r
13#include "prox.h"\r
14#include "../common/iso14443_crc.c"\r
0c2ed92d 15#include "../common/crc16.c"\r
6658905f 16\r
17#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
9760414b 18#define BIT(x) GraphBuffer[x * clock]\r
19#define BITS (GraphTraceLen / clock)\r
6658905f 20\r
9760414b 21int go = 0;\r
6658905f 22static int CmdHisamplest(char *str, int nrlow);\r
23\r
24static void GetFromBigBuf(BYTE *dest, int bytes)\r
25{\r
26 int n = bytes/4;\r
27\r
28 if(n % 48 != 0) {\r
29 PrintToScrollback("bad len in GetFromBigBuf");\r
30 return;\r
31 }\r
32\r
33 int i;\r
34 for(i = 0; i < n; i += 12) {\r
35 UsbCommand c;\r
36 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
37 c.ext1 = i;\r
38 SendCommand(&c, FALSE);\r
39 ReceiveCommand(&c);\r
40 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 41 PrintToScrollback("bad resp");\r
6658905f 42 return;\r
43 }\r
44\r
45 memcpy(dest+(i*4), c.d.asBytes, 48);\r
46 }\r
47}\r
48\r
d722c4ce 49static void CmdReset(char *str)\r
50{\r
51 UsbCommand c;\r
52 c.cmd = CMD_HARDWARE_RESET;\r
53 SendCommand(&c, FALSE);\r
54}\r
55\r
f23e056d 56static void CmdBuffClear(char *str)\r
57{\r
58 UsbCommand c;\r
59 c.cmd = CMD_BUFF_CLEAR;\r
60 SendCommand(&c, FALSE);\r
61 CmdClearGraph(TRUE);\r
62}\r
d722c4ce 63\r
6658905f 64static void CmdQuit(char *str)\r
65{\r
66 exit(0);\r
67}\r
68\r
69static void CmdHIDdemodFSK(char *str)\r
70{\r
71 UsbCommand c;\r
72 c.cmd = CMD_HID_DEMOD_FSK;\r
73 SendCommand(&c, FALSE);\r
74}\r
75\r
76static void CmdTune(char *str)\r
77{\r
78 UsbCommand c;\r
79 c.cmd = CMD_MEASURE_ANTENNA_TUNING;\r
80 SendCommand(&c, FALSE);\r
81}\r
82\r
83static void CmdHi15read(char *str)\r
84{\r
85 UsbCommand c;\r
86 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;\r
87 SendCommand(&c, FALSE);\r
88}\r
89\r
90static void CmdHi14read(char *str)\r
91{\r
92 UsbCommand c;\r
93 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
94 c.ext1 = atoi(str);\r
95 SendCommand(&c, FALSE);\r
96}\r
9760414b 97\r
98\r
99/* New command to read the contents of a SRI512 tag\r
100 * SRI512 tags are ISO14443-B modulated memory tags,\r
101 * this command just dumps the contents of the memory/\r
102 */\r
103static void CmdSri512read(char *str)\r
104{\r
fb25b483 105 UsbCommand c;\r
106 c.cmd = CMD_READ_SRI512_TAG;\r
107 c.ext1 = atoi(str);\r
9760414b 108 SendCommand(&c, FALSE);\r
109}\r
6658905f 110\r
111// ## New command\r
112static void CmdHi14areader(char *str)\r
113{\r
114 UsbCommand c;\r
115 c.cmd = CMD_READER_ISO_14443a;\r
116 c.ext1 = atoi(str);\r
117 SendCommand(&c, FALSE);\r
118}\r
119\r
120// ## New command\r
121static void CmdHi15reader(char *str)\r
122{\r
123 UsbCommand c;\r
124 c.cmd = CMD_READER_ISO_15693;\r
125 c.ext1 = atoi(str);\r
126 SendCommand(&c, FALSE);\r
127}\r
128\r
129// ## New command\r
130static void CmdHi15tag(char *str)\r
131{\r
132 UsbCommand c;\r
133 c.cmd = CMD_SIMTAG_ISO_15693;\r
134 c.ext1 = atoi(str);\r
135 SendCommand(&c, FALSE);\r
136}\r
137\r
138static void CmdHi14read_sim(char *str)\r
139{\r
140 UsbCommand c;\r
141 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM;\r
142 c.ext1 = atoi(str);\r
143 SendCommand(&c, FALSE);\r
144}\r
145\r
146static void CmdHi14readt(char *str)\r
147{\r
148 UsbCommand c;\r
149 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
150 c.ext1 = atoi(str);\r
151 SendCommand(&c, FALSE);\r
152\r
153 //CmdHisamplest(str);\r
154 while(CmdHisamplest(str,atoi(str))==0) {\r
155 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
156 c.ext1 = atoi(str);\r
157 SendCommand(&c, FALSE);\r
158 }\r
159 RepaintGraphWindow();\r
160}\r
161\r
162static void CmdHisimlisten(char *str)\r
163{\r
164 UsbCommand c;\r
165 c.cmd = CMD_SIMULATE_TAG_HF_LISTEN;\r
166 SendCommand(&c, FALSE);\r
167}\r
168\r
169static void CmdHi14sim(char *str)\r
170{\r
171 UsbCommand c;\r
172 c.cmd = CMD_SIMULATE_TAG_ISO_14443;\r
173 SendCommand(&c, FALSE);\r
174}\r
6658905f 175\r
176static void CmdHi14asim(char *str) // ## simulate iso14443a tag\r
177{ // ## greg - added ability to specify tag UID\r
178\r
179 unsigned int hi=0, lo=0;\r
180 int n=0, i=0;\r
181 UsbCommand c;\r
182\r
183 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
184 hi=(hi<<4)|(lo>>28);\r
185 lo=(lo<<4)|(n&0xf);\r
186 }\r
187\r
188 c.cmd = CMD_SIMULATE_TAG_ISO_14443a;\r
189 // c.ext should be set to *str or convert *str to the correct format for a uid\r
190 c.ext1 = hi;\r
191 c.ext2 = lo;\r
192 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi, lo);\r
193 SendCommand(&c, FALSE);\r
194}\r
195\r
196static void CmdHi14snoop(char *str)\r
197{\r
198 UsbCommand c;\r
199 c.cmd = CMD_SNOOP_ISO_14443;\r
200 SendCommand(&c, FALSE);\r
201}\r
202\r
203static void CmdHi14asnoop(char *str)\r
204{\r
205 UsbCommand c;\r
206 c.cmd = CMD_SNOOP_ISO_14443a;\r
207 SendCommand(&c, FALSE);\r
208}\r
209\r
210static void CmdFPGAOff(char *str) // ## FPGA Control\r
211{\r
212 UsbCommand c;\r
213 c.cmd = CMD_FPGA_MAJOR_MODE_OFF;\r
214 SendCommand(&c, FALSE);\r
215}\r
216\r
9760414b 217/* clear out our graph window */\r
218int CmdClearGraph(int redraw)\r
219{\r
220 int gtl = GraphTraceLen;\r
221 GraphTraceLen = 0;\r
15db5fb7 222\r
9760414b 223 if (redraw)\r
224 RepaintGraphWindow();\r
15db5fb7 225\r
9760414b 226 return gtl;\r
227}\r
228\r
229/* write a bit to the graph */\r
230static void CmdAppendGraph(int redraw, int clock, int bit)\r
6658905f 231{\r
232 int i;\r
233\r
9760414b 234 for (i = 0; i < (int)(clock/2); i++)\r
235 GraphBuffer[GraphTraceLen++] = bit ^ 1;\r
15db5fb7 236\r
237 for (i = (int)(clock/2); i < clock; i++)\r
9760414b 238 GraphBuffer[GraphTraceLen++] = bit;\r
239\r
240 if (redraw)\r
241 RepaintGraphWindow();\r
242}\r
243\r
244/* Function is equivalent of loread + losamples + em410xread\r
245 * looped until an EM410x tag is detected */\r
246static void CmdEM410xwatch(char *str)\r
247{\r
248 char *zero = "";\r
249 char *twok = "2000";\r
250 go = 1;\r
15db5fb7 251\r
9760414b 252 do\r
253 {\r
254 CmdLoread(zero);\r
255 CmdLosamples(twok);\r
256 CmdEM410xread(zero);\r
257 } while (go);\r
258}\r
259\r
955aa93f 260/* Read the transmitted data of an EM4x50 tag\r
261 * Format:\r
262 *\r
263 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
264 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
265 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
266 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
267 * CCCCCCCC <- column parity bits\r
268 * 0 <- stop bit\r
269 * LW <- Listen Window\r
270 *\r
271 * This pattern repeats for every block of data being transmitted.\r
272 * Transmission starts with two Listen Windows (LW - a modulated\r
273 * pattern of 320 cycles each (32/32/128/64/64)).\r
274 *\r
275 * Note that this data may or may not be the UID. It is whatever data\r
67853904 276 * is stored in the blocks defined in the control word First and Last\r
955aa93f 277 * Word Read values. UID is stored in block 32.\r
67853904 278 */\r
955aa93f 279static void CmdEM4x50read(char *str)\r
280{\r
281 int i, j, startblock, clock, skip, block, start, end, low, high;\r
282 BOOL complete= FALSE;\r
283 int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];\r
284 char tmp[6];\r
285\r
286 high= low= 0;\r
287 clock= 64;\r
288\r
289 /* first get high and low values */\r
290 for (i = 0; i < GraphTraceLen; i++)\r
291 {\r
67853904 292 if (GraphBuffer[i] > high)\r
955aa93f 293 high = GraphBuffer[i];\r
294 else if (GraphBuffer[i] < low)\r
295 low = GraphBuffer[i];\r
296 }\r
297\r
298 /* populate a buffer with pulse lengths */\r
299 i= 0;\r
300 j= 0;\r
301 while(i < GraphTraceLen)\r
302 {\r
303 // measure from low to low\r
3628c318 304 while((GraphBuffer[i] > low) && (i<GraphTraceLen))\r
955aa93f 305 ++i;\r
306 start= i;\r
3628c318 307 while((GraphBuffer[i] < high) && (i<GraphTraceLen))\r
955aa93f 308 ++i;\r
3628c318 309 while((GraphBuffer[i] > low) && (i<GraphTraceLen))\r
955aa93f 310 ++i;\r
3628c318 311 if (j>(MAX_GRAPH_TRACE_LEN/64)) {\r
312 break;\r
313 }\r
955aa93f 314 tmpbuff[j++]= i - start;\r
315 }\r
316\r
955aa93f 317 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */\r
318 start= -1;\r
319 skip= 0;\r
320 for (i= 0; i < j - 4 ; ++i)\r
321 {\r
322 skip += tmpbuff[i];\r
323 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
324 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
325 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
326 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
327 {\r
328 start= i + 3;\r
329 break;\r
330 }\r
331 }\r
332 startblock= i + 3;\r
333\r
334 /* skip over the remainder of the LW */\r
335 skip += tmpbuff[i+1]+tmpbuff[i+2];\r
f81c82c3 336 while(skip < MAX_GRAPH_TRACE_LEN && GraphBuffer[skip] > low)\r
955aa93f 337 ++skip;\r
338 skip += 8;\r
339\r
340 /* now do it again to find the end */\r
341 end= start;\r
342 for (i += 3; i < j - 4 ; ++i)\r
343 {\r
344 end += tmpbuff[i];\r
345 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
346 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
347 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
348 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
349 {\r
350 complete= TRUE;\r
351 break;\r
352 }\r
353 }\r
354\r
355 if (start >= 0)\r
356 PrintToScrollback("Found data at sample: %i",skip);\r
357 else\r
358 {\r
359 PrintToScrollback("No data found!");\r
360 PrintToScrollback("Try again with more samples.");\r
361 return;\r
362 }\r
363\r
364 if (!complete)\r
365 {\r
366 PrintToScrollback("*** Warning!");\r
367 PrintToScrollback("Partial data - no end found!");\r
368 PrintToScrollback("Try again with more samples.");\r
369 }\r
370\r
371 /* get rid of leading crap */\r
372 sprintf(tmp,"%i",skip);\r
373 CmdLtrim(tmp);\r
374\r
375 /* now work through remaining buffer printing out data blocks */\r
376 block= 0;\r
377 i= startblock;\r
378 while(block < 6)\r
379 {\r
380 PrintToScrollback("Block %i:", block);\r
381 // mandemod routine needs to be split so we can call it for data\r
382 // just print for now for debugging\r
383 Cmdmanchesterdemod("i 64");\r
384 skip= 0;\r
385 /* look for LW before start of next block */\r
386 for ( ; i < j - 4 ; ++i)\r
387 {\r
388 skip += tmpbuff[i];\r
389 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
390 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
391 break;\r
392 }\r
393 while(GraphBuffer[skip] > low)\r
394 ++skip;\r
395 skip += 8;\r
396 sprintf(tmp,"%i",skip);\r
397 CmdLtrim(tmp);\r
398 start += skip;\r
399 block++;\r
400 }\r
401}\r
402\r
403\r
9760414b 404/* Read the ID of an EM410x tag.\r
405 * Format:\r
406 * 1111 1111 1 <-- standard non-repeatable header\r
407 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
408 * ....\r
409 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column\r
410 * 0 <-- stop bit, end of tag\r
411 */\r
412static void CmdEM410xread(char *str)\r
413{\r
414 int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low;\r
415 int parity[4];\r
416 char id[11];\r
a91ff4c8 417 int retested = 0;\r
9760414b 418 int BitStream[MAX_GRAPH_TRACE_LEN];\r
419 high = low = 0;\r
15db5fb7 420\r
9760414b 421 /* Detect high and lows and clock */\r
422 for (i = 0; i < GraphTraceLen; i++)\r
423 {\r
424 if (GraphBuffer[i] > high)\r
425 high = GraphBuffer[i];\r
426 else if (GraphBuffer[i] < low)\r
427 low = GraphBuffer[i];\r
15db5fb7 428 }\r
429\r
9760414b 430 /* get clock */\r
431 clock = GetClock(str, high);\r
15db5fb7 432\r
9760414b 433 /* parity for our 4 columns */\r
434 parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
435 header = rows = 0;\r
15db5fb7 436\r
9760414b 437 /* manchester demodulate */\r
438 bit = bit2idx = 0;\r
439 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
440 {\r
441 hithigh = 0;\r
442 hitlow = 0;\r
443 first = 1;\r
15db5fb7 444\r
9760414b 445 /* Find out if we hit both high and low peaks */\r
446 for (j = 0; j < clock; j++)\r
447 {\r
448 if (GraphBuffer[(i * clock) + j] == high)\r
449 hithigh = 1;\r
450 else if (GraphBuffer[(i * clock) + j] == low)\r
451 hitlow = 1;\r
15db5fb7 452\r
9760414b 453 /* it doesn't count if it's the first part of our read\r
454 because it's really just trailing from the last sequence */\r
455 if (first && (hithigh || hitlow))\r
456 hithigh = hitlow = 0;\r
457 else\r
458 first = 0;\r
15db5fb7 459\r
9760414b 460 if (hithigh && hitlow)\r
461 break;\r
462 }\r
67853904 463\r
9760414b 464 /* If we didn't hit both high and low peaks, we had a bit transition */\r
465 if (!hithigh || !hitlow)\r
466 bit ^= 1;\r
67853904 467\r
9760414b 468 BitStream[bit2idx++] = bit;\r
469 }\r
67853904 470\r
a91ff4c8 471retest:\r
9760414b 472 /* We go till 5 before the graph ends because we'll get that far below */\r
473 for (i = 1; i < bit2idx - 5; i++)\r
474 {\r
475 /* Step 2: We have our header but need our tag ID */\r
476 if (header == 9 && rows < 10)\r
477 {\r
478 /* Confirm parity is correct */\r
479 if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4])\r
480 {\r
481 /* Read another byte! */\r
482 sprintf(id+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3]));\r
483 rows++;\r
15db5fb7 484\r
9760414b 485 /* Keep parity info */\r
486 parity[0] ^= BitStream[i];\r
487 parity[1] ^= BitStream[i+1];\r
488 parity[2] ^= BitStream[i+2];\r
489 parity[3] ^= BitStream[i+3];\r
15db5fb7 490\r
9760414b 491 /* Move 4 bits ahead */\r
492 i += 4;\r
493 }\r
15db5fb7 494\r
9760414b 495 /* Damn, something wrong! reset */\r
496 else\r
497 {\r
498 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i);\r
15db5fb7 499\r
9760414b 500 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */\r
501 i -= 9 + (5 * rows) - 5;\r
502\r
503 rows = header = 0;\r
504 }\r
505 }\r
15db5fb7 506\r
9760414b 507 /* Step 3: Got our 40 bits! confirm column parity */\r
508 else if (rows == 10)\r
509 {\r
510 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */\r
511 if (BitStream[i] == parity[0] && BitStream[i+1] == parity[1] &&\r
512 BitStream[i+2] == parity[2] && BitStream[i+3] == parity[3] &&\r
513 BitStream[i+4] == 0)\r
514 {\r
515 /* Sweet! */\r
516 PrintToScrollback("EM410x Tag ID: %s", id);\r
15db5fb7 517\r
9760414b 518 /* Stop any loops */\r
519 go = 0;\r
a91ff4c8 520 return;\r
9760414b 521 }\r
15db5fb7 522\r
9760414b 523 /* Crap! Incorrect parity or no stop bit, start all over */\r
524 else\r
525 {\r
526 rows = header = 0;\r
15db5fb7 527\r
9760414b 528 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */\r
529 i -= 59;\r
530 }\r
531 }\r
15db5fb7 532\r
9760414b 533 /* Step 1: get our header */\r
534 else if (header < 9)\r
535 {\r
536 /* Need 9 consecutive 1's */\r
537 if (BitStream[i] == 1)\r
538 header++;\r
15db5fb7 539\r
9760414b 540 /* We don't have a header, not enough consecutive 1 bits */\r
541 else\r
542 header = 0;\r
543 }\r
544 }\r
67853904 545\r
a91ff4c8 546 /* if we've already retested after flipping bits, return */\r
547 if (retested++)\r
548 return;\r
549\r
550 /* if this didn't work, try flipping bits */\r
551 for (i = 0; i < bit2idx; i++)\r
552 BitStream[i] ^= 1;\r
553\r
554 goto retest;\r
9760414b 555}\r
556\r
557/* emulate an EM410X tag\r
558 * Format:\r
559 * 1111 1111 1 <-- standard non-repeatable header\r
560 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
561 * ....\r
562 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column\r
563 * 0 <-- stop bit, end of tag\r
564 */\r
565static void CmdEM410xsim(char *str)\r
566{\r
567 int i, n, j, h, binary[4], parity[4];\r
568 char *s = "0";\r
15db5fb7 569\r
9760414b 570 /* clock is 64 in EM410x tags */\r
571 int clock = 64;\r
15db5fb7 572\r
9760414b 573 /* clear our graph */\r
574 CmdClearGraph(0);\r
15db5fb7 575\r
9760414b 576 /* write it out a few times */\r
577 for (h = 0; h < 4; h++)\r
578 {\r
579 /* write 9 start bits */\r
580 for (i = 0; i < 9; i++)\r
581 CmdAppendGraph(0, clock, 1);\r
15db5fb7 582\r
9760414b 583 /* for each hex char */\r
584 parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
585 for (i = 0; i < 10; i++)\r
586 {\r
587 /* read each hex char */\r
588 sscanf(&str[i], "%1x", &n);\r
589 for (j = 3; j >= 0; j--, n/= 2)\r
590 binary[j] = n % 2;\r
15db5fb7 591\r
9760414b 592 /* append each bit */\r
593 CmdAppendGraph(0, clock, binary[0]);\r
594 CmdAppendGraph(0, clock, binary[1]);\r
595 CmdAppendGraph(0, clock, binary[2]);\r
596 CmdAppendGraph(0, clock, binary[3]);\r
15db5fb7 597\r
9760414b 598 /* append parity bit */\r
599 CmdAppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);\r
15db5fb7 600\r
9760414b 601 /* keep track of column parity */\r
602 parity[0] ^= binary[0];\r
603 parity[1] ^= binary[1];\r
604 parity[2] ^= binary[2];\r
605 parity[3] ^= binary[3];\r
606 }\r
15db5fb7 607\r
9760414b 608 /* parity columns */\r
609 CmdAppendGraph(0, clock, parity[0]);\r
610 CmdAppendGraph(0, clock, parity[1]);\r
611 CmdAppendGraph(0, clock, parity[2]);\r
612 CmdAppendGraph(0, clock, parity[3]);\r
15db5fb7 613\r
9760414b 614 /* stop bit */\r
615 CmdAppendGraph(0, clock, 0);\r
616 }\r
15db5fb7 617\r
9760414b 618 /* modulate that biatch */\r
619 Cmdmanchestermod(s);\r
15db5fb7 620\r
9760414b 621 /* booyah! */\r
622 RepaintGraphWindow();\r
623\r
624 CmdLosim(s);\r
625}\r
626\r
627static void ChkBitstream(char *str)\r
628{\r
629 int i;\r
15db5fb7 630\r
9760414b 631 /* convert to bitstream if necessary */\r
632 for (i = 0; i < (int)(GraphTraceLen / 2); i++)\r
633 {\r
634 if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)\r
635 {\r
636 Cmdbitstream(str);\r
637 break;\r
638 }\r
639 }\r
640}\r
641\r
642static void CmdLosim(char *str)\r
643{\r
644 int i;\r
15db5fb7 645\r
9760414b 646 /* convert to bitstream if necessary */\r
647 ChkBitstream(str);\r
15db5fb7 648\r
9760414b 649 for (i = 0; i < GraphTraceLen; i += 48) {\r
6658905f 650 UsbCommand c;\r
651 int j;\r
652 for(j = 0; j < 48; j++) {\r
653 c.d.asBytes[j] = GraphBuffer[i+j];\r
654 }\r
655 c.cmd = CMD_DOWNLOADED_SIM_SAMPLES_125K;\r
656 c.ext1 = i;\r
657 SendCommand(&c, FALSE);\r
658 }\r
659\r
660 UsbCommand c;\r
661 c.cmd = CMD_SIMULATE_TAG_125K;\r
662 c.ext1 = GraphTraceLen;\r
663 SendCommand(&c, FALSE);\r
664}\r
665\r
0fa9ca5b 666static void CmdLosimBidir(char *str)\r
667{\r
668 UsbCommand c;\r
669 c.cmd = CMD_LF_SIMULATE_BIDIR;\r
670 c.ext1 = 47; /* Set ADC to twice the carrier for a slight supersampling */\r
671 c.ext2 = 384;\r
672 SendCommand(&c, FALSE);\r
673}\r
674\r
6658905f 675static void CmdLoread(char *str)\r
676{\r
677 UsbCommand c;\r
678 // 'h' means higher-low-frequency, 134 kHz\r
679 if(*str == 'h') {\r
680 c.ext1 = 1;\r
681 } else if (*str == '\0') {\r
682 c.ext1 = 0;\r
683 } else {\r
684 PrintToScrollback("use 'loread' or 'loread h'");\r
685 return;\r
686 }\r
687 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
688 SendCommand(&c, FALSE);\r
689}\r
690\r
7f348042 691static void CmdDetectReader(char *str)\r
692{\r
693 UsbCommand c;\r
694 // 'l' means LF - 125/134 kHz\r
695 if(*str == 'l') {\r
696 c.ext1 = 1;\r
697 } else if (*str == 'h') {\r
698 c.ext1 = 2;\r
699 } else if (*str != '\0') {\r
700 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");\r
701 return;\r
702 }\r
703 c.cmd = CMD_LISTEN_READER_FIELD;\r
704 SendCommand(&c, FALSE);\r
705}\r
706\r
959baa89 707/* send a command before reading */\r
708static void CmdLoCommandRead(char *str)\r
709{\r
710 static char dummy[3];\r
711\r
712 dummy[0]= ' ';\r
67853904 713\r
959baa89 714 UsbCommand c;\r
715 c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
1dd23352 716 sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, (char *) &c.d.asBytes,(char *) &dummy+1);\r
959baa89 717 // in case they specified 'h'\r
8172fb35 718 strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);\r
959baa89 719 SendCommand(&c, FALSE);\r
720}\r
721\r
6658905f 722static void CmdLosamples(char *str)\r
723{\r
724 int cnt = 0;\r
725 int i;\r
726 int n;\r
727\r
728 n=atoi(str);\r
729 if (n==0) n=128;\r
730 if (n>16000) n=16000;\r
731\r
732 for(i = 0; i < n; i += 12) {\r
733 UsbCommand c;\r
734 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
735 c.ext1 = i;\r
736 SendCommand(&c, FALSE);\r
737 ReceiveCommand(&c);\r
738 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 739 if (!go)\r
740 PrintToScrollback("bad resp");\r
6658905f 741 return;\r
742 }\r
743 int j;\r
744 for(j = 0; j < 48; j++) {\r
745 GraphBuffer[cnt++] = ((int)c.d.asBytes[j]) - 128;\r
746 }\r
747 }\r
748 GraphTraceLen = n*4;\r
749 RepaintGraphWindow();\r
750}\r
751\r
752static void CmdBitsamples(char *str)\r
753{\r
754 int cnt = 0;\r
755 int i;\r
756 int n;\r
757\r
758 n = 3072;\r
759 for(i = 0; i < n; i += 12) {\r
760 UsbCommand c;\r
761 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
762 c.ext1 = i;\r
763 SendCommand(&c, FALSE);\r
764 ReceiveCommand(&c);\r
765 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 766 PrintToScrollback("bad resp");\r
6658905f 767 return;\r
768 }\r
769 int j, k;\r
770 for(j = 0; j < 48; j++) {\r
771 for(k = 0; k < 8; k++) {\r
772 if(c.d.asBytes[j] & (1 << (7 - k))) {\r
773 GraphBuffer[cnt++] = 1;\r
774 } else {\r
775 GraphBuffer[cnt++] = 0;\r
776 }\r
777 }\r
778 }\r
779 }\r
780 GraphTraceLen = cnt;\r
781 RepaintGraphWindow();\r
782}\r
783\r
784static void CmdHisamples(char *str)\r
785{\r
786 int cnt = 0;\r
787 int i;\r
788 int n;\r
789 n = 1000;\r
790 for(i = 0; i < n; i += 12) {\r
791 UsbCommand c;\r
792 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
793 c.ext1 = i;\r
794 SendCommand(&c, FALSE);\r
795 ReceiveCommand(&c);\r
796 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 797 PrintToScrollback("bad resp");\r
6658905f 798 return;\r
799 }\r
800 int j;\r
801 for(j = 0; j < 48; j++) {\r
802 GraphBuffer[cnt++] = (int)((BYTE)c.d.asBytes[j]);\r
803 }\r
804 }\r
805 GraphTraceLen = n*4;\r
806\r
807 RepaintGraphWindow();\r
808}\r
809\r
6658905f 810static int CmdHisamplest(char *str, int nrlow)\r
811{\r
812 int cnt = 0;\r
813 int t1, t2;\r
814 int i;\r
815 int n;\r
816 int hasbeennull;\r
817 int show;\r
818\r
819\r
820 n = 1000;\r
821 hasbeennull = 0;\r
822 for(i = 0; i < n; i += 12) {\r
823 UsbCommand c;\r
824 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
825 c.ext1 = i;\r
826 SendCommand(&c, FALSE);\r
827 ReceiveCommand(&c);\r
828 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 829 PrintToScrollback("bad resp");\r
6658905f 830 return 0;\r
831 }\r
832 int j;\r
833 for(j = 0; j < 48; j++) {\r
834 t2 = (int)((BYTE)c.d.asBytes[j]);\r
835 if((t2 ^ 0xC0) & 0xC0) { hasbeennull++; }\r
836\r
837 show = 0;\r
838 switch(show) {\r
839 case 0:\r
840 // combined\r
841 t1 = (t2 & 0x80) ^ (t2 & 0x20);\r
842 t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x20);\r
843 break;\r
844\r
845 case 1:\r
846 // only reader\r
847 t1 = (t2 & 0x80);\r
848 t2 = ((t2 << 1) & 0x80);\r
849 break;\r
850\r
851 case 2:\r
852 // only tag\r
853 t1 = (t2 & 0x20);\r
854 t2 = ((t2 << 1) & 0x20);\r
855 break;\r
856\r
857 case 3:\r
858 // both, but tag with other algorithm\r
859 t1 = (t2 & 0x80) ^ (t2 & 0x08);\r
860 t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x08);\r
861 break;\r
862 }\r
863\r
864 GraphBuffer[cnt++] = t1;\r
865 GraphBuffer[cnt++] = t2;\r
866 }\r
867 }\r
868 GraphTraceLen = n*4;\r
869// 1130\r
870 if(hasbeennull>nrlow || nrlow==0) {\r
871 PrintToScrollback("hasbeennull=%d", hasbeennull);\r
872 return 1;\r
873 }\r
874 else {\r
875 return 0;\r
876 }\r
877}\r
878\r
879\r
880static void CmdHexsamples(char *str)\r
881{\r
882 int i;\r
883 int n;\r
884\r
885 if(atoi(str) == 0) {\r
886 n = 12;\r
887 } else {\r
888 n = atoi(str)/4;\r
889 }\r
890\r
891 for(i = 0; i < n; i += 12) {\r
892 UsbCommand c;\r
893 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
894 c.ext1 = i;\r
895 SendCommand(&c, FALSE);\r
896 ReceiveCommand(&c);\r
897 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 898 PrintToScrollback("bad resp");\r
6658905f 899 return;\r
900 }\r
901 int j;\r
902 for(j = 0; j < 48; j += 8) {\r
903 PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",\r
904 c.d.asBytes[j+0],\r
905 c.d.asBytes[j+1],\r
906 c.d.asBytes[j+2],\r
907 c.d.asBytes[j+3],\r
908 c.d.asBytes[j+4],\r
909 c.d.asBytes[j+5],\r
910 c.d.asBytes[j+6],\r
911 c.d.asBytes[j+7],\r
912 c.d.asBytes[j+8]\r
913 );\r
914 }\r
915 }\r
916}\r
917\r
918static void CmdHisampless(char *str)\r
919{\r
920 int cnt = 0;\r
921 int i;\r
922 int n;\r
923\r
924 if(atoi(str) == 0) {\r
925 n = 1000;\r
926 } else {\r
927 n = atoi(str)/4;\r
928 }\r
929\r
930 for(i = 0; i < n; i += 12) {\r
931 UsbCommand c;\r
932 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
933 c.ext1 = i;\r
934 SendCommand(&c, FALSE);\r
935 ReceiveCommand(&c);\r
936 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 937 PrintToScrollback("bad resp");\r
6658905f 938 return;\r
939 }\r
940 int j;\r
941 for(j = 0; j < 48; j++) {\r
942 GraphBuffer[cnt++] = (int)((signed char)c.d.asBytes[j]);\r
943 }\r
944 }\r
945 GraphTraceLen = cnt;\r
946\r
947 RepaintGraphWindow();\r
948}\r
949\r
950static WORD Iso15693Crc(BYTE *v, int n)\r
951{\r
952 DWORD reg;\r
953 int i, j;\r
954\r
955 reg = 0xffff;\r
956 for(i = 0; i < n; i++) {\r
957 reg = reg ^ ((DWORD)v[i]);\r
958 for (j = 0; j < 8; j++) {\r
959 if (reg & 0x0001) {\r
960 reg = (reg >> 1) ^ 0x8408;\r
961 } else {\r
962 reg = (reg >> 1);\r
963 }\r
964 }\r
965 }\r
966\r
967 return (WORD)~reg;\r
968}\r
969\r
970static void CmdHi14bdemod(char *str)\r
971{\r
972 int i, j, iold;\r
973 int isum, qsum;\r
974 int outOfWeakAt;\r
975 BOOL negateI, negateQ;\r
976\r
977 BYTE data[256];\r
978 int dataLen=0;\r
979\r
980 // As received, the samples are pairs, correlations against I and Q\r
981 // square waves. So estimate angle of initial carrier (or just\r
982 // quadrant, actually), and then do the demod.\r
983\r
984 // First, estimate where the tag starts modulating.\r
985 for(i = 0; i < GraphTraceLen; i += 2) {\r
986 if(abs(GraphBuffer[i]) + abs(GraphBuffer[i+1]) > 40) {\r
987 break;\r
988 }\r
989 }\r
990 if(i >= GraphTraceLen) {\r
991 PrintToScrollback("too weak to sync");\r
992 return;\r
993 }\r
994 PrintToScrollback("out of weak at %d", i);\r
995 outOfWeakAt = i;\r
996\r
997 // Now, estimate the phase in the initial modulation of the tag\r
998 isum = 0;\r
999 qsum = 0;\r
1000 for(; i < (outOfWeakAt + 16); i += 2) {\r
1001 isum += GraphBuffer[i+0];\r
1002 qsum += GraphBuffer[i+1];\r
1003 }\r
1004 negateI = (isum < 0);\r
1005 negateQ = (qsum < 0);\r
1006\r
1007 // Turn the correlation pairs into soft decisions on the bit.\r
1008 j = 0;\r
1009 for(i = 0; i < GraphTraceLen/2; i++) {\r
1010 int si = GraphBuffer[j];\r
1011 int sq = GraphBuffer[j+1];\r
1012 if(negateI) si = -si;\r
1013 if(negateQ) sq = -sq;\r
1014 GraphBuffer[i] = si + sq;\r
1015 j += 2;\r
1016 }\r
1017 GraphTraceLen = i;\r
1018\r
1019 i = outOfWeakAt/2;\r
1020 while(GraphBuffer[i] > 0 && i < GraphTraceLen)\r
1021 i++;\r
1022 if(i >= GraphTraceLen) goto demodError;\r
1023\r
1024 iold = i;\r
1025 while(GraphBuffer[i] < 0 && i < GraphTraceLen)\r
1026 i++;\r
1027 if(i >= GraphTraceLen) goto demodError;\r
1028 if((i - iold) > 23) goto demodError;\r
1029\r
1030 PrintToScrollback("make it to demod loop");\r
1031\r
1032 for(;;) {\r
1033 iold = i;\r
1034 while(GraphBuffer[i] >= 0 && i < GraphTraceLen)\r
1035 i++;\r
1036 if(i >= GraphTraceLen) goto demodError;\r
1037 if((i - iold) > 6) goto demodError;\r
1038\r
1039 WORD shiftReg = 0;\r
1040 if(i + 20 >= GraphTraceLen) goto demodError;\r
1041\r
1042 for(j = 0; j < 10; j++) {\r
1043 int soft = GraphBuffer[i] + GraphBuffer[i+1];\r
1044\r
1045 if(abs(soft) < ((abs(isum) + abs(qsum))/20)) {\r
1046 PrintToScrollback("weak bit");\r
1047 }\r
1048\r
1049 shiftReg >>= 1;\r
1050 if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {\r
1051 shiftReg |= 0x200;\r
1052 }\r
1053\r
1054 i+= 2;\r
1055 }\r
1056\r
1057 if( (shiftReg & 0x200) &&\r
1058 !(shiftReg & 0x001))\r
1059 {\r
1060 // valid data byte, start and stop bits okay\r
1061 PrintToScrollback(" %02x", (shiftReg >> 1) & 0xff);\r
1062 data[dataLen++] = (shiftReg >> 1) & 0xff;\r
1063 if(dataLen >= sizeof(data)) {\r
1064 return;\r
1065 }\r
1066 } else if(shiftReg == 0x000) {\r
1067 // this is EOF\r
1068 break;\r
1069 } else {\r
1070 goto demodError;\r
1071 }\r
1072 }\r
1073\r
1074 BYTE first, second;\r
1075 ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);\r
1076 PrintToScrollback("CRC: %02x %02x (%s)\n", first, second,\r
1077 (first == data[dataLen-2] && second == data[dataLen-1]) ?\r
1078 "ok" : "****FAIL****");\r
1079\r
1080 RepaintGraphWindow();\r
1081 return;\r
1082\r
1083demodError:\r
1084 PrintToScrollback("demod error");\r
1085 RepaintGraphWindow();\r
1086}\r
1087\r
1088static void CmdHi14list(char *str)\r
1089{\r
1090 BYTE got[960];\r
1091 GetFromBigBuf(got, sizeof(got));\r
1092\r
1093 PrintToScrollback("recorded activity:");\r
1094 PrintToScrollback(" time :rssi: who bytes");\r
1095 PrintToScrollback("---------+----+----+-----------");\r
1096\r
1097 int i = 0;\r
1098 int prev = -1;\r
1099\r
1100 for(;;) {\r
1101 if(i >= 900) {\r
1102 break;\r
1103 }\r
1104\r
1105 BOOL isResponse;\r
1106 int timestamp = *((DWORD *)(got+i));\r
1107 if(timestamp & 0x80000000) {\r
1108 timestamp &= 0x7fffffff;\r
1109 isResponse = 1;\r
1110 } else {\r
1111 isResponse = 0;\r
1112 }\r
1113 int metric = *((DWORD *)(got+i+4));\r
1114\r
1115 int len = got[i+8];\r
1116\r
1117 if(len > 100) {\r
1118 break;\r
1119 }\r
1120 if(i + len >= 900) {\r
1121 break;\r
1122 }\r
1123\r
1124 BYTE *frame = (got+i+9);\r
1125\r
1126 char line[1000] = "";\r
1127 int j;\r
1128 for(j = 0; j < len; j++) {\r
1129 sprintf(line+(j*3), "%02x ", frame[j]);\r
1130 }\r
1131\r
1132 char *crc;\r
1133 if(len > 2) {\r
1134 BYTE b1, b2;\r
1135 ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2);\r
1136 if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
1137 crc = "**FAIL CRC**";\r
1138 } else {\r
1139 crc = "";\r
1140 }\r
1141 } else {\r
1142 crc = "(SHORT)";\r
1143 }\r
1144\r
1145 char metricString[100];\r
1146 if(isResponse) {\r
1147 sprintf(metricString, "%3d", metric);\r
1148 } else {\r
1149 strcpy(metricString, " ");\r
1150 }\r
1151\r
1152 PrintToScrollback(" +%7d: %s: %s %s %s",\r
1153 (prev < 0 ? 0 : timestamp - prev),\r
1154 metricString,\r
1155 (isResponse ? "TAG" : " "), line, crc);\r
1156\r
1157 prev = timestamp;\r
1158 i += (len + 9);\r
1159 }\r
1160}\r
1161\r
1162static void CmdHi14alist(char *str)\r
1163{\r
1164 BYTE got[1920];\r
1165 GetFromBigBuf(got, sizeof(got));\r
1166\r
1167 PrintToScrollback("recorded activity:");\r
1168 PrintToScrollback(" ETU :rssi: who bytes");\r
1169 PrintToScrollback("---------+----+----+-----------");\r
1170\r
1171 int i = 0;\r
1172 int prev = -1;\r
1173\r
1174 for(;;) {\r
1175 if(i >= 1900) {\r
1176 break;\r
1177 }\r
1178\r
1179 BOOL isResponse;\r
1180 int timestamp = *((DWORD *)(got+i));\r
1181 if(timestamp & 0x80000000) {\r
1182 timestamp &= 0x7fffffff;\r
1183 isResponse = 1;\r
1184 } else {\r
1185 isResponse = 0;\r
1186 }\r
1187\r
1188 int metric = 0;\r
1189 int parityBits = *((DWORD *)(got+i+4));\r
1190 // 4 bytes of additional information...\r
1191 // maximum of 32 additional parity bit information\r
1192 //\r
1193 // TODO:\r
1194 // at each quarter bit period we can send power level (16 levels)\r
1195 // or each half bit period in 256 levels.\r
1196\r
1197\r
1198 int len = got[i+8];\r
1199\r
1200 if(len > 100) {\r
1201 break;\r
1202 }\r
1203 if(i + len >= 1900) {\r
1204 break;\r
1205 }\r
1206\r
1207 BYTE *frame = (got+i+9);\r
1208\r
1209 // Break and stick with current result if buffer was not completely full\r
1210 if(frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }\r
1211\r
1212 char line[1000] = "";\r
1213 int j;\r
1214 for(j = 0; j < len; j++) {\r
1215 int oddparity = 0x01;\r
1216 int k;\r
1217\r
1218 for(k=0;k<8;k++) {\r
1219 oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);\r
1220 }\r
1221\r
1222 //if((parityBits >> (len - j - 1)) & 0x01) {\r
1223 if(isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {\r
1224 sprintf(line+(j*4), "%02x! ", frame[j]);\r
1225 }\r
1226 else {\r
1227 sprintf(line+(j*4), "%02x ", frame[j]);\r
1228 }\r
1229 }\r
1230\r
1231 char *crc;\r
1232 crc = "";\r
1233 if(len > 2) {\r
1234 BYTE b1, b2;\r
1235 for(j = 0; j < (len - 1); j++) {\r
1236 // gives problems... search for the reason..\r
1237 /*if(frame[j] == 0xAA) {\r
1238 switch(frame[j+1]) {\r
1239 case 0x01:\r
1240 crc = "[1] Two drops close after each other";\r
1241 break;\r
1242 case 0x02:\r
1243 crc = "[2] Potential SOC with a drop in second half of bitperiod";\r
1244 break;\r
1245 case 0x03:\r
1246 crc = "[3] Segment Z after segment X is not possible";\r
1247 break;\r
1248 case 0x04:\r
1249 crc = "[4] Parity bit of a fully received byte was wrong";\r
1250 break;\r
1251 default:\r
1252 crc = "[?] Unknown error";\r
1253 break;\r
1254 }\r
1255 break;\r
1256 }*/\r
1257 }\r
1258\r
1259 if(strlen(crc)==0) {\r
1260 ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2);\r
1261 if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
1262 crc = (isResponse & (len < 6)) ? "" : " !crc";\r
1263 } else {\r
1264 crc = "";\r
1265 }\r
1266 }\r
1267 } else {\r
1268 crc = ""; // SHORT\r
1269 }\r
1270\r
1271 char metricString[100];\r
1272 if(isResponse) {\r
1273 sprintf(metricString, "%3d", metric);\r
1274 } else {\r
1275 strcpy(metricString, " ");\r
1276 }\r
1277\r
1278 PrintToScrollback(" +%7d: %s: %s %s %s",\r
1279 (prev < 0 ? 0 : (timestamp - prev)),\r
1280 metricString,\r
1281 (isResponse ? "TAG" : " "), line, crc);\r
1282\r
1283 prev = timestamp;\r
1284 i += (len + 9);\r
1285 }\r
1286 CommandFinished = 1;\r
1287}\r
1288\r
1289static void CmdHi15demod(char *str)\r
1290{\r
1291 // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
1292\r
0e25ae11 1293 // SOF defined as\r
6658905f 1294 // 1) Unmodulated time of 56.64us\r
1295 // 2) 24 pulses of 423.75khz\r
1296 // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
1297\r
1298 static const int FrameSOF[] = {\r
1299 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1300 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1301 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1302 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1303 -1, -1, -1, -1,\r
1304 -1, -1, -1, -1,\r
1305 1, 1, 1, 1,\r
1306 1, 1, 1, 1\r
1307 };\r
1308 static const int Logic0[] = {\r
1309 1, 1, 1, 1,\r
1310 1, 1, 1, 1,\r
1311 -1, -1, -1, -1,\r
1312 -1, -1, -1, -1\r
1313 };\r
1314 static const int Logic1[] = {\r
1315 -1, -1, -1, -1,\r
1316 -1, -1, -1, -1,\r
1317 1, 1, 1, 1,\r
1318 1, 1, 1, 1\r
1319 };\r
1320\r
0e25ae11 1321 // EOF defined as\r
6658905f 1322 // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
1323 // 2) 24 pulses of 423.75khz\r
1324 // 3) Unmodulated time of 56.64us\r
1325\r
1326 static const int FrameEOF[] = {\r
1327 1, 1, 1, 1,\r
1328 1, 1, 1, 1,\r
1329 -1, -1, -1, -1,\r
1330 -1, -1, -1, -1,\r
1331 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1332 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1333 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1334 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
1335 };\r
1336\r
1337 int i, j;\r
1338 int max = 0, maxPos;\r
1339\r
1340 int skip = 4;\r
1341\r
1342 if(GraphTraceLen < 1000) return;\r
1343\r
1344 // First, correlate for SOF\r
1345 for(i = 0; i < 100; i++) {\r
1346 int corr = 0;\r
1347 for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
1348 corr += FrameSOF[j]*GraphBuffer[i+(j/skip)];\r
1349 }\r
1350 if(corr > max) {\r
1351 max = corr;\r
1352 maxPos = i;\r
1353 }\r
1354 }\r
1355 PrintToScrollback("SOF at %d, correlation %d", maxPos,\r
1356 max/(arraylen(FrameSOF)/skip));\r
1357\r
1358 i = maxPos + arraylen(FrameSOF)/skip;\r
1359 int k = 0;\r
1360 BYTE outBuf[20];\r
1361 memset(outBuf, 0, sizeof(outBuf));\r
1362 BYTE mask = 0x01;\r
1363 for(;;) {\r
1364 int corr0 = 0, corr1 = 0, corrEOF = 0;\r
1365 for(j = 0; j < arraylen(Logic0); j += skip) {\r
1366 corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];\r
1367 }\r
1368 for(j = 0; j < arraylen(Logic1); j += skip) {\r
1369 corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];\r
1370 }\r
1371 for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
1372 corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];\r
1373 }\r
1374 // Even things out by the length of the target waveform.\r
1375 corr0 *= 4;\r
1376 corr1 *= 4;\r
1377\r
1378 if(corrEOF > corr1 && corrEOF > corr0) {\r
1379 PrintToScrollback("EOF at %d", i);\r
1380 break;\r
1381 } else if(corr1 > corr0) {\r
1382 i += arraylen(Logic1)/skip;\r
1383 outBuf[k] |= mask;\r
1384 } else {\r
1385 i += arraylen(Logic0)/skip;\r
1386 }\r
1387 mask <<= 1;\r
1388 if(mask == 0) {\r
1389 k++;\r
1390 mask = 0x01;\r
1391 }\r
1392 if((i+(int)arraylen(FrameEOF)) >= GraphTraceLen) {\r
1393 PrintToScrollback("ran off end!");\r
1394 break;\r
1395 }\r
1396 }\r
1397 if(mask != 0x01) {\r
1398 PrintToScrollback("error, uneven octet! (discard extra bits!)");\r
1399 PrintToScrollback(" mask=%02x", mask);\r
1400 }\r
1401 PrintToScrollback("%d octets", k);\r
1402\r
1403 for(i = 0; i < k; i++) {\r
1404 PrintToScrollback("# %2d: %02x ", i, outBuf[i]);\r
1405 }\r
1406 PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
1407}\r
1408\r
67853904 1409static void CmdFSKdemod(char *cmdline)\r
1410{\r
1411 static const int LowTone[] = {\r
1412 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1413 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1414 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1415 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1416 1, 1, 1, 1, 1, -1, -1, -1, -1, -1\r
1417 };\r
1418 static const int HighTone[] = {\r
1419 1, 1, 1, 1, 1, -1, -1, -1, -1,\r
1420 1, 1, 1, 1, -1, -1, -1, -1,\r
1421 1, 1, 1, 1, -1, -1, -1, -1,\r
1422 1, 1, 1, 1, -1, -1, -1, -1,\r
1423 1, 1, 1, 1, -1, -1, -1, -1,\r
1424 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1425 };\r
1426\r
7381e8f2 1427 int lowLen = sizeof(LowTone)/sizeof(int);\r
1428 int highLen = sizeof(HighTone)/sizeof(int);\r
1429 int convLen = (highLen>lowLen)?highLen:lowLen;\r
67853904 1430 DWORD hi = 0, lo = 0;\r
1431\r
1432 int i, j;\r
1433 int minMark=0, maxMark=0;\r
67853904 1434\r
1435 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
1436 int lowSum = 0, highSum = 0;\r
1437\r
1438 for(j = 0; j < lowLen; j++) {\r
1439 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1440 }\r
1441 for(j = 0; j < highLen; j++) {\r
1442 highSum += HighTone[j]*GraphBuffer[i+j];\r
1443 }\r
1444 lowSum = abs((100*lowSum) / lowLen);\r
1445 highSum = abs((100*highSum) / highLen);\r
1446 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1447 }\r
1448\r
1449 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
1450 int j;\r
1451 int lowTot = 0, highTot = 0;\r
1452 // 10 and 8 are f_s divided by f_l and f_h, rounded\r
1453 for(j = 0; j < 10; j++) {\r
1454 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1455 }\r
1456 for(j = 0; j < 8; j++) {\r
1457 highTot += (GraphBuffer[i+j] >> 16);\r
1458 }\r
1459 GraphBuffer[i] = lowTot - highTot;\r
1460 if (GraphBuffer[i]>maxMark) maxMark=GraphBuffer[i];\r
1461 if (GraphBuffer[i]<minMark) minMark=GraphBuffer[i];\r
1462 }\r
1463\r
1464 GraphTraceLen -= (convLen + 16);\r
1465\r
1466 RepaintGraphWindow();\r
1467\r
1468 // Find bit-sync (3 lo followed by 3 high)\r
1469 int max = 0, maxPos = 0;\r
1470 for(i = 0; i < 6000; i++) {\r
1471 int dec = 0;\r
7381e8f2 1472 for(j = 0; j < 3*lowLen; j++) {\r
67853904 1473 dec -= GraphBuffer[i+j];\r
1474 }\r
7381e8f2 1475 for(; j < 3*(lowLen + highLen ); j++) {\r
67853904 1476 dec += GraphBuffer[i+j];\r
1477 }\r
1478 if(dec > max) {\r
1479 max = dec;\r
1480 maxPos = i;\r
1481 }\r
1482 }\r
1483\r
1484 // place start of bit sync marker in graph\r
1485 GraphBuffer[maxPos] = maxMark;\r
1486 GraphBuffer[maxPos+1] = minMark;\r
1487\r
1488 maxPos += j;\r
1489\r
1490 // place end of bit sync marker in graph\r
1491 GraphBuffer[maxPos] = maxMark;\r
1492 GraphBuffer[maxPos+1] = minMark;\r
1493\r
1494 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
7381e8f2 1495 PrintToScrollback("length %d/%d", highLen, lowLen);\r
67853904 1496\r
1497 BYTE bits[46];\r
1498 bits[sizeof(bits)-1] = '\0';\r
1499\r
1500 // find bit pairs and manchester decode them\r
1501 for(i = 0; i < arraylen(bits)-1; i++) {\r
1502 int dec = 0;\r
7381e8f2 1503 for(j = 0; j < lowLen; j++) {\r
67853904 1504 dec -= GraphBuffer[maxPos+j];\r
1505 }\r
7381e8f2 1506 for(; j < lowLen + highLen; j++) {\r
67853904 1507 dec += GraphBuffer[maxPos+j];\r
1508 }\r
1509 maxPos += j;\r
1510 // place inter bit marker in graph\r
1511 GraphBuffer[maxPos] = maxMark;\r
1512 GraphBuffer[maxPos+1] = minMark;\r
1513\r
1514 // hi and lo form a 64 bit pair\r
1515 hi = (hi<<1)|(lo>>31);\r
1516 lo = (lo<<1);\r
1517 // store decoded bit as binary (in hi/lo) and text (in bits[])\r
1518 if(dec<0) {\r
1519 bits[i] = '1';\r
1520 lo|=1;\r
1521 } else {\r
1522 bits[i] = '0';\r
1523 }\r
1524 }\r
1525 PrintToScrollback("bits: '%s'", bits);\r
1526 PrintToScrollback("hex: %08x %08x", hi, lo);\r
1527}\r
1528\r
9bea179a 1529// read a TI tag and return its ID\r
1530static void CmdTIRead(char *str)\r
1531{\r
1532 UsbCommand c;\r
1533 c.cmd = CMD_READ_TI_TYPE;\r
1534 SendCommand(&c, FALSE);\r
1535}\r
1536\r
1537// write new data to a r/w TI tag\r
1538static void CmdTIWrite(char *str)\r
1539{\r
1540 UsbCommand c;\r
1541 int res=0;\r
1542\r
1543 c.cmd = CMD_WRITE_TI_TYPE;\r
1544 res = sscanf(str, "0x%x 0x%x 0x%x ", &c.ext1, &c.ext2, &c.ext3);\r
1545 if (res == 2) c.ext3=0;\r
1546 if (res<2)\r
7381e8f2 1547 PrintToScrollback("Please specify the data as two hex strings, optionally the CRC as a third");\r
3628c318 1548 else\r
9bea179a 1549 SendCommand(&c, FALSE);\r
1550}\r
1551\r
1552static void CmdTIDemod(char *cmdline)\r
6658905f 1553{\r
1554 /* MATLAB as follows:\r
1555f_s = 2000000; % sampling frequency\r
1556f_l = 123200; % low FSK tone\r
1557f_h = 134200; % high FSK tone\r
1558\r
1559T_l = 119e-6; % low bit duration\r
1560T_h = 130e-6; % high bit duration\r
1561\r
1562l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);\r
1563h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);\r
1564\r
1565l = sign(sin(cumsum(l)));\r
1566h = sign(sin(cumsum(h)));\r
1567 */\r
7381e8f2 1568\r
1569// 2M*16/134.2k = 238\r
67853904 1570 static const int LowTone[] = {\r
7381e8f2 1571 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1572 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1573 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1574 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1575 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1576 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1577 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1578 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1579 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1580 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1581 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1582 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1583 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1584 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1585 1, 1, 1, 1, 1, 1, 1, 1, -1, -1\r
67853904 1586 };\r
7381e8f2 1587// 2M*16/123.2k = 260\r
67853904 1588 static const int HighTone[] = {\r
7381e8f2 1589 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1590 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1591 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1592 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1593 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1594 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1595 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1596 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1597 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1598 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1599 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1600 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1601 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1602 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1603 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1604 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1605 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1606 1, 1, 1, 1, 1, 1, 1, 1\r
67853904 1607 };\r
7381e8f2 1608 int lowLen = sizeof(LowTone)/sizeof(int);\r
1609 int highLen = sizeof(HighTone)/sizeof(int);\r
1610 int convLen = (highLen>lowLen)?highLen:lowLen;\r
0c2ed92d 1611 WORD crc;\r
7381e8f2 1612 int i, j, TagType;\r
1613 int lowSum = 0, highSum = 0;;\r
1614 int lowTot = 0, highTot = 0;\r
1615\r
6658905f 1616 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
7381e8f2 1617 lowSum = 0;\r
1618 highSum = 0;;\r
6658905f 1619\r
1620 for(j = 0; j < lowLen; j++) {\r
1621 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1622 }\r
1623 for(j = 0; j < highLen; j++) {\r
1624 highSum += HighTone[j]*GraphBuffer[i+j];\r
1625 }\r
1626 lowSum = abs((100*lowSum) / lowLen);\r
1627 highSum = abs((100*highSum) / highLen);\r
7381e8f2 1628 lowSum = (lowSum<0)?-lowSum:lowSum;\r
1629 highSum = (highSum<0)?-highSum:highSum;\r
1630\r
6658905f 1631 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1632 }\r
1633\r
1634 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
7381e8f2 1635 lowTot = 0;\r
1636 highTot = 0;\r
6658905f 1637 // 16 and 15 are f_s divided by f_l and f_h, rounded\r
1638 for(j = 0; j < 16; j++) {\r
1639 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1640 }\r
1641 for(j = 0; j < 15; j++) {\r
1642 highTot += (GraphBuffer[i+j] >> 16);\r
1643 }\r
1644 GraphBuffer[i] = lowTot - highTot;\r
1645 }\r
1646\r
1647 GraphTraceLen -= (convLen + 16);\r
1648\r
1649 RepaintGraphWindow();\r
1650\r
0c2ed92d 1651 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,\r
1652 // 16 crc CCITT bits, 8 stop bits, 15 end bits\r
1653\r
1654 // the 16 prebits are always low\r
1655 // the 8 start and stop bits of a tag must match\r
1656 // the start/stop prebits of a ro tag are 01111110\r
1657 // the start/stop prebits of a rw tag are 11111110\r
1658 // the 15 end bits of a ro tag are all low\r
1659 // the 15 end bits of a rw tag match bits 15-1 of the data bits\r
6658905f 1660\r
0c2ed92d 1661 // Okay, so now we have unsliced soft decisions;\r
1662 // find bit-sync, and then get some bits.\r
1663 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)\r
6658905f 1664 int max = 0, maxPos = 0;\r
1665 for(i = 0; i < 6000; i++) {\r
1666 int j;\r
1667 int dec = 0;\r
0c2ed92d 1668 // searching 17 consecutive lows\r
7381e8f2 1669 for(j = 0; j < 17*lowLen; j++) {\r
6658905f 1670 dec -= GraphBuffer[i+j];\r
1671 }\r
0c2ed92d 1672 // searching 7 consecutive highs\r
7381e8f2 1673 for(; j < 17*lowLen + 6*highLen; j++) {\r
6658905f 1674 dec += GraphBuffer[i+j];\r
1675 }\r
1676 if(dec > max) {\r
1677 max = dec;\r
1678 maxPos = i;\r
1679 }\r
1680 }\r
6658905f 1681\r
0c2ed92d 1682 // place a marker in the buffer to visually aid location\r
1683 // of the start of sync\r
6658905f 1684 GraphBuffer[maxPos] = 800;\r
1685 GraphBuffer[maxPos+1] = -800;\r
6658905f 1686\r
0c2ed92d 1687 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)\r
7381e8f2 1688 maxPos += 17*lowLen;\r
1689 maxPos += 6*highLen;\r
0c2ed92d 1690\r
1691 // place a marker in the buffer to visually aid location\r
1692 // of the end of sync\r
6658905f 1693 GraphBuffer[maxPos] = 800;\r
1694 GraphBuffer[maxPos+1] = -800;\r
1695\r
1696 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
1697\r
7381e8f2 1698 PrintToScrollback("length %d/%d", highLen, lowLen);\r
6658905f 1699\r
0c2ed92d 1700 BYTE bits[1+64+16+8+16];\r
6658905f 1701 bits[sizeof(bits)-1] = '\0';\r
1702\r
0c2ed92d 1703 DWORD shift3 = 0x7e000000, shift2 = 0, shift1 = 0, shift0 = 0;\r
1704\r
1705 for(i = 0; i < arraylen(bits)-1; i++) {\r
6658905f 1706 int high = 0;\r
1707 int low = 0;\r
1708 int j;\r
7381e8f2 1709 for(j = 0; j < lowLen; j++) {\r
6658905f 1710 low -= GraphBuffer[maxPos+j];\r
1711 }\r
7381e8f2 1712 for(j = 0; j < highLen; j++) {\r
6658905f 1713 high += GraphBuffer[maxPos+j];\r
1714 }\r
0c2ed92d 1715\r
6658905f 1716 if(high > low) {\r
1717 bits[i] = '1';\r
7381e8f2 1718 maxPos += highLen;\r
0c2ed92d 1719 // bitstream arrives lsb first so shift right\r
1720 shift3 |= (1<<31);\r
6658905f 1721 } else {\r
1722 bits[i] = '.';\r
7381e8f2 1723 maxPos += lowLen;\r
6658905f 1724 }\r
0c2ed92d 1725\r
1726 // 128 bit right shift register\r
1727 shift0 = (shift0>>1) | (shift1 << 31);\r
1728 shift1 = (shift1>>1) | (shift2 << 31);\r
1729 shift2 = (shift2>>1) | (shift3 << 31);\r
1730 shift3 >>= 1;\r
1731\r
1732 // place a marker in the buffer between bits to visually aid location\r
6658905f 1733 GraphBuffer[maxPos] = 800;\r
1734 GraphBuffer[maxPos+1] = -800;\r
1735 }\r
0c2ed92d 1736 PrintToScrollback("Info: raw tag bits = %s", bits);\r
6658905f 1737\r
0c2ed92d 1738 TagType = (shift3>>8)&0xff;\r
1739 if ( TagType != ((shift0>>16)&0xff) ) {\r
1740 PrintToScrollback("Error: start and stop bits do not match!");\r
1741 return;\r
1742 }\r
1743 else if (TagType == 0x7e) {\r
1744 PrintToScrollback("Info: Readonly TI tag detected.");\r
1745 return;\r
6658905f 1746 }\r
0c2ed92d 1747 else if (TagType == 0xfe) {\r
1748 PrintToScrollback("Info: Rewriteable TI tag detected.");\r
1749\r
1750 // put 64 bit data into shift1 and shift0\r
1751 shift0 = (shift0>>24) | (shift1 << 8);\r
1752 shift1 = (shift1>>24) | (shift2 << 8);\r
1753\r
1754 // align 16 bit crc into lower half of shift2\r
1755 shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;\r
1756\r
1757 // align 16 bit "end bits" or "ident" into lower half of shift3\r
1758 shift3 >>= 16;\r
1759\r
9bea179a 1760 // only 15 bits compare, last bit of ident is not valid\r
1761 if ( (shift3^shift0)&0x7fff ) {\r
0c2ed92d 1762 PrintToScrollback("Error: Ident mismatch!");\r
1763 }\r
9bea179a 1764 // WARNING the order of the bytes in which we calc crc below needs checking\r
1765 // i'm 99% sure the crc algorithm is correct, but it may need to eat the\r
1766 // bytes in reverse or something\r
0c2ed92d 1767 // calculate CRC\r
1768 crc=0;\r
1769 crc = update_crc16(crc, (shift0)&0xff);\r
1770 crc = update_crc16(crc, (shift0>>8)&0xff);\r
1771 crc = update_crc16(crc, (shift0>>16)&0xff);\r
1772 crc = update_crc16(crc, (shift0>>24)&0xff);\r
1773 crc = update_crc16(crc, (shift1)&0xff);\r
1774 crc = update_crc16(crc, (shift1>>8)&0xff);\r
1775 crc = update_crc16(crc, (shift1>>16)&0xff);\r
1776 crc = update_crc16(crc, (shift1>>24)&0xff);\r
1777 PrintToScrollback("Info: Tag data = %08X%08X", shift1, shift0);\r
1778 if (crc != (shift2&0xffff)) {\r
1779 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc, shift2&0xffff);\r
1780 } else {\r
1781 PrintToScrollback("Info: CRC %04X is good", crc);\r
6658905f 1782 }\r
1783 }\r
0c2ed92d 1784 else {\r
1785 PrintToScrollback("Unknown tag type.");\r
1786 return;\r
1787 }\r
6658905f 1788}\r
1789\r
1790static void CmdNorm(char *str)\r
1791{\r
1792 int i;\r
1793 int max = INT_MIN, min = INT_MAX;\r
1794 for(i = 10; i < GraphTraceLen; i++) {\r
1795 if(GraphBuffer[i] > max) {\r
1796 max = GraphBuffer[i];\r
1797 }\r
1798 if(GraphBuffer[i] < min) {\r
1799 min = GraphBuffer[i];\r
1800 }\r
1801 }\r
1802 if(max != min) {\r
1803 for(i = 0; i < GraphTraceLen; i++) {\r
1804 GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/\r
1805 (max - min);\r
1806 }\r
1807 }\r
1808 RepaintGraphWindow();\r
1809}\r
1810\r
523f4c90 1811static void CmdAmp(char *str)\r
1812{\r
1813 int i, rising, falling;\r
1814 int max = INT_MIN, min = INT_MAX;\r
1815 for(i = 10; i < GraphTraceLen; i++) {\r
1816 if(GraphBuffer[i] > max) {\r
1817 max = GraphBuffer[i];\r
1818 }\r
1819 if(GraphBuffer[i] < min) {\r
1820 min = GraphBuffer[i];\r
1821 }\r
1822 }\r
1823 if(max != min) {\r
1824 rising= falling= 0;\r
1825 for(i = 0; i < GraphTraceLen; i++) {\r
1826 if(GraphBuffer[i+1] < GraphBuffer[i]) {\r
1827 if(rising) {\r
1828 GraphBuffer[i]= max;\r
1829 rising= 0;\r
1830 }\r
1831 falling= 1;\r
1832 }\r
1833 if(GraphBuffer[i+1] > GraphBuffer[i]) {\r
1834 if(falling) {\r
1835 GraphBuffer[i]= min;\r
1836 falling= 0;\r
1837 }\r
1838 rising= 1;\r
1839 }\r
1840 }\r
1841 }\r
1842 RepaintGraphWindow();\r
1843}\r
1844\r
6658905f 1845static void CmdDec(char *str)\r
1846{\r
1847 int i;\r
1848 for(i = 0; i < (GraphTraceLen/2); i++) {\r
1849 GraphBuffer[i] = GraphBuffer[i*2];\r
1850 }\r
1851 GraphTraceLen /= 2;\r
1852 PrintToScrollback("decimated by 2");\r
1853 RepaintGraphWindow();\r
1854}\r
1855\r
1856static void CmdHpf(char *str)\r
1857{\r
1858 int i;\r
1859 int accum = 0;\r
1860 for(i = 10; i < GraphTraceLen; i++) {\r
1861 accum += GraphBuffer[i];\r
1862 }\r
1863 accum /= (GraphTraceLen - 10);\r
1864 for(i = 0; i < GraphTraceLen; i++) {\r
1865 GraphBuffer[i] -= accum;\r
1866 }\r
1867\r
1868 RepaintGraphWindow();\r
1869}\r
1870\r
1871static void CmdZerocrossings(char *str)\r
1872{\r
1873 int i;\r
1874 // Zero-crossings aren't meaningful unless the signal is zero-mean.\r
1875 CmdHpf("");\r
1876\r
1877 int sign = 1;\r
1878 int zc = 0;\r
1879 int lastZc = 0;\r
1880 for(i = 0; i < GraphTraceLen; i++) {\r
1881 if(GraphBuffer[i]*sign >= 0) {\r
1882 // No change in sign, reproduce the previous sample count.\r
1883 zc++;\r
1884 GraphBuffer[i] = lastZc;\r
1885 } else {\r
1886 // Change in sign, reset the sample count.\r
1887 sign = -sign;\r
1888 GraphBuffer[i] = lastZc;\r
1889 if(sign > 0) {\r
1890 lastZc = zc;\r
1891 zc = 0;\r
1892 }\r
1893 }\r
1894 }\r
1895\r
1896 RepaintGraphWindow();\r
1897}\r
1898\r
67853904 1899static void CmdThreshold(char *str)\r
1900{\r
1901 int i;\r
1902 int threshold = atoi(str);\r
1903\r
1904 for(i = 0; i < GraphTraceLen; i++) {\r
1905 if(GraphBuffer[i]>= threshold)\r
bd4cc2c9 1906 GraphBuffer[i]=1;\r
67853904 1907 else\r
bd4cc2c9 1908 GraphBuffer[i]=-1;\r
67853904 1909 }\r
1910 RepaintGraphWindow();\r
1911}\r
1912\r
6658905f 1913static void CmdLtrim(char *str)\r
1914{\r
1915 int i;\r
1916 int ds = atoi(str);\r
1917\r
1918 for(i = ds; i < GraphTraceLen; i++) {\r
1919 GraphBuffer[i-ds] = GraphBuffer[i];\r
1920 }\r
1921 GraphTraceLen -= ds;\r
1922\r
1923 RepaintGraphWindow();\r
1924}\r
1925\r
1926static void CmdAutoCorr(char *str)\r
1927{\r
1928 static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];\r
1929\r
1930 int window = atoi(str);\r
1931\r
1932 if(window == 0) {\r
1933 PrintToScrollback("needs a window");\r
1934 return;\r
1935 }\r
1936\r
1937 if(window >= GraphTraceLen) {\r
1938 PrintToScrollback("window must be smaller than trace (%d samples)",\r
1939 GraphTraceLen);\r
1940 return;\r
1941 }\r
1942\r
1943 PrintToScrollback("performing %d correlations", GraphTraceLen - window);\r
1944\r
1945 int i;\r
1946 for(i = 0; i < GraphTraceLen - window; i++) {\r
1947 int sum = 0;\r
1948 int j;\r
1949 for(j = 0; j < window; j++) {\r
1950 sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;\r
1951 }\r
1952 CorrelBuffer[i] = sum;\r
1953 }\r
1954 GraphTraceLen = GraphTraceLen - window;\r
1955 memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));\r
1956\r
1957 RepaintGraphWindow();\r
1958}\r
1959\r
1960static void CmdVchdemod(char *str)\r
1961{\r
1962 // Is this the entire sync pattern, or does this also include some\r
1963 // data bits that happen to be the same everywhere? That would be\r
1964 // lovely to know.\r
1965 static const int SyncPattern[] = {\r
1966 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1967 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1968 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1969 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1970 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1971 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1972 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1973 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1974 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1975 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1976 };\r
1977\r
1978 // So first, we correlate for the sync pattern, and mark that.\r
1979 int bestCorrel = 0, bestPos = 0;\r
1980 int i;\r
1981 // It does us no good to find the sync pattern, with fewer than\r
1982 // 2048 samples after it...\r
1983 for(i = 0; i < (GraphTraceLen-2048); i++) {\r
1984 int sum = 0;\r
1985 int j;\r
1986 for(j = 0; j < arraylen(SyncPattern); j++) {\r
1987 sum += GraphBuffer[i+j]*SyncPattern[j];\r
1988 }\r
1989 if(sum > bestCorrel) {\r
1990 bestCorrel = sum;\r
1991 bestPos = i;\r
1992 }\r
1993 }\r
1994 PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);\r
1995\r
1996 char bits[257];\r
1997 bits[256] = '\0';\r
1998\r
1999 int worst = INT_MAX;\r
2000 int worstPos;\r
2001\r
2002 for(i = 0; i < 2048; i += 8) {\r
2003 int sum = 0;\r
2004 int j;\r
2005 for(j = 0; j < 8; j++) {\r
2006 sum += GraphBuffer[bestPos+i+j];\r
2007 }\r
2008 if(sum < 0) {\r
2009 bits[i/8] = '.';\r
2010 } else {\r
2011 bits[i/8] = '1';\r
2012 }\r
2013 if(abs(sum) < worst) {\r
2014 worst = abs(sum);\r
2015 worstPos = i;\r
2016 }\r
2017 }\r
2018 PrintToScrollback("bits:");\r
2019 PrintToScrollback("%s", bits);\r
2020 PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);\r
2021\r
2022 if(strcmp(str, "clone")==0) {\r
2023 GraphTraceLen = 0;\r
2024 char *s;\r
2025 for(s = bits; *s; s++) {\r
2026 int j;\r
2027 for(j = 0; j < 16; j++) {\r
2028 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;\r
2029 }\r
2030 }\r
2031 RepaintGraphWindow();\r
2032 }\r
2033}\r
2034\r
a60612db 2035static void CmdIndalademod(char *str)\r
2036{\r
2037 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID\r
2038\r
2039 int state = -1;\r
2040 int count = 0;\r
2041 int i, j;\r
2042 // worst case with GraphTraceLen=64000 is < 4096\r
2043 // under normal conditions it's < 2048\r
2044 BYTE rawbits[4096];\r
2045 int rawbit = 0;\r
2046 int worst = 0, worstPos = 0;\r
2047 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen/32);\r
2048 for(i = 0; i < GraphTraceLen-1; i += 2) {\r
2049 count+=1;\r
2050 if((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {\r
2051 if (state == 0) {\r
2052 for(j = 0; j < count - 8; j += 16) {\r
2053 rawbits[rawbit++] = 0;\r
2054 }\r
2055 if ((abs(count - j)) > worst) {\r
2056 worst = abs(count - j);\r
2057 worstPos = i;\r
2058 }\r
2059 }\r
2060 state = 1;\r
2061 count=0;\r
2062 } else if((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {\r
2063 if (state == 1) {\r
2064 for(j = 0; j < count - 8; j += 16) {\r
2065 rawbits[rawbit++] = 1;\r
2066 }\r
2067 if ((abs(count - j)) > worst) {\r
2068 worst = abs(count - j);\r
2069 worstPos = i;\r
2070 }\r
2071 }\r
2072 state = 0;\r
2073 count=0;\r
2074 }\r
2075 }\r
2076 PrintToScrollback("Recovered %d raw bits", rawbit);\r
2077 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);\r
2078\r
2079 // Finding the start of a UID\r
2080 int uidlen, long_wait;\r
2081 if(strcmp(str, "224") == 0) {\r
2082 uidlen=224;\r
2083 long_wait=30;\r
2084 } else {\r
2085 uidlen=64;\r
2086 long_wait=29;\r
2087 }\r
2088 int start;\r
2089 int first = 0;\r
2090 for(start = 0; start <= rawbit - uidlen; start++) {\r
2091 first = rawbits[start];\r
2092 for(i = start; i < start + long_wait; i++) {\r
2093 if(rawbits[i] != first) {\r
2094 break;\r
2095 }\r
2096 }\r
2097 if(i == (start + long_wait)) {\r
2098 break;\r
2099 }\r
2100 }\r
2101 if(start == rawbit - uidlen + 1) {\r
2102 PrintToScrollback("nothing to wait for");\r
2103 return;\r
2104 }\r
2105\r
2106 // Inverting signal if needed\r
2107 if(first == 1) {\r
2108 for(i = start; i < rawbit; i++) {\r
2109 rawbits[i] = !rawbits[i];\r
2110 }\r
2111 }\r
2112\r
2113 // Dumping UID\r
2114 BYTE bits[224];\r
2115 char showbits[225];\r
2116 showbits[uidlen]='\0';\r
2117 int bit;\r
2118 i = start;\r
2119 int times = 0;\r
2120 if(uidlen > rawbit) {\r
2121 PrintToScrollback("Warning: not enough raw bits to get a full UID");\r
2122 for(bit = 0; bit < rawbit; bit++) {\r
2123 bits[bit] = rawbits[i++];\r
2124 // As we cannot know the parity, let's use "." and "/"\r
2125 showbits[bit] = '.' + bits[bit];\r
2126 }\r
2127 showbits[bit+1]='\0';\r
2128 PrintToScrollback("Partial UID=%s", showbits);\r
2129 return;\r
2130 } else {\r
2131 for(bit = 0; bit < uidlen; bit++) {\r
2132 bits[bit] = rawbits[i++];\r
2133 showbits[bit] = '0' + bits[bit];\r
2134 }\r
2135 times = 1;\r
2136 }\r
2137 PrintToScrollback("UID=%s", showbits);\r
2138\r
2139 // Checking UID against next occurences\r
2140 for(; i + uidlen <= rawbit;) {\r
2141 int failed = 0;\r
2142 for(bit = 0; bit < uidlen; bit++) {\r
2143 if(bits[bit] != rawbits[i++]) {\r
2144 failed = 1;\r
2145 break;\r
2146 }\r
2147 }\r
2148 if (failed == 1) {\r
2149 break;\r
2150 }\r
2151 times += 1;\r
2152 }\r
2153 PrintToScrollback("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);\r
2154\r
2155 // Remodulating for tag cloning\r
2156 GraphTraceLen = 32*uidlen;\r
2157 i = 0;\r
2158 int phase = 0;\r
2159 for(bit = 0; bit < uidlen; bit++) {\r
2160 if(bits[bit] == 0) {\r
2161 phase = 0;\r
2162 } else {\r
2163 phase = 1;\r
2164 }\r
2165 int j;\r
2166 for(j = 0; j < 32; j++) {\r
2167 GraphBuffer[i++] = phase;\r
2168 phase = !phase;\r
2169 }\r
2170 }\r
2171\r
2172 RepaintGraphWindow();\r
2173}\r
2174\r
6658905f 2175static void CmdFlexdemod(char *str)\r
2176{\r
2177 int i;\r
2178 for(i = 0; i < GraphTraceLen; i++) {\r
2179 if(GraphBuffer[i] < 0) {\r
2180 GraphBuffer[i] = -1;\r
2181 } else {\r
2182 GraphBuffer[i] = 1;\r
2183 }\r
2184 }\r
2185\r
2186#define LONG_WAIT 100\r
2187 int start;\r
2188 for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {\r
2189 int first = GraphBuffer[start];\r
2190 for(i = start; i < start + LONG_WAIT; i++) {\r
2191 if(GraphBuffer[i] != first) {\r
2192 break;\r
2193 }\r
2194 }\r
2195 if(i == (start + LONG_WAIT)) {\r
2196 break;\r
2197 }\r
2198 }\r
2199 if(start == GraphTraceLen - LONG_WAIT) {\r
2200 PrintToScrollback("nothing to wait for");\r
2201 return;\r
2202 }\r
2203\r
2204 GraphBuffer[start] = 2;\r
2205 GraphBuffer[start+1] = -2;\r
2206\r
2207 BYTE bits[64];\r
2208\r
2209 int bit;\r
2210 i = start;\r
2211 for(bit = 0; bit < 64; bit++) {\r
2212 int j;\r
2213 int sum = 0;\r
2214 for(j = 0; j < 16; j++) {\r
2215 sum += GraphBuffer[i++];\r
2216 }\r
2217 if(sum > 0) {\r
2218 bits[bit] = 1;\r
2219 } else {\r
2220 bits[bit] = 0;\r
2221 }\r
2222 PrintToScrollback("bit %d sum %d", bit, sum);\r
2223 }\r
2224\r
2225 for(bit = 0; bit < 64; bit++) {\r
2226 int j;\r
2227 int sum = 0;\r
2228 for(j = 0; j < 16; j++) {\r
2229 sum += GraphBuffer[i++];\r
2230 }\r
2231 if(sum > 0 && bits[bit] != 1) {\r
2232 PrintToScrollback("oops1 at %d", bit);\r
2233 }\r
2234 if(sum < 0 && bits[bit] != 0) {\r
2235 PrintToScrollback("oops2 at %d", bit);\r
2236 }\r
2237 }\r
2238\r
2239 GraphTraceLen = 32*64;\r
2240 i = 0;\r
2241 int phase = 0;\r
2242 for(bit = 0; bit < 64; bit++) {\r
2243 if(bits[bit] == 0) {\r
2244 phase = 0;\r
2245 } else {\r
2246 phase = 1;\r
2247 }\r
2248 int j;\r
2249 for(j = 0; j < 32; j++) {\r
2250 GraphBuffer[i++] = phase;\r
2251 phase = !phase;\r
2252 }\r
2253 }\r
2254\r
2255 RepaintGraphWindow();\r
2256}\r
9760414b 2257\r
2258/*\r
15db5fb7 2259 * Generic command to demodulate ASK.\r
9760414b 2260 *\r
15db5fb7 2261 * Argument is convention: positive or negative (High mod means zero\r
9760414b 2262 * or high mod means one)\r
2263 *\r
2264 * Updates the Graph trace with 0/1 values\r
2265 *\r
2266 * Arguments:\r
9760414b 2267 * c : 0 or 1\r
2268 */\r
2269\r
2270static void Cmdaskdemod(char *str) {\r
2271 int i;\r
8172fb35 2272 int c, high = 0, low = 0;\r
9760414b 2273\r
2274 // TODO: complain if we do not give 2 arguments here !\r
c2c80de8 2275 // (AL - this doesn't make sense! we're only using one argument!!!)\r
15db5fb7 2276 sscanf(str, "%i", &c);\r
2277\r
2278 /* Detect high and lows and clock */\r
c2c80de8 2279 // (AL - clock???)\r
15db5fb7 2280 for (i = 0; i < GraphTraceLen; i++)\r
2281 {\r
2282 if (GraphBuffer[i] > high)\r
2283 high = GraphBuffer[i];\r
2284 else if (GraphBuffer[i] < low)\r
2285 low = GraphBuffer[i];\r
9760414b 2286 }\r
c2c80de8 2287 if(c != 0 && c != 1) {\r
2288 PrintToScrollback("Invalid argument: %s",str);\r
2289 return;\r
2290 }\r
9760414b 2291\r
15db5fb7 2292 if (GraphBuffer[0] > 0) {\r
2293 GraphBuffer[0] = 1-c;\r
9760414b 2294 } else {\r
15db5fb7 2295 GraphBuffer[0] = c;\r
9760414b 2296 }\r
2297 for(i=1;i<GraphTraceLen;i++) {\r
15db5fb7 2298 /* Transitions are detected at each peak\r
2299 * Transitions are either:\r
2300 * - we're low: transition if we hit a high\r
2301 * - we're high: transition if we hit a low\r
2302 * (we need to do it this way because some tags keep high or\r
2303 * low for long periods, others just reach the peak and go\r
a91ff4c8 2304 * down)\r
15db5fb7 2305 */\r
2306 if ((GraphBuffer[i]==high) && (GraphBuffer[i-1] == c)) {\r
2307 GraphBuffer[i]=1-c;\r
2308 } else if ((GraphBuffer[i]==low) && (GraphBuffer[i-1] == (1-c))){\r
2309 GraphBuffer[i] = c;\r
9760414b 2310 } else {\r
15db5fb7 2311 /* No transition */\r
9760414b 2312 GraphBuffer[i] = GraphBuffer[i-1];\r
2313 }\r
2314 }\r
2315 RepaintGraphWindow();\r
2316}\r
2317\r
2318/* Print our clock rate */\r
2319static void Cmddetectclockrate(char *str)\r
2320{\r
2321 int clock = detectclock(0);\r
2322 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2323}\r
2324\r
2325/*\r
2326 * Detect clock rate\r
2327 */\r
2328int detectclock(int peak)\r
2329{\r
2330 int i;\r
2331 int clock = 0xFFFF;\r
2332 int lastpeak = 0;\r
2333\r
2334 /* Detect peak if we don't have one */\r
2335 if (!peak)\r
2336 for (i = 0; i < GraphTraceLen; i++)\r
2337 if (GraphBuffer[i] > peak)\r
2338 peak = GraphBuffer[i];\r
2339\r
2340 for (i = 1; i < GraphTraceLen; i++)\r
2341 {\r
2342 /* If this is the beginning of a peak */\r
2343 if (GraphBuffer[i-1] != GraphBuffer[i] && GraphBuffer[i] == peak)\r
2344 {\r
2345 /* Find lowest difference between peaks */\r
2346 if (lastpeak && i - lastpeak < clock)\r
2347 {\r
2348 clock = i - lastpeak;\r
2349 }\r
2350 lastpeak = i;\r
2351 }\r
2352 }\r
15db5fb7 2353\r
9760414b 2354 return clock;\r
2355}\r
2356\r
2357/* Get or auto-detect clock rate */\r
2358int GetClock(char *str, int peak)\r
2359{\r
2360 int clock;\r
15db5fb7 2361\r
9760414b 2362 sscanf(str, "%i", &clock);\r
2363 if (!strcmp(str, ""))\r
2364 clock = 0;\r
2365\r
2366 /* Auto-detect clock */\r
2367 if (!clock)\r
2368 {\r
2369 clock = detectclock(peak);\r
15db5fb7 2370\r
9760414b 2371 /* Only print this message if we're not looping something */\r
2372 if (!go)\r
2373 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2374 }\r
15db5fb7 2375\r
9760414b 2376 return clock;\r
2377}\r
2378\r
2379/*\r
2380 * Convert to a bitstream\r
2381 */\r
2382static void Cmdbitstream(char *str) {\r
c9f99c01 2383 int i, j;\r
2384 int bit;\r
9760414b 2385 int gtl;\r
2386 int clock;\r
c9f99c01 2387 int low = 0;\r
2388 int high = 0;\r
2389 int hithigh, hitlow, first;\r
9760414b 2390\r
2391 /* Detect high and lows and clock */\r
2392 for (i = 0; i < GraphTraceLen; i++)\r
c9f99c01 2393 {\r
9760414b 2394 if (GraphBuffer[i] > high)\r
2395 high = GraphBuffer[i];\r
2396 else if (GraphBuffer[i] < low)\r
2397 low = GraphBuffer[i];\r
c9f99c01 2398 }\r
9760414b 2399\r
2400 /* Get our clock */\r
2401 clock = GetClock(str, high);\r
15db5fb7 2402\r
9760414b 2403 gtl = CmdClearGraph(0);\r
15db5fb7 2404\r
9760414b 2405 bit = 0;\r
2406 for (i = 0; i < (int)(gtl / clock); i++)\r
2407 {\r
2408 hithigh = 0;\r
2409 hitlow = 0;\r
2410 first = 1;\r
15db5fb7 2411\r
9760414b 2412 /* Find out if we hit both high and low peaks */\r
2413 for (j = 0; j < clock; j++)\r
2414 {\r
2415 if (GraphBuffer[(i * clock) + j] == high)\r
2416 hithigh = 1;\r
2417 else if (GraphBuffer[(i * clock) + j] == low)\r
2418 hitlow = 1;\r
15db5fb7 2419\r
9760414b 2420 /* it doesn't count if it's the first part of our read\r
2421 because it's really just trailing from the last sequence */\r
2422 if (first && (hithigh || hitlow))\r
2423 hithigh = hitlow = 0;\r
2424 else\r
2425 first = 0;\r
15db5fb7 2426\r
9760414b 2427 if (hithigh && hitlow)\r
2428 break;\r
2429 }\r
15db5fb7 2430\r
9760414b 2431 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2432 if (!hithigh || !hitlow)\r
2433 bit ^= 1;\r
2434\r
2435 CmdAppendGraph(0, clock, bit);\r
2436// for (j = 0; j < (int)(clock/2); j++)\r
2437// GraphBuffer[(i * clock) + j] = bit ^ 1;\r
2438// for (j = (int)(clock/2); j < clock; j++)\r
2439// GraphBuffer[(i * clock) + j] = bit;\r
2440 }\r
2441\r
2442 RepaintGraphWindow();\r
2443}\r
2444\r
2445/* Modulate our data into manchester */\r
2446static void Cmdmanchestermod(char *str)\r
2447{\r
2448 int i, j;\r
2449 int clock;\r
2450 int bit, lastbit, wave;\r
15db5fb7 2451\r
9760414b 2452 /* Get our clock */\r
2453 clock = GetClock(str, 0);\r
2454\r
2455 wave = 0;\r
2456 lastbit = 1;\r
2457 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
2458 {\r
2459 bit = GraphBuffer[i * clock] ^ 1;\r
15db5fb7 2460\r
9760414b 2461 for (j = 0; j < (int)(clock/2); j++)\r
2462 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave;\r
2463 for (j = (int)(clock/2); j < clock; j++)\r
2464 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1;\r
15db5fb7 2465\r
9760414b 2466 /* Keep track of how we start our wave and if we changed or not this time */\r
2467 wave ^= bit ^ lastbit;\r
2468 lastbit = bit;\r
2469 }\r
15db5fb7 2470\r
9760414b 2471 RepaintGraphWindow();\r
2472}\r
2473\r
2474/*\r
2475 * Manchester demodulate a bitstream. The bitstream needs to be already in\r
2476 * the GraphBuffer as 0 and 1 values\r
2477 *\r
2478 * Give the clock rate as argument in order to help the sync - the algorithm\r
2479 * resyncs at each pulse anyway.\r
2480 *\r
2481 * Not optimized by any means, this is the 1st time I'm writing this type of\r
2482 * routine, feel free to improve...\r
2483 *\r
2484 * 1st argument: clock rate (as number of samples per clock rate)\r
2485 * Typical values can be 64, 32, 128...\r
2486 */\r
2487static void Cmdmanchesterdemod(char *str) {\r
736aea60 2488 int i, j, invert= 0;\r
9760414b 2489 int bit;\r
2490 int clock;\r
2491 int lastval;\r
2492 int low = 0;\r
2493 int high = 0;\r
2494 int hithigh, hitlow, first;\r
2495 int lc = 0;\r
2496 int bitidx = 0;\r
2497 int bit2idx = 0;\r
2498 int warnings = 0;\r
2499\r
736aea60 2500 /* check if we're inverting output */\r
2501 if(*str == 'i')\r
2502 {\r
2503 PrintToScrollback("Inverting output");\r
2504 invert= 1;\r
2505 do\r
2506 ++str;\r
2507 while(*str == ' '); // in case a 2nd argument was given\r
2508 }\r
2509\r
9760414b 2510 /* Holds the decoded bitstream: each clock period contains 2 bits */\r
2511 /* later simplified to 1 bit after manchester decoding. */\r
2512 /* Add 10 bits to allow for noisy / uncertain traces without aborting */\r
2513 /* int BitStream[GraphTraceLen*2/clock+10]; */\r
2514\r
2515 /* But it does not work if compiling on WIndows: therefore we just allocate a */\r
2516 /* large array */\r
2517 int BitStream[MAX_GRAPH_TRACE_LEN];\r
2518\r
c9f99c01 2519 /* Detect high and lows */\r
2520 for (i = 0; i < GraphTraceLen; i++)\r
2521 {\r
2522 if (GraphBuffer[i] > high)\r
2523 high = GraphBuffer[i];\r
2524 else if (GraphBuffer[i] < low)\r
2525 low = GraphBuffer[i];\r
2526 }\r
2527\r
9760414b 2528 /* Get our clock */\r
2529 clock = GetClock(str, high);\r
15db5fb7 2530\r
9760414b 2531 int tolerance = clock/4;\r
15db5fb7 2532\r
9760414b 2533 /* Detect first transition */\r
2534 /* Lo-Hi (arbitrary) */\r
ac86b656 2535 /* skip to the first high */\r
2536 for (i= 0; i < GraphTraceLen; i++)\r
2537 if(GraphBuffer[i] == high)\r
2538 break;\r
2539 /* now look for the first low */\r
2540 for (; i < GraphTraceLen; i++)\r
c9f99c01 2541 {\r
2542 if (GraphBuffer[i] == low)\r
2543 {\r
9760414b 2544 lastval = i;\r
2545 break;\r
2546 }\r
2547 }\r
c9f99c01 2548\r
2549 /* If we're not working with 1/0s, demod based off clock */\r
2550 if (high != 1)\r
2551 {\r
15db5fb7 2552 bit = 0; /* We assume the 1st bit is zero, it may not be\r
2553 * the case: this routine (I think) has an init problem.\r
2554 * Ed.\r
2555 */\r
2556 for (; i < (int)(GraphTraceLen / clock); i++)\r
c9f99c01 2557 {\r
2558 hithigh = 0;\r
2559 hitlow = 0;\r
2560 first = 1;\r
2561\r
2562 /* Find out if we hit both high and low peaks */\r
2563 for (j = 0; j < clock; j++)\r
2564 {\r
2565 if (GraphBuffer[(i * clock) + j] == high)\r
2566 hithigh = 1;\r
2567 else if (GraphBuffer[(i * clock) + j] == low)\r
2568 hitlow = 1;\r
2569\r
2570 /* it doesn't count if it's the first part of our read\r
2571 because it's really just trailing from the last sequence */\r
2572 if (first && (hithigh || hitlow))\r
2573 hithigh = hitlow = 0;\r
2574 else\r
2575 first = 0;\r
2576\r
2577 if (hithigh && hitlow)\r
2578 break;\r
2579 }\r
2580\r
2581 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2582 if (!hithigh || !hitlow)\r
2583 bit ^= 1;\r
2584\r
736aea60 2585 BitStream[bit2idx++] = bit ^ invert;\r
c9f99c01 2586 }\r
2587 }\r
2588\r
2589 /* standard 1/0 bitstream */\r
2590 else\r
2591 {\r
9760414b 2592\r
736aea60 2593 /* Then detect duration between 2 successive transitions */\r
c9f99c01 2594 for (bitidx = 1; i < GraphTraceLen; i++)\r
2595 {\r
2596 if (GraphBuffer[i-1] != GraphBuffer[i])\r
2597 {\r
9760414b 2598 lc = i-lastval;\r
2599 lastval = i;\r
2600\r
2601 // Error check: if bitidx becomes too large, we do not\r
2602 // have a Manchester encoded bitstream or the clock is really\r
2603 // wrong!\r
2604 if (bitidx > (GraphTraceLen*2/clock+8) ) {\r
2605 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");\r
2606 return;\r
2607 }\r
2608 // Then switch depending on lc length:\r
2609 // Tolerance is 1/4 of clock rate (arbitrary)\r
2610 if (abs(lc-clock/2) < tolerance) {\r
2611 // Short pulse : either "1" or "0"\r
2612 BitStream[bitidx++]=GraphBuffer[i-1];\r
2613 } else if (abs(lc-clock) < tolerance) {\r
2614 // Long pulse: either "11" or "00"\r
2615 BitStream[bitidx++]=GraphBuffer[i-1];\r
2616 BitStream[bitidx++]=GraphBuffer[i-1];\r
2617 } else {\r
2618 // Error\r
c9f99c01 2619 warnings++;\r
9760414b 2620 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");\r
2621 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");\r
c9f99c01 2622\r
2623 if (warnings > 100)\r
2624 {\r
2625 PrintToScrollback("Error: too many detection errors, aborting.");\r
2626 return;\r
2627 }\r
736aea60 2628 }\r
9760414b 2629 }\r
2630 }\r
9760414b 2631\r
736aea60 2632 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream\r
2633 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful\r
2634 // to stop output at the final bitidx2 value, not bitidx\r
2635 for (i = 0; i < bitidx; i += 2) {\r
2636 if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {\r
2637 BitStream[bit2idx++] = 1 ^ invert;\r
9760414b 2638 } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {\r
736aea60 2639 BitStream[bit2idx++] = 0 ^ invert;\r
9760414b 2640 } else {\r
2641 // We cannot end up in this state, this means we are unsynchronized,\r
2642 // move up 1 bit:\r
2643 i++;\r
c9f99c01 2644 warnings++;\r
9760414b 2645 PrintToScrollback("Unsynchronized, resync...");\r
2646 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");\r
c9f99c01 2647\r
2648 if (warnings > 100)\r
2649 {\r
2650 PrintToScrollback("Error: too many decode errors, aborting.");\r
2651 return;\r
2652 }\r
736aea60 2653 }\r
67853904 2654 }\r
c9f99c01 2655 }\r
2656\r
2657 PrintToScrollback("Manchester decoded bitstream");\r
9760414b 2658 // Now output the bitstream to the scrollback by line of 16 bits\r
2659 for (i = 0; i < (bit2idx-16); i+=16) {\r
2660 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",\r
2661 BitStream[i],\r
2662 BitStream[i+1],\r
2663 BitStream[i+2],\r
2664 BitStream[i+3],\r
2665 BitStream[i+4],\r
2666 BitStream[i+5],\r
2667 BitStream[i+6],\r
2668 BitStream[i+7],\r
2669 BitStream[i+8],\r
2670 BitStream[i+9],\r
2671 BitStream[i+10],\r
2672 BitStream[i+11],\r
2673 BitStream[i+12],\r
2674 BitStream[i+13],\r
2675 BitStream[i+14],\r
2676 BitStream[i+15]);\r
2677 }\r
2678}\r
2679\r
9760414b 2680/*\r
2681 * Usage ???\r
6658905f 2682 */\r
2683static void CmdHiddemod(char *str)\r
2684{\r
2685 if(GraphTraceLen < 4800) {\r
2686 PrintToScrollback("too short; need at least 4800 samples");\r
2687 return;\r
2688 }\r
2689\r
2690 GraphTraceLen = 4800;\r
2691 int i;\r
2692 for(i = 0; i < GraphTraceLen; i++) {\r
2693 if(GraphBuffer[i] < 0) {\r
2694 GraphBuffer[i] = 0;\r
2695 } else {\r
2696 GraphBuffer[i] = 1;\r
2697 }\r
2698 }\r
2699 RepaintGraphWindow();\r
2700}\r
2701\r
2702static void CmdPlot(char *str)\r
2703{\r
2704 ShowGraphWindow();\r
2705}\r
2706\r
bd4cc2c9 2707static void CmdGrid(char *str)\r
2708{\r
f4434ad2 2709 sscanf(str, "%i %i", &PlotGridX, &PlotGridY);\r
bd4cc2c9 2710 RepaintGraphWindow();\r
2711}\r
2712\r
6658905f 2713static void CmdHide(char *str)\r
2714{\r
2715 HideGraphWindow();\r
2716}\r
2717\r
2718static void CmdScale(char *str)\r
2719{\r
2720 CursorScaleFactor = atoi(str);\r
2721 if(CursorScaleFactor == 0) {\r
2722 PrintToScrollback("bad, can't have zero scale");\r
2723 CursorScaleFactor = 1;\r
2724 }\r
2725 RepaintGraphWindow();\r
2726}\r
2727\r
2728static void CmdSave(char *str)\r
2729{\r
2730 FILE *f = fopen(str, "w");\r
2731 if(!f) {\r
2732 PrintToScrollback("couldn't open '%s'", str);\r
2733 return;\r
2734 }\r
2735 int i;\r
2736 for(i = 0; i < GraphTraceLen; i++) {\r
2737 fprintf(f, "%d\n", GraphBuffer[i]);\r
2738 }\r
2739 fclose(f);\r
2740 PrintToScrollback("saved to '%s'", str);\r
2741}\r
2742\r
2743static void CmdLoad(char *str)\r
2744{\r
2745 FILE *f = fopen(str, "r");\r
2746 if(!f) {\r
2747 PrintToScrollback("couldn't open '%s'", str);\r
2748 return;\r
2749 }\r
2750\r
2751 GraphTraceLen = 0;\r
2752 char line[80];\r
2753 while(fgets(line, sizeof(line), f)) {\r
2754 GraphBuffer[GraphTraceLen] = atoi(line);\r
2755 GraphTraceLen++;\r
2756 }\r
2757 fclose(f);\r
2758 PrintToScrollback("loaded %d samples", GraphTraceLen);\r
2759 RepaintGraphWindow();\r
2760}\r
2761\r
2762static void CmdHIDsimTAG(char *str)\r
2763{\r
2764 unsigned int hi=0, lo=0;\r
2765 int n=0, i=0;\r
2766 UsbCommand c;\r
2767\r
2768 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
2769 hi=(hi<<4)|(lo>>28);\r
2770 lo=(lo<<4)|(n&0xf);\r
2771 }\r
2772\r
2773 PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);\r
2774\r
2775 c.cmd = CMD_HID_SIM_TAG;\r
2776 c.ext1 = hi;\r
2777 c.ext2 = lo;\r
2778 SendCommand(&c, FALSE);\r
2779}\r
2780\r
1dff8c42 2781static void CmdReadmem(char *str)\r
2782{\r
2783 UsbCommand c;\r
2784 c.cmd = CMD_READ_MEM;\r
2785 c.ext1 = atoi(str);\r
2786 SendCommand(&c, FALSE);\r
2787}\r
2788\r
ba8a80b3 2789static void CmdVersion(char *str)\r
2790{\r
2791 UsbCommand c;\r
2792 c.cmd = CMD_VERSION;\r
2793 SendCommand(&c, FALSE);\r
2794}\r
2795\r
6658905f 2796static void CmdLcdReset(char *str)\r
2797{\r
2798 UsbCommand c;\r
2799 c.cmd = CMD_LCD_RESET;\r
2800 c.ext1 = atoi(str);\r
2801 SendCommand(&c, FALSE);\r
2802}\r
2803\r
2804static void CmdLcd(char *str)\r
2805{\r
2806 int i, j;\r
2807 UsbCommand c;\r
2808 c.cmd = CMD_LCD;\r
2809 sscanf(str, "%x %d", &i, &j);\r
2810 while (j--) {\r
2811 c.ext1 = i&0x1ff;\r
2812 SendCommand(&c, FALSE);\r
2813 }\r
2814}\r
2815\r
9760414b 2816/*\r
2817 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below\r
2818 * 600kHz.\r
2819 */\r
30f2a7d3 2820static void CmdSetDivisor(char *str)\r
2821{\r
2822 UsbCommand c;\r
2823 c.cmd = CMD_SET_LF_DIVISOR;\r
2824 c.ext1 = atoi(str);\r
2825 if (( c.ext1<0) || (c.ext1>255)) {\r
2826 PrintToScrollback("divisor must be between 19 and 255");\r
2827 } else {\r
2828 SendCommand(&c, FALSE);\r
2829 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c.ext1+1));\r
2830 }\r
2831}\r
2832\r
6658905f 2833typedef void HandlerFunction(char *cmdline);\r
2834\r
3f030abe 2835/* in alphabetic order */\r
6658905f 2836static struct {\r
fb25b483 2837 char *name;\r
2838 HandlerFunction *handler;\r
2839 int offline; // 1 if the command can be used when in offline mode\r
9760414b 2840 char *docString;\r
6658905f 2841} CommandTable[] = {\r
523f4c90 2842 {"amp", CmdAmp, 1, "Amplify peaks"},\r
c2c80de8 2843 {"askdemod", Cmdaskdemod, 1, "<0|1> -- Attempt to demodulate simple ASK tags"},\r
bd4cc2c9 2844 {"autocorr", CmdAutoCorr, 1, "<window length> -- Autocorrelation over window"},\r
2845 {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"},\r
2846 {"bitstream", Cmdbitstream, 1, "[clock rate] -- Convert waveform into a bitstream"},\r
1569d977 2847 {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"},\r
bd4cc2c9 2848 {"dec", CmdDec, 1, "Decimate samples"},\r
2849 {"detectclock", Cmddetectclockrate, 1, "Detect clock rate"},\r
2850 {"detectreader", CmdDetectReader, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},\r
2851 {"em410xsim", CmdEM410xsim, 1, "<UID> -- Simulate EM410x tag"},\r
2852 {"em410xread", CmdEM410xread, 1, "[clock rate] -- Extract ID from EM410x tag"},\r
2853 {"em410xwatch", CmdEM410xwatch, 0, "Watches for EM410x tags"},\r
2854 {"em4x50read", CmdEM4x50read, 1, "Extract data from EM4x50 tag"},\r
2855 {"exit", CmdQuit, 1, "Exit program"},\r
2856 {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},\r
2857 {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"},\r
2858 {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"},\r
f4434ad2 2859 {"grid", CmdGrid, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},\r
bd4cc2c9 2860 {"hexsamples", CmdHexsamples, 0, "<blocks> -- Dump big buffer as hex bytes"},\r
2861 {"hi14alist", CmdHi14alist, 0, "List ISO 14443a history"},\r
2862 {"hi14areader", CmdHi14areader, 0, "Act like an ISO14443 Type A reader"},\r
2863 {"hi14asim", CmdHi14asim, 0, "<UID> -- Fake ISO 14443a tag"},\r
2864 {"hi14asnoop", CmdHi14asnoop, 0, "Eavesdrop ISO 14443 Type A"},\r
2865 {"hi14bdemod", CmdHi14bdemod, 1, "Demodulate ISO14443 Type B from tag"},\r
2866 {"hi14list", CmdHi14list, 0, "List ISO 14443 history"},\r
2867 {"hi14read", CmdHi14read, 0, "Read HF tag (ISO 14443)"},\r
2868 {"hi14sim", CmdHi14sim, 0, "Fake ISO 14443 tag"},\r
2869 {"hi14snoop", CmdHi14snoop, 0, "Eavesdrop ISO 14443"},\r
2870 {"hi15demod", CmdHi15demod, 1, "Demodulate ISO15693 from tag"},\r
2871 {"hi15read", CmdHi15read, 0, "Read HF tag (ISO 15693)"},\r
2872 {"hi15reader", CmdHi15reader, 0, "Act like an ISO15693 reader"},\r
2873 {"hi15sim", CmdHi15tag, 0, "Fake an ISO15693 tag"},\r
2874 {"hiddemod", CmdHiddemod, 1, "Demodulate HID Prox Card II (not optimal)"},\r
2875 {"hide", CmdHide, 1, "Hide graph window"},\r
2876 {"hidfskdemod", CmdHIDdemodFSK, 0, "Realtime HID FSK demodulator"},\r
2877 {"hidsimtag", CmdHIDsimTAG, 0, "<ID> -- HID tag simulator"},\r
2878 {"higet", CmdHi14read_sim, 0, "<samples> -- Get samples HF, 'analog'"},\r
2879 {"hisamples", CmdHisamples, 0, "Get raw samples for HF tag"},\r
2880 {"hisampless", CmdHisampless, 0, "<samples> -- Get signed raw samples, HF tag"},\r
2881 {"hisamplest", CmdHi14readt, 0, "Get samples HF, for testing"},\r
2882 {"hisimlisten", CmdHisimlisten, 0, "Get HF samples as fake tag"},\r
2883 {"hpf", CmdHpf, 1, "Remove DC offset from trace"},\r
2884 {"indalademod", CmdIndalademod, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},\r
2885 {"lcd", CmdLcd, 0, "<HEX command> <count> -- Send command/data to LCD"},\r
2886 {"lcdreset", CmdLcdReset, 0, "Hardware reset LCD"},\r
2887 {"load", CmdLoad, 1, "<filename> -- Load trace (to graph window"},\r
2888 {"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)"},\r
2889 {"loread", CmdLoread, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},\r
2890 {"losamples", CmdLosamples, 0, "[128 - 16000] -- Get raw samples for LF tag"},\r
2891 {"losim", CmdLosim, 0, "Simulate LF tag"},\r
0fa9ca5b 2892 {"losimbidir", CmdLosimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},\r
bd4cc2c9 2893 {"ltrim", CmdLtrim, 1, "<samples> -- Trim samples from left of trace"},\r
2894 {"mandemod", Cmdmanchesterdemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},\r
2895 {"manmod", Cmdmanchestermod, 1, "[clock rate] -- Manchester modulate a binary stream"},\r
2896 {"norm", CmdNorm, 1, "Normalize max/min to +/-500"},\r
2897 {"plot", CmdPlot, 1, "Show graph window"},\r
2898 {"quit", CmdQuit, 1, "Quit program"},\r
2899 {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"},\r
2900 {"reset", CmdReset, 0, "Reset the Proxmark3"},\r
2901 {"save", CmdSave, 1, "<filename> -- Save trace (from graph window)"},\r
2902 {"scale", CmdScale, 1, "<int> -- Set cursor display scale"},\r
2903 {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},\r
2904 {"sri512read", CmdSri512read, 0, "<int> -- Read contents of a SRI512 tag"},\r
9bea179a 2905 {"tidemod", CmdTIDemod, 1, "Demodulate raw bits for TI-type LF tag"},\r
9bea179a 2906 {"tiread", CmdTIRead, 0, "Read and decode a TI 134 kHz tag"},\r
2907 {"tiwrite", CmdTIWrite, 0, "Write new data to a r/w TI 134 kHz tag"},\r
bd4cc2c9 2908 {"threshold", CmdThreshold, 1, "Maximize/minimize every value in the graph window depending on threshold"},\r
2909 {"tune", CmdTune, 0, "Measure antenna tuning"},\r
2910 {"vchdemod", CmdVchdemod, 0, "['clone'] -- Demodulate samples for VeriChip"},\r
269a820f 2911 {"version", CmdVersion, 0, "Show version inforation about the connected Proxmark"},\r
bd4cc2c9 2912 {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"},\r
6658905f 2913};\r
2914\r
7f93ef2c 2915static struct {\r
2916 char *name;\r
2917 char *args;\r
2918 char *argshelp;\r
2919 char *description;\r
2920 } CommandExtendedHelp[]= {\r
a52a7d19 2921 {"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."},\r
e7aee94e 2922 {"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."},\r
7f93ef2c 2923 };\r
fb25b483 2924\r
6658905f 2925//-----------------------------------------------------------------------------\r
2926// Entry point into our code: called whenever the user types a command and\r
2927// then presses Enter, which the full command line that they typed.\r
2928//-----------------------------------------------------------------------------\r
2929void CommandReceived(char *cmd)\r
2930{\r
2931 int i;\r
7f93ef2c 2932 char line[256];\r
6658905f 2933\r
2934 PrintToScrollback("> %s", cmd);\r
2935\r
7f93ef2c 2936 if(strcmp(cmd, "help") == 0 || strncmp(cmd,"help ",strlen("help ")) == 0) {\r
2937 // check if we're doing extended help\r
2938 if(strlen(cmd) > strlen("help ")) {\r
2939 cmd += strlen("help ");\r
2940 for(i = 0; i < sizeof(CommandExtendedHelp) / sizeof(CommandExtendedHelp[0]); i++) {\r
2941 if(strcmp(CommandExtendedHelp[i].name,cmd) == 0) {\r
2942 PrintToScrollback("\nExtended help for '%s':\n", cmd);\r
2943 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp[i].args,CommandExtendedHelp[i].argshelp);\r
2944 PrintToScrollback(CommandExtendedHelp[i].description);\r
a52a7d19 2945 PrintToScrollback("");\r
7f93ef2c 2946 return;\r
2947 }\r
2948 }\r
2949 PrintToScrollback("No extended help available for '%s'", cmd);\r
2950 return;\r
2951 }\r
d722c4ce 2952 if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");\r
6658905f 2953 PrintToScrollback("\r\nAvailable commands:");\r
2954 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
d722c4ce 2955 if (offline && (CommandTable[i].offline==0)) continue;\r
6658905f 2956 memset(line, ' ', sizeof(line));\r
2957 strcpy(line+2, CommandTable[i].name);\r
2958 line[strlen(line)] = ' ';\r
2959 sprintf(line+15, " -- %s", CommandTable[i].docString);\r
2960 PrintToScrollback("%s", line);\r
2961 }\r
2962 PrintToScrollback("");\r
a52a7d19 2963 PrintToScrollback("'help <command>' for extended help on that command\n");\r
6658905f 2964 return;\r
2965 }\r
2966\r
2967 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
2968 char *name = CommandTable[i].name;\r
2969 if(memcmp(cmd, name, strlen(name))==0 &&\r
2970 (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
2971 {\r
2972 cmd += strlen(name);\r
2973 while(*cmd == ' ') {\r
2974 cmd++;\r
2975 }\r
d722c4ce 2976 if (offline && (CommandTable[i].offline==0)) {\r
2977 PrintToScrollback("Offline mode, cannot use this command.");\r
2978 return;\r
2979 }\r
6658905f 2980 (CommandTable[i].handler)(cmd);\r
2981 return;\r
2982 }\r
2983 }\r
2984 PrintToScrollback(">> bad command '%s'", cmd);\r
2985}\r
2986\r
2987//-----------------------------------------------------------------------------\r
2988// Entry point into our code: called whenever we received a packet over USB\r
2989// that we weren't necessarily expecting, for example a debug print.\r
2990//-----------------------------------------------------------------------------\r
2991void UsbCommandReceived(UsbCommand *c)\r
2992{\r
2993 switch(c->cmd) {\r
2994 case CMD_DEBUG_PRINT_STRING: {\r
2995 char s[100];\r
2996 if(c->ext1 > 70 || c->ext1 < 0) {\r
2997 c->ext1 = 0;\r
2998 }\r
2999 memcpy(s, c->d.asBytes, c->ext1);\r
3000 s[c->ext1] = '\0';\r
3001 PrintToScrollback("#db# %s", s);\r
9760414b 3002 break;\r
6658905f 3003 }\r
3004\r
3005 case CMD_DEBUG_PRINT_INTEGERS:\r
3006 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
3007 break;\r
3008\r
3009 case CMD_MEASURED_ANTENNA_TUNING: {\r
e7aee94e 3010 int peakv, peakf;\r
6658905f 3011 int vLf125, vLf134, vHf;\r
3012 vLf125 = c->ext1 & 0xffff;\r
3013 vLf134 = c->ext1 >> 16;\r
e7aee94e 3014 vHf = c->ext2 & 0xffff;;\r
3015 peakf = c->ext3 & 0xffff;\r
3016 peakv = c->ext3 >> 16;\r
ad2a9782 3017 PrintToScrollback("");\r
3018 PrintToScrollback("");\r
3019 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0);\r
3020 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0);\r
3021 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1));\r
3022 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0);\r
e7aee94e 3023 if (peakv<2000)\r
67853904 3024 PrintToScrollback("# Your LF antenna is unusable.");\r
e7aee94e 3025 else if (peakv<10000)\r
3026 PrintToScrollback("# Your LF antenna is marginal.");\r
3027 if (vHf<2000)\r
67853904 3028 PrintToScrollback("# Your HF antenna is unusable.");\r
e7aee94e 3029 else if (vHf<5000)\r
3030 PrintToScrollback("# Your HF antenna is marginal.");\r
6658905f 3031 break;\r
3032 }\r
3033 default:\r
3034 PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
3035 break;\r
3036 }\r
3037}\r
Impressum, Datenschutz