Creating C++ OOT with gr-modtool

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

Creating an OOT 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 multDivSelect: $ gr_modtool add multDivSelect

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, because the block we're making will produce the same number of output items on the output port for each item it consumes from the input port. See Types of Blocks for more info on different block types that are available. Enter block type: sync

Enter cpp as the language: Language (python/cpp): cpp Language: C++ Block/code identifier: multDivSelect

Enter the name or organization of the copyright holder: Please specify the copyright holder: YourName

Our OOT block allows the gnuradio-companion user to specify a selector value, which at the C++ level is a boolean (true/false) value. To enable this, we need to enter the C++ expression shown below that declares the selector variable with a default value of true as an argument to our OOT block:

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/multDivSelect_impl.h'... Adding file 'lib/multDivSelect_impl.cc'... Adding file 'include/gnuradio/customModule/multDivSelect.h'... Adding file 'python/customModule/bindings/docstrings/multDivSelect_pydoc_template.h'... Adding file 'python/customModule/bindings/multDivSelect_python.cc'... Adding file 'grc/customModule_multDivSelect.block.yml'... Editing grc/CMakeLists.txt...

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

$ gedit lib/multDivSelect_impl.h &

The following code will be displayed:

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

Press CTRL + S to save the file.

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

$ gedit lib/multDivSelect_impl.cc &

The code will be as displayed:

Remove the pragma messages and define the input and output type to be 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:

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:

Press CTRL + S to save the file.

Modifying the YAML .yml File
gnuradio-companion uses files in the YAML (yet another markup language) format to learn about our OOT block and how to call it. More information about this kind of file may be found in the YAML GRC page.

Open our block's YAML file using a text editor:

$ gedit grc/customModule_multDivSelect.block.yml &

The code will be displayed:

Update the parameter definition with the information for selector:

Update the input port and output port definitions:

Press CTRL + S to save the file.

Compiling and Installing the Block
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/multDivSelect.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_multDivSelect.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 installed to /usr/local/.

Run ldconfig to update the linking for the customModule library:

$ sudo ldconfig

Using the Custom Block in a Flowgraph
If GRC is already running, press the Reload button to refresh the list of blocks in the library:



Otherwise, start GRC from the command line: $ gnuradio-companion &

The multDivBlock can now be seen under the customModule tab. The addSubSelect is a Python block created in the Creating Python OOT with gr-modtool tutorial.



Drag the multDivSelect block into the flowgraph:



Now drag in the following blocks and update their properties:
 * Signal Source
 * Frequency: 100
 * Constant Source
 * Constant: 2
 * Throttle
 * QT GUI Time Sink
 * Autoscale: Yes

Connect the flowgraph accordingly:



Running the Flowgraph
Run the flowgraph. The QT GUI Time Sink will display the following output. Notice that the amplitude of the sinusoid is 2, due to the multiplication by 2 in the multDivSelect block.



Edit the properties of the multDivSelect block and enter False for the selector:



Click OK to save the property.

Run the flowgraph. The QT GUI Time Sink will display the following output. Notice that the amplitude of the sinusoid is 0.5, due to the division by 2 in the multDivSelect block.



Making Changes
It is suggested to recompile and reinstall the module any time a change is made, followed by reloading the block library in GRC. This includes changes such as:
 * Number of parameters
 * Type of parameters
 * Number of input ports or output ports
 * Types of input ports or output ports
 * Modifying the YAML .yml file
 * Modifying any c++ .h or .cc files

Removing and re-creating the build/ directory may be necessary before recompiling and reinstalling the module depending on the scope of the change:

$ rm -rf gr-customModule/build $ mkdir gr-customModule/build

The previous tutorial, Creating Python OOT with gr-modtool, describes how to build a custom Python OOT module.