From c3366bda71c0b5ee0f9b632838f76a67f9df8c63 Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Mon, 8 Oct 2012 04:32:16 +0200 Subject: [PATCH] use rtl-sdr instead of USRP Signed-off-by: Steve Markgraf --- AUTHORS | 2 +- README | 3 + configure.ac | 6 +- src/Makefile.am | 4 +- src/kal.cc | 51 ++++++++++------ src/offset.cc | 4 ++ src/usrp_source.cc | 141 +++++++++++++++++++++------------------------ src/usrp_source.h | 11 ++-- 8 files changed, 120 insertions(+), 102 deletions(-) diff --git a/AUTHORS b/AUTHORS index e999767..40cb5f3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,3 @@ Joshua Lackey Alexander Chemeris - +Steve Markgraf diff --git a/README b/README index c4e433e..b3b361d 100644 --- a/README +++ b/README @@ -5,3 +5,6 @@ offset. See http://thre.at/kalibrate Copyright (c) 2010, Joshua Lackey (jl@thre.at) + +modified for use with rtl-sdr devices, +Copyright (c) 2012, Steve Markgraf (steve@steve-m.de) diff --git a/configure.ac b/configure.ac index 652cfb2..214d07d 100644 --- a/configure.ac +++ b/configure.ac @@ -26,9 +26,9 @@ PKG_CHECK_MODULES(FFTW3, fftw3 >= 3.0) AC_SUBST(FFTW3_LIBS) AC_SUBST(FFTW3_CFLAGS) -PKG_CHECK_MODULES(USRP, usrp >= 3.3) -AC_SUBST(USRP_LIBS) -AC_SUBST(USRP_CFLAGS) +PKG_CHECK_MODULES(LIBRTLSDR, librtlsdr) +AC_SUBST(LIBRTLSDR_LIBS) +AC_SUBST(LIBRTLSDR_CFLAGS) # OSX doesn't support System V shared memory AC_CANONICAL_HOST diff --git a/src/Makefile.am b/src/Makefile.am index a6e5123..a1dc7ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,5 +19,5 @@ kal_SOURCES = \ util.h\ version.h -kal_CXXFLAGS = $(FFTW3_CFLAGS) $(USRP_CFLAGS) -kal_LDADD = $(FFTW3_LIBS) $(USRP_LIBS) +kal_CXXFLAGS = $(FFTW3_CFLAGS) $(LIBRTLSDR_CFLAGS) +kal_LDADD = $(FFTW3_LIBS) $(LIBRTLSDR_LIBS) diff --git a/src/kal.cc b/src/kal.cc index 29259f6..6e745d2 100644 --- a/src/kal.cc +++ b/src/kal.cc @@ -67,7 +67,8 @@ int g_debug = 0; void usage(char *prog) { - printf("kalibrate v%s, Copyright (c) 2010, Joshua Lackey\n", kal_version_string); + printf("kalibrate v%s-rtl, Copyright (c) 2010, Joshua Lackey\n", kal_version_string); + printf("modified for use with rtl-sdr devices, Copyright (c) 2012, Steve Markgraf"); printf("\nUsage:\n"); printf("\tGSM Base Station Scan:\n"); printf("\t\t%s <-s band indicator> [options]\n", basename(prog)); @@ -80,10 +81,9 @@ void usage(char *prog) { printf("\t-f\tfrequency of nearby GSM base station\n"); printf("\t-c\tchannel of nearby GSM base station\n"); printf("\t-b\tband indicator (GSM850, GSM900, EGSM, DCS, PCS)\n"); - printf("\t-R\tside A (0) or B (1), defaults to B\n"); - printf("\t-A\tantenna TX/RX (0) or RX2 (1), defaults to RX2\n"); - printf("\t-g\tgain as %% of range, defaults to 45%%\n"); - printf("\t-F\tFPGA master clock frequency, defaults to 52MHz\n"); + printf("\t-g\tgain in dB\n"); + printf("\t-d\trtl-sdr device index\n"); + printf("\t-e\tinitial frequency error in ppm\n"); printf("\t-v\tverbose\n"); printf("\t-D\tenable debug messages\n"); printf("\t-h\thelp\n"); @@ -95,13 +95,14 @@ int main(int argc, char **argv) { char *endptr; int c, antenna = 1, bi = BI_NOT_DEFINED, chan = -1, bts_scan = 0; - unsigned int subdev = 1, decimation = 192; + int ppm_error = 0; + unsigned int subdev = 0, decimation = 192; long int fpga_master_clock_freq = 52000000; - float gain = 0.45; + float gain = 0; double freq = -1.0, fd; usrp_source *u; - while((c = getopt(argc, argv, "f:c:s:b:R:A:g:F:vDh?")) != EOF) { + while((c = getopt(argc, argv, "f:c:s:b:R:A:g:e:d:vDh?")) != EOF) { switch(c) { case 'f': freq = strtod(optarg, 0); @@ -163,11 +164,7 @@ int main(int argc, char **argv) { break; case 'g': - gain = strtod(optarg, 0); - if((gain > 1.0) && (gain <= 100.0)) - gain /= 100.0; - if((gain < 0.0) || (1.0 < gain)) - usage(argv[0]); + gain = strtof(optarg, 0) * 10; break; case 'F': @@ -181,6 +178,14 @@ int main(int argc, char **argv) { } break; + case 'e': + ppm_error = strtol(optarg, 0, 0); + break; + + case 'd': + subdev = strtol(optarg, 0, 0); + break; + case 'v': g_verbosity++; break; @@ -221,6 +226,7 @@ int main(int argc, char **argv) { chan = freq_to_arfcn(freq, &bi); } +#if 0 // sanity check clock if(fpga_master_clock_freq < 48000000) { fprintf(stderr, "error: FPGA master clock too slow: %li\n", fpga_master_clock_freq); @@ -230,7 +236,7 @@ int main(int argc, char **argv) { // calculate decimation -- get as close to GSM rate as we can fd = (double)fpga_master_clock_freq / GSM_RATE; decimation = (unsigned int)fd; - +#endif if(g_debug) { #ifdef D_HOST_OSX printf("debug: Mac OS X version\n"); @@ -251,10 +257,19 @@ int main(int argc, char **argv) { fprintf(stderr, "error: usrp_source::open\n"); return -1; } - u->set_antenna(antenna); - if(!u->set_gain(gain)) { - fprintf(stderr, "error: usrp_source::set_gain\n"); - return -1; +// u->set_antenna(antenna); + if (gain != 0) { + if(!u->set_gain(gain)) { + fprintf(stderr, "error: usrp_source::set_gain\n"); + return -1; + } + } + + if (ppm_error != 0) { + if(u->set_freq_correction(ppm_error) < 0) { + fprintf(stderr, "error: usrp_source::set_freq_correction\n"); + return -1; + } } if(!bts_scan) { diff --git a/src/offset.cc b/src/offset.cc index d091974..24fe2f6 100644 --- a/src/offset.cc +++ b/src/offset.cc @@ -46,6 +46,7 @@ int offset_detect(usrp_source *u) { unsigned int s_len, b_len, consumed, count; float offset = 0.0, min = 0.0, max = 0.0, avg_offset = 0.0, stddev = 0.0, sps, offsets[AVG_COUNT]; + double total_ppm; complex *cbuf; fcch_detector *l; circular_buffer *cb; @@ -118,5 +119,8 @@ int offset_detect(usrp_source *u) { printf("overruns: %u\n", overruns); printf("not found: %u\n", notfound); + total_ppm = u->m_freq_corr - (avg_offset / u->m_center_freq) * 1000000; + + printf("average absolute error: %.3f ppm\n", total_ppm); return 0; } diff --git a/src/usrp_source.cc b/src/usrp_source.cc index 2311215..a6dbd0c 100644 --- a/src/usrp_source.cc +++ b/src/usrp_source.cc @@ -34,10 +34,6 @@ #include #include -#include -#include -#include - #include "usrp_source.h" extern int g_verbosity; @@ -49,8 +45,6 @@ usrp_source::usrp_source(float sample_rate, long int fpga_master_clock_freq) { m_desired_sample_rate = sample_rate; m_sample_rate = 0.0; m_decimation = 0; - m_u_rx.reset(); - m_db_rx.reset(); m_cb = new circular_buffer(CB_LEN, sizeof(complex), 0); pthread_mutex_init(&m_u_mutex, 0); @@ -61,8 +55,6 @@ usrp_source::usrp_source(unsigned int decimation, long int fpga_master_clock_fre m_fpga_master_clock_freq = fpga_master_clock_freq; m_sample_rate = 0.0; - m_u_rx.reset(); - m_db_rx.reset(); m_cb = new circular_buffer(CB_LEN, sizeof(complex), 0); pthread_mutex_init(&m_u_mutex, 0); @@ -79,6 +71,7 @@ usrp_source::~usrp_source() { stop(); delete m_cb; + rtlsdr_close(dev); pthread_mutex_destroy(&m_u_mutex); } @@ -86,10 +79,6 @@ usrp_source::~usrp_source() { void usrp_source::stop() { pthread_mutex_lock(&m_u_mutex); - if(m_db_rx) - m_db_rx->set_enable(0); - if(m_u_rx) - m_u_rx->stop(); pthread_mutex_unlock(&m_u_mutex); } @@ -97,10 +86,6 @@ void usrp_source::stop() { void usrp_source::start() { pthread_mutex_lock(&m_u_mutex); - if(m_db_rx) - m_db_rx->set_enable(1); - if(m_u_rx) - m_u_rx->start(); pthread_mutex_unlock(&m_u_mutex); } @@ -109,7 +94,7 @@ void usrp_source::calculate_decimation() { float decimation_f; - decimation_f = (float)m_u_rx->fpga_master_clock_freq() / m_desired_sample_rate; +// decimation_f = (float)m_u_rx->fpga_master_clock_freq() / m_desired_sample_rate; m_decimation = (unsigned int)round(decimation_f) & ~1; if(m_decimation < 4) @@ -128,31 +113,42 @@ float usrp_source::sample_rate() { int usrp_source::tune(double freq) { - int r; - usrp_tune_result tr; + int r = 0; pthread_mutex_lock(&m_u_mutex); - r = m_u_rx->tune(0, m_db_rx, freq, &tr); + if (freq != m_center_freq) { + r = rtlsdr_set_center_freq(dev, (uint32_t)freq); +// fprintf(stderr, "Tuned to %i Hz.\n", (uint32_t)freq); + m_center_freq = freq; + } + pthread_mutex_unlock(&m_u_mutex); - return r; + return (r < 0) ? 0 : 1; } +int usrp_source::set_freq_correction(int ppm) { + m_freq_corr = ppm; + return rtlsdr_set_freq_correction(dev, ppm); +} bool usrp_source::set_antenna(int antenna) { - return m_db_rx->select_rx_antenna(antenna); + return 0; } - bool usrp_source::set_gain(float gain) { + int r, g = gain * 10; - float min = m_db_rx->gain_min(), max = m_db_rx->gain_max(); + /* Enable manual gain */ + r = rtlsdr_set_tuner_gain_mode(dev, 1); + if (r < 0) + fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); - if((gain < 0.0) || (1.0 < gain)) - return false; + fprintf(stderr, "Setting gain: %.1f dB\n", gain/10); + r = rtlsdr_set_tuner_gain(dev, g); - return m_db_rx->set_gain(min + gain * (max - min)); + return (r < 0) ? 0 : 1; } @@ -160,75 +156,73 @@ bool usrp_source::set_gain(float gain) { * open() should be called before multiple threads access usrp_source. */ int usrp_source::open(unsigned int subdev) { + int i, r, device_count, count; + uint32_t dev_index = subdev; + uint32_t samp_rate = 270833; - int do_set_decim = 0; - usrp_subdev_spec ss(subdev, 0); + m_sample_rate = 270833.002142; - if(!m_u_rx) { - if(!m_decimation) { - do_set_decim = 1; - m_decimation = 4; - } - if(!(m_u_rx = usrp_standard_rx::make(0, m_decimation, - NCHAN, INITIAL_MUX, usrp_standard_rx::FPGA_MODE_NORMAL, - FUSB_BLOCK_SIZE, FUSB_NBLOCKS, FPGA_FILENAME()))) { - fprintf(stderr, "error: usrp_standard_rx::make: " - "failed!\n"); - return -1; - } - m_u_rx->set_fpga_master_clock_freq(m_fpga_master_clock_freq); - m_u_rx->stop(); - - if(do_set_decim) { - calculate_decimation(); - } - - m_u_rx->set_decim_rate(m_decimation); - m_sample_rate = (double)m_u_rx->fpga_master_clock_freq() / m_decimation; - - if(g_verbosity > 1) { - fprintf(stderr, "FPGA clock : %ld\n", m_u_rx->fpga_master_clock_freq()); - fprintf(stderr, "Decimation : %u\n", m_decimation); - fprintf(stderr, "Sample rate: %f\n", m_sample_rate); - } - } - if(!m_u_rx->is_valid(ss)) { - fprintf(stderr, "error: invalid daughterboard\n"); - return -1; - } - if(!(m_db_rx = m_u_rx->selected_subdev(ss))) { - fprintf(stderr, "error: no daughterboard\n"); - return -1; + device_count = rtlsdr_get_device_count(); + if (!device_count) { + fprintf(stderr, "No supported devices found.\n"); + exit(1); } - m_u_rx->set_mux(m_u_rx->determine_rx_mux_value(ss)); + fprintf(stderr, "Found %d device(s):\n", device_count); + for (i = 0; i < device_count; i++) + fprintf(stderr, " %d: %s\n", i, rtlsdr_get_device_name(i)); + fprintf(stderr, "\n"); - set_gain(0.45); - m_db_rx->select_rx_antenna(1); // this is a nop for most db + fprintf(stderr, "Using device %d: %s\n", + dev_index, + rtlsdr_get_device_name(dev_index)); + + r = rtlsdr_open(&dev, dev_index); + if (r < 0) { + fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); + exit(1); + } + + /* Set the sample rate */ + r = rtlsdr_set_sample_rate(dev, samp_rate); + if (r < 0) + fprintf(stderr, "WARNING: Failed to set sample rate.\n"); + + /* Reset endpoint before we start reading from it (mandatory) */ + r = rtlsdr_reset_buffer(dev); + if (r < 0) + fprintf(stderr, "WARNING: Failed to reset buffers.\n"); + +// r = rtlsdr_set_offset_tuning(dev, 1); +// if (r < 0) +// fprintf(stderr, "WARNING: Failed to enable offset tuning\n"); return 0; } +#define USB_PACKET_SIZE (2 * 16384) +#define FLUSH_SIZE 512 -#define USB_PACKET_SIZE 512 int usrp_source::fill(unsigned int num_samples, unsigned int *overrun_i) { bool overrun; unsigned char ubuf[USB_PACKET_SIZE]; - short *s = (short *)ubuf; unsigned int i, j, space, overruns = 0; complex *c; + int n_read; while((m_cb->data_available() < num_samples) && (m_cb->space_available() > 0)) { // read one usb packet from the usrp pthread_mutex_lock(&m_u_mutex); - if(m_u_rx->read(ubuf, sizeof(ubuf), &overrun) != sizeof(ubuf)) { + + if (rtlsdr_read_sync(dev, ubuf, sizeof(ubuf), &n_read) < 0) { pthread_mutex_unlock(&m_u_mutex); fprintf(stderr, "error: usrp_standard_rx::read\n"); return -1; } + pthread_mutex_unlock(&m_u_mutex); if(overrun) overruns++; @@ -237,12 +231,11 @@ int usrp_source::fill(unsigned int num_samples, unsigned int *overrun_i) { c = (complex *)m_cb->poke(&space); // set space to number of complex items to copy - if(space > (USB_PACKET_SIZE >> 2)) - space = USB_PACKET_SIZE >> 2; + space = n_read / 2; // write data for(i = 0, j = 0; i < space; i += 1, j += 2) - c[i] = complex(s[j], s[j + 1]); + c[i] = complex((ubuf[j] - 127) * 256, (ubuf[j + 1] - 127) * 256); // update cb m_cb->wrote(i); @@ -290,7 +283,7 @@ circular_buffer *usrp_source::get_buffer() { int usrp_source::flush(unsigned int flush_count) { m_cb->flush(); - fill(flush_count * USB_PACKET_SIZE, 0); + fill(flush_count * FLUSH_SIZE, 0); m_cb->flush(); return 0; diff --git a/src/usrp_source.h b/src/usrp_source.h index cf4a2ae..73e9c01 100644 --- a/src/usrp_source.h +++ b/src/usrp_source.h @@ -25,7 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include "usrp_complex.h" #include "circular_buffer.h" @@ -41,6 +41,7 @@ public: int read(complex *buf, unsigned int num_samples, unsigned int *samples_read); int fill(unsigned int num_samples, unsigned int *overrun); int tune(double freq); + int set_freq_correction(int ppm); bool set_antenna(int antenna); bool set_gain(float gain); void start(); @@ -53,11 +54,13 @@ public: static const unsigned int side_A = 0; static const unsigned int side_B = 1; + double m_center_freq; + int m_freq_corr; + private: void calculate_decimation(); - usrp_standard_rx_sptr m_u_rx; - db_base_sptr m_db_rx; + rtlsdr_dev_t *dev; float m_sample_rate; float m_desired_sample_rate; @@ -74,7 +77,7 @@ private: pthread_mutex_t m_u_mutex; static const unsigned int FLUSH_COUNT = 10; - static const unsigned int CB_LEN = (1 << 20); + static const unsigned int CB_LEN = (16 * 16384); static const int NCHAN = 1; static const int INITIAL_MUX = -1; static const int FUSB_BLOCK_SIZE = 1024;