diff options
author | Dimitri Stolnikov <horiz0n@gmx.net> | 2012-05-26 22:24:47 +0200 |
---|---|---|
committer | Dimitri Stolnikov <horiz0n@gmx.net> | 2012-05-26 22:24:47 +0200 |
commit | 9a5e93cf0deadba6b18d0bc3aba4d2df1e46995d (patch) | |
tree | 17dbad764cf707d7e0cca663e7b6ab5592c6f417 /lib/osmosdr | |
parent | f4f5918c25894bf9f6dbdb3e7bdf5c92133f67df (diff) |
osmosdr: change implementation to use libosmosdr
Diffstat (limited to 'lib/osmosdr')
-rw-r--r-- | lib/osmosdr/CMakeLists.txt | 6 | ||||
-rw-r--r-- | lib/osmosdr/osmosdr_control.cc | 105 | ||||
-rw-r--r-- | lib/osmosdr/osmosdr_control.h | 67 | ||||
-rw-r--r-- | lib/osmosdr/osmosdr_snk_c.cc | 16 | ||||
-rw-r--r-- | lib/osmosdr/osmosdr_snk_c.h | 4 | ||||
-rw-r--r-- | lib/osmosdr/osmosdr_src_c.cc | 260 | ||||
-rw-r--r-- | lib/osmosdr/osmosdr_src_c.h | 34 |
7 files changed, 240 insertions, 252 deletions
diff --git a/lib/osmosdr/CMakeLists.txt b/lib/osmosdr/CMakeLists.txt index a0a3ef7..977b1ee 100644 --- a/lib/osmosdr/CMakeLists.txt +++ b/lib/osmosdr/CMakeLists.txt @@ -23,11 +23,10 @@ include_directories(APPEND ${CMAKE_CURRENT_SOURCE_DIR} - ${GNURADIO_AUDIO_INCLUDE_DIRS} + ${LIBOSMOSDR_INCLUDE_DIR} ) set(osmosdr_srcs - ${CMAKE_CURRENT_SOURCE_DIR}/osmosdr_control.cc ${CMAKE_CURRENT_SOURCE_DIR}/osmosdr_snk_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/osmosdr_src_c.cc ) @@ -36,5 +35,4 @@ set(osmosdr_srcs # Append gnuradio-osmosdr library sources ######################################################################## list(APPEND gr_osmosdr_srcs ${osmosdr_srcs}) -list(APPEND gr_osmosdr_libs ${GNURADIO_AUDIO_LIBRARIES}) - +list(APPEND gr_osmosdr_libs ${LIBOSMOSDR_LIBRARIES}) diff --git a/lib/osmosdr/osmosdr_control.cc b/lib/osmosdr/osmosdr_control.cc deleted file mode 100644 index 7de2773..0000000 --- a/lib/osmosdr/osmosdr_control.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> - * - * 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. - */ - -#include <fstream> -#include <string> -#include <sstream> - -#include <boost/assign.hpp> - -#include "osmosdr_control.h" - -using namespace boost::assign; - -osmosdr_control::osmosdr_control(const std::string &args) -{ - /* lookup acm control channel device name for a given alsa device name */ - - /* - if (args.empty()) - pick first available device or throw an exception(); - */ -} - -osmosdr_control::~osmosdr_control() -{ -} - -/* - 1 [OsmoSDR ]: USB-Audio - OsmoSDR - sysmocom OsmoSDR at usb-0000:00:06.1-2, high speed - */ -std::vector< std::string > osmosdr_control::find_devices() -{ - std::vector< std::string > devices; - - std::string line; - std::ifstream cards( "/proc/asound/cards" ); - if ( cards.is_open() ) - { - while ( cards.good() ) - { - getline (cards, line); - - if ( line.find( "USB-Audio - OsmoSDR" ) != std::string::npos ) - { - int id; - std::istringstream( line ) >> id; - - std::ostringstream hw_id; - hw_id << "hw:" << id; // build alsa identifier - - devices += hw_id.str(); - } - } - - cards.close(); - } - - return devices; -} - -std::string osmosdr_control::audio_dev_name() -{ - return "hw:1"; -} - -std::string osmosdr_control::control_dev_name() -{ - return "/dev/ttyUSB0"; -} - -osmosdr_rx_control::osmosdr_rx_control(const std::string &args) : - osmosdr_control(args) -{ -} - -osmosdr_rx_control::~osmosdr_rx_control() -{ -} - -osmosdr_tx_control::osmosdr_tx_control(const std::string &args) : - osmosdr_control(args) -{ -} - -osmosdr_tx_control::~osmosdr_tx_control() -{ -} diff --git a/lib/osmosdr/osmosdr_control.h b/lib/osmosdr/osmosdr_control.h deleted file mode 100644 index ea9b298..0000000 --- a/lib/osmosdr/osmosdr_control.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> - * - * 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. - */ -#ifndef OSMOSDR_CONTROL_H -#define OSMOSDR_CONTROL_H - -#include <string> -#include <complex> -#include <osmosdr_ranges.h> - -/*! - * session object to cdc-acm based control channel of the device - */ -class osmosdr_control -{ -public: - osmosdr_control(const std::string &args); - virtual ~osmosdr_control(); - - /*! - * Discovers all devices connected to the host computer. - * \return a vector of device addresses - */ - static std::vector< std::string > find_devices(); - -protected: - std::string audio_dev_name(); - std::string control_dev_name(); -}; - -/*! - * osmosdr_source class derives from this class to be able to control the device - */ -class osmosdr_rx_control : public osmosdr_control -{ -public: - osmosdr_rx_control(const std::string &args); - virtual ~osmosdr_rx_control(); -}; - -/*! - * osmosdr_sink class derives from this class to be able to control the device - */ -class osmosdr_tx_control : public osmosdr_control -{ -public: - osmosdr_tx_control(const std::string &args); - virtual ~osmosdr_tx_control(); -}; - -#endif // OSMOSDR_CONTROL_H diff --git a/lib/osmosdr/osmosdr_snk_c.cc b/lib/osmosdr/osmosdr_snk_c.cc index edd589e..2dd3555 100644 --- a/lib/osmosdr/osmosdr_snk_c.cc +++ b/lib/osmosdr/osmosdr_snk_c.cc @@ -62,21 +62,9 @@ static const int MAX_OUT = 0; // maximum number of output streams osmosdr_snk_c::osmosdr_snk_c (const std::string & args) : gr_hier_block2 ("osmosdr_snk_c", gr_make_io_signature (MIN_IN, MAX_IN, sizeof (gr_complex)), - gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (gr_complex))), - osmosdr_tx_control(args) + gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (gr_complex))) { - throw std::runtime_error("FIXME: OsmoSDR sink is not yet implemented"); - - /* Audio sink; sample rate is 96kHz by default */ - audio_sink::sptr snk = audio_make_sink(96000, audio_dev_name(), true); - - gr_complex_to_real_sptr real_part = gr_make_complex_to_real(1); - gr_complex_to_imag_sptr imag_part = gr_make_complex_to_imag(1); - - connect(self(), 0, real_part, 0); - connect(self(), 0, imag_part, 0); - connect(imag_part, 0, snk, 0); /* Left is I */ - connect(real_part, 0, snk, 1); /* Right is Q */ + throw std::runtime_error("FIXME: OsmoSDR sink is not yet implemented."); } /* diff --git a/lib/osmosdr/osmosdr_snk_c.h b/lib/osmosdr/osmosdr_snk_c.h index efef0c8..8cb9e81 100644 --- a/lib/osmosdr/osmosdr_snk_c.h +++ b/lib/osmosdr/osmosdr_snk_c.h @@ -21,7 +21,6 @@ #define INCLUDED_OSMOSDR_SNK_C_H #include <osmosdr_api.h> -#include <osmosdr_control.h> #include <gr_hier_block2.h> class osmosdr_snk_c; @@ -55,8 +54,7 @@ OSMOSDR_API osmosdr_snk_c_sptr osmosdr_make_snk_c (const std::string & args = "" * This uses the preferred technique: subclassing gr_hier_block2. */ class OSMOSDR_API osmosdr_snk_c : - public gr_hier_block2, - public osmosdr_tx_control + public gr_hier_block2 { private: // The friend declaration allows osmosdr_make_snk_c to diff --git a/lib/osmosdr/osmosdr_src_c.cc b/lib/osmosdr/osmosdr_src_c.cc index e8181fb..1331c75 100644 --- a/lib/osmosdr/osmosdr_src_c.cc +++ b/lib/osmosdr/osmosdr_src_c.cc @@ -17,6 +17,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ + /* * config.h is generated by configure. It contains the results * of probing for features, options etc. It should be the first @@ -28,15 +29,26 @@ #include "osmosdr_src_c.h" #include <gr_io_signature.h> -#include <gr_audio_source.h> -#include <gr_float_to_complex.h> #include <boost/assign.hpp> +#include <boost/format.hpp> + +#include <stdexcept> +#include <iostream> +#include <stdio.h> + +#include <osmosdr.h> #include <osmosdr_arg_helpers.h> using namespace boost::assign; +#define BUF_SIZE (16 * 32 * 512) +#define BUF_NUM 32 +#define BUF_SKIP 1 // buffers to skip due to garbage + +#define BYTES_PER_SAMPLE 4 // osmosdr device delivers 16 bit signed IQ data + /* * Create a new instance of osmosdr_src_c and return * a boost shared_ptr. This is effectively the public constructor. @@ -51,12 +63,11 @@ osmosdr_make_src_c (const std::string &args) * The private constructor */ osmosdr_src_c::osmosdr_src_c (const std::string &args) - : gr_hier_block2 ("osmosdr_src_c", + : gr_sync_block ("osmosdr_src_c", gr_make_io_signature (0, 0, sizeof (gr_complex)), - args_to_io_signature(args)), - osmosdr_rx_control(args) + args_to_io_signature(args)) { - std::string dev_name; + int ret; unsigned int dev_index = 0, mcr = 0; size_t nchan = 1; @@ -68,27 +79,64 @@ osmosdr_src_c::osmosdr_src_c (const std::string &args) if (dict.count("mcr")) mcr = (unsigned int) boost::lexical_cast< double >( dict["mcr"] ); + if (mcr != 0) + throw std::runtime_error("Setting the master clock rate is not supported."); + if (dict.count("nchan")) nchan = boost::lexical_cast< size_t >( dict["nchan"] ); - std::vector< std::string > devices = osmosdr_control::find_devices(); + if (nchan != 1) + throw std::runtime_error("Values of nchan != 1 are not supported."); + + _buf_num = BUF_NUM; + + if (dict.count("buffers")) { + _buf_num = (unsigned int)boost::lexical_cast< double >( dict["buffers"] ); + if (0 == _buf_num) + _buf_num = BUF_NUM; + std::cerr << "Using " << _buf_num << " buffers of size " << BUF_SIZE << "." + << std::endl; + } + + _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 / BYTES_PER_SAMPLE; + + if ( dev_index >= osmosdr_get_device_count() ) + throw std::runtime_error("Wrong osmosdr device index given."); + + std::cerr << "Using device #" << dev_index << ": " + << osmosdr_get_device_name(dev_index) + << std::endl; - if ( devices.size() ) - dev_name = devices[dev_index]; - else - throw std::runtime_error("No OsmoSDR devices found."); + _dev = NULL; + ret = osmosdr_open( &_dev, dev_index ); + if (ret < 0) + throw std::runtime_error("Failed to open osmosdr device."); - /* Audio source; sample rate is 500kHz by default */ - audio_source::sptr src = audio_make_source(500000, dev_name, true); + ret = osmosdr_set_sample_rate( _dev, 500000 ); + if (ret < 0) + throw std::runtime_error("Failed to set default samplerate."); - /* block to convert stereo audio to a complex stream */ - gr_float_to_complex_sptr f2c = gr_make_float_to_complex(1); + ret = osmosdr_reset_buffer( _dev ); + if (ret < 0) + throw std::runtime_error("Failed to reset usb buffers."); - connect(src, 0, f2c, 0); /* Left is I */ - connect(src, 1, f2c, 1); /* Right is Q */ - connect(f2c, 0, self(), 0); + ret = osmosdr_set_tuner_gain_mode(_dev, 1); + if (ret < 0) + throw std::runtime_error("Failed to enable manual gain mode."); + + _running = true; _auto_gain = false; + + _skipped = 0; + + _thread = gruel::thread(_osmosdr_wait, this); } /* @@ -96,17 +144,132 @@ osmosdr_src_c::osmosdr_src_c (const std::string &args) */ osmosdr_src_c::~osmosdr_src_c () { - // nothing else required in this example + if (_dev) { + _running = false; + osmosdr_cancel_async( _dev ); + _thread.timed_join( boost::posix_time::milliseconds(200) ); + osmosdr_close( _dev ); + _dev = NULL; + } + + for(unsigned int i = 0; i < _buf_num; ++i) { + if (_buf[i]) + free(_buf[i]); + } + + free(_buf); + _buf = NULL; +} + +void osmosdr_src_c::_osmosdr_callback(unsigned char *buf, uint32_t len, void *ctx) +{ + osmosdr_src_c *obj = (osmosdr_src_c *)ctx; + obj->osmosdr_callback(buf, len); +} + +void osmosdr_src_c::osmosdr_callback(unsigned char *buf, uint32_t len) +{ + if (_skipped < BUF_SKIP) { + _skipped++; + return; + } + + if (len != BUF_SIZE) { + printf("U(%d)\n", len); fflush(stdout); + return; + } + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + int buf_tail = (_buf_head + _buf_used) % _buf_num; + memcpy(_buf[buf_tail], buf, len); + + if (_buf_used == _buf_num) { + printf("O"); fflush(stdout); + _buf_head = (_buf_head + 1) % _buf_num; + } else { + _buf_used++; + } + } + + _buf_cond.notify_one(); +} + +void osmosdr_src_c::_osmosdr_wait(osmosdr_src_c *obj) +{ + obj->osmosdr_wait(); +} + +void osmosdr_src_c::osmosdr_wait() +{ + int ret = osmosdr_read_async( _dev, _osmosdr_callback, (void *)this, 0, BUF_SIZE ); + + _running = false; + + if ( ret != 0 ) + std::cerr << "osmosdr_read_async returned with " << ret << std::endl; +} + +int osmosdr_src_c::work( int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items ) +{ + gr_complex *out = (gr_complex *)output_items[0]; + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + while (_buf_used < 3 && _running) // collect at least 3 buffers + _buf_cond.wait( lock ); + } + + if (!_running) + return WORK_DONE; + + unsigned short *buf = _buf[_buf_head] + _buf_offset; + + if (noutput_items <= int(_samp_avail)) { + for (int i = 0; i < noutput_items; i += 2) + *out++ = gr_complex( float(*(buf + i + 0)) * (1.0f/32767.5f), + float(*(buf + i + 1)) * (1.0f/32767.5f) ); + + _buf_offset += noutput_items * 2; + _samp_avail -= noutput_items; + } else { + for (int i = 0; i < int(_samp_avail); i += 2) + *out++ = gr_complex( float(*(buf + i + 0)) * (1.0f/32767.5f), + float(*(buf + i + 1)) * (1.0f/32767.5f) ); + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + _buf_head = (_buf_head + 1) % _buf_num; + _buf_used--; + } + + buf = _buf[_buf_head]; + + int remaining = noutput_items - _samp_avail; + + for (int i = 0; i < remaining; i += 2) + *out++ = gr_complex( float(*(buf + i + 0)) * (1.0f/32767.5f), + float(*(buf + i + 1)) * (1.0f/32767.5f) ); + + _buf_offset = remaining * 2; + _samp_avail = (BUF_SIZE / BYTES_PER_SAMPLE) - remaining; + } + + return noutput_items; } std::vector<std::string> osmosdr_src_c::get_devices() { - int id = 0; std::vector< std::string > devices; - BOOST_FOREACH( std::string dev, osmosdr_control::find_devices() ) { - std::string args = "osmosdr=" + boost::lexical_cast< std::string >( id++ ); - args += ",label='sysmocom OsmoSDR'"; + for (unsigned int i = 0; i < osmosdr_get_device_count(); i++) { + std::string args = "osmosdr=" + boost::lexical_cast< std::string >( i ); + args += ",label='" + std::string(osmosdr_get_device_name( i )) + "'"; devices.push_back( args ); } @@ -122,14 +285,7 @@ osmosdr::meta_range_t osmosdr_src_c::get_sample_rates() { osmosdr::meta_range_t range; - range += osmosdr::range_t( 1024000 ); // known to work - range += osmosdr::range_t( 1800000 ); // known to work - range += osmosdr::range_t( 2048000 ); // known to work - range += osmosdr::range_t( 2400000 ); // may work - range += osmosdr::range_t( 2600000 ); // may work - range += osmosdr::range_t( 2800000 ); // may work - range += osmosdr::range_t( 3000000 ); // may work - range += osmosdr::range_t( 3200000 ); // max rate, may work + range += osmosdr::range_t( 500000 ); // known to work // TODO: read from the libosmosdr as soon as the api is available @@ -138,17 +294,17 @@ osmosdr::meta_range_t osmosdr_src_c::get_sample_rates() double osmosdr_src_c::set_sample_rate(double rate) { -// if (_dev) { -// osmosdr_set_sample_rate( _dev, (uint32_t)rate ); -// } + if (_dev) { + osmosdr_set_sample_rate( _dev, (uint32_t)rate ); + } return get_sample_rate(); } double osmosdr_src_c::get_sample_rate() { -// if (_dev) -// return (double)osmosdr_get_sample_rate( _dev ); + if (_dev) + return (double)osmosdr_get_sample_rate( _dev ); return 0; } @@ -166,33 +322,27 @@ osmosdr::freq_range_t osmosdr_src_c::get_freq_range( size_t chan ) double osmosdr_src_c::set_center_freq( double freq, size_t chan ) { -// if (_dev) -// osmosdr_set_center_freq( _dev, (uint32_t)freq ); + if (_dev) + osmosdr_set_center_freq( _dev, (uint32_t)freq ); return get_center_freq( chan ); } double osmosdr_src_c::get_center_freq( size_t chan ) { -// if (_dev) -// return (double)osmosdr_get_center_freq( _dev ); + if (_dev) + return (double)osmosdr_get_center_freq( _dev ); return 0; } double osmosdr_src_c::set_freq_corr( double ppm, size_t chan ) { -// if ( _dev ) -// osmosdr_set_freq_correction( _dev, (int)ppm ); - return get_freq_corr( chan ); } double osmosdr_src_c::get_freq_corr( size_t chan ) { -// if ( _dev ) -// return (double)osmosdr_get_freq_correction( _dev ); - return 0; } @@ -240,11 +390,11 @@ osmosdr::gain_range_t osmosdr_src_c::get_gain_range( const std::string & name, s bool osmosdr_src_c::set_gain_mode( bool automatic, size_t chan ) { -// if (_dev) { -// if (!osmosdr_set_tuner_gain_mode(_dev, int(!automatic))) { -// _auto_gain = automatic; -// } -// } + if (_dev) { + if (!osmosdr_set_tuner_gain_mode(_dev, int(!automatic))) { + _auto_gain = automatic; + } + } return get_gain_mode(chan); } @@ -277,8 +427,8 @@ double osmosdr_src_c::set_gain( double gain, size_t chan ) osmosdr::gain_range_t gains = osmosdr_src_c::get_gain_range( chan ); double picked_gain = pick_closest_gain( gains, gain ); -// if (_dev) -// osmosdr_set_tuner_gain( _dev, int(picked_gain * 10.0) ); + if (_dev) + osmosdr_set_tuner_gain( _dev, int(picked_gain * 10.0) ); return get_gain( chan ); } @@ -290,8 +440,8 @@ double osmosdr_src_c::set_gain( double gain, const std::string & name, size_t ch double osmosdr_src_c::get_gain( size_t chan ) { -// if ( _dev ) -// return ((double)osmosdr_get_tuner_gain( _dev )) / 10.0; + if ( _dev ) + return ((double)osmosdr_get_tuner_gain( _dev )) / 10.0; return 0; } diff --git a/lib/osmosdr/osmosdr_src_c.h b/lib/osmosdr/osmosdr_src_c.h index 9a78ce3..412d037 100644 --- a/lib/osmosdr/osmosdr_src_c.h +++ b/lib/osmosdr/osmosdr_src_c.h @@ -21,12 +21,16 @@ #define INCLUDED_OSMOSDR_SRC_C_H #include <osmosdr_api.h> -#include <osmosdr_control.h> -#include <gr_hier_block2.h> +#include <gr_sync_block.h> + +#include <gruel/thread.h> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include "osmosdr_src_iface.h" class osmosdr_src_c; +typedef struct osmosdr_dev osmosdr_dev_t; /* * We use boost::shared_ptr's instead of raw pointers for all access @@ -57,8 +61,7 @@ OSMOSDR_API osmosdr_src_c_sptr osmosdr_make_src_c (const std::string & args = "" * \sa osmosdr_sink_c for a version that subclasses gr_hier_block2. */ class OSMOSDR_API osmosdr_src_c : - public gr_hier_block2, - public osmosdr_rx_control, + public gr_sync_block, public osmosdr_src_iface { private: @@ -75,6 +78,10 @@ private: public: ~osmosdr_src_c (); // public destructor + int work( int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items ); + static std::vector< std::string > get_devices(); size_t get_num_channels( void ); @@ -104,7 +111,26 @@ private: std::string get_antenna( size_t chan = 0 ); private: + static void _osmosdr_callback(unsigned char *buf, uint32_t len, void *ctx); + void osmosdr_callback(unsigned char *buf, uint32_t len); + static void _osmosdr_wait(osmosdr_src_c *obj); + void osmosdr_wait(); + + osmosdr_dev_t *_dev; + gruel::thread _thread; + unsigned short **_buf; + unsigned int _buf_num; + unsigned int _buf_head; + unsigned int _buf_used; + boost::mutex _buf_mutex; + boost::condition_variable _buf_cond; + bool _running; + + unsigned int _buf_offset; + unsigned int _samp_avail; + bool _auto_gain; + unsigned int _skipped; }; #endif /* INCLUDED_OSMOSDR_SRC_C_H */ |