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:
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;
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;
#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);
#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;
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;
}
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.
*/
/**
* 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.
int lmin=128, lmax=128;
uint8_t dir;
- AcquireRawAdcSamples125k(0);
+ AcquireRawAdcSamples125k(0,0,0);
lmin = 64;
lmax = 192;
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)
{
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)
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)
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;
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;
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);