diff options
-rw-r--r-- | gr-blocks/grc/blocks_block_tree.xml | 1 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_stream_mux.xml | 75 | ||||
-rw-r--r-- | gr-blocks/include/blocks/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-blocks/include/blocks/stream_mux.h | 69 | ||||
-rw-r--r-- | gr-blocks/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-blocks/lib/stream_mux_impl.cc | 126 | ||||
-rw-r--r-- | gr-blocks/lib/stream_mux_impl.h | 55 | ||||
-rwxr-xr-x | gr-blocks/python/qa_stream_mux.py | 169 | ||||
-rw-r--r-- | gr-blocks/swig/blocks_swig.i | 3 |
9 files changed, 500 insertions, 0 deletions
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml index 557bf64db..8f98f15e0 100644 --- a/gr-blocks/grc/blocks_block_tree.xml +++ b/gr-blocks/grc/blocks_block_tree.xml @@ -78,5 +78,6 @@ <block>blocks_keep_m_in_n.xml</block> <block>blocks_keep_one_in_n.xml</block> <block>blocks_repeat.xml</block> + <block>stream_mux.xml</block> </cat> </cat> diff --git a/gr-blocks/grc/blocks_stream_mux.xml b/gr-blocks/grc/blocks_stream_mux.xml new file mode 100644 index 000000000..5e56a65d9 --- /dev/null +++ b/gr-blocks/grc/blocks_stream_mux.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Stream Mux: +## all types, many inputs, only one output +################################################### + --> +<block> + <name>Stream Mux</name> + <key>blocks_stream_mux</key> + <import>from gnuradio import blocks</import> + <make>blocks.stream_mux($type.size*$vlen, $lengths)</make> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Lengths</name> + <key>lengths</key> + <value>1, 1</value> + <type>int_vector</type> + </param> + <param> + <name>Num Inputs</name> + <key>num_inputs</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$num_inputs > 0</check> + <check>$num_inputs == len($lengths)</check> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + <nports>$num_inputs</nports> + </sink> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/gr-blocks/include/blocks/CMakeLists.txt b/gr-blocks/include/blocks/CMakeLists.txt index 8c14d5a49..7ec0524ae 100644 --- a/gr-blocks/include/blocks/CMakeLists.txt +++ b/gr-blocks/include/blocks/CMakeLists.txt @@ -120,6 +120,7 @@ install(FILES repeat.h short_to_char.h short_to_float.h + stream_mux.h uchar_to_float.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/blocks COMPONENT "blocks_devel" diff --git a/gr-blocks/include/blocks/stream_mux.h b/gr-blocks/include/blocks/stream_mux.h new file mode 100644 index 000000000..905ea3c9f --- /dev/null +++ b/gr-blocks/include/blocks/stream_mux.h @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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_BLOCKS_STREAM_MUX_H +#define INCLUDED_BLOCKS_STREAM_MUX_H + +#include <blocks/api.h> +#include <gr_block.h> +#include <vector> + +namespace gr { + namespace blocks { + + /*! + * \brief Stream muxing block to multiplex many streams into + * one with a specified format. + * + * Muxes N streams together producing an output stream that + * contains N0 items from the first stream, N1 items from the second, + * etc. and repeats: + * + * [N0, N1, N2, ..., Nm, N0, N1, ...] + */ + class BLOCKS_API stream_mux : virtual public gr_block + { + public: + + // gr::blocks::stream_mux::sptr + typedef boost::shared_ptr<stream_mux> sptr; + + /*! + * \brief Creates a stream muxing block to multiplex many streams into + * one with a specified format. + * \ingroup converter_blk + * + * \param itemsize the item size of the stream + * \param length a vector (list/tuple) specifying the number of + * items from each stream the mux together. + * Warning: this requires that at least as many items + * per stream are available or the system will wait + * indefinitely for the items. + * + */ + static sptr make(size_t itemsize, const std::vector<int> &lengths); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_BLOCKS_STREAM_MUX_H */ diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt index 9b0043d4b..72e09d5f9 100644 --- a/gr-blocks/lib/CMakeLists.txt +++ b/gr-blocks/lib/CMakeLists.txt @@ -157,6 +157,7 @@ list(APPEND gr_blocks_sources repeat_impl.cc short_to_char_impl.cc short_to_float_impl.cc + stream_mux_impl.cc uchar_array_to_float.cc uchar_to_float_impl.cc ) diff --git a/gr-blocks/lib/stream_mux_impl.cc b/gr-blocks/lib/stream_mux_impl.cc new file mode 100644 index 000000000..214734c4b --- /dev/null +++ b/gr-blocks/lib/stream_mux_impl.cc @@ -0,0 +1,126 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 "stream_mux_impl.h" +#include <gr_io_signature.h> +#include <string.h> +#include <cstdio> + +#define VERBOSE 0 + +namespace gr { + namespace blocks { + + stream_mux::sptr stream_mux::make(size_t itemsize, const std::vector<int> &lengths) + { + return gnuradio::get_initial_sptr(new stream_mux_impl(itemsize, lengths)); + } + + stream_mux_impl::stream_mux_impl(size_t itemsize, const std::vector<int> &lengths) + : gr_block("stream_mux", + gr_make_io_signature (1, -1, itemsize), + gr_make_io_signature (1, 1, itemsize)), + d_itemsize(itemsize), + d_stream(0), + d_residual(0), + d_lengths(lengths) + { + if(d_lengths[d_stream] == 0) { + increment_stream(); + } + d_residual = d_lengths[d_stream]; + } + + void + stream_mux_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size (); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = (d_lengths[i] == 0 ? 0 : 1); + } + + void + stream_mux_impl::increment_stream() + { + do { + d_stream = (d_stream+1) % d_lengths.size(); + } while(d_lengths[d_stream] == 0); + + d_residual = d_lengths[d_stream]; + } + + + int + stream_mux_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + char *out = (char *) output_items[0]; + const char *in; + int out_index = 0; + std::vector<int> input_index(d_lengths.size(), 0); + + if(VERBOSE) { + printf("mux: nouput_items: %d d_stream: %d\n", noutput_items, d_stream); + for(size_t i = 0; i < d_lengths.size(); i++) + printf("\tninput_items[%zu]: %d\n", i, ninput_items[i]); + } + + while (1) { + int r = std::min(noutput_items - out_index, + std::min(d_residual, + ninput_items[d_stream] - input_index[d_stream])); + if(VERBOSE) { + printf("mux: r=%d\n", r); + printf("\tnoutput_items - out_index: %d\n", + noutput_items - out_index); + printf("\td_residual: %d\n", + d_residual); + printf("\tninput_items[d_stream] - input_index[d_stream]: %d\n", + ninput_items[d_stream] - input_index[d_stream]); + } + + if(r <= 0) { + return out_index; + } + + in = (const char *) input_items[d_stream] + input_index[d_stream]*d_itemsize; + + memcpy(&out[out_index*d_itemsize], in, r*d_itemsize); + out_index += r; + input_index[d_stream] += r; + d_residual -= r; + + consume(d_stream, r); + + if(d_residual == 0) { + increment_stream(); + } + } + } + } /* namespace blocks */ +} /* namespace gr */ diff --git a/gr-blocks/lib/stream_mux_impl.h b/gr-blocks/lib/stream_mux_impl.h new file mode 100644 index 000000000..7b2dac95c --- /dev/null +++ b/gr-blocks/lib/stream_mux_impl.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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_STREAM_MUX_IMPL_H +#define INCLUDED_STREAM_MUX_IMPL_H + +#include <blocks/stream_mux.h> + +namespace gr { + namespace blocks { + + class BLOCKS_API stream_mux_impl : public stream_mux + { + private: + size_t d_itemsize; + unsigned int d_stream; // index of currently selected stream + int d_residual; // number if items left to put into current stream + gr_vector_int d_lengths; // number if items to pack per stream + + void increment_stream(); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + public: + stream_mux_impl(size_t itemsize, const std::vector<int> &lengths); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_STREAM_MUX_IMPL_H */ diff --git a/gr-blocks/python/qa_stream_mux.py b/gr-blocks/python/qa_stream_mux.py new file mode 100755 index 000000000..f21a9bbbc --- /dev/null +++ b/gr-blocks/python/qa_stream_mux.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005,2007,2010,2012 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. +# + +from gnuradio import gr, gr_unittest +import blocks_swig + +class test_stream_mux (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def help_stream_2ff(self, N, stream_sizes): + v0 = gr.vector_source_f(N*[1,], False) + v1 = gr.vector_source_f(N*[2,], False) + + mux = blocks_swig.stream_mux(gr.sizeof_float, stream_sizes) + + dst = gr.vector_sink_f () + + self.tb.connect (v0, (mux,0)) + self.tb.connect (v1, (mux,1)) + self.tb.connect (mux, dst) + self.tb.run () + + return dst.data () + + def help_stream_ramp_2ff(self, N, stream_sizes): + r1 = range(N) + r2 = range(N) + r2.reverse() + + v0 = gr.vector_source_f(r1, False) + v1 = gr.vector_source_f(r2, False) + + mux = blocks_swig.stream_mux(gr.sizeof_float, stream_sizes) + + dst = gr.vector_sink_f () + + self.tb.connect (v0, (mux,0)) + self.tb.connect (v1, (mux,1)) + self.tb.connect (mux, dst) + self.tb.run () + + return dst.data () + + def test_stream_2NN_ff(self): + N = 40 + stream_sizes = [10, 10] + result_data = self.help_stream_2ff(N, stream_sizes) + + exp_data = (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0) + self.assertEqual (exp_data, result_data) + + def test_stream_ramp_2NN_ff(self): + N = 40 + stream_sizes = [10, 10] + result_data = self.help_stream_ramp_2ff(N, stream_sizes) + + exp_data = ( 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, + 39.0, 38.0, 37.0, 36.0, 35.0, 34.0, 33.0, 32.0, 31.0, 30.0, + 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, + 29.0, 28.0, 27.0, 26.0, 25.0, 24.0, 23.0, 22.0, 21.0, 20.0, + 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, + 19.0, 18.0, 17.0, 16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0, + 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, + 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0) + self.assertEqual (exp_data, result_data) + + def test_stream_2NM_ff(self): + N = 40 + stream_sizes = [7, 9] + self.help_stream_2ff(N, stream_sizes) + + result_data = self.help_stream_2ff(N, stream_sizes) + + exp_data = (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0) + + self.assertEqual (exp_data, result_data) + + + def test_stream_2MN_ff(self): + N = 37 + stream_sizes = [7, 9] + self.help_stream_2ff(N, stream_sizes) + + result_data = self.help_stream_2ff(N, stream_sizes) + + exp_data = (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0) + + self.assertEqual (exp_data, result_data) + + def test_stream_2N0_ff(self): + N = 30 + stream_sizes = [7, 0] + self.help_stream_2ff(N, stream_sizes) + + result_data = self.help_stream_2ff(N, stream_sizes) + + exp_data = (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0) + + self.assertEqual (exp_data, result_data) + + def test_stream_20N_ff(self): + N = 30 + stream_sizes = [0, 9] + self.help_stream_2ff(N, stream_sizes) + + result_data = self.help_stream_2ff(N, stream_sizes) + + exp_data = (2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, + 2.0, 2.0, 2.0) + + self.assertEqual (exp_data, result_data) + +if __name__ == '__main__': + gr_unittest.run(test_stream_mux, "test_stream_mux.xml") diff --git a/gr-blocks/swig/blocks_swig.i b/gr-blocks/swig/blocks_swig.i index 3161dd773..a99d90d4f 100644 --- a/gr-blocks/swig/blocks_swig.i +++ b/gr-blocks/swig/blocks_swig.i @@ -98,6 +98,7 @@ #include "blocks/repeat.h" #include "blocks/short_to_char.h" #include "blocks/short_to_float.h" +#include "blocks/stream_mux.h" #include "blocks/sub_ff.h" #include "blocks/sub_ss.h" #include "blocks/sub_ii.h" @@ -178,6 +179,7 @@ %include "blocks/repeat.h" %include "blocks/short_to_char.h" %include "blocks/short_to_float.h" +%include "blocks/stream_mux.h" %include "blocks/sub_ff.h" %include "blocks/sub_ss.h" %include "blocks/sub_ii.h" @@ -257,6 +259,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, or_ii); GR_SWIG_BLOCK_MAGIC2(blocks, repeat); GR_SWIG_BLOCK_MAGIC2(blocks, short_to_char); GR_SWIG_BLOCK_MAGIC2(blocks, short_to_float); +GR_SWIG_BLOCK_MAGIC2(blocks, stream_mux); GR_SWIG_BLOCK_MAGIC2(blocks, sub_ff); GR_SWIG_BLOCK_MAGIC2(blocks, sub_ss); GR_SWIG_BLOCK_MAGIC2(blocks, sub_ii); |