Creating C++ OOT with gr-modtool

From GNU Radio
Revision as of 18:53, 9 March 2022 by Mattcarrick (talk | contribs)
Jump to navigation Jump to search
Beginner Tutorials

Introducing GNU Radio

  1. What is GNU Radio?
  2. Installing GNU Radio
  3. Your First Flowgraph

Flowgraph Fundamentals

  1. Python Variables in GRC
  2. Variables in Flowgraphs
  3. Runtime Updating Variables
  4. Signal Data Types
  5. Converting Data Types
  6. Packing Bits
  7. Streams and Vectors
  8. Hier Blocks and Parameters

Creating and Modifying Python Blocks

  1. Creating Your First Block
  2. Python Block With Vectors
  3. Python Block Message Passing
  4. Python Block Tags

DSP Blocks

  1. Low Pass Filter Example
  2. Designing Filter Taps
  3. Sample Rate Change
  4. Frequency Shifting
  5. Reading and Writing Binary Files

SDR Hardware

  1. RTL-SDR FM Receiver
  2. B200-B205mini FM Receiver

This tutorial describes how to create a custom c++ block and use it in a flowgraph:

  • Create a new c++ block using gr_modtool
  • Modify the c++ .h and .cc code so the block will function
  • Modify the YAML file so it can be read in GRC
  • Install and run the block in a flowgraph

The previous tutorial, Creating Python OOT with gr-modtool, describes how to create a Python block in an OOT module. This c++ OOT tutorial builds upon the previous Python one, so it is is suggested to at least complete the Creating an OOT Module portion of that tutorial before completing this one.

Installation Note

This tutorial was written using GNU Radio v3.10.1.1 on Ubuntu 21.10, installed using the Ubuntu PPA from the Installation Wiki Page. The basic GNU Radio install using:

$ sudo apt-get install gnuradio

does not come with the proper libraries needed to compile and install OOT modules. Consider installing the following packages before continuing:

$ sudo apt-get install gnuradio-dev cmake libspdlog-dev clang-format

Adding a New Block

Move to the gr-customModule directory created in the Creating Python OOT with gr-modtool tutorial:

cd your-path/gr-customModule

Add a new block named multDivSelector:

$ gr_modtool add multDivSelector

The types of blocks will be displayed:

GNU Radio module name identified: customModule
('sink', 'source', 'sync', 'decimator', 'interpolator', 'general', 'tagged_stream', 'hier', 'noblock')

Enter sync as the block type:

Enter block type: sync

Enter cpp as the language:

Language (python/cpp): cpp
Language: C++
Block/code identifier: multDivSelector

Enter the name or organization of the copyright holder:

Please specify the copyright holder: YourName

Create a boolean variable selector with a default value of true:

Enter valid argument list, including default arguments: 
bool selector=true

Select whether or not QA code is desired:

Add Python QA code? [Y/n] n
Add C++ QA code? [Y/n] n

Multiple files will then be created or modified:

Adding file 'lib/multDivSelector_impl.h'...
Adding file 'lib/multDivSelector_impl.cc'...
Adding file 'include/gnuradio/customModule/multDivSelector.h'...
Adding file 'python/customModule/bindings/docstrings/multDivSelector_pydoc_template.h'...
Adding file 'python/customModule/bindings/multDivSelector_python.cc'...
Adding file 'grc/customModule_multDivSelector.block.yml'...
Editing grc/CMakeLists.txt...

Editing the c++ Header

Many of the files are automatically generated wrapper code that do not need to be modified. However, the multDivSelector_impl.h and multDivSelector_impl.cc files defines the operation of the block and must be modified. Open the file with a text editor:

$ gedit lib/multDivSelector_impl.h &

The following code will be displayed:

/* -*- c++ -*- */
/*
 * Copyright 2022 YourName.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#ifndef INCLUDED_CUSTOMMODULE_MULTDIVSELECTOR_IMPL_H
#define INCLUDED_CUSTOMMODULE_MULTDIVSELECTOR_IMPL_H

#include <gnuradio/customModule/multDivSelector.h>

namespace gr {
namespace customModule {

class multDivSelector_impl : public multDivSelector
{
private:
    // Nothing to declare in this block.

public:
    multDivSelector_impl(bool selector);
    ~multDivSelector_impl();

    // Where all the action really happens
    int work(int noutput_items,
             gr_vector_const_void_star& input_items,
             gr_vector_void_star& output_items);
};

} // namespace customModule
} // namespace gr

#endif /* INCLUDED_CUSTOMMODULE_MULTDIVSELECTOR_IMPL_H */

Create a boolean private member _selector which will hold the value of the selector parameter:

class multDivSelector_impl : public multDivSelector
{
private:
    bool _selector;

Press CTRL + S to save the file.

Editing the c++ impl

The .cc file needs to be modified to define the desired operation of the block. Open the file with a text editor:

$ gedit lib/multDivSelector_impl.cc &

The code will be as displayed:

/* -*- c++ -*- */
/*
 * Copyright 2022 YourName.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

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

namespace gr {
namespace customModule {

#pragma message("set the following appropriately and remove this warning")
using input_type = float;
#pragma message("set the following appropriately and remove this warning")
using output_type = float;
multDivSelector::sptr multDivSelector::make(bool selector)
{
    return gnuradio::make_block_sptr<multDivSelector_impl>(selector);
}


/*
 * The private constructor
 */
multDivSelector_impl::multDivSelector_impl(bool selector)
    : gr::sync_block("multDivSelector",
                     gr::io_signature::make(
                         1 /* min inputs */, 1 /* max inputs */, sizeof(input_type)),
                     gr::io_signature::make(
                         1 /* min outputs */, 1 /*max outputs */, sizeof(output_type)))
{
}

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

int multDivSelector_impl::work(int noutput_items,
                               gr_vector_const_void_star& input_items,
                               gr_vector_void_star& output_items)
{
    auto in = static_cast<const input_type*>(input_items[0]);
    auto out = static_cast<output_type*>(output_items[0]);

#pragma message("Implement the signal processing in your block and remove this warning")
    // Do <+signal processing+>

    // Tell runtime system how many output items we produced.
    return noutput_items;
}

} /* namespace customModule */
} /* namespace gr */

Remove the pragma messages and define the input and output type to be gr_complex:

using input_type = gr_complex;
using output_type = gr_complex;

Update to two inputs and store the value of the selector parameter using the private member _selector as defined in multDivSelector_impl.h:

/*
 * The private constructor
 */
multDivSelector_impl::multDivSelector_impl(bool selector)
    : gr::sync_block("multDivSelector",
                     gr::io_signature::make(
                         2 /* min inputs */, 1 /* max inputs */, sizeof(input_type)),
                     gr::io_signature::make(
                         1 /* min outputs */, 1 /*max outputs */, sizeof(output_type)))
{
    _selector = selector;
}

Modify the work() function by removing the pragma message, defining the variables in0 and in1 corresponding to the two input ports, and multiply the two inputs if _selector is true and divide them if _selector is false:

int multDivSelector_impl::work(int noutput_items,
                               gr_vector_const_void_star& input_items,
                               gr_vector_void_star& output_items)
{
    auto in0 = static_cast<const input_type*>(input_items[0]);
    auto in1 = static_cast<const input_type*>(input_items[1]);
    auto out = static_cast<output_type*>(output_items[0]);

    for (int index = 0; index < noutput_items; index++) {
        if (_selector) { out[index] = in0[index] * in1[index]; }
        else{ out[index] = in0[index] * in1[index]; }
    }


    // Tell runtime system how many output items we produced.
    return noutput_items;
}

Press CTRL + S to save the file.

Editing the YAML File

Open the YAML file using a text editor:

$ gedit gedit grc/customModule_multDivSelector.block.yml &

The code will be displayed:

id: customModule_multDivSelector
label: multDivSelector
category: '[customModule]'

templates:
  imports: from gnuradio import customModule
  make: customModule.multDivSelector(${selector})

#  Make one 'parameters' list entry for every parameter you want settable from the GUI.
#     Keys include:
#     * id (makes the value accessible as keyname, e.g. in the make entry)
#     * label (label shown in the GUI)
#     * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
#     * default
parameters:
- id: parametername_replace_me
  label: FIX ME:
  dtype: string
  default: You need to fill in your grc/customModule_multDivSelector.block.yaml
#- id: ...
#  label: ...
#  dtype: ...

#  Make one 'inputs' list entry per input and one 'outputs' list entry per output.
#  Keys include:
#      * label (an identifier for the GUI)
#      * domain (optional - stream or message. Default is stream)
#      * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
#      * vlen (optional - data stream vector length. Default is 1)
#      * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
#- label: ...
#  domain: ...
#  dtype: ...
#  vlen: ...
#  optional: ...

outputs:
#- label: ...
#  domain: ...
#  dtype: ...
#  vlen: ...
#  optional: ...

#  'file_format' specifies the version of the GRC yml format used in the file
#  and should usually not be changed.
file_format: 1

Update the parameter definition with the information for selector:

parameters:
- id: selector
  label: Selector, Multiply (true) or Divide (false)
  dtype: bool
  default: true

Update the input port and output port definitions:

inputs:
- label: in0
  domain: stream
  dtype: complex
- label: in1
  domain: stream
  dtype: complex
outputs:
- label: out0
  domain: stream
  dtype: complex

Press CTRL + S to save the file.

Compile and Install

The block needs to be compiled and installed. Ensure you are in the gr-customModule directory:

$ cd your-path/gr-customModule

If the build/ directory already exists, remove it:

rm -rf build/

Create the build directory:

$ mkdir build

Move into the build directory:

cd build

Run cmake to build the makefiles:

cmake ..

Compile the module:

make

Install the module:

sudo make install

The new files will then be installed:

-- Install configuration: "Release"
-- Up-to-date: /usr/local/lib/cmake/gnuradio-customModule/gnuradio-customModuleConfig.cmake
-- Up-to-date: /usr/local/include/gnuradio/customModule/api.h
-- Installing: /usr/local/include/gnuradio/customModule/multDivSelector.h
-- Installing: /usr/local/lib/x86_64-linux-gnu/libgnuradio-customModule.so.1.0.0.0
-- Installing: /usr/local/lib/x86_64-linux-gnu/libgnuradio-customModule.so.1.0.0
-- Installing: /usr/local/lib/x86_64-linux-gnu/libgnuradio-customModule.so
-- Installing: /usr/local/lib/cmake/gnuradio-customModule/gnuradio-customModuleTargets.cmake
-- Installing: /usr/local/lib/cmake/gnuradio-customModule/gnuradio-customModuleTargets-release.cmake
-- Installing: /usr/local/lib/cmake/gnuradio-customModule/gnuradio-customModuleConfig.cmake
-- Up-to-date: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/__init__.py
-- Up-to-date: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/addSubSelect.py
-- Installing: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/__init__.pyc
-- Installing: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/addSubSelect.pyc
-- Installing: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/__init__.pyo
-- Installing: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/addSubSelect.pyo
-- Installing: /usr/local/lib/python3.9/dist-packages/gnuradio/customModule/customModule_python.cpython-39-x86_64-linux-gnu.so
-- Set runtime path of "/usr/local/lib/python3.9/dist-packages/gnuradio/customModule/customModule_python.cpython-39-x86_64-linux-gnu.so" to ""
-- Up-to-date: /usr/local/share/gnuradio/grc/blocks/customModule_addSubSelect.block.yml
-- Installing: /usr/local/share/gnuradio/grc/blocks/customModule_multDivSelector.block.yml

Some of the files are listed as Up-to-date because they correspond to the addSubSelect block created in the Creating Python OOT with gr-modtool tutorial. All of the files corresponding to multDivSelect are now instlaled to /usr/local/.