From cb366e9dbd0f421c143d6a9f02d7e0abc86c90ba Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 22 Jan 2015 23:01:29 +0100 Subject: [PATCH 1/7] Added a lf acquisition-mode which can do decimation and quantization, in order to be able to record longer transactions --- armsrc/lfops.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index f5040850c..1d7d2036e 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -8,6 +8,7 @@ // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- +#include #include "proxmark3.h" #include "apps.h" #include "util.h" @@ -16,6 +17,83 @@ #include "string.h" #include "lfdemod.h" +typedef struct { + uint8_t * buffer; + uint32_t numbits; + uint8_t position; +} BitstreamOut; +/** + * @brief Pushes bit onto the stream + * @param stream + * @param bit + */ +void pushBit( BitstreamOut* stream, bool bit) +{ + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = stream->position & 7; + *(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos); + stream->position++; + stream->numbits++; +} +void DoAcquisition(int decimation, int quantization, int trigger_threshold, bool averaging) +{ + //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); + // You can't decimate 8 bits more than 7 times + if(quantization > 7) quantization = 7; + // Use a bit stream to handle the output + BitstreamOut data = { dest , 0, 0}; + int sample_counter = 0; + uint8_t sample = 0; + //If we want to do averaging + uint32_t sample_sum =0 ; + uint32_t sample_total_numbers =0 ; + uint32_t sample_total_saved =0 ; + + for(;;) { + WDT_HIT(); + 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) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + sample_total_numbers++; + if (trigger_threshold != -1 && sample < trigger_threshold) + continue; + + LED_D_OFF(); + trigger_threshold = -1; + sample_counter++; + sample_sum += sample; + //Check decimation + if(sample_counter < decimation) continue; + //Averaging + if(averaging) sample = sample_sum / decimation; + + sample_counter = 0; + sample_sum =0; + sample_total_saved ++; + pushBit(&data, sample & 0x80); + if(quantization < 7) pushBit(&data, sample & 0x40); + if(quantization < 6) pushBit(&data, sample & 0x20); + if(quantization < 5) pushBit(&data, sample & 0x10); + if(quantization < 4) pushBit(&data, sample & 0x08); + if(quantization < 3) pushBit(&data, sample & 0x04); + if(quantization < 2) pushBit(&data, sample & 0x02); + if(quantization < 1) pushBit(&data, sample & 0x01); + + if(data.numbits +1 >= bufsize) break; + } + } + Dbprintf("Done, saved %l out of %l seen samples.",sample_total_saved, sample_total_numbers); + +} + /** * Does the sample acquisition. If threshold is specified, the actual sampling From 7242efa07c18a92c4139c26ad7009f2d8866fc89 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 22 Jan 2015 23:04:59 +0100 Subject: [PATCH 2/7] bugfix --- armsrc/lfops.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 1d7d2036e..c1bf6d2b0 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -8,7 +8,6 @@ // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- -#include #include "proxmark3.h" #include "apps.h" #include "util.h" @@ -62,9 +61,9 @@ void DoAcquisition(int decimation, int quantization, int trigger_threshold, bool } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - sample_total_numbers++; if (trigger_threshold != -1 && sample < trigger_threshold) continue; + sample_total_numbers++; LED_D_OFF(); trigger_threshold = -1; @@ -87,7 +86,7 @@ void DoAcquisition(int decimation, int quantization, int trigger_threshold, bool if(quantization < 2) pushBit(&data, sample & 0x02); if(quantization < 1) pushBit(&data, sample & 0x01); - if(data.numbits +1 >= bufsize) break; + if((data.numbits / 8) +1 >= bufsize) break; } } Dbprintf("Done, saved %l out of %l seen samples.",sample_total_saved, sample_total_numbers); From 7c676e7269ce6ca6be9fbadb237873dd31b4d27d Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 26 Jan 2015 21:15:28 +0100 Subject: [PATCH 3/7] Some documentation --- armsrc/lfops.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c1bf6d2b0..3cd2bc36d 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -34,7 +34,19 @@ void pushBit( BitstreamOut* stream, bool bit) stream->position++; stream->numbits++; } -void DoAcquisition(int decimation, int quantization, int trigger_threshold, bool averaging) +/** + * @brief Does LF sample acquisition, 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. + * @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. + * @return the number of bits occupied by the samples. + */ +uint8_t DoAcquisition(int decimation, int bits_per_sample, int trigger_threshold, bool averaging) { //A decimation of 2 means we keep every 2nd sample //A decimation of 3 means we keep 1 in 3 samples. @@ -42,8 +54,9 @@ void DoAcquisition(int decimation, int quantization, int trigger_threshold, bool uint8_t *dest = (uint8_t *)BigBuf; int bufsize = BIGBUF_SIZE; memset(dest, 0, bufsize); - // You can't decimate 8 bits more than 7 times - if(quantization > 7) quantization = 7; + if(bits_per_sample < 1) bits_per_sample = 1; + if(bits_per_sample > 8) bits_per_sample = 8; + // Use a bit stream to handle the output BitstreamOut data = { dest , 0, 0}; int sample_counter = 0; @@ -78,19 +91,20 @@ void DoAcquisition(int decimation, int quantization, int trigger_threshold, bool sample_sum =0; sample_total_saved ++; pushBit(&data, sample & 0x80); - if(quantization < 7) pushBit(&data, sample & 0x40); - if(quantization < 6) pushBit(&data, sample & 0x20); - if(quantization < 5) pushBit(&data, sample & 0x10); - if(quantization < 4) pushBit(&data, sample & 0x08); - if(quantization < 3) pushBit(&data, sample & 0x04); - if(quantization < 2) pushBit(&data, sample & 0x02); - if(quantization < 1) pushBit(&data, sample & 0x01); + 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 / 8) +1 >= bufsize) break; + if((data.numbits >> 3) +1 >= bufsize) break; } } Dbprintf("Done, saved %l out of %l seen samples.",sample_total_saved, sample_total_numbers); + return data.numbits; } From f6d9fb173fec6d117faeb6c39cf37ee449d4ef16 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 29 Jan 2015 00:57:22 +0100 Subject: [PATCH 4/7] Added client-side support for recording longer samples, fixed last (?) issues on device-side --- armsrc/appmain.c | 4 +- armsrc/apps.h | 7 +- armsrc/lfops.c | 164 +++++++++++++++++++++++++---------------------- client/cmddata.c | 61 +++++++++++++++--- client/cmdlf.c | 97 +++++++++++++++++++++++----- client/graph.h | 3 +- client/util.c | 28 ++++++++ client/util.h | 2 + 8 files changed, 260 insertions(+), 106 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 530dc39cd..83d9dd1fb 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 5a1ab6902..110e03b3a 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 3cd2bc36d..c10314473 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; + + trigger_threshold = -1; sample_total_numbers++; - LED_D_OFF(); - trigger_threshold = -1; - sample_counter++; - sample_sum += sample; + 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 a88fa4e10..793845807 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 e3361cb50..93a9f5866 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|] [b ] [d ] [a 0|1]"); + PrintAndLog("Options: "); + PrintAndLog(" h This help"); + PrintAndLog(" H High frequency (134 KHz). Defaults to 125 KHz"); + PrintAndLog(" Manually set divisor. 88-> 134KHz, 95-> 125 Hz"); + PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); + PrintAndLog(" d 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; - // '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 '"); - return 0; - } - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - return 0; + uint8_t cmdp =0; + if(param_getchar(Cmd, cmdp) == 'h') + { + return CmdLFReadUsage(); + } + + // 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 1abeeb25a..2c448161c 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 b8d5c316c..bce1c122e 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 22d41e0c8..5001acdcb 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); From 31abe49fd323411b391dd10335eb4c60cfcecb06 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 30 Jan 2015 23:03:44 +0100 Subject: [PATCH 5/7] Some more fixes to longer lf recordings. Now also supports longer snoops, and an additional command 'lf config' has been defined, instead of having to specify all params for every call --- armsrc/Makefile | 2 +- armsrc/appmain.c | 14 +-- armsrc/apps.h | 4 +- armsrc/lfops.c | 241 +++++------------------------------------- armsrc/lfsampling.c | 251 ++++++++++++++++++++++++++++++++++++++++++++ armsrc/lfsampling.h | 59 +++++++++++ client/cmddata.c | 25 +++-- client/cmdlf.c | 225 +++++++++++++++++++++++---------------- client/util.c | 9 +- include/usb_cmd.h | 11 ++ 10 files changed, 518 insertions(+), 323 deletions(-) create mode 100644 armsrc/lfsampling.c create mode 100644 armsrc/lfsampling.h diff --git a/armsrc/Makefile b/armsrc/Makefile index b9019541e..4e460623f 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -14,7 +14,7 @@ APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ #-DWITH_LCD #SRC_LCD = fonts.c LCD.c -SRC_LF = lfops.c hitag2.c +SRC_LF = lfops.c hitag2.c lfsampling.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c SRC_ISO14443b = iso14443.c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 83d9dd1fb..32b7e5924 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -23,7 +23,7 @@ #include "legicrf.h" #include - +#include "lfsampling.h" #ifdef WITH_LCD #include "LCD.h" #endif @@ -629,16 +629,17 @@ void UsbPacketReceived(uint8_t *packet, int len) switch(c->cmd) { #ifdef WITH_LF + case CMD_SET_LF_SAMPLING_CONFIG: + setSamplingConfig((sample_config *) c->d.asBytes); + break; case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: - AcquireRawAdcSamples125k(c->arg[0], c->arg[1], c->arg[2]); - cmd_send(CMD_ACK,0,0,0,0,0); + cmd_send(CMD_ACK,SampleLF(),0,0,0,0); break; case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K: ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); break; case CMD_LF_SNOOP_RAW_ADC_SAMPLES: - SnoopLFRawAdcSamples(c->arg[0], c->arg[1]); - cmd_send(CMD_ACK,0,0,0,0,0); + cmd_send(CMD_ACK,SnoopLF(),0,0,0,0); break; case CMD_HID_DEMOD_FSK: CmdHIDdemodFSK(c->arg[0], 0, 0, 1); @@ -910,7 +911,8 @@ 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,bits_per_sample,decimation,0,0,0); + // We put a 1 in arg[0] to alert the host we're also sending sample_config + cmd_send(CMD_ACK,1,0,0,getSamplingConfig(),sizeof(sample_config)); LED_B_OFF(); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 110e03b3a..89440bfec 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -81,8 +81,6 @@ int AvgAdc(int ch); void ToSendStuffBit(int b); void ToSendReset(void); void ListenReaderField(int limit); -void SnoopLFRawAdcSamples(int divisor, int trigger_threshold); -void DoAcquisition125k(int trigger_threshold); extern int ToSendMax; extern uint8_t ToSend[]; extern uint32_t BigBuf[]; @@ -147,7 +145,7 @@ extern uint8_t decimation; extern uint8_t bits_per_sample ; extern bool averaging; -void AcquireRawAdcSamples125k(int divisor,int arg1, int arg2); +void AcquireRawAdcSamples125k(int divisor); 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 c10314473..43af4eed4 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -15,231 +15,44 @@ #include "crc16.h" #include "string.h" #include "lfdemod.h" - -uint8_t decimation = 1; -uint8_t bits_per_sample = 8; -bool averaging = 1; +#include "lfsampling.h" -typedef struct { - uint8_t * buffer; - uint32_t numbits; - uint32_t position; -} BitstreamOut; /** - * @brief Pushes bit onto the stream - * @param stream - * @param bit + * Function to do a modulation and then get samples. + * @param delay_off + * @param period_0 + * @param period_1 + * @param command */ -void pushBit( BitstreamOut* stream, uint8_t bit) -{ - int bytepos = stream->position >> 3; // divide by 8 - int bitpos = stream->position & 7; - *(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos); - stream->position++; - stream->numbits++; -} - -/** - * 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. - * 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 silent - is true, now outputs are made. If false, dbprints the status - * @return the number of bits occupied by the samples. - */ -uint32_t DoAcquisition125k_internal(int trigger_threshold,bool silent) -{ - //. - 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; - uint8_t sample = 0; - //If we want to do averaging - uint32_t sample_sum =0 ; - uint32_t sample_total_numbers =0 ; - uint32_t sample_total_saved =0 ; - - while(!BUTTON_PRESS()) { - WDT_HIT(); - 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) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); - if (trigger_threshold != -1 && sample < trigger_threshold) - continue; - - trigger_threshold = -1; - sample_total_numbers++; - - if(averaging) - { - sample_sum += sample; - } - //Check decimation - if(decimation > 1) - { - sample_counter++; - if(sample_counter < decimation) continue; - sample_counter = 0; - } - //Averaging - if(averaging && decimation > 1) { - sample = sample_sum / decimation; - sample_sum =0; - } - //Store the sample - sample_total_saved ++; - 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; - } - } - } - - 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; -} -/** -* Perform sample aquisition. -*/ -void DoAcquisition125k(int trigger_threshold) -{ - DoAcquisition125k_internal(trigger_threshold, false); -} - -/** -* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream -* if not already loaded, sets divisor and starts up the antenna. -* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz -* 0 or 95 ==> 125 KHz -* -**/ -void LFSetupFPGAForADC(int divisor, bool lf_field) -{ - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else if (divisor == 0) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); -} -/** -* Initializes the FPGA, and acquires the samples. -**/ -void AcquireRawAdcSamples125k(int divisor,int arg1, int arg2) -{ - 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. -**/ - -void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) -{ - LFSetupFPGAForADC(divisor, false); - DoAcquisition125k(trigger_threshold); -} - void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) { - /* Make sure the tag is reset */ - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(2500); - - int divisor_used = 95; // 125 KHz // see if 'h' was specified if (command[strlen((char *) command) - 1] == 'h') divisor_used = 88; // 134.8 KHz + sample_config sc = { 0,0,1, divisor_used, 0}; + setSamplingConfig(&sc); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); + /* Make sure the tag is reset */ + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(2500); - // And a little more time for the tag to fully power up - SpinDelay(2000); + LFSetupFPGAForADC(sc.divisor, 1); - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + // And a little more time for the tag to fully power up + SpinDelay(2000); // now modulate the reader field while(*command != '\0' && *command != ' ') { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); LED_D_ON(); @@ -251,14 +64,16 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // now do the read - DoAcquisition125k(-1); + DoAcquisition_config(false); } + + /* blank r/w tag data stream ...0000000000000000 01111111 1010101010101010101010101010101010101010101010101010101010101010 @@ -745,8 +560,8 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition125k_internal(-1,true); - // FSK demodulator + DoAcquisition_default(-1,true); + // FSK demodulator size = HIDdemodFSK(dest, sizeof(BigBuf), &hi2, &hi, &lo); WDT_HIT(); @@ -833,8 +648,8 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition125k_internal(-1,true); - size = sizeof(BigBuf); + DoAcquisition_default(-1,true); + size = sizeof(BigBuf); //Dbprintf("DEBUG: Buffer got"); //askdemod and manchester decode errCnt = askmandemod(dest, &size, &clk, &invert); @@ -884,8 +699,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) while(!BUTTON_PRESS()) { WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition125k_internal(-1,true); - //fskdemod and get start index + DoAcquisition_default(-1,true); + //fskdemod and get start index WDT_HIT(); idx = IOdemodFSK(dest,sizeof(BigBuf)); if (idx>0){ @@ -1489,7 +1304,9 @@ int DemodPCF7931(uint8_t **outBlocks) { int lmin=128, lmax=128; uint8_t dir; - AcquireRawAdcSamples125k(0,0,0); + LFSetupFPGAForADC(95, true); + DoAcquisition_default(0, 0); + lmin = 64; lmax = 192; diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c new file mode 100644 index 000000000..6314ac746 --- /dev/null +++ b/armsrc/lfsampling.c @@ -0,0 +1,251 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Miscellaneous routines for low frequency sampling. +//----------------------------------------------------------------------------- + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "lfsampling.h" + +sample_config config = { 1, 8, 1, 88, 0 } ; + +void printConfig() +{ + Dbprintf("Sampling config: "); + Dbprintf(" [q] divisor: %d ", config.divisor); + Dbprintf(" [b] bps: %d ", config.bits_per_sample); + Dbprintf(" [d] decimation: %d ", config.decimation); + Dbprintf(" [a] averaging: %d ", config.averaging); + Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold); +} + + +/** + * Called from the USB-handler to set the sampling configuration + * The sampling config is used for std reading and snooping. + * + * Other functions may read samples and ignore the sampling config, + * such as functions to read the UID from a prox tag or similar. + * + * Values set to '0' implies no change (except for averaging) + * @brief setSamplingConfig + * @param sc + */ +void setSamplingConfig(sample_config *sc) +{ + if(sc->divisor != 0) config.divisor = sc->divisor; + if(sc->bits_per_sample!= 0) config.bits_per_sample= sc->bits_per_sample; + if(sc->decimation!= 0) config.decimation= sc->decimation; + if(sc->trigger_threshold != -1) config.trigger_threshold= sc->trigger_threshold; + + config.averaging= sc->averaging; + if(config.bits_per_sample > 8) config.bits_per_sample = 8; + if(config.decimation < 1) config.decimation = 1; + + printConfig(); +} + +sample_config* getSamplingConfig() +{ + return &config; +} + +typedef struct { + uint8_t * buffer; + uint32_t numbits; + uint32_t position; +} BitstreamOut; + + +/** + * @brief Pushes bit onto the stream + * @param stream + * @param 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 > 0) << (7 - bitpos); + stream->position++; + stream->numbits++; +} + +/** +* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream +* if not already loaded, sets divisor and starts up the antenna. +* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz +* 0 or 95 ==> 125 KHz +* +**/ +void LFSetupFPGAForADC(int divisor, bool lf_field) +{ + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else if (divisor == 0) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); +} + + +/** + * 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. + * Uses the following global settings: + * @param decimation - how much should the signal be decimated. A decimation of N means we keep 1 in N samples, etc. + * @param bits_per_sample - bits per sample. Max 8, min 1 bit per sample. + * @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 trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set + * to -1 to ignore threshold. + * @param silent - is true, now outputs are made. If false, dbprints the status + * @return the number of bits occupied by the samples. + */ + +uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold,bool silent) +{ + //. + 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; + uint8_t sample = 0; + //If we want to do averaging + uint32_t sample_sum =0 ; + uint32_t sample_total_numbers =0 ; + uint32_t sample_total_saved =0 ; + + while(!BUTTON_PRESS()) { + WDT_HIT(); + 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) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + LED_D_OFF(); + if (trigger_threshold > 0 && sample < trigger_threshold) + continue; + + trigger_threshold = 0; + sample_total_numbers++; + + if(averaging) + { + sample_sum += sample; + } + //Check decimation + if(decimation > 1) + { + sample_counter++; + if(sample_counter < decimation) continue; + sample_counter = 0; + } + //Averaging + if(averaging && decimation > 1) { + sample = sample_sum / decimation; + sample_sum =0; + } + //Store the sample + sample_total_saved ++; + 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; + } + } + } + + 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; +} +/** + * @brief Does sample acquisition, ignoring the config values set in the sample_config. + * This method is typically used by tag-specific readers who just wants to read the samples + * the normal way + * @param trigger_threshold + * @param silent + * @return number of bits sampled + */ +uint32_t DoAcquisition_default(int trigger_threshold, bool silent) +{ + return DoAcquisition(1,8,0,trigger_threshold,silent); +} +uint32_t DoAcquisition_config( bool silent) +{ + return DoAcquisition(config.decimation + ,config.bits_per_sample + ,config.averaging + ,config.trigger_threshold + ,silent); +} + +uint32_t ReadLF(bool activeField) +{ + printConfig(); + LFSetupFPGAForADC(config.divisor, activeField); + // Now call the acquisition routine + return DoAcquisition_config(false); +} + +/** +* Initializes the FPGA for reader-mode (field on), and acquires the samples. +* @return number of bits sampled +**/ +uint32_t SampleLF() +{ + return ReadLF(true); +} +/** +* Initializes the FPGA for snoop-mode (field off), and acquires the samples. +* @return number of bits sampled +**/ + +uint32_t SnoopLF() +{ + return ReadLF(false); +} diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h new file mode 100644 index 000000000..9ab458f81 --- /dev/null +++ b/armsrc/lfsampling.h @@ -0,0 +1,59 @@ +#ifndef LFSAMPLING_H +#define LFSAMPLING_H + +/** +* Initializes the FPGA for reader-mode (field on), and acquires the samples. +* @return number of bits sampled +**/ +uint32_t SampleLF(); + +/** +* Initializes the FPGA for snoop-mode (field off), and acquires the samples. +* @return number of bits sampled +**/ + +uint32_t SnoopLF(); + +/** + * @brief Does sample acquisition, ignoring the config values set in the sample_config. + * This method is typically used by tag-specific readers who just wants to read the samples + * the normal way + * @param trigger_threshold + * @param silent + * @return number of bits sampled + */ +uint32_t DoAcquisition_default(int trigger_threshold, bool silent); +/** + * @brief Does sample acquisition, using the config values set in the sample_config. + * @param trigger_threshold + * @param silent + * @return number of bits sampled + */ + +uint32_t DoAcquisition_config( bool silent); + +/** +* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream +* if not already loaded, sets divisor and starts up the antenna. +* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz +* 0 or 95 ==> 125 KHz +* +**/ +void LFSetupFPGAForADC(int divisor, bool lf_field); + + +/** + * Called from the USB-handler to set the sampling configuration + * The sampling config is used for std reading and snooping. + * + * Other functions may read samples and ignore the sampling config, + * such as functions to read the UID from a prox tag or similar. + * + * Values set to '0' implies no change (except for averaging) + * @brief setSamplingConfig + * @param sc + */ +void setSamplingConfig(sample_config *sc); + +sample_config * getSamplingConfig(); +#endif // LFSAMPLING_H diff --git a/client/cmddata.c b/client/cmddata.c index 793845807..fa056b679 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -21,6 +21,8 @@ #include "cmdmain.h" #include "cmddata.h" #include "lfdemod.h" +#include "usb_cmd.h" + uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; int DemodBufferLen; static int CmdHelp(const char *Cmd); @@ -1077,11 +1079,15 @@ uint8_t getByte(uint8_t bits_per_sample, BitstreamOut* b) int CmdSamples(const char *Cmd) { - uint8_t got[40000]; + //If we get all but the last byte in bigbuf, + // we don't have to worry about remaining trash + // in the last byte in case the bits-per-sample + // does not line up on byte boundaries + uint8_t got[40000-1]; int n = strtol(Cmd, NULL, 0); if (n == 0) - n = 20000; + n = sizeof(got); if (n > sizeof(got)) n = sizeof(got); @@ -1091,14 +1097,22 @@ int CmdSamples(const char *Cmd) 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); + uint8_t bits_per_sample = 8; + + //Old devices without this feature would send 0 at arg[0] + if(response.arg[0] > 0) + { + sample_config *sc = (sample_config *) response.d.asBytes; + PrintAndLog("Samples @ %d bits/smpl, decimation 1:%d ", sc->bits_per_sample + , sc->decimation); + bits_per_sample = sc->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++) { + for (j = 0; j * bits_per_sample < n * 8 && j < sizeof(GraphBuffer); j++) { uint8_t sample = getByte(bits_per_sample, &bout); GraphBuffer[j] = ((int) sample )- 128; } @@ -1110,7 +1124,6 @@ int CmdSamples(const char *Cmd) GraphBuffer[j] = ((int)got[j]) - 128; } GraphTraceLen = n; - } RepaintGraphWindow(); diff --git a/client/cmdlf.c b/client/cmdlf.c index 93a9f5866..09d930024 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -356,88 +356,152 @@ int CmdIndalaClone(const char *Cmd) return 0; } -int CmdLFReadUsage() +int usage_lf_read() { - PrintAndLog("Usage: lf read [H|] [b ] [d ] [a 0|1]"); + PrintAndLog("Usage: lf read"); PrintAndLog("Options: "); PrintAndLog(" h This help"); - PrintAndLog(" H High frequency (134 KHz). Defaults to 125 KHz"); - PrintAndLog(" Manually set divisor. 88-> 134KHz, 95-> 125 Hz"); - PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); - PrintAndLog(" d 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."); + PrintAndLog("This function takes no arguments. "); + PrintAndLog("Use 'lf config' to set parameters."); return 0; } +int usage_lf_snoop() +{ + PrintAndLog("Usage: lf snoop"); + PrintAndLog("Options: "); + PrintAndLog(" h This help"); + PrintAndLog("This function takes no arguments. "); + PrintAndLog("Use 'lf config' to set parameters."); + return 0; +} + +int usage_lf_config() +{ + PrintAndLog("Usage: lf config [H|] [b ] [d ] [a 0|1]"); + PrintAndLog("Options: "); + PrintAndLog(" h This help"); + PrintAndLog(" L Low frequency (125 KHz)"); + PrintAndLog(" H High frequency (134 KHz)"); + PrintAndLog(" q Manually set divisor. 88-> 134KHz, 95-> 125 Hz"); + PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); + PrintAndLog(" d 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(" t Sets trigger threshold. 0 means no threshold"); + PrintAndLog("Examples:"); + PrintAndLog(" lf config b 8 L"); + PrintAndLog(" Samples at 125KHz, 8bps."); + PrintAndLog(" lf config H b 4 d 3"); + PrintAndLog(" Samples at 134KHz, averages three samples into one, stored with "); + PrintAndLog(" a resolution of 4 bits per sample."); + PrintAndLog(" lf read"); + PrintAndLog(" Performs a read (active field)"); + PrintAndLog(" lf snoop"); + PrintAndLog(" Performs a snoop (no active field)"); + return 0; +} + +int CmdLFSetConfig(const char *Cmd) +{ + + uint8_t divisor = 0;//Frequency divisor + uint8_t bps = 0; // Bits per sample + uint8_t decimation = 0; //How many to keep + bool averaging = 1; // Defaults to true + bool errors = FALSE; + int trigger_threshold =-1;//Means no change + uint8_t unsigned_trigg = 0; + + uint8_t cmdp =0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + PrintAndLog("working %c", param_getchar(Cmd, cmdp)); + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + return usage_lf_config(); + case 'H': + divisor = 88; + cmdp++; + break; + case 'L': + divisor = 95; + cmdp++; + break; + case 'q': + errors |= param_getdec(Cmd,cmdp+1,&divisor); + cmdp+=2; + break; + case 't': + errors |= param_getdec(Cmd,cmdp+1,&unsigned_trigg); + cmdp+=2; + if(!errors) trigger_threshold = unsigned_trigg; + break; + case 'b': + errors |= param_getdec(Cmd,cmdp+1,&bps); + cmdp+=2; + break; + case 'd': + errors |= param_getdec(Cmd,cmdp+1,&decimation); + cmdp+=2; + break; + case 'a': + averaging = param_getchar(Cmd,cmdp+1) == '1'; + cmdp+=2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = 1; + break; + } + if(errors) break; + } + if(cmdp == 0) + { + errors = 1;// No args + } + + //Validations + if(errors) + { + return usage_lf_config(); + } + //Bps is limited to 8, so fits in lower half of arg1 + if(bps >> 8) bps = 8; + + sample_config config = { + decimation,bps,averaging,divisor,trigger_threshold + }; + //Averaging is a flag on high-bit of arg[1] + UsbCommand c = {CMD_SET_LF_SAMPLING_CONFIG}; + memcpy(c.d.asBytes,&config,sizeof(sample_config)); + SendCommand(&c); + return 0; +} + int CmdLFRead(const char *Cmd) { - 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(); + return usage_lf_read(); } - - // 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; +} +int CmdLFSnoop(const char *Cmd) +{ + uint8_t cmdp =0; + if(param_getchar(Cmd, cmdp) == 'h') + { + return usage_lf_snoop(); + } + + UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES}; SendCommand(&c); WaitForResponse(CMD_ACK,NULL); return 0; @@ -517,30 +581,6 @@ int CmdLFSimManchester(const char *Cmd) return 0; } -int CmdLFSnoop(const char *Cmd) -{ - UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES}; - - // 'h' means higher-low-frequency, 134 kHz - c.arg[0] = 0; - c.arg[1] = -1; - - if (*Cmd == 'l') { - sscanf(Cmd, "l %"lli, &c.arg[1]); - } else if(*Cmd == 'h') { - c.arg[0] = 1; - sscanf(Cmd, "h %"lli, &c.arg[1]); - } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { - PrintAndLog("usage 1: snoop"); - PrintAndLog(" 2: snoop {l,h} [trigger threshold]"); - PrintAndLog(" 3: snoop [trigger threshold]"); - return 0; - } - - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - return 0; -} int CmdVchDemod(const char *Cmd) { @@ -673,12 +713,13 @@ static command_t CommandTable[] = {"help", CmdHelp, 1, "This help"}, {"cmdread", CmdLFCommandRead, 0, " <'0' period> <'1' period> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"}, {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"}, + {"config", CmdLFSetConfig, 0, "Set config for LF sampling, bit/sample, decimation, frequency"}, {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"}, {"hid", CmdLFHID, 1, "{ HID RFIDs... }"}, {"io", CmdLFIO, 1, "{ ioProx tags... }"}, {"indalademod", CmdIndalaDemod, 1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"}, {"indalaclone", CmdIndalaClone, 0, " ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"}, - {"read", CmdLFRead, 0, "['h' or ] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134, alternatively: f=12MHz/(divisor+1))"}, + {"read", CmdLFRead, 0, "Read 125/134 kHz LF ID-only tag. Do 'lf read h' for help"}, {"search", CmdLFfind, 1, "Read and Search for valid known tag (in offline mode it you can load first then search)"}, {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, diff --git a/client/util.c b/client/util.c index bce1c122e..6b47eab9e 100644 --- a/client/util.c +++ b/client/util.c @@ -213,6 +213,7 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) return 0; } + char param_getchar(const char *line, int paramnum) { int bg, en; @@ -228,14 +229,16 @@ uint8_t param_get8(const char *line, int paramnum) } /** - * @brief Reads a decimal integer + * @brief Reads a decimal integer (actually, 0-254, not 255) * @param line * @param paramnum - * @return + * @return -1 if error */ uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination) { - uint8_t val = param_get8ex(line, paramnum, 10, 10); + uint8_t val = param_get8ex(line, paramnum, 255, 10); + printf("read %i", (int8_t ) val); + if( (int8_t) val == -1) return 1; (*destination) = val; return 0; } diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 69c3c1b6a..6ee6509eb 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -33,6 +33,14 @@ typedef struct { uint32_t asDwords[USB_CMD_DATA_SIZE/4]; } d; } PACKED UsbCommand; +// A struct used to send sample-configs over USB +typedef struct{ + uint8_t decimation; + uint8_t bits_per_sample; + bool averaging; + int divisor; + int trigger_threshold; +} sample_config; // For the bootloader #define CMD_DEVICE_INFO 0x0000 @@ -82,6 +90,8 @@ typedef struct { #define CMD_IO_DEMOD_FSK 0x021A #define CMD_IO_CLONE_TAG 0x021B #define CMD_EM410X_DEMOD 0x021c +// Sampling configuration for LF reader/snooper +#define CMD_SET_LF_SAMPLING_CONFIG 0x021d /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ @@ -187,6 +197,7 @@ typedef struct { #define FLAG_ICLASS_READER_ONLY_ONCE 0x01 #define FLAG_ICLASS_READER_GET_CC 0x02 + // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ #define DEVICE_INFO_FLAG_BOOTROM_PRESENT (1<<0) From 698b649e0ec1a4fd6c18f518cce1f5c8b79d67b1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 31 Jan 2015 00:05:04 +0100 Subject: [PATCH 6/7] Added undec to un-decimate data on the client side, so we can use all those sweet demodders even if the data has been decimated on the ARM side --- client/cmddata.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/client/cmddata.c b/client/cmddata.c index fa056b679..964b8031b 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -540,6 +540,35 @@ int CmdDec(const char *Cmd) RepaintGraphWindow(); return 0; } +/** + * Undecimate - I'd call it 'interpolate', but we'll save that + * name until someone does an actual interpolation command, not just + * blindly repeating samples + * @param Cmd + * @return + */ +int CmdUndec(const char *Cmd) +{ + //We have memory, don't we? + int swap[MAX_GRAPH_TRACE_LEN] = { 0 }; + uint32_t i = 0 ,j = 0; + while(j+1 < MAX_GRAPH_TRACE_LEN && i < GraphTraceLen) + { + swap[j] = GraphBuffer[i]; + swap[j+1] = GraphBuffer[i]; + i++; + j+=2; + } + memcpy(GraphBuffer,swap, j); + GraphTraceLen = j; + PrintAndLog("Undecimated by 2"); + RepaintGraphWindow(); + + /* + * Something is not right here, need to look into it, + * the undec seems to only operate on half the values **/ + return 0; +} /* Print our clock rate */ // uses data from graphbuffer @@ -1651,7 +1680,8 @@ static command_t CommandTable[] = {"threshold", CmdThreshold, 1, " -- Maximize/minimize every value in the graph window depending on threshold"}, {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, {"tune", CmdTuneSamples, 0, "Get hw tune samples for graph window"}, - {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"}, + {"undec", CmdUndec, 1, "Un-decimate samples by 2"}, + {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"}, {NULL, NULL, 0, NULL} }; From c856ceae8acabef3a35a0c70fb4a671d6c5ca292 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 31 Jan 2015 12:42:40 +0100 Subject: [PATCH 7/7] Fixed undecimation command --- client/cmddata.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 964b8031b..8f73b4007 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -549,24 +549,32 @@ int CmdDec(const char *Cmd) */ int CmdUndec(const char *Cmd) { + if(param_getchar(Cmd, 0) == 'h') + { + PrintAndLog("Usage: data undec [factor]"); + PrintAndLog("This function performs un-decimation, by repeating each sample N times"); + PrintAndLog("Options: "); + PrintAndLog(" h This help"); + PrintAndLog(" factor The number of times to repeat each sample.[default:2]"); + PrintAndLog("Example: 'data undec 3'"); + return 0; + } + + uint8_t factor = param_get8ex(Cmd, 0,2, 10); //We have memory, don't we? int swap[MAX_GRAPH_TRACE_LEN] = { 0 }; - uint32_t i = 0 ,j = 0; - while(j+1 < MAX_GRAPH_TRACE_LEN && i < GraphTraceLen) + uint32_t g_index = 0 ,s_index = 0; + while(g_index < GraphTraceLen && s_index < MAX_GRAPH_TRACE_LEN) { - swap[j] = GraphBuffer[i]; - swap[j+1] = GraphBuffer[i]; - i++; - j+=2; + int count = 0; + for(count = 0; count < factor && s_index+count < MAX_GRAPH_TRACE_LEN; count ++) + swap[s_index+count] = GraphBuffer[g_index]; + s_index+=count; } - memcpy(GraphBuffer,swap, j); - GraphTraceLen = j; - PrintAndLog("Undecimated by 2"); - RepaintGraphWindow(); - /* - * Something is not right here, need to look into it, - * the undec seems to only operate on half the values **/ + memcpy(GraphBuffer,swap, s_index * sizeof(int)); + GraphTraceLen = s_index; + RepaintGraphWindow(); return 0; }