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