summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/lib/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core/src/lib/runtime')
-rw-r--r--gnuradio-core/src/lib/runtime/Makefile.am8
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.cc68
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.h85
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.i3
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_detail.cc92
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_detail.h73
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_executor.cc87
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_executor.h3
-rw-r--r--gnuradio-core/src/lib/runtime/gr_buffer.cc71
-rw-r--r--gnuradio-core/src/lib/runtime/gr_buffer.h50
-rw-r--r--gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc7
-rw-r--r--gnuradio-core/src/lib/runtime/gr_preferences.cc24
-rw-r--r--gnuradio-core/src/lib/runtime/gr_tag_info.cc38
-rw-r--r--gnuradio-core/src/lib/runtime/gr_tag_info.h87
-rw-r--r--gnuradio-core/src/lib/runtime/qa_block_tags.cc450
-rw-r--r--gnuradio-core/src/lib/runtime/qa_block_tags.h52
-rw-r--r--gnuradio-core/src/lib/runtime/qa_runtime.cc2
17 files changed, 1170 insertions, 30 deletions
diff --git a/gnuradio-core/src/lib/runtime/Makefile.am b/gnuradio-core/src/lib/runtime/Makefile.am
index f67e8843d..dd9a8ea64 100644
--- a/gnuradio-core/src/lib/runtime/Makefile.am
+++ b/gnuradio-core/src/lib/runtime/Makefile.am
@@ -68,7 +68,8 @@ libruntime_la_SOURCES = \
gr_vmcircbuf_mmap_tmpfile.cc \
gr_vmcircbuf_createfilemapping.cc \
gr_vmcircbuf_sysv_shm.cc \
- gr_select_handler.cc
+ gr_select_handler.cc \
+ gr_tag_info.cc
libruntime_qa_la_SOURCES = \
qa_gr_block.cc \
@@ -79,6 +80,7 @@ libruntime_qa_la_SOURCES = \
qa_gr_top_block.cc \
qa_gr_io_signature.cc \
qa_gr_vmcircbuf.cc \
+ qa_block_tags.cc \
qa_runtime.cc
grinclude_HEADERS = \
@@ -121,7 +123,8 @@ grinclude_HEADERS = \
gr_tmp_path.h \
gr_types.h \
gr_unittests.h \
- gr_vmcircbuf.h
+ gr_vmcircbuf.h \
+ gr_tag_info.h
noinst_HEADERS = \
gr_vmcircbuf_mmap_shm_open.h \
@@ -136,6 +139,7 @@ noinst_HEADERS = \
qa_gr_io_signature.h \
qa_gr_top_block.h \
qa_gr_vmcircbuf.h \
+ qa_block_tags.h \
qa_runtime.h
if PYTHON
diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc
index 8915f3360..81a55af9d 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -36,7 +36,8 @@ gr_block::gr_block (const std::string &name,
d_output_multiple (1),
d_relative_rate (1.0),
d_history(1),
- d_fixed_rate(false)
+ d_fixed_rate(false),
+ d_tag_propagation_policy(TPP_ALL_TO_ALL)
{
}
@@ -117,6 +118,69 @@ gr_block::fixed_rate_noutput_to_ninput(int noutput)
throw std::runtime_error("Unimplemented");
}
+uint64_t
+gr_block::nitems_read(unsigned int which_input)
+{
+ if(d_detail) {
+ return d_detail->nitems_read(which_input);
+ }
+ else {
+ //throw std::runtime_error("No block_detail associated with block yet");
+ return 0;
+ }
+}
+
+uint64_t
+gr_block::nitems_written(unsigned int which_output)
+{
+ if(d_detail) {
+ return d_detail->nitems_written(which_output);
+ }
+ else {
+ //throw std::runtime_error("No block_detail associated with block yet");
+ return 0;
+ }
+}
+
+void
+gr_block::add_item_tag(unsigned int which_output,
+ uint64_t offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid)
+{
+ d_detail->add_item_tag(which_output, offset, key, value, srcid);
+}
+
+void
+gr_block::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_output,
+ uint64_t start, uint64_t end)
+{
+ d_detail->get_tags_in_range(v, which_output, start, end);
+}
+
+void
+gr_block::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_output,
+ uint64_t start, uint64_t end,
+ const pmt::pmt_t &key)
+{
+ d_detail->get_tags_in_range(v, which_output, start, end, key);
+}
+
+gr_block::tag_propagation_policy_t
+gr_block::tag_propagation_policy()
+{
+ return d_tag_propagation_policy;
+}
+
+void
+gr_block::set_tag_propagation_policy(tag_propagation_policy_t p)
+{
+ d_tag_propagation_policy = p;
+}
+
std::ostream&
operator << (std::ostream& os, const gr_block *m)
{
diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h
index b6f724dde..ad7fa9555 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_block.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2007,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2007,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -63,6 +63,12 @@ class gr_block : public gr_basic_block {
WORK_DONE = -1
};
+ enum tag_propagation_policy_t {
+ TPP_DONT = 0,
+ TPP_ALL_TO_ALL = 1,
+ TPP_ONE_TO_ONE = 2
+ };
+
virtual ~gr_block ();
/*!
@@ -198,6 +204,26 @@ class gr_block : public gr_basic_block {
*/
virtual int fixed_rate_noutput_to_ninput(int noutput);
+ /*!
+ * \brief Return the number of items read on input stream which_input
+ */
+ uint64_t nitems_read(unsigned int which_input);
+
+ /*!
+ * \brief Return the number of items written on output stream which_output
+ */
+ uint64_t nitems_written(unsigned int which_output);
+
+ /*!
+ * \brief Asks for the policy used by the scheduler to moved tags downstream.
+ */
+ tag_propagation_policy_t tag_propagation_policy();
+
+ /*!
+ * \brief Set the policy by the scheduler to determine how tags are moved downstream.
+ */
+ void set_tag_propagation_policy(tag_propagation_policy_t p);
+
// ----------------------------------------------------------------------------
private:
@@ -207,6 +233,7 @@ class gr_block : public gr_basic_block {
gr_block_detail_sptr d_detail; // implementation details
unsigned d_history;
bool d_fixed_rate;
+ tag_propagation_policy_t d_tag_propagation_policy; // policy for moving tags downstream
protected:
@@ -216,6 +243,62 @@ class gr_block : public gr_basic_block {
void set_fixed_rate(bool fixed_rate){ d_fixed_rate = fixed_rate; }
+
+ /*!
+ * \brief Adds a new tag onto the given output buffer.
+ *
+ * \param which_output an integer of which output stream to attach the tag
+ * \param abs_offset a uint64 number of the absolute item number
+ * assicated with the tag. Can get from nitems_written.
+ * \param key the tag key as a PMT symbol
+ * \param value any PMT holding any value for the given key
+ * \param srcid optional source ID specifier; defaults to PMT_F
+ */
+ void add_item_tag(unsigned int which_output,
+ uint64_t abs_offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid=pmt::PMT_F);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range.
+ *
+ * Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range
+ * with a given key.
+ *
+ * Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ * \param key a PMT symbol key to filter only tags of this key
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt::pmt_t &key);
+
// These are really only for internal use, but leaving them public avoids
// having to work up an ever-varying list of friends
diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i
index f4ee43477..bb0c5f221 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_block.i
@@ -49,6 +49,9 @@ class gr_block : public gr_basic_block {
bool start();
bool stop();
+ uint64_t nitems_read(unsigned int which_input);
+ uint64_t nitems_written(unsigned int which_output);
+
// internal use
gr_block_detail_sptr detail () const { return d_detail; }
void set_detail (gr_block_detail_sptr detail) { d_detail = detail; }
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
index 38d4a13ca..a360240c0 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -27,6 +27,8 @@
#include <gr_block_detail.h>
#include <gr_buffer.h>
+using namespace pmt;
+
static long s_ncurrently_allocated = 0;
long
@@ -88,16 +90,20 @@ gr_block_detail::set_done (bool done)
void
gr_block_detail::consume (int which_input, int how_many_items)
{
- if (how_many_items > 0)
+ if (how_many_items > 0) {
input (which_input)->update_read_pointer (how_many_items);
+ }
}
+
void
gr_block_detail::consume_each (int how_many_items)
{
- if (how_many_items > 0)
- for (int i = 0; i < ninputs (); i++)
+ if (how_many_items > 0) {
+ for (int i = 0; i < ninputs (); i++) {
d_input[i]->update_read_pointer (how_many_items);
+ }
+ }
}
void
@@ -112,16 +118,88 @@ gr_block_detail::produce (int which_output, int how_many_items)
void
gr_block_detail::produce_each (int how_many_items)
{
- if (how_many_items > 0){
- for (int i = 0; i < noutputs (); i++)
+ if (how_many_items > 0) {
+ for (int i = 0; i < noutputs (); i++) {
d_output[i]->update_write_pointer (how_many_items);
+ }
d_produce_or |= how_many_items;
}
}
void
-gr_block_detail::_post(pmt::pmt_t msg)
+gr_block_detail::_post(pmt_t msg)
{
d_tpb.insert_tail(msg);
}
+
+uint64_t
+gr_block_detail::nitems_read(unsigned int which_input)
+{
+ if(which_input >= d_ninputs)
+ throw std::invalid_argument ("gr_block_detail::n_input_items");
+ return d_input[which_input]->nitems_read();
+}
+
+uint64_t
+gr_block_detail::nitems_written(unsigned int which_output)
+{
+ if(which_output >= d_noutputs)
+ throw std::invalid_argument ("gr_block_detail::n_output_items");
+ return d_output[which_output]->nitems_written();
+}
+
+void
+gr_block_detail::add_item_tag(unsigned int which_output,
+ uint64_t abs_offset,
+ const pmt_t &key,
+ const pmt_t &value,
+ const pmt_t &srcid)
+{
+ if(!pmt_is_symbol(key)) {
+ throw pmt_wrong_type("gr_block_detail::add_item_tag key", key);
+ }
+ else {
+ // build tag tuple
+ pmt_t nitem = pmt_from_uint64(abs_offset);
+ pmt_t tuple = pmt_make_tuple(nitem, srcid, key, value);
+
+ // Add tag to gr_buffer's deque tags
+ d_output[which_output]->add_item_tag(tuple);
+ }
+}
+
+void
+gr_block_detail::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end)
+{
+ // get from gr_buffer_reader's deque of tags
+ d_input[which_input]->get_tags_in_range(v, abs_start, abs_end);
+}
+
+void
+gr_block_detail::get_tags_in_range(std::vector<pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt_t &key)
+{
+ std::vector<pmt_t> found_items;
+
+ v.resize(0);
+
+ // get from gr_buffer_reader's deque of tags
+ d_input[which_input]->get_tags_in_range(found_items, abs_start, abs_end);
+
+ // Filter further by key name
+ pmt_t itemkey;
+ std::vector<pmt_t>::iterator itr;
+ for(itr = found_items.begin(); itr != found_items.end(); itr++) {
+ itemkey = pmt_tuple_ref(*itr, 2);
+ if(pmt_eqv(key, itemkey)) {
+ v.push_back(*itr);
+ }
+ }
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h
index c5787a5ad..d7ec3b136 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.h
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -25,6 +25,7 @@
#include <gr_runtime_types.h>
#include <gr_tpb_detail.h>
+#include <gr_tag_info.h>
#include <stdexcept>
/*!
@@ -88,6 +89,75 @@ class gr_block_detail {
*/
void _post(pmt::pmt_t msg);
+ // Return the number of items read on input stream which_input
+ uint64_t nitems_read(unsigned int which_input);
+
+ // Return the number of items written on output stream which_output
+ uint64_t nitems_written(unsigned int which_output);
+
+
+ /*!
+ * \brief Adds a new tag to the given output stream.
+ *
+ * This takes the input parameters and builds a PMT tuple
+ * from it. It then calls gr_buffer::add_item_tag(pmt::pmt_t t),
+ * which appends the tag onto its deque.
+ *
+ * \param which_output an integer of which output stream to attach the tag
+ * \param abs_offset a uint64 number of the absolute item number
+ * assicated with the tag. Can get from nitems_written.
+ * \param key the tag key as a PMT symbol
+ * \param value any PMT holding any value for the given key
+ * \param srcid a PMT source ID specifier
+ */
+ void add_item_tag(unsigned int which_output,
+ uint64_t abs_offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range.
+ *
+ * Pass-through function to gr_buffer_reader to get a vector of tags
+ * in given range. Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range
+ * with a given key.
+ *
+ * Calls get_tags_in_range(which_input, abs_start, abs_end) to get a vector of
+ * tags from the buffers. This function then provides a secondary filter to
+ * the tags to extract only tags with the given 'key'.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ * \param key a PMT symbol to select only tags of this key
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt::pmt_t &key);
+
gr_tpb_detail d_tpb; // used by thread-per-block scheduler
int d_produce_or;
@@ -100,7 +170,6 @@ class gr_block_detail {
std::vector<gr_buffer_sptr> d_output;
bool d_done;
-
gr_block_detail (unsigned int ninputs, unsigned int noutputs);
friend class gr_tpb_detail;
diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.cc b/gnuradio-core/src/lib/runtime/gr_block_executor.cc
index 2c21a0b0f..112150235 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_executor.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_executor.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -87,7 +87,80 @@ min_available_space (gr_block_detail *d, int output_multiple)
return min_space;
}
+static bool
+propagate_tags(gr_block::tag_propagation_policy_t policy, gr_block_detail *d,
+ const std::vector<uint64_t> &start_nitems_read, double rrate,
+ std::vector<pmt::pmt_t> &rtags)
+{
+ // Move tags downstream
+ // if a sink, we don't need to move downstream;
+ // and do not bother if block uses TAGS_NONE attribute
+ if(d->sink_p()) {
+ return true;
+ }
+ switch(policy) {
+ case gr_block::TPP_DONT:
+ return true;
+ break;
+ case gr_block::TPP_ALL_TO_ALL:
+ // every tag on every input propogates to everyone downstream
+ for(int i = 0; i < d->ninputs(); i++) {
+ d->get_tags_in_range(rtags, i, start_nitems_read[i],
+ d->nitems_read(i));
+
+ std::vector<pmt::pmt_t>::iterator t;
+ if(rrate == 1.0) {
+ for(t = rtags.begin(); t != rtags.end(); t++) {
+ for(int o = 0; o < d->noutputs(); o++)
+ d->output(o)->add_item_tag(*t);
+ }
+ }
+ else {
+ for(t = rtags.begin(); t != rtags.end(); t++) {
+ uint64_t newcount = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*t, 0));
+ pmt::pmt_t newtup = pmt::mp(pmt::pmt_from_uint64(newcount * rrate),
+ pmt::pmt_tuple_ref(*t, 1),
+ pmt::pmt_tuple_ref(*t, 2),
+ pmt::pmt_tuple_ref(*t, 3));
+
+ for(int o = 0; o < d->noutputs(); o++)
+ d->output(o)->add_item_tag(newtup);
+ }
+ }
+ }
+ break;
+ case gr_block::TPP_ONE_TO_ONE:
+ // tags from input i only go to output i
+ // this requires d->ninputs() == d->noutputs; this is checked when this
+ // type of tag-propagation system is selected in gr_block_detail
+ if(d->ninputs() == d->noutputs()) {
+ for(int i = 0; i < d->ninputs(); i++) {
+ d->get_tags_in_range(rtags, i, start_nitems_read[i],
+ d->nitems_read(i));
+
+ std::vector<pmt::pmt_t>::iterator t;
+ for(t = rtags.begin(); t != rtags.end(); t++) {
+ uint64_t newcount = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*t, 0));
+ pmt::pmt_t newtup = pmt::mp(pmt::pmt_from_uint64(newcount * rrate),
+ pmt::pmt_tuple_ref(*t, 1),
+ pmt::pmt_tuple_ref(*t, 2),
+ pmt::pmt_tuple_ref(*t, 3));
+ d->output(i)->add_item_tag(newtup);
+ }
+ }
+ }
+ else {
+ std::cerr << "Error: gr_block_executor: propagation_policy 'ONE-TO-ONE' requires ninputs == noutputs" << std::endl;
+ return false;
+ }
+
+ break;
+ default:
+ return true;
+ }
+ return true;
+}
gr_block_executor::gr_block_executor (gr_block_sptr block)
: d_block(block), d_log(0)
@@ -134,6 +207,7 @@ gr_block_executor::run_one_iteration()
d_input_items.resize (0);
d_input_done.resize(0);
d_output_items.resize (d->noutputs ());
+ d_start_nitems_read.resize(0);
// determine the minimum available output space
noutput_items = min_available_space (d, m->output_multiple ());
@@ -155,6 +229,7 @@ gr_block_executor::run_one_iteration()
d_input_items.resize (d->ninputs ());
d_input_done.resize(d->ninputs());
d_output_items.resize (0);
+ d_start_nitems_read.resize(d->ninputs());
LOG(*d_log << " sink\n");
max_items_avail = 0;
@@ -198,6 +273,7 @@ gr_block_executor::run_one_iteration()
d_input_items.resize (d->ninputs ());
d_input_done.resize(d->ninputs());
d_output_items.resize (d->noutputs ());
+ d_start_nitems_read.resize(d->ninputs());
max_items_avail = 0;
for (int i = 0; i < d->ninputs (); i++){
@@ -294,12 +370,21 @@ gr_block_executor::run_one_iteration()
for (int i = 0; i < d->noutputs (); i++)
d_output_items[i] = d->output(i)->write_pointer();
+ // determine where to start looking for new tags
+ for (int i = 0; i < d->ninputs(); i++)
+ d_start_nitems_read[i] = d->nitems_read(i);
+
// Do the actual work of the block
int n = m->general_work (noutput_items, d_ninput_items,
d_input_items, d_output_items);
LOG(*d_log << " general_work: noutput_items = " << noutput_items
<< " result = " << n << std::endl);
+ if(!propagate_tags(m->tag_propagation_policy(), d,
+ d_start_nitems_read, m->relative_rate(),
+ d_returned_tags))
+ goto were_done;
+
if (n == gr_block::WORK_DONE)
goto were_done;
diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.h b/gnuradio-core/src/lib/runtime/gr_block_executor.h
index 41b5ede7c..77ace5522 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_executor.h
+++ b/gnuradio-core/src/lib/runtime/gr_block_executor.h
@@ -25,6 +25,7 @@
#include <gr_runtime_types.h>
#include <fstream>
+#include <gruel/pmt.h>
//class gr_block_executor;
//typedef boost::shared_ptr<gr_block_executor> gr_block_executor_sptr;
@@ -47,6 +48,8 @@ protected:
gr_vector_const_void_star d_input_items;
std::vector<bool> d_input_done;
gr_vector_void_star d_output_items;
+ std::vector<uint64_t> d_start_nitems_read; //stores where tag counts are before work
+ std::vector<pmt::pmt_t> d_returned_tags;
public:
gr_block_executor(gr_block_sptr block);
diff --git a/gnuradio-core/src/lib/runtime/gr_buffer.cc b/gnuradio-core/src/lib/runtime/gr_buffer.cc
index db2db5d6d..0b2eb52a0 100644
--- a/gnuradio-core/src/lib/runtime/gr_buffer.cc
+++ b/gnuradio-core/src/lib/runtime/gr_buffer.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -80,7 +80,7 @@ minimum_buffer_items (long type_size, long page_size)
gr_buffer::gr_buffer (int nitems, size_t sizeof_item, gr_block_sptr link)
: d_base (0), d_bufsize (0), d_vmcircbuf (0),
d_sizeof_item (sizeof_item), d_link(link),
- d_write_index (0), d_done (false)
+ d_write_index (0), d_abs_write_offset(0), d_done (false)
{
if (!allocate_buffer (nitems, sizeof_item))
throw std::bad_alloc ();
@@ -156,8 +156,13 @@ gr_buffer::space_available ()
// Find out the maximum amount of data available to our readers
int most_data = d_readers[0]->items_available ();
- for (unsigned int i = 1; i < d_readers.size (); i++)
+ uint64_t min_items_read = d_readers[0]->nitems_read();
+ for (size_t i = 1; i < d_readers.size (); i++) {
most_data = std::max (most_data, d_readers[i]->items_available ());
+ min_items_read = std::min(min_items_read, d_readers[i]->nitems_read());
+ }
+
+ prune_tags(min_items_read);
// The -1 ensures that the case d_write_index == d_read_index is
// unambiguous. It indicates that there is no data for the reader
@@ -177,6 +182,7 @@ gr_buffer::update_write_pointer (int nitems)
{
gruel::scoped_lock guard(*mutex());
d_write_index = index_add (d_write_index, nitems);
+ d_abs_write_offset += nitems;
}
void
@@ -215,6 +221,40 @@ gr_buffer::drop_reader (gr_buffer_reader *reader)
d_readers.erase (result);
}
+void
+gr_buffer::add_item_tag(const pmt::pmt_t &tag)
+{
+ gruel::scoped_lock guard(*mutex());
+ d_item_tags.push_back(tag);
+}
+
+void
+gr_buffer::prune_tags(uint64_t max_time)
+{
+ /* NOTE: this function _should_ lock the mutex before editing
+ d_item_tags. In practice, this function is only called at
+ runtime by min_available_space in gr_block_executor.cc,
+ which locks the mutex itself.
+
+ If this function is used elsewhere, remember to lock the
+ buffer's mutex al la the scoped_lock line below.
+ */
+ //gruel::scoped_lock guard(*mutex());
+
+ int n = 0;
+ uint64_t item_time;
+ std::deque<pmt::pmt_t>::iterator itr = d_item_tags.begin();
+
+ while(itr != d_item_tags.end()) {
+ item_time = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*itr, 0));
+ if(item_time < max_time) {
+ d_item_tags.pop_front();
+ n++;
+ }
+ itr++;
+ }
+}
+
long
gr_buffer_ncurrently_allocated ()
{
@@ -225,7 +265,7 @@ gr_buffer_ncurrently_allocated ()
gr_buffer_reader::gr_buffer_reader(gr_buffer_sptr buffer, unsigned int read_index,
gr_block_sptr link)
- : d_buffer(buffer), d_read_index(read_index), d_link(link)
+ : d_buffer(buffer), d_read_index(read_index), d_abs_read_offset(0), d_link(link)
{
s_buffer_reader_count++;
}
@@ -253,6 +293,29 @@ gr_buffer_reader::update_read_pointer (int nitems)
{
gruel::scoped_lock guard(*mutex());
d_read_index = d_buffer->index_add (d_read_index, nitems);
+ d_abs_read_offset += nitems;
+}
+
+void
+gr_buffer_reader::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ uint64_t abs_start,
+ uint64_t abs_end)
+{
+ gruel::scoped_lock guard(*mutex());
+
+ v.resize(0);
+ std::deque<pmt::pmt_t>::iterator itr = d_buffer->get_tags_begin();
+
+ uint64_t item_time;
+ while(itr != d_buffer->get_tags_end()) {
+ item_time = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*itr, 0));
+
+ if((item_time >= abs_start) && (item_time <= abs_end)) {
+ v.push_back(*itr);
+ }
+
+ itr++;
+ }
}
long
diff --git a/gnuradio-core/src/lib/runtime/gr_buffer.h b/gnuradio-core/src/lib/runtime/gr_buffer.h
index 207bfe7c5..fe0e7585d 100644
--- a/gnuradio-core/src/lib/runtime/gr_buffer.h
+++ b/gnuradio-core/src/lib/runtime/gr_buffer.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -26,6 +26,7 @@
#include <gr_runtime_types.h>
#include <boost/weak_ptr.hpp>
#include <gruel/thread.h>
+#include <gruel/pmt.h>
class gr_vmcircbuf;
@@ -88,6 +89,26 @@ class gr_buffer {
gruel::mutex *mutex() { return &d_mutex; }
+ uint64_t nitems_written() { return d_abs_write_offset; }
+
+
+ /*!
+ * \brief Adds a new tag to the buffer.
+ *
+ * \param tag a PMT tuple containing the new tag
+ */
+ void add_item_tag(const pmt::pmt_t &tag);
+
+ /*!
+ * \brief Removes all tags before \p max_time from buffer
+ *
+ * \param max_time the time (item number) to trim up until.
+ */
+ void prune_tags(uint64_t max_time);
+
+ std::deque<pmt::pmt_t>::iterator get_tags_begin() { return d_item_tags.begin(); }
+ std::deque<pmt::pmt_t>::iterator get_tags_end() { return d_item_tags.end(); }
+
// -------------------------------------------------------------------------
private:
@@ -106,11 +127,15 @@ class gr_buffer {
boost::weak_ptr<gr_block> d_link; // block that writes to this buffer
//
- // The mutex protects d_write_index, d_done and the d_read_index's in the buffer readers.
+ // The mutex protects d_write_index, d_abs_write_offset, d_done, d_item_tags
+ // and the d_read_index's and d_abs_read_offset's in the buffer readers.
//
gruel::mutex d_mutex;
unsigned int d_write_index; // in items [0,d_bufsize)
+ uint64_t d_abs_write_offset; // num items written since the start
bool d_done;
+ std::deque<pmt::pmt_t> d_item_tags;
+
unsigned
index_add (unsigned a, unsigned b)
@@ -220,11 +245,31 @@ class gr_buffer_reader {
gruel::mutex *mutex() { return d_buffer->mutex(); }
+ uint64_t nitems_read() { return d_abs_read_offset; }
+
/*!
* \brief Return the block that reads via this reader.
+ *
*/
gr_block_sptr link() { return gr_block_sptr(d_link); }
+
+ /*!
+ * \brief Given a [start,end), returns a vector all tags in the range.
+ *
+ * Get a vector of tags in given range. Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ uint64_t abs_start,
+ uint64_t abs_end);
+
// -------------------------------------------------------------------------
private:
@@ -236,6 +281,7 @@ class gr_buffer_reader {
gr_buffer_sptr d_buffer;
unsigned int d_read_index; // in items [0,d->buffer.d_bufsize)
+ uint64_t d_abs_read_offset; // num items seen since the start
boost::weak_ptr<gr_block> d_link; // block that reads via this buffer reader
//! constructor is private. Use gr_buffer::add_reader to create instances
diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
index 031eb6dfd..5d1057e0f 100644
--- a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
+++ b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
@@ -264,16 +264,13 @@ void gr_flat_flowgraph::dump()
int no = detail->noutputs();
for (int i = 0; i < no; i++) {
gr_buffer_sptr buffer = detail->output(i);
- std::cout << " output " << i << ": " << buffer
- << " space=" << buffer->space_available() << std::endl;
+ std::cout << " output " << i << ": " << buffer << std::endl;
}
for (int i = 0; i < ni; i++) {
gr_buffer_reader_sptr reader = detail->input(i);
std::cout << " reader " << i << ": " << reader
- << " reading from buffer=" << reader->buffer()
- << " avail=" << reader->items_available() << " items"
- << std::endl;
+ << " reading from buffer=" << reader->buffer() << std::endl;
}
}
diff --git a/gnuradio-core/src/lib/runtime/gr_preferences.cc b/gnuradio-core/src/lib/runtime/gr_preferences.cc
index e0be2db62..5f7412248 100644
--- a/gnuradio-core/src/lib/runtime/gr_preferences.cc
+++ b/gnuradio-core/src/lib/runtime/gr_preferences.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2003 Free Software Foundation, Inc.
+ * Copyright 2003,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -77,11 +77,20 @@ gr_preferences::get (const char *key)
static char buf[1024];
FILE *fp = fopen (pathname (key), "r");
- if (fp == 0)
+ if (fp == 0) {
+ perror (pathname (key));
return 0;
+ }
memset (buf, 0, sizeof (buf));
- fread (buf, 1, sizeof (buf) - 1, fp);
+ size_t ret = fread (buf, 1, sizeof (buf) - 1, fp);
+ if(ret == 0) {
+ if(ferror(fp) != 0) {
+ perror (pathname (key));
+ fclose (fp);
+ return 0;
+ }
+ }
fclose (fp);
return buf;
}
@@ -97,6 +106,13 @@ gr_preferences::set (const char *key, const char *value)
return;
}
- fwrite (value, 1, strlen (value), fp);
+ size_t ret = fwrite (value, 1, strlen (value), fp);
+ if(ret == 0) {
+ if(ferror(fp) != 0) {
+ perror (pathname (key));
+ fclose (fp);
+ return;
+ }
+ }
fclose (fp);
};
diff --git a/gnuradio-core/src/lib/runtime/gr_tag_info.cc b/gnuradio-core/src/lib/runtime/gr_tag_info.cc
new file mode 100644
index 000000000..f15329f9b
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_tag_info.cc
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gr_tag_info.h>
+#include <gruel/pmt.h>
+
+namespace gr_tags {
+/*
+ const pmt::pmt_t key_time = pmt::pmt_string_to_symbol("time");
+ const pmt::pmt_t key_sample_rate = pmt::pmt_string_to_symbol("sample_rate");
+ const pmt::pmt_t key_frequency = pmt::pmt_string_to_symbol("frequency");
+ const pmt::pmt_t key_rssi = pmt::pmt_string_to_symbol("rssi");
+ const pmt::pmt_t key_rx_gain = pmt::pmt_string_to_symbol("gain");
+*/
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_tag_info.h b/gnuradio-core/src/lib/runtime/gr_tag_info.h
new file mode 100644
index 000000000..5a1e1555a
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_tag_info.h
@@ -0,0 +1,87 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+#ifndef INCLUDED_GR_TAG_INFO_H
+#define INCLUDED_GR_TAG_INFO_H
+
+#include <gruel/pmt.h>
+
+namespace gr_tags {
+
+ enum {
+ TAG_NITEM_REF = 0,
+ TAG_SRCID_REF,
+ TAG_KEY_REF,
+ TAG_VALUE_REF
+ };
+
+ /*
+ extern const pmt::pmt_t key_time;
+ extern const pmt::pmt_t key_sample_rate;
+ extern const pmt::pmt_t key_frequency;
+ extern const pmt::pmt_t key_rssi;
+ extern const pmt::pmt_t key_gain;
+ */
+
+ /*!
+ * \brief Returns the item \p tag occurred at (as a uint64_t)
+ */
+ static inline uint64_t
+ get_nitems(const pmt::pmt_t &tag) {
+ return pmt::pmt_to_uint64(pmt::pmt_tuple_ref(tag, TAG_NITEM_REF));
+ }
+
+ /*!
+ * \brief Returns the source ID of \p tag (as a PMT)
+ */
+ static inline pmt::pmt_t
+ get_srcid(const pmt::pmt_t &tag) {
+ return pmt::pmt_tuple_ref(tag, TAG_SRCID_REF);
+ }
+
+ /*!
+ * \brief Returns the key of \p tag (as a PMT symbol)
+ */
+ static inline pmt::pmt_t
+ get_key(const pmt::pmt_t &tag) {
+ return pmt::pmt_tuple_ref(tag, TAG_KEY_REF);
+ }
+
+ /*!
+ * \brief Returns the value of \p tag (as a PMT)
+ */
+ static inline pmt::pmt_t
+ get_value(const pmt::pmt_t &tag) {
+ return pmt::pmt_tuple_ref(tag, TAG_VALUE_REF);
+ }
+
+ /*!
+ * \brief Comparison function to test which tag, \p x or \p y, came first in time
+ */
+ static inline bool
+ nitems_compare(pmt::pmt_t x, pmt::pmt_t y) {
+ return get_nitems(x) < get_nitems(y);
+ }
+
+}; /* namespace tags */
+
+#endif /* GR_TAG_INFO */
diff --git a/gnuradio-core/src/lib/runtime/qa_block_tags.cc b/gnuradio-core/src/lib/runtime/qa_block_tags.cc
new file mode 100644
index 000000000..07ce5c276
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/qa_block_tags.cc
@@ -0,0 +1,450 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <qa_block_tags.h>
+#include <gr_block.h>
+#include <gr_top_block.h>
+#include <gr_null_source.h>
+#include <gr_null_sink.h>
+#include <gr_head.h>
+#include <gr_annotator_alltoall.h>
+#include <gr_annotator_1to1.h>
+#include <gr_keep_one_in_n.h>
+#include <gr_firdes.h>
+#include <gruel/pmt.h>
+
+
+// ----------------------------------------------------------------
+
+using namespace pmt;
+
+// set to 1 to turn on debug output
+// The debug output fully checks that the tags seen are what are expected. While
+// this behavior currently works with our implementation, there is no guarentee
+// that the tags will be coming in this specific order, so it's dangerous to
+// rely on this as a test of the tag system working. We would really want to
+// tags we know we should see and then test that they all occur once, but in no
+// particular order.
+#define QA_TAGS_DEBUG 0
+
+void
+qa_block_tags::t0 ()
+{
+ unsigned int N = 1000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_block_sptr snk (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, snk, 0);
+
+ //CPPUNIT_ASSERT_THROW(src->nitems_read(0), std::runtime_error);
+ //CPPUNIT_ASSERT_THROW(src->nitems_written(0), std::runtime_error);
+ CPPUNIT_ASSERT_EQUAL(src->nitems_read(0), (uint64_t)0);
+ CPPUNIT_ASSERT_EQUAL(src->nitems_written(0), (uint64_t)0);
+
+ tb->run();
+
+ CPPUNIT_ASSERT_THROW(src->nitems_read(0), std::invalid_argument);
+ CPPUNIT_ASSERT(src->nitems_written(0) >= N);
+ CPPUNIT_ASSERT_EQUAL(snk->nitems_read(0), (uint64_t)1000);
+ CPPUNIT_ASSERT_THROW(snk->nitems_written(0), std::invalid_argument);
+}
+
+
+void
+qa_block_tags::t1 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_alltoall_sptr ann0 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann3 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann4 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann2, 0);
+ tb->connect(ann1, 0, ann3, 0);
+ tb->connect(ann2, 0, ann4, 0);
+
+ tb->connect(ann3, 0, snk0, 0);
+ tb->connect(ann4, 0, snk1, 0);
+
+ tb->run();
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags3 = ann3->data();
+ std::vector<pmt::pmt_t> tags4 = ann4->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags3.size(), (size_t)8);
+ CPPUNIT_ASSERT_EQUAL(tags4.size(), (size_t)8);
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1, str2;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+ str2 << ann2->name() << ann2->unique_id();
+
+ pmt_t expected_tags3[8];
+ expected_tags3[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags3[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags3[2] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(1));
+ expected_tags3[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags3[4] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags3[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags3[6] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags3[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+
+ pmt_t expected_tags4[8];
+ expected_tags4[0] = mp(pmt_from_uint64(0), mp(str2.str()), mp("seq"), mp(0));
+ expected_tags4[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags4[2] = mp(pmt_from_uint64(10000), mp(str2.str()), mp("seq"), mp(1));
+ expected_tags4[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags4[4] = mp(pmt_from_uint64(20000), mp(str2.str()), mp("seq"), mp(2));
+ expected_tags4[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags4[6] = mp(pmt_from_uint64(30000), mp(str2.str()), mp("seq"), mp(3));
+ expected_tags4[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ std::cout << std::endl << "qa_block_tags::t1" << std::endl;
+
+ // For annotator 3, we know it gets tags from ann0 and ann1, test this
+ for(size_t i = 0; i < tags3.size(); i++) {
+ std::cout << "tags3[" << i << "] = " << tags3[i] << "\t\t" << expected_tags3[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags3[i]), pmt_write_string(expected_tags3[i]));
+ }
+
+ // For annotator 4, we know it gets tags from ann0 and ann2, test this
+ std::cout << std::endl;
+ for(size_t i = 0; i < tags4.size(); i++) {
+ std::cout << "tags4[" << i << "] = " << tags4[i] << "\t\t" << expected_tags4[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags4[i]), pmt_write_string(expected_tags4[i]));
+ }
+#endif
+}
+
+void
+qa_block_tags::t2 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_alltoall_sptr ann0 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann3 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann4 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk2 (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann1, 1);
+ tb->connect(ann1, 0, ann2, 0);
+ tb->connect(ann1, 1, ann3, 0);
+ tb->connect(ann1, 2, ann4, 0);
+
+ tb->connect(ann2, 0, snk0, 0);
+ tb->connect(ann3, 0, snk1, 0);
+ tb->connect(ann4, 0, snk2, 0);
+
+ tb->run();
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags1 = ann1->data();
+ std::vector<pmt::pmt_t> tags2 = ann2->data();
+ std::vector<pmt::pmt_t> tags3 = ann4->data();
+ std::vector<pmt::pmt_t> tags4 = ann4->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags1.size(), (size_t)8);
+
+ // Make sure the rest all have 12 tags
+ CPPUNIT_ASSERT_EQUAL(tags2.size(), (size_t)12);
+ CPPUNIT_ASSERT_EQUAL(tags3.size(), (size_t)12);
+ CPPUNIT_ASSERT_EQUAL(tags4.size(), (size_t)12);
+
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+
+ pmt_t expected_tags2[12];
+ expected_tags2[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags2[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags2[2] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags2[3] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags2[4] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags2[5] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags2[6] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(6));
+ expected_tags2[7] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags2[8] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags2[9] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(9));
+ expected_tags2[10] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+ expected_tags2[11] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ pmt_t expected_tags4[12];
+ expected_tags4[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags4[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags4[2] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags4[3] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(5));
+ expected_tags4[4] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags4[5] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags4[6] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(8));
+ expected_tags4[7] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags4[8] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags4[9] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(11));
+ expected_tags4[10] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+ expected_tags4[11] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ std::cout << std::endl << "qa_block_tags::t2" << std::endl;
+
+ // For annotator[2-4], we know it gets tags from ann0 and ann1
+ // but the tags from the different outputs of ann1 are different for each.
+ // Just testing ann2 and ann4; if they are correct it would be
+ // inconceivable for ann3 to have it wrong.
+ for(size_t i = 0; i < tags2.size(); i++) {
+ std::cout << "tags2[" << i << "] = " << tags2[i] << "\t\t" << expected_tags2[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags2[i]), pmt_write_string(expected_tags2[i]));
+ }
+
+ std::cout << std::endl;
+ for(size_t i = 0; i < tags4.size(); i++) {
+ std::cout << "tags2[" << i << "] = " << tags4[i] << "\t\t" << expected_tags4[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags4[i]), pmt_write_string(expected_tags4[i]));
+ }
+#endif
+}
+
+
+void
+qa_block_tags::t3 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_1to1_sptr ann0 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann3 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann4 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+ tb->connect(head, 0, ann0, 1);
+
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann2, 0);
+ tb->connect(ann1, 0, ann3, 0);
+ tb->connect(ann2, 0, ann4, 0);
+
+ tb->connect(ann3, 0, snk0, 0);
+ tb->connect(ann4, 0, snk1, 0);
+
+ tb->run();
+
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags3 = ann3->data();
+ std::vector<pmt::pmt_t> tags4 = ann4->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags3.size(), (size_t)8);
+ CPPUNIT_ASSERT_EQUAL(tags4.size(), (size_t)8);
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1, str2;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+ str2 << ann2->name() << ann2->unique_id();
+
+ pmt_t expected_tags3[8];
+ expected_tags3[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags3[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags3[2] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(1));
+ expected_tags3[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags3[4] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags3[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags3[6] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags3[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+
+ pmt_t expected_tags4[8];
+ expected_tags4[0] = mp(pmt_from_uint64(0), mp(str2.str()), mp("seq"), mp(0));
+ expected_tags4[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags4[2] = mp(pmt_from_uint64(10000), mp(str2.str()), mp("seq"), mp(1));
+ expected_tags4[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags4[4] = mp(pmt_from_uint64(20000), mp(str2.str()), mp("seq"), mp(2));
+ expected_tags4[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags4[6] = mp(pmt_from_uint64(30000), mp(str2.str()), mp("seq"), mp(3));
+ expected_tags4[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ std::cout << std::endl << "qa_block_tags::t3" << std::endl;
+
+ // For annotator 3, we know it gets tags from ann0 and ann1, test this
+ for(size_t i = 0; i < tags3.size(); i++) {
+ std::cout << "tags3[" << i << "] = " << tags3[i] << "\t\t" << expected_tags3[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags3[i]), pmt_write_string(expected_tags3[i]));
+ }
+
+ // For annotator 4, we know it gets tags from ann0 and ann2, test this
+ std::cout << std::endl;
+ for(size_t i = 0; i < tags4.size(); i++) {
+ std::cout << "tags4[" << i << "] = " << tags4[i] << "\t\t" << expected_tags4[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags4[i]), pmt_write_string(expected_tags4[i]));
+ }
+#endif
+}
+
+
+void
+qa_block_tags::t4 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_1to1_sptr ann0 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann1 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann2 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+
+ // using 1-to-1 tag propagation without having equal number of
+ // ins and outs. Make sure this works; will just exit run early.
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann2, 0);
+ tb->connect(ann1, 0, snk0, 0);
+ tb->connect(ann2, 0, snk1, 0);
+
+ std::cerr << std::endl
+ << "NOTE: This is supposed to produce an error from gr_block_executor"
+ << std::endl;
+ tb->run();
+}
+
+
+void
+qa_block_tags::t5 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(float)));
+ gr_block_sptr head (gr_make_head(sizeof(float), N));
+ gr_annotator_alltoall_sptr ann0 (gr_make_annotator_alltoall(10000, sizeof(float)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(float)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(1000, sizeof(float)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(float)));
+
+ // Rate change blocks
+ gr_keep_one_in_n_sptr dec10 (gr_make_keep_one_in_n(sizeof(float), 10));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann1, 0, dec10, 0);
+ tb->connect(dec10, 0, ann2, 0);
+ tb->connect(ann2, 0, snk0, 0);
+
+ tb->run();
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags1 = ann1->data();
+ std::vector<pmt::pmt_t> tags2 = ann2->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags1.size(), (size_t)4);
+ CPPUNIT_ASSERT_EQUAL(tags2.size(), (size_t)8);
+
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1, str2;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+ str2 << ann2->name() << ann2->unique_id();
+
+ pmt_t expected_tags1[5];
+ expected_tags1[0] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags1[1] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags1[2] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags1[3] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(3));
+
+ pmt_t expected_tags2[10];
+ expected_tags2[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags2[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags2[2] = mp(pmt_from_uint64(1000), mp(str1.str()), mp("seq"), mp(1));
+ expected_tags2[3] = mp(pmt_from_uint64(1000), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags2[4] = mp(pmt_from_uint64(2000), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags2[5] = mp(pmt_from_uint64(2000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags2[6] = mp(pmt_from_uint64(3000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags2[7] = mp(pmt_from_uint64(3000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags2[8] = mp(pmt_from_uint64(4000), mp(str1.str()), mp("seq"), mp(4));
+ expected_tags2[9] = mp(pmt_from_uint64(4000), mp(str0.str()), mp("seq"), mp(4));
+
+ std::cout << std::endl << "qa_block_tags::t5" << std::endl;
+
+ // annotator 1 gets tags from annotator 0
+ std::cout << "tags1.size(): " << tags1.size() << std::endl;
+ for(size_t i = 0; i < tags1.size(); i++) {
+ std::cout << "tags1[" << i << "] = " << tags1[i] << "\t\t" << expected_tags1[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags1[i]), pmt_write_string(expected_tags1[i]));
+ }
+
+ // annotator 2 gets tags from annotators 0 and 1
+ std::cout << std::endl;
+ std::cout << "tags2.size(): " << tags2.size() << std::endl;
+ for(size_t i = 0; i < tags2.size(); i++) {
+ std::cout << "tags2[" << i << "] = " << tags2[i] << "\t\t" << expected_tags2[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags2[i]), pmt_write_string(expected_tags2[i]));
+ }
+#endif
+}
+
diff --git a/gnuradio-core/src/lib/runtime/qa_block_tags.h b/gnuradio-core/src/lib/runtime/qa_block_tags.h
new file mode 100644
index 000000000..b0d211390
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/qa_block_tags.h
@@ -0,0 +1,52 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+#ifndef INCLUDED_QA_BLOCK_TAGS_H
+#define INCLUDED_QA_BLOCK_TAGS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+#include <stdexcept>
+
+class qa_block_tags : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE (qa_block_tags);
+ CPPUNIT_TEST (t0);
+ CPPUNIT_TEST (t1);
+ CPPUNIT_TEST (t2);
+ CPPUNIT_TEST (t3);
+ CPPUNIT_TEST (t4);
+ CPPUNIT_TEST (t5);
+ CPPUNIT_TEST_SUITE_END ();
+
+ private:
+ void t0 ();
+ void t1 ();
+ void t2 ();
+ void t3 ();
+ void t4 ();
+ void t5 ();
+
+};
+
+
+#endif /* INCLUDED_QA_BLOCK_TAGS_H */
diff --git a/gnuradio-core/src/lib/runtime/qa_runtime.cc b/gnuradio-core/src/lib/runtime/qa_runtime.cc
index 31e3a82d6..967d4bfa8 100644
--- a/gnuradio-core/src/lib/runtime/qa_runtime.cc
+++ b/gnuradio-core/src/lib/runtime/qa_runtime.cc
@@ -38,6 +38,7 @@
#include <qa_gr_hier_block2.h>
#include <qa_gr_hier_block2_derived.h>
#include <qa_gr_buffer.h>
+#include <qa_block_tags.h>
CppUnit::TestSuite *
qa_runtime::suite ()
@@ -52,6 +53,7 @@ qa_runtime::suite ()
s->addTest (qa_gr_hier_block2::suite ());
s->addTest (qa_gr_hier_block2_derived::suite ());
s->addTest (qa_gr_buffer::suite ());
+ s->addTest (qa_block_tags::suite ());
return s;
}