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