This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/osmocom-sdr@lists.osmocom.org/.
Baffo32 0xloem at gmail.comFrom: Karl Semich <0xloem at gmail.com> Adds support for message commands ala UHD to all devices. Refactored just a little to provide for this. Even if this is too much to review, a comment on the submission of this patch would be a great gift. I'm very interested in this feature and want to do the work to find a way to make it work. --- include/osmosdr/CMakeLists.txt | 1 + include/osmosdr/messages.h | 37 ++ lib/CMakeLists.txt | 1 + lib/common_iface.h | 368 +++++++++++++++++++ lib/dev_manager.cc | 815 +++++++++++++++++++++++++++++++++++++++++ lib/dev_manager.h | 176 +++++++++ lib/sink_iface.h | 336 +---------------- lib/sink_impl.cc | 370 +++---------------- lib/sink_impl.h | 15 +- lib/source_iface.h | 337 +---------------- lib/source_impl.cc | 446 +++------------------- lib/source_impl.h | 20 +- lib/uhd/uhd_sink_c.cc | 5 + lib/uhd/uhd_source_c.cc | 5 + 14 files changed, 1530 insertions(+), 1402 deletions(-) create mode 100644 include/osmosdr/messages.h create mode 100644 lib/common_iface.h create mode 100644 lib/dev_manager.cc create mode 100644 lib/dev_manager.h diff --git a/include/osmosdr/CMakeLists.txt b/include/osmosdr/CMakeLists.txt index d185ee6..6f92eaa 100644 --- a/include/osmosdr/CMakeLists.txt +++ b/include/osmosdr/CMakeLists.txt @@ -26,6 +26,7 @@ install(FILES ranges.h time_spec.h device.h + messages.h source.h sink.h DESTINATION include/osmosdr diff --git a/include/osmosdr/messages.h b/include/osmosdr/messages.h new file mode 100644 index 0000000..b4aacf0 --- /dev/null +++ b/include/osmosdr/messages.h @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 Karl Semich <0xloem at gmail.com> + * + * 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 INCLUDED_OSMOSDR_MESSAGES_H +#define INCLUDED_OSMOSDR_MESSAGES_H + +#include <pmt/pmt.h> + +namespace osmosdr { + +const pmt::pmt_t CMD_PORT = pmt::mp("command"); +const pmt::pmt_t CMD_CHAN_KEY = pmt::mp("chan"); +const pmt::pmt_t CMD_GAIN_KEY = pmt::mp("gain"); +const pmt::pmt_t CMD_FREQ_KEY = pmt::mp("freq"); +const pmt::pmt_t CMD_RATE_KEY = pmt::mp("rate"); +const pmt::pmt_t CMD_ANTENNA_KEY = pmt::mp("antenna"); +const pmt::pmt_t CMD_BANDWIDTH_KEY = pmt::mp("bandwidth"); + +} /* namespace osmosdr */ + +#endif /* INCLUDED_OSMOSDR_MESSAGES_H */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index dbb175a..c2816c9 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -38,6 +38,7 @@ ENDMACRO(GR_OSMOSDR_APPEND_LIBS) GR_OSMOSDR_APPEND_SRCS( source_impl.cc sink_impl.cc + dev_manager.cc ranges.cc device.cc time_spec.cc diff --git a/lib/common_iface.h b/lib/common_iface.h new file mode 100644 index 0000000..b3c6b03 --- /dev/null +++ b/lib/common_iface.h @@ -0,0 +1,368 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Dimitri Stolnikov <horiz0n at 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_COMMON_IFACE_H +#define OSMOSDR_COMMON_IFACE_H + +#include <osmosdr/ranges.h> +#include <osmosdr/time_spec.h> + +/*! + * TODO: document + * + */ +class common_iface +{ +public: + /*! + * Get the number of channels the underlying radio hardware offers. + * \return the number of available channels + */ + virtual size_t get_num_channels( void ) = 0; + + /*! + * Get the possible sample rates for the underlying radio hardware. + * \return a range of rates in Sps + */ + virtual osmosdr::meta_range_t get_sample_rates( void ) = 0; + + /*! + * Set the sample rate for the underlying radio hardware. + * This also will select the appropriate IF bandpass, if applicable. + * \param rate a new rate in Sps + */ + virtual double set_sample_rate( double rate ) = 0; + + /*! + * Get the sample rate for the underlying radio hardware. + * This is the actual sample rate and may differ from the rate set. + * \return the actual rate in Sps + */ + virtual double get_sample_rate( void ) = 0; + + /*! + * Get the tunable frequency range for the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return the frequency range in Hz + */ + virtual osmosdr::freq_range_t get_freq_range( size_t chan = 0 ) = 0; + + /*! + * Tune the underlying radio hardware to the desired center frequency. + * This also will select the appropriate RF bandpass. + * \param freq the desired frequency in Hz + * \param chan the channel index 0 to N-1 + * \return the actual frequency in Hz + */ + virtual double set_center_freq( double freq, size_t chan = 0 ) = 0; + + /*! + * Get the center frequency the underlying radio hardware is tuned to. + * This is the actual frequency and may differ from the frequency set. + * \param chan the channel index 0 to N-1 + * \return the frequency in Hz + */ + virtual double get_center_freq( size_t chan = 0 ) = 0; + + /*! + * Set the frequency correction value in parts per million. + * \param ppm the desired correction value in parts per million + * \param chan the channel index 0 to N-1 + * \return correction value in parts per million + */ + virtual double set_freq_corr( double ppm, size_t chan = 0 ) = 0; + + /*! + * Get the frequency correction value. + * \param chan the channel index 0 to N-1 + * \return correction value in parts per million + */ + virtual double get_freq_corr( size_t chan = 0 ) = 0; + + /*! + * Get the gain stage names of the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return a vector of strings containing the names of gain stages + */ + virtual std::vector<std::string> get_gain_names( size_t chan = 0 ) = 0; + + /*! + * Get the settable overall gain range for the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return the gain range in dB + */ + virtual osmosdr::gain_range_t get_gain_range( size_t chan = 0 ) = 0; + + /*! + * Get the settable gain range for a specific gain stage. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the gain range in dB + */ + virtual osmosdr::gain_range_t get_gain_range( const std::string & name, + size_t chan = 0 ) = 0; + + /*! + * Set the gain mode for the underlying radio hardware. + * This might be supported only for certain hardware types. + * \param automatic the gain mode (true means automatic gain mode) + * \param chan the channel index 0 to N-1 + * \return the actual gain mode + */ + virtual bool set_gain_mode( bool automatic, size_t chan = 0 ) { return false; } + + /*! + * Get the gain mode selected for the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return the actual gain mode (true means automatic gain mode) + */ + virtual bool get_gain_mode( size_t chan = 0 ) { return false; } + + /*! + * Set the gain for the underlying radio hardware. + * This function will automatically distribute the desired gain value over + * available gain stages in an appropriate way and return the actual value. + * \param gain the gain in dB + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double set_gain( double gain, size_t chan = 0 ) = 0; + + /*! + * Set the named gain on the underlying radio hardware. + * \param gain the gain in dB + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double set_gain( double gain, + const std::string & name, + size_t chan = 0 ) = 0; + + /*! + * Get the actual gain setting of the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double get_gain( size_t chan = 0 ) = 0; + + /*! + * Get the actual gain setting of a named stage. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double get_gain( const std::string & name, size_t chan = 0 ) = 0; + + /*! + * Set the IF gain for the underlying radio hardware. + * This function will automatically distribute the desired gain value over + * available IF gain stages in an appropriate way and return the actual value. + * \param gain the gain in dB + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double set_if_gain( double gain, size_t chan = 0 ) { return 0; } + + /*! + * Set the BB gain for the underlying radio hardware. + * This function will automatically distribute the desired gain value over + * available BB gain stages in an appropriate way and return the actual value. + * \param gain the gain in dB + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double set_bb_gain( double gain, size_t chan = 0 ) { return 0; } + + /*! + * Get the available antennas of the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return a vector of strings containing the names of available antennas + */ + virtual std::vector< std::string > get_antennas( size_t chan = 0 ) = 0; + + /*! + * Select the active antenna of the underlying radio hardware. + * \param chan the channel index 0 to N-1 + * \return the actual antenna's name + */ + virtual std::string set_antenna( const std::string & antenna, + size_t chan = 0 ) = 0; + + /*! + * Get the actual underlying radio hardware antenna setting. + * \param chan the channel index 0 to N-1 + * \return the actual antenna's name + */ + virtual std::string get_antenna( size_t chan = 0 ) = 0; + + /*! + * Set the frontend DC offset value. + * The value is complex to control both I and Q. + * For RX, only set this when automatic correction is disabled. + * + * \param offset the dc offset (1.0 is full-scale) + * \param chan the channel index 0 to N-1 + */ + virtual void set_dc_offset( const std::complex<double> &offset, size_t chan = 0 ) { } + + /*! + * Set the frontend IQ balance correction. + * Use this to adjust the magnitude and phase of I and Q. + * + * \param balance the complex correction value + * \param chan the channel index 0 to N-1 + */ + virtual void set_iq_balance( const std::complex<double> &balance, size_t chan = 0 ) { } + + /*! + * Set the bandpass filter on the radio frontend. + * \param bandwidth the filter bandwidth in Hz, set to 0 for automatic selection + * \param chan the channel index 0 to N-1 + * \return the actual filter bandwidth in Hz + */ + virtual double set_bandwidth( double bandwidth, size_t chan = 0 ) { return 0; } + + /*! + * Get the actual bandpass filter setting on the radio frontend. + * \param chan the channel index 0 to N-1 + * \return the actual filter bandwidth in Hz + */ + virtual double get_bandwidth( size_t chan = 0 ) { return 0; } + + /*! + * Get the possible bandpass filter settings on the radio frontend. + * \param chan the channel index 0 to N-1 + * \return a range of bandwidths in Hz + */ + virtual osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 ) + { return osmosdr::freq_range_t(); } + + /*! + * Set the time source for the device. + * This sets the method of time synchronization, + * typically a pulse per second or an encoded time. + * Typical options for source: external, MIMO. + * \param source a string representing the time source + * \param mboard which motherboard to set the config + */ + virtual void set_time_source(const std::string &source, + const size_t mboard = 0) { } + + /*! + * Get the currently set time source. + * \param mboard which motherboard to get the config + * \return the string representing the time source + */ + virtual std::string get_time_source(const size_t mboard) { return ""; } + + /*! + * Get a list of possible time sources. + * \param mboard which motherboard to get the list + * \return a vector of strings for possible settings + */ + virtual std::vector<std::string> get_time_sources(const size_t mboard) + { + return std::vector<std::string>(); + } + + /*! + * Set the clock source for the device. + * This sets the source for a 10 Mhz reference clock. + * Typical options for source: internal, external, MIMO. + * \param source a string representing the clock source + * \param mboard which motherboard to set the config + */ + virtual void set_clock_source(const std::string &source, + const size_t mboard = 0) { } + + /*! + * Get the currently set clock source. + * \param mboard which motherboard to get the config + * \return the string representing the clock source + */ + virtual std::string get_clock_source(const size_t mboard) { return ""; } + + /*! + * Get a list of possible clock sources. + * \param mboard which motherboard to get the list + * \return a vector of strings for possible settings + */ + virtual std::vector<std::string> get_clock_sources(const size_t mboard) + { + return std::vector<std::string>(); + } + + /*! + * Get the master clock rate. + * \param mboard the motherboard index 0 to M-1 + * \return the clock rate in Hz + */ + virtual double get_clock_rate(size_t mboard = 0) { return 0; } + + /*! + * Set the master clock rate. + * \param rate the new rate in Hz + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_clock_rate(double rate, size_t mboard = 0) { } + + /*! + * Get the current time registers. + * \param mboard the motherboard index 0 to M-1 + * \return the current device time + */ + virtual ::osmosdr::time_spec_t get_time_now(size_t mboard = 0) + { + return ::osmosdr::time_spec_t::get_system_time(); + } + + /*! + * Get the time when the last pps pulse occured. + * \param mboard the motherboard index 0 to M-1 + * \return the current device time + */ + virtual ::osmosdr::time_spec_t get_time_last_pps(size_t mboard = 0) + { + return ::osmosdr::time_spec_t::get_system_time(); + } + + /*! + * Sets the time registers immediately. + * \param time_spec the new time + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_time_now(const ::osmosdr::time_spec_t &time_spec, + size_t mboard = 0) { } + + /*! + * Set the time registers at the next pps. + * \param time_spec the new time + */ + virtual void set_time_next_pps(const ::osmosdr::time_spec_t &time_spec) { } + + /*! + * Sync the time registers with an unknown pps edge. + * \param time_spec the new time + */ + virtual void set_time_unknown_pps(const ::osmosdr::time_spec_t &time_spec) { } +}; + +#endif // OSMOSDR_COMMON_IFACE_H diff --git a/lib/dev_manager.cc b/lib/dev_manager.cc new file mode 100644 index 0000000..e2d0319 --- /dev/null +++ b/lib/dev_manager.cc @@ -0,0 +1,815 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 Karl Semich <0xloem at gmail.com> + * + * 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. + */ + +/* + * config.h is generated by configure. It contains the results + * of probing for features, options etc. It should be the first + * file included in your .cc file. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dev_manager.h" + +#include <gnuradio/io_signature.h> + +#include "source_iface.h" + +/* + * Create a new instance of dev_manager and return + * a boost shared_ptr. This is effectively the public constructor. + */ +dev_manager_sptr +make_dev_manager ( gr::hier_block2_sptr outer ) +{ + return gnuradio::get_initial_sptr( new dev_manager ( outer ) ); +} + +/* + * The private constructor + */ +dev_manager::dev_manager ( gr::hier_block2_sptr outer ) + : gr::block ( "dev_manager", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0) ), + _outer(outer), + _channels(0), + _sample_rate(NAN) +{ + message_port_register_in( osmosdr::CMD_PORT ); + set_msg_handler( osmosdr::CMD_PORT, boost::bind(&dev_manager::msg_handler_command, this, _1) ); +} + +int dev_manager::general_work( int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + return 0; +} + +void dev_manager::add_device( gr::basic_block_sptr block, common_iface *iface ) +{ + if ( iface == nullptr || block.get() == nullptr ) { + if ( iface != nullptr || block.get() != nullptr ) + throw std::runtime_error("Either iface or block are NULL."); + return; + } + + size_t mboard = get_num_mboards(); + _devs.push_back( { iface, block, _channels } ); + + if ( is_sink( mboard ) ) { + // sink block + for (size_t i = 0; i < iface->get_num_channels(); i++) { + _outer->connect( _outer->self(), _channels, block, i ); + _chandevs.push_back( mboard ); + _channels++; + } + } else { + // source block + for (size_t i = 0; i < iface->get_num_channels(); i++) { +#ifdef HAVE_IQBALANCE + // add iqbalance blocks if enabled + gr::iqbalance::optimize_c::sptr iq_opt = gr::iqbalance::optimize_c::make( 0 ); + gr::iqbalance::fix_cc::sptr iq_fix = gr::iqbalance::fix_cc::make(); + + connect( block, i, iq_fix, 0 ); + connect( block, i, iq_opt, 0 ); + msg_connect( iq_opt, "iqbal_corr", iq_fix, "iqbal_corr" ); + + _iq_opt.push_back( iq_opt.get() ); + _iq_fix.push_back( iq_fix.get() ); + + _outer->connect( iq_fix, 0, _outer->self(), _channels ); + #else + _outer->connect( block, i, _outer->self(), _channels ); + #endif + _chandevs.push_back( mboard ); + _channels++; + } + } +} + +size_t dev_manager::get_num_mboards() const +{ + return _devs.size(); +} + +size_t dev_manager::get_mboard_for_channel( size_t chan ) const +{ + return _chandevs.at(chan); +} + +bool dev_manager::is_sink( size_t mboard ) const +{ + return get_block(mboard)->input_signature()->max_streams() > 0; +} + +gr::basic_block_sptr dev_manager::get_block( size_t mboard ) const +{ + return _devs.at(mboard).block; +} + +common_iface * dev_manager::get_iface( size_t mboard ) const +{ + return _devs.at(mboard).dev; +} + +size_t dev_manager::get_mboard_channel( size_t mboard ) const +{ + return _devs.at(mboard).chan; +} + +void dev_manager::msg_handler_command( pmt::pmt_t msg ) +{ + if ( !pmt::is_dict(msg) ) { + GR_LOG_ERROR( d_logger, boost::format("Command message is neither dict nor pair: %s") % msg ); + return; + } + + // if pair, this throws and converts to dict + try { + pmt::pmt_t keys = pmt::dict_keys(msg); + } catch ( const pmt::wrong_type & ) { + GR_LOG_DEBUG( d_debug_logger, boost::format("Converting pair to dict: %s") % msg ); + msg = pmt::dict_add( pmt::make_dict(), pmt::car(msg), pmt::cdr(msg) ); + } + + // read chan. defaults to -1, all chans at once + int chan; + try { + chan = int(pmt::to_long( + pmt::dict_ref( + msg, osmosdr::CMD_CHAN_KEY, + pmt::from_long(-1) + ) + )); + } catch ( const pmt::wrong_type & ) { + GR_LOG_ALERT( d_logger, boost::format("Invalid channel number %s") % pmt::dict_ref( msg, osmosdr::CMD_CHAN_KEY ) ); + return; + } + + // rate applies to all channels + pmt::pmt_t rate = pmt::dict_ref( msg, osmosdr::CMD_RATE_KEY, pmt::PMT_NIL ); + if ( rate != pmt::PMT_NIL ) { + if ( !pmt::is_real(rate) && !pmt::is_integer(rate) ) { + GR_LOG_ALERT( d_logger, boost::format("Invalid type for sample rate %s") % rate ); + return; + } + set_sample_rate( pmt::to_double(rate) ); + msg = pmt::dict_delete( msg, osmosdr::CMD_RATE_KEY ); + } + + // extract commands + pmt::pmt_t msg_items = pmt::dict_items(msg); + + // check every device + for (size_t mboard = 0; mboard < get_num_mboards(); mboard++) { + int cur_chan = get_mboard_channel( mboard ); + int next_chan = cur_chan + get_iface( mboard )->get_num_channels(); + if ( chan != -1 && chan >= next_chan ) + continue; + + // if device accepts command messages, just pass it along + gr::basic_block_sptr block = get_block( mboard ); + if ( block->has_msg_port(osmosdr::CMD_PORT) ) { + if ( chan != -1 ) + block->_post( osmosdr::CMD_PORT, pmt::dict_add(msg, osmosdr::CMD_CHAN_KEY, pmt::from_long(chan - cur_chan)) ); + else + block->_post( osmosdr::CMD_PORT, msg ); + continue; + } + + int start_chan, end_chan; + if ( chan == -1 ) { + start_chan = cur_chan; + end_chan = next_chan; + } else { + start_chan = chan; + end_chan = chan + 1; + } + + for (int it_chan = start_chan; it_chan < end_chan; ++ it_chan){ + // execute every command + + for (size_t i = 0; i < pmt::length(msg_items); ++ i){ + pmt::pmt_t const & item = pmt::nth(i, msg_items); + try { + exec_msg_cmd( pmt::car(item), pmt::cdr(item), it_chan ); + } catch (const pmt::wrong_type &) { + try { + GR_LOG_ALERT( d_logger, boost::format("Invalid command value for key %s: %s") % pmt::car(item) % pmt::cdr(item) ); + } catch (const pmt::wrong_type &) { + GR_LOG_ALERT( d_logger, boost::format("Command is not a pair: %s") % item ); + } + return; + } + } + } + } +} + +void dev_manager::exec_msg_cmd( const pmt::pmt_t & cmd, const pmt::pmt_t & val, size_t chan ) +{ + if ( cmd == osmosdr::CMD_FREQ_KEY ) { + set_center_freq( pmt::to_double(val), chan ); + } else if ( cmd == osmosdr::CMD_GAIN_KEY ) { + set_gain( pmt::to_double(val), chan ); + } else if ( cmd == osmosdr::CMD_RATE_KEY ) { + // already set in msg_handler_command + ; + } else if ( cmd == osmosdr::CMD_ANTENNA_KEY ) { + set_antenna( pmt::symbol_to_string(val), chan ); + } else if ( cmd == osmosdr::CMD_BANDWIDTH_KEY ) { + set_bandwidth( pmt::to_double(val), chan ); + } + // unfamiliar commands are ignored +} + +size_t dev_manager::get_num_channels() +{ + return _channels; +} + +bool dev_manager::seek( long seek_point, int whence, size_t chan ) +{ + if ( chan > get_num_channels() ) + return false; + + size_t mboard = get_mboard_for_channel( chan ); + if ( is_sink( mboard ) ) + return false; + + size_t dev_chan = chan - get_mboard_channel( mboard ); + source_iface * dev = static_cast< source_iface * >( get_iface( mboard ) ); + + return dev->seek( seek_point, whence, dev_chan ); +} + +#define NO_DEVICES_MSG "FATAL: No device(s) available to work with." + +osmosdr::meta_range_t dev_manager::get_sample_rates() +{ + if ( get_num_mboards() ) + return get_iface(0)->get_sample_rates(); // assume same devices used in the group +#if 0 + else + throw std::runtime_error(NO_DEVICES_MSG); +#endif + return osmosdr::meta_range_t(); +} + +double dev_manager::set_sample_rate( double rate ) +{ + double sample_rate = 0; + + if (_sample_rate != rate) { +#if 0 + if (!get_num_mboards()) + throw std::runtime_error(NO_DEVICES_MSG); +#endif + for (size_t mboard = 0; mboard < get_num_mboards(); mboard++) { + common_iface *dev = get_iface( mboard ); + sample_rate = dev->set_sample_rate(rate); + if ( !is_sink( mboard ) ) { +#ifdef HAVE_IQBALANCE + // source block, update iqbalance if enabled + size_t channel = get_mboard_channel( mboard ); + size_t end = channel + dev->get_num_channels(); + for (; channel < end; channel++) { + if ( channel < _iq_opt.size() ) { + gr::iqbalance::optimize_c *opt = _iq_opt[channel]; + + if ( opt->period() > 0 ) { /* optimize is enabled */ + opt->set_period( dev->get_sample_rate() / 5 ); + opt_reset(); + } + } + } +#endif + } + } + + _sample_rate = sample_rate; + } + + return sample_rate; +} + +double dev_manager::get_sample_rate() +{ + double sample_rate = 0; + + if (get_num_mboards()) + sample_rate = get_iface(0)->get_sample_rate(); // assume same devices used in the group +#if 0 + else + throw std::runtime_error(NO_DEVICES_MSG); +#endif + return sample_rate; +} + +osmosdr::freq_range_t dev_manager::get_freq_range( size_t chan ) +{ + if ( chan > get_num_channels() ) + return osmosdr::freq_range_t(); + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_freq_range( dev_chan ); +} + +double dev_manager::set_center_freq( double freq, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _center_freq[ chan ] != freq ) { + _center_freq[ chan ] = freq; + return dev->set_center_freq( freq, dev_chan ); + } else { return _center_freq[ chan ]; } +} + +double dev_manager::get_center_freq( size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_center_freq( dev_chan ); +} + +double dev_manager::set_freq_corr( double ppm, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _freq_corr[ chan ] != ppm ) { + _freq_corr[ chan ] = ppm; + return dev->set_freq_corr( ppm, dev_chan ); + } else { return _freq_corr[ chan ]; } +} + +double dev_manager::get_freq_corr( size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_freq_corr( dev_chan ); +} + +std::vector<std::string> dev_manager::get_gain_names( size_t chan ) +{ + if ( chan > get_num_channels() ) + return std::vector< std::string >(); + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_gain_names( dev_chan ); +} + +osmosdr::gain_range_t dev_manager::get_gain_range( size_t chan ) +{ + if ( chan > get_num_channels() ) + return osmosdr::gain_range_t(); + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_gain_range( dev_chan ); +} + +osmosdr::gain_range_t dev_manager::get_gain_range( const std::string & name, size_t chan ) +{ + if ( chan > get_num_channels() ) + return osmosdr::gain_range_t(); + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_gain_range( name, dev_chan ); +} + +bool dev_manager::set_gain_mode( bool automatic, size_t chan ) +{ + if ( chan > get_num_channels() ) + return false; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _gain_mode[ chan ] != automatic ) { + _gain_mode[ chan ] = automatic; + bool mode = dev->set_gain_mode( automatic, dev_chan ); + if (!automatic) // reapply gain value when switched to manual mode + dev->set_gain( _gain[ chan ], dev_chan ); + return mode; + } else { return _gain_mode[ chan ]; } +} + +bool dev_manager::get_gain_mode( size_t chan ) +{ + if ( chan > get_num_channels() ) + return false; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_gain_mode( dev_chan ); +} + +double dev_manager::set_gain( double gain, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _gain[ chan ] != gain ) { + _gain[ chan ] = gain; + return dev->set_gain( gain, dev_chan ); + } else { return _gain[ chan ]; } +} + +double dev_manager::set_gain( double gain, const std::string & name, size_t chan) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->set_gain( gain, name, dev_chan ); +} + +double dev_manager::get_gain( size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_gain( dev_chan ); +} + +double dev_manager::get_gain( const std::string & name, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_gain( name, dev_chan ); +} + +double dev_manager::set_if_gain( double gain, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _if_gain[ chan ] != gain ) { + _if_gain[ chan ] = gain; + return dev->set_if_gain( gain, dev_chan ); + } else { return _if_gain[ chan ]; } +} + +double dev_manager::set_bb_gain( double gain, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _bb_gain[ chan ] != gain ) { + _bb_gain[ chan ] = gain; + return dev->set_bb_gain( gain, dev_chan ); + } else { return _bb_gain[ chan ]; } +} + +std::vector< std::string > dev_manager::get_antennas( size_t chan ) +{ + if ( chan > get_num_channels() ) + return std::vector< std::string >(); + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_antennas( dev_chan ); +} + +std::string dev_manager::set_antenna( const std::string & antenna, size_t chan ) +{ + if ( chan > get_num_channels() ) + return ""; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _antenna[ chan ] != antenna ) { + _antenna[ chan ] = antenna; + return dev->set_antenna( antenna, dev_chan ); + } else { return _antenna[ chan ]; } +} + +std::string dev_manager::get_antenna( size_t chan ) +{ + if ( chan > get_num_channels() ) + return ""; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_antenna( dev_chan ); +} + +void dev_manager::set_dc_offset_mode( int mode, size_t chan ) +{ + if ( chan > get_num_channels() ) + return; + + size_t mboard = get_mboard_for_channel( chan ); + if ( is_sink( mboard ) ) + return; + + size_t dev_chan = chan - get_mboard_channel( mboard ); + source_iface * dev = static_cast< source_iface * >( get_iface( mboard ) ); + + dev->set_dc_offset_mode( mode, dev_chan ); +} + +void dev_manager::set_dc_offset( const std::complex<double> &offset, size_t chan ) +{ + if ( chan > get_num_channels() ) + return; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + dev->set_dc_offset( offset, dev_chan ); +} + +void dev_manager::set_iq_balance_mode( int mode, size_t chan ) +{ + if ( chan > get_num_channels() ) + return; + + size_t mboard = get_mboard_for_channel( chan ); + if ( is_sink( mboard ) ) + return; + + size_t dev_chan = chan - get_mboard_channel( mboard ); + source_iface * dev = static_cast< source_iface * >( get_iface( mboard ) ); + +#ifdef HAVE_IQBALANCE + if ( chan < _iq_opt.size() && chan < _iq_fix.size() ) { + gr::iqbalance::optimize_c *opt = _iq_opt[chan]; + gr::iqbalance::fix_cc *fix = _iq_fix[chan]; + + if ( IQBalanceOff == mode ) { + opt->set_period( 0 ); + /* store current values in order to be able to restore them later */ + _vals[ chan ] = std::pair< float, float >( fix->mag(), fix->phase() ); + fix->set_mag( 0.0f ); + fix->set_phase( 0.0f ); + } else if ( IQBalanceManual == mode ) { + if ( opt->period() == 0 ) { /* transition from Off to Manual */ + /* restore previous values */ + std::pair< float, float > val = _vals[ chan ]; + fix->set_mag( val.first ); + fix->set_phase( val.second ); + } + opt->set_period( 0 ); + } else if ( IQBalanceAutomatic == mode ) { + opt->set_period( dev->get_sample_rate() / 5 ); + opt->reset(); + } + } +#else + return dev->set_iq_balance_mode( mode, dev_chan ); +#endif + +} + +void dev_manager::set_iq_balance( const std::complex<double> &balance, size_t chan ) +{ + if ( chan > get_num_channels() ) + return; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + +#ifdef HAVE_IQBALANCE + if ( ! is_sink( mboard ) ) { + // source block, update iqbalance if enabled + if ( chan < _iq_opt.size() && chan < _iq_fix.size() ) { + gr::iqbalance::optimize_c *opt = _iq_opt[chan]; + gr::iqbalance::fix_cc *fix = _iq_fix[chan]; + + if ( opt->period() == 0 ) { /* automatic optimization desabled */ + fix->set_mag( balance.real() ); + fix->set_phase( balance.imag() ); + } + } + } else { + dev->set_iq_balance( balance, dev_chan ); + } +#else + dev->set_iq_balance( balance, dev_chan ); +#endif +} + +double dev_manager::set_bandwidth( double bandwidth, size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + if ( _bandwidth[ chan ] != bandwidth || 0.0f == bandwidth ) { + _bandwidth[ chan ] = bandwidth; + return dev->set_bandwidth( bandwidth, dev_chan ); + } else { return _bandwidth[ chan ]; } +} + +double dev_manager::get_bandwidth( size_t chan ) +{ + if ( chan > get_num_channels() ) + return 0; + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_bandwidth( dev_chan ); +} + +osmosdr::freq_range_t dev_manager::get_bandwidth_range( size_t chan ) +{ + if ( chan > get_num_channels() ) + return osmosdr::freq_range_t(); + + size_t mboard = get_mboard_for_channel( chan ); + common_iface *dev = get_iface( mboard ); + size_t dev_chan = chan - get_mboard_channel( mboard ); + + return dev->get_bandwidth_range( dev_chan ); +} + +void dev_manager::set_time_source( const std::string &source, const size_t mboard ) +{ + if ( mboard != osmosdr::ALL_MBOARDS ) { + get_iface( mboard )->set_time_source( source ); + return; + } + + for (size_t m = 0; m < get_num_mboards(); m++) { /* propagate ALL_MBOARDS */ + get_iface(m)->set_time_source( source, osmosdr::ALL_MBOARDS ); + } +} + +std::string dev_manager::get_time_source( const size_t mboard ) +{ + return get_iface( mboard )->get_time_source( mboard ); +} + +std::vector<std::string> dev_manager::get_time_sources( const size_t mboard ) +{ + return get_iface( mboard )->get_time_sources( mboard ); +} + +void dev_manager::set_clock_source( const std::string &source, const size_t mboard ) +{ + if (mboard != osmosdr::ALL_MBOARDS){ + get_iface( mboard )->set_clock_source( source ); + return; + } + + for (size_t m = 0; m < get_num_mboards(); m++){ /* propagate ALL_MBOARDS */ + get_iface(m)->set_clock_source( source, osmosdr::ALL_MBOARDS ); + } +} + +std::string dev_manager::get_clock_source( const size_t mboard ) +{ + return get_iface( mboard )->get_clock_source( mboard ); +} + +std::vector<std::string> dev_manager::get_clock_sources( const size_t mboard ) +{ + return get_iface( mboard )->get_clock_sources( mboard ); +} + +double dev_manager::get_clock_rate( size_t mboard ) +{ + return get_iface( mboard )->get_clock_rate( mboard ); +} + +void dev_manager::set_clock_rate( double rate, size_t mboard ) +{ + if ( mboard != osmosdr::ALL_MBOARDS ) { + get_iface( mboard )->set_clock_rate( rate ); + return; + } + + for (size_t m = 0; m < get_num_mboards(); m++) { /* propagate ALL_MBOARDS */ + get_iface(m)->set_clock_rate( rate, osmosdr::ALL_MBOARDS ); + } +} + +osmosdr::time_spec_t dev_manager::get_time_now( size_t mboard ) +{ + return get_iface( mboard )->get_time_now( mboard ); +} + +osmosdr::time_spec_t dev_manager::get_time_last_pps( size_t mboard ) +{ + return get_iface( mboard )->get_time_last_pps( mboard ); +} + +void dev_manager::set_time_now( const osmosdr::time_spec_t &time_spec, size_t mboard ) +{ + if ( mboard != osmosdr::ALL_MBOARDS ) { + get_iface( mboard )->set_time_now( time_spec ); + return; + } + + for (size_t m = 0; m < get_num_mboards(); m++) { /* propagate ALL_MBOARDS */ + get_iface(m)->set_time_now( time_spec, osmosdr::ALL_MBOARDS ); + } +} + +void dev_manager::set_time_next_pps( const osmosdr::time_spec_t &time_spec ) +{ + for (size_t i = 0; i < get_num_mboards(); i++) { + get_iface(i)->set_time_next_pps( time_spec ); + } +} + +void dev_manager::set_time_unknown_pps( const osmosdr::time_spec_t &time_spec ) +{ + for (size_t i = 0; i < get_num_mboards(); i++) { + get_iface(i)->set_time_unknown_pps( time_spec ); + } +} diff --git a/lib/dev_manager.h b/lib/dev_manager.h new file mode 100644 index 0000000..416573f --- /dev/null +++ b/lib/dev_manager.h @@ -0,0 +1,176 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 Karl Semich <0xloem at gmail.com> + * + * 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. + */ + +#ifndef INCLUDED_DEV_CONTROL_H +#define INCLUDED_DEV_CONTROL_H + +#include <gnuradio/hier_block2.h> +#include <gnuradio/block.h> + +#include <osmosdr/messages.h> + +#include "common_iface.h" + +class dev_manager; + +/* + * We use boost::shared_ptr's instead of raw pointers for all access + * to gr::blocks (and many other data structures). The shared_ptr gets + * us transparent reference counting, which greatly simplifies storage + * management issues. This is especially helpful in our hybrid + * C++ / Python system. + * + * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm + * + * As a convention, the _sptr suffix indicates a boost::shared_ptr + */ +typedef boost::shared_ptr<dev_manager> dev_manager_sptr; + +/*! + * \brief Return a shared_ptr to a new instance of dev_manager. + * + * To avoid accidental use of raw pointers, dev_manager's + * constructor is private. make_dev_manager is the public + * interface for creating new instances. + */ +dev_manager_sptr make_dev_manager ( gr::hier_block2_sptr outer ); + +/*! + * \brief Manages a set of osmosdr devices. + * \ingroup block + * + */ +class dev_manager : public gr::block +{ +private: + // The friend declaration allows make_dev_manager to + // access the private constructor. + + friend dev_manager_sptr make_dev_manager ( gr::hier_block2_sptr outer ); + + /*! + * \brief Manages a set of osmosdr devices. + */ + dev_manager ( gr::hier_block2_sptr outer ); // private constructor + +public: + int general_work( int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items ); + + void add_device( gr::basic_block_sptr block, common_iface *iface ); // add a device driver block to be managed + size_t get_num_mboards() const; + size_t get_mboard_for_channel( size_t chan ) const; + bool is_sink( size_t mboard = 0 ) const; + gr::basic_block_sptr get_block( size_t mboard ) const; + common_iface * get_iface( size_t mboard ) const; + size_t get_mboard_channel( size_t mboard ) const; + + size_t get_num_channels(); + + bool seek( long seek_point, int whence, size_t chan); + + 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 ); + double set_center_freq( double freq, size_t chan ); + double get_center_freq( size_t chan ); + double set_freq_corr( double ppm, size_t chan ); + double get_freq_corr( size_t chan ); + + std::vector<std::string> get_gain_names( size_t chan ); + osmosdr::gain_range_t get_gain_range( size_t chan ); + osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan ); + bool set_gain_mode( bool automatic, size_t chan ); + bool get_gain_mode( size_t chan ); + double set_gain( double gain, size_t chan ); + double set_gain( double gain, const std::string & name, size_t chan ); + double get_gain( size_t chan ); + double get_gain( const std::string & name, size_t chan ); + + double set_if_gain( double gain, size_t chan ); + double set_bb_gain( double gain, size_t chan ); + + std::vector< std::string > get_antennas( size_t chan ); + std::string set_antenna( const std::string & antenna, size_t chan ); + std::string get_antenna( size_t chan ); + + void set_dc_offset_mode( int mode, size_t chan ); + void set_dc_offset( const std::complex<double> &offset, size_t chan ); + + void set_iq_balance_mode( int mode, size_t chan ); + void set_iq_balance( const std::complex<double> &balance, size_t chan ); + + double set_bandwidth( double bandwidth, size_t chan ); + double get_bandwidth( size_t chan ); + osmosdr::freq_range_t get_bandwidth_range( size_t chan ); + + void set_time_source(const std::string &source, const size_t mboard = 0); + std::string get_time_source(const size_t mboard); + std::vector<std::string> get_time_sources(const size_t mboard); + void set_clock_source(const std::string &source, const size_t mboard = 0); + std::string get_clock_source(const size_t mboard); + std::vector<std::string> get_clock_sources(const size_t mboard); + double get_clock_rate(size_t mboard = 0); + void set_clock_rate(double rate, size_t mboard = 0); + ::osmosdr::time_spec_t get_time_now(size_t mboard = 0); + ::osmosdr::time_spec_t get_time_last_pps(size_t mboard = 0); + void set_time_now(const ::osmosdr::time_spec_t &time_spec, size_t mboard = 0); + void set_time_next_pps(const ::osmosdr::time_spec_t &time_spec); + void set_time_unknown_pps(const ::osmosdr::time_spec_t &time_spec); + +private: + void msg_handler_command(pmt::pmt_t msg); + void exec_msg_cmd(const pmt::pmt_t &cmd, const pmt::pmt_t &val, size_t chan); + + struct dev_t { + common_iface * dev; + gr::basic_block_sptr block; + size_t chan; + }; + + std::vector< dev_t > _devs; + std::vector< size_t > _chandevs; + gr::hier_block2_sptr _outer; + size_t _channels; + + /* cache to prevent multiple device calls with the same value coming from grc */ + double _sample_rate; + std::map< size_t, double > _center_freq; + std::map< size_t, double > _freq_corr; + std::map< size_t, bool > _gain_mode; + std::map< size_t, double > _gain; + std::map< size_t, double > _if_gain; + std::map< size_t, double > _bb_gain; + std::map< size_t, std::string > _antenna; +#ifdef HAVE_IQBALANCE + std::vector< gr::iqbalance::fix_cc * > _iq_fix; + std::vector< gr::iqbalance::optimize_c * > _iq_opt; + std::map< size_t, std::pair<float, float> > _vals; +#endif + std::map< size_t, double > _bandwidth; +}; + +#endif /* INCLUDED_DEV_CONTROL_H */ diff --git a/lib/sink_iface.h b/lib/sink_iface.h index 39aabc7..f28e88b 100644 --- a/lib/sink_iface.h +++ b/lib/sink_iface.h @@ -25,344 +25,14 @@ #include <osmosdr/time_spec.h> #include <gnuradio/basic_block.h> +#include "common_iface.h" + /*! * TODO: document * */ -class sink_iface +class sink_iface : public common_iface { -public: - /*! - * Get the number of channels the underlying radio hardware offers. - * \return the number of available channels - */ - virtual size_t get_num_channels( void ) = 0; - - /*! - * Get the possible sample rates for the underlying radio hardware. - * \return a range of rates in Sps - */ - virtual osmosdr::meta_range_t get_sample_rates( void ) = 0; - - /*! - * Set the sample rate for the underlying radio hardware. - * This also will select the appropriate IF bandpass, if applicable. - * \param rate a new rate in Sps - */ - virtual double set_sample_rate( double rate ) = 0; - - /*! - * Get the sample rate for the underlying radio hardware. - * This is the actual sample rate and may differ from the rate set. - * \return the actual rate in Sps - */ - virtual double get_sample_rate( void ) = 0; - - /*! - * Get the tunable frequency range for the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the frequency range in Hz - */ - virtual osmosdr::freq_range_t get_freq_range( size_t chan = 0 ) = 0; - - /*! - * Tune the underlying radio hardware to the desired center frequency. - * This also will select the appropriate RF bandpass. - * \param freq the desired frequency in Hz - * \param chan the channel index 0 to N-1 - * \return the actual frequency in Hz - */ - virtual double set_center_freq( double freq, size_t chan = 0 ) = 0; - - /*! - * Get the center frequency the underlying radio hardware is tuned to. - * This is the actual frequency and may differ from the frequency set. - * \param chan the channel index 0 to N-1 - * \return the frequency in Hz - */ - virtual double get_center_freq( size_t chan = 0 ) = 0; - - /*! - * Set the frequency correction value in parts per million. - * \param ppm the desired correction value in parts per million - * \param chan the channel index 0 to N-1 - * \return correction value in parts per million - */ - virtual double set_freq_corr( double ppm, size_t chan = 0 ) = 0; - - /*! - * Get the frequency correction value. - * \param chan the channel index 0 to N-1 - * \return correction value in parts per million - */ - virtual double get_freq_corr( size_t chan = 0 ) = 0; - - /*! - * Get the gain stage names of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return a vector of strings containing the names of gain stages - */ - virtual std::vector<std::string> get_gain_names( size_t chan = 0 ) = 0; - - /*! - * Get the settable overall gain range for the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual osmosdr::gain_range_t get_gain_range( size_t chan = 0 ) = 0; - - /*! - * Get the settable gain range for a specific gain stage. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual osmosdr::gain_range_t get_gain_range( const std::string & name, - size_t chan = 0 ) = 0; - - /*! - * Set the gain mode for the underlying radio hardware. - * This might be supported only for certain hardware types. - * \param automatic the gain mode (true means automatic gain mode) - * \param chan the channel index 0 to N-1 - * \return the actual gain mode - */ - virtual bool set_gain_mode( bool automatic, size_t chan = 0 ) { return false; } - - /*! - * Get the gain mode selected for the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the actual gain mode (true means automatic gain mode) - */ - virtual bool get_gain_mode( size_t chan = 0 ) { return false; } - - /*! - * Set the gain for the underlying radio hardware. - * This function will automatically distribute the desired gain value over - * available gain stages in an appropriate way and return the actual value. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_gain( double gain, size_t chan = 0 ) = 0; - - /*! - * Set the named gain on the underlying radio hardware. - * \param gain the gain in dB - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_gain( double gain, - const std::string & name, - size_t chan = 0 ) = 0; - - /*! - * Get the actual gain setting of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain( size_t chan = 0 ) = 0; - - /*! - * Get the actual gain setting of a named stage. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain( const std::string & name, size_t chan = 0 ) = 0; - - /*! - * Set the IF gain for the underlying radio hardware. - * This function will automatically distribute the desired gain value over - * available IF gain stages in an appropriate way and return the actual value. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_if_gain( double gain, size_t chan = 0 ) { return 0; } - - /*! - * Set the BB gain for the underlying radio hardware. - * This function will automatically distribute the desired gain value over - * available BB gain stages in an appropriate way and return the actual value. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_bb_gain( double gain, size_t chan = 0 ) { return 0; } - - /*! - * Get the available antennas of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return a vector of strings containing the names of available antennas - */ - virtual std::vector< std::string > get_antennas( size_t chan = 0 ) = 0; - - /*! - * Select the active antenna of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the actual antenna's name - */ - virtual std::string set_antenna( const std::string & antenna, - size_t chan = 0 ) = 0; - - /*! - * Get the actual underlying radio hardware antenna setting. - * \param chan the channel index 0 to N-1 - * \return the actual antenna's name - */ - virtual std::string get_antenna( size_t chan = 0 ) = 0; - - /*! - * Set the TX frontend DC offset value. - * The value is complex to control both I and Q. - * - * \param offset the dc offset (1.0 is full-scale) - * \param chan the channel index 0 to N-1 - */ - virtual void set_dc_offset( const std::complex<double> &offset, size_t chan = 0 ) { } - - /*! - * Set the TX frontend IQ balance correction. - * Use this to adjust the magnitude and phase of I and Q. - * - * \param balance the complex correction value - * \param chan the channel index 0 to N-1 - */ - virtual void set_iq_balance( const std::complex<double> &balance, size_t chan = 0 ) { } - - /*! - * Set the bandpass filter on the radio frontend. - * \param bandwidth the filter bandwidth in Hz, set to 0 for automatic selection - * \param chan the channel index 0 to N-1 - * \return the actual filter bandwidth in Hz - */ - virtual double set_bandwidth( double bandwidth, size_t chan = 0 ) { return 0; } - - /*! - * Get the actual bandpass filter setting on the radio frontend. - * \param chan the channel index 0 to N-1 - * \return the actual filter bandwidth in Hz - */ - virtual double get_bandwidth( size_t chan = 0 ) { return 0; } - - /*! - * Get the possible bandpass filter settings on the radio frontend. - * \param chan the channel index 0 to N-1 - * \return a range of bandwidths in Hz - */ - virtual osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 ) - { return osmosdr::freq_range_t(); } - - /*! - * Set the time source for the device. - * This sets the method of time synchronization, - * typically a pulse per second or an encoded time. - * Typical options for source: external, MIMO. - * \param source a string representing the time source - * \param mboard which motherboard to set the config - */ - virtual void set_time_source(const std::string &source, - const size_t mboard = 0) { } - - /*! - * Get the currently set time source. - * \param mboard which motherboard to get the config - * \return the string representing the time source - */ - virtual std::string get_time_source(const size_t mboard) { return ""; } - - /*! - * Get a list of possible time sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_time_sources(const size_t mboard) - { - return std::vector<std::string>(); - } - - /*! - * Set the clock source for the device. - * This sets the source for a 10 Mhz reference clock. - * Typical options for source: internal, external, MIMO. - * \param source a string representing the clock source - * \param mboard which motherboard to set the config - */ - virtual void set_clock_source(const std::string &source, - const size_t mboard = 0) { } - - /*! - * Get the currently set clock source. - * \param mboard which motherboard to get the config - * \return the string representing the clock source - */ - virtual std::string get_clock_source(const size_t mboard) { return ""; } - - /*! - * Get a list of possible clock sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_clock_sources(const size_t mboard) - { - return std::vector<std::string>(); - } - - /*! - * Get the master clock rate. - * \param mboard the motherboard index 0 to M-1 - * \return the clock rate in Hz - */ - virtual double get_clock_rate(size_t mboard = 0) { return 0; } - - /*! - * Set the master clock rate. - * \param rate the new rate in Hz - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_clock_rate(double rate, size_t mboard = 0) { } - - /*! - * Get the current time registers. - * \param mboard the motherboard index 0 to M-1 - * \return the current device time - */ - virtual ::osmosdr::time_spec_t get_time_now(size_t mboard = 0) - { - return ::osmosdr::time_spec_t::get_system_time(); - } - - /*! - * Get the time when the last pps pulse occured. - * \param mboard the motherboard index 0 to M-1 - * \return the current device time - */ - virtual ::osmosdr::time_spec_t get_time_last_pps(size_t mboard = 0) - { - return ::osmosdr::time_spec_t::get_system_time(); - } - - /*! - * Sets the time registers immediately. - * \param time_spec the new time - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_time_now(const ::osmosdr::time_spec_t &time_spec, - size_t mboard = 0) { } - - /*! - * Set the time registers at the next pps. - * \param time_spec the new time - */ - virtual void set_time_next_pps(const ::osmosdr::time_spec_t &time_spec) { } - - /*! - * Sync the time registers with an unknown pps edge. - * \param time_spec the new time - */ - virtual void set_time_unknown_pps(const ::osmosdr::time_spec_t &time_spec) { } }; #endif // OSMOSDR_SINK_IFACE_H diff --git a/lib/sink_impl.cc b/lib/sink_impl.cc index 877b31f..1218425 100644 --- a/lib/sink_impl.cc +++ b/lib/sink_impl.cc @@ -72,11 +72,14 @@ sink_impl::sink_impl( const std::string &args ) : gr::hier_block2 ("sink_impl", args_to_io_signature(args), gr::io_signature::make(0, 0, 0)), - _sample_rate(NAN) + _manager(make_dev_manager(to_hier_block2())) { size_t channel = 0; bool device_specified = false; + message_port_register_hier_in( osmosdr::CMD_PORT ); + msg_connect( self(), osmosdr::CMD_PORT, _manager, osmosdr::CMD_PORT ); + std::vector< std::string > arg_list = args_to_vector(args); std::vector< std::string > dev_types; @@ -216,465 +219,214 @@ sink_impl::sink_impl( const std::string &args ) } #endif - if ( iface != NULL && long(block.get()) != 0 ) { - _devs.push_back( iface ); - - for (size_t i = 0; i < iface->get_num_channels(); i++) { - connect(self(), channel++, block, i); - } - } else if ( (iface != NULL) || (long(block.get()) != 0) ) - throw std::runtime_error("Either iface or block are NULL."); - + _manager->add_device( block, iface ); } - if (!_devs.size()) + if (!_manager->get_num_mboards()) throw std::runtime_error("No devices specified via device arguments."); } size_t sink_impl::get_num_channels() { - size_t channels = 0; - - BOOST_FOREACH( sink_iface *dev, _devs ) - channels += dev->get_num_channels(); - - return channels; + return _manager->get_num_channels(); } -#define NO_DEVICES_MSG "FATAL: No device(s) available to work with." - osmosdr::meta_range_t sink_impl::get_sample_rates() { - if ( ! _devs.empty() ) - return _devs[0]->get_sample_rates(); // assume same devices used in the group -#if 0 - else - throw std::runtime_error(NO_DEVICES_MSG); -#endif - return osmosdr::meta_range_t(); + return _manager->get_sample_rates(); } -double sink_impl::set_sample_rate(double rate) +double sink_impl::set_sample_rate( double rate ) { - double sample_rate = 0; - - if (_sample_rate != rate) { -#if 0 - if (_devs.empty()) - throw std::runtime_error(NO_DEVICES_MSG); -#endif - BOOST_FOREACH( sink_iface *dev, _devs ) - sample_rate = dev->set_sample_rate(rate); - - _sample_rate = sample_rate; - } - - return sample_rate; + return _manager->set_sample_rate( rate ); } double sink_impl::get_sample_rate() { - double sample_rate = 0; - - if (!_devs.empty()) - sample_rate = _devs[0]->get_sample_rate(); // assume same devices used in the group -#if 0 - else - throw std::runtime_error(NO_DEVICES_MSG); -#endif - return sample_rate; + return _manager->get_sample_rate(); } osmosdr::freq_range_t sink_impl::get_freq_range( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_freq_range( dev_chan ); - - return osmosdr::freq_range_t(); + return _manager->get_freq_range( chan ); } double sink_impl::set_center_freq( double freq, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _center_freq[ chan ] != freq ) { - _center_freq[ chan ] = freq; - return dev->set_center_freq( freq, dev_chan ); - } else { return _center_freq[ chan ]; } - } - - return 0; + return _manager->set_center_freq( freq, chan ); } double sink_impl::get_center_freq( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_center_freq( dev_chan ); - - return 0; + return _manager->get_center_freq( chan ); } double sink_impl::set_freq_corr( double ppm, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _freq_corr[ chan ] != ppm ) { - _freq_corr[ chan ] = ppm; - return dev->set_freq_corr( ppm, dev_chan ); - } else { return _freq_corr[ chan ]; } - } - - return 0; + return _manager->set_freq_corr( ppm, chan ); } double sink_impl::get_freq_corr( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_freq_corr( dev_chan ); - - return 0; + return _manager->get_freq_corr( chan ); } std::vector<std::string> sink_impl::get_gain_names( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_names( dev_chan ); - - return std::vector< std::string >(); + return _manager->get_gain_names( chan ); } osmosdr::gain_range_t sink_impl::get_gain_range( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_range( dev_chan ); - - return osmosdr::gain_range_t(); + return _manager->get_gain_range( chan ); } osmosdr::gain_range_t sink_impl::get_gain_range( const std::string & name, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_range( name, dev_chan ); - - return osmosdr::gain_range_t(); + return _manager->get_gain_range( name, chan ); } bool sink_impl::set_gain_mode( bool automatic, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _gain_mode[ chan ] != automatic ) { - _gain_mode[ chan ] = automatic; - bool mode = dev->set_gain_mode( automatic, dev_chan ); - if (!automatic) // reapply gain value when switched to manual mode - dev->set_gain( _gain[ chan ], dev_chan ); - return mode; - } else { return _gain_mode[ chan ]; } - } - - return false; + return _manager->set_gain_mode( automatic, chan ); } bool sink_impl::get_gain_mode( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_mode( dev_chan ); - - return false; + return _manager->get_gain_mode( chan ); } double sink_impl::set_gain( double gain, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _gain[ chan ] != gain ) { - _gain[ chan ] = gain; - return dev->set_gain( gain, dev_chan ); - } else { return _gain[ chan ]; } - } - - return 0; + return _manager->set_gain( gain, chan ); } double sink_impl::set_gain( double gain, const std::string & name, size_t chan) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->set_gain( gain, name, dev_chan ); - - return 0; + return _manager->set_gain( gain, name, chan ); } double sink_impl::get_gain( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain( dev_chan ); - - return 0; + return _manager->get_gain( chan ); } double sink_impl::get_gain( const std::string & name, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain( name, dev_chan ); - - return 0; + return _manager->get_gain( name, chan ); } double sink_impl::set_if_gain( double gain, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _if_gain[ chan ] != gain ) { - _if_gain[ chan ] = gain; - return dev->set_if_gain( gain, dev_chan ); - } else { return _if_gain[ chan ]; } - } - - return 0; + return _manager->set_if_gain( gain, chan ); } double sink_impl::set_bb_gain( double gain, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _bb_gain[ chan ] != gain ) { - _bb_gain[ chan ] = gain; - return dev->set_bb_gain( gain, dev_chan ); - } else { return _bb_gain[ chan ]; } - } - - return 0; + return _manager->set_bb_gain( gain, chan ); } std::vector< std::string > sink_impl::get_antennas( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_antennas( dev_chan ); - - return std::vector< std::string >(); + return _manager->get_antennas( chan ); } std::string sink_impl::set_antenna( const std::string & antenna, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _antenna[ chan ] != antenna ) { - _antenna[ chan ] = antenna; - return dev->set_antenna( antenna, dev_chan ); - } else { return _antenna[ chan ]; } - } - - return ""; + return _manager->set_antenna( antenna, chan ); } std::string sink_impl::get_antenna( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_antenna( dev_chan ); - - return ""; + return _manager->get_antenna( chan ); } void sink_impl::set_dc_offset( const std::complex<double> &offset, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - dev->set_dc_offset( offset, dev_chan ); + _manager->set_dc_offset( offset, chan ); } void sink_impl::set_iq_balance( const std::complex<double> &balance, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - dev->set_iq_balance( balance, dev_chan ); + _manager->set_iq_balance( balance, chan ); } double sink_impl::set_bandwidth( double bandwidth, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _bandwidth[ chan ] != bandwidth || 0.0f == bandwidth ) { - _bandwidth[ chan ] = bandwidth; - return dev->set_bandwidth( bandwidth, dev_chan ); - } else { return _bandwidth[ chan ]; } - } - - return 0; + return _manager->set_bandwidth( bandwidth, chan ); } double sink_impl::get_bandwidth( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_bandwidth( dev_chan ); - - return 0; + return _manager->get_bandwidth( chan ); } osmosdr::freq_range_t sink_impl::get_bandwidth_range( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( sink_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_bandwidth_range( dev_chan ); - - return osmosdr::freq_range_t(); + return _manager->get_bandwidth_range( chan ); } -void sink_impl::set_time_source(const std::string &source, const size_t mboard) +void sink_impl::set_time_source( const std::string &source, const size_t mboard ) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_time_source( source ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_time_source( source, osmosdr::ALL_MBOARDS ); - } + return _manager->set_time_source( source, mboard ); } -std::string sink_impl::get_time_source(const size_t mboard) +std::string sink_impl::get_time_source( const size_t mboard ) { - return _devs.at(mboard)->get_time_source( mboard ); + return _manager->get_time_source( mboard ); } -std::vector<std::string> sink_impl::get_time_sources(const size_t mboard) +std::vector<std::string> sink_impl::get_time_sources( const size_t mboard ) { - return _devs.at(mboard)->get_time_sources( mboard ); + return _manager->get_time_sources( mboard ); } -void sink_impl::set_clock_source(const std::string &source, const size_t mboard) +void sink_impl::set_clock_source( const std::string &source, const size_t mboard ) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_clock_source( source ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_clock_source( source, osmosdr::ALL_MBOARDS ); - } + return _manager->set_clock_source( source, mboard ); } -std::string sink_impl::get_clock_source(const size_t mboard) +std::string sink_impl::get_clock_source( const size_t mboard ) { - return _devs.at(mboard)->get_clock_source( mboard ); + return _manager->get_clock_source( mboard ); } -std::vector<std::string> sink_impl::get_clock_sources(const size_t mboard) +std::vector<std::string> sink_impl::get_clock_sources( const size_t mboard ) { - return _devs.at(mboard)->get_clock_sources( mboard ); + return _manager->get_clock_sources( mboard ); } -double sink_impl::get_clock_rate(size_t mboard) +double sink_impl::get_clock_rate( size_t mboard ) { - return _devs.at(mboard)->get_clock_rate( mboard ); + return _manager->get_clock_rate( mboard ); } -void sink_impl::set_clock_rate(double rate, size_t mboard) +void sink_impl::set_clock_rate( double rate, size_t mboard ) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_clock_rate( rate ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_clock_rate( rate, osmosdr::ALL_MBOARDS ); - } + return _manager->set_clock_rate( rate, mboard ); } -osmosdr::time_spec_t sink_impl::get_time_now(size_t mboard) +osmosdr::time_spec_t sink_impl::get_time_now( size_t mboard ) { - return _devs.at(mboard)->get_time_now( mboard ); + return _manager->get_time_now( mboard ); } -osmosdr::time_spec_t sink_impl::get_time_last_pps(size_t mboard) +osmosdr::time_spec_t sink_impl::get_time_last_pps( size_t mboard ) { - return _devs.at(mboard)->get_time_last_pps( mboard ); + return _manager->get_time_last_pps( mboard ); } -void sink_impl::set_time_now(const osmosdr::time_spec_t &time_spec, size_t mboard) +void sink_impl::set_time_now( const osmosdr::time_spec_t &time_spec, size_t mboard ) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_time_now( time_spec ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_time_now( time_spec, osmosdr::ALL_MBOARDS ); - } + return _manager->set_time_now( time_spec, mboard ); } -void sink_impl::set_time_next_pps(const osmosdr::time_spec_t &time_spec) +void sink_impl::set_time_next_pps( const osmosdr::time_spec_t &time_spec ) { - BOOST_FOREACH( sink_iface *dev, _devs ) - { - dev->set_time_next_pps( time_spec ); - } + return _manager->set_time_next_pps( time_spec ); } -void sink_impl::set_time_unknown_pps(const osmosdr::time_spec_t &time_spec) +void sink_impl::set_time_unknown_pps( const osmosdr::time_spec_t &time_spec ) { - BOOST_FOREACH( sink_iface *dev, _devs ) - { - dev->set_time_unknown_pps( time_spec ); - } + return _manager->set_time_unknown_pps( time_spec ); } diff --git a/lib/sink_impl.h b/lib/sink_impl.h index 1642669..a4589b5 100644 --- a/lib/sink_impl.h +++ b/lib/sink_impl.h @@ -22,7 +22,7 @@ #include "osmosdr/sink.h" -#include "sink_iface.h" +#include "dev_manager.h" #include <map> @@ -83,18 +83,7 @@ public: void set_time_unknown_pps(const ::osmosdr::time_spec_t &time_spec); private: - std::vector< sink_iface * > _devs; - - /* cache to prevent multiple device calls with the same value coming from grc */ - double _sample_rate; - std::map< size_t, double > _center_freq; - std::map< size_t, double > _freq_corr; - std::map< size_t, bool > _gain_mode; - std::map< size_t, double > _gain; - std::map< size_t, double > _if_gain; - std::map< size_t, double > _bb_gain; - std::map< size_t, std::string > _antenna; - std::map< size_t, double > _bandwidth; + dev_manager_sptr _manager; }; #endif /* INCLUDED_OSMOSDR_SINK_IMPL_H */ diff --git a/lib/source_iface.h b/lib/source_iface.h index abb70eb..ff0149f 100644 --- a/lib/source_iface.h +++ b/lib/source_iface.h @@ -25,20 +25,16 @@ #include <osmosdr/time_spec.h> #include <gnuradio/basic_block.h> +#include "common_iface.h" + /*! * TODO: document * */ -class source_iface +class source_iface : public common_iface { public: /*! - * Get the number of channels the underlying radio hardware offers. - * \return the number of available channels - */ - virtual size_t get_num_channels( void ) = 0; - - /*! * \brief seek file to \p seek_point relative to \p whence * * \param seek_point sample offset in file @@ -48,182 +44,6 @@ public: virtual bool seek( long seek_point, int whence, size_t chan = 0 ) { return false; } /*! - * Get the possible sample rates for the underlying radio hardware. - * \return a range of rates in Sps - */ - virtual osmosdr::meta_range_t get_sample_rates( void ) = 0; - - /*! - * Set the sample rate for the underlying radio hardware. - * This also will select the appropriate IF bandpass, if applicable. - * \param rate a new rate in Sps - */ - virtual double set_sample_rate( double rate ) = 0; - - /*! - * Get the sample rate for the underlying radio hardware. - * This is the actual sample rate and may differ from the rate set. - * \return the actual rate in Sps - */ - virtual double get_sample_rate( void ) = 0; - - /*! - * Get the tunable frequency range for the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the frequency range in Hz - */ - virtual osmosdr::freq_range_t get_freq_range( size_t chan = 0 ) = 0; - - /*! - * Tune the underlying radio hardware to the desired center frequency. - * This also will select the appropriate RF bandpass. - * \param freq the desired frequency in Hz - * \param chan the channel index 0 to N-1 - * \return the actual frequency in Hz - */ - virtual double set_center_freq( double freq, size_t chan = 0 ) = 0; - - /*! - * Get the center frequency the underlying radio hardware is tuned to. - * This is the actual frequency and may differ from the frequency set. - * \param chan the channel index 0 to N-1 - * \return the frequency in Hz - */ - virtual double get_center_freq( size_t chan = 0 ) = 0; - - /*! - * Set the frequency correction value in parts per million. - * \param ppm the desired correction value in parts per million - * \param chan the channel index 0 to N-1 - * \return correction value in parts per million - */ - virtual double set_freq_corr( double ppm, size_t chan = 0 ) = 0; - - /*! - * Get the frequency correction value. - * \param chan the channel index 0 to N-1 - * \return correction value in parts per million - */ - virtual double get_freq_corr( size_t chan = 0 ) = 0; - - /*! - * Get the gain stage names of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return a vector of strings containing the names of gain stages - */ - virtual std::vector<std::string> get_gain_names( size_t chan = 0 ) = 0; - - /*! - * Get the settable overall gain range for the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual osmosdr::gain_range_t get_gain_range( size_t chan = 0 ) = 0; - - /*! - * Get the settable gain range for a specific gain stage. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the gain range in dB - */ - virtual osmosdr::gain_range_t get_gain_range( const std::string & name, - size_t chan = 0 ) = 0; - - /*! - * Set the gain mode for the underlying radio hardware. - * This might be supported only for certain hardware types. - * \param automatic the gain mode (true means automatic gain mode) - * \param chan the channel index 0 to N-1 - * \return the actual gain mode - */ - virtual bool set_gain_mode( bool automatic, size_t chan = 0 ) { return false; } - - /*! - * Get the gain mode selected for the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the actual gain mode (true means automatic gain mode) - */ - virtual bool get_gain_mode( size_t chan = 0 ) { return false; } - - /*! - * Set the gain for the underlying radio hardware. - * This function will automatically distribute the desired gain value over - * available gain stages in an appropriate way and return the actual value. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_gain( double gain, size_t chan = 0 ) = 0; - - /*! - * Set the named gain on the underlying radio hardware. - * \param gain the gain in dB - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_gain( double gain, - const std::string & name, - size_t chan = 0 ) = 0; - - /*! - * Get the actual gain setting of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain( size_t chan = 0 ) = 0; - - /*! - * Get the actual gain setting of a named stage. - * \param name the name of the gain stage - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double get_gain( const std::string & name, size_t chan = 0 ) = 0; - - /*! - * Set the IF gain for the underlying radio hardware. - * This function will automatically distribute the desired gain value over - * available IF gain stages in an appropriate way and return the actual value. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_if_gain( double gain, size_t chan = 0 ) { return 0; } - - /*! - * Set the BB gain for the underlying radio hardware. - * This function will automatically distribute the desired gain value over - * available BB gain stages in an appropriate way and return the actual value. - * \param gain the gain in dB - * \param chan the channel index 0 to N-1 - * \return the actual gain in dB - */ - virtual double set_bb_gain( double gain, size_t chan = 0 ) { return 0; } - - /*! - * Get the available antennas of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return a vector of strings containing the names of available antennas - */ - virtual std::vector< std::string > get_antennas( size_t chan = 0 ) = 0; - - /*! - * Select the active antenna of the underlying radio hardware. - * \param chan the channel index 0 to N-1 - * \return the actual antenna's name - */ - virtual std::string set_antenna( const std::string & antenna, - size_t chan = 0 ) = 0; - - /*! - * Get the actual underlying radio hardware antenna setting. - * \param chan the channel index 0 to N-1 - * \return the actual antenna's name - */ - virtual std::string get_antenna( size_t chan = 0 ) = 0; - - /*! * Set the RX frontend DC correction mode. * The automatic correction subtracts out the long-run average. * @@ -238,163 +58,12 @@ public: virtual void set_dc_offset_mode( int mode, size_t chan = 0 ) { } /*! - * Set a constant DC offset value. - * The value is complex to control both I and Q. - * Only set this when automatic correction is disabled. - * - * \param offset the dc offset (1.0 is full-scale) - * \param chan the channel index 0 to N-1 - */ - virtual void set_dc_offset( const std::complex<double> &offset, size_t chan = 0 ) { } - - /*! * Set the RX frontend IQ balance mode. * * \param mode iq balance correction mode: 0 = Off, 1 = Manual, 2 = Automatic * \param chan the channel index 0 to N-1 */ virtual void set_iq_balance_mode( int mode, size_t chan = 0 ) { } - - /*! - * Set the RX frontend IQ balance correction. - * Use this to adjust the magnitude and phase of I and Q. - * - * \param balance the complex correction value - * \param chan the channel index 0 to N-1 - */ - virtual void set_iq_balance( const std::complex<double> &balance, size_t chan = 0 ) { } - - /*! - * Set the bandpass filter on the radio frontend. - * \param bandwidth the filter bandwidth in Hz, set to 0 for automatic selection - * \param chan the channel index 0 to N-1 - * \return the actual filter bandwidth in Hz - */ - virtual double set_bandwidth( double bandwidth, size_t chan = 0 ) { return 0; } - - /*! - * Get the actual bandpass filter setting on the radio frontend. - * \param chan the channel index 0 to N-1 - * \return the actual filter bandwidth in Hz - */ - virtual double get_bandwidth( size_t chan = 0 ) { return 0; } - - /*! - * Get the possible bandpass filter settings on the radio frontend. - * \param chan the channel index 0 to N-1 - * \return a range of bandwidths in Hz - */ - virtual osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 ) - { return osmosdr::freq_range_t(); } - - /*! - * Set the time source for the device. - * This sets the method of time synchronization, - * typically a pulse per second or an encoded time. - * Typical options for source: external, MIMO. - * \param source a string representing the time source - * \param mboard which motherboard to set the config - */ - virtual void set_time_source(const std::string &source, - const size_t mboard = 0) { } - - /*! - * Get the currently set time source. - * \param mboard which motherboard to get the config - * \return the string representing the time source - */ - virtual std::string get_time_source(const size_t mboard) { return ""; } - - /*! - * Get a list of possible time sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_time_sources(const size_t mboard) - { - return std::vector<std::string>(); - } - - /*! - * Set the clock source for the device. - * This sets the source for a 10 Mhz reference clock. - * Typical options for source: internal, external, MIMO. - * \param source a string representing the clock source - * \param mboard which motherboard to set the config - */ - virtual void set_clock_source(const std::string &source, - const size_t mboard = 0) { } - - /*! - * Get the currently set clock source. - * \param mboard which motherboard to get the config - * \return the string representing the clock source - */ - virtual std::string get_clock_source(const size_t mboard) { return ""; } - - /*! - * Get a list of possible clock sources. - * \param mboard which motherboard to get the list - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_clock_sources(const size_t mboard) - { - return std::vector<std::string>(); - } - - /*! - * Get the master clock rate. - * \param mboard the motherboard index 0 to M-1 - * \return the clock rate in Hz - */ - virtual double get_clock_rate(size_t mboard = 0) { return 0; } - - /*! - * Set the master clock rate. - * \param rate the new rate in Hz - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_clock_rate(double rate, size_t mboard = 0) { } - - /*! - * Get the current time registers. - * \param mboard the motherboard index 0 to M-1 - * \return the current device time - */ - virtual ::osmosdr::time_spec_t get_time_now(size_t mboard = 0) - { - return ::osmosdr::time_spec_t::get_system_time(); - } - - /*! - * Get the time when the last pps pulse occured. - * \param mboard the motherboard index 0 to M-1 - * \return the current device time - */ - virtual ::osmosdr::time_spec_t get_time_last_pps(size_t mboard = 0) - { - return ::osmosdr::time_spec_t::get_system_time(); - } - - /*! - * Sets the time registers immediately. - * \param time_spec the new time - * \param mboard the motherboard index 0 to M-1 - */ - virtual void set_time_now(const ::osmosdr::time_spec_t &time_spec, - size_t mboard = 0) { } - - /*! - * Set the time registers at the next pps. - * \param time_spec the new time - */ - virtual void set_time_next_pps(const ::osmosdr::time_spec_t &time_spec) { } - - /*! - * Sync the time registers with an unknown pps edge. - * \param time_spec the new time - */ - virtual void set_time_unknown_pps(const ::osmosdr::time_spec_t &time_spec) { } }; #endif // OSMOSDR_SOURCE_IFACE_H diff --git a/lib/source_impl.cc b/lib/source_impl.cc index a8a3cec..f30e773 100644 --- a/lib/source_impl.cc +++ b/lib/source_impl.cc @@ -112,11 +112,14 @@ source_impl::source_impl( const std::string &args ) : gr::hier_block2 ("source_impl", gr::io_signature::make(0, 0, 0), args_to_io_signature(args)), - _sample_rate(NAN) + _manager(make_dev_manager(to_hier_block2())) { size_t channel = 0; bool device_specified = false; + message_port_register_hier_in( osmosdr::CMD_PORT ); + msg_connect( self(), osmosdr::CMD_PORT, _manager, osmosdr::CMD_PORT ); + std::vector< std::string > arg_list = args_to_vector(args); std::vector< std::string > dev_types; @@ -376,576 +379,229 @@ source_impl::source_impl( const std::string &args ) } #endif - if ( iface != NULL && long(block.get()) != 0 ) { - _devs.push_back( iface ); - - for (size_t i = 0; i < iface->get_num_channels(); i++) { -#ifdef HAVE_IQBALANCE - gr::iqbalance::optimize_c::sptr iq_opt = gr::iqbalance::optimize_c::make( 0 ); - gr::iqbalance::fix_cc::sptr iq_fix = gr::iqbalance::fix_cc::make(); - - connect(block, i, iq_fix, 0); - connect(iq_fix, 0, self(), channel++); - - connect(block, i, iq_opt, 0); - msg_connect(iq_opt, "iqbal_corr", iq_fix, "iqbal_corr"); - - _iq_opt.push_back( iq_opt.get() ); - _iq_fix.push_back( iq_fix.get() ); -#else - connect(block, i, self(), channel++); -#endif - } - } else if ( (iface != NULL) || (long(block.get()) != 0) ) - throw std::runtime_error("Either iface or block are NULL."); - + _manager->add_device( block, iface ); } - if (!_devs.size()) + if (!_manager->get_num_mboards()) throw std::runtime_error("No devices specified via device arguments."); } size_t source_impl::get_num_channels() { - size_t channels = 0; - - BOOST_FOREACH( source_iface *dev, _devs ) - channels += dev->get_num_channels(); - - return channels; + return _manager->get_num_channels(); } bool source_impl::seek( long seek_point, int whence, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->seek( seek_point, whence, dev_chan ); - - return false; + return _manager->seek( seek_point, whence, chan ); } -#define NO_DEVICES_MSG "FATAL: No device(s) available to work with." - osmosdr::meta_range_t source_impl::get_sample_rates() { - if ( ! _devs.empty() ) - return _devs[0]->get_sample_rates(); // assume same devices used in the group -#if 0 - else - throw std::runtime_error(NO_DEVICES_MSG); -#endif - return osmosdr::meta_range_t();; + return _manager->get_sample_rates(); } -double source_impl::set_sample_rate(double rate) +double source_impl::set_sample_rate( double rate ) { - double sample_rate = 0; - - if (_sample_rate != rate) { -#if 0 - if (_devs.empty()) - throw std::runtime_error(NO_DEVICES_MSG); -#endif - BOOST_FOREACH( source_iface *dev, _devs ) - sample_rate = dev->set_sample_rate(rate); - -#ifdef HAVE_IQBALANCE - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) { - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { - if ( channel < _iq_opt.size() ) { - gr::iqbalance::optimize_c *opt = _iq_opt[channel]; - - if ( opt->period() > 0 ) { /* optimize is enabled */ - opt->set_period( dev->get_sample_rate() / 5 ); - opt->reset(); - } - } - - channel++; - } - } -#endif - - _sample_rate = sample_rate; - } - - return sample_rate; + return _manager->set_sample_rate(rate); } double source_impl::get_sample_rate() { - double sample_rate = 0; - - if (!_devs.empty()) - sample_rate = _devs[0]->get_sample_rate(); // assume same devices used in the group -#if 0 - else - throw std::runtime_error(NO_DEVICES_MSG); -#endif - return sample_rate; + return _manager->get_sample_rate(); } osmosdr::freq_range_t source_impl::get_freq_range( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_freq_range( dev_chan ); - - return osmosdr::freq_range_t(); + return _manager->get_freq_range( chan ); } double source_impl::set_center_freq( double freq, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _center_freq[ chan ] != freq ) { - _center_freq[ chan ] = freq; - return dev->set_center_freq( freq, dev_chan ); - } else { return _center_freq[ chan ]; } - } - - return 0; + return _manager->set_center_freq( freq, chan ); } double source_impl::get_center_freq( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_center_freq( dev_chan ); - - return 0; + return _manager->get_center_freq( chan ); } double source_impl::set_freq_corr( double ppm, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _freq_corr[ chan ] != ppm ) { - _freq_corr[ chan ] = ppm; - return dev->set_freq_corr( ppm, dev_chan ); - } else { return _freq_corr[ chan ]; } - } - - return 0; + return _manager->set_freq_corr( ppm, chan ); } double source_impl::get_freq_corr( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_freq_corr( dev_chan ); - - return 0; + return _manager->get_freq_corr( chan ); } std::vector<std::string> source_impl::get_gain_names( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_names( dev_chan ); - - return std::vector< std::string >(); + return _manager->get_gain_names( chan ); } osmosdr::gain_range_t source_impl::get_gain_range( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_range( dev_chan ); - - return osmosdr::gain_range_t(); + return _manager->get_gain_range( chan ); } osmosdr::gain_range_t source_impl::get_gain_range( const std::string & name, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_range( name, dev_chan ); - - return osmosdr::gain_range_t(); + return _manager->get_gain_range( name, chan ); } bool source_impl::set_gain_mode( bool automatic, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _gain_mode[ chan ] != automatic ) { - _gain_mode[ chan ] = automatic; - bool mode = dev->set_gain_mode( automatic, dev_chan ); - if (!automatic) // reapply gain value when switched to manual mode - dev->set_gain( _gain[ chan ], dev_chan ); - return mode; - } else { return _gain_mode[ chan ]; } - } - - return false; + return _manager->set_gain_mode( automatic, chan ); } bool source_impl::get_gain_mode( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain_mode( dev_chan ); - - return false; + return _manager->get_gain_mode( chan ); } double source_impl::set_gain( double gain, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _gain[ chan ] != gain ) { - _gain[ chan ] = gain; - return dev->set_gain( gain, dev_chan ); - } else { return _gain[ chan ]; } - } - - return 0; + return _manager->set_gain( gain, chan ); } double source_impl::set_gain( double gain, const std::string & name, size_t chan) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->set_gain( gain, name, dev_chan ); - - return 0; + return _manager->set_gain( gain, name, chan ); } double source_impl::get_gain( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain( dev_chan ); - - return 0; + return _manager->get_gain( chan ); } double source_impl::get_gain( const std::string & name, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_gain( name, dev_chan ); - - return 0; + return _manager->get_gain( name, chan ); } double source_impl::set_if_gain( double gain, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _if_gain[ chan ] != gain ) { - _if_gain[ chan ] = gain; - return dev->set_if_gain( gain, dev_chan ); - } else { return _if_gain[ chan ]; } - } - - return 0; + return _manager->set_if_gain( gain, chan ); } double source_impl::set_bb_gain( double gain, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _bb_gain[ chan ] != gain ) { - _bb_gain[ chan ] = gain; - return dev->set_bb_gain( gain, dev_chan ); - } else { return _bb_gain[ chan ]; } - } - - return 0; + return _manager->set_bb_gain( gain, chan ); } std::vector< std::string > source_impl::get_antennas( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_antennas( dev_chan ); - - return std::vector< std::string >(); + return _manager->get_antennas( chan ); } std::string source_impl::set_antenna( const std::string & antenna, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _antenna[ chan ] != antenna ) { - _antenna[ chan ] = antenna; - return dev->set_antenna( antenna, dev_chan ); - } else { return _antenna[ chan ]; } - } - - return ""; + return _manager->set_antenna( antenna, chan ); } std::string source_impl::get_antenna( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_antenna( dev_chan ); - - return ""; + return _manager->get_antenna( chan ); } void source_impl::set_dc_offset_mode( int mode, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - dev->set_dc_offset_mode( mode, dev_chan ); + _manager->set_dc_offset_mode( mode, chan ); } void source_impl::set_dc_offset( const std::complex<double> &offset, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - dev->set_dc_offset( offset, dev_chan ); + _manager->set_dc_offset( offset, chan ); } void source_impl::set_iq_balance_mode( int mode, size_t chan ) { - size_t channel = 0; -#ifdef HAVE_IQBALANCE - BOOST_FOREACH( source_iface *dev, _devs ) { - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { - if ( chan == channel++ ) { - if ( chan < _iq_opt.size() && chan < _iq_fix.size() ) { - gr::iqbalance::optimize_c *opt = _iq_opt[chan]; - gr::iqbalance::fix_cc *fix = _iq_fix[chan]; - - if ( IQBalanceOff == mode ) { - opt->set_period( 0 ); - /* store current values in order to be able to restore them later */ - _vals[ chan ] = std::pair< float, float >( fix->mag(), fix->phase() ); - fix->set_mag( 0.0f ); - fix->set_phase( 0.0f ); - } else if ( IQBalanceManual == mode ) { - if ( opt->period() == 0 ) { /* transition from Off to Manual */ - /* restore previous values */ - std::pair< float, float > val = _vals[ chan ]; - fix->set_mag( val.first ); - fix->set_phase( val.second ); - } - opt->set_period( 0 ); - } else if ( IQBalanceAutomatic == mode ) { - opt->set_period( dev->get_sample_rate() / 5 ); - opt->reset(); - } - } - } - } - } -#else - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->set_iq_balance_mode( mode, dev_chan ); -#endif + _manager->set_iq_balance_mode( mode, chan ); } void source_impl::set_iq_balance( const std::complex<double> &balance, size_t chan ) { - size_t channel = 0; -#ifdef HAVE_IQBALANCE - BOOST_FOREACH( source_iface *dev, _devs ) { - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { - if ( chan == channel++ ) { - if ( chan < _iq_opt.size() && chan < _iq_fix.size() ) { - gr::iqbalance::optimize_c *opt = _iq_opt[chan]; - gr::iqbalance::fix_cc *fix = _iq_fix[chan]; - - if ( opt->period() == 0 ) { /* automatic optimization desabled */ - fix->set_mag( balance.real() ); - fix->set_phase( balance.imag() ); - } - } - } - } - } -#else - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->set_iq_balance( balance, dev_chan ); -#endif + _manager->set_iq_balance( balance, chan ); } double source_impl::set_bandwidth( double bandwidth, size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) { - if ( _bandwidth[ chan ] != bandwidth || 0.0f == bandwidth ) { - _bandwidth[ chan ] = bandwidth; - return dev->set_bandwidth( bandwidth, dev_chan ); - } else { return _bandwidth[ chan ]; } - } - - return 0; + return _manager->set_bandwidth( bandwidth, chan ); } double source_impl::get_bandwidth( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_bandwidth( dev_chan ); - - return 0; + return _manager->get_bandwidth( chan ); } osmosdr::freq_range_t source_impl::get_bandwidth_range( size_t chan ) { - size_t channel = 0; - BOOST_FOREACH( source_iface *dev, _devs ) - for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) - if ( chan == channel++ ) - return dev->get_bandwidth_range( dev_chan ); - - return osmosdr::freq_range_t(); + return _manager->get_bandwidth_range( chan ); } void source_impl::set_time_source(const std::string &source, const size_t mboard) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_time_source( source ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_time_source( source, osmosdr::ALL_MBOARDS ); - } + return _manager->set_time_source( source, mboard ); } std::string source_impl::get_time_source(const size_t mboard) { - return _devs.at(mboard)->get_time_source( mboard ); + return _manager->get_time_source( mboard ); } std::vector<std::string> source_impl::get_time_sources(const size_t mboard) { - return _devs.at(mboard)->get_time_sources( mboard ); + return _manager->get_time_sources( mboard ); } void source_impl::set_clock_source(const std::string &source, const size_t mboard) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_clock_source( source ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_clock_source( source, osmosdr::ALL_MBOARDS ); - } + return _manager->set_clock_source( source, mboard ); } std::string source_impl::get_clock_source(const size_t mboard) { - return _devs.at(mboard)->get_clock_source( mboard ); + return _manager->get_clock_source( mboard ); } std::vector<std::string> source_impl::get_clock_sources(const size_t mboard) { - return _devs.at(mboard)->get_clock_sources( mboard ); + return _manager->get_clock_sources( mboard ); } double source_impl::get_clock_rate(size_t mboard) { - return _devs.at(mboard)->get_clock_rate( mboard ); + return _manager->get_clock_rate( mboard ); } void source_impl::set_clock_rate(double rate, size_t mboard) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_clock_rate( rate ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_clock_rate( rate, osmosdr::ALL_MBOARDS ); - } + return _manager->set_clock_rate( rate, mboard ); } osmosdr::time_spec_t source_impl::get_time_now(size_t mboard) { - return _devs.at(mboard)->get_time_now( mboard ); + return _manager->get_time_now( mboard ); } osmosdr::time_spec_t source_impl::get_time_last_pps(size_t mboard) { - return _devs.at(mboard)->get_time_last_pps( mboard ); + return _manager->get_time_last_pps( mboard ); } void source_impl::set_time_now(const osmosdr::time_spec_t &time_spec, size_t mboard) { - if (mboard != osmosdr::ALL_MBOARDS){ - _devs.at(mboard)->set_time_now( time_spec ); - return; - } - - for (size_t m = 0; m < _devs.size(); m++){ /* propagate ALL_MBOARDS */ - _devs.at(m)->set_time_now( time_spec, osmosdr::ALL_MBOARDS ); - } + return _manager->set_time_now( time_spec, mboard ); } void source_impl::set_time_next_pps(const osmosdr::time_spec_t &time_spec) { - BOOST_FOREACH( source_iface *dev, _devs ) - { - dev->set_time_next_pps( time_spec ); - } + return _manager->set_time_next_pps( time_spec ); } void source_impl::set_time_unknown_pps(const osmosdr::time_spec_t &time_spec) { - BOOST_FOREACH( source_iface *dev, _devs ) - { - dev->set_time_unknown_pps( time_spec ); - } + return _manager->set_time_unknown_pps( time_spec ); } diff --git a/lib/source_impl.h b/lib/source_impl.h index 4b65125..238bc6c 100644 --- a/lib/source_impl.h +++ b/lib/source_impl.h @@ -27,7 +27,7 @@ #include <gnuradio/iqbalance/fix_cc.h> #endif -#include <source_iface.h> +#include "dev_manager.h" #include <map> @@ -92,23 +92,7 @@ public: void set_time_unknown_pps(const ::osmosdr::time_spec_t &time_spec); private: - std::vector< source_iface * > _devs; - - /* cache to prevent multiple device calls with the same value coming from grc */ - double _sample_rate; - std::map< size_t, double > _center_freq; - std::map< size_t, double > _freq_corr; - std::map< size_t, bool > _gain_mode; - std::map< size_t, double > _gain; - std::map< size_t, double > _if_gain; - std::map< size_t, double > _bb_gain; - std::map< size_t, std::string > _antenna; -#ifdef HAVE_IQBALANCE - std::vector< gr::iqbalance::fix_cc * > _iq_fix; - std::vector< gr::iqbalance::optimize_c * > _iq_opt; - std::map< size_t, std::pair<float, float> > _vals; -#endif - std::map< size_t, double > _bandwidth; + dev_manager_sptr _manager; }; #endif /* INCLUDED_OSMOSDR_SOURCE_IMPL_H */ diff --git a/lib/uhd/uhd_sink_c.cc b/lib/uhd/uhd_sink_c.cc index a154556..fdac2a6 100644 --- a/lib/uhd/uhd_sink_c.cc +++ b/lib/uhd/uhd_sink_c.cc @@ -24,6 +24,8 @@ //#include <uhd/property_tree.hpp> +#include <osmosdr/messages.h> + #include "arg_helpers.h" #include "uhd_sink_c.h" @@ -124,6 +126,9 @@ uhd_sink_c::uhd_sink_c(const std::string &args) : #endif for ( size_t i = 0; i < nchan; i++ ) connect( self(), i, _snk, i ); + + message_port_register_hier_in( osmosdr::CMD_PORT ); + msg_connect( self(), osmosdr::CMD_PORT, _snk, osmosdr::CMD_PORT ); } uhd_sink_c::~uhd_sink_c() diff --git a/lib/uhd/uhd_source_c.cc b/lib/uhd/uhd_source_c.cc index fc13017..98fd5f1 100644 --- a/lib/uhd/uhd_source_c.cc +++ b/lib/uhd/uhd_source_c.cc @@ -24,6 +24,8 @@ //#include <uhd/property_tree.hpp> +#include <osmosdr/messages.h> + #include "arg_helpers.h" #include "uhd_source_c.h" @@ -125,6 +127,9 @@ uhd_source_c::uhd_source_c(const std::string &args) : #endif for ( size_t i = 0; i < nchan; i++ ) connect( _src, i, self(), i ); + + message_port_register_hier_in( osmosdr::CMD_PORT ); + msg_connect( self(), osmosdr::CMD_PORT, _src, osmosdr::CMD_PORT ); } uhd_source_c::~uhd_source_c() -- 2.11.0