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