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