summaryrefslogtreecommitdiff
path: root/gr-uhd
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd')
-rw-r--r--gr-uhd/examples/tag_sink_demo.h66
-rw-r--r--gr-uhd/examples/tag_source_demo.h129
-rw-r--r--gr-uhd/examples/tags_demo.cc139
-rw-r--r--gr-uhd/grc/gen_uhd_usrp_blocks.py5
-rw-r--r--gr-uhd/include/gr_uhd_usrp_sink.h27
-rw-r--r--gr-uhd/include/gr_uhd_usrp_source.h23
-rw-r--r--gr-uhd/lib/gr_uhd_usrp_sink.cc87
-rw-r--r--gr-uhd/lib/gr_uhd_usrp_source.cc27
-rw-r--r--gr-uhd/swig/__init__.py6
9 files changed, 495 insertions, 14 deletions
diff --git a/gr-uhd/examples/tag_sink_demo.h b/gr-uhd/examples/tag_sink_demo.h
new file mode 100644
index 000000000..84baf0a9c
--- /dev/null
+++ b/gr-uhd/examples/tag_sink_demo.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gr_sync_block.h>
+#include <gr_io_signature.h>
+#include <gr_tag_info.h>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+class tag_sink_demo : public gr_sync_block{
+public:
+
+ tag_sink_demo(void):
+ gr_sync_block(
+ "uhd tag sink demo",
+ gr_make_io_signature(1, 1, sizeof(std::complex<float>)),
+ gr_make_io_signature(0, 0, 0)
+ )
+ {
+ //NOP
+ }
+
+ int work(
+ int ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ){
+ //grab all "rx time" tags in this work call
+ const uint64_t samp0_count = this->nitems_read(0);
+ std::vector<pmt::pmt_t> rx_time_tags;
+ get_tags_in_range(rx_time_tags, 0, samp0_count, samp0_count + ninput_items, pmt::pmt_string_to_symbol("rx_time"));
+
+ //print all tags
+ BOOST_FOREACH(const pmt::pmt_t &rx_time_tag, rx_time_tags){
+ const uint64_t count = gr_tags::get_nitems(rx_time_tag);
+ const pmt::pmt_t &value = gr_tags::get_value(rx_time_tag);
+
+ std::cout << boost::format("Full seconds %u, Frac seconds %f")
+ % pmt::pmt_to_uint64(pmt_tuple_ref(value, 0))
+ % pmt::pmt_to_double(pmt_tuple_ref(value, 1))
+ << std::endl;
+ }
+
+ return ninput_items;
+ }
+};
diff --git a/gr-uhd/examples/tag_source_demo.h b/gr-uhd/examples/tag_source_demo.h
new file mode 100644
index 000000000..c7c0884d3
--- /dev/null
+++ b/gr-uhd/examples/tag_source_demo.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gr_sync_block.h>
+#include <gr_io_signature.h>
+#include <gr_tag_info.h>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+class tag_source_demo : public gr_sync_block{
+public:
+
+ tag_source_demo(
+ const uint64_t start_secs,
+ const double start_fracs,
+ const double samp_rate,
+ const double idle_duration,
+ const double burst_duration
+ ):
+ gr_sync_block(
+ "uhd tag source demo",
+ gr_make_io_signature(0, 0, 0),
+ gr_make_io_signature(1, 1, sizeof(std::complex<float>))
+ ),
+ _time_secs(start_secs),
+ _time_fracs(start_fracs),
+ _samp_rate(samp_rate),
+ _samps_per_burst(samp_rate*burst_duration),
+ _cycle_duration(idle_duration + burst_duration),
+ _samps_left_in_burst(1), //immediate EOB
+ _do_new_burst(false)
+ {
+ //NOP
+ }
+
+ void make_time_tag(const uint64_t tag_count){;
+ const pmt::pmt_t key = pmt::pmt_string_to_symbol("tx_time");
+ const pmt::pmt_t value = pmt::pmt_make_tuple(
+ pmt::pmt_from_uint64(_time_secs),
+ pmt::pmt_from_double(_time_fracs)
+ );
+ const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(this->name());
+ this->add_item_tag(0/*chan0*/, tag_count, key, value, srcid);
+ }
+
+ void make_sob_tag(const uint64_t tag_count){
+ const pmt::pmt_t key = pmt::pmt_string_to_symbol("tx_sob");
+ const pmt::pmt_t value = pmt::PMT_T;
+ const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(this->name());
+ this->add_item_tag(0/*chan0*/, tag_count, key, value, srcid);
+ }
+
+ void make_eob_tag(const uint64_t tag_count){;
+ const pmt::pmt_t key = pmt::pmt_string_to_symbol("tx_eob");
+ const pmt::pmt_t value = pmt::PMT_T;
+ const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(this->name());
+ this->add_item_tag(0/*chan0*/, tag_count, key, value, srcid);
+ }
+
+ int work(
+ int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ){
+ //load the output with a constant
+ std::complex<float> *output = reinterpret_cast<std::complex<float> *>(output_items[0]);
+ for (size_t i = 0; i < size_t(noutput_items); i++){
+ output[i] = std::complex<float>(0.7, 0.7);
+ }
+
+ //Handle the start of burst condition.
+ //Tag a start of burst and timestamp.
+ //Increment the time for the next burst.
+ if (_do_new_burst){
+ _do_new_burst = false;
+ _samps_left_in_burst = _samps_per_burst;
+
+ this->make_sob_tag(this->nitems_written(0));
+ this->make_time_tag(this->nitems_written(0));
+
+ _time_fracs += _cycle_duration;
+ double intpart; //normalize
+ _time_fracs = std::modf(_time_fracs, &intpart);
+ _time_secs += uint64_t(intpart);
+ }
+
+ //Handle the end of burst condition.
+ //Tag an end of burst and return early.
+ //the next work call will be a start of burst.
+ if (_samps_left_in_burst < size_t(noutput_items)){
+ this->make_eob_tag(this->nitems_written(0) + _samps_left_in_burst - 1);
+ _do_new_burst = true;
+ noutput_items = _samps_left_in_burst;
+ }
+
+ _samps_left_in_burst -= noutput_items;
+ return noutput_items;
+ }
+
+private:
+ uint64_t _time_secs;
+ double _time_fracs;
+ const double _samp_rate;
+ const uint64_t _samps_per_burst;
+ const double _cycle_duration;
+ bool _do_new_burst;
+ uint64_t _samps_left_in_burst;
+
+};
diff --git a/gr-uhd/examples/tags_demo.cc b/gr-uhd/examples/tags_demo.cc
new file mode 100644
index 000000000..b40518f34
--- /dev/null
+++ b/gr-uhd/examples/tags_demo.cc
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gr_top_block.h>
+#include <gr_uhd_usrp_source.h>
+#include <gr_uhd_usrp_sink.h>
+#include <tag_source_demo.h>
+#include <tag_sink_demo.h>
+#include <boost/make_shared.hpp>
+#include <boost/thread/thread.hpp> //sleep
+#include <boost/program_options.hpp>
+#include <csignal>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+/***********************************************************************
+ * Signal handlers
+ **********************************************************************/
+static bool stop_signal_called = false;
+void sig_int_handler(int){stop_signal_called = true;}
+
+/***********************************************************************
+ * Main w/ program options
+ **********************************************************************/
+int main(int argc, char *argv[]){
+
+ std::string device_addr;
+ double center_freq, samp_rate, burst_dur, idle_dur;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("addr", po::value<std::string>(&device_addr)->default_value(""), "the device address in string format")
+ ("rate", po::value<double>(&samp_rate)->default_value(1e6), "the sample rate in samples per second")
+ ("freq", po::value<double>(&center_freq)->default_value(10e6), "the center frequency in Hz")
+ ("burst", po::value<double>(&burst_dur)->default_value(0.1), "the duration of each burst in seconds")
+ ("idle", po::value<double>(&idle_dur)->default_value(0.05), "idle time between bursts in seconds")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout
+ << boost::format("UHD Tags Demo %s") % desc << std::endl
+ << "The tags sink demo block will print USRP source time stamps." << std::endl
+ << "The tags source demo block will send bursts to the USRP sink." << std::endl
+ << "Look at the USRP output on a scope to see the timed bursts." << std::endl
+ << std::endl;
+ return ~0;
+ }
+
+ //------------------------------------------------------------------
+ //-- make a top block
+ //------------------------------------------------------------------
+ gr_top_block_sptr tb = gr_make_top_block("tags_demo");
+
+ //------------------------------------------------------------------
+ //-- make the usrp source test blocks
+ //------------------------------------------------------------------
+ boost::shared_ptr<uhd_usrp_source> usrp_source = uhd_make_usrp_source(
+ device_addr, uhd::io_type_t::COMPLEX_FLOAT32, 1
+ );
+ usrp_source->set_samp_rate(samp_rate);
+ usrp_source->set_center_freq(center_freq);
+
+ boost::shared_ptr<tag_sink_demo> tag_sink = boost::make_shared<tag_sink_demo>();
+
+ //------------------------------------------------------------------
+ //-- connect the usrp source test blocks
+ //------------------------------------------------------------------
+ tb->connect(usrp_source, 0, tag_sink, 0);
+
+ //------------------------------------------------------------------
+ //-- make the usrp sink test blocks
+ //------------------------------------------------------------------
+ boost::shared_ptr<uhd_usrp_sink> usrp_sink = uhd_make_usrp_sink(
+ device_addr, uhd::io_type_t::COMPLEX_FLOAT32, 1
+ );
+ usrp_sink->set_samp_rate(samp_rate);
+ usrp_sink->set_center_freq(center_freq);
+ const uhd::time_spec_t time_now = usrp_sink->get_time_now();
+
+ boost::shared_ptr<tag_source_demo> tag_source = boost::make_shared<tag_source_demo>(
+ time_now.get_full_secs() + 1, time_now.get_frac_secs(), //time now + 1 second
+ samp_rate, idle_dur, burst_dur
+ );
+
+ //------------------------------------------------------------------
+ //-- connect the usrp sink test blocks
+ //------------------------------------------------------------------
+ tb->connect(tag_source, 0, usrp_sink, 0);
+
+ //------------------------------------------------------------------
+ //-- start flow graph execution
+ //------------------------------------------------------------------
+ std::cout << "starting flow graph" << std::endl;
+ tb->start();
+
+ //------------------------------------------------------------------
+ //-- poll the exit signal while running
+ //------------------------------------------------------------------
+ std::signal(SIGINT, &sig_int_handler);
+ std::cout << "press ctrl + c to exit" << std::endl;
+ while (not stop_signal_called){
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ }
+
+ //------------------------------------------------------------------
+ //-- stop flow graph execution
+ //------------------------------------------------------------------
+ std::cout << "stopping flow graph" << std::endl;
+ tb->stop();
+ tb->wait();
+
+ std::cout << "done!" << std::endl;
+ return 0;
+}
diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py
index c77df6c97..b6bc5fb79 100644
--- a/gr-uhd/grc/gen_uhd_usrp_blocks.py
+++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py
@@ -256,6 +256,8 @@ The center frequency is the overall frequency of the RF chain. \\
For greater control of how the UHD tunes elements in the RF chain, \\
pass a tune_request object rather than a simple target frequency.
Tuning with an LO offset example: uhd.tune_request(freq, lo_off)
+Tuning without DSP: uhd.tune_request(target_freq, dsp_freq=0, \\
+dsp_freq_policy=uhd.tune_request.POLICY_MANUAL)
Antenna:
For subdevices with only one antenna, this may be left blank. \\
@@ -266,6 +268,9 @@ Bandwidth:
To use the default bandwidth filter setting, this should be zero. \\
Only certain subdevices have configurable bandwidth filters. \\
See the daughterboard application notes for possible configurations.
+
+See the UHD manual for more detailed documentation:
+http://code.ettus.com/redmine/ettus/projects/uhd/wiki
</doc>
</block>
"""
diff --git a/gr-uhd/include/gr_uhd_usrp_sink.h b/gr-uhd/include/gr_uhd_usrp_sink.h
index 2adc5f1bf..c1fc3b09e 100644
--- a/gr-uhd/include/gr_uhd_usrp_sink.h
+++ b/gr-uhd/include/gr_uhd_usrp_sink.h
@@ -28,6 +28,33 @@
class uhd_usrp_sink;
+/*!
+ * \brief Make a new USRP sink block.
+ *
+ * The USRP sink block reads a stream and transmits the samples.
+ * The sink block also provides API calls for transmitter settings.
+ *
+ * TX Stream tagging:
+ *
+ * The following tag keys will be consumed by the work function:
+ * - pmt::pmt_string_to_symbol("tx_sob")
+ * - pmt::pmt_string_to_symbol("tx_eob")
+ * - pmt::pmt_string_to_symbol("tx_time")
+ *
+ * The sob and eob (start and end of burst) tag values are pmt booleans.
+ * When present, burst tags should be set to true (pmt::PMT_T).
+ *
+ * The timstamp tag value is a pmt tuple of the following:
+ * (uint64 seconds, and double fractional seconds).
+ *
+ * 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 io_type the desired input data type
+ * \param num_channels number of stream from the device
+ * \return a new USRP sink block object
+ */
GR_UHD_API boost::shared_ptr<uhd_usrp_sink> uhd_make_usrp_sink(
const uhd::device_addr_t &device_addr,
const uhd::io_type_t &io_type,
diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h
index 6e51a1423..f8ac9361e 100644
--- a/gr-uhd/include/gr_uhd_usrp_source.h
+++ b/gr-uhd/include/gr_uhd_usrp_source.h
@@ -28,6 +28,29 @@
class uhd_usrp_source;
+/*!
+ * \brief Make a new USRP source block.
+ *
+ * The USRP source block receives samples and writes to a stream.
+ * The source block also provides API calls for receiver settings.
+ *
+ * RX Stream tagging:
+ *
+ * The following tag keys will be produced by the work function:
+ * - pmt::pmt_string_to_symbol("rx_time")
+ *
+ * The timstamp tag value is a pmt tuple of the following:
+ * (uint64 seconds, and double fractional seconds).
+ * A timestamp tag is produced at start() and after overflows.
+ *
+ * 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 io_type the desired output data type
+ * \param num_channels number of stream from the device
+ * \return a new USRP source block object
+ */
GR_UHD_API boost::shared_ptr<uhd_usrp_source> uhd_make_usrp_source(
const uhd::device_addr_t &device_addr,
const uhd::io_type_t &io_type,
diff --git a/gr-uhd/lib/gr_uhd_usrp_sink.cc b/gr-uhd/lib/gr_uhd_usrp_sink.cc
index ce9d89d8d..a780f0551 100644
--- a/gr-uhd/lib/gr_uhd_usrp_sink.cc
+++ b/gr-uhd/lib/gr_uhd_usrp_sink.cc
@@ -21,8 +21,13 @@
#include <gr_uhd_usrp_sink.h>
#include <gr_io_signature.h>
+#include <gr_tag_info.h>
#include <stdexcept>
+static const pmt::pmt_t SOB_KEY = pmt::pmt_string_to_symbol("tx_sob");
+static const pmt::pmt_t EOB_KEY = pmt::pmt_string_to_symbol("tx_eob");
+static const pmt::pmt_t TIME_KEY = pmt::pmt_string_to_symbol("tx_time");
+
/***********************************************************************
* UHD Multi USRP Sink Impl
**********************************************************************/
@@ -39,8 +44,7 @@ public:
gr_make_io_signature(0, 0, 0)
),
_type(io_type),
- _nchan(num_channels),
- _has_time_spec(_nchan > 1)
+ _nchan(num_channels)
{
_dev = uhd::usrp::multi_usrp::make(device_addr);
}
@@ -180,13 +184,20 @@ public:
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
){
+ int ninput_items = noutput_items; //cuz its a sync block
+
//send a mid-burst packet with time spec
_metadata.start_of_burst = false;
_metadata.end_of_burst = false;
- _metadata.has_time_spec = _has_time_spec;
- size_t num_sent = _dev->get_device()->send(
- input_items, noutput_items, _metadata,
+ //collect tags in this work()
+ const uint64_t samp0_count = nitems_read(0);
+ get_tags_in_range(_tags, 0, samp0_count, samp0_count + ninput_items);
+ if (not _tags.empty()) this->tag_work(ninput_items);
+
+ //send all ninput_items with metadata
+ const size_t num_sent = _dev->get_device()->send(
+ input_items, ninput_items, _metadata,
_type, uhd::device::SEND_MODE_FULL_BUFF, 1.0
);
@@ -195,12 +206,70 @@ public:
return num_sent;
}
+/***********************************************************************
+ * Tag Work
+ **********************************************************************/
+ inline void tag_work(int &ninput_items){
+ //the for loop below assumes tags sorted by count low -> high
+ std::sort(_tags.begin(), _tags.end(), gr_tags::nitems_compare);
+
+ //extract absolute sample counts
+ const pmt::pmt_t &tag0 = _tags.front();
+ const uint64_t tag0_count = gr_tags::get_nitems(tag0);
+ const uint64_t samp0_count = this->nitems_read(0);
+
+ //only transmit nsamples from 0 to the first tag
+ //this ensures that the next work starts on a tag
+ if (samp0_count != tag0_count){
+ ninput_items = tag0_count - samp0_count;
+ return;
+ }
+
+ //time will not be set unless a time tag is found
+ _metadata.has_time_spec = false;
+
+ //process all of the tags found with the same count as tag0
+ BOOST_FOREACH(const pmt::pmt_t &my_tag, _tags){
+ const uint64_t my_tag_count = gr_tags::get_nitems(my_tag);
+ const pmt::pmt_t &key = gr_tags::get_key(my_tag);
+ const pmt::pmt_t &value = gr_tags::get_value(my_tag);
+
+ //determine how many samples to send...
+ //from zero until the next tag or end of work
+ if (my_tag_count != tag0_count){
+ ninput_items = my_tag_count - samp0_count;
+ break;
+ }
+
+ //handle end of burst with a mini end of burst packet
+ else if (pmt::pmt_equal(key, EOB_KEY)){
+ _metadata.end_of_burst = pmt::pmt_to_bool(value);
+ ninput_items = 1;
+ return;
+ }
+
+ //set the start of burst flag in the metadata
+ else if (pmt::pmt_equal(key, SOB_KEY)){
+ _metadata.start_of_burst = pmt::pmt_to_bool(value);
+ }
+
+ //set the time specification in the metadata
+ else if (pmt::pmt_equal(key, TIME_KEY)){
+ _metadata.has_time_spec = true;
+ _metadata.time_spec = uhd::time_spec_t(
+ pmt::pmt_to_uint64(pmt_tuple_ref(value, 0)),
+ pmt::pmt_to_double(pmt_tuple_ref(value, 1))
+ );
+ }
+ }
+ }
+
//Send an empty start-of-burst packet to begin streaming.
//Set at a time in the near future to avoid late packets.
bool start(void){
_metadata.start_of_burst = true;
_metadata.end_of_burst = false;
- _metadata.has_time_spec = _has_time_spec;
+ _metadata.has_time_spec = _nchan > 1;
_metadata.time_spec = get_time_now() + uhd::time_spec_t(0.01);
_dev->get_device()->send(
@@ -224,13 +293,15 @@ public:
return true;
}
-protected:
+private:
uhd::usrp::multi_usrp::sptr _dev;
const uhd::io_type_t _type;
size_t _nchan;
- bool _has_time_spec;
uhd::tx_metadata_t _metadata;
double _sample_rate;
+
+ //stream tags related stuff
+ std::vector<pmt::pmt_t> _tags;
};
/***********************************************************************
diff --git a/gr-uhd/lib/gr_uhd_usrp_source.cc b/gr-uhd/lib/gr_uhd_usrp_source.cc
index 669f890ea..62da83d96 100644
--- a/gr-uhd/lib/gr_uhd_usrp_source.cc
+++ b/gr-uhd/lib/gr_uhd_usrp_source.cc
@@ -25,6 +25,8 @@
#include <iostream>
#include <boost/format.hpp>
+static const pmt::pmt_t TIME_KEY = pmt::pmt_string_to_symbol("rx_time");
+
/***********************************************************************
* UHD Multi USRP Source Impl
**********************************************************************/
@@ -43,8 +45,11 @@ public:
_type(io_type),
_nchan(num_channels),
_stream_now(_nchan == 1),
- _tmp_buffs(_nchan)
+ _tag_now(false)
{
+ std::stringstream str;
+ str << name() << unique_id();
+ _id = pmt::pmt_string_to_symbol(str.str());
_dev = uhd::usrp::multi_usrp::make(device_addr);
}
@@ -202,7 +207,18 @@ public:
//handle possible errors conditions
switch(_metadata.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
- //TODO insert tag for time stamp
+ if (_tag_now){
+ _tag_now = false;
+ //create a timestamp pmt for the first sample
+ const pmt::pmt_t val = pmt::pmt_make_tuple(
+ pmt::pmt_from_uint64(_metadata.time_spec.get_full_secs()),
+ pmt::pmt_from_double(_metadata.time_spec.get_frac_secs())
+ );
+ //create a timestamp tag for each channel
+ for (size_t i = 0; i < _nchan; i++){
+ this->add_item_tag(i, nitems_written(0), TIME_KEY, val, _id);
+ }
+ }
break;
case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
@@ -211,8 +227,8 @@ public:
return WORK_DONE;
case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
+ _tag_now = true;
//ignore overflows and try work again
- //TODO insert tag for overflow
return work(noutput_items, input_items, output_items);
default:
@@ -232,6 +248,7 @@ public:
stream_cmd.stream_now = _stream_now;
stream_cmd.time_spec = get_time_now() + uhd::time_spec_t(reasonable_delay);
_dev->issue_stream_cmd(stream_cmd);
+ _tag_now = true;
return true;
}
@@ -244,9 +261,9 @@ private:
uhd::usrp::multi_usrp::sptr _dev;
const uhd::io_type_t _type;
size_t _nchan;
- bool _stream_now;
- gr_vector_void_star _tmp_buffs;
+ bool _stream_now, _tag_now;
uhd::rx_metadata_t _metadata;
+ pmt::pmt_t _id;
};
diff --git a/gr-uhd/swig/__init__.py b/gr-uhd/swig/__init__.py
index 5c0c011b7..1f82b4a26 100644
--- a/gr-uhd/swig/__init__.py
+++ b/gr-uhd/swig/__init__.py
@@ -32,9 +32,13 @@ def _prepare_uhd_swig():
#Make the python tune request object inherit from float
#so that it can be passed in GRC as a frequency parameter.
#The type checking in GRC will accept the tune request.
+ #Also use kwargs to construct individual struct elements.
class tune_request_t(uhd_swig.tune_request_t, float):
- def __new__(self, *args): return float.__new__(self)
+ def __new__(self, *args, **kwargs): return float.__new__(self)
def __float__(self): return self.target_freq
+ def __init__(self, *args, **kwargs):
+ super(tune_request_t, self).__init__(*args)
+ for key, val in kwargs.iteritems(): setattr(self, key, val)
setattr(uhd_swig, 'tune_request_t', tune_request_t)
#Make the python tune request object inherit from string