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