From af819dfa4af838fb55ac4da299069156d7fbbf00 Mon Sep 17 00:00:00 2001 From: Dimitri Stolnikov Date: Tue, 7 May 2013 22:46:07 +0200 Subject: [PATCH] uhd: add TX support --- grc/gen_osmosdr_blocks.py | 1 + lib/osmosdr_sink_c_impl.cc | 24 +++- lib/uhd/CMakeLists.txt | 1 + lib/uhd/uhd_sink_c.cc | 264 +++++++++++++++++++++++++++++++++++++ lib/uhd/uhd_sink_c.h | 79 +++++++++++ 5 files changed, 365 insertions(+), 4 deletions(-) create mode 100644 lib/uhd/uhd_sink_c.cc create mode 100644 lib/uhd/uhd_sink_c.h diff --git a/grc/gen_osmosdr_blocks.py b/grc/gen_osmosdr_blocks.py index fe083e3..a74b387 100644 --- a/grc/gen_osmosdr_blocks.py +++ b/grc/gen_osmosdr_blocks.py @@ -146,6 +146,7 @@ Source Mode: Sink Mode: hackrf=0[,buffers=32] + uhd[,serial=...][,lo_offset=0][,mcr=52e6][,nchan=2][,subdev='\\\\'B:0 A:0\\\\''] ... Num Channels: Selects the total number of channels in this multi-device configuration. Required when specifying multiple device arguments. diff --git a/lib/osmosdr_sink_c_impl.cc b/lib/osmosdr_sink_c_impl.cc index bd43fd4..8e08444 100644 --- a/lib/osmosdr_sink_c_impl.cc +++ b/lib/osmosdr_sink_c_impl.cc @@ -34,6 +34,9 @@ #include "osmosdr_sink_c_impl.h" +#ifdef ENABLE_UHD +#include "uhd_sink_c.h" +#endif #ifdef ENABLE_HACKRF #include "hackrf_sink_c.h" #endif @@ -69,6 +72,9 @@ osmosdr_sink_c_impl::osmosdr_sink_c_impl (const std::string &args) std::vector< std::string > dev_types; +#ifdef ENABLE_UHD + dev_types.push_back("uhd"); +#endif #ifdef ENABLE_HACKRF dev_types.push_back("hackrf"); #endif @@ -76,7 +82,7 @@ osmosdr_sink_c_impl::osmosdr_sink_c_impl (const std::string &args) std::cerr << "gr-osmosdr " << GR_OSMOSDR_VERSION " (" GR_OSMOSDR_LIBVER ") " << "gnuradio " << gr_version() << std::endl; - std::cerr << "built-in device types: "; + std::cerr << "built-in sink types: "; BOOST_FOREACH(std::string dev_type, dev_types) std::cerr << dev_type << " "; std::cerr << std::endl << std::flush; @@ -94,9 +100,13 @@ osmosdr_sink_c_impl::osmosdr_sink_c_impl (const std::string &args) try { #endif std::vector< std::string > dev_list; +#ifdef ENABLE_UHD + BOOST_FOREACH( std::string dev, uhd_sink_c::get_devices() ) + dev_list.push_back( dev ); +#endif #ifdef ENABLE_HACKRF BOOST_FOREACH( std::string dev, hackrf_sink_c::get_devices() ) - dev_list.push_back( dev ); + dev_list.push_back( dev ); #endif // std::cerr << std::endl; // BOOST_FOREACH( std::string dev, dev_list ) @@ -120,10 +130,16 @@ osmosdr_sink_c_impl::osmosdr_sink_c_impl (const std::string &args) osmosdr_snk_iface *iface = NULL; gr_basic_block_sptr block; +#ifdef ENABLE_UHD + if ( dict.count("uhd") ) { + uhd_sink_c_sptr sink = make_uhd_sink_c( arg ); + block = sink; iface = sink.get(); + } +#endif #ifdef ENABLE_HACKRF if ( dict.count("hackrf") ) { - hackrf_sink_c_sptr src = make_hackrf_sink_c( arg ); - block = src; iface = src.get(); + hackrf_sink_c_sptr sink = make_hackrf_sink_c( arg ); + block = sink; iface = sink.get(); } #endif diff --git a/lib/uhd/CMakeLists.txt b/lib/uhd/CMakeLists.txt index 2aa7e73..aba5c77 100644 --- a/lib/uhd/CMakeLists.txt +++ b/lib/uhd/CMakeLists.txt @@ -28,6 +28,7 @@ include_directories( ) set(uhd_srcs + ${CMAKE_CURRENT_SOURCE_DIR}/uhd_sink_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/uhd_source_c.cc ) diff --git a/lib/uhd/uhd_sink_c.cc b/lib/uhd/uhd_sink_c.cc new file mode 100644 index 0000000..427087e --- /dev/null +++ b/lib/uhd/uhd_sink_c.cc @@ -0,0 +1,264 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Dimitri Stolnikov + * + * 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 +#include +#include + +//#include + +#include "osmosdr_arg_helpers.h" + +#include "uhd_sink_c.h" + +using namespace boost::assign; + +uhd_sink_c_sptr make_uhd_sink_c(const std::string &args) +{ + return gnuradio::get_initial_sptr(new uhd_sink_c(args)); +} + +uhd_sink_c::uhd_sink_c(const std::string &args) : + gr_hier_block2("uhd_sink_c", + args_to_io_signature(args), + gr_make_io_signature (0, 0, 0)), + _lo_offset(0.0f) +{ + size_t nchan = 1; + dict_t dict = params_to_dict(args); + + if (dict.count("nchan")) + nchan = boost::lexical_cast< size_t >( dict["nchan"] ); + + if (0 == nchan) + nchan = 1; + + if (dict.count("lo_offset")) + _lo_offset = boost::lexical_cast< double >( dict["lo_offset"] ); + + std::string arguments; // rebuild argument string without internal arguments + BOOST_FOREACH( dict_t::value_type &entry, dict ) { + if ( "uhd" != entry.first && + "nchan" != entry.first && + "subdev" != entry.first && + "lo_offset" != entry.first ) { + arguments += entry.first + "=" + entry.second + ","; + } + } + + _snk = uhd_make_usrp_sink( arguments, + uhd::io_type_t::COMPLEX_FLOAT32, + nchan ); + + if (dict.count("subdev")) { + _snk->set_subdev_spec( dict["subdev"] ); + + std::cerr << "-- Using subdev spec '" << _snk->get_subdev_spec() << "'." + << std::endl; + } + + if (0.0 != _lo_offset) + std::cerr << "-- Using lo offset of " << _lo_offset << " Hz." << std::endl; + + for ( size_t i = 0; i < nchan; i++ ) + connect( self(), i, _snk, i ); +} + +uhd_sink_c::~uhd_sink_c() +{ +} + +std::vector< std::string > uhd_sink_c::get_devices() +{ + std::vector< std::string > devices; + + uhd::device_addr_t hint; + BOOST_FOREACH(const uhd::device_addr_t &dev, uhd::device::find(hint)) { + std::string args = "uhd,subdev='A:0'," + dev.to_string(); + + std::string label = "Ettus"; + + std::string type = dev.cast< std::string >("type", "USRP"); + std::string name = dev.cast< std::string >("name", ""); + std::string serial = dev.cast< std::string >("serial", ""); + + if (type.length()) { + boost::to_upper(type); + label += " " + type; + } + + if (name.length()) + label += " " + name; + + if (serial.length()) + label += " " + serial; + + args += ",label='" + label + + "'"; + + devices.push_back( args ); + } + + //devices.clear(); + //devices.push_back( "uhd,type=usrp1,label='Ettus USRP'" ); + + return devices; +} + +std::string uhd_sink_c::name() +{ +// uhd::property_tree::sptr prop_tree = _snk->get_device()->get_device()->get_tree(); +// std::string dev_name = prop_tree->access("/name").get(); + std::string mboard_name = _snk->get_device()->get_mboard_name(); + +// std::cerr << "'" << dev_name << "' '" << mboard_name << "'" << std::endl; +// 'USRP1 Device' 'USRP1 (Classic)' +// 'B-Series Device' 'B100 (B-Hundo)' + + return mboard_name; +} + +size_t uhd_sink_c::get_num_channels() +{ + return _snk->get_device()->get_rx_num_channels(); +} + +osmosdr::meta_range_t uhd_sink_c::get_sample_rates( void ) +{ + osmosdr::meta_range_t rates; + + BOOST_FOREACH( uhd::range_t rate, _snk->get_samp_rates() ) + rates += osmosdr::range_t( rate.start(), rate.stop(), rate.step() ); + + return rates; +} + +double uhd_sink_c::set_sample_rate( double rate ) +{ + _snk->set_samp_rate( rate ); + return get_sample_rate(); +} + +double uhd_sink_c::get_sample_rate( void ) +{ + return _snk->get_samp_rate(); +} + +osmosdr::freq_range_t uhd_sink_c::get_freq_range( size_t chan ) +{ + osmosdr::freq_range_t range; + + BOOST_FOREACH( uhd::range_t freq, _snk->get_freq_range(chan) ) + range += osmosdr::range_t( freq.start(), freq.stop(), freq.step() ); + + return range; +} + +double uhd_sink_c::set_center_freq( double freq, size_t chan ) +{ + //_snk->set_center_freq(freq, chan); + + // advanced tuning with tune_request_t + uhd::tune_request_t tune_req(freq, _lo_offset); + + _snk->set_center_freq(tune_req, chan); + + return get_center_freq(chan); +} + +double uhd_sink_c::get_center_freq( size_t chan ) +{ + return _snk->get_center_freq(chan); +} + +double uhd_sink_c::set_freq_corr( double ppm, size_t chan ) +{ + return get_freq_corr(chan); +} + +double uhd_sink_c::get_freq_corr( size_t chan ) +{ + return 0; // frequency correction is not supported with UHD +} + +std::vector uhd_sink_c::get_gain_names( size_t chan ) +{ + return _snk->get_gain_names( chan ); +} + +osmosdr::gain_range_t uhd_sink_c::get_gain_range( size_t chan ) +{ + osmosdr::gain_range_t range; + + BOOST_FOREACH( uhd::range_t gain, _snk->get_gain_range(chan) ) + range += osmosdr::range_t( gain.start(), gain.stop(), gain.step() ); + + return range; +} + +osmosdr::gain_range_t uhd_sink_c::get_gain_range( const std::string & name, size_t chan ) +{ + osmosdr::gain_range_t range; + + BOOST_FOREACH( uhd::range_t gain, _snk->get_gain_range(name, chan) ) + range += osmosdr::range_t( gain.start(), gain.stop(), gain.step() ); + + return range; +} + +double uhd_sink_c::set_gain( double gain, size_t chan ) +{ + _snk->set_gain(gain, chan); + + return get_gain(chan); +} + +double uhd_sink_c::set_gain( double gain, const std::string & name, size_t chan ) +{ + _snk->set_gain(gain, name, chan); + + return get_gain(name, chan); +} + +double uhd_sink_c::get_gain( size_t chan ) +{ + return _snk->get_gain(chan); +} + +double uhd_sink_c::get_gain( const std::string & name, size_t chan ) +{ + return _snk->get_gain(name, chan); +} + +std::vector< std::string > uhd_sink_c::get_antennas( size_t chan ) +{ + return _snk->get_antennas(chan); +} + +std::string uhd_sink_c::set_antenna( const std::string & antenna, size_t chan ) +{ + _snk->set_antenna(antenna, chan); + + return _snk->get_antenna(chan); +} + +std::string uhd_sink_c::get_antenna( size_t chan ) +{ + return _snk->get_antenna(chan); +} diff --git a/lib/uhd/uhd_sink_c.h b/lib/uhd/uhd_sink_c.h new file mode 100644 index 0000000..704fb33 --- /dev/null +++ b/lib/uhd/uhd_sink_c.h @@ -0,0 +1,79 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Dimitri Stolnikov + * + * 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 UHD_SINK_C_H +#define UHD_SINK_C_H + +#include +#include + +#include "osmosdr_snk_iface.h" + +class uhd_sink_c; + +typedef boost::shared_ptr< uhd_sink_c > uhd_sink_c_sptr; + +uhd_sink_c_sptr make_uhd_sink_c(const std::string &args = ""); + +class uhd_sink_c : + public gr_hier_block2, + public osmosdr_snk_iface +{ +private: + friend uhd_sink_c_sptr make_uhd_sink_c(const std::string &args); + + uhd_sink_c(const std::string &args); + +public: + ~uhd_sink_c(); + + static std::vector< std::string > get_devices(); + + std::string name(); + + size_t get_num_channels( void ); + + osmosdr::meta_range_t get_sample_rates( void ); + double set_sample_rate( double rate ); + double get_sample_rate( void ); + + osmosdr::freq_range_t get_freq_range( size_t chan = 0 ); + double set_center_freq( double freq, size_t chan = 0 ); + double get_center_freq( size_t chan = 0 ); + double set_freq_corr( double ppm, size_t chan = 0 ); + double get_freq_corr( size_t chan = 0 ); + + std::vector get_gain_names( size_t chan = 0 ); + osmosdr::gain_range_t get_gain_range( size_t chan = 0 ); + osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 ); + double set_gain( double gain, size_t chan = 0 ); + double set_gain( double gain, const std::string & name, size_t chan = 0 ); + double get_gain( size_t chan = 0 ); + double get_gain( const std::string & name, size_t chan = 0 ); + + std::vector< std::string > get_antennas( size_t chan = 0 ); + std::string set_antenna( const std::string & antenna, size_t chan = 0 ); + std::string get_antenna( size_t chan = 0 ); + +private: + double _lo_offset; + boost::shared_ptr _snk; +}; + +#endif // UHD_SINK_C_H