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