├── .gitignore ├── Bachelor_thesis_Douglas_Weber.pdf ├── CMakeLists.txt ├── LICENSE ├── MANIFEST.md ├── README.md ├── cmake ├── Modules │ ├── CMakeParseArgumentsCopy.cmake │ ├── FindCppUnit.cmake │ ├── FindGnuradioRuntime.cmake │ ├── GrMiscUtils.cmake │ ├── GrPlatform.cmake │ ├── GrPython.cmake │ ├── GrSwig.cmake │ ├── GrTest.cmake │ ├── UseSWIG.cmake │ └── cbmcConfig.cmake └── cmake_uninstall.cmake.in ├── docs ├── CMakeLists.txt ├── README.cbmc └── doxygen │ ├── CMakeLists.txt │ ├── Doxyfile.in │ ├── Doxyfile.swig_doc.in │ ├── doxyxml │ ├── __init__.py │ ├── __init__.pyc │ ├── base.py │ ├── base.pyc │ ├── doxyindex.py │ ├── doxyindex.pyc │ ├── generated │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── compound.py │ │ ├── compound.pyc │ │ ├── compoundsuper.py │ │ ├── compoundsuper.pyc │ │ ├── index.py │ │ ├── index.pyc │ │ ├── indexsuper.py │ │ └── indexsuper.pyc │ ├── text.py │ └── text.pyc │ ├── other │ ├── group_defs.dox │ └── main_page.dox │ ├── swig_doc.py │ └── swig_doc.pyc ├── examples └── receiver_chain_with_modulation_classification.grc ├── grc ├── CMakeLists.txt ├── cbmc_freq_sps_det.xml ├── cbmc_modulation_classifier.xml └── cbmc_my_pfb_clock_sync.xml ├── include └── cbmc │ ├── CMakeLists.txt │ ├── api.h │ ├── freq_sps_det.h │ ├── modulation_classifier.h │ └── my_pfb_clock_sync.h ├── lib ├── CMakeLists.txt ├── freq_sps_det_impl.cc ├── freq_sps_det_impl.h ├── modulation_classifier_impl.cc ├── modulation_classifier_impl.h ├── my_pfb_clock_sync_impl.cc ├── my_pfb_clock_sync_impl.h ├── qa_cbmc.cc ├── qa_cbmc.h └── test_cbmc.cc ├── pic_example_flowgraph.png ├── python ├── CMakeLists.txt ├── __init__.py ├── __init__.pyc ├── build_utils.py ├── build_utils.pyc ├── build_utils_codes.py └── build_utils_codes.pyc └── swig ├── CMakeLists.txt └── cbmc_swig.i /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Build directory 35 | build/ 36 | -------------------------------------------------------------------------------- /Bachelor_thesis_Douglas_Weber.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/Bachelor_thesis_Douglas_Weber.pdf -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012,2014,2016 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Project setup 22 | ######################################################################## 23 | cmake_minimum_required(VERSION 2.6) 24 | project(gr-cbmc CXX C) 25 | enable_testing() 26 | 27 | #install to PyBOMBS target prefix if defined 28 | if(DEFINED ENV{PYBOMBS_PREFIX}) 29 | set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX}) 30 | message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}") 31 | endif() 32 | 33 | #select the release build type by default to get optimization flags 34 | if(NOT CMAKE_BUILD_TYPE) 35 | set(CMAKE_BUILD_TYPE "Release") 36 | message(STATUS "Build type not specified: defaulting to release.") 37 | endif(NOT CMAKE_BUILD_TYPE) 38 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") 39 | 40 | #make sure our local CMake Modules path comes first 41 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) 42 | 43 | # Set the version information here 44 | set(VERSION_INFO_MAJOR_VERSION 1) 45 | set(VERSION_INFO_API_COMPAT 0) 46 | set(VERSION_INFO_MINOR_VERSION 0) 47 | set(VERSION_INFO_MAINT_VERSION git) 48 | 49 | ######################################################################## 50 | # Compiler specific setup 51 | ######################################################################## 52 | if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) 53 | #http://gcc.gnu.org/wiki/Visibility 54 | add_definitions(-fvisibility=hidden) 55 | endif() 56 | 57 | ######################################################################## 58 | # Find boost 59 | ######################################################################## 60 | if(UNIX AND EXISTS "/usr/lib64") 61 | list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix 62 | endif(UNIX AND EXISTS "/usr/lib64") 63 | set(Boost_ADDITIONAL_VERSIONS 64 | "1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39" 65 | "1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44" 66 | "1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49" 67 | "1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54" 68 | "1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59" 69 | "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64" 70 | "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" 71 | ) 72 | find_package(Boost "1.35" COMPONENTS filesystem system) 73 | 74 | if(NOT Boost_FOUND) 75 | message(FATAL_ERROR "Boost required to compile cbmc") 76 | endif() 77 | 78 | ######################################################################## 79 | # Install directories 80 | ######################################################################## 81 | include(GrPlatform) #define LIB_SUFFIX 82 | set(GR_RUNTIME_DIR bin) 83 | set(GR_LIBRARY_DIR lib${LIB_SUFFIX}) 84 | set(GR_INCLUDE_DIR include/cbmc) 85 | set(GR_DATA_DIR share) 86 | set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) 87 | set(GR_DOC_DIR ${GR_DATA_DIR}/doc) 88 | set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) 89 | set(GR_CONF_DIR etc) 90 | set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) 91 | set(GR_LIBEXEC_DIR libexec) 92 | set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) 93 | set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks) 94 | 95 | ######################################################################## 96 | # On Apple only, set install name and use rpath correctly, if not already set 97 | ######################################################################## 98 | if(APPLE) 99 | if(NOT CMAKE_INSTALL_NAME_DIR) 100 | set(CMAKE_INSTALL_NAME_DIR 101 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 102 | PATH "Library Install Name Destination Directory" FORCE) 103 | endif(NOT CMAKE_INSTALL_NAME_DIR) 104 | if(NOT CMAKE_INSTALL_RPATH) 105 | set(CMAKE_INSTALL_RPATH 106 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 107 | PATH "Library Install RPath" FORCE) 108 | endif(NOT CMAKE_INSTALL_RPATH) 109 | if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 110 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE 111 | BOOL "Do Build Using Library Install RPath" FORCE) 112 | endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 113 | endif(APPLE) 114 | 115 | ######################################################################## 116 | # Find gnuradio build dependencies 117 | ######################################################################## 118 | find_package(CppUnit) 119 | find_package(Doxygen) 120 | 121 | # Search for GNU Radio and its components and versions. Add any 122 | # components required to the list of GR_REQUIRED_COMPONENTS (in all 123 | # caps such as FILTER or FFT) and change the version to the minimum 124 | # API compatible version required. 125 | set(GR_REQUIRED_COMPONENTS RUNTIME FFT FILTER) 126 | find_package(Gnuradio "3.7.2" REQUIRED) 127 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) 128 | include(GrVersion) 129 | 130 | if(NOT CPPUNIT_FOUND) 131 | message(FATAL_ERROR "CppUnit required to compile cbmc") 132 | endif() 133 | 134 | ######################################################################## 135 | # Setup doxygen option 136 | ######################################################################## 137 | if(DOXYGEN_FOUND) 138 | option(ENABLE_DOXYGEN "Build docs using Doxygen" ON) 139 | else(DOXYGEN_FOUND) 140 | option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF) 141 | endif(DOXYGEN_FOUND) 142 | 143 | ######################################################################## 144 | # Setup the include and linker paths 145 | ######################################################################## 146 | include_directories( 147 | ${CMAKE_SOURCE_DIR}/lib 148 | ${CMAKE_SOURCE_DIR}/include 149 | ${CMAKE_BINARY_DIR}/lib 150 | ${CMAKE_BINARY_DIR}/include 151 | ${Boost_INCLUDE_DIRS} 152 | ${CPPUNIT_INCLUDE_DIRS} 153 | ${GNURADIO_ALL_INCLUDE_DIRS} 154 | ) 155 | 156 | link_directories( 157 | ${Boost_LIBRARY_DIRS} 158 | ${CPPUNIT_LIBRARY_DIRS} 159 | ${GNURADIO_RUNTIME_LIBRARY_DIRS} 160 | ) 161 | 162 | # Set component parameters 163 | set(GR_CBMC_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE) 164 | set(GR_CBMC_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE) 165 | 166 | ######################################################################## 167 | # Create uninstall target 168 | ######################################################################## 169 | configure_file( 170 | ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 171 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 172 | @ONLY) 173 | 174 | add_custom_target(uninstall 175 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 176 | ) 177 | 178 | ######################################################################## 179 | # Add subdirectories 180 | ######################################################################## 181 | add_subdirectory(include/cbmc) 182 | add_subdirectory(lib) 183 | add_subdirectory(swig) 184 | add_subdirectory(python) 185 | add_subdirectory(grc) 186 | add_subdirectory(docs) 187 | 188 | ######################################################################## 189 | # Install cmake search helper for this library 190 | ######################################################################## 191 | if(NOT CMAKE_MODULES_DIR) 192 | set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) 193 | endif(NOT CMAKE_MODULES_DIR) 194 | 195 | install(FILES cmake/Modules/cbmcConfig.cmake 196 | DESTINATION ${CMAKE_MODULES_DIR}/cbmc 197 | ) 198 | -------------------------------------------------------------------------------- /MANIFEST.md: -------------------------------------------------------------------------------- 1 | title: The CBMC OOT Module 2 | brief: Cumulant-Based Modulation Classification 3 | tags: 4 | - sdr 5 | - modulation 6 | - classification 7 | - detect 8 | - synchronization 9 | author: 10 | - Douglas Weber # 11 | copyright_owner: 12 | - Douglas Weber 13 | license: 14 | repo: https://github.com/kit-cel/gr-cbmc.git 15 | #website: # If you have a separate project website, put it here 16 | #icon: # Put a URL to a square image here that will be used as an icon on CGRAN 17 | --- 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gr-cbmc 2 | A Cumulant-Based Modulation Classification module for GNU Radio 3 | 4 | ## Features 5 | * Classification of the modulation of a signal 6 | * Detection of BPSK, QPSK, 16-QAM and 8-PSK possible 7 | * Classification and phase correction is done by one block 8 | * The necessary synchronisation is perfomed by custom-built blocks 9 | * Frequency and Symbolrate estimation 10 | * Time synchronization (modified version of pfb_clock_sync) 11 | * The result is a stream of symbols (with 1 sample per symbol) without phase-/frequency-/timing-offset, which includes the current modulation as stream tags 12 | 13 | ## Usage 14 | There is a flowgraph in examples/ which demonstrates the classification receiver chain. The receiver of the flowgraph is displayed here: 15 | 16 | ![Example flowgraph](https://github.com/kit-cel/gr-cbmc/raw/master/pic_example_flowgraph.png "Example flowgraph") 17 | 18 | Further information is available in this [bachelor thesis (german).](https://github.com/kit-cel/gr-cbmc/raw/master/Bachelor_thesis_Douglas_Weber.pdf) This module was built as part of the thesis. An additional interesting source is the doctoral thesis by Michael Sebastian Mühlhaus: [Automatische Modulationsartenerkennung in MIMO-Systemen.](https://publikationen.bibliothek.kit.edu/1000039383) 19 | 20 | ## Installation 21 | To install this module, run these commands: 22 | 23 | $ mkdir build 24 | $ cd build 25 | $ cmake ../ 26 | $ make 27 | $ sudo make install 28 | $ sudo ldconfig 29 | 30 | The build process has been tested with 31 | * cppunit, version 1.14.0 32 | * gnuradio, version 3.7.10 33 | * doxygen, version 1.8.13 34 | 35 | ## Current Constraints 36 | * Just setting stream tags, no actual demodulation of the signal 37 | * If there is only noise, always 8PSK will be classified 38 | 39 | -------------------------------------------------------------------------------- /cmake/Modules/CMakeParseArgumentsCopy.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE_PARSE_ARGUMENTS( args...) 2 | # 3 | # CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for 4 | # parsing the arguments given to that macro or function. 5 | # It processes the arguments and defines a set of variables which hold the 6 | # values of the respective options. 7 | # 8 | # The argument contains all options for the respective macro, 9 | # i.e. keywords which can be used when calling the macro without any value 10 | # following, like e.g. the OPTIONAL keyword of the install() command. 11 | # 12 | # The argument contains all keywords for this macro 13 | # which are followed by one value, like e.g. DESTINATION keyword of the 14 | # install() command. 15 | # 16 | # The argument contains all keywords for this macro 17 | # which can be followed by more than one value, like e.g. the TARGETS or 18 | # FILES keywords of the install() command. 19 | # 20 | # When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the 21 | # keywords listed in , and 22 | # a variable composed of the given 23 | # followed by "_" and the name of the respective keyword. 24 | # These variables will then hold the respective value from the argument list. 25 | # For the keywords this will be TRUE or FALSE. 26 | # 27 | # All remaining arguments are collected in a variable 28 | # _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether 29 | # your macro was called with unrecognized parameters. 30 | # 31 | # As an example here a my_install() macro, which takes similar arguments as the 32 | # real install() command: 33 | # 34 | # function(MY_INSTALL) 35 | # set(options OPTIONAL FAST) 36 | # set(oneValueArgs DESTINATION RENAME) 37 | # set(multiValueArgs TARGETS CONFIGURATIONS) 38 | # cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 39 | # ... 40 | # 41 | # Assume my_install() has been called like this: 42 | # my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) 43 | # 44 | # After the cmake_parse_arguments() call the macro will have set the following 45 | # variables: 46 | # MY_INSTALL_OPTIONAL = TRUE 47 | # MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() 48 | # MY_INSTALL_DESTINATION = "bin" 49 | # MY_INSTALL_RENAME = "" (was not used) 50 | # MY_INSTALL_TARGETS = "foo;bar" 51 | # MY_INSTALL_CONFIGURATIONS = "" (was not used) 52 | # MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" 53 | # 54 | # You can the continue and process these variables. 55 | # 56 | # Keywords terminate lists of values, e.g. if directly after a one_value_keyword 57 | # another recognized keyword follows, this is interpreted as the beginning of 58 | # the new option. 59 | # E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in 60 | # MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would 61 | # be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. 62 | 63 | #============================================================================= 64 | # Copyright 2010 Alexander Neundorf 65 | # 66 | # Distributed under the OSI-approved BSD License (the "License"); 67 | # see accompanying file Copyright.txt for details. 68 | # 69 | # This software is distributed WITHOUT ANY WARRANTY; without even the 70 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 71 | # See the License for more information. 72 | #============================================================================= 73 | # (To distribute this file outside of CMake, substitute the full 74 | # License text for the above reference.) 75 | 76 | 77 | if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) 78 | return() 79 | endif() 80 | set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) 81 | 82 | 83 | function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) 84 | # first set all result variables to empty/FALSE 85 | foreach(arg_name ${_singleArgNames} ${_multiArgNames}) 86 | set(${prefix}_${arg_name}) 87 | endforeach(arg_name) 88 | 89 | foreach(option ${_optionNames}) 90 | set(${prefix}_${option} FALSE) 91 | endforeach(option) 92 | 93 | set(${prefix}_UNPARSED_ARGUMENTS) 94 | 95 | set(insideValues FALSE) 96 | set(currentArgName) 97 | 98 | # now iterate over all arguments and fill the result variables 99 | foreach(currentArg ${ARGN}) 100 | list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword 101 | list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword 102 | list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword 103 | 104 | if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) 105 | if(insideValues) 106 | if("${insideValues}" STREQUAL "SINGLE") 107 | set(${prefix}_${currentArgName} ${currentArg}) 108 | set(insideValues FALSE) 109 | elseif("${insideValues}" STREQUAL "MULTI") 110 | list(APPEND ${prefix}_${currentArgName} ${currentArg}) 111 | endif() 112 | else(insideValues) 113 | list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) 114 | endif(insideValues) 115 | else() 116 | if(NOT ${optionIndex} EQUAL -1) 117 | set(${prefix}_${currentArg} TRUE) 118 | set(insideValues FALSE) 119 | elseif(NOT ${singleArgIndex} EQUAL -1) 120 | set(currentArgName ${currentArg}) 121 | set(${prefix}_${currentArgName}) 122 | set(insideValues "SINGLE") 123 | elseif(NOT ${multiArgIndex} EQUAL -1) 124 | set(currentArgName ${currentArg}) 125 | set(${prefix}_${currentArgName}) 126 | set(insideValues "MULTI") 127 | endif() 128 | endif() 129 | 130 | endforeach(currentArg) 131 | 132 | # propagate the result variables to the caller: 133 | foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) 134 | set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) 135 | endforeach(arg_name) 136 | set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) 137 | 138 | endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) 139 | -------------------------------------------------------------------------------- /cmake/Modules/FindCppUnit.cmake: -------------------------------------------------------------------------------- 1 | # http://www.cmake.org/pipermail/cmake/2006-October/011446.html 2 | # Modified to use pkg config and use standard var names 3 | 4 | # 5 | # Find the CppUnit includes and library 6 | # 7 | # This module defines 8 | # CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc. 9 | # CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit. 10 | # CPPUNIT_FOUND, If false, do not try to use CppUnit. 11 | 12 | INCLUDE(FindPkgConfig) 13 | PKG_CHECK_MODULES(PC_CPPUNIT "cppunit") 14 | 15 | FIND_PATH(CPPUNIT_INCLUDE_DIRS 16 | NAMES cppunit/TestCase.h 17 | HINTS ${PC_CPPUNIT_INCLUDE_DIR} 18 | ${CMAKE_INSTALL_PREFIX}/include 19 | PATHS 20 | /usr/local/include 21 | /usr/include 22 | ) 23 | 24 | FIND_LIBRARY(CPPUNIT_LIBRARIES 25 | NAMES cppunit 26 | HINTS ${PC_CPPUNIT_LIBDIR} 27 | ${CMAKE_INSTALL_PREFIX}/lib 28 | ${CMAKE_INSTALL_PREFIX}/lib64 29 | PATHS 30 | ${CPPUNIT_INCLUDE_DIRS}/../lib 31 | /usr/local/lib 32 | /usr/lib 33 | ) 34 | 35 | LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS}) 36 | 37 | INCLUDE(FindPackageHandleStandardArgs) 38 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS) 39 | MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS) 40 | -------------------------------------------------------------------------------- /cmake/Modules/FindGnuradioRuntime.cmake: -------------------------------------------------------------------------------- 1 | INCLUDE(FindPkgConfig) 2 | PKG_CHECK_MODULES(PC_GNURADIO_RUNTIME gnuradio-runtime) 3 | 4 | if(PC_GNURADIO_RUNTIME_FOUND) 5 | # look for include files 6 | FIND_PATH( 7 | GNURADIO_RUNTIME_INCLUDE_DIRS 8 | NAMES gnuradio/top_block.h 9 | HINTS $ENV{GNURADIO_RUNTIME_DIR}/include 10 | ${PC_GNURADIO_RUNTIME_INCLUDE_DIRS} 11 | ${CMAKE_INSTALL_PREFIX}/include 12 | PATHS /usr/local/include 13 | /usr/include 14 | ) 15 | 16 | # look for libs 17 | FIND_LIBRARY( 18 | GNURADIO_RUNTIME_LIBRARIES 19 | NAMES gnuradio-runtime 20 | HINTS $ENV{GNURADIO_RUNTIME_DIR}/lib 21 | ${PC_GNURADIO_RUNTIME_LIBDIR} 22 | ${CMAKE_INSTALL_PREFIX}/lib/ 23 | ${CMAKE_INSTALL_PREFIX}/lib64/ 24 | PATHS /usr/local/lib 25 | /usr/local/lib64 26 | /usr/lib 27 | /usr/lib64 28 | ) 29 | 30 | set(GNURADIO_RUNTIME_FOUND ${PC_GNURADIO_RUNTIME_FOUND}) 31 | endif(PC_GNURADIO_RUNTIME_FOUND) 32 | 33 | INCLUDE(FindPackageHandleStandardArgs) 34 | # do not check GNURADIO_RUNTIME_INCLUDE_DIRS, is not set when default include path us used. 35 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES) 36 | MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS) 37 | -------------------------------------------------------------------------------- /cmake/Modules/GrPlatform.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE) 21 | return() 22 | endif() 23 | set(__INCLUDED_GR_PLATFORM_CMAKE TRUE) 24 | 25 | ######################################################################## 26 | # Setup additional defines for OS types 27 | ######################################################################## 28 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 29 | set(LINUX TRUE) 30 | endif() 31 | 32 | if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/debian_version") 33 | set(DEBIAN TRUE) 34 | endif() 35 | 36 | if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/redhat-release") 37 | set(REDHAT TRUE) 38 | endif() 39 | 40 | if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/slackware-version") 41 | set(SLACKWARE TRUE) 42 | endif() 43 | 44 | ######################################################################## 45 | # when the library suffix should be 64 (applies to redhat linux family) 46 | ######################################################################## 47 | if (REDHAT OR SLACKWARE) 48 | set(LIB64_CONVENTION TRUE) 49 | endif() 50 | 51 | if(NOT DEFINED LIB_SUFFIX AND LIB64_CONVENTION AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$") 52 | set(LIB_SUFFIX 64) 53 | endif() 54 | set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix") 55 | -------------------------------------------------------------------------------- /cmake/Modules/GrPython.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | if(DEFINED __INCLUDED_GR_PYTHON_CMAKE) 21 | return() 22 | endif() 23 | set(__INCLUDED_GR_PYTHON_CMAKE TRUE) 24 | 25 | ######################################################################## 26 | # Setup the python interpreter: 27 | # This allows the user to specify a specific interpreter, 28 | # or finds the interpreter via the built-in cmake module. 29 | ######################################################################## 30 | #this allows the user to override PYTHON_EXECUTABLE 31 | if(PYTHON_EXECUTABLE) 32 | 33 | set(PYTHONINTERP_FOUND TRUE) 34 | 35 | #otherwise if not set, try to automatically find it 36 | else(PYTHON_EXECUTABLE) 37 | 38 | #use the built-in find script 39 | find_package(PythonInterp 2) 40 | 41 | #and if that fails use the find program routine 42 | if(NOT PYTHONINTERP_FOUND) 43 | find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5) 44 | if(PYTHON_EXECUTABLE) 45 | set(PYTHONINTERP_FOUND TRUE) 46 | endif(PYTHON_EXECUTABLE) 47 | endif(NOT PYTHONINTERP_FOUND) 48 | 49 | endif(PYTHON_EXECUTABLE) 50 | 51 | if (CMAKE_CROSSCOMPILING) 52 | set(QA_PYTHON_EXECUTABLE "/usr/bin/python") 53 | else (CMAKE_CROSSCOMPILING) 54 | set(QA_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) 55 | endif(CMAKE_CROSSCOMPILING) 56 | 57 | #make the path to the executable appear in the cmake gui 58 | set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") 59 | set(QA_PYTHON_EXECUTABLE ${QA_PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter for QA tests") 60 | 61 | #make sure we can use -B with python (introduced in 2.6) 62 | if(PYTHON_EXECUTABLE) 63 | execute_process( 64 | COMMAND ${PYTHON_EXECUTABLE} -B -c "" 65 | OUTPUT_QUIET ERROR_QUIET 66 | RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT 67 | ) 68 | if(PYTHON_HAS_DASH_B_RESULT EQUAL 0) 69 | set(PYTHON_DASH_B "-B") 70 | endif() 71 | endif(PYTHON_EXECUTABLE) 72 | 73 | ######################################################################## 74 | # Check for the existence of a python module: 75 | # - desc a string description of the check 76 | # - mod the name of the module to import 77 | # - cmd an additional command to run 78 | # - have the result variable to set 79 | ######################################################################## 80 | macro(GR_PYTHON_CHECK_MODULE desc mod cmd have) 81 | message(STATUS "") 82 | message(STATUS "Python checking for ${desc}") 83 | execute_process( 84 | COMMAND ${PYTHON_EXECUTABLE} -c " 85 | ######################################### 86 | try: 87 | import ${mod} 88 | assert ${cmd} 89 | except ImportError, AssertionError: exit(-1) 90 | except: pass 91 | #########################################" 92 | RESULT_VARIABLE ${have} 93 | ) 94 | if(${have} EQUAL 0) 95 | message(STATUS "Python checking for ${desc} - found") 96 | set(${have} TRUE) 97 | else(${have} EQUAL 0) 98 | message(STATUS "Python checking for ${desc} - not found") 99 | set(${have} FALSE) 100 | endif(${have} EQUAL 0) 101 | endmacro(GR_PYTHON_CHECK_MODULE) 102 | 103 | ######################################################################## 104 | # Sets the python installation directory GR_PYTHON_DIR 105 | ######################################################################## 106 | if(NOT DEFINED GR_PYTHON_DIR) 107 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " 108 | from distutils import sysconfig 109 | print sysconfig.get_python_lib(plat_specific=True, prefix='') 110 | " OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE 111 | ) 112 | endif() 113 | file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR) 114 | 115 | ######################################################################## 116 | # Create an always-built target with a unique name 117 | # Usage: GR_UNIQUE_TARGET( ) 118 | ######################################################################## 119 | function(GR_UNIQUE_TARGET desc) 120 | file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 121 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib 122 | unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5] 123 | print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))" 124 | OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE) 125 | add_custom_target(${_target} ALL DEPENDS ${ARGN}) 126 | endfunction(GR_UNIQUE_TARGET) 127 | 128 | ######################################################################## 129 | # Install python sources (also builds and installs byte-compiled python) 130 | ######################################################################## 131 | function(GR_PYTHON_INSTALL) 132 | include(CMakeParseArgumentsCopy) 133 | CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN}) 134 | 135 | #################################################################### 136 | if(GR_PYTHON_INSTALL_FILES) 137 | #################################################################### 138 | install(${ARGN}) #installs regular python files 139 | 140 | #create a list of all generated files 141 | unset(pysrcfiles) 142 | unset(pycfiles) 143 | unset(pyofiles) 144 | foreach(pyfile ${GR_PYTHON_INSTALL_FILES}) 145 | get_filename_component(pyfile ${pyfile} ABSOLUTE) 146 | list(APPEND pysrcfiles ${pyfile}) 147 | 148 | #determine if this file is in the source or binary directory 149 | file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile}) 150 | string(LENGTH "${source_rel_path}" source_rel_path_len) 151 | file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile}) 152 | string(LENGTH "${binary_rel_path}" binary_rel_path_len) 153 | 154 | #and set the generated path appropriately 155 | if(${source_rel_path_len} GREATER ${binary_rel_path_len}) 156 | set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path}) 157 | else() 158 | set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path}) 159 | endif() 160 | list(APPEND pycfiles ${pygenfile}c) 161 | list(APPEND pyofiles ${pygenfile}o) 162 | 163 | #ensure generation path exists 164 | get_filename_component(pygen_path ${pygenfile} PATH) 165 | file(MAKE_DIRECTORY ${pygen_path}) 166 | 167 | endforeach(pyfile) 168 | 169 | #the command to generate the pyc files 170 | add_custom_command( 171 | DEPENDS ${pysrcfiles} OUTPUT ${pycfiles} 172 | COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles} 173 | ) 174 | 175 | #the command to generate the pyo files 176 | add_custom_command( 177 | DEPENDS ${pysrcfiles} OUTPUT ${pyofiles} 178 | COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles} 179 | ) 180 | 181 | #create install rule and add generated files to target list 182 | set(python_install_gen_targets ${pycfiles} ${pyofiles}) 183 | install(FILES ${python_install_gen_targets} 184 | DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} 185 | COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} 186 | ) 187 | 188 | #################################################################### 189 | elseif(GR_PYTHON_INSTALL_PROGRAMS) 190 | #################################################################### 191 | file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native) 192 | 193 | if (CMAKE_CROSSCOMPILING) 194 | set(pyexe_native "/usr/bin/env python") 195 | endif() 196 | 197 | foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS}) 198 | get_filename_component(pyfile_name ${pyfile} NAME) 199 | get_filename_component(pyfile ${pyfile} ABSOLUTE) 200 | string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe") 201 | list(APPEND python_install_gen_targets ${pyexefile}) 202 | 203 | get_filename_component(pyexefile_path ${pyexefile} PATH) 204 | file(MAKE_DIRECTORY ${pyexefile_path}) 205 | 206 | add_custom_command( 207 | OUTPUT ${pyexefile} DEPENDS ${pyfile} 208 | COMMAND ${PYTHON_EXECUTABLE} -c 209 | "import re; R=re.compile('^\#!.*$\\n',flags=re.MULTILINE); open('${pyexefile}','w').write('\#!${pyexe_native}\\n'+R.sub('',open('${pyfile}','r').read()))" 210 | COMMENT "Shebangin ${pyfile_name}" 211 | VERBATIM 212 | ) 213 | 214 | #on windows, python files need an extension to execute 215 | get_filename_component(pyfile_ext ${pyfile} EXT) 216 | if(WIN32 AND NOT pyfile_ext) 217 | set(pyfile_name "${pyfile_name}.py") 218 | endif() 219 | 220 | install(PROGRAMS ${pyexefile} RENAME ${pyfile_name} 221 | DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} 222 | COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} 223 | ) 224 | endforeach(pyfile) 225 | 226 | endif() 227 | 228 | GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets}) 229 | 230 | endfunction(GR_PYTHON_INSTALL) 231 | 232 | ######################################################################## 233 | # Write the python helper script that generates byte code files 234 | ######################################################################## 235 | file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py " 236 | import sys, py_compile 237 | files = sys.argv[1:] 238 | srcs, gens = files[:len(files)/2], files[len(files)/2:] 239 | for src, gen in zip(srcs, gens): 240 | py_compile.compile(file=src, cfile=gen, doraise=True) 241 | ") 242 | -------------------------------------------------------------------------------- /cmake/Modules/GrSwig.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | if(DEFINED __INCLUDED_GR_SWIG_CMAKE) 21 | return() 22 | endif() 23 | set(__INCLUDED_GR_SWIG_CMAKE TRUE) 24 | 25 | include(GrPython) 26 | 27 | ######################################################################## 28 | # Builds a swig documentation file to be generated into python docstrings 29 | # Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....) 30 | # 31 | # Set the following variable to specify extra dependent targets: 32 | # - GR_SWIG_DOCS_SOURCE_DEPS 33 | # - GR_SWIG_DOCS_TARGET_DEPS 34 | ######################################################################## 35 | function(GR_SWIG_MAKE_DOCS output_file) 36 | if(ENABLE_DOXYGEN) 37 | 38 | #setup the input files variable list, quote formated 39 | set(input_files) 40 | unset(INPUT_PATHS) 41 | foreach(input_path ${ARGN}) 42 | if(IS_DIRECTORY ${input_path}) #when input path is a directory 43 | file(GLOB input_path_h_files ${input_path}/*.h) 44 | else() #otherwise its just a file, no glob 45 | set(input_path_h_files ${input_path}) 46 | endif() 47 | list(APPEND input_files ${input_path_h_files}) 48 | set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"") 49 | endforeach(input_path) 50 | 51 | #determine the output directory 52 | get_filename_component(name ${output_file} NAME_WE) 53 | get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH) 54 | set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs) 55 | make_directory(${OUTPUT_DIRECTORY}) 56 | 57 | #generate the Doxyfile used by doxygen 58 | configure_file( 59 | ${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in 60 | ${OUTPUT_DIRECTORY}/Doxyfile 61 | @ONLY) 62 | 63 | #Create a dummy custom command that depends on other targets 64 | include(GrMiscUtils) 65 | GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS}) 66 | 67 | #call doxygen on the Doxyfile + input headers 68 | add_custom_command( 69 | OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml 70 | DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps} 71 | COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile 72 | COMMENT "Generating doxygen xml for ${name} docs" 73 | ) 74 | 75 | #call the swig_doc script on the xml files 76 | add_custom_command( 77 | OUTPUT ${output_file} 78 | DEPENDS ${input_files} ${stamp-file} ${OUTPUT_DIRECTORY}/xml/index.xml 79 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} 80 | ${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py 81 | ${OUTPUT_DIRECTORY}/xml 82 | ${output_file} 83 | COMMENT "Generating python docstrings for ${name}" 84 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen 85 | ) 86 | 87 | else(ENABLE_DOXYGEN) 88 | file(WRITE ${output_file} "\n") #no doxygen -> empty file 89 | endif(ENABLE_DOXYGEN) 90 | endfunction(GR_SWIG_MAKE_DOCS) 91 | 92 | ######################################################################## 93 | # Build a swig target for the common gnuradio use case. Usage: 94 | # GR_SWIG_MAKE(target ifile ifile ifile...) 95 | # 96 | # Set the following variables before calling: 97 | # - GR_SWIG_FLAGS 98 | # - GR_SWIG_INCLUDE_DIRS 99 | # - GR_SWIG_LIBRARIES 100 | # - GR_SWIG_SOURCE_DEPS 101 | # - GR_SWIG_TARGET_DEPS 102 | # - GR_SWIG_DOC_FILE 103 | # - GR_SWIG_DOC_DIRS 104 | ######################################################################## 105 | macro(GR_SWIG_MAKE name) 106 | set(ifiles ${ARGN}) 107 | 108 | # Shimming this in here to take care of a SWIG bug with handling 109 | # vector and vector (on 32-bit machines) and 110 | # vector (on 64-bit machines). Use this to test 111 | # the size of size_t, then set SIZE_T_32 if it's a 32-bit machine 112 | # or not if it's 64-bit. The logic in gr_type.i handles the rest. 113 | INCLUDE(CheckTypeSize) 114 | CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T) 115 | CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT) 116 | if(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT}) 117 | list(APPEND GR_SWIG_FLAGS -DSIZE_T_32) 118 | endif(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT}) 119 | 120 | #do swig doc generation if specified 121 | if(GR_SWIG_DOC_FILE) 122 | set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS}) 123 | list(APPEND GR_SWIG_DOCS_TARGET_DEPS ${GR_SWIG_TARGET_DEPS}) 124 | GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS}) 125 | add_custom_target(${name}_swig_doc DEPENDS ${GR_SWIG_DOC_FILE}) 126 | list(APPEND GR_SWIG_TARGET_DEPS ${name}_swig_doc ${GR_RUNTIME_SWIG_DOC_FILE}) 127 | endif() 128 | 129 | #append additional include directories 130 | find_package(PythonLibs 2) 131 | list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs) 132 | list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS}) 133 | 134 | #prepend local swig directories 135 | list(INSERT GR_SWIG_INCLUDE_DIRS 0 ${CMAKE_CURRENT_SOURCE_DIR}) 136 | list(INSERT GR_SWIG_INCLUDE_DIRS 0 ${CMAKE_CURRENT_BINARY_DIR}) 137 | 138 | #determine include dependencies for swig file 139 | execute_process( 140 | COMMAND ${PYTHON_EXECUTABLE} 141 | ${CMAKE_BINARY_DIR}/get_swig_deps.py 142 | "${ifiles}" "${GR_SWIG_INCLUDE_DIRS}" 143 | OUTPUT_STRIP_TRAILING_WHITESPACE 144 | OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS 145 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 146 | ) 147 | 148 | #Create a dummy custom command that depends on other targets 149 | include(GrMiscUtils) 150 | GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS}) 151 | set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag) 152 | add_custom_command( 153 | OUTPUT ${tag_file} 154 | DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps} 155 | COMMAND ${CMAKE_COMMAND} -E touch ${tag_file} 156 | ) 157 | 158 | #append the specified include directories 159 | include_directories(${GR_SWIG_INCLUDE_DIRS}) 160 | list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file}) 161 | 162 | #setup the swig flags with flags and include directories 163 | set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS}) 164 | foreach(dir ${GR_SWIG_INCLUDE_DIRS}) 165 | list(APPEND CMAKE_SWIG_FLAGS "-I${dir}") 166 | endforeach(dir) 167 | 168 | #set the C++ property on the swig .i file so it builds 169 | set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON) 170 | 171 | #setup the actual swig library target to be built 172 | include(UseSWIG) 173 | SWIG_ADD_MODULE(${name} python ${ifiles}) 174 | SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES}) 175 | if(${name} STREQUAL "runtime_swig") 176 | SET_TARGET_PROPERTIES(${SWIG_MODULE_runtime_swig_REAL_NAME} PROPERTIES DEFINE_SYMBOL "gnuradio_runtime_EXPORTS") 177 | endif(${name} STREQUAL "runtime_swig") 178 | 179 | endmacro(GR_SWIG_MAKE) 180 | 181 | ######################################################################## 182 | # Install swig targets generated by GR_SWIG_MAKE. Usage: 183 | # GR_SWIG_INSTALL( 184 | # TARGETS target target target... 185 | # [DESTINATION destination] 186 | # [COMPONENT component] 187 | # ) 188 | ######################################################################## 189 | macro(GR_SWIG_INSTALL) 190 | 191 | include(CMakeParseArgumentsCopy) 192 | CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN}) 193 | 194 | foreach(name ${GR_SWIG_INSTALL_TARGETS}) 195 | install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME} 196 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION} 197 | COMPONENT ${GR_SWIG_INSTALL_COMPONENT} 198 | ) 199 | 200 | include(GrPython) 201 | GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py 202 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION} 203 | COMPONENT ${GR_SWIG_INSTALL_COMPONENT} 204 | ) 205 | 206 | GR_LIBTOOL( 207 | TARGET ${SWIG_MODULE_${name}_REAL_NAME} 208 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION} 209 | ) 210 | 211 | endforeach(name) 212 | 213 | endmacro(GR_SWIG_INSTALL) 214 | 215 | ######################################################################## 216 | # Generate a python file that can determine swig dependencies. 217 | # Used by the make macro above to determine extra dependencies. 218 | # When you build C++, CMake figures out the header dependencies. 219 | # This code essentially performs that logic for swig includes. 220 | ######################################################################## 221 | file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py " 222 | 223 | import os, sys, re 224 | 225 | i_include_matcher = re.compile('%(include|import)\\s*[<|\"](.*)[>|\"]') 226 | h_include_matcher = re.compile('#(include)\\s*[<|\"](.*)[>|\"]') 227 | include_dirs = sys.argv[2].split(';') 228 | 229 | def get_swig_incs(file_path): 230 | if file_path.endswith('.i'): matcher = i_include_matcher 231 | else: matcher = h_include_matcher 232 | file_contents = open(file_path, 'r').read() 233 | return matcher.findall(file_contents, re.MULTILINE) 234 | 235 | def get_swig_deps(file_path, level): 236 | deps = [file_path] 237 | if level == 0: return deps 238 | for keyword, inc_file in get_swig_incs(file_path): 239 | for inc_dir in include_dirs: 240 | inc_path = os.path.join(inc_dir, inc_file) 241 | if not os.path.exists(inc_path): continue 242 | deps.extend(get_swig_deps(inc_path, level-1)) 243 | break #found, we dont search in lower prio inc dirs 244 | return deps 245 | 246 | if __name__ == '__main__': 247 | ifiles = sys.argv[1].split(';') 248 | deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], []) 249 | #sys.stderr.write(';'.join(set(deps)) + '\\n\\n') 250 | print(';'.join(set(deps))) 251 | ") 252 | -------------------------------------------------------------------------------- /cmake/Modules/GrTest.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | if(DEFINED __INCLUDED_GR_TEST_CMAKE) 21 | return() 22 | endif() 23 | set(__INCLUDED_GR_TEST_CMAKE TRUE) 24 | 25 | ######################################################################## 26 | # Add a unit test and setup the environment for a unit test. 27 | # Takes the same arguments as the ADD_TEST function. 28 | # 29 | # Before calling set the following variables: 30 | # GR_TEST_TARGET_DEPS - built targets for the library path 31 | # GR_TEST_LIBRARY_DIRS - directories for the library path 32 | # GR_TEST_PYTHON_DIRS - directories for the python path 33 | # GR_TEST_ENVIRONS - other environment key/value pairs 34 | ######################################################################## 35 | function(GR_ADD_TEST test_name) 36 | 37 | #Ensure that the build exe also appears in the PATH. 38 | list(APPEND GR_TEST_TARGET_DEPS ${ARGN}) 39 | 40 | #In the land of windows, all libraries must be in the PATH. 41 | #Since the dependent libraries are not yet installed, 42 | #we must manually set them in the PATH to run tests. 43 | #The following appends the path of a target dependency. 44 | foreach(target ${GR_TEST_TARGET_DEPS}) 45 | get_target_property(location ${target} LOCATION) 46 | if(location) 47 | get_filename_component(path ${location} PATH) 48 | string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path}) 49 | list(APPEND GR_TEST_LIBRARY_DIRS ${path}) 50 | endif(location) 51 | endforeach(target) 52 | 53 | if(WIN32) 54 | #SWIG generates the python library files into a subdirectory. 55 | #Therefore, we must append this subdirectory into PYTHONPATH. 56 | #Only do this for the python directories matching the following: 57 | foreach(pydir ${GR_TEST_PYTHON_DIRS}) 58 | get_filename_component(name ${pydir} NAME) 59 | if(name MATCHES "^(swig|lib|src)$") 60 | list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE}) 61 | endif() 62 | endforeach(pydir) 63 | endif(WIN32) 64 | 65 | file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir) 66 | file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list? 67 | file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list? 68 | 69 | set(environs "VOLK_GENERIC=1" "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}") 70 | list(APPEND environs ${GR_TEST_ENVIRONS}) 71 | 72 | #http://www.cmake.org/pipermail/cmake/2009-May/029464.html 73 | #Replaced this add test + set environs code with the shell script generation. 74 | #Its nicer to be able to manually run the shell script to diagnose problems. 75 | #ADD_TEST(${ARGV}) 76 | #SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}") 77 | 78 | if(UNIX) 79 | set(LD_PATH_VAR "LD_LIBRARY_PATH") 80 | if(APPLE) 81 | set(LD_PATH_VAR "DYLD_LIBRARY_PATH") 82 | endif() 83 | 84 | set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH") 85 | list(APPEND libpath "$${LD_PATH_VAR}") 86 | list(APPEND pypath "$PYTHONPATH") 87 | 88 | #replace list separator with the path separator 89 | string(REPLACE ";" ":" libpath "${libpath}") 90 | string(REPLACE ";" ":" pypath "${pypath}") 91 | list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}" "PYTHONPATH=${pypath}") 92 | 93 | #generate a bat file that sets the environment and runs the test 94 | if (CMAKE_CROSSCOMPILING) 95 | set(SHELL "/bin/sh") 96 | else(CMAKE_CROSSCOMPILING) 97 | find_program(SHELL sh) 98 | endif(CMAKE_CROSSCOMPILING) 99 | set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh) 100 | file(WRITE ${sh_file} "#!${SHELL}\n") 101 | #each line sets an environment variable 102 | foreach(environ ${environs}) 103 | file(APPEND ${sh_file} "export ${environ}\n") 104 | endforeach(environ) 105 | #load the command to run with its arguments 106 | foreach(arg ${ARGN}) 107 | file(APPEND ${sh_file} "${arg} ") 108 | endforeach(arg) 109 | file(APPEND ${sh_file} "\n") 110 | 111 | #make the shell file executable 112 | execute_process(COMMAND chmod +x ${sh_file}) 113 | 114 | add_test(${test_name} ${SHELL} ${sh_file}) 115 | 116 | endif(UNIX) 117 | 118 | if(WIN32) 119 | list(APPEND libpath ${DLL_PATHS} "%PATH%") 120 | list(APPEND pypath "%PYTHONPATH%") 121 | 122 | #replace list separator with the path separator (escaped) 123 | string(REPLACE ";" "\\;" libpath "${libpath}") 124 | string(REPLACE ";" "\\;" pypath "${pypath}") 125 | list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}") 126 | 127 | #generate a bat file that sets the environment and runs the test 128 | set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat) 129 | file(WRITE ${bat_file} "@echo off\n") 130 | #each line sets an environment variable 131 | foreach(environ ${environs}) 132 | file(APPEND ${bat_file} "SET ${environ}\n") 133 | endforeach(environ) 134 | #load the command to run with its arguments 135 | foreach(arg ${ARGN}) 136 | file(APPEND ${bat_file} "${arg} ") 137 | endforeach(arg) 138 | file(APPEND ${bat_file} "\n") 139 | 140 | add_test(${test_name} ${bat_file}) 141 | endif(WIN32) 142 | 143 | endfunction(GR_ADD_TEST) 144 | -------------------------------------------------------------------------------- /cmake/Modules/UseSWIG.cmake: -------------------------------------------------------------------------------- 1 | # - SWIG module for CMake 2 | # Defines the following macros: 3 | # SWIG_ADD_MODULE(name language [ files ]) 4 | # - Define swig module with given name and specified language 5 | # SWIG_LINK_LIBRARIES(name [ libraries ]) 6 | # - Link libraries to swig module 7 | # All other macros are for internal use only. 8 | # To get the actual name of the swig module, 9 | # use: ${SWIG_MODULE_${name}_REAL_NAME}. 10 | # Set Source files properties such as CPLUSPLUS and SWIG_FLAGS to specify 11 | # special behavior of SWIG. Also global CMAKE_SWIG_FLAGS can be used to add 12 | # special flags to all swig calls. 13 | # Another special variable is CMAKE_SWIG_OUTDIR, it allows one to specify 14 | # where to write all the swig generated module (swig -outdir option) 15 | # The name-specific variable SWIG_MODULE__EXTRA_DEPS may be used 16 | # to specify extra dependencies for the generated modules. 17 | # If the source file generated by swig need some special flag you can use 18 | # set_source_files_properties( ${swig_generated_file_fullname} 19 | # PROPERTIES COMPILE_FLAGS "-bla") 20 | 21 | 22 | #============================================================================= 23 | # Copyright 2004-2009 Kitware, Inc. 24 | # Copyright 2009 Mathieu Malaterre 25 | # 26 | # Distributed under the OSI-approved BSD License (the "License"); 27 | # see accompanying file Copyright.txt for details. 28 | # 29 | # This software is distributed WITHOUT ANY WARRANTY; without even the 30 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 31 | # See the License for more information. 32 | #============================================================================= 33 | # (To distribute this file outside of CMake, substitute the full 34 | # License text for the above reference.) 35 | 36 | set(SWIG_CXX_EXTENSION "cxx") 37 | set(SWIG_EXTRA_LIBRARIES "") 38 | 39 | set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py") 40 | 41 | # 42 | # For given swig module initialize variables associated with it 43 | # 44 | macro(SWIG_MODULE_INITIALIZE name language) 45 | string(TOUPPER "${language}" swig_uppercase_language) 46 | string(TOLOWER "${language}" swig_lowercase_language) 47 | set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}") 48 | set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}") 49 | 50 | set(SWIG_MODULE_${name}_REAL_NAME "${name}") 51 | if("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "UNKNOWN") 52 | message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found") 53 | elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PYTHON") 54 | # when swig is used without the -interface it will produce in the module.py 55 | # a 'import _modulename' statement, which implies having a corresponding 56 | # _modulename.so (*NIX), _modulename.pyd (Win32). 57 | set(SWIG_MODULE_${name}_REAL_NAME "_${name}") 58 | elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PERL") 59 | set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow") 60 | endif() 61 | endmacro() 62 | 63 | # 64 | # For a given language, input file, and output file, determine extra files that 65 | # will be generated. This is internal swig macro. 66 | # 67 | 68 | macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile) 69 | set(${outfiles} "") 70 | get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename 71 | ${infile} SWIG_MODULE_NAME) 72 | if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND") 73 | get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE) 74 | endif() 75 | foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION}) 76 | set(${outfiles} ${${outfiles}} 77 | "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}") 78 | endforeach() 79 | endmacro() 80 | 81 | # 82 | # Take swig (*.i) file and add proper custom commands for it 83 | # 84 | macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile) 85 | set(swig_full_infile ${infile}) 86 | get_filename_component(swig_source_file_path "${infile}" PATH) 87 | get_filename_component(swig_source_file_name_we "${infile}" NAME_WE) 88 | get_source_file_property(swig_source_file_generated ${infile} GENERATED) 89 | get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS) 90 | get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS) 91 | if("${swig_source_file_flags}" STREQUAL "NOTFOUND") 92 | set(swig_source_file_flags "") 93 | endif() 94 | set(swig_source_file_fullname "${infile}") 95 | if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_SOURCE_DIR}") 96 | string(REGEX REPLACE 97 | "^${CMAKE_CURRENT_SOURCE_DIR}" "" 98 | swig_source_file_relative_path 99 | "${swig_source_file_path}") 100 | else() 101 | if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_BINARY_DIR}") 102 | string(REGEX REPLACE 103 | "^${CMAKE_CURRENT_BINARY_DIR}" "" 104 | swig_source_file_relative_path 105 | "${swig_source_file_path}") 106 | set(swig_source_file_generated 1) 107 | else() 108 | set(swig_source_file_relative_path "${swig_source_file_path}") 109 | if(swig_source_file_generated) 110 | set(swig_source_file_fullname "${CMAKE_CURRENT_BINARY_DIR}/${infile}") 111 | else() 112 | set(swig_source_file_fullname "${CMAKE_CURRENT_SOURCE_DIR}/${infile}") 113 | endif() 114 | endif() 115 | endif() 116 | 117 | set(swig_generated_file_fullname 118 | "${CMAKE_CURRENT_BINARY_DIR}") 119 | if(swig_source_file_relative_path) 120 | set(swig_generated_file_fullname 121 | "${swig_generated_file_fullname}/${swig_source_file_relative_path}") 122 | endif() 123 | # If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir 124 | if(CMAKE_SWIG_OUTDIR) 125 | set(swig_outdir ${CMAKE_SWIG_OUTDIR}) 126 | else() 127 | set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR}) 128 | endif() 129 | SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE} 130 | swig_extra_generated_files 131 | "${swig_outdir}" 132 | "${infile}") 133 | set(swig_generated_file_fullname 134 | "${swig_generated_file_fullname}/${swig_source_file_name_we}") 135 | # add the language into the name of the file (i.e. TCL_wrap) 136 | # this allows for the same .i file to be wrapped into different languages 137 | set(swig_generated_file_fullname 138 | "${swig_generated_file_fullname}${SWIG_MODULE_${name}_LANGUAGE}_wrap") 139 | 140 | if(swig_source_file_cplusplus) 141 | set(swig_generated_file_fullname 142 | "${swig_generated_file_fullname}.${SWIG_CXX_EXTENSION}") 143 | else() 144 | set(swig_generated_file_fullname 145 | "${swig_generated_file_fullname}.c") 146 | endif() 147 | 148 | # Shut up some warnings from poor SWIG code generation that we 149 | # can do nothing about, when this flag is available 150 | include(CheckCXXCompilerFlag) 151 | check_cxx_compiler_flag("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) 152 | if(HAVE_WNO_UNUSED_BUT_SET_VARIABLE) 153 | set_source_files_properties(${swig_generated_file_fullname} 154 | PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable") 155 | endif(HAVE_WNO_UNUSED_BUT_SET_VARIABLE) 156 | 157 | get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES) 158 | set(swig_include_dirs) 159 | foreach(it ${cmake_include_directories}) 160 | set(swig_include_dirs ${swig_include_dirs} "-I${it}") 161 | endforeach() 162 | 163 | set(swig_special_flags) 164 | # default is c, so add c++ flag if it is c++ 165 | if(swig_source_file_cplusplus) 166 | set(swig_special_flags ${swig_special_flags} "-c++") 167 | endif() 168 | set(swig_extra_flags) 169 | if(SWIG_MODULE_${name}_EXTRA_FLAGS) 170 | set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS}) 171 | endif() 172 | 173 | # hack to work around CMake bug in add_custom_command with multiple OUTPUT files 174 | 175 | file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 176 | execute_process( 177 | COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib 178 | unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5] 179 | print(re.sub('\\W', '_', '${name} ${reldir} ' + unique))" 180 | OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE 181 | ) 182 | 183 | file( 184 | WRITE ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in 185 | "int main(void){return 0;}\n" 186 | ) 187 | 188 | # create dummy dependencies 189 | add_custom_command( 190 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp 191 | COMMAND ${CMAKE_COMMAND} -E copy 192 | ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in 193 | ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp 194 | DEPENDS "${swig_source_file_fullname}" ${SWIG_MODULE_${name}_EXTRA_DEPS} 195 | COMMENT "" 196 | ) 197 | 198 | # create the dummy target 199 | add_executable(${_target} ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp) 200 | 201 | # add a custom command to the dummy target 202 | add_custom_command( 203 | TARGET ${_target} 204 | # Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir) 205 | COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir} 206 | COMMAND "${SWIG_EXECUTABLE}" 207 | ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}" 208 | ${swig_source_file_flags} 209 | ${CMAKE_SWIG_FLAGS} 210 | -outdir ${swig_outdir} 211 | ${swig_special_flags} 212 | ${swig_extra_flags} 213 | ${swig_include_dirs} 214 | -o "${swig_generated_file_fullname}" 215 | "${swig_source_file_fullname}" 216 | COMMENT "Swig source" 217 | ) 218 | 219 | #add dummy independent dependencies from the _target to each file 220 | #that will be generated by the SWIG command above 221 | 222 | set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files}) 223 | 224 | foreach(swig_gen_file ${${outfiles}}) 225 | add_custom_command( 226 | OUTPUT ${swig_gen_file} 227 | COMMAND "" 228 | DEPENDS ${_target} 229 | COMMENT "" 230 | ) 231 | endforeach() 232 | 233 | set_source_files_properties( 234 | ${outfiles} PROPERTIES GENERATED 1 235 | ) 236 | 237 | endmacro() 238 | 239 | # 240 | # Create Swig module 241 | # 242 | macro(SWIG_ADD_MODULE name language) 243 | SWIG_MODULE_INITIALIZE(${name} ${language}) 244 | set(swig_dot_i_sources) 245 | set(swig_other_sources) 246 | foreach(it ${ARGN}) 247 | if(${it} MATCHES ".*\\.i$") 248 | set(swig_dot_i_sources ${swig_dot_i_sources} "${it}") 249 | else() 250 | set(swig_other_sources ${swig_other_sources} "${it}") 251 | endif() 252 | endforeach() 253 | 254 | set(swig_generated_sources) 255 | foreach(it ${swig_dot_i_sources}) 256 | SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it}) 257 | set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}") 258 | endforeach() 259 | get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES) 260 | set_directory_properties(PROPERTIES 261 | ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}") 262 | add_library(${SWIG_MODULE_${name}_REAL_NAME} 263 | MODULE 264 | ${swig_generated_sources} 265 | ${swig_other_sources}) 266 | string(TOLOWER "${language}" swig_lowercase_language) 267 | if ("${swig_lowercase_language}" STREQUAL "java") 268 | if (APPLE) 269 | # In java you want: 270 | # System.loadLibrary("LIBRARY"); 271 | # then JNI will look for a library whose name is platform dependent, namely 272 | # MacOS : libLIBRARY.jnilib 273 | # Windows: LIBRARY.dll 274 | # Linux : libLIBRARY.so 275 | set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib") 276 | endif () 277 | endif () 278 | if ("${swig_lowercase_language}" STREQUAL "python") 279 | # this is only needed for the python case where a _modulename.so is generated 280 | set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") 281 | # Python extension modules on Windows must have the extension ".pyd" 282 | # instead of ".dll" as of Python 2.5. Older python versions do support 283 | # this suffix. 284 | # http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000 285 | # 286 | # Windows: .dll is no longer supported as a filename extension for extension modules. 287 | # .pyd is now the only filename extension that will be searched for. 288 | # 289 | if(WIN32 AND NOT CYGWIN) 290 | set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd") 291 | endif() 292 | endif () 293 | endmacro() 294 | 295 | # 296 | # Like TARGET_LINK_LIBRARIES but for swig modules 297 | # 298 | macro(SWIG_LINK_LIBRARIES name) 299 | if(SWIG_MODULE_${name}_REAL_NAME) 300 | target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN}) 301 | else() 302 | message(SEND_ERROR "Cannot find Swig library \"${name}\".") 303 | endif() 304 | endmacro() 305 | -------------------------------------------------------------------------------- /cmake/Modules/cbmcConfig.cmake: -------------------------------------------------------------------------------- 1 | INCLUDE(FindPkgConfig) 2 | PKG_CHECK_MODULES(PC_CBMC cbmc) 3 | 4 | FIND_PATH( 5 | CBMC_INCLUDE_DIRS 6 | NAMES cbmc/api.h 7 | HINTS $ENV{CBMC_DIR}/include 8 | ${PC_CBMC_INCLUDEDIR} 9 | PATHS ${CMAKE_INSTALL_PREFIX}/include 10 | /usr/local/include 11 | /usr/include 12 | ) 13 | 14 | FIND_LIBRARY( 15 | CBMC_LIBRARIES 16 | NAMES gnuradio-cbmc 17 | HINTS $ENV{CBMC_DIR}/lib 18 | ${PC_CBMC_LIBDIR} 19 | PATHS ${CMAKE_INSTALL_PREFIX}/lib 20 | ${CMAKE_INSTALL_PREFIX}/lib64 21 | /usr/local/lib 22 | /usr/local/lib64 23 | /usr/lib 24 | /usr/lib64 25 | ) 26 | 27 | INCLUDE(FindPackageHandleStandardArgs) 28 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(CBMC DEFAULT_MSG CBMC_LIBRARIES CBMC_INCLUDE_DIRS) 29 | MARK_AS_ADVANCED(CBMC_LIBRARIES CBMC_INCLUDE_DIRS) 30 | 31 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 2 | 3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | STRING(REGEX REPLACE "\n" ";" files "${files}") 9 | FOREACH(file ${files}) 10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 11 | IF(EXISTS "$ENV{DESTDIR}${file}") 12 | EXEC_PROGRAM( 13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 14 | OUTPUT_VARIABLE rm_out 15 | RETURN_VALUE rm_retval 16 | ) 17 | IF(NOT "${rm_retval}" STREQUAL 0) 18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 19 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | EXEC_PROGRAM( 22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval 25 | ) 26 | IF(NOT "${rm_retval}" STREQUAL 0) 27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 28 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 29 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 32 | ENDFOREACH(file) 33 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Setup dependencies 22 | ######################################################################## 23 | find_package(Doxygen) 24 | 25 | ######################################################################## 26 | # Begin conditional configuration 27 | ######################################################################## 28 | if(ENABLE_DOXYGEN) 29 | 30 | ######################################################################## 31 | # Add subdirectories 32 | ######################################################################## 33 | add_subdirectory(doxygen) 34 | 35 | endif(ENABLE_DOXYGEN) 36 | -------------------------------------------------------------------------------- /docs/README.cbmc: -------------------------------------------------------------------------------- 1 | This is the cbmc-write-a-block package meant as a guide to building 2 | out-of-tree packages. To use the cbmc blocks, the Python namespaces 3 | is in 'cbmc', which is imported as: 4 | 5 | import cbmc 6 | 7 | See the Doxygen documentation for details about the blocks available 8 | in this package. A quick listing of the details can be found in Python 9 | after importing by using: 10 | 11 | help(cbmc) 12 | -------------------------------------------------------------------------------- /docs/doxygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Create the doxygen configuration file 22 | ######################################################################## 23 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) 24 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) 25 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir) 26 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir) 27 | 28 | set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) 29 | set(enable_html_docs YES) 30 | set(enable_latex_docs NO) 31 | set(enable_xml_docs YES) 32 | 33 | configure_file( 34 | ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 35 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 36 | @ONLY) 37 | 38 | set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html) 39 | 40 | ######################################################################## 41 | # Make and install doxygen docs 42 | ######################################################################## 43 | add_custom_command( 44 | OUTPUT ${BUILT_DIRS} 45 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 46 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 47 | COMMENT "Generating documentation with doxygen" 48 | ) 49 | 50 | add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS}) 51 | 52 | install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR}) 53 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | """ 22 | Python interface to contents of doxygen xml documentation. 23 | 24 | Example use: 25 | See the contents of the example folder for the C++ and 26 | doxygen-generated xml used in this example. 27 | 28 | >>> # Parse the doxygen docs. 29 | >>> import os 30 | >>> this_dir = os.path.dirname(globals()['__file__']) 31 | >>> xml_path = this_dir + "/example/xml/" 32 | >>> di = DoxyIndex(xml_path) 33 | 34 | Get a list of all top-level objects. 35 | 36 | >>> print([mem.name() for mem in di.members()]) 37 | [u'Aadvark', u'aadvarky_enough', u'main'] 38 | 39 | Get all functions. 40 | 41 | >>> print([mem.name() for mem in di.in_category(DoxyFunction)]) 42 | [u'aadvarky_enough', u'main'] 43 | 44 | Check if an object is present. 45 | 46 | >>> di.has_member(u'Aadvark') 47 | True 48 | >>> di.has_member(u'Fish') 49 | False 50 | 51 | Get an item by name and check its properties. 52 | 53 | >>> aad = di.get_member(u'Aadvark') 54 | >>> print(aad.brief_description) 55 | Models the mammal Aadvark. 56 | >>> print(aad.detailed_description) 57 | Sadly the model is incomplete and cannot capture all aspects of an aadvark yet. 58 | 59 | This line is uninformative and is only to test line breaks in the comments. 60 | >>> [mem.name() for mem in aad.members()] 61 | [u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness'] 62 | >>> aad.get_member(u'print').brief_description 63 | u'Outputs the vital aadvark statistics.' 64 | 65 | """ 66 | 67 | from doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther 68 | 69 | def _test(): 70 | import os 71 | this_dir = os.path.dirname(globals()['__file__']) 72 | xml_path = this_dir + "/example/xml/" 73 | di = DoxyIndex(xml_path) 74 | # Get the Aadvark class 75 | aad = di.get_member('Aadvark') 76 | aad.brief_description 77 | import doctest 78 | return doctest.testmod() 79 | 80 | if __name__ == "__main__": 81 | _test() 82 | 83 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/__init__.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/base.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | """ 22 | A base class is created. 23 | 24 | Classes based upon this are used to make more user-friendly interfaces 25 | to the doxygen xml docs than the generated classes provide. 26 | """ 27 | 28 | import os 29 | import pdb 30 | 31 | from xml.parsers.expat import ExpatError 32 | 33 | from generated import compound 34 | 35 | 36 | class Base(object): 37 | 38 | class Duplicate(StandardError): 39 | pass 40 | 41 | class NoSuchMember(StandardError): 42 | pass 43 | 44 | class ParsingError(StandardError): 45 | pass 46 | 47 | def __init__(self, parse_data, top=None): 48 | self._parsed = False 49 | self._error = False 50 | self._parse_data = parse_data 51 | self._members = [] 52 | self._dict_members = {} 53 | self._in_category = {} 54 | self._data = {} 55 | if top is not None: 56 | self._xml_path = top._xml_path 57 | # Set up holder of references 58 | else: 59 | top = self 60 | self._refs = {} 61 | self._xml_path = parse_data 62 | self.top = top 63 | 64 | @classmethod 65 | def from_refid(cls, refid, top=None): 66 | """ Instantiate class from a refid rather than parsing object. """ 67 | # First check to see if its already been instantiated. 68 | if top is not None and refid in top._refs: 69 | return top._refs[refid] 70 | # Otherwise create a new instance and set refid. 71 | inst = cls(None, top=top) 72 | inst.refid = refid 73 | inst.add_ref(inst) 74 | return inst 75 | 76 | @classmethod 77 | def from_parse_data(cls, parse_data, top=None): 78 | refid = getattr(parse_data, 'refid', None) 79 | if refid is not None and top is not None and refid in top._refs: 80 | return top._refs[refid] 81 | inst = cls(parse_data, top=top) 82 | if refid is not None: 83 | inst.refid = refid 84 | inst.add_ref(inst) 85 | return inst 86 | 87 | def add_ref(self, obj): 88 | if hasattr(obj, 'refid'): 89 | self.top._refs[obj.refid] = obj 90 | 91 | mem_classes = [] 92 | 93 | def get_cls(self, mem): 94 | for cls in self.mem_classes: 95 | if cls.can_parse(mem): 96 | return cls 97 | raise StandardError(("Did not find a class for object '%s'." \ 98 | % (mem.get_name()))) 99 | 100 | def convert_mem(self, mem): 101 | try: 102 | cls = self.get_cls(mem) 103 | converted = cls.from_parse_data(mem, self.top) 104 | if converted is None: 105 | raise StandardError('No class matched this object.') 106 | self.add_ref(converted) 107 | return converted 108 | except StandardError, e: 109 | print e 110 | 111 | @classmethod 112 | def includes(cls, inst): 113 | return isinstance(inst, cls) 114 | 115 | @classmethod 116 | def can_parse(cls, obj): 117 | return False 118 | 119 | def _parse(self): 120 | self._parsed = True 121 | 122 | def _get_dict_members(self, cat=None): 123 | """ 124 | For given category a dictionary is returned mapping member names to 125 | members of that category. For names that are duplicated the name is 126 | mapped to None. 127 | """ 128 | self.confirm_no_error() 129 | if cat not in self._dict_members: 130 | new_dict = {} 131 | for mem in self.in_category(cat): 132 | if mem.name() not in new_dict: 133 | new_dict[mem.name()] = mem 134 | else: 135 | new_dict[mem.name()] = self.Duplicate 136 | self._dict_members[cat] = new_dict 137 | return self._dict_members[cat] 138 | 139 | def in_category(self, cat): 140 | self.confirm_no_error() 141 | if cat is None: 142 | return self._members 143 | if cat not in self._in_category: 144 | self._in_category[cat] = [mem for mem in self._members 145 | if cat.includes(mem)] 146 | return self._in_category[cat] 147 | 148 | def get_member(self, name, cat=None): 149 | self.confirm_no_error() 150 | # Check if it's in a namespace or class. 151 | bits = name.split('::') 152 | first = bits[0] 153 | rest = '::'.join(bits[1:]) 154 | member = self._get_dict_members(cat).get(first, self.NoSuchMember) 155 | # Raise any errors that are returned. 156 | if member in set([self.NoSuchMember, self.Duplicate]): 157 | raise member() 158 | if rest: 159 | return member.get_member(rest, cat=cat) 160 | return member 161 | 162 | def has_member(self, name, cat=None): 163 | try: 164 | mem = self.get_member(name, cat=cat) 165 | return True 166 | except self.NoSuchMember: 167 | return False 168 | 169 | def data(self): 170 | self.confirm_no_error() 171 | return self._data 172 | 173 | def members(self): 174 | self.confirm_no_error() 175 | return self._members 176 | 177 | def process_memberdefs(self): 178 | mdtss = [] 179 | for sec in self._retrieved_data.compounddef.sectiondef: 180 | mdtss += sec.memberdef 181 | # At the moment we lose all information associated with sections. 182 | # Sometimes a memberdef is in several sectiondef. 183 | # We make sure we don't get duplicates here. 184 | uniques = set([]) 185 | for mem in mdtss: 186 | converted = self.convert_mem(mem) 187 | pair = (mem.name, mem.__class__) 188 | if pair not in uniques: 189 | uniques.add(pair) 190 | self._members.append(converted) 191 | 192 | def retrieve_data(self): 193 | filename = os.path.join(self._xml_path, self.refid + '.xml') 194 | try: 195 | self._retrieved_data = compound.parse(filename) 196 | except ExpatError: 197 | print('Error in xml in file %s' % filename) 198 | self._error = True 199 | self._retrieved_data = None 200 | 201 | def check_parsed(self): 202 | if not self._parsed: 203 | self._parse() 204 | 205 | def confirm_no_error(self): 206 | self.check_parsed() 207 | if self._error: 208 | raise self.ParsingError() 209 | 210 | def error(self): 211 | self.check_parsed() 212 | return self._error 213 | 214 | def name(self): 215 | # first see if we can do it without processing. 216 | if self._parse_data is not None: 217 | return self._parse_data.name 218 | self.check_parsed() 219 | return self._retrieved_data.compounddef.name 220 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/base.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/base.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/doxyindex.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | """ 22 | Classes providing more user-friendly interfaces to the doxygen xml 23 | docs than the generated classes provide. 24 | """ 25 | 26 | import os 27 | 28 | from generated import index 29 | from base import Base 30 | from text import description 31 | 32 | class DoxyIndex(Base): 33 | """ 34 | Parses a doxygen xml directory. 35 | """ 36 | 37 | __module__ = "gnuradio.utils.doxyxml" 38 | 39 | def _parse(self): 40 | if self._parsed: 41 | return 42 | super(DoxyIndex, self)._parse() 43 | self._root = index.parse(os.path.join(self._xml_path, 'index.xml')) 44 | for mem in self._root.compound: 45 | converted = self.convert_mem(mem) 46 | # For files we want the contents to be accessible directly 47 | # from the parent rather than having to go through the file 48 | # object. 49 | if self.get_cls(mem) == DoxyFile: 50 | if mem.name.endswith('.h'): 51 | self._members += converted.members() 52 | self._members.append(converted) 53 | else: 54 | self._members.append(converted) 55 | 56 | 57 | def generate_swig_doc_i(self): 58 | """ 59 | %feature("docstring") gr_make_align_on_samplenumbers_ss::align_state " 60 | Wraps the C++: gr_align_on_samplenumbers_ss::align_state"; 61 | """ 62 | pass 63 | 64 | 65 | class DoxyCompMem(Base): 66 | 67 | 68 | kind = None 69 | 70 | def __init__(self, *args, **kwargs): 71 | super(DoxyCompMem, self).__init__(*args, **kwargs) 72 | 73 | @classmethod 74 | def can_parse(cls, obj): 75 | return obj.kind == cls.kind 76 | 77 | def set_descriptions(self, parse_data): 78 | bd = description(getattr(parse_data, 'briefdescription', None)) 79 | dd = description(getattr(parse_data, 'detaileddescription', None)) 80 | self._data['brief_description'] = bd 81 | self._data['detailed_description'] = dd 82 | 83 | class DoxyCompound(DoxyCompMem): 84 | pass 85 | 86 | class DoxyMember(DoxyCompMem): 87 | pass 88 | 89 | 90 | class DoxyFunction(DoxyMember): 91 | 92 | __module__ = "gnuradio.utils.doxyxml" 93 | 94 | kind = 'function' 95 | 96 | def _parse(self): 97 | if self._parsed: 98 | return 99 | super(DoxyFunction, self)._parse() 100 | self.set_descriptions(self._parse_data) 101 | self._data['params'] = [] 102 | prms = self._parse_data.param 103 | for prm in prms: 104 | self._data['params'].append(DoxyParam(prm)) 105 | 106 | brief_description = property(lambda self: self.data()['brief_description']) 107 | detailed_description = property(lambda self: self.data()['detailed_description']) 108 | params = property(lambda self: self.data()['params']) 109 | 110 | Base.mem_classes.append(DoxyFunction) 111 | 112 | 113 | class DoxyParam(DoxyMember): 114 | 115 | __module__ = "gnuradio.utils.doxyxml" 116 | 117 | def _parse(self): 118 | if self._parsed: 119 | return 120 | super(DoxyParam, self)._parse() 121 | self.set_descriptions(self._parse_data) 122 | self._data['declname'] = self._parse_data.declname 123 | 124 | brief_description = property(lambda self: self.data()['brief_description']) 125 | detailed_description = property(lambda self: self.data()['detailed_description']) 126 | declname = property(lambda self: self.data()['declname']) 127 | 128 | class DoxyClass(DoxyCompound): 129 | 130 | __module__ = "gnuradio.utils.doxyxml" 131 | 132 | kind = 'class' 133 | 134 | def _parse(self): 135 | if self._parsed: 136 | return 137 | super(DoxyClass, self)._parse() 138 | self.retrieve_data() 139 | if self._error: 140 | return 141 | self.set_descriptions(self._retrieved_data.compounddef) 142 | # Sectiondef.kind tells about whether private or public. 143 | # We just ignore this for now. 144 | self.process_memberdefs() 145 | 146 | brief_description = property(lambda self: self.data()['brief_description']) 147 | detailed_description = property(lambda self: self.data()['detailed_description']) 148 | 149 | Base.mem_classes.append(DoxyClass) 150 | 151 | 152 | class DoxyFile(DoxyCompound): 153 | 154 | __module__ = "gnuradio.utils.doxyxml" 155 | 156 | kind = 'file' 157 | 158 | def _parse(self): 159 | if self._parsed: 160 | return 161 | super(DoxyFile, self)._parse() 162 | self.retrieve_data() 163 | self.set_descriptions(self._retrieved_data.compounddef) 164 | if self._error: 165 | return 166 | self.process_memberdefs() 167 | 168 | brief_description = property(lambda self: self.data()['brief_description']) 169 | detailed_description = property(lambda self: self.data()['detailed_description']) 170 | 171 | Base.mem_classes.append(DoxyFile) 172 | 173 | 174 | class DoxyNamespace(DoxyCompound): 175 | 176 | __module__ = "gnuradio.utils.doxyxml" 177 | 178 | kind = 'namespace' 179 | 180 | Base.mem_classes.append(DoxyNamespace) 181 | 182 | 183 | class DoxyGroup(DoxyCompound): 184 | 185 | __module__ = "gnuradio.utils.doxyxml" 186 | 187 | kind = 'group' 188 | 189 | def _parse(self): 190 | if self._parsed: 191 | return 192 | super(DoxyGroup, self)._parse() 193 | self.retrieve_data() 194 | if self._error: 195 | return 196 | cdef = self._retrieved_data.compounddef 197 | self._data['title'] = description(cdef.title) 198 | # Process inner groups 199 | grps = cdef.innergroup 200 | for grp in grps: 201 | converted = DoxyGroup.from_refid(grp.refid, top=self.top) 202 | self._members.append(converted) 203 | # Process inner classes 204 | klasses = cdef.innerclass 205 | for kls in klasses: 206 | converted = DoxyClass.from_refid(kls.refid, top=self.top) 207 | self._members.append(converted) 208 | # Process normal members 209 | self.process_memberdefs() 210 | 211 | title = property(lambda self: self.data()['title']) 212 | 213 | 214 | Base.mem_classes.append(DoxyGroup) 215 | 216 | 217 | class DoxyFriend(DoxyMember): 218 | 219 | __module__ = "gnuradio.utils.doxyxml" 220 | 221 | kind = 'friend' 222 | 223 | Base.mem_classes.append(DoxyFriend) 224 | 225 | 226 | class DoxyOther(Base): 227 | 228 | __module__ = "gnuradio.utils.doxyxml" 229 | 230 | kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 'dir', 'page']) 231 | 232 | @classmethod 233 | def can_parse(cls, obj): 234 | return obj.kind in cls.kinds 235 | 236 | Base.mem_classes.append(DoxyOther) 237 | 238 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/doxyindex.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/doxyindex.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains generated files produced by generateDS.py. 3 | 4 | These do the real work of parsing the doxygen xml files but the 5 | resultant classes are not very friendly to navigate so the rest of the 6 | doxyxml module processes them further. 7 | """ 8 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/generated/__init__.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/compound.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/generated/compound.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/compoundsuper.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/generated/compoundsuper.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generated Mon Feb 9 19:08:05 2009 by generateDS.py. 5 | """ 6 | 7 | from xml.dom import minidom 8 | 9 | import os 10 | import sys 11 | import compound 12 | 13 | import indexsuper as supermod 14 | 15 | class DoxygenTypeSub(supermod.DoxygenType): 16 | def __init__(self, version=None, compound=None): 17 | supermod.DoxygenType.__init__(self, version, compound) 18 | 19 | def find_compounds_and_members(self, details): 20 | """ 21 | Returns a list of all compounds and their members which match details 22 | """ 23 | 24 | results = [] 25 | for compound in self.compound: 26 | members = compound.find_members(details) 27 | if members: 28 | results.append([compound, members]) 29 | else: 30 | if details.match(compound): 31 | results.append([compound, []]) 32 | 33 | return results 34 | 35 | supermod.DoxygenType.subclass = DoxygenTypeSub 36 | # end class DoxygenTypeSub 37 | 38 | 39 | class CompoundTypeSub(supermod.CompoundType): 40 | def __init__(self, kind=None, refid=None, name='', member=None): 41 | supermod.CompoundType.__init__(self, kind, refid, name, member) 42 | 43 | def find_members(self, details): 44 | """ 45 | Returns a list of all members which match details 46 | """ 47 | 48 | results = [] 49 | 50 | for member in self.member: 51 | if details.match(member): 52 | results.append(member) 53 | 54 | return results 55 | 56 | supermod.CompoundType.subclass = CompoundTypeSub 57 | # end class CompoundTypeSub 58 | 59 | 60 | class MemberTypeSub(supermod.MemberType): 61 | 62 | def __init__(self, kind=None, refid=None, name=''): 63 | supermod.MemberType.__init__(self, kind, refid, name) 64 | 65 | supermod.MemberType.subclass = MemberTypeSub 66 | # end class MemberTypeSub 67 | 68 | 69 | def parse(inFilename): 70 | 71 | doc = minidom.parse(inFilename) 72 | rootNode = doc.documentElement 73 | rootObj = supermod.DoxygenType.factory() 74 | rootObj.build(rootNode) 75 | 76 | return rootObj 77 | 78 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/index.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/generated/index.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/indexsuper.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/generated/indexsuper.pyc -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/text.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | """ 22 | Utilities for extracting text from generated classes. 23 | """ 24 | 25 | def is_string(txt): 26 | if isinstance(txt, str): 27 | return True 28 | try: 29 | if isinstance(txt, unicode): 30 | return True 31 | except NameError: 32 | pass 33 | return False 34 | 35 | def description(obj): 36 | if obj is None: 37 | return None 38 | return description_bit(obj).strip() 39 | 40 | def description_bit(obj): 41 | if hasattr(obj, 'content'): 42 | contents = [description_bit(item) for item in obj.content] 43 | result = ''.join(contents) 44 | elif hasattr(obj, 'content_'): 45 | contents = [description_bit(item) for item in obj.content_] 46 | result = ''.join(contents) 47 | elif hasattr(obj, 'value'): 48 | result = description_bit(obj.value) 49 | elif is_string(obj): 50 | return obj 51 | else: 52 | raise StandardError('Expecting a string or something with content, content_ or value attribute') 53 | # If this bit is a paragraph then add one some line breaks. 54 | if hasattr(obj, 'name') and obj.name == 'para': 55 | result += "\n\n" 56 | return result 57 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/text.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/doxyxml/text.pyc -------------------------------------------------------------------------------- /docs/doxygen/other/group_defs.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | * \defgroup block GNU Radio CBMC C++ Signal Processing Blocks 3 | * \brief All C++ blocks that can be used from the CBMC GNU Radio 4 | * module are listed here or in the subcategories below. 5 | * 6 | */ 7 | 8 | -------------------------------------------------------------------------------- /docs/doxygen/other/main_page.dox: -------------------------------------------------------------------------------- 1 | /*! \mainpage 2 | 3 | Welcome to the GNU Radio CBMC Block 4 | 5 | This is the intro page for the Doxygen manual generated for the CBMC 6 | block (docs/doxygen/other/main_page.dox). Edit it to add more detailed 7 | documentation about the new GNU Radio modules contained in this 8 | project. 9 | 10 | */ 11 | -------------------------------------------------------------------------------- /docs/doxygen/swig_doc.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010,2011 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | """ 22 | Creates the swig_doc.i SWIG interface file. 23 | Execute using: python swig_doc.py xml_path outputfilename 24 | 25 | The file instructs SWIG to transfer the doxygen comments into the 26 | python docstrings. 27 | 28 | """ 29 | 30 | import sys 31 | 32 | try: 33 | from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base 34 | except ImportError: 35 | from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base 36 | 37 | 38 | def py_name(name): 39 | bits = name.split('_') 40 | return '_'.join(bits[1:]) 41 | 42 | def make_name(name): 43 | bits = name.split('_') 44 | return bits[0] + '_make_' + '_'.join(bits[1:]) 45 | 46 | 47 | class Block(object): 48 | """ 49 | Checks if doxyxml produced objects correspond to a gnuradio block. 50 | """ 51 | 52 | @classmethod 53 | def includes(cls, item): 54 | if not isinstance(item, DoxyClass): 55 | return False 56 | # Check for a parsing error. 57 | if item.error(): 58 | return False 59 | return item.has_member(make_name(item.name()), DoxyFriend) 60 | 61 | 62 | def utoascii(text): 63 | """ 64 | Convert unicode text into ascii and escape quotes. 65 | """ 66 | if text is None: 67 | return '' 68 | out = text.encode('ascii', 'replace') 69 | out = out.replace('"', '\\"') 70 | return out 71 | 72 | 73 | def combine_descriptions(obj): 74 | """ 75 | Combines the brief and detailed descriptions of an object together. 76 | """ 77 | description = [] 78 | bd = obj.brief_description.strip() 79 | dd = obj.detailed_description.strip() 80 | if bd: 81 | description.append(bd) 82 | if dd: 83 | description.append(dd) 84 | return utoascii('\n\n'.join(description)).strip() 85 | 86 | 87 | entry_templ = '%feature("docstring") {name} "{docstring}"' 88 | def make_entry(obj, name=None, templ="{description}", description=None): 89 | """ 90 | Create a docstring entry for a swig interface file. 91 | 92 | obj - a doxyxml object from which documentation will be extracted. 93 | name - the name of the C object (defaults to obj.name()) 94 | templ - an optional template for the docstring containing only one 95 | variable named 'description'. 96 | description - if this optional variable is set then it's value is 97 | used as the description instead of extracting it from obj. 98 | """ 99 | if name is None: 100 | name=obj.name() 101 | if "operator " in name: 102 | return '' 103 | if description is None: 104 | description = combine_descriptions(obj) 105 | docstring = templ.format(description=description) 106 | if not docstring: 107 | return '' 108 | return entry_templ.format( 109 | name=name, 110 | docstring=docstring, 111 | ) 112 | 113 | 114 | def make_func_entry(func, name=None, description=None, params=None): 115 | """ 116 | Create a function docstring entry for a swig interface file. 117 | 118 | func - a doxyxml object from which documentation will be extracted. 119 | name - the name of the C object (defaults to func.name()) 120 | description - if this optional variable is set then it's value is 121 | used as the description instead of extracting it from func. 122 | params - a parameter list that overrides using func.params. 123 | """ 124 | if params is None: 125 | params = func.params 126 | params = [prm.declname for prm in params] 127 | if params: 128 | sig = "Params: (%s)" % ", ".join(params) 129 | else: 130 | sig = "Params: (NONE)" 131 | templ = "{description}\n\n" + sig 132 | return make_entry(func, name=name, templ=utoascii(templ), 133 | description=description) 134 | 135 | 136 | def make_class_entry(klass, description=None): 137 | """ 138 | Create a class docstring for a swig interface file. 139 | """ 140 | output = [] 141 | output.append(make_entry(klass, description=description)) 142 | for func in klass.in_category(DoxyFunction): 143 | name = klass.name() + '::' + func.name() 144 | output.append(make_func_entry(func, name=name)) 145 | return "\n\n".join(output) 146 | 147 | 148 | def make_block_entry(di, block): 149 | """ 150 | Create class and function docstrings of a gnuradio block for a 151 | swig interface file. 152 | """ 153 | descriptions = [] 154 | # Get the documentation associated with the class. 155 | class_desc = combine_descriptions(block) 156 | if class_desc: 157 | descriptions.append(class_desc) 158 | # Get the documentation associated with the make function 159 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 160 | make_func_desc = combine_descriptions(make_func) 161 | if make_func_desc: 162 | descriptions.append(make_func_desc) 163 | # Get the documentation associated with the file 164 | try: 165 | block_file = di.get_member(block.name() + ".h", DoxyFile) 166 | file_desc = combine_descriptions(block_file) 167 | if file_desc: 168 | descriptions.append(file_desc) 169 | except base.Base.NoSuchMember: 170 | # Don't worry if we can't find a matching file. 171 | pass 172 | # And join them all together to make a super duper description. 173 | super_description = "\n\n".join(descriptions) 174 | # Associate the combined description with the class and 175 | # the make function. 176 | output = [] 177 | output.append(make_class_entry(block, description=super_description)) 178 | creator = block.get_member(block.name(), DoxyFunction) 179 | output.append(make_func_entry(make_func, description=super_description, 180 | params=creator.params)) 181 | return "\n\n".join(output) 182 | 183 | 184 | def make_swig_interface_file(di, swigdocfilename, custom_output=None): 185 | 186 | output = [""" 187 | /* 188 | * This file was automatically generated using swig_doc.py. 189 | * 190 | * Any changes to it will be lost next time it is regenerated. 191 | */ 192 | """] 193 | 194 | if custom_output is not None: 195 | output.append(custom_output) 196 | 197 | # Create docstrings for the blocks. 198 | blocks = di.in_category(Block) 199 | make_funcs = set([]) 200 | for block in blocks: 201 | try: 202 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 203 | make_funcs.add(make_func.name()) 204 | output.append(make_block_entry(di, block)) 205 | except block.ParsingError: 206 | print('Parsing error for block %s' % block.name()) 207 | 208 | # Create docstrings for functions 209 | # Don't include the make functions since they have already been dealt with. 210 | funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in make_funcs] 211 | for f in funcs: 212 | try: 213 | output.append(make_func_entry(f)) 214 | except f.ParsingError: 215 | print('Parsing error for function %s' % f.name()) 216 | 217 | # Create docstrings for classes 218 | block_names = [block.name() for block in blocks] 219 | klasses = [k for k in di.in_category(DoxyClass) if k.name() not in block_names] 220 | for k in klasses: 221 | try: 222 | output.append(make_class_entry(k)) 223 | except k.ParsingError: 224 | print('Parsing error for class %s' % k.name()) 225 | 226 | # Docstrings are not created for anything that is not a function or a class. 227 | # If this excludes anything important please add it here. 228 | 229 | output = "\n\n".join(output) 230 | 231 | swig_doc = file(swigdocfilename, 'w') 232 | swig_doc.write(output) 233 | swig_doc.close() 234 | 235 | if __name__ == "__main__": 236 | # Parse command line options and set up doxyxml. 237 | err_msg = "Execute using: python swig_doc.py xml_path outputfilename" 238 | if len(sys.argv) != 3: 239 | raise StandardError(err_msg) 240 | xml_path = sys.argv[1] 241 | swigdocfilename = sys.argv[2] 242 | di = DoxyIndex(xml_path) 243 | 244 | # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined! 245 | # This is presumably a bug in SWIG. 246 | #msg_q = di.get_member(u'gr_msg_queue', DoxyClass) 247 | #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction) 248 | #delete_head = msg_q.get_member(u'delete_head', DoxyFunction) 249 | output = [] 250 | #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail')) 251 | #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head')) 252 | custom_output = "\n\n".join(output) 253 | 254 | # Generate the docstrings interface file. 255 | make_swig_interface_file(di, swigdocfilename, custom_output=custom_output) 256 | -------------------------------------------------------------------------------- /docs/doxygen/swig_doc.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/docs/doxygen/swig_doc.pyc -------------------------------------------------------------------------------- /grc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | install(FILES 21 | cbmc_modulation_classifier.xml 22 | cbmc_freq_sps_det.xml 23 | cbmc_my_pfb_clock_sync.xml DESTINATION share/gnuradio/grc/blocks 24 | ) 25 | -------------------------------------------------------------------------------- /grc/cbmc_freq_sps_det.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Frequency Correction 4 | cbmc_freq_sps_det 5 | [cbmc] 6 | import cbmc 7 | cbmc.freq_sps_det($decimation, $fft_size) 8 | 9 | 10 | Decimaton 11 | decimation 12 | 512 13 | complex 14 | 15 | 16 | 17 | Goertzel Factor 18 | fft_size 19 | 512 20 | int 21 | 22 | 23 | 24 | in 25 | complex 26 | 27 | 28 | 29 | out 30 | complex 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /grc/cbmc_modulation_classifier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Modulation Classifier 4 | cbmc_modulation_classifier 5 | [cbmc] 6 | import cbmc 7 | cbmc.modulation_classifier($decimation, $probe) 8 | 9 | 10 | Decimaton 11 | decimation 12 | 512 13 | complex 14 | 15 | 16 | 17 | Probe 18 | probe 19 | bool 20 | 24 | 28 | 29 | 30 | 31 | in 32 | complex 33 | 34 | 35 | out 36 | complex 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /grc/cbmc_my_pfb_clock_sync.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | My Polyphase Clock Sync 4 | cbmc_my_pfb_clock_sync 5 | [cbmc] 6 | import cbmc 7 | cbmc.my_pfb_clock_sync($sps, $loop_bw, $filter_size, $init_phase, $max_dev, $osps) 8 | set_loop_bandwidth($loop_bw) 9 | 10 | 11 | Type 12 | type 13 | enum 14 | 21 | 28 | 29 | 30 | 31 | Initial SPS 32 | sps 33 | real 34 | 35 | 36 | Loop Bandwidth 37 | loop_bw 38 | real 39 | 40 | 41 | Filter Size 42 | filter_size 43 | 32 44 | int 45 | 46 | 47 | Initial Phase 48 | init_phase 49 | 16 50 | real 51 | 52 | 53 | Maximum Rate Deviation 54 | max_dev 55 | 1.5 56 | real 57 | 58 | 59 | Output SPS 60 | osps 61 | 1 62 | int 63 | 64 | 65 | Block Size 66 | det_block_size 67 | 10000 68 | int 69 | 70 | 71 | in 72 | $type.input 73 | 74 | 75 | out 76 | $type.output 77 | 78 | 79 | err 80 | float 81 | 1 82 | 83 | 84 | rate 85 | float 86 | 1 87 | 88 | 89 | phase 90 | float 91 | 1 92 | 93 | 94 | -------------------------------------------------------------------------------- /include/cbmc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Install public header files 22 | ######################################################################## 23 | install(FILES 24 | api.h 25 | modulation_classifier.h 26 | freq_sps_det.h 27 | my_pfb_clock_sync.h DESTINATION include/cbmc 28 | ) 29 | -------------------------------------------------------------------------------- /include/cbmc/api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * GNU Radio is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3, or (at your option) 9 | * any later version. 10 | * 11 | * GNU Radio is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with GNU Radio; see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef INCLUDED_CBMC_API_H 23 | #define INCLUDED_CBMC_API_H 24 | 25 | #include 26 | 27 | #ifdef gnuradio_cbmc_EXPORTS 28 | # define CBMC_API __GR_ATTR_EXPORT 29 | #else 30 | # define CBMC_API __GR_ATTR_IMPORT 31 | #endif 32 | 33 | #endif /* INCLUDED_CBMC_API_H */ 34 | -------------------------------------------------------------------------------- /include/cbmc/freq_sps_det.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 Douglas Weber. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | 22 | #ifndef INCLUDED_CBMC_FREQ_SPS_DET_H 23 | #define INCLUDED_CBMC_FREQ_SPS_DET_H 24 | 25 | #include 26 | #include 27 | 28 | namespace gr { 29 | namespace cbmc { 30 | 31 | /*! 32 | * \brief <+description of block+> 33 | * \ingroup cbmc 34 | * 35 | */ 36 | class CBMC_API freq_sps_det : virtual public gr::sync_block 37 | { 38 | public: 39 | typedef boost::shared_ptr sptr; 40 | 41 | /*! 42 | * \brief Return a shared_ptr to a new instance of cbmc::freq_sps_det. 43 | * 44 | * To avoid accidental use of raw pointers, cbmc::freq_sps_det's 45 | * constructor is in a private implementation 46 | * class. cbmc::freq_sps_det::make is the public interface for 47 | * creating new instances. 48 | */ 49 | static sptr make(int decimation, int fft_size); 50 | 51 | virtual std::vector get_stored_freqs() const = 0; 52 | virtual void discard_stored_freqs() = 0; 53 | }; 54 | 55 | } // namespace cbmc 56 | } // namespace gr 57 | 58 | #endif /* INCLUDED_CBMC_FREQ_SPS_DET_H */ 59 | 60 | -------------------------------------------------------------------------------- /include/cbmc/modulation_classifier.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 Douglas Weber. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | 22 | #ifndef INCLUDED_CBMC_MODULATION_CLASSIFIER_H 23 | #define INCLUDED_CBMC_MODULATION_CLASSIFIER_H 24 | 25 | #include 26 | #include 27 | 28 | namespace gr { 29 | namespace cbmc { 30 | 31 | /*! 32 | * \brief <+description of block+> 33 | * \ingroup cbmc 34 | * 35 | */ 36 | class CBMC_API modulation_classifier : virtual public gr::sync_block 37 | { 38 | public: 39 | typedef boost::shared_ptr sptr; 40 | 41 | /*! 42 | * \brief Return a shared_ptr to a new instance of cbmc::modulation_classifier. 43 | * 44 | * To avoid accidental use of raw pointers, cbmc::modulation_classifier's 45 | * constructor is in a private implementation 46 | * class. cbmc::modulation_classifier::make is the public interface for 47 | * creating new instances. 48 | */ 49 | static sptr make(int decimation, bool probe); 50 | 51 | virtual std::vector get_stored_mod() const = 0; 52 | virtual std::vector get_stored_cumu() const = 0; 53 | virtual void reset() = 0; 54 | }; 55 | 56 | } // namespace cbmc 57 | } // namespace gr 58 | 59 | #endif /* INCLUDED_CBMC_MODULATION_CLASSIFIER_H */ 60 | 61 | -------------------------------------------------------------------------------- /include/cbmc/my_pfb_clock_sync.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2009,2010,2012 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | 24 | #ifndef INCLUDED_CBMC_MY_PFB_CLOCK_SYNC_H 25 | #define INCLUDED_CBMC_MY_PFB_CLOCK_SYNC_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace gr { 32 | namespace cbmc { 33 | 34 | /*! 35 | * \brief Timing synchronizer using polyphase filterbanks 36 | * \ingroup synchronizers_blk 37 | * 38 | * \details 39 | * This block performs timing synchronization for PAM signals by 40 | * minimizing the derivative of the filtered signal, which in turn 41 | * maximizes the SNR and minimizes ISI. 42 | * 43 | * This approach works by setting up two filterbanks; one 44 | * filterbank contains the signal's pulse shaping matched filter 45 | * (such as a root raised cosine filter), where each branch of the 46 | * filterbank contains a different phase of the filter. The 47 | * second filterbank contains the derivatives of the filters in 48 | * the first filterbank. Thinking of this in the time domain, the 49 | * first filterbank contains filters that have a sinc shape to 50 | * them. We want to align the output signal to be sampled at 51 | * exactly the peak of the sinc shape. The derivative of the sinc 52 | * contains a zero at the maximum point of the sinc (sinc(0) = 1, 53 | * sinc(0)' = 0). Furthermore, the region around the zero point 54 | * is relatively linear. We make use of this fact to generate the 55 | * error signal. 56 | * 57 | * If the signal out of the derivative filters is d_i[n] for the 58 | * ith filter, and the output of the matched filter is x_i[n], we 59 | * calculate the error as: e[n] = (Re{x_i[n]} * Re{d_i[n]} + 60 | * Im{x_i[n]} * Im{d_i[n]}) / 2.0 This equation averages the error 61 | * in the real and imaginary parts. There are two reasons we 62 | * multiply by the signal itself. First, if the symbol could be 63 | * positive or negative going, but we want the error term to 64 | * always tell us to go in the same direction depending on which 65 | * side of the zero point we are on. The sign of x_i[n] adjusts 66 | * the error term to do this. Second, the magnitude of x_i[n] 67 | * scales the error term depending on the symbol's amplitude, so 68 | * larger signals give us a stronger error term because we have 69 | * more confidence in that symbol's value. Using the magnitude of 70 | * x_i[n] instead of just the sign is especially good for signals 71 | * with low SNR. 72 | * 73 | * The error signal, e[n], gives us a value proportional to how 74 | * far away from the zero point we are in the derivative 75 | * signal. We want to drive this value to zero, so we set up a 76 | * second order loop. We have two variables for this loop; d_k is 77 | * the filter number in the filterbank we are on and d_rate is the 78 | * rate which we travel through the filters in the steady 79 | * state. That is, due to the natural clock differences between 80 | * the transmitter and receiver, d_rate represents that difference 81 | * and would traverse the filter phase paths to keep the receiver 82 | * locked. Thinking of this as a second-order PLL, the d_rate is 83 | * the frequency and d_k is the phase. So we update d_rate and d_k 84 | * using the standard loop equations based on two error signals, 85 | * d_alpha and d_beta. We have these two values set based on each 86 | * other for a critically damped system, so in the block 87 | * constructor, we just ask for "gain," which is d_alpha while 88 | * d_beta is equal to (gain^2)/4. 89 | * 90 | * The block's parameters are: 91 | * 92 | * \li \p sps: The clock sync block needs to know the number of 93 | * samples per symbol, because it defaults to return a single 94 | * point representing the symbol. The sps can be any positive real 95 | * number and does not need to be an integer. 96 | * 97 | * \li \p loop_bw: The loop bandwidth is used to set the gain of 98 | * the inner control loop (see: 99 | * http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html). 100 | * This should be set small (a value of around 2pi/100 is 101 | * suggested in that blog post as the step size for the number of 102 | * radians around the unit circle to move relative to the error). 103 | * 104 | * \li \p taps: One of the most important parameters for this 105 | * block is the taps of the filter. One of the benefits of this 106 | * algorithm is that you can put the matched filter in here as the 107 | * taps, so you get both the matched filter and sample timing 108 | * correction in one go. So create your normal matched filter. For 109 | * a typical digital modulation, this is a root raised cosine 110 | * filter. The number of taps of this filter is based on how long 111 | * you expect the channel to be; that is, how many symbols do you 112 | * want to combine to get the current symbols energy back (there's 113 | * probably a better way of stating that). It's usually 5 to 10 or 114 | * so. That gives you your filter, but now we need to think about 115 | * it as a filter with different phase profiles in each filter. So 116 | * take this number of taps and multiply it by the number of 117 | * filters. This is the number you would use to create your 118 | * prototype filter. When you use this in the PFB filerbank, it 119 | * segments these taps into the filterbanks in such a way that 120 | * each bank now represents the filter at different phases, 121 | * equally spaced at 2pi/N, where N is the number of filters. 122 | * 123 | * \li \p filter_size (default=32): The number of filters can also 124 | * be set and defaults to 32. With 32 filters, you get a good 125 | * enough resolution in the phase to produce very small, almost 126 | * unnoticeable, ISI. Going to 64 filters can reduce this more, 127 | * but after that there is very little gained for the extra 128 | * complexity. 129 | * 130 | * \li \p init_phase (default=0): The initial phase is another 131 | * settable parameter and refers to the filter path the algorithm 132 | * initially looks at (i.e., d_k starts at init_phase). This value 133 | * defaults to zero, but it might be useful to start at a 134 | * different phase offset, such as the mid-point of the filters. 135 | * 136 | * \li \p max_rate_deviation (default=1.5): The next parameter is 137 | * the max_rate_devitation, which defaults to 1.5. This is how far 138 | * we allow d_rate to swing, positive or negative, from 139 | * 0. Constraining the rate can help keep the algorithm from 140 | * walking too far away to lock during times when there is no 141 | * signal. 142 | * 143 | * \li \p osps (default=1): The osps is the number of output 144 | * samples per symbol. By default, the algorithm produces 1 sample 145 | * per symbol, sampled at the exact sample value. This osps value 146 | * was added to better work with equalizers, which do a better job 147 | * of modeling the channel if they have 2 samps/sym. 148 | * 149 | * Reference: 150 | * f. j. harris and M. Rice, "Multirate Digital Filters for Symbol 151 | * Timing Synchronization in Software Defined Radios", IEEE 152 | * Selected Areas in Communications, Vol. 19, No. 12, Dec., 2001. 153 | * 154 | * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.127.1757 155 | */ 156 | class CBMC_API my_pfb_clock_sync : virtual public gr::block 157 | { 158 | public: 159 | // gr::digital::my_pfb_clock_sync::sptr 160 | typedef boost::shared_ptr sptr; 161 | 162 | /*! 163 | * Build the polyphase filterbank timing synchronizer. 164 | * \param sps (double) The number of samples per symbol in the incoming signal 165 | * \param loop_bw (float) The bandwidth of the control loop; set's alpha and beta. 166 | * \param taps (vector) The filter taps. 167 | * \param filter_size (uint) The number of filters in the filterbank (default = 32). 168 | * \param init_phase (float) The initial phase to look at, or which filter to start 169 | * with (default = 0). 170 | * \param max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5). 171 | * \param osps (int) The number of output samples per symbol (default=1). 172 | */ 173 | static sptr make(double sps, float loop_bw, 174 | unsigned int filter_size=32, 175 | float init_phase=0, 176 | float max_rate_deviation=1.5, 177 | int osps=1, 178 | unsigned int d_det_block_size=10000); 179 | 180 | /*! \brief update the system gains from omega and eta 181 | * 182 | * This function updates the system gains based on the loop 183 | * bandwidth and damping factor of the system. 184 | * These two factors can be set separately through their own 185 | * set functions. 186 | */ 187 | virtual void update_gains() = 0; 188 | 189 | /*! 190 | * Resets the filterbank's filter taps with the new prototype filter. 191 | */ 192 | virtual void update_taps(const std::vector &taps) = 0; 193 | 194 | /*! 195 | * Used to set the taps of the filters in the filterbank and 196 | * differential filterbank. 197 | * 198 | * WARNING: this should not be used externally and will be moved 199 | * to a private funtion in the next API. 200 | */ 201 | virtual void set_taps(const std::vector &taps, 202 | std::vector< std::vector > &ourtaps, 203 | std::vector &ourfilter) = 0; 204 | 205 | /*! 206 | * Returns all of the taps of the matched filter 207 | */ 208 | virtual std::vector< std::vector > taps() const = 0; 209 | 210 | /*! 211 | * Returns all of the taps of the derivative filter 212 | */ 213 | virtual std::vector< std::vector > diff_taps() const = 0; 214 | 215 | /*! 216 | * Returns the taps of the matched filter for a particular channel 217 | */ 218 | virtual std::vector channel_taps(int channel) const = 0; 219 | 220 | /*! 221 | * Returns the taps in the derivative filter for a particular channel 222 | */ 223 | virtual std::vector diff_channel_taps(int channel) const = 0; 224 | 225 | /*! 226 | * Return the taps as a formatted string for printing 227 | */ 228 | virtual std::string taps_as_string() const = 0; 229 | 230 | /*! 231 | * Return the derivative filter taps as a formatted string for printing 232 | */ 233 | virtual std::string diff_taps_as_string() const = 0; 234 | 235 | 236 | /******************************************************************* 237 | SET FUNCTIONS 238 | *******************************************************************/ 239 | 240 | /*! 241 | * \brief Set the loop bandwidth 242 | * 243 | * Set the loop filter's bandwidth to \p bw. This should be 244 | * between 2*pi/200 and 2*pi/100 (in rads/samp). It must also be 245 | * a positive number. 246 | * 247 | * When a new damping factor is set, the gains, alpha and beta, 248 | * of the loop are recalculated by a call to update_gains(). 249 | * 250 | * \param bw (float) new bandwidth 251 | */ 252 | virtual void set_loop_bandwidth(float bw) = 0; 253 | 254 | /*! 255 | * \brief Set the loop damping factor 256 | * 257 | * Set the loop filter's damping factor to \p df. The damping 258 | * factor should be sqrt(2)/2.0 for critically damped systems. 259 | * Set it to anything else only if you know what you are 260 | * doing. It must be a number between 0 and 1. 261 | * 262 | * When a new damping factor is set, the gains, alpha and beta, 263 | * of the loop are recalculated by a call to update_gains(). 264 | * 265 | * \param df (float) new damping factor 266 | */ 267 | virtual void set_damping_factor(float df) = 0; 268 | 269 | /*! 270 | * \brief Set the loop gain alpha 271 | * 272 | * Set's the loop filter's alpha gain parameter. 273 | * 274 | * This value should really only be set by adjusting the loop 275 | * bandwidth and damping factor. 276 | * 277 | * \param alpha (float) new alpha gain 278 | */ 279 | virtual void set_alpha(float alpha) = 0; 280 | 281 | /*! 282 | * \brief Set the loop gain beta 283 | * 284 | * Set's the loop filter's beta gain parameter. 285 | * 286 | * This value should really only be set by adjusting the loop 287 | * bandwidth and damping factor. 288 | * 289 | * \param beta (float) new beta gain 290 | */ 291 | virtual void set_beta(float beta) = 0; 292 | 293 | /*! 294 | * Set the maximum deviation from 0 d_rate can have 295 | */ 296 | virtual void set_max_rate_deviation(float m) = 0; 297 | 298 | /******************************************************************* 299 | GET FUNCTIONS 300 | *******************************************************************/ 301 | 302 | /*! 303 | * \brief Returns the loop bandwidth 304 | */ 305 | virtual float loop_bandwidth() const = 0; 306 | 307 | /*! 308 | * \brief Returns the loop damping factor 309 | */ 310 | virtual float damping_factor() const = 0; 311 | 312 | /*! 313 | * \brief Returns the loop gain alpha 314 | */ 315 | virtual float alpha() const = 0; 316 | 317 | /*! 318 | * \brief Returns the loop gain beta 319 | */ 320 | virtual float beta() const = 0; 321 | 322 | /*! 323 | * \brief Returns the current clock rate 324 | */ 325 | virtual float clock_rate() const = 0; 326 | 327 | /*! 328 | * \brief Returns the current error of the control loop. 329 | */ 330 | virtual float error() const = 0; 331 | 332 | /*! 333 | * \brief Returns the current rate of the control loop. 334 | */ 335 | virtual float rate() const = 0; 336 | 337 | /*! 338 | * \brief Returns the current phase arm of the control loop. 339 | */ 340 | virtual float phase() const = 0; 341 | }; 342 | 343 | } // namespace cbmc 344 | } // namespace gr 345 | 346 | #endif /* INCLUDED_CBMC_MY_PFB_CLOCK_SYNC_H */ 347 | 348 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012,2016 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Setup library 22 | ######################################################################## 23 | include(GrPlatform) #define LIB_SUFFIX 24 | 25 | include_directories(${Boost_INCLUDE_DIR}) 26 | link_directories(${Boost_LIBRARY_DIRS}) 27 | 28 | list(APPEND cbmc_sources 29 | modulation_classifier_impl.cc 30 | freq_sps_det_impl.cc 31 | my_pfb_clock_sync_impl.cc 32 | ) 33 | 34 | set(cbmc_sources "${cbmc_sources}" PARENT_SCOPE) 35 | if(NOT cbmc_sources) 36 | MESSAGE(STATUS "No C++ sources... skipping lib/") 37 | return() 38 | endif(NOT cbmc_sources) 39 | 40 | add_library(gnuradio-cbmc SHARED ${cbmc_sources}) 41 | target_link_libraries(gnuradio-cbmc ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES}) 42 | set_target_properties(gnuradio-cbmc PROPERTIES DEFINE_SYMBOL "gnuradio_cbmc_EXPORTS") 43 | 44 | if(APPLE) 45 | set_target_properties(gnuradio-cbmc PROPERTIES 46 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" 47 | ) 48 | endif(APPLE) 49 | 50 | ######################################################################## 51 | # Install built library files 52 | ######################################################################## 53 | include(GrMiscUtils) 54 | GR_LIBRARY_FOO(gnuradio-cbmc RUNTIME_COMPONENT "cbmc_runtime" DEVEL_COMPONENT "cbmc_devel") 55 | 56 | ######################################################################## 57 | # Build and register unit test 58 | ######################################################################## 59 | include(GrTest) 60 | 61 | include_directories(${CPPUNIT_INCLUDE_DIRS}) 62 | 63 | list(APPEND test_cbmc_sources 64 | ${CMAKE_CURRENT_SOURCE_DIR}/test_cbmc.cc 65 | ${CMAKE_CURRENT_SOURCE_DIR}/qa_cbmc.cc 66 | ) 67 | 68 | add_executable(test-cbmc ${test_cbmc_sources}) 69 | 70 | target_link_libraries( 71 | test-cbmc 72 | ${GNURADIO_RUNTIME_LIBRARIES} 73 | ${Boost_LIBRARIES} 74 | ${CPPUNIT_LIBRARIES} 75 | gnuradio-cbmc 76 | ) 77 | 78 | GR_ADD_TEST(test_cbmc test-cbmc) 79 | 80 | ######################################################################## 81 | # Print summary 82 | ######################################################################## 83 | message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") 84 | message(STATUS "Building for version: ${VERSION} / ${LIBVER}") 85 | 86 | -------------------------------------------------------------------------------- /lib/freq_sps_det_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 Douglas Weber. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "freq_sps_det_impl.h" 27 | #include 28 | #include 29 | 30 | namespace gr { 31 | namespace cbmc { 32 | 33 | freq_sps_det::sptr 34 | freq_sps_det::make(int decimation, int fft_size) 35 | { 36 | return gnuradio::get_initial_sptr 37 | (new freq_sps_det_impl(decimation, fft_size)); 38 | } 39 | 40 | freq_sps_det_impl::freq_sps_det_impl(int decimation, int fft_size) 41 | : gr::sync_block("freq_sps_det", 42 | gr::io_signature::make(1, 1, sizeof(gr_complex)), 43 | gr::io_signature::make(1, 1, sizeof(gr_complex))), 44 | d_decimation(decimation), d_nsubdiv(fft_size) 45 | { 46 | d_fft_size = d_decimation; 47 | d_fft = new fft::fft_complex(d_fft_size, true, 1); 48 | d_goertzel = new fft::goertzel(1, d_fft_size, 0); 49 | set_output_multiple(d_decimation); 50 | } 51 | 52 | /* 53 | * Our virtual destructor. 54 | */ 55 | freq_sps_det_impl::~freq_sps_det_impl() 56 | { 57 | delete d_fft; 58 | } 59 | 60 | int 61 | freq_sps_det_impl::work(int noutput_items, 62 | gr_vector_const_void_star &input_items, 63 | gr_vector_void_star &output_items) 64 | { 65 | const gr_complex *in = (const gr_complex *) input_items[0]; 66 | gr_complex *out = (gr_complex *) output_items[0]; 67 | 68 | size_t i = 0; 69 | while ( i < noutput_items ) 70 | { 71 | // Set pointer 'samples' 72 | const gr_complex* samples = in + i; 73 | 74 | // Frequency estimation 75 | float f_offset; 76 | float sps; 77 | calc_f_offset_and_sps(f_offset, sps, samples); 78 | d_stored_freqs.push_back(f_offset); 79 | 80 | // Set streamtag with detected sps 81 | add_item_tag(0, nitems_written(0) + i, pmt::intern("det_sps"), pmt::from_float(sps)); 82 | 83 | // Apply frequency correction and write samples the into output 84 | f_shift_samples(out + i, samples, f_offset); 85 | 86 | // Increase counter of written samples 87 | i += d_decimation; 88 | } 89 | 90 | // Tell runtime system how many output items we produced. 91 | return noutput_items; 92 | } 93 | 94 | // Returns the offset number of points from d_fft_size 95 | // consumes first d_decimation items of samples 96 | void 97 | freq_sps_det_impl::calc_f_offset_and_sps(float &f_offset, float &sps, const gr_complex* samples) 98 | { 99 | // Samples to the power of 2 100 | gr_complex samples_2[d_fft_size]; 101 | volk_32fc_s32f_power_32fc(samples_2, samples, 2, d_decimation); 102 | 103 | // Samples to the power of 4 104 | gr_complex samples_4[d_fft_size]; 105 | volk_32fc_s32f_power_32fc(samples_4, samples_2, 2, d_decimation); 106 | 107 | // Samples to the power of 8 108 | gr_complex samples_8[d_fft_size]; 109 | volk_32fc_s32f_power_32fc(samples_8, samples_4, 2, d_decimation); 110 | 111 | 112 | // Calculate FFTs 113 | gr_complex samples_2_fft[d_fft_size]; 114 | memcpy(d_fft->get_inbuf(), samples_2, d_fft_size*sizeof(gr_complex)); 115 | d_fft->execute(); 116 | memcpy(samples_2_fft, d_fft->get_outbuf(), d_fft_size*sizeof(gr_complex)); 117 | 118 | gr_complex samples_4_fft[d_fft_size]; 119 | memcpy(d_fft->get_inbuf(), samples_4, d_fft_size*sizeof(gr_complex)); 120 | d_fft->execute(); 121 | memcpy(samples_4_fft, d_fft->get_outbuf(), d_fft_size*sizeof(gr_complex)); 122 | 123 | gr_complex samples_8_fft[d_fft_size]; 124 | memcpy(d_fft->get_inbuf(), samples_8, d_fft_size*sizeof(gr_complex)); 125 | d_fft->execute(); 126 | memcpy(samples_8_fft, d_fft->get_outbuf(), d_fft_size*sizeof(gr_complex)); 127 | 128 | // Magnitude of FFTs 129 | float samples_2_abs_fft[d_fft_size]; 130 | volk_32fc_magnitude_32f(samples_2_abs_fft, samples_2_fft, d_fft_size); 131 | 132 | float samples_4_abs_fft[d_fft_size]; 133 | volk_32fc_magnitude_32f(samples_4_abs_fft, samples_4_fft, d_fft_size); 134 | 135 | float samples_8_abs_fft[d_fft_size]; 136 | volk_32fc_magnitude_32f(samples_8_abs_fft, samples_8_fft, d_fft_size); 137 | 138 | 139 | // Calculate Maxima of FFTs 140 | short unsigned int maxIndex_2; 141 | volk_32f_index_max_16u(&maxIndex_2, samples_2_abs_fft, d_fft_size); 142 | 143 | short unsigned int maxIndex_4; 144 | volk_32f_index_max_16u(&maxIndex_4, samples_4_abs_fft, d_fft_size); 145 | 146 | short unsigned int maxIndex_8; 147 | volk_32f_index_max_16u(&maxIndex_8, samples_8_abs_fft, d_fft_size); 148 | 149 | // Calculate quality criterion 150 | float samples_2_qc; 151 | volk_32f_accumulator_s32f(&samples_2_qc, samples_2_abs_fft, d_fft_size); 152 | samples_2_qc = samples_2_abs_fft[maxIndex_2] / samples_2_qc; 153 | 154 | float samples_4_qc; 155 | volk_32f_accumulator_s32f(&samples_4_qc, samples_4_abs_fft, d_fft_size); 156 | samples_4_qc = samples_4_abs_fft[maxIndex_4] / samples_4_qc; 157 | 158 | float samples_8_qc; 159 | volk_32f_accumulator_s32f(&samples_8_qc, samples_8_abs_fft, d_fft_size); 160 | samples_8_qc = samples_8_abs_fft[maxIndex_8] / samples_8_qc; 161 | 162 | 163 | if (samples_2_qc > samples_4_qc && samples_2_qc > samples_8_qc) 164 | { 165 | f_offset = calc_offset(samples_2, maxIndex_2, 0.5); 166 | sps = calc_sps(samples_2_abs_fft, maxIndex_2); 167 | } 168 | else if (samples_4_qc > samples_2_qc && samples_4_qc > samples_8_qc) 169 | { 170 | f_offset = calc_offset(samples_4, maxIndex_4, 0.25); 171 | sps = calc_sps(samples_4_abs_fft, maxIndex_4); 172 | } 173 | else 174 | { 175 | f_offset = calc_offset(samples_8, maxIndex_8, 0.125); 176 | sps = calc_sps(samples_8_abs_fft, maxIndex_8); 177 | } 178 | 179 | } 180 | 181 | inline void 182 | freq_sps_det_impl::f_shift_samples(gr_complex* output, const gr_complex* samples, float f_offset) 183 | { 184 | complexd exp_factor = d_m_j_2pi * complexd(f_offset); 185 | for ( int k = 0; k < d_decimation; k++) 186 | { 187 | d_phase += exp_factor; 188 | *(output + k) = samples[k] * gr_complex(std::exp( d_phase )); 189 | } 190 | // Ignore turns by multiple of 2 pi 191 | d_phase = gr_complex(0, fmod (d_phase.imag(), float(2)*pi)); 192 | } 193 | 194 | inline float 195 | freq_sps_det_impl::calc_offset(const gr_complex* samples_x, short unsigned int maxIndex, float factor) 196 | { 197 | float f_offset; 198 | 199 | // Check if offset is negative 200 | if (maxIndex > d_fft_size/2) 201 | { 202 | f_offset = (float) maxIndex - (float) d_fft_size; 203 | } 204 | else 205 | { 206 | f_offset = (float) maxIndex; 207 | } 208 | 209 | float fine_offset = 0; 210 | if (d_nsubdiv > 1) { 211 | fine_offset = ft_refinement(maxIndex, samples_x, d_nsubdiv); 212 | } 213 | 214 | f_offset = ((float)f_offset + (float)fine_offset) * factor; 215 | 216 | return f_offset/float(d_fft_size); 217 | } 218 | 219 | // Calculation of samples per symbol 220 | // 'destroys' samples_abs_fft 221 | inline float 222 | freq_sps_det_impl::calc_sps(float* samples_abs_fft, short unsigned int maxIndex) 223 | { 224 | float sps; 225 | 226 | // Find second highest peak 227 | samples_abs_fft[maxIndex] = 0; 228 | 229 | // Do not find peaks near f_offset 230 | int frame = 10 * ceil(d_fft_size / d_decimation); 231 | 232 | for (int i = -frame; i < frame; i++) 233 | { 234 | if ((int) maxIndex + i < 0) 235 | { 236 | samples_abs_fft[(int) maxIndex + i + d_fft_size] = 0; 237 | } 238 | else 239 | { 240 | samples_abs_fft[(int) maxIndex + i] = 0; 241 | } 242 | } 243 | 244 | short unsigned int sps_index; 245 | volk_32f_index_max_16u(&sps_index, samples_abs_fft, d_fft_size); 246 | 247 | // Check if sps is negative 248 | if (sps_index > d_fft_size/2) { sps = ((float) sps_index - (float) d_fft_size); } 249 | else { sps = (float) sps_index; } 250 | 251 | // only works, if d_fft_size == d_decimation 252 | int f_offset_index; 253 | if (maxIndex > d_fft_size/2) 254 | { f_offset_index = (int) maxIndex - (int) d_fft_size; } 255 | else { f_offset_index = (int) maxIndex; } 256 | 257 | return std::abs(d_fft_size / (f_offset_index - sps)); 258 | } 259 | 260 | float 261 | freq_sps_det_impl::ft_refinement(short unsigned int rough_index, const gr_complex* samples, const short unsigned int refinem_f) 262 | { 263 | float samples_real[d_decimation]; 264 | volk_32fc_deinterleave_real_32f(samples_real, samples, d_decimation); 265 | float samples_imag[d_decimation]; 266 | volk_32fc_deinterleave_imag_32f(samples_imag, samples, d_decimation); 267 | 268 | short unsigned int n_points = refinem_f; 269 | if ( refinem_f % 2 == 0 ) { n_points += 1; } 270 | gr_complex ans_goertzel[n_points]; 271 | int d; 272 | gr_complex j(0,1); 273 | for (int i = 0; i < n_points; i++){ 274 | d = (int)refinem_f * rough_index - (int)((float)(n_points-1) * 0.5) + i; 275 | if (d < 0) { d += (int)refinem_f * d_decimation; } 276 | else if (d > refinem_f * d_decimation) { d -= (int)refinem_f * d_decimation; } 277 | d_goertzel->set_params(d_decimation*refinem_f, d_decimation, d); 278 | gr_complex bin_r = d_goertzel->batch(samples_real); 279 | gr_complex bin_i = d_goertzel->batch(samples_imag); 280 | ans_goertzel[i] = bin_r + j * bin_i; 281 | } 282 | short unsigned int maxIndex; 283 | float ans_goertzel_abs[n_points]; 284 | volk_32fc_magnitude_32f(ans_goertzel_abs, ans_goertzel, n_points); 285 | volk_32f_index_max_16u(&maxIndex, ans_goertzel_abs, n_points); 286 | 287 | return ((float) maxIndex - (float)(n_points-1) * 0.5)/(float)refinem_f; 288 | } 289 | 290 | } /* namespace cbmc */ 291 | } /* namespace gr */ 292 | 293 | -------------------------------------------------------------------------------- /lib/freq_sps_det_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 Douglas Weber. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_CBMC_FREQ_SPS_DET_IMPL_H 22 | #define INCLUDED_CBMC_FREQ_SPS_DET_IMPL_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace gr { 29 | namespace cbmc { 30 | 31 | class freq_sps_det_impl : public freq_sps_det 32 | { 33 | private: 34 | typedef std::complex complexd; 35 | const double pi = std::acos(-1); 36 | // assign minus j two pi 37 | const complexd d_m_j_2pi = (gr_complex(0,-2) * gr_complex(pi)); 38 | const int d_decimation; 39 | short unsigned int d_fft_size; 40 | fft::fft_complex *d_fft; 41 | fft::goertzel *d_goertzel; 42 | complexd d_phase; 43 | short unsigned int d_nsubdiv; 44 | std::vector d_stored_freqs; 45 | 46 | public: 47 | freq_sps_det_impl(int decimation, int fft_size); 48 | ~freq_sps_det_impl(); 49 | 50 | int work(int noutput_items, 51 | gr_vector_const_void_star &input_items, 52 | gr_vector_void_star &output_items); 53 | 54 | std::vector get_stored_freqs() const 55 | { 56 | return d_stored_freqs; 57 | } 58 | 59 | void discard_stored_freqs() 60 | { 61 | d_stored_freqs.clear(); 62 | } 63 | 64 | void calc_f_offset_and_sps(float &f_offset, float &sps, const gr_complex* samples); 65 | inline void f_shift_samples(gr_complex* output, const gr_complex* samples, float f_offset); 66 | inline float calc_offset(const gr_complex* samples_x, short unsigned int MaxIndex, float factor); 67 | inline float calc_sps(float* samples_abs_fft, short unsigned int maxIndex); 68 | float ft_refinement(short unsigned int rough_freq, const gr_complex* samples, const short unsigned int refinem_f); 69 | }; 70 | 71 | } // namespace cbmc 72 | } // namespace gr 73 | 74 | #endif /* INCLUDED_CBMC_FREQ_SPS_DET_IMPL_H */ 75 | 76 | -------------------------------------------------------------------------------- /lib/modulation_classifier_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 Douglas Weber. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "modulation_classifier_impl.h" 27 | #include // for accumulate 28 | #include 29 | 30 | namespace gr { 31 | namespace cbmc { 32 | 33 | modulation_classifier::sptr 34 | modulation_classifier::make(int decimation, bool probe) 35 | { 36 | return gnuradio::get_initial_sptr 37 | (new modulation_classifier_impl(decimation, probe)); 38 | } 39 | 40 | /* 41 | * The private constructor 42 | */ 43 | modulation_classifier_impl::modulation_classifier_impl(int decimation, bool probe) 44 | : gr::sync_block("modulation_classifier", 45 | gr::io_signature::make(1, 1, sizeof(gr_complex)), 46 | gr::io_signature::make(1, 1, sizeof(gr_complex))), 47 | d_decimation(decimation), d_probe_enabled(probe) 48 | { 49 | set_output_multiple(d_decimation); 50 | } 51 | 52 | /* 53 | * Our virtual destructor. 54 | */ 55 | modulation_classifier_impl::~modulation_classifier_impl() 56 | { 57 | } 58 | 59 | int 60 | modulation_classifier_impl::work(int noutput_items, 61 | gr_vector_const_void_star &input_items, 62 | gr_vector_void_star &output_items) 63 | { 64 | const gr_complex *in = (const gr_complex *) input_items[0]; 65 | gr_complex *out = (gr_complex *) output_items[0]; 66 | 67 | size_t i = 0; 68 | while ( i < noutput_items ) 69 | { 70 | // set pointer 'samples' 71 | const gr_complex* samples = in + i; 72 | 73 | // Decide which modulation has been received and phase shift 74 | gr_complex samples_shifted[d_decimation]; 75 | unsigned int det_mod_index = detMod2(samples_shifted, samples); 76 | if (d_probe_enabled) { 77 | d_stored_mod.push_back(det_mod_index); 78 | } 79 | 80 | // Assignment of Modulations to Indexes 81 | std::string det_mod = ""; 82 | switch(det_mod_index) 83 | { 84 | case 0: 85 | det_mod = "8PSK"; 86 | break; 87 | case 1: 88 | det_mod = "16AM"; 89 | break; 90 | case 2: 91 | det_mod = "QPSK"; 92 | break; 93 | case 3: 94 | det_mod = "BPSK"; 95 | } 96 | 97 | 98 | // set output 99 | std::memcpy(out + i, samples_shifted, d_decimation * sizeof(gr_complex)); 100 | 101 | // Set streamtag to the first item of the sample 102 | add_item_tag(0, // Port number 103 | nitems_written(0) + i, // Offset 104 | pmt::mp("det_mod"), // Key 105 | pmt::mp(det_mod) // Value 106 | ); 107 | 108 | /* 109 | // Verification of modulation detection 110 | // Compares the detected Modulation with the one specified in a stream tag "sent_mod" 111 | 112 | // Get Tags: sent modulation 113 | std::vector sent_mod_tags; 114 | get_tags_in_window( // Note the different method name 115 | sent_mod_tags, // Tags will be saved here 116 | 0, // Port 0 117 | 0, // Start of range (relative to nitems_read(0)) 118 | d_decimation, // End of relative range 119 | pmt::mp("sent_mod") 120 | ); 121 | 122 | if ( !(sent_mod_tags.empty()) ) 123 | { 124 | std::string verif = ""; 125 | 126 | if ( pmt::symbol_to_string(sent_mod_tags[0].value) == det_mod ) 127 | { 128 | verif = "Passed"; 129 | } 130 | else 131 | { 132 | verif = "Failed"; 133 | } 134 | 135 | // Check, if modulation changes within samples (assume, that it does not switch twice) 136 | for (int j = 1; j < sent_mod_tags.size(); j++) 137 | { 138 | if ( !pmt::equal(sent_mod_tags[0].value, sent_mod_tags[j].value) ) 139 | { 140 | verif = "Modulation Changed"; 141 | j = sent_mod_tags.size(); 142 | } 143 | } 144 | 145 | add_item_tag(0, // Port number 146 | nitems_written(0) + i, // Offset 147 | pmt::mp("Verified"), // Key 148 | pmt::mp( verif ) // Value 149 | ); 150 | } 151 | */ 152 | 153 | i += d_decimation; 154 | } 155 | 156 | // Tell runtime system how many output items we produced. 157 | return noutput_items; 158 | } 159 | 160 | // Computes normalized cumulants 161 | // real part would be sufficient 162 | // consumes d_decimation samples and c_2_1 163 | void 164 | modulation_classifier_impl::computeCumulant_4_0_u_4_2(gr_complex &c_4_0, gr_complex &c_4_2, const gr_complex* samples, gr_complex c_2_1) 165 | { 166 | // Samples squared 167 | gr_complex samples_pot[d_decimation]; 168 | volk_32fc_s32f_power_32fc(samples_pot, samples, 2, d_decimation); 169 | 170 | gr_complex c_2_0 = std::accumulate(samples_pot, samples_pot + d_decimation, gr_complex{0}) * a_factor; 171 | 172 | // Cumulant 4_2 173 | // 174 | // Complex conjugate of samples 175 | gr_complex samples_con[d_decimation]; 176 | volk_32fc_conjugate_32fc(samples_con, samples, d_decimation); 177 | 178 | // Conjugate samples sqared 179 | volk_32fc_s32f_power_32fc(samples_con, samples_con, 2, d_decimation); 180 | 181 | // Mean of conjugate samples squared 182 | gr_complex mean_c_sq = std::accumulate(samples_con, samples_con + d_decimation, gr_complex{0}) * a_factor; 183 | 184 | // Conjugate samples squared multiplied by samples squared: stored -> samples_con 185 | volk_32fc_x2_multiply_32fc(samples_con, samples_con, samples_pot, d_decimation); 186 | 187 | // Mean of (samples squared multiplied by conjugate samples squared) 188 | gr_complex mean_c_sq_sq = std::accumulate(samples_con, samples_con + d_decimation, gr_complex{0}) * a_factor; 189 | 190 | c_4_2 = (mean_c_sq_sq - c_2_0 * mean_c_sq - (gr_complex) 2 * pow(c_2_1,2)); 191 | 192 | // Cumulant 4_0 193 | // 194 | // Samples to the power of 4 195 | volk_32fc_s32f_power_32fc(samples_pot, samples_pot, 2, d_decimation); 196 | 197 | // Mean of samples to the power of 4 198 | gr_complex mean_tdpo4 = std::accumulate(samples_pot, samples_pot + d_decimation, gr_complex{0}) * a_factor; 199 | 200 | c_4_0 = (mean_tdpo4 - (gr_complex) 3 * pow(c_2_0,2))/pow(c_2_1,2);//normalized with c_2_1 201 | 202 | 203 | } 204 | 205 | gr_complex 206 | modulation_classifier_impl::computeCumulant_2_1(const gr_complex* samples) 207 | { 208 | gr_complex samples_norm[d_decimation]; 209 | volk_32fc_x2_multiply_conjugate_32fc(samples_norm, samples, samples, d_decimation); 210 | 211 | return std::accumulate(samples_norm, samples_norm + d_decimation, gr_complex{0}) * a_factor; 212 | } 213 | 214 | // Returns estimated phase, input: r = {2,4,8} 215 | float 216 | modulation_classifier_impl::phaseEstim(unsigned int r, float my, const gr_complex* samples) 217 | { 218 | gr_complex samples_c[d_decimation]; 219 | // square first time 220 | volk_32fc_s32f_power_32fc(samples_c, samples, 2, d_decimation); 221 | 222 | switch(r){ 223 | case 8: 224 | // square second time 225 | volk_32fc_s32f_power_32fc(samples_c, samples_c, 2, d_decimation); 226 | case 4: 227 | // square third time 228 | volk_32fc_s32f_power_32fc(samples_c, samples_c, 2, d_decimation); 229 | case 2: 230 | break; 231 | default: 232 | return(0); 233 | } 234 | 235 | gr_complex sum_to_the_r = std::accumulate(samples_c, samples_c + d_decimation, gr_complex{0}); 236 | return 1 / (float) r * std::arg(my * sum_to_the_r);; 237 | } 238 | 239 | void 240 | modulation_classifier_impl::phaseShift(gr_complex* samples_shifted, const gr_complex* samples, float phi) 241 | { 242 | lv_32fc_t scalar = lv_cmake((float)std::cos(phi), (float)std::sin(phi)); 243 | volk_32fc_s32fc_multiply_32fc(samples_shifted, samples, scalar, d_decimation); 244 | } 245 | 246 | // use real part of the cumulant, does not work properly with phase shift 247 | unsigned int 248 | modulation_classifier_impl::detMod1(gr_complex* samples_shifted, const gr_complex* samples) 249 | { 250 | // set boundries 251 | const float b1 = -1.36; 252 | const float b2 = -0.34; 253 | const float b3 = 0.5; 254 | 255 | float phi = 0; 256 | gr_complex c_4_0 = 0; 257 | gr_complex c_4_2 = 0; 258 | gr_complex c_2_1 = computeCumulant_2_1(samples); 259 | 260 | // Asume BPSK 261 | phi = phaseEstim(2, 1, samples); 262 | 263 | phaseShift(samples_shifted, samples, -phi); 264 | 265 | computeCumulant_4_0_u_4_2(c_4_0, c_4_2, samples_shifted, c_2_1); // Compute Cumulants 266 | if ( c_4_0.real() < b1) 267 | { 268 | return 3; //"BPSK" 269 | } 270 | 271 | // Asume 16QAM 272 | phi = phaseEstim(4, -0.68, samples); 273 | 274 | phaseShift(samples_shifted, samples, -phi); 275 | 276 | computeCumulant_4_0_u_4_2(c_4_0, c_4_2, samples_shifted, c_2_1); // Compute Cumulants 277 | if ( c_4_0.real() > b1 && c_4_0.real() < b2) 278 | { 279 | return 1; //"16QAM" 280 | } 281 | 282 | // Asume QPSK 283 | phi = phaseEstim(4, 1, samples); 284 | 285 | phaseShift(samples_shifted, samples, -phi); 286 | 287 | computeCumulant_4_0_u_4_2(c_4_0, c_4_2, samples_shifted, c_2_1); // Compute Cumulants 288 | if ( c_4_0.real() > b3) 289 | { 290 | return 2; //"QPSK" 291 | } 292 | 293 | // Asume 8PSK 294 | phi = phaseEstim(8, 1, samples); 295 | 296 | phaseShift(samples_shifted, samples, -phi); 297 | 298 | computeCumulant_4_0_u_4_2(c_4_0, c_4_2, samples_shifted, c_2_1); // Compute Cumulants 299 | return 0; //"8PSK" 300 | 301 | } 302 | 303 | // RECOMENDED: 304 | // use the absolute value of the cumulant 305 | // No phase shift in the first place 306 | unsigned int 307 | modulation_classifier_impl::detMod2(gr_complex* samples_shifted, const gr_complex* samples) 308 | { 309 | // set boundries 310 | const float b1 = 0.34; 311 | const float b2 = 0.84; 312 | const float b3 = 1.5; 313 | 314 | float phi = 0; 315 | gr_complex c_4_0 = 0; 316 | gr_complex c_4_2 = 0; 317 | gr_complex c_2_1 = computeCumulant_2_1(samples); 318 | 319 | computeCumulant_4_0_u_4_2(c_4_0, c_4_2, samples, c_2_1); // Compute Cumulants 320 | if (d_probe_enabled==true) { 321 | d_stored_cumu.push_back(abs(c_4_0)); 322 | } 323 | 324 | // Asume 8PSK 325 | if ( abs(c_4_0) < b1) 326 | { 327 | phi = phaseEstim(8, 1, samples); 328 | phaseShift(samples_shifted, samples, -phi); 329 | return 0; //"8PSK" 330 | } 331 | 332 | // Asume 16QAM 333 | if ( abs(c_4_0) >= b1 && abs(c_4_0) < b2) 334 | { 335 | phi = phaseEstim(4, -0.68, samples); 336 | phaseShift(samples_shifted, samples, -phi); 337 | return 1; //"16QAM" 338 | } 339 | 340 | // Asume QPSK 341 | if ( abs(c_4_0) >= b2 && abs(c_4_0) < b3) 342 | { 343 | phi = phaseEstim(4, 1, samples); 344 | phaseShift(samples_shifted, samples, -phi); 345 | return 2; //"QPSK" 346 | } 347 | 348 | // Asume BPSK 349 | phi = phaseEstim(2, 1, samples); 350 | phaseShift(samples_shifted, samples, -phi); 351 | return 3; //"BPSK" 352 | } 353 | 354 | } /* namespace cbmc */ 355 | } /* namespace gr */ 356 | 357 | -------------------------------------------------------------------------------- /lib/modulation_classifier_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 Douglas Weber. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_CBMC_MODULATION_CLASSIFIER_IMPL_H 22 | #define INCLUDED_CBMC_MODULATION_CLASSIFIER_IMPL_H 23 | 24 | #include 25 | 26 | namespace gr { 27 | namespace cbmc { 28 | 29 | class modulation_classifier_impl : public modulation_classifier 30 | { 31 | private: 32 | const int d_decimation; 33 | const float a_factor = 1.0/d_decimation; 34 | const double pi = std::acos(-1); 35 | const bool d_probe_enabled; // If enabled store last determined Modulations 36 | std::vector d_stored_mod; // Used to store last determined Modulations 37 | std::vector d_stored_cumu; // Used to store last calculated cumulants 38 | 39 | public: 40 | modulation_classifier_impl(int decimation, bool probe); 41 | ~modulation_classifier_impl(); 42 | 43 | // Where all the action really happens 44 | int work(int noutput_items, 45 | gr_vector_const_void_star &input_items, 46 | gr_vector_void_star &output_items); 47 | 48 | // Get functions 49 | std::vector get_stored_mod() const 50 | { 51 | return d_stored_mod; 52 | } 53 | 54 | std::vector get_stored_cumu() const 55 | { 56 | return d_stored_cumu; 57 | } 58 | 59 | // Reset 60 | void reset() 61 | { 62 | d_stored_mod.clear(); 63 | d_stored_cumu.clear(); 64 | } 65 | 66 | // 67 | float phaseEstim(unsigned int r, float my, const gr_complex* samples); 68 | void phaseShift(gr_complex* samples_shifted, const gr_complex* samples, float phi); 69 | void computeCumulant_4_0_u_4_2(gr_complex &c_4_0, gr_complex &c_4_2, const gr_complex* samples, gr_complex c_2_1); 70 | gr_complex computeCumulant_2_1(const gr_complex* samples); 71 | unsigned int detMod1(gr_complex* samples_shifted, const gr_complex* samples); 72 | unsigned int detMod2(gr_complex* samples_shifted, const gr_complex* samples); 73 | }; 74 | 75 | } // namespace cbmc 76 | } // namespace gr 77 | 78 | #endif /* INCLUDED_CBMC_MODULATION_CLASSIFIER_IMPL_H */ 79 | 80 | -------------------------------------------------------------------------------- /lib/my_pfb_clock_sync_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 <+YOU OR YOUR COMPANY+>. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include "my_pfb_clock_sync_impl.h" 32 | #include 33 | #include 34 | #include 35 | 36 | namespace gr { 37 | namespace cbmc { 38 | 39 | my_pfb_clock_sync::sptr 40 | my_pfb_clock_sync::make(double sps, float loop_bw, 41 | unsigned int filter_size, 42 | float init_phase, 43 | float max_rate_deviation, 44 | int osps, 45 | unsigned int det_block_size) 46 | { 47 | return gnuradio::get_initial_sptr 48 | (new my_pfb_clock_sync_impl(sps, loop_bw, 49 | filter_size, 50 | init_phase, 51 | max_rate_deviation, 52 | osps, 53 | det_block_size)); 54 | } 55 | 56 | static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; 57 | static std::vector iosig(ios, ios+sizeof(ios)/sizeof(int)); 58 | my_pfb_clock_sync_impl::my_pfb_clock_sync_impl(double sps, float loop_bw, 59 | unsigned int filter_size, 60 | float init_phase, 61 | float max_rate_deviation, 62 | int osps, 63 | unsigned int det_block_size) 64 | : block("my_pfb_clock_sync", 65 | io_signature::make(1, 1, sizeof(gr_complex)), 66 | io_signature::makev(1, 4, iosig)), 67 | d_updated(false), d_nfilters(filter_size), 68 | d_max_dev(max_rate_deviation), 69 | d_osps(osps), d_det_block_size(det_block_size), d_error(0), d_out_idx(0) 70 | { 71 | // Let scheduler adjust our relative_rate. 72 | enable_update_rate(true); 73 | 74 | d_nfilters = filter_size; 75 | 76 | // Set the damping factor for a critically damped system 77 | d_damping = 2*d_nfilters; 78 | 79 | // Set the bandwidth, which will then call update_gains() 80 | set_loop_bandwidth(loop_bw); 81 | 82 | // Store the last filter between calls to work 83 | // The accumulator keeps track of overflow to increment the stride correctly. 84 | // set it here to the fractional difference based on the initial phase 85 | d_k = init_phase; 86 | d_filtnum = (int)floor(d_k); 87 | 88 | d_filters = std::vector(d_nfilters); 89 | d_diff_filters = std::vector(d_nfilters); 90 | 91 | // Create an FIR filter for each channel and zero out the taps 92 | std::vector vtaps(1,0); 93 | for(int i = 0; i < d_nfilters; i++) { 94 | d_filters[i] = new kernel::fir_filter_ccf(1, vtaps); 95 | d_diff_filters[i] = new kernel::fir_filter_ccf(1, vtaps); 96 | } 97 | 98 | set_sps(sps); 99 | } 100 | 101 | my_pfb_clock_sync_impl::~my_pfb_clock_sync_impl() 102 | { 103 | for(int i = 0; i < d_nfilters; i++) { 104 | delete d_filters[i]; 105 | delete d_diff_filters[i]; 106 | } 107 | } 108 | 109 | bool 110 | my_pfb_clock_sync_impl::check_topology(int ninputs, int noutputs) 111 | { 112 | return noutputs == 1 || noutputs == 4; 113 | } 114 | 115 | void 116 | my_pfb_clock_sync_impl::forecast(int noutput_items, 117 | gr_vector_int &ninput_items_required) 118 | { 119 | unsigned ninputs = ninput_items_required.size (); 120 | for(unsigned i = 0; i < ninputs; i++) 121 | ninput_items_required[i] = (noutput_items + history()) * (d_sps/d_osps); 122 | } 123 | 124 | void 125 | my_pfb_clock_sync_impl::update_taps(const std::vector &taps) 126 | { 127 | d_updated_taps = taps; 128 | d_updated = true; 129 | } 130 | 131 | 132 | /******************************************************************* 133 | SET FUNCTIONS 134 | *******************************************************************/ 135 | 136 | void 137 | my_pfb_clock_sync_impl::set_loop_bandwidth(float bw) 138 | { 139 | if(bw < 0) { 140 | throw std::out_of_range("my_pfb_clock_sync: invalid bandwidth. Must be >= 0."); 141 | } 142 | 143 | d_loop_bw = bw; 144 | update_gains(); 145 | } 146 | 147 | void 148 | my_pfb_clock_sync_impl::set_damping_factor(float df) 149 | { 150 | if(df < 0 || df > 1.0) { 151 | throw std::out_of_range("my_pfb_clock_sync: invalid damping factor. Must be in [0,1]."); 152 | } 153 | 154 | d_damping = df; 155 | update_gains(); 156 | } 157 | 158 | void 159 | my_pfb_clock_sync_impl::set_alpha(float alpha) 160 | { 161 | if(alpha < 0 || alpha > 1.0) { 162 | throw std::out_of_range("my_pfb_clock_sync: invalid alpha. Must be in [0,1]."); 163 | } 164 | d_alpha = alpha; 165 | } 166 | 167 | void 168 | my_pfb_clock_sync_impl::set_beta(float beta) 169 | { 170 | if(beta < 0 || beta > 1.0) { 171 | throw std::out_of_range("my_pfb_clock_sync: invalid beta. Must be in [0,1]."); 172 | } 173 | d_beta = beta; 174 | } 175 | 176 | /******************************************************************* 177 | GET FUNCTIONS 178 | *******************************************************************/ 179 | 180 | float 181 | my_pfb_clock_sync_impl::loop_bandwidth() const 182 | { 183 | return d_loop_bw; 184 | } 185 | 186 | float 187 | my_pfb_clock_sync_impl::damping_factor() const 188 | { 189 | return d_damping; 190 | } 191 | 192 | float 193 | my_pfb_clock_sync_impl::alpha() const 194 | { 195 | return d_alpha; 196 | } 197 | 198 | float 199 | my_pfb_clock_sync_impl::beta() const 200 | { 201 | return d_beta; 202 | } 203 | 204 | float 205 | my_pfb_clock_sync_impl::clock_rate() const 206 | { 207 | return d_rate_f; 208 | } 209 | 210 | float 211 | my_pfb_clock_sync_impl::error() const 212 | { 213 | return d_error; 214 | } 215 | 216 | float 217 | my_pfb_clock_sync_impl::rate() const 218 | { 219 | return d_rate_f; 220 | } 221 | 222 | float 223 | my_pfb_clock_sync_impl::phase() const 224 | { 225 | return d_k; 226 | } 227 | 228 | /******************************************************************* 229 | *******************************************************************/ 230 | 231 | void 232 | my_pfb_clock_sync_impl::update_gains() 233 | { 234 | float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); 235 | d_alpha = (4*d_damping*d_loop_bw) / denom; 236 | d_beta = (4*d_loop_bw*d_loop_bw) / denom; 237 | } 238 | 239 | void 240 | my_pfb_clock_sync_impl::set_taps(const std::vector &newtaps, 241 | std::vector< std::vector > &ourtaps, 242 | std::vector &ourfilter) 243 | { 244 | int i,j; 245 | 246 | unsigned int ntaps = newtaps.size(); 247 | d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters); 248 | 249 | // Create d_numchan vectors to store each channel's taps 250 | ourtaps.resize(d_nfilters); 251 | 252 | // Make a vector of the taps plus fill it out with 0's to fill 253 | // each polyphase filter with exactly d_taps_per_filter 254 | std::vector tmp_taps; 255 | tmp_taps = newtaps; 256 | while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) { 257 | tmp_taps.push_back(0.0); 258 | } 259 | 260 | // Partition the filter 261 | for(i = 0; i < d_nfilters; i++) { 262 | // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out 263 | ourtaps[i] = std::vector(d_taps_per_filter, 0); 264 | for(j = 0; j < d_taps_per_filter; j++) { 265 | ourtaps[i][j] = tmp_taps[i + j*d_nfilters]; 266 | } 267 | 268 | // Build a filter for each channel and add it's taps to it 269 | ourfilter[i]->set_taps(ourtaps[i]); 270 | } 271 | 272 | // Set the history to ensure enough input items for each filter 273 | set_history(d_taps_per_filter + d_sps + d_sps); 274 | 275 | // Make sure there is enough output space for d_osps outputs/input. 276 | set_output_multiple(d_osps); 277 | } 278 | 279 | void 280 | my_pfb_clock_sync_impl::create_diff_taps(const std::vector &newtaps, 281 | std::vector &difftaps) 282 | { 283 | std::vector diff_filter(3); 284 | diff_filter[0] = -1; 285 | diff_filter[1] = 0; 286 | diff_filter[2] = 1; 287 | 288 | float pwr = 0; 289 | difftaps.clear(); 290 | difftaps.push_back(0); 291 | for(unsigned int i = 0; i < newtaps.size()-2; i++) { 292 | float tap = 0; 293 | for(unsigned int j = 0; j < diff_filter.size(); j++) { 294 | tap += diff_filter[j]*newtaps[i+j]; 295 | } 296 | difftaps.push_back(tap); 297 | pwr += fabsf(tap); 298 | } 299 | difftaps.push_back(0); 300 | 301 | // Normalize the taps 302 | for(unsigned int i = 0; i < difftaps.size(); i++) { 303 | difftaps[i] *= d_nfilters/pwr; 304 | if(difftaps[i] != difftaps[i]) { 305 | throw std::runtime_error("my_pfb_clock_sync::create_diff_taps produced NaN."); 306 | } 307 | } 308 | } 309 | 310 | std::string 311 | my_pfb_clock_sync_impl::taps_as_string() const 312 | { 313 | int i, j; 314 | std::stringstream str; 315 | str.precision(4); 316 | str.setf(std::ios::scientific); 317 | 318 | str << "[ "; 319 | for(i = 0; i < d_nfilters; i++) { 320 | str << "[" << d_taps[i][0] << ", "; 321 | for(j = 1; j < d_taps_per_filter-1; j++) { 322 | str << d_taps[i][j] << ", "; 323 | } 324 | str << d_taps[i][j] << "],"; 325 | } 326 | str << " ]" << std::endl; 327 | 328 | return str.str(); 329 | } 330 | 331 | std::string 332 | my_pfb_clock_sync_impl::diff_taps_as_string() const 333 | { 334 | int i, j; 335 | std::stringstream str; 336 | str.precision(4); 337 | str.setf(std::ios::scientific); 338 | 339 | str << "[ "; 340 | for(i = 0; i < d_nfilters; i++) { 341 | str << "[" << d_dtaps[i][0] << ", "; 342 | for(j = 1; j < d_taps_per_filter-1; j++) { 343 | str << d_dtaps[i][j] << ", "; 344 | } 345 | str << d_dtaps[i][j] << "],"; 346 | } 347 | str << " ]" << std::endl; 348 | 349 | return str.str(); 350 | } 351 | 352 | std::vector< std::vector > 353 | my_pfb_clock_sync_impl::taps() const 354 | { 355 | return d_taps; 356 | } 357 | 358 | std::vector< std::vector > 359 | my_pfb_clock_sync_impl::diff_taps() const 360 | { 361 | return d_dtaps; 362 | } 363 | 364 | std::vector 365 | my_pfb_clock_sync_impl::channel_taps(int channel) const 366 | { 367 | std::vector taps; 368 | for(int i = 0; i < d_taps_per_filter; i++) { 369 | taps.push_back(d_taps[channel][i]); 370 | } 371 | return taps; 372 | } 373 | 374 | std::vector 375 | my_pfb_clock_sync_impl::diff_channel_taps(int channel) const 376 | { 377 | std::vector taps; 378 | for(int i = 0; i < d_taps_per_filter; i++) { 379 | taps.push_back(d_dtaps[channel][i]); 380 | } 381 | return taps; 382 | } 383 | 384 | void 385 | my_pfb_clock_sync_impl::set_sps(double sps) 386 | { 387 | d_last_sps = sps; 388 | d_sps = floor(sps); 389 | 390 | d_rate = (sps-floor(sps))*(double)d_nfilters; 391 | d_rate_i = (int)floor(d_rate); 392 | d_rate_f = d_rate - (float)d_rate_i; 393 | 394 | // create new taps: rrc filter with new sps 395 | d_updated_taps = filter::firdes::root_raised_cosine(d_nfilters, d_nfilters*sps, 1.0, 0.35, 45*d_nfilters); 396 | std::vector dtaps; 397 | create_diff_taps(d_updated_taps, dtaps); 398 | set_taps(d_updated_taps, d_taps, d_filters); 399 | set_taps(dtaps, d_dtaps, d_diff_filters); 400 | 401 | 402 | set_relative_rate((float)d_osps/(float)d_sps); 403 | } 404 | 405 | int 406 | my_pfb_clock_sync_impl::general_work(int noutput_items, 407 | gr_vector_int &ninput_items, 408 | gr_vector_const_void_star &input_items, 409 | gr_vector_void_star &output_items) 410 | { 411 | gr_complex *in = (gr_complex *) input_items[0]; 412 | gr_complex *out = (gr_complex *) output_items[0]; 413 | 414 | std::vector tags; 415 | get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0) + d_det_block_size, pmt::intern("det_sps")); 416 | 417 | if(tags.size() != 0 && pmt::is_number(tags[0].value)) 418 | { 419 | float new_sps = pmt::to_double(tags[0].value); 420 | if( d_last_sps != new_sps && new_sps > 0 && new_sps < 50) 421 | { 422 | set_sps(new_sps); 423 | return 0; 424 | } 425 | } 426 | 427 | if(d_updated) { 428 | std::vector dtaps; 429 | create_diff_taps(d_updated_taps, dtaps); 430 | set_taps(d_updated_taps, d_taps, d_filters); 431 | set_taps(dtaps, d_dtaps, d_diff_filters); 432 | d_updated = false; 433 | return 0; // history requirements may have changed. 434 | } 435 | 436 | float *err = NULL, *outrate = NULL, *outk = NULL; 437 | if(output_items.size() == 4) { 438 | err = (float *) output_items[1]; 439 | outrate = (float*)output_items[2]; 440 | outk = (float*)output_items[3]; 441 | } 442 | 443 | tags.clear(); 444 | get_tags_in_range(tags, 0, nitems_read(0), 445 | nitems_read(0)+d_sps*noutput_items, 446 | pmt::intern("time_est")); 447 | 448 | int i = 0, count = 0; 449 | float error_r, error_i; 450 | 451 | // produce output as long as we can and there are enough input samples 452 | while(i < noutput_items) { 453 | if(tags.size() > 0) { 454 | size_t offset = tags[0].offset-nitems_read(0); 455 | if((offset >= (size_t)count) && (offset < (size_t)(count + d_sps))) { 456 | float center = (float)pmt::to_double(tags[0].value); 457 | d_k = (offset-count - d_sps/2.0) * d_nfilters + (M_PI*center*d_nfilters); 458 | tags.erase(tags.begin()); 459 | } 460 | } 461 | 462 | while(d_out_idx < d_osps) { 463 | 464 | d_filtnum = (int)floor(d_k); 465 | 466 | // Keep the current filter number in [0, d_nfilters] 467 | // If we've run beyond the last filter, wrap around and go to next sample 468 | // If we've gone below 0, wrap around and go to previous sample 469 | while(d_filtnum >= d_nfilters) { 470 | d_k -= d_nfilters; 471 | d_filtnum -= d_nfilters; 472 | count += 1; 473 | } 474 | while(d_filtnum < 0) { 475 | d_k += d_nfilters; 476 | d_filtnum += d_nfilters; 477 | count -= 1; 478 | } 479 | 480 | out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); 481 | d_k = d_k + d_rate_i + d_rate_f; // update phase 482 | d_out_idx++; 483 | 484 | if(output_items.size() == 4) { 485 | err[i] = d_error; 486 | outrate[i] = d_rate_f; 487 | outk[i] = d_k; 488 | } 489 | 490 | // We've run out of output items we can create; return now. 491 | if(i+d_out_idx >= noutput_items) { 492 | consume_each(count); 493 | return i; 494 | } 495 | } 496 | 497 | // reset here; if we didn't complete a full osps samples last time, 498 | // the early return would take care of it. 499 | d_out_idx = 0; 500 | 501 | // Update the phase and rate estimates for this symbol 502 | gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]); 503 | error_r = out[i].real() * diff.real(); 504 | error_i = out[i].imag() * diff.imag(); 505 | d_error = (error_i + error_r) / 2.0; // average error from I&Q channel 506 | 507 | // Run the control loop to update the current phase (k) and 508 | // tracking rate estimates based on the error value 509 | // Interpolating here to update rates for ever sps. 510 | for(int s = 0; s < d_sps; s++) { 511 | d_rate_f = d_rate_f + d_beta*d_error; 512 | d_k = d_k + d_rate_f + d_alpha*d_error; 513 | } 514 | 515 | // Keep our rate within a good range 516 | d_rate_f = gr::branchless_clip(d_rate_f, d_max_dev); 517 | 518 | i+=d_osps; 519 | count += (int)floor(d_sps); 520 | } 521 | 522 | consume_each(count); 523 | return i; 524 | } 525 | 526 | void 527 | my_pfb_clock_sync_impl::setup_rpc() 528 | { 529 | #ifdef GR_CTRLPORT 530 | // Getters 531 | add_rpc_variable( 532 | rpcbasic_sptr(new rpcbasic_register_get( 533 | alias(), "error", 534 | &my_pfb_clock_sync::error, 535 | pmt::mp(-2.0f), pmt::mp(2.0f), pmt::mp(0.0f), 536 | "", "Error signal of loop", RPC_PRIVLVL_MIN, 537 | DISPTIME | DISPOPTSTRIP))); 538 | 539 | add_rpc_variable( 540 | rpcbasic_sptr(new rpcbasic_register_get( 541 | alias(), "rate", 542 | &my_pfb_clock_sync::rate, 543 | pmt::mp(-2.0f), pmt::mp(2.0f), pmt::mp(0.0f), 544 | "", "Rate change of phase", RPC_PRIVLVL_MIN, 545 | DISPTIME | DISPOPTSTRIP))); 546 | 547 | add_rpc_variable( 548 | rpcbasic_sptr(new rpcbasic_register_get( 549 | alias(), "phase", 550 | &my_pfb_clock_sync::phase, 551 | pmt::mp(0), pmt::mp((int)d_nfilters), pmt::mp(0), 552 | "", "Current filter phase arm", RPC_PRIVLVL_MIN, 553 | DISPTIME | DISPOPTSTRIP))); 554 | 555 | add_rpc_variable( 556 | rpcbasic_sptr(new rpcbasic_register_get( 557 | alias(), "loop bw", 558 | &my_pfb_clock_sync::loop_bandwidth, 559 | pmt::mp(0.0f), pmt::mp(1.0f), pmt::mp(0.0f), 560 | "", "Loop bandwidth", 561 | RPC_PRIVLVL_MIN, DISPNULL))); 562 | 563 | // Setters 564 | add_rpc_variable( 565 | rpcbasic_sptr(new rpcbasic_register_set( 566 | alias(), "loop bw", 567 | &my_pfb_clock_sync::set_loop_bandwidth, 568 | pmt::mp(0.0f), pmt::mp(1.0f), pmt::mp(0.0f), 569 | "", "Loop bandwidth", 570 | RPC_PRIVLVL_MIN, DISPNULL))); 571 | #endif /* GR_CTRLPORT */ 572 | } 573 | 574 | } /* namespace cbmc */ 575 | } /* namespace gr */ 576 | 577 | -------------------------------------------------------------------------------- /lib/my_pfb_clock_sync_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2016 <+YOU OR YOUR COMPANY+>. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | 22 | #ifndef INCLUDED_CBMC_MY_PFB_CLOCK_SYNC_IMPL_H 23 | #define INCLUDED_CBMC_MY_PFB_CLOCK_SYNC_IMPL_H 24 | 25 | #include 26 | 27 | using namespace gr::filter; 28 | 29 | namespace gr { 30 | namespace cbmc { 31 | 32 | class my_pfb_clock_sync_impl : public my_pfb_clock_sync 33 | { 34 | private: 35 | unsigned int d_det_block_size; 36 | bool d_updated; 37 | double d_sps; 38 | double d_last_sps; 39 | double d_sample_num; 40 | float d_loop_bw; 41 | float d_damping; 42 | float d_alpha; 43 | float d_beta; 44 | 45 | int d_nfilters; 46 | int d_taps_per_filter; 47 | std::vector d_filters; 48 | std::vector d_diff_filters; 49 | std::vector d_init_taps; 50 | std::vector< std::vector > d_taps; 51 | std::vector< std::vector > d_dtaps; 52 | std::vector d_updated_taps; 53 | 54 | float d_init_phase; 55 | float d_k; 56 | float d_rate; 57 | float d_rate_i; 58 | float d_rate_f; 59 | float d_max_dev; 60 | int d_filtnum; 61 | int d_osps; 62 | float d_error; 63 | int d_out_idx; 64 | 65 | void create_diff_taps(const std::vector &newtaps, 66 | std::vector &difftaps); 67 | 68 | public: 69 | my_pfb_clock_sync_impl(double sps, float loop_bw, 70 | unsigned int filter_size=32, 71 | float init_phase=0, 72 | float max_rate_deviation=1.5, 73 | int osps=1, 74 | unsigned int det_block_size=10000); 75 | ~my_pfb_clock_sync_impl(); 76 | 77 | void setup_rpc(); 78 | 79 | void update_gains(); 80 | 81 | void forecast(int noutput_items, gr_vector_int &ninput_items_required); 82 | 83 | void update_taps(const std::vector &taps); 84 | 85 | void set_taps(const std::vector &taps, 86 | std::vector< std::vector > &ourtaps, 87 | std::vector &ourfilter); 88 | 89 | void set_sps(double new_sps); 90 | 91 | std::vector< std::vector > taps() const; 92 | std::vector< std::vector > diff_taps() const; 93 | std::vector channel_taps(int channel) const; 94 | std::vector diff_channel_taps(int channel) const; 95 | std::string taps_as_string() const; 96 | std::string diff_taps_as_string() const; 97 | 98 | void set_loop_bandwidth(float bw); 99 | void set_damping_factor(float df); 100 | void set_alpha(float alpha); 101 | void set_beta(float beta); 102 | void set_max_rate_deviation(float m) 103 | { 104 | d_max_dev = m; 105 | } 106 | 107 | float loop_bandwidth() const; 108 | float damping_factor() const; 109 | float alpha() const; 110 | float beta() const; 111 | float clock_rate() const; 112 | 113 | float error() const; 114 | float rate() const; 115 | float phase() const; 116 | 117 | 118 | /******************************************************************* 119 | *******************************************************************/ 120 | 121 | bool check_topology(int ninputs, int noutputs); 122 | 123 | int general_work(int noutput_items, 124 | gr_vector_int &ninput_items, 125 | gr_vector_const_void_star &input_items, 126 | gr_vector_void_star &output_items); 127 | }; 128 | 129 | } // namespace cbmc 130 | } // namespace gr 131 | 132 | #endif /* INCLUDED_CBMC_MY_PFB_CLOCK_SYNC_IMPL_H */ 133 | 134 | -------------------------------------------------------------------------------- /lib/qa_cbmc.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * GNU Radio is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3, or (at your option) 9 | * any later version. 10 | * 11 | * GNU Radio is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with GNU Radio; see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | /* 23 | * This class gathers together all the test cases for the gr-filter 24 | * directory into a single test suite. As you create new test cases, 25 | * add them here. 26 | */ 27 | 28 | #include "qa_cbmc.h" 29 | 30 | CppUnit::TestSuite * 31 | qa_cbmc::suite() 32 | { 33 | CppUnit::TestSuite *s = new CppUnit::TestSuite("cbmc"); 34 | 35 | return s; 36 | } 37 | -------------------------------------------------------------------------------- /lib/qa_cbmc.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2012 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifndef _QA_CBMC_H_ 24 | #define _QA_CBMC_H_ 25 | 26 | #include 27 | #include 28 | 29 | //! collect all the tests for the gr-filter directory 30 | 31 | class __GR_ATTR_EXPORT qa_cbmc 32 | { 33 | public: 34 | //! return suite of tests for all of gr-filter directory 35 | static CppUnit::TestSuite *suite(); 36 | }; 37 | 38 | #endif /* _QA_CBMC_H_ */ 39 | -------------------------------------------------------------------------------- /lib/test_cbmc.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2012 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include "qa_cbmc.h" 32 | #include 33 | #include 34 | 35 | int 36 | main (int argc, char **argv) 37 | { 38 | CppUnit::TextTestRunner runner; 39 | std::ofstream xmlfile(get_unittest_path("cbmc.xml").c_str()); 40 | CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile); 41 | 42 | runner.addTest(qa_cbmc::suite()); 43 | runner.setOutputter(xmlout); 44 | 45 | bool was_successful = runner.run("", false); 46 | 47 | return was_successful ? 0 : 1; 48 | } 49 | -------------------------------------------------------------------------------- /pic_example_flowgraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/pic_example_flowgraph.png -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Include python install macros 22 | ######################################################################## 23 | include(GrPython) 24 | if(NOT PYTHONINTERP_FOUND) 25 | return() 26 | endif() 27 | 28 | ######################################################################## 29 | # Install python sources 30 | ######################################################################## 31 | GR_PYTHON_INSTALL( 32 | FILES 33 | __init__.py 34 | DESTINATION ${GR_PYTHON_DIR}/cbmc 35 | ) 36 | 37 | ######################################################################## 38 | # Handle the unit tests 39 | ######################################################################## 40 | include(GrTest) 41 | 42 | set(GR_TEST_TARGET_DEPS gnuradio-cbmc) 43 | set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) 44 | GR_ADD_TEST(qa_my_pfb_clock_sync ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_my_pfb_clock_sync.py) 45 | -------------------------------------------------------------------------------- /python/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008,2009 Free Software Foundation, Inc. 3 | # 4 | # This application is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation; either version 3, or (at your option) 7 | # any later version. 8 | # 9 | # This application is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along 15 | # with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | 19 | # The presence of this file turns this directory into a Python package 20 | 21 | ''' 22 | This is the GNU Radio CBMC module. Place your Python package 23 | description here (python/__init__.py). 24 | ''' 25 | 26 | # import swig generated symbols into the cbmc namespace 27 | try: 28 | # this might fail if the module is python-only 29 | from cbmc_swig import * 30 | except ImportError: 31 | pass 32 | 33 | # import any pure python here 34 | # 35 | -------------------------------------------------------------------------------- /python/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/python/__init__.pyc -------------------------------------------------------------------------------- /python/build_utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2004,2009,2012 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | """Misc utilities used at build time 23 | """ 24 | 25 | import re, os, os.path 26 | from build_utils_codes import * 27 | 28 | 29 | # set srcdir to the directory that contains Makefile.am 30 | try: 31 | srcdir = os.environ['srcdir'] 32 | except KeyError, e: 33 | srcdir = "." 34 | srcdir = srcdir + '/' 35 | 36 | # set do_makefile to either true or false dependeing on the environment 37 | try: 38 | if os.environ['do_makefile'] == '0': 39 | do_makefile = False 40 | else: 41 | do_makefile = True 42 | except KeyError, e: 43 | do_makefile = False 44 | 45 | # set do_sources to either true or false dependeing on the environment 46 | try: 47 | if os.environ['do_sources'] == '0': 48 | do_sources = False 49 | else: 50 | do_sources = True 51 | except KeyError, e: 52 | do_sources = True 53 | 54 | name_dict = {} 55 | 56 | def log_output_name (name): 57 | (base, ext) = os.path.splitext (name) 58 | ext = ext[1:] # drop the leading '.' 59 | 60 | entry = name_dict.setdefault (ext, []) 61 | entry.append (name) 62 | 63 | def open_and_log_name (name, dir): 64 | global do_sources 65 | if do_sources: 66 | f = open (name, dir) 67 | else: 68 | f = None 69 | log_output_name (name) 70 | return f 71 | 72 | def expand_template (d, template_filename, extra = ""): 73 | '''Given a dictionary D and a TEMPLATE_FILENAME, expand template into output file 74 | ''' 75 | global do_sources 76 | output_extension = extract_extension (template_filename) 77 | template = open_src (template_filename, 'r') 78 | output_name = d['NAME'] + extra + '.' + output_extension 79 | log_output_name (output_name) 80 | if do_sources: 81 | output = open (output_name, 'w') 82 | do_substitution (d, template, output) 83 | output.close () 84 | template.close () 85 | 86 | def output_glue (dirname): 87 | output_makefile_fragment () 88 | output_ifile_include (dirname) 89 | 90 | def output_makefile_fragment (): 91 | global do_makefile 92 | if not do_makefile: 93 | return 94 | # overwrite the source, which must be writable; this should have been 95 | # checked for beforehand in the top-level Makefile.gen.gen . 96 | f = open (os.path.join (os.environ.get('gendir', os.environ.get('srcdir', '.')), 'Makefile.gen'), 'w') 97 | f.write ('#\n# This file is machine generated. All edits will be overwritten\n#\n') 98 | output_subfrag (f, 'h') 99 | output_subfrag (f, 'i') 100 | output_subfrag (f, 'cc') 101 | f.close () 102 | 103 | def output_ifile_include (dirname): 104 | global do_sources 105 | if do_sources: 106 | f = open ('%s_generated.i' % (dirname,), 'w') 107 | f.write ('//\n// This file is machine generated. All edits will be overwritten\n//\n') 108 | files = name_dict.setdefault ('i', []) 109 | files.sort () 110 | f.write ('%{\n') 111 | for file in files: 112 | f.write ('#include <%s>\n' % (file[0:-1] + 'h',)) 113 | f.write ('%}\n\n') 114 | for file in files: 115 | f.write ('%%include <%s>\n' % (file,)) 116 | 117 | def output_subfrag (f, ext): 118 | files = name_dict.setdefault (ext, []) 119 | files.sort () 120 | f.write ("GENERATED_%s =" % (ext.upper ())) 121 | for file in files: 122 | f.write (" \\\n\t%s" % (file,)) 123 | f.write ("\n\n") 124 | 125 | def extract_extension (template_name): 126 | # template name is something like: GrFIRfilterXXX.h.t 127 | # we return everything between the penultimate . and .t 128 | mo = re.search (r'\.([a-z]+)\.t$', template_name) 129 | if not mo: 130 | raise ValueError, "Incorrectly formed template_name '%s'" % (template_name,) 131 | return mo.group (1) 132 | 133 | def open_src (name, mode): 134 | global srcdir 135 | return open (os.path.join (srcdir, name), mode) 136 | 137 | def do_substitution (d, in_file, out_file): 138 | def repl (match_obj): 139 | key = match_obj.group (1) 140 | # print key 141 | return d[key] 142 | 143 | inp = in_file.read () 144 | out = re.sub (r"@([a-zA-Z0-9_]+)@", repl, inp) 145 | out_file.write (out) 146 | 147 | 148 | 149 | copyright = '''/* -*- c++ -*- */ 150 | /* 151 | * Copyright 2003,2004 Free Software Foundation, Inc. 152 | * 153 | * This file is part of GNU Radio 154 | * 155 | * GNU Radio is free software; you can redistribute it and/or modify 156 | * it under the terms of the GNU General Public License as published by 157 | * the Free Software Foundation; either version 3, or (at your option) 158 | * any later version. 159 | * 160 | * GNU Radio is distributed in the hope that it will be useful, 161 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 162 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 163 | * GNU General Public License for more details. 164 | * 165 | * You should have received a copy of the GNU General Public License 166 | * along with GNU Radio; see the file COPYING. If not, write to 167 | * the Free Software Foundation, Inc., 51 Franklin Street, 168 | * Boston, MA 02110-1301, USA. 169 | */ 170 | ''' 171 | 172 | def is_complex (code3): 173 | if i_code (code3) == 'c' or o_code (code3) == 'c': 174 | return '1' 175 | else: 176 | return '0' 177 | 178 | 179 | def standard_dict (name, code3, package='gr'): 180 | d = {} 181 | d['NAME'] = name 182 | d['NAME_IMPL'] = name+'_impl' 183 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) 184 | d['GUARD_NAME_IMPL'] = 'INCLUDED_%s_%s_IMPL_H' % (package.upper(), name.upper()) 185 | d['BASE_NAME'] = re.sub ('^' + package + '_', '', name) 186 | d['SPTR_NAME'] = '%s_sptr' % name 187 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' 188 | d['COPYRIGHT'] = copyright 189 | d['TYPE'] = i_type (code3) 190 | d['I_TYPE'] = i_type (code3) 191 | d['O_TYPE'] = o_type (code3) 192 | d['TAP_TYPE'] = tap_type (code3) 193 | d['IS_COMPLEX'] = is_complex (code3) 194 | return d 195 | 196 | 197 | def standard_dict2 (name, code3, package): 198 | d = {} 199 | d['NAME'] = name 200 | d['BASE_NAME'] = name 201 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) 202 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' 203 | d['COPYRIGHT'] = copyright 204 | d['TYPE'] = i_type (code3) 205 | d['I_TYPE'] = i_type (code3) 206 | d['O_TYPE'] = o_type (code3) 207 | d['TAP_TYPE'] = tap_type (code3) 208 | d['IS_COMPLEX'] = is_complex (code3) 209 | return d 210 | 211 | def standard_impl_dict2 (name, code3, package): 212 | d = {} 213 | d['NAME'] = name 214 | d['IMPL_NAME'] = name 215 | d['BASE_NAME'] = name.rstrip("impl").rstrip("_") 216 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) 217 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' 218 | d['COPYRIGHT'] = copyright 219 | d['FIR_TYPE'] = "fir_filter_" + code3 220 | d['CFIR_TYPE'] = "fir_filter_" + code3[0:2] + 'c' 221 | d['TYPE'] = i_type (code3) 222 | d['I_TYPE'] = i_type (code3) 223 | d['O_TYPE'] = o_type (code3) 224 | d['TAP_TYPE'] = tap_type (code3) 225 | d['IS_COMPLEX'] = is_complex (code3) 226 | return d 227 | -------------------------------------------------------------------------------- /python/build_utils.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/python/build_utils.pyc -------------------------------------------------------------------------------- /python/build_utils_codes.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2004 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | def i_code (code3): 23 | return code3[0] 24 | 25 | def o_code (code3): 26 | if len (code3) >= 2: 27 | return code3[1] 28 | else: 29 | return code3[0] 30 | 31 | def tap_code (code3): 32 | if len (code3) >= 3: 33 | return code3[2] 34 | else: 35 | return code3[0] 36 | 37 | def i_type (code3): 38 | return char_to_type[i_code (code3)] 39 | 40 | def o_type (code3): 41 | return char_to_type[o_code (code3)] 42 | 43 | def tap_type (code3): 44 | return char_to_type[tap_code (code3)] 45 | 46 | 47 | char_to_type = {} 48 | char_to_type['s'] = 'short' 49 | char_to_type['i'] = 'int' 50 | char_to_type['f'] = 'float' 51 | char_to_type['c'] = 'gr_complex' 52 | char_to_type['b'] = 'unsigned char' 53 | -------------------------------------------------------------------------------- /python/build_utils_codes.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-cel/gr-cbmc/c90d7f0b43b1236f0c5199b6e2491a9f803cc86d/python/build_utils_codes.pyc -------------------------------------------------------------------------------- /swig/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Check if there is C++ code at all 22 | ######################################################################## 23 | if(NOT cbmc_sources) 24 | MESSAGE(STATUS "No C++ sources... skipping swig/") 25 | return() 26 | endif(NOT cbmc_sources) 27 | 28 | ######################################################################## 29 | # Include swig generation macros 30 | ######################################################################## 31 | find_package(SWIG) 32 | find_package(PythonLibs 2) 33 | if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND) 34 | return() 35 | endif() 36 | include(GrSwig) 37 | include(GrPython) 38 | 39 | ######################################################################## 40 | # Setup swig generation 41 | ######################################################################## 42 | foreach(incdir ${GNURADIO_RUNTIME_INCLUDE_DIRS}) 43 | list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gnuradio/swig) 44 | endforeach(incdir) 45 | 46 | set(GR_SWIG_LIBRARIES gnuradio-cbmc) 47 | set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/cbmc_swig_doc.i) 48 | set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include) 49 | 50 | GR_SWIG_MAKE(cbmc_swig cbmc_swig.i) 51 | 52 | ######################################################################## 53 | # Install the build swig module 54 | ######################################################################## 55 | GR_SWIG_INSTALL(TARGETS cbmc_swig DESTINATION ${GR_PYTHON_DIR}/cbmc) 56 | 57 | ######################################################################## 58 | # Install swig .i files for development 59 | ######################################################################## 60 | install( 61 | FILES 62 | cbmc_swig.i 63 | ${CMAKE_CURRENT_BINARY_DIR}/cbmc_swig_doc.i 64 | DESTINATION ${GR_INCLUDE_DIR}/cbmc/swig 65 | ) 66 | -------------------------------------------------------------------------------- /swig/cbmc_swig.i: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | 3 | #define CBMC_API 4 | 5 | %include "gnuradio.i" // the common stuff 6 | 7 | //load generated python docstrings 8 | %include "cbmc_swig_doc.i" 9 | 10 | %{ 11 | #include "cbmc/modulation_classifier.h" 12 | #include "cbmc/freq_sps_det.h" 13 | #include "cbmc/my_pfb_clock_sync.h" 14 | %} 15 | 16 | 17 | %include "cbmc/modulation_classifier.h" 18 | GR_SWIG_BLOCK_MAGIC2(cbmc, modulation_classifier); 19 | %include "cbmc/freq_sps_det.h" 20 | GR_SWIG_BLOCK_MAGIC2(cbmc, freq_sps_det); 21 | %include "cbmc/my_pfb_clock_sync.h" 22 | GR_SWIG_BLOCK_MAGIC2(cbmc, my_pfb_clock_sync); 23 | --------------------------------------------------------------------------------