aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/b200/b200_io_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/b200/b200_io_impl.cpp')
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp161
1 files changed, 132 insertions, 29 deletions
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index 1e11e7ff6..20807bdd4 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -21,8 +21,10 @@
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "async_packet_handler.hpp"
+#include <uhd/utils/math.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
+#include <boost/math/common_factor.hpp>
#include <set>
using namespace uhd;
@@ -34,30 +36,32 @@ using namespace uhd::transport;
**********************************************************************/
void b200_impl::check_tick_rate_with_current_streamers(double rate)
{
- size_t max_tx_chan_count = 0, max_rx_chan_count = 0;
+ // Defined in b200_impl.cpp
+ enforce_tick_rate_limits(max_chan_count("RX"), rate, "RX");
+ enforce_tick_rate_limits(max_chan_count("TX"), rate, "TX");
+}
+
+// direction can either be "TX", "RX", or empty (default)
+size_t b200_impl::max_chan_count(const std::string &direction /* = "" */)
+{
+ size_t max_count = 0;
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
- {
+ if ((direction == "RX" or direction.empty()) and not perif.rx_streamer.expired()) {
boost::shared_ptr<sph::recv_packet_streamer> rx_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (rx_streamer)
- max_rx_chan_count = std::max(max_rx_chan_count, rx_streamer->get_num_channels());
+ max_count = std::max(max_count, rx_streamer->get_num_channels());
}
-
- {
+ if ((direction == "TX" or direction.empty()) and not perif.tx_streamer.expired()) {
boost::shared_ptr<sph::send_packet_streamer> tx_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (tx_streamer)
- max_tx_chan_count = std::max(max_tx_chan_count, tx_streamer->get_num_channels());
+ max_count = std::max(max_count, tx_streamer->get_num_channels());
}
}
-
- // Defined in b200_impl.cpp
- enforce_tick_rate_limits(max_rx_chan_count, rate, "RX");
- enforce_tick_rate_limits(max_tx_chan_count, rate, "TX");
+ return max_count;
}
-void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/)
+void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction /*= ""*/)
{
std::set<size_t> chans_set;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
@@ -69,33 +73,115 @@ void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_
enforce_tick_rate_limits(chans_set.size(), tick_rate, direction); // Defined in b200_impl.cpp
}
-void b200_impl::update_tick_rate(const double rate)
+void b200_impl::set_auto_tick_rate(
+ const double rate,
+ const fs_path &tree_dsp_path,
+ size_t num_chans
+) {
+ if (num_chans == 0) { // Divine them
+ num_chans = std::max(size_t(1), max_chan_count());
+ }
+ const double max_tick_rate = ad9361_device_t::AD9361_MAX_CLOCK_RATE/num_chans;
+ if (rate != 0.0 and
+ (uhd::math::fp_compare::fp_compare_delta<double>(rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) >
+ uhd::math::fp_compare::fp_compare_delta<double>(max_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ))) {
+ throw uhd::value_error(str(
+ boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate of %.2f MHz.")
+ % (rate / 1e6) % (max_tick_rate / 1e6)
+ ));
+ }
+
+ // See also the doxygen documentation for these steps in b200_impl.hpp
+ // Step 1: Obtain LCM and max rate from all relevant dsps
+ boost::uint32_t lcm_rate = (rate == 0) ? 1 : static_cast<boost::uint32_t>(floor(rate + 0.5));
+ for (int i = 0; i < 2; i++) { // Loop through rx and tx
+ std::string dir = (i == 0) ? "tx" : "rx";
+ // We have no way of knowing which DSPs are used, so we check them all.
+ BOOST_FOREACH(const std::string &dsp_no, _tree->list(str(boost::format("/mboards/0/%s_dsps") % dir))) {
+ fs_path dsp_path = str(boost::format("/mboards/0/%s_dsps/%s") % dir % dsp_no);
+ if (dsp_path == tree_dsp_path) {
+ continue;
+ }
+ double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get();
+ // Check if the user selected something completely unreasonable:
+ if (uhd::math::fp_compare::fp_compare_delta<double>(this_dsp_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) >
+ uhd::math::fp_compare::fp_compare_delta<double>(max_tick_rate, uhd::math::FREQ_COMPARISON_DELTA_HZ)) {
+ throw uhd::value_error(str(
+ boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate of %.2f MHz.")
+ % (this_dsp_rate / 1e6) % (max_tick_rate / 1e6)
+ ));
+ }
+ // If this_dsp_rate == 0.0, the sampling rate for this DSP hasn't been set, so
+ // we don't take that into consideration.
+ if (this_dsp_rate == 0.0) {
+ continue;
+ }
+ lcm_rate = boost::math::lcm<boost::uint32_t>(
+ lcm_rate,
+ static_cast<boost::uint32_t>(floor(this_dsp_rate + 0.5))
+ );
+ }
+ }
+ if (lcm_rate == 1) {
+ // In this case, no one has ever set a sampling rate.
+ return;
+ }
+
+ double base_rate = static_cast<double>(lcm_rate);
+ try {
+ // Step 2: Get a good tick rate value
+ const double new_rate = _codec_mgr->get_auto_tick_rate(base_rate, num_chans);
+ // Step 3: Set the new tick rate value (if any change)
+ if (!uhd::math::frequencies_are_equal(_tree->access<double>("/mboards/0/tick_rate").get(), new_rate)) {
+ _tree->access<double>("/mboards/0/tick_rate").set(new_rate);
+ }
+ } catch (const uhd::value_error &e) {
+ UHD_MSG(warning)
+ << "Cannot automatically determine an appropriate tick rate for these sampling rates." << std::endl
+ << "Consider using different sampling rates, or manually specify a suitable master clock rate." << std::endl;
+ return; // Let the others handle this
+ }
+}
+
+void b200_impl::update_tick_rate(const double new_tick_rate)
{
- check_tick_rate_with_current_streamers(rate);
+ check_tick_rate_with_current_streamers(new_tick_rate);
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.framer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.framer->set_tick_rate(new_tick_rate);
}
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.deframer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.deframer->set_tick_rate(new_tick_rate);
}
}
-#define CHECK_BANDWIDTH(dir) \
- if (rate > _codec_ctrl->get_bw_filter_range(dir).stop()) { \
- UHD_MSG(warning) \
- << "Selected " << dir << " bandwidth (" << (rate/1e6) << " MHz) exceeds\n" \
- << "analog frontend filter bandwidth (" << (_codec_ctrl->get_bw_filter_range(dir).stop()/1e6) << " MHz)." \
- << std::endl; \
+#define CHECK_RATE_AND_THROW(rate) \
+ if (uhd::math::fp_compare::fp_compare_delta<double>(rate, uhd::math::FREQ_COMPARISON_DELTA_HZ) > \
+ uhd::math::fp_compare::fp_compare_delta<double>(ad9361_device_t::AD9361_MAX_CLOCK_RATE, uhd::math::FREQ_COMPARISON_DELTA_HZ)) { \
+ throw uhd::value_error(str( \
+ boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate.") \
+ % (rate / 1e6) \
+ )); \
+ }
+
+double b200_impl::coerce_rx_samp_rate(rx_dsp_core_3000::sptr ddc, size_t dspno, const double rx_rate)
+{
+ // Have to set tick rate first, or the ddc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ CHECK_RATE_AND_THROW(rx_rate);
+ const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(rx_rate, dsp_path);
}
+ return ddc->set_host_rate(rx_rate);
+}
void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
{
@@ -105,7 +191,18 @@ void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
my_streamer->set_samp_rate(rate);
const double adj = _radio_perifs[dspno].ddc->get_scaling_adjustment();
my_streamer->set_scale_factor(adj);
- CHECK_BANDWIDTH("Rx");
+ _codec_mgr->check_bandwidth(rate, "Rx");
+}
+
+double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno, const double tx_rate)
+{
+ // Have to set tick rate first, or the duc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ CHECK_RATE_AND_THROW(tx_rate);
+ const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(tx_rate, dsp_path);
+ }
+ return duc->set_host_rate(tx_rate);
}
void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)
@@ -116,7 +213,7 @@ void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)
my_streamer->set_samp_rate(rate);
const double adj = _radio_perifs[dspno].duc->get_scaling_adjustment();
my_streamer->set_scale_factor(adj);
- CHECK_BANDWIDTH("Tx");
+ _codec_mgr->check_bandwidth(rate, "Tx");
}
/***********************************************************************
@@ -276,6 +373,9 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::recv_packet_streamer> my_streamer;
@@ -383,7 +483,10 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- check_streamer_args(args, this->get_tick_rate(), "TX");
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
+ check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::send_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)