From f6d9fb173fec6d117faeb6c39cf37ee449d4ef16 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 29 Jan 2015 00:57:22 +0100 Subject: [PATCH] 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 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|] [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; + + 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 '"); - 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); -- 2.39.2