diff options
author | Johnathan Corgan <johnathan@corganlabs.com> | 2015-04-02 11:55:14 -0700 |
---|---|---|
committer | Johnathan Corgan <johnathan@corganlabs.com> | 2015-04-02 11:55:14 -0700 |
commit | 50b66458748057fe19dca5b736cc9ece331905d0 (patch) | |
tree | 6e17ea3b893501c59d89608ffbc2dbfe9e3797b1 | |
parent | c6b430aec86325991239b0378a74eba508d0f0a7 (diff) | |
parent | f1281442c99ecdcae548f427559431cb637582dd (diff) |
Merge branch 'master' into next
49 files changed, 3172 insertions, 106 deletions
diff --git a/gnuradio-runtime/include/gnuradio/hier_block2.h b/gnuradio-runtime/include/gnuradio/hier_block2.h index 1bf8dddc1a..3a74a37d6d 100644 --- a/gnuradio-runtime/include/gnuradio/hier_block2.h +++ b/gnuradio-runtime/include/gnuradio/hier_block2.h @@ -56,6 +56,7 @@ namespace gr { * \brief Private implementation details of gr::hier_block2 */ hier_block2_detail *d_detail; + protected: hier_block2(void) {} // allows pure virtual interface sub-classes @@ -170,6 +171,37 @@ namespace gr { */ virtual void unlock(); + /*! + * \brief Returns max buffer size (itemcount) on output port \p i. + */ + size_t max_output_buffer(size_t i=0); + + /*! + * \brief Sets max buffer size (itemcount) on all output ports. + */ + void set_max_output_buffer(size_t max_output_buffer); + + /*! + * \brief Sets max buffer size (itemcount) on output port \p port. + */ + void set_max_output_buffer(int port, size_t max_output_buffer); + + /*! + * \brief Returns min buffer size (itemcount) on output port \p i. + */ + size_t min_output_buffer(size_t i=0); + + /*! + * \brief Sets min buffer size (itemcount) on all output ports. + */ + void set_min_output_buffer(size_t min_output_buffer); + + /*! + * \brief Sets min buffer size (itemcount) on output port \p port. + */ + void set_min_output_buffer(int port, size_t min_output_buffer); + + // This is a public method for ease of code organization, but should be // ignored by the user. flat_flowgraph_sptr flatten() const; @@ -233,6 +265,22 @@ namespace gr { * call could be misleading. */ std::vector<int> processor_affinity(); + + /*! + * \brief Get if all block min buffers should be set. + * + * \details this returns whether all the block min output buffers + * should be set or just the block ports connected to the hier ports. + */ + bool all_min_output_buffer_p(void); + + /*! + * \brief Get if all block max buffers should be set. + * + * \details this returns whether all the block max output buffers + * should be set or just the block ports connected to the hier ports. + */ + bool all_max_output_buffer_p(void); }; /*! diff --git a/gnuradio-runtime/lib/flat_flowgraph.cc b/gnuradio-runtime/lib/flat_flowgraph.cc index 9e5964cb7d..b580238b7c 100644 --- a/gnuradio-runtime/lib/flat_flowgraph.cc +++ b/gnuradio-runtime/lib/flat_flowgraph.cc @@ -50,6 +50,7 @@ namespace gr { flat_flowgraph::flat_flowgraph() { + configure_default_loggers(d_logger, d_debug_logger, "flat_flowgraph"); } flat_flowgraph::~flat_flowgraph() @@ -107,6 +108,13 @@ namespace gr { detail->set_output(i, buffer); // Update the block's max_output_buffer based on what was actually allocated. + if((grblock->max_output_buffer(i) != buffer->bufsize()) && (grblock->max_output_buffer(i) != -1)) + GR_LOG_WARN(d_logger, boost::format("Block (%1%) max output buffer set to %2% instead of requested %3%") \ + % grblock->alias() % buffer->bufsize() % grblock->max_output_buffer(i)); + //std::cout << ">>> Warning: Block (" << grblock->alias() + // << ") max output buffer set to " << buffer->bufsize() + // << " instead of requested " << grblock->max_output_buffer(i) + // << std::endl; grblock->set_max_output_buffer(i, buffer->bufsize()); } diff --git a/gnuradio-runtime/lib/flat_flowgraph.h b/gnuradio-runtime/lib/flat_flowgraph.h index 6c299ee5f9..fad14279ae 100644 --- a/gnuradio-runtime/lib/flat_flowgraph.h +++ b/gnuradio-runtime/lib/flat_flowgraph.h @@ -26,6 +26,7 @@ #include <gnuradio/api.h> #include <gnuradio/flowgraph.h> #include <gnuradio/block.h> +#include <gnuradio/logger.h> namespace gr { @@ -89,6 +90,9 @@ namespace gr { * start and restarts. */ void setup_buffer_alignment(block_sptr block); + + gr::logger_ptr d_logger; + gr::logger_ptr d_debug_logger; }; } /* namespace gr */ diff --git a/gnuradio-runtime/lib/hier_block2.cc b/gnuradio-runtime/lib/hier_block2.cc index f145b9344b..4d2c460c12 100644 --- a/gnuradio-runtime/lib/hier_block2.cc +++ b/gnuradio-runtime/lib/hier_block2.cc @@ -182,4 +182,97 @@ namespace gr { return dot_graph_fg(hierblock2->flatten()); } + size_t + hier_block2::max_output_buffer(size_t i) + { + if(i >= d_detail->d_max_output_buffer.size()) + throw std::invalid_argument("hier_block2::max_output_buffer: port out of range."); + return d_detail->d_max_output_buffer[i]; + } + + void + hier_block2::set_max_output_buffer(size_t max_output_buffer) + { + if(output_signature()->max_streams()>0) + { + if(d_detail->d_max_output_buffer.size() == 0) + throw std::length_error("hier_block2::max_output_buffer: out_sig greater than zero, buff_vect isn't"); + for(size_t idx = 0; idx < output_signature()->max_streams(); idx++){ + d_detail->d_max_output_buffer[idx] = max_output_buffer; + } + } + } + + void + hier_block2::set_max_output_buffer(int port, size_t max_output_buffer) + { + if((size_t)port >= d_detail->d_max_output_buffer.size()) + throw std::invalid_argument("hier_block2::max_output_buffer: port out of range."); + else{ + d_detail->d_max_output_buffer[port] = max_output_buffer; + } + } + + size_t + hier_block2::min_output_buffer(size_t i) + { + if(i >= d_detail->d_min_output_buffer.size()) + throw std::invalid_argument("hier_block2::min_output_buffer: port out of range."); + return d_detail->d_min_output_buffer[i]; + } + + void + hier_block2::set_min_output_buffer(size_t min_output_buffer) + { + if(output_signature()->max_streams()>0) + { + if(d_detail->d_min_output_buffer.size() == 0) + throw std::length_error("hier_block2::min_output_buffer: out_sig greater than zero, buff_vect isn't"); + for(size_t idx = 0; idx < output_signature()->max_streams(); idx++){ + d_detail->d_min_output_buffer[idx] = min_output_buffer; + } + } + } + + void + hier_block2::set_min_output_buffer(int port, size_t min_output_buffer) + { + if((size_t)port >= d_detail->d_min_output_buffer.size()) + throw std::invalid_argument("hier_block2::min_output_buffer: port out of range."); + else{ + d_detail->d_min_output_buffer[port] = min_output_buffer; + } + } + + bool + hier_block2::all_min_output_buffer_p(void) + { + if(d_detail->d_min_output_buffer.size() > 0){ + bool all_equal = true; + for(int idx = 1; (idx < d_detail->d_min_output_buffer.size()) && all_equal; idx++){ + if(d_detail->d_min_output_buffer[0] != d_detail->d_min_output_buffer[idx]) + all_equal = false; + } + return all_equal; + } + else{ + return false; + } + } + bool + hier_block2::all_max_output_buffer_p(void) + { + if(d_detail->d_max_output_buffer.size() > 0){ + bool all_equal = true; + for(int idx = 1; (idx < d_detail->d_max_output_buffer.size()) && all_equal; idx++){ + if(d_detail->d_max_output_buffer[0] != d_detail->d_max_output_buffer[idx]) + all_equal = false; + } + return all_equal; + } + else{ + return false; + } + } + } /* namespace gr */ diff --git a/gnuradio-runtime/lib/hier_block2_detail.cc b/gnuradio-runtime/lib/hier_block2_detail.cc index ad8fc87122..a735de3fff 100644 --- a/gnuradio-runtime/lib/hier_block2_detail.cc +++ b/gnuradio-runtime/lib/hier_block2_detail.cc @@ -56,6 +56,9 @@ namespace gr { d_inputs = std::vector<endpoint_vector_t>(max_inputs); d_outputs = endpoint_vector_t(max_outputs); + + d_max_output_buffer = std::vector<size_t>(std::max(max_outputs,1), 0); + d_min_output_buffer = std::vector<size_t>(std::max(max_outputs,1), 0); } hier_block2_detail::~hier_block2_detail() @@ -513,6 +516,24 @@ namespace gr { // Only run setup_rpc if ControlPort config param is enabled. bool ctrlport_on = prefs::singleton()->get_bool("ControlPort", "on", false); + + size_t min_buff(0), max_buff(0); + // Determine how the buffers should be set + bool set_all_min_buff = d_owner->all_min_output_buffer_p(); + bool set_all_max_buff = d_owner->all_max_output_buffer_p(); + // Get the min and max buffer length + if(set_all_min_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Getting (" << (d_owner->alias()).c_str() + << ") min buffer" << std::endl; + min_buff = d_owner->min_output_buffer(); + } + if(set_all_max_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Getting (" << (d_owner->alias()).c_str() + << ") max buffer" << std::endl; + max_buff = d_owner->max_output_buffer(); + } // For every block (gr::block and gr::hier_block2), set up the RPC // interface. @@ -526,6 +547,60 @@ namespace gr { b->rpc_set(); } } + if(set_all_min_buff){ + //sets the min buff for every block within hier_block2 + if(min_buff != 0){ + block_sptr bb = boost::dynamic_pointer_cast<block>(b); + if(bb != 0){ + if(bb->min_output_buffer(0) != min_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block (" << (bb->alias()).c_str() + << ") min_buff (" << min_buff + << ")" << std::endl; + bb->set_min_output_buffer(min_buff); + } + } + else{ + hier_block2_sptr hh = boost::dynamic_pointer_cast<hier_block2>(b); + if(hh != 0){ + if(hh->min_output_buffer(0) != min_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "HBlock (" << (hh->alias()).c_str() + << ") min_buff (" << min_buff + << ")" << std::endl; + hh->set_min_output_buffer(min_buff); + } + } + } + } + } + if(set_all_max_buff){ + //sets the max buff for every block within hier_block2 + if(max_buff != 0){ + block_sptr bb = boost::dynamic_pointer_cast<block>(b); + if(bb != 0){ + if(bb->max_output_buffer(0) != max_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block (" << (bb->alias()).c_str() + << ") max_buff (" << max_buff + << ")" << std::endl; + bb->set_max_output_buffer(max_buff); + } + } + else{ + hier_block2_sptr hh = boost::dynamic_pointer_cast<hier_block2>(b); + if(hh != 0){ + if(hh->max_output_buffer(0) != max_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "HBlock (" << (hh->alias()).c_str() + << ") max_buff (" << max_buff + << ")" << std::endl; + hh->set_max_output_buffer(max_buff); + } + } + } + } + } b = p->dst().block(); if(ctrlport_on) { @@ -534,6 +609,60 @@ namespace gr { b->rpc_set(); } } + if(set_all_min_buff){ + //sets the min buff for every block within hier_block2 + if(min_buff != 0){ + block_sptr bb = boost::dynamic_pointer_cast<block>(b); + if(bb != 0){ + if(bb->min_output_buffer(0) != min_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block (" << (bb->alias()).c_str() + << ") min_buff (" << min_buff + << ")" << std::endl; + bb->set_min_output_buffer(min_buff); + } + } + else{ + hier_block2_sptr hh = boost::dynamic_pointer_cast<hier_block2>(b); + if(hh != 0){ + if(hh->min_output_buffer(0) != min_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "HBlock (" << (hh->alias()).c_str() + << ") min_buff (" << min_buff + << ")" << std::endl; + hh->set_min_output_buffer(min_buff); + } + } + } + } + } + if(set_all_max_buff){ + //sets the max buff for every block within hier_block2 + if(max_buff != 0){ + block_sptr bb = boost::dynamic_pointer_cast<block>(b); + if(bb != 0){ + if(bb->max_output_buffer(0) != max_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block (" << (bb->alias()).c_str() + << ") max_buff (" << max_buff + << ")" << std::endl; + bb->set_max_output_buffer(max_buff); + } + } + else{ + hier_block2_sptr hh = boost::dynamic_pointer_cast<hier_block2>(b); + if(hh != 0){ + if(hh->max_output_buffer(0) != max_buff){ + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "HBlock (" << (hh->alias()).c_str() + << ") max_buff (" << max_buff + << ")" << std::endl; + hh->set_max_output_buffer(max_buff); + } + } + } + } + } } if(HIER_BLOCK2_DETAIL_DEBUG) @@ -641,6 +770,61 @@ namespace gr { << " is not connected internally"; throw std::runtime_error(msg.str()); } + // Set the buffers of only the blocks connected to the hier output + if(!set_all_min_buff){ + min_buff = d_owner->min_output_buffer(i); + if(min_buff != 0){ + block_sptr bb = boost::dynamic_pointer_cast<block>(blk); + if(bb != 0){ + int bb_src_port = d_outputs[i].port(); + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block (" << (bb->alias()).c_str() + << ") Port (" << bb_src_port + << ") min_buff (" << min_buff + << ")" << std::endl; + bb->set_min_output_buffer(bb_src_port, min_buff); + } + else{ + hier_block2_sptr hh = boost::dynamic_pointer_cast<hier_block2>(blk); + if(hh != 0){ + int hh_src_port = d_outputs[i].port(); + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "HBlock (" << (hh->alias()).c_str() + << ") Port (" << hh_src_port + << ") min_buff ("<< min_buff + << ")" << std::endl; + hh->set_min_output_buffer(hh_src_port, min_buff); + } + } + } + } + if(!set_all_max_buff){ + max_buff = d_owner->max_output_buffer(i); + if(max_buff != 0){ + block_sptr bb = boost::dynamic_pointer_cast<block>(blk); + if(bb != 0){ + int bb_src_port = d_outputs[i].port(); + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block (" << (bb->alias()).c_str() + << ") Port (" << bb_src_port + << ") max_buff (" << max_buff + << ")" << std::endl; + bb->set_max_output_buffer(bb_src_port, max_buff); + } + else{ + hier_block2_sptr hh = boost::dynamic_pointer_cast<hier_block2>(blk); + if(hh != 0){ + int hh_src_port = d_outputs[i].port(); + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "HBlock (" << (hh->alias()).c_str() + << ") Port (" << hh_src_port + << ") max_buff (" << max_buff + << ")" << std::endl; + hh->set_max_output_buffer(hh_src_port, max_buff); + } + } + } + } tmp.push_back(blk); } sort(tmp.begin(), tmp.end()); diff --git a/gnuradio-runtime/lib/hier_block2_detail.h b/gnuradio-runtime/lib/hier_block2_detail.h index 806738360f..8c38c3754a 100644 --- a/gnuradio-runtime/lib/hier_block2_detail.h +++ b/gnuradio-runtime/lib/hier_block2_detail.h @@ -57,6 +57,10 @@ namespace gr { void set_processor_affinity(const std::vector<int> &mask); void unset_processor_affinity(); std::vector<int> processor_affinity(); + + // Track output buffer min/max settings + std::vector<size_t> d_max_output_buffer; + std::vector<size_t> d_min_output_buffer; private: // Private implementation data diff --git a/gnuradio-runtime/swig/hier_block2.i b/gnuradio-runtime/swig/hier_block2.i index 053f24721d..12190d0452 100644 --- a/gnuradio-runtime/swig/hier_block2.i +++ b/gnuradio-runtime/swig/hier_block2.i @@ -91,6 +91,14 @@ namespace gr { void unset_processor_affinity(); std::vector<int> processor_affinity(); + // Methods to manage block's min/max buffer sizes. + size_t max_output_buffer(int i); + void set_max_output_buffer(size_t max_output_buffer); + void set_max_output_buffer(int port, size_t max_output_buffer); + size_t min_output_buffer(int i); + void set_min_output_buffer(size_t min_output_buffer); + void set_min_output_buffer(int port, size_t min_output_buffer); + gr::hier_block2_sptr to_hier_block2(); // Needed for Python type coercion }; diff --git a/gr-digital/grc/digital_chunks_to_symbols.xml b/gr-digital/grc/digital_chunks_to_symbols.xml index 494be274df..9c6f952ec0 100644 --- a/gr-digital/grc/digital_chunks_to_symbols.xml +++ b/gr-digital/grc/digital_chunks_to_symbols.xml @@ -9,6 +9,7 @@ <key>digital_chunks_to_symbols_xx</key> <import>from gnuradio import digital</import> <make>digital.chunks_to_symbols_$(in_type.fcn)$(out_type.fcn)($symbol_table, $dimension)</make> + <callback>set_symbol_table($symbol_table)</callback> <param> <name>Input Type</name> <key>in_type</key> diff --git a/gr-digital/include/gnuradio/digital/chunks_to_symbols_XX.h.t b/gr-digital/include/gnuradio/digital/chunks_to_symbols_XX.h.t index c6f2060c34..6683ea94fc 100644 --- a/gr-digital/include/gnuradio/digital/chunks_to_symbols_XX.h.t +++ b/gr-digital/include/gnuradio/digital/chunks_to_symbols_XX.h.t @@ -68,6 +68,7 @@ namespace gr { virtual int D() const = 0; virtual std::vector<@O_TYPE@> symbol_table() const = 0; + virtual void set_symbol_table(const std::vector<@O_TYPE@> &symbol_table) =0; }; } /* namespace digital */ diff --git a/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t b/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t index fd334b99d7..b08bdde08f 100644 --- a/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t +++ b/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t @@ -87,7 +87,7 @@ namespace gr { void - @IMPL_NAME@::set_symbol_table(std::vector<@O_TYPE@> &symbol_table) + @IMPL_NAME@::set_symbol_table(const std::vector<@O_TYPE@> &symbol_table) { d_symbol_table.resize(0); for (unsigned int i=0; i<symbol_table.size(); i++) { diff --git a/gr-digital/lib/chunks_to_symbols_XX_impl.h.t b/gr-digital/lib/chunks_to_symbols_XX_impl.h.t index 031bb6947c..e0857bfb3c 100644 --- a/gr-digital/lib/chunks_to_symbols_XX_impl.h.t +++ b/gr-digital/lib/chunks_to_symbols_XX_impl.h.t @@ -45,7 +45,7 @@ namespace gr { void set_vector_from_pmt(std::vector<gr_complex> &symbol_table, pmt::pmt_t &symbol_table_pmt); void handle_set_symbol_table(pmt::pmt_t symbol_table_pmt); - void set_symbol_table(std::vector<@O_TYPE@> &symbol_table); + void set_symbol_table(const std::vector<@O_TYPE@> &symbol_table); int D() const { return d_D; } std::vector<@O_TYPE@> symbol_table() const { return d_symbol_table; } diff --git a/gr-digital/python/digital/qa_chunks_to_symbols.py b/gr-digital/python/digital/qa_chunks_to_symbols.py index d6a9566807..0d80f71d6c 100755 --- a/gr-digital/python/digital/qa_chunks_to_symbols.py +++ b/gr-digital/python/digital/qa_chunks_to_symbols.py @@ -136,6 +136,39 @@ class test_chunks_to_symbols(gr_unittest.TestCase): actual_result = dst.data() self.assertEqual(expected_result, actual_result) + + def test_sf_callback(self): + constA = [-3, -1, 1, 3] + constB = [12, -12, 6, -6] + src_data = (0, 1, 2, 3, 3, 2, 1, 0) + expected_result=(12, -12, 6, -6, -6, 6, -12, 12) + + src = blocks.vector_source_s(src_data, False, 1, "") + op = digital.chunks_to_symbols_sf(constA) + op.set_symbol_table(constB) + dst = blocks.vector_sink_f() + self.tb.connect(src, op) + self.tb.connect(op, dst) + self.tb.run() + actual_result = dst.data() + self.assertEqual(expected_result, actual_result) + + def test_sc_callback(self): + constA = [-3.0+1j, -1.0-1j, 1.0+1j, 3-1j] + constB = [12.0+1j, -12.0-1j, 6.0+1j, -6-1j] + src_data = (0, 1, 2, 3, 3, 2, 1, 0) + expected_result=(12.0+1j, -12.0-1j, 6.0+1j, -6-1j, -6-1j, 6+1j, -12-1j, 12+1j) + + src = blocks.vector_source_s(src_data, False, 1, "") + op = digital.chunks_to_symbols_sc(constA) + op.set_symbol_table(constB) + dst = blocks.vector_sink_c() + self.tb.connect(src, op) + self.tb.connect(op, dst) + self.tb.run() + actual_result = dst.data() + self.assertEqual(expected_result, actual_result) + def test_sf_tag(self): constA = [-3.0, -1.0, 1.0, 3] constB = [12.0, -12.0, 6.0, -6] diff --git a/gr-fec/examples/271.127.3.112 b/gr-fec/examples/271.127.3.112 new file mode 100644 index 0000000000..205d5adab1 --- /dev/null +++ b/gr-fec/examples/271.127.3.112 @@ -0,0 +1,402 @@ +271 127 +3 7 +3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 +121 50 63 +20 1 68 +98 56 60 +48 99 57 +53 31 59 +93 101 46 +47 15 2 +9 49 75 +38 39 77 +118 16 55 +76 13 40 +29 54 91 +48 23 114 +94 24 68 +100 114 21 +127 19 34 +44 8 33 +3 123 50 +78 100 79 +59 81 98 +67 39 37 +124 54 47 +7 27 64 +67 28 74 +51 75 118 +5 88 55 +45 81 18 +66 103 99 +41 82 102 +65 123 86 +118 25 119 +60 78 113 +89 110 87 +88 30 22 +4 14 44 +110 102 17 +122 125 70 +46 22 109 +16 90 97 +35 73 58 +102 3 119 +127 11 10 +59 36 111 +37 50 78 +34 73 101 +92 74 29 +79 26 40 +97 22 100 +65 84 12 +26 55 9 +38 21 31 +108 45 70 +3 43 26 +57 105 33 +51 31 74 +69 71 60 +96 124 117 +93 72 71 +13 5 30 +42 86 11 +37 6 95 +12 50 47 +43 113 80 +90 107 9 +24 125 44 +83 82 15 +107 28 21 +7 87 81 +124 104 23 +89 121 98 +5 122 27 +83 38 12 +77 120 76 +4 25 33 +40 114 95 +108 20 23 +37 56 2 +126 89 24 +53 52 10 +120 109 117 +49 64 8 +111 6 77 +70 49 19 +112 96 1 +14 72 10 +36 17 87 +7 32 115 +28 34 5 +72 18 8 +29 49 11 +63 119 13 +83 61 11 +27 17 26 +51 93 82 +39 91 61 +30 110 115 +22 15 28 +115 20 42 +96 67 97 +116 38 105 +27 45 32 +16 3 6 +106 14 88 +58 51 61 +103 29 20 +94 84 117 +6 109 13 +19 66 53 +86 30 57 +48 105 43 +35 12 25 +58 14 18 +44 36 1 +62 46 35 +41 64 69 +113 121 1 +9 127 4 +43 92 42 +52 25 104 +35 7 122 +112 120 36 +65 71 23 +52 54 41 +39 85 32 +32 80 24 +48 123 63 +15 40 31 +90 106 56 +21 45 91 +116 92 68 +112 18 116 +80 125 47 +4 17 2 +106 107 101 +94 108 62 +126 69 99 +41 95 34 +111 19 2 +75 62 42 +104 103 33 +84 85 16 +73 46 76 +10 85 8 +79 126 66 +68 63 3 +59 25 91 +69 2 81 +50 23 89 +69 49 22 +80 98 30 +24 31 127 +88 37 104 +52 18 37 +6 104 65 +40 2 22 +6 81 40 +110 33 51 +110 5 42 +112 84 119 +74 53 63 +60 123 124 +4 104 60 +122 105 55 +43 12 16 +126 44 114 +124 84 118 +57 10 50 +98 108 13 +116 22 126 +54 95 18 +107 19 7 +45 28 118 +61 54 72 +6 39 97 +67 34 93 +10 42 121 +94 91 123 +66 96 40 +75 78 44 +71 49 101 +88 83 26 +20 62 7 +119 87 38 +17 32 100 +63 87 85 +92 30 15 +82 23 60 +113 98 20 +5 73 24 +46 102 89 +71 62 58 +65 9 48 +99 45 62 +86 23 26 +91 117 51 +65 42 36 +87 112 126 +127 50 114 +125 124 102 +41 8 114 +54 77 1 +29 99 33 +111 45 47 +30 14 105 +108 107 116 +19 47 32 +76 122 112 +116 21 64 +72 80 92 +110 14 64 +35 108 78 +55 4 89 +115 82 27 +25 56 27 +17 95 111 +59 43 29 +47 61 16 +39 81 90 +15 35 18 +103 85 13 +106 99 34 +109 66 90 +26 115 31 +120 27 3 +83 70 10 +118 57 4 +41 15 58 +34 36 117 +125 28 53 +109 38 24 +35 20 5 +36 96 16 +72 106 19 +1 46 122 +94 76 97 +106 2 61 +80 48 13 +68 52 74 +94 121 82 +86 113 14 +57 37 107 +44 119 48 +121 68 31 +66 46 125 +77 7 79 +90 3 83 +102 9 73 +84 100 58 +29 73 78 +103 67 11 +33 49 32 +12 8 28 +93 69 97 +120 127 67 +71 75 103 +92 101 52 +105 96 85 +120 75 56 +88 79 53 +17 8 1 +59 64 101 +109 12 79 +77 21 113 +11 93 38 +11 74 70 +41 115 123 +25 117 55 +70 86 100 +43 56 76 +95 9 51 +21 111 39 +260 234 201 116 113 84 2 +236 155 147 138 133 77 7 +246 224 145 102 53 41 18 +226 212 162 133 117 74 35 +231 189 158 88 71 59 26 +174 156 154 107 102 82 61 +245 182 171 120 87 68 23 +260 252 200 143 89 81 17 +270 247 192 117 64 50 8 +225 176 167 143 85 79 42 +265 264 250 92 90 60 42 +262 252 164 111 72 62 49 +237 220 168 107 91 59 11 +240 210 204 112 103 85 35 +227 219 186 127 97 66 7 +232 217 164 141 102 39 10 +260 215 184 133 93 86 36 +219 170 153 131 112 89 27 +233 206 171 138 108 83 16 +231 188 182 105 98 76 2 +271 263 208 129 67 51 15 +169 155 149 97 48 38 34 +194 187 148 122 76 69 13 +230 189 151 125 78 65 14 +267 214 146 119 111 74 31 +223 194 181 93 53 50 47 +224 214 213 101 93 71 23 +252 229 172 97 88 67 24 +249 216 202 105 90 46 12 +204 186 150 109 96 59 34 +243 223 151 127 55 51 5 +251 206 184 125 124 101 87 +251 202 157 140 74 54 17 +228 221 175 137 88 45 16 +231 219 211 120 114 111 40 +232 228 196 121 113 86 43 +241 153 152 77 61 44 21 +264 230 183 100 72 51 9 +271 218 174 124 95 21 9 +178 156 155 127 75 47 11 +266 227 200 137 123 115 29 +196 176 158 139 118 98 60 +269 216 164 118 110 63 53 +242 179 165 113 65 35 17 +203 193 172 129 101 52 27 +244 234 190 142 114 38 6 +217 206 203 132 62 22 7 +242 237 192 126 110 13 4 +251 180 149 90 83 81 8 +198 167 148 62 44 18 1 +270 195 157 104 94 55 25 +256 238 153 123 119 79 0 +259 229 160 108 79 5 0 +201 173 170 123 22 12 0 +267 212 163 50 26 10 0 +269 258 214 128 77 3 0 +241 226 167 109 54 4 0 +248 227 191 112 104 40 0 +261 216 146 43 20 5 0 +187 162 161 56 32 3 0 +236 217 173 104 95 92 0 +193 191 182 139 135 114 0 +185 160 145 126 91 1 0 +261 210 208 115 81 23 0 +196 192 154 122 49 30 0 +244 222 178 144 108 28 0 +254 250 175 99 24 21 0 +243 238 145 130 14 2 0 +253 149 147 136 115 56 0 +268 265 225 83 52 37 0 +255 191 180 122 58 56 0 +233 209 173 89 85 58 0 +249 247 189 142 45 40 0 +265 238 160 55 46 24 0 +258 255 179 139 25 8 0 +269 235 207 142 73 11 0 +263 245 201 82 73 9 0 +249 211 179 44 32 19 0 +262 259 245 144 47 19 0 +237 209 150 132 125 63 0 +218 156 147 68 27 20 0 +239 213 187 94 66 29 0 +246 225 181 92 72 66 0 +248 166 159 141 106 49 0 +257 220 185 143 141 124 0 +268 240 194 109 60 30 0 +197 185 183 86 68 33 0 +259 181 152 103 34 26 0 +212 190 148 78 70 33 0 +246 222 218 128 64 39 0 +195 177 146 129 95 12 0 +256 209 186 130 118 46 0 +264 253 175 94 58 6 0 +239 235 177 135 106 14 0 +270 215 170 137 75 61 0 +257 232 178 99 84 57 0 +253 235 174 99 48 39 0 +188 168 150 70 20 3 0 +221 202 193 136 28 4 0 +268 248 184 48 19 15 0 +261 256 180 134 45 6 0 +247 199 190 41 36 29 0 +255 250 220 140 105 28 0 +162 154 152 140 119 69 0 +257 204 163 110 100 54 0 +236 233 221 134 128 103 0 +241 205 171 134 67 64 0 +211 205 168 135 76 52 0 +262 230 222 107 80 38 0 +210 158 157 96 36 33 0 +271 215 203 138 82 43 0 +207 197 159 131 121 84 0 +263 240 188 116 63 32 0 +200 198 165 75 15 13 0 +266 223 213 98 96 87 0 +208 205 169 131 130 100 0 +267 228 195 106 80 57 0 +226 172 166 31 25 10 0 +242 183 159 91 41 31 0 +258 254 224 121 80 73 0 +243 239 176 116 70 1 0 +234 207 163 120 71 37 0 +266 177 161 126 30 18 0 +199 166 161 69 57 22 0 +244 229 199 132 65 37 0 +197 169 165 144 136 78 0 +254 198 151 117 42 16 0 diff --git a/gr-fec/grc/fec_block_tree.xml b/gr-fec/grc/fec_block_tree.xml index c674531e3f..97610f08c8 100644 --- a/gr-fec/grc/fec_block_tree.xml +++ b/gr-fec/grc/fec_block_tree.xml @@ -12,6 +12,7 @@ <name>Decoders</name> <block>variable_cc_decoder_def</block> <block>variable_repetition_decoder_def</block> + <block>variable_ldpc_decoder_def</block> <block>variable_dummy_decoder_def</block> </cat> <cat> @@ -19,6 +20,7 @@ <block>variable_cc_encoder_def</block> <block>variable_ccsds_encoder_def</block> <block>variable_repetition_encoder_def</block> + <block>variable_ldpc_encoder_def</block> <block>variable_dummy_encoder_def</block> </cat> <block>fec_extended_encoder</block> diff --git a/gr-fec/grc/ldpc_decoder_def_list.xml b/gr-fec/grc/ldpc_decoder_def_list.xml new file mode 100644 index 0000000000..22df93909f --- /dev/null +++ b/gr-fec/grc/ldpc_decoder_def_list.xml @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<!-- +################################################### +# FEC MAKING FOR GREAT JUSTICE +################################################### + --> +<block> + <name>LDPC Decoder Definition</name> + <key>variable_ldpc_decoder_def</key> + <import>from gnuradio import fec</import> + <var_make> +#if int($ndim())==0 # +self.$(id) = $(id) = fec.ldpc_decoder.make($file, $sigma, $max_iter); #slurp +#else if int($ndim())==1 # +self.$(id) = $(id) = map( (lambda a: fec.ldpc_decoder.make($file, $sigma, $max_iter)), range(0,$dim1) ); #slurp +#else +self.$(id) = $(id) = map( (lambda b: map( ( lambda a: fec.ldpc_decoder.make($file, $sigma, $max_iter)), range(0,$dim2) ) ), range(0,$dim1)); #slurp +#end if</var_make> + <make></make> + +<!-- This definition below is wierd, it seems required for the GRC to be happy, im confused --> + <param> + <name>Ignore Me</name> + <key>value</key> + <value>"ok"</value> + <type>raw</type> + <hide>all</hide> + </param> + + <param> + <name>Parallelism</name> + <key>ndim</key> + <value>0</value> + <type>enum</type> + <option> + <name>0</name> + <key>0</key> + </option> + <option> + <name>1</name> + <key>1</key> + </option> + <option> + <name>2</name> + <key>2</key> + </option> + </param> + + <param> + <name>Dimension 1</name> + <key>dim1</key> + <value>4</value> + <type>int</type> + <hide>#if (int($ndim()) >= 1) then 'none' else 'all' #</hide> + </param> + + <param> + <name>Dimension 2</name> + <key>dim2</key> + <value>4</value> + <type>int</type> + <hide>#if (int($ndim()) >= 2) then 'none' else 'all' #</hide> + </param> + + <param> + <name>AList File</name> + <key>file</key> + <type>file_open</type> + </param> + + <param> + <name>Sigma</name> + <key>sigma</key> + <value>0.5</value> + <type>float</type> + </param> + + <param> + <name>Max Iterations</name> + <key>max_iter</key> + <value>50</value> + <type>int</type> + </param> + + <doc> + This block does some kind of ldpc + </doc> +</block> diff --git a/gr-fec/grc/ldpc_encoder_def_list.xml b/gr-fec/grc/ldpc_encoder_def_list.xml new file mode 100755 index 0000000000..5975f781dd --- /dev/null +++ b/gr-fec/grc/ldpc_encoder_def_list.xml @@ -0,0 +1,75 @@ +<?xml version="1.0"?> +<!-- +################################################### +# FEC MAKING FOR GREAT JUSTICE +################################################### + --> +<block> + <name>LDPC Encoder Definition</name> + <key>variable_ldpc_encoder_def</key> + <import>from gnuradio import fec</import> + <var_make> +#if int($ndim())==0 # +self.$(id) = $(id) = fec.ldpc_encoder_make($file); #slurp +#else if int($ndim())==1 # +self.$(id) = $(id) = map( (lambda a: fec.ldpc_encoder_make($file)), range(0,$dim1) ); #slurp +#else +self.$(id) = $(id) = map( (lambda b: map( ( lambda a: fec.ldpc_encoder_make($file)), range(0,$dim2) ) ), range(0,$dim1)); #slurp +#end if</var_make> + <var_value>fec.ldpc_encoder_make($file)</var_value> + <make></make> + +<!-- This definition below is wierd, it seems required for the GRC to be happy, im confused --> + <param> + <name>Ignore Me</name> + <key>value</key> + <value>"ok"</value> + <type>raw</type> + <hide>all</hide> + </param> + + <param> + <name>Parallelism</name> + <key>ndim</key> + <value>0</value> + <type>enum</type> + <option> + <name>0</name> + <key>0</key> + </option> + <option> + <name>1</name> + <key>1</key> + </option> + <option> + <name>2</name> + <key>2</key> + </option> + </param> + + <param> + <name>Dimension 1</name> + <key>dim1</key> + <value>1</value> + <type>int</type> + <hide>#if (int($ndim()) >= 1) then 'none' else 'all' #</hide> + </param> + + <param> + <name>Dimension 2</name> + <key>dim2</key> + <value>4</value> + <type>int</type> + <hide>#if (int($ndim()) >= 2) then 'none' else 'all' #</hide> + </param> + + <param> + <name>AList File</name> + <key>file</key> + <type>file_open</type> + </param> + + <doc> + This block does LDPC + </doc> +</block> diff --git a/gr-fec/include/gnuradio/fec/alist.h b/gr-fec/include/gnuradio/fec/alist.h new file mode 100644 index 0000000000..85f6a79cd7 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/alist.h @@ -0,0 +1,121 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + + /* ----------------------------------------------------------------- + * + * This class handles sparse matrices specified in alist-format. + * For details about alist format please visit the link below. + * - http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html + * + * Alist class is an efficient way of representing a sparse matrix + * the parity check matrix H of an LDPC code for instance. + * + */ + +#ifndef ALIST_H +#define ALIST_H + +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> +#include <stdlib.h> +#include <gnuradio/fec/api.h> + +class FEC_API alist +{ + public: + + //! Default Constructor + alist() : data_ok(false) {} + + //! Constructor which loads alist class from an alist-file + alist(const char * fname); + + //! Read alist data from a file + void read(const char * fname); + + //! Write alist data to a file + void write(const char * fname) const; + + //! Retuns N, the number of variable nodes + int get_N(); + + //! Return M, the number of check nodes + int get_M(); + + //! Return the m_list variable + std::vector< std::vector<int> > get_mlist(); + + //! Returns the n_list variable + std::vector< std::vector<int> > get_nlist(); + + //! Returns the num_mlist variable + std::vector<int> get_num_mlist(); + + //! Returns the num_nlist variable + std::vector<int> get_num_nlist(); + + //! Returns the max_num_nlist variable + int get_max_num_nlist(); + + //! Returns the max_num_mlist variable + int get_max_num_mlist(); + + //! Prints the nlist[i] variable + void print_nlist_i(int i); + + //! Prints the mlist[i] variable + void print_mlist_i(int i); + + //! Returns the corresponding H matrix + std::vector<std::vector<char> > get_matrix(); + + protected: + //! A variable indicating if data has been read from alist-file + bool data_ok; + + //! Number of variable nodes + int N; + + //! Number of check nodes + int M; + + //! Maximum weight of rows + int max_num_mlist; + + //! Maximum weight of columns + int max_num_nlist; + + //! Weight of each column n + std::vector<int> num_nlist; + + //! Weight of each row m + std::vector<int> num_mlist; + + //! List of integer coordinates along each rows with non-zero entries + std::vector< std::vector<int> > mlist; + + //! List of integer coordinates along each column with non-zero entries + std::vector< std::vector<int> > nlist; +}; +#endif // ifndef ALIST_H diff --git a/gr-fec/include/gnuradio/fec/awgn_bp.h b/gr-fec/include/gnuradio/fec/awgn_bp.h new file mode 100644 index 0000000000..f420d76394 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/awgn_bp.h @@ -0,0 +1,175 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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. + */ + +/* ----------------------------------------------------------------- + * + * This class defines functions for message passing mechanism for a + * AWGN channel. Message passing (also known as belief propagation) + * is used for decoding LDPC codes. Details of how LDPC codes are + * decoded is available in the link below + * - http://www.cs.utoronto.ca/~radford/ftp/LDPC-2012-02-11/decoding.html + * + * Belief propagation decoding is a suboptimal but efficient method of + * decoding LDPC codes. + * + */ + +#ifndef AWGN_BP_H +#define AWGN_BP_H + +#include <vector> +#include <cmath> +#include <iostream> +#include "gf2mat.h" +#include "alist.h" +#include <gnuradio/fec/api.h> + +class FEC_API awgn_bp +{ + public: + //! Default constructor + awgn_bp () {}; + + //! A constructor for given GF2Mat and sigma + awgn_bp (const GF2Mat X, float sgma); + + //! A constructor for given alist and sigma + awgn_bp (alist _list, float sgma); + + //! Initializes the class using given alist and sigma + void set_alist_sigma(alist _list, float sgma); + + //! Returns the variable Q + std::vector< std::vector<double> > get_Q(); + + //! Returns the variable R + std::vector< std::vector<double> > get_R(); + + //! Returns the variable H + GF2Mat get_H(); + + //! Calculates the likelihood ratios given an input vector + void rx_lr_calc(std::vector<float> codeword); + + //! Returns the variable rx_lr + std::vector<double> get_rx_lr(); + + //! Returns the variable lr + std::vector<double> get_lr(); + + //! Initializes the sum product algorithm set-up + void spa_initialize(); + + //! Updates the check-nodes based on messages from variable nodes + void update_chks(); + + //! Updates the variable-nodes based on messages from check nodes + void update_vars(); + + //! Returns the current estimate + std::vector<char> get_estimate(); + + //! Computes initial estimate based on the vector rx_word + void compute_init_estimate(std::vector<float> rx_word); + + //! Computes the estimate based on current likelihood-ratios lr + void decision(); + + //! Returns the syndrome for the current estimate + std::vector<char> get_syndrome(); + + //! Returns the syndrome for the input codeword + std::vector<char> get_syndrome(const std::vector<char> codeword); + + //! Checks if the current estimate is a codeword + bool is_codeword(); + + //! Checks if the input is a codeword + bool is_codeword(const std::vector<char> codeword); + + //! Sets the variable K + void set_K(int k); + + //! Returns the variable K + int get_K(); + + //! Sets the variable max_iterations + void set_max_iterations(int k); + + //! Returns the variable max_iterations + int get_max_iterations(); + + /*! + \brief Decodes the given vector rx_word by message passing. + + \param *niterations is the number of message passing iterations + done to decode this codeword + */ + std::vector<char> decode (std::vector<float> rx_word, + int *niterations); + private: + //! The number of check nodes in the tanner-graph + int M; + + //! The number of variable nodes in the tanner-graph + int N; + + //! The dimension of the code used + int K; + + //! The maximum number of message passing iterations allowed + int max_iterations; + + //! The parity check matrix of the LDPC code + GF2Mat H; + + //! The standard-deviation of the AWGN channel + float sigma; + + //! Matrix holding messages from check nodes to variable nodes + std::vector< std::vector<double> > R; + + //! Matrix holding messages from variable nodes to check nodes + std::vector< std::vector<double> > Q; + + //! The array of likelihood computed from the channel output + std::vector<double> rx_lr; + + //! The array for holding likelihoods computed on BP decoding + std::vector<double> lr; + + //! List of integer coordinates along each column with non-zero entries + std::vector < std::vector<int> > nlist; + + //! List of integer coordinates along each row with non-zero entries + std::vector < std::vector<int> > mlist; + + //! Weight of each column n + std::vector <int> num_nlist; + + //! Weight of each row m + std::vector <int> num_mlist; + + //! The array for holding estimate computed on BP decoding + std::vector<char> estimate; +}; +#endif // ifndef AWGN_BP_H diff --git a/gr-fec/include/gnuradio/fec/cldpc.h b/gr-fec/include/gnuradio/fec/cldpc.h new file mode 100644 index 0000000000..6bc7c02343 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/cldpc.h @@ -0,0 +1,115 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 LDPC_H +#define LDPC_H + +#include <iostream> +#include <vector> + +#include "gnuradio/fec/gf2vec.h" +#include "gnuradio/fec/gf2mat.h" +#include "gnuradio/fec/alist.h" + + +#include <gnuradio/fec/api.h> +class FEC_API cldpc +{ + public: + //! Default constructor + cldpc() {}; + + //! Constructs the LDPC class from given GF2mat X + cldpc(const GF2Mat X); + + //! Constructs the class from the given alist _list + cldpc(const alist _list); + + //! Prints the variable permute + void print_permute(); + + /*! + \brief Encode the given vector dataword. + + dataword is of length K where K is the dimension of the code. + The function returns a vector of length N where N is the + block-length of the code. + + For encoding a G matrix in the form [I P] is obtained from the + parity matrix H, by (a) Column permutations, (b) Row additions + and (c) Row permutations. Details of encoding is given in + section A.1 of the reference given below. + - "Modern Coding Theory", T Richardson and R Urbanke. + */ + std::vector<char> encode(std::vector<char> dataword); + + //! Returns the dimension of the code + int dimension(); + + //! Returns the parity check matrix H + GF2Mat get_H(); + + //! Returns the matrix G used in encoding + GF2Mat get_G(); + + //! Returns the variable M + int get_M(); + + //! Returns the variable N + int get_N(); + + //! Returns the syndrome for a given vector "in" + std::vector<char> syndrome(const std::vector<char> in); + + //! Returns true if "in" is a codeword, else false + bool is_codeword(const std::vector<char> in); + + //! Set the variable _list + void set_alist(const alist _list); + + //! Obtain systematic bits from "in" + std::vector<char> get_systematic_bits(std::vector<char> in); + + private: + //! The parity check matrix + GF2Mat H; + + //! An equivalent matrix obtained from H used for encoding + GF2Mat G; + + //! Stores the column permutation in obtaining G from H + std::vector<int> permute; + + //! Rank of the H matrix + int rank_H; + + //! The number of check nodes in the Tanner-graph + int M; + + //! The number of variable nodes in the Tanner-graph + int N; + + //! The dimension of the code + size_t K; +}; + +#endif // ifndef LDPC_H diff --git a/gr-fec/include/gnuradio/fec/generic_decoder.h b/gr-fec/include/gnuradio/fec/generic_decoder.h index 0e14d49e76..bfce85a8c1 100644 --- a/gr-fec/include/gnuradio/fec/generic_decoder.h +++ b/gr-fec/include/gnuradio/fec/generic_decoder.h @@ -210,6 +210,15 @@ namespace gr { * behavior. It should also provide bounds checks. */ virtual bool set_frame_size(unsigned int frame_size) = 0; + + + /*! + * Get repetitions to decode. + * + * The child class should implement this function and return the + * number of iterations required to decode. + */ + virtual float get_iterations(){ return -1; } }; /*! see generic_decoder::get_output_size() */ diff --git a/gr-fec/include/gnuradio/fec/gf2mat.h b/gr-fec/include/gnuradio/fec/gf2mat.h new file mode 100644 index 0000000000..963b20830d --- /dev/null +++ b/gr-fec/include/gnuradio/fec/gf2mat.h @@ -0,0 +1,111 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 GF2MAT_H +#define GF2MAT_H +#include <vector> +#include "gf2vec.h" +#include "alist.h" + +class GF2Mat +{ + //! The matrix H + std::vector < std::vector <char> > H; + + //! Number of rows in H + int M; + + //! Number of columns in H + int N; + + public: + //! Default constructor + GF2Mat() {}; + + //! Construct an M x N matrix with all 0 entries + GF2Mat(int m, int n); + + //! Loads the matrix from alist _list + GF2Mat(alist _list); + + //! Initializes the class from a 2-D vector X + GF2Mat(std::vector <std::vector <char> > X); + + //! Returns the variable M + int get_M(); + + //! Returns the variable N + int get_N(); + + //! Set the element at (i, j) coordinate to val + void set_element(int i, int j, char val); + + //! Returns the element at coordinate (i, j) + char get_element(int i, int j); + + //! Returns the ith row + GF2Vec get_row(int i); + + //! Returns the ith column + GF2Vec get_col(int i); + + //! Returns the ith row + GF2Vec operator[](int i); + + //! Prints the matrix H + void print_matrix(); + + //! Sets the ith column with the given vector + void set_col(int i, GF2Vec vec); + + //! Sets the ith row with the given vector + void set_row(int i, GF2Vec vec); + + //! Swaps columns i and j + void swap_cols(int i, int j); + + //! Adds column j to i and replace i with the sum + void add_cols(int i, int j); + + //! Add row j to i and replace j with the sum + void add_rows(int i, int j); + + //! Returns the variable H + std::vector<std::vector<char> > get_H(); + + /*! + \brief Obtains an equivalent representation of H for encoding + + For encoding a G matrix in the form [I P] is obtained from the + parity matrix H, by (a) Column permutations, (b) Row additions + and (c) Row permutations. Details of encoding is given in + section A.1 of the reference given below. + - "Modern Coding Theory", T Richardson and R Urbanke. + + \param p is the column permutation during this operation + \ + */ + GF2Mat get_G(std::vector<int> & p, int & rank); + +}; + +#endif // #ifndef GF2MAT_H diff --git a/gr-fec/include/gnuradio/fec/gf2vec.h b/gr-fec/include/gnuradio/fec/gf2vec.h new file mode 100644 index 0000000000..1b406c0278 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/gf2vec.h @@ -0,0 +1,71 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 GF2VEC_H +#define GF2VEC_H +#include <vector> + +class GF2Vec +{ + //! The vector vec + std::vector<char> vec; + + //! Resize the vector + void resize(int size); + + public: + + //! Default constructor + GF2Vec() {} + + //! Constructs a vector of length "size" with all 0 entries + GF2Vec(int size); + + //! Returns the vector + std::vector<char> get_vec(); + + //! Returns the size of the vector + int size(); + + //! Resets the vector with the given input + void set_vec(std::vector<char>); + + //! Access the ith element + char & operator [](int i); + + //! Overloading the operator '=' + void operator=(GF2Vec x); + + //! Obtain a subvector between the indices i to j + GF2Vec sub_vector(int i, int j); + + //! Overloading the operator '+' + friend GF2Vec operator+(GF2Vec a, GF2Vec b); + + //! Overloading the operator '*' + friend char operator*(GF2Vec a, GF2Vec b); + + //! Prints the vector + void print_vec(); +}; + +#endif // #ifndef GF2VEC_H diff --git a/gr-fec/include/gnuradio/fec/ldpc_decoder.h b/gr-fec/include/gnuradio/fec/ldpc_decoder.h new file mode 100644 index 0000000000..02cf12d585 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/ldpc_decoder.h @@ -0,0 +1,79 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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_LDPC_DECODER_H +#define INCLUDED_LDPC_DECODER_H + +typedef float INPUT_DATATYPE; +typedef unsigned char OUTPUT_DATATYPE; + +#include <map> +#include <string> +#include <gnuradio/fec/decoder.h> +#include <vector> + +#include <gnuradio/fec/cldpc.h> +#include <gnuradio/fec/alist.h> +#include <gnuradio/fec/awgn_bp.h> + +namespace gr { + namespace fec { + + +#define MAXLOG 1e7 + +class FEC_API ldpc_decoder : public generic_decoder { + //private constructor + ldpc_decoder (std::string alist_file, float sigma, int max_iterations); + + //plug into the generic fec api + int get_history(); + float get_shift(); + const char* get_conversion(); + void generic_work(void *inBuffer, void *outbuffer); + float d_iterations; + int inputSize, outputSize; + + alist d_list; + cldpc d_code; + awgn_bp d_spa; + + public: + ~ldpc_decoder (); + + double rate() { return (1.0*get_output_size() / get_input_size()); } + bool set_frame_size(unsigned int frame_size) { return false; } + + static generic_decoder::sptr + make (std::string alist_file, float sigma=0.5, int max_iterations=50); + int get_output_size(); + int get_input_size(); + int get_input_item_size(); + int get_output_item_size(); + float get_iterations(){ return d_iterations; } + +}; + +} +} + +#endif /* INCLUDED_LDPC_DECODER_H */ diff --git a/gr-fec/include/gnuradio/fec/ldpc_encoder.h b/gr-fec/include/gnuradio/fec/ldpc_encoder.h new file mode 100755 index 0000000000..1ed02e8efe --- /dev/null +++ b/gr-fec/include/gnuradio/fec/ldpc_encoder.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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_LDPC_ENCODER_H +#define INCLUDED_LDPC_ENCODER_H + +#include <gnuradio/fec/encoder.h> +#include <gnuradio/fec/cldpc.h> +#include <gnuradio/fec/alist.h> +#include <map> +#include <string> +#include <vector> + +namespace gr { + namespace fec { + + class FEC_API ldpc_encoder : public generic_encoder { + //private constructor + ldpc_encoder (std::string alist_file); + + //plug into the generic fec api + void generic_work(void *inBuffer, void *outbuffer); + + // memory allocated for processing + int outputSize; + int inputSize; + alist d_list; + cldpc d_code; + + public: + ~ldpc_encoder (); + static generic_encoder::sptr make (std::string alist_file); + double rate() { return (1.0*get_input_size() / get_output_size()); } + bool set_frame_size(unsigned int frame_size) { return false; } + int get_output_size(); + int get_input_size(); + }; + + } +} + +#endif /* INCLUDED_LDPC_ENCODER_H */ diff --git a/gr-fec/include/gnuradio/fec/maxstar.h b/gr-fec/include/gnuradio/fec/maxstar.h new file mode 100644 index 0000000000..f226550e5c --- /dev/null +++ b/gr-fec/include/gnuradio/fec/maxstar.h @@ -0,0 +1,99 @@ +/* -*- c++ -*- */
+/*
+ * Copyright 2015 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.
+ */
+
+/* File maxstar.h
+
+ Description: Performs the max* operations (Jacobian logarithm) defined as:
+ max*( x, y ) = max( x,y) + log( 1 + exp( - |x-y| ) )
+
+ There are several versions of this function, max_starX, where "X":
+ X = 0 For linear approximation to log-MAP
+ = 1 For max-log-MAP algorithm (i.e. max*(x,y) = max(x,y) )
+ = 2 For Constant-log-MAP algorithm
+ = 3 For log-MAP, correction factor from small nonuniform table and interpolation
+ = 4 For log-MAP, correction factor uses C function calls
+
+ Calling syntax:
+ output = max_starX( delta1, delta2 )
+
+ Where:
+ output = The result of max*(x,y)
+
+ delta1 = T] he first argument (i.e. x) of max*(x,y)
+ delta2 = The second argument (i.e. y) of max*(x,y)
+
+ Functions max_star0, max_star1, max_star2, max_star3, and max_star4
+ are part of the Iterative Solutions Coded Modulation Library
+ The Iterative Solutions Coded Modulation Library is free software;
+ you can redistribute it and/or modify it under the terms of
+ the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License,
+ or (at your option) any later version.
+
+*/
+
+#ifndef INCLUDED_FECAPI_MAXSTAR_H
+#define INCLUDED_FECAPI_MAXSTAR_H
+
+/* values for the jacobian logarithm table (DecoderType=4) */
+#define BOUNDARY0 0
+#define BOUNDARY1 0.4200
+#define BOUNDARY2 0.8500
+#define BOUNDARY3 1.3100
+#define BOUNDARY4 1.8300
+#define BOUNDARY5 2.4100
+#define BOUNDARY6 3.1300
+#define BOUNDARY7 4.0800
+#define BOUNDARY8 5.6000
+
+#define SLOPE0 -0.44788139700522
+#define SLOPE1 -0.34691145436176
+#define SLOPE2 -0.25432579542705
+#define SLOPE3 -0.17326680196715
+#define SLOPE4 -0.10822110027877
+#define SLOPE5 -0.06002650498009
+#define SLOPE6 -0.02739265095522
+#define SLOPE7 -0.00860202759280
+
+#define VALUE0 0.68954718055995
+#define VALUE1 0.50153699381775
+#define VALUE2 0.35256506844219
+#define VALUE3 0.23567520254575
+#define VALUE4 0.14607646552283
+#define VALUE5 0.08360822736113
+#define VALUE6 0.04088914377547
+#define VALUE7 0.01516612536801
+
+/* values for the constant log-MAP algorithm (DecoderType=3) */
+#define CVALUE 0.5
+#define TVALUE 1.5
+
+/* values for the linear approximation (DecoderType=1) */
+#define TTHRESH 2.508
+#define AVALUE -0.236
+#define BVALUE 0.592
+
+/* Values for linear approximation (DecoderType=5) */
+#define AJIAN -0.24904163195436
+#define TJIAN 2.50681740420944
+
+#endif
diff --git a/gr-fec/lib/CMakeLists.txt b/gr-fec/lib/CMakeLists.txt index 884bb4489a..99f701cc2c 100644 --- a/gr-fec/lib/CMakeLists.txt +++ b/gr-fec/lib/CMakeLists.txt @@ -71,6 +71,13 @@ list(APPEND gnuradio_fec_sources puncture_bb_impl.cc puncture_ff_impl.cc depuncture_bb_impl.cc + ldpc_encoder.cc + ldpc_decoder.cc + cldpc.cc + awgn_bp.cc + gf2vec.cc + gf2mat.cc + alist.cc ) #Add Windows DLL resource file if using MSVC diff --git a/gr-fec/lib/alist.cc b/gr-fec/lib/alist.cc new file mode 100644 index 0000000000..ac7cb3384e --- /dev/null +++ b/gr-fec/lib/alist.cc @@ -0,0 +1,205 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/alist.h> + +alist::alist(const char * fname) + : data_ok(false) { + read(fname); +} + +std::vector<std::vector<char> > alist::get_matrix() { + std::vector<std::vector<char> > mat; + mat.resize(M); + for ( int i = 0; i < M; i++ ) { + mat[i].resize(N); + for ( int j = 0; j < N; j++ ) { + mat[i][j] = char(0); + } + for ( int k = 0; k < num_mlist[i]; k++ ) { + mat[i][mlist[i][k] - 1] = char(1); + } + } + return mat; +} + +std::vector< std::vector<int> > alist::get_mlist() { + return mlist; +} + +std::vector< std::vector<int> > alist::get_nlist() { + return nlist; +} + +std::vector<int> alist::get_num_mlist() { + return num_mlist; +} + +std::vector<int> alist::get_num_nlist() { + return num_nlist; +} + +void alist::read(const char * fname) { + std::ifstream file; + std::string line; + std::stringstream ss; + + file.open(fname); + if(!(file.is_open())) { + std::cout << "Could not open the file" << std::endl; + } + + // Parse N and M + std::getline(file, line); + ss << line; + ss >> N >> M; + num_nlist.resize(N); + num_mlist.resize(M); + nlist.resize(N); + mlist.resize(M); + ss.seekg(0, std::ios::end); + ss.clear(); + + // parse max_num_n and max_num_m + std::getline(file, line); + ss << line; + ss >> max_num_nlist >> max_num_mlist; + ss.seekg(0, std::ios::end); + ss.clear(); + + // Parse weight of each column n + std::getline(file, line); + ss << line; + for (int i = 0; i < N; i++ ) { + ss >> num_nlist[i]; + nlist[i].resize(num_nlist[i]); + } + ss.seekg(0, std::ios::end); + ss.clear(); + + // Parse weight of each row m + std::getline(file, line); + ss << line; + for (int i = 0; i < M; i++ ) { + ss >> num_mlist[i]; + mlist[i].resize(num_mlist[i]); + } + ss.seekg(0, std::ios::end); + ss.clear(); + + // Parse indices with non zero entries in ith column + for (int column = 0; column < N; column++) { + std::getline(file, line); + ss << line; + for (int entry = 0; entry < num_nlist[column]; entry++) { + ss >> nlist[column][entry]; + } + ss.seekg(0, std::ios::end); + ss.clear(); + } + + // Parse indices with non zero entries in ith row + for (int row = 0; row < M; row++) { + std::getline(file, line); + ss << line; + for (int entry = 0; entry < num_mlist[row]; entry++) { + ss >> mlist[row][entry]; + } + ss.seekg(0, std::ios::end); + ss.clear(); + } + + file.close(); + data_ok = true; +} + +void alist::write(const char * fname) const +{ + if (!data_ok) { + std::cout << "Data not ok, exiting" << std::endl; + exit(1); + } + // Else + std::ofstream file(fname, std::ofstream::out); + // Write N and M + file << N << " " << M << std::endl; + file << max_num_nlist << " " << max_num_mlist << std::endl; + // Write column weights + for (size_t i = 0; i < num_nlist.size() - 1; i++) { + file << num_nlist[i] << " "; + } + file << num_nlist[num_nlist.size() - 1] << std::endl; + // Write row weights + for (size_t i = 0; i < num_mlist.size() - 1; i++) { + file << num_mlist[i] << " "; + } + file << num_mlist[num_mlist.size() - 1] << std::endl; + // Write non zero indices in the ith column + for (int i = 0; i < N; i++) { + for (int j = 0; j < num_nlist[i] - 1; j++) { + file << nlist[i][j] << "\t"; + } + file << nlist[i][num_nlist[i] - 1]; + file << std::endl; + } + // Write non zero indices in the ith row + for (int i = 0; i < M; i++) { + for (int j = 0; j < num_mlist[i] - 1; j++) { + file << mlist[i][j] << "\t"; + } + file << mlist[i][num_mlist[i] - 1]; + file << std::endl; + } + file.close(); +} + +int alist::get_N() { + return N; +} + +int alist::get_M() { + return M; +} + +int alist::get_max_num_nlist() { + return max_num_nlist; +} + +int alist::get_max_num_mlist() { + return max_num_mlist; +} + +void alist::print_nlist_i(int column) { + std::cout << "Indices in column " << column << std::endl; + for (int i = 0; i < num_nlist[column] - 1; i++) { + std::cout << nlist[column][i] << ", "; + } + std::cout << nlist[column][num_nlist[column] - 1] << std::endl; +} + +void alist::print_mlist_i(int row) { + std::cout << "Indices in row " << row << std::endl; + for (int i = 0; i < num_mlist[row] - 1; i++) { + std::cout << mlist[row][i] << ", "; + } + std::cout << mlist[row][num_mlist[row] - 1] << std::endl; +} diff --git a/gr-fec/lib/async_decoder_impl.cc b/gr-fec/lib/async_decoder_impl.cc index f5924ec1f9..2cdea6a1a6 100644 --- a/gr-fec/lib/async_decoder_impl.cc +++ b/gr-fec/lib/async_decoder_impl.cc @@ -114,15 +114,27 @@ namespace gr { int diff = d_decoder->rate()*d_decoder->get_input_size() - d_decoder->get_output_size(); int nbits_in = pmt::length(bits); - int nbits_out = nbits_in*d_decoder->rate() - diff; + size_t nbits_out = 0; + size_t nblocks = 1; + bool variable_frame_size = d_decoder->set_frame_size(nbits_out); // Check here if the frame size is larger than what we've // allocated for in the constructor. - if(nbits_in > d_max_bits_in) { + if(variable_frame_size && (nbits_in > d_max_bits_in)) { throw std::runtime_error("async_decoder: Received frame larger than max frame size."); } - d_decoder->set_frame_size(nbits_out); + // set up nbits_out + if(variable_frame_size){ + nbits_out = nbits_in*d_decoder->rate() - diff; + } else { + nblocks = nbits_in / d_decoder->get_input_size(); + nbits_out = nblocks * d_decoder->get_output_size(); + if(nblocks * d_decoder->get_input_size() != nbits_in){ + throw std::runtime_error("bad block multiple in!"); + } + } + size_t o0(0); const float* f32in = pmt::f32vector_elements(bits, o0); @@ -133,6 +145,14 @@ namespace gr { volk_32f_s32f_multiply_32f(d_tmp_f32, f32in, 48.0f, nbits_in); } else { + + // grow d_tmp_f32 if needed + if(nbits_in > d_max_bits_in){ + d_max_bits_in = nbits_in; + volk_free(d_tmp_f32); + d_tmp_f32 = (float*)volk_malloc(d_max_bits_in*sizeof(float), + volk_get_alignment()); + } memcpy(d_tmp_f32, f32in, nbits_in*sizeof(float)); } @@ -149,9 +169,12 @@ namespace gr { d_decoder->generic_work((void*)d_tmp_u8, (void*)u8out); } else { - d_decoder->generic_work((void*)d_tmp_f32, (void*)u8out); + for(size_t i=0; i<nblocks; i++){ + d_decoder->generic_work((void*)&d_tmp_f32[i*d_decoder->get_input_size()], (void*)&u8out[i*d_decoder->get_output_size()]); + } } + meta = pmt::dict_add(meta, pmt::mp("iterations"), pmt::mp(d_decoder->get_iterations()) ); message_port_pub(d_out_port, pmt::cons(meta, outvec)); } diff --git a/gr-fec/lib/async_encoder_impl.cc b/gr-fec/lib/async_encoder_impl.cc index d6ce67d491..106ad25cc4 100644 --- a/gr-fec/lib/async_encoder_impl.cc +++ b/gr-fec/lib/async_encoder_impl.cc @@ -110,9 +110,21 @@ namespace gr { int nbits_in = pmt::length(bits); const uint8_t* bits_in = pmt::u8vector_elements(bits, o0); - d_encoder->set_frame_size(nbits_in); + bool variable_framesize = d_encoder->set_frame_size(nbits_in); + size_t nbits_out = 0; + size_t nblocks = 1; + if( variable_framesize ){ + nbits_out = d_encoder->get_output_size(); + } else { + nblocks = nbits_in / d_encoder->get_input_size(); + if( nblocks * d_encoder->get_input_size() != nbits_in ){ + printf("nblocks: %d, in_block_size: %d, got_input_size: %d\n", + nblocks, d_encoder->get_input_size(), nbits_in); + throw std::runtime_error("input does not divide into code block size!"); + } + nbits_out = nblocks * d_encoder->get_output_size(); + } - int nbits_out = d_encoder->get_output_size(); // buffers for output bits to go to pmt::pmt_t outvec = pmt::make_u8vector(nbits_out, 0x00); @@ -123,7 +135,9 @@ namespace gr { d_encoder->generic_work((void*)d_bits_in, (void*)bits_out); } else { - d_encoder->generic_work((void*)bits_in, (void*)bits_out); + for(size_t i=0; i<nblocks; i++){ + d_encoder->generic_work((void*) &bits_in[i*d_encoder->get_input_size()], (void*)&bits_out[i*d_encoder->get_output_size()]); + } } pmt::pmt_t msg_pair = pmt::cons(meta, outvec); diff --git a/gr-fec/lib/awgn_bp.cc b/gr-fec/lib/awgn_bp.cc new file mode 100644 index 0000000000..66a50c0d56 --- /dev/null +++ b/gr-fec/lib/awgn_bp.cc @@ -0,0 +1,259 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/awgn_bp.h> + +awgn_bp::awgn_bp ( const GF2Mat X, float sgma) { + H = X; + M = H.get_M(); + N = H.get_N(); + Q.resize(M); + R.resize(M); + sigma = sgma; + for (int i = 0; i < M; i++) { + Q[i].resize(N); + R[i].resize(N); + } + lr.resize(N); + estimate.resize(N); +} + +awgn_bp::awgn_bp ( alist _list, float sgma) { + H = GF2Mat(_list); + mlist = _list.get_mlist(); + nlist = _list.get_nlist(); + num_mlist = _list.get_num_mlist(); + num_nlist = _list.get_num_nlist(); + M = H.get_M(); + N = H.get_N(); + Q.resize(M); + R.resize(M); + sigma = sgma; + for (int i = 0; i < M; i++) { + Q[i].resize(N); + R[i].resize(N); + } + lr.resize(N); + estimate.resize(N); +} + +void awgn_bp::set_alist_sigma(alist _list, float sgma) { + H = GF2Mat(_list); + mlist = _list.get_mlist(); + nlist = _list.get_nlist(); + num_mlist = _list.get_num_mlist(); + num_nlist = _list.get_num_nlist(); + M = H.get_M(); + N = H.get_N(); + Q.resize(M); + R.resize(M); + sigma = sgma; + for (int i = 0; i < M; i++) { + Q[i].resize(N); + R[i].resize(N); + } + lr.resize(N); + estimate.resize(N); +} + +std::vector< std::vector<double> > awgn_bp::get_Q() { + return Q; +} + +std::vector< std::vector<double> > awgn_bp::get_R() { + return R; +} + +GF2Mat awgn_bp::get_H() { + return H; +} + +void awgn_bp::rx_lr_calc(std::vector<float> codeword) { + rx_lr.resize(N); + float y; + for ( int i = 0; i < N; i++){ + y = codeword[i]; + rx_lr[i] = exp((-1*y)/(2*sigma*sigma)); + } +} + +std::vector<double> awgn_bp::get_rx_lr() { + return rx_lr; +} + +std::vector<double> awgn_bp::get_lr() { + return lr; +} + +void awgn_bp::spa_initialize() { + int row; + for ( int var = 0; var < N; var++ ) { + for ( int i = 0; i < num_nlist[var]; i++ ) { + row = nlist[var][i] - 1; + Q[row][var] = rx_lr[var]; + } + } +} + +void awgn_bp::update_chks() { + double product, _prdct; + int v; + for ( int chk = 0; chk < M; chk++ ) { + product = double(1.0); + for (int i = 0; i < num_mlist[chk]; i++) { + v = mlist[chk][i] - 1; + product = product*double( 2/(1 + Q[chk][v]) - 1 ); + } + for ( int i = 0; i < num_mlist[chk]; i++ ) { + v = mlist[chk][i] - 1; + _prdct = product/double( 2/(1 + Q[chk][v]) - 1); + R[chk][v] = double((1 - _prdct)/(1 + _prdct)); + } + } +} + +void awgn_bp::update_vars() { + double _sum, __sum; + int c; + for ( int var = 0; var < N; var++ ) { + _sum = rx_lr[var]; + for ( int i = 0; i < num_nlist[var]; i++ ) { + c = nlist[var][i] - 1; + _sum = _sum * double(R[c][var]); + } + lr[var] = _sum; + for ( int i = 0; i < num_nlist[var]; i++ ) { + c = nlist[var][i] - 1; + __sum = _sum/R[c][var]; + Q[c][var] = __sum; + } + } +} + +std::vector<char> awgn_bp::get_estimate() { + return estimate; +} + +void awgn_bp::compute_init_estimate(std::vector<float> rx_word) { + for (size_t i = 0; i < rx_word.size(); i++ ) { + if (rx_word[i] < 0) + estimate[i] = char(1); + else + estimate[i] = char(0); + } +} + +void awgn_bp::decision() { + for ( int i = 0; i < N; i++ ){ + if ( lr[i] > 1 ) + estimate[i] = char(1); + else + estimate[i] = char(0); + } +} + +void awgn_bp::set_K(int k) { + K = k; +} + +int awgn_bp::get_K() { + return K; +} + +std::vector<char> awgn_bp::get_syndrome(std::vector<char> codeword) { + std::vector<char> synd; + synd.resize(N - K); + GF2Vec in_bvec; + in_bvec.set_vec(codeword); + for ( int i = 0; i < N - K; i++ ) { + synd[i] = H[i]*in_bvec; + } + return synd; +} + +std::vector<char> awgn_bp::get_syndrome() { + std::vector<char> synd; + synd.resize(N - K); + GF2Vec in_bvec; + in_bvec.set_vec(estimate); + for ( int i = 0; i < N - K; i++ ) { + synd[i] = H[i]*in_bvec; + } + return synd; +} + +bool awgn_bp::is_codeword(std::vector<char> codeword) { + std::vector<char> synd; + synd = get_syndrome(codeword); + bool is_code; + is_code = true; + for ( int i = 0; i < N - K; i++ ) { + if ( synd[i] != char(0) ) { + is_code = false; + } + } + return is_code; +} + +bool awgn_bp::is_codeword() { + std::vector<char> synd; + synd = get_syndrome(); + bool is_code; + is_code = true; + for ( int i = 0; i < N - K; i++ ) { + if ( synd[i] != char(0) ) { + is_code = false; + } + } + return is_code; +} + +void awgn_bp::set_max_iterations(int k) { + max_iterations = k; +} + +int awgn_bp::get_max_iterations() { + return max_iterations; +} + +std::vector<char> awgn_bp::decode(std::vector<float> rx_word, + int *niteration) { + *niteration = 0; + compute_init_estimate(rx_word); + if (is_codeword()) { + return estimate; + } + else { + rx_lr_calc(rx_word); + spa_initialize(); + while (*niteration < max_iterations) { + *niteration += 1; + update_chks(); + update_vars(); + decision(); + if (is_codeword()) { + break; + } + } + return estimate; + } +} diff --git a/gr-fec/lib/cldpc.cc b/gr-fec/lib/cldpc.cc new file mode 100644 index 0000000000..df7be904f0 --- /dev/null +++ b/gr-fec/lib/cldpc.cc @@ -0,0 +1,132 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/cldpc.h> +#include <stdexcept> + +cldpc::cldpc(const GF2Mat X) { + H = X; + M = H.get_M(); + N = H.get_N(); + G = H.get_G(permute, rank_H); + K = N - rank_H; +} + +cldpc::cldpc(const alist _list) { + H = GF2Mat(_list); + M = H.get_M(); + N = H.get_N(); + G = H.get_G(permute, rank_H); + K = N - rank_H; +} + +void cldpc::set_alist(const alist _list) { + H = GF2Mat(_list); + M = H.get_M(); + N = H.get_N(); + G = H.get_G(permute, rank_H); + K = N - rank_H; +} + +std::vector<char> cldpc::get_systematic_bits(std::vector<char> in) { + std::vector<char> data; + data.resize(K); + int index; + for (size_t i = 0; i < K; i++ ) { + index = permute[i + rank_H]; + data[i] = in[index]; + } + return data; +} + +void cldpc::print_permute() { + for (size_t i = 0; i < permute.size(); i++ ) { + std::cout << permute[i] << ", "; + } + std::cout << "\n"; +} + +std::vector<char> cldpc::syndrome(const std::vector<char> in) { + std::vector<char> synd; + synd.resize(rank_H); + GF2Vec in_bvec; + in_bvec.set_vec(in); + for ( int i = 0; i < rank_H; i++ ) { + synd[i] = H[i]*in_bvec; + } + return synd; +} + +bool cldpc::is_codeword(const std::vector<char> in) { + std::vector<char> synd; + synd = syndrome(in); + bool is_code; + is_code = true; + for ( int i = 0; i < rank_H; i++ ) { + if ( synd[i] != char(0) ) { + is_code = false; + } + } + return is_code; +} + +std::vector<char> cldpc::encode(std::vector<char> dataword) { + if (dataword.size() == K) { + GF2Vec x(N); + GF2Vec data(K); + data.set_vec(dataword); + for ( int i = rank_H; i < N; i++ ) { + x[i] = dataword[i - rank_H]; + } + for ( int i = 0; i < rank_H; i++ ) { + x[i] = G[i].sub_vector(N-K, N)*data; + } + GF2Vec y(N); + for ( int i = 0; i < N; i++ ) { + y[permute[i]] = x[i]; + } + return y.get_vec(); + } else { + throw std::runtime_error("bad vector length!"); + return std::vector<char>(); + } +} + +int cldpc::dimension() { + return K; +} + +int cldpc::get_M() { + return M; +} + +int cldpc::get_N() { + return N; +} + +GF2Mat cldpc::get_H() { + return H; +} + +GF2Mat cldpc::get_G() { + return G; +} diff --git a/gr-fec/lib/gf2mat.cc b/gr-fec/lib/gf2mat.cc new file mode 100644 index 0000000000..87cb300890 --- /dev/null +++ b/gr-fec/lib/gf2mat.cc @@ -0,0 +1,193 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/gf2mat.h> +#include <iostream> + +GF2Mat::GF2Mat(int m, int n) { + M = m; + N = n; + H.resize(M); + for ( int i = 0; i < M; i++ ) { + H[i].resize(N); + for ( int j = 0; j < N; j++ ) { + H[i][j] = char(0); + } + } +} + +GF2Mat::GF2Mat(std::vector <std::vector<char> > X) { + M = X.size(); + N = X[0].size(); + H.resize(M); + for ( int i = 0; i < M; i++ ) { + H[i].resize(N); + for ( int j = 0; j < N; j++ ){ + H[i][j] = X[i][j]; + } + } +} + +GF2Mat::GF2Mat(alist _list) { + M = _list.get_M(); + N = _list.get_N(); + H.resize(M); + for ( int i = 0; i < M; i++ ) { + H[i].resize(N); + for ( int j = 0; j < N; j++ ) { + H[i][j] = char(0); + } + } + H = _list.get_matrix(); +} + +int GF2Mat::get_M() { + return M; +} + +int GF2Mat::get_N() { + return N; +} + +void GF2Mat::set_element(int i, int j, char val) { + H[i][j] = val; +} + +char GF2Mat::get_element(int i, int j) { + return H[i][j]; +} + +void GF2Mat::print_matrix() { + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + std::cout << int(H[i][j]) << " "; + } + std::cout << '\n'; + } +} + +GF2Vec GF2Mat::operator[](int i) { + GF2Vec row(N); + row.set_vec(H[i]); + return row; +} + +GF2Vec GF2Mat::get_row(int i) { + GF2Vec row(N); + for ( int j = 0; j < N; j++ ){ + row[j] = H[i][j]; + } + return row; +} + +GF2Vec GF2Mat::get_col(int i) { + GF2Vec col(M); + for ( int j = 0; j < M; j++ ) { + col[j] = H[j][i]; + } + return col; +} + +void GF2Mat::add_cols(int i, int j) { + for ( int row = 0; row < M; row++ ) { + H[row][i] = H[row][i] xor H[row][j]; + } +} + +void GF2Mat::add_rows(int i, int j) { + for ( int col = 0; col < N; col++ ) { + H[i][col] = H[i][col] xor H[j][col]; + } +} + +void GF2Mat::set_row(int row, GF2Vec vec) { + for ( int j = 0; j < N; j++ ) { + H[row][j] = vec[j]; + } +} + +void GF2Mat::set_col(int col, GF2Vec vec) { + for ( int j = 0; j < M; j++ ) { + H[j][col] = vec[j]; + } +} + +void GF2Mat::swap_cols(int i, int j) { + GF2Vec tmp; + tmp = get_col(i); + set_col(i, get_col(j)); + set_col(j, tmp); +} + +GF2Mat GF2Mat::get_G(std::vector<int> & permute, + int & rank) { + permute.resize(N); + rank = 0; + for ( int col = 0; col < N; col++ ) { + permute[col] = col; + } + GF2Mat G(H); + int diag = 0; + int limit = M; + int temp; + while (diag < limit) { + bool non_zero = false; + for ( int col = diag; col < N; col++ ) { + if ( G.get_element(diag, col) == char(1) ) { + non_zero = true; + rank++; + G.swap_cols(diag, col); + temp = permute[diag]; + permute[diag] = permute[col]; + permute[col] = temp; + break; + } + } + if (non_zero) { + for ( int row = 0; row < diag; row++ ) { + if (G.get_element(row, diag) == char(1)){ + G.add_rows(row, diag); + } + } + for ( int row = diag + 1; row < M; row++ ) { + if (G.get_element(row, diag) == char(1)) { + G.add_rows(row, diag); + } + } + diag++; + } + else{ + GF2Vec current_row; + current_row = G.get_row(diag); + for ( int row = diag; row < limit - 1; row++ ) { + G.set_row(row, G.get_row(row + 1)); + } + G.set_row(limit - 1, current_row); + limit--; + } + } + return G; +} + +std::vector<std::vector<char> > GF2Mat::get_H() { + return H; +} diff --git a/gr-fec/lib/gf2vec.cc b/gr-fec/lib/gf2vec.cc new file mode 100644 index 0000000000..464bf6a39e --- /dev/null +++ b/gr-fec/lib/gf2vec.cc @@ -0,0 +1,91 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/gf2vec.h> +#include <iostream> + +GF2Vec::GF2Vec(int size) { + vec.resize(size); + for( int i = 0; i < size; i++) { + vec[i] = char(0); + } +} + +void GF2Vec::set_vec(const std::vector<char> in) { + resize(in.size()); + for (size_t i = 0; i < vec.size(); i++ ) { + vec[i] = in[i]; + } +} + +std::vector<char> GF2Vec::get_vec(){ + return vec; +} + +int GF2Vec::size() { + return vec.size(); +} + +char & GF2Vec::operator[](int i) { + return vec[i]; +} + +GF2Vec operator+(GF2Vec a, GF2Vec b) { + GF2Vec sum(a.size()); + for( int i = 0; i < sum.size(); i++) { + sum[i] = a[i] ^ b[i]; + } + return sum; +} + +GF2Vec GF2Vec::sub_vector(int from, int to) { + int len = to - from; + GF2Vec x(len); + for ( int i = 0; i < len; i++ ) { + x[i] = vec[i + from]; + } + return x; +} + +char operator*(GF2Vec a, GF2Vec b) { + char sum; + sum = char(0); + for (int i = 0; i < a.size(); i++) { + sum = sum ^ ( a[i] & b[i] ); + } + return sum; +} + +void GF2Vec::print_vec() { + for (int i = 0; i < size(); i++ ) { + std::cout << int(vec[i]) << " "; + } + std::cout << '\n'; +} + +void GF2Vec::resize(int size) { + vec.resize(size); +} + +void GF2Vec::operator=(GF2Vec x) { + set_vec(x.get_vec()); +} diff --git a/gr-fec/lib/ldpc_decoder.cc b/gr-fec/lib/ldpc_decoder.cc new file mode 100644 index 0000000000..066024c9e0 --- /dev/null +++ b/gr-fec/lib/ldpc_decoder.cc @@ -0,0 +1,105 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/ldpc_decoder.h> +#include <math.h> +#include <boost/assign/list_of.hpp> +#include <volk/volk.h> +#include <sstream> +#include <stdio.h> +#include <vector> +#include <gnuradio/fec/decoder.h> +#include <algorithm> // for std::reverse +#include <string.h> // for memcpy +#include <gnuradio/fec/maxstar.h> + + +namespace gr { + namespace fec { + +generic_decoder::sptr +ldpc_decoder::make(std::string alist_file, float sigma, int max_iterations) +{ + return generic_decoder::sptr(new ldpc_decoder(alist_file, sigma, max_iterations)); +} + +ldpc_decoder::ldpc_decoder (std::string alist_file, float sigma, int max_iterations) + : generic_decoder("ldpc_decoder") +{ + if(!boost::filesystem::exists( alist_file )) + throw std::runtime_error("Bad AList file name!"); + d_list.read(alist_file.c_str()); + d_code.set_alist(d_list); + d_spa.set_alist_sigma(d_list, sigma); + inputSize = d_code.get_N(); + outputSize = d_code.dimension(); + d_spa.set_K(outputSize); + d_spa.set_max_iterations(max_iterations); +} + +int ldpc_decoder::get_output_size() { + return outputSize; +} + +int ldpc_decoder::get_input_size() { + return inputSize; +} + +void ldpc_decoder::generic_work(void *inBuffer, void *outBuffer) { + const float *inPtr = (const float *) inBuffer; + unsigned char *out = (unsigned char *) outBuffer; + + std::vector<float> rx(inputSize); + for(int i=0; i<inputSize; i++){ rx[i] = inPtr[i] * (-1); } + //memcpy(&rx[0], inPtr, inputSize*sizeof(float)); + int n_iterations = 0; + std::vector<char> estimate( d_spa.decode(rx, &n_iterations) ); + std::vector<char> data( d_code.get_systematic_bits(estimate) ); + memcpy(out, &data[0], outputSize); + d_iterations = n_iterations; +} + +int ldpc_decoder::get_input_item_size() { + return sizeof(INPUT_DATATYPE); +} + +int ldpc_decoder::get_output_item_size() { + return sizeof(OUTPUT_DATATYPE); +} + +int ldpc_decoder::get_history() { + return 0; +} + +float ldpc_decoder::get_shift() { + return 0.0; +} + +const char* ldpc_decoder::get_conversion() { + return "none"; +} + +ldpc_decoder::~ldpc_decoder() { +} + +} +} diff --git a/gr-fec/lib/ldpc_encoder.cc b/gr-fec/lib/ldpc_encoder.cc new file mode 100755 index 0000000000..813715a06b --- /dev/null +++ b/gr-fec/lib/ldpc_encoder.cc @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 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 <gnuradio/fec/ldpc_encoder.h> +#include <math.h> +#include <boost/assign/list_of.hpp> +#include <volk/volk.h> +#include <sstream> +#include <stdio.h> +#include <vector> +#include <algorithm> // for std::reverse +#include <string.h> // for memcpy + +namespace gr { + namespace fec { + +generic_encoder::sptr +ldpc_encoder::make(std::string alist_file) +{ + return generic_encoder::sptr(new ldpc_encoder(alist_file)); +} + +ldpc_encoder::ldpc_encoder (std::string alist_file) +{ + if(!boost::filesystem::exists( alist_file )) + throw std::runtime_error("Bad AList file name!"); + d_list.read(alist_file.c_str()); + d_code.set_alist(d_list); + inputSize = d_code.dimension(); + outputSize = d_code.get_N(); + printf("ENCODER: inputSize = %d, outputSize = %d\n",inputSize, outputSize); +} + +int ldpc_encoder::get_output_size() { + return outputSize; +} + +int ldpc_encoder::get_input_size() { + return inputSize; +} + +void ldpc_encoder::generic_work(void *inBuffer, void *outBuffer) { + const unsigned char *in = (const unsigned char *) inBuffer; + unsigned char *out = (unsigned char *) outBuffer; + std::vector<char> inbuf(inputSize); + memcpy(&inbuf[0], in, inputSize); + std::vector<char> coded(d_code.encode(inbuf)); + memcpy(&out[0], &coded[0], coded.size()); +} + + +ldpc_encoder::~ldpc_encoder() +{ +} + +} +} diff --git a/gr-fec/swig/fec_swig.i b/gr-fec/swig/fec_swig.i index 8ad845fd1c..858c72d78f 100644 --- a/gr-fec/swig/fec_swig.i +++ b/gr-fec/swig/fec_swig.i @@ -58,6 +58,8 @@ #include "gnuradio/fec/puncture_bb.h" #include "gnuradio/fec/puncture_ff.h" #include "gnuradio/fec/depuncture_bb.h" +#include "gnuradio/fec/ldpc_encoder.h" +#include "gnuradio/fec/ldpc_decoder.h" %} %include "gnuradio/fec/generic_decoder.h" @@ -82,6 +84,8 @@ %include "gnuradio/fec/puncture_bb.h" %include "gnuradio/fec/puncture_ff.h" %include "gnuradio/fec/depuncture_bb.h" +%include "gnuradio/fec/ldpc_encoder.h" +%include "gnuradio/fec/ldpc_decoder.h" GR_SWIG_BLOCK_MAGIC2(fec, decoder); GR_SWIG_BLOCK_MAGIC2(fec, encoder); diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml index c1c94e4e24..6588dc72d0 100644 --- a/grc/blocks/options.xml +++ b/grc/blocks/options.xml @@ -158,6 +158,22 @@ part#slurp <key>1</key> </option> </param> + <param> + <name>Thread-safe setters</name> + <key>thread_safe_setters</key> + <value></value> + <type>enum</type> + <hide>part</hide> + <option> + <name>Off</name> + <key></key> + </option> + <option> + <name>On</name> + <key>1</key> + </option> + <tab>Advanced</tab> + </param> <check>len($window_size) == 2</check> <check>300 <= $(window_size)[0] <= 4096</check> <check>300 <= $(window_size)[1] <= 4096</check> diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 6c56a94e9c..116dff189b 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -108,7 +108,7 @@ class ActionHandler: def _handle_action(self, action): #print action ################################################## - # Initalize/Quit + # Initialize/Quit ################################################## if action == Actions.APPLICATION_INITIALIZE: for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled @@ -129,7 +129,7 @@ class ActionHandler: Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(True) if not self.init_file_paths: - self.init_file_paths = Preferences.files_open() + self.init_file_paths = filter(os.path.exists, Preferences.files_open()) if not self.init_file_paths: self.init_file_paths = [''] for file_path in self.init_file_paths: if file_path: self.main_window.new_page(file_path) #load pages from file paths diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 5041a28f14..6ce614bc99 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -121,6 +121,30 @@ MENU_BAR_LIST = ( Actions.ABOUT_WINDOW_DISPLAY, ]), ) + + +CONTEXT_MENU_LIST = [ + Actions.BLOCK_CUT, + Actions.BLOCK_COPY, + Actions.BLOCK_PASTE, + Actions.ELEMENT_DELETE, + None, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, + Actions.BLOCK_ENABLE, + Actions.BLOCK_DISABLE, + None, + (gtk.Action('More', '_More', None, None), [ + Actions.BLOCK_CREATE_HIER, + Actions.OPEN_HIER, + None, + Actions.BUSSIFY_SOURCES, + Actions.BUSSIFY_SINKS, + ]), + Actions.BLOCK_PARAM_MODIFY +] + + class Toolbar(gtk.Toolbar): """The gtk toolbar with actions added from the toolbar list.""" @@ -138,6 +162,7 @@ class Toolbar(gtk.Toolbar): action.set_property('tooltip', action.get_property('tooltip')) else: self.add(gtk.SeparatorToolItem()) + class MenuBar(gtk.MenuBar): """The gtk menu bar with actions added from the menu bar list.""" @@ -157,7 +182,29 @@ class MenuBar(gtk.MenuBar): main_menu = gtk.Menu() main_menu_item.set_submenu(main_menu) for action in actions: - if action: #append a menu item - main_menu.append(action.create_menu_item()) - else: main_menu.append(gtk.SeparatorMenuItem()) + main_menu.append(action.create_menu_item() if action else + gtk.SeparatorMenuItem()) main_menu.show_all() #this show all is required for the separators to show + + +class ContextMenu(gtk.Menu): + """The gtk menu with actions added from the context menu list.""" + + def __init__(self): + gtk.Menu.__init__(self) + for action in CONTEXT_MENU_LIST: + if isinstance(action, tuple): + action, sub_menu_action_list = action + item = action.create_menu_item() + self.append(item) + sub_menu = gtk.Menu() + item.set_submenu(sub_menu) + for action in sub_menu_action_list: + sub_menu.append(action.create_menu_item() if action else + gtk.SeparatorMenuItem()) + sub_menu.show_all() + + else: + self.append(action.create_menu_item() if action else + gtk.SeparatorMenuItem()) + self.show_all() diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index f075a18175..badf8e8a82 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -37,8 +37,8 @@ class Connection(Element): def __init__(self): Element.__init__(self) - self._color = Colors.CONNECTION_ENABLED_COLOR - self._bg_color = self._arrow_color = self._color + # can't use Colors.CONNECTION_ENABLED_COLOR here, might not be defined (grcc) + self._bg_color = self._arrow_color = self._color = None def get_coordinate(self): """ @@ -48,7 +48,7 @@ class Connection(Element): Returns: 0, 0 """ - return (0, 0) + return 0, 0 def get_rotation(self): """ diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index eb0a6c11b0..e1fc680bde 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -116,7 +116,7 @@ class TextDisplay(gtk.TextView): menu.show_all() return False -def MessageDialogHelper(type, buttons, title=None, markup=None): +def MessageDialogHelper(type, buttons, title=None, markup=None, default_response=None, extra_buttons=None): """ Create a modal message dialog and run it. @@ -126,8 +126,10 @@ def MessageDialogHelper(type, buttons, title=None, markup=None): gtk.BUTTONS_NONE, gtk.BUTTONS_OK, gtk.BUTTONS_CLOSE, gtk.BUTTONS_CANCEL, gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL Args: - tittle: the title of the window (string) + title: the title of the window (string) markup: the message text with pango markup + default_response: if set, determines which button is highlighted by default + extra_buttons: a tuple containing pairs of values; each value is the button's text and the button's return value Returns: the gtk response from run() @@ -135,6 +137,8 @@ def MessageDialogHelper(type, buttons, title=None, markup=None): message_dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, type, buttons) if title: message_dialog.set_title(title) if markup: message_dialog.set_markup(markup) + if extra_buttons: message_dialog.add_buttons(*extra_buttons) + if default_response: message_dialog.set_default_response(default_response) response = message_dialog.run() message_dialog.destroy() return response diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 794d992e4e..f8be2f6cc3 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -27,6 +27,7 @@ pygtk.require('2.0') import gtk import random import Messages +import Bars class FlowGraph(Element): """ @@ -54,25 +55,7 @@ class FlowGraph(Element): # current mouse hover element self.element_under_mouse = None #context menu - self._context_menu = gtk.Menu() - for action in [ - Actions.BLOCK_CUT, - Actions.BLOCK_COPY, - Actions.BLOCK_PASTE, - Actions.ELEMENT_DELETE, - None, - Actions.BLOCK_ROTATE_CCW, - Actions.BLOCK_ROTATE_CW, - Actions.BLOCK_ENABLE, - Actions.BLOCK_DISABLE, - None, - Actions.BLOCK_CREATE_HIER, - Actions.OPEN_HIER, - Actions.BUSSIFY_SOURCES, - Actions.BUSSIFY_SINKS, - None, - Actions.BLOCK_PARAM_MODIFY - ]: self._context_menu.append(action.create_menu_item() if action else gtk.SeparatorMenuItem()) + self._context_menu = Bars.ContextMenu() self.get_context_menu = lambda: self._context_menu ########################################################################### diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index d1cf866ce7..07d0661e94 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -209,9 +209,11 @@ class MainWindow(gtk.Window): open_files = filter(lambda file: file, self._get_files()) #filter blank files open_file = self.get_page().get_file_path() #close each page - for page in self.get_pages(): + for page in sorted(self.get_pages(), key=lambda p: p.get_saved()): self.page_to_be_closed = page - self.close_page(False) + closed = self.close_page(False) + if not closed: + break if self.notebook.get_n_pages(): return False #save state before closing Preferences.files_open(open_files) @@ -236,17 +238,23 @@ class MainWindow(gtk.Window): if self.page_to_be_closed.get_proc() or not self.page_to_be_closed.get_saved(): self._set_page(self.page_to_be_closed) #unsaved? ask the user - if not self.page_to_be_closed.get_saved() and self._save_changes(): - Actions.FLOW_GRAPH_SAVE() #try to save - if not self.page_to_be_closed.get_saved(): #still unsaved? - self.page_to_be_closed = None #set the page to be closed back to None - return + if not self.page_to_be_closed.get_saved(): + response = self._save_changes() # return value is either OK, CLOSE, or CANCEL + if response == gtk.RESPONSE_OK: + Actions.FLOW_GRAPH_SAVE() #try to save + if not self.page_to_be_closed.get_saved(): #still unsaved? + self.page_to_be_closed = None #set the page to be closed back to None + return False + elif response == gtk.RESPONSE_CANCEL: + self.page_to_be_closed = None + return False #stop the flow graph if executing if self.page_to_be_closed.get_proc(): Actions.FLOW_GRAPH_KILL() #remove the page self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed)) if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one self.page_to_be_closed = None #set the page to be closed back to None + return True ############################################################ # Misc @@ -337,12 +345,17 @@ class MainWindow(gtk.Window): Save changes to flow graph? Returns: - true if yes + the response_id (see buttons variable below) """ + buttons = ( + 'Close without saving', gtk.RESPONSE_CLOSE, + gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_SAVE, gtk.RESPONSE_OK + ) return MessageDialogHelper( - gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved Changes!', - 'Would you like to save changes before closing?' - ) == gtk.RESPONSE_YES + gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, 'Unsaved Changes!', + 'Would you like to save changes before closing?', gtk.RESPONSE_OK, buttons + ) def _get_files(self): """ diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 2ef8603a83..1efa56326e 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -72,20 +72,31 @@ class InputParam(gtk.HBox): self._changed_but_unchecked = True self._update_gui() - def _apply_change(self, *args): + def apply_change(self, *args): """ Handle a gui change by setting the new param value, calling the callback (if applicable), and updating. """ + if not self._changed_but_unchecked: + return #set the new value self.param.set_value(self.get_text()) #call the callback - if self._callback: self._callback(*args) - else: self.param.validate() + if self._callback: + self._callback(*args) + else: + self.param.validate() #gui update self._changed_but_unchecked = False self._update_gui() + def _handle_key_press(self, widget, event): + if event.keyval == gtk.keysyms.Return and event.state & gtk.gdk.CONTROL_MASK: + self.apply_change() + return True + return False + + class EntryParam(InputParam): """Provide an entry box for strings and numbers.""" @@ -94,7 +105,8 @@ class EntryParam(InputParam): self._input = gtk.Entry() self._input.set_text(self.param.get_value()) self._input.connect('changed', self._mark_changed) - self._input.connect('focus-out-event', self._apply_change) + self._input.connect('focus-out-event', self.apply_change) + self._input.connect('key-press-event', self._handle_key_press) self.pack_start(self._input, True) def get_text(self): return self._input.get_text() def set_color(self, color): @@ -114,7 +126,7 @@ class EnumParam(InputParam): self._input = gtk.combo_box_new_text() for option in self.param.get_options(): self._input.append_text(option.get_name()) self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) - self._input.connect('changed', self._apply_change) + self._input.connect('changed', self.apply_change) self.pack_start(self._input, False) def get_text(self): return self.param.get_option_keys()[self._input.get_active()] def set_tooltip_text(self, text): @@ -123,6 +135,7 @@ class EnumParam(InputParam): except AttributeError: pass # no tooltips for old GTK + class EnumEntryParam(InputParam): """Provide an entry box and drop down menu for Raw Enum types.""" @@ -134,9 +147,10 @@ class EnumEntryParam(InputParam): except: self._input.set_active(-1) self._input.get_child().set_text(self.param.get_value()) - self._input.connect('changed', self._apply_change) + self._input.connect('changed', self.apply_change) self._input.get_child().connect('changed', self._mark_changed) - self._input.get_child().connect('focus-out-event', self._apply_change) + self._input.get_child().connect('focus-out-event', self.apply_change) + self._input.get_child().connect('key-press-event', self._handle_key_press) self.pack_start(self._input, False) def get_text(self): if self._input.get_active() == -1: return self._input.get_child().get_text() @@ -191,7 +205,7 @@ class FileParam(EntryParam): if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog file_path = file_dialog.get_filename() #get the file path self._input.set_text(file_path) - self._apply_change() + self.apply_change() file_dialog.destroy() #destroy the dialog diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py index 1d6675da32..e7b05519ea 100644 --- a/grc/gui/Preferences.py +++ b/grc/gui/Preferences.py @@ -68,9 +68,11 @@ def files_open(files=None): files = list() i = 0 while True: - try: files.append(_config_parser.get('files_open', 'file_open_%d'%i)) - except: return files - i = i + 1 + try: + files.append(_config_parser.get('files_open', 'file_open_%d'%i)) + except: + return files + i += 1 def reports_window_position(pos=None): if pos is not None: _config_parser.set('main', 'reports_window_position', pos) @@ -91,4 +93,4 @@ def bool_entry(key, active=None, default=True): try: return _config_parser.getboolean('main', key) except: - return default
\ No newline at end of file + return default diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index d7ba8c51c9..d172175aba 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -65,7 +65,9 @@ class PropsDialog(gtk.Dialog): gtk.Dialog.__init__( self, title='Properties: %s' % block.get_name(), - buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT), + buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, + gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_APPLY, gtk.RESPONSE_APPLY) ) self._block = block self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) @@ -109,6 +111,7 @@ class PropsDialog(gtk.Dialog): # Connect events self.connect('key-press-event', self._handle_key_press) self.connect('show', self._update_gui) + self.connect('response', self._handle_response) self.show_all() # show all (performs initial gui update) def _params_changed(self): @@ -183,11 +186,18 @@ class PropsDialog(gtk.Dialog): Returns: false to forward the keypress """ - if event.keyval == gtk.keysyms.Return: + if event.keyval == gtk.keysyms.Return and event.state & gtk.gdk.CONTROL_MASK == 0: self.response(gtk.RESPONSE_ACCEPT) return True # handled here return False # forward the keypress + def _handle_response(self, widget, response): + if response == gtk.RESPONSE_APPLY: + for tab, label, vbox in self._params_boxes: + vbox.forall(lambda c: c.apply_change()) + return True + return False + def run(self): """ Run the dialog and get its response. @@ -195,6 +205,9 @@ class PropsDialog(gtk.Dialog): Returns: true if the response was accept """ - response = gtk.Dialog.run(self) + response = gtk.RESPONSE_APPLY + # don't close dialog on apply click + while response == gtk.RESPONSE_APPLY: + response = gtk.Dialog.run(self) self.destroy() return response == gtk.RESPONSE_ACCEPT diff --git a/grc/python/Generator.py b/grc/python/Generator.py index 7512cfb633..a3f9f10fc1 100644 --- a/grc/python/Generator.py +++ b/grc/python/Generator.py @@ -101,9 +101,12 @@ class TopBlockGenerator(object): "This is usually undesired. Consider " "removing the throttle block.") # generate - open(self.get_file_path(), 'w').write( - self._build_python_code_from_template() - ) + with open(self.get_file_path(), 'w') as fp: + fp.write(self._build_python_code_from_template()) + try: + os.chmod(self.get_file_path(), self._mode) + except: + pass def get_popen(self): """ @@ -231,6 +234,10 @@ class HierBlockGenerator(TopBlockGenerator): TopBlockGenerator.write(self) ParseXML.to_file(self._build_block_n_from_flow_graph_io(), self.get_file_path_xml()) ParseXML.validate_dtd(self.get_file_path_xml(), BLOCK_DTD) + try: + os.chmod(self.get_file_path_xml(), self._mode) + except: + pass def _build_block_n_from_flow_graph_io(self): """ @@ -254,7 +261,8 @@ class HierBlockGenerator(TopBlockGenerator): self._flow_graph.get_option('id').replace('_', ' ').title() block_n['key'] = block_key block_n['category'] = self._flow_graph.get_option('category') - block_n['import'] = 'execfile("{0}")'.format(self.get_file_path()) + block_n['import'] = "from {0} import {0} # grc-generated hier_block".format( + self._flow_graph.get_option('id')) # make data if parameters: block_n['make'] = '{cls}(\n {kwargs},\n)'.format( diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl index 859611e528..814b513213 100644 --- a/grc/python/flow_graph.tmpl +++ b/grc/python/flow_graph.tmpl @@ -1,4 +1,6 @@ -#!/usr/bin/env python +#if $generate_options != 'hb' +#!/usr/bin/env python2 +#end if ######################################################## ##Cheetah template - gnuradio_python ## @@ -19,7 +21,7 @@ $code#slurp #import time #set $DIVIDER = '#'*50 $DIVIDER -# Gnuradio Python Flow Graph +# GNU Radio Python Flow Graph # Title: $title #if $flow_graph.get_option('author') # Author: $flow_graph.get_option('author') @@ -29,6 +31,9 @@ $DIVIDER #end if # Generated: $time.ctime() $DIVIDER +#if $flow_graph.get_option('thread_safe_setters') +import threading +#end if ## Call XInitThreads as the _very_ first thing. ## After some Qt import, it's too late @@ -48,8 +53,15 @@ if __name__ == '__main__': ######################################################## ##Create Imports ######################################################## +#if any(imp.endswith("# grc-generated hier_block") for imp in $imports) +import os +import sys +#set imports = $filter(lambda i: i not in ("import os", "import sys"), $imports) +sys.path.append(os.environ.get('GRC_HIER_PATH', os.path.expanduser('~/.grc_gnuradio'))) + +#end if #for $imp in $imports -$imp +$(imp.replace(" # grc-generated hier_block", "")) #end for ######################################################## @@ -132,6 +144,10 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))]) self.message_port_register_hier_in("$pad['label']") #end for #end if +#if $flow_graph.get_option('thread_safe_setters') + + self._lock = threading.RLock() +#end if ######################################################## ##Create Parameters ## Set the parameter to a property of self. @@ -255,10 +271,18 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))]) return self.$id def set_$(id)(self, $id): + #if $flow_graph.get_option('thread_safe_setters') + with self._lock: + self.$id = $id + #for $callback in $var_id2cbs[$id] + $indent($callback) + #end for + #else self.$id = $id - #for $callback in $var_id2cbs[$id] + #for $callback in $var_id2cbs[$id] $indent($callback) - #end for + #end for + #end if #end for ######################################################## diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion index 6d45ecc246..239fc95d8a 100755 --- a/grc/scripts/gnuradio-companion +++ b/grc/scripts/gnuradio-companion @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -Copyright 2009-2012 Free Software Foundation, Inc. +Copyright 2009-2015 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -18,13 +18,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +import os +import sys +import optparse + import pygtk pygtk.require('2.0') import gtk -try: from gnuradio import gr -except ImportError, e: - d = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, message_format=""" + +GR_IMPORT_ERROR_MESSAGE = """\ Cannot import gnuradio. Is the python path environment variable set correctly? @@ -34,39 +37,77 @@ Is the library path environment variable set correctly? Linux: LD_LIBRARY_PATH Windows: PATH MacOSX: DYLD_LIBRARY_PATH -""") - d.set_title(str(e)) - d.run() - exit(-1) - -from optparse import OptionParser -import os +""" -if __name__ == "__main__": - if ('GR_DONT_LOAD_PREFS' in os.environ.keys() and - (not 'GRC_BLOCKS_PATH' in os.environ.keys() or len(os.environ['GRC_BLOCKS_PATH']) == 0)): - d = gtk.MessageDialog( - type=gtk.MESSAGE_ERROR, - buttons=gtk.BUTTONS_CLOSE, - message_format="""Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH. """) - d.set_title("No block definitions available.") - d.run() - exit(-1) - usage = 'usage: %prog [options] [saved flow graphs]' - version = """ +VERSION_AND_DISCLAIMER_TEMPLATE = """\ GNU Radio Companion %s This program is part of GNU Radio GRC comes with ABSOLUTELY NO WARRANTY. -This is free software, -and you are welcome to redistribute it. -"""%gr.version() - parser = OptionParser(usage=usage, version=version) - (options, args) = parser.parse_args() - from gnuradio.grc.python.Platform import Platform - from gnuradio.grc.gui.ActionHandler import ActionHandler - #setup icon using icon theme - try: gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0)) - except: pass +This is free software, and you are welcome to redistribute it. +""" + + +def show_gtk_error_dialog(title, message): + d = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, + message_format=message) + d.set_title(title) + d.run() + + +def check_gnuradio_import(): + try: + from gnuradio import gr + except ImportError as e: + show_gtk_error_dialog(str(e), GR_IMPORT_ERROR_MESSAGE) + exit(-1) + + +def ensure_blocks_path(): + if 'GR_DONT_LOAD_PREFS' in os.environ and not os.environ.get('GRC_BLOCKS_PATH', ''): + show_gtk_error_dialog( + title="No block definitions available.", + message="Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH." + ) + exit(-1) + + +def get_source_tree_root(): + source_tree_subpath = "/grc/scripts" + script_path = os.path.dirname(__file__) + if script_path.endswith(source_tree_subpath): + return script_path[:-len(source_tree_subpath)] + + +def main(): + from gnuradio import gr + + parser = optparse.OptionParser( + usage='usage: %prog [options] [saved flow graphs]', + version=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version()) + options, args = parser.parse_args() + + source_tree_root = get_source_tree_root() + if not source_tree_root: + # run the installed version + from gnuradio.grc.python.Platform import Platform + from gnuradio.grc.gui.ActionHandler import ActionHandler + + else: + print("Running from source tree") + sys.path.insert(1, source_tree_root) + from grc.python.Platform import Platform + from grc.gui.ActionHandler import ActionHandler + + try: + gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0)) + except: + pass + ActionHandler(args, Platform()) + +if __name__ == '__main__': + check_gnuradio_import() + ensure_blocks_path() + main() |