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