summaryrefslogtreecommitdiff
path: root/gr-uhd/lib/usrp_sink_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd/lib/usrp_sink_impl.cc')
-rw-r--r--gr-uhd/lib/usrp_sink_impl.cc237
1 files changed, 131 insertions, 106 deletions
diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc
index b6a98391be..cdbe7b58f4 100644
--- a/gr-uhd/lib/usrp_sink_impl.cc
+++ b/gr-uhd/lib/usrp_sink_impl.cc
@@ -25,11 +25,12 @@
#include "usrp_sink_impl.h"
#include "gr_uhd_common.h"
#include <gnuradio/io_signature.h>
-#include <boost/make_shared.hpp>
namespace gr {
namespace uhd {
+ static const size_t ALL_CHANS = ::uhd::usrp::multi_usrp::ALL_CHANS;
+
usrp_sink::sptr
usrp_sink::make(const ::uhd::device_addr_t &device_addr,
const ::uhd::io_type_t &io_type,
@@ -66,36 +67,63 @@ namespace gr {
: sync_block("gr uhd usrp sink",
args_to_io_sig(stream_args),
io_signature::make(0, 0, 0)),
- _stream_args(stream_args),
- _nchan(stream_args.channels.size()),
- _stream_now(_nchan == 1 and length_tag_name.empty()),
- _start_time_set(false),
+ usrp_common_impl(device_addr, stream_args, length_tag_name),
_length_tag_key(length_tag_name.empty() ? pmt::PMT_NIL : pmt::string_to_symbol(length_tag_name)),
_nitems_to_send(0),
- _curr_freq(stream_args.channels.size(), 0.0),
- _curr_lo_offset(stream_args.channels.size(), 0.0),
- _curr_gain(stream_args.channels.size(), 0.0),
- _chans_to_tune(stream_args.channels.size(), false),
- _call_tune(false)
- {
- if(stream_args.cpu_format == "fc32")
- _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_FLOAT32);
- if(stream_args.cpu_format == "sc16")
- _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_INT16);
- _dev = ::uhd::usrp::multi_usrp::make(device_addr);
-
+ _curr_freq(stream_args.channels.size(), 0.0),
+ _curr_lo_offset(stream_args.channels.size(), 0.0),
+ _curr_gain(stream_args.channels.size(), 0.0),
+ _chans_to_tune(stream_args.channels.size())
+ {
message_port_register_in(pmt::mp("command"));
set_msg_handler(
- pmt::mp("command"),
- boost::bind(&usrp_sink_impl::msg_handler_command, this, _1)
+ pmt::mp("command"),
+ boost::bind(&usrp_sink_impl::msg_handler_command, this, _1)
);
- //message_port_register_in(pmt::mp("query"));
- //set_msg_handler(
- //pmt::mp("query"),
- //boost::bind(&usrp_sink_impl::msg_handler_query, this, _1)
- //);
+
+ _check_sensors_locked();
+ }
+
+ bool usrp_sink_impl::_check_sensors_locked()
+ {
+ bool clocks_locked = true;
+
+ // 1) Check ref lock for all mboards
+ for (size_t mboard_index = 0; mboard_index < _dev->get_num_mboards(); mboard_index++) {
+ std::string sensor_name = "ref_locked";
+ if (_dev->get_clock_source(mboard_index) == "internal") {
+ continue;
+ }
+ else if (_dev->get_clock_source(mboard_index) == "mimo") {
+ sensor_name = "mimo_locked";
+ }
+ if (not _wait_for_locked_sensor(
+ get_mboard_sensor_names(mboard_index),
+ sensor_name,
+ boost::bind(&usrp_sink_impl::get_mboard_sensor, this, _1, mboard_index)
+ )) {
+ GR_LOG_WARN(d_logger, boost::format("Sensor '%s' failed to lock within timeout on motherboard %d.") % sensor_name % mboard_index);
+ clocks_locked = false;
+ }
+ }
+
+ // 2) Check LO for all channels
+ for (size_t i = 0; i < _nchan; i++) {
+ size_t chan_index = _stream_args.channels[i];
+ if (not _wait_for_locked_sensor(
+ get_sensor_names(chan_index),
+ "lo_locked",
+ boost::bind(&usrp_sink_impl::get_sensor, this, _1, chan_index)
+ )) {
+ GR_LOG_WARN(d_logger, boost::format("Sensor 'lo_locked' failed to lock within timeout on channel %d.") % chan_index);
+ clocks_locked = false;
+ }
+ }
+
+ return clocks_locked;
}
+
usrp_sink_impl::~usrp_sink_impl()
{
}
@@ -569,9 +597,12 @@ namespace gr {
_metadata.time_spec += ::uhd::time_spec_t(0, num_sent, _sample_rate);
// Some post-processing tasks if we actually transmitted the entire burst
- if (_call_tune and num_sent == size_t(ninput_items)) {
- _set_center_freq_from_internals_allchans();
- _call_tune = false;
+ if (not _pending_cmds.empty() and num_sent == size_t(ninput_items)) {
+ GR_LOG_DEBUG(d_debug_logger, boost::format("Executing %d pending commands.") % _pending_cmds.size());
+ BOOST_FOREACH(const pmt::pmt_t &cmd_pmt, _pending_cmds) {
+ msg_handler_command(cmd_pmt);
+ }
+ _pending_cmds.clear();
}
return num_sent;
@@ -593,10 +624,9 @@ namespace gr {
// Go through tag list until something indicates the end of a burst.
bool found_time_tag = false;
bool found_eob = false;
- bool found_freq_tag_in_burst = false;
- uint64_t freq_cmd_offset = 0;
- double freq_cmd_freq;
- int freq_cmd_chan;
+ // For commands that are in the middle in the burst:
+ std::vector<pmt::pmt_t> commands_in_burst; // Store the command
+ uint64_t in_burst_cmd_offset = 0; // Store its position
BOOST_FOREACH(const tag_t &my_tag, _tags) {
const uint64_t my_tag_count = my_tag.offset;
const pmt::pmt_t &key = my_tag.key;
@@ -605,11 +635,11 @@ namespace gr {
if (my_tag_count >= max_count) {
break;
}
- else if (not pmt::is_null(_length_tag_key) and my_tag_count > samp0_count + _nitems_to_send) {
+ else if (not pmt::is_null(_length_tag_key) and my_tag_count > samp0_count + _nitems_to_send) {
break;
- }
+ }
- /* I. Bursts that can only be on the first sample of burst
+ /* I. Tags that can only be on the first sample of a burst
*
* This includes:
* - tx_time
@@ -634,7 +664,7 @@ namespace gr {
max_count = my_tag_count;
break;
}
- found_time_tag = true;
+ found_time_tag = true;
_metadata.has_time_spec = true;
_metadata.time_spec = ::uhd::time_spec_t
(pmt::to_uint64(pmt::tuple_ref(value, 0)),
@@ -647,8 +677,8 @@ namespace gr {
max_count = my_tag_count;
break;
}
- // Bursty tx will not use time specs, unless a tx_time tag is also given.
- _metadata.has_time_spec = false;
+ // Bursty tx will not use time specs, unless a tx_time tag is also given.
+ _metadata.has_time_spec = false;
_metadata.start_of_burst = pmt::to_bool(value);
}
@@ -656,49 +686,41 @@ namespace gr {
else if(not pmt::is_null(_length_tag_key) and pmt::equal(key, _length_tag_key)) {
if (my_tag_count != samp0_count) {
max_count = my_tag_count;
- break;
+ break;
}
//If there are still items left to send, the current burst has been preempted.
//Set the items remaining counter to the new burst length. Notify the user of
//the tag preemption.
- else if(_nitems_to_send > 0) {
+ else if(_nitems_to_send > 0) {
std::cerr << "tP" << std::flush;
}
_nitems_to_send = pmt::to_long(value);
_metadata.start_of_burst = true;
}
- /* II. Bursts that can be on the first OR last sample of a burst
+ /* II. Tags that can be on the first OR last sample of a burst
*
* This includes:
- * - tx_freq (tags that don't actually change the frequency are ignored)
+ * - tx_freq
*
* With these tags, we check if they're at the start of a burst, and do
* the appropriate action. Otherwise, make sure the corresponding sample
* is the last one.
*/
- else if (pmt::equal(key, FREQ_KEY) and my_tag_count == samp0_count) {
- int chan = pmt::to_long(pmt::tuple_ref(value, 0));
- double new_freq = pmt::to_double(pmt::tuple_ref(value, 1));
- if (new_freq != _curr_freq[chan]) {
- _curr_freq[chan] = new_freq;
- _set_center_freq_from_internals(chan);
- }
- }
-
- else if(pmt::equal(key, FREQ_KEY) and not found_freq_tag_in_burst) {
- int chan = pmt::to_long(pmt::tuple_ref(value, 0));
- double new_freq = pmt::to_double(pmt::tuple_ref(value, 1));
- if (new_freq != _curr_freq[chan]) {
- freq_cmd_freq = new_freq;
- freq_cmd_chan = chan;
- freq_cmd_offset = my_tag_count;
- max_count = my_tag_count + 1;
- found_freq_tag_in_burst = true;
- }
+ else if (pmt::equal(key, FREQ_KEY) and my_tag_count == samp0_count) {
+ // If it's on the first sample, immediately do the tune:
+ GR_LOG_DEBUG(d_debug_logger, boost::format("Received tx_freq on start of burst."));
+ msg_handler_command(pmt::cons(pmt::mp("freq"), value));
+ }
+ else if(pmt::equal(key, FREQ_KEY)) {
+ // If it's not on the first sample, queue this command and only tx until here:
+ GR_LOG_DEBUG(d_debug_logger, boost::format("Received tx_freq mid-burst."));
+ commands_in_burst.push_back(pmt::cons(pmt::mp("freq"), value));
+ max_count = my_tag_count + 1;
+ in_burst_cmd_offset = my_tag_count;
}
- /* III. Bursts that can only be on the last sample of a burst
+ /* III. Tags that can only be on the last sample of a burst
*
* This includes:
* - tx_eob
@@ -716,20 +738,25 @@ namespace gr {
found_eob = true;
}
- if (found_freq_tag_in_burst) {
+ // If a command was found in-burst that may appear at the end of burst,
+ // there's two options:
+ // 1) The command was actually on the last sample (eob). Then, stash the
+ // commands for running after work().
+ // 2) The command was not on the last sample. In this case, only send()
+ // until before the tag, so it will be on the first sample of the next run.
+ if (not commands_in_burst.empty()) {
if (not found_eob) {
// If it's in the middle of a burst, only send() until before the tag
- max_count = freq_cmd_offset;
- } else if (freq_cmd_offset < max_count) {
- // Otherwise, tune after work()
- _curr_freq[freq_cmd_chan] = freq_cmd_freq;
- _chans_to_tune[freq_cmd_chan] = true;
- _call_tune = true;
+ max_count = in_burst_cmd_offset;
+ } else if (in_burst_cmd_offset < max_count) {
+ BOOST_FOREACH(const pmt::pmt_t &cmd_pmt, commands_in_burst) {
+ _pending_cmds.push_back(cmd_pmt);
+ }
}
}
if (found_time_tag) {
- _metadata.has_time_spec = true;
+ _metadata.has_time_spec = true;
}
// Only transmit up to and including end of burst,
@@ -801,46 +828,44 @@ namespace gr {
/************** External interfaces (RPC + Message passing) ********************/
- // Helper function for msg_handler_command: Extracts chan and command value from
- // the 2-tuple in cmd_val, updates the value in vector_to_update[chan] and returns
- // true if it was different from the old value.
- bool _unpack_chan_command(pmt::pmt_t &cmd_val, int &chan, std::vector<double> &vector_to_update)
- {
- chan = pmt::to_long(pmt::tuple_ref(cmd_val, 0));
- double new_value = pmt::to_double(pmt::tuple_ref(cmd_val, 1));
- if (new_value == vector_to_update[chan]) {
- return false;
- } else {
- vector_to_update[chan] = new_value;
- return true;
- }
- }
-
void usrp_sink_impl::msg_handler_command(pmt::pmt_t msg)
{
- const std::string command(pmt::symbol_to_string(pmt::car(msg)));
- pmt::pmt_t value(pmt::cdr(msg));
- int chan = 0;
- if (command == "freq") {
- if (_unpack_chan_command(value, chan, _curr_freq)) {
- _set_center_freq_from_internals(chan);
- }
- } else if (command == "lo_offset") {
- if (_unpack_chan_command(value, chan, _curr_lo_offset)) {
- _set_center_freq_from_internals(chan);
- }
- } else if (command == "gain") {
- if (_unpack_chan_command(value, chan, _curr_gain)) {
- set_gain(_curr_gain[chan], chan);
- }
- } else {
- GR_LOG_ALERT(d_logger, boost::format("Received unknown command: %s") % command);
+ std::string command;
+ pmt::pmt_t cmd_value;
+ int chan = -1;
+ if (not _unpack_chan_command(command, cmd_value, chan, msg)) {
+ GR_LOG_ALERT(d_logger, boost::format("Error while unpacking command PMT: %s") % msg);
+ return;
+ }
+ GR_LOG_DEBUG(d_debug_logger, boost::format("Received command: %s") % command);
+ try {
+ if (command == "freq") {
+ _chans_to_tune = _update_vector_from_cmd_val<double>(
+ _curr_freq, chan, pmt::to_double(cmd_value), true
+ );
+ _set_center_freq_from_internals_allchans();
+ } else if (command == "lo_offset") {
+ _chans_to_tune = _update_vector_from_cmd_val<double>(
+ _curr_lo_offset, chan, pmt::to_double(cmd_value), true
+ );
+ _set_center_freq_from_internals_allchans();
+ } else if (command == "gain") {
+ boost::dynamic_bitset<> chans_to_change = _update_vector_from_cmd_val<double>(
+ _curr_gain, chan, pmt::to_double(cmd_value), true
+ );
+ if (chans_to_change.any()) {
+ for (size_t i = 0; i < chans_to_change.size(); i++) {
+ if (chans_to_change[i]) {
+ set_gain(_curr_gain[i], i);
+ }
+ }
+ }
+ } else {
+ GR_LOG_ALERT(d_logger, boost::format("Received unknown command: %s") % command);
+ }
+ } catch (pmt::wrong_type &e) {
+ GR_LOG_ALERT(d_logger, boost::format("Received command '%s' with invalid command value: %s") % command % cmd_value);
}
- }
-
- void usrp_sink_impl::msg_handler_query(pmt::pmt_t msg)
- {
- //tbi
}
void