diff options
Diffstat (limited to 'host/lib/usrp/multi_usrp.cpp')
-rw-r--r-- | host/lib/usrp/multi_usrp.cpp | 322 |
1 files changed, 316 insertions, 6 deletions
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 794438b90..396237e24 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -26,10 +26,13 @@ #include <uhd/usrp/mboard_eeprom.hpp> #include <uhd/usrp/dboard_eeprom.hpp> #include <uhd/convert.hpp> +#include <uhd/utils/soft_register.hpp> #include <boost/assign/list_of.hpp> #include <boost/thread.hpp> #include <boost/foreach.hpp> #include <boost/format.hpp> +#include <boost/algorithm/string.hpp> +#include <algorithm> #include <cmath> using namespace uhd; @@ -69,7 +72,7 @@ static void do_samp_rate_warning_message( } } -static void do_tune_freq_results_message( +/*static void do_tune_freq_results_message( const tune_request_t &tune_req, const tune_result_t &tune_result, double actual_freq, @@ -171,7 +174,7 @@ static void do_tune_freq_results_message( UHD_MSG(warning) << results_string << std::endl; } -} +}*/ /*! The CORDIC can be used to shift the baseband below / past the tunable * limits of the actual RF front-end. The baseband filter, located on the @@ -309,7 +312,9 @@ static tune_result_t tune_xx_subdev_and_dsp( //------------------------------------------------------------------ //-- Tune the RF frontend //------------------------------------------------------------------ - rf_fe_subtree->access<double>("freq/value").set(target_rf_freq); + if (tune_request.rf_freq_policy != tune_request_t::POLICY_NONE) { + rf_fe_subtree->access<double>("freq/value").set(target_rf_freq); + } const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get(); //------------------------------------------------------------------ @@ -346,7 +351,9 @@ static tune_result_t tune_xx_subdev_and_dsp( //------------------------------------------------------------------ //-- Tune the DSP //------------------------------------------------------------------ - dsp_subtree->access<double>("freq/value").set(target_dsp_freq); + if (tune_request.dsp_freq_policy != tune_request_t::POLICY_NONE) { + dsp_subtree->access<double>("freq/value").set(target_dsp_freq); + } const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get(); //------------------------------------------------------------------ @@ -431,6 +438,9 @@ public: ******************************************************************/ void set_master_clock_rate(double rate, size_t mboard){ if (mboard != ALL_MBOARDS){ + if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) { + _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false); + } _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate); return; } @@ -800,7 +810,7 @@ public: _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan)), tune_request); - do_tune_freq_results_message(tune_request, result, get_rx_freq(chan), "RX"); + //do_tune_freq_results_message(tune_request, result, get_rx_freq(chan), "RX"); return result; } @@ -821,6 +831,26 @@ public: } void set_rx_gain(double gain, const std::string &name, size_t chan){ + /* Check if any AGC mode is enable and if so warn the user */ + if (chan != ALL_CHANS) { + if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc")) { + bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get(); + if(agc) { + UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl; + } + } + } else { + for (size_t c = 0; c < get_rx_num_channels(); c++){ + if (_tree->exists(rx_rf_fe_root(c) / "gain" / "agc")) { + bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get(); + if(agc) { + UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl; + } + } + } + } + /* Apply gain setting. + * If device is in AGC mode it will ignore the setting. */ try { return rx_gain_group(chan)->set_value(gain, name); } catch (uhd::key_error &) { @@ -828,6 +858,32 @@ public: } } + void set_normalized_rx_gain(double gain, size_t chan = 0) + { + if (gain > 1.0 || gain < 0.0) { + throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1]."); + } + gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan); + double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start(); + set_rx_gain(abs_gain, ALL_GAINS, chan); + } + + void set_rx_agc(bool enable, size_t chan = 0) + { + if (chan != ALL_CHANS){ + if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc" / "enable")) { + _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").set(enable); + } else { + UHD_MSG(warning) << "AGC is not available on this device." << std::endl; + } + return; + } + for (size_t c = 0; c < get_rx_num_channels(); c++){ + this->set_rx_agc(enable, c); + } + + } + double get_rx_gain(const std::string &name, size_t chan){ try { return rx_gain_group(chan)->get_value(name); @@ -836,6 +892,21 @@ public: } } + double get_normalized_rx_gain(size_t chan) + { + gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan); + double gain_range_width = gain_range.stop() - gain_range.start(); + // In case we have a device without a range of gains: + if (gain_range_width == 0.0) { + return 0; + } + double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width; + // Avoid rounding errors: + if (norm_gain > 1.0) return 1.0; + if (norm_gain < 0.0) return 0.0; + return norm_gain; + } + gain_range_t get_rx_gain_range(const std::string &name, size_t chan){ try { return rx_gain_group(chan)->get_range(name); @@ -888,6 +959,9 @@ public: if (chan != ALL_CHANS){ if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "enable")) { _tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb); + } else if (_tree->exists(rx_rf_fe_root(chan) / "dc_offset" / "enable")) { + /*For B2xx devices the dc-offset correction is implemented in the rf front-end*/ + _tree->access<bool>(rx_rf_fe_root(chan) / "dc_offset" / "enable").set(enb); } else { UHD_MSG(warning) << "Setting DC offset compensation is not possible on this device." << std::endl; } @@ -912,6 +986,20 @@ public: } } + void set_rx_iq_balance(const bool enb, size_t chan){ + if (chan != ALL_CHANS){ + if (_tree->exists(rx_rf_fe_root(chan) / "iq_balance" / "enable")) { + _tree->access<bool>(rx_rf_fe_root(chan) / "iq_balance" / "enable").set(enb); + } else { + UHD_MSG(warning) << "Setting IQ imbalance compensation is not possible on this device." << std::endl; + } + return; + } + for (size_t c = 0; c < get_rx_num_channels(); c++){ + this->set_rx_iq_balance(enb, c); + } + } + void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){ if (chan != ALL_CHANS){ if (_tree->exists(rx_fe_root(chan) / "iq_balance" / "value")) { @@ -926,6 +1014,87 @@ public: } } + std::vector<std::string> get_filter_names(const std::string &search_mask) + { + std::vector<std::string> ret; + + for (size_t chan = 0; chan < get_rx_num_channels(); chan++){ + + if (_tree->exists(rx_rf_fe_root(chan) / "filters")) { + std::vector<std::string> names = _tree->list(rx_rf_fe_root(chan) / "filters"); + for(size_t i = 0; i < names.size(); i++) + { + std::string name = rx_rf_fe_root(chan) / "filters" / names[i]; + if((search_mask.empty()) or boost::contains(name, search_mask)) { + ret.push_back(name); + } + } + } + if (_tree->exists(rx_dsp_root(chan) / "filters")) { + std::vector<std::string> names = _tree->list(rx_dsp_root(chan) / "filters"); + for(size_t i = 0; i < names.size(); i++) + { + std::string name = rx_dsp_root(chan) / "filters" / names[i]; + if((search_mask.empty()) or (boost::contains(name, search_mask))) { + ret.push_back(name); + } + } + } + + } + + for (size_t chan = 0; chan < get_tx_num_channels(); chan++){ + + if (_tree->exists(tx_rf_fe_root(chan) / "filters")) { + std::vector<std::string> names = _tree->list(tx_rf_fe_root(chan) / "filters"); + for(size_t i = 0; i < names.size(); i++) + { + std::string name = tx_rf_fe_root(chan) / "filters" / names[i]; + if((search_mask.empty()) or (boost::contains(name, search_mask))) { + ret.push_back(name); + } + } + } + if (_tree->exists(rx_dsp_root(chan) / "filters")) { + std::vector<std::string> names = _tree->list(tx_dsp_root(chan) / "filters"); + for(size_t i = 0; i < names.size(); i++) + { + std::string name = tx_dsp_root(chan) / "filters" / names[i]; + if((search_mask.empty()) or (boost::contains(name, search_mask))) { + ret.push_back(name); + } + } + } + + } + + return ret; + } + + filter_info_base::sptr get_filter(const std::string &path) + { + std::vector<std::string> possible_names = get_filter_names(""); + std::vector<std::string>::iterator it; + it = find(possible_names.begin(), possible_names.end(), path); + if (it == possible_names.end()) { + throw uhd::runtime_error("Attempting to get non-existing filter: "+path); + } + + return _tree->access<filter_info_base::sptr>(path / "value").get(); + } + + void set_filter(const std::string &path, filter_info_base::sptr filter) + { + std::vector<std::string> possible_names = get_filter_names(""); + std::vector<std::string>::iterator it; + it = find(possible_names.begin(), possible_names.end(), path); + if (it == possible_names.end()) { + throw uhd::runtime_error("Attempting to set non-existing filter: "+path); + } + + _tree->access<filter_info_base::sptr>(path / "value").set(filter); + } + /******************************************************************* * TX methods ******************************************************************/ @@ -1001,7 +1170,7 @@ public: _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan)), tune_request); - do_tune_freq_results_message(tune_request, result, get_tx_freq(chan), "TX"); + //do_tune_freq_results_message(tune_request, result, get_tx_freq(chan), "TX"); return result; } @@ -1029,6 +1198,17 @@ public: } } + void set_normalized_tx_gain(double gain, size_t chan = 0) + { + if (gain > 1.0 || gain < 0.0) { + throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1]."); + } + gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan); + double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start(); + set_tx_gain(abs_gain, ALL_GAINS, chan); + } + + double get_tx_gain(const std::string &name, size_t chan){ try { return tx_gain_group(chan)->get_value(name); @@ -1037,6 +1217,21 @@ public: } } + double get_normalized_tx_gain(size_t chan) + { + gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan); + double gain_range_width = gain_range.stop() - gain_range.start(); + // In case we have a device without a range of gains: + if (gain_range_width == 0.0) { + return 0.0; + } + double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width; + // Avoid rounding errors: + if (norm_gain > 1.0) return 1.0; + if (norm_gain < 0.0) return 0.0; + return norm_gain; + } + gain_range_t get_tx_gain_range(const std::string &name, size_t chan){ try { return tx_gain_group(chan)->get_range(name); @@ -1181,6 +1376,121 @@ public: return 0; } + void write_register(const std::string &path, const boost::uint32_t field, const boost::uint64_t value, const size_t mboard) + { + if (_tree->exists(mb_root(mboard) / "registers")) + { + uhd::soft_regmap_accessor_t::sptr accessor = + _tree->access<uhd::soft_regmap_accessor_t::sptr>(mb_root(mboard) / "registers").get(); + uhd::soft_register_base& reg = accessor->lookup(path); + + if (not reg.is_writable()) { + throw uhd::runtime_error("multi_usrp::write_register - register not writable: " + path); + } + + switch (reg.get_bitwidth()) { + case 16: + if (reg.is_readable()) + uhd::soft_register_base::cast<uhd::soft_reg16_rw_t>(reg).write(field, static_cast<boost::uint16_t>(value)); + else + uhd::soft_register_base::cast<uhd::soft_reg16_wo_t>(reg).write(field, static_cast<boost::uint16_t>(value)); + break; + + case 32: + if (reg.is_readable()) + uhd::soft_register_base::cast<uhd::soft_reg32_rw_t>(reg).write(field, static_cast<boost::uint32_t>(value)); + else + uhd::soft_register_base::cast<uhd::soft_reg32_wo_t>(reg).write(field, static_cast<boost::uint32_t>(value)); + break; + + case 64: + if (reg.is_readable()) + uhd::soft_register_base::cast<uhd::soft_reg64_rw_t>(reg).write(field, value); + else + uhd::soft_register_base::cast<uhd::soft_reg64_wo_t>(reg).write(field, value); + break; + + default: + throw uhd::assertion_error("multi_usrp::write_register - register has invalid bitwidth"); + } + + } else { + throw uhd::not_implemented_error("multi_usrp::write_register - register IO not supported for this device"); + } + } + + boost::uint64_t read_register(const std::string &path, const boost::uint32_t field, const size_t mboard) + { + if (_tree->exists(mb_root(mboard) / "registers")) + { + uhd::soft_regmap_accessor_t::sptr accessor = + _tree->access<uhd::soft_regmap_accessor_t::sptr>(mb_root(mboard) / "registers").get(); + uhd::soft_register_base& reg = accessor->lookup(path); + + if (not reg.is_readable()) { + throw uhd::runtime_error("multi_usrp::read_register - register not readable: " + path); + } + + switch (reg.get_bitwidth()) { + case 16: + if (reg.is_writable()) + return static_cast<boost::uint64_t>(uhd::soft_register_base::cast<uhd::soft_reg16_rw_t>(reg).read(field)); + else + return static_cast<boost::uint64_t>(uhd::soft_register_base::cast<uhd::soft_reg16_ro_t>(reg).read(field)); + break; + + case 32: + if (reg.is_writable()) + return static_cast<boost::uint64_t>(uhd::soft_register_base::cast<uhd::soft_reg32_rw_t>(reg).read(field)); + else + return static_cast<boost::uint64_t>(uhd::soft_register_base::cast<uhd::soft_reg32_ro_t>(reg).read(field)); + break; + + case 64: + if (reg.is_writable()) + return uhd::soft_register_base::cast<uhd::soft_reg64_rw_t>(reg).read(field); + else + return uhd::soft_register_base::cast<uhd::soft_reg64_ro_t>(reg).read(field); + break; + + default: + throw uhd::assertion_error("multi_usrp::read_register - register has invalid bitwidth: " + path); + } + } else { + throw uhd::not_implemented_error("multi_usrp::read_register - register IO not supported for this device"); + } + } + + std::vector<std::string> enumerate_registers(const size_t mboard) + { + if (_tree->exists(mb_root(mboard) / "registers")) + { + uhd::soft_regmap_accessor_t::sptr accessor = + _tree->access<uhd::soft_regmap_accessor_t::sptr>(mb_root(mboard) / "registers").get(); + return accessor->enumerate(); + } else { + return std::vector<std::string>(); + } + } + + register_info_t get_register_info(const std::string &path, const size_t mboard = 0) + { + if (_tree->exists(mb_root(mboard) / "registers")) + { + uhd::soft_regmap_accessor_t::sptr accessor = + _tree->access<uhd::soft_regmap_accessor_t::sptr>(mb_root(mboard) / "registers").get(); + uhd::soft_register_base& reg = accessor->lookup(path); + + register_info_t info; + info.bitwidth = reg.get_bitwidth(); + info.readable = reg.is_readable(); + info.writable = reg.is_writable(); + return info; + } else { + throw uhd::not_implemented_error("multi_usrp::read_register - register IO not supported for this device"); + } + } + private: device::sptr _dev; property_tree::sptr _tree; |