diff options
author | Martin Braun <martin.braun@ettus.com> | 2014-04-04 17:56:25 +0200 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2014-04-26 23:31:55 +0200 |
commit | fe815bdd4f79c0159ebee0361d0d7e15e7b920aa (patch) | |
tree | 6eda4ea550691188d1c663a81f5719dd68a7203a /gr-uhd | |
parent | fdafa6a6ed03d5bfea5e2c11584902d64032c761 (diff) |
uhd: Added retune-by-tag and a command interface via message passing
Diffstat (limited to 'gr-uhd')
-rw-r--r-- | gr-uhd/include/gnuradio/uhd/usrp_sink.h | 10 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_sink_impl.cc | 117 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_sink_impl.h | 19 |
3 files changed, 142 insertions, 4 deletions
diff --git a/gr-uhd/include/gnuradio/uhd/usrp_sink.h b/gr-uhd/include/gnuradio/uhd/usrp_sink.h index c57524efa4..cac3e0185c 100644 --- a/gr-uhd/include/gnuradio/uhd/usrp_sink.h +++ b/gr-uhd/include/gnuradio/uhd/usrp_sink.h @@ -72,6 +72,7 @@ namespace gr { * - pmt::string_to_symbol("tx_sob") * - pmt::string_to_symbol("tx_eob") * - pmt::string_to_symbol("tx_time") + * - pmt::string_to_symbol("tx_freq") * - pmt::string_to_symbol(length_tag_name) * * The sob and eob (start and end of burst) tag values are pmt booleans. @@ -86,10 +87,13 @@ namespace gr { * The timstamp tag value is a pmt tuple of the following: * (uint64 seconds, and double fractional seconds). * + * The tx_freq tag has to be a double, and will re-tune the USRP to the given frequency, + * if possible. + * * See the UHD manual for more detailed documentation: * http://code.ettus.com/redmine/ettus/projects/uhd/wiki * - * \param device_addr the address to identify the hardware + * \param device_addr the address to identify the hardware (e.g. "type=b200", "addr=192.168.10.2") * \param io_type the desired input data type * \param num_channels number of stream from the device * \param length_tag_name the name of the tag identifying tagged stream length @@ -112,6 +116,7 @@ namespace gr { * - pmt::string_to_symbol("tx_sob") * - pmt::string_to_symbol("tx_eob") * - pmt::string_to_symbol("tx_time") + * - pmt::string_to_symbol("tx_freq") * - pmt::string_to_symbol(length_tag_name) * * The sob and eob (start and end of burst) tag values are pmt booleans. @@ -126,6 +131,9 @@ namespace gr { * The timstamp tag value is a pmt tuple of the following: * (uint64 seconds, and double fractional seconds). * + * The tx_freq tag has to be a double, and will re-tune the USRP to the given frequency, + * if possible. + * * See the UHD manual for more detailed documentation: * http://code.ettus.com/redmine/ettus/projects/uhd/wiki * diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc index 413952add7..f55d1f5796 100644 --- a/gr-uhd/lib/usrp_sink_impl.cc +++ b/gr-uhd/lib/usrp_sink_impl.cc @@ -71,13 +71,27 @@ namespace gr { _stream_now(_nchan == 1), _start_time_set(false), _length_tag_key(length_tag_name.empty() ? pmt::PMT_NIL : pmt::string_to_symbol(length_tag_name)), - _nitems_to_send(0) + _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) { 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); + + message_port_register_in(pmt::mp("command")); + set_msg_handler( + 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) + ); } usrp_sink_impl::~usrp_sink_impl() @@ -138,10 +152,29 @@ namespace gr { usrp_sink_impl::set_center_freq(const ::uhd::tune_request_t tune_request, size_t chan) { + _curr_freq[chan] = tune_request.target_freq; + if (tune_request.rf_freq_policy == ::uhd::tune_request_t::POLICY_MANUAL) { + _curr_lo_offset[chan] = tune_request.rf_freq - tune_request.target_freq; + } else { + _curr_lo_offset[chan] = 0.0; + } chan = _stream_args.channels[chan]; return _dev->set_tx_freq(tune_request, chan); } + ::uhd::tune_result_t + usrp_sink_impl::_set_center_freq_from_internals(size_t chan) + { + if (_curr_lo_offset[chan] == 0.0) { + return _dev->set_tx_freq(_curr_freq[chan], _stream_args.channels[chan]); + } else { + return _dev->set_tx_freq( + ::uhd::tune_request_t(_curr_freq[chan], _curr_lo_offset[chan]), + _stream_args.channels[chan] + ); + } + } + double usrp_sink_impl::get_center_freq(size_t chan) { @@ -159,6 +192,7 @@ namespace gr { void usrp_sink_impl::set_gain(double gain, size_t chan) { + _curr_gain[chan] = gain; chan = _stream_args.channels[chan]; return _dev->set_tx_gain(gain, chan); } @@ -168,6 +202,7 @@ namespace gr { const std::string &name, size_t chan) { + _curr_gain[chan] = gain; chan = _stream_args.channels[chan]; return _dev->set_tx_gain(gain, name, chan); } @@ -546,6 +581,8 @@ namespace gr { //time will not be set unless a time tag is found _metadata.has_time_spec = false; + bool call_tune_loop = false; + std::vector<bool> do_tune(_nchan, false); //process all of the tags found with the same count as tag0 BOOST_FOREACH(const tag_t &my_tag, _tags) { const uint64_t my_tag_count = my_tag.offset; @@ -590,8 +627,38 @@ namespace gr { (pmt::to_uint64(pmt::tuple_ref(value, 0)), pmt::to_double(pmt::tuple_ref(value, 1))); } - } - } + + //set the new tx frequency + else if(pmt::equal(key, FREQ_KEY)) { + 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]) { + call_tune_loop = true; + do_tune[chan] = true; + _curr_freq[chan] = new_freq; + } + } + + //set the new lo offset + else if(pmt::equal(key, LO_OFFS_KEY)) { + int chan = pmt::to_long(pmt::tuple_ref(value, 0)); + double new_lo_offs = pmt::to_double(pmt::tuple_ref(value, 1)); + if (new_lo_offs != _curr_lo_offset[chan]) { + call_tune_loop = true; + do_tune[chan] = true; + _curr_lo_offset[chan] = new_lo_offs; + } + } + } // end foreach + // If there was a freq tag, tune the transmitter(s) + if (call_tune_loop) { + for (size_t chan = 0; chan < _nchan; chan++) { + if (do_tune[chan]) { + _set_center_freq_from_internals(chan); + } + } + } // end if call_tune_loop + } // end tag_work() void usrp_sink_impl::set_start_time(const ::uhd::time_spec_t &time) @@ -653,6 +720,50 @@ namespace gr { return true; } + + /************** 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); + } + } + + void usrp_sink_impl::msg_handler_query(pmt::pmt_t msg) + { + + } + void usrp_sink_impl::setup_rpc() { diff --git a/gr-uhd/lib/usrp_sink_impl.h b/gr-uhd/lib/usrp_sink_impl.h index ae31b51458..c2e488e81b 100644 --- a/gr-uhd/lib/usrp_sink_impl.h +++ b/gr-uhd/lib/usrp_sink_impl.h @@ -26,6 +26,8 @@ static const pmt::pmt_t SOB_KEY = pmt::string_to_symbol("tx_sob"); static const pmt::pmt_t EOB_KEY = pmt::string_to_symbol("tx_eob"); static const pmt::pmt_t TIME_KEY = pmt::string_to_symbol("tx_time"); +static const pmt::pmt_t FREQ_KEY = pmt::string_to_symbol("tx_freq"); +static const pmt::pmt_t LO_OFFS_KEY = pmt::string_to_symbol("tx_lo_offset"); namespace gr { namespace uhd { @@ -120,6 +122,13 @@ namespace gr { inline void tag_work(int &ninput_items); private: + //! Like set_center_freq(), but uses _curr_freq and _curr_lo_offset + ::uhd::tune_result_t _set_center_freq_from_internals(size_t chan); + //! Receives commands and handles them + void msg_handler_command(pmt::pmt_t msg); + //! Receives queries and posts a response + void msg_handler_query(pmt::pmt_t msg); + ::uhd::usrp::multi_usrp::sptr _dev; const ::uhd::stream_args_t _stream_args; boost::shared_ptr< ::uhd::io_type_t > _type; @@ -138,6 +147,16 @@ namespace gr { std::vector<tag_t> _tags; const pmt::pmt_t _length_tag_key; long _nitems_to_send; + + //! Stores the last value we told the USRP to tune to for every channel + // (this is not necessarily the true value the USRP is currently tuned to!). + // We could theoretically ask the device, but during streaming, we want to minimize + // communication with the USRP. + std::vector<double> _curr_freq; + //! Stores the last value we told the USRP to have the LO offset for every channel. + std::vector<double> _curr_lo_offset; + //! Stores the last gain value we told the USRP to have for every channel. + std::vector<double> _curr_gain; }; } /* namespace uhd */ |