summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/lib/runtime/gr_block.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core/src/lib/runtime/gr_block.cc')
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.cc459
1 files changed, 459 insertions, 0 deletions
diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc
new file mode 100644
index 000000000..443ac8f64
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_block.cc
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2012-2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "pmx_helper.hpp"
+#include <gr_block.h>
+#include <boost/foreach.hpp>
+#include <iostream>
+#include <boost/detail/atomic_count.hpp>
+
+static boost::detail::atomic_count unique_id_pool(0);
+
+gr_block::gr_block(void)
+{
+ //NOP
+}
+
+gr_block::gr_block(
+ const std::string &name,
+ gr_io_signature_sptr input_signature,
+ gr_io_signature_sptr output_signature
+):
+ gras::Block(name),
+ _unique_id(++unique_id_pool),
+ _name(name)
+{
+ //this initializes private vars, order matters
+ this->set_fixed_rate(false);
+ this->set_output_multiple(1);
+ this->set_history(1);
+ this->set_relative_rate(1.0);
+ this->set_decimation(1);
+ this->set_interpolation(1);
+ this->set_tag_propagation_policy(TPP_ALL_TO_ALL);
+ this->set_input_signature(input_signature);
+ this->set_output_signature(output_signature);
+}
+
+gr_io_signature_sptr gr_block::input_signature(void) const
+{
+ return _in_sig;
+}
+
+gr_io_signature_sptr gr_block::output_signature(void) const
+{
+ return _out_sig;
+}
+
+void gr_block::set_input_signature(gr_io_signature_sptr sig)
+{
+ for (size_t i = 0; i < sig->sizeof_stream_items().size(); i++)
+ {
+ this->input_config(i).item_size = sig->sizeof_stream_items().at(i);
+ }
+ _in_sig = sig;
+}
+
+void gr_block::set_output_signature(gr_io_signature_sptr sig)
+{
+ for (size_t i = 0; i < sig->sizeof_stream_items().size(); i++)
+ {
+ this->output_config(i).item_size = sig->sizeof_stream_items().at(i);
+ }
+ _out_sig = sig;
+}
+
+gr_block::~gr_block(void)
+{
+ //NOP
+}
+
+void gr_block::notify_active(void)
+{
+ this->start();
+}
+
+bool gr_block::start(void)
+{
+ return true;
+}
+
+void gr_block::notify_inactive(void)
+{
+ this->stop();
+}
+
+bool gr_block::stop(void)
+{
+ return true;
+}
+
+void gr_block::notify_topology(const size_t num_inputs, const size_t num_outputs)
+{
+ _num_outputs = num_outputs;
+ _fcast_ninput_items.resize(num_inputs);
+ _work_ninput_items.resize(num_inputs);
+ this->check_topology(num_inputs, num_outputs);
+}
+
+bool gr_block::check_topology(int, int)
+{
+ return true;
+}
+
+void gr_block::work(
+ const InputItems &input_items,
+ const OutputItems &output_items
+){
+ _work_io_ptr_mask = 0;
+ #define REALLY_BIG size_t(1 << 30)
+ const size_t num_inputs = input_items.size();
+ const size_t num_outputs = output_items.size();
+
+ //------------------------------------------------------------------
+ //-- initialize input buffers before work
+ //------------------------------------------------------------------
+ size_t num_input_items = input_items.min();
+ if (_enable_fixed_rate) num_input_items -= _input_history_items;
+ for (size_t i = 0; i < num_inputs; i++)
+ {
+ _work_ninput_items[i] = input_items[i].size();
+ _work_io_ptr_mask |= ptrdiff_t(input_items.vec()[i]);
+ if GRAS_UNLIKELY(_enable_fixed_rate and input_items[i].size() <= _input_history_items)
+ {
+ return this->mark_input_fail(i);
+ }
+ }
+
+ //------------------------------------------------------------------
+ //-- initialize output buffers before work
+ //------------------------------------------------------------------
+ size_t num_output_items = output_items.min();
+ num_output_items /= _output_multiple_items;
+ num_output_items *= _output_multiple_items;
+ for (size_t i = 0; i < num_outputs; i++)
+ {
+ _work_io_ptr_mask |= ptrdiff_t(output_items.vec()[i]);
+ }
+
+ //------------------------------------------------------------------
+ //-- calculate the work_noutput_items given:
+ //-- min of num_input_items
+ //-- min of num_output_items
+ //-- relative rate and output multiple items
+ //------------------------------------------------------------------
+ size_t work_noutput_items = num_output_items;
+ if (num_inputs and (_enable_fixed_rate or not num_outputs))
+ {
+ size_t calc_output_items = size_t(num_input_items*_relative_rate);
+ calc_output_items += _output_multiple_items-1;
+ calc_output_items /= _output_multiple_items;
+ calc_output_items *= _output_multiple_items;
+ if (calc_output_items and calc_output_items < work_noutput_items)
+ work_noutput_items = calc_output_items;
+ }
+
+ //------------------------------------------------------------------
+ //-- forecast
+ //------------------------------------------------------------------
+ if (num_inputs or num_outputs)
+ {
+ forecast_again_you_jerk:
+ _fcast_ninput_items = _work_ninput_items; //init for NOP case
+ this->forecast(work_noutput_items, _fcast_ninput_items);
+ for (size_t i = 0; i < input_items.size(); i++)
+ {
+ if GRAS_LIKELY(_fcast_ninput_items[i] <= _work_ninput_items[i]) continue;
+
+ //handle the case of forecast failing
+ if GRAS_UNLIKELY(work_noutput_items <= _output_multiple_items)
+ {
+ return this->mark_input_fail(i);
+ }
+
+ work_noutput_items = work_noutput_items/2; //backoff regime
+ work_noutput_items += _output_multiple_items-1;
+ work_noutput_items /= _output_multiple_items;
+ work_noutput_items *= _output_multiple_items;
+ goto forecast_again_you_jerk;
+ }
+ }
+
+ const int work_ret = this->general_work(
+ work_noutput_items,
+ _work_ninput_items,
+ const_cast<InputItems &>(input_items).vec(),
+ const_cast<OutputItems &>(output_items).vec()
+ );
+
+ if GRAS_LIKELY(work_ret > 0) for (size_t i = 0; i < num_outputs; i++)
+ {
+ this->produce(i, work_ret);
+ }
+
+ if GRAS_UNLIKELY(work_ret == -1) this->mark_done();
+}
+
+static inline unsigned long long myullround(const double x)
+{
+ return (unsigned long long)(x + 0.5);
+}
+
+void gr_block::propagate_tags(const size_t which_input, const gras::TagIter &iter)
+{
+ switch (_tag_prop_policy)
+ {
+ case TPP_DONT: break; //well that was ez
+ case TPP_ALL_TO_ALL:
+ for (size_t out_i = 0; out_i < _num_outputs; out_i++)
+ {
+ BOOST_FOREACH(gras::Tag t, iter)
+ {
+ t.offset = myullround(t.offset * _relative_rate);
+ this->post_output_tag(out_i, t);
+ }
+ }
+ break;
+ case TPP_ONE_TO_ONE:
+ if (which_input < _num_outputs)
+ {
+ BOOST_FOREACH(gras::Tag t, iter)
+ {
+ t.offset = myullround(t.offset * _relative_rate);
+ this->post_output_tag(which_input, t);
+ }
+ }
+ break;
+ };
+}
+
+void gr_block::forecast(int noutput_items, std::vector<int> &ninputs_req)
+{
+ for (size_t i = 0; i < ninputs_req.size(); i++)
+ {
+ ninputs_req[i] = fixed_rate_noutput_to_ninput(noutput_items);
+ }
+}
+
+int gr_block::general_work(
+ int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+){
+ throw std::runtime_error("gr_block subclasses must overload general_work!");
+}
+
+void gr_block::set_alignment(const size_t)
+{
+ //TODO
+ //probably dont need this since buffers always start aligned
+ //and therefore alignment is always re-acheived
+}
+
+size_t gr_block::fixed_rate_noutput_to_ninput(const size_t noutput_items)
+{
+ return ((decimation()*noutput_items)/interpolation()) + _input_history_items;
+}
+
+void gr_block::set_interpolation(const size_t interp)
+{
+ _interp = interp;
+ this->set_relative_rate(1.0*interp);
+ this->set_output_multiple(interp);
+}
+
+void gr_block::set_decimation(const size_t decim)
+{
+ _decim = decim;
+ this->set_relative_rate(1.0/decim);
+}
+
+unsigned gr_block::history(void) const
+{
+ //implement off-by-one history compat
+ return _input_history_items+1;
+}
+
+void gr_block::set_history(unsigned history)
+{
+ //implement off-by-one history compat
+ if (history == 0) history++;
+ _input_history_items = history-1;
+ this->input_config(0).preload_items = _input_history_items;
+ this->commit_config();
+}
+
+void gr_block::set_fixed_rate(const bool fixed_rate)
+{
+ _enable_fixed_rate = fixed_rate;
+}
+
+bool gr_block::fixed_rate(void) const
+{
+ return _enable_fixed_rate;
+}
+
+void gr_block::_update_input_reserve(void)
+{
+ /*!
+ * Set an input reserve for fixed rate blocks.
+ *
+ * FIXME: Also do this when output multiple is large,
+ * This makes gr-trellis pass under conditions where not fixed rate set,
+ * but the output multiple is so large that default input isnt sufficient.
+ */
+ if (_enable_fixed_rate or _output_multiple_items > 1024)
+ {
+ const size_t reserve = size_t(0.5 + _output_multiple_items/_relative_rate);
+ if (reserve) this->input_config(0).reserve_items = reserve;
+ }
+}
+
+void gr_block::set_output_multiple(const size_t multiple)
+{
+ _output_multiple_items = multiple;
+ this->output_config(0).reserve_items = multiple;
+ this->_update_input_reserve();
+}
+
+size_t gr_block::output_multiple(void) const
+{
+ return _output_multiple_items;
+}
+
+void gr_block::set_relative_rate(double relative_rate)
+{
+ _relative_rate = relative_rate;
+ this->_update_input_reserve();
+}
+
+double gr_block::relative_rate(void) const
+{
+ return _relative_rate;
+}
+
+int gr_block::max_noutput_items(void) const
+{
+ return this->output_config(0).maximum_items;
+}
+
+void gr_block::set_max_noutput_items(int max_items)
+{
+ this->output_config(0).maximum_items = max_items;
+}
+
+void gr_block::unset_max_noutput_items(void)
+{
+ this->set_max_noutput_items(0);
+}
+
+bool gr_block::is_set_max_noutput_items(void) const
+{
+ return this->max_noutput_items() != 0;
+}
+
+static gr_tag_t Tag2gr_tag(const gras::Tag &tag)
+{
+ gr_tag_t t;
+ t.offset = tag.offset;
+ const gras::StreamTag &st = tag.object.as<gras::StreamTag>();
+ t.key = pmt::pmc_to_pmt(st.key);
+ t.value = pmt::pmc_to_pmt(st.val);
+ t.srcid = pmt::pmc_to_pmt(st.src);
+ return t;
+}
+
+static gras::Tag gr_tag2Tag(const gr_tag_t &tag)
+{
+ return gras::Tag
+ (
+ tag.offset,
+ PMC_M(gras::StreamTag(
+ pmt::pmt_to_pmc(tag.key),
+ pmt::pmt_to_pmc(tag.value),
+ pmt::pmt_to_pmc(tag.srcid)
+ ))
+ );
+}
+
+void gr_block::add_item_tag(
+ const size_t which_output, const gr_tag_t &tag
+){
+ this->post_output_tag(which_output, gr_tag2Tag(tag));
+}
+
+void gr_block::add_item_tag(
+ const size_t which_output,
+ uint64_t abs_offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid
+){
+ gr_tag_t t;
+ t.offset = abs_offset;
+ t.key = key;
+ t.value = value;
+ t.srcid = srcid;
+ this->add_item_tag(which_output, t);
+}
+
+void gr_block::get_tags_in_range(
+ std::vector<gr_tag_t> &tags,
+ const size_t which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt::pmt_t &key
+){
+ tags.clear();
+ BOOST_FOREACH(const gras::Tag &tag, this->get_input_tags(which_input))
+ {
+ if (tag.offset >= abs_start and tag.offset <= abs_end)
+ {
+ gr_tag_t t = Tag2gr_tag(tag);
+ if (not key or pmt::pmt_equal(t.key, key)) tags.push_back(t);
+ }
+ }
+}
+
+gr_block::tag_propagation_policy_t gr_block::tag_propagation_policy(void)
+{
+ return _tag_prop_policy;
+}
+
+void gr_block::set_tag_propagation_policy(gr_block::tag_propagation_policy_t p)
+{
+ _tag_prop_policy = p;
+}
+
+gras::BufferQueueSptr gr_block::input_buffer_allocator(const size_t, const gras::SBufferConfig &config)
+{
+ if (_input_history_items)
+ {
+ return gras::BufferQueue::make_circ(config, 32/*many*/);
+ }
+ return gras::BufferQueueSptr();
+}
+
+gras::BufferQueueSptr gr_block::output_buffer_allocator(const size_t which, const gras::SBufferConfig &config)
+{
+ return gras::Block::output_buffer_allocator(which, config);
+}