Search code examples
c++blockgnuradiognuradio-companion

GNU Radio no output from other blocks parallel with my own OOT block


I would like to code my own general block with 1 input and 1 output for GNU Radio in C++. I followed the steps in gnuradio.org using gr_modtool. It can works well. But when I connect other block(scope sink2) with the same source there is no output in it.

I connect the flow graph as:

                            /-> Scope Sink2
Signal Source -> Throttle -|
                            \-> my own block -> Scope Sink1

I'm using GNU Radio Companion v3.7.6.1-65-g500517ac

I created the block 'energy_de'. This create among other four files: energy_de.h

#ifndef INCLUDED_CPP_ENERGY_DE_H
#define INCLUDED_CPP_ENERGY_DE_H

#include <cpp/api.h>
#include <gnuradio/block.h>

namespace gr {
  namespace cpp {

    /*!
     * \brief <+description of block+>
     * \ingroup cpp
     *
     */
    class CPP_API energy_de : virtual public gr::block
    {
     public:
      typedef boost::shared_ptr<energy_de> sptr;

      /*!
       * \brief Return a shared_ptr to a new instance of cpp::energy_de.
       *
       * To avoid accidental use of raw pointers, cpp::energy_de's
       * constructor is in a private implementation
       * class. cpp::energy_de::make is the public interface for
       * creating new instances.
       */
      static sptr make(float makenoise);

      virtual float noise () const = 0;
      virtual void set_noise (float noise) = 0;
    };

  } // namespace cpp
} // namespace gr

energy_de_impl.h

#ifndef INCLUDED_CPP_ENERGY_DE_IMPL_H
#define INCLUDED_CPP_ENERGY_DE_IMPL_H

#include <cpp/energy_de.h>

namespace gr {
  namespace cpp {

    class energy_de_impl : public energy_de
    {
     private:
      float d_noise;

     public:
      energy_de_impl(float noise);
      ~energy_de_impl();

      // Where all the action really happens
      void forecast (int noutput_items, gr_vector_int &ninput_items_required);
      float noise() const { return d_noise; }
      void set_noise(float noise) { d_noise = noise; }

      int general_work(int noutput_items,
               gr_vector_int &ninput_items,
               gr_vector_const_void_star &input_items,
               gr_vector_void_star &output_items);
    };

  } // namespace cpp
} // namespace gr

energy_de_impl.cc

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/io_signature.h>
#include "energy_de_impl.h"

namespace gr {
  namespace cpp {

    energy_de::sptr
    energy_de::make(float noise)
    {
      return gnuradio::get_initial_sptr
        (new energy_de_impl(noise));
    }

    /*
     * The private constructor
     */
    energy_de_impl::energy_de_impl(float noise)
      : gr::block("energy_de",
              gr::io_signature::make(1, 1, sizeof(float)),
              gr::io_signature::make(1, 1, sizeof(float))),
        d_noise(noise)
    {
    }

    /*
     * Our virtual destructor.
     */
    energy_de_impl::~energy_de_impl()
    {
    }

    void
    energy_de_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
    {
         ninput_items_required[0] = noutput_items;
    }

    int
    energy_de_impl::general_work (int noutput_items,
                       gr_vector_int &ninput_items,
                       gr_vector_const_void_star &input_items,
                       gr_vector_void_star &output_items)
    {
        const float *in = (const float *) input_items[0];
        float *out = (float *) output_items[0];

        for(int i = 0; i < noutput_items; i++){
            if (in[i]*in[i] > d_noise){
              out[i] = 1.0;
            }
            else{
              out[i] = 0.0;
            }
        }

        return noutput_items;
    }

  } /* namespace cpp */
} /* namespace gr */

cpp_energy_de.xml

<?xml version="1.0"?>
<block>
  <name>energy_de</name>
  <key>cpp_energy_de</key>
  <category>cpp</category>
  <import>import cpp</import>
  <make>cpp.energy_de($noise)</make>
  <callback>set_niose($noise)</callback>

  <param>
    <name>noise</name>
    <key>noise</key>
    <type>float</type>
  </param>


  <sink>
    <name>in</name>
    <type>float</type>
  </sink>

  <source>
    <name>out</name>
    <type>float</type>
  </source>
</block>

Why I cannot get an out put from Scope Sink2? What have I forgotten to write inside the four files? Is this the problem about input_items buffer of my block?


Solution

  • When using a general block rather than a sync_block, your general_work must call consume, indicating how many items you've read, otherwise your own block's input buffer (== throttle's output buffer) quickly fills up, throttle can't put new samples into it and your flow graph halts. At that point, your scope sink might simply not have enough input to show anything.

    I think for your use case, just using a sync_block would be much easier, and hence, the correct way to do this.

    I'd like to point you to a mail I've written today to the discuss GNU Radio mailing list. It explains the buffer space concepts behind this.

                  /->A->Null Sink
    File Source -|
                  \->B->File Sink
    

    [...]

    So the mechanism below is: the output buffer of File Source is the input buffer of A and the input buffer of B. No memory duplication here.

    File Source has a buffer writer with a write pointer, and A and B have their own read pointers pointing into that buffer.

    When File Source produces N items, the write pointer advances by N.

    Similarly, when A consumes M items, A's read pointer advances by M.

    When calling (general_)work, the input_items buffer(s) is (are) really just a pointer (start_of_buffer + read pointer). Equivalently, the output_items buffer(s) is (are) really just pointing to the write pointer.

    File Source is only allowed to produce so many items that the write pointer doesn't advance beyond the minimum read pointer, because in that case, it would overwrite samples that a downstream block hasn't consumed.