aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/multi_usrp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/multi_usrp.cpp')
-rw-r--r--host/lib/usrp/multi_usrp.cpp322
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;