]> git.zerfleddert.de Git - proxmark3-svn/blame - winsrc/command.cpp
get rid of annoying "declared ‘static’ but never defined" warning
[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
704 sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, &c.d.asBytes,&dummy+1);\r
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
2523static void CmdLcdReset(char *str)\r
2524{\r
2525 UsbCommand c;\r
2526 c.cmd = CMD_LCD_RESET;\r
2527 c.ext1 = atoi(str);\r
2528 SendCommand(&c, FALSE);\r
2529}\r
2530\r
2531static void CmdLcd(char *str)\r
2532{\r
2533 int i, j;\r
2534 UsbCommand c;\r
2535 c.cmd = CMD_LCD;\r
2536 sscanf(str, "%x %d", &i, &j);\r
2537 while (j--) {\r
2538 c.ext1 = i&0x1ff;\r
2539 SendCommand(&c, FALSE);\r
2540 }\r
2541}\r
2542\r
d722c4ce 2543\r
2544\r
6658905f 2545static void CmdTest(char *str)\r
2546{\r
2547}\r
9760414b 2548\r
2549/*\r
2550 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below\r
2551 * 600kHz.\r
2552 */\r
30f2a7d3 2553static void CmdSetDivisor(char *str)\r
2554{\r
2555 UsbCommand c;\r
2556 c.cmd = CMD_SET_LF_DIVISOR;\r
2557 c.ext1 = atoi(str);\r
2558 if (( c.ext1<0) || (c.ext1>255)) {\r
2559 PrintToScrollback("divisor must be between 19 and 255");\r
2560 } else {\r
2561 SendCommand(&c, FALSE);\r
2562 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c.ext1+1));\r
2563 }\r
2564}\r
2565\r
2566static void CmdSweepLF(char *str)\r
2567{\r
2568 UsbCommand c;\r
2569 c.cmd = CMD_SWEEP_LF;\r
2570 SendCommand(&c, FALSE);\r
2571}\r
9760414b 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
3f030abe 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
f23e056d 2587 "buffclear", CmdBuffClear,0, " Clear sample buffer and graph window",\r
3f030abe 2588 "dec", CmdDec,1, " Decimate samples",\r
2589 "detectclock", Cmddetectclockrate,1, " Detect clock rate",\r
7f348042 2590 "detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)",\r
3f030abe 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
955aa93f 2594 "em4x50read", CmdEM4x50read,1, " Extract data from EM4x50 tag",\r
3f030abe 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
736aea60 2622 "indalademod", CmdIndalademod,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)",\r
3f030abe 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
1de3416e 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
3f030abe 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
736aea60 2631 "mandemod", Cmdmanchesterdemod,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)",\r
3f030abe 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
2636 "reset", CmdReset,0, " Reset the Proxmark3",\r
2637 "save", CmdSave,1, "<filename> -- Save trace (from graph window)",\r
2638 "scale", CmdScale,1, "<int> -- Set cursor display scale",\r
2639 "setlfdivisor", CmdSetDivisor,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)",\r
2640 "sri512read", CmdSri512read,0, "<int> -- Read contents of a SRI512 tag",\r
2641 "sweeplf", CmdSweepLF,0, " Sweep through LF freq range and store results in buffer",\r
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
fb25b483 2650\r
6658905f 2651//-----------------------------------------------------------------------------\r
2652// Entry point into our code: called whenever the user types a command and\r
2653// then presses Enter, which the full command line that they typed.\r
2654//-----------------------------------------------------------------------------\r
2655void CommandReceived(char *cmd)\r
2656{\r
2657 int i;\r
2658\r
2659 PrintToScrollback("> %s", cmd);\r
2660\r
2661 if(strcmp(cmd, "help")==0) {\r
d722c4ce 2662 if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");\r
6658905f 2663 PrintToScrollback("\r\nAvailable commands:");\r
2664 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
d722c4ce 2665 if (offline && (CommandTable[i].offline==0)) continue;\r
6658905f 2666 char line[256];\r
2667 memset(line, ' ', sizeof(line));\r
2668 strcpy(line+2, CommandTable[i].name);\r
2669 line[strlen(line)] = ' ';\r
2670 sprintf(line+15, " -- %s", CommandTable[i].docString);\r
2671 PrintToScrollback("%s", line);\r
2672 }\r
2673 PrintToScrollback("");\r
2674 PrintToScrollback("and also: help, cls");\r
2675 return;\r
2676 }\r
2677\r
2678 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
2679 char *name = CommandTable[i].name;\r
2680 if(memcmp(cmd, name, strlen(name))==0 &&\r
2681 (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
2682 {\r
2683 cmd += strlen(name);\r
2684 while(*cmd == ' ') {\r
2685 cmd++;\r
2686 }\r
d722c4ce 2687 if (offline && (CommandTable[i].offline==0)) {\r
2688 PrintToScrollback("Offline mode, cannot use this command.");\r
2689 return;\r
2690 }\r
6658905f 2691 (CommandTable[i].handler)(cmd);\r
2692 return;\r
2693 }\r
2694 }\r
2695 PrintToScrollback(">> bad command '%s'", cmd);\r
2696}\r
2697\r
2698//-----------------------------------------------------------------------------\r
2699// Entry point into our code: called whenever we received a packet over USB\r
2700// that we weren't necessarily expecting, for example a debug print.\r
2701//-----------------------------------------------------------------------------\r
2702void UsbCommandReceived(UsbCommand *c)\r
2703{\r
2704 switch(c->cmd) {\r
2705 case CMD_DEBUG_PRINT_STRING: {\r
2706 char s[100];\r
2707 if(c->ext1 > 70 || c->ext1 < 0) {\r
2708 c->ext1 = 0;\r
2709 }\r
2710 memcpy(s, c->d.asBytes, c->ext1);\r
2711 s[c->ext1] = '\0';\r
2712 PrintToScrollback("#db# %s", s);\r
9760414b 2713 break;\r
6658905f 2714 }\r
2715\r
2716 case CMD_DEBUG_PRINT_INTEGERS:\r
2717 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
2718 break;\r
2719\r
2720 case CMD_MEASURED_ANTENNA_TUNING: {\r
2721 int zLf, zHf;\r
2722 int vLf125, vLf134, vHf;\r
2723 vLf125 = c->ext1 & 0xffff;\r
2724 vLf134 = c->ext1 >> 16;\r
2725 vHf = c->ext2;\r
2726 zLf = c->ext3 & 0xffff;\r
2727 zHf = c->ext3 >> 16;\r
2728 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",\r
2729 vLf125/zLf, vLf125, zLf);\r
2730 PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",\r
2731 vLf134/((zLf*125)/134), vLf134, (zLf*125)/134);\r
2732 PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",\r
2733 vHf/zHf, vHf, zHf);\r
2734 break;\r
2735 }\r
2736 default:\r
2737 PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
2738 break;\r
2739 }\r
2740}\r
Impressum, Datenschutz