X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/e7aee94e6a3f4f7ef38a4d06b837cf6141e731b9..bea2a8660edd6cabce704207548d669761ef4a6d:/winsrc/command.cpp?ds=inline

diff --git a/winsrc/command.cpp b/winsrc/command.cpp
index 14974528..08feb3dd 100644
--- a/winsrc/command.cpp
+++ b/winsrc/command.cpp
@@ -12,6 +12,7 @@
 
 #include "prox.h"
 #include "../common/iso14443_crc.c"
+#include "../common/crc16.c"
 
 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
 #define BIT(x) GraphBuffer[x * clock]
@@ -272,9 +273,9 @@ static void CmdEM410xwatch(char *str)
  * pattern of 320 cycles each (32/32/128/64/64)).
  *
  * Note that this data may or may not be the UID. It is whatever data
- * is stored in the blocks defined in the control word First and Last 
+ * is stored in the blocks defined in the control word First and Last
  * Word Read values. UID is stored in block 32.
- */ 
+ */
 static void CmdEM4x50read(char *str)
 {
 	int i, j, startblock, clock, skip, block, start, end, low, high;
@@ -288,7 +289,7 @@ static void CmdEM4x50read(char *str)
 	/* first get high and low values */
 	for (i = 0; i < GraphTraceLen; i++)
 	{
-		if (GraphBuffer[i] > high)	
+		if (GraphBuffer[i] > high)
 			high = GraphBuffer[i];
 		else if (GraphBuffer[i] < low)
 			low = GraphBuffer[i];
@@ -300,17 +301,19 @@ static void CmdEM4x50read(char *str)
 	while(i < GraphTraceLen)
 		{
 		// measure from low to low
-		while(GraphBuffer[i] > low)
+		while((GraphBuffer[i] > low) && (i<GraphTraceLen))
 			++i;
 		start= i;
-		while(GraphBuffer[i] < high)
+		while((GraphBuffer[i] < high) && (i<GraphTraceLen))
 			++i;
-		while(GraphBuffer[i] > low)
+		while((GraphBuffer[i] > low) && (i<GraphTraceLen))
 			++i;
+		if (j>(MAX_GRAPH_TRACE_LEN/64)) {
+			break;
+		}
 		tmpbuff[j++]= i - start;
 		}
 
-	
 	/* look for data start - should be 2 pairs of LW (pulses of 192,128) */
 	start= -1;
 	skip= 0;
@@ -330,7 +333,7 @@ static void CmdEM4x50read(char *str)
 
 	/* skip over the remainder of the LW */
 	skip += tmpbuff[i+1]+tmpbuff[i+2];
-	while(GraphBuffer[skip] > low)
+	while(skip < MAX_GRAPH_TRACE_LEN && GraphBuffer[skip] > low)
 		++skip;
 	skip += 8;
 
@@ -457,14 +460,14 @@ static void CmdEM410xread(char *str)
 			if (hithigh && hitlow)
 				break;
 		}
-		
+
 		/* If we didn't hit both high and low peaks, we had a bit transition */
 		if (!hithigh || !hitlow)
 			bit ^= 1;
-		
+
 		BitStream[bit2idx++] = bit;
 	}
-	
+
 retest:
 	/* We go till 5 before the graph ends because we'll get that far below */
 	for (i = 1; i < bit2idx - 5; i++)
@@ -539,7 +542,7 @@ retest:
 				header = 0;
 		}
 	}
-	
+
 	/* if we've already retested after flipping bits, return */
 	if (retested++)
 		return;
@@ -698,7 +701,7 @@ static void CmdLoCommandRead(char *str)
 	static char dummy[3];
 
 	dummy[0]= ' ';
-	
+
 	UsbCommand c;
 	c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K;
 	sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, (char *) &c.d.asBytes,(char *) &dummy+1);
@@ -795,7 +798,6 @@ static void CmdHisamples(char *str)
 	RepaintGraphWindow();
 }
 
-
 static int CmdHisamplest(char *str, int nrlow)
 {
 	int cnt = 0;
@@ -1395,44 +1397,150 @@ static void CmdHi15demod(char *str)
 	PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));
 }
 
-static void CmdTiread(char *str)
+static void CmdFSKdemod(char *cmdline)
 {
-	UsbCommand c;
-	c.cmd = CMD_ACQUIRE_RAW_BITS_TI_TYPE;
-	SendCommand(&c, FALSE);
-}
+	static const int LowTone[]  = {
+		1,  1,  1,  1,  1, -1, -1, -1, -1, -1,
+		1,  1,  1,  1,  1, -1, -1, -1, -1, -1,
+		1,  1,  1,  1,  1, -1, -1, -1, -1, -1,
+		1,  1,  1,  1,  1, -1, -1, -1, -1, -1,
+		1,  1,  1,  1,  1, -1, -1, -1, -1, -1
+	};
+	static const int HighTone[] = {
+		1,  1,  1,  1,  1,     -1, -1, -1, -1,
+		1,  1,  1,  1,         -1, -1, -1, -1,
+		1,  1,  1,  1,         -1, -1, -1, -1,
+		1,  1,  1,  1,         -1, -1, -1, -1,
+		1,  1,  1,  1,         -1, -1, -1, -1,
+		1,  1,  1,  1,     -1, -1, -1, -1, -1,
+	};
 
-static void CmdTibits(char *str)
-{
-	int cnt = 0;
-	int i;
-	for(i = 0; i < 1536; i += 12) {
-		UsbCommand c;
-		c.cmd = CMD_DOWNLOAD_RAW_BITS_TI_TYPE;
-		c.ext1 = i;
-		SendCommand(&c, FALSE);
-		ReceiveCommand(&c);
-		if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {
-			PrintToScrollback("bad resp");
-			return;
+	int lowLen = sizeof(LowTone)/sizeof(int);
+	int highLen = sizeof(HighTone)/sizeof(int);
+	int convLen = (highLen>lowLen)?highLen:lowLen;
+	DWORD hi = 0, lo = 0;
+
+	int i, j;
+	int minMark=0, maxMark=0;
+
+	for(i = 0; i < GraphTraceLen - convLen; i++) {
+		int lowSum = 0, highSum = 0;
+
+		for(j = 0; j < lowLen; j++) {
+			lowSum += LowTone[j]*GraphBuffer[i+j];
 		}
+		for(j = 0; j < highLen; j++) {
+			highSum += HighTone[j]*GraphBuffer[i+j];
+		}
+		lowSum = abs((100*lowSum) / lowLen);
+		highSum = abs((100*highSum) / highLen);
+		GraphBuffer[i] = (highSum << 16) | lowSum;
+	}
+
+	for(i = 0; i < GraphTraceLen - convLen - 16; i++) {
 		int j;
-		for(j = 0; j < 12; j++) {
-			int k;
-			for(k = 31; k >= 0; k--) {
-				if(c.d.asDwords[j] & (1 << k)) {
-					GraphBuffer[cnt++] = 1;
-				} else {
-					GraphBuffer[cnt++] = -1;
-				}
-			}
+		int lowTot = 0, highTot = 0;
+		// 10 and 8 are f_s divided by f_l and f_h, rounded
+		for(j = 0; j < 10; j++) {
+			lowTot += (GraphBuffer[i+j] & 0xffff);
 		}
+		for(j = 0; j < 8; j++) {
+			highTot += (GraphBuffer[i+j] >> 16);
+		}
+		GraphBuffer[i] = lowTot - highTot;
+		if (GraphBuffer[i]>maxMark) maxMark=GraphBuffer[i];
+		if (GraphBuffer[i]<minMark) minMark=GraphBuffer[i];
 	}
-	GraphTraceLen = 1536*32;
+
+	GraphTraceLen -= (convLen + 16);
+
 	RepaintGraphWindow();
+
+	// Find bit-sync (3 lo followed by 3 high)
+	int max = 0, maxPos = 0;
+	for(i = 0; i < 6000; i++) {
+		int dec = 0;
+		for(j = 0; j < 3*lowLen; j++) {
+			dec -= GraphBuffer[i+j];
+		}
+		for(; j < 3*(lowLen + highLen ); j++) {
+			dec += GraphBuffer[i+j];
+		}
+		if(dec > max) {
+			max = dec;
+			maxPos = i;
+		}
+	}
+
+	// place start of bit sync marker in graph
+	GraphBuffer[maxPos] = maxMark;
+	GraphBuffer[maxPos+1] = minMark;
+
+	maxPos += j;
+
+	// place end of bit sync marker in graph
+	GraphBuffer[maxPos] = maxMark;
+	GraphBuffer[maxPos+1] = minMark;
+
+	PrintToScrollback("actual data bits start at sample %d", maxPos);
+	PrintToScrollback("length %d/%d", highLen, lowLen);
+
+	BYTE bits[46];
+	bits[sizeof(bits)-1] = '\0';
+
+	// find bit pairs and manchester decode them
+	for(i = 0; i < arraylen(bits)-1; i++) {
+		int dec = 0;
+		for(j = 0; j < lowLen; j++) {
+			dec -= GraphBuffer[maxPos+j];
+		}
+		for(; j < lowLen + highLen; j++) {
+			dec += GraphBuffer[maxPos+j];
+		}
+		maxPos += j;
+		// place inter bit marker in graph
+		GraphBuffer[maxPos] = maxMark;
+		GraphBuffer[maxPos+1] = minMark;
+
+		// hi and lo form a 64 bit pair
+		hi = (hi<<1)|(lo>>31);
+		lo = (lo<<1);
+		// store decoded bit as binary (in hi/lo) and text (in bits[])
+		if(dec<0) {
+			bits[i] = '1';
+			lo|=1;
+		} else {
+			bits[i] = '0';
+		}
+	}
+	PrintToScrollback("bits: '%s'", bits);
+	PrintToScrollback("hex: %08x %08x", hi, lo);
 }
 
-static void CmdTidemod(char *cmdline)
+// read a TI tag and return its ID
+static void CmdTIRead(char *str)
+{
+	UsbCommand c;
+	c.cmd = CMD_READ_TI_TYPE;
+	SendCommand(&c, FALSE);
+}
+
+// write new data to a r/w TI tag
+static void CmdTIWrite(char *str)
+{
+	UsbCommand c;
+	int res=0;
+
+	c.cmd = CMD_WRITE_TI_TYPE;
+	res = sscanf(str, "0x%x 0x%x 0x%x ", &c.ext1, &c.ext2, &c.ext3);
+	if (res == 2) c.ext3=0;
+	if (res<2)
+		PrintToScrollback("Please specify the data as two hex strings, optionally the CRC as a third");
+	else
+		SendCommand(&c, FALSE);
+}
+
+static void CmdTIDemod(char *cmdline)
 {
 	/* MATLAB as follows:
 f_s = 2000000;  % sampling frequency
@@ -1448,46 +1556,57 @@ h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);
 l = sign(sin(cumsum(l)));
 h = sign(sin(cumsum(h)));
 	*/
-	static const int LowTone[] = {
-		1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,
-		1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
-		1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
-		-1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
-		-1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,
-		-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
-		1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,
-		1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
-		1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,
-		-1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,
-		-1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
-		-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
-		1, 1, 1, 1, 1, 1, 1, -1, -1, -1,
-	};
-	static const int HighTone[] = {
-		1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
-		1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
-		-1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
-		-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
-		1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
-		1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
-		-1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
-		-1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
-		1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
-		1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
-		-1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
-		-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,
-		1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,
-		1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,
-	};
 
-	int convLen = max(arraylen(HighTone), arraylen(LowTone));
+// 2M*16/134.2k = 238
+ static const int LowTone[] = {
+	1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		 -1, -1
+ };
+// 2M*16/123.2k = 260
+ static const int HighTone[] = {
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1,		-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1,			-1, -1, -1, -1, -1, -1, -1,
+	1, 1, 1, 1, 1, 1, 1, 1
+ };
+	int lowLen = sizeof(LowTone)/sizeof(int);
+	int highLen = sizeof(HighTone)/sizeof(int);
+	int convLen = (highLen>lowLen)?highLen:lowLen;
+	WORD crc;
+	int i, j, TagType;
+	int lowSum = 0, highSum = 0;;
+	int lowTot = 0, highTot = 0;
 
-	int i;
 	for(i = 0; i < GraphTraceLen - convLen; i++) {
-		int j;
-		int lowSum = 0, highSum = 0;;
-		int lowLen = arraylen(LowTone);
-		int highLen = arraylen(HighTone);
+		lowSum = 0;
+		highSum = 0;;
 
 		for(j = 0; j < lowLen; j++) {
 			lowSum += LowTone[j]*GraphBuffer[i+j];
@@ -1497,12 +1616,15 @@ h = sign(sin(cumsum(h)));
 		}
 		lowSum = abs((100*lowSum) / lowLen);
 		highSum = abs((100*highSum) / highLen);
+		lowSum = (lowSum<0)?-lowSum:lowSum;
+		highSum = (highSum<0)?-highSum:highSum;
+
 		GraphBuffer[i] = (highSum << 16) | lowSum;
 	}
 
 	for(i = 0; i < GraphTraceLen - convLen - 16; i++) {
-		int j;
-		int lowTot = 0, highTot = 0;
+		lowTot = 0;
+		highTot = 0;
 		// 16 and 15 are f_s divided by f_l and f_h, rounded
 		for(j = 0; j < 16; j++) {
 			lowTot += (GraphBuffer[i+j] & 0xffff);
@@ -1517,17 +1639,29 @@ h = sign(sin(cumsum(h)));
 
 	RepaintGraphWindow();
 
-	// Okay, so now we have unsliced soft decisions; find bit-sync, and then
-	// get some bits.
+	// TI tag data format is 16 prebits, 8 start bits, 64 data bits,
+	// 16 crc CCITT bits, 8 stop bits, 15 end bits
+
+	// the 16 prebits are always low
+	// the 8 start and stop bits of a tag must match
+	// the start/stop prebits of a ro tag are 01111110
+	// the start/stop prebits of a rw tag are 11111110
+  // the 15 end bits of a ro tag are all low
+  // the 15 end bits of a rw tag match bits 15-1 of the data bits
 
+	// Okay, so now we have unsliced soft decisions;
+	// find bit-sync, and then get some bits.
+	// look for 17 low bits followed by 6 highs (common pattern for ro and rw tags)
 	int max = 0, maxPos = 0;
 	for(i = 0; i < 6000; i++) {
 		int j;
 		int dec = 0;
-		for(j = 0; j < 8*arraylen(LowTone); j++) {
+		// searching 17 consecutive lows
+		for(j = 0; j < 17*lowLen; j++) {
 			dec -= GraphBuffer[i+j];
 		}
-		for(; j < 8*arraylen(LowTone) + 8*arraylen(HighTone); j++) {
+		// searching 7 consecutive highs
+		for(; j < 17*lowLen + 6*highLen; j++) {
 			dec += GraphBuffer[i+j];
 		}
 		if(dec > max) {
@@ -1535,61 +1669,113 @@ h = sign(sin(cumsum(h)));
 			maxPos = i;
 		}
 	}
-	GraphBuffer[maxPos] = 800;
-	GraphBuffer[maxPos+1] = -800;
 
-	maxPos += 8*arraylen(LowTone);
+	// place a marker in the buffer to visually aid location
+	// of the start of sync
 	GraphBuffer[maxPos] = 800;
 	GraphBuffer[maxPos+1] = -800;
-	maxPos += 8*arraylen(HighTone);
 
+	// advance pointer to start of actual data stream (after 16 pre and 8 start bits)
+	maxPos += 17*lowLen;
+	maxPos += 6*highLen;
+
+	// place a marker in the buffer to visually aid location
+	// of the end of sync
 	GraphBuffer[maxPos] = 800;
 	GraphBuffer[maxPos+1] = -800;
 
 	PrintToScrollback("actual data bits start at sample %d", maxPos);
 
-	PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));
-
-	GraphBuffer[maxPos] = 800;
-	GraphBuffer[maxPos+1] = -800;
+	PrintToScrollback("length %d/%d", highLen, lowLen);
 
-	BYTE bits[64+16+8+1];
+	BYTE bits[1+64+16+8+16];
 	bits[sizeof(bits)-1] = '\0';
 
-	for(i = 0; i < arraylen(bits); i++) {
+	DWORD shift3 = 0x7e000000, shift2 = 0, shift1 = 0, shift0 = 0;
+
+	for(i = 0; i < arraylen(bits)-1; i++) {
 		int high = 0;
 		int low = 0;
 		int j;
-		for(j = 0; j < arraylen(LowTone); j++) {
+		for(j = 0; j < lowLen; j++) {
 			low -= GraphBuffer[maxPos+j];
 		}
-		for(j = 0; j < arraylen(HighTone); j++) {
+		for(j = 0; j < highLen; j++) {
 			high += GraphBuffer[maxPos+j];
 		}
+
 		if(high > low) {
 			bits[i] = '1';
-			maxPos += arraylen(HighTone);
+			maxPos += highLen;
+			// bitstream arrives lsb first so shift right
+			shift3 |= (1<<31);
 		} else {
 			bits[i] = '.';
-			maxPos += arraylen(LowTone);
+			maxPos += lowLen;
 		}
+
+		// 128 bit right shift register
+	  shift0 = (shift0>>1) | (shift1 << 31);
+	  shift1 = (shift1>>1) | (shift2 << 31);
+	  shift2 = (shift2>>1) | (shift3 << 31);
+	  shift3 >>= 1;
+
+		// place a marker in the buffer between bits to visually aid location
 		GraphBuffer[maxPos] = 800;
 		GraphBuffer[maxPos+1] = -800;
 	}
-	PrintToScrollback("bits: '%s'", bits);
+	PrintToScrollback("Info: raw tag bits = %s", bits);
 
-	DWORD h = 0, l = 0;
-	for(i = 0; i < 32; i++) {
-		if(bits[i] == '1') {
-			l |= (1<<i);
-		}
+	TagType = (shift3>>8)&0xff;
+	if ( TagType != ((shift0>>16)&0xff) ) {
+		PrintToScrollback("Error: start and stop bits do not match!");
+		return;
+	}
+	else if (TagType == 0x7e) {
+		PrintToScrollback("Info: Readonly TI tag detected.");
+		return;
 	}
-	for(i = 32; i < 64; i++) {
-		if(bits[i] == '1') {
-			h |= (1<<(i-32));
+	else if (TagType == 0xfe) {
+		PrintToScrollback("Info: Rewriteable TI tag detected.");
+
+	  // put 64 bit data into shift1 and shift0
+	  shift0 = (shift0>>24) | (shift1 << 8);
+	  shift1 = (shift1>>24) | (shift2 << 8);
+
+		// align 16 bit crc into lower half of shift2
+	  shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;
+
+		// align 16 bit "end bits" or "ident" into lower half of shift3
+	  shift3 >>= 16;
+
+		// only 15 bits compare, last bit of ident is not valid
+		if ( (shift3^shift0)&0x7fff ) {
+			PrintToScrollback("Error: Ident mismatch!");
+		}
+		// WARNING the order of the bytes in which we calc crc below needs checking
+		// i'm 99% sure the crc algorithm is correct, but it may need to eat the
+		// bytes in reverse or something
+		// calculate CRC
+		crc=0;
+	 	crc = update_crc16(crc, (shift0)&0xff);
+		crc = update_crc16(crc, (shift0>>8)&0xff);
+		crc = update_crc16(crc, (shift0>>16)&0xff);
+		crc = update_crc16(crc, (shift0>>24)&0xff);
+		crc = update_crc16(crc, (shift1)&0xff);
+		crc = update_crc16(crc, (shift1>>8)&0xff);
+		crc = update_crc16(crc, (shift1>>16)&0xff);
+		crc = update_crc16(crc, (shift1>>24)&0xff);
+		PrintToScrollback("Info: Tag data = %08X%08X", shift1, shift0);
+		if (crc != (shift2&0xffff)) {
+			PrintToScrollback("Error: CRC mismatch, calculated %04X, got ^04X", crc, shift2&0xffff);
+		} else {
+			PrintToScrollback("Info: CRC %04X is good", crc);
 		}
 	}
-	PrintToScrollback("hex: %08x %08x", h, l);
+	else {
+		PrintToScrollback("Unknown tag type.");
+		return;
+	}
 }
 
 static void CmdNorm(char *str)
@@ -1667,6 +1853,20 @@ static void CmdZerocrossings(char *str)
 	RepaintGraphWindow();
 }
 
+static void CmdThreshold(char *str)
+{
+	int i;
+	int threshold = atoi(str);
+
+	for(i = 0; i < GraphTraceLen; i++) {
+		if(GraphBuffer[i]>= threshold)
+			GraphBuffer[i]=1;
+		else
+			GraphBuffer[i]=-1;
+	}
+	RepaintGraphWindow();
+}
+
 static void CmdLtrim(char *str)
 {
 	int i;
@@ -2397,7 +2597,7 @@ static void Cmdmanchesterdemod(char *str) {
 					return;
 				}
 			}
-		}	
+		}
 	}
 
 	PrintToScrollback("Manchester decoded bitstream");
@@ -2423,8 +2623,6 @@ static void Cmdmanchesterdemod(char *str) {
 	}
 }
 
-
-
 /*
  * Usage ???
  */
@@ -2452,6 +2650,12 @@ static void CmdPlot(char *str)
 	ShowGraphWindow();
 }
 
+static void CmdGrid(char *str)
+{
+  	sscanf(str, "%i %i", &PlotGridX, &PlotGridY);
+	RepaintGraphWindow();
+}
+
 static void CmdHide(char *str)
 {
 	HideGraphWindow();
@@ -2548,12 +2752,6 @@ static void CmdLcd(char *str)
 	}
 }
 
-
-
-static void CmdTest(char *str)
-{
-}
-
 /*
  * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
  * 600kHz.
@@ -2580,71 +2778,74 @@ static struct {
 	int		offline;  // 1 if the command can be used when in offline mode
 	char		*docString;
 } CommandTable[] = {
-	{"askdemod",			Cmdaskdemod,1,		"<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags"},
-	{"autocorr",			CmdAutoCorr,1,		"<window length> -- Autocorrelation over window"},
-	{"bitsamples",		CmdBitsamples,0,	"    Get raw samples as bitstring"},
-	{"bitstream",		Cmdbitstream,1,		"[clock rate] -- Convert waveform into a bitstream"},
-	{"buffclear",		CmdBuffClear,0,		"    Clear sample buffer and graph window"},
-	{"dec",				CmdDec,1,		"    Decimate samples"},
-	{"detectclock",		Cmddetectclockrate,1, "    Detect clock rate"},
-	{"detectreader",		CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
-	{"em410xsim",		CmdEM410xsim,1,		"<UID> -- Simulate EM410x tag"},
-	{"em410xread",		CmdEM410xread,1,	"[clock rate] -- Extract ID from EM410x tag"},
-	{"em410xwatch",		CmdEM410xwatch,0,	"    Watches for EM410x tags"},
-	{"em4x50read",		CmdEM4x50read,1,	"    Extract data from EM4x50 tag"},
-	{"exit",				CmdQuit,1,			"    Exit program"},
-	{"flexdemod",		CmdFlexdemod,1,		"    Demodulate samples for FlexPass"},
-	{"fpgaoff",			CmdFPGAOff,0,		"    Set FPGA off"},							// ## FPGA Control
-	{"hexsamples",		CmdHexsamples,0,	"<blocks> -- Dump big buffer as hex bytes"},
-	{"hi14alist",		CmdHi14alist,0,		"    List ISO 14443a history"},				// ## New list command
-	{"hi14areader",		CmdHi14areader,0,	"    Act like an ISO14443 Type A reader"},	// ## New reader command
-	{"hi14asim",			CmdHi14asim,0,		"<UID> -- Fake ISO 14443a tag"},					// ## Simulate 14443a tag
-	{"hi14asnoop",		CmdHi14asnoop,0,	"    Eavesdrop ISO 14443 Type A"},			// ## New snoop command
-	{"hi14bdemod",		CmdHi14bdemod,1,	"    Demodulate ISO14443 Type B from tag"},
-	{"hi14list",			CmdHi14list,0,		"    List ISO 14443 history"},
-	{"hi14read",			CmdHi14read,0,		"    Read HF tag (ISO 14443)"},
-	{"hi14sim",			CmdHi14sim,0,		"    Fake ISO 14443 tag"},
-	{"hi14snoop",		CmdHi14snoop,0,		"    Eavesdrop ISO 14443"},
-	{"hi15demod",		CmdHi15demod,1,		"    Demodulate ISO15693 from tag"},
-	{"hi15read",			CmdHi15read,0,		"    Read HF tag (ISO 15693)"},
-	{"hi15reader",		CmdHi15reader,0,	"    Act like an ISO15693 reader"}, // new command greg
-	{"hi15sim",			CmdHi15tag,0,		"    Fake an ISO15693 tag"}, // new command greg
-	{"hiddemod",			CmdHiddemod,1,		"    Demodulate HID Prox Card II (not optimal)"},
-	{"hide",				CmdHide,1,		"    Hide graph window"},
-	{"hidfskdemod",		CmdHIDdemodFSK,0,	"    Realtime HID FSK demodulator"},
-	{"hidsimtag",		CmdHIDsimTAG,0,		"<ID> -- HID tag simulator"},
-	{"higet",			CmdHi14read_sim,0,	"<samples> -- Get samples HF, 'analog'"},
-	{"hisamples",		CmdHisamples,0,		"    Get raw samples for HF tag"},
-	{"hisampless",		CmdHisampless,0,	"<samples> -- Get signed raw samples, HF tag"},
-	{"hisamplest",		CmdHi14readt,0,		"    Get samples HF, for testing"},
-	{"hisimlisten",		CmdHisimlisten,0,	"    Get HF samples as fake tag"},
-	{"hpf",				CmdHpf,1,		"    Remove DC offset from trace"},
-	{"indalademod",		CmdIndalademod,0,         "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
-	{"lcd",				CmdLcd,0,			"<HEX command> <count> -- Send command/data to LCD"},
-	{"lcdreset",			CmdLcdReset,0,		"    Hardware reset LCD"},
-	{"load",				CmdLoad,1,		"<filename> -- Load trace (to graph window"},
-	{"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)"},
-	{"loread",			CmdLoread,0,		"['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
-	{"losamples",		CmdLosamples,0,		"[128 - 16000] -- Get raw samples for LF tag"},
-	{"losim",			CmdLosim,0,		"    Simulate LF tag"},
-	{"ltrim",			CmdLtrim,1,		"<samples> -- Trim samples from left of trace"},
-	{"mandemod",			Cmdmanchesterdemod,1,	"[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
-	{"manmod",			Cmdmanchestermod,1,	"[clock rate] -- Manchester modulate a binary stream"},
-	{"norm",				CmdNorm,1,		"    Normalize max/min to +/-500"},
-	{"plot",				CmdPlot,1,		"    Show graph window"},
-	{"quit",				CmdQuit,1,			"    Quit program"},
-	{"readmem",			CmdReadmem,0,			"    [address] Read memory at decimal address from flash"},
-	{"reset",			CmdReset,0,			"    Reset the Proxmark3"},
-	{"save",				CmdSave,1,		"<filename> -- Save trace (from graph window)"},
-	{"scale",			CmdScale,1,		"<int> -- Set cursor display scale"},
-	{"setlfdivisor",		CmdSetDivisor,0,	"<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
-	{"sri512read",		CmdSri512read,0,	"<int> -- Read contents of a SRI512 tag"},
-	{"tibits",			CmdTibits,0,		"    Get raw bits for TI-type LF tag"},
-	{"tidemod",			CmdTidemod,0,		"    Demodulate raw bits for TI-type LF tag"},
-	{"tiread",			CmdTiread,0,		"    Read a TI-type 134 kHz tag"},
-	{"tune",				CmdTune,0,		"    Measure antenna tuning"},
-	{"vchdemod",			CmdVchdemod,0,		"['clone'] -- Demodulate samples for VeriChip"},
-	{"zerocrossings",	CmdZerocrossings,1,	"    Count time between zero-crossings"},
+	{"askdemod",			Cmdaskdemod,				1, "<samples per bit> <0|1> -- Attempt to demodulate simple ASK tags"},
+	{"autocorr",			CmdAutoCorr,				1, "<window length> -- Autocorrelation over window"},
+	{"bitsamples",		CmdBitsamples,			0, "Get raw samples as bitstring"},
+	{"bitstream",			Cmdbitstream,				1, "[clock rate] -- Convert waveform into a bitstream"},
+	{"buffclear",			CmdBuffClear,				1, "Clear sample buffer and graph window"},
+	{"dec",						CmdDec,							1, "Decimate samples"},
+	{"detectclock",		Cmddetectclockrate,	1, "Detect clock rate"},
+	{"detectreader",	CmdDetectReader,		0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"},
+	{"em410xsim",			CmdEM410xsim,				1, "<UID> -- Simulate EM410x tag"},
+	{"em410xread",		CmdEM410xread,			1, "[clock rate] -- Extract ID from EM410x tag"},
+	{"em410xwatch",		CmdEM410xwatch,			0, "Watches for EM410x tags"},
+	{"em4x50read",		CmdEM4x50read,			1, "Extract data from EM4x50 tag"},
+	{"exit",					CmdQuit,						1, "Exit program"},
+	{"flexdemod",			CmdFlexdemod,				1, "Demodulate samples for FlexPass"},
+	{"fpgaoff",				CmdFPGAOff,					0, "Set FPGA off"},
+	{"fskdemod",			CmdFSKdemod,				1, "Demodulate graph window as a HID FSK"},
+	{"grid",					CmdGrid,						1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
+	{"hexsamples",		CmdHexsamples,			0, "<blocks> -- Dump big buffer as hex bytes"},
+	{"hi14alist",			CmdHi14alist,				0, "List ISO 14443a history"},
+	{"hi14areader",		CmdHi14areader,			0, "Act like an ISO14443 Type A reader"},
+	{"hi14asim",			CmdHi14asim,				0, "<UID> -- Fake ISO 14443a tag"},
+	{"hi14asnoop",		CmdHi14asnoop,			0, "Eavesdrop ISO 14443 Type A"},
+	{"hi14bdemod",		CmdHi14bdemod,			1, "Demodulate ISO14443 Type B from tag"},
+	{"hi14list",			CmdHi14list,				0, "List ISO 14443 history"},
+	{"hi14read",			CmdHi14read,				0, "Read HF tag (ISO 14443)"},
+	{"hi14sim",				CmdHi14sim,					0, "Fake ISO 14443 tag"},
+	{"hi14snoop",			CmdHi14snoop,				0, "Eavesdrop ISO 14443"},
+	{"hi15demod",			CmdHi15demod,				1, "Demodulate ISO15693 from tag"},
+	{"hi15read",			CmdHi15read,				0, "Read HF tag (ISO 15693)"},
+	{"hi15reader",		CmdHi15reader,			0, "Act like an ISO15693 reader"},
+	{"hi15sim",				CmdHi15tag,					0, "Fake an ISO15693 tag"},
+	{"hiddemod",			CmdHiddemod,				1, "Demodulate HID Prox Card II (not optimal)"},
+	{"hide",					CmdHide,						1, "Hide graph window"},
+	{"hidfskdemod",		CmdHIDdemodFSK,			0, "Realtime HID FSK demodulator"},
+	{"hidsimtag",			CmdHIDsimTAG,				0, "<ID> -- HID tag simulator"},
+	{"higet",					CmdHi14read_sim,		0, "<samples> -- Get samples HF, 'analog'"},
+	{"hisamples",			CmdHisamples,				0, "Get raw samples for HF tag"},
+	{"hisampless",		CmdHisampless,			0, "<samples> -- Get signed raw samples, HF tag"},
+	{"hisamplest",		CmdHi14readt,				0, "Get samples HF, for testing"},
+	{"hisimlisten",		CmdHisimlisten,			0, "Get HF samples as fake tag"},
+	{"hpf",						CmdHpf,							1, "Remove DC offset from trace"},
+	{"indalademod",		CmdIndalademod,			0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
+	{"lcd",						CmdLcd,							0, "<HEX command> <count> -- Send command/data to LCD"},
+	{"lcdreset",			CmdLcdReset,				0, "Hardware reset LCD"},
+	{"load",					CmdLoad,						1, "<filename> -- Load trace (to graph window"},
+	{"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)"},
+	{"loread",				CmdLoread,					0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
+	{"losamples",			CmdLosamples,				0, "[128 - 16000] -- Get raw samples for LF tag"},
+	{"losim",					CmdLosim,						0, "Simulate LF tag"},
+	{"ltrim",					CmdLtrim,						1, "<samples> -- Trim samples from left of trace"},
+	{"mandemod",			Cmdmanchesterdemod,	1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"},
+	{"manmod",				Cmdmanchestermod,		1, "[clock rate] -- Manchester modulate a binary stream"},
+	{"norm",					CmdNorm,						1, "Normalize max/min to +/-500"},
+	{"plot",					CmdPlot,						1, "Show graph window"},
+	{"quit",					CmdQuit,						1, "Quit program"},
+	{"readmem",				CmdReadmem,					0, "[address] -- Read memory at decimal address from flash"},
+	{"reset",					CmdReset,						0, "Reset the Proxmark3"},
+	{"save",					CmdSave,						1, "<filename> -- Save trace (from graph window)"},
+	{"scale",					CmdScale,						1, "<int> -- Set cursor display scale"},
+	{"setlfdivisor",	CmdSetDivisor,			0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"},
+	{"sri512read",		CmdSri512read,			0, "<int> -- Read contents of a SRI512 tag"},
+	{"tidemod",				CmdTIDemod,					1, "Demodulate raw bits for TI-type LF tag"},
+	{"tiread",				CmdTIRead,					0, "Read and decode a TI 134 kHz tag"},
+	{"tiwrite",				CmdTIWrite,					0, "Write new data to a r/w TI 134 kHz tag"},
+	{"threshold",			CmdThreshold,				1, "Maximize/minimize every value in the graph window depending on threshold"},
+	{"tune",					CmdTune,						0, "Measure antenna tuning"},
+	{"vchdemod",			CmdVchdemod,				0, "['clone'] -- Demodulate samples for VeriChip"},
+	{"zerocrossings",	CmdZerocrossings,		1, "Count time between zero-crossings"},
 };
 
 static struct {
@@ -2749,16 +2950,18 @@ void UsbCommandReceived(UsbCommand *c)
 			vHf = c->ext2 & 0xffff;;
 			peakf = c->ext3 & 0xffff;
 			peakv = c->ext3 >> 16;
-			PrintToScrollback("# LF antenna: %.2f V @ 125.00Khz", vLf125/1000.0);
-			PrintToScrollback("# LF antenna: %.2f V @ 134.00Khz", vLf134/1000.0);
-			PrintToScrollback("# LF optimal: %.2f V @ %.2fKHz", peakv/1000.0, 12000.0/(peakf+1));
-			PrintToScrollback("# HF antenna: %.2f V @  13.56Mhz", vHf/1000.0);
+			PrintToScrollback("");
+			PrintToScrollback("");
+			PrintToScrollback("# LF antenna: %5.2f V @   125.00 kHz", vLf125/1000.0);
+			PrintToScrollback("# LF antenna: %5.2f V @   134.00 kHz", vLf134/1000.0);
+			PrintToScrollback("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1));
+			PrintToScrollback("# HF antenna: %5.2f V @    13.56 MHz", vHf/1000.0);
 			if (peakv<2000)
-				PrintToScrollback("# Your LF antenna is unusable."); 
+				PrintToScrollback("# Your LF antenna is unusable.");
 			else if (peakv<10000)
 				PrintToScrollback("# Your LF antenna is marginal.");
 			if (vHf<2000)
-				PrintToScrollback("# Your HF antenna is unusable."); 
+				PrintToScrollback("# Your HF antenna is unusable.");
 			else if (vHf<5000)
 				PrintToScrollback("# Your HF antenna is marginal.");
 			break;