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