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