├── examples ├── README └── top_block.py ├── docs ├── doxygen │ ├── other │ │ ├── group_defs.dox │ │ └── main_page.dox │ ├── doxyxml │ │ ├── generated │ │ │ ├── __init__.py │ │ │ ├── index.py │ │ │ └── indexsuper.py │ │ ├── text.py │ │ ├── __init__.py │ │ ├── base.py │ │ └── doxyindex.py │ ├── CMakeLists.txt │ └── swig_doc.py ├── README.devsync └── CMakeLists.txt ├── swig ├── devsync_swig.i └── CMakeLists.txt ├── grc ├── devsync_alligner.xml ├── devsync_rms_normalization.xml ├── CMakeLists.txt └── devsync_peak_detector.xml ├── cmake ├── Modules │ ├── devsyncConfig.cmake │ ├── FindCppUnit.cmake │ ├── FindGnuradioRuntime.cmake │ ├── GrPlatform.cmake │ ├── GrTest.cmake │ ├── CMakeParseArgumentsCopy.cmake │ ├── GrPython.cmake │ ├── GrSwig.cmake │ └── UseSWIG.cmake └── cmake_uninstall.cmake.in ├── apps └── CMakeLists.txt ├── include └── devsync │ ├── CMakeLists.txt │ ├── api.h │ ├── log.h │ ├── alligner.h │ ├── rms_normalization.h │ └── peak_detector.h ├── python ├── __init__.py ├── build_utils_codes.py ├── CMakeLists.txt └── build_utils.py ├── lib ├── rms_normalization_impl.h ├── peak_detector_impl.h ├── alligner_impl.h ├── CMakeLists.txt ├── rms_normalization_impl.cc ├── alligner_impl.cc └── peak_detector_impl.cc ├── README.md └── CMakeLists.txt /examples/README: -------------------------------------------------------------------------------- 1 | It is considered good practice to add examples in here to demonstrate the 2 | functionality of your OOT module. Python scripts, GRC flow graphs or other 3 | code can go here. 4 | 5 | -------------------------------------------------------------------------------- /docs/doxygen/other/group_defs.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | * \defgroup block GNU Radio DEVSYNC C++ Signal Processing Blocks 3 | * \brief All C++ blocks that can be used from the DEVSYNC GNU Radio 4 | * module are listed here or in the subcategories below. 5 | * 6 | */ 7 | 8 | -------------------------------------------------------------------------------- /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/other/main_page.dox: -------------------------------------------------------------------------------- 1 | /*! \mainpage 2 | 3 | Welcome to the GNU Radio DEVSYNC Block 4 | 5 | This is the intro page for the Doxygen manual generated for the DEVSYNC 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/README.devsync: -------------------------------------------------------------------------------- 1 | This is the devsync-write-a-block package meant as a guide to building 2 | out-of-tree packages. To use the devsync blocks, the Python namespaces 3 | is in 'devsync', which is imported as: 4 | 5 | import devsync 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(devsync) 12 | -------------------------------------------------------------------------------- /swig/devsync_swig.i: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | 3 | #define DEVSYNC_API 4 | 5 | %include "gnuradio.i" // the common stuff 6 | 7 | //load generated python docstrings 8 | %include "devsync_swig_doc.i" 9 | 10 | %{ 11 | #include "devsync/alligner.h" 12 | #include "devsync/peak_detector.h" 13 | #include "devsync/rms_normalization.h" 14 | %} 15 | 16 | 17 | %include "devsync/alligner.h" 18 | GR_SWIG_BLOCK_MAGIC2(devsync, alligner); 19 | %include "devsync/peak_detector.h" 20 | GR_SWIG_BLOCK_MAGIC2(devsync, peak_detector); 21 | %include "devsync/rms_normalization.h" 22 | GR_SWIG_BLOCK_MAGIC2(devsync, rms_normalization); 23 | -------------------------------------------------------------------------------- /grc/devsync_alligner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | alligner 4 | devsync_alligner 5 | [devsync] 6 | import devsync 7 | devsync.alligner($num_streams) 8 | 9 | Number of streams 10 | num_streams 11 | int 12 | 13 | 14 | in 15 | complex 16 | $num_streams 17 | 18 | 19 | phase_init 20 | message 21 | 22 | 23 | out 24 | complex 25 | $num_streams 26 | 27 | 28 | -------------------------------------------------------------------------------- /grc/devsync_rms_normalization.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rms_normalization 4 | devsync_rms_normalization 5 | [devsync] 6 | import devsync 7 | devsync.rms_normalization($num_streams, $vlen) 8 | 9 | Num Streams 10 | num_streams 11 | 2 12 | int 13 | 14 | 15 | Vec Length 16 | vlen 17 | 1 18 | int 19 | 20 | 21 | in 22 | complex 23 | $vlen 24 | $num_streams 25 | 26 | 27 | out 28 | complex 29 | $vlen 30 | $num_streams 31 | 32 | 33 | -------------------------------------------------------------------------------- /cmake/Modules/devsyncConfig.cmake: -------------------------------------------------------------------------------- 1 | INCLUDE(FindPkgConfig) 2 | PKG_CHECK_MODULES(PC_DEVSYNC devsync) 3 | 4 | FIND_PATH( 5 | DEVSYNC_INCLUDE_DIRS 6 | NAMES devsync/api.h 7 | HINTS $ENV{DEVSYNC_DIR}/include 8 | ${PC_DEVSYNC_INCLUDEDIR} 9 | PATHS ${CMAKE_INSTALL_PREFIX}/include 10 | /usr/local/include 11 | /usr/include 12 | ) 13 | 14 | FIND_LIBRARY( 15 | DEVSYNC_LIBRARIES 16 | NAMES gnuradio-devsync 17 | HINTS $ENV{DEVSYNC_DIR}/lib 18 | ${PC_DEVSYNC_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(DEVSYNC DEFAULT_MSG DEVSYNC_LIBRARIES DEVSYNC_INCLUDE_DIRS) 29 | MARK_AS_ADVANCED(DEVSYNC_LIBRARIES DEVSYNC_INCLUDE_DIRS) 30 | 31 | -------------------------------------------------------------------------------- /apps/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 | include(GrPython) 21 | 22 | GR_PYTHON_INSTALL( 23 | PROGRAMS 24 | DESTINATION bin 25 | ) 26 | -------------------------------------------------------------------------------- /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 | devsync_alligner.xml 22 | devsync_peak_detector.xml 23 | devsync_rms_normalization.xml DESTINATION share/gnuradio/grc/blocks 24 | ) 25 | -------------------------------------------------------------------------------- /grc/devsync_peak_detector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | peak_detector 4 | devsync_peak_detector 5 | [devsync] 6 | import devsync 7 | devsync.peak_detector($num_streams, $win, $scale, $inf, $disc_samp) 8 | 9 | Num Streams 10 | num_streams 11 | 2 12 | int 13 | 14 | 15 | Window 16 | win 17 | 100 18 | int 19 | 20 | 21 | Discarted Samples 22 | disc_samp 23 | 100 24 | int 25 | 26 | 27 | Scale 28 | scale 29 | 1 30 | float 31 | 32 | 33 | Influence 34 | inf 35 | 0 36 | float 37 | 38 | 39 | in 40 | complex 41 | $num_streams 42 | 43 | 44 | shifts_out 45 | message 46 | 47 | 48 | -------------------------------------------------------------------------------- /include/devsync/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 | alligner.h 26 | peak_detector.h 27 | log.h 28 | rms_normalization.h DESTINATION include/devsync 29 | ) 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 DEVSYNC module. Place your Python package 23 | description here (python/__init__.py). 24 | ''' 25 | 26 | # import swig generated symbols into the devsync namespace 27 | try: 28 | # this might fail if the module is python-only 29 | from devsync_swig import * 30 | except ImportError: 31 | pass 32 | 33 | # import any pure python here 34 | # 35 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /include/devsync/api.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifndef INCLUDED_DEVSYNC_API_H 21 | #define INCLUDED_DEVSYNC_API_H 22 | 23 | #include 24 | 25 | #ifdef gnuradio_devsync_EXPORTS 26 | # define DEVSYNC_API __GR_ATTR_EXPORT 27 | #else 28 | # define DEVSYNC_API __GR_ATTR_IMPORT 29 | #endif 30 | 31 | typedef enum{ 32 | NO_SYNC=0, 33 | PREAMBLE=1, 34 | POST_PREAMBLE=2, 35 | SYNC=3, 36 | IN_SYNC=4, 37 | }state; 38 | 39 | typedef enum{ 40 | SYNCING=0, 41 | FIRST_SYNC_NOW=1, 42 | FIRST_SYNC_FOUND=2, 43 | FIRST_BUFFER_FILL=3, 44 | SYNCED=4, 45 | NO_PHASE_DIFF=5, 46 | FINE_SYNC=6, 47 | WINDOW_FILL=7, 48 | FIRST_SYNCING=8 49 | }overall_state; 50 | 51 | #define ENABLE_DEBUG_MSG 1 52 | #endif /* INCLUDED_DEVSYNC_API_H */ 53 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/rms_normalization_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifndef INCLUDED_DEVSYNC_RMS_NORMALIZATION_IMPL_H 21 | #define INCLUDED_DEVSYNC_RMS_NORMALIZATION_IMPL_H 22 | 23 | #include 24 | 25 | namespace gr 26 | { 27 | namespace devsync 28 | { 29 | 30 | class rms_normalization_impl : public rms_normalization 31 | { 32 | private: 33 | size_t d_vlen; 34 | size_t d_num_streams; 35 | 36 | public: 37 | rms_normalization_impl (size_t num_streams, size_t vlen); 38 | ~rms_normalization_impl (); 39 | 40 | int 41 | work (int noutput_items, gr_vector_const_void_star &input_items, 42 | gr_vector_void_star &output_items); 43 | }; 44 | 45 | } // namespace devsync 46 | } // namespace gr 47 | 48 | #endif /* INCLUDED_DEVSYNC_RMS_NORMALIZATION_IMPL_H */ 49 | 50 | -------------------------------------------------------------------------------- /include/devsync/log.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifndef LOG_H_ 21 | #define LOG_H_ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | //#if ENABLE_DEBUG_MSG 31 | #define LOG_INFO(M, ...) \ 32 | fprintf(stderr, "[INFO]: " M " \n", ##__VA_ARGS__) 33 | 34 | //#else 35 | //#define LOG_INFO(M, ...) 36 | //#endif 37 | 38 | #define LOG_ERROR(M, ...) \ 39 | fprintf(stderr, "[ERROR] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) 40 | 41 | #define LOG_WARN(M, ...) \ 42 | fprintf(stderr, "[WARNING] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) 43 | 44 | #if ENABLE_DEBUG_MSG 45 | #define LOG_DEBUG(M, ...) \ 46 | fprintf(stderr, "[DEBUG]: " M "\n", ##__VA_ARGS__) 47 | #else 48 | #define LOG_DEBUG(M, ...) 49 | #endif 50 | 51 | 52 | #endif /* UTILS_LOG_H_ */ 53 | -------------------------------------------------------------------------------- /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}/devsync 35 | ) 36 | 37 | ######################################################################## 38 | # Handle the unit tests 39 | ######################################################################## 40 | include(GrTest) 41 | 42 | set(GR_TEST_TARGET_DEPS gnuradio-devsync) 43 | set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) 44 | -------------------------------------------------------------------------------- /include/devsync/alligner.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | 21 | #ifndef INCLUDED_DEVSYNC_ALLIGNER_H 22 | #define INCLUDED_DEVSYNC_ALLIGNER_H 23 | 24 | #include 25 | #include 26 | 27 | namespace gr { 28 | namespace devsync { 29 | 30 | /*! 31 | * \brief Sample alligner block 32 | * \ingroup devsync 33 | * 34 | * \details 35 | * This block alligns the samples of the receiving streams 36 | * according to the information provided by the peak detector 37 | * block. One stream is taken as the reference stream, and 38 | * an offset is applied to the rest of the streams so that 39 | * they become alligned in phase. 40 | */ 41 | class DEVSYNC_API alligner : virtual public gr::sync_block 42 | { 43 | public: 44 | typedef boost::shared_ptr sptr; 45 | 46 | /*! 47 | * Build the alligner block 48 | * 49 | * \param num_streams (size_t) Total number of receiving streams 50 | */ 51 | static sptr make(size_t num_streams); 52 | }; 53 | 54 | } // namespace devsync 55 | } // namespace gr 56 | 57 | #endif /* INCLUDED_DEVSYNC_ALLIGNER_H */ 58 | 59 | -------------------------------------------------------------------------------- /include/devsync/rms_normalization.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | 21 | #ifndef INCLUDED_DEVSYNC_RMS_NORMALIZATION_H 22 | #define INCLUDED_DEVSYNC_RMS_NORMALIZATION_H 23 | 24 | #include 25 | #include 26 | 27 | namespace gr { 28 | namespace devsync { 29 | 30 | /*! 31 | * \brief RMS normalization block 32 | * \ingroup devsync 33 | * 34 | *\details 35 | * This block performs a simple RMS normalization method to bring 36 | * the amplitudes of all receiving channels at the same level for 37 | * effective peak detection. 38 | */ 39 | class DEVSYNC_API rms_normalization : virtual public gr::sync_block 40 | { 41 | public: 42 | typedef boost::shared_ptr sptr; 43 | 44 | /*! 45 | * Build the RMS normalization block 46 | * 47 | * \param num_streams (size_t) Total number of receiving streams 48 | * \param vlen (size_t) Length of window over which the normalization 49 | * will take place. 50 | * 51 | */ 52 | static sptr make(size_t num_streams, size_t vlen); 53 | }; 54 | 55 | } // namespace devsync 56 | } // namespace gr 57 | 58 | #endif /* INCLUDED_DEVSYNC_RMS_NORMALIZATION_H */ 59 | 60 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | 55 | ######################################################################## 56 | # Detect /lib versus /lib64 57 | ######################################################################## 58 | if (CMAKE_INSTALL_LIBDIR MATCHES lib64) 59 | set(LIB_SUFFIX 64) 60 | endif() 61 | 62 | set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix") 63 | -------------------------------------------------------------------------------- /lib/peak_detector_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifndef INCLUDED_DEVSYNC_PEAK_DETECTOR_IMPL_H 21 | #define INCLUDED_DEVSYNC_PEAK_DETECTOR_IMPL_H 22 | 23 | #include 24 | #include 25 | namespace gr 26 | { 27 | namespace devsync 28 | { 29 | 30 | class peak_detector_impl : public peak_detector 31 | { 32 | private: 33 | size_t d_num_streams; 34 | size_t d_window; 35 | float d_scale; 36 | float d_influence; 37 | size_t d_sample_counter; 38 | overall_state ov_state; 39 | size_t d_synced_streams; 40 | size_t d_ref_stream; 41 | size_t *d_sample_difference; 42 | state *d_state_vector; 43 | size_t d_cyc_buf_next_idx; 44 | size_t *d_zero_counter; 45 | size_t d_discarted_samples_counter; 46 | size_t d_discarted_samples; 47 | size_t d_ninput_items; 48 | size_t d_noutput_items; 49 | float *d_amp_thres; 50 | std::vector> filteredY; 51 | float *avgFilter; 52 | float *stdFilter; 53 | float *d_max_abs_sample; 54 | gr_complex *d_max_sample; 55 | float *d_sum; 56 | float *d_sumsqr; 57 | pmt::pmt_t d_phase_shifts_out; 58 | 59 | public: 60 | peak_detector_impl (size_t num_streams, size_t window, float scale, 61 | float influence, size_t discarted_samples); 62 | ~peak_detector_impl (); 63 | void 64 | mean_std (int stream, float discarded_val); 65 | 66 | int 67 | work (int noutput_items, gr_vector_const_void_star &input_items, 68 | gr_vector_void_star &output_items); 69 | }; 70 | 71 | } // namespace devsync 72 | } // namespace gr 73 | 74 | #endif /* INCLUDED_DEVSYNC_PEAK_DETECTOR_IMPL_H */ 75 | 76 | -------------------------------------------------------------------------------- /lib/alligner_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifndef INCLUDED_DEVSYNC_ALLIGNER_IMPL_H 21 | #define INCLUDED_DEVSYNC_ALLIGNER_IMPL_H 22 | 23 | #include 24 | 25 | namespace gr 26 | { 27 | namespace devsync 28 | { 29 | 30 | class alligner_impl : public alligner 31 | { 32 | private: 33 | size_t d_num_streams; 34 | size_t d_sample_counter; 35 | pmt::pmt_t d_phase_init; 36 | overall_state ov_state; 37 | size_t d_init_filled_streams; 38 | size_t d_num_delayed_streams; 39 | gr_complex** d_delayed_samples_buf; 40 | size_t *d_sample_difference; 41 | size_t *d_cyc_buf_next_idx; /*Index of available next sample to be copied to the output stream*/ 42 | size_t *d_filled_buf_rem; /*How many bytes remaining for the buffer of the stream 43 | to fill initially*/ 44 | double *d_fine_phase_diffs; 45 | std::complex* d_fine_complex_shifts; 46 | boost::shared_ptr d_init_thread; 47 | size_t d_ref_stream; 48 | 49 | public: 50 | alligner_impl (size_t num_streams); 51 | ~alligner_impl (); 52 | 53 | void 54 | recv_phase_shifts (pmt::pmt_t msg); 55 | void 56 | setup_delays (); 57 | void 58 | initial_buff_fill (gr_vector_const_void_star &input_items, 59 | gr_vector_void_star &out, int noutput_items); 60 | void 61 | delay_samples (gr_vector_const_void_star &input_items, 62 | gr_vector_void_star &output_items, int noutput_items); 63 | 64 | int 65 | work (int noutput_items, gr_vector_const_void_star &input_items, 66 | gr_vector_void_star &output_items); 67 | }; 68 | 69 | } // namespace devsync 70 | } // namespace gr 71 | 72 | #endif /* INCLUDED_DEVSYNC_ALLIGNER_IMPL_H */ 73 | 74 | -------------------------------------------------------------------------------- /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 | include_directories(${ARMADILLO_INCLUDE_DIRS}) 27 | link_directories(${Boost_LIBRARY_DIRS}) 28 | link_directories(${Armadillo_LIBRARY_DIRS}) 29 | 30 | list(APPEND devsync_sources 31 | alligner_impl.cc 32 | peak_detector_impl.cc 33 | rms_normalization_impl.cc 34 | ) 35 | 36 | set(devsync_sources "${devsync_sources}" PARENT_SCOPE) 37 | if(NOT devsync_sources) 38 | MESSAGE(STATUS "No C++ sources... skipping lib/") 39 | return() 40 | endif(NOT devsync_sources) 41 | 42 | add_library(gnuradio-devsync SHARED ${devsync_sources}) 43 | target_link_libraries(gnuradio-devsync ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES}) 44 | set_target_properties(gnuradio-devsync PROPERTIES DEFINE_SYMBOL "gnuradio_devsync_EXPORTS") 45 | 46 | if(APPLE) 47 | set_target_properties(gnuradio-devsync PROPERTIES 48 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" 49 | ) 50 | endif(APPLE) 51 | 52 | ######################################################################## 53 | # Install built library files 54 | ######################################################################## 55 | include(GrMiscUtils) 56 | GR_LIBRARY_FOO(gnuradio-devsync RUNTIME_COMPONENT "devsync_runtime" DEVEL_COMPONENT "devsync_devel") 57 | 58 | ######################################################################## 59 | # Print summary 60 | ######################################################################## 61 | message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") 62 | message(STATUS "Building for version: ${VERSION} / ${LIBVER}") 63 | 64 | -------------------------------------------------------------------------------- /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 devsync_sources) 24 | MESSAGE(STATUS "No C++ sources... skipping swig/") 25 | return() 26 | endif(NOT devsync_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-devsync) 47 | set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/devsync_swig_doc.i) 48 | set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include) 49 | 50 | GR_SWIG_MAKE(devsync_swig devsync_swig.i) 51 | 52 | ######################################################################## 53 | # Install the build swig module 54 | ######################################################################## 55 | GR_SWIG_INSTALL(TARGETS devsync_swig DESTINATION ${GR_PYTHON_DIR}/devsync) 56 | 57 | ######################################################################## 58 | # Install swig .i files for development 59 | ######################################################################## 60 | install( 61 | FILES 62 | devsync_swig.i 63 | ${CMAKE_CURRENT_BINARY_DIR}/devsync_swig_doc.i 64 | DESTINATION ${GR_INCLUDE_DIR}/devsync/swig 65 | ) 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## GR-DEVSYNC 2 | gr-devsync is an Out Of Tree module of GNURadio, designed to provide phase synchronization for multiple SDR devices. 3 | 4 | # Description 5 | The goal of this project is to provide a low-cost, extendable solution to phase synchronizing multiple SDR devices for use in MIMO scenarios. Apart from the antenna array to be synchronized, gr-devysnc also requires an SDR device with transmit capability. A known signal is transmitted, and received by all elements of the antenna array. Using crosscorrelation with the known sequence at the receiver, we detect the arrival of the signal at all channels, and provided that the signal is received at (almost) the same time from each one, we compensate digitally for the phase offset between them. For the purpose of this project, the long training sequence of the IEEE802.11 protocol is being used as the transmitted known signal. Also, it is assumed that the RX devices are synchronized in frequency. 6 | 7 | # Usage 8 | The transmitting element is placed at the far field side of the antenna array so that the signal arrives at the array as a plane wave. Also, it must be placed at a direction, such that the distance of the transmitting antenna to each of the receiving elements, is almost equal. For example, if the array is a linear array, the transmitting antenna should be placed at azimuth 90 and elevation 0, so that the signal arrives at the same time at all receiving elements. 9 | 10 | After the start of execution, a (user-defined) number of samples is discarded, and after, the noise floor estimation takes place. For this reason, and depending on the values defined by the user in the corresponding blocks, the transmission of the signal should occur a few seconds after the start of execution. 11 | 12 | Furthermore, an RMS normalization method is used to bring the receiving signals of the different channels on the same level, in order to compensate for possible amplitude offsets, which degrade the performance of the synchronizer. 13 | 14 | Please refer to the examples folder for a sample flowgraph of how the different blocks are combined. 15 | 16 | # Dependencies 17 | Apart from the dependencies of gnuradio, gr-devsync also requires the Armadillo library to build. 18 | 19 | # Installation 20 | gr-devsync uses the cmake tool for generating the appropriate Makefiles 21 | 22 | First create a build directory 23 | 24 | 25 | ```sh 26 | $ mkdir build 27 | ``` 28 | 29 | Execute the cmake command with the appropriate arguments inside the build directory 30 | 31 | ```sh 32 | $ cmake .. 33 | ``` 34 | 35 | And finally build the project 36 | 37 | ```sh 38 | $ make 39 | $ sudo make install 40 | ``` 41 | 42 | # Contact 43 | For any information you will find me on the gnuradio and usrp lists, or email me at vardakis@csd.uoc.gr -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/rms_normalization_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #include 25 | #include "rms_normalization_impl.h" 26 | 27 | #include 28 | #include 29 | using namespace arma; 30 | namespace gr 31 | { 32 | namespace devsync 33 | { 34 | 35 | rms_normalization::sptr 36 | rms_normalization::make (size_t num_streams, size_t vlen) 37 | { 38 | return gnuradio::get_initial_sptr ( 39 | new rms_normalization_impl (num_streams, vlen)); 40 | } 41 | 42 | rms_normalization_impl::rms_normalization_impl (size_t num_streams, 43 | size_t vlen) : 44 | gr::sync_block ( 45 | "rms_normalization", 46 | gr::io_signature::make (num_streams, num_streams, 47 | sizeof(std::complex) * vlen), 48 | gr::io_signature::make (num_streams, num_streams, 49 | sizeof(std::complex) * vlen)), 50 | d_vlen (vlen), 51 | d_num_streams (num_streams) 52 | { 53 | } 54 | 55 | rms_normalization_impl::~rms_normalization_impl () 56 | { 57 | } 58 | 59 | int 60 | rms_normalization_impl::work (int noutput_items, 61 | gr_vector_const_void_star &input_items, 62 | gr_vector_void_star &output_items) 63 | { 64 | std::complex **in = (std::complex **) &input_items[0]; 65 | 66 | std::complex **out = (std::complex **) &output_items[0]; 67 | for (int i = 0; i < noutput_items; i++) { 68 | cx_fmat batch (&in[0][i * d_vlen], 1, d_vlen, false, true); 69 | float ref = std::sqrt (sum (sum (pow (abs (batch), 2))) / d_vlen); 70 | memcpy (&out[0][i * d_vlen], &in[0][i * d_vlen], 71 | sizeof(std::complex) * d_vlen); 72 | for (int j = 1; j < d_num_streams; j++) { 73 | cx_fmat batch (&in[j][i * d_vlen], 1, d_vlen, false, true); 74 | float rms = std::sqrt (sum (sum (pow (abs (batch), 2))) / d_vlen); 75 | batch = batch * (ref / rms); 76 | memcpy (&out[j][i * d_vlen], batch.memptr (), 77 | sizeof(std::complex) * d_vlen); 78 | } 79 | } 80 | return noutput_items; 81 | } 82 | 83 | } /* namespace devsync */ 84 | } /* namespace gr */ 85 | 86 | -------------------------------------------------------------------------------- /include/devsync/peak_detector.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | 21 | #ifndef INCLUDED_DEVSYNC_PEAK_DETECTOR_H 22 | #define INCLUDED_DEVSYNC_PEAK_DETECTOR_H 23 | 24 | #include 25 | #include 26 | 27 | namespace gr { 28 | namespace devsync { 29 | 30 | /*! 31 | * \brief The peak detector block 32 | * \ingroup devsync 33 | * 34 | * \details This block performs a simple peak detection algorithm 35 | * on the output of the FFT filter blocks in order to detect the 36 | * peaks that correspond to the reception of the training sequence 37 | * by the receiving channels. 38 | * 39 | * The peak detection algorithm first makes a rough noise floor 40 | * estimation. Next, it attempts to detect peak values by keeping 41 | * a moving average of previous energy values. If the difference 42 | * in energy levels between the last and the new sample exceeds the 43 | * last sample's energy, scaled by a value, then a peak 44 | * is detected. The user also has the option, through the influence 45 | * parameter to dictate if the current sample's energy (influence = 1) 46 | * , or the moving average of the previous samples in the window 47 | * (influence = 0), will have the most effect on the calculations. 48 | * 49 | * The last stream on which a peak is detected, is taken as the 50 | * reference stream : all remaining streams will allign their samples 51 | * according to it. Apart from the coarse synchronization, in 52 | * sample level, between the streams, a fine synchronization also 53 | * takes place to account for phase differences smaller than a 54 | * sample. This is done by estimating the angle between the peak 55 | * value of the reference stream, and the rest of the streams. 56 | * All the information is passed through the message output to 57 | * the alligner block. 58 | * 59 | */ 60 | class DEVSYNC_API peak_detector : virtual public gr::sync_block 61 | { 62 | public: 63 | typedef boost::shared_ptr sptr; 64 | 65 | /*! 66 | * Build the peak detection block 67 | * 68 | * \param num_streams (size_t) The total number of receiving streams 69 | * \param window (size_t) The length in samples of the window over which 70 | * the noise floor estimation at the beginning will occur 71 | * \param scale (float) Scaling value of the previous sample's energy 72 | * used in the calculations of the peak detection 73 | * \param influence (float) The influence of the new sample's energy 74 | * in the peak detection algorithm calculations. 1 for total trust 75 | * on the new sample's value in the algorithm, 0 for total trust on 76 | * the moving average calculated by previous samples 77 | * \param discarted_samples (size_t) Number of samples to discard in 78 | * the beginning of execution 79 | */ 80 | static sptr make(size_t num_streams, size_t window, float scale, float influence, size_t discarted_samples); 81 | }; 82 | 83 | } // namespace devsync 84 | } // namespace gr 85 | 86 | #endif /* INCLUDED_DEVSYNC_PEAK_DETECTOR_H */ 87 | 88 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-devsync CXX C) 25 | enable_testing() 26 | 27 | #install to PyBOMBS target prefix if defined 28 | if(DEFINED ENV{PYBOMBS_PREFIX}) 29 | #IGNORE 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 | #IGNORE set(CMAKE_BUILD_TYPE "Release") 36 | message(STATUS "Build type not specified: defaulting to release.") 37 | endif(NOT CMAKE_BUILD_TYPE) 38 | #IGNORE 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 | # Set cmake policies. 50 | # This will suppress developer warnings during the cmake process that can occur 51 | # if a newer cmake version than the minimum is used. 52 | 53 | if(POLICY CMP0026) 54 | cmake_policy(SET CMP0026 OLD) 55 | endif() 56 | if(POLICY CMP0043) 57 | cmake_policy(SET CMP0043 OLD) 58 | endif() 59 | if(POLICY CMP0045) 60 | cmake_policy(SET CMP0045 OLD) 61 | endif() 62 | if(POLICY CMP0046) 63 | cmake_policy(SET CMP0046 OLD) 64 | endif() 65 | 66 | ######################################################################## 67 | # Compiler specific setup 68 | ######################################################################## 69 | if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) 70 | #http://gcc.gnu.org/wiki/Visibility 71 | add_definitions(-fvisibility=hidden) 72 | endif() 73 | 74 | ######################################################################## 75 | # Find boost 76 | ######################################################################## 77 | if(UNIX AND EXISTS "/usr/lib64") 78 | list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix 79 | endif(UNIX AND EXISTS "/usr/lib64") 80 | set(Boost_ADDITIONAL_VERSIONS 81 | "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" 82 | "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" 83 | "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" 84 | "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" 85 | "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" 86 | "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" 87 | "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" 88 | ) 89 | find_package(Boost "1.35" COMPONENTS filesystem system) 90 | 91 | if(NOT Boost_FOUND) 92 | message(FATAL_ERROR "Boost required to compile devsync") 93 | endif() 94 | find_package(Armadillo "1.35" COMPONENTS filesystem system) 95 | 96 | if(NOT Armadillo_FOUND) 97 | message(FATAL_ERROR "Armadillo required to compile devsync") 98 | endif() 99 | ######################################################################## 100 | # Install directories 101 | ######################################################################## 102 | include(GrPlatform) #define LIB_SUFFIX 103 | set(GR_RUNTIME_DIR bin) 104 | set(GR_LIBRARY_DIR lib${LIB_SUFFIX}) 105 | set(GR_INCLUDE_DIR include/devsync) 106 | set(GR_DATA_DIR share) 107 | set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) 108 | set(GR_DOC_DIR ${GR_DATA_DIR}/doc) 109 | set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) 110 | set(GR_CONF_DIR etc) 111 | set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) 112 | set(GR_LIBEXEC_DIR libexec) 113 | set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) 114 | set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks) 115 | 116 | ######################################################################## 117 | # On Apple only, set install name and use rpath correctly, if not already set 118 | ######################################################################## 119 | if(APPLE) 120 | if(NOT CMAKE_INSTALL_NAME_DIR) 121 | set(CMAKE_INSTALL_NAME_DIR 122 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 123 | PATH "Library Install Name Destination Directory" FORCE) 124 | endif(NOT CMAKE_INSTALL_NAME_DIR) 125 | if(NOT CMAKE_INSTALL_RPATH) 126 | set(CMAKE_INSTALL_RPATH 127 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 128 | PATH "Library Install RPath" FORCE) 129 | endif(NOT CMAKE_INSTALL_RPATH) 130 | if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 131 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE 132 | BOOL "Do Build Using Library Install RPath" FORCE) 133 | endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 134 | endif(APPLE) 135 | 136 | ######################################################################## 137 | # Find gnuradio build dependencies 138 | ######################################################################## 139 | find_package(CppUnit) 140 | find_package(Doxygen) 141 | 142 | # Search for GNU Radio and its components and versions. Add any 143 | # components required to the list of GR_REQUIRED_COMPONENTS (in all 144 | # caps such as FILTER or FFT) and change the version to the minimum 145 | # API compatible version required. 146 | set(GR_REQUIRED_COMPONENTS RUNTIME) 147 | find_package(Gnuradio "3.7.2" REQUIRED) 148 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) 149 | include(GrVersion) 150 | 151 | if(NOT CPPUNIT_FOUND) 152 | message(FATAL_ERROR "CppUnit required to compile devsync") 153 | endif() 154 | 155 | ######################################################################## 156 | # Setup doxygen option 157 | ######################################################################## 158 | if(DOXYGEN_FOUND) 159 | option(ENABLE_DOXYGEN "Build docs using Doxygen" ON) 160 | else(DOXYGEN_FOUND) 161 | option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF) 162 | endif(DOXYGEN_FOUND) 163 | 164 | ######################################################################## 165 | # Setup the include and linker paths 166 | ######################################################################## 167 | include_directories( 168 | ${CMAKE_SOURCE_DIR}/lib 169 | ${CMAKE_SOURCE_DIR}/include 170 | ${CMAKE_BINARY_DIR}/lib 171 | ${CMAKE_BINARY_DIR}/include 172 | ${Boost_INCLUDE_DIRS} 173 | ${CPPUNIT_INCLUDE_DIRS} 174 | ${GNURADIO_ALL_INCLUDE_DIRS} 175 | ) 176 | 177 | link_directories( 178 | ${Boost_LIBRARY_DIRS} 179 | ${CPPUNIT_LIBRARY_DIRS} 180 | ${GNURADIO_RUNTIME_LIBRARY_DIRS} 181 | ) 182 | 183 | # Set component parameters 184 | set(GR_DEVSYNC_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE) 185 | set(GR_DEVSYNC_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE) 186 | 187 | ######################################################################## 188 | # Create uninstall target 189 | ######################################################################## 190 | configure_file( 191 | ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 192 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 193 | @ONLY) 194 | 195 | add_custom_target(uninstall 196 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 197 | ) 198 | 199 | ######################################################################## 200 | # Add subdirectories 201 | ######################################################################## 202 | add_subdirectory(include/devsync) 203 | add_subdirectory(lib) 204 | add_subdirectory(swig) 205 | add_subdirectory(python) 206 | add_subdirectory(grc) 207 | add_subdirectory(apps) 208 | add_subdirectory(docs) 209 | 210 | ######################################################################## 211 | # Install cmake search helper for this library 212 | ######################################################################## 213 | if(NOT CMAKE_MODULES_DIR) 214 | set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) 215 | endif(NOT CMAKE_MODULES_DIR) 216 | 217 | install(FILES cmake/Modules/devsyncConfig.cmake 218 | DESTINATION ${CMAKE_MODULES_DIR}/devsync 219 | ) 220 | -------------------------------------------------------------------------------- /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 and namespaces we want the contents to be 47 | # accessible directly from the parent rather than having 48 | # to go through the file 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 | elif self.get_cls(mem) == DoxyNamespace: 54 | self._members += converted.members() 55 | self._members.append(converted) 56 | else: 57 | self._members.append(converted) 58 | 59 | 60 | def generate_swig_doc_i(self): 61 | """ 62 | %feature("docstring") gr_make_align_on_samplenumbers_ss::align_state " 63 | Wraps the C++: gr_align_on_samplenumbers_ss::align_state"; 64 | """ 65 | pass 66 | 67 | 68 | class DoxyCompMem(Base): 69 | 70 | 71 | kind = None 72 | 73 | def __init__(self, *args, **kwargs): 74 | super(DoxyCompMem, self).__init__(*args, **kwargs) 75 | 76 | @classmethod 77 | def can_parse(cls, obj): 78 | return obj.kind == cls.kind 79 | 80 | def set_descriptions(self, parse_data): 81 | bd = description(getattr(parse_data, 'briefdescription', None)) 82 | dd = description(getattr(parse_data, 'detaileddescription', None)) 83 | self._data['brief_description'] = bd 84 | self._data['detailed_description'] = dd 85 | 86 | def set_parameters(self, data): 87 | vs = [ddc.value for ddc in data.detaileddescription.content_] 88 | pls = [] 89 | for v in vs: 90 | if hasattr(v, 'parameterlist'): 91 | pls += v.parameterlist 92 | pis = [] 93 | for pl in pls: 94 | pis += pl.parameteritem 95 | dpis = [] 96 | for pi in pis: 97 | dpi = DoxyParameterItem(pi) 98 | dpi._parse() 99 | dpis.append(dpi) 100 | self._data['params'] = dpis 101 | 102 | 103 | class DoxyCompound(DoxyCompMem): 104 | pass 105 | 106 | class DoxyMember(DoxyCompMem): 107 | pass 108 | 109 | class DoxyFunction(DoxyMember): 110 | 111 | __module__ = "gnuradio.utils.doxyxml" 112 | 113 | kind = 'function' 114 | 115 | def _parse(self): 116 | if self._parsed: 117 | return 118 | super(DoxyFunction, self)._parse() 119 | self.set_descriptions(self._parse_data) 120 | self.set_parameters(self._parse_data) 121 | if not self._data['params']: 122 | # If the params weren't set by a comment then just grab the names. 123 | self._data['params'] = [] 124 | prms = self._parse_data.param 125 | for prm in prms: 126 | self._data['params'].append(DoxyParam(prm)) 127 | 128 | brief_description = property(lambda self: self.data()['brief_description']) 129 | detailed_description = property(lambda self: self.data()['detailed_description']) 130 | params = property(lambda self: self.data()['params']) 131 | 132 | Base.mem_classes.append(DoxyFunction) 133 | 134 | 135 | class DoxyParam(DoxyMember): 136 | 137 | __module__ = "gnuradio.utils.doxyxml" 138 | 139 | def _parse(self): 140 | if self._parsed: 141 | return 142 | super(DoxyParam, self)._parse() 143 | self.set_descriptions(self._parse_data) 144 | self._data['declname'] = self._parse_data.declname 145 | 146 | @property 147 | def description(self): 148 | descriptions = [] 149 | if self.brief_description: 150 | descriptions.append(self.brief_description) 151 | if self.detailed_description: 152 | descriptions.append(self.detailed_description) 153 | return '\n\n'.join(descriptions) 154 | 155 | brief_description = property(lambda self: self.data()['brief_description']) 156 | detailed_description = property(lambda self: self.data()['detailed_description']) 157 | name = property(lambda self: self.data()['declname']) 158 | 159 | class DoxyParameterItem(DoxyMember): 160 | """A different representation of a parameter in Doxygen.""" 161 | 162 | def _parse(self): 163 | if self._parsed: 164 | return 165 | super(DoxyParameterItem, self)._parse() 166 | names = [] 167 | for nl in self._parse_data.parameternamelist: 168 | for pn in nl.parametername: 169 | names.append(description(pn)) 170 | # Just take first name 171 | self._data['name'] = names[0] 172 | # Get description 173 | pd = description(self._parse_data.get_parameterdescription()) 174 | self._data['description'] = pd 175 | 176 | description = property(lambda self: self.data()['description']) 177 | name = property(lambda self: self.data()['name']) 178 | 179 | 180 | class DoxyClass(DoxyCompound): 181 | 182 | __module__ = "gnuradio.utils.doxyxml" 183 | 184 | kind = 'class' 185 | 186 | def _parse(self): 187 | if self._parsed: 188 | return 189 | super(DoxyClass, self)._parse() 190 | self.retrieve_data() 191 | if self._error: 192 | return 193 | self.set_descriptions(self._retrieved_data.compounddef) 194 | self.set_parameters(self._retrieved_data.compounddef) 195 | # Sectiondef.kind tells about whether private or public. 196 | # We just ignore this for now. 197 | self.process_memberdefs() 198 | 199 | brief_description = property(lambda self: self.data()['brief_description']) 200 | detailed_description = property(lambda self: self.data()['detailed_description']) 201 | params = property(lambda self: self.data()['params']) 202 | 203 | Base.mem_classes.append(DoxyClass) 204 | 205 | 206 | class DoxyFile(DoxyCompound): 207 | 208 | __module__ = "gnuradio.utils.doxyxml" 209 | 210 | kind = 'file' 211 | 212 | def _parse(self): 213 | if self._parsed: 214 | return 215 | super(DoxyFile, self)._parse() 216 | self.retrieve_data() 217 | self.set_descriptions(self._retrieved_data.compounddef) 218 | if self._error: 219 | return 220 | self.process_memberdefs() 221 | 222 | brief_description = property(lambda self: self.data()['brief_description']) 223 | detailed_description = property(lambda self: self.data()['detailed_description']) 224 | 225 | Base.mem_classes.append(DoxyFile) 226 | 227 | 228 | class DoxyNamespace(DoxyCompound): 229 | 230 | __module__ = "gnuradio.utils.doxyxml" 231 | 232 | kind = 'namespace' 233 | 234 | def _parse(self): 235 | if self._parsed: 236 | return 237 | super(DoxyNamespace, self)._parse() 238 | self.retrieve_data() 239 | self.set_descriptions(self._retrieved_data.compounddef) 240 | if self._error: 241 | return 242 | self.process_memberdefs() 243 | 244 | Base.mem_classes.append(DoxyNamespace) 245 | 246 | 247 | class DoxyGroup(DoxyCompound): 248 | 249 | __module__ = "gnuradio.utils.doxyxml" 250 | 251 | kind = 'group' 252 | 253 | def _parse(self): 254 | if self._parsed: 255 | return 256 | super(DoxyGroup, self)._parse() 257 | self.retrieve_data() 258 | if self._error: 259 | return 260 | cdef = self._retrieved_data.compounddef 261 | self._data['title'] = description(cdef.title) 262 | # Process inner groups 263 | grps = cdef.innergroup 264 | for grp in grps: 265 | converted = DoxyGroup.from_refid(grp.refid, top=self.top) 266 | self._members.append(converted) 267 | # Process inner classes 268 | klasses = cdef.innerclass 269 | for kls in klasses: 270 | converted = DoxyClass.from_refid(kls.refid, top=self.top) 271 | self._members.append(converted) 272 | # Process normal members 273 | self.process_memberdefs() 274 | 275 | title = property(lambda self: self.data()['title']) 276 | 277 | 278 | Base.mem_classes.append(DoxyGroup) 279 | 280 | 281 | class DoxyFriend(DoxyMember): 282 | 283 | __module__ = "gnuradio.utils.doxyxml" 284 | 285 | kind = 'friend' 286 | 287 | Base.mem_classes.append(DoxyFriend) 288 | 289 | 290 | class DoxyOther(Base): 291 | 292 | __module__ = "gnuradio.utils.doxyxml" 293 | 294 | kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 295 | 'dir', 'page', 'signal', 'slot', 'property']) 296 | 297 | @classmethod 298 | def can_parse(cls, obj): 299 | return obj.kind in cls.kinds 300 | 301 | Base.mem_classes.append(DoxyOther) 302 | -------------------------------------------------------------------------------- /lib/alligner_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #include 25 | #include "alligner_impl.h" 26 | 27 | #include 28 | #define MODPI(a) (((a)<-M_PI) ? a+2*M_PI : ((a)>M_PI ? a-2*M_PI : a)) 29 | 30 | namespace gr 31 | { 32 | namespace devsync 33 | { 34 | 35 | alligner::sptr 36 | alligner::make (size_t num_streams) 37 | { 38 | return gnuradio::get_initial_sptr (new alligner_impl (num_streams)); 39 | } 40 | 41 | alligner_impl::alligner_impl (size_t num_streams) : 42 | gr::sync_block ( 43 | "alligner", 44 | gr::io_signature::make (num_streams, num_streams, 45 | sizeof(gr_complex)), 46 | gr::io_signature::make (num_streams, num_streams, 47 | sizeof(gr_complex))), 48 | d_num_streams (num_streams), 49 | d_sample_counter (0), 50 | d_phase_init (pmt::mp ("phase_init")), 51 | ov_state (SYNCING), 52 | d_init_filled_streams (0), 53 | d_num_delayed_streams (0) 54 | { 55 | message_port_register_in (d_phase_init); 56 | d_delayed_samples_buf = NULL; 57 | d_sample_difference = new size_t[num_streams]; 58 | d_cyc_buf_next_idx = new size_t[num_streams]; 59 | d_filled_buf_rem = new size_t[num_streams]; 60 | d_fine_phase_diffs = new double[num_streams]; 61 | d_fine_complex_shifts = new std::complex[num_streams]; 62 | for (int i = 0; i < num_streams; i++) { 63 | d_sample_difference[i] = 0; 64 | d_cyc_buf_next_idx[i] = 0; 65 | d_filled_buf_rem[i] = 0; 66 | d_fine_phase_diffs[i] = 0; 67 | } 68 | set_msg_handler ( 69 | d_phase_init, 70 | boost::bind (&alligner_impl::recv_phase_shifts, this, _1)); 71 | } 72 | 73 | alligner_impl::~alligner_impl () 74 | { 75 | } 76 | 77 | int 78 | alligner_impl::work (int noutput_items, 79 | gr_vector_const_void_star &input_items, 80 | gr_vector_void_star &output_items) 81 | { 82 | const gr_complex *in; 83 | gr_complex *out; 84 | if (ov_state == SYNCING) { 85 | for (int i = 0; i < d_num_streams; i++) { 86 | in = (const gr_complex *) input_items[i]; 87 | out = (gr_complex *) output_items[i]; 88 | memcpy (out, in, noutput_items * sizeof(gr_complex)); 89 | } 90 | return noutput_items; 91 | } 92 | else if (ov_state == NO_PHASE_DIFF) { 93 | for (int i = 0; i < d_num_streams; i++) { 94 | in = (const gr_complex *) input_items[i]; 95 | out = (gr_complex *) output_items[i]; 96 | memcpy (out, in, noutput_items * sizeof(gr_complex)); 97 | } 98 | return noutput_items; 99 | } 100 | if (ov_state == FIRST_BUFFER_FILL) { 101 | initial_buff_fill (input_items, output_items, noutput_items); 102 | if (ov_state == FIRST_BUFFER_FILL) { 103 | return noutput_items; 104 | } 105 | } 106 | if (ov_state == SYNCED) { 107 | delay_samples (input_items, output_items, noutput_items); 108 | return noutput_items; 109 | } 110 | return noutput_items; 111 | } 112 | 113 | void 114 | alligner_impl::recv_phase_shifts (pmt::pmt_t msg) 115 | { 116 | size_t* diffs = (size_t*) pmt::blob_data (pmt::tuple_ref (msg, 1)); 117 | memcpy (d_sample_difference, diffs, d_num_streams * sizeof(size_t)); 118 | d_ref_stream = pmt::to_uint64 (pmt::tuple_ref (msg, 0)); 119 | gr_complex* fine_shifts = (gr_complex*) pmt::blob_data ( 120 | pmt::tuple_ref (msg, 2)); 121 | float angle; 122 | for (int i = 0; i < d_num_streams; i++) { 123 | angle = std::atan2 (std::imag (fine_shifts[i]), 124 | std::real (fine_shifts[i])); 125 | std::complex c (std::cos (-angle), std::sin (-angle)); 126 | d_fine_complex_shifts[i] = c; 127 | if (d_sample_difference[i] != 0) { 128 | ov_state = FIRST_BUFFER_FILL; 129 | } 130 | } 131 | if (ov_state == FIRST_BUFFER_FILL) { 132 | setup_delays (); 133 | } 134 | else { 135 | ov_state = NO_PHASE_DIFF; 136 | } 137 | return; 138 | } 139 | 140 | void 141 | alligner_impl::setup_delays () 142 | { 143 | d_delayed_samples_buf = (gr_complex**) malloc ( 144 | d_num_streams * sizeof(gr_complex*)); 145 | size_t temp_diffs[d_num_streams]; 146 | memcpy (temp_diffs, d_sample_difference, d_num_streams * sizeof(size_t)); 147 | for (int i = 0; i < d_num_streams; i++) { 148 | d_sample_difference[i] = temp_diffs[d_ref_stream] - temp_diffs[i]; 149 | d_filled_buf_rem[i] = d_sample_difference[i]; 150 | d_delayed_samples_buf[i] = (gr_complex*) malloc ( 151 | d_sample_difference[i] * sizeof(gr_complex)); 152 | if (d_sample_difference[i] > 0) 153 | d_num_delayed_streams++; 154 | } 155 | ov_state = FIRST_BUFFER_FILL; 156 | return; 157 | 158 | } 159 | 160 | void 161 | alligner_impl::initial_buff_fill (gr_vector_const_void_star &input_items, 162 | gr_vector_void_star &out, 163 | int noutput_items) 164 | { 165 | const gr_complex* in; 166 | for (int i = 0; i < d_num_streams; i++) { 167 | in = (const gr_complex *) input_items[i]; 168 | if (d_filled_buf_rem[i] > 0) { 169 | if (noutput_items >= d_filled_buf_rem[i]) { 170 | if (d_cyc_buf_next_idx[i] == 0) { 171 | memcpy (&d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], 172 | &in[noutput_items - d_filled_buf_rem[i]], 173 | d_filled_buf_rem[i] * sizeof(gr_complex)); 174 | } 175 | else { 176 | memcpy (&d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], in, 177 | d_filled_buf_rem[i] * sizeof(gr_complex)); 178 | } 179 | d_init_filled_streams++; 180 | d_cyc_buf_next_idx[i] = 0; 181 | d_filled_buf_rem[i] = 0; 182 | } 183 | else { 184 | memcpy (&d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], &in[0], 185 | noutput_items * sizeof(gr_complex)); 186 | d_cyc_buf_next_idx[i] += noutput_items; 187 | d_filled_buf_rem[i] -= noutput_items; 188 | } 189 | } 190 | } 191 | if (d_init_filled_streams == d_num_delayed_streams) { 192 | ov_state = SYNCED; 193 | } 194 | return; 195 | } 196 | 197 | void 198 | alligner_impl::delay_samples (gr_vector_const_void_star &input_items, 199 | gr_vector_void_star &output_items, 200 | int noutput_items) 201 | { 202 | const gr_complex* in; 203 | gr_complex* out; 204 | size_t num_first_copy = 0; 205 | size_t num_sec_copy = 0; 206 | for (int i = 0; i < d_num_streams; i++) { 207 | in = (const gr_complex *) input_items[i]; 208 | out = (gr_complex *) output_items[i]; 209 | if (d_sample_difference[i] == 0) { 210 | memcpy (out, in, noutput_items * sizeof(gr_complex)); 211 | volk_32fc_s32fc_multiply_32fc (out, out, d_fine_complex_shifts[i], 212 | noutput_items); 213 | continue; 214 | } 215 | size_t len; 216 | if (noutput_items >= d_sample_difference[i]) { 217 | len = d_sample_difference[i]; 218 | } 219 | else { 220 | len = noutput_items; 221 | } 222 | if (d_cyc_buf_next_idx[i] + len <= d_sample_difference[i]) { 223 | memcpy (out, &d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], 224 | len * sizeof(gr_complex)); 225 | memcpy (&d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], 226 | &in[noutput_items - len], len * sizeof(gr_complex)); 227 | if (noutput_items > len) { 228 | memcpy (out + len, in, (noutput_items - len) * sizeof(gr_complex)); 229 | 230 | } 231 | d_cyc_buf_next_idx[i] = (d_cyc_buf_next_idx[i] + len) 232 | % d_sample_difference[i]; 233 | } 234 | else { 235 | num_first_copy = d_sample_difference[i] - d_cyc_buf_next_idx[i]; 236 | num_sec_copy = len - num_first_copy; 237 | memcpy (out, &d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], 238 | num_first_copy * sizeof(gr_complex)); 239 | memcpy (out + num_first_copy, d_delayed_samples_buf[i], 240 | num_sec_copy * sizeof(gr_complex)); 241 | memcpy (&d_delayed_samples_buf[i][d_cyc_buf_next_idx[i]], 242 | &in[noutput_items - len], 243 | num_first_copy * sizeof(gr_complex)); 244 | memcpy (&d_delayed_samples_buf[i][0], 245 | &in[noutput_items - num_sec_copy], 246 | num_sec_copy * sizeof(gr_complex)); 247 | d_cyc_buf_next_idx[i] = num_sec_copy % d_sample_difference[i]; 248 | if (noutput_items > len) { 249 | memcpy (out + len, in, (noutput_items - len) * sizeof(gr_complex)); 250 | } 251 | } 252 | volk_32fc_s32fc_multiply_32fc (out, out, d_fine_complex_shifts[i], 253 | noutput_items); 254 | } 255 | } 256 | } /* namespace devsync */ 257 | } /* namespace gr */ 258 | 259 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/top_block.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | ################################################## 4 | # GNU Radio Python Flow Graph 5 | # Title: Top Block 6 | # Generated: Tue Feb 20 15:54:13 2018 7 | ################################################## 8 | 9 | if __name__ == '__main__': 10 | import ctypes 11 | import sys 12 | if sys.platform.startswith('linux'): 13 | try: 14 | x11 = ctypes.cdll.LoadLibrary('libX11.so') 15 | x11.XInitThreads() 16 | except: 17 | print "Warning: failed to XInitThreads()" 18 | 19 | from PyQt4 import Qt 20 | from gnuradio import blocks 21 | from gnuradio import eng_notation 22 | from gnuradio import filter 23 | from gnuradio import gr 24 | from gnuradio.eng_option import eng_option 25 | from gnuradio.filter import firdes 26 | from optparse import OptionParser 27 | import cmath 28 | import devsync 29 | import numpy 30 | import sys 31 | from gnuradio import qtgui 32 | 33 | 34 | class top_block(gr.top_block, Qt.QWidget): 35 | 36 | def __init__(self): 37 | gr.top_block.__init__(self, "Top Block") 38 | Qt.QWidget.__init__(self) 39 | self.setWindowTitle("Top Block") 40 | qtgui.util.check_set_qss() 41 | try: 42 | self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) 43 | except: 44 | pass 45 | self.top_scroll_layout = Qt.QVBoxLayout() 46 | self.setLayout(self.top_scroll_layout) 47 | self.top_scroll = Qt.QScrollArea() 48 | self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) 49 | self.top_scroll_layout.addWidget(self.top_scroll) 50 | self.top_scroll.setWidgetResizable(True) 51 | self.top_widget = Qt.QWidget() 52 | self.top_scroll.setWidget(self.top_widget) 53 | self.top_layout = Qt.QVBoxLayout(self.top_widget) 54 | self.top_grid_layout = Qt.QGridLayout() 55 | self.top_layout.addLayout(self.top_grid_layout) 56 | 57 | self.settings = Qt.QSettings("GNU Radio", "top_block") 58 | self.restoreGeometry(self.settings.value("geometry").toByteArray()) 59 | 60 | 61 | ################################################## 62 | # Variables 63 | ################################################## 64 | self.samp_rate = samp_rate = 32000 65 | self.num_streams = num_streams = 4 66 | self.num_elements = num_elements = 1024 67 | self.long_seq = long_seq = [ 0.1562 - 0.0j , -0.0051 + 0.1203j, 0.0397 + 0.1112j, 0.0968 - 0.0828j, 68 | 0.0211 - 0.0279j, 0.0598 + 0.0877j, -0.1151 + 0.0552j, -0.0383 + 0.1062j, 69 | 0.0975 + 0.0259j, 0.0533 - 0.0041j, 0.0010 + 0.115j , -0.1368 + 0.0474j, 70 | 0.0245 + 0.0585j, 0.0587 + 0.0149j, -0.0225 - 0.1607j, 0.1192 + 0.0041j, 71 | 0.0625 + 0.0625j, 0.0369 - 0.0983j, -0.0572 - 0.0393j, -0.1313 - 0.0652j, 72 | 0.0822 - 0.0924j, 0.0696 - 0.0141j, -0.0603 - 0.0813j, -0.0565 + 0.0218j, 73 | - 0.0350 + 0.1509j, -0.1219 + 0.0166j, -0.1273 + 0.0205j, 0.0751 + 0.074j , 74 | - 0.0028 - 0.0538j, -0.0919 - 0.1151j, 0.0917 - 0.1059j, 0.0123 - 0.0976j, 75 | - 0.1562 - 0.0j , 0.0123 + 0.0976j, 0.0917 + 0.1059j, -0.0919 + 0.1151j, 76 | - 0.0028 + 0.0538j, 0.0751 - 0.074j , -0.1273 - 0.0205j, -0.1219 - 0.0166j, 77 | - 0.0350 - 0.1509j, -0.0565 - 0.0218j, -0.0603 + 0.0813j, 0.0696 + 0.0141j, 78 | 0.0822 + 0.0924j, -0.1313 + 0.0652j, -0.0572 + 0.0393j, 0.0369 + 0.0983j, 79 | 0.0625 - 0.0625j, 0.1192 - 0.0041j, -0.0225 + 0.1607j, 0.0587 - 0.0149j, 80 | 0.0245 - 0.0585j, -0.1368 - 0.0474j, 0.0010 - 0.115j , 0.0533 + 0.0041j, 81 | 0.0975 - 0.0259j, -0.0383 - 0.1062j, -0.1151 - 0.0552j, 0.0598 - 0.0877j, 82 | 0.0211 + 0.0279j, 0.0968 + 0.0828j, 0.0397 - 0.1112j, -0.0051 - 0.1203j] + 1000*[0] 83 | 84 | ################################################## 85 | # Blocks 86 | ################################################## 87 | self.fft_filter_xxx_0_4_0_0_0 = filter.fft_filter_ccc(1, (long_seq[::-1]), 1) 88 | self.fft_filter_xxx_0_4_0_0_0.declare_sample_delay(0) 89 | self.fft_filter_xxx_0_4_0_0 = filter.fft_filter_ccc(1, (long_seq[::-1]), 1) 90 | self.fft_filter_xxx_0_4_0_0.declare_sample_delay(0) 91 | self.fft_filter_xxx_0_4_0 = filter.fft_filter_ccc(1, (long_seq[::-1]), 1) 92 | self.fft_filter_xxx_0_4_0.declare_sample_delay(0) 93 | self.fft_filter_xxx_0_4 = filter.fft_filter_ccc(1, (long_seq[::-1]), 1) 94 | self.fft_filter_xxx_0_4.declare_sample_delay(0) 95 | self.devsync_rms_normalization_0 = devsync.rms_normalization(num_streams, num_elements) 96 | self.devsync_peak_detector_0 = devsync.peak_detector(num_streams, 100, 1, 0, 100) 97 | self.devsync_alligner_0 = devsync.alligner(num_streams) 98 | self.blocks_vector_to_stream_1_2 = blocks.vector_to_stream(gr.sizeof_gr_complex*1, num_elements) 99 | self.blocks_vector_to_stream_1_1 = blocks.vector_to_stream(gr.sizeof_gr_complex*1, num_elements) 100 | self.blocks_vector_to_stream_1_0 = blocks.vector_to_stream(gr.sizeof_gr_complex*1, num_elements) 101 | self.blocks_vector_to_stream_1 = blocks.vector_to_stream(gr.sizeof_gr_complex*1, num_elements) 102 | self.blocks_vector_source_x_1 = blocks.vector_source_c(numpy.conj(long_seq) , True, 1, []) 103 | self.blocks_stream_to_vector_0_3_1 = blocks.stream_to_vector(gr.sizeof_gr_complex*1, 1024) 104 | self.blocks_stream_to_vector_0_0_0_1 = blocks.stream_to_vector(gr.sizeof_gr_complex*1, 1024) 105 | self.blocks_stream_to_vector_0_0_0_0_0 = blocks.stream_to_vector(gr.sizeof_gr_complex*1, 1024) 106 | self.blocks_stream_to_vector_0_0 = blocks.stream_to_vector(gr.sizeof_gr_complex*1, 1024) 107 | self.blocks_null_source_0 = blocks.null_source(gr.sizeof_gr_complex*1) 108 | self.blocks_null_sink_1 = blocks.null_sink(gr.sizeof_gr_complex*1) 109 | self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_gr_complex*1) 110 | 111 | 112 | 113 | ################################################## 114 | # Connections 115 | ################################################## 116 | self.msg_connect((self.devsync_peak_detector_0, 'shifts_out'), (self.devsync_alligner_0, 'phase_init')) 117 | self.connect((self.blocks_null_source_0, 0), (self.devsync_alligner_0, 0)) 118 | self.connect((self.blocks_null_source_0, 1), (self.devsync_alligner_0, 1)) 119 | self.connect((self.blocks_null_source_0, 2), (self.devsync_alligner_0, 2)) 120 | self.connect((self.blocks_null_source_0, 3), (self.devsync_alligner_0, 3)) 121 | self.connect((self.blocks_null_source_0, 0), (self.fft_filter_xxx_0_4, 0)) 122 | self.connect((self.blocks_null_source_0, 2), (self.fft_filter_xxx_0_4_0, 0)) 123 | self.connect((self.blocks_null_source_0, 1), (self.fft_filter_xxx_0_4_0_0, 0)) 124 | self.connect((self.blocks_null_source_0, 3), (self.fft_filter_xxx_0_4_0_0_0, 0)) 125 | self.connect((self.blocks_stream_to_vector_0_0, 0), (self.devsync_rms_normalization_0, 1)) 126 | self.connect((self.blocks_stream_to_vector_0_0_0_0_0, 0), (self.devsync_rms_normalization_0, 3)) 127 | self.connect((self.blocks_stream_to_vector_0_0_0_1, 0), (self.devsync_rms_normalization_0, 2)) 128 | self.connect((self.blocks_stream_to_vector_0_3_1, 0), (self.devsync_rms_normalization_0, 0)) 129 | self.connect((self.blocks_vector_source_x_1, 0), (self.blocks_null_sink_0, 0)) 130 | self.connect((self.blocks_vector_to_stream_1, 0), (self.devsync_peak_detector_0, 0)) 131 | self.connect((self.blocks_vector_to_stream_1_0, 0), (self.devsync_peak_detector_0, 2)) 132 | self.connect((self.blocks_vector_to_stream_1_1, 0), (self.devsync_peak_detector_0, 3)) 133 | self.connect((self.blocks_vector_to_stream_1_2, 0), (self.devsync_peak_detector_0, 1)) 134 | self.connect((self.devsync_alligner_0, 0), (self.blocks_null_sink_1, 0)) 135 | self.connect((self.devsync_alligner_0, 1), (self.blocks_null_sink_1, 1)) 136 | self.connect((self.devsync_alligner_0, 2), (self.blocks_null_sink_1, 2)) 137 | self.connect((self.devsync_alligner_0, 3), (self.blocks_null_sink_1, 3)) 138 | self.connect((self.devsync_rms_normalization_0, 0), (self.blocks_vector_to_stream_1, 0)) 139 | self.connect((self.devsync_rms_normalization_0, 2), (self.blocks_vector_to_stream_1_0, 0)) 140 | self.connect((self.devsync_rms_normalization_0, 3), (self.blocks_vector_to_stream_1_1, 0)) 141 | self.connect((self.devsync_rms_normalization_0, 1), (self.blocks_vector_to_stream_1_2, 0)) 142 | self.connect((self.fft_filter_xxx_0_4, 0), (self.blocks_stream_to_vector_0_3_1, 0)) 143 | self.connect((self.fft_filter_xxx_0_4_0, 0), (self.blocks_stream_to_vector_0_0_0_1, 0)) 144 | self.connect((self.fft_filter_xxx_0_4_0_0, 0), (self.blocks_stream_to_vector_0_0, 0)) 145 | self.connect((self.fft_filter_xxx_0_4_0_0_0, 0), (self.blocks_stream_to_vector_0_0_0_0_0, 0)) 146 | 147 | def closeEvent(self, event): 148 | self.settings = Qt.QSettings("GNU Radio", "top_block") 149 | self.settings.setValue("geometry", self.saveGeometry()) 150 | event.accept() 151 | 152 | def get_samp_rate(self): 153 | return self.samp_rate 154 | 155 | def set_samp_rate(self, samp_rate): 156 | self.samp_rate = samp_rate 157 | 158 | def get_num_streams(self): 159 | return self.num_streams 160 | 161 | def set_num_streams(self, num_streams): 162 | self.num_streams = num_streams 163 | 164 | def get_num_elements(self): 165 | return self.num_elements 166 | 167 | def set_num_elements(self, num_elements): 168 | self.num_elements = num_elements 169 | 170 | def get_long_seq(self): 171 | return self.long_seq 172 | 173 | def set_long_seq(self, long_seq): 174 | self.long_seq = long_seq 175 | self.fft_filter_xxx_0_4_0_0_0.set_taps((self.long_seq[::-1])) 176 | self.fft_filter_xxx_0_4_0_0.set_taps((self.long_seq[::-1])) 177 | self.fft_filter_xxx_0_4_0.set_taps((self.long_seq[::-1])) 178 | self.fft_filter_xxx_0_4.set_taps((self.long_seq[::-1])) 179 | self.blocks_vector_source_x_1.set_data(numpy.conj(self.long_seq) , []) 180 | 181 | 182 | def main(top_block_cls=top_block, options=None): 183 | 184 | from distutils.version import StrictVersion 185 | if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"): 186 | style = gr.prefs().get_string('qtgui', 'style', 'raster') 187 | Qt.QApplication.setGraphicsSystem(style) 188 | qapp = Qt.QApplication(sys.argv) 189 | 190 | tb = top_block_cls() 191 | tb.start() 192 | tb.show() 193 | 194 | def quitting(): 195 | tb.stop() 196 | tb.wait() 197 | qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting) 198 | qapp.exec_() 199 | 200 | 201 | if __name__ == '__main__': 202 | main() 203 | -------------------------------------------------------------------------------- /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 | if(APPLE) 175 | set(PYTHON_LINK_OPTIONS "-undefined dynamic_lookup") 176 | else() 177 | set(PYTHON_LINK_OPTIONS ${PYTHON_LIBRARIES}) 178 | endif(APPLE) 179 | SWIG_LINK_LIBRARIES(${name} ${PYTHON_LINK_OPTIONS} ${GR_SWIG_LIBRARIES}) 180 | if(${name} STREQUAL "runtime_swig") 181 | SET_TARGET_PROPERTIES(${SWIG_MODULE_runtime_swig_REAL_NAME} PROPERTIES DEFINE_SYMBOL "gnuradio_runtime_EXPORTS") 182 | endif(${name} STREQUAL "runtime_swig") 183 | 184 | endmacro(GR_SWIG_MAKE) 185 | 186 | ######################################################################## 187 | # Install swig targets generated by GR_SWIG_MAKE. Usage: 188 | # GR_SWIG_INSTALL( 189 | # TARGETS target target target... 190 | # [DESTINATION destination] 191 | # [COMPONENT component] 192 | # ) 193 | ######################################################################## 194 | macro(GR_SWIG_INSTALL) 195 | 196 | include(CMakeParseArgumentsCopy) 197 | CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN}) 198 | 199 | foreach(name ${GR_SWIG_INSTALL_TARGETS}) 200 | install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME} 201 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION} 202 | COMPONENT ${GR_SWIG_INSTALL_COMPONENT} 203 | ) 204 | 205 | include(GrPython) 206 | GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py 207 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION} 208 | COMPONENT ${GR_SWIG_INSTALL_COMPONENT} 209 | ) 210 | 211 | GR_LIBTOOL( 212 | TARGET ${SWIG_MODULE_${name}_REAL_NAME} 213 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION} 214 | ) 215 | 216 | endforeach(name) 217 | 218 | endmacro(GR_SWIG_INSTALL) 219 | 220 | ######################################################################## 221 | # Generate a python file that can determine swig dependencies. 222 | # Used by the make macro above to determine extra dependencies. 223 | # When you build C++, CMake figures out the header dependencies. 224 | # This code essentially performs that logic for swig includes. 225 | ######################################################################## 226 | file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py " 227 | 228 | import os, sys, re 229 | 230 | i_include_matcher = re.compile('%(include|import)\\s*[<|\"](.*)[>|\"]') 231 | h_include_matcher = re.compile('#(include)\\s*[<|\"](.*)[>|\"]') 232 | include_dirs = sys.argv[2].split(';') 233 | 234 | def get_swig_incs(file_path): 235 | if file_path.endswith('.i'): matcher = i_include_matcher 236 | else: matcher = h_include_matcher 237 | file_contents = open(file_path, 'r').read() 238 | return matcher.findall(file_contents, re.MULTILINE) 239 | 240 | def get_swig_deps(file_path, level): 241 | deps = [file_path] 242 | if level == 0: return deps 243 | for keyword, inc_file in get_swig_incs(file_path): 244 | for inc_dir in include_dirs: 245 | inc_path = os.path.join(inc_dir, inc_file) 246 | if not os.path.exists(inc_path): continue 247 | deps.extend(get_swig_deps(inc_path, level-1)) 248 | break #found, we dont search in lower prio inc dirs 249 | return deps 250 | 251 | if __name__ == '__main__': 252 | ifiles = sys.argv[1].split(';') 253 | deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], []) 254 | #sys.stderr.write(';'.join(set(deps)) + '\\n\\n') 255 | print(';'.join(set(deps))) 256 | ") 257 | -------------------------------------------------------------------------------- /lib/peak_detector_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | gr-devsync a phase synchronizer for mutliple SDR devices 4 | Copyright (C) 2018 George Vardakis 5 | 6 | This program 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 of the License, or 9 | (at your option) any later version. 10 | 11 | This program 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 this program. If not, see . 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #include 25 | #include "peak_detector_impl.h" 26 | #include 27 | #include 28 | #include 29 | namespace gr 30 | { 31 | namespace devsync 32 | { 33 | 34 | peak_detector::sptr 35 | peak_detector::make (size_t num_streams, size_t window, float scale, 36 | float influence, size_t discarted_samples) 37 | { 38 | return gnuradio::get_initial_sptr ( 39 | new peak_detector_impl (num_streams, window, scale, influence, 40 | discarted_samples)); 41 | } 42 | 43 | peak_detector_impl::peak_detector_impl (size_t num_streams, size_t window, 44 | float scale, float influence, 45 | size_t discarted_samples) : 46 | gr::sync_block ( 47 | "peak_detector", 48 | gr::io_signature::make (num_streams, num_streams, 49 | sizeof(gr_complex)), 50 | gr::io_signature::make (0, 0,0)), 51 | d_num_streams (num_streams), 52 | d_window (window), 53 | d_scale (scale), 54 | d_influence (influence), 55 | d_discarted_samples (discarted_samples), 56 | d_sample_counter (0), 57 | ov_state (WINDOW_FILL), 58 | d_synced_streams (0), 59 | d_ref_stream (0), 60 | d_cyc_buf_next_idx (0), 61 | d_discarted_samples_counter (0), 62 | d_ninput_items (0), 63 | d_noutput_items (0), 64 | d_phase_shifts_out (pmt::mp ("shifts_out")) 65 | { 66 | d_state_vector = new state[num_streams]; 67 | d_sample_difference = new size_t[num_streams]; 68 | d_zero_counter = new size_t[num_streams]; 69 | avgFilter = new float[num_streams]; 70 | stdFilter = new float[num_streams]; 71 | d_sum = new float[num_streams]; 72 | d_sumsqr = new float[num_streams]; 73 | d_amp_thres = new float[num_streams]; 74 | filteredY.resize (num_streams); 75 | d_max_sample = new gr_complex[num_streams]; 76 | d_max_abs_sample = new float[num_streams]; 77 | for (int i = 0; i < num_streams; i++) { 78 | d_state_vector[i] = NO_SYNC; 79 | d_sample_difference[i] = 0; 80 | d_max_sample[i] = 0; 81 | d_max_abs_sample[i] = 0; 82 | d_zero_counter[i] = 0; 83 | filteredY[i].resize (d_window); 84 | } 85 | message_port_register_out (d_phase_shifts_out); 86 | LOG_INFO("Discarding initial samples"); 87 | } 88 | 89 | peak_detector_impl::~peak_detector_impl () 90 | { 91 | } 92 | 93 | int 94 | peak_detector_impl::work (int noutput_items, 95 | gr_vector_const_void_star &input_items, 96 | gr_vector_void_star &output_items) 97 | { 98 | const gr_complex *in; 99 | float temp; 100 | d_ninput_items += noutput_items; 101 | 102 | /* At the beginning we discard some samples */ 103 | if (d_discarted_samples_counter < d_discarted_samples) { 104 | d_discarted_samples_counter += noutput_items; 105 | d_noutput_items += noutput_items; 106 | return noutput_items; 107 | } 108 | /* Next we estimate the noise floor */ 109 | if (ov_state == WINDOW_FILL) { 110 | if (d_sample_counter + noutput_items <= d_window) { 111 | for (int i = 0; i < d_num_streams; i++) { 112 | in = (const gr_complex *) input_items[i]; 113 | volk_32fc_magnitude_squared_32f ( 114 | filteredY[i].data () + d_sample_counter, in, noutput_items); 115 | } 116 | d_sample_counter += noutput_items; 117 | if (d_sample_counter + noutput_items == d_window) { 118 | ov_state = SYNCING; 119 | d_sample_counter = 0; 120 | mean_std (-1, 0); 121 | d_cyc_buf_next_idx++; 122 | } 123 | d_noutput_items += noutput_items; 124 | return noutput_items; 125 | } 126 | else { 127 | for (int i = 0; i < d_num_streams; i++) { 128 | in = (const gr_complex *) input_items[i]; 129 | volk_32fc_magnitude_squared_32f ( 130 | filteredY[i].data () + d_sample_counter, in, 131 | (d_window - d_sample_counter)); 132 | } 133 | d_sample_counter += (d_window - d_sample_counter); 134 | d_noutput_items += (d_window - d_sample_counter); 135 | ov_state = FIRST_SYNCING; 136 | mean_std (-1, 0); 137 | d_cyc_buf_next_idx++; 138 | LOG_INFO("Transmit the training sequence!"); 139 | } 140 | } 141 | if (ov_state == SYNCED) { 142 | d_noutput_items += noutput_items; 143 | return noutput_items; 144 | } 145 | int c; 146 | if (ov_state == FIRST_SYNCING) { 147 | c = (d_window - d_sample_counter); 148 | d_sample_counter = 0; 149 | } 150 | else { 151 | c = 0; 152 | } 153 | size_t prev_index; 154 | if (d_cyc_buf_next_idx == 0) { 155 | prev_index = (d_window - 1); 156 | } 157 | else { 158 | prev_index = (d_cyc_buf_next_idx - 1); 159 | } 160 | for (int i = c; i < noutput_items; i++) { 161 | 162 | if (ov_state == FIRST_SYNC_FOUND) { 163 | d_sample_counter++; 164 | } 165 | else if (ov_state == SYNCED) { 166 | d_noutput_items += (noutput_items - i); 167 | break; 168 | } 169 | d_noutput_items++; 170 | float curr_sample; 171 | for (int stream = 0; stream < d_num_streams; stream++) { 172 | in = (const gr_complex *) input_items[stream]; 173 | curr_sample = std::pow (std::real (in[i]), 2) 174 | + std::pow (std::imag (in[i]), 2); 175 | if (d_state_vector[stream] == SYNC) { 176 | continue; 177 | } 178 | 179 | /* The following three conditions will determine the existence 180 | * of a peak */ 181 | if ((curr_sample > 0.0001) 182 | && std::abs (curr_sample - avgFilter[stream]) 183 | > d_scale * filteredY[stream][prev_index]) { 184 | if (curr_sample > avgFilter[stream]) { 185 | if (curr_sample > d_max_abs_sample[stream]) { 186 | d_max_sample[stream] = in[i]; 187 | d_max_abs_sample[stream] = curr_sample; 188 | d_zero_counter[stream] = 0; 189 | } 190 | else { 191 | d_zero_counter[stream]++; 192 | } 193 | } 194 | temp = filteredY[stream][d_cyc_buf_next_idx]; 195 | filteredY[stream][d_cyc_buf_next_idx] = d_influence * curr_sample 196 | + (1 - d_influence) * filteredY[stream][prev_index]; 197 | mean_std (stream, temp); 198 | } 199 | else { 200 | temp = filteredY[stream][d_cyc_buf_next_idx]; 201 | filteredY[stream][d_cyc_buf_next_idx] = curr_sample; 202 | mean_std (stream, temp); 203 | } 204 | if (d_zero_counter[stream] > 100) { 205 | LOG_DEBUG ("Last max for stream %d is %f\n", stream, 206 | d_max_abs_sample[stream]); 207 | d_state_vector[stream] = SYNC; 208 | LOG_INFO("Stream %d synced", stream); 209 | d_synced_streams++; 210 | if (!(ov_state == FIRST_SYNC_FOUND)) { 211 | d_sample_counter = d_zero_counter[stream]; 212 | d_sample_difference[stream] = 0; 213 | ov_state = FIRST_SYNC_FOUND; 214 | } 215 | else { 216 | d_sample_difference[stream] = d_sample_counter 217 | - d_zero_counter[stream]; 218 | } 219 | if (d_synced_streams == d_num_streams) { 220 | d_ref_stream = stream; 221 | ov_state = SYNCED; 222 | LOG_INFO("All streams synced"); 223 | pmt::pmt_t tup = pmt::make_tuple ( 224 | pmt::from_uint64 (d_ref_stream), 225 | pmt::make_blob (d_sample_difference, 226 | d_num_streams * sizeof(size_t)), 227 | pmt::make_blob (d_max_sample, 228 | d_num_streams * sizeof(gr_complex))); 229 | message_port_pub (d_phase_shifts_out, tup); 230 | for (int l = 0; l < d_num_streams; l++) { 231 | LOG_INFO("Stream %d, sample offset %d\n", l, d_sample_difference[l]); 232 | } 233 | } 234 | } 235 | if (d_max_abs_sample[stream] > 0) { 236 | if (curr_sample > d_max_abs_sample[stream]) { 237 | d_zero_counter[stream] = 0; 238 | } 239 | else { 240 | d_zero_counter[stream]++; 241 | } 242 | } 243 | d_cyc_buf_next_idx = d_cyc_buf_next_idx % d_window; 244 | } 245 | } 246 | if (ov_state == FIRST_SYNCING) 247 | ov_state = SYNCING; 248 | 249 | return noutput_items; 250 | } 251 | void 252 | peak_detector_impl::mean_std (int stream, float discarded_val) 253 | { 254 | if (stream == -1) { 255 | for (int i = 0; i < d_num_streams; i++) { 256 | if (d_state_vector[i] == NO_SYNC) { 257 | float sum = std::accumulate (std::begin (filteredY[i]), 258 | std::end (filteredY[i]), 0.0); 259 | avgFilter[i] = sum / filteredY[i].size (); 260 | d_sum[i] = sum; 261 | 262 | float accum = 0.0; 263 | std::for_each (std::begin (filteredY[i]), std::end (filteredY[i]), 264 | [&](const float d) { 265 | accum += (d - avgFilter[i]) * (d - avgFilter[i]); 266 | }); 267 | stdFilter[i] = sqrt (accum / (filteredY[i].size () - 1)); 268 | 269 | std::for_each (std::begin (filteredY[i]), std::end (filteredY[i]), 270 | [&](const float d) { 271 | accum += (d * d); 272 | }); 273 | d_sumsqr[i] = accum; 274 | d_amp_thres[i] = avgFilter[i]; 275 | } 276 | } 277 | } 278 | else { 279 | if (d_state_vector[stream] == NO_SYNC) { 280 | double mean = 0, M2 = 0, variance = 0; 281 | d_sum[stream] = d_sum[stream] - discarded_val 282 | + filteredY[stream][d_cyc_buf_next_idx]; 283 | d_sumsqr[stream] = d_sumsqr[stream] - discarded_val * discarded_val 284 | + filteredY[stream][d_cyc_buf_next_idx] 285 | * filteredY[stream][d_cyc_buf_next_idx]; 286 | avgFilter[stream] = d_sum[stream] / d_window; 287 | stdFilter[stream] = std::sqrt ( 288 | (d_sumsqr[stream] - 2 * avgFilter[stream] * d_sum[stream] 289 | + d_window * avgFilter[stream] * avgFilter[stream]) 290 | / (d_window - 1)); 291 | 292 | } 293 | } 294 | } 295 | 296 | } /* namespace devsync */ 297 | } /* namespace gr */ 298 | 299 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/doxygen/swig_doc.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-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 | 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, time 31 | 32 | from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile 33 | from doxyxml import DoxyOther, base 34 | 35 | def py_name(name): 36 | bits = name.split('_') 37 | return '_'.join(bits[1:]) 38 | 39 | def make_name(name): 40 | bits = name.split('_') 41 | return bits[0] + '_make_' + '_'.join(bits[1:]) 42 | 43 | 44 | class Block(object): 45 | """ 46 | Checks if doxyxml produced objects correspond to a gnuradio block. 47 | """ 48 | 49 | @classmethod 50 | def includes(cls, item): 51 | if not isinstance(item, DoxyClass): 52 | return False 53 | # Check for a parsing error. 54 | if item.error(): 55 | return False 56 | friendname = make_name(item.name()) 57 | is_a_block = item.has_member(friendname, DoxyFriend) 58 | # But now sometimes the make function isn't a friend so check again. 59 | if not is_a_block: 60 | is_a_block = di.has_member(friendname, DoxyFunction) 61 | return is_a_block 62 | 63 | class Block2(object): 64 | """ 65 | Checks if doxyxml produced objects correspond to a new style 66 | gnuradio block. 67 | """ 68 | 69 | @classmethod 70 | def includes(cls, item): 71 | if not isinstance(item, DoxyClass): 72 | return False 73 | # Check for a parsing error. 74 | if item.error(): 75 | return False 76 | is_a_block2 = item.has_member('make', DoxyFunction) and item.has_member('sptr', DoxyOther) 77 | return is_a_block2 78 | 79 | 80 | def utoascii(text): 81 | """ 82 | Convert unicode text into ascii and escape quotes. 83 | """ 84 | if text is None: 85 | return '' 86 | out = text.encode('ascii', 'replace') 87 | out = out.replace('"', '\\"') 88 | return out 89 | 90 | 91 | def combine_descriptions(obj): 92 | """ 93 | Combines the brief and detailed descriptions of an object together. 94 | """ 95 | description = [] 96 | bd = obj.brief_description.strip() 97 | dd = obj.detailed_description.strip() 98 | if bd: 99 | description.append(bd) 100 | if dd: 101 | description.append(dd) 102 | return utoascii('\n\n'.join(description)).strip() 103 | 104 | def format_params(parameteritems): 105 | output = ['Args:'] 106 | template = ' {0} : {1}' 107 | for pi in parameteritems: 108 | output.append(template.format(pi.name, pi.description)) 109 | return '\n'.join(output) 110 | 111 | entry_templ = '%feature("docstring") {name} "{docstring}"' 112 | def make_entry(obj, name=None, templ="{description}", description=None, params=[]): 113 | """ 114 | Create a docstring entry for a swig interface file. 115 | 116 | obj - a doxyxml object from which documentation will be extracted. 117 | name - the name of the C object (defaults to obj.name()) 118 | templ - an optional template for the docstring containing only one 119 | variable named 'description'. 120 | description - if this optional variable is set then it's value is 121 | used as the description instead of extracting it from obj. 122 | """ 123 | if name is None: 124 | name=obj.name() 125 | if "operator " in name: 126 | return '' 127 | if description is None: 128 | description = combine_descriptions(obj) 129 | if params: 130 | description += '\n\n' 131 | description += utoascii(format_params(params)) 132 | docstring = templ.format(description=description) 133 | if not docstring: 134 | return '' 135 | return entry_templ.format( 136 | name=name, 137 | docstring=docstring, 138 | ) 139 | 140 | 141 | def make_func_entry(func, name=None, description=None, params=None): 142 | """ 143 | Create a function docstring entry for a swig interface file. 144 | 145 | func - a doxyxml object from which documentation will be extracted. 146 | name - the name of the C object (defaults to func.name()) 147 | description - if this optional variable is set then it's value is 148 | used as the description instead of extracting it from func. 149 | params - a parameter list that overrides using func.params. 150 | """ 151 | #if params is None: 152 | # params = func.params 153 | #params = [prm.declname for prm in params] 154 | #if params: 155 | # sig = "Params: (%s)" % ", ".join(params) 156 | #else: 157 | # sig = "Params: (NONE)" 158 | #templ = "{description}\n\n" + sig 159 | #return make_entry(func, name=name, templ=utoascii(templ), 160 | # description=description) 161 | return make_entry(func, name=name, description=description, params=params) 162 | 163 | 164 | def make_class_entry(klass, description=None, ignored_methods=[], params=None): 165 | """ 166 | Create a class docstring for a swig interface file. 167 | """ 168 | if params is None: 169 | params = klass.params 170 | output = [] 171 | output.append(make_entry(klass, description=description, params=params)) 172 | for func in klass.in_category(DoxyFunction): 173 | if func.name() not in ignored_methods: 174 | name = klass.name() + '::' + func.name() 175 | output.append(make_func_entry(func, name=name)) 176 | return "\n\n".join(output) 177 | 178 | 179 | def make_block_entry(di, block): 180 | """ 181 | Create class and function docstrings of a gnuradio block for a 182 | swig interface file. 183 | """ 184 | descriptions = [] 185 | # Get the documentation associated with the class. 186 | class_desc = combine_descriptions(block) 187 | if class_desc: 188 | descriptions.append(class_desc) 189 | # Get the documentation associated with the make function 190 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 191 | make_func_desc = combine_descriptions(make_func) 192 | if make_func_desc: 193 | descriptions.append(make_func_desc) 194 | # Get the documentation associated with the file 195 | try: 196 | block_file = di.get_member(block.name() + ".h", DoxyFile) 197 | file_desc = combine_descriptions(block_file) 198 | if file_desc: 199 | descriptions.append(file_desc) 200 | except base.Base.NoSuchMember: 201 | # Don't worry if we can't find a matching file. 202 | pass 203 | # And join them all together to make a super duper description. 204 | super_description = "\n\n".join(descriptions) 205 | # Associate the combined description with the class and 206 | # the make function. 207 | output = [] 208 | output.append(make_class_entry(block, description=super_description)) 209 | output.append(make_func_entry(make_func, description=super_description, 210 | params=block.params)) 211 | return "\n\n".join(output) 212 | 213 | def make_block2_entry(di, block): 214 | """ 215 | Create class and function docstrings of a new style gnuradio block for a 216 | swig interface file. 217 | """ 218 | descriptions = [] 219 | # For new style blocks all the relevant documentation should be 220 | # associated with the 'make' method. 221 | class_description = combine_descriptions(block) 222 | make_func = block.get_member('make', DoxyFunction) 223 | make_description = combine_descriptions(make_func) 224 | description = class_description + "\n\nConstructor Specific Documentation:\n\n" + make_description 225 | # Associate the combined description with the class and 226 | # the make function. 227 | output = [] 228 | output.append(make_class_entry( 229 | block, description=description, 230 | ignored_methods=['make'], params=make_func.params)) 231 | makename = block.name() + '::make' 232 | output.append(make_func_entry( 233 | make_func, name=makename, description=description, 234 | params=make_func.params)) 235 | return "\n\n".join(output) 236 | 237 | def make_swig_interface_file(di, swigdocfilename, custom_output=None): 238 | 239 | output = [""" 240 | /* 241 | * This file was automatically generated using swig_doc.py. 242 | * 243 | * Any changes to it will be lost next time it is regenerated. 244 | */ 245 | """] 246 | 247 | if custom_output is not None: 248 | output.append(custom_output) 249 | 250 | # Create docstrings for the blocks. 251 | blocks = di.in_category(Block) 252 | blocks2 = di.in_category(Block2) 253 | 254 | make_funcs = set([]) 255 | for block in blocks: 256 | try: 257 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 258 | # Don't want to risk writing to output twice. 259 | if make_func.name() not in make_funcs: 260 | make_funcs.add(make_func.name()) 261 | output.append(make_block_entry(di, block)) 262 | except block.ParsingError: 263 | sys.stderr.write('Parsing error for block {0}\n'.format(block.name())) 264 | raise 265 | 266 | for block in blocks2: 267 | try: 268 | make_func = block.get_member('make', DoxyFunction) 269 | make_func_name = block.name() +'::make' 270 | # Don't want to risk writing to output twice. 271 | if make_func_name not in make_funcs: 272 | make_funcs.add(make_func_name) 273 | output.append(make_block2_entry(di, block)) 274 | except block.ParsingError: 275 | sys.stderr.write('Parsing error for block {0}\n'.format(block.name())) 276 | raise 277 | 278 | # Create docstrings for functions 279 | # Don't include the make functions since they have already been dealt with. 280 | funcs = [f for f in di.in_category(DoxyFunction) 281 | if f.name() not in make_funcs and not f.name().startswith('std::')] 282 | for f in funcs: 283 | try: 284 | output.append(make_func_entry(f)) 285 | except f.ParsingError: 286 | sys.stderr.write('Parsing error for function {0}\n'.format(f.name())) 287 | 288 | # Create docstrings for classes 289 | block_names = [block.name() for block in blocks] 290 | block_names += [block.name() for block in blocks2] 291 | klasses = [k for k in di.in_category(DoxyClass) 292 | if k.name() not in block_names and not k.name().startswith('std::')] 293 | for k in klasses: 294 | try: 295 | output.append(make_class_entry(k)) 296 | except k.ParsingError: 297 | sys.stderr.write('Parsing error for class {0}\n'.format(k.name())) 298 | 299 | # Docstrings are not created for anything that is not a function or a class. 300 | # If this excludes anything important please add it here. 301 | 302 | output = "\n\n".join(output) 303 | 304 | swig_doc = file(swigdocfilename, 'w') 305 | swig_doc.write(output) 306 | swig_doc.close() 307 | 308 | if __name__ == "__main__": 309 | # Parse command line options and set up doxyxml. 310 | err_msg = "Execute using: python swig_doc.py xml_path outputfilename" 311 | if len(sys.argv) != 3: 312 | raise StandardError(err_msg) 313 | xml_path = sys.argv[1] 314 | swigdocfilename = sys.argv[2] 315 | di = DoxyIndex(xml_path) 316 | 317 | # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined! 318 | # This is presumably a bug in SWIG. 319 | #msg_q = di.get_member(u'gr_msg_queue', DoxyClass) 320 | #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction) 321 | #delete_head = msg_q.get_member(u'delete_head', DoxyFunction) 322 | output = [] 323 | #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail')) 324 | #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head')) 325 | custom_output = "\n\n".join(output) 326 | 327 | # Generate the docstrings interface file. 328 | make_swig_interface_file(di, swigdocfilename, custom_output=custom_output) 329 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/indexsuper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Generated Thu Jun 11 18:43:54 2009 by generateDS.py. 5 | # 6 | 7 | import sys 8 | import getopt 9 | from string import lower as str_lower 10 | from xml.dom import minidom 11 | from xml.dom import Node 12 | 13 | # 14 | # User methods 15 | # 16 | # Calls to the methods in these classes are generated by generateDS.py. 17 | # You can replace these methods by re-implementing the following class 18 | # in a module named generatedssuper.py. 19 | 20 | try: 21 | from generatedssuper import GeneratedsSuper 22 | except ImportError, exp: 23 | 24 | class GeneratedsSuper: 25 | def format_string(self, input_data, input_name=''): 26 | return input_data 27 | def format_integer(self, input_data, input_name=''): 28 | return '%d' % input_data 29 | def format_float(self, input_data, input_name=''): 30 | return '%f' % input_data 31 | def format_double(self, input_data, input_name=''): 32 | return '%e' % input_data 33 | def format_boolean(self, input_data, input_name=''): 34 | return '%s' % input_data 35 | 36 | 37 | # 38 | # If you have installed IPython you can uncomment and use the following. 39 | # IPython is available from http://ipython.scipy.org/. 40 | # 41 | 42 | ## from IPython.Shell import IPShellEmbed 43 | ## args = '' 44 | ## ipshell = IPShellEmbed(args, 45 | ## banner = 'Dropping into IPython', 46 | ## exit_msg = 'Leaving Interpreter, back to program.') 47 | 48 | # Then use the following line where and when you want to drop into the 49 | # IPython shell: 50 | # ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') 51 | 52 | # 53 | # Globals 54 | # 55 | 56 | ExternalEncoding = 'ascii' 57 | 58 | # 59 | # Support/utility functions. 60 | # 61 | 62 | def showIndent(outfile, level): 63 | for idx in range(level): 64 | outfile.write(' ') 65 | 66 | def quote_xml(inStr): 67 | s1 = (isinstance(inStr, basestring) and inStr or 68 | '%s' % inStr) 69 | s1 = s1.replace('&', '&') 70 | s1 = s1.replace('<', '<') 71 | s1 = s1.replace('>', '>') 72 | return s1 73 | 74 | def quote_attrib(inStr): 75 | s1 = (isinstance(inStr, basestring) and inStr or 76 | '%s' % inStr) 77 | s1 = s1.replace('&', '&') 78 | s1 = s1.replace('<', '<') 79 | s1 = s1.replace('>', '>') 80 | if '"' in s1: 81 | if "'" in s1: 82 | s1 = '"%s"' % s1.replace('"', """) 83 | else: 84 | s1 = "'%s'" % s1 85 | else: 86 | s1 = '"%s"' % s1 87 | return s1 88 | 89 | def quote_python(inStr): 90 | s1 = inStr 91 | if s1.find("'") == -1: 92 | if s1.find('\n') == -1: 93 | return "'%s'" % s1 94 | else: 95 | return "'''%s'''" % s1 96 | else: 97 | if s1.find('"') != -1: 98 | s1 = s1.replace('"', '\\"') 99 | if s1.find('\n') == -1: 100 | return '"%s"' % s1 101 | else: 102 | return '"""%s"""' % s1 103 | 104 | 105 | class MixedContainer: 106 | # Constants for category: 107 | CategoryNone = 0 108 | CategoryText = 1 109 | CategorySimple = 2 110 | CategoryComplex = 3 111 | # Constants for content_type: 112 | TypeNone = 0 113 | TypeText = 1 114 | TypeString = 2 115 | TypeInteger = 3 116 | TypeFloat = 4 117 | TypeDecimal = 5 118 | TypeDouble = 6 119 | TypeBoolean = 7 120 | def __init__(self, category, content_type, name, value): 121 | self.category = category 122 | self.content_type = content_type 123 | self.name = name 124 | self.value = value 125 | def getCategory(self): 126 | return self.category 127 | def getContenttype(self, content_type): 128 | return self.content_type 129 | def getValue(self): 130 | return self.value 131 | def getName(self): 132 | return self.name 133 | def export(self, outfile, level, name, namespace): 134 | if self.category == MixedContainer.CategoryText: 135 | outfile.write(self.value) 136 | elif self.category == MixedContainer.CategorySimple: 137 | self.exportSimple(outfile, level, name) 138 | else: # category == MixedContainer.CategoryComplex 139 | self.value.export(outfile, level, namespace,name) 140 | def exportSimple(self, outfile, level, name): 141 | if self.content_type == MixedContainer.TypeString: 142 | outfile.write('<%s>%s' % (self.name, self.value, self.name)) 143 | elif self.content_type == MixedContainer.TypeInteger or \ 144 | self.content_type == MixedContainer.TypeBoolean: 145 | outfile.write('<%s>%d' % (self.name, self.value, self.name)) 146 | elif self.content_type == MixedContainer.TypeFloat or \ 147 | self.content_type == MixedContainer.TypeDecimal: 148 | outfile.write('<%s>%f' % (self.name, self.value, self.name)) 149 | elif self.content_type == MixedContainer.TypeDouble: 150 | outfile.write('<%s>%g' % (self.name, self.value, self.name)) 151 | def exportLiteral(self, outfile, level, name): 152 | if self.category == MixedContainer.CategoryText: 153 | showIndent(outfile, level) 154 | outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ 155 | (self.category, self.content_type, self.name, self.value)) 156 | elif self.category == MixedContainer.CategorySimple: 157 | showIndent(outfile, level) 158 | outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ 159 | (self.category, self.content_type, self.name, self.value)) 160 | else: # category == MixedContainer.CategoryComplex 161 | showIndent(outfile, level) 162 | outfile.write('MixedContainer(%d, %d, "%s",\n' % \ 163 | (self.category, self.content_type, self.name,)) 164 | self.value.exportLiteral(outfile, level + 1) 165 | showIndent(outfile, level) 166 | outfile.write(')\n') 167 | 168 | 169 | class _MemberSpec(object): 170 | def __init__(self, name='', data_type='', container=0): 171 | self.name = name 172 | self.data_type = data_type 173 | self.container = container 174 | def set_name(self, name): self.name = name 175 | def get_name(self): return self.name 176 | def set_data_type(self, data_type): self.data_type = data_type 177 | def get_data_type(self): return self.data_type 178 | def set_container(self, container): self.container = container 179 | def get_container(self): return self.container 180 | 181 | 182 | # 183 | # Data representation classes. 184 | # 185 | 186 | class DoxygenType(GeneratedsSuper): 187 | subclass = None 188 | superclass = None 189 | def __init__(self, version=None, compound=None): 190 | self.version = version 191 | if compound is None: 192 | self.compound = [] 193 | else: 194 | self.compound = compound 195 | def factory(*args_, **kwargs_): 196 | if DoxygenType.subclass: 197 | return DoxygenType.subclass(*args_, **kwargs_) 198 | else: 199 | return DoxygenType(*args_, **kwargs_) 200 | factory = staticmethod(factory) 201 | def get_compound(self): return self.compound 202 | def set_compound(self, compound): self.compound = compound 203 | def add_compound(self, value): self.compound.append(value) 204 | def insert_compound(self, index, value): self.compound[index] = value 205 | def get_version(self): return self.version 206 | def set_version(self, version): self.version = version 207 | def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''): 208 | showIndent(outfile, level) 209 | outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) 210 | self.exportAttributes(outfile, level, namespace_, name_='DoxygenType') 211 | if self.hasContent_(): 212 | outfile.write('>\n') 213 | self.exportChildren(outfile, level + 1, namespace_, name_) 214 | showIndent(outfile, level) 215 | outfile.write('\n' % (namespace_, name_)) 216 | else: 217 | outfile.write(' />\n') 218 | def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'): 219 | outfile.write(' version=%s' % (self.format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), )) 220 | def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'): 221 | for compound_ in self.compound: 222 | compound_.export(outfile, level, namespace_, name_='compound') 223 | def hasContent_(self): 224 | if ( 225 | self.compound is not None 226 | ): 227 | return True 228 | else: 229 | return False 230 | def exportLiteral(self, outfile, level, name_='DoxygenType'): 231 | level += 1 232 | self.exportLiteralAttributes(outfile, level, name_) 233 | if self.hasContent_(): 234 | self.exportLiteralChildren(outfile, level, name_) 235 | def exportLiteralAttributes(self, outfile, level, name_): 236 | if self.version is not None: 237 | showIndent(outfile, level) 238 | outfile.write('version = %s,\n' % (self.version,)) 239 | def exportLiteralChildren(self, outfile, level, name_): 240 | showIndent(outfile, level) 241 | outfile.write('compound=[\n') 242 | level += 1 243 | for compound in self.compound: 244 | showIndent(outfile, level) 245 | outfile.write('model_.compound(\n') 246 | compound.exportLiteral(outfile, level, name_='compound') 247 | showIndent(outfile, level) 248 | outfile.write('),\n') 249 | level -= 1 250 | showIndent(outfile, level) 251 | outfile.write('],\n') 252 | def build(self, node_): 253 | attrs = node_.attributes 254 | self.buildAttributes(attrs) 255 | for child_ in node_.childNodes: 256 | nodeName_ = child_.nodeName.split(':')[-1] 257 | self.buildChildren(child_, nodeName_) 258 | def buildAttributes(self, attrs): 259 | if attrs.get('version'): 260 | self.version = attrs.get('version').value 261 | def buildChildren(self, child_, nodeName_): 262 | if child_.nodeType == Node.ELEMENT_NODE and \ 263 | nodeName_ == 'compound': 264 | obj_ = CompoundType.factory() 265 | obj_.build(child_) 266 | self.compound.append(obj_) 267 | # end class DoxygenType 268 | 269 | 270 | class CompoundType(GeneratedsSuper): 271 | subclass = None 272 | superclass = None 273 | def __init__(self, kind=None, refid=None, name=None, member=None): 274 | self.kind = kind 275 | self.refid = refid 276 | self.name = name 277 | if member is None: 278 | self.member = [] 279 | else: 280 | self.member = member 281 | def factory(*args_, **kwargs_): 282 | if CompoundType.subclass: 283 | return CompoundType.subclass(*args_, **kwargs_) 284 | else: 285 | return CompoundType(*args_, **kwargs_) 286 | factory = staticmethod(factory) 287 | def get_name(self): return self.name 288 | def set_name(self, name): self.name = name 289 | def get_member(self): return self.member 290 | def set_member(self, member): self.member = member 291 | def add_member(self, value): self.member.append(value) 292 | def insert_member(self, index, value): self.member[index] = value 293 | def get_kind(self): return self.kind 294 | def set_kind(self, kind): self.kind = kind 295 | def get_refid(self): return self.refid 296 | def set_refid(self, refid): self.refid = refid 297 | def export(self, outfile, level, namespace_='', name_='CompoundType', namespacedef_=''): 298 | showIndent(outfile, level) 299 | outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) 300 | self.exportAttributes(outfile, level, namespace_, name_='CompoundType') 301 | if self.hasContent_(): 302 | outfile.write('>\n') 303 | self.exportChildren(outfile, level + 1, namespace_, name_) 304 | showIndent(outfile, level) 305 | outfile.write('\n' % (namespace_, name_)) 306 | else: 307 | outfile.write(' />\n') 308 | def exportAttributes(self, outfile, level, namespace_='', name_='CompoundType'): 309 | outfile.write(' kind=%s' % (quote_attrib(self.kind), )) 310 | outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) 311 | def exportChildren(self, outfile, level, namespace_='', name_='CompoundType'): 312 | if self.name is not None: 313 | showIndent(outfile, level) 314 | outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) 315 | for member_ in self.member: 316 | member_.export(outfile, level, namespace_, name_='member') 317 | def hasContent_(self): 318 | if ( 319 | self.name is not None or 320 | self.member is not None 321 | ): 322 | return True 323 | else: 324 | return False 325 | def exportLiteral(self, outfile, level, name_='CompoundType'): 326 | level += 1 327 | self.exportLiteralAttributes(outfile, level, name_) 328 | if self.hasContent_(): 329 | self.exportLiteralChildren(outfile, level, name_) 330 | def exportLiteralAttributes(self, outfile, level, name_): 331 | if self.kind is not None: 332 | showIndent(outfile, level) 333 | outfile.write('kind = "%s",\n' % (self.kind,)) 334 | if self.refid is not None: 335 | showIndent(outfile, level) 336 | outfile.write('refid = %s,\n' % (self.refid,)) 337 | def exportLiteralChildren(self, outfile, level, name_): 338 | showIndent(outfile, level) 339 | outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) 340 | showIndent(outfile, level) 341 | outfile.write('member=[\n') 342 | level += 1 343 | for member in self.member: 344 | showIndent(outfile, level) 345 | outfile.write('model_.member(\n') 346 | member.exportLiteral(outfile, level, name_='member') 347 | showIndent(outfile, level) 348 | outfile.write('),\n') 349 | level -= 1 350 | showIndent(outfile, level) 351 | outfile.write('],\n') 352 | def build(self, node_): 353 | attrs = node_.attributes 354 | self.buildAttributes(attrs) 355 | for child_ in node_.childNodes: 356 | nodeName_ = child_.nodeName.split(':')[-1] 357 | self.buildChildren(child_, nodeName_) 358 | def buildAttributes(self, attrs): 359 | if attrs.get('kind'): 360 | self.kind = attrs.get('kind').value 361 | if attrs.get('refid'): 362 | self.refid = attrs.get('refid').value 363 | def buildChildren(self, child_, nodeName_): 364 | if child_.nodeType == Node.ELEMENT_NODE and \ 365 | nodeName_ == 'name': 366 | name_ = '' 367 | for text__content_ in child_.childNodes: 368 | name_ += text__content_.nodeValue 369 | self.name = name_ 370 | elif child_.nodeType == Node.ELEMENT_NODE and \ 371 | nodeName_ == 'member': 372 | obj_ = MemberType.factory() 373 | obj_.build(child_) 374 | self.member.append(obj_) 375 | # end class CompoundType 376 | 377 | 378 | class MemberType(GeneratedsSuper): 379 | subclass = None 380 | superclass = None 381 | def __init__(self, kind=None, refid=None, name=None): 382 | self.kind = kind 383 | self.refid = refid 384 | self.name = name 385 | def factory(*args_, **kwargs_): 386 | if MemberType.subclass: 387 | return MemberType.subclass(*args_, **kwargs_) 388 | else: 389 | return MemberType(*args_, **kwargs_) 390 | factory = staticmethod(factory) 391 | def get_name(self): return self.name 392 | def set_name(self, name): self.name = name 393 | def get_kind(self): return self.kind 394 | def set_kind(self, kind): self.kind = kind 395 | def get_refid(self): return self.refid 396 | def set_refid(self, refid): self.refid = refid 397 | def export(self, outfile, level, namespace_='', name_='MemberType', namespacedef_=''): 398 | showIndent(outfile, level) 399 | outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) 400 | self.exportAttributes(outfile, level, namespace_, name_='MemberType') 401 | if self.hasContent_(): 402 | outfile.write('>\n') 403 | self.exportChildren(outfile, level + 1, namespace_, name_) 404 | showIndent(outfile, level) 405 | outfile.write('\n' % (namespace_, name_)) 406 | else: 407 | outfile.write(' />\n') 408 | def exportAttributes(self, outfile, level, namespace_='', name_='MemberType'): 409 | outfile.write(' kind=%s' % (quote_attrib(self.kind), )) 410 | outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) 411 | def exportChildren(self, outfile, level, namespace_='', name_='MemberType'): 412 | if self.name is not None: 413 | showIndent(outfile, level) 414 | outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) 415 | def hasContent_(self): 416 | if ( 417 | self.name is not None 418 | ): 419 | return True 420 | else: 421 | return False 422 | def exportLiteral(self, outfile, level, name_='MemberType'): 423 | level += 1 424 | self.exportLiteralAttributes(outfile, level, name_) 425 | if self.hasContent_(): 426 | self.exportLiteralChildren(outfile, level, name_) 427 | def exportLiteralAttributes(self, outfile, level, name_): 428 | if self.kind is not None: 429 | showIndent(outfile, level) 430 | outfile.write('kind = "%s",\n' % (self.kind,)) 431 | if self.refid is not None: 432 | showIndent(outfile, level) 433 | outfile.write('refid = %s,\n' % (self.refid,)) 434 | def exportLiteralChildren(self, outfile, level, name_): 435 | showIndent(outfile, level) 436 | outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) 437 | def build(self, node_): 438 | attrs = node_.attributes 439 | self.buildAttributes(attrs) 440 | for child_ in node_.childNodes: 441 | nodeName_ = child_.nodeName.split(':')[-1] 442 | self.buildChildren(child_, nodeName_) 443 | def buildAttributes(self, attrs): 444 | if attrs.get('kind'): 445 | self.kind = attrs.get('kind').value 446 | if attrs.get('refid'): 447 | self.refid = attrs.get('refid').value 448 | def buildChildren(self, child_, nodeName_): 449 | if child_.nodeType == Node.ELEMENT_NODE and \ 450 | nodeName_ == 'name': 451 | name_ = '' 452 | for text__content_ in child_.childNodes: 453 | name_ += text__content_.nodeValue 454 | self.name = name_ 455 | # end class MemberType 456 | 457 | 458 | USAGE_TEXT = """ 459 | Usage: python .py [ -s ] 460 | Options: 461 | -s Use the SAX parser, not the minidom parser. 462 | """ 463 | 464 | def usage(): 465 | print USAGE_TEXT 466 | sys.exit(1) 467 | 468 | 469 | def parse(inFileName): 470 | doc = minidom.parse(inFileName) 471 | rootNode = doc.documentElement 472 | rootObj = DoxygenType.factory() 473 | rootObj.build(rootNode) 474 | # Enable Python to collect the space used by the DOM. 475 | doc = None 476 | sys.stdout.write('\n') 477 | rootObj.export(sys.stdout, 0, name_="doxygenindex", 478 | namespacedef_='') 479 | return rootObj 480 | 481 | 482 | def parseString(inString): 483 | doc = minidom.parseString(inString) 484 | rootNode = doc.documentElement 485 | rootObj = DoxygenType.factory() 486 | rootObj.build(rootNode) 487 | # Enable Python to collect the space used by the DOM. 488 | doc = None 489 | sys.stdout.write('\n') 490 | rootObj.export(sys.stdout, 0, name_="doxygenindex", 491 | namespacedef_='') 492 | return rootObj 493 | 494 | 495 | def parseLiteral(inFileName): 496 | doc = minidom.parse(inFileName) 497 | rootNode = doc.documentElement 498 | rootObj = DoxygenType.factory() 499 | rootObj.build(rootNode) 500 | # Enable Python to collect the space used by the DOM. 501 | doc = None 502 | sys.stdout.write('from index import *\n\n') 503 | sys.stdout.write('rootObj = doxygenindex(\n') 504 | rootObj.exportLiteral(sys.stdout, 0, name_="doxygenindex") 505 | sys.stdout.write(')\n') 506 | return rootObj 507 | 508 | 509 | def main(): 510 | args = sys.argv[1:] 511 | if len(args) == 1: 512 | parse(args[0]) 513 | else: 514 | usage() 515 | 516 | 517 | 518 | 519 | if __name__ == '__main__': 520 | main() 521 | #import pdb 522 | #pdb.run('main()') 523 | 524 | --------------------------------------------------------------------------------