From: Karl Semich <0xloem(a)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(a)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(a)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(a)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(a)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