Initial commit - gsm-receiver with removed quick hacks
This commit is contained in:
commit
437f5467a1
|
@ -0,0 +1,5 @@
|
|||
build
|
||||
*.o
|
||||
*.log
|
||||
*~
|
||||
*qa_*
|
|
@ -0,0 +1,155 @@
|
|||
# Copyright 2011,2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
########################################################################
|
||||
# Project setup
|
||||
########################################################################
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(gr-gsm CXX C)
|
||||
enable_testing()
|
||||
|
||||
#select the release build type by default to get optimization flags
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
message(STATUS "Build type not specified: defaulting to release.")
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||
|
||||
########################################################################
|
||||
# Compiler specific setup
|
||||
########################################################################
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32)
|
||||
#http://gcc.gnu.org/wiki/Visibility
|
||||
add_definitions(-fvisibility=hidden)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Find boost
|
||||
########################################################################
|
||||
if(UNIX AND EXISTS "/usr/lib64")
|
||||
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
|
||||
endif(UNIX AND EXISTS "/usr/lib64")
|
||||
set(Boost_ADDITIONAL_VERSIONS
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
)
|
||||
find_package(Boost "1.35" COMPONENTS filesystem system)
|
||||
|
||||
if(NOT Boost_FOUND)
|
||||
message(FATAL_ERROR "Boost required to compile gsm")
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Install directories
|
||||
########################################################################
|
||||
include(GrPlatform) #define LIB_SUFFIX
|
||||
set(GR_RUNTIME_DIR bin)
|
||||
set(GR_LIBRARY_DIR lib${LIB_SUFFIX})
|
||||
set(GR_INCLUDE_DIR include/gsm)
|
||||
set(GR_DATA_DIR share)
|
||||
set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME})
|
||||
set(GR_DOC_DIR ${GR_DATA_DIR}/doc)
|
||||
set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME})
|
||||
set(GR_CONF_DIR etc)
|
||||
set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d)
|
||||
set(GR_LIBEXEC_DIR libexec)
|
||||
set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME})
|
||||
set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
|
||||
|
||||
########################################################################
|
||||
# Find gnuradio build dependencies
|
||||
########################################################################
|
||||
find_package(GnuradioRuntime)
|
||||
find_package(CppUnit)
|
||||
|
||||
# To run a more advanced search for GNU Radio and it's components and
|
||||
# versions, use the following. Add any components required to the list
|
||||
# of GR_REQUIRED_COMPONENTS (in all caps) and change "version" to the
|
||||
# minimum API compatible version required.
|
||||
#
|
||||
# set(GR_REQUIRED_COMPONENTS RUNTIME BLOCKS FILTER ...)
|
||||
# find_package(Gnuradio "version")
|
||||
|
||||
if(NOT GNURADIO_RUNTIME_FOUND)
|
||||
message(FATAL_ERROR "GnuRadio Runtime required to compile gsm")
|
||||
endif()
|
||||
if(NOT CPPUNIT_FOUND)
|
||||
message(FATAL_ERROR "CppUnit required to compile gsm")
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Setup the include and linker paths
|
||||
########################################################################
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/lib
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_BINARY_DIR}/lib
|
||||
${CMAKE_BINARY_DIR}/include
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${CPPUNIT_INCLUDE_DIRS}
|
||||
${GNURADIO_RUNTIME_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
link_directories(
|
||||
${Boost_LIBRARY_DIRS}
|
||||
${CPPUNIT_LIBRARY_DIRS}
|
||||
${GNURADIO_RUNTIME_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
# Set component parameters
|
||||
set(GR_GSM_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE)
|
||||
set(GR_GSM_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE)
|
||||
|
||||
########################################################################
|
||||
# Create uninstall target
|
||||
########################################################################
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
|
||||
@ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Add subdirectories
|
||||
########################################################################
|
||||
add_subdirectory(include/gsm)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(swig)
|
||||
add_subdirectory(python)
|
||||
add_subdirectory(grc)
|
||||
add_subdirectory(apps)
|
||||
add_subdirectory(docs)
|
||||
|
||||
########################################################################
|
||||
# Install cmake search helper for this library
|
||||
########################################################################
|
||||
install(FILES cmake/Modules/gsmConfig.cmake
|
||||
DESTINATION lib/cmake/gsm
|
||||
)
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
include(GrPython)
|
||||
|
||||
GR_PYTHON_INSTALL(
|
||||
PROGRAMS
|
||||
DESTINATION bin
|
||||
)
|
|
@ -0,0 +1,138 @@
|
|||
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
|
||||
#
|
||||
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for
|
||||
# parsing the arguments given to that macro or function.
|
||||
# It processes the arguments and defines a set of variables which hold the
|
||||
# values of the respective options.
|
||||
#
|
||||
# The <options> argument contains all options for the respective macro,
|
||||
# i.e. keywords which can be used when calling the macro without any value
|
||||
# following, like e.g. the OPTIONAL keyword of the install() command.
|
||||
#
|
||||
# The <one_value_keywords> argument contains all keywords for this macro
|
||||
# which are followed by one value, like e.g. DESTINATION keyword of the
|
||||
# install() command.
|
||||
#
|
||||
# The <multi_value_keywords> argument contains all keywords for this macro
|
||||
# which can be followed by more than one value, like e.g. the TARGETS or
|
||||
# FILES keywords of the install() command.
|
||||
#
|
||||
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
|
||||
# keywords listed in <options>, <one_value_keywords> and
|
||||
# <multi_value_keywords> a variable composed of the given <prefix>
|
||||
# followed by "_" and the name of the respective keyword.
|
||||
# These variables will then hold the respective value from the argument list.
|
||||
# For the <options> keywords this will be TRUE or FALSE.
|
||||
#
|
||||
# All remaining arguments are collected in a variable
|
||||
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see whether
|
||||
# your macro was called with unrecognized parameters.
|
||||
#
|
||||
# As an example here a my_install() macro, which takes similar arguments as the
|
||||
# real install() command:
|
||||
#
|
||||
# function(MY_INSTALL)
|
||||
# set(options OPTIONAL FAST)
|
||||
# set(oneValueArgs DESTINATION RENAME)
|
||||
# set(multiValueArgs TARGETS CONFIGURATIONS)
|
||||
# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
# ...
|
||||
#
|
||||
# Assume my_install() has been called like this:
|
||||
# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
|
||||
#
|
||||
# After the cmake_parse_arguments() call the macro will have set the following
|
||||
# variables:
|
||||
# MY_INSTALL_OPTIONAL = TRUE
|
||||
# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
|
||||
# MY_INSTALL_DESTINATION = "bin"
|
||||
# MY_INSTALL_RENAME = "" (was not used)
|
||||
# MY_INSTALL_TARGETS = "foo;bar"
|
||||
# MY_INSTALL_CONFIGURATIONS = "" (was not used)
|
||||
# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
|
||||
#
|
||||
# You can the continue and process these variables.
|
||||
#
|
||||
# Keywords terminate lists of values, e.g. if directly after a one_value_keyword
|
||||
# another recognized keyword follows, this is interpreted as the beginning of
|
||||
# the new option.
|
||||
# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
|
||||
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
|
||||
# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
|
||||
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
|
||||
return()
|
||||
endif()
|
||||
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
|
||||
|
||||
|
||||
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
|
||||
# first set all result variables to empty/FALSE
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames})
|
||||
set(${prefix}_${arg_name})
|
||||
endforeach(arg_name)
|
||||
|
||||
foreach(option ${_optionNames})
|
||||
set(${prefix}_${option} FALSE)
|
||||
endforeach(option)
|
||||
|
||||
set(${prefix}_UNPARSED_ARGUMENTS)
|
||||
|
||||
set(insideValues FALSE)
|
||||
set(currentArgName)
|
||||
|
||||
# now iterate over all arguments and fill the result variables
|
||||
foreach(currentArg ${ARGN})
|
||||
list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
|
||||
if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
|
||||
if(insideValues)
|
||||
if("${insideValues}" STREQUAL "SINGLE")
|
||||
set(${prefix}_${currentArgName} ${currentArg})
|
||||
set(insideValues FALSE)
|
||||
elseif("${insideValues}" STREQUAL "MULTI")
|
||||
list(APPEND ${prefix}_${currentArgName} ${currentArg})
|
||||
endif()
|
||||
else(insideValues)
|
||||
list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
|
||||
endif(insideValues)
|
||||
else()
|
||||
if(NOT ${optionIndex} EQUAL -1)
|
||||
set(${prefix}_${currentArg} TRUE)
|
||||
set(insideValues FALSE)
|
||||
elseif(NOT ${singleArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "SINGLE")
|
||||
elseif(NOT ${multiArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "MULTI")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach(currentArg)
|
||||
|
||||
# propagate the result variables to the caller:
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
|
||||
set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
|
||||
endforeach(arg_name)
|
||||
set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
|
||||
|
||||
endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
|
|
@ -0,0 +1,36 @@
|
|||
# http://www.cmake.org/pipermail/cmake/2006-October/011446.html
|
||||
# Modified to use pkg config and use standard var names
|
||||
|
||||
#
|
||||
# Find the CppUnit includes and library
|
||||
#
|
||||
# This module defines
|
||||
# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
|
||||
# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
|
||||
# CPPUNIT_FOUND, If false, do not try to use CppUnit.
|
||||
|
||||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(PC_CPPUNIT "cppunit")
|
||||
|
||||
FIND_PATH(CPPUNIT_INCLUDE_DIRS
|
||||
NAMES cppunit/TestCase.h
|
||||
HINTS ${PC_CPPUNIT_INCLUDE_DIR}
|
||||
PATHS
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(CPPUNIT_LIBRARIES
|
||||
NAMES cppunit
|
||||
HINTS ${PC_CPPUNIT_LIBDIR}
|
||||
PATHS
|
||||
${CPPUNIT_INCLUDE_DIRS}/../lib
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
|
@ -0,0 +1,36 @@
|
|||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(PC_GNURADIO_RUNTIME gnuradio-runtime)
|
||||
|
||||
if(PC_GNURADIO_RUNTIME_FOUND)
|
||||
# look for include files
|
||||
FIND_PATH(
|
||||
GNURADIO_RUNTIME_INCLUDE_DIRS
|
||||
NAMES gnuradio/top_block.h
|
||||
HINTS $ENV{GNURADIO_RUNTIME_DIR}/include
|
||||
${PC_GNURADIO_RUNTIME_INCLUDE_DIRS}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
PATHS /usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
# look for libs
|
||||
FIND_LIBRARY(
|
||||
GNURADIO_RUNTIME_LIBRARIES
|
||||
NAMES gnuradio-runtime
|
||||
HINTS $ENV{GNURADIO_RUNTIME_DIR}/lib
|
||||
${PC_GNURADIO_RUNTIME_LIBDIR}
|
||||
${CMAKE_INSTALL_PREFIX}/lib/
|
||||
${CMAKE_INSTALL_PREFIX}/lib64/
|
||||
PATHS /usr/local/lib
|
||||
/usr/local/lib64
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
)
|
||||
|
||||
set(GNURADIO_RUNTIME_FOUND ${PC_GNURADIO_RUNTIME_FOUND})
|
||||
endif(PC_GNURADIO_RUNTIME_FOUND)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
# do not check GNURADIO_RUNTIME_INCLUDE_DIRS, is not set when default include path us used.
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES)
|
||||
MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
|
|
@ -0,0 +1,210 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Set global variable macro.
|
||||
# Used for subdirectories to export settings.
|
||||
# Example: include and library paths.
|
||||
########################################################################
|
||||
function(GR_SET_GLOBAL var)
|
||||
set(${var} ${ARGN} CACHE INTERNAL "" FORCE)
|
||||
endfunction(GR_SET_GLOBAL)
|
||||
|
||||
########################################################################
|
||||
# Set the pre-processor definition if the condition is true.
|
||||
# - def the pre-processor definition to set and condition name
|
||||
########################################################################
|
||||
function(GR_ADD_COND_DEF def)
|
||||
if(${def})
|
||||
add_definitions(-D${def})
|
||||
endif(${def})
|
||||
endfunction(GR_ADD_COND_DEF)
|
||||
|
||||
########################################################################
|
||||
# Check for a header and conditionally set a compile define.
|
||||
# - hdr the relative path to the header file
|
||||
# - def the pre-processor definition to set
|
||||
########################################################################
|
||||
function(GR_CHECK_HDR_N_DEF hdr def)
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX(${hdr} ${def})
|
||||
GR_ADD_COND_DEF(${def})
|
||||
endfunction(GR_CHECK_HDR_N_DEF)
|
||||
|
||||
########################################################################
|
||||
# Include subdirectory macro.
|
||||
# Sets the CMake directory variables,
|
||||
# includes the subdirectory CMakeLists.txt,
|
||||
# resets the CMake directory variables.
|
||||
#
|
||||
# This macro includes subdirectories rather than adding them
|
||||
# so that the subdirectory can affect variables in the level above.
|
||||
# This provides a work-around for the lack of convenience libraries.
|
||||
# This way a subdirectory can append to the list of library sources.
|
||||
########################################################################
|
||||
macro(GR_INCLUDE_SUBDIRECTORY subdir)
|
||||
#insert the current directories on the front of the list
|
||||
list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
#set the current directories to the names of the subdirs
|
||||
set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir})
|
||||
set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir})
|
||||
|
||||
#include the subdirectory CMakeLists to run it
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
|
||||
|
||||
#reset the value of the current directories
|
||||
list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR)
|
||||
list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR)
|
||||
|
||||
#pop the subdir names of the front of the list
|
||||
list(REMOVE_AT _cmake_source_dirs 0)
|
||||
list(REMOVE_AT _cmake_binary_dirs 0)
|
||||
endmacro(GR_INCLUDE_SUBDIRECTORY)
|
||||
|
||||
########################################################################
|
||||
# Check if a compiler flag works and conditionally set a compile define.
|
||||
# - flag the compiler flag to check for
|
||||
# - have the variable to set with result
|
||||
########################################################################
|
||||
macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
|
||||
if(${have})
|
||||
add_definitions(${flag})
|
||||
endif(${have})
|
||||
endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
|
||||
|
||||
########################################################################
|
||||
# Generates the .la libtool file
|
||||
# This appears to generate libtool files that cannot be used by auto*.
|
||||
# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest])
|
||||
# Notice: there is not COMPONENT option, these will not get distributed.
|
||||
########################################################################
|
||||
function(GR_LIBTOOL)
|
||||
if(NOT DEFINED GENERATE_LIBTOOL)
|
||||
set(GENERATE_LIBTOOL OFF) #disabled by default
|
||||
endif()
|
||||
|
||||
if(GENERATE_LIBTOOL)
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN})
|
||||
|
||||
find_program(LIBTOOL libtool)
|
||||
if(LIBTOOL)
|
||||
include(CMakeMacroLibtoolFile)
|
||||
CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION})
|
||||
endif(LIBTOOL)
|
||||
endif(GENERATE_LIBTOOL)
|
||||
|
||||
endfunction(GR_LIBTOOL)
|
||||
|
||||
########################################################################
|
||||
# Do standard things to the library target
|
||||
# - set target properties
|
||||
# - make install rules
|
||||
# Also handle gnuradio custom naming conventions w/ extras mode.
|
||||
########################################################################
|
||||
function(GR_LIBRARY_FOO target)
|
||||
#parse the arguments for component names
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN})
|
||||
|
||||
#set additional target properties
|
||||
set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER})
|
||||
|
||||
#install the generated files like so...
|
||||
install(TARGETS ${target}
|
||||
LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file
|
||||
ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file
|
||||
RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file
|
||||
)
|
||||
|
||||
#extras mode enabled automatically on linux
|
||||
if(NOT DEFINED LIBRARY_EXTRAS)
|
||||
set(LIBRARY_EXTRAS ${LINUX})
|
||||
endif()
|
||||
|
||||
#special extras mode to enable alternative naming conventions
|
||||
if(LIBRARY_EXTRAS)
|
||||
|
||||
#create .la file before changing props
|
||||
GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR})
|
||||
|
||||
#give the library a special name with ultra-zero soversion
|
||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0")
|
||||
set(target_name lib${target}-${LIBVER}.so.0.0.0)
|
||||
|
||||
#custom command to generate symlinks
|
||||
add_custom_command(
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install
|
||||
)
|
||||
|
||||
#and install the extra symlinks
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
|
||||
DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT}
|
||||
)
|
||||
|
||||
endif(LIBRARY_EXTRAS)
|
||||
endfunction(GR_LIBRARY_FOO)
|
||||
|
||||
########################################################################
|
||||
# Create a dummy custom command that depends on other targets.
|
||||
# Usage:
|
||||
# GR_GEN_TARGET_DEPS(unique_name target_deps <target1> <target2> ...)
|
||||
# ADD_CUSTOM_COMMAND(<the usual args> ${target_deps})
|
||||
#
|
||||
# Custom command cant depend on targets, but can depend on executables,
|
||||
# and executables can depend on targets. So this is the process:
|
||||
########################################################################
|
||||
function(GR_GEN_TARGET_DEPS name var)
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
|
||||
"int main(void){return 0;}\n"
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp
|
||||
)
|
||||
add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp)
|
||||
if(ARGN)
|
||||
add_dependencies(${name} ${ARGN})
|
||||
endif(ARGN)
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross
|
||||
else()
|
||||
set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction(GR_GEN_TARGET_DEPS)
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_PLATFORM_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Setup additional defines for OS types
|
||||
########################################################################
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
|
||||
if(LINUX AND EXISTS "/etc/debian_version")
|
||||
set(DEBIAN TRUE)
|
||||
endif()
|
||||
|
||||
if(LINUX AND EXISTS "/etc/redhat-release")
|
||||
set(REDHAT TRUE)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# when the library suffix should be 64 (applies to redhat linux family)
|
||||
########################################################################
|
||||
if(NOT DEFINED LIB_SUFFIX AND REDHAT AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$")
|
||||
set(LIB_SUFFIX 64)
|
||||
endif()
|
||||
set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix")
|
|
@ -0,0 +1,227 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_PYTHON_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_PYTHON_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Setup the python interpreter:
|
||||
# This allows the user to specify a specific interpreter,
|
||||
# or finds the interpreter via the built-in cmake module.
|
||||
########################################################################
|
||||
#this allows the user to override PYTHON_EXECUTABLE
|
||||
if(PYTHON_EXECUTABLE)
|
||||
|
||||
set(PYTHONINTERP_FOUND TRUE)
|
||||
|
||||
#otherwise if not set, try to automatically find it
|
||||
else(PYTHON_EXECUTABLE)
|
||||
|
||||
#use the built-in find script
|
||||
find_package(PythonInterp 2)
|
||||
|
||||
#and if that fails use the find program routine
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5)
|
||||
if(PYTHON_EXECUTABLE)
|
||||
set(PYTHONINTERP_FOUND TRUE)
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
endif(NOT PYTHONINTERP_FOUND)
|
||||
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
|
||||
#make the path to the executable appear in the cmake gui
|
||||
set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
|
||||
|
||||
#make sure we can use -B with python (introduced in 2.6)
|
||||
if(PYTHON_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -B -c ""
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT
|
||||
)
|
||||
if(PYTHON_HAS_DASH_B_RESULT EQUAL 0)
|
||||
set(PYTHON_DASH_B "-B")
|
||||
endif()
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
|
||||
########################################################################
|
||||
# Check for the existence of a python module:
|
||||
# - desc a string description of the check
|
||||
# - mod the name of the module to import
|
||||
# - cmd an additional command to run
|
||||
# - have the result variable to set
|
||||
########################################################################
|
||||
macro(GR_PYTHON_CHECK_MODULE desc mod cmd have)
|
||||
message(STATUS "")
|
||||
message(STATUS "Python checking for ${desc}")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||
#########################################
|
||||
try: import ${mod}
|
||||
except: exit(-1)
|
||||
try: assert ${cmd}
|
||||
except: exit(-1)
|
||||
#########################################"
|
||||
RESULT_VARIABLE ${have}
|
||||
)
|
||||
if(${have} EQUAL 0)
|
||||
message(STATUS "Python checking for ${desc} - found")
|
||||
set(${have} TRUE)
|
||||
else(${have} EQUAL 0)
|
||||
message(STATUS "Python checking for ${desc} - not found")
|
||||
set(${have} FALSE)
|
||||
endif(${have} EQUAL 0)
|
||||
endmacro(GR_PYTHON_CHECK_MODULE)
|
||||
|
||||
########################################################################
|
||||
# Sets the python installation directory GR_PYTHON_DIR
|
||||
########################################################################
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||
from distutils import sysconfig
|
||||
print sysconfig.get_python_lib(plat_specific=True, prefix='')
|
||||
" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
|
||||
|
||||
########################################################################
|
||||
# Create an always-built target with a unique name
|
||||
# Usage: GR_UNIQUE_TARGET(<description> <dependencies list>)
|
||||
########################################################################
|
||||
function(GR_UNIQUE_TARGET desc)
|
||||
file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
|
||||
unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
|
||||
print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))"
|
||||
OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
add_custom_target(${_target} ALL DEPENDS ${ARGN})
|
||||
endfunction(GR_UNIQUE_TARGET)
|
||||
|
||||
########################################################################
|
||||
# Install python sources (also builds and installs byte-compiled python)
|
||||
########################################################################
|
||||
function(GR_PYTHON_INSTALL)
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN})
|
||||
|
||||
####################################################################
|
||||
if(GR_PYTHON_INSTALL_FILES)
|
||||
####################################################################
|
||||
install(${ARGN}) #installs regular python files
|
||||
|
||||
#create a list of all generated files
|
||||
unset(pysrcfiles)
|
||||
unset(pycfiles)
|
||||
unset(pyofiles)
|
||||
foreach(pyfile ${GR_PYTHON_INSTALL_FILES})
|
||||
get_filename_component(pyfile ${pyfile} ABSOLUTE)
|
||||
list(APPEND pysrcfiles ${pyfile})
|
||||
|
||||
#determine if this file is in the source or binary directory
|
||||
file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile})
|
||||
string(LENGTH "${source_rel_path}" source_rel_path_len)
|
||||
file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile})
|
||||
string(LENGTH "${binary_rel_path}" binary_rel_path_len)
|
||||
|
||||
#and set the generated path appropriately
|
||||
if(${source_rel_path_len} GREATER ${binary_rel_path_len})
|
||||
set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path})
|
||||
else()
|
||||
set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path})
|
||||
endif()
|
||||
list(APPEND pycfiles ${pygenfile}c)
|
||||
list(APPEND pyofiles ${pygenfile}o)
|
||||
|
||||
#ensure generation path exists
|
||||
get_filename_component(pygen_path ${pygenfile} PATH)
|
||||
file(MAKE_DIRECTORY ${pygen_path})
|
||||
|
||||
endforeach(pyfile)
|
||||
|
||||
#the command to generate the pyc files
|
||||
add_custom_command(
|
||||
DEPENDS ${pysrcfiles} OUTPUT ${pycfiles}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles}
|
||||
)
|
||||
|
||||
#the command to generate the pyo files
|
||||
add_custom_command(
|
||||
DEPENDS ${pysrcfiles} OUTPUT ${pyofiles}
|
||||
COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles}
|
||||
)
|
||||
|
||||
#create install rule and add generated files to target list
|
||||
set(python_install_gen_targets ${pycfiles} ${pyofiles})
|
||||
install(FILES ${python_install_gen_targets}
|
||||
DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
|
||||
)
|
||||
|
||||
|
||||
####################################################################
|
||||
elseif(GR_PYTHON_INSTALL_PROGRAMS)
|
||||
####################################################################
|
||||
file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
|
||||
|
||||
foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
|
||||
get_filename_component(pyfile_name ${pyfile} NAME)
|
||||
get_filename_component(pyfile ${pyfile} ABSOLUTE)
|
||||
string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe")
|
||||
list(APPEND python_install_gen_targets ${pyexefile})
|
||||
|
||||
get_filename_component(pyexefile_path ${pyexefile} PATH)
|
||||
file(MAKE_DIRECTORY ${pyexefile_path})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${pyexefile} DEPENDS ${pyfile}
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c
|
||||
\"open('${pyexefile}', 'w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())\"
|
||||
COMMENT "Shebangin ${pyfile_name}"
|
||||
)
|
||||
|
||||
#on windows, python files need an extension to execute
|
||||
get_filename_component(pyfile_ext ${pyfile} EXT)
|
||||
if(WIN32 AND NOT pyfile_ext)
|
||||
set(pyfile_name "${pyfile_name}.py")
|
||||
endif()
|
||||
|
||||
install(PROGRAMS ${pyexefile} RENAME ${pyfile_name}
|
||||
DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
|
||||
)
|
||||
endforeach(pyfile)
|
||||
|
||||
endif()
|
||||
|
||||
GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets})
|
||||
|
||||
endfunction(GR_PYTHON_INSTALL)
|
||||
|
||||
########################################################################
|
||||
# Write the python helper script that generates byte code files
|
||||
########################################################################
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py "
|
||||
import sys, py_compile
|
||||
files = sys.argv[1:]
|
||||
srcs, gens = files[:len(files)/2], files[len(files)/2:]
|
||||
for src, gen in zip(srcs, gens):
|
||||
py_compile.compile(file=src, cfile=gen, doraise=True)
|
||||
")
|
|
@ -0,0 +1,229 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_SWIG_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_SWIG_CMAKE TRUE)
|
||||
|
||||
include(GrPython)
|
||||
|
||||
########################################################################
|
||||
# Builds a swig documentation file to be generated into python docstrings
|
||||
# Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....)
|
||||
#
|
||||
# Set the following variable to specify extra dependent targets:
|
||||
# - GR_SWIG_DOCS_SOURCE_DEPS
|
||||
# - GR_SWIG_DOCS_TARGET_DEPS
|
||||
########################################################################
|
||||
function(GR_SWIG_MAKE_DOCS output_file)
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
|
||||
#setup the input files variable list, quote formated
|
||||
set(input_files)
|
||||
unset(INPUT_PATHS)
|
||||
foreach(input_path ${ARGN})
|
||||
if (IS_DIRECTORY ${input_path}) #when input path is a directory
|
||||
file(GLOB input_path_h_files ${input_path}/*.h)
|
||||
else() #otherwise its just a file, no glob
|
||||
set(input_path_h_files ${input_path})
|
||||
endif()
|
||||
list(APPEND input_files ${input_path_h_files})
|
||||
set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"")
|
||||
endforeach(input_path)
|
||||
|
||||
#determine the output directory
|
||||
get_filename_component(name ${output_file} NAME_WE)
|
||||
get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH)
|
||||
set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs)
|
||||
make_directory(${OUTPUT_DIRECTORY})
|
||||
|
||||
#generate the Doxyfile used by doxygen
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in
|
||||
${OUTPUT_DIRECTORY}/Doxyfile
|
||||
@ONLY)
|
||||
|
||||
#Create a dummy custom command that depends on other targets
|
||||
include(GrMiscUtils)
|
||||
GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS})
|
||||
|
||||
#call doxygen on the Doxyfile + input headers
|
||||
add_custom_command(
|
||||
OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml
|
||||
DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile
|
||||
COMMENT "Generating doxygen xml for ${name} docs"
|
||||
)
|
||||
|
||||
#call the swig_doc script on the xml files
|
||||
add_custom_command(
|
||||
OUTPUT ${output_file}
|
||||
DEPENDS ${input_files} ${OUTPUT_DIRECTORY}/xml/index.xml
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||
${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py
|
||||
${OUTPUT_DIRECTORY}/xml
|
||||
${output_file}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen
|
||||
)
|
||||
|
||||
else(DOXYGEN_FOUND)
|
||||
file(WRITE ${output_file} "\n") #no doxygen -> empty file
|
||||
endif(DOXYGEN_FOUND)
|
||||
endfunction(GR_SWIG_MAKE_DOCS)
|
||||
|
||||
########################################################################
|
||||
# Build a swig target for the common gnuradio use case. Usage:
|
||||
# GR_SWIG_MAKE(target ifile ifile ifile...)
|
||||
#
|
||||
# Set the following variables before calling:
|
||||
# - GR_SWIG_FLAGS
|
||||
# - GR_SWIG_INCLUDE_DIRS
|
||||
# - GR_SWIG_LIBRARIES
|
||||
# - GR_SWIG_SOURCE_DEPS
|
||||
# - GR_SWIG_TARGET_DEPS
|
||||
# - GR_SWIG_DOC_FILE
|
||||
# - GR_SWIG_DOC_DIRS
|
||||
########################################################################
|
||||
macro(GR_SWIG_MAKE name)
|
||||
set(ifiles ${ARGN})
|
||||
|
||||
#do swig doc generation if specified
|
||||
if (GR_SWIG_DOC_FILE)
|
||||
set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
|
||||
set(GR_SWIG_DOCS_TAREGT_DEPS ${GR_SWIG_TARGET_DEPS})
|
||||
GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
|
||||
list(APPEND GR_SWIG_SOURCE_DEPS ${GR_SWIG_DOC_FILE})
|
||||
endif()
|
||||
|
||||
#append additional include directories
|
||||
find_package(PythonLibs 2)
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs)
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
#determine include dependencies for swig file
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${CMAKE_BINARY_DIR}/get_swig_deps.py
|
||||
"${ifiles}" "${GR_SWIG_INCLUDE_DIRS}"
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
#Create a dummy custom command that depends on other targets
|
||||
include(GrMiscUtils)
|
||||
GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS})
|
||||
set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag)
|
||||
add_custom_command(
|
||||
OUTPUT ${tag_file}
|
||||
DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${tag_file}
|
||||
)
|
||||
|
||||
#append the specified include directories
|
||||
include_directories(${GR_SWIG_INCLUDE_DIRS})
|
||||
list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file})
|
||||
|
||||
#setup the swig flags with flags and include directories
|
||||
set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS})
|
||||
foreach(dir ${GR_SWIG_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_SWIG_FLAGS "-I${dir}")
|
||||
endforeach(dir)
|
||||
|
||||
#set the C++ property on the swig .i file so it builds
|
||||
set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON)
|
||||
|
||||
#setup the actual swig library target to be built
|
||||
include(UseSWIG)
|
||||
SWIG_ADD_MODULE(${name} python ${ifiles})
|
||||
SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
|
||||
|
||||
endmacro(GR_SWIG_MAKE)
|
||||
|
||||
########################################################################
|
||||
# Install swig targets generated by GR_SWIG_MAKE. Usage:
|
||||
# GR_SWIG_INSTALL(
|
||||
# TARGETS target target target...
|
||||
# [DESTINATION destination]
|
||||
# [COMPONENT component]
|
||||
# )
|
||||
########################################################################
|
||||
macro(GR_SWIG_INSTALL)
|
||||
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
|
||||
|
||||
foreach(name ${GR_SWIG_INSTALL_TARGETS})
|
||||
install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME}
|
||||
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
|
||||
)
|
||||
|
||||
include(GrPython)
|
||||
GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py
|
||||
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
|
||||
)
|
||||
|
||||
GR_LIBTOOL(
|
||||
TARGET ${SWIG_MODULE_${name}_REAL_NAME}
|
||||
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||
)
|
||||
|
||||
endforeach(name)
|
||||
|
||||
endmacro(GR_SWIG_INSTALL)
|
||||
|
||||
########################################################################
|
||||
# Generate a python file that can determine swig dependencies.
|
||||
# Used by the make macro above to determine extra dependencies.
|
||||
# When you build C++, CMake figures out the header dependencies.
|
||||
# This code essentially performs that logic for swig includes.
|
||||
########################################################################
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py "
|
||||
|
||||
import os, sys, re
|
||||
|
||||
include_matcher = re.compile('[#|%]include\\s*[<|\"](.*)[>|\"]')
|
||||
include_dirs = sys.argv[2].split(';')
|
||||
|
||||
def get_swig_incs(file_path):
|
||||
file_contents = open(file_path, 'r').read()
|
||||
return include_matcher.findall(file_contents, re.MULTILINE)
|
||||
|
||||
def get_swig_deps(file_path, level):
|
||||
deps = [file_path]
|
||||
if level == 0: return deps
|
||||
for inc_file in get_swig_incs(file_path):
|
||||
for inc_dir in include_dirs:
|
||||
inc_path = os.path.join(inc_dir, inc_file)
|
||||
if not os.path.exists(inc_path): continue
|
||||
deps.extend(get_swig_deps(inc_path, level-1))
|
||||
return deps
|
||||
|
||||
if __name__ == '__main__':
|
||||
ifiles = sys.argv[1].split(';')
|
||||
deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], [])
|
||||
#sys.stderr.write(';'.join(set(deps)) + '\\n\\n')
|
||||
print(';'.join(set(deps)))
|
||||
")
|
|
@ -0,0 +1,133 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_TEST_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_TEST_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Add a unit test and setup the environment for a unit test.
|
||||
# Takes the same arguments as the ADD_TEST function.
|
||||
#
|
||||
# Before calling set the following variables:
|
||||
# GR_TEST_TARGET_DEPS - built targets for the library path
|
||||
# GR_TEST_LIBRARY_DIRS - directories for the library path
|
||||
# GR_TEST_PYTHON_DIRS - directories for the python path
|
||||
########################################################################
|
||||
function(GR_ADD_TEST test_name)
|
||||
|
||||
if(WIN32)
|
||||
#Ensure that the build exe also appears in the PATH.
|
||||
list(APPEND GR_TEST_TARGET_DEPS ${ARGN})
|
||||
|
||||
#In the land of windows, all libraries must be in the PATH.
|
||||
#Since the dependent libraries are not yet installed,
|
||||
#we must manually set them in the PATH to run tests.
|
||||
#The following appends the path of a target dependency.
|
||||
foreach(target ${GR_TEST_TARGET_DEPS})
|
||||
get_target_property(location ${target} LOCATION)
|
||||
if(location)
|
||||
get_filename_component(path ${location} PATH)
|
||||
string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path})
|
||||
list(APPEND GR_TEST_LIBRARY_DIRS ${path})
|
||||
endif(location)
|
||||
endforeach(target)
|
||||
|
||||
#SWIG generates the python library files into a subdirectory.
|
||||
#Therefore, we must append this subdirectory into PYTHONPATH.
|
||||
#Only do this for the python directories matching the following:
|
||||
foreach(pydir ${GR_TEST_PYTHON_DIRS})
|
||||
get_filename_component(name ${pydir} NAME)
|
||||
if(name MATCHES "^(swig|lib|src)$")
|
||||
list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
endforeach(pydir)
|
||||
endif(WIN32)
|
||||
|
||||
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir)
|
||||
file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list?
|
||||
file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list?
|
||||
|
||||
set(environs "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}")
|
||||
|
||||
#http://www.cmake.org/pipermail/cmake/2009-May/029464.html
|
||||
#Replaced this add test + set environs code with the shell script generation.
|
||||
#Its nicer to be able to manually run the shell script to diagnose problems.
|
||||
#ADD_TEST(${ARGV})
|
||||
#SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}")
|
||||
|
||||
if(UNIX)
|
||||
set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH")
|
||||
#set both LD and DYLD paths to cover multiple UNIX OS library paths
|
||||
list(APPEND libpath "$LD_LIBRARY_PATH" "$DYLD_LIBRARY_PATH")
|
||||
list(APPEND pypath "$PYTHONPATH")
|
||||
|
||||
#replace list separator with the path separator
|
||||
string(REPLACE ";" ":" libpath "${libpath}")
|
||||
string(REPLACE ";" ":" pypath "${pypath}")
|
||||
list(APPEND environs "PATH=${binpath}" "LD_LIBRARY_PATH=${libpath}" "DYLD_LIBRARY_PATH=${libpath}" "PYTHONPATH=${pypath}")
|
||||
|
||||
#generate a bat file that sets the environment and runs the test
|
||||
find_program(SHELL sh)
|
||||
set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
|
||||
file(WRITE ${sh_file} "#!${SHELL}\n")
|
||||
#each line sets an environment variable
|
||||
foreach(environ ${environs})
|
||||
file(APPEND ${sh_file} "export ${environ}\n")
|
||||
endforeach(environ)
|
||||
#load the command to run with its arguments
|
||||
foreach(arg ${ARGN})
|
||||
file(APPEND ${sh_file} "${arg} ")
|
||||
endforeach(arg)
|
||||
file(APPEND ${sh_file} "\n")
|
||||
|
||||
#make the shell file executable
|
||||
execute_process(COMMAND chmod +x ${sh_file})
|
||||
|
||||
add_test(${test_name} ${SHELL} ${sh_file})
|
||||
|
||||
endif(UNIX)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND libpath ${DLL_PATHS} "%PATH%")
|
||||
list(APPEND pypath "%PYTHONPATH%")
|
||||
|
||||
#replace list separator with the path separator (escaped)
|
||||
string(REPLACE ";" "\\;" libpath "${libpath}")
|
||||
string(REPLACE ";" "\\;" pypath "${pypath}")
|
||||
list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}")
|
||||
|
||||
#generate a bat file that sets the environment and runs the test
|
||||
set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat)
|
||||
file(WRITE ${bat_file} "@echo off\n")
|
||||
#each line sets an environment variable
|
||||
foreach(environ ${environs})
|
||||
file(APPEND ${bat_file} "SET ${environ}\n")
|
||||
endforeach(environ)
|
||||
#load the command to run with its arguments
|
||||
foreach(arg ${ARGN})
|
||||
file(APPEND ${bat_file} "${arg} ")
|
||||
endforeach(arg)
|
||||
file(APPEND ${bat_file} "\n")
|
||||
|
||||
add_test(${test_name} ${bat_file})
|
||||
endif(WIN32)
|
||||
|
||||
endfunction(GR_ADD_TEST)
|
|
@ -0,0 +1,30 @@
|
|||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(PC_GSM gsm)
|
||||
|
||||
FIND_PATH(
|
||||
GSM_INCLUDE_DIRS
|
||||
NAMES gsm/api.h
|
||||
HINTS $ENV{GSM_DIR}/include
|
||||
${PC_GSM_INCLUDEDIR}
|
||||
PATHS ${CMAKE_INSTALL_PREFIX}/include
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(
|
||||
GSM_LIBRARIES
|
||||
NAMES gnuradio-gsm
|
||||
HINTS $ENV{GSM_DIR}/lib
|
||||
${PC_GSM_LIBDIR}
|
||||
PATHS ${CMAKE_INSTALL_PREFIX}/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
/usr/local/lib
|
||||
/usr/local/lib64
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSM DEFAULT_MSG GSM_LIBRARIES GSM_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(GSM_LIBRARIES GSM_INCLUDE_DIRS)
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
|
||||
|
||||
IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
STRING(REGEX REPLACE "\n" ";" files "${files}")
|
||||
FOREACH(file ${files})
|
||||
MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
IF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSE(EXISTS "$ENV{DESTDIR}${file}")
|
||||
MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
ENDIF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
ENDFOREACH(file)
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Setup dependencies
|
||||
########################################################################
|
||||
find_package(Doxygen)
|
||||
|
||||
########################################################################
|
||||
# Begin conditional configuration
|
||||
########################################################################
|
||||
if(ENABLE_DOXYGEN)
|
||||
|
||||
########################################################################
|
||||
# Add subdirectories
|
||||
########################################################################
|
||||
add_subdirectory(doxygen)
|
||||
|
||||
endif(ENABLE_DOXYGEN)
|
|
@ -0,0 +1,11 @@
|
|||
This is the gsm-write-a-block package meant as a guide to building
|
||||
out-of-tree packages. To use the gsm blocks, the Python namespaces
|
||||
is in 'gsm', which is imported as:
|
||||
|
||||
import gsm
|
||||
|
||||
See the Doxygen documentation for details about the blocks available
|
||||
in this package. A quick listing of the details can be found in Python
|
||||
after importing by using:
|
||||
|
||||
help(gsm)
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Create the doxygen configuration file
|
||||
########################################################################
|
||||
file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir)
|
||||
file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir)
|
||||
file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir)
|
||||
file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir)
|
||||
|
||||
set(HAVE_DOT ${DOXYGEN_DOT_FOUND})
|
||||
set(enable_html_docs YES)
|
||||
set(enable_latex_docs NO)
|
||||
set(enable_xml_docs YES)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
@ONLY)
|
||||
|
||||
set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html)
|
||||
|
||||
########################################################################
|
||||
# Make and install doxygen docs
|
||||
########################################################################
|
||||
add_custom_command(
|
||||
OUTPUT ${BUILT_DIRS}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating documentation with doxygen"
|
||||
)
|
||||
|
||||
add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS})
|
||||
|
||||
install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR})
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Python interface to contents of doxygen xml documentation.
|
||||
|
||||
Example use:
|
||||
See the contents of the example folder for the C++ and
|
||||
doxygen-generated xml used in this example.
|
||||
|
||||
>>> # Parse the doxygen docs.
|
||||
>>> import os
|
||||
>>> this_dir = os.path.dirname(globals()['__file__'])
|
||||
>>> xml_path = this_dir + "/example/xml/"
|
||||
>>> di = DoxyIndex(xml_path)
|
||||
|
||||
Get a list of all top-level objects.
|
||||
|
||||
>>> print([mem.name() for mem in di.members()])
|
||||
[u'Aadvark', u'aadvarky_enough', u'main']
|
||||
|
||||
Get all functions.
|
||||
|
||||
>>> print([mem.name() for mem in di.in_category(DoxyFunction)])
|
||||
[u'aadvarky_enough', u'main']
|
||||
|
||||
Check if an object is present.
|
||||
|
||||
>>> di.has_member(u'Aadvark')
|
||||
True
|
||||
>>> di.has_member(u'Fish')
|
||||
False
|
||||
|
||||
Get an item by name and check its properties.
|
||||
|
||||
>>> aad = di.get_member(u'Aadvark')
|
||||
>>> print(aad.brief_description)
|
||||
Models the mammal Aadvark.
|
||||
>>> print(aad.detailed_description)
|
||||
Sadly the model is incomplete and cannot capture all aspects of an aadvark yet.
|
||||
<BLANKLINE>
|
||||
This line is uninformative and is only to test line breaks in the comments.
|
||||
>>> [mem.name() for mem in aad.members()]
|
||||
[u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness']
|
||||
>>> aad.get_member(u'print').brief_description
|
||||
u'Outputs the vital aadvark statistics.'
|
||||
|
||||
"""
|
||||
|
||||
from doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther
|
||||
|
||||
def _test():
|
||||
import os
|
||||
this_dir = os.path.dirname(globals()['__file__'])
|
||||
xml_path = this_dir + "/example/xml/"
|
||||
di = DoxyIndex(xml_path)
|
||||
# Get the Aadvark class
|
||||
aad = di.get_member('Aadvark')
|
||||
aad.brief_description
|
||||
import doctest
|
||||
return doctest.testmod()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
A base class is created.
|
||||
|
||||
Classes based upon this are used to make more user-friendly interfaces
|
||||
to the doxygen xml docs than the generated classes provide.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pdb
|
||||
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
from generated import compound
|
||||
|
||||
|
||||
class Base(object):
|
||||
|
||||
class Duplicate(StandardError):
|
||||
pass
|
||||
|
||||
class NoSuchMember(StandardError):
|
||||
pass
|
||||
|
||||
class ParsingError(StandardError):
|
||||
pass
|
||||
|
||||
def __init__(self, parse_data, top=None):
|
||||
self._parsed = False
|
||||
self._error = False
|
||||
self._parse_data = parse_data
|
||||
self._members = []
|
||||
self._dict_members = {}
|
||||
self._in_category = {}
|
||||
self._data = {}
|
||||
if top is not None:
|
||||
self._xml_path = top._xml_path
|
||||
# Set up holder of references
|
||||
else:
|
||||
top = self
|
||||
self._refs = {}
|
||||
self._xml_path = parse_data
|
||||
self.top = top
|
||||
|
||||
@classmethod
|
||||
def from_refid(cls, refid, top=None):
|
||||
""" Instantiate class from a refid rather than parsing object. """
|
||||
# First check to see if its already been instantiated.
|
||||
if top is not None and refid in top._refs:
|
||||
return top._refs[refid]
|
||||
# Otherwise create a new instance and set refid.
|
||||
inst = cls(None, top=top)
|
||||
inst.refid = refid
|
||||
inst.add_ref(inst)
|
||||
return inst
|
||||
|
||||
@classmethod
|
||||
def from_parse_data(cls, parse_data, top=None):
|
||||
refid = getattr(parse_data, 'refid', None)
|
||||
if refid is not None and top is not None and refid in top._refs:
|
||||
return top._refs[refid]
|
||||
inst = cls(parse_data, top=top)
|
||||
if refid is not None:
|
||||
inst.refid = refid
|
||||
inst.add_ref(inst)
|
||||
return inst
|
||||
|
||||
def add_ref(self, obj):
|
||||
if hasattr(obj, 'refid'):
|
||||
self.top._refs[obj.refid] = obj
|
||||
|
||||
mem_classes = []
|
||||
|
||||
def get_cls(self, mem):
|
||||
for cls in self.mem_classes:
|
||||
if cls.can_parse(mem):
|
||||
return cls
|
||||
raise StandardError(("Did not find a class for object '%s'." \
|
||||
% (mem.get_name())))
|
||||
|
||||
def convert_mem(self, mem):
|
||||
try:
|
||||
cls = self.get_cls(mem)
|
||||
converted = cls.from_parse_data(mem, self.top)
|
||||
if converted is None:
|
||||
raise StandardError('No class matched this object.')
|
||||
self.add_ref(converted)
|
||||
return converted
|
||||
except StandardError, e:
|
||||
print e
|
||||
|
||||
@classmethod
|
||||
def includes(cls, inst):
|
||||
return isinstance(inst, cls)
|
||||
|
||||
@classmethod
|
||||
def can_parse(cls, obj):
|
||||
return False
|
||||
|
||||
def _parse(self):
|
||||
self._parsed = True
|
||||
|
||||
def _get_dict_members(self, cat=None):
|
||||
"""
|
||||
For given category a dictionary is returned mapping member names to
|
||||
members of that category. For names that are duplicated the name is
|
||||
mapped to None.
|
||||
"""
|
||||
self.confirm_no_error()
|
||||
if cat not in self._dict_members:
|
||||
new_dict = {}
|
||||
for mem in self.in_category(cat):
|
||||
if mem.name() not in new_dict:
|
||||
new_dict[mem.name()] = mem
|
||||
else:
|
||||
new_dict[mem.name()] = self.Duplicate
|
||||
self._dict_members[cat] = new_dict
|
||||
return self._dict_members[cat]
|
||||
|
||||
def in_category(self, cat):
|
||||
self.confirm_no_error()
|
||||
if cat is None:
|
||||
return self._members
|
||||
if cat not in self._in_category:
|
||||
self._in_category[cat] = [mem for mem in self._members
|
||||
if cat.includes(mem)]
|
||||
return self._in_category[cat]
|
||||
|
||||
def get_member(self, name, cat=None):
|
||||
self.confirm_no_error()
|
||||
# Check if it's in a namespace or class.
|
||||
bits = name.split('::')
|
||||
first = bits[0]
|
||||
rest = '::'.join(bits[1:])
|
||||
member = self._get_dict_members(cat).get(first, self.NoSuchMember)
|
||||
# Raise any errors that are returned.
|
||||
if member in set([self.NoSuchMember, self.Duplicate]):
|
||||
raise member()
|
||||
if rest:
|
||||
return member.get_member(rest, cat=cat)
|
||||
return member
|
||||
|
||||
def has_member(self, name, cat=None):
|
||||
try:
|
||||
mem = self.get_member(name, cat=cat)
|
||||
return True
|
||||
except self.NoSuchMember:
|
||||
return False
|
||||
|
||||
def data(self):
|
||||
self.confirm_no_error()
|
||||
return self._data
|
||||
|
||||
def members(self):
|
||||
self.confirm_no_error()
|
||||
return self._members
|
||||
|
||||
def process_memberdefs(self):
|
||||
mdtss = []
|
||||
for sec in self._retrieved_data.compounddef.sectiondef:
|
||||
mdtss += sec.memberdef
|
||||
# At the moment we lose all information associated with sections.
|
||||
# Sometimes a memberdef is in several sectiondef.
|
||||
# We make sure we don't get duplicates here.
|
||||
uniques = set([])
|
||||
for mem in mdtss:
|
||||
converted = self.convert_mem(mem)
|
||||
pair = (mem.name, mem.__class__)
|
||||
if pair not in uniques:
|
||||
uniques.add(pair)
|
||||
self._members.append(converted)
|
||||
|
||||
def retrieve_data(self):
|
||||
filename = os.path.join(self._xml_path, self.refid + '.xml')
|
||||
try:
|
||||
self._retrieved_data = compound.parse(filename)
|
||||
except ExpatError:
|
||||
print('Error in xml in file %s' % filename)
|
||||
self._error = True
|
||||
self._retrieved_data = None
|
||||
|
||||
def check_parsed(self):
|
||||
if not self._parsed:
|
||||
self._parse()
|
||||
|
||||
def confirm_no_error(self):
|
||||
self.check_parsed()
|
||||
if self._error:
|
||||
raise self.ParsingError()
|
||||
|
||||
def error(self):
|
||||
self.check_parsed()
|
||||
return self._error
|
||||
|
||||
def name(self):
|
||||
# first see if we can do it without processing.
|
||||
if self._parse_data is not None:
|
||||
return self._parse_data.name
|
||||
self.check_parsed()
|
||||
return self._retrieved_data.compounddef.name
|
|
@ -0,0 +1,237 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Classes providing more user-friendly interfaces to the doxygen xml
|
||||
docs than the generated classes provide.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from generated import index
|
||||
from base import Base
|
||||
from text import description
|
||||
|
||||
class DoxyIndex(Base):
|
||||
"""
|
||||
Parses a doxygen xml directory.
|
||||
"""
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyIndex, self)._parse()
|
||||
self._root = index.parse(os.path.join(self._xml_path, 'index.xml'))
|
||||
for mem in self._root.compound:
|
||||
converted = self.convert_mem(mem)
|
||||
# For files we want the contents to be accessible directly
|
||||
# from the parent rather than having to go through the file
|
||||
# object.
|
||||
if self.get_cls(mem) == DoxyFile:
|
||||
if mem.name.endswith('.h'):
|
||||
self._members += converted.members()
|
||||
self._members.append(converted)
|
||||
else:
|
||||
self._members.append(converted)
|
||||
|
||||
|
||||
def generate_swig_doc_i(self):
|
||||
"""
|
||||
%feature("docstring") gr_make_align_on_samplenumbers_ss::align_state "
|
||||
Wraps the C++: gr_align_on_samplenumbers_ss::align_state";
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DoxyCompMem(Base):
|
||||
|
||||
|
||||
kind = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DoxyCompMem, self).__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def can_parse(cls, obj):
|
||||
return obj.kind == cls.kind
|
||||
|
||||
def set_descriptions(self, parse_data):
|
||||
bd = description(getattr(parse_data, 'briefdescription', None))
|
||||
dd = description(getattr(parse_data, 'detaileddescription', None))
|
||||
self._data['brief_description'] = bd
|
||||
self._data['detailed_description'] = dd
|
||||
|
||||
class DoxyCompound(DoxyCompMem):
|
||||
pass
|
||||
|
||||
class DoxyMember(DoxyCompMem):
|
||||
pass
|
||||
|
||||
|
||||
class DoxyFunction(DoxyMember):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'function'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyFunction, self)._parse()
|
||||
self.set_descriptions(self._parse_data)
|
||||
self._data['params'] = []
|
||||
prms = self._parse_data.param
|
||||
for prm in prms:
|
||||
self._data['params'].append(DoxyParam(prm))
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
params = property(lambda self: self.data()['params'])
|
||||
|
||||
Base.mem_classes.append(DoxyFunction)
|
||||
|
||||
|
||||
class DoxyParam(DoxyMember):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyParam, self)._parse()
|
||||
self.set_descriptions(self._parse_data)
|
||||
self._data['declname'] = self._parse_data.declname
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
declname = property(lambda self: self.data()['declname'])
|
||||
|
||||
class DoxyClass(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'class'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyClass, self)._parse()
|
||||
self.retrieve_data()
|
||||
if self._error:
|
||||
return
|
||||
self.set_descriptions(self._retrieved_data.compounddef)
|
||||
# Sectiondef.kind tells about whether private or public.
|
||||
# We just ignore this for now.
|
||||
self.process_memberdefs()
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
|
||||
Base.mem_classes.append(DoxyClass)
|
||||
|
||||
|
||||
class DoxyFile(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'file'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyFile, self)._parse()
|
||||
self.retrieve_data()
|
||||
self.set_descriptions(self._retrieved_data.compounddef)
|
||||
if self._error:
|
||||
return
|
||||
self.process_memberdefs()
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
|
||||
Base.mem_classes.append(DoxyFile)
|
||||
|
||||
|
||||
class DoxyNamespace(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'namespace'
|
||||
|
||||
Base.mem_classes.append(DoxyNamespace)
|
||||
|
||||
|
||||
class DoxyGroup(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'group'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyGroup, self)._parse()
|
||||
self.retrieve_data()
|
||||
if self._error:
|
||||
return
|
||||
cdef = self._retrieved_data.compounddef
|
||||
self._data['title'] = description(cdef.title)
|
||||
# Process inner groups
|
||||
grps = cdef.innergroup
|
||||
for grp in grps:
|
||||
converted = DoxyGroup.from_refid(grp.refid, top=self.top)
|
||||
self._members.append(converted)
|
||||
# Process inner classes
|
||||
klasses = cdef.innerclass
|
||||
for kls in klasses:
|
||||
converted = DoxyClass.from_refid(kls.refid, top=self.top)
|
||||
self._members.append(converted)
|
||||
# Process normal members
|
||||
self.process_memberdefs()
|
||||
|
||||
title = property(lambda self: self.data()['title'])
|
||||
|
||||
|
||||
Base.mem_classes.append(DoxyGroup)
|
||||
|
||||
|
||||
class DoxyFriend(DoxyMember):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'friend'
|
||||
|
||||
Base.mem_classes.append(DoxyFriend)
|
||||
|
||||
|
||||
class DoxyOther(Base):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 'dir', 'page'])
|
||||
|
||||
@classmethod
|
||||
def can_parse(cls, obj):
|
||||
return obj.kind in cls.kinds
|
||||
|
||||
Base.mem_classes.append(DoxyOther)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Contains generated files produced by generateDS.py.
|
||||
|
||||
These do the real work of parsing the doxygen xml files but the
|
||||
resultant classes are not very friendly to navigate so the rest of the
|
||||
doxyxml module processes them further.
|
||||
"""
|
|
@ -0,0 +1,503 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
|
||||
"""
|
||||
|
||||
from string import lower as str_lower
|
||||
from xml.dom import minidom
|
||||
from xml.dom import Node
|
||||
|
||||
import sys
|
||||
|
||||
import compoundsuper as supermod
|
||||
from compoundsuper import MixedContainer
|
||||
|
||||
|
||||
class DoxygenTypeSub(supermod.DoxygenType):
|
||||
def __init__(self, version=None, compounddef=None):
|
||||
supermod.DoxygenType.__init__(self, version, compounddef)
|
||||
|
||||
def find(self, details):
|
||||
|
||||
return self.compounddef.find(details)
|
||||
|
||||
supermod.DoxygenType.subclass = DoxygenTypeSub
|
||||
# end class DoxygenTypeSub
|
||||
|
||||
|
||||
class compounddefTypeSub(supermod.compounddefType):
|
||||
def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None):
|
||||
supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, incdepgraph, invincdepgraph, innerdir, innerfile, innerclass, innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, programlisting, location, listofallmembers)
|
||||
|
||||
def find(self, details):
|
||||
|
||||
if self.id == details.refid:
|
||||
return self
|
||||
|
||||
for sectiondef in self.sectiondef:
|
||||
result = sectiondef.find(details)
|
||||
if result:
|
||||
return result
|
||||
|
||||
|
||||
supermod.compounddefType.subclass = compounddefTypeSub
|
||||
# end class compounddefTypeSub
|
||||
|
||||
|
||||
class listofallmembersTypeSub(supermod.listofallmembersType):
|
||||
def __init__(self, member=None):
|
||||
supermod.listofallmembersType.__init__(self, member)
|
||||
supermod.listofallmembersType.subclass = listofallmembersTypeSub
|
||||
# end class listofallmembersTypeSub
|
||||
|
||||
|
||||
class memberRefTypeSub(supermod.memberRefType):
|
||||
def __init__(self, virt=None, prot=None, refid=None, ambiguityscope=None, scope='', name=''):
|
||||
supermod.memberRefType.__init__(self, virt, prot, refid, ambiguityscope, scope, name)
|
||||
supermod.memberRefType.subclass = memberRefTypeSub
|
||||
# end class memberRefTypeSub
|
||||
|
||||
|
||||
class compoundRefTypeSub(supermod.compoundRefType):
|
||||
def __init__(self, virt=None, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.compoundRefType.__init__(self, mixedclass_, content_)
|
||||
supermod.compoundRefType.subclass = compoundRefTypeSub
|
||||
# end class compoundRefTypeSub
|
||||
|
||||
|
||||
class reimplementTypeSub(supermod.reimplementType):
|
||||
def __init__(self, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.reimplementType.__init__(self, mixedclass_, content_)
|
||||
supermod.reimplementType.subclass = reimplementTypeSub
|
||||
# end class reimplementTypeSub
|
||||
|
||||
|
||||
class incTypeSub(supermod.incType):
|
||||
def __init__(self, local=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.incType.__init__(self, mixedclass_, content_)
|
||||
supermod.incType.subclass = incTypeSub
|
||||
# end class incTypeSub
|
||||
|
||||
|
||||
class refTypeSub(supermod.refType):
|
||||
def __init__(self, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.refType.__init__(self, mixedclass_, content_)
|
||||
supermod.refType.subclass = refTypeSub
|
||||
# end class refTypeSub
|
||||
|
||||
|
||||
|
||||
class refTextTypeSub(supermod.refTextType):
|
||||
def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.refTextType.__init__(self, mixedclass_, content_)
|
||||
|
||||
supermod.refTextType.subclass = refTextTypeSub
|
||||
# end class refTextTypeSub
|
||||
|
||||
class sectiondefTypeSub(supermod.sectiondefType):
|
||||
|
||||
|
||||
def __init__(self, kind=None, header='', description=None, memberdef=None):
|
||||
supermod.sectiondefType.__init__(self, kind, header, description, memberdef)
|
||||
|
||||
def find(self, details):
|
||||
|
||||
for memberdef in self.memberdef:
|
||||
if memberdef.id == details.refid:
|
||||
return memberdef
|
||||
|
||||
return None
|
||||
|
||||
|
||||
supermod.sectiondefType.subclass = sectiondefTypeSub
|
||||
# end class sectiondefTypeSub
|
||||
|
||||
|
||||
class memberdefTypeSub(supermod.memberdefType):
|
||||
def __init__(self, initonly=None, kind=None, volatile=None, const=None, raise_=None, virt=None, readable=None, prot=None, explicit=None, new=None, final=None, writable=None, add=None, static=None, remove=None, sealed=None, mutable=None, gettable=None, inline=None, settable=None, id=None, templateparamlist=None, type_=None, definition='', argsstring='', name='', read='', write='', bitfield='', reimplements=None, reimplementedby=None, param=None, enumvalue=None, initializer=None, exceptions=None, briefdescription=None, detaileddescription=None, inbodydescription=None, location=None, references=None, referencedby=None):
|
||||
supermod.memberdefType.__init__(self, initonly, kind, volatile, const, raise_, virt, readable, prot, explicit, new, final, writable, add, static, remove, sealed, mutable, gettable, inline, settable, id, templateparamlist, type_, definition, argsstring, name, read, write, bitfield, reimplements, reimplementedby, param, enumvalue, initializer, exceptions, briefdescription, detaileddescription, inbodydescription, location, references, referencedby)
|
||||
supermod.memberdefType.subclass = memberdefTypeSub
|
||||
# end class memberdefTypeSub
|
||||
|
||||
|
||||
class descriptionTypeSub(supermod.descriptionType):
|
||||
def __init__(self, title='', para=None, sect1=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.descriptionType.__init__(self, mixedclass_, content_)
|
||||
supermod.descriptionType.subclass = descriptionTypeSub
|
||||
# end class descriptionTypeSub
|
||||
|
||||
|
||||
class enumvalueTypeSub(supermod.enumvalueType):
|
||||
def __init__(self, prot=None, id=None, name='', initializer=None, briefdescription=None, detaileddescription=None, mixedclass_=None, content_=None):
|
||||
supermod.enumvalueType.__init__(self, mixedclass_, content_)
|
||||
supermod.enumvalueType.subclass = enumvalueTypeSub
|
||||
# end class enumvalueTypeSub
|
||||
|
||||
|
||||
class templateparamlistTypeSub(supermod.templateparamlistType):
|
||||
def __init__(self, param=None):
|
||||
supermod.templateparamlistType.__init__(self, param)
|
||||
supermod.templateparamlistType.subclass = templateparamlistTypeSub
|
||||
# end class templateparamlistTypeSub
|
||||
|
||||
|
||||
class paramTypeSub(supermod.paramType):
|
||||
def __init__(self, type_=None, declname='', defname='', array='', defval=None, briefdescription=None):
|
||||
supermod.paramType.__init__(self, type_, declname, defname, array, defval, briefdescription)
|
||||
supermod.paramType.subclass = paramTypeSub
|
||||
# end class paramTypeSub
|
||||
|
||||
|
||||
class linkedTextTypeSub(supermod.linkedTextType):
|
||||
def __init__(self, ref=None, mixedclass_=None, content_=None):
|
||||
supermod.linkedTextType.__init__(self, mixedclass_, content_)
|
||||
supermod.linkedTextType.subclass = linkedTextTypeSub
|
||||
# end class linkedTextTypeSub
|
||||
|
||||
|
||||
class graphTypeSub(supermod.graphType):
|
||||
def __init__(self, node=None):
|
||||
supermod.graphType.__init__(self, node)
|
||||
supermod.graphType.subclass = graphTypeSub
|
||||
# end class graphTypeSub
|
||||
|
||||
|
||||
class nodeTypeSub(supermod.nodeType):
|
||||
def __init__(self, id=None, label='', link=None, childnode=None):
|
||||
supermod.nodeType.__init__(self, id, label, link, childnode)
|
||||
supermod.nodeType.subclass = nodeTypeSub
|
||||
# end class nodeTypeSub
|
||||
|
||||
|
||||
class childnodeTypeSub(supermod.childnodeType):
|
||||
def __init__(self, relation=None, refid=None, edgelabel=None):
|
||||
supermod.childnodeType.__init__(self, relation, refid, edgelabel)
|
||||
supermod.childnodeType.subclass = childnodeTypeSub
|
||||
# end class childnodeTypeSub
|
||||
|
||||
|
||||
class linkTypeSub(supermod.linkType):
|
||||
def __init__(self, refid=None, external=None, valueOf_=''):
|
||||
supermod.linkType.__init__(self, refid, external)
|
||||
supermod.linkType.subclass = linkTypeSub
|
||||
# end class linkTypeSub
|
||||
|
||||
|
||||
class listingTypeSub(supermod.listingType):
|
||||
def __init__(self, codeline=None):
|
||||
supermod.listingType.__init__(self, codeline)
|
||||
supermod.listingType.subclass = listingTypeSub
|
||||
# end class listingTypeSub
|
||||
|
||||
|
||||
class codelineTypeSub(supermod.codelineType):
|
||||
def __init__(self, external=None, lineno=None, refkind=None, refid=None, highlight=None):
|
||||
supermod.codelineType.__init__(self, external, lineno, refkind, refid, highlight)
|
||||
supermod.codelineType.subclass = codelineTypeSub
|
||||
# end class codelineTypeSub
|
||||
|
||||
|
||||
class highlightTypeSub(supermod.highlightType):
|
||||
def __init__(self, class_=None, sp=None, ref=None, mixedclass_=None, content_=None):
|
||||
supermod.highlightType.__init__(self, mixedclass_, content_)
|
||||
supermod.highlightType.subclass = highlightTypeSub
|
||||
# end class highlightTypeSub
|
||||
|
||||
|
||||
class referenceTypeSub(supermod.referenceType):
|
||||
def __init__(self, endline=None, startline=None, refid=None, compoundref=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.referenceType.__init__(self, mixedclass_, content_)
|
||||
supermod.referenceType.subclass = referenceTypeSub
|
||||
# end class referenceTypeSub
|
||||
|
||||
|
||||
class locationTypeSub(supermod.locationType):
|
||||
def __init__(self, bodystart=None, line=None, bodyend=None, bodyfile=None, file=None, valueOf_=''):
|
||||
supermod.locationType.__init__(self, bodystart, line, bodyend, bodyfile, file)
|
||||
supermod.locationType.subclass = locationTypeSub
|
||||
# end class locationTypeSub
|
||||
|
||||
|
||||
class docSect1TypeSub(supermod.docSect1Type):
|
||||
def __init__(self, id=None, title='', para=None, sect2=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect1Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect1Type.subclass = docSect1TypeSub
|
||||
# end class docSect1TypeSub
|
||||
|
||||
|
||||
class docSect2TypeSub(supermod.docSect2Type):
|
||||
def __init__(self, id=None, title='', para=None, sect3=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect2Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect2Type.subclass = docSect2TypeSub
|
||||
# end class docSect2TypeSub
|
||||
|
||||
|
||||
class docSect3TypeSub(supermod.docSect3Type):
|
||||
def __init__(self, id=None, title='', para=None, sect4=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect3Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect3Type.subclass = docSect3TypeSub
|
||||
# end class docSect3TypeSub
|
||||
|
||||
|
||||
class docSect4TypeSub(supermod.docSect4Type):
|
||||
def __init__(self, id=None, title='', para=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect4Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect4Type.subclass = docSect4TypeSub
|
||||
# end class docSect4TypeSub
|
||||
|
||||
|
||||
class docInternalTypeSub(supermod.docInternalType):
|
||||
def __init__(self, para=None, sect1=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalType.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalType.subclass = docInternalTypeSub
|
||||
# end class docInternalTypeSub
|
||||
|
||||
|
||||
class docInternalS1TypeSub(supermod.docInternalS1Type):
|
||||
def __init__(self, para=None, sect2=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS1Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS1Type.subclass = docInternalS1TypeSub
|
||||
# end class docInternalS1TypeSub
|
||||
|
||||
|
||||
class docInternalS2TypeSub(supermod.docInternalS2Type):
|
||||
def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS2Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS2Type.subclass = docInternalS2TypeSub
|
||||
# end class docInternalS2TypeSub
|
||||
|
||||
|
||||
class docInternalS3TypeSub(supermod.docInternalS3Type):
|
||||
def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS3Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS3Type.subclass = docInternalS3TypeSub
|
||||
# end class docInternalS3TypeSub
|
||||
|
||||
|
||||
class docInternalS4TypeSub(supermod.docInternalS4Type):
|
||||
def __init__(self, para=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS4Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS4Type.subclass = docInternalS4TypeSub
|
||||
# end class docInternalS4TypeSub
|
||||
|
||||
|
||||
class docURLLinkSub(supermod.docURLLink):
|
||||
def __init__(self, url=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docURLLink.__init__(self, mixedclass_, content_)
|
||||
supermod.docURLLink.subclass = docURLLinkSub
|
||||
# end class docURLLinkSub
|
||||
|
||||
|
||||
class docAnchorTypeSub(supermod.docAnchorType):
|
||||
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docAnchorType.__init__(self, mixedclass_, content_)
|
||||
supermod.docAnchorType.subclass = docAnchorTypeSub
|
||||
# end class docAnchorTypeSub
|
||||
|
||||
|
||||
class docFormulaTypeSub(supermod.docFormulaType):
|
||||
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docFormulaType.__init__(self, mixedclass_, content_)
|
||||
supermod.docFormulaType.subclass = docFormulaTypeSub
|
||||
# end class docFormulaTypeSub
|
||||
|
||||
|
||||
class docIndexEntryTypeSub(supermod.docIndexEntryType):
|
||||
def __init__(self, primaryie='', secondaryie=''):
|
||||
supermod.docIndexEntryType.__init__(self, primaryie, secondaryie)
|
||||
supermod.docIndexEntryType.subclass = docIndexEntryTypeSub
|
||||
# end class docIndexEntryTypeSub
|
||||
|
||||
|
||||
class docListTypeSub(supermod.docListType):
|
||||
def __init__(self, listitem=None):
|
||||
supermod.docListType.__init__(self, listitem)
|
||||
supermod.docListType.subclass = docListTypeSub
|
||||
# end class docListTypeSub
|
||||
|
||||
|
||||
class docListItemTypeSub(supermod.docListItemType):
|
||||
def __init__(self, para=None):
|
||||
supermod.docListItemType.__init__(self, para)
|
||||
supermod.docListItemType.subclass = docListItemTypeSub
|
||||
# end class docListItemTypeSub
|
||||
|
||||
|
||||
class docSimpleSectTypeSub(supermod.docSimpleSectType):
|
||||
def __init__(self, kind=None, title=None, para=None):
|
||||
supermod.docSimpleSectType.__init__(self, kind, title, para)
|
||||
supermod.docSimpleSectType.subclass = docSimpleSectTypeSub
|
||||
# end class docSimpleSectTypeSub
|
||||
|
||||
|
||||
class docVarListEntryTypeSub(supermod.docVarListEntryType):
|
||||
def __init__(self, term=None):
|
||||
supermod.docVarListEntryType.__init__(self, term)
|
||||
supermod.docVarListEntryType.subclass = docVarListEntryTypeSub
|
||||
# end class docVarListEntryTypeSub
|
||||
|
||||
|
||||
class docRefTextTypeSub(supermod.docRefTextType):
|
||||
def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docRefTextType.__init__(self, mixedclass_, content_)
|
||||
supermod.docRefTextType.subclass = docRefTextTypeSub
|
||||
# end class docRefTextTypeSub
|
||||
|
||||
|
||||
class docTableTypeSub(supermod.docTableType):
|
||||
def __init__(self, rows=None, cols=None, row=None, caption=None):
|
||||
supermod.docTableType.__init__(self, rows, cols, row, caption)
|
||||
supermod.docTableType.subclass = docTableTypeSub
|
||||
# end class docTableTypeSub
|
||||
|
||||
|
||||
class docRowTypeSub(supermod.docRowType):
|
||||
def __init__(self, entry=None):
|
||||
supermod.docRowType.__init__(self, entry)
|
||||
supermod.docRowType.subclass = docRowTypeSub
|
||||
# end class docRowTypeSub
|
||||
|
||||
|
||||
class docEntryTypeSub(supermod.docEntryType):
|
||||
def __init__(self, thead=None, para=None):
|
||||
supermod.docEntryType.__init__(self, thead, para)
|
||||
supermod.docEntryType.subclass = docEntryTypeSub
|
||||
# end class docEntryTypeSub
|
||||
|
||||
|
||||
class docHeadingTypeSub(supermod.docHeadingType):
|
||||
def __init__(self, level=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docHeadingType.__init__(self, mixedclass_, content_)
|
||||
supermod.docHeadingType.subclass = docHeadingTypeSub
|
||||
# end class docHeadingTypeSub
|
||||
|
||||
|
||||
class docImageTypeSub(supermod.docImageType):
|
||||
def __init__(self, width=None, type_=None, name=None, height=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docImageType.__init__(self, mixedclass_, content_)
|
||||
supermod.docImageType.subclass = docImageTypeSub
|
||||
# end class docImageTypeSub
|
||||
|
||||
|
||||
class docDotFileTypeSub(supermod.docDotFileType):
|
||||
def __init__(self, name=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docDotFileType.__init__(self, mixedclass_, content_)
|
||||
supermod.docDotFileType.subclass = docDotFileTypeSub
|
||||
# end class docDotFileTypeSub
|
||||
|
||||
|
||||
class docTocItemTypeSub(supermod.docTocItemType):
|
||||
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docTocItemType.__init__(self, mixedclass_, content_)
|
||||
supermod.docTocItemType.subclass = docTocItemTypeSub
|
||||
# end class docTocItemTypeSub
|
||||
|
||||
|
||||
class docTocListTypeSub(supermod.docTocListType):
|
||||
def __init__(self, tocitem=None):
|
||||
supermod.docTocListType.__init__(self, tocitem)
|
||||
supermod.docTocListType.subclass = docTocListTypeSub
|
||||
# end class docTocListTypeSub
|
||||
|
||||
|
||||
class docLanguageTypeSub(supermod.docLanguageType):
|
||||
def __init__(self, langid=None, para=None):
|
||||
supermod.docLanguageType.__init__(self, langid, para)
|
||||
supermod.docLanguageType.subclass = docLanguageTypeSub
|
||||
# end class docLanguageTypeSub
|
||||
|
||||
|
||||
class docParamListTypeSub(supermod.docParamListType):
|
||||
def __init__(self, kind=None, parameteritem=None):
|
||||
supermod.docParamListType.__init__(self, kind, parameteritem)
|
||||
supermod.docParamListType.subclass = docParamListTypeSub
|
||||
# end class docParamListTypeSub
|
||||
|
||||
|
||||
class docParamListItemSub(supermod.docParamListItem):
|
||||
def __init__(self, parameternamelist=None, parameterdescription=None):
|
||||
supermod.docParamListItem.__init__(self, parameternamelist, parameterdescription)
|
||||
supermod.docParamListItem.subclass = docParamListItemSub
|
||||
# end class docParamListItemSub
|
||||
|
||||
|
||||
class docParamNameListSub(supermod.docParamNameList):
|
||||
def __init__(self, parametername=None):
|
||||
supermod.docParamNameList.__init__(self, parametername)
|
||||
supermod.docParamNameList.subclass = docParamNameListSub
|
||||
# end class docParamNameListSub
|
||||
|
||||
|
||||
class docParamNameSub(supermod.docParamName):
|
||||
def __init__(self, direction=None, ref=None, mixedclass_=None, content_=None):
|
||||
supermod.docParamName.__init__(self, mixedclass_, content_)
|
||||
supermod.docParamName.subclass = docParamNameSub
|
||||
# end class docParamNameSub
|
||||
|
||||
|
||||
class docXRefSectTypeSub(supermod.docXRefSectType):
|
||||
def __init__(self, id=None, xreftitle=None, xrefdescription=None):
|
||||
supermod.docXRefSectType.__init__(self, id, xreftitle, xrefdescription)
|
||||
supermod.docXRefSectType.subclass = docXRefSectTypeSub
|
||||
# end class docXRefSectTypeSub
|
||||
|
||||
|
||||
class docCopyTypeSub(supermod.docCopyType):
|
||||
def __init__(self, link=None, para=None, sect1=None, internal=None):
|
||||
supermod.docCopyType.__init__(self, link, para, sect1, internal)
|
||||
supermod.docCopyType.subclass = docCopyTypeSub
|
||||
# end class docCopyTypeSub
|
||||
|
||||
|
||||
class docCharTypeSub(supermod.docCharType):
|
||||
def __init__(self, char=None, valueOf_=''):
|
||||
supermod.docCharType.__init__(self, char)
|
||||
supermod.docCharType.subclass = docCharTypeSub
|
||||
# end class docCharTypeSub
|
||||
|
||||
class docParaTypeSub(supermod.docParaType):
|
||||
def __init__(self, char=None, valueOf_=''):
|
||||
supermod.docParaType.__init__(self, char)
|
||||
|
||||
self.parameterlist = []
|
||||
self.simplesects = []
|
||||
self.content = []
|
||||
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
supermod.docParaType.buildChildren(self, child_, nodeName_)
|
||||
|
||||
if child_.nodeType == Node.TEXT_NODE:
|
||||
obj_ = self.mixedclass_(MixedContainer.CategoryText,
|
||||
MixedContainer.TypeNone, '', child_.nodeValue)
|
||||
self.content.append(obj_)
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == "ref":
|
||||
obj_ = supermod.docRefTextType.factory()
|
||||
obj_.build(child_)
|
||||
self.content.append(obj_)
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'parameterlist':
|
||||
obj_ = supermod.docParamListType.factory()
|
||||
obj_.build(child_)
|
||||
self.parameterlist.append(obj_)
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'simplesect':
|
||||
obj_ = supermod.docSimpleSectType.factory()
|
||||
obj_.build(child_)
|
||||
self.simplesects.append(obj_)
|
||||
|
||||
|
||||
supermod.docParaType.subclass = docParaTypeSub
|
||||
# end class docParaTypeSub
|
||||
|
||||
|
||||
|
||||
def parse(inFilename):
|
||||
doc = minidom.parse(inFilename)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = supermod.DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
return rootObj
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
|
||||
"""
|
||||
|
||||
from xml.dom import minidom
|
||||
|
||||
import os
|
||||
import sys
|
||||
import compound
|
||||
|
||||
import indexsuper as supermod
|
||||
|
||||
class DoxygenTypeSub(supermod.DoxygenType):
|
||||
def __init__(self, version=None, compound=None):
|
||||
supermod.DoxygenType.__init__(self, version, compound)
|
||||
|
||||
def find_compounds_and_members(self, details):
|
||||
"""
|
||||
Returns a list of all compounds and their members which match details
|
||||
"""
|
||||
|
||||
results = []
|
||||
for compound in self.compound:
|
||||
members = compound.find_members(details)
|
||||
if members:
|
||||
results.append([compound, members])
|
||||
else:
|
||||
if details.match(compound):
|
||||
results.append([compound, []])
|
||||
|
||||
return results
|
||||
|
||||
supermod.DoxygenType.subclass = DoxygenTypeSub
|
||||
# end class DoxygenTypeSub
|
||||
|
||||
|
||||
class CompoundTypeSub(supermod.CompoundType):
|
||||
def __init__(self, kind=None, refid=None, name='', member=None):
|
||||
supermod.CompoundType.__init__(self, kind, refid, name, member)
|
||||
|
||||
def find_members(self, details):
|
||||
"""
|
||||
Returns a list of all members which match details
|
||||
"""
|
||||
|
||||
results = []
|
||||
|
||||
for member in self.member:
|
||||
if details.match(member):
|
||||
results.append(member)
|
||||
|
||||
return results
|
||||
|
||||
supermod.CompoundType.subclass = CompoundTypeSub
|
||||
# end class CompoundTypeSub
|
||||
|
||||
|
||||
class MemberTypeSub(supermod.MemberType):
|
||||
|
||||
def __init__(self, kind=None, refid=None, name=''):
|
||||
supermod.MemberType.__init__(self, kind, refid, name)
|
||||
|
||||
supermod.MemberType.subclass = MemberTypeSub
|
||||
# end class MemberTypeSub
|
||||
|
||||
|
||||
def parse(inFilename):
|
||||
|
||||
doc = minidom.parse(inFilename)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = supermod.DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
|
||||
return rootObj
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Generated Thu Jun 11 18:43:54 2009 by generateDS.py.
|
||||
#
|
||||
|
||||
import sys
|
||||
import getopt
|
||||
from string import lower as str_lower
|
||||
from xml.dom import minidom
|
||||
from xml.dom import Node
|
||||
|
||||
#
|
||||
# User methods
|
||||
#
|
||||
# Calls to the methods in these classes are generated by generateDS.py.
|
||||
# You can replace these methods by re-implementing the following class
|
||||
# in a module named generatedssuper.py.
|
||||
|
||||
try:
|
||||
from generatedssuper import GeneratedsSuper
|
||||
except ImportError, exp:
|
||||
|
||||
class GeneratedsSuper:
|
||||
def format_string(self, input_data, input_name=''):
|
||||
return input_data
|
||||
def format_integer(self, input_data, input_name=''):
|
||||
return '%d' % input_data
|
||||
def format_float(self, input_data, input_name=''):
|
||||
return '%f' % input_data
|
||||
def format_double(self, input_data, input_name=''):
|
||||
return '%e' % input_data
|
||||
def format_boolean(self, input_data, input_name=''):
|
||||
return '%s' % input_data
|
||||
|
||||
|
||||
#
|
||||
# If you have installed IPython you can uncomment and use the following.
|
||||
# IPython is available from http://ipython.scipy.org/.
|
||||
#
|
||||
|
||||
## from IPython.Shell import IPShellEmbed
|
||||
## args = ''
|
||||
## ipshell = IPShellEmbed(args,
|
||||
## banner = 'Dropping into IPython',
|
||||
## exit_msg = 'Leaving Interpreter, back to program.')
|
||||
|
||||
# Then use the following line where and when you want to drop into the
|
||||
# IPython shell:
|
||||
# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit')
|
||||
|
||||
#
|
||||
# Globals
|
||||
#
|
||||
|
||||
ExternalEncoding = 'ascii'
|
||||
|
||||
#
|
||||
# Support/utility functions.
|
||||
#
|
||||
|
||||
def showIndent(outfile, level):
|
||||
for idx in range(level):
|
||||
outfile.write(' ')
|
||||
|
||||
def quote_xml(inStr):
|
||||
s1 = (isinstance(inStr, basestring) and inStr or
|
||||
'%s' % inStr)
|
||||
s1 = s1.replace('&', '&')
|
||||
s1 = s1.replace('<', '<')
|
||||
s1 = s1.replace('>', '>')
|
||||
return s1
|
||||
|
||||
def quote_attrib(inStr):
|
||||
s1 = (isinstance(inStr, basestring) and inStr or
|
||||
'%s' % inStr)
|
||||
s1 = s1.replace('&', '&')
|
||||
s1 = s1.replace('<', '<')
|
||||
s1 = s1.replace('>', '>')
|
||||
if '"' in s1:
|
||||
if "'" in s1:
|
||||
s1 = '"%s"' % s1.replace('"', """)
|
||||
else:
|
||||
s1 = "'%s'" % s1
|
||||
else:
|
||||
s1 = '"%s"' % s1
|
||||
return s1
|
||||
|
||||
def quote_python(inStr):
|
||||
s1 = inStr
|
||||
if s1.find("'") == -1:
|
||||
if s1.find('\n') == -1:
|
||||
return "'%s'" % s1
|
||||
else:
|
||||
return "'''%s'''" % s1
|
||||
else:
|
||||
if s1.find('"') != -1:
|
||||
s1 = s1.replace('"', '\\"')
|
||||
if s1.find('\n') == -1:
|
||||
return '"%s"' % s1
|
||||
else:
|
||||
return '"""%s"""' % s1
|
||||
|
||||
|
||||
class MixedContainer:
|
||||
# Constants for category:
|
||||
CategoryNone = 0
|
||||
CategoryText = 1
|
||||
CategorySimple = 2
|
||||
CategoryComplex = 3
|
||||
# Constants for content_type:
|
||||
TypeNone = 0
|
||||
TypeText = 1
|
||||
TypeString = 2
|
||||
TypeInteger = 3
|
||||
TypeFloat = 4
|
||||
TypeDecimal = 5
|
||||
TypeDouble = 6
|
||||
TypeBoolean = 7
|
||||
def __init__(self, category, content_type, name, value):
|
||||
self.category = category
|
||||
self.content_type = content_type
|
||||
self.name = name
|
||||
self.value = value
|
||||
def getCategory(self):
|
||||
return self.category
|
||||
def getContenttype(self, content_type):
|
||||
return self.content_type
|
||||
def getValue(self):
|
||||
return self.value
|
||||
def getName(self):
|
||||
return self.name
|
||||
def export(self, outfile, level, name, namespace):
|
||||
if self.category == MixedContainer.CategoryText:
|
||||
outfile.write(self.value)
|
||||
elif self.category == MixedContainer.CategorySimple:
|
||||
self.exportSimple(outfile, level, name)
|
||||
else: # category == MixedContainer.CategoryComplex
|
||||
self.value.export(outfile, level, namespace,name)
|
||||
def exportSimple(self, outfile, level, name):
|
||||
if self.content_type == MixedContainer.TypeString:
|
||||
outfile.write('<%s>%s</%s>' % (self.name, self.value, self.name))
|
||||
elif self.content_type == MixedContainer.TypeInteger or \
|
||||
self.content_type == MixedContainer.TypeBoolean:
|
||||
outfile.write('<%s>%d</%s>' % (self.name, self.value, self.name))
|
||||
elif self.content_type == MixedContainer.TypeFloat or \
|
||||
self.content_type == MixedContainer.TypeDecimal:
|
||||
outfile.write('<%s>%f</%s>' % (self.name, self.value, self.name))
|
||||
elif self.content_type == MixedContainer.TypeDouble:
|
||||
outfile.write('<%s>%g</%s>' % (self.name, self.value, self.name))
|
||||
def exportLiteral(self, outfile, level, name):
|
||||
if self.category == MixedContainer.CategoryText:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \
|
||||
(self.category, self.content_type, self.name, self.value))
|
||||
elif self.category == MixedContainer.CategorySimple:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \
|
||||
(self.category, self.content_type, self.name, self.value))
|
||||
else: # category == MixedContainer.CategoryComplex
|
||||
showIndent(outfile, level)
|
||||
outfile.write('MixedContainer(%d, %d, "%s",\n' % \
|
||||
(self.category, self.content_type, self.name,))
|
||||
self.value.exportLiteral(outfile, level + 1)
|
||||
showIndent(outfile, level)
|
||||
outfile.write(')\n')
|
||||
|
||||
|
||||
class _MemberSpec(object):
|
||||
def __init__(self, name='', data_type='', container=0):
|
||||
self.name = name
|
||||
self.data_type = data_type
|
||||
self.container = container
|
||||
def set_name(self, name): self.name = name
|
||||
def get_name(self): return self.name
|
||||
def set_data_type(self, data_type): self.data_type = data_type
|
||||
def get_data_type(self): return self.data_type
|
||||
def set_container(self, container): self.container = container
|
||||
def get_container(self): return self.container
|
||||
|
||||
|
||||
#
|
||||
# Data representation classes.
|
||||
#
|
||||
|
||||
class DoxygenType(GeneratedsSuper):
|
||||
subclass = None
|
||||
superclass = None
|
||||
def __init__(self, version=None, compound=None):
|
||||
self.version = version
|
||||
if compound is None:
|
||||
self.compound = []
|
||||
else:
|
||||
self.compound = compound
|
||||
def factory(*args_, **kwargs_):
|
||||
if DoxygenType.subclass:
|
||||
return DoxygenType.subclass(*args_, **kwargs_)
|
||||
else:
|
||||
return DoxygenType(*args_, **kwargs_)
|
||||
factory = staticmethod(factory)
|
||||
def get_compound(self): return self.compound
|
||||
def set_compound(self, compound): self.compound = compound
|
||||
def add_compound(self, value): self.compound.append(value)
|
||||
def insert_compound(self, index, value): self.compound[index] = value
|
||||
def get_version(self): return self.version
|
||||
def set_version(self, version): self.version = version
|
||||
def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
|
||||
self.exportAttributes(outfile, level, namespace_, name_='DoxygenType')
|
||||
if self.hasContent_():
|
||||
outfile.write('>\n')
|
||||
self.exportChildren(outfile, level + 1, namespace_, name_)
|
||||
showIndent(outfile, level)
|
||||
outfile.write('</%s%s>\n' % (namespace_, name_))
|
||||
else:
|
||||
outfile.write(' />\n')
|
||||
def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'):
|
||||
outfile.write(' version=%s' % (self.format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), ))
|
||||
def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'):
|
||||
for compound_ in self.compound:
|
||||
compound_.export(outfile, level, namespace_, name_='compound')
|
||||
def hasContent_(self):
|
||||
if (
|
||||
self.compound is not None
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def exportLiteral(self, outfile, level, name_='DoxygenType'):
|
||||
level += 1
|
||||
self.exportLiteralAttributes(outfile, level, name_)
|
||||
if self.hasContent_():
|
||||
self.exportLiteralChildren(outfile, level, name_)
|
||||
def exportLiteralAttributes(self, outfile, level, name_):
|
||||
if self.version is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('version = %s,\n' % (self.version,))
|
||||
def exportLiteralChildren(self, outfile, level, name_):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('compound=[\n')
|
||||
level += 1
|
||||
for compound in self.compound:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('model_.compound(\n')
|
||||
compound.exportLiteral(outfile, level, name_='compound')
|
||||
showIndent(outfile, level)
|
||||
outfile.write('),\n')
|
||||
level -= 1
|
||||
showIndent(outfile, level)
|
||||
outfile.write('],\n')
|
||||
def build(self, node_):
|
||||
attrs = node_.attributes
|
||||
self.buildAttributes(attrs)
|
||||
for child_ in node_.childNodes:
|
||||
nodeName_ = child_.nodeName.split(':')[-1]
|
||||
self.buildChildren(child_, nodeName_)
|
||||
def buildAttributes(self, attrs):
|
||||
if attrs.get('version'):
|
||||
self.version = attrs.get('version').value
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
if child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'compound':
|
||||
obj_ = CompoundType.factory()
|
||||
obj_.build(child_)
|
||||
self.compound.append(obj_)
|
||||
# end class DoxygenType
|
||||
|
||||
|
||||
class CompoundType(GeneratedsSuper):
|
||||
subclass = None
|
||||
superclass = None
|
||||
def __init__(self, kind=None, refid=None, name=None, member=None):
|
||||
self.kind = kind
|
||||
self.refid = refid
|
||||
self.name = name
|
||||
if member is None:
|
||||
self.member = []
|
||||
else:
|
||||
self.member = member
|
||||
def factory(*args_, **kwargs_):
|
||||
if CompoundType.subclass:
|
||||
return CompoundType.subclass(*args_, **kwargs_)
|
||||
else:
|
||||
return CompoundType(*args_, **kwargs_)
|
||||
factory = staticmethod(factory)
|
||||
def get_name(self): return self.name
|
||||
def set_name(self, name): self.name = name
|
||||
def get_member(self): return self.member
|
||||
def set_member(self, member): self.member = member
|
||||
def add_member(self, value): self.member.append(value)
|
||||
def insert_member(self, index, value): self.member[index] = value
|
||||
def get_kind(self): return self.kind
|
||||
def set_kind(self, kind): self.kind = kind
|
||||
def get_refid(self): return self.refid
|
||||
def set_refid(self, refid): self.refid = refid
|
||||
def export(self, outfile, level, namespace_='', name_='CompoundType', namespacedef_=''):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
|
||||
self.exportAttributes(outfile, level, namespace_, name_='CompoundType')
|
||||
if self.hasContent_():
|
||||
outfile.write('>\n')
|
||||
self.exportChildren(outfile, level + 1, namespace_, name_)
|
||||
showIndent(outfile, level)
|
||||
outfile.write('</%s%s>\n' % (namespace_, name_))
|
||||
else:
|
||||
outfile.write(' />\n')
|
||||
def exportAttributes(self, outfile, level, namespace_='', name_='CompoundType'):
|
||||
outfile.write(' kind=%s' % (quote_attrib(self.kind), ))
|
||||
outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), ))
|
||||
def exportChildren(self, outfile, level, namespace_='', name_='CompoundType'):
|
||||
if self.name is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
|
||||
for member_ in self.member:
|
||||
member_.export(outfile, level, namespace_, name_='member')
|
||||
def hasContent_(self):
|
||||
if (
|
||||
self.name is not None or
|
||||
self.member is not None
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def exportLiteral(self, outfile, level, name_='CompoundType'):
|
||||
level += 1
|
||||
self.exportLiteralAttributes(outfile, level, name_)
|
||||
if self.hasContent_():
|
||||
self.exportLiteralChildren(outfile, level, name_)
|
||||
def exportLiteralAttributes(self, outfile, level, name_):
|
||||
if self.kind is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('kind = "%s",\n' % (self.kind,))
|
||||
if self.refid is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('refid = %s,\n' % (self.refid,))
|
||||
def exportLiteralChildren(self, outfile, level, name_):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding))
|
||||
showIndent(outfile, level)
|
||||
outfile.write('member=[\n')
|
||||
level += 1
|
||||
for member in self.member:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('model_.member(\n')
|
||||
member.exportLiteral(outfile, level, name_='member')
|
||||
showIndent(outfile, level)
|
||||
outfile.write('),\n')
|
||||
level -= 1
|
||||
showIndent(outfile, level)
|
||||
outfile.write('],\n')
|
||||
def build(self, node_):
|
||||
attrs = node_.attributes
|
||||
self.buildAttributes(attrs)
|
||||
for child_ in node_.childNodes:
|
||||
nodeName_ = child_.nodeName.split(':')[-1]
|
||||
self.buildChildren(child_, nodeName_)
|
||||
def buildAttributes(self, attrs):
|
||||
if attrs.get('kind'):
|
||||
self.kind = attrs.get('kind').value
|
||||
if attrs.get('refid'):
|
||||
self.refid = attrs.get('refid').value
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
if child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'name':
|
||||
name_ = ''
|
||||
for text__content_ in child_.childNodes:
|
||||
name_ += text__content_.nodeValue
|
||||
self.name = name_
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'member':
|
||||
obj_ = MemberType.factory()
|
||||
obj_.build(child_)
|
||||
self.member.append(obj_)
|
||||
# end class CompoundType
|
||||
|
||||
|
||||
class MemberType(GeneratedsSuper):
|
||||
subclass = None
|
||||
superclass = None
|
||||
def __init__(self, kind=None, refid=None, name=None):
|
||||
self.kind = kind
|
||||
self.refid = refid
|
||||
self.name = name
|
||||
def factory(*args_, **kwargs_):
|
||||
if MemberType.subclass:
|
||||
return MemberType.subclass(*args_, **kwargs_)
|
||||
else:
|
||||
return MemberType(*args_, **kwargs_)
|
||||
factory = staticmethod(factory)
|
||||
def get_name(self): return self.name
|
||||
def set_name(self, name): self.name = name
|
||||
def get_kind(self): return self.kind
|
||||
def set_kind(self, kind): self.kind = kind
|
||||
def get_refid(self): return self.refid
|
||||
def set_refid(self, refid): self.refid = refid
|
||||
def export(self, outfile, level, namespace_='', name_='MemberType', namespacedef_=''):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
|
||||
self.exportAttributes(outfile, level, namespace_, name_='MemberType')
|
||||
if self.hasContent_():
|
||||
outfile.write('>\n')
|
||||
self.exportChildren(outfile, level + 1, namespace_, name_)
|
||||
showIndent(outfile, level)
|
||||
outfile.write('</%s%s>\n' % (namespace_, name_))
|
||||
else:
|
||||
outfile.write(' />\n')
|
||||
def exportAttributes(self, outfile, level, namespace_='', name_='MemberType'):
|
||||
outfile.write(' kind=%s' % (quote_attrib(self.kind), ))
|
||||
outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), ))
|
||||
def exportChildren(self, outfile, level, namespace_='', name_='MemberType'):
|
||||
if self.name is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
|
||||
def hasContent_(self):
|
||||
if (
|
||||
self.name is not None
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def exportLiteral(self, outfile, level, name_='MemberType'):
|
||||
level += 1
|
||||
self.exportLiteralAttributes(outfile, level, name_)
|
||||
if self.hasContent_():
|
||||
self.exportLiteralChildren(outfile, level, name_)
|
||||
def exportLiteralAttributes(self, outfile, level, name_):
|
||||
if self.kind is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('kind = "%s",\n' % (self.kind,))
|
||||
if self.refid is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('refid = %s,\n' % (self.refid,))
|
||||
def exportLiteralChildren(self, outfile, level, name_):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding))
|
||||
def build(self, node_):
|
||||
attrs = node_.attributes
|
||||
self.buildAttributes(attrs)
|
||||
for child_ in node_.childNodes:
|
||||
nodeName_ = child_.nodeName.split(':')[-1]
|
||||
self.buildChildren(child_, nodeName_)
|
||||
def buildAttributes(self, attrs):
|
||||
if attrs.get('kind'):
|
||||
self.kind = attrs.get('kind').value
|
||||
if attrs.get('refid'):
|
||||
self.refid = attrs.get('refid').value
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
if child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'name':
|
||||
name_ = ''
|
||||
for text__content_ in child_.childNodes:
|
||||
name_ += text__content_.nodeValue
|
||||
self.name = name_
|
||||
# end class MemberType
|
||||
|
||||
|
||||
USAGE_TEXT = """
|
||||
Usage: python <Parser>.py [ -s ] <in_xml_file>
|
||||
Options:
|
||||
-s Use the SAX parser, not the minidom parser.
|
||||
"""
|
||||
|
||||
def usage():
|
||||
print USAGE_TEXT
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse(inFileName):
|
||||
doc = minidom.parse(inFileName)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
# Enable Python to collect the space used by the DOM.
|
||||
doc = None
|
||||
sys.stdout.write('<?xml version="1.0" ?>\n')
|
||||
rootObj.export(sys.stdout, 0, name_="doxygenindex",
|
||||
namespacedef_='')
|
||||
return rootObj
|
||||
|
||||
|
||||
def parseString(inString):
|
||||
doc = minidom.parseString(inString)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
# Enable Python to collect the space used by the DOM.
|
||||
doc = None
|
||||
sys.stdout.write('<?xml version="1.0" ?>\n')
|
||||
rootObj.export(sys.stdout, 0, name_="doxygenindex",
|
||||
namespacedef_='')
|
||||
return rootObj
|
||||
|
||||
|
||||
def parseLiteral(inFileName):
|
||||
doc = minidom.parse(inFileName)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
# Enable Python to collect the space used by the DOM.
|
||||
doc = None
|
||||
sys.stdout.write('from index import *\n\n')
|
||||
sys.stdout.write('rootObj = doxygenindex(\n')
|
||||
rootObj.exportLiteral(sys.stdout, 0, name_="doxygenindex")
|
||||
sys.stdout.write(')\n')
|
||||
return rootObj
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 1:
|
||||
parse(args[0])
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
#import pdb
|
||||
#pdb.run('main()')
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Utilities for extracting text from generated classes.
|
||||
"""
|
||||
|
||||
def is_string(txt):
|
||||
if isinstance(txt, str):
|
||||
return True
|
||||
try:
|
||||
if isinstance(txt, unicode):
|
||||
return True
|
||||
except NameError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def description(obj):
|
||||
if obj is None:
|
||||
return None
|
||||
return description_bit(obj).strip()
|
||||
|
||||
def description_bit(obj):
|
||||
if hasattr(obj, 'content'):
|
||||
contents = [description_bit(item) for item in obj.content]
|
||||
result = ''.join(contents)
|
||||
elif hasattr(obj, 'content_'):
|
||||
contents = [description_bit(item) for item in obj.content_]
|
||||
result = ''.join(contents)
|
||||
elif hasattr(obj, 'value'):
|
||||
result = description_bit(obj.value)
|
||||
elif is_string(obj):
|
||||
return obj
|
||||
else:
|
||||
raise StandardError('Expecting a string or something with content, content_ or value attribute')
|
||||
# If this bit is a paragraph then add one some line breaks.
|
||||
if hasattr(obj, 'name') and obj.name == 'para':
|
||||
result += "\n\n"
|
||||
return result
|
|
@ -0,0 +1,7 @@
|
|||
/*!
|
||||
* \defgroup block GNU Radio GSM C++ Signal Processing Blocks
|
||||
* \brief All C++ blocks that can be used from the GSM GNU Radio
|
||||
* module are listed here or in the subcategories below.
|
||||
*
|
||||
*/
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/*! \mainpage
|
||||
|
||||
Welcome to the GNU Radio GSM Block
|
||||
|
||||
This is the intro page for the Doxygen manual generated for the GSM
|
||||
block (docs/doxygen/other/main_page.dox). Edit it to add more detailed
|
||||
documentation about the new GNU Radio modules contained in this
|
||||
project.
|
||||
|
||||
*/
|
|
@ -0,0 +1,255 @@
|
|||
#
|
||||
# Copyright 2010,2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Creates the swig_doc.i SWIG interface file.
|
||||
Execute using: python swig_doc.py xml_path outputfilename
|
||||
|
||||
The file instructs SWIG to transfer the doxygen comments into the
|
||||
python docstrings.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
|
||||
except ImportError:
|
||||
from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
|
||||
|
||||
|
||||
def py_name(name):
|
||||
bits = name.split('_')
|
||||
return '_'.join(bits[1:])
|
||||
|
||||
def make_name(name):
|
||||
bits = name.split('_')
|
||||
return bits[0] + '_make_' + '_'.join(bits[1:])
|
||||
|
||||
|
||||
class Block(object):
|
||||
"""
|
||||
Checks if doxyxml produced objects correspond to a gnuradio block.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def includes(cls, item):
|
||||
if not isinstance(item, DoxyClass):
|
||||
return False
|
||||
# Check for a parsing error.
|
||||
if item.error():
|
||||
return False
|
||||
return item.has_member(make_name(item.name()), DoxyFriend)
|
||||
|
||||
|
||||
def utoascii(text):
|
||||
"""
|
||||
Convert unicode text into ascii and escape quotes.
|
||||
"""
|
||||
if text is None:
|
||||
return ''
|
||||
out = text.encode('ascii', 'replace')
|
||||
out = out.replace('"', '\\"')
|
||||
return out
|
||||
|
||||
|
||||
def combine_descriptions(obj):
|
||||
"""
|
||||
Combines the brief and detailed descriptions of an object together.
|
||||
"""
|
||||
description = []
|
||||
bd = obj.brief_description.strip()
|
||||
dd = obj.detailed_description.strip()
|
||||
if bd:
|
||||
description.append(bd)
|
||||
if dd:
|
||||
description.append(dd)
|
||||
return utoascii('\n\n'.join(description)).strip()
|
||||
|
||||
|
||||
entry_templ = '%feature("docstring") {name} "{docstring}"'
|
||||
def make_entry(obj, name=None, templ="{description}", description=None):
|
||||
"""
|
||||
Create a docstring entry for a swig interface file.
|
||||
|
||||
obj - a doxyxml object from which documentation will be extracted.
|
||||
name - the name of the C object (defaults to obj.name())
|
||||
templ - an optional template for the docstring containing only one
|
||||
variable named 'description'.
|
||||
description - if this optional variable is set then it's value is
|
||||
used as the description instead of extracting it from obj.
|
||||
"""
|
||||
if name is None:
|
||||
name=obj.name()
|
||||
if "operator " in name:
|
||||
return ''
|
||||
if description is None:
|
||||
description = combine_descriptions(obj)
|
||||
docstring = templ.format(description=description)
|
||||
if not docstring:
|
||||
return ''
|
||||
return entry_templ.format(
|
||||
name=name,
|
||||
docstring=docstring,
|
||||
)
|
||||
|
||||
|
||||
def make_func_entry(func, name=None, description=None, params=None):
|
||||
"""
|
||||
Create a function docstring entry for a swig interface file.
|
||||
|
||||
func - a doxyxml object from which documentation will be extracted.
|
||||
name - the name of the C object (defaults to func.name())
|
||||
description - if this optional variable is set then it's value is
|
||||
used as the description instead of extracting it from func.
|
||||
params - a parameter list that overrides using func.params.
|
||||
"""
|
||||
if params is None:
|
||||
params = func.params
|
||||
params = [prm.declname for prm in params]
|
||||
if params:
|
||||
sig = "Params: (%s)" % ", ".join(params)
|
||||
else:
|
||||
sig = "Params: (NONE)"
|
||||
templ = "{description}\n\n" + sig
|
||||
return make_entry(func, name=name, templ=utoascii(templ),
|
||||
description=description)
|
||||
|
||||
|
||||
def make_class_entry(klass, description=None):
|
||||
"""
|
||||
Create a class docstring for a swig interface file.
|
||||
"""
|
||||
output = []
|
||||
output.append(make_entry(klass, description=description))
|
||||
for func in klass.in_category(DoxyFunction):
|
||||
name = klass.name() + '::' + func.name()
|
||||
output.append(make_func_entry(func, name=name))
|
||||
return "\n\n".join(output)
|
||||
|
||||
|
||||
def make_block_entry(di, block):
|
||||
"""
|
||||
Create class and function docstrings of a gnuradio block for a
|
||||
swig interface file.
|
||||
"""
|
||||
descriptions = []
|
||||
# Get the documentation associated with the class.
|
||||
class_desc = combine_descriptions(block)
|
||||
if class_desc:
|
||||
descriptions.append(class_desc)
|
||||
# Get the documentation associated with the make function
|
||||
make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
||||
make_func_desc = combine_descriptions(make_func)
|
||||
if make_func_desc:
|
||||
descriptions.append(make_func_desc)
|
||||
# Get the documentation associated with the file
|
||||
try:
|
||||
block_file = di.get_member(block.name() + ".h", DoxyFile)
|
||||
file_desc = combine_descriptions(block_file)
|
||||
if file_desc:
|
||||
descriptions.append(file_desc)
|
||||
except base.Base.NoSuchMember:
|
||||
# Don't worry if we can't find a matching file.
|
||||
pass
|
||||
# And join them all together to make a super duper description.
|
||||
super_description = "\n\n".join(descriptions)
|
||||
# Associate the combined description with the class and
|
||||
# the make function.
|
||||
output = []
|
||||
output.append(make_class_entry(block, description=super_description))
|
||||
creator = block.get_member(block.name(), DoxyFunction)
|
||||
output.append(make_func_entry(make_func, description=super_description,
|
||||
params=creator.params))
|
||||
return "\n\n".join(output)
|
||||
|
||||
|
||||
def make_swig_interface_file(di, swigdocfilename, custom_output=None):
|
||||
|
||||
output = ["""
|
||||
/*
|
||||
* This file was automatically generated using swig_doc.py.
|
||||
*
|
||||
* Any changes to it will be lost next time it is regenerated.
|
||||
*/
|
||||
"""]
|
||||
|
||||
if custom_output is not None:
|
||||
output.append(custom_output)
|
||||
|
||||
# Create docstrings for the blocks.
|
||||
blocks = di.in_category(Block)
|
||||
make_funcs = set([])
|
||||
for block in blocks:
|
||||
try:
|
||||
make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
||||
make_funcs.add(make_func.name())
|
||||
output.append(make_block_entry(di, block))
|
||||
except block.ParsingError:
|
||||
print('Parsing error for block %s' % block.name())
|
||||
|
||||
# Create docstrings for functions
|
||||
# Don't include the make functions since they have already been dealt with.
|
||||
funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in make_funcs]
|
||||
for f in funcs:
|
||||
try:
|
||||
output.append(make_func_entry(f))
|
||||
except f.ParsingError:
|
||||
print('Parsing error for function %s' % f.name())
|
||||
|
||||
# Create docstrings for classes
|
||||
block_names = [block.name() for block in blocks]
|
||||
klasses = [k for k in di.in_category(DoxyClass) if k.name() not in block_names]
|
||||
for k in klasses:
|
||||
try:
|
||||
output.append(make_class_entry(k))
|
||||
except k.ParsingError:
|
||||
print('Parsing error for class %s' % k.name())
|
||||
|
||||
# Docstrings are not created for anything that is not a function or a class.
|
||||
# If this excludes anything important please add it here.
|
||||
|
||||
output = "\n\n".join(output)
|
||||
|
||||
swig_doc = file(swigdocfilename, 'w')
|
||||
swig_doc.write(output)
|
||||
swig_doc.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Parse command line options and set up doxyxml.
|
||||
err_msg = "Execute using: python swig_doc.py xml_path outputfilename"
|
||||
if len(sys.argv) != 3:
|
||||
raise StandardError(err_msg)
|
||||
xml_path = sys.argv[1]
|
||||
swigdocfilename = sys.argv[2]
|
||||
di = DoxyIndex(xml_path)
|
||||
|
||||
# gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined!
|
||||
# This is presumably a bug in SWIG.
|
||||
#msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
|
||||
#insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
|
||||
#delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
|
||||
output = []
|
||||
#output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
|
||||
#output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
|
||||
custom_output = "\n\n".join(output)
|
||||
|
||||
# Generate the docstrings interface file.
|
||||
make_swig_interface_file(di, swigdocfilename, custom_output=custom_output)
|
|
@ -0,0 +1,4 @@
|
|||
It is considered good practice to add examples in here to demonstrate the
|
||||
functionality of your OOT module. Python scripts, GRC flow graphs or other
|
||||
code can go here.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
install(FILES
|
||||
gsm_receiver.xml
|
||||
gsm_receiver_hier.xml DESTINATION share/gnuradio/grc/blocks
|
||||
)
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0"?>
|
||||
<block>
|
||||
<name>receiver</name>
|
||||
<key>gsm_receiver</key>
|
||||
<category>gsm</category>
|
||||
<import>import gsm</import>
|
||||
<make>gsm.receiver($tuner, $osr)</make>
|
||||
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
|
||||
Sub-nodes:
|
||||
* name
|
||||
* key (makes the value accessible as $keyname, e.g. in the make node)
|
||||
* type -->
|
||||
<param>
|
||||
<name>...</name>
|
||||
<key>...</key>
|
||||
<type>...</type>
|
||||
</param>
|
||||
|
||||
<!-- Make one 'sink' node per input. Sub-nodes:
|
||||
* name (an identifier for the GUI)
|
||||
* type
|
||||
* vlen
|
||||
* optional (set to 1 for optional inputs) -->
|
||||
<sink>
|
||||
<name>in</name>
|
||||
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
|
||||
</sink>
|
||||
|
||||
<!-- Make one 'source' node per output. Sub-nodes:
|
||||
* name (an identifier for the GUI)
|
||||
* type
|
||||
* vlen
|
||||
* optional (set to 1 for optional inputs) -->
|
||||
<source>
|
||||
<name>out</name>
|
||||
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
|
||||
</source>
|
||||
</block>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0"?>
|
||||
<block>
|
||||
<name>GSM Receiver</name>
|
||||
<key>gsm_receiver_hier</key>
|
||||
<category>GSM</category>
|
||||
<import>import gsm</import>
|
||||
<make>gsm.receiver_hier($input_rate, $osr)</make>
|
||||
<param>
|
||||
<name>Input rate</name>
|
||||
<key>input_rate</key>
|
||||
<value>samp_rate</value>
|
||||
<type>real</type>
|
||||
</param>
|
||||
|
||||
<param>
|
||||
<name>Oversampling ration</name>
|
||||
<key>osr</key>
|
||||
<value>4</value>
|
||||
<type>int</type>
|
||||
</param>
|
||||
|
||||
<sink>
|
||||
<name>in</name>
|
||||
<type>complex</type>
|
||||
</sink>
|
||||
|
||||
<source>
|
||||
<name>out</name>
|
||||
<type>float</type>
|
||||
<vlen>142</vlen>
|
||||
</source>
|
||||
</block>
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright 2011,2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Install public header files
|
||||
########################################################################
|
||||
install(FILES
|
||||
api.h
|
||||
receiver.h DESTINATION include/gsm
|
||||
)
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_GSM_API_H
|
||||
#define INCLUDED_GSM_API_H
|
||||
|
||||
#include <gnuradio/attributes.h>
|
||||
|
||||
#ifdef gnuradio_gsm_EXPORTS
|
||||
# define GSM_API __GR_ATTR_EXPORT
|
||||
#else
|
||||
# define GSM_API __GR_ATTR_IMPORT
|
||||
#endif
|
||||
|
||||
#endif /* INCLUDED_GSM_API_H */
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2014 <+YOU OR YOUR COMPANY+>.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_GSM_RECEIVER_H
|
||||
#define INCLUDED_GSM_RECEIVER_H
|
||||
|
||||
#include <gsm/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
#include <gnuradio/feval.h>
|
||||
|
||||
namespace gr {
|
||||
namespace gsm {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup gsm
|
||||
*
|
||||
*/
|
||||
class GSM_API receiver : virtual public block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<receiver> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of gsm::receiver.
|
||||
*
|
||||
* To avoid accidental use of raw pointers, gsm::receiver's
|
||||
* constructor is in a private implementation
|
||||
* class. gsm::receiver::make is the public interface for
|
||||
* creating new instances.
|
||||
*/
|
||||
static sptr make(feval_dd * tuner, int osr);
|
||||
};
|
||||
|
||||
} // namespace gsm
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_GSM_RECEIVER_H */
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# Copyright 2011,2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Setup library
|
||||
########################################################################
|
||||
include(GrPlatform) #define LIB_SUFFIX
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIR})
|
||||
link_directories(${Boost_LIBRARY_DIRS})
|
||||
|
||||
list(APPEND gsm_sources
|
||||
receiver_impl.cc
|
||||
receiver_config.cc
|
||||
viterbi_detector.cc
|
||||
sch.c
|
||||
)
|
||||
|
||||
add_library(gnuradio-gsm SHARED ${gsm_sources})
|
||||
target_link_libraries(gnuradio-gsm ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES})
|
||||
set_target_properties(gnuradio-gsm PROPERTIES DEFINE_SYMBOL "gnuradio_gsm_EXPORTS")
|
||||
|
||||
########################################################################
|
||||
# Install built library files
|
||||
########################################################################
|
||||
install(TARGETS gnuradio-gsm
|
||||
LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
|
||||
ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
|
||||
RUNTIME DESTINATION bin # .dll file
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Build and register unit test
|
||||
########################################################################
|
||||
include(GrTest)
|
||||
|
||||
include_directories(${CPPUNIT_INCLUDE_DIRS})
|
||||
|
||||
list(APPEND test_gsm_sources
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_gsm.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qa_gsm.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qa_receiver.cc
|
||||
)
|
||||
|
||||
add_executable(test-gsm ${test_gsm_sources})
|
||||
|
||||
target_link_libraries(
|
||||
test-gsm
|
||||
${GNURADIO_RUNTIME_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${CPPUNIT_LIBRARIES}
|
||||
gnuradio-gsm
|
||||
)
|
||||
|
||||
GR_ADD_TEST(test_gsm test-gsm)
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This software is distributed under the terms of the GNU Public License.
|
||||
* See the COPYING file in the main directory for details.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSERT_H
|
||||
#define ASSERT_H
|
||||
|
||||
#include "stdio.h"
|
||||
#include <iostream>
|
||||
|
||||
//#define NDEBUG
|
||||
|
||||
/**@name Macros for standard messages. */
|
||||
//@{
|
||||
#define COUT(text) { std::cout << text << std::endl; }
|
||||
#define CERR(text) { std::cerr << __FILE__ << ":" << __LINE__ << ": " << text; }
|
||||
#ifdef NDEBUG
|
||||
#define DCOUT(text) {}
|
||||
#define OBJDCOUT(text) {}
|
||||
#else
|
||||
#define DCOUT(text) { COUT(__FILE__ << ":" << __LINE__ << " " << text); }
|
||||
#define OBJDCOUT(text) { DCOUT(this << " " << text); }
|
||||
#endif
|
||||
//@}
|
||||
|
||||
|
||||
/** This is thrown by assert() so that gdb can catch it. */
|
||||
|
||||
class assertion
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
assertion() {
|
||||
fprintf( stderr,"Try setting a breakpoint @ %s:%u.\n",__FILE__,__LINE__ );
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(EXPR) {};
|
||||
#else
|
||||
/** This replaces the regular assert() with a C++ exception. */
|
||||
#include "stdio.h"
|
||||
#define assert(E) { if (!(E)) { fprintf(stderr,"%s:%u failed assertion '%s'\n",__FILE__,__LINE__,#E); throw Assertion(); } }
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,154 @@
|
|||
#ifndef INCLUDED_GSM_CONSTANTS_H
|
||||
#define INCLUDED_GSM_CONSTANTS_H
|
||||
|
||||
#define GSM_SYMBOL_RATE (1625000.0/6.0) //symbols per second
|
||||
#define GSM_SYMBOL_PERIOD (1.0/GSM_SYMBOL_RATE) //seconds per symbol
|
||||
|
||||
//Burst timing
|
||||
#define TAIL_BITS 3
|
||||
#define GUARD_BITS 8
|
||||
#define GUARD_FRACTIONAL 0.25 //fractional part of guard period
|
||||
#define GUARD_PERIOD GUARD_BITS + GUARD_FRACTIONAL
|
||||
#define DATA_BITS 57 //size of 1 data block in normal burst
|
||||
#define STEALING_BIT 1
|
||||
#define N_TRAIN_BITS 26
|
||||
#define N_SYNC_BITS 64
|
||||
#define USEFUL_BITS 142 //(2*(DATA_BITS+STEALING_BIT) + N_TRAIN_BITS )
|
||||
#define FCCH_BITS USEFUL_BITS
|
||||
#define BURST_SIZE (USEFUL_BITS+2*TAIL_BITS)
|
||||
|
||||
#define SCH_DATA_LEN 39
|
||||
#define TS_BITS (TAIL_BITS+USEFUL_BITS+TAIL_BITS+GUARD_BITS) //a full TS (156 bits)
|
||||
#define TS_PER_FRAME 8
|
||||
#define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // 156.25 * 8
|
||||
#define FCCH_POS TAIL_BITS
|
||||
#define SYNC_POS 39
|
||||
#define TRAIN_POS ( TAIL_BITS + (DATA_BITS+STEALING_BIT) + 5) //first 5 bits of a training sequence
|
||||
//aren't used for channel impulse response estimation
|
||||
#define TRAIN_BEGINNING 5
|
||||
#define SAFETY_MARGIN 6 //
|
||||
|
||||
#define FCCH_HITS_NEEDED (USEFUL_BITS - 4)
|
||||
#define FCCH_MAX_MISSES 1
|
||||
#define FCCH_MAX_FREQ_OFFSET 100
|
||||
|
||||
#define CHAN_IMP_RESP_LENGTH 5
|
||||
|
||||
#define MAX_SCH_ERRORS 5 //maximum number of subsequent sch errors after which gsm receiver goes to find_next_fcch state
|
||||
|
||||
typedef enum {empty, fcch_burst, sch_burst, normal_burst, rach_burst, dummy, dummy_or_normal} burst_type;
|
||||
typedef enum {unknown, multiframe_26, multiframe_51} multiframe_type;
|
||||
|
||||
static const unsigned char SYNC_BITS[] = {
|
||||
1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1
|
||||
};
|
||||
|
||||
const unsigned FCCH_FRAMES[] = {0, 10, 20, 30, 40};
|
||||
const unsigned SCH_FRAMES[] = {1, 11, 21, 31, 41};
|
||||
|
||||
const unsigned BCCH_FRAMES[] = {2, 3, 4, 5}; //!!the receiver shouldn't care about logical
|
||||
//!!channels so this will be removed from this header
|
||||
const unsigned TEST_CCH_FRAMES[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 46, 47, 48, 49};
|
||||
const unsigned TRAFFIC_CHANNEL_F[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
|
||||
const unsigned TEST51[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50};
|
||||
|
||||
|
||||
#define TSC0 0
|
||||
#define TSC1 1
|
||||
#define TSC2 2
|
||||
#define TSC3 3
|
||||
#define TSC4 4
|
||||
#define TSC5 5
|
||||
#define TSC6 6
|
||||
#define TSC7 7
|
||||
#define TS_DUMMY 8
|
||||
|
||||
#define TRAIN_SEQ_NUM 9
|
||||
|
||||
#define TIMESLOT0 0
|
||||
#define TIMESLOT1 1
|
||||
#define TIMESLOT2 2
|
||||
#define TIMESLOT3 3
|
||||
#define TIMESLOT4 4
|
||||
#define TIMESLOT5 5
|
||||
#define TIMESLOT6 6
|
||||
#define TIMESLOT7 7
|
||||
|
||||
|
||||
static const unsigned char train_seq[TRAIN_SEQ_NUM][N_TRAIN_BITS] = {
|
||||
{0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1},
|
||||
{0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1},
|
||||
{0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0},
|
||||
{0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0},
|
||||
{0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1},
|
||||
{0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0},
|
||||
{1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0},
|
||||
{0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1} // DUMMY
|
||||
};
|
||||
|
||||
|
||||
//Dummy burst 0xFB 76 0A 4E 09 10 1F 1C 5C 5C 57 4A 33 39 E9 F1 2F A8
|
||||
static const unsigned char dummy_burst[] = {
|
||||
0, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 0, 0,
|
||||
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 1, 0, 1, 1, 1,
|
||||
0, 0, 0, 1, 0, 1,
|
||||
|
||||
0, 1, 1, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 1, 0, 0, 1, 1, 1,
|
||||
1, 0, 1, 0, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 1, 1,
|
||||
1, 1, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The frequency correction burst is used for frequency synchronization
|
||||
* of the mobile. This is broadcast in TS0 together with the SCH and
|
||||
* BCCH.
|
||||
*
|
||||
* Modulating the bits below causes a spike at 62.5kHz above (below for
|
||||
* COMPACT) the center frequency. One can use this spike with a narrow
|
||||
* band filter to accurately determine the center of the channel.
|
||||
*/
|
||||
static const unsigned char fc_fb[] = {
|
||||
0, 0, 0, //I don't use this tables,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //I copied this here from burst_types.h because
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //the description is very informative - p.krysik
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
static const unsigned char fc_compact_fb[] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDED_GSM_CONSTANTS_H */
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* @file
|
||||
* @author Piotr Krysik <pkrysik@stud.elka.pw.edu.pl>
|
||||
* @section LICENSE
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
* This file contains classes which define gsm_receiver configuration
|
||||
* and the burst_counter which is used to store internal state of the receiver
|
||||
* when it's synchronized
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <receiver_config.h>
|
||||
|
||||
burst_counter & burst_counter::operator++(int)
|
||||
{
|
||||
d_timeslot_nr++;
|
||||
if (d_timeslot_nr == TS_PER_FRAME) {
|
||||
d_timeslot_nr = 0;
|
||||
|
||||
if ((d_t2 == 25) && (d_t3 == 50)) {
|
||||
d_t1 = (d_t1 + 1) % (1 << 11);
|
||||
}
|
||||
|
||||
d_t2 = (d_t2 + 1) % 26;
|
||||
d_t3 = (d_t3 + 1) % 51;
|
||||
}
|
||||
|
||||
//update offset - this is integer for d_OSR which is multiple of four
|
||||
d_offset_fractional += GUARD_FRACTIONAL * d_OSR;
|
||||
d_offset_integer = floor(d_offset_fractional);
|
||||
d_offset_fractional = d_offset_fractional - d_offset_integer;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void burst_counter::set(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr)
|
||||
{
|
||||
d_t1 = t1;
|
||||
d_t2 = t2;
|
||||
d_t3 = t3;
|
||||
d_timeslot_nr = timeslot_nr;
|
||||
double first_sample_position = (get_frame_nr() * 8 + timeslot_nr) * TS_BITS;
|
||||
d_offset_fractional = first_sample_position - floor(first_sample_position);
|
||||
d_offset_integer = 0;
|
||||
}
|
||||
|
||||
burst_type channel_configuration::get_burst_type(burst_counter burst_nr)
|
||||
{
|
||||
uint32_t timeslot_nr = burst_nr.get_timeslot_nr();
|
||||
multiframe_type m_type = d_timeslots_descriptions[timeslot_nr].get_type();
|
||||
uint32_t nr;
|
||||
|
||||
switch (m_type) {
|
||||
case multiframe_26:
|
||||
nr = burst_nr.get_t2();
|
||||
break;
|
||||
case multiframe_51:
|
||||
nr = burst_nr.get_t3();
|
||||
break;
|
||||
default:
|
||||
nr = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return d_timeslots_descriptions[timeslot_nr].get_burst_type(nr);
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* @file
|
||||
* @author Piotr Krysik <pkrysik@stud.elka.pw.edu.pl>
|
||||
* @section LICENSE
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
* This file contains classes which define gsm_receiver configuration
|
||||
* and the burst_counter which is used to store internal state of the receiver
|
||||
* when it's synchronized
|
||||
*/
|
||||
#ifndef INCLUDED_GSM_RECEIVER_CONFIG_H
|
||||
#define INCLUDED_GSM_RECEIVER_CONFIG_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <gsm_constants.h>
|
||||
|
||||
class multiframe_configuration
|
||||
{
|
||||
private:
|
||||
multiframe_type d_type;
|
||||
std::vector<burst_type> d_burst_types;
|
||||
public:
|
||||
multiframe_configuration() {
|
||||
d_type = unknown;
|
||||
fill(d_burst_types.begin(), d_burst_types.end(), empty);
|
||||
}
|
||||
|
||||
~multiframe_configuration() {}
|
||||
|
||||
void set_type(multiframe_type type) {
|
||||
if (type == multiframe_26) {
|
||||
d_burst_types.resize(26);
|
||||
} else {
|
||||
d_burst_types.resize(51);
|
||||
}
|
||||
|
||||
d_type = type;
|
||||
}
|
||||
|
||||
void set_burst_type(int nr, burst_type type) {
|
||||
d_burst_types[nr] = type;
|
||||
}
|
||||
|
||||
multiframe_type get_type() {
|
||||
return d_type;
|
||||
}
|
||||
|
||||
burst_type get_burst_type(int nr) {
|
||||
return d_burst_types[nr];
|
||||
}
|
||||
};
|
||||
|
||||
class burst_counter
|
||||
{
|
||||
private:
|
||||
const int d_OSR;
|
||||
uint32_t d_t1, d_t2, d_t3, d_timeslot_nr;
|
||||
double d_offset_fractional;
|
||||
double d_offset_integer;
|
||||
public:
|
||||
burst_counter(int osr):
|
||||
d_OSR(osr),
|
||||
d_t1(0),
|
||||
d_t2(0),
|
||||
d_t3(0),
|
||||
d_timeslot_nr(0),
|
||||
d_offset_fractional(0.0),
|
||||
d_offset_integer(0.0) {
|
||||
}
|
||||
|
||||
burst_counter(int osr, uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr):
|
||||
d_OSR(osr),
|
||||
d_t1(t1),
|
||||
d_t2(t2),
|
||||
d_t3(t3),
|
||||
d_timeslot_nr(timeslot_nr),
|
||||
d_offset_fractional(0.0),
|
||||
d_offset_integer(0.0) {
|
||||
double first_sample_position = (get_frame_nr() * 8 + timeslot_nr) * TS_BITS;
|
||||
d_offset_integer = floor(first_sample_position);
|
||||
d_offset_fractional = first_sample_position - floor(first_sample_position);
|
||||
}
|
||||
|
||||
burst_counter & operator++(int);
|
||||
void set(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr);
|
||||
|
||||
uint32_t get_t1() {
|
||||
return d_t1;
|
||||
}
|
||||
|
||||
uint32_t get_t2() {
|
||||
return d_t2;
|
||||
}
|
||||
|
||||
uint32_t get_t3() {
|
||||
return d_t3;
|
||||
}
|
||||
|
||||
uint32_t get_timeslot_nr() {
|
||||
return d_timeslot_nr;
|
||||
}
|
||||
|
||||
uint32_t get_frame_nr() {
|
||||
return (51 * 26 * d_t1) + (51 * (((d_t3 + 26) - d_t2) % 26)) + d_t3;
|
||||
}
|
||||
|
||||
uint32_t get_frame_nr_mod() {
|
||||
return (d_t1 << 11) + (d_t3 << 5) + d_t2;
|
||||
}
|
||||
|
||||
unsigned get_offset() {
|
||||
return (unsigned)d_offset_integer;
|
||||
}
|
||||
};
|
||||
|
||||
class channel_configuration
|
||||
{
|
||||
private:
|
||||
multiframe_configuration d_timeslots_descriptions[TS_PER_FRAME];
|
||||
public:
|
||||
channel_configuration() {
|
||||
for (int i = 0; i < TS_PER_FRAME; i++) {
|
||||
d_timeslots_descriptions[i].set_type(unknown);
|
||||
}
|
||||
}
|
||||
|
||||
void set_multiframe_type(int timeslot_nr, multiframe_type type) {
|
||||
d_timeslots_descriptions[timeslot_nr].set_type(type);
|
||||
}
|
||||
|
||||
void set_burst_types(int timeslot_nr, const unsigned mapping[], unsigned mapping_size, burst_type b_type) {
|
||||
unsigned i;
|
||||
for (i = 0; i < mapping_size; i++) {
|
||||
d_timeslots_descriptions[timeslot_nr].set_burst_type(mapping[i], b_type);
|
||||
}
|
||||
}
|
||||
|
||||
void set_single_burst_type(int timeslot_nr, int burst_nr, burst_type b_type) {
|
||||
d_timeslots_descriptions[timeslot_nr].set_burst_type(burst_nr, b_type);
|
||||
}
|
||||
|
||||
burst_type get_burst_type(burst_counter burst_nr);
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_GSM_RECEIVER_CONFIG_H */
|
|
@ -0,0 +1,770 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2014 <+YOU OR YOUR COMPANY+>.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gnuradio/io_signature.h>
|
||||
#include "receiver_impl.h"
|
||||
|
||||
#include <gnuradio/io_signature.h>
|
||||
#include <gnuradio/math.h>
|
||||
#include <math.h>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <viterbi_detector.h>
|
||||
#include <string.h>
|
||||
#include <sch.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define SYNC_SEARCH_RANGE 30
|
||||
|
||||
namespace gr {
|
||||
namespace gsm {
|
||||
|
||||
typedef std::list<float> list_float;
|
||||
typedef std::vector<float> vector_float;
|
||||
|
||||
typedef boost::circular_buffer<float> circular_buffer_float;
|
||||
|
||||
receiver::sptr
|
||||
receiver::make(feval_dd * tuner, int osr)
|
||||
{
|
||||
return gnuradio::get_initial_sptr
|
||||
(new receiver_impl(tuner, osr));
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
receiver_impl::receiver_impl(feval_dd * tuner, int osr)
|
||||
: gr::block("receiver",
|
||||
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
||||
gr::io_signature::make(0, 1, 142 * sizeof(float))),
|
||||
d_OSR(osr),
|
||||
d_chan_imp_length(CHAN_IMP_RESP_LENGTH),
|
||||
d_tuner(tuner),
|
||||
d_counter(0),
|
||||
d_fcch_start_pos(0),
|
||||
d_freq_offset(0),
|
||||
d_state(first_fcch_search),
|
||||
d_burst_nr(osr),
|
||||
d_failed_sch(0)
|
||||
{
|
||||
int i;
|
||||
gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0));
|
||||
for (i = 0; i < TRAIN_SEQ_NUM; i++) {
|
||||
gr_complex startpoint;
|
||||
if (i == 6 || i == 7) { //this is nasty hack
|
||||
startpoint = gr_complex(-1.0, 0.0); //if I don't change it here all bits of normal bursts for BTSes with bcc=6 will have reversed values
|
||||
} else {
|
||||
startpoint = gr_complex(1.0, 0.0); //I've checked this hack for bcc==0,1,2,3,4,6
|
||||
} //I don't know what about bcc==5 and 7 yet
|
||||
//TODO:find source of this situation - this is purely mathematical problem I guess
|
||||
|
||||
gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
receiver_impl::~receiver_impl()
|
||||
{
|
||||
}
|
||||
|
||||
void receiver_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
|
||||
{
|
||||
ninput_items_required[0] = noutput_items * floor((TS_BITS + 2 * GUARD_PERIOD) * d_OSR);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
receiver_impl::general_work(int noutput_items,
|
||||
gr_vector_int &ninput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
const gr_complex *input = (const gr_complex *) input_items[0];
|
||||
//float *out = (float *) output_items[0];
|
||||
int produced_out = 0; //how many output elements were produced - this isn't used yet
|
||||
//probably the gsm receiver will be changed into sink so this variable won't be necessary
|
||||
switch (d_state) {
|
||||
//bootstrapping
|
||||
case first_fcch_search:
|
||||
if (find_fcch_burst(input, ninput_items[0])) { //find frequency correction burst in the input buffer
|
||||
set_frequency(d_freq_offset); //if fcch search is successful set frequency offset
|
||||
//produced_out = 0;
|
||||
d_state = next_fcch_search;
|
||||
} else {
|
||||
//produced_out = 0;
|
||||
d_state = first_fcch_search;
|
||||
}
|
||||
break;
|
||||
|
||||
case next_fcch_search: { //this state is used because it takes some time (a bunch of buffered samples)
|
||||
COUT("fcch");
|
||||
float prev_freq_offset = d_freq_offset; //before previous set_frequqency cause change
|
||||
if (find_fcch_burst(input, ninput_items[0])) {
|
||||
if (abs(prev_freq_offset - d_freq_offset) > FCCH_MAX_FREQ_OFFSET) {
|
||||
set_frequency(d_freq_offset); //call set_frequncy only frequency offset change is greater than some value
|
||||
}
|
||||
//produced_out = 0;
|
||||
d_state = sch_search;
|
||||
} else {
|
||||
//produced_out = 0;
|
||||
d_state = next_fcch_search;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case sch_search: {
|
||||
vector_complex channel_imp_resp(CHAN_IMP_RESP_LENGTH*d_OSR);
|
||||
int t1, t2, t3;
|
||||
int burst_start = 0;
|
||||
unsigned char output_binary[BURST_SIZE];
|
||||
|
||||
if (reach_sch_burst(ninput_items[0])) { //wait for a SCH burst
|
||||
burst_start = get_sch_chan_imp_resp(input, &channel_imp_resp[0]); //get channel impulse response from it
|
||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //detect bits using MLSE detection
|
||||
if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //decode SCH burst
|
||||
COUT("sch burst_start: " << burst_start);
|
||||
COUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3);
|
||||
d_burst_nr.set(t1, t2, t3, 0); //set counter of bursts value
|
||||
|
||||
//configure the receiver - tell him where to find which burst type
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT0, multiframe_51); //in the timeslot nr.0 bursts changes according to t3 counter
|
||||
configure_receiver();//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||
d_channel_conf.set_burst_types(TIMESLOT0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); //tell where to find fcch bursts
|
||||
d_channel_conf.set_burst_types(TIMESLOT0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); //sch bursts
|
||||
d_channel_conf.set_burst_types(TIMESLOT0, BCCH_FRAMES, sizeof(BCCH_FRAMES) / sizeof(unsigned), normal_burst);//!and maybe normal bursts of the BCCH logical channel
|
||||
d_burst_nr++;
|
||||
|
||||
consume_each(burst_start + BURST_SIZE * d_OSR); //consume samples up to next guard period
|
||||
d_state = synchronized;
|
||||
} else {
|
||||
d_state = next_fcch_search; //if there is error in the sch burst go back to fcch search phase
|
||||
}
|
||||
} else {
|
||||
d_state = sch_search;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//in this state receiver is synchronized and it processes bursts according to burst type for given burst number
|
||||
case synchronized: {
|
||||
vector_complex channel_imp_resp(CHAN_IMP_RESP_LENGTH*d_OSR);
|
||||
int burst_start;
|
||||
int offset = 0;
|
||||
int to_consume = 0;
|
||||
unsigned char output_binary[BURST_SIZE];
|
||||
|
||||
burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); //get burst type for given burst number
|
||||
|
||||
switch (b_type) {
|
||||
case fcch_burst: { //if it's FCCH burst
|
||||
const unsigned first_sample = ceil((GUARD_PERIOD + 2 * TAIL_BITS) * d_OSR) + 1;
|
||||
const unsigned last_sample = first_sample + USEFUL_BITS * d_OSR - TAIL_BITS * d_OSR;
|
||||
double freq_offset = compute_freq_offset(input, first_sample, last_sample); //extract frequency offset from it
|
||||
|
||||
d_freq_offset_vals.push_front(freq_offset);
|
||||
//process_normal_burst(d_burst_nr, fc_fb);
|
||||
if (d_freq_offset_vals.size() >= 10) {
|
||||
double sum = std::accumulate(d_freq_offset_vals.begin(), d_freq_offset_vals.end(), 0);
|
||||
double mean_offset = sum / d_freq_offset_vals.size(); //compute mean
|
||||
d_freq_offset_vals.clear();
|
||||
if (abs(mean_offset) > FCCH_MAX_FREQ_OFFSET) {
|
||||
d_freq_offset -= mean_offset; //and adjust frequency if it have changed beyond
|
||||
set_frequency(d_freq_offset); //some limit
|
||||
DCOUT("mean_offset: " << mean_offset);
|
||||
DCOUT("Adjusting frequency, new frequency offset: " << d_freq_offset << "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sch_burst: { //if it's SCH burst
|
||||
int t1, t2, t3, d_ncc, d_bcc;
|
||||
burst_start = get_sch_chan_imp_resp(input, &channel_imp_resp[0]); //get channel impulse response
|
||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits
|
||||
//process_normal_burst(d_burst_nr, output_binary);
|
||||
if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //and decode SCH data
|
||||
// d_burst_nr.set(t1, t2, t3, 0); //but only to check if burst_start value is correct
|
||||
d_failed_sch = 0;
|
||||
DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3);
|
||||
offset = burst_start - floor((GUARD_PERIOD) * d_OSR); //compute offset from burst_start - burst should start after a guard period
|
||||
DCOUT(offset);
|
||||
to_consume += offset; //adjust with offset number of samples to be consumed
|
||||
} else {
|
||||
d_failed_sch++;
|
||||
if (d_failed_sch >= MAX_SCH_ERRORS) {
|
||||
// d_state = next_fcch_search; //TODO: this isn't good, the receiver is going wild when it goes back to next_fcch_search from here
|
||||
// d_freq_offset_vals.clear();
|
||||
DCOUT("many sch decoding errors");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case normal_burst: //if it's normal burst
|
||||
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); //get channel impulse response for given training sequence number - d_bcc
|
||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits
|
||||
process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||
break;
|
||||
|
||||
case dummy_or_normal: {
|
||||
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TS_DUMMY);
|
||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary);
|
||||
|
||||
std::vector<unsigned char> v(20);
|
||||
std::vector<unsigned char>::iterator it;
|
||||
it = std::set_difference(output_binary + TRAIN_POS, output_binary + TRAIN_POS + 16, &train_seq[TS_DUMMY][5], &train_seq[TS_DUMMY][21], v.begin());
|
||||
int different_bits = (it - v.begin());
|
||||
|
||||
if (different_bits > 2) {
|
||||
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc);
|
||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary);
|
||||
//if (!output_binary[0] && !output_binary[1] && !output_binary[2]) {
|
||||
COUT("Normal burst");
|
||||
process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||
//}
|
||||
} else {
|
||||
//process_normal_burst(d_burst_nr, dummy_burst);
|
||||
}
|
||||
}
|
||||
case rach_burst:
|
||||
//implementation of this channel isn't possible in current gsm_receiver
|
||||
//it would take some realtime processing, counter of samples from USRP to
|
||||
//stay synchronized with this device and possibility to switch frequency from uplink
|
||||
//to C0 (where sch is) back and forth
|
||||
|
||||
break;
|
||||
case dummy: //if it's dummy
|
||||
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TS_DUMMY); //read dummy
|
||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); // but as far as I know it's pointless
|
||||
break;
|
||||
case empty: //if it's empty burst
|
||||
break; //do nothing
|
||||
}
|
||||
|
||||
d_burst_nr++; //go to next burst
|
||||
|
||||
to_consume += TS_BITS * d_OSR + d_burst_nr.get_offset(); //consume samples of the burst up to next guard period
|
||||
//and add offset which is introduced by
|
||||
//0.25 fractional part of a guard period
|
||||
//burst_number computes this offset
|
||||
//but choice of this class to do this was random
|
||||
consume_each(to_consume);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return produced_out;
|
||||
}
|
||||
|
||||
|
||||
bool receiver_impl::find_fcch_burst(const gr_complex *input, const int nitems)
|
||||
{
|
||||
circular_buffer_float phase_diff_buffer(FCCH_HITS_NEEDED * d_OSR); //circular buffer used to scan throug signal to find
|
||||
//best match for FCCH burst
|
||||
float phase_diff = 0;
|
||||
gr_complex conjprod;
|
||||
int start_pos = -1;
|
||||
int hit_count = 0;
|
||||
int miss_count = 0;
|
||||
float min_phase_diff;
|
||||
float max_phase_diff;
|
||||
double best_sum = 0;
|
||||
float lowest_max_min_diff = 99999;
|
||||
|
||||
int to_consume = 0;
|
||||
int sample_number = 0;
|
||||
bool end = false;
|
||||
bool result = false;
|
||||
circular_buffer_float::iterator buffer_iter;
|
||||
|
||||
/**@name Possible states of FCCH search algorithm*/
|
||||
//@{
|
||||
enum states {
|
||||
init, ///< initialize variables
|
||||
search, ///< search for positive samples
|
||||
found_something, ///< search for FCCH and the best position of it
|
||||
fcch_found, ///< when FCCH was found
|
||||
search_fail ///< when there is no FCCH in the input vector
|
||||
} fcch_search_state;
|
||||
//@}
|
||||
|
||||
fcch_search_state = init;
|
||||
|
||||
while (!end) {
|
||||
switch (fcch_search_state) {
|
||||
|
||||
case init: //initialize variables
|
||||
hit_count = 0;
|
||||
miss_count = 0;
|
||||
start_pos = -1;
|
||||
lowest_max_min_diff = 99999;
|
||||
phase_diff_buffer.clear();
|
||||
fcch_search_state = search;
|
||||
|
||||
break;
|
||||
|
||||
case search: // search for positive samples
|
||||
sample_number++;
|
||||
|
||||
if (sample_number > nitems - FCCH_HITS_NEEDED * d_OSR) { //if it isn't possible to find FCCH because
|
||||
//there's too few samples left to look into,
|
||||
to_consume = sample_number; //don't do anything with those samples which are left
|
||||
//and consume only those which were checked
|
||||
fcch_search_state = search_fail;
|
||||
} else {
|
||||
phase_diff = compute_phase_diff(input[sample_number], input[sample_number-1]);
|
||||
|
||||
if (phase_diff > 0) { //if a positive phase difference was found
|
||||
to_consume = sample_number;
|
||||
fcch_search_state = found_something; //switch to state in which searches for FCCH
|
||||
} else {
|
||||
fcch_search_state = search;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case found_something: {// search for FCCH and the best position of it
|
||||
if (phase_diff > 0) {
|
||||
hit_count++; //positive phase differencies increases hits_count
|
||||
} else {
|
||||
miss_count++; //negative increases miss_count
|
||||
}
|
||||
|
||||
if ((miss_count >= FCCH_MAX_MISSES * d_OSR) && (hit_count <= FCCH_HITS_NEEDED * d_OSR)) {
|
||||
//if miss_count exceeds limit before hit_count
|
||||
fcch_search_state = init; //go to init
|
||||
continue;
|
||||
} else if (((miss_count >= FCCH_MAX_MISSES * d_OSR) && (hit_count > FCCH_HITS_NEEDED * d_OSR)) || (hit_count > 2 * FCCH_HITS_NEEDED * d_OSR)) {
|
||||
//if hit_count and miss_count exceeds limit then FCCH was found
|
||||
fcch_search_state = fcch_found;
|
||||
continue;
|
||||
} else if ((miss_count < FCCH_MAX_MISSES * d_OSR) && (hit_count > FCCH_HITS_NEEDED * d_OSR)) {
|
||||
//find difference between minimal and maximal element in the buffer
|
||||
//for FCCH this value should be low
|
||||
//this part is searching for a region where this value is lowest
|
||||
min_phase_diff = * (min_element(phase_diff_buffer.begin(), phase_diff_buffer.end()));
|
||||
max_phase_diff = * (max_element(phase_diff_buffer.begin(), phase_diff_buffer.end()));
|
||||
|
||||
if (lowest_max_min_diff > max_phase_diff - min_phase_diff) {
|
||||
lowest_max_min_diff = max_phase_diff - min_phase_diff;
|
||||
start_pos = sample_number - FCCH_HITS_NEEDED * d_OSR - FCCH_MAX_MISSES * d_OSR; //store start pos
|
||||
best_sum = 0;
|
||||
|
||||
for (buffer_iter = phase_diff_buffer.begin();
|
||||
buffer_iter != (phase_diff_buffer.end());
|
||||
buffer_iter++) {
|
||||
best_sum += *buffer_iter - (M_PI / 2) / d_OSR; //store best value of phase offset sum
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sample_number++;
|
||||
|
||||
if (sample_number >= nitems) { //if there's no single sample left to check
|
||||
fcch_search_state = search_fail;//FCCH search failed
|
||||
continue;
|
||||
}
|
||||
|
||||
phase_diff = compute_phase_diff(input[sample_number], input[sample_number-1]);
|
||||
phase_diff_buffer.push_back(phase_diff);
|
||||
fcch_search_state = found_something;
|
||||
}
|
||||
break;
|
||||
|
||||
case fcch_found: {
|
||||
DCOUT("fcch found on position: " << d_counter + start_pos);
|
||||
to_consume = start_pos + FCCH_HITS_NEEDED * d_OSR + 1; //consume one FCCH burst
|
||||
|
||||
d_fcch_start_pos = d_counter + start_pos;
|
||||
|
||||
//compute frequency offset
|
||||
double phase_offset = best_sum / FCCH_HITS_NEEDED;
|
||||
double freq_offset = phase_offset * 1625000.0 / (12.0 * M_PI);
|
||||
d_freq_offset -= freq_offset;
|
||||
DCOUT("freq_offset: " << d_freq_offset);
|
||||
|
||||
end = true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case search_fail:
|
||||
end = true;
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
d_counter += to_consume;
|
||||
consume_each(to_consume);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
double receiver_impl::compute_freq_offset(const gr_complex * input, unsigned first_sample, unsigned last_sample)
|
||||
{
|
||||
double phase_sum = 0;
|
||||
unsigned ii;
|
||||
|
||||
for (ii = first_sample; ii < last_sample; ii++) {
|
||||
double phase_diff = compute_phase_diff(input[ii], input[ii-1]) - (M_PI / 2) / d_OSR;
|
||||
phase_sum += phase_diff;
|
||||
}
|
||||
|
||||
double phase_offset = phase_sum / (last_sample - first_sample);
|
||||
double freq_offset = phase_offset * 1625000.0 / (12.0 * M_PI);
|
||||
return freq_offset;
|
||||
}
|
||||
|
||||
void receiver_impl::set_frequency(double freq_offset)
|
||||
{
|
||||
d_tuner->calleval(freq_offset);
|
||||
}
|
||||
|
||||
inline float receiver_impl::compute_phase_diff(gr_complex val1, gr_complex val2)
|
||||
{
|
||||
gr_complex conjprod = val1 * conj(val2);
|
||||
return fast_atan2f(imag(conjprod), real(conjprod));
|
||||
}
|
||||
|
||||
bool receiver_impl::reach_sch_burst(const int nitems)
|
||||
{
|
||||
//it just consumes samples to get near to a SCH burst
|
||||
int to_consume = 0;
|
||||
bool result = false;
|
||||
unsigned sample_nr_near_sch_start = d_fcch_start_pos + (FRAME_BITS - SAFETY_MARGIN) * d_OSR;
|
||||
|
||||
//consume samples until d_counter will be equal to sample_nr_near_sch_start
|
||||
if (d_counter < sample_nr_near_sch_start) {
|
||||
if (d_counter + nitems >= sample_nr_near_sch_start) {
|
||||
to_consume = sample_nr_near_sch_start - d_counter;
|
||||
} else {
|
||||
to_consume = nitems;
|
||||
}
|
||||
result = false;
|
||||
} else {
|
||||
to_consume = 0;
|
||||
result = true;
|
||||
}
|
||||
|
||||
d_counter += to_consume;
|
||||
consume_each(to_consume);
|
||||
return result;
|
||||
}
|
||||
|
||||
int receiver_impl::get_sch_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp)
|
||||
{
|
||||
vector_complex correlation_buffer;
|
||||
vector_float power_buffer;
|
||||
vector_float window_energy_buffer;
|
||||
|
||||
int strongest_window_nr;
|
||||
int burst_start = 0;
|
||||
int chan_imp_resp_center = 0;
|
||||
float max_correlation = 0;
|
||||
float energy = 0;
|
||||
|
||||
for (int ii = SYNC_POS * d_OSR; ii < (SYNC_POS + SYNC_SEARCH_RANGE) *d_OSR; ii++) {
|
||||
gr_complex correlation = correlate_sequence(&d_sch_training_seq[5], N_SYNC_BITS - 10, &input[ii]);
|
||||
correlation_buffer.push_back(correlation);
|
||||
power_buffer.push_back(std::pow(abs(correlation), 2));
|
||||
}
|
||||
|
||||
//compute window energies
|
||||
vector_float::iterator iter = power_buffer.begin();
|
||||
bool loop_end = false;
|
||||
while (iter != power_buffer.end()) {
|
||||
vector_float::iterator iter_ii = iter;
|
||||
energy = 0;
|
||||
|
||||
for (int ii = 0; ii < (d_chan_imp_length) *d_OSR; ii++, iter_ii++) {
|
||||
if (iter_ii == power_buffer.end()) {
|
||||
loop_end = true;
|
||||
break;
|
||||
}
|
||||
energy += (*iter_ii);
|
||||
}
|
||||
if (loop_end) {
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
window_energy_buffer.push_back(energy);
|
||||
}
|
||||
|
||||
strongest_window_nr = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin();
|
||||
// d_channel_imp_resp.clear();
|
||||
|
||||
max_correlation = 0;
|
||||
for (int ii = 0; ii < (d_chan_imp_length) *d_OSR; ii++) {
|
||||
gr_complex correlation = correlation_buffer[strongest_window_nr + ii];
|
||||
if (abs(correlation) > max_correlation) {
|
||||
chan_imp_resp_center = ii;
|
||||
max_correlation = abs(correlation);
|
||||
}
|
||||
// d_channel_imp_resp.push_back(correlation);
|
||||
chan_imp_resp[ii] = correlation;
|
||||
}
|
||||
|
||||
burst_start = strongest_window_nr + chan_imp_resp_center - 48 * d_OSR - 2 * d_OSR + 2 + SYNC_POS * d_OSR;
|
||||
return burst_start;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void receiver_impl::detect_burst(const gr_complex * input, gr_complex * chan_imp_resp, int burst_start, unsigned char * output_binary)
|
||||
{
|
||||
float output[BURST_SIZE];
|
||||
gr_complex rhh_temp[CHAN_IMP_RESP_LENGTH*d_OSR];
|
||||
gr_complex rhh[CHAN_IMP_RESP_LENGTH];
|
||||
gr_complex filtered_burst[BURST_SIZE];
|
||||
int start_state = 3;
|
||||
unsigned int stop_states[2] = {4, 12};
|
||||
|
||||
autocorrelation(chan_imp_resp, rhh_temp, d_chan_imp_length*d_OSR);
|
||||
for (int ii = 0; ii < (d_chan_imp_length); ii++) {
|
||||
rhh[ii] = conj(rhh_temp[ii*d_OSR]);
|
||||
}
|
||||
|
||||
mafi(&input[burst_start], BURST_SIZE, chan_imp_resp, d_chan_imp_length*d_OSR, filtered_burst);
|
||||
|
||||
viterbi_detector(filtered_burst, BURST_SIZE, rhh, start_state, stop_states, 2, output);
|
||||
|
||||
for (int i = 0; i < BURST_SIZE ; i++) {
|
||||
output_binary[i] = (output[i] > 0);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO consider placing this funtion in a separate class for signal processing
|
||||
void receiver_impl::gmsk_mapper(const unsigned char * input, int nitems, gr_complex * gmsk_output, gr_complex start_point)
|
||||
{
|
||||
gr_complex j = gr_complex(0.0, 1.0);
|
||||
|
||||
int current_symbol;
|
||||
int encoded_symbol;
|
||||
int previous_symbol = 2 * input[0] - 1;
|
||||
gmsk_output[0] = start_point;
|
||||
|
||||
for (int i = 1; i < nitems; i++) {
|
||||
//change bits representation to NRZ
|
||||
current_symbol = 2 * input[i] - 1;
|
||||
//differentially encode
|
||||
encoded_symbol = current_symbol * previous_symbol;
|
||||
//and do gmsk mapping
|
||||
gmsk_output[i] = j * gr_complex(encoded_symbol, 0.0) * gmsk_output[i-1];
|
||||
previous_symbol = current_symbol;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO consider use of some generalized function for correlation and placing it in a separate class for signal processing
|
||||
gr_complex receiver_impl::correlate_sequence(const gr_complex * sequence, int length, const gr_complex * input)
|
||||
{
|
||||
gr_complex result(0.0, 0.0);
|
||||
int sample_number = 0;
|
||||
|
||||
for (int ii = 0; ii < length; ii++) {
|
||||
sample_number = (ii * d_OSR) ;
|
||||
result += sequence[ii] * conj(input[sample_number]);
|
||||
}
|
||||
|
||||
result = result / gr_complex(length, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//computes autocorrelation for positive arguments
|
||||
//TODO consider placing this funtion in a separate class for signal processing
|
||||
inline void receiver_impl::autocorrelation(const gr_complex * input, gr_complex * out, int nitems)
|
||||
{
|
||||
int i, k;
|
||||
for (k = nitems - 1; k >= 0; k--) {
|
||||
out[k] = gr_complex(0, 0);
|
||||
for (i = k; i < nitems; i++) {
|
||||
out[k] += input[i] * conj(input[i-k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO consider use of some generalized function for filtering and placing it in a separate class for signal processing
|
||||
inline void receiver_impl::mafi(const gr_complex * input, int nitems, gr_complex * filter, int filter_length, gr_complex * output)
|
||||
{
|
||||
int ii = 0, n, a;
|
||||
|
||||
for (n = 0; n < nitems; n++) {
|
||||
a = n * d_OSR;
|
||||
output[n] = 0;
|
||||
ii = 0;
|
||||
|
||||
while (ii < filter_length) {
|
||||
if ((a + ii) >= nitems*d_OSR)
|
||||
break;
|
||||
output[n] += input[a+ii] * filter[ii];
|
||||
ii++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: get_norm_chan_imp_resp is similar to get_sch_chan_imp_resp - consider joining this two functions
|
||||
//TODO: this is place where most errors are introduced and can be corrected by improvements to this fuction
|
||||
//especially computations of strongest_window_nr
|
||||
int receiver_impl::get_norm_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp, int bcc)
|
||||
{
|
||||
vector_complex correlation_buffer;
|
||||
vector_float power_buffer;
|
||||
vector_float window_energy_buffer;
|
||||
|
||||
int strongest_window_nr;
|
||||
int burst_start = 0;
|
||||
int chan_imp_resp_center = 0;
|
||||
float max_correlation = 0;
|
||||
float energy = 0;
|
||||
|
||||
int search_center = (int)((TRAIN_POS + GUARD_PERIOD) * d_OSR);
|
||||
int search_start_pos = search_center + 1;
|
||||
// int search_start_pos = search_center - d_chan_imp_length * d_OSR;
|
||||
int search_stop_pos = search_center + d_chan_imp_length * d_OSR + 2 * d_OSR;
|
||||
|
||||
for (int ii = search_start_pos; ii < search_stop_pos; ii++) {
|
||||
gr_complex correlation = correlate_sequence(&d_norm_training_seq[bcc][TRAIN_BEGINNING], N_TRAIN_BITS - 10, &input[ii]);
|
||||
|
||||
correlation_buffer.push_back(correlation);
|
||||
power_buffer.push_back(std::pow(abs(correlation), 2));
|
||||
}
|
||||
|
||||
//compute window energies
|
||||
vector_float::iterator iter = power_buffer.begin();
|
||||
bool loop_end = false;
|
||||
while (iter != power_buffer.end()) {
|
||||
vector_float::iterator iter_ii = iter;
|
||||
energy = 0;
|
||||
|
||||
for (int ii = 0; ii < (d_chan_imp_length - 2)*d_OSR; ii++, iter_ii++) {
|
||||
// for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++, iter_ii++) {
|
||||
if (iter_ii == power_buffer.end()) {
|
||||
loop_end = true;
|
||||
break;
|
||||
}
|
||||
energy += (*iter_ii);
|
||||
}
|
||||
if (loop_end) {
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
|
||||
window_energy_buffer.push_back(energy);
|
||||
}
|
||||
//!why doesn't this work
|
||||
int strongest_window_nr_new = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin();
|
||||
strongest_window_nr = 3; //! so I have to override it here
|
||||
|
||||
max_correlation = 0;
|
||||
for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++) {
|
||||
gr_complex correlation = correlation_buffer[strongest_window_nr + ii];
|
||||
if (abs(correlation) > max_correlation) {
|
||||
chan_imp_resp_center = ii;
|
||||
max_correlation = abs(correlation);
|
||||
}
|
||||
// d_channel_imp_resp.push_back(correlation);
|
||||
chan_imp_resp[ii] = correlation;
|
||||
}
|
||||
// We want to use the first sample of the impulseresponse, and the
|
||||
// corresponding samples of the received signal.
|
||||
// the variable sync_w should contain the beginning of the used part of
|
||||
// training sequence, which is 3+57+1+6=67 bits into the burst. That is
|
||||
// we have that sync_t16 equals first sample in bit number 67.
|
||||
|
||||
burst_start = search_start_pos + chan_imp_resp_center + strongest_window_nr - TRAIN_POS * d_OSR;
|
||||
|
||||
// GMSK modulator introduces ISI - each bit is expanded for 3*Tb
|
||||
// and it's maximum value is in the last bit period, so burst starts
|
||||
// 2*Tb earlier
|
||||
burst_start -= 2 * d_OSR;
|
||||
burst_start += 2;
|
||||
COUT("Poczatek ###############################");
|
||||
std::cout << " burst_start: " << burst_start << " center: " << ((float)(search_start_pos + strongest_window_nr + chan_imp_resp_center)) / d_OSR << " stronegest window nr: " << strongest_window_nr << "\n";
|
||||
COUT("burst_start_new: " << (search_start_pos + strongest_window_nr_new - TRAIN_POS * d_OSR));
|
||||
burst_start=(search_start_pos + strongest_window_nr_new - TRAIN_POS * d_OSR)
|
||||
return burst_start;
|
||||
}
|
||||
|
||||
|
||||
void receiver_impl::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary)
|
||||
{
|
||||
int ii;
|
||||
//std::cout << "fn:" <<burst_nr.get_frame_nr() << " ts" << burst_nr.get_timeslot_nr() << " ";
|
||||
for(ii=0;ii<148;ii++){
|
||||
std::cout << std::setprecision(1) << static_cast<int>(burst_binary[ii]);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
//TODO: this shouldn't be here also - the same reason
|
||||
void receiver_impl::configure_receiver()
|
||||
{
|
||||
d_channel_conf.set_multiframe_type(TSC0, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT0, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
|
||||
d_channel_conf.set_burst_types(TSC0, TEST_CCH_FRAMES, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst);
|
||||
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT1, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT1, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT2, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT2, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT3, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT3, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT4, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT4, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT5, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT5, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT6, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT6, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
// d_channel_conf.set_multiframe_type(TIMESLOT7, multiframe_26);
|
||||
// d_channel_conf.set_burst_types(TIMESLOT7, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT1, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT1, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT2, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT2, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT3, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT3, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT4, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT4, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT5, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT5, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT6, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT6, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
d_channel_conf.set_multiframe_type(TIMESLOT7, multiframe_51);
|
||||
d_channel_conf.set_burst_types(TIMESLOT7, TEST51, sizeof(TEST51) / sizeof(unsigned), dummy_or_normal);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} /* namespace gsm */
|
||||
} /* namespace gr */
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2014 <+YOU OR YOUR COMPANY+>.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_GSM_RECEIVER_IMPL_H
|
||||
#define INCLUDED_GSM_RECEIVER_IMPL_H
|
||||
|
||||
#include <gsm/receiver.h>
|
||||
#include <gsm_constants.h>
|
||||
#include <receiver_config.h>
|
||||
|
||||
namespace gr {
|
||||
namespace gsm {
|
||||
|
||||
typedef std::vector<gr_complex> vector_complex;
|
||||
|
||||
class receiver_impl : public receiver
|
||||
{
|
||||
private:
|
||||
/**@name Configuration of the receiver */
|
||||
//@{
|
||||
const int d_OSR; ///< oversampling ratio
|
||||
const int d_chan_imp_length; ///< channel impulse length
|
||||
//@}
|
||||
|
||||
gr_complex d_sch_training_seq[N_SYNC_BITS]; ///<encoded training sequence of a SCH burst
|
||||
gr_complex d_norm_training_seq[TRAIN_SEQ_NUM][N_TRAIN_BITS]; ///<encoded training sequences of a normal bursts and dummy bursts
|
||||
|
||||
feval_dd *d_tuner; ///<callback to a python object which is used for frequency tunning
|
||||
|
||||
/** Counts samples consumed by the receiver
|
||||
*
|
||||
* It is used in beetween find_fcch_burst and reach_sch_burst calls.
|
||||
* My intention was to synchronize this counter with some internal sample
|
||||
* counter of the USRP. Simple access to such USRP's counter isn't possible
|
||||
* so this variable isn't used in the "synchronized" state of the receiver yet.
|
||||
*/
|
||||
unsigned d_counter;
|
||||
|
||||
/**@name Variables used to store result of the find_fcch_burst fuction */
|
||||
//@{
|
||||
unsigned d_fcch_start_pos; ///< position of the first sample of the fcch burst
|
||||
float d_freq_offset; ///< frequency offset of the received signal
|
||||
//@}
|
||||
std::list<double> d_freq_offset_vals;
|
||||
|
||||
/**@name Identifiers of the BTS extracted from the SCH burst */
|
||||
//@{
|
||||
int d_ncc; ///< network color code
|
||||
int d_bcc; ///< base station color code
|
||||
//@}
|
||||
|
||||
/**@name Internal state of the gsm receiver */
|
||||
//@{
|
||||
enum states {
|
||||
first_fcch_search, next_fcch_search, sch_search, // synchronization search part
|
||||
synchronized // receiver is synchronized in this state
|
||||
} d_state;
|
||||
//@}
|
||||
|
||||
/**@name Variables which make internal state in the "synchronized" state */
|
||||
//@{
|
||||
burst_counter d_burst_nr; ///< frame number and timeslot number
|
||||
channel_configuration d_channel_conf; ///< mapping of burst_counter to burst_type
|
||||
//@}
|
||||
|
||||
unsigned d_failed_sch; ///< number of subsequent erroneous SCH bursts
|
||||
|
||||
/** Function whis is used to search a FCCH burst and to compute frequency offset before
|
||||
* "synchronized" state of the receiver
|
||||
*
|
||||
* TODO: Describe the FCCH search algorithm in the documentation
|
||||
* @param input vector with input signal
|
||||
* @param nitems number of samples in the input vector
|
||||
* @return
|
||||
*/
|
||||
bool find_fcch_burst(const gr_complex *input, const int nitems);
|
||||
|
||||
/** Computes frequency offset from FCCH burst samples
|
||||
*
|
||||
* @param input vector with input samples
|
||||
* @param first_sample number of the first sample of the FCCH busrt
|
||||
* @param last_sample number of the last sample of the FCCH busrt
|
||||
* @return frequency offset
|
||||
*/
|
||||
double compute_freq_offset(const gr_complex * input, unsigned first_sample, unsigned last_sample);
|
||||
|
||||
/** Calls d_tuner's method to set frequency offset from Python level
|
||||
*
|
||||
* @param freq_offset absolute frequency offset of the received signal
|
||||
*/
|
||||
void set_frequency(double freq_offset);
|
||||
|
||||
/** Computes angle between two complex numbers
|
||||
*
|
||||
* @param val1 first complex number
|
||||
* @param val2 second complex number
|
||||
* @return
|
||||
*/
|
||||
inline float compute_phase_diff(gr_complex val1, gr_complex val2);
|
||||
|
||||
/** Function whis is used to get near to SCH burst
|
||||
*
|
||||
* @param nitems number of samples in the gsm_receiver's buffer
|
||||
* @return true if SCH burst is near, false otherwise
|
||||
*/
|
||||
bool reach_sch_burst(const int nitems);
|
||||
|
||||
/** Extracts channel impulse response from a SCH burst and computes first sample number of this burst
|
||||
*
|
||||
* @param input vector with input samples
|
||||
* @param chan_imp_resp complex vector where channel impulse response will be stored
|
||||
* @return number of first sample of the burst
|
||||
*/
|
||||
int get_sch_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp);
|
||||
|
||||
/** MLSE detection of a burst bits
|
||||
*
|
||||
* Detects bits of burst using viterbi algorithm.
|
||||
* @param input vector with input samples
|
||||
* @param chan_imp_resp vector with the channel impulse response
|
||||
* @param burst_start number of the first sample of the burst
|
||||
* @param output_binary vector with output bits
|
||||
*/
|
||||
void detect_burst(const gr_complex * input, gr_complex * chan_imp_resp, int burst_start, unsigned char * output_binary);
|
||||
|
||||
/** Encodes differentially input bits and maps them into MSK states
|
||||
*
|
||||
* @param input vector with input bits
|
||||
* @param nitems number of samples in the "input" vector
|
||||
* @param gmsk_output bits mapped into MSK states
|
||||
* @param start_point first state
|
||||
*/
|
||||
void gmsk_mapper(const unsigned char * input, int nitems, gr_complex * gmsk_output, gr_complex start_point);
|
||||
|
||||
/** Correlates MSK mapped sequence with input signal
|
||||
*
|
||||
* @param sequence MKS mapped sequence
|
||||
* @param length length of the sequence
|
||||
* @param input_signal vector with input samples
|
||||
* @return correlation value
|
||||
*/
|
||||
gr_complex correlate_sequence(const gr_complex * sequence, int length, const gr_complex * input);
|
||||
|
||||
/** Computes autocorrelation of input vector for positive arguments
|
||||
*
|
||||
* @param input vector with input samples
|
||||
* @param out output vector
|
||||
* @param nitems length of the input vector
|
||||
*/
|
||||
inline void autocorrelation(const gr_complex * input, gr_complex * out, int nitems);
|
||||
|
||||
/** Filters input signal through channel impulse response
|
||||
*
|
||||
* @param input vector with input samples
|
||||
* @param nitems number of samples to pass through filter
|
||||
* @param filter filter taps - channel impulse response
|
||||
* @param filter_length nember of filter taps
|
||||
* @param output vector with filtered samples
|
||||
*/
|
||||
inline void mafi(const gr_complex * input, int nitems, gr_complex * filter, int filter_length, gr_complex * output);
|
||||
|
||||
/** Extracts channel impulse response from a normal burst and computes first sample number of this burst
|
||||
*
|
||||
* @param input vector with input samples
|
||||
* @param chan_imp_resp complex vector where channel impulse response will be stored
|
||||
* @param search_range possible absolute offset of a channel impulse response start
|
||||
* @param bcc base station color code - number of a training sequence
|
||||
* @return first sample number of normal burst
|
||||
*/
|
||||
int get_norm_chan_imp_resp(const gr_complex * input, gr_complex * chan_imp_resp, int bcc);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void configure_receiver();
|
||||
|
||||
public:
|
||||
receiver_impl(feval_dd * tuner, int osr);
|
||||
~receiver_impl();
|
||||
|
||||
void forecast(int noutput_items, gr_vector_int &ninput_items_required);
|
||||
|
||||
// Where all the action really happens
|
||||
int general_work(int noutput_items,
|
||||
gr_vector_int &ninput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
} // namespace gsm
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_GSM_RECEIVER_IMPL_H */
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
#include "system.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "gsm_constants.h"
|
||||
|
||||
/*
|
||||
* Synchronization channel.
|
||||
*
|
||||
* Timeslot Repeat length Frame Number (mod repeat length)
|
||||
* 0 51 1, 11, 21, 31, 41
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parity (FIRE) for the GSM SCH.
|
||||
*
|
||||
* g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1
|
||||
*/
|
||||
#define DATA_BLOCK_SIZE 25
|
||||
#define PARITY_SIZE 10
|
||||
#define TAIL_BITS_SIZE 4
|
||||
#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + TAIL_BITS_SIZE)
|
||||
|
||||
static const unsigned char parity_polynomial[PARITY_SIZE + 1] = {
|
||||
1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1
|
||||
};
|
||||
|
||||
static const unsigned char parity_remainder[PARITY_SIZE] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
|
||||
static void parity_encode(unsigned char *d, unsigned char *p)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
|
||||
|
||||
memcpy(buf, d, DATA_BLOCK_SIZE);
|
||||
memset(buf + DATA_BLOCK_SIZE, 0, PARITY_SIZE);
|
||||
|
||||
for (q = buf; q < buf + DATA_BLOCK_SIZE; q++)
|
||||
if (*q)
|
||||
for (i = 0; i < PARITY_SIZE + 1; i++)
|
||||
q[i] ^= parity_polynomial[i];
|
||||
for (i = 0; i < PARITY_SIZE; i++)
|
||||
p[i] = !buf[DATA_BLOCK_SIZE + i];
|
||||
}
|
||||
|
||||
|
||||
static int parity_check(unsigned char *d)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q;
|
||||
|
||||
memcpy(buf, d, DATA_BLOCK_SIZE + PARITY_SIZE);
|
||||
|
||||
for (q = buf; q < buf + DATA_BLOCK_SIZE; q++)
|
||||
if (*q)
|
||||
for (i = 0; i < PARITY_SIZE + 1; i++)
|
||||
q[i] ^= parity_polynomial[i];
|
||||
return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convolutional encoding and Viterbi decoding for the GSM SCH.
|
||||
* (Equivalent to the GSM SACCH.)
|
||||
*
|
||||
* G_0 = 1 + x^3 + x^4
|
||||
* G_1 = 1 + x + x^3 + x^4
|
||||
*
|
||||
* i.e.,
|
||||
*
|
||||
* c_{2k} = u_k + u_{k - 3} + u_{k - 4}
|
||||
* c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4}
|
||||
*/
|
||||
#define CONV_INPUT_SIZE PARITY_OUTPUT_SIZE
|
||||
#define CONV_SIZE (2 * CONV_INPUT_SIZE)
|
||||
#define K 5
|
||||
#define MAX_ERROR (2 * CONV_INPUT_SIZE + 1)
|
||||
|
||||
|
||||
/*
|
||||
* Given the current state and input bit, what are the output bits?
|
||||
*
|
||||
* encode[current_state][input_bit]
|
||||
*/
|
||||
static const unsigned int encode[1 << (K - 1)][2] = {
|
||||
{0, 3}, {3, 0}, {3, 0}, {0, 3},
|
||||
{0, 3}, {3, 0}, {3, 0}, {0, 3},
|
||||
{1, 2}, {2, 1}, {2, 1}, {1, 2},
|
||||
{1, 2}, {2, 1}, {2, 1}, {1, 2}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Given the current state and input bit, what is the next state?
|
||||
*
|
||||
* next_state[current_state][input_bit]
|
||||
*/
|
||||
static const unsigned int next_state[1 << (K - 1)][2] = {
|
||||
{0, 8}, {0, 8}, {1, 9}, {1, 9},
|
||||
{2, 10}, {2, 10}, {3, 11}, {3, 11},
|
||||
{4, 12}, {4, 12}, {5, 13}, {5, 13},
|
||||
{6, 14}, {6, 14}, {7, 15}, {7, 15}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Given the previous state and the current state, what input bit caused
|
||||
* the transition? If it is impossible to transition between the two
|
||||
* states, the value is 2.
|
||||
*
|
||||
* prev_next_state[previous_state][current_state]
|
||||
*/
|
||||
static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = {
|
||||
{ 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
|
||||
{ 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2},
|
||||
{ 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
|
||||
{ 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2},
|
||||
{ 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
|
||||
{ 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2},
|
||||
{ 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
|
||||
{ 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2},
|
||||
{ 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
|
||||
{ 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2},
|
||||
{ 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
|
||||
{ 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2},
|
||||
{ 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
|
||||
{ 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2},
|
||||
{ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1},
|
||||
{ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}
|
||||
};
|
||||
|
||||
|
||||
static inline unsigned int hamming_distance2(unsigned int w)
|
||||
{
|
||||
|
||||
return (w & 1) + !!(w & 2);
|
||||
}
|
||||
|
||||
|
||||
static void conv_encode(unsigned char *data, unsigned char *output)
|
||||
{
|
||||
|
||||
unsigned int i, state = 0, o;
|
||||
|
||||
// encode data
|
||||
for (i = 0; i < CONV_INPUT_SIZE; i++) {
|
||||
o = encode[state][data[i]];
|
||||
state = next_state[state][data[i]];
|
||||
*output++ = !!(o & 2);
|
||||
*output++ = o & 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int conv_decode(unsigned char *data, unsigned char *output)
|
||||
{
|
||||
|
||||
int i, t;
|
||||
unsigned int rdata, state, nstate, b, o, distance, accumulated_error,
|
||||
min_state, min_error, cur_state;
|
||||
|
||||
unsigned int ae[1 << (K - 1)];
|
||||
unsigned int nae[1 << (K - 1)]; // next accumulated error
|
||||
unsigned int state_history[1 << (K - 1)][CONV_INPUT_SIZE + 1];
|
||||
|
||||
// initialize accumulated error, assume starting state is 0
|
||||
for (i = 0; i < (1 << (K - 1)); i++)
|
||||
ae[i] = nae[i] = MAX_ERROR;
|
||||
ae[0] = 0;
|
||||
|
||||
// build trellis
|
||||
for (t = 0; t < CONV_INPUT_SIZE; t++) {
|
||||
|
||||
// get received data symbol
|
||||
rdata = (data[2 * t] << 1) | data[2 * t + 1];
|
||||
|
||||
// for each state
|
||||
for (state = 0; state < (1 << (K - 1)); state++) {
|
||||
|
||||
// make sure this state is possible
|
||||
if (ae[state] >= MAX_ERROR)
|
||||
continue;
|
||||
|
||||
// find all states we lead to
|
||||
for (b = 0; b < 2; b++) {
|
||||
|
||||
// get next state given input bit b
|
||||
nstate = next_state[state][b];
|
||||
|
||||
// find output for this transition
|
||||
o = encode[state][b];
|
||||
|
||||
// calculate distance from received data
|
||||
distance = hamming_distance2(rdata ^ o);
|
||||
|
||||
// choose surviving path
|
||||
accumulated_error = ae[state] + distance;
|
||||
if (accumulated_error < nae[nstate]) {
|
||||
|
||||
// save error for surviving state
|
||||
nae[nstate] = accumulated_error;
|
||||
|
||||
// update state history
|
||||
state_history[nstate][t + 1] = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get accumulated error ready for next time slice
|
||||
for (i = 0; i < (1 << (K - 1)); i++) {
|
||||
ae[i] = nae[i];
|
||||
nae[i] = MAX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// the final state is the state with the fewest errors
|
||||
min_state = (unsigned int) - 1;
|
||||
min_error = MAX_ERROR;
|
||||
for (i = 0; i < (1 << (K - 1)); i++) {
|
||||
if (ae[i] < min_error) {
|
||||
min_state = i;
|
||||
min_error = ae[i];
|
||||
}
|
||||
}
|
||||
|
||||
// trace the path
|
||||
cur_state = min_state;
|
||||
for (t = CONV_INPUT_SIZE; t >= 1; t--) {
|
||||
min_state = cur_state;
|
||||
cur_state = state_history[cur_state][t]; // get previous
|
||||
output[t - 1] = prev_next_state[cur_state][min_state];
|
||||
}
|
||||
|
||||
// return the number of errors detected (hard-decision)
|
||||
return min_error;
|
||||
}
|
||||
|
||||
|
||||
int decode_sch(const unsigned char *buf, int * t1_o, int * t2_o, int * t3_o, int * ncc_o, int * bcc_o)
|
||||
{
|
||||
|
||||
int errors, t1, t2, t3p, t3, ncc, bcc;
|
||||
unsigned char data[CONV_SIZE], decoded_data[PARITY_OUTPUT_SIZE];
|
||||
|
||||
// extract encoded data from synchronization burst
|
||||
/* buf, 39 bit */
|
||||
/* buf + 39 + 64 = 103, 39 */
|
||||
memcpy(data, buf, SCH_DATA_LEN);
|
||||
memcpy(data + SCH_DATA_LEN, buf + SCH_DATA_LEN + N_SYNC_BITS, SCH_DATA_LEN);
|
||||
|
||||
// Viterbi decode
|
||||
if (errors = conv_decode(data, decoded_data)) {
|
||||
// fprintf(stderr, "error: sch: conv_decode (%d)\n", errors);
|
||||
DEBUGF("ERR: conv_decode %d\n", errors);
|
||||
return errors;
|
||||
}
|
||||
|
||||
// check parity
|
||||
if (parity_check(decoded_data)) {
|
||||
// fprintf(stderr, "error: sch: parity failed\n");
|
||||
DEBUGF("ERR: parity_check failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Synchronization channel information, 44.018 page 171. (V7.2.0)
|
||||
ncc =
|
||||
(decoded_data[ 7] << 2) |
|
||||
(decoded_data[ 6] << 1) |
|
||||
(decoded_data[ 5] << 0);
|
||||
bcc =
|
||||
(decoded_data[ 4] << 2) |
|
||||
(decoded_data[ 3] << 1) |
|
||||
(decoded_data[ 2] << 0);
|
||||
t1 =
|
||||
(decoded_data[ 1] << 10) |
|
||||
(decoded_data[ 0] << 9) |
|
||||
(decoded_data[15] << 8) |
|
||||
(decoded_data[14] << 7) |
|
||||
(decoded_data[13] << 6) |
|
||||
(decoded_data[12] << 5) |
|
||||
(decoded_data[11] << 4) |
|
||||
(decoded_data[10] << 3) |
|
||||
(decoded_data[ 9] << 2) |
|
||||
(decoded_data[ 8] << 1) |
|
||||
(decoded_data[23] << 0);
|
||||
t2 =
|
||||
(decoded_data[22] << 4) |
|
||||
(decoded_data[21] << 3) |
|
||||
(decoded_data[20] << 2) |
|
||||
(decoded_data[19] << 1) |
|
||||
(decoded_data[18] << 0);
|
||||
t3p =
|
||||
(decoded_data[17] << 2) |
|
||||
(decoded_data[16] << 1) |
|
||||
(decoded_data[24] << 0);
|
||||
|
||||
t3 = 10 * t3p + 1;
|
||||
|
||||
// modulo arithmetic t3 - t2 mod 26
|
||||
// tt = ((t3 + 26) - t2) % 26;
|
||||
|
||||
// fn = (51 * 26 * t1) + (51 * tt) + t3;
|
||||
|
||||
/*
|
||||
* BSIC: Base Station Identification Code
|
||||
* BCC: Base station Color Code
|
||||
* NCC: Network Color Code
|
||||
*
|
||||
* FN: Frame Number
|
||||
*/
|
||||
|
||||
// printf("bsic: %x (bcc: %u; ncc: %u)\tFN: %u\n", bsic, bsic & 7,
|
||||
// (bsic >> 3) & 7, fn);
|
||||
|
||||
// if (fn_o)
|
||||
// *fn_o = fn;
|
||||
// if (bsic_o)
|
||||
if (t1_o && t2_o && t3_o && ncc_o && bcc_o) {
|
||||
*t1_o = t1;
|
||||
*t2_o = t2;
|
||||
*t3_o = t3;
|
||||
*bcc_o = bcc;
|
||||
*ncc_o = ncc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
#ifndef __SCH_H__
|
||||
#define __SCH_H__ 1
|
||||
|
||||
#include <gsm/api.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
GSM_API int decode_sch(const unsigned char *buf, int * t1_o, int * t2_o, int * t3_o, int * ncc, int * bcc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef __GSMTVOID_SYSTEM_H__
|
||||
#define __GSMTVOID_SYSTEM_H__ 1
|
||||
|
||||
#define DEBUGF(a...) { \
|
||||
fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \
|
||||
fprintf(stderr, a); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2012 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cppunit/TextTestRunner.h>
|
||||
#include <cppunit/XmlOutputter.h>
|
||||
|
||||
#include <gnuradio/unittests.h>
|
||||
#include "qa_gsm.h"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
CppUnit::TextTestRunner runner;
|
||||
std::ofstream xmlfile(get_unittest_path("gsm.xml").c_str());
|
||||
CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile);
|
||||
|
||||
runner.addTest(qa_gsm::suite());
|
||||
runner.setOutputter(xmlout);
|
||||
|
||||
bool was_successful = runner.run("", false);
|
||||
|
||||
return was_successful ? 0 : 1;
|
||||
}
|
|
@ -0,0 +1,554 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* @file
|
||||
* @author Piotr Krysik <pkrysik@stud.elka.pw.edu.pl>
|
||||
* @section LICENSE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* viterbi_detector:
|
||||
* This part does the detection of received sequnece.
|
||||
* Employed algorithm is viterbi Maximum Likehood Sequence Estimation.
|
||||
* At this moment it gives hard decisions on the output, but
|
||||
* it was designed with soft decisions in mind.
|
||||
*
|
||||
* SYNTAX: void viterbi_detector(
|
||||
* const gr_complex * input,
|
||||
* unsigned int samples_num,
|
||||
* gr_complex * rhh,
|
||||
* unsigned int start_state,
|
||||
* const unsigned int * stop_states,
|
||||
* unsigned int stops_num,
|
||||
* float * output)
|
||||
*
|
||||
* INPUT: input: Complex received signal afted matched filtering.
|
||||
* samples_num: Number of samples in the input table.
|
||||
* rhh: The autocorrelation of the estimated channel
|
||||
* impulse response.
|
||||
* start_state: Number of the start point. In GSM each burst
|
||||
* starts with sequence of three bits (0,0,0) which
|
||||
* indicates start point of the algorithm.
|
||||
* stop_states: Table with numbers of possible stop states.
|
||||
* stops_num: Number of possible stop states
|
||||
*
|
||||
*
|
||||
* OUTPUT: output: Differentially decoded hard output of the algorithm:
|
||||
* -1 for logical "0" and 1 for logical "1"
|
||||
*
|
||||
* SUB_FUNC: none
|
||||
*
|
||||
* TEST(S): Tested with real world normal burst.
|
||||
*/
|
||||
|
||||
#include <gnuradio/gr_complex.h>
|
||||
#include <gsm_constants.h>
|
||||
#define PATHS_NUM (1 << (CHAN_IMP_RESP_LENGTH-1))
|
||||
|
||||
void viterbi_detector(const gr_complex * input, unsigned int samples_num, gr_complex * rhh, unsigned int start_state, const unsigned int * stop_states, unsigned int stops_num, float * output)
|
||||
{
|
||||
float increment[8];
|
||||
float path_metrics1[16];
|
||||
float path_metrics2[16];
|
||||
float * new_path_metrics;
|
||||
float * old_path_metrics;
|
||||
float * tmp;
|
||||
float trans_table[BURST_SIZE][16];
|
||||
float pm_candidate1, pm_candidate2;
|
||||
bool real_imag;
|
||||
float input_symbol_real, input_symbol_imag;
|
||||
unsigned int i, sample_nr;
|
||||
|
||||
/*
|
||||
* Setup first path metrics, so only state pointed by start_state is possible.
|
||||
* Start_state metric is equal to zero, the rest is written with some very low value,
|
||||
* which makes them practically impossible to occur.
|
||||
*/
|
||||
for(i=0; i<PATHS_NUM; i++){
|
||||
path_metrics1[i]=(-10e30);
|
||||
}
|
||||
path_metrics1[start_state]=0;
|
||||
|
||||
/*
|
||||
* Compute Increment - a table of values which does not change for subsequent input samples.
|
||||
* Increment is table of reference levels for computation of branch metrics:
|
||||
* branch metric = (+/-)received_sample (+/-) reference_level
|
||||
*/
|
||||
increment[0] = -rhh[1].imag() -rhh[2].real() -rhh[3].imag() +rhh[4].real();
|
||||
increment[1] = rhh[1].imag() -rhh[2].real() -rhh[3].imag() +rhh[4].real();
|
||||
increment[2] = -rhh[1].imag() +rhh[2].real() -rhh[3].imag() +rhh[4].real();
|
||||
increment[3] = rhh[1].imag() +rhh[2].real() -rhh[3].imag() +rhh[4].real();
|
||||
increment[4] = -rhh[1].imag() -rhh[2].real() +rhh[3].imag() +rhh[4].real();
|
||||
increment[5] = rhh[1].imag() -rhh[2].real() +rhh[3].imag() +rhh[4].real();
|
||||
increment[6] = -rhh[1].imag() +rhh[2].real() +rhh[3].imag() +rhh[4].real();
|
||||
increment[7] = rhh[1].imag() +rhh[2].real() +rhh[3].imag() +rhh[4].real();
|
||||
|
||||
|
||||
/*
|
||||
* Computation of path metrics and decisions (Add-Compare-Select).
|
||||
* It's composed of two parts: one for odd input samples (imaginary numbers)
|
||||
* and one for even samples (real numbers).
|
||||
* Each part is composed of independent (parallelisable) statements like
|
||||
* this one:
|
||||
* pm_candidate1 = old_path_metrics[0] - input_symbol_real - increment[7];
|
||||
* pm_candidate2 = old_path_metrics[8] - input_symbol_real + increment[0];
|
||||
* if(pm_candidate1 > pm_candidate2){
|
||||
* new_path_metrics[0] = pm_candidate1;
|
||||
* trans_table[sample_nr][0] = -1.0;
|
||||
* }
|
||||
* else{
|
||||
* new_path_metrics[0] = pm_candidate2;
|
||||
* trans_table[sample_nr][0] = 1.0;
|
||||
* }
|
||||
* This is very good point for optimisations (SIMD or OpenMP) as it's most time
|
||||
* consuming part of this function.
|
||||
*/
|
||||
sample_nr=0;
|
||||
old_path_metrics=path_metrics1;
|
||||
new_path_metrics=path_metrics2;
|
||||
while(sample_nr<samples_num){
|
||||
//Processing imag states
|
||||
real_imag=1;
|
||||
input_symbol_imag = input[sample_nr].imag();
|
||||
|
||||
pm_candidate1 = old_path_metrics[0] + input_symbol_imag - increment[2];
|
||||
pm_candidate2 = old_path_metrics[8] + input_symbol_imag + increment[5];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[0] = pm_candidate1;
|
||||
trans_table[sample_nr][0] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[0] = pm_candidate2;
|
||||
trans_table[sample_nr][0] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[0] - input_symbol_imag + increment[2];
|
||||
pm_candidate2 = old_path_metrics[8] - input_symbol_imag - increment[5];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[1] = pm_candidate1;
|
||||
trans_table[sample_nr][1] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[1] = pm_candidate2;
|
||||
trans_table[sample_nr][1] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[1] + input_symbol_imag - increment[3];
|
||||
pm_candidate2 = old_path_metrics[9] + input_symbol_imag + increment[4];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[2] = pm_candidate1;
|
||||
trans_table[sample_nr][2] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[2] = pm_candidate2;
|
||||
trans_table[sample_nr][2] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[1] - input_symbol_imag + increment[3];
|
||||
pm_candidate2 = old_path_metrics[9] - input_symbol_imag - increment[4];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[3] = pm_candidate1;
|
||||
trans_table[sample_nr][3] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[3] = pm_candidate2;
|
||||
trans_table[sample_nr][3] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[2] + input_symbol_imag - increment[0];
|
||||
pm_candidate2 = old_path_metrics[10] + input_symbol_imag + increment[7];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[4] = pm_candidate1;
|
||||
trans_table[sample_nr][4] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[4] = pm_candidate2;
|
||||
trans_table[sample_nr][4] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[2] - input_symbol_imag + increment[0];
|
||||
pm_candidate2 = old_path_metrics[10] - input_symbol_imag - increment[7];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[5] = pm_candidate1;
|
||||
trans_table[sample_nr][5] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[5] = pm_candidate2;
|
||||
trans_table[sample_nr][5] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[3] + input_symbol_imag - increment[1];
|
||||
pm_candidate2 = old_path_metrics[11] + input_symbol_imag + increment[6];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[6] = pm_candidate1;
|
||||
trans_table[sample_nr][6] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[6] = pm_candidate2;
|
||||
trans_table[sample_nr][6] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[3] - input_symbol_imag + increment[1];
|
||||
pm_candidate2 = old_path_metrics[11] - input_symbol_imag - increment[6];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[7] = pm_candidate1;
|
||||
trans_table[sample_nr][7] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[7] = pm_candidate2;
|
||||
trans_table[sample_nr][7] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[4] + input_symbol_imag - increment[6];
|
||||
pm_candidate2 = old_path_metrics[12] + input_symbol_imag + increment[1];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[8] = pm_candidate1;
|
||||
trans_table[sample_nr][8] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[8] = pm_candidate2;
|
||||
trans_table[sample_nr][8] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[4] - input_symbol_imag + increment[6];
|
||||
pm_candidate2 = old_path_metrics[12] - input_symbol_imag - increment[1];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[9] = pm_candidate1;
|
||||
trans_table[sample_nr][9] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[9] = pm_candidate2;
|
||||
trans_table[sample_nr][9] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[5] + input_symbol_imag - increment[7];
|
||||
pm_candidate2 = old_path_metrics[13] + input_symbol_imag + increment[0];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[10] = pm_candidate1;
|
||||
trans_table[sample_nr][10] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[10] = pm_candidate2;
|
||||
trans_table[sample_nr][10] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[5] - input_symbol_imag + increment[7];
|
||||
pm_candidate2 = old_path_metrics[13] - input_symbol_imag - increment[0];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[11] = pm_candidate1;
|
||||
trans_table[sample_nr][11] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[11] = pm_candidate2;
|
||||
trans_table[sample_nr][11] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[6] + input_symbol_imag - increment[4];
|
||||
pm_candidate2 = old_path_metrics[14] + input_symbol_imag + increment[3];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[12] = pm_candidate1;
|
||||
trans_table[sample_nr][12] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[12] = pm_candidate2;
|
||||
trans_table[sample_nr][12] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[6] - input_symbol_imag + increment[4];
|
||||
pm_candidate2 = old_path_metrics[14] - input_symbol_imag - increment[3];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[13] = pm_candidate1;
|
||||
trans_table[sample_nr][13] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[13] = pm_candidate2;
|
||||
trans_table[sample_nr][13] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[7] + input_symbol_imag - increment[5];
|
||||
pm_candidate2 = old_path_metrics[15] + input_symbol_imag + increment[2];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[14] = pm_candidate1;
|
||||
trans_table[sample_nr][14] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[14] = pm_candidate2;
|
||||
trans_table[sample_nr][14] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[7] - input_symbol_imag + increment[5];
|
||||
pm_candidate2 = old_path_metrics[15] - input_symbol_imag - increment[2];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[15] = pm_candidate1;
|
||||
trans_table[sample_nr][15] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[15] = pm_candidate2;
|
||||
trans_table[sample_nr][15] = 1.0;
|
||||
}
|
||||
tmp=old_path_metrics;
|
||||
old_path_metrics=new_path_metrics;
|
||||
new_path_metrics=tmp;
|
||||
|
||||
sample_nr++;
|
||||
if(sample_nr==samples_num)
|
||||
break;
|
||||
|
||||
//Processing real states
|
||||
real_imag=0;
|
||||
input_symbol_real = input[sample_nr].real();
|
||||
|
||||
pm_candidate1 = old_path_metrics[0] - input_symbol_real - increment[7];
|
||||
pm_candidate2 = old_path_metrics[8] - input_symbol_real + increment[0];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[0] = pm_candidate1;
|
||||
trans_table[sample_nr][0] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[0] = pm_candidate2;
|
||||
trans_table[sample_nr][0] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[0] + input_symbol_real + increment[7];
|
||||
pm_candidate2 = old_path_metrics[8] + input_symbol_real - increment[0];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[1] = pm_candidate1;
|
||||
trans_table[sample_nr][1] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[1] = pm_candidate2;
|
||||
trans_table[sample_nr][1] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[1] - input_symbol_real - increment[6];
|
||||
pm_candidate2 = old_path_metrics[9] - input_symbol_real + increment[1];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[2] = pm_candidate1;
|
||||
trans_table[sample_nr][2] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[2] = pm_candidate2;
|
||||
trans_table[sample_nr][2] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[1] + input_symbol_real + increment[6];
|
||||
pm_candidate2 = old_path_metrics[9] + input_symbol_real - increment[1];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[3] = pm_candidate1;
|
||||
trans_table[sample_nr][3] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[3] = pm_candidate2;
|
||||
trans_table[sample_nr][3] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[2] - input_symbol_real - increment[5];
|
||||
pm_candidate2 = old_path_metrics[10] - input_symbol_real + increment[2];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[4] = pm_candidate1;
|
||||
trans_table[sample_nr][4] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[4] = pm_candidate2;
|
||||
trans_table[sample_nr][4] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[2] + input_symbol_real + increment[5];
|
||||
pm_candidate2 = old_path_metrics[10] + input_symbol_real - increment[2];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[5] = pm_candidate1;
|
||||
trans_table[sample_nr][5] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[5] = pm_candidate2;
|
||||
trans_table[sample_nr][5] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[3] - input_symbol_real - increment[4];
|
||||
pm_candidate2 = old_path_metrics[11] - input_symbol_real + increment[3];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[6] = pm_candidate1;
|
||||
trans_table[sample_nr][6] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[6] = pm_candidate2;
|
||||
trans_table[sample_nr][6] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[3] + input_symbol_real + increment[4];
|
||||
pm_candidate2 = old_path_metrics[11] + input_symbol_real - increment[3];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[7] = pm_candidate1;
|
||||
trans_table[sample_nr][7] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[7] = pm_candidate2;
|
||||
trans_table[sample_nr][7] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[4] - input_symbol_real - increment[3];
|
||||
pm_candidate2 = old_path_metrics[12] - input_symbol_real + increment[4];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[8] = pm_candidate1;
|
||||
trans_table[sample_nr][8] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[8] = pm_candidate2;
|
||||
trans_table[sample_nr][8] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[4] + input_symbol_real + increment[3];
|
||||
pm_candidate2 = old_path_metrics[12] + input_symbol_real - increment[4];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[9] = pm_candidate1;
|
||||
trans_table[sample_nr][9] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[9] = pm_candidate2;
|
||||
trans_table[sample_nr][9] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[5] - input_symbol_real - increment[2];
|
||||
pm_candidate2 = old_path_metrics[13] - input_symbol_real + increment[5];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[10] = pm_candidate1;
|
||||
trans_table[sample_nr][10] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[10] = pm_candidate2;
|
||||
trans_table[sample_nr][10] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[5] + input_symbol_real + increment[2];
|
||||
pm_candidate2 = old_path_metrics[13] + input_symbol_real - increment[5];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[11] = pm_candidate1;
|
||||
trans_table[sample_nr][11] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[11] = pm_candidate2;
|
||||
trans_table[sample_nr][11] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[6] - input_symbol_real - increment[1];
|
||||
pm_candidate2 = old_path_metrics[14] - input_symbol_real + increment[6];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[12] = pm_candidate1;
|
||||
trans_table[sample_nr][12] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[12] = pm_candidate2;
|
||||
trans_table[sample_nr][12] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[6] + input_symbol_real + increment[1];
|
||||
pm_candidate2 = old_path_metrics[14] + input_symbol_real - increment[6];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[13] = pm_candidate1;
|
||||
trans_table[sample_nr][13] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[13] = pm_candidate2;
|
||||
trans_table[sample_nr][13] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[7] - input_symbol_real - increment[0];
|
||||
pm_candidate2 = old_path_metrics[15] - input_symbol_real + increment[7];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[14] = pm_candidate1;
|
||||
trans_table[sample_nr][14] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[14] = pm_candidate2;
|
||||
trans_table[sample_nr][14] = 1.0;
|
||||
}
|
||||
|
||||
pm_candidate1 = old_path_metrics[7] + input_symbol_real + increment[0];
|
||||
pm_candidate2 = old_path_metrics[15] + input_symbol_real - increment[7];
|
||||
if(pm_candidate1 > pm_candidate2){
|
||||
new_path_metrics[15] = pm_candidate1;
|
||||
trans_table[sample_nr][15] = -1.0;
|
||||
}
|
||||
else{
|
||||
new_path_metrics[15] = pm_candidate2;
|
||||
trans_table[sample_nr][15] = 1.0;
|
||||
}
|
||||
tmp=old_path_metrics;
|
||||
old_path_metrics=new_path_metrics;
|
||||
new_path_metrics=tmp;
|
||||
|
||||
sample_nr++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the best from the stop states by comparing their path metrics.
|
||||
* Not every stop state is always possible, so we are searching in
|
||||
* a subset of them.
|
||||
*/
|
||||
unsigned int best_stop_state;
|
||||
float stop_state_metric, max_stop_state_metric;
|
||||
best_stop_state = stop_states[0];
|
||||
max_stop_state_metric = old_path_metrics[best_stop_state];
|
||||
for(i=1; i< stops_num; i++){
|
||||
stop_state_metric = old_path_metrics[stop_states[i]];
|
||||
if(stop_state_metric > max_stop_state_metric){
|
||||
max_stop_state_metric = stop_state_metric;
|
||||
best_stop_state = stop_states[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This table was generated with hope that it gives a litle speedup during
|
||||
* traceback stage.
|
||||
* Received bit is related to the number of state in the trellis.
|
||||
* I've numbered states so their parity (number of ones) is related
|
||||
* to a received bit.
|
||||
*/
|
||||
static const unsigned int parity_table[PATHS_NUM] = { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, };
|
||||
|
||||
/*
|
||||
* Table of previous states in the trellis diagram.
|
||||
* For GMSK modulation every state has two previous states.
|
||||
* Example:
|
||||
* previous_state_nr1 = prev_table[current_state_nr][0]
|
||||
* previous_state_nr2 = prev_table[current_state_nr][1]
|
||||
*/
|
||||
static const unsigned int prev_table[PATHS_NUM][2] = { {0,8}, {0,8}, {1,9}, {1,9}, {2,10}, {2,10}, {3,11}, {3,11}, {4,12}, {4,12}, {5,13}, {5,13}, {6,14}, {6,14}, {7,15}, {7,15}, };
|
||||
|
||||
/*
|
||||
* Traceback and differential decoding of received sequence.
|
||||
* Decisions stored in trans_table are used to restore best path in the trellis.
|
||||
*/
|
||||
sample_nr=samples_num;
|
||||
unsigned int state_nr=best_stop_state;
|
||||
unsigned int decision;
|
||||
bool out_bit=0;
|
||||
|
||||
while(sample_nr>0){
|
||||
sample_nr--;
|
||||
decision = (trans_table[sample_nr][state_nr]>0);
|
||||
|
||||
if(decision != out_bit)
|
||||
output[sample_nr]=-trans_table[sample_nr][state_nr];
|
||||
else
|
||||
output[sample_nr]=trans_table[sample_nr][state_nr];
|
||||
|
||||
out_bit = out_bit ^ real_imag ^ parity_table[state_nr];
|
||||
state_nr = prev_table[state_nr][decision];
|
||||
real_imag = !real_imag;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* @file
|
||||
* @author Piotr Krysik <pkrysik@stud.elka.pw.edu.pl>
|
||||
* @section LICENSE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* viterbi_detector:
|
||||
* This part does the detection of received sequnece.
|
||||
* Employed algorithm is viterbi Maximum Likehood Sequence Estimation.
|
||||
* At this moment it gives hard decisions on the output, but
|
||||
* it was designed with soft decisions in mind.
|
||||
*
|
||||
* SYNTAX: void viterbi_detector(
|
||||
* const gr_complex * input,
|
||||
* unsigned int samples_num,
|
||||
* gr_complex * rhh,
|
||||
* unsigned int start_state,
|
||||
* const unsigned int * stop_states,
|
||||
* unsigned int stops_num,
|
||||
* float * output)
|
||||
*
|
||||
* INPUT: input: Complex received signal afted matched filtering.
|
||||
* samples_num: Number of samples in the input table.
|
||||
* rhh: The autocorrelation of the estimated channel
|
||||
* impulse response.
|
||||
* start_state: Number of the start point. In GSM each burst
|
||||
* starts with sequence of three bits (0,0,0) which
|
||||
* indicates start point of the algorithm.
|
||||
* stop_states: Table with numbers of possible stop states.
|
||||
* stops_num: Number of possible stop states
|
||||
*
|
||||
*
|
||||
* OUTPUT: output: Differentially decoded hard output of the algorithm:
|
||||
* -1 for logical "0" and 1 for logical "1"
|
||||
*
|
||||
* SUB_FUNC: none
|
||||
*
|
||||
* TEST(S): Tested with real world normal burst.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_VITERBI_DETECTOR_H
|
||||
#define INCLUDED_VITERBI_DETECTOR_H
|
||||
|
||||
void viterbi_detector(const gr_complex * input, unsigned int samples_num, gr_complex * rhh, unsigned int start_state, const unsigned int * stop_states, unsigned int stops_num, float * output);
|
||||
|
||||
#endif /* INCLUDED_VITERBI_DETECTOR_H */
|
|
@ -0,0 +1,45 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Include python install macros
|
||||
########################################################################
|
||||
include(GrPython)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
return()
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Install python sources
|
||||
########################################################################
|
||||
GR_PYTHON_INSTALL(
|
||||
FILES
|
||||
__init__.py
|
||||
receiver_hier.py DESTINATION ${GR_PYTHON_DIR}/gsm
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Handle the unit tests
|
||||
########################################################################
|
||||
include(GrTest)
|
||||
|
||||
set(GR_TEST_TARGET_DEPS gnuradio-gsm)
|
||||
set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
|
||||
GR_ADD_TEST(qa_receiver ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_receiver.py)
|
||||
GR_ADD_TEST(qa_receiver_hier ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_receiver_hier.py)
|
|
@ -0,0 +1,55 @@
|
|||
#
|
||||
# Copyright 2008,2009 Free Software Foundation, Inc.
|
||||
#
|
||||
# This application is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This application is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
# The presence of this file turns this directory into a Python package
|
||||
|
||||
'''
|
||||
This is the GNU Radio GSM module. Place your Python package
|
||||
description here (python/__init__.py).
|
||||
'''
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Temporary workaround for ticket:181 (swig+python problem)
|
||||
import sys
|
||||
_RTLD_GLOBAL = 0
|
||||
try:
|
||||
from dl import RTLD_GLOBAL as _RTLD_GLOBAL
|
||||
except ImportError:
|
||||
try:
|
||||
from DLFCN import RTLD_GLOBAL as _RTLD_GLOBAL
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
if _RTLD_GLOBAL != 0:
|
||||
_dlopenflags = sys.getdlopenflags()
|
||||
sys.setdlopenflags(_dlopenflags|_RTLD_GLOBAL)
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# import swig generated symbols into the gsm namespace
|
||||
from gsm_swig import *
|
||||
|
||||
# import any pure python here
|
||||
from receiver_hier import receiver_hier
|
||||
#
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Tail of workaround
|
||||
if _RTLD_GLOBAL != 0:
|
||||
sys.setdlopenflags(_dlopenflags) # Restore original flags
|
||||
# ----------------------------------------------------------------
|
|
@ -0,0 +1,226 @@
|
|||
#
|
||||
# Copyright 2004,2009,2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
"""Misc utilities used at build time
|
||||
"""
|
||||
|
||||
import re, os, os.path
|
||||
from build_utils_codes import *
|
||||
|
||||
|
||||
# set srcdir to the directory that contains Makefile.am
|
||||
try:
|
||||
srcdir = os.environ['srcdir']
|
||||
except KeyError, e:
|
||||
srcdir = "."
|
||||
srcdir = srcdir + '/'
|
||||
|
||||
# set do_makefile to either true or false dependeing on the environment
|
||||
try:
|
||||
if os.environ['do_makefile'] == '0':
|
||||
do_makefile = False
|
||||
else:
|
||||
do_makefile = True
|
||||
except KeyError, e:
|
||||
do_makefile = False
|
||||
|
||||
# set do_sources to either true or false dependeing on the environment
|
||||
try:
|
||||
if os.environ['do_sources'] == '0':
|
||||
do_sources = False
|
||||
else:
|
||||
do_sources = True
|
||||
except KeyError, e:
|
||||
do_sources = True
|
||||
|
||||
name_dict = {}
|
||||
|
||||
def log_output_name (name):
|
||||
(base, ext) = os.path.splitext (name)
|
||||
ext = ext[1:] # drop the leading '.'
|
||||
|
||||
entry = name_dict.setdefault (ext, [])
|
||||
entry.append (name)
|
||||
|
||||
def open_and_log_name (name, dir):
|
||||
global do_sources
|
||||
if do_sources:
|
||||
f = open (name, dir)
|
||||
else:
|
||||
f = None
|
||||
log_output_name (name)
|
||||
return f
|
||||
|
||||
def expand_template (d, template_filename, extra = ""):
|
||||
'''Given a dictionary D and a TEMPLATE_FILENAME, expand template into output file
|
||||
'''
|
||||
global do_sources
|
||||
output_extension = extract_extension (template_filename)
|
||||
template = open_src (template_filename, 'r')
|
||||
output_name = d['NAME'] + extra + '.' + output_extension
|
||||
log_output_name (output_name)
|
||||
if do_sources:
|
||||
output = open (output_name, 'w')
|
||||
do_substitution (d, template, output)
|
||||
output.close ()
|
||||
template.close ()
|
||||
|
||||
def output_glue (dirname):
|
||||
output_makefile_fragment ()
|
||||
output_ifile_include (dirname)
|
||||
|
||||
def output_makefile_fragment ():
|
||||
global do_makefile
|
||||
if not do_makefile:
|
||||
return
|
||||
# overwrite the source, which must be writable; this should have been
|
||||
# checked for beforehand in the top-level Makefile.gen.gen .
|
||||
f = open (os.path.join (os.environ.get('gendir', os.environ.get('srcdir', '.')), 'Makefile.gen'), 'w')
|
||||
f.write ('#\n# This file is machine generated. All edits will be overwritten\n#\n')
|
||||
output_subfrag (f, 'h')
|
||||
output_subfrag (f, 'i')
|
||||
output_subfrag (f, 'cc')
|
||||
f.close ()
|
||||
|
||||
def output_ifile_include (dirname):
|
||||
global do_sources
|
||||
if do_sources:
|
||||
f = open ('%s_generated.i' % (dirname,), 'w')
|
||||
f.write ('//\n// This file is machine generated. All edits will be overwritten\n//\n')
|
||||
files = name_dict.setdefault ('i', [])
|
||||
files.sort ()
|
||||
f.write ('%{\n')
|
||||
for file in files:
|
||||
f.write ('#include <%s>\n' % (file[0:-1] + 'h',))
|
||||
f.write ('%}\n\n')
|
||||
for file in files:
|
||||
f.write ('%%include <%s>\n' % (file,))
|
||||
|
||||
def output_subfrag (f, ext):
|
||||
files = name_dict.setdefault (ext, [])
|
||||
files.sort ()
|
||||
f.write ("GENERATED_%s =" % (ext.upper ()))
|
||||
for file in files:
|
||||
f.write (" \\\n\t%s" % (file,))
|
||||
f.write ("\n\n")
|
||||
|
||||
def extract_extension (template_name):
|
||||
# template name is something like: GrFIRfilterXXX.h.t
|
||||
# we return everything between the penultimate . and .t
|
||||
mo = re.search (r'\.([a-z]+)\.t$', template_name)
|
||||
if not mo:
|
||||
raise ValueError, "Incorrectly formed template_name '%s'" % (template_name,)
|
||||
return mo.group (1)
|
||||
|
||||
def open_src (name, mode):
|
||||
global srcdir
|
||||
return open (os.path.join (srcdir, name), mode)
|
||||
|
||||
def do_substitution (d, in_file, out_file):
|
||||
def repl (match_obj):
|
||||
key = match_obj.group (1)
|
||||
# print key
|
||||
return d[key]
|
||||
|
||||
inp = in_file.read ()
|
||||
out = re.sub (r"@([a-zA-Z0-9_]+)@", repl, inp)
|
||||
out_file.write (out)
|
||||
|
||||
|
||||
|
||||
copyright = '''/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2003,2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
'''
|
||||
|
||||
def is_complex (code3):
|
||||
if i_code (code3) == 'c' or o_code (code3) == 'c':
|
||||
return '1'
|
||||
else:
|
||||
return '0'
|
||||
|
||||
|
||||
def standard_dict (name, code3, package='gr'):
|
||||
d = {}
|
||||
d['NAME'] = name
|
||||
d['NAME_IMPL'] = name+'_impl'
|
||||
d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper())
|
||||
d['GUARD_NAME_IMPL'] = 'INCLUDED_%s_%s_IMPL_H' % (package.upper(), name.upper())
|
||||
d['BASE_NAME'] = re.sub ('^' + package + '_', '', name)
|
||||
d['SPTR_NAME'] = '%s_sptr' % name
|
||||
d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten'
|
||||
d['COPYRIGHT'] = copyright
|
||||
d['TYPE'] = i_type (code3)
|
||||
d['I_TYPE'] = i_type (code3)
|
||||
d['O_TYPE'] = o_type (code3)
|
||||
d['TAP_TYPE'] = tap_type (code3)
|
||||
d['IS_COMPLEX'] = is_complex (code3)
|
||||
return d
|
||||
|
||||
|
||||
def standard_dict2 (name, code3, package):
|
||||
d = {}
|
||||
d['NAME'] = name
|
||||
d['BASE_NAME'] = name
|
||||
d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper())
|
||||
d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten'
|
||||
d['COPYRIGHT'] = copyright
|
||||
d['TYPE'] = i_type (code3)
|
||||
d['I_TYPE'] = i_type (code3)
|
||||
d['O_TYPE'] = o_type (code3)
|
||||
d['TAP_TYPE'] = tap_type (code3)
|
||||
d['IS_COMPLEX'] = is_complex (code3)
|
||||
return d
|
||||
|
||||
def standard_impl_dict2 (name, code3, package):
|
||||
d = {}
|
||||
d['NAME'] = name
|
||||
d['IMPL_NAME'] = name
|
||||
d['BASE_NAME'] = name.rstrip("impl").rstrip("_")
|
||||
d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper())
|
||||
d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten'
|
||||
d['COPYRIGHT'] = copyright
|
||||
d['FIR_TYPE'] = "fir_filter_" + code3
|
||||
d['CFIR_TYPE'] = "fir_filter_" + code3[0:2] + 'c'
|
||||
d['TYPE'] = i_type (code3)
|
||||
d['I_TYPE'] = i_type (code3)
|
||||
d['O_TYPE'] = o_type (code3)
|
||||
d['TAP_TYPE'] = tap_type (code3)
|
||||
d['IS_COMPLEX'] = is_complex (code3)
|
||||
return d
|
|
@ -0,0 +1,52 @@
|
|||
#
|
||||
# Copyright 2004 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
def i_code (code3):
|
||||
return code3[0]
|
||||
|
||||
def o_code (code3):
|
||||
if len (code3) >= 2:
|
||||
return code3[1]
|
||||
else:
|
||||
return code3[0]
|
||||
|
||||
def tap_code (code3):
|
||||
if len (code3) >= 3:
|
||||
return code3[2]
|
||||
else:
|
||||
return code3[0]
|
||||
|
||||
def i_type (code3):
|
||||
return char_to_type[i_code (code3)]
|
||||
|
||||
def o_type (code3):
|
||||
return char_to_type[o_code (code3)]
|
||||
|
||||
def tap_type (code3):
|
||||
return char_to_type[tap_code (code3)]
|
||||
|
||||
|
||||
char_to_type = {}
|
||||
char_to_type['s'] = 'short'
|
||||
char_to_type['i'] = 'int'
|
||||
char_to_type['f'] = 'float'
|
||||
char_to_type['c'] = 'gr_complex'
|
||||
char_to_type['b'] = 'unsigned char'
|
Binary file not shown.
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import gsm
|
||||
from gnuradio.eng_option import eng_option
|
||||
from gnuradio import gr, gru, blocks
|
||||
from gnuradio import filter
|
||||
|
||||
|
||||
class tuner(gr.feval_dd):
|
||||
def __init__(self, top_block):
|
||||
gr.feval_dd.__init__(self)
|
||||
self.top_block = top_block
|
||||
def eval(self, freq_offet):
|
||||
self.top_block.set_center_frequency(freq_offet)
|
||||
return freq_offet
|
||||
|
||||
class receiver_hier(gr.hier_block2):
|
||||
def __init__(self, input_rate, osr=4):
|
||||
gr.hier_block2.__init__(self,
|
||||
"receiver_hier",
|
||||
gr.io_signature(1, 1, gr.sizeof_gr_complex),
|
||||
gr.io_signature(1, 1, 142*gr.sizeof_float))
|
||||
#set rates
|
||||
gsm_symb_rate = 1625000/6.0
|
||||
self.input_rate = input_rate
|
||||
self.osr = osr
|
||||
self.sps = input_rate / gsm_symb_rate / osr
|
||||
|
||||
#create callbacks
|
||||
self.tuner_callback = tuner(self)
|
||||
#create accompaning blocks
|
||||
self.filtr = self._set_filter()
|
||||
self.interpolator = self._set_interpolator()
|
||||
self.receiver = self._set_receiver()
|
||||
self.connect(self, self.filtr, self.interpolator, self.receiver, self)
|
||||
|
||||
def _set_filter(self):
|
||||
filter_cutoff = 125e3
|
||||
filter_t_width = 10e3
|
||||
offset = 0
|
||||
|
||||
filter_taps = filter.firdes.low_pass(1.0, self.input_rate, filter_cutoff, filter_t_width, filter.firdes.WIN_HAMMING)
|
||||
filtr = filter.freq_xlating_fir_filter_ccf(1, filter_taps, offset, self.input_rate)
|
||||
return filtr
|
||||
|
||||
def _set_interpolator(self):
|
||||
interpolator = filter.fractional_resampler_cc(0, self.sps)
|
||||
return interpolator
|
||||
|
||||
def _set_receiver(self):
|
||||
receiver = gsm.receiver(self.tuner_callback, self.osr)
|
||||
return receiver
|
||||
|
||||
def set_center_frequency(self, center_freq):
|
||||
self.filtr.set_center_freq(center_freq)
|
||||
|
||||
def set_timing(self, timing_offset):
|
||||
pass
|
||||
|
Binary file not shown.
|
@ -0,0 +1,57 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Include swig generation macros
|
||||
########################################################################
|
||||
find_package(SWIG)
|
||||
find_package(PythonLibs 2)
|
||||
if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND)
|
||||
return()
|
||||
endif()
|
||||
include(GrSwig)
|
||||
include(GrPython)
|
||||
|
||||
########################################################################
|
||||
# Setup swig generation
|
||||
########################################################################
|
||||
foreach(incdir ${GNURADIO_RUNTIME_INCLUDE_DIRS})
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gnuradio/swig)
|
||||
endforeach(incdir)
|
||||
|
||||
set(GR_SWIG_LIBRARIES gnuradio-gsm)
|
||||
set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/gsm_swig_doc.i)
|
||||
set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
||||
|
||||
GR_SWIG_MAKE(gsm_swig gsm_swig.i)
|
||||
|
||||
########################################################################
|
||||
# Install the build swig module
|
||||
########################################################################
|
||||
GR_SWIG_INSTALL(TARGETS gsm_swig DESTINATION ${GR_PYTHON_DIR}/gsm)
|
||||
|
||||
########################################################################
|
||||
# Install swig .i files for development
|
||||
########################################################################
|
||||
install(
|
||||
FILES
|
||||
gsm_swig.i
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gsm_swig_doc.i
|
||||
DESTINATION ${GR_INCLUDE_DIR}/gsm/swig
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
/* -*- c++ -*- */
|
||||
|
||||
#define GSM_API
|
||||
|
||||
%include "gnuradio.i" // the common stuff
|
||||
|
||||
//load generated python docstrings
|
||||
%include "gsm_swig_doc.i"
|
||||
|
||||
%{
|
||||
#include "gsm/receiver.h"
|
||||
%}
|
||||
|
||||
|
||||
%include "gsm/receiver.h"
|
||||
GR_SWIG_BLOCK_MAGIC2(gsm, receiver);
|
Loading…
Reference in New Issue