Editing Interfacing Hardware with a C++ OOT Module

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 5: Line 5:
 
== Linking against Driver Library ==
 
== Linking against Driver Library ==
 
The first thing you will need when writing a block, that connects your design to hardware, is getting the driver compiled and linked against your module. To do this make sure you have installed the driver library and corresponding dependencies correctly on your system e.g. by compiling a small example application executing some basic routines of the driver. What you need next is to tell cmake where to find the libraries you want to include. It is known as best practice to do this writing a [https://cmake.org/Wiki/CMake:How_To_Find_Libraries#Writing_find_modules find module] for every external library. Modules for cmake in GNURadio OOTs are located under ''cmake/Modules''. In this directory create a file and give it a proper name e.g. ''FindLimeSuite.cmake''. The find module can for instance look as follows:
 
The first thing you will need when writing a block, that connects your design to hardware, is getting the driver compiled and linked against your module. To do this make sure you have installed the driver library and corresponding dependencies correctly on your system e.g. by compiling a small example application executing some basic routines of the driver. What you need next is to tell cmake where to find the libraries you want to include. It is known as best practice to do this writing a [https://cmake.org/Wiki/CMake:How_To_Find_Libraries#Writing_find_modules find module] for every external library. Modules for cmake in GNURadio OOTs are located under ''cmake/Modules''. In this directory create a file and give it a proper name e.g. ''FindLimeSuite.cmake''. The find module can for instance look as follows:
<syntaxhighlight lang="C++">
+
<source lang="cmake">
 
# - Looking for LimeSuite on the machine
 
# - Looking for LimeSuite on the machine
 
# Once done this will define
 
# Once done this will define
Line 53: Line 53:
 
         message(STATUS "Found LimeSuite: ${LIMESUITE_LIBRARIES} and ${LIMESUITE_INCLUDE_DIRS}.")
 
         message(STATUS "Found LimeSuite: ${LIMESUITE_LIBRARIES} and ${LIMESUITE_INCLUDE_DIRS}.")
 
endif()
 
endif()
</syntaxhighlight>
+
</source>
  
 
As one can see this module, silently assumed it is written correctly, sets three variables: ''LIMESUITE_INCLUDE_DIRS'', ''LIMESUITE_LIBRARIES'' and ''LIMESUITE_FOUND''. These variables are put to use later on. Our module is executed by calling it in the CMakeLists.txt, located in the root of the OOT module:   
 
As one can see this module, silently assumed it is written correctly, sets three variables: ''LIMESUITE_INCLUDE_DIRS'', ''LIMESUITE_LIBRARIES'' and ''LIMESUITE_FOUND''. These variables are put to use later on. Our module is executed by calling it in the CMakeLists.txt, located in the root of the OOT module:   
<syntaxhighlight lang="cmake">
+
<source lang="cmake">
 
# Call the module
 
# Call the module
 
find_package(LimeSuite)
 
find_package(LimeSuite)
Line 62: Line 62:
 
         message(FATAL_ERROR "LimeSuite required to compile limesdr.")
 
         message(FATAL_ERROR "LimeSuite required to compile limesdr.")
 
endif()
 
endif()
</syntaxhighlight>  
+
</source>  
 
The code above can be placed into the segment where cmake searches for GNURadio dependencies.  
 
The code above can be placed into the segment where cmake searches for GNURadio dependencies.  
  
 
So far so good. We triggered cmake to seek the library and used ''LIMESUITE_FOUND'' to see if cmake was successful. However, we have not made use of the other two variables yet, right? ''LIMESUITE_LIBRARIES'' holds the directory where the dynamically linked library (a .so file) is installed on the system. cmake needs to know, that we want to link this library against our code. Therefore, it provides a macro, which is called in ''lib/CMakeLists.txt''.  
 
So far so good. We triggered cmake to seek the library and used ''LIMESUITE_FOUND'' to see if cmake was successful. However, we have not made use of the other two variables yet, right? ''LIMESUITE_LIBRARIES'' holds the directory where the dynamically linked library (a .so file) is installed on the system. cmake needs to know, that we want to link this library against our code. Therefore, it provides a macro, which is called in ''lib/CMakeLists.txt''.  
<syntaxhighlight lang="cmake">
+
<source lang="cmake">
 
target_link_libraries(gnuradio-limesdr ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES} ${LIMESUITE_LIBRARIES})
 
target_link_libraries(gnuradio-limesdr ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES} ${LIMESUITE_LIBRARIES})
</syntaxhighlight>
+
</source>
 
The final step is to take the last unused variable and communicate to cmake, that there are header files we want to have added to our project.  
 
The final step is to take the last unused variable and communicate to cmake, that there are header files we want to have added to our project.  
<syntaxhighlight lang="cmake">
+
<source lang="cmake">
 
########################################################################
 
########################################################################
 
# Setup the include and linker paths
 
# Setup the include and linker paths
Line 84: Line 84:
 
     ${LIMESUITE_INCLUDE_DIRS}
 
     ${LIMESUITE_INCLUDE_DIRS}
 
)
 
)
</syntaxhighlight>
+
</source>
 
In case you did not mess up something, you will be able to use the the driver library from now own in your code with a normal include like
 
In case you did not mess up something, you will be able to use the the driver library from now own in your code with a normal include like
<syntaxhighlight lang="c++">
+
<source lang="c++">
 
#include <LimeSuite.h>
 
#include <LimeSuite.h>
</syntaxhighlight>
+
</source>
 
If something is wrong, you perhaps will get a quite nasty and really annoying error message similar to ''AttributeError: 'module' object has no attribute 'MODULE_NAME'''. Usually, this can be interpreted as, that you did configure something wrong in the steps described above and you should iterate through the whole procedure again.  
 
If something is wrong, you perhaps will get a quite nasty and really annoying error message similar to ''AttributeError: 'module' object has no attribute 'MODULE_NAME'''. Usually, this can be interpreted as, that you did configure something wrong in the steps described above and you should iterate through the whole procedure again.  
  
 
Fortunately, there is a way provided by a program called ''ldd'' ("print shared object dependencies", says man ldd) to find out if you linked the dynamic library properly against your library (produced and deployed when you type sudo make install):
 
Fortunately, there is a way provided by a program called ''ldd'' ("print shared object dependencies", says man ldd) to find out if you linked the dynamic library properly against your library (produced and deployed when you type sudo make install):
<syntaxhighlight>
+
<source>
 
ldd /usr/local/lib/libgnuradio-limesdr.so | grep LimeSuite
 
ldd /usr/local/lib/libgnuradio-limesdr.so | grep LimeSuite
</syntaxhighlight>
+
</source>
 
The output should be something like
 
The output should be something like
<syntaxhighlight>
+
<source>
 
libLimeSuite.so.18.02-1 => /usr/local/lib/libLimeSuite.so.18.02-1 (0x00007f5b86be8000)
 
libLimeSuite.so.18.02-1 => /usr/local/lib/libLimeSuite.so.18.02-1 (0x00007f5b86be8000)
</syntaxhighlight>
+
</source>
 
and can be interpreted as a success of the previous steps. Hurray! If you can not scream the 'Hurray!' yet, since it does not work, the following might be some helpful piece code for you
 
and can be interpreted as a success of the previous steps. Hurray! If you can not scream the 'Hurray!' yet, since it does not work, the following might be some helpful piece code for you
<syntaxhighlight lang="cmake">
+
<source lang="cmake">
 
########################################################################
 
########################################################################
 
# Debugging
 
# Debugging
Line 111: Line 111:
 
         endforeach()
 
         endforeach()
 
endif(PRINT_ALL_VARS)
 
endif(PRINT_ALL_VARS)
</syntaxhighlight>  
+
</source>  
 
which is borrowed from [https://stackoverflow.com/questions/9298278/cmake-print-out-all-accessible-variables-in-a-script#9328525 here].
 
which is borrowed from [https://stackoverflow.com/questions/9298278/cmake-print-out-all-accessible-variables-in-a-script#9328525 here].
  
Line 123: Line 123:
 
However, one can not solely trust on this mechanism as it seems not to be called when ''start ()'' fails. One approach for a sane design might be to call ''stop ()'' oneself as part of the exception handling in a catch block. An example implementation of ''start()'' is the following:
 
However, one can not solely trust on this mechanism as it seems not to be called when ''start ()'' fails. One approach for a sane design might be to call ''stop ()'' oneself as part of the exception handling in a catch block. An example implementation of ''start()'' is the following:
  
<syntaxhighlight lang="c++">
+
<source lang="c++">
 
try
 
try
 
{
 
{
Line 137: Line 137:
 
   throw;
 
   throw;
 
}  
 
}  
</syntaxhighlight>
+
</source>
  
 
The above example tries to initialize the HW, if it fails, the device will be deinitialized again as ''stop()'' is called.
 
The above example tries to initialize the HW, if it fails, the device will be deinitialized again as ''stop()'' is called.
Line 147: Line 147:
 
The implementation of the stop function can be much simpler as it avoids exceptions:
 
The implementation of the stop function can be much simpler as it avoids exceptions:
  
<syntaxhighlight lang="c++">
+
<source lang="c++">
 
LOG << "stop() called.";
 
LOG << "stop() called.";
 
// Deinitialize HW.
 
// Deinitialize HW.
 
deinit_hw();
 
deinit_hw();
</syntaxhighlight>
+
</source>
  
 
One more thing to mention is, that having a signal source with a fixed sample rate, should embed the function ''set_output_multiple(...)'' provided by [https://gnuradio.org/doc/doxygen/classgr_1_1block.html gr::block] somewhere in the constructor. The argument of this function should be the size of the buffer for communication between the (hopefully) asynchronous driver and the GNURadio block. This makes sure, that the data size the work function has to output (''noutput_items'') is always a multiple of buffer's size and it is always OK to return less samples. Yet, it is not recommended to produce less samples than specified with ''noutput_items''.
 
One more thing to mention is, that having a signal source with a fixed sample rate, should embed the function ''set_output_multiple(...)'' provided by [https://gnuradio.org/doc/doxygen/classgr_1_1block.html gr::block] somewhere in the constructor. The argument of this function should be the size of the buffer for communication between the (hopefully) asynchronous driver and the GNURadio block. This makes sure, that the data size the work function has to output (''noutput_items'') is always a multiple of buffer's size and it is always OK to return less samples. Yet, it is not recommended to produce less samples than specified with ''noutput_items''.

Please note that all contributions to GNU Radio are considered to be released under the Creative Commons Attribution-ShareAlike (see GNU Radio:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To edit this page, please answer the question that appears below (more info):

Cancel | Editing help (opens in new window)