From d9de20fa4bb0a36052927b55c4185caa204c5c4d Mon Sep 17 00:00:00 2001
From: pwpiwi <pwpiwi@users.noreply.github.com>
Date: Sat, 12 Jan 2019 13:28:26 +0100
Subject: [PATCH] Fix 15 snoop (#752)

* fixing hf 15: implement hf 15 snoop
* rename hf 15 record to hf 15 snoop
* speedup sampling / decoding:
*   new FPGA mode FPGA_HF_READER_RX_XCORR_AMPLITUDE implements amplitude(ci, cq) on FPGA
*   inlining the decoders in iso15693.c
*   inlining memcpy/memset in LogTrace()
*   giving up the moving correlator for SOF in Handle15693SamplesFromTag
* decode more of EOF in Handle15693SamplesFromTag()
* some refactoring
---
 CHANGELOG.md            |   4 +-
 armsrc/BigBuf.c         |  31 +-
 armsrc/appmain.c        |   6 +-
 armsrc/apps.h           |  11 -
 armsrc/fpgaloader.h     |  63 ++--
 armsrc/iclass.c         |  60 ++--
 armsrc/iso14443a.c      |  14 +-
 armsrc/iso14443b.c      |  36 +-
 armsrc/iso15693.c       | 742 +++++++++++++++++++++++-----------------
 armsrc/iso15693.h       |  24 ++
 client/cmdhf.c          |  11 +-
 client/cmdhf15.c        |  88 +++--
 common/iso15693tools.h  |  53 ---
 fpga/fpga_hf.bit        | Bin 42175 -> 42175 bytes
 fpga/fpga_hf.v          |   4 +-
 fpga/hi_read_rx_xcorr.v | 136 +++++---
 include/usb_cmd.h       |   2 +-
 17 files changed, 713 insertions(+), 572 deletions(-)
 create mode 100644 armsrc/iso15693.h

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19db5195..f2c285b4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 
 ### Fixed
 - AC-Mode decoding for HitagS
-- Wrong UID at HitagS simulation 
+- Wrong UID at HitagS simulation
+- 'hf 15 sim' now works as expected (piwi)
 
 ### Added
 - Support Standard Communication Mode in HITAG S
@@ -24,6 +25,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok)
 - Added `lf paradox clone` to clone a Paradox card
 - Added `emv` commmands working for both contactless and smart cards (Merlok)
+- Added 'hf 15 snoop' (piwi)
 
 
 ## [v3.1.0][2018-10-10]
diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c
index 4b1264b6..e2f51311 100644
--- a/armsrc/BigBuf.c
+++ b/armsrc/BigBuf.c
@@ -36,8 +36,8 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE;
 static uint8_t *emulator_memory = NULL;
 
 // trace related variables
-static uint16_t traceLen = 0;
-int tracing = 1; //Last global one.. todo static?
+static uint32_t traceLen = 0;
+static bool tracing = true;
 
 // get the address of BigBuf
 uint8_t *BigBuf_get_addr(void)
@@ -66,7 +66,7 @@ void BigBuf_Clear(void)
 // clear ALL of BigBuf
 void BigBuf_Clear_ext(bool verbose)
 {
-	memset(BigBuf,0,BIGBUF_SIZE);
+	memset(BigBuf, 0, BIGBUF_SIZE);
 	if (verbose) 
 		Dbprintf("Buffer cleared (%i bytes)",BIGBUF_SIZE);
 }
@@ -76,7 +76,7 @@ void BigBuf_Clear_EM(void){
 
 void BigBuf_Clear_keep_EM(void)
 {
-	memset(BigBuf,0,BigBuf_hi);
+	memset(BigBuf, 0, BigBuf_hi);
 }
 
 // allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory
@@ -162,8 +162,8 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
 
 	uint8_t *trace = BigBuf_get_addr();
 
-	uint16_t num_paritybytes = (iLen-1)/8 + 1;	// number of valid paritybytes in *parity
-	uint16_t duration = timestamp_end - timestamp_start;
+	uint32_t num_paritybytes = (iLen-1)/8 + 1;	// number of valid paritybytes in *parity
+	uint32_t duration = timestamp_end - timestamp_start;
 
 	// Return when trace is full
 	uint16_t max_traceLen = BigBuf_max_traceLen();
@@ -200,19 +200,23 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
 
 	// data bytes
 	if (btBytes != NULL && iLen != 0) {
-		memcpy(trace + traceLen, btBytes, iLen);
+		for (int i = 0; i < iLen; i++) {
+			trace[traceLen++] = *btBytes++;
+		}
 	}
-	traceLen += iLen;
 
 	// parity bytes
 	if (num_paritybytes != 0) {
 		if (parity != NULL) {
-			memcpy(trace + traceLen, parity, num_paritybytes);
+			for (int i = 0; i < num_paritybytes; i++) {
+				trace[traceLen++] = *parity++;
+			}
 		} else {
-			memset(trace + traceLen, 0x00, num_paritybytes);
+			for (int i = 0; i < num_paritybytes; i++) {
+				trace[traceLen++] = 0x00;
+			}
 		}
 	}
-	traceLen += num_paritybytes;
 
 	return true;
 }
@@ -259,8 +263,9 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
 	trace[traceLen++] = ((dwParity >> 24) & 0xff);
 	trace[traceLen++] = iBits;
 
-	memcpy(trace + traceLen, btBytes, iLen);
-	traceLen += iLen;
+	for (int i = 0; i < iLen; i++) {
+		trace[traceLen++] = *btBytes++;
+	}
 
 	return true;
 }
diff --git a/armsrc/appmain.c b/armsrc/appmain.c
index 58c979db..1348ef04 100644
--- a/armsrc/appmain.c
+++ b/armsrc/appmain.c
@@ -24,6 +24,7 @@
 #include "legicrfsim.h"
 #include "hitag2.h"
 #include "hitagS.h"
+#include "iso15693.h"
 #include "lfsampling.h"
 #include "BigBuf.h"
 #include "mifareutil.h"
@@ -1115,8 +1116,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
 		case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
 			AcquireRawAdcSamplesIso15693();
 			break;
-		case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693:
-			RecordRawAdcSamplesIso15693();
+			
+		case CMD_SNOOP_ISO_15693:
+			SnoopIso15693();
 			break;
 			
 		case CMD_ISO_15693_COMMAND:
diff --git a/armsrc/apps.h b/armsrc/apps.h
index b9b1f3de..fad9e6eb 100644
--- a/armsrc/apps.h
+++ b/armsrc/apps.h
@@ -25,7 +25,6 @@
 
 extern const uint8_t OddByteParity[256];
 extern int rsamples;   // = 0;
-extern int tracing;    // = TRUE;
 extern uint8_t trigger;
 
 // This may be used (sparingly) to declare a function to be copied to
@@ -101,7 +100,6 @@ void RAMFUNC SnoopIso14443b(void);
 void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
 
 // Also used in iclass.c
-bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
 void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity);
 
 void RAMFUNC SniffMifare(uint8_t param);
@@ -150,15 +148,6 @@ void 	OnSuccess();
 void 	OnError(uint8_t reason);
 
 
-/// iso15693.h
-void RecordRawAdcSamplesIso15693(void);
-void AcquireRawAdcSamplesIso15693(void);
-void ReaderIso15693(uint32_t parameter);	// Simulate an ISO15693 reader - greg
-void SimTagIso15693(uint32_t parameter, uint8_t *uid);	// simulate an ISO15693 tag - greg
-void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox
-void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); // send arbitrary commands from CLI - atrox 
-void SetDebugIso15693(uint32_t flag);
-
 /// iclass.h
 void RAMFUNC SnoopIClass(void);
 void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h
index 5aff6505..0600067e 100644
--- a/armsrc/fpgaloader.h
+++ b/armsrc/fpgaloader.h
@@ -24,7 +24,7 @@ void SetupSpi(int mode);
 bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count);
 void Fpga_print_status();
 int FpgaGetCurrent();
-#define FpgaDisableSscDma(void)	AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
 #define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
 void SetAdcMuxFor(uint32_t whichGpio);
 
@@ -33,46 +33,47 @@ void SetAdcMuxFor(uint32_t whichGpio);
 #define FPGA_BITSTREAM_HF 2
 
 // Definitions for the FPGA commands.
-#define FPGA_CMD_SET_CONFREG						(1<<12)
-#define FPGA_CMD_SET_DIVISOR						(2<<12)
-#define FPGA_CMD_SET_USER_BYTE1						(3<<12)
+#define FPGA_CMD_SET_CONFREG                        (1<<12)
+#define FPGA_CMD_SET_DIVISOR                        (2<<12)
+#define FPGA_CMD_SET_USER_BYTE1                     (3<<12)
 // Definitions for the FPGA configuration word.
 // LF
-#define FPGA_MAJOR_MODE_LF_ADC						(0<<5)
-#define FPGA_MAJOR_MODE_LF_EDGE_DETECT				(1<<5)
-#define FPGA_MAJOR_MODE_LF_PASSTHRU					(2<<5)
+#define FPGA_MAJOR_MODE_LF_ADC                      (0<<5)
+#define FPGA_MAJOR_MODE_LF_EDGE_DETECT              (1<<5)
+#define FPGA_MAJOR_MODE_LF_PASSTHRU                 (2<<5)
 // HF
-#define FPGA_MAJOR_MODE_HF_READER_TX				(0<<5)
-#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR			(1<<5)
-#define FPGA_MAJOR_MODE_HF_SIMULATOR				(2<<5)
-#define FPGA_MAJOR_MODE_HF_ISO14443A				(3<<5)
-#define FPGA_MAJOR_MODE_HF_SNOOP				(4<<5)
+#define FPGA_MAJOR_MODE_HF_READER_TX                (0<<5)
+#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR          (1<<5)
+#define FPGA_MAJOR_MODE_HF_SIMULATOR                (2<<5)
+#define FPGA_MAJOR_MODE_HF_ISO14443A                (3<<5)
+#define FPGA_MAJOR_MODE_HF_SNOOP                    (4<<5)
 // BOTH
-#define FPGA_MAJOR_MODE_OFF							(7<<5)
+#define FPGA_MAJOR_MODE_OFF                         (7<<5)
 // Options for LF_ADC
-#define FPGA_LF_ADC_READER_FIELD					(1<<0)
+#define FPGA_LF_ADC_READER_FIELD                    (1<<0)
 // Options for LF_EDGE_DETECT
-#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD			FPGA_CMD_SET_USER_BYTE1
-#define FPGA_LF_EDGE_DETECT_READER_FIELD 			(1<<0)
-#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE				(1<<1)
+#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD          FPGA_CMD_SET_USER_BYTE1
+#define FPGA_LF_EDGE_DETECT_READER_FIELD            (1<<0)
+#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE             (1<<1)
 // Options for the HF reader, tx to tag
-#define FPGA_HF_READER_TX_SHALLOW_MOD				(1<<0)
+#define FPGA_HF_READER_TX_SHALLOW_MOD               (1<<0)
 // Options for the HF reader, correlating against rx from tag
-#define FPGA_HF_READER_RX_XCORR_848_KHZ				(1<<0)
-#define FPGA_HF_READER_RX_XCORR_SNOOP				(1<<1)
-#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ		(1<<2)
+#define FPGA_HF_READER_RX_XCORR_848_KHZ             (1<<0)
+#define FPGA_HF_READER_RX_XCORR_SNOOP               (1<<1)
+#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ        (1<<2)
+#define FPGA_HF_READER_RX_XCORR_AMPLITUDE           (1<<3)
 // Options for the HF simulated tag, how to modulate
-#define FPGA_HF_SIMULATOR_NO_MODULATION				(0<<0)
-#define FPGA_HF_SIMULATOR_MODULATE_BPSK				(1<<0)
-#define FPGA_HF_SIMULATOR_MODULATE_212K				(2<<0)
-#define FPGA_HF_SIMULATOR_MODULATE_424K				(4<<0)
-#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT		0x5//101
+#define FPGA_HF_SIMULATOR_NO_MODULATION             (0<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_BPSK             (1<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_212K             (2<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_424K             (4<<0)
+#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT        0x5//101
 
 // Options for ISO14443A
-#define FPGA_HF_ISO14443A_SNIFFER					(0<<0)
-#define FPGA_HF_ISO14443A_TAGSIM_LISTEN				(1<<0)
-#define FPGA_HF_ISO14443A_TAGSIM_MOD				(2<<0)
-#define FPGA_HF_ISO14443A_READER_LISTEN				(3<<0)
-#define FPGA_HF_ISO14443A_READER_MOD				(4<<0)
+#define FPGA_HF_ISO14443A_SNIFFER                   (0<<0)
+#define FPGA_HF_ISO14443A_TAGSIM_LISTEN             (1<<0)
+#define FPGA_HF_ISO14443A_TAGSIM_MOD                (2<<0)
+#define FPGA_HF_ISO14443A_READER_LISTEN             (3<<0)
+#define FPGA_HF_ISO14443A_READER_MOD                (4<<0)
 
 #endif
diff --git a/armsrc/iclass.c b/armsrc/iclass.c
index 1591a062..d27fc1c6 100644
--- a/armsrc/iclass.c
+++ b/armsrc/iclass.c
@@ -751,12 +751,9 @@ void RAMFUNC SnoopIClass(void)
 
 			//if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,true)) break;
 			//if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break;
-			if(tracing)	{
-				uint8_t parity[MAX_PARITY_SIZE];
-				GetParity(Uart.output, Uart.byteCnt, parity);
-				LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true);
-			}
-
+			uint8_t parity[MAX_PARITY_SIZE];
+			GetParity(Uart.output, Uart.byteCnt, parity);
+			LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true);
 
 			/* And ready to receive another command. */
 		    Uart.state = STATE_UNSYNCD;
@@ -779,11 +776,9 @@ void RAMFUNC SnoopIClass(void)
 			rsamples = samples - Demod.samples;
 		    LED_B_ON();
 
-			if(tracing)	{
-				uint8_t parity[MAX_PARITY_SIZE];
-				GetParity(Demod.output, Demod.len, parity);
-				LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false);
-			}
+			uint8_t parity[MAX_PARITY_SIZE];
+			GetParity(Demod.output, Demod.len, parity);
+			LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false);
 
 		    // And ready to receive another response.
 		    memset(&Demod, 0, sizeof(Demod));
@@ -1322,20 +1317,17 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
 			t2r_time = GetCountSspClk();
 		}
 
-		if (tracing) {
-			uint8_t parity[MAX_PARITY_SIZE];
-			GetParity(receivedCmd, len, parity);
-			LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true);
-
-			if (trace_data != NULL) {
-				GetParity(trace_data, trace_data_size, parity);
-				LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false);
-			}
-			if(!tracing) {
-				DbpString("Trace full");
-				//break;
-			}
+		uint8_t parity[MAX_PARITY_SIZE];
+		GetParity(receivedCmd, len, parity);
+		LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true);
 
+		if (trace_data != NULL) {
+			GetParity(trace_data, trace_data_size, parity);
+			LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false);
+		}
+		if(!get_tracing()) {
+			DbpString("Trace full");
+			//break;
 		}
 	}
 
@@ -1509,11 +1501,9 @@ void ReaderTransmitIClass(uint8_t* frame, int len)
 		LED_A_ON();
 
 	// Store reader command in buffer
-	if (tracing) {
-		uint8_t par[MAX_PARITY_SIZE];
-		GetParity(frame, len, par);
-		LogTrace(frame, len, rsamples, rsamples, par, true);
-	}
+	uint8_t par[MAX_PARITY_SIZE];
+	GetParity(frame, len, par);
+	LogTrace(frame, len, rsamples, rsamples, par, true);
 }
 
 //-----------------------------------------------------------------------------
@@ -1569,11 +1559,9 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer)
   int samples = 0;
   if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return false;
   rsamples += samples;
-  if (tracing) {
-	uint8_t parity[MAX_PARITY_SIZE];
-	GetParity(receivedAnswer, Demod.len, parity);
-	LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false);
-  }
+  uint8_t parity[MAX_PARITY_SIZE];
+  GetParity(receivedAnswer, Demod.len, parity);
+  LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false);
   if(samples == 0) return false;
   return Demod.len;
 }
@@ -1715,7 +1703,7 @@ void ReaderIClass(uint8_t arg0) {
 		// if only looking for one card try 2 times if we missed it the first time
 		if (try_once && tryCnt > 2) break; 
 		tryCnt++;
-		if(!tracing) {
+		if(!get_tracing()) {
 			DbpString("Trace full");
 			break;
 		}
@@ -1828,7 +1816,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
 	
 		WDT_HIT();
 
-		if(!tracing) {
+		if(!get_tracing()) {
 			DbpString("Trace full");
 			break;
 		}
diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index 7bf8f5af..f5fcc91c 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -1220,7 +1220,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
 			EmSendPrecompiledCmd(p_response);
 		}
 		
-		if (!tracing) {
+		if (!get_tracing()) {
 			Dbprintf("Trace Full. Simulation stopped.");
 			break;
 		}
@@ -1619,9 +1619,7 @@ void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t
 		LED_A_ON();
   
 	// Log reader command in trace buffer
-	if (tracing) {
-		LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true);
-	}
+	LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true);
 }
 
 
@@ -1652,9 +1650,7 @@ void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing)
 static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity)
 {
 	if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, offset)) return false;
-	if (tracing) {
-		LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false);
-	}
+	LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false);
 	return Demod.len;
 }
 
@@ -1662,9 +1658,7 @@ static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t
 int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
 {
 	if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, 0)) return false;
-	if (tracing) {
-		LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false);
-	}
+	LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false);
 	return Demod.len;
 }
 
diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c
index cb8567fa..76d7a075 100644
--- a/armsrc/iso14443b.c
+++ b/armsrc/iso14443b.c
@@ -386,10 +386,7 @@ void SimulateIso14443bTag(void)
 			break;
 		}
 
-		if (tracing) {
-			uint8_t parity[MAX_PARITY_SIZE];
-			LogTrace(receivedCmd, len, 0, 0, parity, true);
-		}
+		LogTrace(receivedCmd, len, 0, 0, NULL, true);
 
 		// Good, look at the command now.
 		if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0)
@@ -463,10 +460,7 @@ void SimulateIso14443bTag(void)
 		}
 
 		// trace the response:
-		if (tracing) {
-			uint8_t parity[MAX_PARITY_SIZE];
-			LogTrace(resp, respLen, 0, 0, parity, false);
-		}
+		LogTrace(resp, respLen, 0, 0, NULL, false);
 
 	}
 }
@@ -763,9 +757,8 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
 
 	if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
 	//Tracing
-	if (tracing && Demod.len > 0) {
-		uint8_t parity[MAX_PARITY_SIZE];
-		LogTrace(Demod.output, Demod.len, 0, 0, parity, false);
+	if (Demod.len > 0) {
+		LogTrace(Demod.output, Demod.len, 0, 0, NULL, false);
 	}
 }
 
@@ -858,10 +851,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
 {
 	CodeIso14443bAsReader(cmd, len);
 	TransmitFor14443b();
-	if (tracing) {
-		uint8_t parity[MAX_PARITY_SIZE];
-		LogTrace(cmd,len, 0, 0, parity, true);
-	}
+	LogTrace(cmd,len, 0, 0, NULL, true);
 }
 
 /* Sends an APDU to the tag
@@ -1153,7 +1143,6 @@ void RAMFUNC SnoopIso14443b(void)
 	upTo = dmaBuf;
 	lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
 	FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
-	uint8_t parity[MAX_PARITY_SIZE];
 
 	bool TagIsActive = false;
 	bool ReaderIsActive = false;
@@ -1198,9 +1187,7 @@ void RAMFUNC SnoopIso14443b(void)
 		if (!TagIsActive) {							// no need to try decoding reader data if the tag is sending
 			if(Handle14443bUartBit(ci & 0x01)) {
 				triggered = true;
-				if(tracing) {
-					LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
-				}
+				LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true);
 				/* And ready to receive another command. */
 				UartReset();
 				/* And also reset the demod code, which might have been */
@@ -1209,9 +1196,7 @@ void RAMFUNC SnoopIso14443b(void)
 			}
 			if(Handle14443bUartBit(cq & 0x01)) {
 				triggered = true;
-				if(tracing) {
-					LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
-				}
+				LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true);
 				/* And ready to receive another command. */
 				UartReset();
 				/* And also reset the demod code, which might have been */
@@ -1223,13 +1208,8 @@ void RAMFUNC SnoopIso14443b(void)
 
 		if(!ReaderIsActive && triggered) {						// no need to try decoding tag data if the reader is sending or not yet triggered
 			if(Handle14443bSamplesDemod(ci/2, cq/2)) {
-
 				//Use samples as a time measurement
-				if(tracing)
-				{
-					uint8_t parity[MAX_PARITY_SIZE];
-					LogTrace(Demod.output, Demod.len, samples, samples, parity, false);
-				}
+				LogTrace(Demod.output, Demod.len, samples, samples, NULL, false);
 				// And ready to receive another response.
 				DemodReset();
 			}
diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c
index da2aab69..f6868297 100644
--- a/armsrc/iso15693.c
+++ b/armsrc/iso15693.c
@@ -47,9 +47,10 @@
 // *) add anti-collision support for inventory-commands
 // *) read security status of a block
 // *) sniffing and simulation do not support two subcarrier modes.
-// *) remove or refactor code under "depricated"
+// *) remove or refactor code under "deprecated"
 // *) document all the functions
 
+#include "iso15693.h"
 
 #include "proxmark3.h"
 #include "util.h"
@@ -58,6 +59,7 @@
 #include "iso15693tools.h"
 #include "protocols.h"
 #include "cmd.h"
+#include "BigBuf.h"
 
 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
 
@@ -68,27 +70,20 @@ static int DEBUG = 0;
 // This section basicly contains transmission and receiving of bits
 ///////////////////////////////////////////////////////////////////////
 
-#define FrameSOF              Iso15693FrameSOF
-#define Logic0                Iso15693Logic0
-#define Logic1                Iso15693Logic1
-#define FrameEOF              Iso15693FrameEOF
-
 #define Crc(data,datalen)     Iso15693Crc(data,datalen)
 #define AddCrc(data,datalen)  Iso15693AddCrc(data,datalen)
 #define sprintUID(target,uid)	Iso15693sprintUID(target,uid)
 
-// approximate amplitude=sqrt(ci^2+cq^2) by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|)
-#define AMPLITUDE(ci, cq) (MAX(ABS(ci), ABS(cq)) + MIN(ABS(ci), ABS(cq))/2)
-
 // buffers
-#define ISO15693_DMA_BUFFER_SIZE     128
-#define ISO15693_MAX_RESPONSE_LENGTH  36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet
-#define ISO15693_MAX_COMMAND_LENGTH   45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet
+#define ISO15693_DMA_BUFFER_SIZE        2048 // must be a power of 2
+#define ISO15693_MAX_RESPONSE_LENGTH     36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet
+#define ISO15693_MAX_COMMAND_LENGTH      45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet
 
 // timing. Delays in SSP_CLK ticks.
 #define DELAY_READER_TO_ARM            8
 #define DELAY_ARM_TO_READER            1
 #define DELAY_ISO15693_VCD_TO_VICC   132 // 132/423.75kHz = 311.5us from end of EOF to start of tag response
+#define DELAY_ISO15693_VICC_TO_VCD  1017 // 1017/3.39MHz = 300us between end of tag response and next reader command
 
 // ---------------------------
 // Signal Processing
@@ -271,11 +266,13 @@ static void CodeIso15693AsTag(uint8_t *cmd, int n)
 
 
 // Transmit the command (to the tag) that was placed in cmd[].
-static void TransmitTo15693Tag(const uint8_t *cmd, int len)
+static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t start_time)
 {
 	FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
 
+	while (GetCountSspClk() < start_time);
+
 	LED_B_ON();
     for(int c = 0; c < len; ) {
         if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
@@ -302,6 +299,7 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start
 	}
 
 	while (GetCountSspClk() < (start_time & 0xfffffff8)) ;
+
 	AT91C_BASE_SSC->SSC_THR = 0x00; // clear TXRDY
 
 	LED_C_ON();
@@ -329,7 +327,7 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start
 
 //=============================================================================
 // An ISO 15693 decoder for tag responses (one subcarrier only).
-// Uses cross correlation to identify the SOF, each bit, and EOF.
+// Uses cross correlation to identify each bit and EOF.
 // This function is called 8 times per bit (every 2 subcarrier cycles).
 // Subcarrier frequency fs is 424kHz, 1/fs = 2,36us,
 // i.e. function is called every 4,72us
@@ -341,16 +339,15 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start
 //          false if we are still waiting for some more
 //=============================================================================
 
-#define SUBCARRIER_DETECT_THRESHOLD	2
-#define SOF_CORRELATOR_LEN (1<<5)
+#define NOISE_THRESHOLD    30      // don't try to correlate noise
 
 typedef struct DecodeTag {
 	enum {
-		STATE_TAG_UNSYNCD,
-		STATE_TAG_AWAIT_SOF_1,
-		STATE_TAG_AWAIT_SOF_2,
+		STATE_TAG_SOF_LOW,
+		STATE_TAG_SOF_HIGH,
+		STATE_TAG_SOF_HIGH_END,
 		STATE_TAG_RECEIVING_DATA,
-		STATE_TAG_AWAIT_EOF
+		STATE_TAG_EOF
 	}         state;
 	int       bitCount;
 	int       posCount;
@@ -361,84 +358,68 @@ typedef struct DecodeTag {
 		SOF_PART2
 	}         lastBit;
 	uint16_t  shiftReg;
+	uint16_t  max_len;
 	uint8_t   *output;
 	int       len;
 	int       sum1, sum2;
-	uint8_t   SOF_low;
-	uint8_t   SOF_high;
-	uint8_t   SOF_last;
-	int32_t   SOF_corr;
-	int32_t   SOF_corr_prev;
-	uint8_t   SOF_correlator[SOF_CORRELATOR_LEN];
 } DecodeTag_t;
 
-static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTag)
+
+static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag)
 {
 	switch(DecodeTag->state) {
-		case STATE_TAG_UNSYNCD:
-			// initialize SOF correlator. We are looking for 12 samples low and 12 samples high.
-			DecodeTag->SOF_low = 0;
-			DecodeTag->SOF_high = 12;
-			DecodeTag->SOF_last = 23;
-			memset(DecodeTag->SOF_correlator, 0x00, DecodeTag->SOF_last + 1);
-			DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq);
-			DecodeTag->SOF_corr = DecodeTag->SOF_correlator[DecodeTag->SOF_last];
-			DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr;
-			// initialize Decoder
-			DecodeTag->posCount = 0;
-			DecodeTag->bitCount = 0;
-			DecodeTag->len = 0;
-			DecodeTag->state = STATE_TAG_AWAIT_SOF_1;
-			break;
-
-		case STATE_TAG_AWAIT_SOF_1:
-			// calculate the correlation in real time. Look at differences only.
-			DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_low++];
-			DecodeTag->SOF_corr -= 2*DecodeTag->SOF_correlator[DecodeTag->SOF_high++];
-			DecodeTag->SOF_last++;
-			DecodeTag->SOF_low &= (SOF_CORRELATOR_LEN-1);
-			DecodeTag->SOF_high &= (SOF_CORRELATOR_LEN-1);
-			DecodeTag->SOF_last &= (SOF_CORRELATOR_LEN-1);
-			DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq);
-			DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_last];
-
-			// if correlation increases for 10 consecutive samples, we are close to maximum correlation
-			if (DecodeTag->SOF_corr > DecodeTag->SOF_corr_prev + SUBCARRIER_DETECT_THRESHOLD) {
+		case STATE_TAG_SOF_LOW: 
+			// waiting for 12 times low (11 times low is accepted as well)
+			if (amplitude < NOISE_THRESHOLD) {
 				DecodeTag->posCount++;
 			} else {
-				DecodeTag->posCount = 0;
+				if (DecodeTag->posCount > 10) {
+					DecodeTag->posCount = 1;
+					DecodeTag->sum1 = 0;
+					DecodeTag->state = STATE_TAG_SOF_HIGH;
+				} else {
+					DecodeTag->posCount = 0;
+				}
 			}
-
-			if (DecodeTag->posCount == 10) {	// correlation increased 10 times
-				DecodeTag->state = STATE_TAG_AWAIT_SOF_2;
+			break;
+			
+		case STATE_TAG_SOF_HIGH:
+			// waiting for 10 times high. Take average over the last 8
+			if (amplitude > NOISE_THRESHOLD) {
+				DecodeTag->posCount++;
+				if (DecodeTag->posCount > 2) {
+					DecodeTag->sum1 += amplitude; // keep track of average high value
+				}
+				if (DecodeTag->posCount == 10) {
+					DecodeTag->sum1 >>= 4;        // calculate half of average high value (8 samples)
+					DecodeTag->state = STATE_TAG_SOF_HIGH_END;
+				}
+			} else { // high phase was too short
+				DecodeTag->posCount = 1;
+				DecodeTag->state = STATE_TAG_SOF_LOW;
 			}
-
-			DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr;
-
 			break;
 
-		case STATE_TAG_AWAIT_SOF_2:
-			// calculate the correlation in real time. Look at differences only.
-			DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_low++];
-			DecodeTag->SOF_corr -= 2*DecodeTag->SOF_correlator[DecodeTag->SOF_high++];
-			DecodeTag->SOF_last++;
-			DecodeTag->SOF_low &= (SOF_CORRELATOR_LEN-1);
-			DecodeTag->SOF_high &= (SOF_CORRELATOR_LEN-1);
-			DecodeTag->SOF_last &= (SOF_CORRELATOR_LEN-1);
-			DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq);
-			DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_last];
-
-			if (DecodeTag->SOF_corr >= DecodeTag->SOF_corr_prev) { // we are looking for the maximum correlation
-				DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr;
-			} else {
-				DecodeTag->lastBit = SOF_PART1;  // detected 1st part of SOF
-				DecodeTag->sum1 = DecodeTag->SOF_correlator[DecodeTag->SOF_last];
+		case STATE_TAG_SOF_HIGH_END:
+			// waiting for a falling edge
+			if (amplitude < DecodeTag->sum1) {   // signal drops below 50% average high: a falling edge
+				DecodeTag->lastBit = SOF_PART1;  // detected 1st part of SOF (12 samples low and 12 samples high)
+				DecodeTag->shiftReg = 0;
+				DecodeTag->bitCount = 0;
+				DecodeTag->len = 0;
+				DecodeTag->sum1 = amplitude;
 				DecodeTag->sum2 = 0;
 				DecodeTag->posCount = 2;
 				DecodeTag->state = STATE_TAG_RECEIVING_DATA;
 				LED_C_ON();
+			} else {
+				DecodeTag->posCount++;
+				if (DecodeTag->posCount > 13) { // high phase too long
+					DecodeTag->posCount = 0;
+					DecodeTag->state = STATE_TAG_SOF_LOW;
+					LED_C_OFF();
+				}
 			}
-
 			break;
 
 		case STATE_TAG_RECEIVING_DATA:
@@ -446,23 +427,27 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa
 				DecodeTag->sum1 = 0;
 				DecodeTag->sum2 = 0;
 			}
-
 			if (DecodeTag->posCount <= 4) {
-				DecodeTag->sum1 += AMPLITUDE(ci, cq);
+				DecodeTag->sum1 += amplitude;
 			} else {
-				DecodeTag->sum2 += AMPLITUDE(ci, cq);
+				DecodeTag->sum2 += amplitude;
 			}
-
 			if (DecodeTag->posCount == 8) {
-				int16_t corr_1 = (DecodeTag->sum2 - DecodeTag->sum1) / 4;
-				int16_t corr_0 = (DecodeTag->sum1 - DecodeTag->sum2) / 4;
-				int16_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 8;
+				int32_t corr_1 = DecodeTag->sum2 - DecodeTag->sum1;
+				int32_t corr_0 = -corr_1;
+				int32_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 2;
 				if (corr_EOF > corr_0 && corr_EOF > corr_1) {
-					DecodeTag->state = STATE_TAG_AWAIT_EOF;
+					if (DecodeTag->lastBit == LOGIC0) {  // this was already part of EOF
+						DecodeTag->state = STATE_TAG_EOF;
+					} else {
+						DecodeTag->posCount = 0;
+						DecodeTag->state = STATE_TAG_SOF_LOW;
+						LED_C_OFF();
+					}
 				} else if (corr_1 > corr_0) {
 					// logic 1
 					if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF
-						DecodeTag->lastBit = SOF_PART2;
+						DecodeTag->lastBit = SOF_PART2;    // SOF completed
 					} else {
 						DecodeTag->lastBit = LOGIC1;
 						DecodeTag->shiftReg >>= 1;
@@ -471,6 +456,12 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa
 						if (DecodeTag->bitCount == 8) {
 							DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg;
 							DecodeTag->len++;
+							if (DecodeTag->len > DecodeTag->max_len) {
+								// buffer overflow, give up
+								DecodeTag->posCount = 0;
+								DecodeTag->state = STATE_TAG_SOF_LOW;
+								LED_C_OFF();
+							}
 							DecodeTag->bitCount = 0;
 							DecodeTag->shiftReg = 0;
 						}
@@ -478,7 +469,8 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa
 				} else {
 					// logic 0
 					if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF
-						DecodeTag->state = STATE_TAG_UNSYNCD;
+						DecodeTag->posCount = 0;
+						DecodeTag->state = STATE_TAG_SOF_LOW;
 						LED_C_OFF();
 					} else {
 						DecodeTag->lastBit = LOGIC0;
@@ -487,6 +479,12 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa
 						if (DecodeTag->bitCount == 8) {
 							DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg;
 							DecodeTag->len++;
+							if (DecodeTag->len > DecodeTag->max_len) {
+								// buffer overflow, give up
+								DecodeTag->posCount = 0;
+								DecodeTag->state = STATE_TAG_SOF_LOW;
+								LED_C_OFF();
+							}
 							DecodeTag->bitCount = 0;
 							DecodeTag->shiftReg = 0;
 						}
@@ -497,89 +495,106 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa
 			DecodeTag->posCount++;
 			break;
 
-		case STATE_TAG_AWAIT_EOF:
-			if (DecodeTag->lastBit == LOGIC0) {  // this was already part of EOF
-				LED_C_OFF();
-				return true;
+		case STATE_TAG_EOF:
+			if (DecodeTag->posCount == 1) {
+				DecodeTag->sum1 = 0;
+				DecodeTag->sum2 = 0;
+			}
+			if (DecodeTag->posCount <= 4) {
+				DecodeTag->sum1 += amplitude;
 			} else {
-				DecodeTag->state = STATE_TAG_UNSYNCD;
-				LED_C_OFF();
+				DecodeTag->sum2 += amplitude;
 			}
+			if (DecodeTag->posCount == 8) {
+				int32_t corr_1 = DecodeTag->sum2 - DecodeTag->sum1;
+				int32_t corr_0 = -corr_1;
+				int32_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 2;
+				if (corr_EOF > corr_0 || corr_1 > corr_0) {
+					DecodeTag->posCount = 0;
+					DecodeTag->state = STATE_TAG_SOF_LOW;
+					LED_C_OFF();
+				} else {
+					LED_C_OFF();
+					return true;
+				}
+			}
+			DecodeTag->posCount++;
 			break;
 
-		default:
-			DecodeTag->state = STATE_TAG_UNSYNCD;
-			LED_C_OFF();
-			break;
 	}
 
 	return false;
 }
 
 
-static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data)
+static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len)
 {
+	DecodeTag->posCount = 0;
+	DecodeTag->state = STATE_TAG_SOF_LOW;
 	DecodeTag->output = data;
-	DecodeTag->state = STATE_TAG_UNSYNCD;
+	DecodeTag->max_len = max_len;
+}
+
+
+static void DecodeTagReset(DecodeTag_t *DecodeTag)
+{
+	DecodeTag->posCount = 0;
+	DecodeTag->state = STATE_TAG_SOF_LOW;
 }
 
+
 /*
  *  Receive and decode the tag response, also log to tracebuffer
  */
-static int GetIso15693AnswerFromTag(uint8_t* response, int timeout)
+static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int timeout)
 {
-	int maxBehindBy = 0;
-	int lastRxCounter, samples = 0;
-	int8_t ci, cq;
+	int samples = 0;
 	bool gotFrame = false;
 
-	uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE];
-
+	uint16_t *dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t));
+	
 	// the Decoder data structure
-	DecodeTag_t DecodeTag;
-	DecodeTagInit(&DecodeTag, response);
+	DecodeTag_t DecodeTag = { 0 };
+	DecodeTagInit(&DecodeTag, response, max_len);
 
 	// wait for last transfer to complete
 	while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY));
 
 	// And put the FPGA in the appropriate mode
-	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_AMPLITUDE);
 
 	// Setup and start DMA.
 	FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
 	FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE);
 	uint16_t *upTo = dmaBuf;
-	lastRxCounter = ISO15693_DMA_BUFFER_SIZE;
 
 	for(;;) {
-		int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO15693_DMA_BUFFER_SIZE-1);
-		if(behindBy > maxBehindBy) {
-			maxBehindBy = behindBy;
-		}
+		uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1);
 
-		if (behindBy < 1) continue;
+		if (behindBy == 0) continue;
 
-		ci = (int8_t)(*upTo >> 8);
-		cq = (int8_t)(*upTo & 0xff);
+		uint16_t tagdata = *upTo++;
 
-		upTo++;
-		lastRxCounter--;
 		if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) {                // we have read all of the DMA buffer content.
 			upTo = dmaBuf;                                             // start reading the circular buffer from the beginning
-			lastRxCounter += ISO15693_DMA_BUFFER_SIZE;
+			if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) {
+				Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy);
+				break;
+			}
 		}
 		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) {              // DMA Counter Register had reached 0, already rotated.
 			AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;          // refresh the DMA Next Buffer and
 			AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE;   // DMA Next Counter registers
 		}
+
 		samples++;
 
-		if (Handle15693SamplesFromTag(ci, cq, &DecodeTag)) {
+		if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) {
 			gotFrame = true;
 			break;
 		}
 
-		if(samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) {
+		if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) {
 			DecodeTag.len = 0;
 			break;
 		}
@@ -587,11 +602,12 @@ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout)
 	}
 
 	FpgaDisableSscDma();
+	BigBuf_free();
+	
+	if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d",
+	                    samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount);
 
-	if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d",
-	                    maxBehindBy, samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount);
-
-	if (tracing && DecodeTag.len > 0) {
+	if (DecodeTag.len > 0) {
 		LogTrace(DecodeTag.output, DecodeTag.len, 0, 0, NULL, false);
 	}
 
@@ -636,14 +652,32 @@ typedef struct DecodeReader {
 } DecodeReader_t;
 
 
-static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader)
+static void DecodeReaderInit(DecodeReader_t* DecodeReader, uint8_t *data, uint16_t max_len)
+{
+	DecodeReader->output = data;
+	DecodeReader->byteCountMax = max_len;
+	DecodeReader->state = STATE_READER_UNSYNCD;
+	DecodeReader->byteCount = 0;
+	DecodeReader->bitCount = 0;
+	DecodeReader->posCount = 1;
+	DecodeReader->shiftReg = 0;
+}
+
+
+static void DecodeReaderReset(DecodeReader_t* DecodeReader)
+{
+	DecodeReader->state = STATE_READER_UNSYNCD;
+}
+
+
+static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uint8_t bit, DecodeReader_t *restrict DecodeReader)
 {
 	switch(DecodeReader->state) {
 		case STATE_READER_UNSYNCD:
 			if(!bit) {
 				// we went low, so this could be the beginning of a SOF
-				DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF;
 				DecodeReader->posCount = 1;
+				DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF;
 			}
 			break;
 
@@ -651,13 +685,13 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 			DecodeReader->posCount++;
 			if(bit) { // detected rising edge
 				if(DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5)
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 				} else { // SOF
 					DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF;
 				}
 			} else {
 				if(DecodeReader->posCount > 5) { // stayed low for too long
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 				} else {
 					// do nothing, keep waiting
 				}
@@ -668,19 +702,19 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 			DecodeReader->posCount++;
 			if(!bit) { // detected a falling edge
 				if (DecodeReader->posCount < 20) {         // falling edge too early (nominally expected at 21 earliest)
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 				} else if (DecodeReader->posCount < 23) {  // SOF for 1 out of 4 coding
 					DecodeReader->Coding = CODING_1_OUT_OF_4;
 					DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF;
 				} else if (DecodeReader->posCount < 28) {  // falling edge too early (nominally expected at 29 latest)
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 				} else {                                 // SOF for 1 out of 4 coding
 					DecodeReader->Coding = CODING_1_OUT_OF_256;
 					DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF;
 				}
 			} else {
 				if(DecodeReader->posCount > 29) { // stayed high for too long
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 				} else {
 					// do nothing, keep waiting
 				}
@@ -692,7 +726,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 			if (bit) { // detected rising edge
 				if (DecodeReader->Coding == CODING_1_OUT_OF_256) {
 					if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33)
-						DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 					} else {
 						DecodeReader->posCount = 1;
 						DecodeReader->bitCount = 0;
@@ -703,7 +737,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 					}
 				} else { // CODING_1_OUT_OF_4
 					if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25)
-						DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 					} else {
 						DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4;
 					}
@@ -711,13 +745,13 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 			} else {
 				if (DecodeReader->Coding == CODING_1_OUT_OF_256) {
 					if (DecodeReader->posCount > 34) { // signal stayed low for too long
-						DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 					} else {
 						// do nothing, keep waiting
 					}
 				} else { // CODING_1_OUT_OF_4
 					if (DecodeReader->posCount > 26) { // signal stayed low for too long
-						DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 					} else {
 						// do nothing, keep waiting
 					}
@@ -739,7 +773,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 					// do nothing, keep waiting
 				}
 			} else { // unexpected falling edge
-				DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 			}
 			break;
 
@@ -761,7 +795,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 				int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2;
 				if (corr01 > corr11 && corr01 > corr10) { // EOF
 					LED_B_OFF(); // Finished receiving
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 					if (DecodeReader->byteCount != 0) {
 						return true;
 					}
@@ -775,9 +809,10 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 					if (DecodeReader->byteCount > DecodeReader->byteCountMax) {
 						// buffer overflow, give up
 						LED_B_OFF();
-						DecodeReader->state = STATE_READER_UNSYNCD;
+						DecodeReaderReset(DecodeReader);
 					}
 					DecodeReader->bitCount = 0;
+					DecodeReader->shiftReg = 0;
 				} else {
 					DecodeReader->bitCount++;
 				}
@@ -802,7 +837,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 				int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2;
 				if (corr01 > corr11 && corr01 > corr10) { // EOF
 					LED_B_OFF(); // Finished receiving
-					DecodeReader->state = STATE_READER_UNSYNCD;
+					DecodeReaderReset(DecodeReader);
 					if (DecodeReader->byteCount != 0) {
 						return true;
 					}
@@ -815,7 +850,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 					if (DecodeReader->byteCount > DecodeReader->byteCountMax) {
 						// buffer overflow, give up
 						LED_B_OFF();
-						DecodeReader->state = STATE_READER_UNSYNCD;
+						DecodeReaderReset(DecodeReader);
 					}
 				}
 				DecodeReader->bitCount++;
@@ -824,7 +859,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 
 		default:
 			LED_B_OFF();
-			DecodeReader->state = STATE_READER_UNSYNCD;
+			DecodeReaderReset(DecodeReader);
 			break;
 	}
 
@@ -832,18 +867,6 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader
 }
 
 
-static void DecodeReaderInit(uint8_t *data, uint16_t max_len, DecodeReader_t* DecodeReader)
-{
-	DecodeReader->output = data;
-	DecodeReader->byteCountMax = max_len;
-	DecodeReader->state = STATE_READER_UNSYNCD;
-	DecodeReader->byteCount = 0;
-	DecodeReader->bitCount = 0;
-	DecodeReader->posCount = 0;
-	DecodeReader->shiftReg = 0;
-}
-
-
 //-----------------------------------------------------------------------------
 // Receive a command (from the reader to us, where we are the simulated tag),
 // and store it in the given buffer, up to the given maximum length. Keeps
@@ -856,16 +879,15 @@ static void DecodeReaderInit(uint8_t *data, uint16_t max_len, DecodeReader_t* De
 
 static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time)
 {
-	int maxBehindBy = 0;
-	int lastRxCounter, samples = 0;
+	int samples = 0;
 	bool gotFrame = false;
 	uint8_t b;
 
-	uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE];
+	uint8_t *dmaBuf = BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE);
 
 	// the decoder data structure
 	DecodeReader_t DecodeReader = {0};
-	DecodeReaderInit(received, max_len, &DecodeReader);
+	DecodeReaderInit(&DecodeReader, received, max_len);
 
 	// wait for last transfer to complete
 	while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY));
@@ -883,21 +905,19 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3
 	// Setup and start DMA.
 	FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE);
 	uint8_t *upTo = dmaBuf;
-	lastRxCounter = ISO15693_DMA_BUFFER_SIZE;
 
 	for(;;) {
-		int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO15693_DMA_BUFFER_SIZE-1);
-		if(behindBy > maxBehindBy) {
-			maxBehindBy = behindBy;
-		}
+		uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1);
 
-		if (behindBy < 1) continue;
+		if (behindBy == 0) continue;
 
 		b = *upTo++;
-		lastRxCounter--;
 		if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) {                // we have read all of the DMA buffer content.
 			upTo = dmaBuf;                                             // start reading the circular buffer from the beginning
-			lastRxCounter += ISO15693_DMA_BUFFER_SIZE;
+			if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) {
+				Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy);
+				break;
+			}
 		}
 		if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) {              // DMA Counter Register had reached 0, already rotated.
 			AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;          // refresh the DMA Next Buffer and
@@ -927,11 +947,12 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3
 
 
 	FpgaDisableSscDma();
+	BigBuf_free_keep_EM();
+	
+	if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d",
+	                    samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount);
 
-	if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d",
-	                    maxBehindBy, samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount);
-
-	if (tracing && DecodeReader.byteCount > 0) {
+	if (DecodeReader.byteCount > 0) {
 		LogTrace(DecodeReader.output, DecodeReader.byteCount, 0, 0, NULL, true);
 	}
 
@@ -939,7 +960,29 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3
 }
 
 
-static void BuildIdentifyRequest(void);
+// Encode (into the ToSend buffers) an identify request, which is the first
+// thing that you must send to a tag to get a response.
+static void BuildIdentifyRequest(void)
+{
+	uint8_t cmd[5];
+
+	uint16_t crc;
+	// one sub-carrier, inventory, 1 slot, fast rate
+	// AFI is at bit 5 (1<<4) when doing an INVENTORY
+	cmd[0] = (1 << 2) | (1 << 5) | (1 << 1);
+	// inventory command code
+	cmd[1] = 0x01;
+	// no mask
+	cmd[2] = 0x00;
+	//Now the CRC
+	crc = Crc(cmd, 3);
+	cmd[3] = crc & 0xff;
+	cmd[4] = crc >> 8;
+
+	CodeIso15693AsReader(cmd, sizeof(cmd));
+}
+
+
 //-----------------------------------------------------------------------------
 // Start to read an ISO 15693 tag. We send an identify request, then wait
 // for the response. The response is not demodulated, just left in the buffer
@@ -980,18 +1023,12 @@ void AcquireRawAdcSamplesIso15693(void)
 	while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY));
 
 	FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
-	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_AMPLITUDE);
 
 	for(int c = 0; c < 4000; ) {
 		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-			uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
-			// The samples are correlations against I and Q versions of the
-			// tone that the tag AM-modulates. We just want power,
-			// so abs(I) + abs(Q) is close to what we want.
-			int8_t i = (int8_t)(iq >> 8);
-			int8_t q = (int8_t)(iq & 0xff);
-			uint8_t r = AMPLITUDE(i, q);
-			dest[c++] = r;
+			uint16_t r = AT91C_BASE_SSC->SSC_RHR;
+			dest[c++] = r >> 5;
 		}
 	}
 
@@ -1000,49 +1037,139 @@ void AcquireRawAdcSamplesIso15693(void)
 }
 
 
-// TODO: there is no trigger condition. The 14000 samples represent a time frame of 66ms.
-// It is unlikely that we get something meaningful.
-// TODO: Currently we only record tag answers. Add tracing of reader commands.
-// TODO: would we get something at all? The carrier is switched on...
-void RecordRawAdcSamplesIso15693(void)
+void SnoopIso15693(void)
 {
-	LEDsoff();
-	LED_A_ON();
+	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+	BigBuf_free();
 
-	uint8_t *dest = BigBuf_get_addr();
+	clear_trace();
+	set_tracing(true);
 
-	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-	// Setup SSC
-	FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
 
-	// Start from off (no field generated)
-   	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-   	SpinDelay(200);
+	// The DMA buffer, used to stream samples from the FPGA
+	uint16_t* dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t));
+	uint16_t *upTo;
+
+	// Count of samples received so far, so that we can include timing
+	// information in the trace buffer.
+	int samples = 0;
+
+	DecodeTag_t DecodeTag = {0};
+	uint8_t response[ISO15693_MAX_RESPONSE_LENGTH];
+	DecodeTagInit(&DecodeTag, response, sizeof(response));
 
+	DecodeReader_t DecodeReader = {0};;
+	uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH];
+	DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd));
+
+	// Print some debug information about the buffer sizes
+	if (DEBUG) {
+		Dbprintf("Snooping buffers initialized:");
+		Dbprintf("  Trace:         %i bytes", BigBuf_max_traceLen());
+		Dbprintf("  Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH);
+		Dbprintf("  tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH);
+		Dbprintf("  DMA:           %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t));
+	}
+	Dbprintf("Snoop started. Press button to stop.");
+	
+	// Signal field is off, no reader signal, no tag signal
+	LEDsoff();
+	// And put the FPGA in the appropriate mode
+	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP | FPGA_HF_READER_RX_XCORR_AMPLITUDE);
 	SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
 
-	SpinDelay(100);
+	// Setup for the DMA.
+	FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+	upTo = dmaBuf;
+	FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE);
 
-	LED_D_ON();
-	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
+	bool TagIsActive = false;
+	bool ReaderIsActive = false;
+	bool ExpectTagAnswer = false;
 
-	for(int c = 0; c < 14000;) {
-		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-			uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
-			// The samples are correlations against I and Q versions of the
-			// tone that the tag AM-modulates. We just want power,
-			// so abs(I) + abs(Q) is close to what we want.
-			int8_t i = (int8_t)(iq >> 8);
-			int8_t q = (int8_t)(iq & 0xff);
-			uint8_t r = AMPLITUDE(i, q);
-			dest[c++] = r;
+	// And now we loop, receiving samples.
+	for(;;) {
+		uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1);
+
+		if (behindBy == 0) continue;
+
+		uint16_t snoopdata = *upTo++;
+
+		if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) {                    // we have read all of the DMA buffer content.
+			upTo = dmaBuf;                                                 // start reading the circular buffer from the beginning
+			if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) {
+				Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples);
+				break;
+			}
+			if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) {              // DMA Counter Register had reached 0, already rotated.
+				AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;          // refresh the DMA Next Buffer and
+				AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE;   // DMA Next Counter registers
+				WDT_HIT();
+				if(BUTTON_PRESS()) {
+					DbpString("Snoop stopped.");
+					break;
+				}
+			}
+		}
+		samples++;
+		
+		if (!TagIsActive) {                                            // no need to try decoding reader data if the tag is sending
+			if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) {
+				FpgaDisableSscDma();
+				ExpectTagAnswer = true;
+				LogTrace(DecodeReader.output, DecodeReader.byteCount, samples, samples, NULL, true);
+				/* And ready to receive another command. */
+				DecodeReaderReset(&DecodeReader);
+				/* And also reset the demod code, which might have been */
+				/* false-triggered by the commands from the reader. */
+				DecodeTagReset(&DecodeTag);
+				upTo = dmaBuf;
+				FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE);
+			}
+			if (Handle15693SampleFromReader(snoopdata & 0x01, &DecodeReader)) {
+				FpgaDisableSscDma();
+				ExpectTagAnswer = true;
+				LogTrace(DecodeReader.output, DecodeReader.byteCount, samples, samples, NULL, true);
+				/* And ready to receive another command. */
+				DecodeReaderReset(&DecodeReader);
+				/* And also reset the demod code, which might have been */
+				/* false-triggered by the commands from the reader. */
+				DecodeTagReset(&DecodeTag);
+				upTo = dmaBuf;
+				FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE);
+			}
+			ReaderIsActive = (DecodeReader.state >= STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF);
 		}
+
+		if (!ReaderIsActive && ExpectTagAnswer) {						// no need to try decoding tag data if the reader is currently sending or no answer expected yet
+			if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) {
+				FpgaDisableSscDma();
+				//Use samples as a time measurement
+				LogTrace(DecodeTag.output, DecodeTag.len, samples, samples, NULL, false);
+				// And ready to receive another response.
+				DecodeTagReset(&DecodeTag);
+				DecodeReaderReset(&DecodeReader);
+				ExpectTagAnswer = false;
+				upTo = dmaBuf;
+				FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE);
+			}
+			TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA);
+		}
+
 	}
 
-	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-	LED_D_OFF();
-	Dbprintf("finished recording");
-	LED_A_OFF();
+	FpgaDisableSscDma();
+	BigBuf_free();
+	
+	LEDsoff();
+
+	DbpString("Snoop statistics:");
+	Dbprintf("  ExpectTagAnswer: %d", ExpectTagAnswer);
+	Dbprintf("  DecodeTag State: %d", DecodeTag.state);
+	Dbprintf("  DecodeTag byteCnt: %d", DecodeTag.len);
+	Dbprintf("  DecodeReader State: %d", DecodeReader.state);
+	Dbprintf("  DecodeReader byteCnt: %d", DecodeReader.byteCount);
+	Dbprintf("  Trace length: %d", BigBuf_get_traceLen());
 }
 
 
@@ -1072,27 +1199,6 @@ static void Iso15693InitReader() {
 // This section basically contains transmission and receiving of bits
 ///////////////////////////////////////////////////////////////////////
 
-// Encode (into the ToSend buffers) an identify request, which is the first
-// thing that you must send to a tag to get a response.
-static void BuildIdentifyRequest(void)
-{
-	uint8_t cmd[5];
-
-	uint16_t crc;
-	// one sub-carrier, inventory, 1 slot, fast rate
-	// AFI is at bit 5 (1<<4) when doing an INVENTORY
-	cmd[0] = (1 << 2) | (1 << 5) | (1 << 1);
-	// inventory command code
-	cmd[1] = 0x01;
-	// no mask
-	cmd[2] = 0x00;
-	//Now the CRC
-	crc = Crc(cmd, 3);
-	cmd[3] = crc & 0xff;
-	cmd[4] = crc >> 8;
-
-	CodeIso15693AsReader(cmd, sizeof(cmd));
-}
 
 // uid is in transmission order (which is reverse of display order)
 static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber )
@@ -1100,12 +1206,11 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber )
 	uint8_t cmd[13];
 
 	uint16_t crc;
-	// If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
-	// followed by teh block data
-	// one sub-carrier, inventory, 1 slot, fast rate
-	cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit
+	// If we set the Option_Flag in this request, the VICC will respond with the security status of the block
+	// followed by the block data
+	cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; 
 	// READ BLOCK command code
-	cmd[1] = 0x20;
+	cmd[1] = ISO15693_READBLOCK;
 	// UID may be optionally specified here
 	// 64-bit UID
 	cmd[2] = uid[0];
@@ -1117,7 +1222,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber )
 	cmd[8] = uid[6];
 	cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique)
 	// Block number to read
-	cmd[10] = blockNumber;//0x00;
+	cmd[10] = blockNumber;
 	//Now the CRC
 	crc = Crc(cmd, 11); // the crc needs to be calculated over 11 bytes
 	cmd[11] = crc & 0xff;
@@ -1156,10 +1261,9 @@ static void BuildInventoryResponse(uint8_t *uid)
 // Universal Method for sending to and recv bytes from a tag
 // 	init ... should we initialize the reader?
 // 	speed ... 0 low speed, 1 hi speed
-// 	**recv will return you a pointer to the received data
-// 	If you do not need the answer use NULL for *recv[]
+// 	*recv will contain the tag's answer
 //	return: lenght of received data
-int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv) {
+int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time) {
 
 	LED_A_ON();
 	LED_B_OFF();
@@ -1168,8 +1272,6 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv
 	if (init) Iso15693InitReader();
 
 	int answerLen=0;
-	uint8_t *answer = BigBuf_get_addr() + 4000;
-	if (recv != NULL) memset(answer, 0, 100);
 
 	if (!speed) {
 		// low speed (1 out of 256)
@@ -1179,11 +1281,11 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv
 		CodeIso15693AsReader(send, sendlen);
 	}
 
-	TransmitTo15693Tag(ToSend,ToSendMax);
+	TransmitTo15693Tag(ToSend, ToSendMax, start_time);
+
 	// Now wait for a response
-	if (recv!=NULL) {
-		answerLen = GetIso15693AnswerFromTag(answer, 100);
-		*recv=answer;
+	if (recv != NULL) {
+		answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC * 2);
 	}
 
 	LED_A_OFF();
@@ -1202,46 +1304,46 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) {
 	char status[DBD15STATLEN+1]={0};
 	uint16_t crc;
 
-	if (len>3) {
-		if (d[0]&(1<<3))
-			strncat(status,"ProtExt ",DBD15STATLEN);
-		if (d[0]&1) {
+	if (len > 3) {
+		if (d[0] & ISO15693_RES_EXT)
+			strncat(status,"ProtExt ", DBD15STATLEN);
+		if (d[0] & ISO15693_RES_ERROR) {
 			// error
-			strncat(status,"Error ",DBD15STATLEN);
+			strncat(status,"Error ", DBD15STATLEN);
 			switch (d[1]) {
 				case 0x01:
-					strncat(status,"01:notSupp",DBD15STATLEN);
+					strncat(status,"01:notSupp", DBD15STATLEN);
 					break;
 				case 0x02:
-					strncat(status,"02:notRecog",DBD15STATLEN);
+					strncat(status,"02:notRecog", DBD15STATLEN);
 					break;
 				case 0x03:
-					strncat(status,"03:optNotSupp",DBD15STATLEN);
+					strncat(status,"03:optNotSupp", DBD15STATLEN);
 					break;
 				case 0x0f:
-					strncat(status,"0f:noInfo",DBD15STATLEN);
+					strncat(status,"0f:noInfo", DBD15STATLEN);
 					break;
 				case 0x10:
-					strncat(status,"10:dontExist",DBD15STATLEN);
+					strncat(status,"10:doesn'tExist", DBD15STATLEN);
 					break;
 				case 0x11:
-					strncat(status,"11:lockAgain",DBD15STATLEN);
+					strncat(status,"11:lockAgain", DBD15STATLEN);
 					break;
 				case 0x12:
-					strncat(status,"12:locked",DBD15STATLEN);
+					strncat(status,"12:locked", DBD15STATLEN);
 					break;
 				case 0x13:
-					strncat(status,"13:progErr",DBD15STATLEN);
+					strncat(status,"13:progErr", DBD15STATLEN);
 					break;
 				case 0x14:
-					strncat(status,"14:lockErr",DBD15STATLEN);
+					strncat(status,"14:lockErr", DBD15STATLEN);
 					break;
 				default:
-					strncat(status,"unknownErr",DBD15STATLEN);
+					strncat(status,"unknownErr", DBD15STATLEN);
 			}
-			strncat(status," ",DBD15STATLEN);
+			strncat(status," ", DBD15STATLEN);
 		} else {
-			strncat(status,"NoErr ",DBD15STATLEN);
+			strncat(status,"NoErr ", DBD15STATLEN);
 		}
 
 		crc=Crc(d,len-2);
@@ -1266,6 +1368,7 @@ void SetDebugIso15693(uint32_t debug) {
 	return;
 }
 
+
 //-----------------------------------------------------------------------------
 // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector
 // all demodulation performed in arm rather than host. - greg
@@ -1275,13 +1378,14 @@ void ReaderIso15693(uint32_t parameter)
 	LEDsoff();
 	LED_A_ON();
 
-	int answerLen1 = 0;
+	set_tracing(true);
+	
+	int answerLen = 0;
 	uint8_t TagUID[8] = {0x00};
 
 	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
 
-	uint8_t *answer1 = BigBuf_get_addr() + 4000;
-	memset(answer1, 0x00, 200);
+	uint8_t answer[ISO15693_MAX_RESPONSE_LENGTH];
 
 	SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
 	// Setup SSC
@@ -1295,37 +1399,39 @@ void ReaderIso15693(uint32_t parameter)
 	LED_D_ON();
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
 	SpinDelay(200);
+	StartCountSspClk();
+
 
 	// FIRST WE RUN AN INVENTORY TO GET THE TAG UID
 	// THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME
 
 	// Now send the IDENTIFY command
 	BuildIdentifyRequest();
-
-	TransmitTo15693Tag(ToSend,ToSendMax);
+	TransmitTo15693Tag(ToSend, ToSendMax, 0);
 
 	// Now wait for a response
-	answerLen1 = GetIso15693AnswerFromTag(answer1, 100) ;
+	answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC * 2) ;
+	uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD;
 
-	if (answerLen1 >=12) // we should do a better check than this
+	if (answerLen >=12) // we should do a better check than this
 	{
-		TagUID[0] = answer1[2];
-		TagUID[1] = answer1[3];
-		TagUID[2] = answer1[4];
-		TagUID[3] = answer1[5];
-		TagUID[4] = answer1[6];
-		TagUID[5] = answer1[7];
-		TagUID[6] = answer1[8]; // IC Manufacturer code
-		TagUID[7] = answer1[9]; // always E0
+		TagUID[0] = answer[2];
+		TagUID[1] = answer[3];
+		TagUID[2] = answer[4];
+		TagUID[3] = answer[5];
+		TagUID[4] = answer[6];
+		TagUID[5] = answer[7];
+		TagUID[6] = answer[8]; // IC Manufacturer code
+		TagUID[7] = answer[9]; // always E0
 
 	}
 
-	Dbprintf("%d octets read from IDENTIFY request:", answerLen1);
-	DbdecodeIso15693Answer(answerLen1, answer1);
-	Dbhexdump(answerLen1, answer1, false);
+	Dbprintf("%d octets read from IDENTIFY request:", answerLen);
+	DbdecodeIso15693Answer(answerLen, answer);
+	Dbhexdump(answerLen, answer, false);
 
 	// UID is reverse
-	if (answerLen1 >= 12)
+	if (answerLen >= 12)
 		Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX",
 			TagUID[7],TagUID[6],TagUID[5],TagUID[4],
 			TagUID[3],TagUID[2],TagUID[1],TagUID[0]);
@@ -1340,18 +1446,21 @@ void ReaderIso15693(uint32_t parameter)
 	// Dbhexdump(answerLen3,answer3,true);
 
 	// read all pages
-	if (answerLen1 >= 12 && DEBUG) {
-		uint8_t *answer2 = BigBuf_get_addr() + 4100;
+	if (answerLen >= 12 && DEBUG) {
+
+		// debugptr = BigBuf_get_addr();
+
 		int i = 0;
 		while (i < 32) {  // sanity check, assume max 32 pages
 			BuildReadBlockRequest(TagUID, i);
-			TransmitTo15693Tag(ToSend, ToSendMax);
-			int answerLen2 = GetIso15693AnswerFromTag(answer2, 100);
-			if (answerLen2 > 0) {
-				Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen2);
-				DbdecodeIso15693Answer(answerLen2, answer2);
-				Dbhexdump(answerLen2, answer2, false);
-				if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr
+			TransmitTo15693Tag(ToSend, ToSendMax, start_time);
+			int answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC * 2);
+			start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD;
+			if (answerLen > 0) {
+				Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen);
+				DbdecodeIso15693Answer(answerLen, answer);
+				Dbhexdump(answerLen, answer, false);
+				if ( *((uint32_t*) answer) == 0x07160101 ) break; // exit on NoPageErr
 			}
 			i++;
 		}
@@ -1412,12 +1521,14 @@ void BruteforceIso15693Afi(uint32_t speed)
 	LEDsoff();
 	LED_A_ON();
 
-	uint8_t data[20];
-	uint8_t *recv=data;
+	uint8_t data[6];
+	uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH];
+	
 	int datalen=0, recvlen=0;
 
 	Iso15693InitReader();
-
+	StartCountSspClk();
+	
 	// first without AFI
 	// Tags should respond without AFI and with AFI=0 even when AFI is active
 
@@ -1425,10 +1536,11 @@ void BruteforceIso15693Afi(uint32_t speed)
 	data[1] = ISO15693_INVENTORY;
 	data[2] = 0; // mask length
 	datalen = AddCrc(data,3);
-	recvlen = SendDataTag(data, datalen, false, speed, &recv);
+	recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), 0);
+	uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VCD_TO_VICC;
 	WDT_HIT();
 	if (recvlen>=12) {
-		Dbprintf("NoAFI UID=%s",sprintUID(NULL,&recv[2]));
+		Dbprintf("NoAFI UID=%s", sprintUID(NULL, &recv[2]));
 	}
 
 	// now with AFI
@@ -1438,13 +1550,14 @@ void BruteforceIso15693Afi(uint32_t speed)
 	data[2] = 0; // AFI
 	data[3] = 0; // mask length
 
-	for (int i=0;i<256;i++) {
-		data[2]=i & 0xFF;
-		datalen=AddCrc(data,4);
-		recvlen=SendDataTag(data, datalen, false, speed, &recv);
+	for (int i = 0; i < 256; i++) {
+		data[2] = i & 0xFF;
+		datalen = AddCrc(data,4);
+		recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time);
+		start_time = GetCountSspClk() + DELAY_ISO15693_VCD_TO_VICC;
 		WDT_HIT();
-		if (recvlen>=12) {
-			Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL,&recv[2]));
+		if (recvlen >= 12) {
+			Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL, &recv[2]));
 		}
 	}
 	Dbprintf("AFI Bruteforcing done.");
@@ -1456,26 +1569,27 @@ void BruteforceIso15693Afi(uint32_t speed)
 // Allows to directly send commands to the tag via the client
 void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]) {
 
-	int recvlen=0;
-	uint8_t *recvbuf = BigBuf_get_addr();
+	int recvlen = 0;
+	uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
 
 	LED_A_ON();
 
 	if (DEBUG) {
-		Dbprintf("SEND");
+		Dbprintf("SEND:");
 		Dbhexdump(datalen, data, false);
 	}
 
-	recvlen = SendDataTag(data, datalen, true, speed, (recv?&recvbuf:NULL));
+	recvlen = SendDataTag(data, datalen, true, speed, (recv?recvbuf:NULL), sizeof(recvbuf), 0);
 
 	if (recv) {
-		cmd_send(CMD_ACK, recvlen>48?48:recvlen, 0, 0, recvbuf, 48);
-
 		if (DEBUG) {
-			Dbprintf("RECV");
-			DbdecodeIso15693Answer(recvlen,recvbuf);
+			Dbprintf("RECV:");
 			Dbhexdump(recvlen, recvbuf, false);
+			DbdecodeIso15693Answer(recvlen, recvbuf);
 		}
+
+		cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH);
+
 	}
 
 	// for the time being, switch field off to protect rdv4.0
diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h
new file mode 100644
index 00000000..e5b78a8a
--- /dev/null
+++ b/armsrc/iso15693.h
@@ -0,0 +1,24 @@
+//-----------------------------------------------------------------------------
+// Piwi - October 2018
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Routines to support ISO 15693.
+//-----------------------------------------------------------------------------
+
+#ifndef __ISO15693_H
+#define __ISO15693_H
+
+#include <stdint.h>
+
+void SnoopIso15693(void);
+void AcquireRawAdcSamplesIso15693(void);
+void ReaderIso15693(uint32_t parameter);
+void SimTagIso15693(uint32_t parameter, uint8_t *uid);
+void BruteforceIso15693Afi(uint32_t speed);
+void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); 
+void SetDebugIso15693(uint32_t flag);
+
+#endif
diff --git a/client/cmdhf.c b/client/cmdhf.c
index 56b1cb3d..744a95d2 100644
--- a/client/cmdhf.c
+++ b/client/cmdhf.c
@@ -264,7 +264,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
 
 		uint8_t parityBits = parityBytes[j>>3];
 		if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
-			snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]);
+			snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]);
 		} else {
 			snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]);
 		}
@@ -281,14 +281,11 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
 		}
 	}
 
-	if(data_len == 0)
-	{
-		if(data_len == 0){
-			sprintf(line[0],"<empty trace - possible error>");
-		}
+	if (data_len == 0) {
+		sprintf(line[0]," <empty trace - possible error>");
 	}
-	//--- Draw the CRC column
 
+	//--- Draw the CRC column
 	char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : "    "));
 
 	EndOfTransmissionTimestamp = timestamp + duration;
diff --git a/client/cmdhf15.c b/client/cmdhf15.c
index e5f4af31..da83ccaf 100644
--- a/client/cmdhf15.c
+++ b/client/cmdhf15.c
@@ -38,15 +38,54 @@
 #include "protocols.h"
 #include "cmdmain.h"
 
-#define FrameSOF              Iso15693FrameSOF
-#define Logic0						Iso15693Logic0
-#define Logic1						Iso15693Logic1
-#define FrameEOF					Iso15693FrameEOF
-
 #define Crc(data,datalen)     Iso15693Crc(data,datalen)
 #define AddCrc(data,datalen)  Iso15693AddCrc(data,datalen)
 #define sprintUID(target,uid)	Iso15693sprintUID(target,uid)
 
+// SOF defined as
+// 1) Unmodulated time of 56.64us
+// 2) 24 pulses of 423.75khz
+// 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
+
+static const int Iso15693FrameSOF[] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+	 1,  1,  1,  1,  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 Iso15693Logic0[] = {
+	 1,  1,  1,  1,
+	 1,  1,  1,  1,
+	-1, -1, -1, -1,
+	-1, -1, -1, -1
+};
+static const int Iso15693Logic1[] = {
+	-1, -1, -1, -1,
+	-1, -1, -1, -1,
+	 1,  1,  1,  1,
+	 1,  1,  1,  1
+};
+
+// EOF defined as
+// 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
+// 2) 24 pulses of 423.75khz
+// 3) Unmodulated time of 56.64us
+
+static const int Iso15693FrameEOF[] = {
+	 1,  1,  1,  1,
+	 1,  1,  1,  1,
+	-1, -1, -1, -1,
+	-1, -1, -1, -1,
+	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
 // structure and database for uid -> tagtype lookups 
 typedef struct { 
 	uint64_t uid;
@@ -293,8 +332,8 @@ int CmdHF15Demod(const char *Cmd)
 	// First, correlate for SOF
 	for (i = 0; i < 200; i++) {
 		int corr = 0;
-		for (j = 0; j < arraylen(FrameSOF); j += skip) {
-			corr += FrameSOF[j] * GraphBuffer[i + (j / skip)];
+		for (j = 0; j < arraylen(Iso15693FrameSOF); j += skip) {
+			corr += Iso15693FrameSOF[j] * GraphBuffer[i + (j / skip)];
 		}
 		if (corr > max) {
 			max = corr;
@@ -302,28 +341,28 @@ int CmdHF15Demod(const char *Cmd)
 		}
 	}
 	PrintAndLog("SOF at %d, correlation %d", maxPos,
-		max / (arraylen(FrameSOF) / skip));
+		max / (arraylen(Iso15693FrameSOF) / skip));
 	
-	i = maxPos + arraylen(FrameSOF) / skip;
+	i = maxPos + arraylen(Iso15693FrameSOF) / skip;
 	int k = 0;
 	uint8_t outBuf[20];
 	memset(outBuf, 0, sizeof(outBuf));
 	uint8_t mask = 0x01;
 	for (;;) {
 			int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0;
-			for(j = 0; j < arraylen(Logic0); j += skip) {
-				corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];
+			for(j = 0; j < arraylen(Iso15693Logic0); j += skip) {
+				corr0 += Iso15693Logic0[j]*GraphBuffer[i+(j/skip)];
 			}
 			corr01 = corr00 = corr0;
-			for(j = 0; j < arraylen(Logic0); j += skip) {
-				corr00 += Logic0[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)];
-				corr01 += Logic1[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)];
+			for(j = 0; j < arraylen(Iso15693Logic0); j += skip) {
+				corr00 += Iso15693Logic0[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)];
+				corr01 += Iso15693Logic1[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)];
 			}
-			for(j = 0; j < arraylen(Logic1); j += skip) {
-				corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];
+			for(j = 0; j < arraylen(Iso15693Logic1); j += skip) {
+				corr1 += Iso15693Logic1[j]*GraphBuffer[i+(j/skip)];
 			}
-			for(j = 0; j < arraylen(FrameEOF); j += skip) {
-				corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];
+			for(j = 0; j < arraylen(Iso15693FrameEOF); j += skip) {
+				corrEOF += Iso15693FrameEOF[j]*GraphBuffer[i+(j/skip)];
 			}
 			// Even things out by the length of the target waveform.
 			corr00 *= 2;
@@ -335,17 +374,17 @@ int CmdHF15Demod(const char *Cmd)
 				PrintAndLog("EOF at %d", i);
 				break;
 		} else if (corr1 > corr0) {
-			i += arraylen(Logic1) / skip;
+			i += arraylen(Iso15693Logic1) / skip;
 			outBuf[k] |= mask;
 		} else {
-			i += arraylen(Logic0) / skip;
+			i += arraylen(Iso15693Logic0) / skip;
 		}
 		mask <<= 1;
 		if (mask == 0) {
 			k++;
 			mask = 0x01;
 		}
-		if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) {
+		if ((i + (int)arraylen(Iso15693FrameEOF)) >= GraphTraceLen) {
 			PrintAndLog("ran off end!");
 			break;
 		}
@@ -374,10 +413,9 @@ int CmdHF15Read(const char *Cmd)
 }
 
 // Record Activity without enabling carrier
-// TODO: currently it DOES enable the carrier
-int CmdHF15Record(const char *Cmd)
+int CmdHF15Snoop(const char *Cmd)
 {
-	UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693};
+	UsbCommand c = {CMD_SNOOP_ISO_15693};
 	SendCommand(&c);
 	return 0;
 }
@@ -514,7 +552,7 @@ static command_t CommandTable15[] =
 	{"help",    CmdHF15Help,    1, "This help"},
 	{"demod",   CmdHF15Demod,   1, "Demodulate ISO15693 from tag"},
 	{"read",    CmdHF15Read,    0, "Read HF tag (ISO 15693)"},
-	{"record",  CmdHF15Record,  0, "Record Samples (ISO 15693)"}, // atrox
+	{"snoop",   CmdHF15Snoop,   0, "Eavesdrop ISO 15693 communications"},
 	{"reader",  CmdHF15Reader,  0, "Act like an ISO15693 reader"},
 	{"sim",     CmdHF15Sim,     0, "Fake an ISO15693 tag"},
 	{"cmd",     CmdHF15Cmd,     0, "Send direct commands to ISO15693 tag"},
diff --git a/common/iso15693tools.h b/common/iso15693tools.h
index 96095fba..d9f59cc6 100644
--- a/common/iso15693tools.h
+++ b/common/iso15693tools.h
@@ -14,57 +14,4 @@ int Iso15693AddCrc(uint8_t *req, int n);
 char* Iso15693sprintUID(char *target,uint8_t *uid);
 unsigned short iclass_crc16(char *data_p, unsigned short length);
 
-//-----------------------------------------------------------------------------
-// Map a sequence of octets (~layer 2 command) into the set of bits to feed
-// to the FPGA, to transmit that command to the tag.
-// Mode: highspeed && one subcarrier (ASK)
-//-----------------------------------------------------------------------------
-
-	// The sampling rate is 106.353 ksps/s, for T = 18.8 us
-
-	// SOF defined as
-	// 1) Unmodulated time of 56.64us
-	// 2) 24 pulses of 423.75khz
-	// 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
-
-	static const int Iso15693FrameSOF[] = {
-		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-		 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-		 1,  1,  1,  1,  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 Iso15693Logic0[] = {
-		 1,  1,  1,  1,
-		 1,  1,  1,  1,
-		-1, -1, -1, -1,
-		-1, -1, -1, -1
-	};
-	static const int Iso15693Logic1[] = {
-		-1, -1, -1, -1,
-		-1, -1, -1, -1,
-		 1,  1,  1,  1,
-		 1,  1,  1,  1
-	};
-
-	// EOF defined as
-	// 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
-	// 2) 24 pulses of 423.75khz
-	// 3) Unmodulated time of 56.64us
-
-	static const int Iso15693FrameEOF[] = {
-		 1,  1,  1,  1,
-		 1,  1,  1,  1,
-		-1, -1, -1, -1,
-		-1, -1, -1, -1,
-		 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-		 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
-	};
-
-
 #endif
diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit
index bd296174f0978d3214bae003d25a7063bff60021..f16fd0614fbd2614e713a29da5f47a29094953e5 100644
GIT binary patch
literal 42175
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

literal 42175
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
ZK6Bx<ugQ|lzsD5?`1jCETFQIL{{yB^19<=d

diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v
index f99a43dd..5d55cb89 100644
--- a/fpga/fpga_hf.v
+++ b/fpga/fpga_hf.v
@@ -75,6 +75,8 @@ wire hi_read_rx_xcorr_848 = conf_word[0];
 wire hi_read_rx_xcorr_snoop = conf_word[1];
 // divide subcarrier frequency by 4
 wire hi_read_rx_xcorr_quarter = conf_word[2];
+// send amplitude only instead of ci/cq pair
+wire hi_read_rx_xcorr_amplitude = conf_word[3];
 
 // For the high-frequency simulated tag: what kind of modulation to use.
 wire [2:0] hi_simulate_mod_type = conf_word[2:0];
@@ -102,7 +104,7 @@ hi_read_rx_xcorr hrxc(
 	hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,
 	cross_hi, cross_lo,
 	hrxc_dbg,
-	hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter
+	hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter, hi_read_rx_xcorr_amplitude
 );
 
 hi_simulate hs(
diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v
index 8233960f..503c8d67 100644
--- a/fpga/hi_read_rx_xcorr.v
+++ b/fpga/hi_read_rx_xcorr.v
@@ -10,7 +10,7 @@ module hi_read_rx_xcorr(
     ssp_frame, ssp_din, ssp_dout, ssp_clk,
     cross_hi, cross_lo,
     dbg,
-    xcorr_is_848, snoop, xcorr_quarter_freq
+    xcorr_is_848, snoop, xcorr_quarter_freq, hi_read_rx_xcorr_amplitude
 );
     input pck0, ck_1356meg, ck_1356megb;
     output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
@@ -20,7 +20,7 @@ module hi_read_rx_xcorr(
     output ssp_frame, ssp_din, ssp_clk;
     input cross_hi, cross_lo;
     output dbg;
-    input xcorr_is_848, snoop, xcorr_quarter_freq;
+    input xcorr_is_848, snoop, xcorr_quarter_freq, hi_read_rx_xcorr_amplitude;
 
 // Carrier is steady on through this, unless we're snooping.
 assign pwr_hi = ck_1356megb & (~snoop);
@@ -83,11 +83,46 @@ reg signed [13:0] corr_q_accum;
 // we will report maximum 8 significant bits
 reg signed [7:0] corr_i_out;
 reg signed [7:0] corr_q_out;
+
 // clock and frame signal for communication to ARM
 reg ssp_clk;
 reg ssp_frame;
 
 
+
+// the amplitude of the subcarrier is sqrt(ci^2 + cq^2).
+// approximate by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|)
+reg [13:0] corr_amplitude, abs_ci, abs_cq, max_ci_cq, min_ci_cq;
+
+
+always @(corr_i_accum or corr_q_accum)
+begin
+	if (corr_i_accum[13] == 1'b0)
+		abs_ci <= corr_i_accum;
+	else
+		abs_ci <= -corr_i_accum;
+	
+	if (corr_q_accum[13] == 1'b0)
+		abs_cq <= corr_q_accum;
+	else
+		abs_cq <= -corr_q_accum;
+	
+	if (abs_ci > abs_cq)
+	begin
+		max_ci_cq <= abs_ci;
+		min_ci_cq <= abs_cq;
+	end
+	else
+	begin
+		max_ci_cq <= abs_cq;
+		min_ci_cq <= abs_ci;
+	end
+
+	corr_amplitude <= max_ci_cq + min_ci_cq/2;
+
+end
+
+
 // The subcarrier reference signals
 reg subcarrier_I;
 reg subcarrier_Q;
@@ -110,52 +145,75 @@ begin
 			subcarrier_Q = ~(corr_i_cnt[4] ^ corr_i_cnt[3]);
 		end
 end
-	
+
+
 // ADC data appears on the rising edge, so sample it on the falling edge
 always @(negedge adc_clk)
 begin
     // These are the correlators: we correlate against in-phase and quadrature
-    // versions of our reference signal, and keep the (signed) result to
-    // send out later over the SSP.
+    // versions of our reference signal, and keep the (signed) results or the
+    // resulting amplitude to send out later over the SSP.
     if(corr_i_cnt == 6'd0)
     begin
         if(snoop)
         begin
-			// Send 7 most significant bits of tag signal (signed), plus 1 bit reader signal
-			if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) 
-				corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev};
-			else // truncate to maximum value
-				if (corr_i_accum[13] == 1'b0)
-					corr_i_out <= {7'b0111111, after_hysteresis_prev_prev};
-				else
-					corr_i_out <= {7'b1000000, after_hysteresis_prev_prev};
-			if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) 
-				corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev};
-			else // truncate to maximum value
-				if (corr_q_accum[13] == 1'b0)
-					corr_q_out <= {7'b0111111, after_hysteresis_prev};
-				else
-					corr_q_out <= {7'b1000000, after_hysteresis_prev};
-			after_hysteresis_prev_prev <= after_hysteresis;
+			if (hi_read_rx_xcorr_amplitude)
+			begin
+				// send amplitude plus 2 bits reader signal
+				corr_i_out <= corr_amplitude[13:6];
+				corr_q_out <= {corr_amplitude[5:0], after_hysteresis_prev_prev, after_hysteresis_prev};
+			end	
+			else
+			begin
+				// Send 7 most significant bits of in phase tag signal (signed), plus 1 bit reader signal
+				if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) 
+					corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev};
+				else // truncate to maximum value
+					if (corr_i_accum[13] == 1'b0)
+						corr_i_out <= {7'b0111111, after_hysteresis_prev_prev};
+					else
+						corr_i_out <= {7'b1000000, after_hysteresis_prev_prev};
+				// Send 7 most significant bits of quadrature phase tag signal (signed), plus 1 bit reader signal
+				if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) 
+					corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev};
+				else // truncate to maximum value
+					if (corr_q_accum[13] == 1'b0)
+						corr_q_out <= {7'b0111111, after_hysteresis_prev};
+					else
+						corr_q_out <= {7'b1000000, after_hysteresis_prev};
+			end
         end
         else
         begin
-            // Send 8 bits of tag signal
-			if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) 
-				corr_i_out <= corr_i_accum[11:4];
-			else // truncate to maximum value
-				if (corr_i_accum[13] == 1'b0)
-					corr_i_out <= 8'b01111111;
-				else
-					corr_i_out <= 8'b10000000;
-			if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) 
-				corr_q_out <= corr_q_accum[11:4];
-			else // truncate to maximum value
-				if (corr_q_accum[13] == 1'b0)
-					corr_q_out <= 8'b01111111;
-				else
-					corr_q_out <= 8'b10000000;
+			if (hi_read_rx_xcorr_amplitude)
+			begin
+				// send amplitude
+				corr_i_out <= {2'b00, corr_amplitude[13:8]};
+				corr_q_out <= corr_amplitude[7:0];
+			end	
+			else
+			begin
+				// Send 8 bits of in phase tag signal
+				if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) 
+					corr_i_out <= corr_i_accum[11:4];
+				else // truncate to maximum value
+					if (corr_i_accum[13] == 1'b0)
+						corr_i_out <= 8'b01111111;
+					else
+						corr_i_out <= 8'b10000000;
+				// Send 8 bits of quadrature phase tag signal
+				if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) 
+					corr_q_out <= corr_q_accum[11:4];
+				else // truncate to maximum value
+					if (corr_q_accum[13] == 1'b0)
+						corr_q_out <= 8'b01111111;
+					else
+						corr_q_out <= 8'b10000000;
+			end
         end
+
+		// for each Q/I pair report two reader signal samples when sniffing. Store the 1st.
+		after_hysteresis_prev_prev <= after_hysteresis;
 		// Initialize next correlation. 
 		// Both I and Q reference signals are high when corr_i_nct == 0. Therefore need to accumulate.
         corr_i_accum <= $signed({1'b0,adc_d});
@@ -172,16 +230,16 @@ begin
             corr_q_accum <= corr_q_accum + $signed({1'b0,adc_d});
         else
             corr_q_accum <= corr_q_accum - $signed({1'b0,adc_d});
-
     end
 
-	// for each Q/I pair report two reader signal samples when sniffing
+	// for each Q/I pair report two reader signal samples when sniffing. Store the 2nd.
     if(corr_i_cnt == 6'd32)
         after_hysteresis_prev <= after_hysteresis;
 
     // Then the result from last time is serialized and send out to the ARM.
     // We get one report each cycle, and each report is 16 bits, so the
-    // ssp_clk should be the adc_clk divided by 64/16 = 4.
+    // ssp_clk should be the adc_clk divided by 64/16 = 4. 
+	// ssp_clk frequency = 13,56MHz / 4 = 3.39MHz
 
     if(corr_i_cnt[1:0] == 2'b10)
         ssp_clk <= 1'b0;
diff --git a/include/usb_cmd.h b/include/usb_cmd.h
index e73aa2a7..785435f0 100644
--- a/include/usb_cmd.h
+++ b/include/usb_cmd.h
@@ -125,7 +125,7 @@ typedef struct{
 #define CMD_ISO_14443B_COMMAND                                            0x0305
 #define CMD_READER_ISO_15693                                              0x0310
 #define CMD_SIMTAG_ISO_15693                                              0x0311
-#define CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693                              0x0312
+#define CMD_SNOOP_ISO_15693                                               0x0312
 #define CMD_ISO_15693_COMMAND                                             0x0313
 #define CMD_ISO_15693_COMMAND_DONE                                        0x0314
 #define CMD_ISO_15693_FIND_AFI                                            0x0315
-- 
2.39.5