]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - winsrc/command.cpp
with em410xread, retest if we read our bits the wrong way (1=0 and 0=1)
[proxmark3-svn] / winsrc / command.cpp
index 9599645d1faa9e3cddb206158258776578dd6fa4..8da91f528f8addc5aafe7993d32d82e3f0a206d9 100644 (file)
 #include "../common/iso14443_crc.c"\r
 \r
 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
+#define BIT(x) GraphBuffer[x * clock]\r
+#define BITS (GraphTraceLen / clock)\r
 \r
+int go = 0;\r
 static int CmdHisamplest(char *str, int nrlow);\r
 \r
 static void GetFromBigBuf(BYTE *dest, int bytes)\r
@@ -34,7 +37,7 @@ static void GetFromBigBuf(BYTE *dest, int bytes)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return;\r
                }\r
 \r
@@ -42,6 +45,14 @@ static void GetFromBigBuf(BYTE *dest, int bytes)
        }\r
 }\r
 \r
+static void CmdReset(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_HARDWARE_RESET;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+\r
 static void CmdQuit(char *str)\r
 {\r
        exit(0);\r
@@ -75,19 +86,19 @@ static void CmdHi14read(char *str)
        c.ext1 = atoi(str);\r
        SendCommand(&c, FALSE);\r
 }\r
-
-
-/* New command to read the contents of a SRI512 tag
- * SRI512 tags are ISO14443-B modulated memory tags,
- * this command just dumps the contents of the memory/
- */
-static void CmdSri512read(char *str)
-{
+\r
+\r
+/* New command to read the contents of a SRI512 tag\r
+ * SRI512 tags are ISO14443-B modulated memory tags,\r
+ * this command just dumps the contents of the memory/\r
+ */\r
+static void CmdSri512read(char *str)\r
+{\r
        UsbCommand c;\r
        c.cmd = CMD_READ_SRI512_TAG;\r
        c.ext1 = atoi(str);\r
-       SendCommand(&c, FALSE);
-}
+       SendCommand(&c, FALSE);\r
+}\r
 \r
 // ## New command\r
 static void CmdHi14areader(char *str)\r
@@ -153,8 +164,6 @@ static void CmdHi14sim(char *str)
        c.cmd = CMD_SIMULATE_TAG_ISO_14443;\r
        SendCommand(&c, FALSE);\r
 }\r
-
-
 \r
 static void CmdHi14asim(char *str)     // ## simulate iso14443a tag\r
 {                                      // ## greg - added ability to specify tag UID\r
@@ -197,11 +206,296 @@ static void CmdFPGAOff(char *str)                // ## FPGA Control
        SendCommand(&c, FALSE);\r
 }\r
 \r
+/* clear out our graph window */\r
+int CmdClearGraph(int redraw)\r
+{\r
+       int gtl = GraphTraceLen;\r
+       GraphTraceLen = 0;\r
+\r
+       if (redraw)\r
+               RepaintGraphWindow();\r
+\r
+       return gtl;\r
+}\r
+\r
+/* write a bit to the graph */\r
+static void CmdAppendGraph(int redraw, int clock, int bit)\r
+{\r
+       int i;\r
+\r
+       for (i = 0; i < (int)(clock/2); i++)\r
+               GraphBuffer[GraphTraceLen++] = bit ^ 1;\r
+\r
+       for (i = (int)(clock/2); i < clock; i++)\r
+               GraphBuffer[GraphTraceLen++] = bit;\r
+\r
+       if (redraw)\r
+               RepaintGraphWindow();\r
+}\r
+\r
+/* Function is equivalent of loread + losamples + em410xread\r
+ * looped until an EM410x tag is detected */\r
+static void CmdEM410xwatch(char *str)\r
+{\r
+       char *zero = "";\r
+       char *twok = "2000";\r
+       go = 1;\r
+\r
+       do\r
+       {\r
+               CmdLoread(zero);\r
+               CmdLosamples(twok);\r
+               CmdEM410xread(zero);\r
+       } while (go);\r
+}\r
+\r
+/* Read the ID of an EM410x tag.\r
+ * Format:\r
+ *   1111 1111 1           <-- standard non-repeatable header\r
+ *   XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
+ *   ....\r
+ *   CCCC                  <-- each bit here is parity for the 10 bits above in corresponding column\r
+ *   0                     <-- stop bit, end of tag\r
+ */\r
+static void CmdEM410xread(char *str)\r
+{\r
+       int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low;\r
+       int parity[4];\r
+       char id[11];\r
+       int retested = 0;\r
+       int BitStream[MAX_GRAPH_TRACE_LEN];\r
+       high = low = 0;\r
+\r
+       /* Detect high and lows and clock */\r
+       for (i = 0; i < GraphTraceLen; i++)\r
+       {\r
+               if (GraphBuffer[i] > high)\r
+                       high = GraphBuffer[i];\r
+               else if (GraphBuffer[i] < low)\r
+                       low = GraphBuffer[i];\r
+       }\r
+\r
+       /* get clock */\r
+       clock = GetClock(str, high);\r
+\r
+       /* parity for our 4 columns */\r
+       parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
+       header = rows = 0;\r
+\r
+       /* manchester demodulate */\r
+       bit = bit2idx = 0;\r
+       for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
+       {\r
+               hithigh = 0;\r
+               hitlow = 0;\r
+               first = 1;\r
+\r
+               /* Find out if we hit both high and low peaks */\r
+               for (j = 0; j < clock; j++)\r
+               {\r
+                       if (GraphBuffer[(i * clock) + j] == high)\r
+                               hithigh = 1;\r
+                       else if (GraphBuffer[(i * clock) + j] == low)\r
+                               hitlow = 1;\r
+\r
+                       /* it doesn't count if it's the first part of our read\r
+                        because it's really just trailing from the last sequence */\r
+                       if (first && (hithigh || hitlow))\r
+                               hithigh = hitlow = 0;\r
+                       else\r
+                               first = 0;\r
+\r
+                       if (hithigh && hitlow)\r
+                               break;\r
+               }\r
+               \r
+               /* If we didn't hit both high and low peaks, we had a bit transition */\r
+               if (!hithigh || !hitlow)\r
+                       bit ^= 1;\r
+               \r
+               BitStream[bit2idx++] = bit;\r
+       }\r
+       \r
+retest:\r
+       /* We go till 5 before the graph ends because we'll get that far below */\r
+       for (i = 1; i < bit2idx - 5; i++)\r
+       {\r
+               /* Step 2: We have our header but need our tag ID */\r
+               if (header == 9 && rows < 10)\r
+               {\r
+                       /* Confirm parity is correct */\r
+                       if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4])\r
+                       {\r
+                               /* Read another byte! */\r
+                               sprintf(id+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3]));\r
+                               rows++;\r
+\r
+                               /* Keep parity info */\r
+                               parity[0] ^= BitStream[i];\r
+                               parity[1] ^= BitStream[i+1];\r
+                               parity[2] ^= BitStream[i+2];\r
+                               parity[3] ^= BitStream[i+3];\r
+\r
+                               /* Move 4 bits ahead */\r
+                               i += 4;\r
+                       }\r
+\r
+                       /* Damn, something wrong! reset */\r
+                       else\r
+                       {\r
+                               PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i);\r
+\r
+                               /* Start back rows * 5 + 9 header bits, -1 to not start at same place */\r
+                               i -= 9 + (5 * rows) - 5;\r
+\r
+                               rows = header = 0;\r
+                       }\r
+               }\r
+\r
+               /* Step 3: Got our 40 bits! confirm column parity */\r
+               else if (rows == 10)\r
+               {\r
+                       /* We need to make sure our 4 bits of parity are correct and we have a stop bit */\r
+                       if (BitStream[i] == parity[0] && BitStream[i+1] == parity[1] &&\r
+                               BitStream[i+2] == parity[2] && BitStream[i+3] == parity[3] &&\r
+                               BitStream[i+4] == 0)\r
+                       {\r
+                               /* Sweet! */\r
+                               PrintToScrollback("EM410x Tag ID: %s", id);\r
+\r
+                               /* Stop any loops */\r
+                               go = 0;\r
+                               return;\r
+                       }\r
+\r
+                       /* Crap! Incorrect parity or no stop bit, start all over */\r
+                       else\r
+                       {\r
+                               rows = header = 0;\r
+\r
+                               /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */\r
+                               i -= 59;\r
+                       }\r
+               }\r
+\r
+               /* Step 1: get our header */\r
+               else if (header < 9)\r
+               {\r
+                       /* Need 9 consecutive 1's */\r
+                       if (BitStream[i] == 1)\r
+                               header++;\r
+\r
+                       /* We don't have a header, not enough consecutive 1 bits */\r
+                       else\r
+                               header = 0;\r
+               }\r
+       }\r
+       \r
+       /* if we've already retested after flipping bits, return */\r
+       if (retested++)\r
+               return;\r
+\r
+       /* if this didn't work, try flipping bits */\r
+       for (i = 0; i < bit2idx; i++)\r
+               BitStream[i] ^= 1;\r
+\r
+       goto retest;\r
+}\r
+\r
+/* emulate an EM410X tag\r
+ * Format:\r
+ *   1111 1111 1           <-- standard non-repeatable header\r
+ *   XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID\r
+ *   ....\r
+ *   CCCC                  <-- each bit here is parity for the 10 bits above in corresponding column\r
+ *   0                     <-- stop bit, end of tag\r
+ */\r
+static void CmdEM410xsim(char *str)\r
+{\r
+       int i, n, j, h, binary[4], parity[4];\r
+       char *s = "0";\r
+\r
+       /* clock is 64 in EM410x tags */\r
+       int clock = 64;\r
+\r
+       /* clear our graph */\r
+       CmdClearGraph(0);\r
+\r
+       /* write it out a few times */\r
+       for (h = 0; h < 4; h++)\r
+       {\r
+               /* write 9 start bits */\r
+               for (i = 0; i < 9; i++)\r
+                       CmdAppendGraph(0, clock, 1);\r
+\r
+               /* for each hex char */\r
+               parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
+               for (i = 0; i < 10; i++)\r
+               {\r
+                       /* read each hex char */\r
+                       sscanf(&str[i], "%1x", &n);\r
+                       for (j = 3; j >= 0; j--, n/= 2)\r
+                               binary[j] = n % 2;\r
+\r
+                       /* append each bit */\r
+                       CmdAppendGraph(0, clock, binary[0]);\r
+                       CmdAppendGraph(0, clock, binary[1]);\r
+                       CmdAppendGraph(0, clock, binary[2]);\r
+                       CmdAppendGraph(0, clock, binary[3]);\r
+\r
+                       /* append parity bit */\r
+                       CmdAppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);\r
+\r
+                       /* keep track of column parity */\r
+                       parity[0] ^= binary[0];\r
+                       parity[1] ^= binary[1];\r
+                       parity[2] ^= binary[2];\r
+                       parity[3] ^= binary[3];\r
+               }\r
+\r
+               /* parity columns */\r
+               CmdAppendGraph(0, clock, parity[0]);\r
+               CmdAppendGraph(0, clock, parity[1]);\r
+               CmdAppendGraph(0, clock, parity[2]);\r
+               CmdAppendGraph(0, clock, parity[3]);\r
+\r
+               /* stop bit */\r
+               CmdAppendGraph(0, clock, 0);\r
+       }\r
+\r
+       /* modulate that biatch */\r
+       Cmdmanchestermod(s);\r
+\r
+       /* booyah! */\r
+       RepaintGraphWindow();\r
+\r
+       CmdLosim(s);\r
+}\r
+\r
+static void ChkBitstream(char *str)\r
+{\r
+       int i;\r
+\r
+       /* convert to bitstream if necessary */\r
+       for (i = 0; i < (int)(GraphTraceLen / 2); i++)\r
+       {\r
+               if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)\r
+               {\r
+                       Cmdbitstream(str);\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
 static void CmdLosim(char *str)\r
 {\r
        int i;\r
+       char *zero = "0";\r
+\r
+       /* convert to bitstream if necessary */\r
+       ChkBitstream(str);\r
 \r
-       for(i = 0; i < GraphTraceLen; i += 48) {\r
+       for (i = 0; i < GraphTraceLen; i += 48) {\r
                UsbCommand c;\r
                int j;\r
                for(j = 0; j < 48; j++) {\r
@@ -251,7 +545,8 @@ static void CmdLosamples(char *str)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       if (!go)\r
+                               PrintToScrollback("bad resp");\r
                        return;\r
                }\r
                int j;\r
@@ -277,7 +572,7 @@ static void CmdBitsamples(char *str)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return;\r
                }\r
                int j, k;\r
@@ -308,7 +603,7 @@ static void CmdHisamples(char *str)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return;\r
                }\r
                int j;\r
@@ -341,7 +636,7 @@ static int CmdHisamplest(char *str, int nrlow)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return 0;\r
                }\r
                int j;\r
@@ -410,7 +705,7 @@ static void CmdHexsamples(char *str)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return;\r
                }\r
                int j;\r
@@ -449,7 +744,7 @@ static void CmdHisampless(char *str)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return;\r
                }\r
                int j;\r
@@ -939,7 +1234,7 @@ static void CmdTibits(char *str)
                SendCommand(&c, FALSE);\r
                ReceiveCommand(&c);\r
                if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {\r
-                       PrintToScrollback("bad resp\n");\r
+                       PrintToScrollback("bad resp");\r
                        return;\r
                }\r
                int j;\r
@@ -1537,185 +1832,413 @@ static void CmdFlexdemod(char *str)
 \r
        RepaintGraphWindow();\r
 }\r
-
-/*
- * Generic command to demodulate ASK. bit length in argument.
- * Giving the bit length helps discriminate ripple effects
- * upon zero crossing for noisy traces.
- *
- * Second is convention: positive or negative (High mod means zero
- * or high mod means one)
- *
- * Updates the Graph trace with 0/1 values
- *
- * Arguments:
- * sl : bit length in terms of number of samples per bit
- *      (use yellow/purple markers to compute).
- * c : 0 or 1
- */
-
-static void Cmdaskdemod(char *str) {
-       int i;
-       int sign = 1;
-       int n = 0;
-       int c = 0;\r
-       int t1 = 0;
-
-       // TODO: complain if we do not give 2 arguments here !
-       sscanf(str, "%i %i", &n, &c);
-       if (c == 0) {
-               c = 1 ;
-       } else {
-               c = -1;
-       }
-
-       if (GraphBuffer[0]*c > 0) {
-               GraphBuffer[0] = 1;
-       } else {
-               GraphBuffer[0] = 0;
-       }
-       for(i=1;i<GraphTraceLen;i++) {
-               /* Analyse signal within the symbol length */
-               /* Decide if we crossed a zero */
-               if (GraphBuffer[i]*sign < 0) {
-                        /* Crossed a zero, check if this is a ripple or not */
-                       if ( (i-t1) > n/4 ) {
-                               sign = -sign;
-                               t1=i;
-                               if (GraphBuffer[i]*c > 0){
-                                       GraphBuffer[i]=1;
-                               } else {
-                                       GraphBuffer[i]=0;
-                               }
-                       } else {
-                       /* This is a ripple, set the current sample value
-                          to the same as previous */
-                               GraphBuffer[i] = GraphBuffer[i-1];
-                       }
-               } else {
-                       GraphBuffer[i] = GraphBuffer[i-1];
-               }
-       }
-       RepaintGraphWindow();
-}
-
-
-/*
- * Manchester demodulate a bitstream. The bitstream needs to be already in
- * the GraphBuffer as 0 and 1 values
- *
- * Give the clock rate as argument in order to help the sync - the algorithm
- * resyncs at each pulse anyway.
- *
- * Not optimized by any means, this is the 1st time I'm writing this type of
- * routine, feel free to improve...
- *
- * 1st argument: clock rate (as number of samples per clock rate)
- *               Typical values can be 64, 32, 128...
- */
-static void Cmdmanchesterdemod(char *str) {
-       int i;
-       int clock;
-       int lastval;
-       int lc = 0;
-       int bitidx = 0;
-       int bit2idx = 0;
-
-
-       sscanf(str, "%i", &clock);
-
-       int tolerance = clock/4;
-       /* Holds the decoded bitstream: each clock period contains 2 bits       */
-       /* later simplified to 1 bit after manchester decoding.                 */
-       /* Add 10 bits to allow for noisy / uncertain traces without aborting   */
-       /* int BitStream[GraphTraceLen*2/clock+10]; */
-
-       /* But it does not work if compiling on WIndows: therefore we just allocate a */
-       /* large array */
-       int BitStream[MAX_GRAPH_TRACE_LEN];
-
-       /* Detect first transition */
-       /* Lo-Hi (arbitrary)       */
-       for(i=1;i<GraphTraceLen;i++) {
-               if (GraphBuffer[i-1]<GraphBuffer[i]) {
-               lastval = i;
-               BitStream[0]=0; // Previous state = 0;
-               break;
-               }
-       }
-
-       /* Then detect duration between 2 successive transitions */
-       for(bitidx = 1 ;i<GraphTraceLen;i++) {
-               if (GraphBuffer[i-1] != GraphBuffer[i]) {
-                       lc = i-lastval;
-                       lastval = i;
-                       // Error check: if bitidx becomes too large, we do not
-                       // have a Manchester encoded bitstream or the clock is really
-                       // wrong!
-                       if (bitidx > (GraphTraceLen*2/clock+8) ) {
-                               PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");
-                               return;
-                       }
-                       // Then switch depending on lc length:
-                       // Tolerance is 1/4 of clock rate (arbitrary)
-                       if (abs(lc-clock/2) < tolerance) {
-                               // Short pulse : either "1" or "0"
-                               BitStream[bitidx++]=GraphBuffer[i-1];
-                       } else if (abs(lc-clock) < tolerance) {
-                               // Long pulse: either "11" or "00"
-                               BitStream[bitidx++]=GraphBuffer[i-1];
-                               BitStream[bitidx++]=GraphBuffer[i-1];
-                       } else {
-                               // Error
-                               PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
-                               PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
-                       }
-               }
-       }
-
-       // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
-       // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
-       // to stop output at the final bitidx2 value, not bitidx
-       for (i = 0; i < bitidx; i += 2) {
-               if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {
-                       BitStream[bit2idx++] = 1;
-               } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {
-                       BitStream[bit2idx++] = 0;
-               } else {
-                       // We cannot end up in this state, this means we are unsynchronized,
-                       // move up 1 bit:
-                       i++;
-                       PrintToScrollback("Unsynchronized, resync...");
-                       PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
-               }
-       }
-       PrintToScrollback("Manchester decoded bitstream \n---------");
-       // Now output the bitstream to the scrollback by line of 16 bits
-       for (i = 0; i < (bit2idx-16); i+=16) {
-               PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
-                       BitStream[i],
-                       BitStream[i+1],
-                       BitStream[i+2],
-                       BitStream[i+3],
-                       BitStream[i+4],
-                       BitStream[i+5],
-                       BitStream[i+6],
-                       BitStream[i+7],
-                       BitStream[i+8],
-                       BitStream[i+9],
-                       BitStream[i+10],
-                       BitStream[i+11],
-                       BitStream[i+12],
-                       BitStream[i+13],
-                       BitStream[i+14],
-                       BitStream[i+15]);
-       }
-}
-
-
-
-/*
- * Usage ???
+\r
+/*\r
+ * Generic command to demodulate ASK.\r
+ *\r
+ * Argument is convention: positive or negative (High mod means zero\r
+ * or high mod means one)\r
+ *\r
+ * Updates the Graph trace with 0/1 values\r
+ *\r
+ * Arguments:\r
+ * c : 0 or 1\r
+ */\r
+\r
+static void Cmdaskdemod(char *str) {\r
+       int i;\r
+       int n = 0;\r
+       int c,high,low = 0;\r
+\r
+       // TODO: complain if we do not give 2 arguments here !\r
+       sscanf(str, "%i", &c);\r
+\r
+       /* Detect high and lows and clock */\r
+       for (i = 0; i < GraphTraceLen; i++)\r
+       {\r
+               if (GraphBuffer[i] > high)\r
+                       high = GraphBuffer[i];\r
+               else if (GraphBuffer[i] < low)\r
+                       low = GraphBuffer[i];\r
+       }\r
+\r
+       if (GraphBuffer[0] > 0) {\r
+               GraphBuffer[0] = 1-c;\r
+       } else {\r
+               GraphBuffer[0] = c;\r
+       }\r
+       for(i=1;i<GraphTraceLen;i++) {\r
+               /* Transitions are detected at each peak\r
+                * Transitions are either:\r
+                * - we're low: transition if we hit a high\r
+                * - we're high: transition if we hit a low\r
+                * (we need to do it this way because some tags keep high or\r
+                * low for long periods, others just reach the peak and go\r
+                * down)\r
+                */\r
+               if ((GraphBuffer[i]==high) && (GraphBuffer[i-1] == c)) {\r
+                                       GraphBuffer[i]=1-c;\r
+               } else if ((GraphBuffer[i]==low) && (GraphBuffer[i-1] == (1-c))){\r
+                       GraphBuffer[i] = c;\r
+               } else {\r
+                       /* No transition */\r
+                       GraphBuffer[i] = GraphBuffer[i-1];\r
+               }\r
+       }\r
+       RepaintGraphWindow();\r
+}\r
+\r
+/* Print our clock rate */\r
+static void Cmddetectclockrate(char *str)\r
+{\r
+       int clock = detectclock(0);\r
+       PrintToScrollback("Auto-detected clock rate: %d", clock);\r
+}\r
+\r
+/*\r
+ * Detect clock rate\r
+ */\r
+int detectclock(int peak)\r
+{\r
+       int i;\r
+       int clock = 0xFFFF;\r
+       int lastpeak = 0;\r
+\r
+       /* Detect peak if we don't have one */\r
+       if (!peak)\r
+               for (i = 0; i < GraphTraceLen; i++)\r
+                       if (GraphBuffer[i] > peak)\r
+                               peak = GraphBuffer[i];\r
+\r
+       for (i = 1; i < GraphTraceLen; i++)\r
+       {\r
+               /* If this is the beginning of a peak */\r
+               if (GraphBuffer[i-1] != GraphBuffer[i] && GraphBuffer[i] == peak)\r
+               {\r
+                       /* Find lowest difference between peaks */\r
+                       if (lastpeak && i - lastpeak < clock)\r
+                       {\r
+                               clock = i - lastpeak;\r
+                       }\r
+                       lastpeak = i;\r
+               }\r
+       }\r
+\r
+       return clock;\r
+}\r
+\r
+/* Get or auto-detect clock rate */\r
+int GetClock(char *str, int peak)\r
+{\r
+       int clock;\r
+\r
+       sscanf(str, "%i", &clock);\r
+       if (!strcmp(str, ""))\r
+               clock = 0;\r
+\r
+       /* Auto-detect clock */\r
+       if (!clock)\r
+       {\r
+               clock = detectclock(peak);\r
+\r
+               /* Only print this message if we're not looping something */\r
+               if (!go)\r
+                       PrintToScrollback("Auto-detected clock rate: %d", clock);\r
+       }\r
+\r
+       return clock;\r
+}\r
+\r
+/*\r
+ * Convert to a bitstream\r
+ */\r
+static void Cmdbitstream(char *str) {\r
+       int i, j;\r
+       int bit;\r
+       int gtl;\r
+       int clock;\r
+       int low = 0;\r
+       int high = 0;\r
+       int hithigh, hitlow, first;\r
+\r
+       /* Detect high and lows and clock */\r
+       for (i = 0; i < GraphTraceLen; i++)\r
+       {\r
+               if (GraphBuffer[i] > high)\r
+                       high = GraphBuffer[i];\r
+               else if (GraphBuffer[i] < low)\r
+                       low = GraphBuffer[i];\r
+       }\r
+\r
+       /* Get our clock */\r
+       clock = GetClock(str, high);\r
+\r
+       gtl = CmdClearGraph(0);\r
+\r
+       bit = 0;\r
+       for (i = 0; i < (int)(gtl / clock); i++)\r
+       {\r
+               hithigh = 0;\r
+               hitlow = 0;\r
+               first = 1;\r
+\r
+               /* Find out if we hit both high and low peaks */\r
+               for (j = 0; j < clock; j++)\r
+               {\r
+                       if (GraphBuffer[(i * clock) + j] == high)\r
+                               hithigh = 1;\r
+                       else if (GraphBuffer[(i * clock) + j] == low)\r
+                               hitlow = 1;\r
+\r
+                       /* it doesn't count if it's the first part of our read\r
+                        because it's really just trailing from the last sequence */\r
+                       if (first && (hithigh || hitlow))\r
+                               hithigh = hitlow = 0;\r
+                       else\r
+                               first = 0;\r
+\r
+                       if (hithigh && hitlow)\r
+                               break;\r
+               }\r
+\r
+               /* If we didn't hit both high and low peaks, we had a bit transition */\r
+               if (!hithigh || !hitlow)\r
+                       bit ^= 1;\r
+\r
+               CmdAppendGraph(0, clock, bit);\r
+//             for (j = 0; j < (int)(clock/2); j++)\r
+//                     GraphBuffer[(i * clock) + j] = bit ^ 1;\r
+//             for (j = (int)(clock/2); j < clock; j++)\r
+//                     GraphBuffer[(i * clock) + j] = bit;\r
+       }\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+/* Modulate our data into manchester */\r
+static void Cmdmanchestermod(char *str)\r
+{\r
+       int i, j;\r
+       int clock;\r
+       int bit, lastbit, wave;\r
+\r
+       /* Get our clock */\r
+       clock = GetClock(str, 0);\r
+\r
+       wave = 0;\r
+       lastbit = 1;\r
+       for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
+       {\r
+               bit = GraphBuffer[i * clock] ^ 1;\r
+\r
+               for (j = 0; j < (int)(clock/2); j++)\r
+                       GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave;\r
+               for (j = (int)(clock/2); j < clock; j++)\r
+                       GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1;\r
+\r
+               /* Keep track of how we start our wave and if we changed or not this time */\r
+               wave ^= bit ^ lastbit;\r
+               lastbit = bit;\r
+       }\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+/*\r
+ * Manchester demodulate a bitstream. The bitstream needs to be already in\r
+ * the GraphBuffer as 0 and 1 values\r
+ *\r
+ * Give the clock rate as argument in order to help the sync - the algorithm\r
+ * resyncs at each pulse anyway.\r
+ *\r
+ * Not optimized by any means, this is the 1st time I'm writing this type of\r
+ * routine, feel free to improve...\r
+ *\r
+ * 1st argument: clock rate (as number of samples per clock rate)\r
+ *               Typical values can be 64, 32, 128...\r
+ */\r
+static void Cmdmanchesterdemod(char *str) {\r
+       int i, j;\r
+       int bit;\r
+       int clock;\r
+       int lastval;\r
+       int low = 0;\r
+       int high = 0;\r
+       int hithigh, hitlow, first;\r
+       int lc = 0;\r
+       int bitidx = 0;\r
+       int bit2idx = 0;\r
+       int warnings = 0;\r
+\r
+       /* Holds the decoded bitstream: each clock period contains 2 bits       */\r
+       /* later simplified to 1 bit after manchester decoding.                 */\r
+       /* Add 10 bits to allow for noisy / uncertain traces without aborting   */\r
+       /* int BitStream[GraphTraceLen*2/clock+10]; */\r
+\r
+       /* But it does not work if compiling on WIndows: therefore we just allocate a */\r
+       /* large array */\r
+       int BitStream[MAX_GRAPH_TRACE_LEN];\r
+\r
+       /* Detect high and lows */\r
+       for (i = 0; i < GraphTraceLen; i++)\r
+       {\r
+               if (GraphBuffer[i] > high)\r
+                       high = GraphBuffer[i];\r
+               else if (GraphBuffer[i] < low)\r
+                       low = GraphBuffer[i];\r
+       }\r
+\r
+       /* Get our clock */\r
+       clock = GetClock(str, high);\r
+\r
+       int tolerance = clock/4;\r
+\r
+       /* Detect first transition */\r
+       /* Lo-Hi (arbitrary)       */\r
+       for (i = 0; i < GraphTraceLen; i++)\r
+       {\r
+               if (GraphBuffer[i] == low)\r
+               {\r
+                       lastval = i;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       /* If we're not working with 1/0s, demod based off clock */\r
+       if (high != 1)\r
+       {\r
+               bit = 0; /* We assume the 1st bit is zero, it may not be\r
+                         * the case: this routine (I think) has an init problem.\r
+                         * Ed.\r
+                         */\r
+               for (; i < (int)(GraphTraceLen / clock); i++)\r
+               {\r
+                       hithigh = 0;\r
+                       hitlow = 0;\r
+                       first = 1;\r
+\r
+                       /* Find out if we hit both high and low peaks */\r
+                       for (j = 0; j < clock; j++)\r
+                       {\r
+                               if (GraphBuffer[(i * clock) + j] == high)\r
+                                       hithigh = 1;\r
+                               else if (GraphBuffer[(i * clock) + j] == low)\r
+                                       hitlow = 1;\r
+\r
+                               /* it doesn't count if it's the first part of our read\r
+                                  because it's really just trailing from the last sequence */\r
+                               if (first && (hithigh || hitlow))\r
+                                       hithigh = hitlow = 0;\r
+                               else\r
+                                       first = 0;\r
+\r
+                               if (hithigh && hitlow)\r
+                                       break;\r
+                       }\r
+\r
+                       /* If we didn't hit both high and low peaks, we had a bit transition */\r
+                       if (!hithigh || !hitlow)\r
+                               bit ^= 1;\r
+\r
+                       BitStream[bit2idx++] = bit;\r
+               }\r
+       }\r
+\r
+       /* standard 1/0 bitstream */\r
+       else\r
+       {\r
+\r
+       /* Then detect duration between 2 successive transitions */\r
+               for (bitidx = 1; i < GraphTraceLen; i++)\r
+               {\r
+                       if (GraphBuffer[i-1] != GraphBuffer[i])\r
+                       {\r
+                       lc = i-lastval;\r
+                       lastval = i;\r
+\r
+                       // Error check: if bitidx becomes too large, we do not\r
+                       // have a Manchester encoded bitstream or the clock is really\r
+                       // wrong!\r
+                       if (bitidx > (GraphTraceLen*2/clock+8) ) {\r
+                               PrintToScrollback("Error: the clock you gave is probably wrong, aborting.");\r
+                               return;\r
+                       }\r
+                       // Then switch depending on lc length:\r
+                       // Tolerance is 1/4 of clock rate (arbitrary)\r
+                       if (abs(lc-clock/2) < tolerance) {\r
+                               // Short pulse : either "1" or "0"\r
+                               BitStream[bitidx++]=GraphBuffer[i-1];\r
+                       } else if (abs(lc-clock) < tolerance) {\r
+                               // Long pulse: either "11" or "00"\r
+                               BitStream[bitidx++]=GraphBuffer[i-1];\r
+                               BitStream[bitidx++]=GraphBuffer[i-1];\r
+                       } else {\r
+                               // Error\r
+                                       warnings++;\r
+                               PrintToScrollback("Warning: Manchester decode error for pulse width detection.");\r
+                               PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");\r
+\r
+                                       if (warnings > 100)\r
+                                       {\r
+                                               PrintToScrollback("Error: too many detection errors, aborting.");\r
+                                               return;\r
+                                       }\r
+                       }\r
+               }\r
+       }\r
+\r
+       // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream\r
+       // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful\r
+       // to stop output at the final bitidx2 value, not bitidx\r
+       for (i = 0; i < bitidx; i += 2) {\r
+               if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {\r
+                       BitStream[bit2idx++] = 1;\r
+               } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {\r
+                       BitStream[bit2idx++] = 0;\r
+               } else {\r
+                       // We cannot end up in this state, this means we are unsynchronized,\r
+                       // move up 1 bit:\r
+                       i++;\r
+                               warnings++;\r
+                       PrintToScrollback("Unsynchronized, resync...");\r
+                       PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");\r
+\r
+                               if (warnings > 100)\r
+                               {\r
+                                       PrintToScrollback("Error: too many decode errors, aborting.");\r
+                                       return;\r
+                               }\r
+               }\r
+       }\r
+       }\r
+\r
+       PrintToScrollback("Manchester decoded bitstream");\r
+       // Now output the bitstream to the scrollback by line of 16 bits\r
+       for (i = 0; i < (bit2idx-16); i+=16) {\r
+               PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",\r
+                       BitStream[i],\r
+                       BitStream[i+1],\r
+                       BitStream[i+2],\r
+                       BitStream[i+3],\r
+                       BitStream[i+4],\r
+                       BitStream[i+5],\r
+                       BitStream[i+6],\r
+                       BitStream[i+7],\r
+                       BitStream[i+8],\r
+                       BitStream[i+9],\r
+                       BitStream[i+10],\r
+                       BitStream[i+11],\r
+                       BitStream[i+12],\r
+                       BitStream[i+13],\r
+                       BitStream[i+14],\r
+                       BitStream[i+15]);\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * Usage ???\r
  */\r
 static void CmdHiddemod(char *str)\r
 {\r
@@ -1829,14 +2352,16 @@ static void CmdLcd(char *str)
        }\r
 }\r
 \r
+\r
+\r
 static void CmdTest(char *str)\r
 {\r
 }\r
-
-/*
- * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
- * 600kHz.
- */
+\r
+/*\r
+ * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below\r
+ * 600kHz.\r
+ */\r
 static void CmdSetDivisor(char *str)\r
 {\r
        UsbCommand c;\r
@@ -1856,69 +2381,78 @@ static void CmdSweepLF(char *str)
        c.cmd = CMD_SWEEP_LF;\r
        SendCommand(&c, FALSE);\r
 }\r
-
-
+\r
+\r
 typedef void HandlerFunction(char *cmdline);\r
 \r
+/* in alphabetic order */\r
 static struct {\r
        char            *name;\r
        HandlerFunction *handler;\r
        int             offline;  // 1 if the command can be used when in offline mode\r
-       char            *docString;
+       char            *docString;\r
 } CommandTable[] = {\r
-       "tune",                 CmdTune,0,              "measure antenna tuning",\r
-       "tiread",               CmdTiread,0,            "read a TI-type 134 kHz tag",\r
-       "tibits",               CmdTibits,0,            "get raw bits for TI-type LF tag",\r
-       "tidemod",              CmdTidemod,0,           "demod raw bits for TI-type LF tag",\r
-       "vchdemod",             CmdVchdemod,0,          "demod samples for VeriChip",\r
-       "plot",                 CmdPlot,1,              "show graph window",\r
-       "hide",                 CmdHide,1,              "hide graph window",\r
-       "losim",                CmdLosim,0,             "simulate LF tag",\r
-       "loread",               CmdLoread,0,            "read (125/134 kHz) LF ID-only tag",\r
-       "losamples",            CmdLosamples,0,         "get raw samples for LF tag",\r
-       "hisamples",            CmdHisamples,0,         "get raw samples for HF tag",\r
-       "hisampless",           CmdHisampless,0,        "get signed raw samples, HF tag",\r
-       "hisamplest",           CmdHi14readt,0,         "get samples HF, for testing",\r
-       "higet",                CmdHi14read_sim,0,      "get samples HF, 'analog'",\r
-       "bitsamples",           CmdBitsamples,0,        "get raw samples as bitstring",\r
-       "hexsamples",           CmdHexsamples,0,        "dump big buffer as hex bytes",\r
-       "hi15read",             CmdHi15read,0,          "read HF tag (ISO 15693)",\r
-       "hi15reader",           CmdHi15reader,0,        "act like an ISO15693 reader", // new command greg\r
-       "hi15sim",              CmdHi15tag,0,           "fake an ISO15693 tag", // new command greg\r
-       "hi14read",             CmdHi14read,0,          "read HF tag (ISO 14443)",\r
-       "sri512read",           CmdSri512read,0,        "Read contents of a SRI512 tag",\r
-       "hi14areader",          CmdHi14areader,0,       "act like an ISO14443 Type A reader",   // ## New reader command\r
-       "hi15demod",            CmdHi15demod,1,         "demod ISO15693 from tag",\r
-       "hi14bdemod",           CmdHi14bdemod,1,        "demod ISO14443 Type B from tag",\r
-       "autocorr",             CmdAutoCorr,1,          "autocorrelation over window",\r
-       "norm",                 CmdNorm,1,              "normalize max/min to +/-500",\r
-       "dec",                  CmdDec,1,               "decimate",\r
-       "hpf",                  CmdHpf,1,               "remove DC offset from trace",\r
-       "zerocrossings",        CmdZerocrossings,1,     "count time between zero-crossings",\r
-       "ltrim",                CmdLtrim,1,             "trim from left of trace",\r
-       "scale",                CmdScale,1,             "set cursor display scale",\r
-       "flexdemod",            CmdFlexdemod,1,         "demod samples for FlexPass",\r
-       "save",                 CmdSave,1,              "save trace (from graph window)",\r
-       "load",                 CmdLoad,1,              "load trace (to graph window",\r
-       "hisimlisten",          CmdHisimlisten,0,       "get HF samples as fake tag",\r
-       "hi14sim",              CmdHi14sim,0,           "fake ISO 14443 tag",\r
-       "hi14asim",             CmdHi14asim,0,          "fake ISO 14443a tag",                                  // ## Simulate 14443a tag\r
-       "hi14snoop",            CmdHi14snoop,0,         "eavesdrop ISO 14443",\r
-       "hi14asnoop",           CmdHi14asnoop,0,        "eavesdrop ISO 14443 Type A",                   // ## New snoop command\r
-       "hi14list",             CmdHi14list,0,          "list ISO 14443 history",\r
-       "hi14alist",            CmdHi14alist,0,         "list ISO 14443a history",                              // ## New list command\r
-       "hiddemod",             CmdHiddemod,1,          "HID Prox Card II (not optimal)",\r
-       "hidfskdemod",          CmdHIDdemodFSK,0,       "HID FSK demodulator",\r
-    "indalademod",          CmdIndalademod,0,         "demod samples for Indala",\r
-       "askdemod",             Cmdaskdemod,1,          "Attempt to demodulate simple ASK tags",\r
-       "hidsimtag",            CmdHIDsimTAG,0,         "HID tag simulator",\r
-       "mandemod",             Cmdmanchesterdemod,1,   "Try a Manchester demodulation on a binary stream",\r
-       "fpgaoff",              CmdFPGAOff,0,           "set FPGA off",                                                 // ## FPGA Control\r
-       "lcdreset",             CmdLcdReset,0,          "Hardware reset LCD",\r
-       "lcd",                  CmdLcd,0,               "Send command/data to LCD",\r
-       "setlfdivisor",         CmdSetDivisor,0,        "Drive LF antenna at 12Mhz/(divisor+1)",\r
-       "sweeplf",              CmdSweepLF,0,           "Sweep through LF freq range and store results in buffer",\r
-       "quit",                 CmdQuit,0,              "quit program"\r
+       "askdemod",                     Cmdaskdemod,1,          "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags",\r
+       "autocorr",                     CmdAutoCorr,1,          "<window length> -- Autocorrelation over window",\r
+       "bitsamples",           CmdBitsamples,0,        "    Get raw samples as bitstring",\r
+       "bitstream",            Cmdbitstream,1,         "[clock rate] -- Convert waveform into a bitstream",\r
+       "dec",                          CmdDec,1,               "    Decimate samples",\r
+       "detectclock",          Cmddetectclockrate,1, "    Detect clock rate",\r
+       "em410xsim",            CmdEM410xsim,1,         "<UID> -- Simulate EM410x tag",\r
+       "em410xread",           CmdEM410xread,1,        "[clock rate] -- Extract ID from EM410x tag",\r
+       "em410xwatch",          CmdEM410xwatch,0,       "    Watches for EM410x tags",\r
+       "exit",                         CmdQuit,1,                      "    Exit program",\r
+       "flexdemod",            CmdFlexdemod,1,         "    Demodulate samples for FlexPass",\r
+       "fpgaoff",                      CmdFPGAOff,0,           "    Set FPGA off",                                                     // ## FPGA Control\r
+       "hexsamples",           CmdHexsamples,0,        "<blocks> -- Dump big buffer as hex bytes",\r
+       "hi14alist",            CmdHi14alist,0,         "    List ISO 14443a history",                          // ## New list command\r
+       "hi14areader",          CmdHi14areader,0,       "    Act like an ISO14443 Type A reader",       // ## New reader command\r
+       "hi14asim",                     CmdHi14asim,0,          "<UID> -- Fake ISO 14443a tag",                                 // ## Simulate 14443a tag\r
+       "hi14asnoop",           CmdHi14asnoop,0,        "    Eavesdrop ISO 14443 Type A",                       // ## New snoop command\r
+       "hi14bdemod",           CmdHi14bdemod,1,        "    Demodulate ISO14443 Type B from tag",\r
+       "hi14list",                     CmdHi14list,0,          "    List ISO 14443 history",\r
+       "hi14read",                     CmdHi14read,0,          "    Read HF tag (ISO 14443)",\r
+       "hi14sim",                      CmdHi14sim,0,           "    Fake ISO 14443 tag",\r
+       "hi14snoop",            CmdHi14snoop,0,         "    Eavesdrop ISO 14443",\r
+       "hi15demod",            CmdHi15demod,1,         "    Demodulate ISO15693 from tag",\r
+       "hi15read",                     CmdHi15read,0,          "    Read HF tag (ISO 15693)",\r
+       "hi15reader",           CmdHi15reader,0,        "    Act like an ISO15693 reader", // new command greg\r
+       "hi15sim",                      CmdHi15tag,0,           "    Fake an ISO15693 tag", // new command greg\r
+       "hiddemod",                     CmdHiddemod,1,          "    Demodulate HID Prox Card II (not optimal)",\r
+       "hide",                         CmdHide,1,              "    Hide graph window",\r
+       "hidfskdemod",          CmdHIDdemodFSK,0,       "    Realtime HID FSK demodulator",\r
+       "hidsimtag",            CmdHIDsimTAG,0,         "<ID> -- HID tag simulator",\r
+       "higet",                        CmdHi14read_sim,0,      "<samples> -- Get samples HF, 'analog'",\r
+       "hisamples",            CmdHisamples,0,         "    Get raw samples for HF tag",\r
+       "hisampless",           CmdHisampless,0,        "<samples> -- Get signed raw samples, HF tag",\r
+       "hisamplest",           CmdHi14readt,0,         "    Get samples HF, for testing",\r
+       "hisimlisten",          CmdHisimlisten,0,       "    Get HF samples as fake tag",\r
+       "hpf",                          CmdHpf,1,               "    Remove DC offset from trace",\r
+       "indalademod",          CmdIndalademod,0,         "['224'] -- Demodulate samples for Indala",\r
+       "lcd",                          CmdLcd,0,                       "<HEX command> <count> -- Send command/data to LCD",\r
+       "lcdreset",                     CmdLcdReset,0,          "    Hardware reset LCD",\r
+       "load",                         CmdLoad,1,              "<filename> -- Load trace (to graph window",\r
+       "loread",                       CmdLoread,0,            "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)",\r
+       "losamples",            CmdLosamples,0,         "[128 - 16000] -- Get raw samples for LF tag",\r
+       "losim",                        CmdLosim,0,             "    Simulate LF tag",\r
+       "ltrim",                        CmdLtrim,1,             "<samples> -- Trim samples from left of trace",\r
+       "mandemod",                     Cmdmanchesterdemod,1,   "[clock rate] -- Try a Manchester demodulation on a binary stream",\r
+       "manmod",                       Cmdmanchestermod,1,     "[clock rate] -- Manchester modulate a binary stream",\r
+       "norm",                         CmdNorm,1,              "    Normalize max/min to +/-500",\r
+       "plot",                         CmdPlot,1,              "    Show graph window",\r
+       "quit",                         CmdQuit,1,                      "    Quit program",\r
+       "reset",                        CmdReset,0,                     "    Reset the Proxmark3",\r
+       "save",                         CmdSave,1,              "<filename> -- Save trace (from graph window)",\r
+       "scale",                        CmdScale,1,             "<int> -- Set cursor display scale",\r
+       "setlfdivisor",         CmdSetDivisor,0,        "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)",\r
+       "sri512read",           CmdSri512read,0,        "<int> -- Read contents of a SRI512 tag",\r
+       "sweeplf",                      CmdSweepLF,0,           "    Sweep through LF freq range and store results in buffer",\r
+       "tibits",                       CmdTibits,0,            "    Get raw bits for TI-type LF tag",\r
+       "tidemod",                      CmdTidemod,0,           "    Demodulate raw bits for TI-type LF tag",\r
+       "tiread",                       CmdTiread,0,            "    Read a TI-type 134 kHz tag",\r
+       "tune",                         CmdTune,0,              "    Measure antenna tuning",\r
+       "vchdemod",                     CmdVchdemod,0,          "['clone'] -- Demodulate samples for VeriChip",\r
+       "zerocrossings",        CmdZerocrossings,1,     "    Count time between zero-crossings",\r
 };\r
 \r
 \r
@@ -1933,8 +2467,10 @@ void CommandReceived(char *cmd)
        PrintToScrollback("> %s", cmd);\r
 \r
        if(strcmp(cmd, "help")==0) {\r
+               if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)");\r
                PrintToScrollback("\r\nAvailable commands:");\r
                for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
+                       if (offline && (CommandTable[i].offline==0)) continue;\r
                        char line[256];\r
                        memset(line, ' ', sizeof(line));\r
                        strcpy(line+2, CommandTable[i].name);\r
@@ -1956,6 +2492,10 @@ void CommandReceived(char *cmd)
                        while(*cmd == ' ') {\r
                                cmd++;\r
                        }\r
+                       if (offline && (CommandTable[i].offline==0)) {\r
+                               PrintToScrollback("Offline mode, cannot use this command.");\r
+                               return;\r
+                       }\r
                        (CommandTable[i].handler)(cmd);\r
                        return;\r
                }\r
@@ -1978,7 +2518,7 @@ void UsbCommandReceived(UsbCommand *c)
                        memcpy(s, c->d.asBytes, c->ext1);\r
                        s[c->ext1] = '\0';\r
                        PrintToScrollback("#db# %s", s);\r
-                       break;
+                       break;\r
                }\r
 \r
                case CMD_DEBUG_PRINT_INTEGERS:\r
Impressum, Datenschutz