rtl: reimplement buffering to make it more efficient

This commit is contained in:
Dimitri Stolnikov 2012-04-26 19:14:42 +02:00
parent 514b806d0a
commit d5589e8e1d
3 changed files with 118 additions and 37 deletions

35
lib/rtl/CMakeLists.txt Normal file
View File

@ -0,0 +1,35 @@
# Copyright 2012 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# This file included, use CMake directory variables
########################################################################
include_directories(APPEND ${CMAKE_CURRENT_SOURCE_DIR} ${LIBRTLSDR_INCLUDE_DIR})
set(rtl_srcs
${CMAKE_CURRENT_SOURCE_DIR}/rtl_source_c.cc
)
########################################################################
# Append gnuradio-osmosdr library sources
########################################################################
list(APPEND gr_osmosdr_srcs ${rtl_srcs})
list(APPEND gr_osmosdr_libs ${LIBRTLSDR_LIBRARIES})

View File

@ -1,10 +1,7 @@
/* -*- c++ -*- */ /* -*- c++ -*- */
/* /*
* Copyright 2012 Free Software Foundation, Inc.
* Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net>
* *
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify * GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option) * the Free Software Foundation; either version 3, or (at your option)
@ -43,6 +40,8 @@
using namespace boost::assign; using namespace boost::assign;
#define BUF_SIZE (16 * 32 * 512)
/* /*
* Create a new instance of rtl_source_c and return * Create a new instance of rtl_source_c and return
* a boost shared_ptr. This is effectively the public constructor. * a boost shared_ptr. This is effectively the public constructor.
@ -76,13 +75,21 @@ rtl_source_c::rtl_source_c (const std::string &args)
gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (gr_complex))) gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (gr_complex)))
{ {
int ret; int ret;
int dev_index = 0; unsigned int dev_index = atoi( args.c_str() );
_buf = boost::circular_buffer<unsigned short>(1024*1024); std::cout << "'" << args << "'" << std::endl;
_buf_num = 32;
_buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *));
for(unsigned int i = 0; i < _buf_num; ++i)
_buf[i] = (unsigned short *) malloc(BUF_SIZE);
_buf_head = _buf_used = _buf_offset = 0;
_samp_avail = BUF_SIZE;
// create a lookup table for gr_complex values // create a lookup table for gr_complex values
for (unsigned int i = 0; i <= 0xffff; i++) for (unsigned int i = 0; i <= 0xffff; i++) {
{
#if 1 // little endian #if 1 // little endian
_lut.push_back( gr_complex( (float(i & 0xff) - 127.5f) *(1.0f/128.0f), _lut.push_back( gr_complex( (float(i & 0xff) - 127.5f) *(1.0f/128.0f),
(float(i >> 8) - 127.5f) * (1.0f/128.0f) ) ); (float(i >> 8) - 127.5f) * (1.0f/128.0f) ) );
@ -92,6 +99,9 @@ rtl_source_c::rtl_source_c (const std::string &args)
#endif #endif
} }
if ( dev_index >= rtlsdr_get_device_count() )
throw std::runtime_error("Device index out of bounds for rtlsdr.");
std::cerr << "Using device #" << dev_index << " " std::cerr << "Using device #" << dev_index << " "
<< "(" << rtlsdr_get_device_name(dev_index) << ")" << "(" << rtlsdr_get_device_name(dev_index) << ")"
<< std::endl; << std::endl;
@ -125,6 +135,14 @@ rtl_source_c::~rtl_source_c ()
rtlsdr_close( _dev ); rtlsdr_close( _dev );
_dev = NULL; _dev = NULL;
} }
for(unsigned int i = 0; i < _buf_num; ++i) {
if (_buf[i])
free(_buf[i]);
}
free(_buf);
_buf = NULL;
} }
void rtl_source_c::_rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) void rtl_source_c::_rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
@ -135,20 +153,22 @@ void rtl_source_c::_rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
void rtl_source_c::rtlsdr_callback(unsigned char *buf, uint32_t len) void rtl_source_c::rtlsdr_callback(unsigned char *buf, uint32_t len)
{ {
unsigned short * sbuf = (unsigned short *)buf; if (len != BUF_SIZE) {
printf("U(%d)\n", len); fflush(stdout);
boost::mutex::scoped_lock lock( _buf_mutex ); return;
if (len % 2 != 0) {
printf("!!! len: %d\n", len); fflush(stdout);
} }
for (int i = 0; i < len/2; i++) { {
if (!_buf.full()) { boost::mutex::scoped_lock lock( _buf_mutex );
_buf.push_back( sbuf[i] );
} else { int buf_tail = (_buf_head + _buf_used) % _buf_num;
memcpy(_buf[buf_tail], buf, len);
if (_buf_used == _buf_num) {
printf("O"); fflush(stdout); printf("O"); fflush(stdout);
break; _buf_head = (_buf_head + 1) % _buf_num;
} else {
_buf_used++;
} }
} }
@ -162,7 +182,7 @@ void rtl_source_c::_rtlsdr_wait(rtl_source_c *obj)
void rtl_source_c::rtlsdr_wait() void rtl_source_c::rtlsdr_wait()
{ {
int ret = rtlsdr_read_async( _dev, _rtlsdr_callback, (void *)this, 0, 0 ); int ret = rtlsdr_read_async( _dev, _rtlsdr_callback, (void *)this, 0, BUF_SIZE );
_running = false; _running = false;
@ -176,29 +196,49 @@ int rtl_source_c::work( int noutput_items,
{ {
gr_complex *out = (gr_complex *)output_items[0]; gr_complex *out = (gr_complex *)output_items[0];
{
boost::mutex::scoped_lock lock( _buf_mutex );
while (_buf_used < 3 && _running)
_buf_cond.wait( lock );
}
if (!_running) if (!_running)
return WORK_DONE; return WORK_DONE;
int items_left = noutput_items; unsigned short *buf = _buf[_buf_head];
while ( items_left )
{
{
boost::mutex::scoped_lock lock( _buf_mutex );
while( _buf.empty() ) { if (noutput_items <= int(_samp_avail)) {
_buf_cond.wait( lock ); for (int i = 0; i <= noutput_items; ++i)
} *out++ = _lut[ *(buf + _buf_offset + i) ];
}
// convert samples to gr_complex type by using the lookup table _buf_offset += noutput_items;
*out++ = _lut[ _buf.front() ]; _samp_avail -= noutput_items;
items_left--; return noutput_items;
} else {
for (int i = 0; i <= int(_samp_avail); ++i)
*out++ = _lut[ *(buf + _buf_offset + i) ];
{ {
boost::mutex::scoped_lock lock( _buf_mutex ); boost::mutex::scoped_lock lock( _buf_mutex );
_buf.pop_front(); _buf_head = (_buf_head + 1) % _buf_num;
_buf_used--;
} }
buf = _buf[_buf_head];
_buf_offset = 0;
int remaining = noutput_items - _samp_avail;
for (int i = 0; i <= remaining; ++i)
*out++ = _lut[ *(buf + _buf_offset + i) ];
_buf_offset = remaining;
_samp_avail = (BUF_SIZE/2) - remaining;
return noutput_items;
} }
return noutput_items; return noutput_items;
@ -213,9 +253,9 @@ osmosdr::meta_range_t rtl_source_c::get_sample_rates()
{ {
osmosdr::meta_range_t range; osmosdr::meta_range_t range;
range += osmosdr::range_t( 1024000 ); range += osmosdr::range_t( 1024000 ); // known to work
range += osmosdr::range_t( 2048000 ); range += osmosdr::range_t( 2048000 ); // known to work
range += osmosdr::range_t( 3200000 ); range += osmosdr::range_t( 3200000 ); // max rate, may work
// TODO: read from the librtlsdr as soon as the api is available // TODO: read from the librtlsdr as soon as the api is available

View File

@ -25,8 +25,8 @@
#include <osmosdr_api.h> #include <osmosdr_api.h>
#include <gr_sync_block.h> #include <gr_sync_block.h>
#include <gruel/thread.h> #include <gruel/thread.h>
#include <boost/circular_buffer.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp> #include <boost/thread/condition_variable.hpp>
@ -117,10 +117,16 @@ private:
rtlsdr_dev_t *_dev; rtlsdr_dev_t *_dev;
gruel::thread _thread; gruel::thread _thread;
boost::circular_buffer<unsigned short> _buf; unsigned short **_buf;
unsigned int _buf_num;
unsigned int _buf_head;
unsigned int _buf_used;
boost::mutex _buf_mutex; boost::mutex _buf_mutex;
boost::condition_variable _buf_cond; boost::condition_variable _buf_cond;
bool _running; bool _running;
unsigned int _buf_offset;
unsigned int _samp_avail;
}; };
#endif /* INCLUDED_RTLSDR_SOURCE_C_H */ #endif /* INCLUDED_RTLSDR_SOURCE_C_H */