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