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