From: Martin Holst Swende <martin@swende.se>
Date: Wed, 28 Jan 2015 23:57:22 +0000 (+0100)
Subject: Added client-side support for recording longer samples, fixed last (?) issues on... 
X-Git-Tag: v2.0.0-rc1~33^2~4
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/f6d9fb173fec6d117faeb6c39cf37ee449d4ef16?hp=7c676e7269ce6ca6be9fbadb237873dd31b4d27d

Added client-side support for recording longer samples, fixed last (?) issues on device-side
---

diff --git a/armsrc/appmain.c b/armsrc/appmain.c
index 530dc39c..83d9dd1f 100644
--- a/armsrc/appmain.c
+++ b/armsrc/appmain.c
@@ -630,7 +630,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
 	switch(c->cmd) {
 #ifdef WITH_LF
 		case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
-			AcquireRawAdcSamples125k(c->arg[0]);
+			AcquireRawAdcSamples125k(c->arg[0], c->arg[1], c->arg[2]);
 			cmd_send(CMD_ACK,0,0,0,0,0);
 			break;
 		case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
@@ -910,7 +910,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
 				cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,i,len,0,((byte_t*)BigBuf)+c->arg[0]+i,len);
 			}
 			// Trigger a finish downloading signal with an ACK frame
-			cmd_send(CMD_ACK,0,0,0,0,0);
+			cmd_send(CMD_ACK,bits_per_sample,decimation,0,0,0);
 			LED_B_OFF();
 			break;
 
diff --git a/armsrc/apps.h b/armsrc/apps.h
index 5a1ab690..110e03b3 100644
--- a/armsrc/apps.h
+++ b/armsrc/apps.h
@@ -81,7 +81,6 @@ int AvgAdc(int ch);
 void ToSendStuffBit(int b);
 void ToSendReset(void);
 void ListenReaderField(int limit);
-void AcquireRawAdcSamples125k(int at134khz);
 void SnoopLFRawAdcSamples(int divisor, int trigger_threshold);
 void DoAcquisition125k(int trigger_threshold);
 extern int ToSendMax;
@@ -144,7 +143,11 @@ void SetAdcMuxFor(uint32_t whichGpio);
 #define FPGA_HF_ISO14443A_READER_MOD				(4<<0)
 
 /// lfops.h
-void AcquireRawAdcSamples125k(int divisor);
+extern uint8_t decimation;
+extern uint8_t bits_per_sample ;
+extern bool averaging;
+
+void AcquireRawAdcSamples125k(int divisor,int arg1, int arg2);
 void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,uint8_t *command);
 void ReadTItag(void);
 void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc);
diff --git a/armsrc/lfops.c b/armsrc/lfops.c
index 3cd2bc36..c1031447 100644
--- a/armsrc/lfops.c
+++ b/armsrc/lfops.c
@@ -16,47 +16,58 @@
 #include "string.h"
 #include "lfdemod.h"
 
+uint8_t decimation  = 1;
+uint8_t bits_per_sample = 8;
+bool averaging = 1;
+
+
 typedef struct {
 	uint8_t * buffer;
 	uint32_t numbits;
-	uint8_t position;
+	uint32_t position;
 } BitstreamOut;
 /**
  * @brief Pushes bit onto the stream
  * @param stream
  * @param bit
  */
-void pushBit( BitstreamOut* stream, bool bit)
+void pushBit( BitstreamOut* stream, uint8_t bit)
 {
 	int bytepos = stream->position >> 3; // divide by 8
 	int bitpos = stream->position & 7;
-	*(stream->buffer+bytepos) |= (bit & 1) <<  (7 - bitpos);
+	*(stream->buffer+bytepos) |= (bit > 0) <<  (7 - bitpos);
 	stream->position++;
 	stream->numbits++;
 }
+
 /**
- * @brief Does LF sample acquisition, this method implements decimation and quantization in order to
+ * Does the sample acquisition. If threshold is specified, the actual sampling
+ * is not commenced until the threshold has been reached.
+ * This method implements decimation and quantization in order to
  * be able to provide longer sample traces.
- * @param decimation - how much should the signal be decimated. A decimation of 1 means every sample, 2 means
- * every other sample, etc.
- * @param bits_per_sample - bits per sample. Max 8, min 1 bit per sample.
+ * Uses the following global settings:
+ * - decimation - how much should the signal be decimated. A decimation of N means we keep 1 in N samples, etc.
+ * - bits_per_sample - bits per sample. Max 8, min 1 bit per sample.
+ * - averaging If set to true, decimation will use averaging, so that if e.g. decimation is 3, the sample
+ * value that will be used is the average value of the three samples.
+ *
  * @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set
  * to -1 to ignore threshold.
- * @param averaging If set to true, decimation will use averaging, so that if e.g. decimation is 3, the sample
- * value that will be used is the average value of the three samples.
+ * @param silent - is true, now outputs are made. If false, dbprints the status
  * @return the number of bits occupied by the samples.
  */
-uint8_t DoAcquisition(int decimation, int bits_per_sample, int trigger_threshold, bool averaging)
+uint32_t DoAcquisition125k_internal(int trigger_threshold,bool silent)
 {
-	//A decimation of 2 means we keep every 2nd sample
-	//A decimation of 3 means we keep 1 in 3 samples.
-	//A quantization of 1 means one bit is discarded from the sample (division by 2).
+	//.
 	uint8_t *dest = (uint8_t *)BigBuf;
 	int bufsize = BIGBUF_SIZE;
 	memset(dest, 0, bufsize);
+
 	if(bits_per_sample < 1) bits_per_sample = 1;
 	if(bits_per_sample > 8) bits_per_sample = 8;
 
+	if(decimation < 1) decimation = 1;
+
 	// Use a bit stream to handle the output
 	BitstreamOut data = { dest , 0, 0};
 	int sample_counter = 0;
@@ -66,7 +77,7 @@ uint8_t DoAcquisition(int decimation, int bits_per_sample, int trigger_threshold
 	uint32_t sample_total_numbers =0 ;
 	uint32_t sample_total_saved =0 ;
 
-	for(;;) {
+	while(!BUTTON_PRESS()) {
 		WDT_HIT();
 		if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
 			AT91C_BASE_SSC->SSC_THR = 0x43;
@@ -74,76 +85,59 @@ uint8_t DoAcquisition(int decimation, int bits_per_sample, int trigger_threshold
 		}
 		if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
 			sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+			LED_D_OFF();
 			if (trigger_threshold != -1 && sample < trigger_threshold)
 				continue;
-			sample_total_numbers++;
 
-			LED_D_OFF();
 			trigger_threshold = -1;
-			sample_counter++;
-			sample_sum += sample;
+			sample_total_numbers++;
+
+			if(averaging)
+			{
+				sample_sum += sample;
+			}
 			//Check decimation
-			if(sample_counter < decimation) continue;
+			if(decimation > 1)
+			{
+				sample_counter++;
+				if(sample_counter < decimation) continue;
+				sample_counter = 0;
+			}
 			//Averaging
-			if(averaging) sample = sample_sum / decimation;
-
-			sample_counter = 0;
-			sample_sum =0;
+			if(averaging && decimation > 1) {
+				sample = sample_sum / decimation;
+				sample_sum =0;
+			}
+			//Store the sample
 			sample_total_saved ++;
-			pushBit(&data, sample & 0x80);
-			if(bits_per_sample > 1)	pushBit(&data, sample & 0x40);
-			if(bits_per_sample > 2)	pushBit(&data, sample & 0x20);
-			if(bits_per_sample > 3)	pushBit(&data, sample & 0x10);
-			if(bits_per_sample > 4)	pushBit(&data, sample & 0x08);
-			if(bits_per_sample > 5)	pushBit(&data, sample & 0x04);
-			if(bits_per_sample > 6)	pushBit(&data, sample & 0x02);
-			if(bits_per_sample > 7)	pushBit(&data, sample & 0x01);
-
-			if((data.numbits >> 3) +1  >= bufsize) break;
+			if(bits_per_sample == 8){
+				dest[sample_total_saved-1] = sample;
+				data.numbits = sample_total_saved << 3;//Get the return value correct
+				if(sample_total_saved >= bufsize) break;
+			}
+			else{
+				pushBit(&data, sample & 0x80);
+				if(bits_per_sample > 1)	pushBit(&data, sample & 0x40);
+				if(bits_per_sample > 2)	pushBit(&data, sample & 0x20);
+				if(bits_per_sample > 3)	pushBit(&data, sample & 0x10);
+				if(bits_per_sample > 4)	pushBit(&data, sample & 0x08);
+				if(bits_per_sample > 5)	pushBit(&data, sample & 0x04);
+				if(bits_per_sample > 6)	pushBit(&data, sample & 0x02);
+				//Not needed, 8bps is covered above
+				//if(bits_per_sample > 7)	pushBit(&data, sample & 0x01);
+				if((data.numbits >> 3) +1  >= bufsize) break;
+			}
 		}
 	}
-	Dbprintf("Done, saved %l out of %l seen samples.",sample_total_saved, sample_total_numbers);
 
+	if(!silent)
+	{
+		Dbprintf("Done, saved %d out of %d seen samples at %d bits/sample",sample_total_saved, sample_total_numbers,bits_per_sample);
+		Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
+					dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
+	}
 	return data.numbits;
 }
-
-
-/**
-* Does the sample acquisition. If threshold is specified, the actual sampling
-* is not commenced until the threshold has been reached.
-* @param trigger_threshold - the threshold
-* @param silent - is true, now outputs are made. If false, dbprints the status
-*/
-void DoAcquisition125k_internal(int trigger_threshold,bool silent)
-{
-    uint8_t *dest = (uint8_t *)BigBuf;
-    int n = sizeof(BigBuf);
-    int i;
-
-    memset(dest, 0, n);
-    i = 0;
-    for(;;) {
-        if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
-            AT91C_BASE_SSC->SSC_THR = 0x43;
-            LED_D_ON();
-        }
-        if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
-            dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-            LED_D_OFF();
-            if (trigger_threshold != -1 && dest[i] < trigger_threshold)
-                continue;
-            else
-                trigger_threshold = -1;
-            if (++i >= n) break;
-        }
-    }
-    if(!silent)
-    {
-        Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
-                 dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
-
-    }
-}
 /**
 * Perform sample aquisition.
 */
@@ -181,11 +175,27 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
 /**
 * Initializes the FPGA, and acquires the samples.
 **/
-void AcquireRawAdcSamples125k(int divisor)
+void AcquireRawAdcSamples125k(int divisor,int arg1, int arg2)
 {
-    LFSetupFPGAForADC(divisor, true);
-    // Now call the acquisition routine
-    DoAcquisition125k_internal(-1,false);
+	if (arg1 != 0)
+	{
+		averaging = (arg1 & 0x80) != 0;
+		bits_per_sample = (arg1 & 0x0F);
+	}
+	if(arg2 != 0)
+	{
+		decimation = arg2;
+	}
+
+	Dbprintf("Sampling config: ");
+	Dbprintf("   divisor:    %d ", divisor);
+	Dbprintf("   bps:        %d ", bits_per_sample);
+	Dbprintf("   decimation: %d ", decimation);
+	Dbprintf("   averaging:  %d ", averaging);
+
+	LFSetupFPGAForADC(divisor, true);
+	// Now call the acquisition routine
+	DoAcquisition125k_internal(-1,false);
 }
 /**
 * Initializes the FPGA for snoop-mode, and acquires the samples.
@@ -1479,7 +1489,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
     int lmin=128, lmax=128;
     uint8_t dir;
 
-    AcquireRawAdcSamples125k(0);
+	AcquireRawAdcSamples125k(0,0,0);
 
     lmin = 64;
     lmax = 192;
diff --git a/client/cmddata.c b/client/cmddata.c
index a88fa4e1..79384580 100644
--- a/client/cmddata.c
+++ b/client/cmddata.c
@@ -1051,6 +1051,29 @@ int CmdHpf(const char *Cmd)
   RepaintGraphWindow();
   return 0;
 }
+typedef struct {
+	uint8_t * buffer;
+	uint32_t numbits;
+	uint32_t position;
+}BitstreamOut;
+
+bool _headBit( BitstreamOut *stream)
+{
+	int bytepos = stream->position >> 3; // divide by 8
+	int bitpos = (stream->position++) & 7; // mask out 00000111
+	return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
+}
+
+uint8_t getByte(uint8_t bits_per_sample, BitstreamOut* b)
+{
+	int i;
+	uint8_t val = 0;
+	for(i =0 ; i < bits_per_sample; i++)
+	{
+		val |= (_headBit(b) << (7-i));
+	}
+	return val;
+}
 
 int CmdSamples(const char *Cmd)
 {
@@ -1063,15 +1086,35 @@ int CmdSamples(const char *Cmd)
 	if (n > sizeof(got))
 		n = sizeof(got);
 
-	PrintAndLog("Reading %d samples from device memory\n", n);
-  GetFromBigBuf(got,n,0);
-  WaitForResponse(CMD_ACK,NULL);
-	for (int j = 0; j < n; j++) {
-		GraphBuffer[j] = ((int)got[j]) - 128;
-  }
-  GraphTraceLen = n;
-  RepaintGraphWindow();
-  return 0;
+	PrintAndLog("Reading %d bytes from device memory\n", n);
+	GetFromBigBuf(got,n,0);
+	PrintAndLog("Data fetched");
+	UsbCommand response;
+	WaitForResponse(CMD_ACK, &response);
+	uint8_t bits_per_sample = response.arg[0];
+	PrintAndLog("Samples packed at %d bits per sample", bits_per_sample);
+	if(bits_per_sample < 8)
+	{
+		PrintAndLog("Unpacking...");
+		BitstreamOut bout = { got, bits_per_sample * n,  0};
+		int j =0;
+		for (j = 0; j * bits_per_sample < n * 8 && j < GraphTraceLen; j++) {
+			uint8_t sample = getByte(bits_per_sample, &bout);
+			GraphBuffer[j] = ((int) sample )- 128;
+		}
+		GraphTraceLen = j;
+		PrintAndLog("Unpacked %d samples" , j );
+	}else
+	{
+		for (int j = 0; j < n; j++) {
+			GraphBuffer[j] = ((int)got[j]) - 128;
+		}
+		GraphTraceLen = n;
+
+	}
+
+	RepaintGraphWindow();
+	return 0;
 }
 
 int CmdTuneSamples(const char *Cmd)
diff --git a/client/cmdlf.c b/client/cmdlf.c
index e3361cb5..93a9f586 100644
--- a/client/cmdlf.c
+++ b/client/cmdlf.c
@@ -356,24 +356,91 @@ int CmdIndalaClone(const char *Cmd)
   return 0;
 }
 
+int CmdLFReadUsage()
+{
+	PrintAndLog("Usage: lf read [H|<divisor>] [b <bps>] [d <decim>] [a 0|1]");
+	PrintAndLog("Options:        ");
+	PrintAndLog("       h            This help");
+	PrintAndLog("       H            High frequency (134 KHz). Defaults to 125 KHz");
+	PrintAndLog("       <divisor>    Manually set divisor. 88-> 134KHz, 95-> 125 Hz");
+	PrintAndLog("       b <bps>      Sets resolution of bits per sample. Default (max): 8");
+	PrintAndLog("       d <decim>    Sets decimation. A value of N saves only 1 in N samples. Default: 1");
+	PrintAndLog("       a [0|1]      Averaging - if set, will average the stored sample value when decimating. Default: 1");
+	PrintAndLog("Examples:");
+	PrintAndLog("      lf read");
+	PrintAndLog("                    Samples at 125KHz, 8bps.");
+	PrintAndLog("      lf read h b 4 d 3");
+	PrintAndLog("                    Samples at 134KHz, averages three samples into one, stored with ");
+	PrintAndLog("                    a resolution of 4 bits per sample.");
+	return 0;
+}
 int CmdLFRead(const char *Cmd)
 {
-  UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
+	uint8_t divisor =  95;//Frequency divisor
+	uint8_t bps = 8; // Bits per sample
+	uint8_t decimation = 1; //How many to keep
+	bool averaging = 1; // Should we use averaging when discarding samples?
+	bool errors = FALSE;
+
+	uint8_t cmdp =0;
+	if(param_getchar(Cmd, cmdp) == 'h')
+	{
+		return CmdLFReadUsage();
+	}
 
-  // 'h' means higher-low-frequency, 134 kHz
-  if(*Cmd == 'h') {
-    c.arg[0] = 1;
-  } else if (*Cmd == '\0') {
-    c.arg[0] = 0;
-  } else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) {
-		PrintAndLog("Samples 1: 'lf read'");
-		PrintAndLog("        2: 'lf read h'");
-		PrintAndLog("        3: 'lf read <divisor>'");
-    return 0;
-  }
-  SendCommand(&c);
-  WaitForResponse(CMD_ACK,NULL);
-  return 0;
+	// Divisor
+	if(param_getchar(Cmd, cmdp) == 'H') {
+		divisor = 88;
+		cmdp++;
+	}else if(param_isdec(Cmd,cmdp) )
+	{
+		errors |= param_getdec(Cmd,cmdp, &divisor);
+	}
+	//BPS
+	if(param_getchar(Cmd, cmdp) == 'b') {
+		errors |= param_getdec(Cmd,cmdp+1,&bps);
+		cmdp+=2;
+	}
+	//Decimation
+	if(param_getchar(Cmd, cmdp) == 'd')
+	{
+		errors |= param_getdec(Cmd,cmdp+1,&decimation);
+		cmdp+=2;
+	}
+	//Averaging
+	if(param_getchar(Cmd, cmdp) == 'a')
+	{
+		averaging = param_getchar(Cmd,cmdp+1) == '1';
+		cmdp+=2;
+	}
+	//Validations
+	if(errors)
+	{
+		return CmdLFReadUsage();
+	}
+
+	//Bps is limited to 8, so fits in lower half of arg1
+	if(bps > 8) bps = 8;
+
+	//Feedback
+	PrintAndLog("Sampling config: ");
+	PrintAndLog("   divisor:    %d ", divisor);
+	PrintAndLog("   bps:        %d ", bps);
+	PrintAndLog("   decimation: %d ", decimation);
+	PrintAndLog("   averaging:  %d ", averaging);
+	PrintAndLog("OBS, this is sticky on the device and affects all LF listening operations");
+	PrintAndLog("To reset, issue 'lf read'");
+
+	//And ship it to device
+	//Averaging is a flag on high-bit of arg[1]
+	UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
+	c.arg[0] = divisor;
+	c.arg[1] = bps | (averaging << 7) ;
+	c.arg[2] = decimation;
+
+	SendCommand(&c);
+	WaitForResponse(CMD_ACK,NULL);
+	return 0;
 }
 
 static void ChkBitstream(const char *str)
diff --git a/client/graph.h b/client/graph.h
index 1abeeb25..2c448161 100644
--- a/client/graph.h
+++ b/client/graph.h
@@ -20,7 +20,8 @@ int GetClock(const char *str, int peak, int verbose);
 int GetNRZpskClock(const char *str, int peak, int verbose);
 void setGraphBuf(uint8_t *buff, size_t size);
 
-#define MAX_GRAPH_TRACE_LEN (1024*128)
+// Max graph trace len: 40000 (bigbuf) * 8 (at 1 bit per sample)
+#define MAX_GRAPH_TRACE_LEN (40000 * 8 )
 extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];
 extern int GraphTraceLen;
 
diff --git a/client/util.c b/client/util.c
index b8d5c316..bce1c122 100644
--- a/client/util.c
+++ b/client/util.c
@@ -227,6 +227,34 @@ uint8_t param_get8(const char *line, int paramnum)
 	return param_get8ex(line, paramnum, 10, 0);
 }
 
+/**
+ * @brief Reads a decimal integer
+ * @param line
+ * @param paramnum
+ * @return
+ */
+uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination)
+{
+	uint8_t val = param_get8ex(line, paramnum, 10, 10);
+	(*destination) = val;
+	return 0;
+}
+/**
+ * @brief Checks if param is decimal
+ * @param line
+ * @param paramnum
+ * @return
+ */
+uint8_t param_isdec(const char *line, int paramnum)
+{
+	int bg, en;
+	//TODO, check more thorougly
+	if (!param_getptr(line, &bg, &en, paramnum)) return 1;
+		//		return strtoul(&line[bg], NULL, 10) & 0xff;
+
+	return 0;
+}
+
 uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base)
 {
 	int bg, en;
diff --git a/client/util.h b/client/util.h
index 22d41e0c..5001acdc 100644
--- a/client/util.h
+++ b/client/util.h
@@ -49,6 +49,8 @@ uint8_t param_get8(const char *line, int paramnum);
 uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
 uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base);
 uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base);
+uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination);
+uint8_t param_isdec(const char *line, int paramnum);
 int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
 int param_getstr(const char *line, int paramnum, char * str);