]> git.zerfleddert.de Git - proxmark3-svn/blame - winsrc/command.cpp
fast flash mode (button already held down) and both (os & fpga) flashing mode
[proxmark3-svn] / winsrc / command.cpp
CommitLineData
6658905f 1//-----------------------------------------------------------------------------\r
2// The actual command interpeter for what the user types at the command line.\r
3// Jonathan Westhues, Sept 2005\r
4// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
5//-----------------------------------------------------------------------------\r
6#include <windows.h>\r
7#include <stdlib.h>\r
8#include <string.h>\r
9#include <stdio.h>\r
10#include <limits.h>\r
11#include <math.h>\r
12\r
13#include "prox.h"\r
14#include "../common/iso14443_crc.c"\r
0c2ed92d 15#include "../common/crc16.c"\r
6658905f 16\r
17#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
9760414b 18#define BIT(x) GraphBuffer[x * clock]\r
19#define BITS (GraphTraceLen / clock)\r
6658905f 20\r
9760414b 21int go = 0;\r
6658905f 22static int CmdHisamplest(char *str, int nrlow);\r
23\r
24static void GetFromBigBuf(BYTE *dest, int bytes)\r
25{\r
26 int n = bytes/4;\r
27\r
28 if(n % 48 != 0) {\r
29 PrintToScrollback("bad len in GetFromBigBuf");\r
30 return;\r
31 }\r
32\r
33 int i;\r
34 for(i = 0; i < n; i += 12) {\r
35 UsbCommand c;\r
36 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
37 c.ext1 = i;\r
38 SendCommand(&c, FALSE);\r
39 ReceiveCommand(&c);\r
40 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 41 PrintToScrollback("bad resp");\r
6658905f 42 return;\r
43 }\r
44\r
45 memcpy(dest+(i*4), c.d.asBytes, 48);\r
46 }\r
47}\r
48\r
d722c4ce 49static void CmdReset(char *str)\r
50{\r
51 UsbCommand c;\r
52 c.cmd = CMD_HARDWARE_RESET;\r
53 SendCommand(&c, FALSE);\r
54}\r
55\r
f23e056d 56static void CmdBuffClear(char *str)\r
57{\r
58 UsbCommand c;\r
59 c.cmd = CMD_BUFF_CLEAR;\r
60 SendCommand(&c, FALSE);\r
61 CmdClearGraph(TRUE);\r
62}\r
d722c4ce 63\r
6658905f 64static void CmdQuit(char *str)\r
65{\r
66 exit(0);\r
67}\r
68\r
69static void CmdHIDdemodFSK(char *str)\r
70{\r
71 UsbCommand c;\r
72 c.cmd = CMD_HID_DEMOD_FSK;\r
73 SendCommand(&c, FALSE);\r
74}\r
75\r
76static void CmdTune(char *str)\r
77{\r
78 UsbCommand c;\r
79 c.cmd = CMD_MEASURE_ANTENNA_TUNING;\r
80 SendCommand(&c, FALSE);\r
81}\r
82\r
83static void CmdHi15read(char *str)\r
84{\r
85 UsbCommand c;\r
86 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;\r
87 SendCommand(&c, FALSE);\r
88}\r
89\r
90static void CmdHi14read(char *str)\r
91{\r
92 UsbCommand c;\r
93 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
94 c.ext1 = atoi(str);\r
95 SendCommand(&c, FALSE);\r
96}\r
9760414b 97\r
98\r
99/* New command to read the contents of a SRI512 tag\r
100 * SRI512 tags are ISO14443-B modulated memory tags,\r
101 * this command just dumps the contents of the memory/\r
102 */\r
103static void CmdSri512read(char *str)\r
104{\r
fb25b483 105 UsbCommand c;\r
106 c.cmd = CMD_READ_SRI512_TAG;\r
107 c.ext1 = atoi(str);\r
9760414b 108 SendCommand(&c, FALSE);\r
109}\r
6658905f 110\r
111// ## New command\r
112static void CmdHi14areader(char *str)\r
113{\r
114 UsbCommand c;\r
115 c.cmd = CMD_READER_ISO_14443a;\r
116 c.ext1 = atoi(str);\r
117 SendCommand(&c, FALSE);\r
118}\r
119\r
120// ## New command\r
121static void CmdHi15reader(char *str)\r
122{\r
123 UsbCommand c;\r
124 c.cmd = CMD_READER_ISO_15693;\r
125 c.ext1 = atoi(str);\r
126 SendCommand(&c, FALSE);\r
127}\r
128\r
129// ## New command\r
130static void CmdHi15tag(char *str)\r
131{\r
132 UsbCommand c;\r
133 c.cmd = CMD_SIMTAG_ISO_15693;\r
134 c.ext1 = atoi(str);\r
135 SendCommand(&c, FALSE);\r
136}\r
137\r
138static void CmdHi14read_sim(char *str)\r
139{\r
140 UsbCommand c;\r
141 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM;\r
142 c.ext1 = atoi(str);\r
143 SendCommand(&c, FALSE);\r
144}\r
145\r
146static void CmdHi14readt(char *str)\r
147{\r
148 UsbCommand c;\r
149 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
150 c.ext1 = atoi(str);\r
151 SendCommand(&c, FALSE);\r
152\r
153 //CmdHisamplest(str);\r
154 while(CmdHisamplest(str,atoi(str))==0) {\r
155 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
156 c.ext1 = atoi(str);\r
157 SendCommand(&c, FALSE);\r
158 }\r
159 RepaintGraphWindow();\r
160}\r
161\r
162static void CmdHisimlisten(char *str)\r
163{\r
164 UsbCommand c;\r
165 c.cmd = CMD_SIMULATE_TAG_HF_LISTEN;\r
166 SendCommand(&c, FALSE);\r
167}\r
168\r
169static void CmdHi14sim(char *str)\r
170{\r
171 UsbCommand c;\r
172 c.cmd = CMD_SIMULATE_TAG_ISO_14443;\r
173 SendCommand(&c, FALSE);\r
174}\r
6658905f 175\r
176static void CmdHi14asim(char *str) // ## simulate iso14443a tag\r
177{ // ## greg - added ability to specify tag UID\r
178\r
179 unsigned int hi=0, lo=0;\r
180 int n=0, i=0;\r
181 UsbCommand c;\r
182\r
183 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
184 hi=(hi<<4)|(lo>>28);\r
185 lo=(lo<<4)|(n&0xf);\r
186 }\r
187\r
188 c.cmd = CMD_SIMULATE_TAG_ISO_14443a;\r
189 // c.ext should be set to *str or convert *str to the correct format for a uid\r
190 c.ext1 = hi;\r
191 c.ext2 = lo;\r
192 PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi, lo);\r
193 SendCommand(&c, FALSE);\r
194}\r
195\r
196static void CmdHi14snoop(char *str)\r
197{\r
198 UsbCommand c;\r
199 c.cmd = CMD_SNOOP_ISO_14443;\r
200 SendCommand(&c, FALSE);\r
201}\r
202\r
203static void CmdHi14asnoop(char *str)\r
204{\r
205 UsbCommand c;\r
206 c.cmd = CMD_SNOOP_ISO_14443a;\r
207 SendCommand(&c, FALSE);\r
208}\r
209\r
210static void CmdFPGAOff(char *str) // ## FPGA Control\r
211{\r
212 UsbCommand c;\r
213 c.cmd = CMD_FPGA_MAJOR_MODE_OFF;\r
214 SendCommand(&c, FALSE);\r
215}\r
216\r
9760414b 217/* clear out our graph window */\r
218int CmdClearGraph(int redraw)\r
219{\r
220 int gtl = GraphTraceLen;\r
221 GraphTraceLen = 0;\r
15db5fb7 222\r
9760414b 223 if (redraw)\r
224 RepaintGraphWindow();\r
15db5fb7 225\r
9760414b 226 return gtl;\r
227}\r
228\r
229/* write a bit to the graph */\r
230static void CmdAppendGraph(int redraw, int clock, int bit)\r
6658905f 231{\r
232 int i;\r
233\r
9760414b 234 for (i = 0; i < (int)(clock/2); i++)\r
235 GraphBuffer[GraphTraceLen++] = bit ^ 1;\r
15db5fb7 236\r
237 for (i = (int)(clock/2); i < clock; i++)\r
9760414b 238 GraphBuffer[GraphTraceLen++] = bit;\r
239\r
240 if (redraw)\r
241 RepaintGraphWindow();\r
242}\r
243\r
244/* Function is equivalent of loread + losamples + em410xread\r
245 * looped until an EM410x tag is detected */\r
246static void CmdEM410xwatch(char *str)\r
247{\r
248 char *zero = "";\r
249 char *twok = "2000";\r
250 go = 1;\r
15db5fb7 251\r
9760414b 252 do\r
253 {\r
254 CmdLoread(zero);\r
255 CmdLosamples(twok);\r
256 CmdEM410xread(zero);\r
257 } while (go);\r
258}\r
259\r
955aa93f 260/* Read the transmitted data of an EM4x50 tag\r
261 * Format:\r
262 *\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 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
267 * CCCCCCCC <- column parity bits\r
268 * 0 <- stop bit\r
269 * LW <- Listen Window\r
270 *\r
271 * This pattern repeats for every block of data being transmitted.\r
272 * Transmission starts with two Listen Windows (LW - a modulated\r
273 * pattern of 320 cycles each (32/32/128/64/64)).\r
274 *\r
275 * Note that this data may or may not be the UID. It is whatever data\r
67853904 276 * is stored in the blocks defined in the control word First and Last\r
955aa93f 277 * Word Read values. UID is stored in block 32.\r
67853904 278 */\r
955aa93f 279static void CmdEM4x50read(char *str)\r
280{\r
281 int i, j, startblock, clock, skip, block, start, end, low, high;\r
282 BOOL complete= FALSE;\r
283 int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];\r
284 char tmp[6];\r
285\r
286 high= low= 0;\r
287 clock= 64;\r
288\r
289 /* first get high and low values */\r
290 for (i = 0; i < GraphTraceLen; i++)\r
291 {\r
67853904 292 if (GraphBuffer[i] > high)\r
955aa93f 293 high = GraphBuffer[i];\r
294 else if (GraphBuffer[i] < low)\r
295 low = GraphBuffer[i];\r
296 }\r
297\r
298 /* populate a buffer with pulse lengths */\r
299 i= 0;\r
300 j= 0;\r
301 while(i < GraphTraceLen)\r
302 {\r
303 // measure from low to low\r
304 while(GraphBuffer[i] > low)\r
305 ++i;\r
306 start= i;\r
307 while(GraphBuffer[i] < high)\r
308 ++i;\r
309 while(GraphBuffer[i] > low)\r
310 ++i;\r
311 tmpbuff[j++]= i - start;\r
312 }\r
313\r
67853904 314\r
955aa93f 315 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */\r
316 start= -1;\r
317 skip= 0;\r
318 for (i= 0; i < j - 4 ; ++i)\r
319 {\r
320 skip += tmpbuff[i];\r
321 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
322 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
323 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
324 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
325 {\r
326 start= i + 3;\r
327 break;\r
328 }\r
329 }\r
330 startblock= i + 3;\r
331\r
332 /* skip over the remainder of the LW */\r
333 skip += tmpbuff[i+1]+tmpbuff[i+2];\r
334 while(GraphBuffer[skip] > low)\r
335 ++skip;\r
336 skip += 8;\r
337\r
338 /* now do it again to find the end */\r
339 end= start;\r
340 for (i += 3; i < j - 4 ; ++i)\r
341 {\r
342 end += tmpbuff[i];\r
343 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
344 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
345 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
346 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
347 {\r
348 complete= TRUE;\r
349 break;\r
350 }\r
351 }\r
352\r
353 if (start >= 0)\r
354 PrintToScrollback("Found data at sample: %i",skip);\r
355 else\r
356 {\r
357 PrintToScrollback("No data found!");\r
358 PrintToScrollback("Try again with more samples.");\r
359 return;\r
360 }\r
361\r
362 if (!complete)\r
363 {\r
364 PrintToScrollback("*** Warning!");\r
365 PrintToScrollback("Partial data - no end found!");\r
366 PrintToScrollback("Try again with more samples.");\r
367 }\r
368\r
369 /* get rid of leading crap */\r
370 sprintf(tmp,"%i",skip);\r
371 CmdLtrim(tmp);\r
372\r
373 /* now work through remaining buffer printing out data blocks */\r
374 block= 0;\r
375 i= startblock;\r
376 while(block < 6)\r
377 {\r
378 PrintToScrollback("Block %i:", block);\r
379 // mandemod routine needs to be split so we can call it for data\r
380 // just print for now for debugging\r
381 Cmdmanchesterdemod("i 64");\r
382 skip= 0;\r
383 /* look for LW before start of next block */\r
384 for ( ; i < j - 4 ; ++i)\r
385 {\r
386 skip += tmpbuff[i];\r
387 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
388 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
389 break;\r
390 }\r
391 while(GraphBuffer[skip] > low)\r
392 ++skip;\r
393 skip += 8;\r
394 sprintf(tmp,"%i",skip);\r
395 CmdLtrim(tmp);\r
396 start += skip;\r
397 block++;\r
398 }\r
399}\r
400\r
401\r
9760414b 402/* Read the ID of an EM410x tag.\r
403 * Format:\r
404 * 1111 1111 1 <-- standard non-repeatable header\r
405 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
406 * ....\r
407 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column\r
408 * 0 <-- stop bit, end of tag\r
409 */\r
410static void CmdEM410xread(char *str)\r
411{\r
412 int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low;\r
413 int parity[4];\r
414 char id[11];\r
a91ff4c8 415 int retested = 0;\r
9760414b 416 int BitStream[MAX_GRAPH_TRACE_LEN];\r
417 high = low = 0;\r
15db5fb7 418\r
9760414b 419 /* Detect high and lows and clock */\r
420 for (i = 0; i < GraphTraceLen; i++)\r
421 {\r
422 if (GraphBuffer[i] > high)\r
423 high = GraphBuffer[i];\r
424 else if (GraphBuffer[i] < low)\r
425 low = GraphBuffer[i];\r
15db5fb7 426 }\r
427\r
9760414b 428 /* get clock */\r
429 clock = GetClock(str, high);\r
15db5fb7 430\r
9760414b 431 /* parity for our 4 columns */\r
432 parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
433 header = rows = 0;\r
15db5fb7 434\r
9760414b 435 /* manchester demodulate */\r
436 bit = bit2idx = 0;\r
437 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
438 {\r
439 hithigh = 0;\r
440 hitlow = 0;\r
441 first = 1;\r
15db5fb7 442\r
9760414b 443 /* Find out if we hit both high and low peaks */\r
444 for (j = 0; j < clock; j++)\r
445 {\r
446 if (GraphBuffer[(i * clock) + j] == high)\r
447 hithigh = 1;\r
448 else if (GraphBuffer[(i * clock) + j] == low)\r
449 hitlow = 1;\r
15db5fb7 450\r
9760414b 451 /* it doesn't count if it's the first part of our read\r
452 because it's really just trailing from the last sequence */\r
453 if (first && (hithigh || hitlow))\r
454 hithigh = hitlow = 0;\r
455 else\r
456 first = 0;\r
15db5fb7 457\r
9760414b 458 if (hithigh && hitlow)\r
459 break;\r
460 }\r
67853904 461\r
9760414b 462 /* If we didn't hit both high and low peaks, we had a bit transition */\r
463 if (!hithigh || !hitlow)\r
464 bit ^= 1;\r
67853904 465\r
9760414b 466 BitStream[bit2idx++] = bit;\r
467 }\r
67853904 468\r
a91ff4c8 469retest:\r
9760414b 470 /* We go till 5 before the graph ends because we'll get that far below */\r
471 for (i = 1; i < bit2idx - 5; i++)\r
472 {\r
473 /* Step 2: We have our header but need our tag ID */\r
474 if (header == 9 && rows < 10)\r
475 {\r
476 /* Confirm parity is correct */\r
477 if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4])\r
478 {\r
479 /* Read another byte! */\r
480 sprintf(id+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3]));\r
481 rows++;\r
15db5fb7 482\r
9760414b 483 /* Keep parity info */\r
484 parity[0] ^= BitStream[i];\r
485 parity[1] ^= BitStream[i+1];\r
486 parity[2] ^= BitStream[i+2];\r
487 parity[3] ^= BitStream[i+3];\r
15db5fb7 488\r
9760414b 489 /* Move 4 bits ahead */\r
490 i += 4;\r
491 }\r
15db5fb7 492\r
9760414b 493 /* Damn, something wrong! reset */\r
494 else\r
495 {\r
496 PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i);\r
15db5fb7 497\r
9760414b 498 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */\r
499 i -= 9 + (5 * rows) - 5;\r
500\r
501 rows = header = 0;\r
502 }\r
503 }\r
15db5fb7 504\r
9760414b 505 /* Step 3: Got our 40 bits! confirm column parity */\r
506 else if (rows == 10)\r
507 {\r
508 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */\r
509 if (BitStream[i] == parity[0] && BitStream[i+1] == parity[1] &&\r
510 BitStream[i+2] == parity[2] && BitStream[i+3] == parity[3] &&\r
511 BitStream[i+4] == 0)\r
512 {\r
513 /* Sweet! */\r
514 PrintToScrollback("EM410x Tag ID: %s", id);\r
15db5fb7 515\r
9760414b 516 /* Stop any loops */\r
517 go = 0;\r
a91ff4c8 518 return;\r
9760414b 519 }\r
15db5fb7 520\r
9760414b 521 /* Crap! Incorrect parity or no stop bit, start all over */\r
522 else\r
523 {\r
524 rows = header = 0;\r
15db5fb7 525\r
9760414b 526 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */\r
527 i -= 59;\r
528 }\r
529 }\r
15db5fb7 530\r
9760414b 531 /* Step 1: get our header */\r
532 else if (header < 9)\r
533 {\r
534 /* Need 9 consecutive 1's */\r
535 if (BitStream[i] == 1)\r
536 header++;\r
15db5fb7 537\r
9760414b 538 /* We don't have a header, not enough consecutive 1 bits */\r
539 else\r
540 header = 0;\r
541 }\r
542 }\r
67853904 543\r
a91ff4c8 544 /* if we've already retested after flipping bits, return */\r
545 if (retested++)\r
546 return;\r
547\r
548 /* if this didn't work, try flipping bits */\r
549 for (i = 0; i < bit2idx; i++)\r
550 BitStream[i] ^= 1;\r
551\r
552 goto retest;\r
9760414b 553}\r
554\r
555/* emulate an EM410X tag\r
556 * Format:\r
557 * 1111 1111 1 <-- standard non-repeatable header\r
558 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
559 * ....\r
560 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column\r
561 * 0 <-- stop bit, end of tag\r
562 */\r
563static void CmdEM410xsim(char *str)\r
564{\r
565 int i, n, j, h, binary[4], parity[4];\r
566 char *s = "0";\r
15db5fb7 567\r
9760414b 568 /* clock is 64 in EM410x tags */\r
569 int clock = 64;\r
15db5fb7 570\r
9760414b 571 /* clear our graph */\r
572 CmdClearGraph(0);\r
15db5fb7 573\r
9760414b 574 /* write it out a few times */\r
575 for (h = 0; h < 4; h++)\r
576 {\r
577 /* write 9 start bits */\r
578 for (i = 0; i < 9; i++)\r
579 CmdAppendGraph(0, clock, 1);\r
15db5fb7 580\r
9760414b 581 /* for each hex char */\r
582 parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
583 for (i = 0; i < 10; i++)\r
584 {\r
585 /* read each hex char */\r
586 sscanf(&str[i], "%1x", &n);\r
587 for (j = 3; j >= 0; j--, n/= 2)\r
588 binary[j] = n % 2;\r
15db5fb7 589\r
9760414b 590 /* append each bit */\r
591 CmdAppendGraph(0, clock, binary[0]);\r
592 CmdAppendGraph(0, clock, binary[1]);\r
593 CmdAppendGraph(0, clock, binary[2]);\r
594 CmdAppendGraph(0, clock, binary[3]);\r
15db5fb7 595\r
9760414b 596 /* append parity bit */\r
597 CmdAppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);\r
15db5fb7 598\r
9760414b 599 /* keep track of column parity */\r
600 parity[0] ^= binary[0];\r
601 parity[1] ^= binary[1];\r
602 parity[2] ^= binary[2];\r
603 parity[3] ^= binary[3];\r
604 }\r
15db5fb7 605\r
9760414b 606 /* parity columns */\r
607 CmdAppendGraph(0, clock, parity[0]);\r
608 CmdAppendGraph(0, clock, parity[1]);\r
609 CmdAppendGraph(0, clock, parity[2]);\r
610 CmdAppendGraph(0, clock, parity[3]);\r
15db5fb7 611\r
9760414b 612 /* stop bit */\r
613 CmdAppendGraph(0, clock, 0);\r
614 }\r
15db5fb7 615\r
9760414b 616 /* modulate that biatch */\r
617 Cmdmanchestermod(s);\r
15db5fb7 618\r
9760414b 619 /* booyah! */\r
620 RepaintGraphWindow();\r
621\r
622 CmdLosim(s);\r
623}\r
624\r
625static void ChkBitstream(char *str)\r
626{\r
627 int i;\r
15db5fb7 628\r
9760414b 629 /* convert to bitstream if necessary */\r
630 for (i = 0; i < (int)(GraphTraceLen / 2); i++)\r
631 {\r
632 if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)\r
633 {\r
634 Cmdbitstream(str);\r
635 break;\r
636 }\r
637 }\r
638}\r
639\r
640static void CmdLosim(char *str)\r
641{\r
642 int i;\r
15db5fb7 643\r
9760414b 644 /* convert to bitstream if necessary */\r
645 ChkBitstream(str);\r
15db5fb7 646\r
9760414b 647 for (i = 0; i < GraphTraceLen; i += 48) {\r
6658905f 648 UsbCommand c;\r
649 int j;\r
650 for(j = 0; j < 48; j++) {\r
651 c.d.asBytes[j] = GraphBuffer[i+j];\r
652 }\r
653 c.cmd = CMD_DOWNLOADED_SIM_SAMPLES_125K;\r
654 c.ext1 = i;\r
655 SendCommand(&c, FALSE);\r
656 }\r
657\r
658 UsbCommand c;\r
659 c.cmd = CMD_SIMULATE_TAG_125K;\r
660 c.ext1 = GraphTraceLen;\r
661 SendCommand(&c, FALSE);\r
662}\r
663\r
664static void CmdLoread(char *str)\r
665{\r
666 UsbCommand c;\r
667 // 'h' means higher-low-frequency, 134 kHz\r
668 if(*str == 'h') {\r
669 c.ext1 = 1;\r
670 } else if (*str == '\0') {\r
671 c.ext1 = 0;\r
672 } else {\r
673 PrintToScrollback("use 'loread' or 'loread h'");\r
674 return;\r
675 }\r
676 c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
677 SendCommand(&c, FALSE);\r
678}\r
679\r
7f348042 680static void CmdDetectReader(char *str)\r
681{\r
682 UsbCommand c;\r
683 // 'l' means LF - 125/134 kHz\r
684 if(*str == 'l') {\r
685 c.ext1 = 1;\r
686 } else if (*str == 'h') {\r
687 c.ext1 = 2;\r
688 } else if (*str != '\0') {\r
689 PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");\r
690 return;\r
691 }\r
692 c.cmd = CMD_LISTEN_READER_FIELD;\r
693 SendCommand(&c, FALSE);\r
694}\r
695\r
959baa89 696/* send a command before reading */\r
697static void CmdLoCommandRead(char *str)\r
698{\r
699 static char dummy[3];\r
700\r
701 dummy[0]= ' ';\r
67853904 702\r
959baa89 703 UsbCommand c;\r
704 c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
1dd23352 705 sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, (char *) &c.d.asBytes,(char *) &dummy+1);\r
959baa89 706 // in case they specified 'h'\r
8172fb35 707 strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);\r
959baa89 708 SendCommand(&c, FALSE);\r
709}\r
710\r
6658905f 711static void CmdLosamples(char *str)\r
712{\r
713 int cnt = 0;\r
714 int i;\r
715 int n;\r
716\r
717 n=atoi(str);\r
718 if (n==0) n=128;\r
719 if (n>16000) n=16000;\r
720\r
721 for(i = 0; i < n; i += 12) {\r
722 UsbCommand c;\r
723 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
724 c.ext1 = i;\r
725 SendCommand(&c, FALSE);\r
726 ReceiveCommand(&c);\r
727 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 728 if (!go)\r
729 PrintToScrollback("bad resp");\r
6658905f 730 return;\r
731 }\r
732 int j;\r
733 for(j = 0; j < 48; j++) {\r
734 GraphBuffer[cnt++] = ((int)c.d.asBytes[j]) - 128;\r
735 }\r
736 }\r
737 GraphTraceLen = n*4;\r
738 RepaintGraphWindow();\r
739}\r
740\r
741static void CmdBitsamples(char *str)\r
742{\r
743 int cnt = 0;\r
744 int i;\r
745 int n;\r
746\r
747 n = 3072;\r
748 for(i = 0; i < n; i += 12) {\r
749 UsbCommand c;\r
750 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
751 c.ext1 = i;\r
752 SendCommand(&c, FALSE);\r
753 ReceiveCommand(&c);\r
754 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 755 PrintToScrollback("bad resp");\r
6658905f 756 return;\r
757 }\r
758 int j, k;\r
759 for(j = 0; j < 48; j++) {\r
760 for(k = 0; k < 8; k++) {\r
761 if(c.d.asBytes[j] & (1 << (7 - k))) {\r
762 GraphBuffer[cnt++] = 1;\r
763 } else {\r
764 GraphBuffer[cnt++] = 0;\r
765 }\r
766 }\r
767 }\r
768 }\r
769 GraphTraceLen = cnt;\r
770 RepaintGraphWindow();\r
771}\r
772\r
773static void CmdHisamples(char *str)\r
774{\r
775 int cnt = 0;\r
776 int i;\r
777 int n;\r
778 n = 1000;\r
779 for(i = 0; i < n; i += 12) {\r
780 UsbCommand c;\r
781 c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
782 c.ext1 = i;\r
783 SendCommand(&c, FALSE);\r
784 ReceiveCommand(&c);\r
785 if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
9760414b 786 PrintToScrollback("bad resp");\r
6658905f 787 return;\r
788 }\r
789 int j;\r
790 for(j = 0; j < 48; j++) {\r
791 GraphBuffer[cnt++] = (int)((BYTE)c.d.asBytes[j]);\r
792 }\r
793 }\r
794 GraphTraceLen = n*4;\r
795\r
796 RepaintGraphWindow();\r
797}\r
798\r
6658905f 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
67853904 1409// for(i = 0; i < 1536; i += 12) {\r
1410 for(i = 0; i < 4000; i += 12) {\r
6658905f 1411 UsbCommand c;\r
1412 c.cmd = CMD_DOWNLOAD_RAW_BITS_TI_TYPE;\r
1413 c.ext1 = i;\r
1414 SendCommand(&c, FALSE);\r
1415 ReceiveCommand(&c);\r
1416 if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {\r
9760414b 1417 PrintToScrollback("bad resp");\r
6658905f 1418 return;\r
1419 }\r
1420 int j;\r
1421 for(j = 0; j < 12; j++) {\r
1422 int k;\r
1423 for(k = 31; k >= 0; k--) {\r
1424 if(c.d.asDwords[j] & (1 << k)) {\r
1425 GraphBuffer[cnt++] = 1;\r
1426 } else {\r
1427 GraphBuffer[cnt++] = -1;\r
1428 }\r
1429 }\r
1430 }\r
1431 }\r
67853904 1432// GraphTraceLen = 1536*32;\r
1433 GraphTraceLen = 4000*32;\r
6658905f 1434 RepaintGraphWindow();\r
1435}\r
1436\r
67853904 1437static void CmdFSKdemod(char *cmdline)\r
1438{\r
1439 static const int LowTone[] = {\r
1440 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1441 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1442 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1443 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1444 1, 1, 1, 1, 1, -1, -1, -1, -1, -1\r
1445 };\r
1446 static const int HighTone[] = {\r
1447 1, 1, 1, 1, 1, -1, -1, -1, -1,\r
1448 1, 1, 1, 1, -1, -1, -1, -1,\r
1449 1, 1, 1, 1, -1, -1, -1, -1,\r
1450 1, 1, 1, 1, -1, -1, -1, -1,\r
1451 1, 1, 1, 1, -1, -1, -1, -1,\r
1452 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
1453 };\r
1454\r
1455 int convLen = max(arraylen(HighTone), arraylen(LowTone));\r
1456 DWORD hi = 0, lo = 0;\r
1457\r
1458 int i, j;\r
1459 int minMark=0, maxMark=0;\r
1460 int lowLen = arraylen(LowTone);\r
1461 int highLen = arraylen(HighTone);\r
1462\r
1463 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
1464 int lowSum = 0, highSum = 0;\r
1465\r
1466 for(j = 0; j < lowLen; j++) {\r
1467 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1468 }\r
1469 for(j = 0; j < highLen; j++) {\r
1470 highSum += HighTone[j]*GraphBuffer[i+j];\r
1471 }\r
1472 lowSum = abs((100*lowSum) / lowLen);\r
1473 highSum = abs((100*highSum) / highLen);\r
1474 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1475 }\r
1476\r
1477 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
1478 int j;\r
1479 int lowTot = 0, highTot = 0;\r
1480 // 10 and 8 are f_s divided by f_l and f_h, rounded\r
1481 for(j = 0; j < 10; j++) {\r
1482 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1483 }\r
1484 for(j = 0; j < 8; j++) {\r
1485 highTot += (GraphBuffer[i+j] >> 16);\r
1486 }\r
1487 GraphBuffer[i] = lowTot - highTot;\r
1488 if (GraphBuffer[i]>maxMark) maxMark=GraphBuffer[i];\r
1489 if (GraphBuffer[i]<minMark) minMark=GraphBuffer[i];\r
1490 }\r
1491\r
1492 GraphTraceLen -= (convLen + 16);\r
1493\r
1494 RepaintGraphWindow();\r
1495\r
1496 // Find bit-sync (3 lo followed by 3 high)\r
1497 int max = 0, maxPos = 0;\r
1498 for(i = 0; i < 6000; i++) {\r
1499 int dec = 0;\r
1500 for(j = 0; j < 3*arraylen(LowTone); j++) {\r
1501 dec -= GraphBuffer[i+j];\r
1502 }\r
1503 for(; j < 3*(arraylen(LowTone) + arraylen(HighTone) ); j++) {\r
1504 dec += GraphBuffer[i+j];\r
1505 }\r
1506 if(dec > max) {\r
1507 max = dec;\r
1508 maxPos = i;\r
1509 }\r
1510 }\r
1511\r
1512 // place start of bit sync marker in graph\r
1513 GraphBuffer[maxPos] = maxMark;\r
1514 GraphBuffer[maxPos+1] = minMark;\r
1515\r
1516 maxPos += j;\r
1517\r
1518 // place end of bit sync marker in graph\r
1519 GraphBuffer[maxPos] = maxMark;\r
1520 GraphBuffer[maxPos+1] = minMark;\r
1521\r
1522 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
1523 PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));\r
1524\r
1525 BYTE bits[46];\r
1526 bits[sizeof(bits)-1] = '\0';\r
1527\r
1528 // find bit pairs and manchester decode them\r
1529 for(i = 0; i < arraylen(bits)-1; i++) {\r
1530 int dec = 0;\r
1531 for(j = 0; j < arraylen(LowTone); j++) {\r
1532 dec -= GraphBuffer[maxPos+j];\r
1533 }\r
1534 for(; j < arraylen(LowTone) + arraylen(HighTone); j++) {\r
1535 dec += GraphBuffer[maxPos+j];\r
1536 }\r
1537 maxPos += j;\r
1538 // place inter bit marker in graph\r
1539 GraphBuffer[maxPos] = maxMark;\r
1540 GraphBuffer[maxPos+1] = minMark;\r
1541\r
1542 // hi and lo form a 64 bit pair\r
1543 hi = (hi<<1)|(lo>>31);\r
1544 lo = (lo<<1);\r
1545 // store decoded bit as binary (in hi/lo) and text (in bits[])\r
1546 if(dec<0) {\r
1547 bits[i] = '1';\r
1548 lo|=1;\r
1549 } else {\r
1550 bits[i] = '0';\r
1551 }\r
1552 }\r
1553 PrintToScrollback("bits: '%s'", bits);\r
1554 PrintToScrollback("hex: %08x %08x", hi, lo);\r
1555}\r
1556\r
6658905f 1557static void CmdTidemod(char *cmdline)\r
1558{\r
1559 /* MATLAB as follows:\r
1560f_s = 2000000; % sampling frequency\r
1561f_l = 123200; % low FSK tone\r
1562f_h = 134200; % high FSK tone\r
1563\r
1564T_l = 119e-6; % low bit duration\r
1565T_h = 130e-6; % high bit duration\r
1566\r
1567l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);\r
1568h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);\r
1569\r
1570l = sign(sin(cumsum(l)));\r
1571h = sign(sin(cumsum(h)));\r
1572 */\r
67853904 1573 static const int LowTone[] = {\r
1574 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1575 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1576 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1577 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1578 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1579 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1580 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1581 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1582 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1583 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1584 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1585 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1586 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1587 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1588 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
1589 };\r
1590 static const int HighTone[] = {\r
1591 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1592 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1593 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1594 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1595 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1596 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1597 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1598 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1599 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1600 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1601 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1602 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1603 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1604 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1605 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
1606 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1607 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1608 1, 1, 1, 1, 1, 1, 1,\r
1609 };\r
6658905f 1610\r
1611 int convLen = max(arraylen(HighTone), arraylen(LowTone));\r
0c2ed92d 1612 WORD crc;\r
1613 int i, TagType;\r
6658905f 1614 for(i = 0; i < GraphTraceLen - convLen; i++) {\r
1615 int j;\r
1616 int lowSum = 0, highSum = 0;;\r
1617 int lowLen = arraylen(LowTone);\r
1618 int highLen = arraylen(HighTone);\r
1619\r
1620 for(j = 0; j < lowLen; j++) {\r
1621 lowSum += LowTone[j]*GraphBuffer[i+j];\r
1622 }\r
1623 for(j = 0; j < highLen; j++) {\r
1624 highSum += HighTone[j]*GraphBuffer[i+j];\r
1625 }\r
1626 lowSum = abs((100*lowSum) / lowLen);\r
1627 highSum = abs((100*highSum) / highLen);\r
1628 GraphBuffer[i] = (highSum << 16) | lowSum;\r
1629 }\r
1630\r
1631 for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
1632 int j;\r
1633 int lowTot = 0, highTot = 0;\r
1634 // 16 and 15 are f_s divided by f_l and f_h, rounded\r
1635 for(j = 0; j < 16; j++) {\r
1636 lowTot += (GraphBuffer[i+j] & 0xffff);\r
1637 }\r
1638 for(j = 0; j < 15; j++) {\r
1639 highTot += (GraphBuffer[i+j] >> 16);\r
1640 }\r
1641 GraphBuffer[i] = lowTot - highTot;\r
1642 }\r
1643\r
1644 GraphTraceLen -= (convLen + 16);\r
1645\r
1646 RepaintGraphWindow();\r
1647\r
0c2ed92d 1648 // TI tag data format is 16 prebits, 8 start bits, 64 data bits,\r
1649 // 16 crc CCITT bits, 8 stop bits, 15 end bits\r
1650\r
1651 // the 16 prebits are always low\r
1652 // the 8 start and stop bits of a tag must match\r
1653 // the start/stop prebits of a ro tag are 01111110\r
1654 // the start/stop prebits of a rw tag are 11111110\r
1655 // the 15 end bits of a ro tag are all low\r
1656 // the 15 end bits of a rw tag match bits 15-1 of the data bits\r
6658905f 1657\r
0c2ed92d 1658 // Okay, so now we have unsliced soft decisions;\r
1659 // find bit-sync, and then get some bits.\r
1660 // look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)\r
6658905f 1661 int max = 0, maxPos = 0;\r
1662 for(i = 0; i < 6000; i++) {\r
1663 int j;\r
1664 int dec = 0;\r
0c2ed92d 1665 // searching 17 consecutive lows\r
1666 for(j = 0; j < 17*arraylen(LowTone); j++) {\r
6658905f 1667 dec -= GraphBuffer[i+j];\r
1668 }\r
0c2ed92d 1669 // searching 7 consecutive highs\r
1670 for(; j < 17*arraylen(LowTone) + 6*arraylen(HighTone); j++) {\r
6658905f 1671 dec += GraphBuffer[i+j];\r
1672 }\r
1673 if(dec > max) {\r
1674 max = dec;\r
1675 maxPos = i;\r
1676 }\r
1677 }\r
6658905f 1678\r
0c2ed92d 1679 // place a marker in the buffer to visually aid location\r
1680 // of the start of sync\r
6658905f 1681 GraphBuffer[maxPos] = 800;\r
1682 GraphBuffer[maxPos+1] = -800;\r
6658905f 1683\r
0c2ed92d 1684 // advance pointer to start of actual data stream (after 16 pre and 8 start bits)\r
1685 maxPos += 17*arraylen(LowTone);\r
1686 maxPos += 6*arraylen(HighTone);\r
1687\r
1688 // place a marker in the buffer to visually aid location\r
1689 // of the end of sync\r
6658905f 1690 GraphBuffer[maxPos] = 800;\r
1691 GraphBuffer[maxPos+1] = -800;\r
1692\r
1693 PrintToScrollback("actual data bits start at sample %d", maxPos);\r
1694\r
1695 PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));\r
1696\r
0c2ed92d 1697 BYTE bits[1+64+16+8+16];\r
6658905f 1698 bits[sizeof(bits)-1] = '\0';\r
1699\r
0c2ed92d 1700 DWORD shift3 = 0x7e000000, shift2 = 0, shift1 = 0, shift0 = 0;\r
1701\r
1702 for(i = 0; i < arraylen(bits)-1; i++) {\r
6658905f 1703 int high = 0;\r
1704 int low = 0;\r
1705 int j;\r
1706 for(j = 0; j < arraylen(LowTone); j++) {\r
1707 low -= GraphBuffer[maxPos+j];\r
1708 }\r
1709 for(j = 0; j < arraylen(HighTone); j++) {\r
1710 high += GraphBuffer[maxPos+j];\r
1711 }\r
0c2ed92d 1712\r
6658905f 1713 if(high > low) {\r
1714 bits[i] = '1';\r
1715 maxPos += arraylen(HighTone);\r
0c2ed92d 1716 // bitstream arrives lsb first so shift right\r
1717 shift3 |= (1<<31);\r
6658905f 1718 } else {\r
1719 bits[i] = '.';\r
1720 maxPos += arraylen(LowTone);\r
1721 }\r
0c2ed92d 1722\r
1723 // 128 bit right shift register\r
1724 shift0 = (shift0>>1) | (shift1 << 31);\r
1725 shift1 = (shift1>>1) | (shift2 << 31);\r
1726 shift2 = (shift2>>1) | (shift3 << 31);\r
1727 shift3 >>= 1;\r
1728\r
1729 // place a marker in the buffer between bits to visually aid location\r
6658905f 1730 GraphBuffer[maxPos] = 800;\r
1731 GraphBuffer[maxPos+1] = -800;\r
1732 }\r
0c2ed92d 1733 PrintToScrollback("Info: raw tag bits = %s", bits);\r
6658905f 1734\r
0c2ed92d 1735 TagType = (shift3>>8)&0xff;\r
1736 if ( TagType != ((shift0>>16)&0xff) ) {\r
1737 PrintToScrollback("Error: start and stop bits do not match!");\r
1738 return;\r
1739 }\r
1740 else if (TagType == 0x7e) {\r
1741 PrintToScrollback("Info: Readonly TI tag detected.");\r
1742 return;\r
6658905f 1743 }\r
0c2ed92d 1744 else if (TagType == 0xfe) {\r
1745 PrintToScrollback("Info: Rewriteable TI tag detected.");\r
1746\r
1747 // put 64 bit data into shift1 and shift0\r
1748 shift0 = (shift0>>24) | (shift1 << 8);\r
1749 shift1 = (shift1>>24) | (shift2 << 8);\r
1750\r
1751 // align 16 bit crc into lower half of shift2\r
1752 shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;\r
1753\r
1754 // align 16 bit "end bits" or "ident" into lower half of shift3\r
1755 shift3 >>= 16;\r
1756\r
1757 if ( (shift3^shift0)&0xffff ) {\r
1758 PrintToScrollback("Error: Ident mismatch!");\r
1759 }\r
1760 // calculate CRC\r
1761 crc=0;\r
1762 crc = update_crc16(crc, (shift0)&0xff);\r
1763 crc = update_crc16(crc, (shift0>>8)&0xff);\r
1764 crc = update_crc16(crc, (shift0>>16)&0xff);\r
1765 crc = update_crc16(crc, (shift0>>24)&0xff);\r
1766 crc = update_crc16(crc, (shift1)&0xff);\r
1767 crc = update_crc16(crc, (shift1>>8)&0xff);\r
1768 crc = update_crc16(crc, (shift1>>16)&0xff);\r
1769 crc = update_crc16(crc, (shift1>>24)&0xff);\r
1770 PrintToScrollback("Info: Tag data = %08X%08X", shift1, shift0);\r
1771 if (crc != (shift2&0xffff)) {\r
1772 PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc, shift2&0xffff);\r
1773 } else {\r
1774 PrintToScrollback("Info: CRC %04X is good", crc);\r
6658905f 1775 }\r
1776 }\r
0c2ed92d 1777 else {\r
1778 PrintToScrollback("Unknown tag type.");\r
1779 return;\r
1780 }\r
6658905f 1781}\r
1782\r
1783static void CmdNorm(char *str)\r
1784{\r
1785 int i;\r
1786 int max = INT_MIN, min = INT_MAX;\r
1787 for(i = 10; i < GraphTraceLen; i++) {\r
1788 if(GraphBuffer[i] > max) {\r
1789 max = GraphBuffer[i];\r
1790 }\r
1791 if(GraphBuffer[i] < min) {\r
1792 min = GraphBuffer[i];\r
1793 }\r
1794 }\r
1795 if(max != min) {\r
1796 for(i = 0; i < GraphTraceLen; i++) {\r
1797 GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/\r
1798 (max - min);\r
1799 }\r
1800 }\r
1801 RepaintGraphWindow();\r
1802}\r
1803\r
1804static void CmdDec(char *str)\r
1805{\r
1806 int i;\r
1807 for(i = 0; i < (GraphTraceLen/2); i++) {\r
1808 GraphBuffer[i] = GraphBuffer[i*2];\r
1809 }\r
1810 GraphTraceLen /= 2;\r
1811 PrintToScrollback("decimated by 2");\r
1812 RepaintGraphWindow();\r
1813}\r
1814\r
1815static void CmdHpf(char *str)\r
1816{\r
1817 int i;\r
1818 int accum = 0;\r
1819 for(i = 10; i < GraphTraceLen; i++) {\r
1820 accum += GraphBuffer[i];\r
1821 }\r
1822 accum /= (GraphTraceLen - 10);\r
1823 for(i = 0; i < GraphTraceLen; i++) {\r
1824 GraphBuffer[i] -= accum;\r
1825 }\r
1826\r
1827 RepaintGraphWindow();\r
1828}\r
1829\r
1830static void CmdZerocrossings(char *str)\r
1831{\r
1832 int i;\r
1833 // Zero-crossings aren't meaningful unless the signal is zero-mean.\r
1834 CmdHpf("");\r
1835\r
1836 int sign = 1;\r
1837 int zc = 0;\r
1838 int lastZc = 0;\r
1839 for(i = 0; i < GraphTraceLen; i++) {\r
1840 if(GraphBuffer[i]*sign >= 0) {\r
1841 // No change in sign, reproduce the previous sample count.\r
1842 zc++;\r
1843 GraphBuffer[i] = lastZc;\r
1844 } else {\r
1845 // Change in sign, reset the sample count.\r
1846 sign = -sign;\r
1847 GraphBuffer[i] = lastZc;\r
1848 if(sign > 0) {\r
1849 lastZc = zc;\r
1850 zc = 0;\r
1851 }\r
1852 }\r
1853 }\r
1854\r
1855 RepaintGraphWindow();\r
1856}\r
1857\r
67853904 1858static void CmdThreshold(char *str)\r
1859{\r
1860 int i;\r
1861 int threshold = atoi(str);\r
1862\r
1863 for(i = 0; i < GraphTraceLen; i++) {\r
1864 if(GraphBuffer[i]>= threshold)\r
bd4cc2c9 1865 GraphBuffer[i]=1;\r
67853904 1866 else\r
bd4cc2c9 1867 GraphBuffer[i]=-1;\r
67853904 1868 }\r
1869 RepaintGraphWindow();\r
1870}\r
1871\r
6658905f 1872static void CmdLtrim(char *str)\r
1873{\r
1874 int i;\r
1875 int ds = atoi(str);\r
1876\r
1877 for(i = ds; i < GraphTraceLen; i++) {\r
1878 GraphBuffer[i-ds] = GraphBuffer[i];\r
1879 }\r
1880 GraphTraceLen -= ds;\r
1881\r
1882 RepaintGraphWindow();\r
1883}\r
1884\r
1885static void CmdAutoCorr(char *str)\r
1886{\r
1887 static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];\r
1888\r
1889 int window = atoi(str);\r
1890\r
1891 if(window == 0) {\r
1892 PrintToScrollback("needs a window");\r
1893 return;\r
1894 }\r
1895\r
1896 if(window >= GraphTraceLen) {\r
1897 PrintToScrollback("window must be smaller than trace (%d samples)",\r
1898 GraphTraceLen);\r
1899 return;\r
1900 }\r
1901\r
1902 PrintToScrollback("performing %d correlations", GraphTraceLen - window);\r
1903\r
1904 int i;\r
1905 for(i = 0; i < GraphTraceLen - window; i++) {\r
1906 int sum = 0;\r
1907 int j;\r
1908 for(j = 0; j < window; j++) {\r
1909 sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;\r
1910 }\r
1911 CorrelBuffer[i] = sum;\r
1912 }\r
1913 GraphTraceLen = GraphTraceLen - window;\r
1914 memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));\r
1915\r
1916 RepaintGraphWindow();\r
1917}\r
1918\r
1919static void CmdVchdemod(char *str)\r
1920{\r
1921 // Is this the entire sync pattern, or does this also include some\r
1922 // data bits that happen to be the same everywhere? That would be\r
1923 // lovely to know.\r
1924 static const int SyncPattern[] = {\r
1925 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1926 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1927 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1928 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1929 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1930 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1931 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1932 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1933 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
1934 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
1935 };\r
1936\r
1937 // So first, we correlate for the sync pattern, and mark that.\r
1938 int bestCorrel = 0, bestPos = 0;\r
1939 int i;\r
1940 // It does us no good to find the sync pattern, with fewer than\r
1941 // 2048 samples after it...\r
1942 for(i = 0; i < (GraphTraceLen-2048); i++) {\r
1943 int sum = 0;\r
1944 int j;\r
1945 for(j = 0; j < arraylen(SyncPattern); j++) {\r
1946 sum += GraphBuffer[i+j]*SyncPattern[j];\r
1947 }\r
1948 if(sum > bestCorrel) {\r
1949 bestCorrel = sum;\r
1950 bestPos = i;\r
1951 }\r
1952 }\r
1953 PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);\r
1954\r
1955 char bits[257];\r
1956 bits[256] = '\0';\r
1957\r
1958 int worst = INT_MAX;\r
1959 int worstPos;\r
1960\r
1961 for(i = 0; i < 2048; i += 8) {\r
1962 int sum = 0;\r
1963 int j;\r
1964 for(j = 0; j < 8; j++) {\r
1965 sum += GraphBuffer[bestPos+i+j];\r
1966 }\r
1967 if(sum < 0) {\r
1968 bits[i/8] = '.';\r
1969 } else {\r
1970 bits[i/8] = '1';\r
1971 }\r
1972 if(abs(sum) < worst) {\r
1973 worst = abs(sum);\r
1974 worstPos = i;\r
1975 }\r
1976 }\r
1977 PrintToScrollback("bits:");\r
1978 PrintToScrollback("%s", bits);\r
1979 PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);\r
1980\r
1981 if(strcmp(str, "clone")==0) {\r
1982 GraphTraceLen = 0;\r
1983 char *s;\r
1984 for(s = bits; *s; s++) {\r
1985 int j;\r
1986 for(j = 0; j < 16; j++) {\r
1987 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;\r
1988 }\r
1989 }\r
1990 RepaintGraphWindow();\r
1991 }\r
1992}\r
1993\r
a60612db 1994static void CmdIndalademod(char *str)\r
1995{\r
1996 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID\r
1997\r
1998 int state = -1;\r
1999 int count = 0;\r
2000 int i, j;\r
2001 // worst case with GraphTraceLen=64000 is < 4096\r
2002 // under normal conditions it's < 2048\r
2003 BYTE rawbits[4096];\r
2004 int rawbit = 0;\r
2005 int worst = 0, worstPos = 0;\r
2006 PrintToScrollback("Expecting a bit less than %d raw bits", GraphTraceLen/32);\r
2007 for(i = 0; i < GraphTraceLen-1; i += 2) {\r
2008 count+=1;\r
2009 if((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {\r
2010 if (state == 0) {\r
2011 for(j = 0; j < count - 8; j += 16) {\r
2012 rawbits[rawbit++] = 0;\r
2013 }\r
2014 if ((abs(count - j)) > worst) {\r
2015 worst = abs(count - j);\r
2016 worstPos = i;\r
2017 }\r
2018 }\r
2019 state = 1;\r
2020 count=0;\r
2021 } else if((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {\r
2022 if (state == 1) {\r
2023 for(j = 0; j < count - 8; j += 16) {\r
2024 rawbits[rawbit++] = 1;\r
2025 }\r
2026 if ((abs(count - j)) > worst) {\r
2027 worst = abs(count - j);\r
2028 worstPos = i;\r
2029 }\r
2030 }\r
2031 state = 0;\r
2032 count=0;\r
2033 }\r
2034 }\r
2035 PrintToScrollback("Recovered %d raw bits", rawbit);\r
2036 PrintToScrollback("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);\r
2037\r
2038 // Finding the start of a UID\r
2039 int uidlen, long_wait;\r
2040 if(strcmp(str, "224") == 0) {\r
2041 uidlen=224;\r
2042 long_wait=30;\r
2043 } else {\r
2044 uidlen=64;\r
2045 long_wait=29;\r
2046 }\r
2047 int start;\r
2048 int first = 0;\r
2049 for(start = 0; start <= rawbit - uidlen; start++) {\r
2050 first = rawbits[start];\r
2051 for(i = start; i < start + long_wait; i++) {\r
2052 if(rawbits[i] != first) {\r
2053 break;\r
2054 }\r
2055 }\r
2056 if(i == (start + long_wait)) {\r
2057 break;\r
2058 }\r
2059 }\r
2060 if(start == rawbit - uidlen + 1) {\r
2061 PrintToScrollback("nothing to wait for");\r
2062 return;\r
2063 }\r
2064\r
2065 // Inverting signal if needed\r
2066 if(first == 1) {\r
2067 for(i = start; i < rawbit; i++) {\r
2068 rawbits[i] = !rawbits[i];\r
2069 }\r
2070 }\r
2071\r
2072 // Dumping UID\r
2073 BYTE bits[224];\r
2074 char showbits[225];\r
2075 showbits[uidlen]='\0';\r
2076 int bit;\r
2077 i = start;\r
2078 int times = 0;\r
2079 if(uidlen > rawbit) {\r
2080 PrintToScrollback("Warning: not enough raw bits to get a full UID");\r
2081 for(bit = 0; bit < rawbit; bit++) {\r
2082 bits[bit] = rawbits[i++];\r
2083 // As we cannot know the parity, let's use "." and "/"\r
2084 showbits[bit] = '.' + bits[bit];\r
2085 }\r
2086 showbits[bit+1]='\0';\r
2087 PrintToScrollback("Partial UID=%s", showbits);\r
2088 return;\r
2089 } else {\r
2090 for(bit = 0; bit < uidlen; bit++) {\r
2091 bits[bit] = rawbits[i++];\r
2092 showbits[bit] = '0' + bits[bit];\r
2093 }\r
2094 times = 1;\r
2095 }\r
2096 PrintToScrollback("UID=%s", showbits);\r
2097\r
2098 // Checking UID against next occurences\r
2099 for(; i + uidlen <= rawbit;) {\r
2100 int failed = 0;\r
2101 for(bit = 0; bit < uidlen; bit++) {\r
2102 if(bits[bit] != rawbits[i++]) {\r
2103 failed = 1;\r
2104 break;\r
2105 }\r
2106 }\r
2107 if (failed == 1) {\r
2108 break;\r
2109 }\r
2110 times += 1;\r
2111 }\r
2112 PrintToScrollback("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);\r
2113\r
2114 // Remodulating for tag cloning\r
2115 GraphTraceLen = 32*uidlen;\r
2116 i = 0;\r
2117 int phase = 0;\r
2118 for(bit = 0; bit < uidlen; bit++) {\r
2119 if(bits[bit] == 0) {\r
2120 phase = 0;\r
2121 } else {\r
2122 phase = 1;\r
2123 }\r
2124 int j;\r
2125 for(j = 0; j < 32; j++) {\r
2126 GraphBuffer[i++] = phase;\r
2127 phase = !phase;\r
2128 }\r
2129 }\r
2130\r
2131 RepaintGraphWindow();\r
2132}\r
2133\r
6658905f 2134static void CmdFlexdemod(char *str)\r
2135{\r
2136 int i;\r
2137 for(i = 0; i < GraphTraceLen; i++) {\r
2138 if(GraphBuffer[i] < 0) {\r
2139 GraphBuffer[i] = -1;\r
2140 } else {\r
2141 GraphBuffer[i] = 1;\r
2142 }\r
2143 }\r
2144\r
2145#define LONG_WAIT 100\r
2146 int start;\r
2147 for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {\r
2148 int first = GraphBuffer[start];\r
2149 for(i = start; i < start + LONG_WAIT; i++) {\r
2150 if(GraphBuffer[i] != first) {\r
2151 break;\r
2152 }\r
2153 }\r
2154 if(i == (start + LONG_WAIT)) {\r
2155 break;\r
2156 }\r
2157 }\r
2158 if(start == GraphTraceLen - LONG_WAIT) {\r
2159 PrintToScrollback("nothing to wait for");\r
2160 return;\r
2161 }\r
2162\r
2163 GraphBuffer[start] = 2;\r
2164 GraphBuffer[start+1] = -2;\r
2165\r
2166 BYTE bits[64];\r
2167\r
2168 int bit;\r
2169 i = start;\r
2170 for(bit = 0; bit < 64; bit++) {\r
2171 int j;\r
2172 int sum = 0;\r
2173 for(j = 0; j < 16; j++) {\r
2174 sum += GraphBuffer[i++];\r
2175 }\r
2176 if(sum > 0) {\r
2177 bits[bit] = 1;\r
2178 } else {\r
2179 bits[bit] = 0;\r
2180 }\r
2181 PrintToScrollback("bit %d sum %d", bit, sum);\r
2182 }\r
2183\r
2184 for(bit = 0; bit < 64; bit++) {\r
2185 int j;\r
2186 int sum = 0;\r
2187 for(j = 0; j < 16; j++) {\r
2188 sum += GraphBuffer[i++];\r
2189 }\r
2190 if(sum > 0 && bits[bit] != 1) {\r
2191 PrintToScrollback("oops1 at %d", bit);\r
2192 }\r
2193 if(sum < 0 && bits[bit] != 0) {\r
2194 PrintToScrollback("oops2 at %d", bit);\r
2195 }\r
2196 }\r
2197\r
2198 GraphTraceLen = 32*64;\r
2199 i = 0;\r
2200 int phase = 0;\r
2201 for(bit = 0; bit < 64; bit++) {\r
2202 if(bits[bit] == 0) {\r
2203 phase = 0;\r
2204 } else {\r
2205 phase = 1;\r
2206 }\r
2207 int j;\r
2208 for(j = 0; j < 32; j++) {\r
2209 GraphBuffer[i++] = phase;\r
2210 phase = !phase;\r
2211 }\r
2212 }\r
2213\r
2214 RepaintGraphWindow();\r
2215}\r
9760414b 2216\r
2217/*\r
15db5fb7 2218 * Generic command to demodulate ASK.\r
9760414b 2219 *\r
15db5fb7 2220 * Argument is convention: positive or negative (High mod means zero\r
9760414b 2221 * or high mod means one)\r
2222 *\r
2223 * Updates the Graph trace with 0/1 values\r
2224 *\r
2225 * Arguments:\r
9760414b 2226 * c : 0 or 1\r
2227 */\r
2228\r
2229static void Cmdaskdemod(char *str) {\r
2230 int i;\r
8172fb35 2231 int c, high = 0, low = 0;\r
9760414b 2232\r
2233 // TODO: complain if we do not give 2 arguments here !\r
15db5fb7 2234 sscanf(str, "%i", &c);\r
2235\r
2236 /* Detect high and lows and clock */\r
2237 for (i = 0; i < GraphTraceLen; i++)\r
2238 {\r
2239 if (GraphBuffer[i] > high)\r
2240 high = GraphBuffer[i];\r
2241 else if (GraphBuffer[i] < low)\r
2242 low = GraphBuffer[i];\r
9760414b 2243 }\r
2244\r
15db5fb7 2245 if (GraphBuffer[0] > 0) {\r
2246 GraphBuffer[0] = 1-c;\r
9760414b 2247 } else {\r
15db5fb7 2248 GraphBuffer[0] = c;\r
9760414b 2249 }\r
2250 for(i=1;i<GraphTraceLen;i++) {\r
15db5fb7 2251 /* Transitions are detected at each peak\r
2252 * Transitions are either:\r
2253 * - we're low: transition if we hit a high\r
2254 * - we're high: transition if we hit a low\r
2255 * (we need to do it this way because some tags keep high or\r
2256 * low for long periods, others just reach the peak and go\r
a91ff4c8 2257 * down)\r
15db5fb7 2258 */\r
2259 if ((GraphBuffer[i]==high) && (GraphBuffer[i-1] == c)) {\r
2260 GraphBuffer[i]=1-c;\r
2261 } else if ((GraphBuffer[i]==low) && (GraphBuffer[i-1] == (1-c))){\r
2262 GraphBuffer[i] = c;\r
9760414b 2263 } else {\r
15db5fb7 2264 /* No transition */\r
9760414b 2265 GraphBuffer[i] = GraphBuffer[i-1];\r
2266 }\r
2267 }\r
2268 RepaintGraphWindow();\r
2269}\r
2270\r
2271/* Print our clock rate */\r
2272static void Cmddetectclockrate(char *str)\r
2273{\r
2274 int clock = detectclock(0);\r
2275 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2276}\r
2277\r
2278/*\r
2279 * Detect clock rate\r
2280 */\r
2281int detectclock(int peak)\r
2282{\r
2283 int i;\r
2284 int clock = 0xFFFF;\r
2285 int lastpeak = 0;\r
2286\r
2287 /* Detect peak if we don't have one */\r
2288 if (!peak)\r
2289 for (i = 0; i < GraphTraceLen; i++)\r
2290 if (GraphBuffer[i] > peak)\r
2291 peak = GraphBuffer[i];\r
2292\r
2293 for (i = 1; i < GraphTraceLen; i++)\r
2294 {\r
2295 /* If this is the beginning of a peak */\r
2296 if (GraphBuffer[i-1] != GraphBuffer[i] && GraphBuffer[i] == peak)\r
2297 {\r
2298 /* Find lowest difference between peaks */\r
2299 if (lastpeak && i - lastpeak < clock)\r
2300 {\r
2301 clock = i - lastpeak;\r
2302 }\r
2303 lastpeak = i;\r
2304 }\r
2305 }\r
15db5fb7 2306\r
9760414b 2307 return clock;\r
2308}\r
2309\r
2310/* Get or auto-detect clock rate */\r
2311int GetClock(char *str, int peak)\r
2312{\r
2313 int clock;\r
15db5fb7 2314\r
9760414b 2315 sscanf(str, "%i", &clock);\r
2316 if (!strcmp(str, ""))\r
2317 clock = 0;\r
2318\r
2319 /* Auto-detect clock */\r
2320 if (!clock)\r
2321 {\r
2322 clock = detectclock(peak);\r
15db5fb7 2323\r
9760414b 2324 /* Only print this message if we're not looping something */\r
2325 if (!go)\r
2326 PrintToScrollback("Auto-detected clock rate: %d", clock);\r
2327 }\r
15db5fb7 2328\r
9760414b 2329 return clock;\r
2330}\r
2331\r
2332/*\r
2333 * Convert to a bitstream\r
2334 */\r
2335static void Cmdbitstream(char *str) {\r
c9f99c01 2336 int i, j;\r
2337 int bit;\r
9760414b 2338 int gtl;\r
2339 int clock;\r
c9f99c01 2340 int low = 0;\r
2341 int high = 0;\r
2342 int hithigh, hitlow, first;\r
9760414b 2343\r
2344 /* Detect high and lows and clock */\r
2345 for (i = 0; i < GraphTraceLen; i++)\r
c9f99c01 2346 {\r
9760414b 2347 if (GraphBuffer[i] > high)\r
2348 high = GraphBuffer[i];\r
2349 else if (GraphBuffer[i] < low)\r
2350 low = GraphBuffer[i];\r
c9f99c01 2351 }\r
9760414b 2352\r
2353 /* Get our clock */\r
2354 clock = GetClock(str, high);\r
15db5fb7 2355\r
9760414b 2356 gtl = CmdClearGraph(0);\r
15db5fb7 2357\r
9760414b 2358 bit = 0;\r
2359 for (i = 0; i < (int)(gtl / clock); i++)\r
2360 {\r
2361 hithigh = 0;\r
2362 hitlow = 0;\r
2363 first = 1;\r
15db5fb7 2364\r
9760414b 2365 /* Find out if we hit both high and low peaks */\r
2366 for (j = 0; j < clock; j++)\r
2367 {\r
2368 if (GraphBuffer[(i * clock) + j] == high)\r
2369 hithigh = 1;\r
2370 else if (GraphBuffer[(i * clock) + j] == low)\r
2371 hitlow = 1;\r
15db5fb7 2372\r
9760414b 2373 /* it doesn't count if it's the first part of our read\r
2374 because it's really just trailing from the last sequence */\r
2375 if (first && (hithigh || hitlow))\r
2376 hithigh = hitlow = 0;\r
2377 else\r
2378 first = 0;\r
15db5fb7 2379\r
9760414b 2380 if (hithigh && hitlow)\r
2381 break;\r
2382 }\r
15db5fb7 2383\r
9760414b 2384 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2385 if (!hithigh || !hitlow)\r
2386 bit ^= 1;\r
2387\r
2388 CmdAppendGraph(0, clock, bit);\r
2389// for (j = 0; j < (int)(clock/2); j++)\r
2390// GraphBuffer[(i * clock) + j] = bit ^ 1;\r
2391// for (j = (int)(clock/2); j < clock; j++)\r
2392// GraphBuffer[(i * clock) + j] = bit;\r
2393 }\r
2394\r
2395 RepaintGraphWindow();\r
2396}\r
2397\r
2398/* Modulate our data into manchester */\r
2399static void Cmdmanchestermod(char *str)\r
2400{\r
2401 int i, j;\r
2402 int clock;\r
2403 int bit, lastbit, wave;\r
15db5fb7 2404\r
9760414b 2405 /* Get our clock */\r
2406 clock = GetClock(str, 0);\r
2407\r
2408 wave = 0;\r
2409 lastbit = 1;\r
2410 for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
2411 {\r
2412 bit = GraphBuffer[i * clock] ^ 1;\r
15db5fb7 2413\r
9760414b 2414 for (j = 0; j < (int)(clock/2); j++)\r
2415 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave;\r
2416 for (j = (int)(clock/2); j < clock; j++)\r
2417 GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1;\r
15db5fb7 2418\r
9760414b 2419 /* Keep track of how we start our wave and if we changed or not this time */\r
2420 wave ^= bit ^ lastbit;\r
2421 lastbit = bit;\r
2422 }\r
15db5fb7 2423\r
9760414b 2424 RepaintGraphWindow();\r
2425}\r
2426\r
2427/*\r
2428 * Manchester demodulate a bitstream. The bitstream needs to be already in\r
2429 * the GraphBuffer as 0 and 1 values\r
2430 *\r
2431 * Give the clock rate as argument in order to help the sync - the algorithm\r
2432 * resyncs at each pulse anyway.\r
2433 *\r
2434 * Not optimized by any means, this is the 1st time I'm writing this type of\r
2435 * routine, feel free to improve...\r
2436 *\r
2437 * 1st argument: clock rate (as number of samples per clock rate)\r
2438 * Typical values can be 64, 32, 128...\r
2439 */\r
2440static void Cmdmanchesterdemod(char *str) {\r
736aea60 2441 int i, j, invert= 0;\r
9760414b 2442 int bit;\r
2443 int clock;\r
2444 int lastval;\r
2445 int low = 0;\r
2446 int high = 0;\r
2447 int hithigh, hitlow, first;\r
2448 int lc = 0;\r
2449 int bitidx = 0;\r
2450 int bit2idx = 0;\r
2451 int warnings = 0;\r
2452\r
736aea60 2453 /* check if we're inverting output */\r
2454 if(*str == 'i')\r
2455 {\r
2456 PrintToScrollback("Inverting output");\r
2457 invert= 1;\r
2458 do\r
2459 ++str;\r
2460 while(*str == ' '); // in case a 2nd argument was given\r
2461 }\r
2462\r
9760414b 2463 /* Holds the decoded bitstream: each clock period contains 2 bits */\r
2464 /* later simplified to 1 bit after manchester decoding. */\r
2465 /* Add 10 bits to allow for noisy / uncertain traces without aborting */\r
2466 /* int BitStream[GraphTraceLen*2/clock+10]; */\r
2467\r
2468 /* But it does not work if compiling on WIndows: therefore we just allocate a */\r
2469 /* large array */\r
2470 int BitStream[MAX_GRAPH_TRACE_LEN];\r
2471\r
c9f99c01 2472 /* Detect high and lows */\r
2473 for (i = 0; i < GraphTraceLen; i++)\r
2474 {\r
2475 if (GraphBuffer[i] > high)\r
2476 high = GraphBuffer[i];\r
2477 else if (GraphBuffer[i] < low)\r
2478 low = GraphBuffer[i];\r
2479 }\r
2480\r
9760414b 2481 /* Get our clock */\r
2482 clock = GetClock(str, high);\r
15db5fb7 2483\r
9760414b 2484 int tolerance = clock/4;\r
15db5fb7 2485\r
9760414b 2486 /* Detect first transition */\r
2487 /* Lo-Hi (arbitrary) */\r
c9f99c01 2488 for (i = 0; i < GraphTraceLen; i++)\r
2489 {\r
2490 if (GraphBuffer[i] == low)\r
2491 {\r
9760414b 2492 lastval = i;\r
2493 break;\r
2494 }\r
2495 }\r
c9f99c01 2496\r
2497 /* If we're not working with 1/0s, demod based off clock */\r
2498 if (high != 1)\r
2499 {\r
15db5fb7 2500 bit = 0; /* We assume the 1st bit is zero, it may not be\r
2501 * the case: this routine (I think) has an init problem.\r
2502 * Ed.\r
2503 */\r
2504 for (; i < (int)(GraphTraceLen / clock); i++)\r
c9f99c01 2505 {\r
2506 hithigh = 0;\r
2507 hitlow = 0;\r
2508 first = 1;\r
2509\r
2510 /* Find out if we hit both high and low peaks */\r
2511 for (j = 0; j < clock; j++)\r
2512 {\r
2513 if (GraphBuffer[(i * clock) + j] == high)\r
2514 hithigh = 1;\r
2515 else if (GraphBuffer[(i * clock) + j] == low)\r
2516 hitlow = 1;\r
2517\r
2518 /* it doesn't count if it's the first part of our read\r
2519 because it's really just trailing from the last sequence */\r
2520 if (first && (hithigh || hitlow))\r
2521 hithigh = hitlow = 0;\r
2522 else\r
2523 first = 0;\r
2524\r
2525 if (hithigh && hitlow)\r
2526 break;\r
2527 }\r
2528\r
2529 /* If we didn't hit both high and low peaks, we had a bit transition */\r
2530 if (!hithigh || !hitlow)\r
2531 bit ^= 1;\r
2532\r
736aea60 2533 BitStream[bit2idx++] = bit ^ invert;\r
c9f99c01 2534 }\r
2535 }\r
2536\r
2537 /* standard 1/0 bitstream */\r
2538 else\r
2539 {\r
9760414b 2540\r
736aea60 2541 /* Then detect duration between 2 successive transitions */\r
c9f99c01 2542 for (bitidx = 1; i < GraphTraceLen; i++)\r
2543 {\r
2544 if (GraphBuffer[i-1] != GraphBuffer[i])\r
2545 {\r
9760414b 2546 lc = i-lastval;\r
2547 lastval = i;\r
2548\r
2549 // Error check: if bitidx becomes too large, we do not\r
2550 // have a Manchester encoded bitstream or the clock is really\r
2551 // wrong!\r
2552 if (bitidx > (GraphTraceLen*2/clock+8) ) {\r
2553 PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");\r
2554 return;\r
2555 }\r
2556 // Then switch depending on lc length:\r
2557 // Tolerance is 1/4 of clock rate (arbitrary)\r
2558 if (abs(lc-clock/2) < tolerance) {\r
2559 // Short pulse : either "1" or "0"\r
2560 BitStream[bitidx++]=GraphBuffer[i-1];\r
2561 } else if (abs(lc-clock) < tolerance) {\r
2562 // Long pulse: either "11" or "00"\r
2563 BitStream[bitidx++]=GraphBuffer[i-1];\r
2564 BitStream[bitidx++]=GraphBuffer[i-1];\r
2565 } else {\r
2566 // Error\r
c9f99c01 2567 warnings++;\r
9760414b 2568 PrintToScrollback("Warning: Manchester decode error for pulse width detection.");\r
2569 PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");\r
c9f99c01 2570\r
2571 if (warnings > 100)\r
2572 {\r
2573 PrintToScrollback("Error: too many detection errors, aborting.");\r
2574 return;\r
2575 }\r
736aea60 2576 }\r
9760414b 2577 }\r
2578 }\r
9760414b 2579\r
736aea60 2580 // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream\r
2581 // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful\r
2582 // to stop output at the final bitidx2 value, not bitidx\r
2583 for (i = 0; i < bitidx; i += 2) {\r
2584 if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {\r
2585 BitStream[bit2idx++] = 1 ^ invert;\r
9760414b 2586 } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {\r
736aea60 2587 BitStream[bit2idx++] = 0 ^ invert;\r
9760414b 2588 } else {\r
2589 // We cannot end up in this state, this means we are unsynchronized,\r
2590 // move up 1 bit:\r
2591 i++;\r
c9f99c01 2592 warnings++;\r
9760414b 2593 PrintToScrollback("Unsynchronized, resync...");\r
2594 PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");\r
c9f99c01 2595\r
2596 if (warnings > 100)\r
2597 {\r
2598 PrintToScrollback("Error: too many decode errors, aborting.");\r
2599 return;\r
2600 }\r
736aea60 2601 }\r
67853904 2602 }\r
c9f99c01 2603 }\r
2604\r
2605 PrintToScrollback("Manchester decoded bitstream");\r
9760414b 2606 // Now output the bitstream to the scrollback by line of 16 bits\r
2607 for (i = 0; i < (bit2idx-16); i+=16) {\r
2608 PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",\r
2609 BitStream[i],\r
2610 BitStream[i+1],\r
2611 BitStream[i+2],\r
2612 BitStream[i+3],\r
2613 BitStream[i+4],\r
2614 BitStream[i+5],\r
2615 BitStream[i+6],\r
2616 BitStream[i+7],\r
2617 BitStream[i+8],\r
2618 BitStream[i+9],\r
2619 BitStream[i+10],\r
2620 BitStream[i+11],\r
2621 BitStream[i+12],\r
2622 BitStream[i+13],\r
2623 BitStream[i+14],\r
2624 BitStream[i+15]);\r
2625 }\r
2626}\r
2627\r
9760414b 2628/*\r
2629 * Usage ???\r
6658905f 2630 */\r
2631static void CmdHiddemod(char *str)\r
2632{\r
2633 if(GraphTraceLen < 4800) {\r
2634 PrintToScrollback("too short; need at least 4800 samples");\r
2635 return;\r
2636 }\r
2637\r
2638 GraphTraceLen = 4800;\r
2639 int i;\r
2640 for(i = 0; i < GraphTraceLen; i++) {\r
2641 if(GraphBuffer[i] < 0) {\r
2642 GraphBuffer[i] = 0;\r
2643 } else {\r
2644 GraphBuffer[i] = 1;\r
2645 }\r
2646 }\r
2647 RepaintGraphWindow();\r
2648}\r
2649\r
2650static void CmdPlot(char *str)\r
2651{\r
2652 ShowGraphWindow();\r
2653}\r
2654\r
bd4cc2c9 2655static void CmdGrid(char *str)\r
2656{\r
f4434ad2 2657 sscanf(str, "%i %i", &PlotGridX, &PlotGridY);\r
bd4cc2c9 2658 RepaintGraphWindow();\r
2659}\r
2660\r
6658905f 2661static void CmdHide(char *str)\r
2662{\r
2663 HideGraphWindow();\r
2664}\r
2665\r
2666static void CmdScale(char *str)\r
2667{\r
2668 CursorScaleFactor = atoi(str);\r
2669 if(CursorScaleFactor == 0) {\r
2670 PrintToScrollback("bad, can't have zero scale");\r
2671 CursorScaleFactor = 1;\r
2672 }\r
2673 RepaintGraphWindow();\r
2674}\r
2675\r
2676static void CmdSave(char *str)\r
2677{\r
2678 FILE *f = fopen(str, "w");\r
2679 if(!f) {\r
2680 PrintToScrollback("couldn't open '%s'", str);\r
2681 return;\r
2682 }\r
2683 int i;\r
2684 for(i = 0; i < GraphTraceLen; i++) {\r
2685 fprintf(f, "%d\n", GraphBuffer[i]);\r
2686 }\r
2687 fclose(f);\r
2688 PrintToScrollback("saved to '%s'", str);\r
2689}\r
2690\r
2691static void CmdLoad(char *str)\r
2692{\r
2693 FILE *f = fopen(str, "r");\r
2694 if(!f) {\r
2695 PrintToScrollback("couldn't open '%s'", str);\r
2696 return;\r
2697 }\r
2698\r
2699 GraphTraceLen = 0;\r
2700 char line[80];\r
2701 while(fgets(line, sizeof(line), f)) {\r
2702 GraphBuffer[GraphTraceLen] = atoi(line);\r
2703 GraphTraceLen++;\r
2704 }\r
2705 fclose(f);\r
2706 PrintToScrollback("loaded %d samples", GraphTraceLen);\r
2707 RepaintGraphWindow();\r
2708}\r
2709\r
2710static void CmdHIDsimTAG(char *str)\r
2711{\r
2712 unsigned int hi=0, lo=0;\r
2713 int n=0, i=0;\r
2714 UsbCommand c;\r
2715\r
2716 while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
2717 hi=(hi<<4)|(lo>>28);\r
2718 lo=(lo<<4)|(n&0xf);\r
2719 }\r
2720\r
2721 PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);\r
2722\r
2723 c.cmd = CMD_HID_SIM_TAG;\r
2724 c.ext1 = hi;\r
2725 c.ext2 = lo;\r
2726 SendCommand(&c, FALSE);\r
2727}\r
2728\r
1dff8c42 2729static void CmdReadmem(char *str)\r
2730{\r
2731 UsbCommand c;\r
2732 c.cmd = CMD_READ_MEM;\r
2733 c.ext1 = atoi(str);\r
2734 SendCommand(&c, FALSE);\r
2735}\r
2736\r
6658905f 2737static void CmdLcdReset(char *str)\r
2738{\r
2739 UsbCommand c;\r
2740 c.cmd = CMD_LCD_RESET;\r
2741 c.ext1 = atoi(str);\r
2742 SendCommand(&c, FALSE);\r
2743}\r
2744\r
2745static void CmdLcd(char *str)\r
2746{\r
2747 int i, j;\r
2748 UsbCommand c;\r
2749 c.cmd = CMD_LCD;\r
2750 sscanf(str, "%x %d", &i, &j);\r
2751 while (j--) {\r
2752 c.ext1 = i&0x1ff;\r
2753 SendCommand(&c, FALSE);\r
2754 }\r
2755}\r
2756\r
9760414b 2757/*\r
2758 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below\r
2759 * 600kHz.\r
2760 */\r
30f2a7d3 2761static void CmdSetDivisor(char *str)\r
2762{\r
2763 UsbCommand c;\r
2764 c.cmd = CMD_SET_LF_DIVISOR;\r
2765 c.ext1 = atoi(str);\r
2766 if (( c.ext1<0) || (c.ext1>255)) {\r
2767 PrintToScrollback("divisor must be between 19 and 255");\r
2768 } else {\r
2769 SendCommand(&c, FALSE);\r
2770 PrintToScrollback("Divisor set, expected freq=%dHz", 12000000/(c.ext1+1));\r
2771 }\r
2772}\r
2773\r
6658905f 2774typedef void HandlerFunction(char *cmdline);\r
2775\r
3f030abe 2776/* in alphabetic order */\r
6658905f 2777static struct {\r
fb25b483 2778 char *name;\r
2779 HandlerFunction *handler;\r
2780 int offline; // 1 if the command can be used when in offline mode\r
9760414b 2781 char *docString;\r
6658905f 2782} CommandTable[] = {\r
bd4cc2c9 2783 {"askdemod", Cmdaskdemod, 1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags"},\r
2784 {"autocorr", CmdAutoCorr, 1, "<window length> -- Autocorrelation over window"},\r
2785 {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"},\r
2786 {"bitstream", Cmdbitstream, 1, "[clock rate] -- Convert waveform into a bitstream"},\r
1569d977 2787 {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"},\r
bd4cc2c9 2788 {"dec", CmdDec, 1, "Decimate samples"},\r
2789 {"detectclock", Cmddetectclockrate, 1, "Detect clock rate"},\r
2790 {"detectreader", CmdDetectReader, 0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},\r
2791 {"em410xsim", CmdEM410xsim, 1, "<UID> -- Simulate EM410x tag"},\r
2792 {"em410xread", CmdEM410xread, 1, "[clock rate] -- Extract ID from EM410x tag"},\r
2793 {"em410xwatch", CmdEM410xwatch, 0, "Watches for EM410x tags"},\r
2794 {"em4x50read", CmdEM4x50read, 1, "Extract data from EM4x50 tag"},\r
2795 {"exit", CmdQuit, 1, "Exit program"},\r
2796 {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},\r
2797 {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"},\r
2798 {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"},\r
f4434ad2 2799 {"grid", CmdGrid, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},\r
bd4cc2c9 2800 {"hexsamples", CmdHexsamples, 0, "<blocks> -- Dump big buffer as hex bytes"},\r
2801 {"hi14alist", CmdHi14alist, 0, "List ISO 14443a history"},\r
2802 {"hi14areader", CmdHi14areader, 0, "Act like an ISO14443 Type A reader"},\r
2803 {"hi14asim", CmdHi14asim, 0, "<UID> -- Fake ISO 14443a tag"},\r
2804 {"hi14asnoop", CmdHi14asnoop, 0, "Eavesdrop ISO 14443 Type A"},\r
2805 {"hi14bdemod", CmdHi14bdemod, 1, "Demodulate ISO14443 Type B from tag"},\r
2806 {"hi14list", CmdHi14list, 0, "List ISO 14443 history"},\r
2807 {"hi14read", CmdHi14read, 0, "Read HF tag (ISO 14443)"},\r
2808 {"hi14sim", CmdHi14sim, 0, "Fake ISO 14443 tag"},\r
2809 {"hi14snoop", CmdHi14snoop, 0, "Eavesdrop ISO 14443"},\r
2810 {"hi15demod", CmdHi15demod, 1, "Demodulate ISO15693 from tag"},\r
2811 {"hi15read", CmdHi15read, 0, "Read HF tag (ISO 15693)"},\r
2812 {"hi15reader", CmdHi15reader, 0, "Act like an ISO15693 reader"},\r
2813 {"hi15sim", CmdHi15tag, 0, "Fake an ISO15693 tag"},\r
2814 {"hiddemod", CmdHiddemod, 1, "Demodulate HID Prox Card II (not optimal)"},\r
2815 {"hide", CmdHide, 1, "Hide graph window"},\r
2816 {"hidfskdemod", CmdHIDdemodFSK, 0, "Realtime HID FSK demodulator"},\r
2817 {"hidsimtag", CmdHIDsimTAG, 0, "<ID> -- HID tag simulator"},\r
2818 {"higet", CmdHi14read_sim, 0, "<samples> -- Get samples HF, 'analog'"},\r
2819 {"hisamples", CmdHisamples, 0, "Get raw samples for HF tag"},\r
2820 {"hisampless", CmdHisampless, 0, "<samples> -- Get signed raw samples, HF tag"},\r
2821 {"hisamplest", CmdHi14readt, 0, "Get samples HF, for testing"},\r
2822 {"hisimlisten", CmdHisimlisten, 0, "Get HF samples as fake tag"},\r
2823 {"hpf", CmdHpf, 1, "Remove DC offset from trace"},\r
2824 {"indalademod", CmdIndalademod, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},\r
2825 {"lcd", CmdLcd, 0, "<HEX command> <count> -- Send command/data to LCD"},\r
2826 {"lcdreset", CmdLcdReset, 0, "Hardware reset LCD"},\r
2827 {"load", CmdLoad, 1, "<filename> -- Load trace (to graph window"},\r
2828 {"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
2829 {"loread", CmdLoread, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},\r
2830 {"losamples", CmdLosamples, 0, "[128 - 16000] -- Get raw samples for LF tag"},\r
2831 {"losim", CmdLosim, 0, "Simulate LF tag"},\r
2832 {"ltrim", CmdLtrim, 1, "<samples> -- Trim samples from left of trace"},\r
2833 {"mandemod", Cmdmanchesterdemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},\r
2834 {"manmod", Cmdmanchestermod, 1, "[clock rate] -- Manchester modulate a binary stream"},\r
2835 {"norm", CmdNorm, 1, "Normalize max/min to +/-500"},\r
2836 {"plot", CmdPlot, 1, "Show graph window"},\r
2837 {"quit", CmdQuit, 1, "Quit program"},\r
2838 {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"},\r
2839 {"reset", CmdReset, 0, "Reset the Proxmark3"},\r
2840 {"save", CmdSave, 1, "<filename> -- Save trace (from graph window)"},\r
2841 {"scale", CmdScale, 1, "<int> -- Set cursor display scale"},\r
2842 {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},\r
2843 {"sri512read", CmdSri512read, 0, "<int> -- Read contents of a SRI512 tag"},\r
2844 {"tibits", CmdTibits, 0, "Get raw bits for TI-type LF tag"},\r
2845 {"tidemod", CmdTidemod, 1, "Demodulate raw bits for TI-type LF tag"},\r
2846 {"tiread", CmdTiread, 0, "Read a TI-type 134 kHz tag"},\r
2847 {"threshold", CmdThreshold, 1, "Maximize/minimize every value in the graph window depending on threshold"},\r
2848 {"tune", CmdTune, 0, "Measure antenna tuning"},\r
2849 {"vchdemod", CmdVchdemod, 0, "['clone'] -- Demodulate samples for VeriChip"},\r
2850 {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"},\r
6658905f 2851};\r
2852\r
7f93ef2c 2853static struct {\r
2854 char *name;\r
2855 char *args;\r
2856 char *argshelp;\r
2857 char *description;\r
2858 } CommandExtendedHelp[]= {\r
a52a7d19 2859 {"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 2860 {"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 2861 };\r
fb25b483 2862\r
6658905f 2863//-----------------------------------------------------------------------------\r
2864// Entry point into our code: called whenever the user types a command and\r
2865// then presses Enter, which the full command line that they typed.\r
2866//-----------------------------------------------------------------------------\r
2867void CommandReceived(char *cmd)\r
2868{\r
2869 int i;\r
7f93ef2c 2870 char line[256];\r
6658905f 2871\r
2872 PrintToScrollback("> %s", cmd);\r
2873\r
7f93ef2c 2874 if(strcmp(cmd, "help") == 0 || strncmp(cmd,"help ",strlen("help ")) == 0) {\r
2875 // check if we're doing extended help\r
2876 if(strlen(cmd) > strlen("help ")) {\r
2877 cmd += strlen("help ");\r
2878 for(i = 0; i < sizeof(CommandExtendedHelp) / sizeof(CommandExtendedHelp[0]); i++) {\r
2879 if(strcmp(CommandExtendedHelp[i].name,cmd) == 0) {\r
2880 PrintToScrollback("\nExtended help for '%s':\n", cmd);\r
2881 PrintToScrollback("Args: %s\t- %s\n",CommandExtendedHelp[i].args,CommandExtendedHelp[i].argshelp);\r
2882 PrintToScrollback(CommandExtendedHelp[i].description);\r
a52a7d19 2883 PrintToScrollback("");\r
7f93ef2c 2884 return;\r
2885 }\r
2886 }\r
2887 PrintToScrollback("No extended help available for '%s'", cmd);\r
2888 return;\r
2889 }\r
d722c4ce 2890 if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");\r
6658905f 2891 PrintToScrollback("\r\nAvailable commands:");\r
2892 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
d722c4ce 2893 if (offline && (CommandTable[i].offline==0)) continue;\r
6658905f 2894 memset(line, ' ', sizeof(line));\r
2895 strcpy(line+2, CommandTable[i].name);\r
2896 line[strlen(line)] = ' ';\r
2897 sprintf(line+15, " -- %s", CommandTable[i].docString);\r
2898 PrintToScrollback("%s", line);\r
2899 }\r
2900 PrintToScrollback("");\r
a52a7d19 2901 PrintToScrollback("'help <command>' for extended help on that command\n");\r
6658905f 2902 return;\r
2903 }\r
2904\r
2905 for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
2906 char *name = CommandTable[i].name;\r
2907 if(memcmp(cmd, name, strlen(name))==0 &&\r
2908 (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
2909 {\r
2910 cmd += strlen(name);\r
2911 while(*cmd == ' ') {\r
2912 cmd++;\r
2913 }\r
d722c4ce 2914 if (offline && (CommandTable[i].offline==0)) {\r
2915 PrintToScrollback("Offline mode, cannot use this command.");\r
2916 return;\r
2917 }\r
6658905f 2918 (CommandTable[i].handler)(cmd);\r
2919 return;\r
2920 }\r
2921 }\r
2922 PrintToScrollback(">> bad command '%s'", cmd);\r
2923}\r
2924\r
2925//-----------------------------------------------------------------------------\r
2926// Entry point into our code: called whenever we received a packet over USB\r
2927// that we weren't necessarily expecting, for example a debug print.\r
2928//-----------------------------------------------------------------------------\r
2929void UsbCommandReceived(UsbCommand *c)\r
2930{\r
2931 switch(c->cmd) {\r
2932 case CMD_DEBUG_PRINT_STRING: {\r
2933 char s[100];\r
2934 if(c->ext1 > 70 || c->ext1 < 0) {\r
2935 c->ext1 = 0;\r
2936 }\r
2937 memcpy(s, c->d.asBytes, c->ext1);\r
2938 s[c->ext1] = '\0';\r
2939 PrintToScrollback("#db# %s", s);\r
9760414b 2940 break;\r
6658905f 2941 }\r
2942\r
2943 case CMD_DEBUG_PRINT_INTEGERS:\r
2944 PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
2945 break;\r
2946\r
2947 case CMD_MEASURED_ANTENNA_TUNING: {\r
e7aee94e 2948 int peakv, peakf;\r
6658905f 2949 int vLf125, vLf134, vHf;\r
2950 vLf125 = c->ext1 & 0xffff;\r
2951 vLf134 = c->ext1 >> 16;\r
e7aee94e 2952 vHf = c->ext2 & 0xffff;;\r
2953 peakf = c->ext3 & 0xffff;\r
2954 peakv = c->ext3 >> 16;\r
ad2a9782 2955 PrintToScrollback("");\r
2956 PrintToScrollback("");\r
2957 PrintToScrollback("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0);\r
2958 PrintToScrollback("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0);\r
2959 PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1));\r
2960 PrintToScrollback("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0);\r
e7aee94e 2961 if (peakv<2000)\r
67853904 2962 PrintToScrollback("# Your LF antenna is unusable.");\r
e7aee94e 2963 else if (peakv<10000)\r
2964 PrintToScrollback("# Your LF antenna is marginal.");\r
2965 if (vHf<2000)\r
67853904 2966 PrintToScrollback("# Your HF antenna is unusable.");\r
e7aee94e 2967 else if (vHf<5000)\r
2968 PrintToScrollback("# Your HF antenna is marginal.");\r
6658905f 2969 break;\r
2970 }\r
2971 default:\r
2972 PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
2973 break;\r
2974 }\r
2975}\r
Impressum, Datenschutz