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