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