SendCommand(&c, FALSE);\r
}\r
\r
+static void CmdBuffClear(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_BUFF_CLEAR;\r
+ SendCommand(&c, FALSE);\r
+ CmdClearGraph(TRUE);\r
+}\r
\r
static void CmdQuit(char *str)\r
{\r
{\r
int gtl = GraphTraceLen;\r
GraphTraceLen = 0;\r
- \r
+\r
if (redraw)\r
RepaintGraphWindow();\r
- \r
+\r
return gtl;\r
}\r
\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
+\r
+ for (i = (int)(clock/2); i < clock; i++)\r
GraphBuffer[GraphTraceLen++] = bit;\r
\r
if (redraw)\r
char *zero = "";\r
char *twok = "2000";\r
go = 1;\r
- \r
+\r
do\r
{\r
CmdLoread(zero);\r
} while (go);\r
}\r
\r
+/* Read the transmitted data of an EM4x50 tag\r
+ * Format:\r
+ *\r
+ * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
+ * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
+ * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
+ * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity\r
+ * CCCCCCCC <- column parity bits\r
+ * 0 <- stop bit\r
+ * LW <- Listen Window\r
+ *\r
+ * This pattern repeats for every block of data being transmitted.\r
+ * Transmission starts with two Listen Windows (LW - a modulated\r
+ * pattern of 320 cycles each (32/32/128/64/64)).\r
+ *\r
+ * Note that this data may or may not be the UID. It is whatever data\r
+ * is stored in the blocks defined in the control word First and Last \r
+ * Word Read values. UID is stored in block 32.\r
+ */ \r
+static void CmdEM4x50read(char *str)\r
+{\r
+ int i, j, startblock, clock, skip, block, start, end, low, high;\r
+ BOOL complete= FALSE;\r
+ int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];\r
+ char tmp[6];\r
+\r
+ high= low= 0;\r
+ clock= 64;\r
+\r
+ /* first get high and low values */\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
+ /* populate a buffer with pulse lengths */\r
+ i= 0;\r
+ j= 0;\r
+ while(i < GraphTraceLen)\r
+ {\r
+ // measure from low to low\r
+ while(GraphBuffer[i] > low)\r
+ ++i;\r
+ start= i;\r
+ while(GraphBuffer[i] < high)\r
+ ++i;\r
+ while(GraphBuffer[i] > low)\r
+ ++i;\r
+ tmpbuff[j++]= i - start;\r
+ }\r
+\r
+ \r
+ /* look for data start - should be 2 pairs of LW (pulses of 192,128) */\r
+ start= -1;\r
+ skip= 0;\r
+ for (i= 0; i < j - 4 ; ++i)\r
+ {\r
+ skip += tmpbuff[i];\r
+ if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
+ if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
+ if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
+ if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
+ {\r
+ start= i + 3;\r
+ break;\r
+ }\r
+ }\r
+ startblock= i + 3;\r
+\r
+ /* skip over the remainder of the LW */\r
+ skip += tmpbuff[i+1]+tmpbuff[i+2];\r
+ while(GraphBuffer[skip] > low)\r
+ ++skip;\r
+ skip += 8;\r
+\r
+ /* now do it again to find the end */\r
+ end= start;\r
+ for (i += 3; i < j - 4 ; ++i)\r
+ {\r
+ end += tmpbuff[i];\r
+ if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
+ if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
+ if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)\r
+ if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)\r
+ {\r
+ complete= TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (start >= 0)\r
+ PrintToScrollback("Found data at sample: %i",skip);\r
+ else\r
+ {\r
+ PrintToScrollback("No data found!");\r
+ PrintToScrollback("Try again with more samples.");\r
+ return;\r
+ }\r
+\r
+ if (!complete)\r
+ {\r
+ PrintToScrollback("*** Warning!");\r
+ PrintToScrollback("Partial data - no end found!");\r
+ PrintToScrollback("Try again with more samples.");\r
+ }\r
+\r
+ /* get rid of leading crap */\r
+ sprintf(tmp,"%i",skip);\r
+ CmdLtrim(tmp);\r
+\r
+ /* now work through remaining buffer printing out data blocks */\r
+ block= 0;\r
+ i= startblock;\r
+ while(block < 6)\r
+ {\r
+ PrintToScrollback("Block %i:", block);\r
+ // mandemod routine needs to be split so we can call it for data\r
+ // just print for now for debugging\r
+ Cmdmanchesterdemod("i 64");\r
+ skip= 0;\r
+ /* look for LW before start of next block */\r
+ for ( ; i < j - 4 ; ++i)\r
+ {\r
+ skip += tmpbuff[i];\r
+ if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)\r
+ if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)\r
+ break;\r
+ }\r
+ while(GraphBuffer[skip] > low)\r
+ ++skip;\r
+ skip += 8;\r
+ sprintf(tmp,"%i",skip);\r
+ CmdLtrim(tmp);\r
+ start += skip;\r
+ block++;\r
+ }\r
+}\r
+\r
+\r
/* Read the ID of an EM410x tag.\r
* Format:\r
* 1111 1111 1 <-- standard non-repeatable header\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
+\r
/* Detect high and lows and clock */\r
for (i = 0; i < GraphTraceLen; i++)\r
{\r
high = GraphBuffer[i];\r
else if (GraphBuffer[i] < low)\r
low = GraphBuffer[i];\r
- } \r
- \r
+ }\r
+\r
/* get clock */\r
clock = GetClock(str, high);\r
- \r
+\r
/* parity for our 4 columns */\r
parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
header = rows = 0;\r
- \r
+\r
/* manchester demodulate */\r
bit = bit2idx = 0;\r
for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
hithigh = 0;\r
hitlow = 0;\r
first = 1;\r
- \r
+\r
/* Find out if we hit both high and low peaks */\r
for (j = 0; j < clock; j++)\r
{\r
hithigh = 1;\r
else if (GraphBuffer[(i * clock) + j] == low)\r
hitlow = 1;\r
- \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
+\r
if (hithigh && hitlow)\r
break;\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
/* 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
+\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
+\r
/* Move 4 bits ahead */\r
i += 4;\r
}\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
+\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
+\r
/* Step 3: Got our 40 bits! confirm column parity */\r
else if (rows == 10)\r
{\r
{\r
/* Sweet! */\r
PrintToScrollback("EM410x Tag ID: %s", id);\r
- \r
+\r
/* Stop any loops */\r
go = 0;\r
- break;\r
+ return;\r
}\r
- \r
+\r
/* Crap! Incorrect parity or no stop bit, start all over */\r
else\r
{\r
rows = header = 0;\r
- \r
+\r
/* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */\r
i -= 59;\r
}\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
+\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
{\r
int i, n, j, h, binary[4], parity[4];\r
char *s = "0";\r
- \r
+\r
/* clock is 64 in EM410x tags */\r
int clock = 64;\r
- \r
+\r
/* clear our graph */\r
CmdClearGraph(0);\r
- \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
+\r
/* for each hex char */\r
parity[0] = parity[1] = parity[2] = parity[3] = 0;\r
for (i = 0; i < 10; i++)\r
sscanf(&str[i], "%1x", &n);\r
for (j = 3; j >= 0; j--, n/= 2)\r
binary[j] = n % 2;\r
- \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
+\r
/* append parity bit */\r
CmdAppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);\r
- \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
+\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
+\r
/* stop bit */\r
CmdAppendGraph(0, clock, 0);\r
}\r
- \r
+\r
/* modulate that biatch */\r
Cmdmanchestermod(s);\r
- \r
+\r
/* booyah! */\r
RepaintGraphWindow();\r
\r
static void ChkBitstream(char *str)\r
{\r
int i;\r
- \r
+\r
/* convert to bitstream if necessary */\r
for (i = 0; i < (int)(GraphTraceLen / 2); i++)\r
{\r
static void CmdLosim(char *str)\r
{\r
int i;\r
- char *zero = "0";\r
- \r
+\r
/* convert to bitstream if necessary */\r
ChkBitstream(str);\r
- \r
+\r
for (i = 0; i < GraphTraceLen; i += 48) {\r
UsbCommand c;\r
int j;\r
SendCommand(&c, FALSE);\r
}\r
\r
+static void CmdDetectReader(char *str)\r
+{\r
+ UsbCommand c;\r
+ // 'l' means LF - 125/134 kHz\r
+ if(*str == 'l') {\r
+ c.ext1 = 1;\r
+ } else if (*str == 'h') {\r
+ c.ext1 = 2;\r
+ } else if (*str != '\0') {\r
+ PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'");\r
+ return;\r
+ }\r
+ c.cmd = CMD_LISTEN_READER_FIELD;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+/* send a command before reading */\r
+static void CmdLoCommandRead(char *str)\r
+{\r
+ static char dummy[3];\r
+\r
+ dummy[0]= ' ';\r
+ \r
+ UsbCommand c;\r
+ c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
+ sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, &c.d.asBytes,&dummy+1);\r
+ // in case they specified 'h'\r
+ strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
static void CmdLosamples(char *str)\r
{\r
int cnt = 0;\r
}\r
\r
/*\r
- * Generic command to demodulate ASK. bit length in argument.\r
- * Giving the bit length helps discriminate ripple effects\r
- * upon zero crossing for noisy traces.\r
+ * Generic command to demodulate ASK.\r
*\r
- * Second is convention: positive or negative (High mod means zero\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
- * sl : bit length in terms of number of samples per bit\r
- * (use yellow/purple markers to compute).\r
* c : 0 or 1\r
*/\r
\r
static void Cmdaskdemod(char *str) {\r
int i;\r
- int sign = 1;\r
- int n = 0;\r
- int c = 0;\r
- int t1 = 0;\r
+ int c, high = 0, low = 0;\r
\r
// TODO: complain if we do not give 2 arguments here !\r
- sscanf(str, "%i %i", &n, &c);\r
- if (c == 0) {\r
- c = 1 ;\r
- } else {\r
- c = -1;\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]*c > 0) {\r
- GraphBuffer[0] = 1;\r
+ if (GraphBuffer[0] > 0) {\r
+ GraphBuffer[0] = 1-c;\r
} else {\r
- GraphBuffer[0] = 0;\r
+ GraphBuffer[0] = c;\r
}\r
for(i=1;i<GraphTraceLen;i++) {\r
- /* Analyse signal within the symbol length */\r
- /* Decide if we crossed a zero */\r
- if (GraphBuffer[i]*sign < 0) {\r
- /* Crossed a zero, check if this is a ripple or not */\r
- if ( (i-t1) > n/4 ) {\r
- sign = -sign;\r
- t1=i;\r
- if (GraphBuffer[i]*c > 0){\r
- GraphBuffer[i]=1;\r
- } else {\r
- GraphBuffer[i]=0;\r
- }\r
- } else {\r
- /* This is a ripple, set the current sample value\r
- to the same as previous */\r
- GraphBuffer[i] = GraphBuffer[i-1];\r
- }\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
lastpeak = i;\r
}\r
}\r
- \r
+\r
return clock;\r
}\r
\r
int GetClock(char *str, int peak)\r
{\r
int clock;\r
- \r
+\r
sscanf(str, "%i", &clock);\r
if (!strcmp(str, ""))\r
clock = 0;\r
if (!clock)\r
{\r
clock = detectclock(peak);\r
- \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
+\r
return clock;\r
}\r
\r
\r
/* Get our clock */\r
clock = GetClock(str, high);\r
- \r
+\r
gtl = CmdClearGraph(0);\r
- \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
+\r
/* Find out if we hit both high and low peaks */\r
for (j = 0; j < clock; j++)\r
{\r
hithigh = 1;\r
else if (GraphBuffer[(i * clock) + j] == low)\r
hitlow = 1;\r
- \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
+\r
if (hithigh && hitlow)\r
break;\r
}\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
int i, j;\r
int clock;\r
int bit, lastbit, wave;\r
- \r
+\r
/* Get our clock */\r
clock = GetClock(str, 0);\r
\r
for (i = 0; i < (int)(GraphTraceLen / clock); i++)\r
{\r
bit = GraphBuffer[i * clock] ^ 1;\r
- \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
+\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
+\r
RepaintGraphWindow();\r
}\r
\r
* Typical values can be 64, 32, 128...\r
*/\r
static void Cmdmanchesterdemod(char *str) {\r
- int i, j;\r
+ int i, j, invert= 0;\r
int bit;\r
int clock;\r
int lastval;\r
int bit2idx = 0;\r
int warnings = 0;\r
\r
+ /* check if we're inverting output */\r
+ if(*str == 'i')\r
+ {\r
+ PrintToScrollback("Inverting output");\r
+ invert= 1;\r
+ do\r
+ ++str;\r
+ while(*str == ' '); // in case a 2nd argument was given\r
+ }\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
\r
/* Get our clock */\r
clock = GetClock(str, high);\r
- \r
+\r
int tolerance = clock/4;\r
- \r
+\r
/* Detect first transition */\r
/* Lo-Hi (arbitrary) */\r
for (i = 0; i < GraphTraceLen; i++)\r
/* If we're not working with 1/0s, demod based off clock */\r
if (high != 1)\r
{\r
- bit = 0;\r
- for (i = 0; i < (int)(GraphTraceLen / clock); i++)\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
if (!hithigh || !hitlow)\r
bit ^= 1;\r
\r
- BitStream[bit2idx++] = bit;\r
+ BitStream[bit2idx++] = bit ^ invert;\r
}\r
}\r
\r
else\r
{\r
\r
- /* Then detect duration between 2 successive transitions */\r
+ /* Then detect duration between 2 successive transitions */\r
for (bitidx = 1; i < GraphTraceLen; i++)\r
{\r
if (GraphBuffer[i-1] != GraphBuffer[i])\r
PrintToScrollback("Error: too many detection errors, aborting.");\r
return;\r
}\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
+ // 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 ^ invert;\r
} else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {\r
- BitStream[bit2idx++] = 0;\r
+ BitStream[bit2idx++] = 0 ^ invert;\r
} else {\r
// We cannot end up in this state, this means we are unsynchronized,\r
// move up 1 bit:\r
PrintToScrollback("Error: too many decode errors, aborting.");\r
return;\r
}\r
- }\r
- }\r
+ }\r
+ } \r
}\r
\r
PrintToScrollback("Manchester decoded bitstream");\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
+ "buffclear", CmdBuffClear,0, " Clear sample buffer and graph window",\r
"dec", CmdDec,1, " Decimate samples",\r
"detectclock", Cmddetectclockrate,1, " Detect clock rate",\r
+ "detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)",\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
+ "em4x50read", CmdEM4x50read,1, " Extract data from EM4x50 tag",\r
"exit", CmdQuit,1, " Exit program",\r
"flexdemod", CmdFlexdemod,1, " Demodulate samples for FlexPass",\r
"fpgaoff", CmdFPGAOff,0, " Set FPGA off", // ## FPGA Control\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
+ "indalademod", CmdIndalademod,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)",\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
+ "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
"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
+ "mandemod", Cmdmanchesterdemod,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)",\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