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.am10
-rw-r--r--gnuradio-core/src/lib/runtime/gr_basic_block.cc2
-rw-r--r--gnuradio-core/src/lib/runtime/gr_basic_block.h2
-rw-r--r--gnuradio-core/src/lib/runtime/gr_basic_block.i6
-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.i10
-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.cc86
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_executor.h3
-rw-r--r--gnuradio-core/src/lib/runtime/gr_buffer.cc80
-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_hier_block2.cc5
-rw-r--r--gnuradio-core/src/lib/runtime/gr_hier_block2.h2
-rw-r--r--gnuradio-core/src/lib/runtime/gr_hier_block2.i7
-rw-r--r--gnuradio-core/src/lib/runtime/gr_msg_queue.i65
-rw-r--r--gnuradio-core/src/lib/runtime/gr_single_threaded_scheduler.i3
-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/gr_top_block.cc6
-rw-r--r--gnuradio-core/src/lib/runtime/gr_top_block.h7
-rw-r--r--gnuradio-core/src/lib/runtime/gr_top_block.i43
-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
-rw-r--r--gnuradio-core/src/lib/runtime/runtime.i7
28 files changed, 1306 insertions, 42 deletions
diff --git a/gnuradio-core/src/lib/runtime/Makefile.am b/gnuradio-core/src/lib/runtime/Makefile.am
index f67e8843d..0fdb58aff 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,9 +139,9 @@ 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
swiginclude_HEADERS = \
gr_basic_block.i \
gr_block.i \
@@ -158,4 +161,3 @@ swiginclude_HEADERS = \
gr_sync_interpolator.i \
gr_top_block.i \
runtime.i
-endif
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.cc b/gnuradio-core/src/lib/runtime/gr_basic_block.cc
index 2fa1066cb..0e0dad16b 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.cc
@@ -56,7 +56,7 @@ gr_basic_block::~gr_basic_block()
}
gr_basic_block_sptr
-gr_basic_block::basic_block()
+gr_basic_block::to_basic_block()
{
return shared_from_this();
}
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.h b/gnuradio-core/src/lib/runtime/gr_basic_block.h
index b8797fdc6..d059a4bd3 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.h
@@ -81,7 +81,7 @@ public:
std::string name() const { return d_name; }
gr_io_signature_sptr input_signature() const { return d_input_signature; }
gr_io_signature_sptr output_signature() const { return d_output_signature; }
- gr_basic_block_sptr basic_block(); // Needed for Python type coercion
+ gr_basic_block_sptr to_basic_block(); // Needed for Python/Guile type coercion
/*!
* \brief Confirm that ninputs and noutputs is an acceptable combination.
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.i b/gnuradio-core/src/lib/runtime/gr_basic_block.i
index 60e08aac3..03d4725d5 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2006,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -40,13 +40,15 @@ public:
gr_io_signature_sptr input_signature() const;
gr_io_signature_sptr output_signature() const;
long unique_id() const;
- gr_basic_block_sptr basic_block();
+ gr_basic_block_sptr to_basic_block();
bool check_topology (int ninputs, int noutputs);
};
%rename(block_ncurrently_allocated) gr_basic_block_ncurrently_allocated;
long gr_basic_block_ncurrently_allocated();
+#ifdef SWIGPYTHON
%pythoncode %{
gr_basic_block_sptr.__repr__ = lambda self: "<gr_basic_block %s (%d)>" % (self.name(), self.unique_id ())
%}
+#endif
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 c2e2aa4b8..bb0c5f221 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_block.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004 Free Software Foundation, Inc.
+ * Copyright 2004,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -49,12 +49,10 @@ 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; }
};
-
-%pythoncode %{
-gr_block_sptr.__repr__ = lambda self: "<gr_block %s (%d)>" % (self.name(), self.unique_id ())
-gr_block_sptr.block = lambda self: self
-%}
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..a8d0bc1c8 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,79 @@ 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
+ 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 +206,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 +228,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 +272,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 +369,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..03d5a8738 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,8 @@ 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),
+ d_last_min_items_read(0)
{
if (!allocate_buffer (nitems, sizeof_item))
throw std::bad_alloc ();
@@ -156,8 +157,16 @@ 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());
+ }
+
+ if(min_items_read != d_last_min_items_read) {
+ prune_tags(d_last_min_items_read);
+ d_last_min_items_read = 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 +186,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 +225,45 @@ 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());
+ std::deque<pmt::pmt_t>::iterator itr = d_item_tags.begin();
+
+ uint64_t item_time;
+
+ // Since tags are not guarenteed to be in any particular order,
+ // we need to erase here instead of pop_front. An erase in the
+ // middle invalidates all iterators; so this resets the iterator
+ // to find more. Mostly, we wil be erasing from the front and
+ // therefore lose little time this way.
+ 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.erase(itr);
+ itr = d_item_tags.begin();
+ }
+ else
+ itr++;
+ }
+}
+
long
gr_buffer_ncurrently_allocated ()
{
@@ -225,7 +274,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 +302,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..aa26f1e09 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;
+ uint64_t d_last_min_items_read;
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_hier_block2.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2.cc
index e3a25e1a8..d6e317136 100644
--- a/gnuradio-core/src/lib/runtime/gr_hier_block2.cc
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.cc
@@ -61,6 +61,11 @@ gr_hier_block2::self()
return shared_from_this();
}
+gr_hier_block2_sptr
+gr_hier_block2::to_hier_block2()
+{
+ return cast_to_hier_block2_sptr(shared_from_this());
+}
void
gr_hier_block2::connect(gr_basic_block_sptr block)
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.h b/gnuradio-core/src/lib/runtime/gr_hier_block2.h
index f50b1cb94..0a40c36b7 100644
--- a/gnuradio-core/src/lib/runtime/gr_hier_block2.h
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.h
@@ -147,6 +147,8 @@ public:
// This is a public method for ease of code organization, but should be
// ignored by the user.
gr_flat_flowgraph_sptr flatten() const;
+
+ gr_hier_block2_sptr to_hier_block2(); // Needed for Python/Guile type coercion
};
inline gr_hier_block2_sptr cast_to_hier_block2_sptr(gr_basic_block_sptr block) {
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.i b/gnuradio-core/src/lib/runtime/gr_hier_block2.i
index a62f50e84..32b656e24 100644
--- a/gnuradio-core/src/lib/runtime/gr_hier_block2.i
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.i
@@ -34,6 +34,11 @@ gr_hier_block2_sptr gr_make_hier_block2(const std::string name,
gr_io_signature_sptr output_signature)
throw (std::runtime_error);
+// Rename connect and disconnect so that we can more easily build a
+// better interface in scripting land.
+%rename(primitive_connect) gr_hier_block2::connect;
+%rename(primitive_disconnect) gr_hier_block2::disconnect;
+
class gr_hier_block2 : public gr_basic_block
{
private:
@@ -57,4 +62,6 @@ public:
void disconnect_all();
void lock();
void unlock();
+
+ gr_hier_block2_sptr to_hier_block2(); // Needed for Python/Guile type coercion
};
diff --git a/gnuradio-core/src/lib/runtime/gr_msg_queue.i b/gnuradio-core/src/lib/runtime/gr_msg_queue.i
index 9ca92b6ec..c9214bef3 100644
--- a/gnuradio-core/src/lib/runtime/gr_msg_queue.i
+++ b/gnuradio-core/src/lib/runtime/gr_msg_queue.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2005,2009 Free Software Foundation, Inc.
+ * Copyright 2005,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -81,6 +81,7 @@ public:
* functions into the gr.msg_queue wrapper class, so that everything
* appears normal. (An evil laugh is heard in the distance...)
*/
+#ifdef SWIGPYTHON
%inline %{
gr_message_sptr gr_py_msg_queue__delete_head(gr_msg_queue_sptr q) {
gr_message_sptr msg;
@@ -103,3 +104,65 @@ gr_msg_queue_sptr.delete_head = gr_py_msg_queue__delete_head
gr_msg_queue_sptr.insert_tail = gr_py_msg_queue__insert_tail
gr_msg_queue_sptr.handle = gr_py_msg_queue__insert_tail
%}
+#endif // SWIGPYTHON
+
+/*
+ * Similar trickery as above, only this time for Guile
+ */
+#ifdef SWIGGUILE
+
+%{
+ struct arg_holder {
+ gr_msg_queue_sptr q;
+ gr_message_sptr msg;
+ };
+
+ static void *
+ insert_tail_shim(void *arg)
+ {
+ arg_holder *a = (arg_holder *)arg;
+ a->q->insert_tail(a->msg);
+ return 0;
+ }
+
+ static void *
+ delete_head_shim(void *arg)
+ {
+ arg_holder *a = (arg_holder *)arg;
+ a->msg = a->q->delete_head();
+ return 0;
+ }
+%}
+
+%inline %{
+
+ // handle and insert_tail are equivalent
+ static void
+ handle(gr_msg_queue_sptr q, gr_message_sptr msg)
+ {
+ arg_holder a;
+ a.q = q;
+ a.msg = msg;
+ scm_without_guile(insert_tail_shim, (void *) &a);
+ }
+
+ static void
+ insert_tail(gr_msg_queue_sptr q, gr_message_sptr msg)
+ {
+ arg_holder a;
+ a.q = q;
+ a.msg = msg;
+ scm_without_guile(insert_tail_shim, (void *) &a);
+ }
+
+ static gr_message_sptr
+ delete_head(gr_msg_queue_sptr q)
+ {
+ arg_holder a;
+ a.q = q;
+ scm_without_guile(delete_head_shim, (void *) &a);
+ return a.msg;
+ }
+%}
+
+#endif // SWIGGUILE
diff --git a/gnuradio-core/src/lib/runtime/gr_single_threaded_scheduler.i b/gnuradio-core/src/lib/runtime/gr_single_threaded_scheduler.i
index 5e9032449..2378a1880 100644
--- a/gnuradio-core/src/lib/runtime/gr_single_threaded_scheduler.i
+++ b/gnuradio-core/src/lib/runtime/gr_single_threaded_scheduler.i
@@ -42,6 +42,7 @@ class gr_single_threaded_scheduler {
gr_single_threaded_scheduler (const std::vector<gr_block_sptr> &modules);
};
+#ifdef SWIGPYTHON
%inline %{
void sts_pyrun (gr_single_threaded_scheduler_sptr s) {
Py_BEGIN_ALLOW_THREADS; // release global interpreter lock
@@ -49,3 +50,5 @@ class gr_single_threaded_scheduler {
Py_END_ALLOW_THREADS; // acquire global interpreter lock
}
%}
+#endif
+
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/gr_top_block.cc b/gnuradio-core/src/lib/runtime/gr_top_block.cc
index 09e46dfbb..f341525c0 100644
--- a/gnuradio-core/src/lib/runtime/gr_top_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_top_block.cc
@@ -95,3 +95,9 @@ gr_top_block::dump()
{
d_impl->dump();
}
+
+gr_top_block_sptr
+gr_top_block::to_top_block()
+{
+ return cast_to_top_block_sptr(shared_from_this());
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.h b/gnuradio-core/src/lib/runtime/gr_top_block.h
index 8052954e3..ed244cb7c 100644
--- a/gnuradio-core/src/lib/runtime/gr_top_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_top_block.h
@@ -105,6 +105,13 @@ public:
* Displays flattened flowgraph edges and block connectivity
*/
void dump();
+
+ gr_top_block_sptr to_top_block(); // Needed for Python/Guile type coercion
};
+inline gr_top_block_sptr cast_to_top_block_sptr(gr_basic_block_sptr block) {
+ return boost::dynamic_pointer_cast<gr_top_block, gr_basic_block>(block);
+}
+
+
#endif /* INCLUDED_GR_TOP_BLOCK_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.i b/gnuradio-core/src/lib/runtime/gr_top_block.i
index 670e5b5e5..90fa18b94 100644
--- a/gnuradio-core/src/lib/runtime/gr_top_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_top_block.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -42,13 +42,17 @@ public:
void start() throw (std::runtime_error);
void stop();
- void wait();
- void run();
+ //void wait();
+ //void run() throw (std::runtime_error);
void lock();
void unlock() throw (std::runtime_error);
void dump();
+
+ gr_top_block_sptr to_top_block(); // Needed for Python/Guile type coercion
};
+#ifdef SWIGPYTHON
+
%inline %{
void top_block_run_unlocked(gr_top_block_sptr r) throw (std::runtime_error)
{
@@ -64,3 +68,36 @@ void top_block_wait_unlocked(gr_top_block_sptr r) throw (std::runtime_error)
Py_END_ALLOW_THREADS; // acquire global interpreter lock
}
%}
+
+#endif
+
+#ifdef SWIGGUILE
+
+%{
+ struct tb_arg_holder {
+ gr_top_block_sptr tb;
+ };
+
+ static void *
+ tb_wait_shim(void *arg)
+ {
+ tb_arg_holder *a = (tb_arg_holder *)arg;
+ a->tb->wait();
+ return 0;
+ }
+
+%}
+
+%inline %{
+
+ static void
+ top_block_wait_unlocked(gr_top_block_sptr r) throw (std::runtime_error)
+ {
+ tb_arg_holder a;
+ a.tb = r;
+ scm_without_guile(tb_wait_shim, (void *) &a);
+ }
+
+%}
+
+#endif
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;
}
diff --git a/gnuradio-core/src/lib/runtime/runtime.i b/gnuradio-core/src/lib/runtime/runtime.i
index 20cf68a03..ca89b8fbd 100644
--- a/gnuradio-core/src/lib/runtime/runtime.i
+++ b/gnuradio-core/src/lib/runtime/runtime.i
@@ -40,6 +40,13 @@
#include <gr_top_block.h>
%}
+%constant int sizeof_char = sizeof(char);
+%constant int sizeof_short = sizeof(short);
+%constant int sizeof_int = sizeof(int);
+%constant int sizeof_float = sizeof(float);
+%constant int sizeof_double = sizeof(double);
+%constant int sizeof_gr_complex = sizeof(gr_complex);
+
%include <gr_io_signature.i>
%include <gr_buffer.i>
%include <gr_basic_block.i>