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