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