Initial check-in.

This commit is contained in:
root 2013-12-10 01:47:21 +01:00
commit e9aa1ab5fe
265 changed files with 55519 additions and 0 deletions

145
op25/gr-op25/CMakeLists.txt Normal file
View File

@ -0,0 +1,145 @@
# 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-op25 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 op25")
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/op25)
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 op25")
endif()
if(NOT CPPUNIT_FOUND)
message(FATAL_ERROR "CppUnit required to compile op25")
endif()
########################################################################
# Setup the include and linker paths
########################################################################
include_directories(
${CMAKE_SOURCE_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_OP25_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE)
set(GR_OP25_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/op25)
add_subdirectory(lib)
add_subdirectory(swig)
add_subdirectory(python)
add_subdirectory(grc)
add_subdirectory(apps)
add_subdirectory(docs)

View File

@ -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
)

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,6 @@
INCLUDE(FindPkgConfig)
PKG_CHECK_MODULES(GNURADIO_RUNTIME gnuradio-runtime)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)

View File

@ -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)

View File

@ -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")

View File

@ -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)
")

View File

@ -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)))
")

View File

@ -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)

View File

@ -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)

View 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)

View File

@ -0,0 +1,11 @@
This is the op25-write-a-block package meant as a guide to building
out-of-tree packages. To use the op25 blocks, the Python namespaces
is in 'op25', which is imported as:
import op25
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(op25)

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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.
"""

View File

@ -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

View File

@ -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

View File

@ -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('&', '&amp;')
s1 = s1.replace('<', '&lt;')
s1 = s1.replace('>', '&gt;')
return s1
def quote_attrib(inStr):
s1 = (isinstance(inStr, basestring) and inStr or
'%s' % inStr)
s1 = s1.replace('&', '&amp;')
s1 = s1.replace('<', '&lt;')
s1 = s1.replace('>', '&gt;')
if '"' in s1:
if "'" in s1:
s1 = '"%s"' % s1.replace('"', "&quot;")
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()')

View File

@ -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

View File

@ -0,0 +1,7 @@
/*!
* \defgroup block GNU Radio OP25 C++ Signal Processing Blocks
* \brief All C++ blocks that can be used from the OP25 GNU Radio
* module are listed here or in the subcategories below.
*
*/

View File

@ -0,0 +1,10 @@
/*! \mainpage
Welcome to the GNU Radio OP25 Block
This is the intro page for the Doxygen manual generated for the OP25
block (docs/doxygen/other/main_page.dox). Edit it to add more detailed
documentation about the new GNU Radio modules contained in this
project.
*/

View File

@ -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)

View File

@ -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.
install(FILES
op25_fsk4_demod_ff.xml
op25_fsk4_slicer_fb.xml
op25_decoder_ff.xml
op25_decoder_bf.xml
op25_pcap_source_b.xml DESTINATION share/gnuradio/grc/blocks
)

View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<block>
<name>decoder_bf</name>
<key>op25_decoder_bf</key>
<category>op25</category>
<import>import op25</import>
<make>op25.decoder_bf()</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>msgq</name>
<key>msgq</key>
<type>gr.msg_queue</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>bits</name>
<type>byte</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>audio</name>
<type>float</type>
</source>
</block>

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<block>
<name>decoder_ff</name>
<key>op25_decoder_ff</key>
<category>op25</category>
<import>import op25</import>
<make>op25.decoder_ff($)</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>

View File

@ -0,0 +1,48 @@
<?xml version="1.0"?>
<block>
<name>fsk4_demod_ff</name>
<key>op25_fsk4_demod_ff</key>
<category>op25</category>
<import>import op25</import>
<make>op25.fsk4_demod_ff(self.auto_tune_msgq, $sample_rate, $symbol_rate)</make>
<param>
<name>Sample Rate</name>
<key>sample_rate</key>
<value>28800</value>
<type>real</type>
</param>
<param>
<name>Symbol Rate</name>
<key>symbol_rate</key>
<value>4800</value>
<type>real</type>
</param>
<param>
<name>Output Auto Tune</name>
<key>tune_out</key>
<value>True</value>
<type>bool</type>
<hide>part</hide>
<option>
<name>Yes</name>
<key>True</key>
</option>
<option>
<name>No</name>
<key>False</key>
</option>
</param>
<sink>
<name>in</name>
<type>float</type>
</sink>
<source>
<name>dibits</name>
<type>float</type>
</source>
</block>

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<block>
<name>fsk4_slicer_fb</name>
<key>op25_fsk4_slicer_fb</key>
<category>op25</category>
<import>import op25</import>
<make>op25.fsk4_slicer_fb([-2.0,0.0,2.0,4.0])</make>
<sink>
<name>in</name>
<type>float</type>
</sink>
<source>
<name>out</name>
<type>byte</type>
</source>
</block>

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<block>
<name>pcap_source_b</name>
<key>op25_pcap_source_b</key>
<category>op25</category>
<import>import op25</import>
<make>op25.pcap_source_b($*path, $delay)</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>filename</name>
<key>filename</key>
<type>string</type>
</param>
<param>
<name>delay</name>
<key>delay</key>
<type>float</type>
</param>
<!-- 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>byte</type>
</source>
</block>

View File

@ -0,0 +1,30 @@
# 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
fsk4_demod_ff.h
fsk4_slicer_fb.h
decoder_ff.h
decoder_bf.h
pcap_source_b.h DESTINATION include/op25
)

View File

@ -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_OP25_API_H
#define INCLUDED_OP25_API_H
#include <gnuradio/attributes.h>
#ifdef gnuradio_op25_EXPORTS
# define OP25_API __GR_ATTR_EXPORT
#else
# define OP25_API __GR_ATTR_IMPORT
#endif
#endif /* INCLUDED_OP25_API_H */

View File

@ -0,0 +1,87 @@
/* -*- c++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* 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_OP25_DECODER_BF_H
#define INCLUDED_OP25_DECODER_BF_H
#include <op25/api.h>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
namespace gr {
namespace op25 {
/*!
* \brief Decode APCO P25 signals
* \ingroup op25
*
* op25_decoder_bf is a GNU Radio block for decoding APCO P25
* signals. This class expects its input to be a stream of dibit
* symbols from the demodulator and produces a mono audio stream.
*
*/
class OP25_API decoder_bf : virtual public gr::block
{
public:
typedef boost::shared_ptr<decoder_bf> sptr;
/*!
* \brief Return a shared_ptr to a new instance of op25::decoder_bf.
*
* To avoid accidental use of raw pointers, op25::decoder_bf's
* constructor is in a private implementation
* class. op25::decoder_bf::make is the public interface for
* creating new instances.
*/
static sptr make();
/**
* Return a pointer to a string identifying the destination of
* the received frames.
*
* \return A pointer to a NUL-terminated character string.
*/
virtual const char *destination() const = 0;
/**
* Accessor for the msgq attribute. Returns a pointer to the
* msgq if it exists.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
virtual gr::msg_queue::sptr get_msgq() const = 0;
/**
* Accessor for the msgq attribute. Sets the msgq to point to
* the provided message queue object.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
virtual void set_msgq(gr::msg_queue::sptr msgq) = 0;
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_DECODER_BF_H */

View File

@ -0,0 +1,84 @@
/* -*- c++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* 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_OP25_DECODER_FF_H
#define INCLUDED_OP25_DECODER_FF_H
#include <op25/api.h>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
namespace gr {
namespace op25 {
/*!
* \brief <+description of block+>
* \ingroup op25
*
*/
class OP25_API decoder_ff : virtual public gr::block
{
public:
typedef boost::shared_ptr<decoder_ff> sptr;
/*!
* \brief Return a shared_ptr to a new instance of
* op25::decoder_ff.
*
* To avoid accidental use of raw pointers, op25::decoder_ff's
* constructor is in a private implementation
* class. op25::decoder_ff::make is the public interface for
* creating new instances.
*/
static sptr make();
/**
* Return a pointer to a string identifying the destination of
* the received frames.
*
* \return A pointer to a NUL-terminated character string.
*/
virtual const char *destination() const = 0;
/**
* Accessor for the msgq attribute. Returns a pointer to the
* msgq if it exists.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
virtual gr::msg_queue::sptr get_msgq() const = 0;
/**
* Accessor for the msgq attribute. Sets the msgq to point to
* the provided message queue object.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
virtual void set_msgq(gr::msg_queue::sptr msgq) = 0;
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_DECODER_FF_H */

View File

@ -0,0 +1,64 @@
/* -*- c++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* 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_OP25_FSK4_DEMOD_FF_H
#define INCLUDED_OP25_FSK4_DEMOD_FF_H
#include <op25/api.h>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
namespace gr {
namespace op25 {
/*!
* \brief <+description of block+>
* \ingroup op25
*
*/
class OP25_API fsk4_demod_ff : virtual public gr::block
{
public:
typedef boost::shared_ptr<fsk4_demod_ff> sptr;
/*!
* \brief Demodulate APCO P25 CF4M signals.
*
* op25_fsk4_demod_ff is a GNU Radio block for demodulating APCO
* P25 CF4M signals. This class expects its input to consist of
* a 4 level FSK modulated baseband signal. It produces a stream
* of symbols.
*
* All inputs are post FM demodulator and symbol shaping filter
* data is normalized before being sent to this block so these
* parameters should not need adjusting even when working on
* different signals.
*
* Nominal levels are -3, -1, +1, and +3.
*/
static sptr make(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_FSK4_DEMOD_FF_H */

View File

@ -0,0 +1,56 @@
/* -*- c++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* 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_OP25_FSK4_SLICER_FB_H
#define INCLUDED_OP25_FSK4_SLICER_FB_H
#include <op25/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace op25 {
/*!
* \brief <+description of block+>
* \ingroup op25
*
*/
class OP25_API fsk4_slicer_fb : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<fsk4_slicer_fb> sptr;
/*!
* \brief Return a shared_ptr to a new instance of op25::fsk4_slicer_fb.
*
* To avoid accidental use of raw pointers, op25::fsk4_slicer_fb's
* constructor is in a private implementation
* class. op25::fsk4_slicer_fb::make is the public interface for
* creating new instances.
*/
static sptr make(const std::vector<float> &slice_levels);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_FSK4_SLICER_FB_H */

View File

@ -0,0 +1,55 @@
/* -*- c++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* 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_OP25_PCAP_SOURCE_B_H
#define INCLUDED_OP25_PCAP_SOURCE_B_H
#include <op25/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace op25 {
/*!
* \brief Read PCAP from a file and produce a stream of octets.
* \ingroup op25
*/
class OP25_API pcap_source_b : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<pcap_source_b> sptr;
/*!
* \brief Return a shared_ptr to a new instance of op25::pcap_source_b.
*
* To avoid accidental use of raw pointers, op25::pcap_source_b's
* constructor is in a private implementation
* class. op25::pcap_source_b::make is the public interface for
* creating new instances.
*/
static sptr make(const char *path, float delay);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_PCAP_SOURCE_B_H */

View File

@ -0,0 +1,93 @@
# 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 op25_sources
fsk4_demod_ff_impl.cc
fsk4_slicer_fb_impl.cc
decoder_bf_impl.cc
decoder_ff_impl.cc
abstract_data_unit.cc
data_unit.cc
hdu.cc
ldu1.cc
ldu2.cc
pdu.cc
tdu.cc
tsbk.cc
data_unit_handler.cc
logfile_du_handler.cc
p25cai_du_handler.cc
snapshot_du_handler.cc
imbe_decoder.cc
imbe_decoder_factory.cc
dummy_imbe_decoder.cc
offline_imbe_decoder.cc
voice_data_unit.cc
voice_du_handler.cc
pcap_source_b_impl.cc
software_imbe_decoder.cc
vc55_imbe_decoder.cc
value_string.cc
pickle.cc
pcap_source_b_impl.cc
)
add_library(gnuradio-op25 SHARED ${op25_sources})
target_link_libraries(gnuradio-op25 ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} itpp pcap)
set_target_properties(gnuradio-op25 PROPERTIES DEFINE_SYMBOL "gnuradio_op25_EXPORTS")
########################################################################
# Install built library files
########################################################################
install(TARGETS gnuradio-op25
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_op25_sources
${CMAKE_CURRENT_SOURCE_DIR}/test_op25.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_op25.cc
)
add_executable(test-op25 ${test_op25_sources})
target_link_libraries(
test-op25
${GNURADIO_RUNTIME_LIBRARIES}
${Boost_LIBRARIES}
${CPPUNIT_LIBRARIES}
gnuradio-op25
)
GR_ADD_TEST(test_op25 test-op25)

View File

@ -0,0 +1,181 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "abstract_data_unit.h"
#include <algorithm>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <utility>
using namespace std;
abstract_data_unit::~abstract_data_unit()
{
}
void
abstract_data_unit::correct_errors()
{
if(is_complete()) {
do_correct_errors(d_frame_body);
} else {
ostringstream msg;
msg << "cannot correct errors - frame is not complete" << endl;
msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
msg << "func: " << __PRETTY_FUNCTION__ << endl;
msg << "file: " << __FILE__ << endl;
msg << "line: " << __LINE__ << endl;
throw logic_error(msg.str());
}
}
void
abstract_data_unit::decode_audio(imbe_decoder& imbe)
{
if(is_complete()) {
do_decode_audio(d_frame_body, imbe);
} else {
ostringstream msg;
msg << "cannot decode audio - frame is not complete" << endl;
msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
msg << "func: " << __PRETTY_FUNCTION__ << endl;
msg << "file: " << __FILE__ << endl;
msg << "line: " << __LINE__ << endl;
throw logic_error(msg.str());
}
}
size_t
abstract_data_unit::decode_frame(size_t msg_sz, uint8_t *msg)
{
return decode_frame(d_frame_body, msg_sz, msg);
}
size_t
abstract_data_unit::decode_frame(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg)
{
size_t n = 0;
if(is_complete()) {
if(size() <= msg_sz) {
n = extract(frame_body, 0, static_cast<int>(frame_body.size()), msg);
} else {
ostringstream msg;
msg << "cannot decode frame body ";
msg << "(msg size: " << msg_sz << ", actual size: " << size() << ")" << endl;
msg << "func: " << __PRETTY_FUNCTION__ << endl;
msg << "file: " << __FILE__ << endl;
msg << "line: " << __LINE__ << endl;
throw length_error(msg.str());
}
} else {
ostringstream msg;
msg << "cannot decode frame - frame is not complete" << endl;
msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
msg << "func: " << __PRETTY_FUNCTION__ << endl;
msg << "file: " << __FILE__ << endl;
msg << "line: " << __LINE__ << endl;
throw logic_error(msg.str());
}
return n;
}
void
abstract_data_unit::extend(dibit d)
{
if(frame_size() < frame_size_max()) {
d_frame_body.push_back(d & 0x2);
d_frame_body.push_back(d & 0x1);
} else {
ostringstream msg;
msg << "cannot extend frame " << endl;
msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
msg << "func: " << __PRETTY_FUNCTION__ << endl;
msg << "file: " << __FILE__ << endl;
msg << "line: " << __LINE__ << endl;
throw length_error(msg.str());
}
}
bool
abstract_data_unit::is_complete() const
{
return frame_size() >= frame_size_max();
}
uint16_t
abstract_data_unit::size() const
{
return (7 + frame_size_max()) >> 3;
}
std::string
abstract_data_unit::snapshot() const
{
string empty;
return empty;
}
void
abstract_data_unit::dump(ostream& os) const
{
uint32_t nbits = d_frame_body.size();
os << setw(4) << nbits << " ";
for(size_t i = 48; i < nbits; ++i) {
os << (d_frame_body[i] ? "#" : "-");
}
os << endl;
}
abstract_data_unit::abstract_data_unit(const_bit_queue& frame_body) :
d_frame_body(frame_body.size())
{
copy(frame_body.begin(), frame_body.end(), d_frame_body.begin());
}
void
abstract_data_unit::do_correct_errors(bit_vector& frame_body)
{
}
void
abstract_data_unit::do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe)
{
}
const_bit_vector&
abstract_data_unit::frame_body() const
{
return d_frame_body;
}
uint16_t
abstract_data_unit::frame_size() const
{
return d_frame_body.size();
}

View File

@ -0,0 +1,192 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_ABSTRACT_DATA_UNIT_H
#define INCLUDED_ABSTRACT_DATA_UNIT_H
#include "data_unit.h"
#include "op25_yank.h"
#include <string>
#include <vector>
#include <itpp/base/vec.h>
#include <vector>
typedef std::vector<bool> bit_vector;
typedef const std::vector<bool> const_bit_vector;
/**
* Abstract P25 data unit.
*/
class abstract_data_unit : public data_unit
{
public:
/**
* abstract data_unit virtual destructor.
*/
virtual ~abstract_data_unit();
/**
* Apply error correction to this data_unit.
*
* \precondition is_complete() == true.
*/
virtual void correct_errors();
/**
* Decode compressed audio using the supplied imbe_decoder.
*
* \precondition is_complete() == true.
* \param imbe The imbe_decoder to use to generate the audio.
*/
virtual void decode_audio(imbe_decoder& imbe);
/**
* Decode the frame into an octet vector.
*
* \precondition is_complete() == true.
* \param msg_sz The size of the message buffer.
* \param msg A pointer to the message buffer.
* \return The number of octets written to msg.
*/
virtual size_t decode_frame(size_t msg_sz, uint8_t *msg);
/**
* Dump this data unit in human readable format to stream s.
*
* \param s The stream to write on
*/
virtual void dump(std::ostream& os) const;
/**
* Extends this data_unit with the specified dibit. If this
* data_unit is already complete a range_error is thrown.
*
* \precondition is_complete() == false.
* \param d The dibit to extend the frame with.
* \throws range_error When the frame already is at its maximum size.
* \return true when the frame is complete otherwise false.
*/
virtual void extend(dibit d);
/**
* Tests whether this data unit has enough data to begin decoding.
*
* \return true when this data_unit is complete; otherwise returns
* false.
*/
virtual bool is_complete() const;
/**
* Returns the size (in octets) of this data_unit.
*
* \return The size (in octets) of this data_unit.
*/
virtual uint16_t size() const;
/**
* Return a snapshot of the key fields from this frame in a manner
* suitable for display by the UI. The string is encoded as a
* pickled Python dictionary.
*
* \precondition is_complete() == true.
* \return A string containing the fields to display.
*/
virtual std::string snapshot() const;
protected:
/**
* abstract_data_unit constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
*/
abstract_data_unit(const_bit_queue& frame_body);
/**
* Applies error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
*/
virtual void do_correct_errors(bit_vector& frame_body);
/**
* Decode compressed audio using the supplied imbe_decoder.
*
* \precondition is_complete() == true.
* \param frame_body The const_bit_vector to decode.
* \param imbe The imbe_decoder to use.
*/
virtual void do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe);
/**
* Decode frame_body and write the decoded frame contents to msg.
*
* \param frame_body The bit vector to decode.
* \param msg_sz The size of the message buffer.
* \param msg A pointer to where the data unit content will be written.
* \return The number of octets written to msg.
*/
virtual size_t decode_frame(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg);
/**
* Returns a string describing the Data Unit ID (DUID).
*
* \return A string identifying the DUID.
*/
virtual std::string duid_str() const = 0;
/**
* Return a reference to the frame body.
*/
const_bit_vector& frame_body() const;
/**
* Returns the expected size (in bits) of this data_unit. For
* variable-length data this should return UINT16_MAX until the
* actual length of this frame is known.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const = 0;
/**
* Returns the current size (in bits) of this data_unit.
*
* \return The current size (in bits) of this data_unit.
*/
virtual uint16_t frame_size() const;
private:
/**
* A bit vector containing the frame body.
*/
bit_vector d_frame_body;
};
#endif /* INCLUDED_ABSTRACT_DATA_UNIT_H */

View File

@ -0,0 +1,73 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "data_unit.h"
#include "hdu.h"
#include "ldu1.h"
#include "ldu2.h"
#include "pdu.h"
#include "tdu.h"
#include "tsbk.h"
#include "op25_yank.h"
using namespace std;
data_unit_sptr
data_unit::make_data_unit(const_bit_queue& frame_body)
{
data_unit_sptr d;
uint8_t duid = extract(frame_body, 60, 64);
switch(duid) {
case 0x0:
d = data_unit_sptr(new hdu(frame_body));
break;
case 0x3:
d = data_unit_sptr(new tdu(frame_body, false));
break;
case 0x5:
d = data_unit_sptr(new ldu1(frame_body));
break;
case 0x7:
d = data_unit_sptr(new tsbk(frame_body));
break;
case 0xa:
d = data_unit_sptr(new ldu2(frame_body));
break;
case 0x9: // VSELP "voice PDU"
case 0xc:
d = data_unit_sptr(new pdu(frame_body));
break;
case 0xf:
d = data_unit_sptr(new tdu(frame_body, true));
break;
};
return d;
}
data_unit::~data_unit()
{
}
data_unit::data_unit()
{
}

View File

@ -0,0 +1,143 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_DATA_UNIT_H
#define INCLUDED_DATA_UNIT_H
#include "imbe_decoder.h"
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <deque>
#include <iosfwd>
#include <stdint.h>
typedef std::deque<bool> bit_queue;
typedef const std::deque<bool> const_bit_queue;
typedef uint8_t dibit;
typedef std::deque<float> float_queue;
typedef boost::shared_ptr<class data_unit> data_unit_sptr;
/**
* A P25 data unit.
*/
class data_unit : public boost::noncopyable
{
public:
/**
* data_unit (virtual) constructor. Returns a pointer to an
* appropriate data_unit instance given the initial frame_body.
* \param fs The frame sync value for this data_unit.
* \param nid The network ID for this data_unit.
* \return A (possibly null-valued) pointer to the data_unit.
*/
static data_unit_sptr make_data_unit(const_bit_queue& frame_body);
/**
* data_unit (virtual) destructor.
*/
virtual ~data_unit();
/**
* Apply error correction to this data_unit.
*
* \precondition is_complete() == true.
*/
virtual void correct_errors() = 0;
/**
* Decode compressed audio using the supplied imbe_decoder and
* writes output to audio.
*
* \precondition is_complete() == true.
* \param imbe The imbe_decoder to use to generate the audio.
*/
virtual void decode_audio(imbe_decoder& imbe) = 0;
/**
* Decode the frame into an octet vector.
*
* \precondition is_complete() == true.
* \param msg_sz The size of the message buffer.
* \param msg A pointer to the message buffer.
* \return The number of octets written to msg.
*/
virtual size_t decode_frame(size_t msg_sz, uint8_t *msg) = 0;
/**
* Dump this data unit in human readable format to stream s.
*
* \param s The stream to write on
*/
virtual void dump(std::ostream& os) const = 0;
/**
* Extends this data_unit with the specified dibit. If this
* data_unit is already complete a range_error is thrown.
*
* \precondition is_complete() == false.
* \param d The dibit to extend the frame with.
* \throws range_error When the frame already is at its maximum size.
* \return true when the frame is complete otherwise false.
*/
virtual void extend(dibit d) = 0;
/**
* Tests whether this data unit is complete.
*
* \return true when this data_unit is complete; otherwise returns
* false.
* \ see extend()
*/
virtual bool is_complete() const = 0;
/**
* Returns the size (in octets) of the data_unit.
*
* \return The actual size (in octets) of this data_unit.
*/
virtual uint16_t size() const = 0;
/**
* Return a snapshot of the key fields from this frame in a manner
* suitable for display by the UI. The string is encoded using the
* Python pickle format allowing for different fields to be
* returned.
*
* \return A string containing the fields to display.
*/
virtual std::string snapshot() const = 0;
protected:
/**
* data_unit default constructor.
*/
data_unit();
};
#endif /* INCLUDED_DATA_UNIT_H */

View File

@ -0,0 +1,19 @@
#include "data_unit_handler.h"
data_unit_handler::~data_unit_handler()
{
}
void
data_unit_handler::handle(data_unit_sptr du)
{
if(d_next) {
d_next->handle(du);
}
}
data_unit_handler::data_unit_handler(data_unit_handler_sptr next) :
d_next(next)
{
}

View File

@ -0,0 +1,72 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_DATA_UNIT_HANDLER_H
#define INCLUDED_DATA_UNIT_HANDLER_H
#include "data_unit.h"
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<class data_unit_handler> data_unit_handler_sptr;
/**
* P25 data_unit_handler interface.
*/
class data_unit_handler : public boost::noncopyable
{
public:
/**
* data_unit_handler virtual destructor.
*/
virtual ~data_unit_handler();
/**
* Handle a received P25 frame.
*
* \param du A non-null data_unit_sptr to handle.
*/
virtual void handle(data_unit_sptr du) = 0;
protected:
/**
* data_unit_handler default constructor.
*
* \param next The next data_unit_handler in this chain.
*/
data_unit_handler(data_unit_handler_sptr next);
private:
/**
* The next data_unit_handler in this chain.
*/
data_unit_handler_sptr d_next;
};
#endif /* INCLUDED_DATA_UNIT_HANDLER_H */

View File

@ -0,0 +1,233 @@
/* -*- c++ -*- */
/*
* Copyright 2080-2011 Steve Glass
*
* This file is part of OP25.
*
* 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 "decoder_bf_impl.h"
#include <gnuradio/io_signature.h>
#include <algorithm>
#include <iostream>
#include <itpp/comm/bch.h>
#include "logfile_du_handler.h"
#include "offline_imbe_decoder.h"
#include "voice_du_handler.h"
#include "op25_yank.h"
using namespace std;
namespace gr {
namespace op25 {
decoder_bf::sptr
decoder_bf::make()
{
return gnuradio::get_initial_sptr
(new decoder_bf_impl());
}
decoder_bf_impl::decoder_bf_impl() :
gr::block("decoder_bf",
gr::io_signature::make(1, 1, sizeof(uint8_t)),
gr::io_signature::make(0, 1, sizeof(float))),
d_data_unit(),
d_data_unit_handler(),
d_frame_hdr(),
d_imbe(imbe_decoder::make()),
d_state(SYNCHRONIZING),
d_p25cai_du_handler(NULL)
{
d_p25cai_du_handler = new p25cai_du_handler(d_data_unit_handler,
"224.0.0.1", 23456);
d_data_unit_handler = data_unit_handler_sptr(d_p25cai_du_handler);
d_snapshot_du_handler = new snapshot_du_handler(d_data_unit_handler);
d_data_unit_handler = data_unit_handler_sptr(d_snapshot_du_handler);
d_data_unit_handler = data_unit_handler_sptr(new voice_du_handler(d_data_unit_handler, d_imbe));
}
decoder_bf_impl::~decoder_bf_impl()
{
}
void
decoder_bf_impl::forecast (int noutput_items,
gr_vector_int &ninput_items_required)
{
/* This block consumes 4800 symbols/s and produces 8000
* samples/s. That's a work rate of 3/5 or 0.6. If no audio
* output is available we'll produce silence.
*/
const size_t nof_inputs = ninput_items_required.size();
const int nsamples_reqd = .6 * noutput_items;
fill(&ninput_items_required[0],
&ninput_items_required[nof_inputs],
nsamples_reqd);
}
gr::msg_queue::sptr
decoder_bf_impl::get_msgq() const
{
return d_snapshot_du_handler->get_msgq();
}
void
decoder_bf_impl::set_msgq(gr::msg_queue::sptr msgq)
{
d_snapshot_du_handler->set_msgq(msgq);
}
int
decoder_bf_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
try {
// process input
const uint8_t *in = reinterpret_cast<const uint8_t*>(input_items[0]);
for(int i = 0; i < ninput_items[0]; ++i) {
dibit d = in[i] & 0x3;
receive_symbol(d);
}
consume_each(ninput_items[0]);
// produce audio
audio_samples *samples = d_imbe->audio();
float *out = reinterpret_cast<float*>(output_items[0]);
const int n = min(static_cast<int>(samples->size()), noutput_items);
if(0 < n) {
copy(samples->begin(), samples->begin() + n, out);
samples->erase(samples->begin(), samples->begin() + n);
}
if(n < noutput_items) {
fill(out + n, out + noutput_items, 0.0);
}
return noutput_items;
} catch(const std::exception& x) {
cerr << x.what() << endl;
exit(1);
} catch(...) {
cerr << "unhandled exception" << endl;
exit(2); }
}
const char*
decoder_bf_impl::destination() const
{
return d_p25cai_du_handler->destination();
}
bool
decoder_bf_impl::correlated()
{
static const bool FS[] = {
0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
static const size_t FS_SZ = sizeof(FS)/sizeof(FS[0]);
uint8_t errs = 0;
for(size_t i = 0; i < FS_SZ; ++i) {
if(d_frame_hdr[i] ^ FS[i]) {
++errs;
}
}
return (errs <= 4);
}
data_unit_sptr
decoder_bf_impl::identified()
{
static const size_t NID[] = {
63, 62, 61, 60, 59, 58, 57, 56,
55, 54, 53, 52, 51, 50, 49, 48,
112, 111, 110, 109, 108, 107, 106, 105,
104, 103, 102, 101, 100, 99, 98, 97,
96, 95, 94, 93, 92, 91, 90, 89,
88, 87, 86, 85, 84, 83, 82, 81,
80, 79, 78, 77, 76, 75, 74, 73,
72, 69, 68, 67, 66, 65, 64,
};
size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
itpp::bvec b(63), zeroes(16);
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
yank(d_frame_hdr, NID, NID_SZ, b, 0);
b = bch.decode(b);
if(b != zeroes) {
b = bch.encode(b);
yank_back(b, 0, d_frame_hdr, NID, NID_SZ);
d_data_unit = data_unit::make_data_unit(d_frame_hdr);
} else {
data_unit_sptr null;
d_data_unit = null;
}
return d_data_unit;
}
void
decoder_bf_impl::receive_symbol(dibit d)
{
d_frame_hdr.push_back(d & 0x2);
d_frame_hdr.push_back(d & 0x1);
const size_t frame_hdr_sz = d_frame_hdr.size();
switch(d_state) {
case SYNCHRONIZING:
if(48 <= frame_hdr_sz) {
d_frame_hdr.erase(d_frame_hdr.begin(), d_frame_hdr.begin() + (frame_hdr_sz - 48));
if(correlated()) {
d_state = IDENTIFYING;
}
}
break;
case IDENTIFYING:
if(114 == frame_hdr_sz) {
if(identified()) {
d_state = READING;
} else {
d_state = SYNCHRONIZING;
}
}
break;
case READING:
d_data_unit->extend(d);
if(d_data_unit->is_complete()) {
d_data_unit->correct_errors();
d_data_unit_handler->handle(d_data_unit);
data_unit_sptr null;
d_data_unit = null;
d_state = SYNCHRONIZING;
}
break;
}
}
} /* namespace op25 */
} /* namespace gr */

View File

@ -0,0 +1,147 @@
/* -*- c++ -*- */
/*
* Copyright 2008-2011 Steve Glass
*
* This file is part of OP25.
*
* 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_OP25_DECODER_BF_IMPL_H
#define INCLUDED_OP25_DECODER_BF_IMPL_H
#include <op25/decoder_bf.h>
#include "data_unit.h"
#include "data_unit_handler.h"
#include "imbe_decoder.h"
#include "p25cai_du_handler.h"
#include "snapshot_du_handler.h"
namespace gr {
namespace op25 {
class decoder_bf_impl : public decoder_bf
{
private:
/**
* Tests whether d_frame_header correlates with the APCO P25
* frame sync sequence. This method must only be called when the
* frame header is larger than 48 bits in length (the minimum
* size for the FS).
*
* \return true if the frame header correlates; otherwise false.
*/
bool correlated();
/**
* Tests whether d_frame_header identifies a known data unit and
* if so sets d_data_unit to point to an appropriate instance
* and returns a pointer to it. This method must only be called
* when the frame header is larger than 114 bits in length (the
* minimum size for a frame containing a NID).
*
* \return A data_unit_sptr pointing to an appropriate data_unit
* instance or NULL if the frame header is unrecognized.
*/
data_unit_sptr identified();
/**
* Handle a received symbol.
*
* \param d The symbol to process.
*/
void receive_symbol(dibit d);
private:
/**
* When d_state == READING the current data unit, otherwise
* null.
*/
data_unit_sptr d_data_unit;
/**
* The head of a chain of data_unit_handler instances.
*/
data_unit_handler_sptr d_data_unit_handler;
/**
* A bit_queue used to correlate the FS.
*/
bit_queue d_frame_hdr;
/**
* The IMBE decoder to use.
*/
imbe_decoder_sptr d_imbe;
/**
* Valid states for the decoder state model.
*/
enum { SYNCHRONIZING, IDENTIFYING, READING } d_state;
/**
* The p25cai (TUN/TAP) data unit handler.
*/
class p25cai_du_handler *d_p25cai_du_handler;
/**
* The snapshot data unit handler.
*/
class snapshot_du_handler *d_snapshot_du_handler;
public:
decoder_bf_impl();
~decoder_bf_impl();
// Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
/**
* Return a pointer to a string identifying the destination of
* the received frames.
*
* \return A pointer to a NUL-terminated character string.
*/
const char *destination() const;
/**
* Accessor for the msgq attribute. Returns a pointer to the
* msgq if it exists.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
gr::msg_queue::sptr get_msgq() const;
/**
* Accessor for the msgq attribute. Sets the msgq to point to
* the provided message queue object.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
void set_msgq(gr::msg_queue::sptr msgq);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_DECODER_BF_IMPL_H */

View File

@ -0,0 +1,241 @@
/* -*- c++ -*- */
/*
* Copyright 2008-2011 Steve Glass
*
* This file is part of OP25.
*
* 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 "decoder_ff_impl.h"
#include <gnuradio/io_signature.h>
#include <algorithm>
#include <iostream>
#include <itpp/comm/bch.h>
#include "logfile_du_handler.h"
#include "offline_imbe_decoder.h"
#include "voice_du_handler.h"
#include "op25_yank.h"
using namespace std;
namespace gr {
namespace op25 {
decoder_ff::sptr
decoder_ff::make()
{
return gnuradio::get_initial_sptr
(new decoder_ff_impl());
}
decoder_ff_impl::decoder_ff_impl() :
gr::block("decoder_ff",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(0, 1, sizeof(float))),
d_data_unit(),
d_data_unit_handler(),
d_frame_hdr(),
d_imbe(imbe_decoder::make()),
d_state(SYNCHRONIZING),
d_p25cai_du_handler(NULL)
{
d_p25cai_du_handler = new p25cai_du_handler(d_data_unit_handler,
"224.0.0.1", 23456);
d_data_unit_handler = data_unit_handler_sptr(d_p25cai_du_handler);
d_snapshot_du_handler = new snapshot_du_handler(d_data_unit_handler);
d_data_unit_handler = data_unit_handler_sptr(d_snapshot_du_handler);
d_data_unit_handler = data_unit_handler_sptr(new voice_du_handler(d_data_unit_handler, d_imbe));
}
decoder_ff_impl::~decoder_ff_impl()
{
}
gr::msg_queue::sptr
decoder_ff_impl::get_msgq() const
{
return d_snapshot_du_handler->get_msgq();
}
void
decoder_ff_impl::set_msgq(gr::msg_queue::sptr msgq)
{
d_snapshot_du_handler->set_msgq(msgq);
}
void
decoder_ff_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
/* This block consumes 4800 symbols/s and produces 8000
* samples/s. That's a work rate of 3/5 or 0.6. If no audio
* output is available we'll produce silence.
*/
const size_t ninputs = ninput_items_required.size();
const int nsamples_reqired = .6 * noutput_items;
fill(&ninput_items_required[0],
&ninput_items_required[ninputs],
nsamples_reqired);
}
int
decoder_ff_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
try {
// process input
const float *in = reinterpret_cast<const float*>(input_items[0]);
for(int i = 0; i < ninput_items[0]; ++i) {
dibit d;
if(in[i] < -2.0) {
d = 3;
} else if(in[i] < 0.0) {
d = 2;
} else if(in[i] < 2.0) {
d = 0;
} else {
d = 1;
}
receive_symbol(d);
}
consume_each(ninput_items[0]);
// produce audio
audio_samples *samples = d_imbe->audio();
float *out = reinterpret_cast<float*>(output_items[0]);
const int n = min(static_cast<int>(samples->size()), noutput_items);
if(0 < n) {
copy(samples->begin(), samples->begin() + n, out);
samples->erase(samples->begin(), samples->begin() + n);
}
if(n < noutput_items) {
fill(out + n, out + noutput_items, 0.0);
}
return noutput_items;
} catch(const std::exception& x) {
cerr << x.what() << endl;
exit(1);
} catch(...) {
cerr << "unhandled exception" << endl;
exit(2); }
}
const char*
decoder_ff_impl::destination() const
{
return d_p25cai_du_handler->destination();
}
bool
decoder_ff_impl::correlated()
{
static const bool FS[] = {
0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
static const size_t FS_SZ = sizeof(FS)/sizeof(FS[0]);
uint8_t errs = 0;
for(size_t i = 0; i < FS_SZ; ++i) {
if(d_frame_hdr[i] ^ FS[i]) {
++errs;
}
}
return (errs <= 4);
}
data_unit_sptr
decoder_ff_impl::identified()
{
static const size_t NID[] = {
63, 62, 61, 60, 59, 58, 57, 56,
55, 54, 53, 52, 51, 50, 49, 48,
112, 111, 110, 109, 108, 107, 106, 105,
104, 103, 102, 101, 100, 99, 98, 97,
96, 95, 94, 93, 92, 91, 90, 89,
88, 87, 86, 85, 84, 83, 82, 81,
80, 79, 78, 77, 76, 75, 74, 73,
72, 69, 68, 67, 66, 65, 64,
};
size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
itpp::bvec b(63), zeroes(16);
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
yank(d_frame_hdr, NID, NID_SZ, b, 0);
b = bch.decode(b);
if(b != zeroes) {
b = bch.encode(b);
yank_back(b, 0, d_frame_hdr, NID, NID_SZ);
d_data_unit = data_unit::make_data_unit(d_frame_hdr);
} else {
data_unit_sptr null;
d_data_unit = null;
}
return d_data_unit;
}
void
decoder_ff_impl::receive_symbol(dibit d)
{
d_frame_hdr.push_back(d & 0x2);
d_frame_hdr.push_back(d & 0x1);
const size_t frame_hdr_sz = d_frame_hdr.size();
switch(d_state) {
case SYNCHRONIZING:
if(48 <= frame_hdr_sz) {
d_frame_hdr.erase(d_frame_hdr.begin(), d_frame_hdr.begin() + (frame_hdr_sz - 48));
if(correlated()) {
d_state = IDENTIFYING;
}
}
break;
case IDENTIFYING:
if(114 == frame_hdr_sz) {
if(identified()) {
d_state = READING;
} else {
d_state = SYNCHRONIZING;
}
}
break;
case READING:
d_data_unit->extend(d);
if(d_data_unit->is_complete()) {
d_data_unit->correct_errors();
d_data_unit_handler->handle(d_data_unit);
data_unit_sptr null;
d_data_unit = null;
d_state = SYNCHRONIZING;
}
break;
}
}
} /* namespace op25 */
} /* namespace gr */

View File

@ -0,0 +1,147 @@
/* -*- c++ -*- */
/*
* Copyright 2008-2011 Steve Glass
*
* This file is part of OP25.
*
* 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_OP25_DECODER_FF_IMPL_H
#define INCLUDED_OP25_DECODER_FF_IMPL_H
#include <op25/decoder_ff.h>
#include "data_unit.h"
#include "data_unit_handler.h"
#include "imbe_decoder.h"
#include "p25cai_du_handler.h"
#include "snapshot_du_handler.h"
namespace gr {
namespace op25 {
class decoder_ff_impl : public decoder_ff
{
private:
/**
* Tests whether d_frame_header correlates with the APCO P25
* frame sync sequence. This method must only be called when the
* frame header is larger than 48 bits in length (the minimum
* size for the FS).
*
* \return true if the frame header correlates; otherwise false.
*/
bool correlated();
/**
* Tests whether d_frame_header identifies a known data unit and
* if so sets d_data_unit to point to an appropriate instance
* and returns a pointer to it. This method must only be called
* when the frame header is larger than 114 bits in length (the
* minimum size for a frame containing a NID).
*
* \return A data_unit_sptr pointing to an appropriate data_unit
* instance or NULL if the frame header is unrecognized.
*/
data_unit_sptr identified();
/**
* Handle a received symbol.
*
* \param d The symbol to process.
*/
void receive_symbol(dibit d);
private:
/**
* When d_state == READING the current data unit, otherwise
* null.
*/
data_unit_sptr d_data_unit;
/**
* The head of a chain of data_unit_handler instances.
*/
data_unit_handler_sptr d_data_unit_handler;
/**
* A bit_queue used to correlate the FS.
*/
bit_queue d_frame_hdr;
/**
* The IMBE decoder to use.
*/
imbe_decoder_sptr d_imbe;
/**
* Valid states for the decoder state model.
*/
enum { SYNCHRONIZING, IDENTIFYING, READING } d_state;
/**
* The p25cai (TUN/TAP) data unit handler.
*/
class p25cai_du_handler *d_p25cai_du_handler;
/**
* The snapshot data unit handler.
*/
class snapshot_du_handler *d_snapshot_du_handler;
public:
decoder_ff_impl();
~decoder_ff_impl();
// Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
/**
* Return a pointer to a string identifying the destination of
* the received frames.
*
* \return A pointer to a NUL-terminated character string.
*/
const char *destination() const;
/**
* Accessor for the msgq attribute. Returns a pointer to the
* msgq if it exists.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
gr::msg_queue::sptr get_msgq() const;
/**
* Accessor for the msgq attribute. Sets the msgq to point to
* the provided message queue object.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the
* message queue.
*/
void set_msgq(gr::msg_queue::sptr msgq);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_DECODER_FF_IMPL_H */

View File

@ -0,0 +1,37 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "dummy_imbe_decoder.h"
dummy_imbe_decoder::dummy_imbe_decoder()
{
}
dummy_imbe_decoder::~dummy_imbe_decoder()
{
}
void
dummy_imbe_decoder::decode(const voice_codeword& cw)
{
}

View File

@ -0,0 +1,55 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_DUMMY_IMBE_DECODER_H
#define INCLUDED_DUMMY_IMBE_DECODER_H
#include "imbe_decoder.h"
/**
* dummy_imbe_decoder is the imbe_decoder of last resort. It consumes
* the voice_codeeword and does nothing.
*/
class dummy_imbe_decoder : public imbe_decoder {
public:
/**
* dummy_imbe_decoder default constructor.
*/
dummy_imbe_decoder();
/**
* dummy_imbe_decoder (virtual) destructor.
*/
virtual ~dummy_imbe_decoder();
/**
* Ignores in_out and generates no audio.
*
* \param cw IMBE codewords and parity.
*/
virtual void decode(const voice_codeword& cw);
};
#endif /* INCLUDED_DUMMY_IMBE_DECODER_H */

View File

@ -0,0 +1,381 @@
/* -*- c++ -*- */
/*
* Copyright 2006, 2007 Frank (Radio Rausch)
* Copyright 2011 Steve Glass
*
* This file is part of OP25.
*
* 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 <stdio.h>
#include <gnuradio/io_signature.h>
#include "fsk4_demod_ff_impl.h"
/*
* This table was machine-generated by gen_interpolator_taps.
* DO NOT EDIT BY HAND.
*/
static const int NTAPS = 8;
static const int NSTEPS = 128;
static const float TAPS[NSTEPS+1][NTAPS] = {
// -4 -3 -2 -1 0 1 2 3 mu
{ 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00 }, // 0/128
{ -1.54700e-04, 8.53777e-04, -2.76968e-03, 7.89295e-03, 9.98534e-01, -5.41054e-03, 1.24642e-03, -1.98993e-04 }, // 1/128
{ -3.09412e-04, 1.70888e-03, -5.55134e-03, 1.58840e-02, 9.96891e-01, -1.07209e-02, 2.47942e-03, -3.96391e-04 }, // 2/128
{ -4.64053e-04, 2.56486e-03, -8.34364e-03, 2.39714e-02, 9.95074e-01, -1.59305e-02, 3.69852e-03, -5.92100e-04 }, // 3/128
{ -6.18544e-04, 3.42130e-03, -1.11453e-02, 3.21531e-02, 9.93082e-01, -2.10389e-02, 4.90322e-03, -7.86031e-04 }, // 4/128
{ -7.72802e-04, 4.27773e-03, -1.39548e-02, 4.04274e-02, 9.90917e-01, -2.60456e-02, 6.09305e-03, -9.78093e-04 }, // 5/128
{ -9.26747e-04, 5.13372e-03, -1.67710e-02, 4.87921e-02, 9.88580e-01, -3.09503e-02, 7.26755e-03, -1.16820e-03 }, // 6/128
{ -1.08030e-03, 5.98883e-03, -1.95925e-02, 5.72454e-02, 9.86071e-01, -3.57525e-02, 8.42626e-03, -1.35627e-03 }, // 7/128
{ -1.23337e-03, 6.84261e-03, -2.24178e-02, 6.57852e-02, 9.83392e-01, -4.04519e-02, 9.56876e-03, -1.54221e-03 }, // 8/128
{ -1.38589e-03, 7.69462e-03, -2.52457e-02, 7.44095e-02, 9.80543e-01, -4.50483e-02, 1.06946e-02, -1.72594e-03 }, // 9/128
{ -1.53777e-03, 8.54441e-03, -2.80746e-02, 8.31162e-02, 9.77526e-01, -4.95412e-02, 1.18034e-02, -1.90738e-03 }, // 10/128
{ -1.68894e-03, 9.39154e-03, -3.09033e-02, 9.19033e-02, 9.74342e-01, -5.39305e-02, 1.28947e-02, -2.08645e-03 }, // 11/128
{ -1.83931e-03, 1.02356e-02, -3.37303e-02, 1.00769e-01, 9.70992e-01, -5.82159e-02, 1.39681e-02, -2.26307e-03 }, // 12/128
{ -1.98880e-03, 1.10760e-02, -3.65541e-02, 1.09710e-01, 9.67477e-01, -6.23972e-02, 1.50233e-02, -2.43718e-03 }, // 13/128
{ -2.13733e-03, 1.19125e-02, -3.93735e-02, 1.18725e-01, 9.63798e-01, -6.64743e-02, 1.60599e-02, -2.60868e-03 }, // 14/128
{ -2.28483e-03, 1.27445e-02, -4.21869e-02, 1.27812e-01, 9.59958e-01, -7.04471e-02, 1.70776e-02, -2.77751e-03 }, // 15/128
{ -2.43121e-03, 1.35716e-02, -4.49929e-02, 1.36968e-01, 9.55956e-01, -7.43154e-02, 1.80759e-02, -2.94361e-03 }, // 16/128
{ -2.57640e-03, 1.43934e-02, -4.77900e-02, 1.46192e-01, 9.51795e-01, -7.80792e-02, 1.90545e-02, -3.10689e-03 }, // 17/128
{ -2.72032e-03, 1.52095e-02, -5.05770e-02, 1.55480e-01, 9.47477e-01, -8.17385e-02, 2.00132e-02, -3.26730e-03 }, // 18/128
{ -2.86289e-03, 1.60193e-02, -5.33522e-02, 1.64831e-01, 9.43001e-01, -8.52933e-02, 2.09516e-02, -3.42477e-03 }, // 19/128
{ -3.00403e-03, 1.68225e-02, -5.61142e-02, 1.74242e-01, 9.38371e-01, -8.87435e-02, 2.18695e-02, -3.57923e-03 }, // 20/128
{ -3.14367e-03, 1.76185e-02, -5.88617e-02, 1.83711e-01, 9.33586e-01, -9.20893e-02, 2.27664e-02, -3.73062e-03 }, // 21/128
{ -3.28174e-03, 1.84071e-02, -6.15931e-02, 1.93236e-01, 9.28650e-01, -9.53307e-02, 2.36423e-02, -3.87888e-03 }, // 22/128
{ -3.41815e-03, 1.91877e-02, -6.43069e-02, 2.02814e-01, 9.23564e-01, -9.84679e-02, 2.44967e-02, -4.02397e-03 }, // 23/128
{ -3.55283e-03, 1.99599e-02, -6.70018e-02, 2.12443e-01, 9.18329e-01, -1.01501e-01, 2.53295e-02, -4.16581e-03 }, // 24/128
{ -3.68570e-03, 2.07233e-02, -6.96762e-02, 2.22120e-01, 9.12947e-01, -1.04430e-01, 2.61404e-02, -4.30435e-03 }, // 25/128
{ -3.81671e-03, 2.14774e-02, -7.23286e-02, 2.31843e-01, 9.07420e-01, -1.07256e-01, 2.69293e-02, -4.43955e-03 }, // 26/128
{ -3.94576e-03, 2.22218e-02, -7.49577e-02, 2.41609e-01, 9.01749e-01, -1.09978e-01, 2.76957e-02, -4.57135e-03 }, // 27/128
{ -4.07279e-03, 2.29562e-02, -7.75620e-02, 2.51417e-01, 8.95936e-01, -1.12597e-01, 2.84397e-02, -4.69970e-03 }, // 28/128
{ -4.19774e-03, 2.36801e-02, -8.01399e-02, 2.61263e-01, 8.89984e-01, -1.15113e-01, 2.91609e-02, -4.82456e-03 }, // 29/128
{ -4.32052e-03, 2.43930e-02, -8.26900e-02, 2.71144e-01, 8.83893e-01, -1.17526e-01, 2.98593e-02, -4.94589e-03 }, // 30/128
{ -4.44107e-03, 2.50946e-02, -8.52109e-02, 2.81060e-01, 8.77666e-01, -1.19837e-01, 3.05345e-02, -5.06363e-03 }, // 31/128
{ -4.55932e-03, 2.57844e-02, -8.77011e-02, 2.91006e-01, 8.71305e-01, -1.22047e-01, 3.11866e-02, -5.17776e-03 }, // 32/128
{ -4.67520e-03, 2.64621e-02, -9.01591e-02, 3.00980e-01, 8.64812e-01, -1.24154e-01, 3.18153e-02, -5.28823e-03 }, // 33/128
{ -4.78866e-03, 2.71272e-02, -9.25834e-02, 3.10980e-01, 8.58189e-01, -1.26161e-01, 3.24205e-02, -5.39500e-03 }, // 34/128
{ -4.89961e-03, 2.77794e-02, -9.49727e-02, 3.21004e-01, 8.51437e-01, -1.28068e-01, 3.30021e-02, -5.49804e-03 }, // 35/128
{ -5.00800e-03, 2.84182e-02, -9.73254e-02, 3.31048e-01, 8.44559e-01, -1.29874e-01, 3.35600e-02, -5.59731e-03 }, // 36/128
{ -5.11376e-03, 2.90433e-02, -9.96402e-02, 3.41109e-01, 8.37557e-01, -1.31581e-01, 3.40940e-02, -5.69280e-03 }, // 37/128
{ -5.21683e-03, 2.96543e-02, -1.01915e-01, 3.51186e-01, 8.30432e-01, -1.33189e-01, 3.46042e-02, -5.78446e-03 }, // 38/128
{ -5.31716e-03, 3.02507e-02, -1.04150e-01, 3.61276e-01, 8.23188e-01, -1.34699e-01, 3.50903e-02, -5.87227e-03 }, // 39/128
{ -5.41467e-03, 3.08323e-02, -1.06342e-01, 3.71376e-01, 8.15826e-01, -1.36111e-01, 3.55525e-02, -5.95620e-03 }, // 40/128
{ -5.50931e-03, 3.13987e-02, -1.08490e-01, 3.81484e-01, 8.08348e-01, -1.37426e-01, 3.59905e-02, -6.03624e-03 }, // 41/128
{ -5.60103e-03, 3.19495e-02, -1.10593e-01, 3.91596e-01, 8.00757e-01, -1.38644e-01, 3.64044e-02, -6.11236e-03 }, // 42/128
{ -5.68976e-03, 3.24843e-02, -1.12650e-01, 4.01710e-01, 7.93055e-01, -1.39767e-01, 3.67941e-02, -6.18454e-03 }, // 43/128
{ -5.77544e-03, 3.30027e-02, -1.14659e-01, 4.11823e-01, 7.85244e-01, -1.40794e-01, 3.71596e-02, -6.25277e-03 }, // 44/128
{ -5.85804e-03, 3.35046e-02, -1.16618e-01, 4.21934e-01, 7.77327e-01, -1.41727e-01, 3.75010e-02, -6.31703e-03 }, // 45/128
{ -5.93749e-03, 3.39894e-02, -1.18526e-01, 4.32038e-01, 7.69305e-01, -1.42566e-01, 3.78182e-02, -6.37730e-03 }, // 46/128
{ -6.01374e-03, 3.44568e-02, -1.20382e-01, 4.42134e-01, 7.61181e-01, -1.43313e-01, 3.81111e-02, -6.43358e-03 }, // 47/128
{ -6.08674e-03, 3.49066e-02, -1.22185e-01, 4.52218e-01, 7.52958e-01, -1.43968e-01, 3.83800e-02, -6.48585e-03 }, // 48/128
{ -6.15644e-03, 3.53384e-02, -1.23933e-01, 4.62289e-01, 7.44637e-01, -1.44531e-01, 3.86247e-02, -6.53412e-03 }, // 49/128
{ -6.22280e-03, 3.57519e-02, -1.25624e-01, 4.72342e-01, 7.36222e-01, -1.45004e-01, 3.88454e-02, -6.57836e-03 }, // 50/128
{ -6.28577e-03, 3.61468e-02, -1.27258e-01, 4.82377e-01, 7.27714e-01, -1.45387e-01, 3.90420e-02, -6.61859e-03 }, // 51/128
{ -6.34530e-03, 3.65227e-02, -1.28832e-01, 4.92389e-01, 7.19116e-01, -1.45682e-01, 3.92147e-02, -6.65479e-03 }, // 52/128
{ -6.40135e-03, 3.68795e-02, -1.30347e-01, 5.02377e-01, 7.10431e-01, -1.45889e-01, 3.93636e-02, -6.68698e-03 }, // 53/128
{ -6.45388e-03, 3.72167e-02, -1.31800e-01, 5.12337e-01, 7.01661e-01, -1.46009e-01, 3.94886e-02, -6.71514e-03 }, // 54/128
{ -6.50285e-03, 3.75341e-02, -1.33190e-01, 5.22267e-01, 6.92808e-01, -1.46043e-01, 3.95900e-02, -6.73929e-03 }, // 55/128
{ -6.54823e-03, 3.78315e-02, -1.34515e-01, 5.32164e-01, 6.83875e-01, -1.45993e-01, 3.96678e-02, -6.75943e-03 }, // 56/128
{ -6.58996e-03, 3.81085e-02, -1.35775e-01, 5.42025e-01, 6.74865e-01, -1.45859e-01, 3.97222e-02, -6.77557e-03 }, // 57/128
{ -6.62802e-03, 3.83650e-02, -1.36969e-01, 5.51849e-01, 6.65779e-01, -1.45641e-01, 3.97532e-02, -6.78771e-03 }, // 58/128
{ -6.66238e-03, 3.86006e-02, -1.38094e-01, 5.61631e-01, 6.56621e-01, -1.45343e-01, 3.97610e-02, -6.79588e-03 }, // 59/128
{ -6.69300e-03, 3.88151e-02, -1.39150e-01, 5.71370e-01, 6.47394e-01, -1.44963e-01, 3.97458e-02, -6.80007e-03 }, // 60/128
{ -6.71985e-03, 3.90083e-02, -1.40136e-01, 5.81063e-01, 6.38099e-01, -1.44503e-01, 3.97077e-02, -6.80032e-03 }, // 61/128
{ -6.74291e-03, 3.91800e-02, -1.41050e-01, 5.90706e-01, 6.28739e-01, -1.43965e-01, 3.96469e-02, -6.79662e-03 }, // 62/128
{ -6.76214e-03, 3.93299e-02, -1.41891e-01, 6.00298e-01, 6.19318e-01, -1.43350e-01, 3.95635e-02, -6.78902e-03 }, // 63/128
{ -6.77751e-03, 3.94578e-02, -1.42658e-01, 6.09836e-01, 6.09836e-01, -1.42658e-01, 3.94578e-02, -6.77751e-03 }, // 64/128
{ -6.78902e-03, 3.95635e-02, -1.43350e-01, 6.19318e-01, 6.00298e-01, -1.41891e-01, 3.93299e-02, -6.76214e-03 }, // 65/128
{ -6.79662e-03, 3.96469e-02, -1.43965e-01, 6.28739e-01, 5.90706e-01, -1.41050e-01, 3.91800e-02, -6.74291e-03 }, // 66/128
{ -6.80032e-03, 3.97077e-02, -1.44503e-01, 6.38099e-01, 5.81063e-01, -1.40136e-01, 3.90083e-02, -6.71985e-03 }, // 67/128
{ -6.80007e-03, 3.97458e-02, -1.44963e-01, 6.47394e-01, 5.71370e-01, -1.39150e-01, 3.88151e-02, -6.69300e-03 }, // 68/128
{ -6.79588e-03, 3.97610e-02, -1.45343e-01, 6.56621e-01, 5.61631e-01, -1.38094e-01, 3.86006e-02, -6.66238e-03 }, // 69/128
{ -6.78771e-03, 3.97532e-02, -1.45641e-01, 6.65779e-01, 5.51849e-01, -1.36969e-01, 3.83650e-02, -6.62802e-03 }, // 70/128
{ -6.77557e-03, 3.97222e-02, -1.45859e-01, 6.74865e-01, 5.42025e-01, -1.35775e-01, 3.81085e-02, -6.58996e-03 }, // 71/128
{ -6.75943e-03, 3.96678e-02, -1.45993e-01, 6.83875e-01, 5.32164e-01, -1.34515e-01, 3.78315e-02, -6.54823e-03 }, // 72/128
{ -6.73929e-03, 3.95900e-02, -1.46043e-01, 6.92808e-01, 5.22267e-01, -1.33190e-01, 3.75341e-02, -6.50285e-03 }, // 73/128
{ -6.71514e-03, 3.94886e-02, -1.46009e-01, 7.01661e-01, 5.12337e-01, -1.31800e-01, 3.72167e-02, -6.45388e-03 }, // 74/128
{ -6.68698e-03, 3.93636e-02, -1.45889e-01, 7.10431e-01, 5.02377e-01, -1.30347e-01, 3.68795e-02, -6.40135e-03 }, // 75/128
{ -6.65479e-03, 3.92147e-02, -1.45682e-01, 7.19116e-01, 4.92389e-01, -1.28832e-01, 3.65227e-02, -6.34530e-03 }, // 76/128
{ -6.61859e-03, 3.90420e-02, -1.45387e-01, 7.27714e-01, 4.82377e-01, -1.27258e-01, 3.61468e-02, -6.28577e-03 }, // 77/128
{ -6.57836e-03, 3.88454e-02, -1.45004e-01, 7.36222e-01, 4.72342e-01, -1.25624e-01, 3.57519e-02, -6.22280e-03 }, // 78/128
{ -6.53412e-03, 3.86247e-02, -1.44531e-01, 7.44637e-01, 4.62289e-01, -1.23933e-01, 3.53384e-02, -6.15644e-03 }, // 79/128
{ -6.48585e-03, 3.83800e-02, -1.43968e-01, 7.52958e-01, 4.52218e-01, -1.22185e-01, 3.49066e-02, -6.08674e-03 }, // 80/128
{ -6.43358e-03, 3.81111e-02, -1.43313e-01, 7.61181e-01, 4.42134e-01, -1.20382e-01, 3.44568e-02, -6.01374e-03 }, // 81/128
{ -6.37730e-03, 3.78182e-02, -1.42566e-01, 7.69305e-01, 4.32038e-01, -1.18526e-01, 3.39894e-02, -5.93749e-03 }, // 82/128
{ -6.31703e-03, 3.75010e-02, -1.41727e-01, 7.77327e-01, 4.21934e-01, -1.16618e-01, 3.35046e-02, -5.85804e-03 }, // 83/128
{ -6.25277e-03, 3.71596e-02, -1.40794e-01, 7.85244e-01, 4.11823e-01, -1.14659e-01, 3.30027e-02, -5.77544e-03 }, // 84/128
{ -6.18454e-03, 3.67941e-02, -1.39767e-01, 7.93055e-01, 4.01710e-01, -1.12650e-01, 3.24843e-02, -5.68976e-03 }, // 85/128
{ -6.11236e-03, 3.64044e-02, -1.38644e-01, 8.00757e-01, 3.91596e-01, -1.10593e-01, 3.19495e-02, -5.60103e-03 }, // 86/128
{ -6.03624e-03, 3.59905e-02, -1.37426e-01, 8.08348e-01, 3.81484e-01, -1.08490e-01, 3.13987e-02, -5.50931e-03 }, // 87/128
{ -5.95620e-03, 3.55525e-02, -1.36111e-01, 8.15826e-01, 3.71376e-01, -1.06342e-01, 3.08323e-02, -5.41467e-03 }, // 88/128
{ -5.87227e-03, 3.50903e-02, -1.34699e-01, 8.23188e-01, 3.61276e-01, -1.04150e-01, 3.02507e-02, -5.31716e-03 }, // 89/128
{ -5.78446e-03, 3.46042e-02, -1.33189e-01, 8.30432e-01, 3.51186e-01, -1.01915e-01, 2.96543e-02, -5.21683e-03 }, // 90/128
{ -5.69280e-03, 3.40940e-02, -1.31581e-01, 8.37557e-01, 3.41109e-01, -9.96402e-02, 2.90433e-02, -5.11376e-03 }, // 91/128
{ -5.59731e-03, 3.35600e-02, -1.29874e-01, 8.44559e-01, 3.31048e-01, -9.73254e-02, 2.84182e-02, -5.00800e-03 }, // 92/128
{ -5.49804e-03, 3.30021e-02, -1.28068e-01, 8.51437e-01, 3.21004e-01, -9.49727e-02, 2.77794e-02, -4.89961e-03 }, // 93/128
{ -5.39500e-03, 3.24205e-02, -1.26161e-01, 8.58189e-01, 3.10980e-01, -9.25834e-02, 2.71272e-02, -4.78866e-03 }, // 94/128
{ -5.28823e-03, 3.18153e-02, -1.24154e-01, 8.64812e-01, 3.00980e-01, -9.01591e-02, 2.64621e-02, -4.67520e-03 }, // 95/128
{ -5.17776e-03, 3.11866e-02, -1.22047e-01, 8.71305e-01, 2.91006e-01, -8.77011e-02, 2.57844e-02, -4.55932e-03 }, // 96/128
{ -5.06363e-03, 3.05345e-02, -1.19837e-01, 8.77666e-01, 2.81060e-01, -8.52109e-02, 2.50946e-02, -4.44107e-03 }, // 97/128
{ -4.94589e-03, 2.98593e-02, -1.17526e-01, 8.83893e-01, 2.71144e-01, -8.26900e-02, 2.43930e-02, -4.32052e-03 }, // 98/128
{ -4.82456e-03, 2.91609e-02, -1.15113e-01, 8.89984e-01, 2.61263e-01, -8.01399e-02, 2.36801e-02, -4.19774e-03 }, // 99/128
{ -4.69970e-03, 2.84397e-02, -1.12597e-01, 8.95936e-01, 2.51417e-01, -7.75620e-02, 2.29562e-02, -4.07279e-03 }, // 100/128
{ -4.57135e-03, 2.76957e-02, -1.09978e-01, 9.01749e-01, 2.41609e-01, -7.49577e-02, 2.22218e-02, -3.94576e-03 }, // 101/128
{ -4.43955e-03, 2.69293e-02, -1.07256e-01, 9.07420e-01, 2.31843e-01, -7.23286e-02, 2.14774e-02, -3.81671e-03 }, // 102/128
{ -4.30435e-03, 2.61404e-02, -1.04430e-01, 9.12947e-01, 2.22120e-01, -6.96762e-02, 2.07233e-02, -3.68570e-03 }, // 103/128
{ -4.16581e-03, 2.53295e-02, -1.01501e-01, 9.18329e-01, 2.12443e-01, -6.70018e-02, 1.99599e-02, -3.55283e-03 }, // 104/128
{ -4.02397e-03, 2.44967e-02, -9.84679e-02, 9.23564e-01, 2.02814e-01, -6.43069e-02, 1.91877e-02, -3.41815e-03 }, // 105/128
{ -3.87888e-03, 2.36423e-02, -9.53307e-02, 9.28650e-01, 1.93236e-01, -6.15931e-02, 1.84071e-02, -3.28174e-03 }, // 106/128
{ -3.73062e-03, 2.27664e-02, -9.20893e-02, 9.33586e-01, 1.83711e-01, -5.88617e-02, 1.76185e-02, -3.14367e-03 }, // 107/128
{ -3.57923e-03, 2.18695e-02, -8.87435e-02, 9.38371e-01, 1.74242e-01, -5.61142e-02, 1.68225e-02, -3.00403e-03 }, // 108/128
{ -3.42477e-03, 2.09516e-02, -8.52933e-02, 9.43001e-01, 1.64831e-01, -5.33522e-02, 1.60193e-02, -2.86289e-03 }, // 109/128
{ -3.26730e-03, 2.00132e-02, -8.17385e-02, 9.47477e-01, 1.55480e-01, -5.05770e-02, 1.52095e-02, -2.72032e-03 }, // 110/128
{ -3.10689e-03, 1.90545e-02, -7.80792e-02, 9.51795e-01, 1.46192e-01, -4.77900e-02, 1.43934e-02, -2.57640e-03 }, // 111/128
{ -2.94361e-03, 1.80759e-02, -7.43154e-02, 9.55956e-01, 1.36968e-01, -4.49929e-02, 1.35716e-02, -2.43121e-03 }, // 112/128
{ -2.77751e-03, 1.70776e-02, -7.04471e-02, 9.59958e-01, 1.27812e-01, -4.21869e-02, 1.27445e-02, -2.28483e-03 }, // 113/128
{ -2.60868e-03, 1.60599e-02, -6.64743e-02, 9.63798e-01, 1.18725e-01, -3.93735e-02, 1.19125e-02, -2.13733e-03 }, // 114/128
{ -2.43718e-03, 1.50233e-02, -6.23972e-02, 9.67477e-01, 1.09710e-01, -3.65541e-02, 1.10760e-02, -1.98880e-03 }, // 115/128
{ -2.26307e-03, 1.39681e-02, -5.82159e-02, 9.70992e-01, 1.00769e-01, -3.37303e-02, 1.02356e-02, -1.83931e-03 }, // 116/128
{ -2.08645e-03, 1.28947e-02, -5.39305e-02, 9.74342e-01, 9.19033e-02, -3.09033e-02, 9.39154e-03, -1.68894e-03 }, // 117/128
{ -1.90738e-03, 1.18034e-02, -4.95412e-02, 9.77526e-01, 8.31162e-02, -2.80746e-02, 8.54441e-03, -1.53777e-03 }, // 118/128
{ -1.72594e-03, 1.06946e-02, -4.50483e-02, 9.80543e-01, 7.44095e-02, -2.52457e-02, 7.69462e-03, -1.38589e-03 }, // 119/128
{ -1.54221e-03, 9.56876e-03, -4.04519e-02, 9.83392e-01, 6.57852e-02, -2.24178e-02, 6.84261e-03, -1.23337e-03 }, // 120/128
{ -1.35627e-03, 8.42626e-03, -3.57525e-02, 9.86071e-01, 5.72454e-02, -1.95925e-02, 5.98883e-03, -1.08030e-03 }, // 121/128
{ -1.16820e-03, 7.26755e-03, -3.09503e-02, 9.88580e-01, 4.87921e-02, -1.67710e-02, 5.13372e-03, -9.26747e-04 }, // 122/128
{ -9.78093e-04, 6.09305e-03, -2.60456e-02, 9.90917e-01, 4.04274e-02, -1.39548e-02, 4.27773e-03, -7.72802e-04 }, // 123/128
{ -7.86031e-04, 4.90322e-03, -2.10389e-02, 9.93082e-01, 3.21531e-02, -1.11453e-02, 3.42130e-03, -6.18544e-04 }, // 124/128
{ -5.92100e-04, 3.69852e-03, -1.59305e-02, 9.95074e-01, 2.39714e-02, -8.34364e-03, 2.56486e-03, -4.64053e-04 }, // 125/128
{ -3.96391e-04, 2.47942e-03, -1.07209e-02, 9.96891e-01, 1.58840e-02, -5.55134e-03, 1.70888e-03, -3.09412e-04 }, // 126/128
{ -1.98993e-04, 1.24642e-03, -5.41054e-03, 9.98534e-01, 7.89295e-03, -2.76968e-03, 8.53777e-04, -1.54700e-04 }, // 127/128
{ 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00 }, // 128/128
};
namespace gr {
namespace op25 {
fsk4_demod_ff::sptr
fsk4_demod_ff::make(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz)
{
return gnuradio::get_initial_sptr
(new fsk4_demod_ff_impl(queue, sample_rate_Hz, symbol_rate_Hz));
}
/*
* The private constructor
*/
fsk4_demod_ff_impl::fsk4_demod_ff_impl(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz)
: gr::block("fsk4_demod_ff",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(1, 1, sizeof(float))),
d_block_rate(sample_rate_Hz / symbol_rate_Hz),
d_history(new float[NTAPS]),
d_history_last(0),
d_queue(queue),
d_symbol_clock(0.0),
d_symbol_spread(2.0), // nominal symbol spread of 2.0 gives outputs at -3, -1, +1, +3
d_symbol_time(symbol_rate_Hz / sample_rate_Hz)
{
fine_frequency_correction = 0.0;
coarse_frequency_correction = 0.0;
std::fill(&d_history[0], &d_history[NTAPS], 0.0);
}
/*
* Our virtual destructor.
*/
fsk4_demod_ff_impl::~fsk4_demod_ff_impl()
{
}
void
fsk4_demod_ff_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
const int nof_samples_reqd = static_cast<int>(ceil(d_block_rate * noutput_items));
std::fill(&ninput_items_required[0], &ninput_items_required[ninput_items_required.size()], nof_samples_reqd);
}
int
fsk4_demod_ff_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
int n = 0;
const float *in = (const float *)input_items[0];
float *out = (float *)output_items[0];
// first we run through all provided data
for(int i = 0; i < noutput_items; i++) {
if(tracking_loop_mmse(in[i], &out[n])) {
++n;
}
}
// send frequency adjusment request if needed
send_frequency_correction();
consume_each (noutput_items);
// Tell runtime system how many output items we produced.
return n;
}
void
fsk4_demod_ff_impl::send_frequency_correction()
{
double arg1, arg2;
// if the queue is full, don't block, drop the data...
if(d_queue->full_p())
return;
const double COARSE_FREQUENCY_DEADBAND = 1.66; // gnuradio frequency adjust messages will not be emitted until we exceed this threshold
if((coarse_frequency_correction < COARSE_FREQUENCY_DEADBAND) && (coarse_frequency_correction > -COARSE_FREQUENCY_DEADBAND))
return;
arg1 = coarse_frequency_correction;
arg2 = 0.0;
coarse_frequency_correction = 0.0;
// build & send a message
gr::message::sptr msg = gr::message::make(0, arg1, arg2, 0); // vlen() * sizeof(float));
d_queue->insert_tail(msg);
msg.reset();
}
bool
fsk4_demod_ff_impl::tracking_loop_mmse(float input, float *output)
{
d_symbol_clock += d_symbol_time;
d_history[d_history_last++] = input;
d_history_last %= NTAPS;
if(d_symbol_clock > 1.0) {
d_symbol_clock -= 1.0;
// at this point we state that linear interpolation was tried
// but found to be slightly inferior. Using MMSE
// interpolation shouldn't be a terrible burden
#if 0
int imu = min(static_cast<int>(floor(0.5 + (NSTEPS * (d_symbol_clock / d_symbol_time)))), NSTEPS - 1);
int imu_p1 = imu + 1;
#else
int imu = (int) floor(0.5 + (NSTEPS * ((d_symbol_clock / d_symbol_time))));
int imu_p1 = imu + 1;
if (imu >= NSTEPS) {
imu = NSTEPS - 1;
imu_p1 = NSTEPS;
}
#endif
#if 0
double interp = 0.0;
double interp_p1 = 0.0;
for(size_t i = 0, j = d_history_last; i < NTAPS; ++i) {
interp += TAPS[imu][i] * d_history[j];
interp_p1 += TAPS[imu_p1][i] * d_history[j];
j = (j + 1) % NTAPS;
}
#else
size_t j = d_history_last;
double interp = 0.0;
double interp_p1 = 0.0;
for(int i=0; i<NTAPS; i++)
{
interp += TAPS[imu ][i] * d_history[j];
interp_p1 += TAPS[imu_p1][i] * d_history[j];
j = (j+1) % NTAPS;
}
#endif
// our output symbol will be interpolated value corrected for
// symbol_spread and frequency offset
interp -= fine_frequency_correction;
interp_p1 -= fine_frequency_correction;
// output is corrected for symbol deviation (spread)
*output = 2.0 * interp / d_symbol_spread;
// detect received symbol error: basically use a hard decision
// and subtract off expected position nominal symbol level
// which will be +/- 0.5 * symbol_spread and +/- 1.5 *
// symbol_spread remember: nominal symbol_spread will be 2.0
double symbol_error;
const double K_SYMBOL_SPREAD = 0.0100; // tracking loop gain constant
if(interp < - d_symbol_spread) {
// symbol is -3: Expected at -1.5 * symbol_spread
symbol_error = interp + (1.5 * d_symbol_spread);
d_symbol_spread -= (symbol_error * 0.5 * K_SYMBOL_SPREAD);
} else if(interp < 0.0) {
// symbol is -1: Expected at -0.5 * symbol_spread
symbol_error = interp + (0.5 * d_symbol_spread);
d_symbol_spread -= (symbol_error * K_SYMBOL_SPREAD);
} else if(interp < d_symbol_spread) {
// symbol is +1: Expected at +0.5 * symbol_spread
symbol_error = interp - (0.5 * d_symbol_spread);
d_symbol_spread += (symbol_error * K_SYMBOL_SPREAD);
} else {
// symbol is +3: Expected at +1.5 * symbol_spread
symbol_error = interp - (1.5 * d_symbol_spread);
d_symbol_spread += (symbol_error * 0.5 * K_SYMBOL_SPREAD);
}
// symbol clock tracking loop gain
const double K_SYMBOL_TIMING = 0.025;
if(interp_p1 < interp) {
d_symbol_clock += symbol_error * K_SYMBOL_TIMING;
} else {
d_symbol_clock -= symbol_error * K_SYMBOL_TIMING;
}
// constraints on symbol spreading
const double SYMBOL_SPREAD_MAX = 2.4; // upper range limit: +20%
const double SYMBOL_SPREAD_MIN = 1.6; // lower range limit: -20%
// it seems reasonable to constrain symbol spread to +/- 20%
// of nominal 2.0
d_symbol_spread = std::max(d_symbol_spread, SYMBOL_SPREAD_MIN);
d_symbol_spread = std::min(d_symbol_spread, SYMBOL_SPREAD_MAX);
// coarse tracking loop: for eventually frequency shift
// request generation
static const double K_COARSE_FREQUENCY = 0.00125; // time constant for coarse tracking loop
coarse_frequency_correction += ((fine_frequency_correction - coarse_frequency_correction) * K_COARSE_FREQUENCY);
// fine loop
static const double K_FINE_FREQUENCY = 0.125; // internal fast loop (must be this high to acquire symbol sync)
fine_frequency_correction += (symbol_error * K_FINE_FREQUENCY);
return true;
}
return false;
}
} /* namespace op25 */
} /* namespace gr */

View File

@ -0,0 +1,72 @@
/* -*- c++ -*- */
/*
* Copyright 2006, 2007 Frank (Radio Rausch)
* Copyright 2011 Steve Glass
*
* This file is part of OP25.
*
* 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_OP25_FSK4_DEMOD_FF_IMPL_H
#define INCLUDED_OP25_FSK4_DEMOD_FF_IMPL_H
#include <op25/fsk4_demod_ff.h>
namespace gr {
namespace op25 {
class fsk4_demod_ff_impl : public fsk4_demod_ff
{
private:
const float d_block_rate;
boost::scoped_array<float> d_history;
size_t d_history_last;
gr::msg_queue::sptr d_queue;
double d_symbol_clock;
double d_symbol_spread;
const float d_symbol_time;
double fine_frequency_correction;
double coarse_frequency_correction;
/**
* Called when we want the input frequency to be adjusted.
*/
void send_frequency_correction();
/**
* Tracking loop.
*/
bool tracking_loop_mmse(float input, float *output);
public:
fsk4_demod_ff_impl(gr::msg_queue::sptr queue, float sample_rate_Hz, float symbol_rate_Hz);
~fsk4_demod_ff_impl();
// Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
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 op25
} // namespace gr
#endif /* INCLUDED_OP25_FSK4_DEMOD_FF_IMPL_H */

View File

@ -0,0 +1,94 @@
/* -*- c++ -*- */
/*
* Copyright 2010, KA1RBI
*
* This file is part of OP25.
*
* 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 "fsk4_slicer_fb_impl.h"
namespace gr {
namespace op25 {
fsk4_slicer_fb::sptr
fsk4_slicer_fb::make(const std::vector<float> &slice_levels)
{
return gnuradio::get_initial_sptr
(new fsk4_slicer_fb_impl(slice_levels));
}
/*
* The private constructor
*/
fsk4_slicer_fb_impl::fsk4_slicer_fb_impl(const std::vector<float> &slice_levels)
: gr::sync_block("fsk4_slicer_fb",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(1, 1, sizeof(unsigned char)))
{
d_slice_levels[0] = slice_levels[0];
d_slice_levels[1] = slice_levels[1];
d_slice_levels[2] = slice_levels[2];
d_slice_levels[3] = slice_levels[3];
}
/*
* Our virtual destructor.
*/
fsk4_slicer_fb_impl::~fsk4_slicer_fb_impl()
{
}
int
fsk4_slicer_fb_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
for(int i = 0; i < noutput_items; i++){
uint8_t dibit;
float sym = in[i];
if(d_slice_levels[3] < 0) {
dibit = 1;
if(d_slice_levels[3] <= sym && sym < d_slice_levels[0])
dibit = 3;
} else {
dibit = 3;
if(d_slice_levels[2] <= sym && sym < d_slice_levels[3])
dibit = 1;
}
if(d_slice_levels[0] <= sym && sym < d_slice_levels[1])
dibit = 2;
if(d_slice_levels[1] <= sym && sym < d_slice_levels[2])
dibit = 0;
out[i] = dibit;
}
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace op25 */
} /* namespace gr */

View File

@ -0,0 +1,50 @@
/* -*- c++ -*- */
/*
* Copyright 2010 KA1RBI
*
* This file is part of OP25.
*
* 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_OP25_FSK4_SLICER_FB_IMPL_H
#define INCLUDED_OP25_FSK4_SLICER_FB_IMPL_H
#include <op25/fsk4_slicer_fb.h>
namespace gr {
namespace op25 {
class fsk4_slicer_fb_impl : public fsk4_slicer_fb
{
private:
float d_slice_levels[4];
public:
fsk4_slicer_fb_impl(const std::vector<float> &slice_levels);
~fsk4_slicer_fb_impl();
// Where all the action really happens
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_FSK4_SLICER_FB_IMPL_H */

225
op25/gr-op25/lib/hdu.cc Normal file
View File

@ -0,0 +1,225 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "hdu.h"
#include "op25_yank.h"
#include "pickle.h"
#include "value_string.h"
#include <iomanip>
#include <sstream>
using namespace std;
hdu::hdu(const_bit_queue& frame_body) :
abstract_data_unit(frame_body)
{
}
hdu::~hdu()
{
}
string
hdu::duid_str() const
{
return string("HDU");
}
std::string
hdu::snapshot() const
{
pickle p;
p.add("duid", duid_str());
p.add("nac", nac_str());
p.add("mfid", mfid_str());
p.add("algid", algid_str());
p.add("kid", kid_str());
p.add("mi", mi_str());
p.add("tgid", tgid_str());
return p.to_string();
}
void
hdu::do_correct_errors(bit_vector& frame)
{
apply_golay_correction(frame);
apply_rs_correction(frame);
}
void
hdu::apply_golay_correction(bit_vector& frame)
{
static const size_t NOF_GOLAY_CODEWORDS = 36, GOLAY_CODEWORD_SZ = 18;
static const size_t GOLAY_CODEWORDS[NOF_GOLAY_CODEWORDS][GOLAY_CODEWORD_SZ] = {
{ 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131 },
{ 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 148, 149, 150, 151 },
{ 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169 },
{ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187 },
{ 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205 },
{ 206, 207, 208, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225 },
{ 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243 },
{ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261 },
{ 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279 },
{ 280, 281, 282, 283, 284, 285, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299 },
{ 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317 },
{ 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335 },
{ 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353 },
{ 354, 355, 356, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373 },
{ 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391 },
{ 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409 },
{ 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427 },
{ 428, 429, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447 },
{ 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465 },
{ 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483 },
{ 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501 },
{ 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521 },
{ 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539 },
{ 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557 },
{ 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 576, 577 },
{ 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595 },
{ 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613 },
{ 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631 },
{ 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 648, 649, 650, 651 },
{ 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669 },
{ 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687 },
{ 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705 },
{ 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 720, 721, 722, 723, 724, 725 },
{ 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743 },
{ 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761 },
{ 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779 }
};
for(size_t i = 0; i < NOF_GOLAY_CODEWORDS; ++i) {
uint32_t cw = extract(frame, GOLAY_CODEWORDS[i], GOLAY_CODEWORD_SZ);
// uint32_t d = golay_decode(cw);
// uint32 cw = golay_encode(cw);
// yank_back(d, PAD_SZ, frame, GOLAY_CODEWORDS[i], GOLAY_DATA_SZ);
}
}
void
hdu::apply_rs_correction(bit_vector& frame)
{
#if 0
static itpp::Reed_Solomon rs(6, 8, true);
const size_t rs_codeword[][6] = {
};
const size_t nof_codeword_bits = sizeof(codeword_bits) / sizeof(codeword_bits[0]);
#endif
}
uint16_t
hdu::frame_size_max() const
{
return 792;
}
string
hdu::algid_str() const
{
const size_t ALGID_BITS[] = {
356, 357, 360, 361, 374, 375, 376, 377
};
const size_t ALGID_BITS_SZ = sizeof(ALGID_BITS) / sizeof(ALGID_BITS[0]);
uint8_t algid = extract(frame_body(), ALGID_BITS, ALGID_BITS_SZ);
return lookup(algid, ALGIDS, ALGIDS_SZ);
}
string
hdu::kid_str() const
{
const size_t KID_BITS[] = {
378, 379, 392, 393, 394, 395, 396, 397,
410, 411, 412, 413, 414, 415, 428, 429
};
const size_t KID_BITS_SZ = sizeof(KID_BITS) / sizeof(KID_BITS[0]);
uint16_t kid = extract(frame_body(), KID_BITS, KID_BITS_SZ);
ostringstream os;
os << hex << showbase << setfill('0') << setw(4) << kid;
return os.str();
}
std::string
hdu::mi_str() const
{
const size_t MI_BITS[] = {
114, 115, 116, 117, 118, 119, 132, 133,
134, 135, 136, 137, 152, 153, 154, 155,
156, 157, 170, 171, 172, 173, 174, 175,
188, 189, 190, 191, 192, 193, 206, 207,
208, 209, 210, 211, 226, 227, 228, 229,
230, 231, 244, 245, 246, 247, 248, 249,
262, 263, 264, 265, 266, 267, 280, 281,
282, 283, 284, 285, 300, 301, 302, 303,
304, 305, 318, 319, 320, 321, 322, 323,
};
const size_t MI_BITS_SZ = sizeof(MI_BITS) / sizeof(MI_BITS[0]);
uint8_t mi[9];
extract(frame_body(), MI_BITS, MI_BITS_SZ, mi);
ostringstream os;
os << "0x";
for(size_t i = 0; i < (sizeof(mi) / sizeof(mi[0])); ++i) {
uint16_t octet = mi[i];
os << hex << setfill('0') << setw(2) << octet;
}
return os.str();
}
string
hdu::mfid_str() const
{
const size_t MFID_BITS[] = {
336, 337, 338, 339, 340, 341, 354, 355
};
const size_t MFID_BITS_SZ = sizeof(MFID_BITS) / sizeof(MFID_BITS_SZ);
uint8_t mfid = extract(frame_body(), MFID_BITS, MFID_BITS_SZ);
return lookup(mfid, MFIDS, MFIDS_SZ);
}
string
hdu::nac_str() const
{
const size_t NAC_BITS[] = {
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59
};
const size_t NAC_BITS_SZ = sizeof(NAC_BITS) / sizeof(NAC_BITS[0]);
uint32_t nac = extract(frame_body(), NAC_BITS, NAC_BITS_SZ);
return lookup(nac, NACS, NACS_SZ);
}
string
hdu::tgid_str() const
{
const size_t TGID_BITS[] = {
432, 433, 434, 435, 448, 449, 450, 451,
452, 453, 466, 467, 468, 469, 470, 471
};
const size_t TGID_BITS_SZ = sizeof(TGID_BITS) / sizeof(TGID_BITS[0]);
const uint16_t tgid = extract(frame_body(), TGID_BITS, TGID_BITS_SZ);
ostringstream os;
os << hex << showbase << setfill('0') << setw(4) << tgid;
return os.str();
}

144
op25/gr-op25/lib/hdu.h Normal file
View File

@ -0,0 +1,144 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_HDU_H
#define INCLUDED_HDU_H
#include "abstract_data_unit.h"
/**
* P25 header data unit (HDU).
*/
class hdu : public abstract_data_unit
{
public:
/**
* hdu constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
*/
hdu(const_bit_queue& frame_body);
/**
* hdu virtual destructor.
*/
virtual ~hdu();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
/**
* Return a snapshot of the key fields from this frame in a manner
* suitable for display by the UI. The string is encoded as a
* pickled Python dictionary.
*
* \return A string containing the fields to display.
*/
virtual std::string snapshot() const;
protected:
/**
* Applies error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void do_correct_errors(bit_vector& frame_body);
/**
* Apply Golay error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void apply_golay_correction(bit_vector& frame_body);
/**
* Apply Reed-Solomon error correction code to the specified
* bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void apply_rs_correction(bit_vector& frame_body);
/**
* Returns the expected size (in bits) of this data unit in
* bits. For variable-length data this should return UINT16_MAX
* until the actual length of this frame is known.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const;
private:
/**
* Return a string describing the encryption algorithm ID (ALGID).
*
* \return A string identifying the ALGID.
*/
std::string algid_str() const;
/**
* Returns a string describing the key id (KID).
*
* \return A string identifying the KID.
*/
virtual std::string kid_str() const;
/**
* Returns a string describing the manufacturer ID (MFID).
*
* \return A string identifying the MFID
*/
virtual std::string mfid_str() const;
/**
* Returns a string describing the message indicator (MI).
*
* \return A string identifying the MI.
*/
virtual std::string mi_str() const;
/**
* Returns a string describing the Network Access Code (NAC).
*
* \return A string identifying the NAC.
*/
virtual std::string nac_str() const;
/**
* Returns a string describing the talk group id (TGID).
*
* \return A string identifying the TGID.
*/
virtual std::string tgid_str() const;
};
#endif /* INCLUDED_HDU_H */

View File

@ -0,0 +1,16 @@
#include "imbe_decoder.h"
imbe_decoder::~imbe_decoder()
{
}
imbe_decoder::imbe_decoder() :
d_audio()
{
}
audio_samples*
imbe_decoder::audio()
{
return &d_audio;
}

View File

@ -0,0 +1,90 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_IMBE_DECODER_H
#define INCLUDED_IMBE_DECODER_H
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <deque>
#include <vector>
typedef std::deque<float> audio_samples;
typedef std::vector<bool> voice_codeword;
typedef boost::shared_ptr<class imbe_decoder> imbe_decoder_sptr;
/**
* imbe_decoder is the interface to the various mechanisms for
* translating P25 voice codewords into audio samples.
*/
class imbe_decoder : public boost::noncopyable {
public:
/**
* imbe_decoder (virtual) constructor. The exact subclass
* instantiated depends on some yet-to-be-decided magic.
*
* \return A shared_ptr to an imbe_decoder.
*/
static imbe_decoder_sptr make();
/**
* imbe_decoder (virtual) destructor.
*/
virtual ~imbe_decoder();
/**
* Decode the compressed IMBE audio.
*
* \param cw IMBE codeword (including parity check bits).
*/
virtual void decode(const voice_codeword& cw) = 0;
/**
* Returns the audio_samples samples. These are mono samples at
* 8KS/s represented as a float in the range -1.0 .. +1.0.
*
* \return A non-null pointer to a deque<float> of audio samples.
*/
audio_samples *audio();
protected:
/**
* Construct an instance of imbe_decoder. Access is protected
* because this is an abstract class and users should call
* make_imbe_decoder to construct concrete instances.
*/
imbe_decoder();
private:
/**
* The audio samples produced by the IMBE decoder.
*/
audio_samples d_audio;
};
#endif /* INCLUDED_IMBE_DECODER_H */

View File

@ -0,0 +1,29 @@
#include "dummy_imbe_decoder.h"
#include "imbe_decoder.h"
#include "offline_imbe_decoder.h"
#include "software_imbe_decoder.h"
#include "vc55_imbe_decoder.h"
#include <cstdlib>
#include <cstring>
imbe_decoder_sptr
imbe_decoder::make()
{
imbe_decoder_sptr imbe;
const char *imbe_type = getenv("IMBE");
if(imbe_type) {
if(strcasecmp(imbe_type, "offline") == 0) {
imbe = imbe_decoder_sptr(new offline_imbe_decoder());
} else if(strcasecmp(imbe_type, "soft") == 0) {
imbe = imbe_decoder_sptr(new software_imbe_decoder());
} else if(strcasecmp(imbe_type, "vc55") == 0) {
imbe = imbe_decoder_sptr(new vc55_imbe_decoder());
} else {
imbe = imbe_decoder_sptr(new dummy_imbe_decoder());
}
} else {
imbe = imbe_decoder_sptr(new software_imbe_decoder());
}
return imbe;
}

41
op25/gr-op25/lib/ldu1.cc Normal file
View File

@ -0,0 +1,41 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "ldu1.h"
using std::string;
ldu1::ldu1(const_bit_queue& frame_body) :
voice_data_unit(frame_body)
{
}
ldu1::~ldu1()
{
}
string
ldu1::duid_str() const
{
return string("LDU1");
}

55
op25/gr-op25/lib/ldu1.h Normal file
View File

@ -0,0 +1,55 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_LDU1_H
#define INCLUDED_LDU1_H
#include "voice_data_unit.h"
/**
* P25 Logical Data Unit 1.
*/
class ldu1 : public voice_data_unit
{
public:
/**
* ldu1 constuctor
*
* \param frame_body A const_bit_queue representing the frame body.
*/
ldu1(const_bit_queue& frame_body);
/**
* ldu1 (virtual) destuctor
*/
virtual ~ldu1();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
};
#endif /* INCLUDED_LDU1_H */

41
op25/gr-op25/lib/ldu2.cc Normal file
View File

@ -0,0 +1,41 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "ldu2.h"
using std::string;
ldu2::ldu2(const_bit_queue& frame_body) :
voice_data_unit(frame_body)
{
}
ldu2::~ldu2()
{
}
string
ldu2::duid_str() const
{
return string("LDU2");
}

54
op25/gr-op25/lib/ldu2.h Normal file
View File

@ -0,0 +1,54 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_LDU2_H
#define INCLUDED_LDU2_H
#include "voice_data_unit.h"
/**
* P25 Logical Data Unit 2.
*/
class ldu2 : public voice_data_unit
{
public:
/**
* ldu2 constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
*/
ldu2(const_bit_queue& frame_body);
/**
* ldu2 (virtual) destructor.
*/
virtual ~ldu2();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
};
#endif /* INCLUDED_LDU2_H */

View File

@ -0,0 +1,48 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "logfile_du_handler.h"
#include <iomanip>
#include <stdint.h>
using namespace std;
logfile_du_handler::logfile_du_handler(data_unit_handler_sptr next, const char *filename) :
data_unit_handler(next),
d_log(filename)
{
}
logfile_du_handler::~logfile_du_handler()
{
d_log.flush();
d_log.close();
}
void
logfile_du_handler::handle(data_unit_sptr du)
{
du->dump(d_log);
data_unit_handler::handle(du);
}

View File

@ -0,0 +1,69 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_LOGFILE_DU_HANDLER_H
#define INCLUDED_LOGFILE_DU_HANDLER_H
#include "data_unit_handler.h"
#include <boost/noncopyable.hpp>
#include <fstream>
/**
* logfile_data_unit_handler writes frames to a log file for later inspection.
*/
class logfile_du_handler : public data_unit_handler
{
public:
/**
* logfile_du_handler constructor.
*
* \param next The next data_unit_handler in the chain.
* \param filename The path to the log file.
*/
logfile_du_handler(data_unit_handler_sptr next, const char *filename);
/**
* logfile_du_handler virtual destructor.
*/
virtual ~logfile_du_handler();
/**
* Handle a received P25 frame.
*
* \param next The next data_unit_handler in this chain.
*/
virtual void handle(data_unit_sptr du);
private:
/**
* The file to which decoded frames are written.
*/
std::ofstream d_log;
};
#endif /* INCLUDED_LOGFILE_DU_HANDLER_H */

View File

@ -0,0 +1,64 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "offline_imbe_decoder.h"
#include "stdint.h"
#include "op25_yank.h"
#include <cstdio>
using namespace std;
offline_imbe_decoder::offline_imbe_decoder()
{
const char *dev = getenv("IMBE_FILE");
if(!dev) {
const char *default_filename = "imbe.dat";
dev = default_filename;
}
d_fp = fopen(dev, "w");
if(NULL == d_fp) {
perror("fopen(dev, \"w\");"); // a warning, not an error
}
}
offline_imbe_decoder::~offline_imbe_decoder()
{
if(d_fp) {
fclose(d_fp);
}
}
void
offline_imbe_decoder::decode(const voice_codeword& cw)
{
if(d_fp) {
uint8_t codewords[18];
extract(cw, 0, 144, codewords);
if(0 == fwrite(codewords, sizeof(codewords), 1, d_fp)) {
perror("fwrite(codewords, sizeof(codewords), 1, d_fp)");
fclose(d_fp);
d_fp = NULL;
}
}
}

View File

@ -0,0 +1,64 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_OFFLINE_IMBE_DECODER_H
#define INCLUDED_OFFLINE_IMBE_DECODER_H
#include "imbe_decoder.h"
#include <cstdio>
/**
* offline_imbe_decoder dumps voice codewords to file for offline decoding.
*
*/
class offline_imbe_decoder : public imbe_decoder {
public:
/**
* offline_imbe_decoder default constructor.
*/
offline_imbe_decoder();
/**
* offline_imbe_decoder (virtual) destructor.
*/
virtual ~offline_imbe_decoder();
/**
* Dump voice_codeword in_out to file.
*
* \param cw IMBE codewords and parity.
*/
virtual void decode(const voice_codeword& cw);
private:
/**
* The output file.
*/
FILE *d_fp;
};
#endif /* INCLUDED_OFFLINE_IMBE_DECODER_H */

113
op25/gr-op25/lib/op25.i Normal file
View File

@ -0,0 +1,113 @@
/* -*- C++ -*- */
%feature("autodoc", "1");
%{
#include <stddef.h>
%}
%include "exception.i"
%import "gnuradio.i"
%{
#include "gnuradio/swig/gnuradio_swig_bug_workaround.h"
#include "op25_fsk4_demod_ff.h"
#include "op25_fsk4_slicer_fb.h"
#include "op25_decoder_bf.h"
#include "op25_pcap_source_b.h"
%}
// ----------------------------------------------------------------
/*
* This does some behind-the-scenes magic so we can
* access fsk4_square_ff from python as fsk4.square_ff
*/
GR_SWIG_BLOCK_MAGIC(op25, fsk4_demod_ff);
/*
* Publicly-accesible default constuctor function for op25_fsk4_demod_bf.
*/
op25_fsk4_demod_ff_sptr op25_make_fsk4_demod_ff(gr::msg_queue::sptr queue, float sample_rate, float symbol_rate);
class op25_fsk4_demod_ff : public gr_block
{
private:
op25_fsk4_demod_ff(gr::msg_queue::sptr queue, float sample_rate, float symbol_rate);
};
// ----------------------------------------------------------------
/*
* This does some behind-the-scenes magic so we can invoke
* op25_make_slicer_fb from python as op25.slicer_fbf.
*/
GR_SWIG_BLOCK_MAGIC(op25, fsk4_slicer_fb);
/*
* Publicly-accesible default constuctor function for op25_decoder_bf.
*/
op25_fsk4_slicer_fb_sptr op25_make_fsk4_slicer_fb(const std::vector<float> &slice_levels);
/*
* The op25_fsk4_slicer block. Takes a series of float samples and
* partitions them into dibit symbols according to the slices_levels
* provided to the constructor.
*/
class op25_fsk4_slicer_fb : public gr_sync_block
{
private:
op25_fsk4_slicer_fb (const std::vector<float> &slice_levels);
};
// ----------------------------------------------------------------
/*
* This does some behind-the-scenes magic so we can invoke
* op25_make_decoder_bsf from python as op25.decoder_bf.
*/
GR_SWIG_BLOCK_MAGIC(op25, decoder_bf);
/*
* Publicly-accesible default constuctor function for op25_decoder_bf.
*/
op25_decoder_bf_sptr op25_make_decoder_bf();
/**
* The op25_decoder_bf block. Accepts a stream of dibit symbols and
* produces an 8KS/s audio stream.
*/
class op25_decoder_bf : public gr_block
{
private:
op25_decoder_bf();
public:
const char *destination() const;
gr::msg_queue::sptr get_msgq() const;
void set_msgq(gr::msg_queue::sptr msgq);
};
// ----------------------------------------------------------------
/*
* This does some behind-the-scenes magic so we can invoke
* op25_make_pcap_source_b from python as op25.pcap_source_b.
*/
GR_SWIG_BLOCK_MAGIC(op25, pcap_source_b);
/*
* Publicly-accesible constuctor function for op25_pcap_source.
*/
op25_pcap_source_b_sptr op25_make_pcap_source_b(const char *path, float delay);
/*
* The op25_pcap_source block. Reads symbols from a tcpdump-formatted
* file and produces a stream of symbols of the appropriate size.
*/
class op25_pcap_source_b : public gr_sync_block
{
private:
op25_pcap_source_b(const char *path, float delay);
};
// ----------------------------------------------------------------

View File

@ -0,0 +1,206 @@
#ifndef INCLUDED_OP25_GOLAY_H
#define INCLUDED_OP25_GOLAY_H
#include <cstddef>
#include <stdint.h>
static inline uint32_t
golay_24_encode(uint32_t code_word_in)
{
static const uint32_t encoding[12] = {
040006165,
020003073,
010007550,
04003664,
02001732,
01006631,
0403315,
0201547,
0106706,
045227,
024476,
014353
};
uint32_t code_word_out = 0;
for(uint16_t i = 0; i < 12; i++) {
uint32_t temp_word = code_word_in & (1 << (11 - i));
if(temp_word >= 1) {
code_word_out = code_word_out ^ encoding[i];
}
}
return(code_word_out);
}
/* APCO Golay(23,11,7) ecoder.
*
* \param val The 12-bit value to encode.
* \return The encoded codeword.
*/
static inline uint32_t
golay_23_encode(uint32_t code_word_in)
{
return golay_24_encode(code_word_in) >> 1;
}
static inline uint32_t
golay_23_syndrome(uint32_t pattern)
{
uint32_t aux = 0x400000;
while(pattern & 0xFFFFF800) {
while((aux & pattern) == 0) {
aux >>= 1;
}
pattern ^= (aux >> 11) * 0xC75;
}
return pattern;
}
/* APCO Golay(23,11,7) decoder.
*
* \param cw The 23-bit codeword to decode.
* \return The number of errors detected.
*/
static inline size_t
golay_23_decode(uint32_t& cw)
{
static const uint32_t decoding[2048] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 147459,
1, 2, 2, 3, 2, 3, 3, 4268035, 2, 3, 3, 1574915, 3, 2097155, 294915, 4099,
1, 2, 2, 3, 2, 3, 3, 147459, 2, 3, 3, 147459, 3, 147459, 147459, 147458,
2, 3, 3, 32771, 3, 2051, 3149827, 786435, 3, 274435, 4194307, 2162691, 589827, 5275651, 10243, 147459,
1, 2, 2, 3, 2, 3, 3, 2621443, 2, 3, 3, 8195, 3, 1118211, 294915, 4196355,
2, 3, 3, 135171, 3, 2051, 294915, 1064963, 3, 4210691, 294915, 2162691, 294915, 663555, 294914, 294915,
2, 3, 3, 5505027, 3, 2051, 65539, 45059, 3, 557059, 6147, 2162691, 6299651, 262147, 1572867, 147459,
3, 2051, 548867, 2162691, 2051, 2050, 4325379, 2051, 1179651, 2162691, 2162691, 2162690, 20483, 2051, 294915, 2162691,
1, 2, 2, 3, 2, 3, 3, 2621443, 2, 3, 3, 327683, 3, 43011, 5242883, 4099,
2, 3, 3, 32771, 3, 1441795, 18435, 4099, 3, 4210691, 2236419, 4099, 589827, 4099, 4099, 4098,
2, 3, 3, 32771, 3, 4198403, 270339, 1116163, 3, 3145731, 6147, 4726787, 589827, 262147, 2129923, 147459,
3, 32771, 32771, 32770, 589827, 2121731, 4325379, 32771, 589827, 133123, 1327107, 32771, 589826, 589827, 589827, 4099,
2, 3, 3, 2621443, 3, 2621443, 2621443, 2621442, 3, 4210691, 6147, 1212419, 131075, 262147, 90115, 2621443,
3, 4210691, 1114115, 272387, 12291, 98307, 4325379, 2621443, 4210691, 4210690, 524291, 4210691, 3147779, 4210691, 294915, 4099,
3, 204803, 6147, 16387, 1097731, 262147, 4325379, 2621443, 6147, 262147, 6146, 6147, 262147, 262146, 6147, 262147,
2359299, 1576963, 4325379, 32771, 4325379, 2051, 4325378, 4325379, 40963, 4210691, 6147, 2162691, 589827, 262147, 4325379, 1056771,
1, 2, 2, 3, 2, 3, 3, 268291, 2, 3, 3, 8195, 3, 2097155, 5242883, 622595,
2, 3, 3, 32771, 3, 2097155, 655363, 1064963, 3, 2097155, 86019, 4587523, 2097155, 2097154, 10243, 2097155,
2, 3, 3, 32771, 3, 1581059, 65539, 6291459, 3, 4261891, 2883587, 1052675, 36867, 262147, 10243, 147459,
3, 32771, 32771, 32770, 4472835, 200707, 10243, 32771, 1179651, 540675, 10243, 32771, 10243, 2097155, 10242, 10243,
2, 3, 3, 8195, 3, 4358147, 65539, 1064963, 3, 8195, 8195, 8194, 542723, 262147, 2232323, 8195,
3, 851971, 6293507, 1064963, 12291, 1064963, 1064963, 1064962, 1179651, 38915, 524291, 8195, 4259843, 2097155, 294915, 1064963,
3, 2117635, 65539, 657411, 65539, 262147, 65538, 65539, 1179651, 262147, 4243459, 8195, 262147, 262146, 65539, 262147,
1179651, 4202499, 266243, 32771, 2654211, 2051, 65539, 1064963, 1179650, 1179651, 1179651, 2162691, 1179651, 262147, 10243, 4722691,
2, 3, 3, 32771, 3, 81923, 5242883, 139267, 3, 659459, 5242883, 2115587, 5242883, 262147, 5242882, 5242883,
3, 32771, 32771, 32770, 12291, 4720643, 2424835, 32771, 264195, 1122307, 524291, 32771, 180227, 2097155, 5242883, 4099,
3, 32771, 32771, 32770, 2230275, 262147, 544771, 32771, 24579, 262147, 196611, 32771, 262147, 262146, 5242883, 262147,
32771, 32770, 32770, 32769, 1048579, 32771, 32771, 32770, 6295555, 32771, 32771, 32770, 589827, 262147, 10243, 32771,
3, 1050627, 409603, 4263939, 12291, 262147, 34819, 2621443, 2195459, 262147, 524291, 8195, 262147, 262146, 5242883, 262147,
12291, 2228227, 524291, 32771, 12290, 12291, 12291, 1064963, 524291, 4210691, 524290, 524291, 12291, 262147, 524291, 198659,
4718595, 262147, 3153923, 32771, 262147, 262146, 65539, 262147, 262147, 262146, 6147, 262147, 262146, 262145, 262147, 262146,
83971, 32771, 32771, 32770, 12291, 262147, 4325379, 32771, 1179651, 262147, 524291, 32771, 262147, 262146, 2113539, 262147,
1, 2, 2, 3, 2, 3, 3, 1081347, 2, 3, 3, 327683, 3, 2097155, 536579, 4196355,
2, 3, 3, 135171, 3, 2097155, 18435, 786435, 3, 2097155, 4194307, 57347, 2097155, 2097154, 1245187, 2097155,
2, 3, 3, 2107395, 3, 4198403, 65539, 786435, 3, 557059, 4194307, 1052675, 1312771, 73731, 2129923, 147459,
3, 1130499, 4194307, 786435, 172035, 786435, 786435, 786434, 4194307, 133123, 4194306, 4194307, 20483, 2097155, 4194307, 786435,
2, 3, 3, 135171, 3, 286723, 65539, 4196355, 3, 557059, 3162115, 4196355, 131075, 4196355, 4196355, 4196354,
3, 135171, 135171, 135170, 5767171, 98307, 2105347, 135171, 75779, 1310723, 524291, 135171, 20483, 2097155, 294915, 4196355,
3, 557059, 65539, 16387, 65539, 3276803, 65538, 65539, 557059, 557058, 401411, 557059, 20483, 557059, 65539, 4196355,
2359299, 4202499, 1083395, 135171, 20483, 2051, 65539, 786435, 20483, 557059, 4194307, 2162691, 20482, 20483, 20483, 1056771,
2, 3, 3, 327683, 3, 4198403, 18435, 139267, 3, 327683, 327683, 327682, 131075, 1589251, 2129923, 327683,
3, 532483, 18435, 7340035, 18435, 98307, 18434, 18435, 1085443, 133123, 524291, 327683, 4464643, 2097155, 18435, 4099,
3, 4198403, 1703939, 16387, 4198403, 4198402, 2129923, 4198403, 24579, 133123, 2129923, 327683, 2129923, 4198403, 2129922, 2129923,
2359299, 133123, 77827, 32771, 1048579, 4198403, 18435, 786435, 133123, 133122, 4194307, 133123, 589827, 133123, 2129923, 1056771,
3, 1050627, 4235267, 16387, 131075, 98307, 1314819, 2621443, 131075, 2109443, 524291, 327683, 131074, 131075, 131075, 4196355,
2359299, 98307, 524291, 135171, 98307, 98306, 18435, 98307, 524291, 4210691, 524290, 524291, 131075, 98307, 524291, 1056771,
2359299, 16387, 16387, 16386, 534531, 4198403, 65539, 16387, 5308419, 557059, 6147, 16387, 131075, 262147, 2129923, 1056771,
2359298, 2359299, 2359299, 16387, 2359299, 98307, 4325379, 1056771, 2359299, 133123, 524291, 1056771, 20483, 1056771, 1056771, 1056770,
2, 3, 3, 4734979, 3, 2097155, 65539, 139267, 3, 2097155, 165891, 1052675, 2097155, 2097154, 278531, 2097155,
3, 2097155, 1318915, 67587, 2097155, 2097154, 4231171, 2097155, 2097155, 2097154, 524291, 2097155, 2097154, 2097153, 2097155, 2097154,
3, 393219, 65539, 1052675, 65539, 51203, 65538, 65539, 24579, 1052675, 1052675, 1052674, 4849667, 2097155, 65539, 1052675,
530435, 4202499, 2244611, 32771, 1048579, 2097155, 65539, 786435, 360451, 2097155, 4194307, 1052675, 2097155, 2097154, 10243, 2097155,
3, 1050627, 65539, 2392067, 65539, 528387, 65538, 65539, 4460547, 212995, 524291, 8195, 1089539, 2097155, 65539, 4196355,
49155, 4202499, 524291, 135171, 395267, 2097155, 65539, 1064963, 524291, 2097155, 524290, 524291, 2097155, 2097154, 524291, 2097155,
65539, 4202499, 65538, 65539, 65538, 65539, 65537, 65538, 2099203, 557059, 65539, 1052675, 65539, 262147, 65538, 65539,
4202499, 4202498, 65539, 4202499, 65539, 4202499, 65538, 65539, 1179651, 4202499, 524291, 280579, 20483, 2097155, 65539, 163843,
3, 1050627, 2101251, 139267, 819203, 139267, 139267, 139266, 24579, 4227075, 524291, 327683, 71683, 2097155, 5242883, 139267,
4390915, 282627, 524291, 32771, 1048579, 2097155, 18435, 139267, 524291, 2097155, 524290, 524291, 2097155, 2097154, 524291, 2097155,
24579, 2686979, 4458499, 32771, 1048579, 4198403, 65539, 139267, 24578, 24579, 24579, 1052675, 24579, 262147, 2129923, 526339,
1048579, 32771, 32771, 32770, 1048578, 1048579, 1048579, 32771, 24579, 133123, 524291, 32771, 1048579, 2097155, 397315, 4276227,
1050627, 1050626, 524291, 1050627, 6307843, 1050627, 65539, 139267, 524291, 1050627, 524290, 524291, 131075, 262147, 524291, 53251,
524291, 1050627, 524290, 524291, 12291, 98307, 524291, 4456451, 524290, 524291, 524289, 524290, 524291, 2097155, 524290, 524291,
167939, 1050627, 65539, 16387, 65539, 262147, 65538, 65539, 24579, 262147, 524291, 6422531, 262147, 262146, 65539, 262147,
2359299, 4202499, 524291, 32771, 1048579, 671747, 65539, 2103299, 524291, 69635, 524290, 524291, 4229123, 262147, 524291, 1056771,
1, 2, 2, 3, 2, 3, 3, 1081347, 2, 3, 3, 8195, 3, 4980739, 2164739, 4099,
2, 3, 3, 2375683, 3, 2051, 655363, 4099, 3, 229379, 4194307, 4099, 1073155, 4099, 4099, 4098,
2, 3, 3, 593923, 3, 2051, 270339, 6291459, 3, 3145731, 4194307, 296963, 36867, 73731, 1572867, 147459,
3, 2051, 4194307, 1187843, 2051, 2050, 114691, 2051, 4194307, 540675, 4194306, 4194307, 2490371, 2051, 4194307, 4099,
2, 3, 3, 8195, 3, 2051, 4214787, 458755, 3, 8195, 8195, 8194, 131075, 2146307, 1572867, 8195,
3, 2051, 1114115, 4751363, 2051, 2050, 2105347, 2051, 2625539, 1310723, 149507, 8195, 4259843, 2051, 294915, 4099,
3, 2051, 2260995, 16387, 2051, 2050, 1572867, 2051, 344067, 4329475, 1572867, 8195, 1572867, 2051, 1572866, 1572867,
2051, 2050, 266243, 2051, 2050, 2049, 2051, 2050, 40963, 2051, 4194307, 2162691, 2051, 2050, 1572867, 2051,
2, 3, 3, 4327427, 3, 81923, 270339, 4099, 3, 3145731, 573443, 4099, 131075, 4099, 4099, 4098,
3, 532483, 1114115, 4099, 6324227, 4099, 4099, 4098, 264195, 4099, 4099, 4098, 4099, 4098, 4098, 4097,
3, 3145731, 270339, 16387, 270339, 688131, 270338, 270339, 3145731, 3145730, 196611, 3145731, 4212739, 3145731, 270339, 4099,
151555, 4521987, 2623491, 32771, 1048579, 2051, 270339, 4099, 40963, 3145731, 4194307, 4099, 589827, 4099, 4099, 4098,
3, 299011, 1114115, 16387, 131075, 5251075, 34819, 2621443, 131075, 591875, 6553603, 8195, 131074, 131075, 131075, 4099,
1114115, 2228227, 1114114, 1114115, 802819, 2051, 1114115, 4099, 40963, 4210691, 1114115, 4099, 131075, 4099, 4099, 4098,
4718595, 16387, 16387, 16386, 2166787, 2051, 270339, 16387, 40963, 3145731, 6147, 16387, 131075, 262147, 1572867, 4292611,
40963, 2051, 1114115, 16387, 2051, 2050, 4325379, 2051, 40962, 40963, 40963, 917507, 40963, 2051, 2113539, 4099,
2, 3, 3, 8195, 3, 81923, 655363, 6291459, 3, 8195, 8195, 8194, 36867, 1181699, 278531, 8195,
3, 5246979, 655363, 67587, 655363, 303107, 655362, 655363, 264195, 540675, 3178499, 8195, 4259843, 2097155, 655363, 4099,
3, 393219, 1067011, 6291459, 36867, 6291459, 6291459, 6291458, 36867, 540675, 196611, 8195, 36866, 36867, 36867, 6291459,
2170883, 540675, 266243, 32771, 1048579, 2051, 655363, 6291459, 540675, 540674, 4194307, 540675, 36867, 540675, 10243, 1376259,
3, 8195, 8195, 8194, 3407875, 528387, 34819, 8195, 8195, 8194, 8194, 8193, 4259843, 8195, 8195, 8194,
49155, 2228227, 266243, 8195, 4259843, 2051, 655363, 1064963, 4259843, 8195, 8195, 8194, 4259842, 4259843, 4259843, 8195,
4718595, 1146883, 266243, 8195, 155651, 2051, 65539, 6291459, 2099203, 8195, 8195, 8194, 36867, 262147, 1572867, 8195,
266243, 2051, 266242, 266243, 2051, 2050, 266243, 2051, 1179651, 540675, 266243, 8195, 4259843, 2051, 2113539, 163843,
3, 81923, 2101251, 1835011, 81923, 81922, 34819, 81923, 264195, 4227075, 196611, 8195, 2629635, 81923, 5242883, 4099,
264195, 2228227, 4218883, 32771, 1048579, 81923, 655363, 4099, 264194, 264195, 264195, 4099, 264195, 4099, 4099, 4098,
4718595, 14339, 196611, 32771, 1048579, 81923, 270339, 6291459, 196611, 3145731, 196610, 196611, 36867, 262147, 196611, 526339,
1048579, 32771, 32771, 32770, 1048578, 1048579, 1048579, 32771, 264195, 540675, 196611, 32771, 1048579, 4333571, 2113539, 4099,
4718595, 2228227, 34819, 8195, 34819, 81923, 34818, 34819, 1069059, 8195, 8195, 8194, 131075, 262147, 34819, 8195,
2228227, 2228226, 1114115, 2228227, 12291, 2228227, 34819, 4456451, 264195, 2228227, 524291, 8195, 4259843, 1605635, 2113539, 4099,
4718594, 4718595, 4718595, 16387, 4718595, 262147, 34819, 1183747, 4718595, 262147, 196611, 8195, 262147, 262146, 2113539, 262147,
4718595, 2228227, 266243, 32771, 1048579, 2051, 2113539, 598019, 40963, 69635, 2113539, 5244931, 2113539, 262147, 2113538, 2113539,
2, 3, 3, 1081347, 3, 1081347, 1081347, 1081346, 3, 22531, 4194307, 2752515, 131075, 73731, 278531, 1081347,
3, 532483, 4194307, 67587, 331779, 4341763, 2105347, 1081347, 4194307, 1310723, 4194306, 4194307, 559107, 2097155, 4194307, 4099,
3, 393219, 4194307, 16387, 2637827, 73731, 137219, 1081347, 4194307, 73731, 4194306, 4194307, 73731, 73730, 4194307, 73731,
4194307, 2134019, 4194306, 4194307, 1048579, 2051, 4194307, 786435, 4194306, 4194307, 4194305, 4194306, 4194307, 73731, 4194306, 4194307,
3, 6356995, 788483, 16387, 131075, 528387, 2105347, 1081347, 131075, 1310723, 102403, 8195, 131074, 131075, 131075, 4196355,
49155, 1310723, 2105347, 135171, 2105347, 2051, 2105346, 2105347, 1310723, 1310722, 4194307, 1310723, 131075, 1310723, 2105347, 606211,
1060867, 16387, 16387, 16386, 4489219, 2051, 65539, 16387, 2099203, 557059, 4194307, 16387, 131075, 73731, 1572867, 2363395,
720899, 2051, 4194307, 16387, 2051, 2050, 2105347, 2051, 4194307, 1310723, 4194306, 4194307, 20483, 2051, 4194307, 163843,
3, 532483, 2101251, 16387, 131075, 2361347, 4784131, 1081347, 131075, 4227075, 1058819, 327683, 131074, 131075, 131075, 4099,
532483, 532482, 425987, 532483, 1048579, 532483, 18435, 4099, 2179075, 532483, 4194307, 4099, 131075, 4099, 4099, 4098,
100355, 16387, 16387, 16386, 1048579, 4198403, 270339, 16387, 790531, 3145731, 4194307, 16387, 131075, 73731, 2129923, 526339,
1048579, 532483, 4194307, 16387, 1048578, 1048579, 1048579, 2293763, 4194307, 133123, 4194306, 4194307, 1048579, 311299, 4194307, 4099,
131075, 16387, 16387, 16386, 131074, 131075, 131075, 16387, 131074, 131075, 131075, 16387, 131073, 131074, 131074, 131075,
4200451, 532483, 1114115, 16387, 131075, 98307, 2105347, 4456451, 131075, 1310723, 524291, 2131971, 131074, 131075, 131075, 4099,
16387, 16386, 16386, 16385, 131075, 16387, 16387, 16386, 131075, 16387, 16387, 16386, 131074, 131075, 131075, 16387,
2359299, 16387, 16387, 16386, 1048579, 2051, 561155, 16387, 40963, 69635, 4194307, 16387, 131075, 6815747, 329731, 1056771,
3, 393219, 2101251, 67587, 4204547, 528387, 278531, 1081347, 1638403, 4227075, 278531, 8195, 278531, 2097155, 278530, 278531,
49155, 67587, 67587, 67586, 1048579, 2097155, 655363, 67587, 143363, 2097155, 4194307, 67587, 2097155, 2097154, 278531, 2097155,
393219, 393218, 565251, 393219, 1048579, 393219, 65539, 6291459, 2099203, 393219, 4194307, 1052675, 36867, 73731, 278531, 526339,
1048579, 393219, 4194307, 67587, 1048578, 1048579, 1048579, 28675, 4194307, 540675, 4194306, 4194307, 1048579, 2097155, 4194307, 163843,
49155, 528387, 5373955, 8195, 528387, 528386, 65539, 528387, 2099203, 8195, 8195, 8194, 131075, 528387, 278531, 8195,
49154, 49155, 49155, 67587, 49155, 528387, 2105347, 4456451, 49155, 1310723, 524291, 8195, 4259843, 2097155, 1054723, 163843,
2099203, 393219, 65539, 16387, 65539, 528387, 65538, 65539, 2099202, 2099203, 2099203, 8195, 2099203, 5259267, 65539, 163843,
49155, 4202499, 266243, 3670019, 1048579, 2051, 65539, 163843, 2099203, 69635, 4194307, 163843, 794627, 163843, 163843, 163842,
2101251, 4227075, 2101250, 2101251, 1048579, 81923, 2101251, 139267, 4227075, 4227074, 2101251, 4227075, 131075, 4227075, 278531, 526339,
1048579, 532483, 2101251, 67587, 1048578, 1048579, 1048579, 4456451, 264195, 4227075, 524291, 1196035, 1048579, 2097155, 106499, 4099,
1048579, 393219, 2101251, 16387, 1048578, 1048579, 1048579, 526339, 24579, 4227075, 196611, 526339, 1048579, 526339, 526339, 526338,
1048578, 1048579, 1048579, 32771, 1048577, 1048578, 1048578, 1048579, 1048579, 69635, 4194307, 2367491, 1048578, 1048579, 1048579, 526339,
335875, 1050627, 2101251, 16387, 131075, 528387, 34819, 4456451, 131075, 4227075, 524291, 8195, 131074, 131075, 131075, 3211267,
49155, 2228227, 524291, 4456451, 1048579, 4456451, 4456451, 4456450, 524291, 69635, 524290, 524291, 131075, 26627, 524291, 4456451,
4718595, 16387, 16387, 16386, 1048579, 2138115, 65539, 16387, 2099203, 69635, 1343491, 16387, 131075, 262147, 4206595, 526339,
1048579, 69635, 141315, 16387, 1048578, 1048579, 1048579, 4456451, 69635, 69634, 524291, 69635, 1048579, 69635, 2113539, 163843
};
cw &= 0x007fffff;
unsigned int correction = decoding[golay_23_syndrome(cw)];
cw ^= correction;
cw >>= 11;
return correction & 3;
}
#endif /* INCLUDED_OP25_GOLAY_H */

View File

@ -0,0 +1,186 @@
#ifndef INCLUDED_OP25_HAMMING_H
#define INCLUDED_OP25_HAMMING_H
#include <cstddef>
#include <stdint.h>
/*
* APCO Hamming(15,11,3) ecoder.
*
* \param val The 11-bit value to encode.
* \return The encoded codeword.
*/
static inline uint16_t
hamming_15_encode(uint16_t code_word_in)
{
static long int encoding[11] = {
0x400f, 0x200e, 0x100d, 0x080c, 0x040b, 0x020a, 0x0109,
0x0087, 0x0046, 0x0025, 0x0013
};
uint16_t code_word_out = 0u;
for(uint8_t i = 0; i < 11; ++i) {
if(code_word_in & (1u << (10 - i))) {
code_word_out ^= encoding[i];
}
}
return code_word_out;
}
/*
* APCO Hamming(15,11,3) decoder.
*
* \param cw The 15-bit codeword to decode.
* \return The number of errors detected.
*/
static inline size_t
hamming_15_decode(uint16_t& cw)
{
static const int encoding[2048] = {
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15
};
static const int decoding[16] = {
0, 0, 0, 1, 0, 2, 4, 8, 0, 16, 32, 64, 128, 256, 512, 1024
};
size_t errs = 0;
uint16_t par = cw & 0xf;
cw &= 0xffff;
cw >>= 4;
uint16_t correction = decoding[encoding[cw] ^ par];
if(correction) {
cw ^= correction;
++errs;
}
return errs;
}
#endif /* INCLUDED_OP25_HAMMING_H */

View File

@ -0,0 +1,428 @@
#ifndef INCLUDED_IMBE_FRAME_H
#define INCLUDED_IMBE_FRAME_H
#include "op25_yank.h"
#include "op25_golay.h"
#include "op25_hamming.h"
#include <cstddef>
#include <stdint.h>
#include <vector>
typedef std::vector<bool> voice_codeword;
typedef const std::vector<bool> const_bit_vector;
typedef std::vector<bool> bit_vector;
static const size_t nof_voice_codewords = 9, voice_codeword_sz = 144;
static const uint16_t imbe_ldu_NID_bits[] = {
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113 };
static const uint16_t imbe_ldu_status_bits[] = {
70, 71, 142, 143, 214, 215, 286, 287, 358, 359, 430, 431,
502, 503, 574, 575, 646, 647, 718, 719, 790, 791, 862, 863,
934, 935, 1006, 1007, 1078, 1079, 1150, 1151, 1222, 1223, 1294, 1295,
1366, 1367, 1438, 1439, 1510, 1511, 1582, 1583, 1654, 1655, 1726, 1727 };
static const uint16_t imbe_ldu_lcf_bits[] = {
410, 411, 412, 413, 414, 415, 420, 421,
422, 423, 424, 425, 432, 433, 434, 435,
436, 437, 442, 443, 444, 445, 446, 447,
600, 601, 602, 603, 604, 605, 610, 611,
612, 613, 614, 615, 620, 621, 622, 623,
624, 625, 630, 631, 632, 633, 634, 635,
788, 789, 792, 793, 794, 795, 800, 801,
802, 803, 804, 805, 810, 811, 812, 813,
814, 815, 820, 821, 822, 823, 824, 825 };
// FIXME: separate these into their respective fields
static const uint16_t imbe_ldu_ls_data_bits[] = {
410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421,
422, 423, 424, 425, 426, 427, 428, 429, 432, 433, 434, 435,
436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447,
448, 449, 450, 451, 600, 601, 602, 603, 604, 605, 606, 607,
608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619,
620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631,
632, 633, 634, 635, 636, 637, 638, 639, 788, 789, 792, 793,
794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805,
806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817,
818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829,
978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989,
990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001,
1002, 1003, 1004, 1005, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015,
1016, 1017, 1018, 1019, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175,
1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187,
1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199,
1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1356, 1357, 1358, 1359,
1360, 1361, 1362, 1363, 1364, 1365, 1368, 1369, 1370, 1371, 1372, 1373,
1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385,
1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397,
1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557,
1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569,
1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577 };
static const uint16_t voice_codeword_bits[nof_voice_codewords][voice_codeword_sz] = {
{ 114, 121, 126, 133, 138, 147, 152, 159, 164, 171, 176, 183,
188, 195, 200, 207, 212, 221, 226, 233, 238, 245, 250, 257,
115, 120, 127, 132, 139, 146, 153, 158, 165, 170, 177, 182,
189, 194, 201, 206, 213, 220, 227, 232, 239, 244, 251, 256,
116, 123, 128, 135, 140, 149, 154, 161, 166, 173, 178, 185,
190, 197, 202, 209, 216, 223, 228, 235, 240, 247, 252, 259,
117, 122, 129, 134, 141, 148, 155, 160, 167, 172, 179, 184,
191, 196, 203, 208, 217, 222, 229, 234, 241, 246, 253, 258,
118, 125, 130, 137, 144, 151, 156, 163, 168, 175, 180, 187,
192, 199, 204, 211, 218, 225, 230, 237, 242, 249, 254, 261,
119, 124, 131, 136, 145, 150, 157, 162, 169, 174, 181, 186,
193, 198, 205, 210, 219, 224, 231, 236, 243, 248, 255, 260 },
{ 262, 269, 274, 281, 288, 295, 300, 307, 312, 319, 324, 331,
336, 343, 348, 355, 362, 369, 374, 381, 386, 393, 398, 405,
263, 268, 275, 280, 289, 294, 301, 306, 313, 318, 325, 330,
337, 342, 349, 354, 363, 368, 375, 380, 387, 392, 399, 404,
264, 271, 276, 283, 290, 297, 302, 309, 314, 321, 326, 333,
338, 345, 350, 357, 364, 371, 376, 383, 388, 395, 400, 407,
265, 270, 277, 282, 291, 296, 303, 308, 315, 320, 327, 332,
339, 344, 351, 356, 365, 370, 377, 382, 389, 394, 401, 406,
266, 273, 278, 285, 292, 299, 304, 311, 316, 323, 328, 335,
340, 347, 352, 361, 366, 373, 378, 385, 390, 397, 402, 409,
267, 272, 279, 284, 293, 298, 305, 310, 317, 322, 329, 334,
341, 346, 353, 360, 367, 372, 379, 384, 391, 396, 403, 408 },
{ 452, 459, 464, 471, 476, 483, 488, 495, 500, 509, 514, 521,
526, 533, 538, 545, 550, 557, 562, 569, 576, 583, 588, 595,
453, 458, 465, 470, 477, 482, 489, 494, 501, 508, 515, 520,
527, 532, 539, 544, 551, 556, 563, 568, 577, 582, 589, 594,
454, 461, 466, 473, 478, 485, 490, 497, 504, 511, 516, 523,
528, 535, 540, 547, 552, 559, 564, 571, 578, 585, 590, 597,
455, 460, 467, 472, 479, 484, 491, 496, 505, 510, 517, 522,
529, 534, 541, 546, 553, 558, 565, 570, 579, 584, 591, 596,
456, 463, 468, 475, 480, 487, 492, 499, 506, 513, 518, 525,
530, 537, 542, 549, 554, 561, 566, 573, 580, 587, 592, 599,
457, 462, 469, 474, 481, 486, 493, 498, 507, 512, 519, 524,
531, 536, 543, 548, 555, 560, 567, 572, 581, 586, 593, 598 },
{ 640, 649, 654, 661, 666, 673, 678, 685, 690, 697, 702, 709,
714, 723, 728, 735, 740, 747, 752, 759, 764, 771, 776, 783,
641, 648, 655, 660, 667, 672, 679, 684, 691, 696, 703, 708,
715, 722, 729, 734, 741, 746, 753, 758, 765, 770, 777, 782,
642, 651, 656, 663, 668, 675, 680, 687, 692, 699, 704, 711,
716, 725, 730, 737, 742, 749, 754, 761, 766, 773, 778, 785,
643, 650, 657, 662, 669, 674, 681, 686, 693, 698, 705, 710,
717, 724, 731, 736, 743, 748, 755, 760, 767, 772, 779, 784,
644, 653, 658, 665, 670, 677, 682, 689, 694, 701, 706, 713,
720, 727, 732, 739, 744, 751, 756, 763, 768, 775, 780, 787,
645, 652, 659, 664, 671, 676, 683, 688, 695, 700, 707, 712,
721, 726, 733, 738, 745, 750, 757, 762, 769, 774, 781, 786 },
{ 830, 837, 842, 849, 854, 861, 868, 875, 880, 887, 892, 899,
904, 911, 916, 923, 928, 937, 942, 949, 954, 961, 966, 973,
831, 836, 843, 848, 855, 860, 869, 874, 881, 886, 893, 898,
905, 910, 917, 922, 929, 936, 943, 948, 955, 960, 967, 972,
832, 839, 844, 851, 856, 865, 870, 877, 882, 889, 894, 901,
906, 913, 918, 925, 930, 939, 944, 951, 956, 963, 968, 975,
833, 838, 845, 850, 857, 864, 871, 876, 883, 888, 895, 900,
907, 912, 919, 924, 931, 938, 945, 950, 957, 962, 969, 974,
834, 841, 846, 853, 858, 867, 872, 879, 884, 891, 896, 903,
908, 915, 920, 927, 932, 941, 946, 953, 958, 965, 970, 977,
835, 840, 847, 852, 859, 866, 873, 878, 885, 890, 897, 902,
909, 914, 921, 926, 933, 940, 947, 952, 959, 964, 971, 976 },
{ 1020, 1027, 1032, 1039, 1044, 1051, 1056, 1063, 1068, 1075, 1082, 1089,
1094, 1101, 1106, 1113, 1118, 1125, 1130, 1137, 1142, 1149, 1156, 1163,
1021, 1026, 1033, 1038, 1045, 1050, 1057, 1062, 1069, 1074, 1083, 1088,
1095, 1100, 1107, 1112, 1119, 1124, 1131, 1136, 1143, 1148, 1157, 1162,
1022, 1029, 1034, 1041, 1046, 1053, 1058, 1065, 1070, 1077, 1084, 1091,
1096, 1103, 1108, 1115, 1120, 1127, 1132, 1139, 1144, 1153, 1158, 1165,
1023, 1028, 1035, 1040, 1047, 1052, 1059, 1064, 1071, 1076, 1085, 1090,
1097, 1102, 1109, 1114, 1121, 1126, 1133, 1138, 1145, 1152, 1159, 1164,
1024, 1031, 1036, 1043, 1048, 1055, 1060, 1067, 1072, 1081, 1086, 1093,
1098, 1105, 1110, 1117, 1122, 1129, 1134, 1141, 1146, 1155, 1160, 1167,
1025, 1030, 1037, 1042, 1049, 1054, 1061, 1066, 1073, 1080, 1087, 1092,
1099, 1104, 1111, 1116, 1123, 1128, 1135, 1140, 1147, 1154, 1161, 1166 },
{ 1208, 1215, 1220, 1229, 1234, 1241, 1246, 1253, 1258, 1265, 1270, 1277,
1282, 1289, 1296, 1303, 1308, 1315, 1320, 1327, 1332, 1339, 1344, 1351,
1209, 1214, 1221, 1228, 1235, 1240, 1247, 1252, 1259, 1264, 1271, 1276,
1283, 1288, 1297, 1302, 1309, 1314, 1321, 1326, 1333, 1338, 1345, 1350,
1210, 1217, 1224, 1231, 1236, 1243, 1248, 1255, 1260, 1267, 1272, 1279,
1284, 1291, 1298, 1305, 1310, 1317, 1322, 1329, 1334, 1341, 1346, 1353,
1211, 1216, 1225, 1230, 1237, 1242, 1249, 1254, 1261, 1266, 1273, 1278,
1285, 1290, 1299, 1304, 1311, 1316, 1323, 1328, 1335, 1340, 1347, 1352,
1212, 1219, 1226, 1233, 1238, 1245, 1250, 1257, 1262, 1269, 1274, 1281,
1286, 1293, 1300, 1307, 1312, 1319, 1324, 1331, 1336, 1343, 1348, 1355,
1213, 1218, 1227, 1232, 1239, 1244, 1251, 1256, 1263, 1268, 1275, 1280,
1287, 1292, 1301, 1306, 1313, 1318, 1325, 1330, 1337, 1342, 1349, 1354 },
{ 1398, 1405, 1410, 1417, 1422, 1429, 1434, 1443, 1448, 1455, 1460, 1467,
1472, 1479, 1484, 1491, 1496, 1503, 1508, 1517, 1522, 1529, 1534, 1541,
1399, 1404, 1411, 1416, 1423, 1428, 1435, 1442, 1449, 1454, 1461, 1466,
1473, 1478, 1485, 1490, 1497, 1502, 1509, 1516, 1523, 1528, 1535, 1540,
1400, 1407, 1412, 1419, 1424, 1431, 1436, 1445, 1450, 1457, 1462, 1469,
1474, 1481, 1486, 1493, 1498, 1505, 1512, 1519, 1524, 1531, 1536, 1543,
1401, 1406, 1413, 1418, 1425, 1430, 1437, 1444, 1451, 1456, 1463, 1468,
1475, 1480, 1487, 1492, 1499, 1504, 1513, 1518, 1525, 1530, 1537, 1542,
1402, 1409, 1414, 1421, 1426, 1433, 1440, 1447, 1452, 1459, 1464, 1471,
1476, 1483, 1488, 1495, 1500, 1507, 1514, 1521, 1526, 1533, 1538, 1545,
1403, 1408, 1415, 1420, 1427, 1432, 1441, 1446, 1453, 1458, 1465, 1470,
1477, 1482, 1489, 1494, 1501, 1506, 1515, 1520, 1527, 1532, 1539, 1544 },
{ 1578, 1587, 1592, 1599, 1604, 1611, 1616, 1623, 1628, 1635, 1640, 1647,
1652, 1661, 1666, 1673, 1678, 1685, 1690, 1697, 1702, 1709, 1714, 1721,
1579, 1586, 1593, 1598, 1605, 1610, 1617, 1622, 1629, 1634, 1641, 1646,
1653, 1660, 1667, 1672, 1679, 1684, 1691, 1696, 1703, 1708, 1715, 1720,
1580, 1589, 1594, 1601, 1606, 1613, 1618, 1625, 1630, 1637, 1642, 1649,
1656, 1663, 1668, 1675, 1680, 1687, 1692, 1699, 1704, 1711, 1716, 1723,
1581, 1588, 1595, 1600, 1607, 1612, 1619, 1624, 1631, 1636, 1643, 1648,
1657, 1662, 1669, 1674, 1681, 1686, 1693, 1698, 1705, 1710, 1717, 1722,
1584, 1591, 1596, 1603, 1608, 1615, 1620, 1627, 1632, 1639, 1644, 1651,
1658, 1665, 1670, 1677, 1682, 1689, 1694, 1701, 1706, 1713, 1718, 1725,
1585, 1590, 1597, 1602, 1609, 1614, 1621, 1626, 1633, 1638, 1645, 1650,
1659, 1664, 1671, 1676, 1683, 1688, 1695, 1700, 1707, 1712, 1719, 1724 },
};
#if DEBUG
/*
* Convert bit vector to hex dump format and print
*/
static inline void
dump_cw(const voice_codeword& cw, int len, FILE* fp) // len in bytes
{
int i, j;
for (i = 0; i < len; i++){
int p = 0;
for (j = 0; j < 8; j++){
p = (p << 1) + cw[ i*8 + j ];
}
fprintf(fp, "%02x ", p);
if (!((i+1) % 16))
fprintf(fp, "\n");
}
fprintf(fp, "\n");
}
#endif
static inline void
imbe_store_bits(voice_codeword& cw, int s, int l, uint32_t v)
{
for (int i = l-1; i >= s; i--) {
cw[i] = v & 1;
v >>= 1;
}
}
static inline uint32_t
pngen15(uint32_t& Pr)
{
int n = 0;
for(int i = 14; i >= 0; --i) {
Pr = (173 * Pr + 13849) & 0xffffu;
if(Pr & 32768) {
n += (1 << i);
}
}
return n;
}
static inline uint32_t
pngen23(uint32_t& Pr)
{
int n = 0;
for(int i = 22; i >= 0; --i) {
Pr = (173 * Pr + 13849) & 0xffffu;
if(Pr & 32768) {
n += (1 << i);
}
}
return n;
}
/* APCO IMBE header decoder.
*
* extracts 88 bits of IMBE parameters given an input 144-bit frame
*
* \param cw Codeword containing bits to be decoded
* \param u0-u7 Result output vectors
*/
static inline void
imbe_header_decode(const voice_codeword& cw, uint32_t& u0, uint32_t& u1, uint32_t& u2, uint32_t& u3, uint32_t& u4, uint32_t& u5, uint32_t& u6, uint32_t& u7, uint32_t& E0, uint32_t& ET)
{
ET = 0;
size_t errs = 0;
uint32_t v0 = extract(cw, 0, 23);
errs = golay_23_decode(v0);
u0 = v0;
E0 = ET;
uint32_t pn = u0 << 4;
uint32_t m1 = pngen23(pn);
uint32_t v1 = extract(cw, 23, 46) ^ m1;
errs += golay_23_decode(v1);
u1 = v1;
uint32_t m2 = pngen23(pn);
uint32_t v2 = extract(cw, 46, 69) ^ m2;
errs += golay_23_decode(v2);
u2 = v2;
uint32_t m3 = pngen23(pn);
uint32_t v3 = extract(cw, 69, 92) ^ m3;
errs += golay_23_decode(v3);
u3 = v3;
uint32_t m4 = pngen15(pn);
uint16_t v4 = extract(cw, 92, 107) ^ m4;
errs += hamming_15_decode(v4);
u4 = v4;
uint32_t m5 = pngen15(pn);
uint16_t v5 = extract(cw, 107, 122) ^ m5;
errs += hamming_15_decode(v5);
u5 = v5;
uint32_t m6 = pngen15(pn);
uint16_t v6 = extract(cw, 122, 137) ^ m6;
errs += hamming_15_decode(v6);
u6 = v6;
u7 = extract(cw, 137, 144);
u7 <<= 1; /* so that bit0 is free (see note about BOT bit */
}
/* APCO IMBE header encoder.
*
* given 88 bits of IMBE parameters, construct output 144-bit IMBE codeword
*
* \param cw Codeword into which 144 bits of results are placed
* \param u0-u7 input parameters
*/
static inline void
imbe_header_encode(voice_codeword& cw, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3, uint32_t u4, uint32_t u5, uint32_t u6, uint32_t u7)
{
// given input 88-bit IMBE frame (in u0-u7),
// add golay / hamming bits to produce a 144-bit frame.
uint32_t c0, c1, c2, c3, c4, c5, c6, c7;
uint32_t pn = u0 << 4;
c0 = golay_23_encode(u0);
imbe_store_bits(cw, 0, 23, c0);
uint32_t m1 = pngen23(pn);
c1 = golay_23_encode(u1) ^ m1;
imbe_store_bits(cw, 23, 46, c1);
uint32_t m2 = pngen23(pn);
c2 = golay_23_encode(u2) ^ m2;
imbe_store_bits(cw, 46, 69, c2);
uint32_t m3 = pngen23(pn);
c3 = golay_23_encode(u3) ^ m3;
imbe_store_bits(cw, 69, 92, c3);
uint32_t m4 = pngen15(pn);
c4 = hamming_15_encode(u4) ^ m4;
imbe_store_bits(cw, 92, 107, c4);
uint32_t m5 = pngen15(pn);
c5 = hamming_15_encode(u5) ^ m5;
imbe_store_bits(cw, 107, 122, c5);
uint32_t m6 = pngen15(pn);
c6 = hamming_15_encode(u6) ^ m6;
imbe_store_bits(cw, 122, 137, c6);
c7 = u7;
imbe_store_bits(cw, 137, 144, c7 >> 1);
}
static inline void
imbe_deinterleave (const_bit_vector& frame_body, voice_codeword& cw, uint32_t frame_nr)
{
for(size_t j = 0; j < voice_codeword_sz; ++j) {
cw[j] = frame_body[voice_codeword_bits[frame_nr][j]];
}
}
static inline void
imbe_interleave(bit_vector& frame_body, const voice_codeword& cw, uint32_t frame_nr)
{
for(size_t j = 0; j < voice_codeword_sz; ++j) {
frame_body[voice_codeword_bits[frame_nr][j]] = cw[j];
}
}
static inline void
imbe_frame_unpack(uint8_t *A, uint32_t& u0, uint32_t& u1, uint32_t& u2, uint32_t& u3, uint32_t& u4, uint32_t& u5, uint32_t& u6, uint32_t& u7, uint32_t& E0, uint32_t& ET)
{
E0 = A[0];
ET = A[1];
u0 = A[4] + (E0 & 240) * 16;
u1 = A[5] + (E0 & 15) * 256;
u2 = A[6] + (ET & 240) * 16;
u3 = A[7] + (ET & 15) * 256;
E0 = A[2];
ET = A[3];
u4 = A[8] + (E0 & 224) * 8;
u5 = A[9] + (E0 & 28) * 64;
u6 = A[10] + (ET & 128) * 2 + (E0 & 3) * 512;
u7 = ET & 127;
E0 = A[11];
if(E0 & 192) exit(4);
ET = E0 & 3;
E0 = (E0 & 84) / 4;
}
/*
* Given a 144-bit IMBE frame(cw),
* 1. Decode frame to error-corrected 88-bit format
* 2. Re-encode frame into 144-bit format with refreshed Hamming/Golay encoding
* 3. FIXME: track decoding error rates and stats
*/
static inline void
imbe_regenerate_frame(bit_vector& cw) {
unsigned int u0 = 0;
unsigned int u1,u2,u3,u4,u5,u6,u7;
unsigned int E0 = 0;
unsigned int ET = 0;
// PN/Hamming/Golay - etc.
imbe_header_decode(cw, u0, u1, u2, u3, u4, u5, u6, u7, E0, ET) ;
#if DEBUG
printf("u_0: %x\r\nu_1: %x\r\nu_2: %x\r\nu_3: %x\r\nu_4: %x\r\nu_5: %x\r\nu_6: %x\r\nu_7: %x\r\n\r\n", u0, u1, u2, u3, u4, u5, u6, u7>>1);
#endif
imbe_header_encode(cw, u0, u1, u2, u3, u4, u5, u6, u7);
}
/*
* process voice units (ldu1 or ldu2)
* perform error correction for each of the nine embedded 144-bit frames
* by regenerating the error-correction coding bits
*/
static inline void
imbe_regenerate_voice_unit(bit_vector& frame_body) {
voice_codeword cw(voice_codeword_sz);
#if DEBUG
dump_cw(frame_body, 216, stderr);
#endif
for(size_t i = 0; i < nof_voice_codewords; ++i) {
imbe_deinterleave(frame_body, cw, i);
imbe_regenerate_frame(cw);
imbe_interleave(frame_body, cw, i);
}
#if DEBUG
dump_cw(frame_body, 216, stderr);
#endif
}
#endif /* INCLUDED_IMBE_FRAME_H */

View File

@ -0,0 +1,38 @@
#ifndef INCLUDED_OP25_P25_FRAME_H
#define INCLUDED_OP25_P25_FRAME_H 1
static const size_t P25_VOICE_FRAME_SIZE = 1728;
static const size_t P25_HEADER_SYMBOLS = 24 + 32 + 1;
static const size_t P25_HEADER_BITS = P25_HEADER_SYMBOLS * 2;
static const uint64_t P25_FRAME_SYNC_MAGIC = 0x5575F5FF77FFLL;
static const uint64_t P25_FRAME_SYNC_REV_P = 0x5575F5FF77FFLL ^ 0xAAAAAAAAAAAALL;
static const uint64_t P25_FRAME_SYNC_MASK = 0xFFFFFFFFFFFFLL;
/* Given a 64-bit frame header word and a frame body which is to be initialized
* 1. Place flags at beginning of frame body
* 2. Store 64-bit frame header word
* 3. FIXME Place first status symbol
*/
static inline void
p25_setup_frame_header(bit_vector& frame_body, uint64_t hw) {
uint64_t acc = P25_FRAME_SYNC_MAGIC;
for (int i=47; i>=0; i--) {
frame_body[ i ] = acc & 1;
acc >>= 1;
}
acc = hw;
for (int i=113; i>=72; i--) {
frame_body[ i ] = acc & 1;
acc >>= 1;
}
// FIXME: insert proper status dibit bits at 70, 71
frame_body[70] = 1;
frame_body[71] = 0;
for (int i=69; i>=48; i--) {
frame_body[ i ] = acc & 1;
acc >>= 1;
}
}
#endif /* INCLUDED_OP25_P25_FRAME_H */

View File

@ -0,0 +1,116 @@
#ifndef INCLUDED_SWAB_H
#define INCLUDED_SWAB_H
#include <stdint.h>
/**
* Yank in[bits[0]..bits[bits_sz]) to out[where,where+bits_sz).
*
* \param in A const reference to the source.
* \param bits An array specifying the ordinals of the bits to copy.
* \param bits_sz The size of the bits array.
* \param out A reference to the destination.
* \param where The offset of the first bit to write.
*/
template <class X, class Y>
void yank(const X& in, const size_t bits[], size_t bits_sz, Y& out, size_t where)
{
for(size_t i = 0; i < bits_sz; ++i) {
out[where+i] = in[bits[i]];
}
}
/**
* Yank back from in[where,where+bits_sz) to out[bits[0]..bits[bits_sz]).
*
* \param in A const reference to the source.
* \param where The offset of the first bit to read.
* \param out A reference to the destination.
* \param bits An array specifying the ordinals of the bits to copy.
* \param bits_sz The size of the bits array.
*/
template <class X, class Y>
void yank_back(const X& in, size_t where, Y& out, const size_t bits[], size_t bits_sz)
{
for(size_t i = 0; i < bits_sz; ++i) {
out[bits[i]] = in[where+i];
}
}
/**
* Extract a bit_vector in[begin,end) to an octet buffer.
*
* \param in A const reference to the source.
* \param begin The offset of the first bit to extract (the MSB).
* \param end The offset of the end bit.
* \param out Address of the octet buffer to write into.
* \return The number of octers written.
*/
template<class X>
size_t extract(const X& in, int begin, int end, uint8_t *out)
{
const size_t out_sz = (7 + end - begin) / 8;
std::fill(out, out + out_sz, 0);
for(int i = begin, j = 0; i < end; ++i, ++j) {
out[j / 8] |= (in[i] ? 1 << (7 - (j % 8)) : 0);
}
return out_sz;
}
/**
* Extract a bit_vector in[bits[0)..bits[bits_sz)) to an octet buffer.
*
* \param in A const reference to the source.
* \param bits An array specifying the ordinals of the bits to extract.
* \param bits_sz The size of the bits array.
* \param out Address of the octet buffer to write into.
* \return The number of octers written.
*/
template<class X>
size_t extract(const X& in, const size_t bits[], size_t bits_sz, uint8_t *out)
{
const size_t out_sz = (7 + bits_sz) / 8;
std::fill(out, out + out_sz, 0);
for(size_t i = 0; i < bits_sz; ++i) {
out[i / 8] ^= in[bits[i]] << (7 - (i % 8));
}
return out_sz;
}
/**
* Extract value of bits from in[bits[0..bits_sz)).
*
* \param in The input const_bit_vector.
* \param begin The offset of the first bit to extract (the MSB).
* \param end The offset of the end bit.
* \return A uint64_t containing the value
*/
template<class X>
uint64_t extract(const X& in, int begin, int end)
{
uint64_t x = 0LL;
for(int i = begin; i < end; ++i) {
x = (x << 1) | (in[i] ? 1 : 0);
}
return x;
}
/**
* Extract value of bits from in[bits[0..bits_sz)).
*
* \param in A const reference to the source.
* \param bits An array specifying the ordinals of the bits to extract.
* \param bits_sz The size of the bits array.
* \return A uint64_t containing the value
*/
template<class X>
uint64_t extract(const X& in, const size_t bits[], size_t bits_sz)
{
uint64_t x = 0LL;
for(size_t i = 0; i < bits_sz; ++i) {
x = (x << 1) | (in[bits[i]] ? 1 : 0);
}
return x;
}
#endif // INCLUDED_SWAB_H

View File

@ -0,0 +1,88 @@
/* -*- C++ -*- */
/*
* Copyright 2008-2011 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "p25cai_du_handler.h"
#include <arpa/inet.h>
#include <cstdio>
#include <cstring>
#include <errno.h>
#include <iomanip>
#include <netinet/in.h>
#include <sstream>
#include <sys/socket.h>
#include <sys/socket.h>
using namespace std;
p25cai_du_handler::p25cai_du_handler(data_unit_handler_sptr next, const char *addr, int port) :
data_unit_handler(next),
d_cai(-1),
d_address("Unavailable")
{
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_aton(addr, &sin.sin_addr);
d_cai = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(-1 != d_cai) {
if(-1 != connect(d_cai, (struct sockaddr*) &sin, sizeof(sin))) {
ostringstream address;
address << addr << ":" << port;
d_address = address.str();
} else {
printf("error %d: %s\n", errno, strerror(errno));
perror("connect(d_tap, (struct sockaddr*) &sin, sizeof(sin))");
close(d_cai);
d_cai = -1;
}
} else {
perror("socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)");
d_cai = -1;
}
}
p25cai_du_handler::~p25cai_du_handler()
{
if(-1 != d_cai) {
close(d_cai);
}
}
const char*
p25cai_du_handler::destination() const
{
return d_address.c_str();
}
void
p25cai_du_handler::handle(data_unit_sptr du)
{
if(-1 != d_cai) {
const size_t CAI_SZ = du->size();
uint8_t cai[CAI_SZ];
du->decode_frame(CAI_SZ, cai);
write(d_cai, cai, CAI_SZ);
}
data_unit_handler::handle(du);
}

View File

@ -0,0 +1,85 @@
/* -*- C++ -*- */
/*
* Copyright 2008-2011 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_P25CAI_DU_HANDLER_H
#define INCLUDED_P25CAI_DU_HANDLER_H
#include "data_unit_handler.h"
#include <string>
/**
* This data_unit_handler forwards received frames using p25cai - a
* straighforward encapsulation of the P25 CAI in a UDP datagram. This
* format is understood by Wireshark and replaces the use of TUN/TAP
* which require root privileges and are not present by default on
* some platforms.
*/
class p25cai_du_handler : public data_unit_handler
{
public:
/**
* p25cai_du_handler constructor.
*
* \param next The next data_unit_handler.
* \param addr The address of the receiver.
* \param port The port number of the receiver.
*/
p25cai_du_handler(data_unit_handler_sptr next, const char *addr, int port);
/**
* p25cai_du_handler virtual destructor.
*/
virtual ~p25cai_du_handler();
/**
* Handle a received P25 frame.
*
* \param du A non-null data_unit_sptr to handle.
*/
virtual void handle(data_unit_sptr du);
/**
* Return a pointer to a string identifying the destination address.
*
* \return A pointer to a NUL-terminated character string.
*/
const char *destination() const;
private:
/**
* file descriptor for the UDP socket.
*/
int32_t d_cai;
/**
* A string identifying the address of the receiver.
*/
std::string d_address;
};
#endif /* INCLUDED_P25CAI_DU_HANDLER_H */

View File

@ -0,0 +1,117 @@
/* -*- c++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* This file is part of OP25.
*
* 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 "pcap_source_b_impl.h"
#define PCAP_DONT_INCLUDE_PCAP_BPF_H
#include <pcap/pcap.h>
using namespace std;
namespace gr {
namespace op25 {
pcap_source_b::sptr
pcap_source_b::make(const char *path, float delay)
{
return gnuradio::get_initial_sptr
(new pcap_source_b_impl(path, delay));
}
/*
* The private constructor
*/
pcap_source_b_impl::pcap_source_b_impl(const char *path, float delay)
: gr::sync_block("pcap_source_b",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(1, 1, sizeof(uint8_t))),
loc_(0),
octets_(/* delay * 1200, 0 */)
{
char err[PCAP_ERRBUF_SIZE];
pcap_t *pcap = pcap_open_offline(path, err);
if(pcap) {
struct pcap_pkthdr hdr;
for(const uint8_t *octets; octets = pcap_next(pcap, &hdr);) {
const size_t ETHERNET_SZ = 14;
const size_t IP_SZ = 20;
const size_t UDP_SZ = 8;
const size_t P25CAI_OFS = ETHERNET_SZ + IP_SZ + UDP_SZ;
if(P25CAI_OFS < hdr.caplen) {
const size_t FRAME_SZ = hdr.caplen - P25CAI_OFS;
#if 0
// push some zero octets to separate frames
const size_t SILENCE_OCTETS = 48;
octets_.resize(octets_.size() + SILENCE_OCTETS, 0);
#endif
// push octets from frame payload into local buffer
octets_.reserve(octets_.size() + hdr.caplen - P25CAI_OFS);
for(size_t i = 0; i < FRAME_SZ; ++i) {
octets_.push_back(octets[P25CAI_OFS + i]);
}
}
}
pcap_close(pcap);
} else {
cerr << "error: failed to open " << path;
cerr << " (" << err << ")" << endl;
exit(EXIT_FAILURE);
}
}
/*
* Our virtual destructor.
*/
pcap_source_b_impl::~pcap_source_b_impl()
{
}
int
pcap_source_b_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
try {
const size_t OCTETS_AVAIL = octets_.size();
uint8_t *out = reinterpret_cast<uint8_t*>(output_items[0]);
const int OCTETS_REQD = static_cast<size_t>(noutput_items);
for(int i = 0; i < OCTETS_REQD; ++i) {
out[i] = octets_[loc_++];
loc_ %= OCTETS_AVAIL;
}
return OCTETS_REQD;
} catch(const exception& x) {
cerr << x.what() << endl;
exit(EXIT_FAILURE);
} catch(...) {
cerr << "unhandled exception" << endl;
exit(EXIT_FAILURE);
}
}
} /* namespace op25 */
} /* namespace gr */

View File

@ -0,0 +1,58 @@
/* -*- c++ -*- */
/*
* Copyright 2010-2011 Steve Glass
*
* This file is part of OP25.
*
* 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_OP25_PCAP_SOURCE_B_IMPL_H
#define INCLUDED_OP25_PCAP_SOURCE_B_IMPL_H
#include <op25/pcap_source_b.h>
namespace gr {
namespace op25 {
class pcap_source_b_impl : public pcap_source_b
{
private:
/**
* The next octet to be read from the input file.
*/
size_t loc_;
/**
* Symbols from the input file.
*/
std::vector<uint8_t> octets_;
public:
pcap_source_b_impl(const char *path, float delay);
~pcap_source_b_impl();
// Where all the action really happens
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace op25
} // namespace gr
#endif /* INCLUDED_OP25_PCAP_SOURCE_B_IMPL_H */

67
op25/gr-op25/lib/pdu.cc Normal file
View File

@ -0,0 +1,67 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "pdu.h"
using std::string;
pdu::pdu(const_bit_queue& frame_body) :
abstract_data_unit(frame_body)
{
}
pdu::~pdu()
{
}
string
pdu::duid_str() const
{
return string("PDU");
}
void
pdu::do_correct_errors(bit_vector& frame_body)
{
}
uint16_t
pdu::frame_size_max() const
{
#if 1
const size_t HEADER_BLOCK_SIZE = 720;
return HEADER_BLOCK_SIZE;
#else
const size_t MIN_HEADER_BLOCK_SZ = 312;
// after HEADER_BLOCK_SIZE bits have been read we can then use the
// header contents to decide on frame_size_max
size_t n = MIN_HEADER_BLOCK_SZ;
if(n < ) {
static const size_t BITS[] = {};
static const size_t BITS_SZ = sizeof(BITS) / sizeof(BITS[0]);
n = extract();
}
return n;
#endif
}

74
op25/gr-op25/lib/pdu.h Normal file
View File

@ -0,0 +1,74 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_PDU_H
#define INCLUDED_PDU_H
#include "abstract_data_unit.h"
/**
* P25 packet data unit (PDU).
*/
class pdu : public abstract_data_unit
{
public:
/**
* P25 packet data unit (PDU) constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
*/
pdu(const_bit_queue& frame_body);
/**
* pdu (virtual) destructor.
*/
virtual ~pdu();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
protected:
/**
* Applies error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void do_correct_errors(bit_vector& frame_body);
/**
* Returns the expected size (in bits) of this data unit in
* bits. For variable-length data this should return UINT16_MAX
* until the actual length of this frame is known.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const;
};
#endif /* INCLUDED_PDU_H */

View File

@ -0,0 +1,59 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "pickle.h"
#include <iomanip>
#include <sstream>
using namespace std;
pickle::pickle()
{
}
pickle::~pickle()
{
}
void
pickle::add(string key, string value)
{
map_[key] = value;
}
string
pickle::to_string() const
{
size_t n = 1;
ostringstream os;
os << "(dp" << n++ << endl;
for(stringmap::const_iterator i(map_.begin()); i != map_.end(); ++i) {
os << "S'" << i->first << "'" << endl;
os << "p" << n++ << endl;
os << "S'" << i->second << "'" << endl;
os << "p" << n++ << endl << "s";
}
os << "." << endl;
return os.str();
}

69
op25/gr-op25/lib/pickle.h Normal file
View File

@ -0,0 +1,69 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_PICKLE_H
#define INCLUDED_PICKLE_H
#include "abstract_data_unit.h"
#include <map>
/**
* A pickled Python dictionary. Used to pass stuff to the UI.
*/
class pickle
{
public:
/**
* pickle constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
*/
pickle();
/**
* pickle virtual destructor.
*/
~pickle();
/**
* Add a key/value pair to the pickled dictionary
*/
void add(std::string key, std::string value);
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string to_string() const;
private:
typedef std::map<std::string, std::string> stringmap;
stringmap map_;
};
#endif /* INCLUDED_PICKLE_H */

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
/*
* This class gathers together all the test cases for the gr-filter
* directory into a single test suite. As you create new test cases,
* add them here.
*/
#include "qa_op25.h"
CppUnit::TestSuite *
qa_op25::suite()
{
CppUnit::TestSuite *s = new CppUnit::TestSuite("op25");
return s;
}

View File

@ -0,0 +1,38 @@
/* -*- 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.
*/
#ifndef _QA_OP25_H_
#define _QA_OP25_H_
#include <gnuradio/attributes.h>
#include <cppunit/TestSuite.h>
//! collect all the tests for the gr-filter directory
class __GR_ATTR_EXPORT qa_op25
{
public:
//! return suite of tests for all of gr-filter directory
static CppUnit::TestSuite *suite();
};
#endif /* _QA_OP25_H_ */

View File

@ -0,0 +1,67 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "snapshot_du_handler.h"
#include <cstring>
#include <string>
using std::string;
snapshot_du_handler::snapshot_du_handler(data_unit_handler_sptr next) :
data_unit_handler(next),
d_data_units(0)
{
}
snapshot_du_handler::~snapshot_du_handler()
{
}
void
snapshot_du_handler::handle(data_unit_sptr du)
{
if(d_msgq) {
string snapshot(du->snapshot());
if(snapshot.size() > 0) {
const size_t snapshot_sz = snapshot.size() + 1;
gr::message::sptr msg = gr::message::make(/*type*/0, /*arg1*/++d_data_units, /*arg2*/0, snapshot_sz);
char *snapshot_data = reinterpret_cast<char*>(msg->msg());
memcpy(snapshot_data, snapshot.c_str(), snapshot_sz);
d_msgq->handle(msg);
}
}
data_unit_handler::handle(du);
}
gr::msg_queue::sptr
snapshot_du_handler::get_msgq() const
{
return d_msgq;
}
void
snapshot_du_handler::set_msgq(gr::msg_queue::sptr msgq)
{
d_msgq = msgq;
}

View File

@ -0,0 +1,95 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_SNAPSHOT_DU_HANDLER_H
#define INCLUDED_SNAPSHOT_DU_HANDLER_H
#include "data_unit_handler.h"
#include <gnuradio/msg_queue.h>
#include <boost/noncopyable.hpp>
/**
* snapshot_du_handler. Writes traffic snapshots to a msg_queue based
* on the HDU frame contents. The format used is that of a pickled
* python dictionary allowing the other end of the queue to pick only
* those fields of interest and ignore the rest.
*/
class snapshot_du_handler : public data_unit_handler
{
public:
/**
* snapshot_du_handler constructor.
*
* \param next The next data_unit_handler in the chain.
* \param msgq A non-null msg_queue_sptr to the msg_queue to use.
*/
snapshot_du_handler(data_unit_handler_sptr next);
/**
* snapshot_du_handler virtual destructor.
*/
virtual ~snapshot_du_handler();
/**
* Handle a received P25 frame.
*
* \param du A non-null data_unit_sptr to handle.
*/
virtual void handle(data_unit_sptr du);
/**
* Accessor for the msgq attribute. Returns a pointer to the msgq
* if it exists.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
*/
gr::msg_queue::sptr get_msgq() const;
/**
* Accessor for the msgq attribute. Sets the msgq to point to the
* provided message queue object.
*
* \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
*/
void set_msgq(gr::msg_queue::sptr msgq);
private:
/**
* Count of the data units seen so far.
*/
uint32_t d_data_units;
/**
* The msg_queue to which decoded frames are written.
*/
gr::msg_queue::sptr d_msgq;
};
#endif /* INCLUDED_SNAPSHOT_DU_HANDLER_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
/* -*- C++ -*- */
/*
* Copyright 2008-2009 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_SOFTWARE_IMBE_DECODER_H
#define INCLUDED_SOFTWARE_IMBE_DECODER_H
#include "imbe_decoder.h"
#include <stdint.h>
/**
* A software implementation of the imbe_decoder interface.
*/
class software_imbe_decoder : public imbe_decoder {
public:
/**
* Default constructor for the software_imbe_decoder.
*/
software_imbe_decoder();
/**
* Destructor for the software_imbe_decoder.
*/
virtual ~software_imbe_decoder();
/**
* Decode the compressed audio.
*
* \cw in IMBE codeword (including parity check bits).
*/
virtual void decode(const voice_codeword& cw);
private:
//NOTE: Single-letter variable names are upper case only; Lower
// case if needed is spelled. e.g. L, ell
// global Seq ER ?
int bee[58]; //Encoded Spectral Amplitudes
float M[57][2]; //Enhanced Spectral Amplitudes
float Mu[57][2]; //Unenhanced Spectral Amplitudes
int vee[57][2]; //V/UV decisions
float suv[160]; //Unvoiced samples
float sv[160]; //Voiced samples
float log2Mu[58][2];
float Olduw[256];
float psi1;
float phi[57][2];
uint32_t u[211];
int Old;
int New;
int L;
int OldL;
float w0;
float Oldw0;
float Luv; //number of unvoiced spectral amplitudes
char sym_b[4096];
char RxData[4096];
int sym_bp;
int ErFlag;
uint32_t pngen15(uint32_t& pn);
uint32_t pngen23(uint32_t& pn);
uint32_t next_u(uint32_t u);
void decode_audio(uint8_t *);
void decode_spectral_amplitudes(int, int );
void decode_vuv(int );
void adaptive_smoothing(float, float, float );
void fft(float i[], float q[]);
void enhance_spectral_amplitudes(float&);
void ifft(float i[], float q[], float[]);
uint16_t rearrange(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3, uint32_t u4, uint32_t u5, uint32_t u6, uint32_t u7);
void synth_unvoiced();
void synth_voiced();
void unpack(uint8_t *buf, uint32_t& u0, uint32_t& u1, uint32_t& u2, uint32_t& u3, uint32_t& u4, uint32_t& u5, uint32_t& u6, uint32_t& u7, uint32_t& E0, uint32_t& ET);
};
#endif /* INCLUDED_SOFTWARE_IMBE_DECODER_H */

85
op25/gr-op25/lib/tdu.cc Normal file
View File

@ -0,0 +1,85 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "tdu.h"
#include "op25_yank.h"
#include <itpp/base/vec.h>
#include <itpp/comm/reedsolomon.h>
using std::string;
tdu::tdu(const_bit_queue& frame_body, bool has_link_control) :
abstract_data_unit(frame_body),
d_has_link_control(has_link_control)
{
}
tdu::~tdu()
{
}
string
tdu::duid_str() const
{
return string("TDU");
}
void
tdu::do_correct_errors(bit_vector& frame)
{
if(d_has_link_control) {
apply_golay_correction(frame);
apply_rs_correction(frame);
}
}
void
tdu::apply_golay_correction(bit_vector& frame)
{
}
void
tdu::apply_rs_correction(bit_vector& frame)
{
#if 0
static itpp::Reed_Solomon rs(63, 17, true);
itpp::bvec b(70);
swab(frame, 114, 122, b, 0);
swab(frame, 122, 126, b, 8);
swab(frame, 138, 142, b, 12);
swab(frame, 144, 152, b, 16);
swab(frame, 164, 176, b, 24);
swab(frame, 188, 200, b, 36);
swab(frame, 212, 213, b, 48);
swab(frame, 216, 226, b, 50);
swab(frame, 238, 250, b, 60);
itpp::bvec bd(rs.decode(b));
#endif
}
uint16_t
tdu::frame_size_max() const
{
return d_has_link_control ? 432 : 144;
}

99
op25/gr-op25/lib/tdu.h Normal file
View File

@ -0,0 +1,99 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_TDU_H
#define INCLUDED_TDU_H
#include "abstract_data_unit.h"
/**
* P25 terminator data unit (TDU).
*/
class tdu : public abstract_data_unit
{
public:
/**
* tdu constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
* \param has_link_control true if frame has link control data, otherwise false.
*/
tdu(const_bit_queue& frame_body, bool has_link_control);
/**
* tdu constructor.
*/
virtual ~tdu();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
protected:
/**
* Applies error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void do_correct_errors(bit_vector& frame_body);
/**
* Apply Golay error correction code to the specified bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void apply_golay_correction(bit_vector& frame_body);
/**
* Apply Reed-Solomon error correction code to the specified
* bit_vector.
*
* \param frame_body The bit vector to decode.
* \return
*/
virtual void apply_rs_correction(bit_vector& frame_body);
/**
* Returns the expected size (in bits) of this data unit in
* bits. For variable-length data this should return UINT16_MAX
* until the actual length of this frame is known.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const;
private:
/**
* Does this TDU have a link_control field?
*/
bool d_has_link_control;
};
#endif /* INCLUDED_TDU_H */

View File

@ -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_op25.h"
#include <iostream>
int
main (int argc, char **argv)
{
CppUnit::TextTestRunner runner;
std::ofstream xmlfile(get_unittest_path("op25.xml").c_str());
CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile);
runner.addTest(qa_op25::suite());
runner.setOutputter(xmlout);
bool was_successful = runner.run("", false);
return was_successful ? 0 : 1;
}

52
op25/gr-op25/lib/tsbk.cc Normal file
View File

@ -0,0 +1,52 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "tsbk.h"
using namespace std;
tsbk::tsbk(const_bit_queue& frame_body) :
abstract_data_unit(frame_body)
{
}
tsbk::~tsbk()
{
}
string
tsbk::duid_str() const
{
return string("TSBK");
}
uint16_t
tsbk::frame_size_max() const
{
#if 1
return 720;
#else
// todo: check this out!
return 358;
#endif
}

66
op25/gr-op25/lib/tsbk.h Normal file
View File

@ -0,0 +1,66 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_TSBK_H
#define INCLUDED_TSBK_H
#include "abstract_data_unit.h"
/**
* P25 trunking signalling block (TSBK).
*/
class tsbk : public abstract_data_unit
{
public:
/**
* tsbk constructor.
*
* \param frame_body A const_bit_queue representing the frame body.
*/
tsbk(const_bit_queue& frame_body);
/**
* tsbk virtual destructor.
*/
virtual ~tsbk();
/**
* Returns a string describing the Data Unit ID (DUID).
*/
std::string duid_str() const;
protected:
/**
* Returns the expected size (in bits) of this data unit in
* bits.
*
* \return The expected size (in bits) of this data_unit when encoded.
*/
virtual uint16_t frame_size_max() const;
};
#endif /* INCLUDED_TSBK_H */

View File

@ -0,0 +1,117 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "value_string.h"
#include <iomanip>
#include <sstream>
using namespace std;
struct value_string {
uint16_t value;
const char *label;
};
string
lookup(uint16_t value, const value_string mappings[], size_t mappings_sz)
{
for(size_t i = 0; i < mappings_sz; ++i) {
if(mappings[i].value == value) {
return mappings[i].label;
}
}
ostringstream os;
os << "Unknown (" << hex << showbase << value << ")";
return os.str();
}
const value_string ALGIDS[] = {
/* Type I */
{ 0x00, "ACCORDION 1.3" },
{ 0x01, "BATON (Auto Even)" },
{ 0x02, "FIREFLY Type 1" },
{ 0x03, "MAYFLY Type 1" },
{ 0x04, "SAVILLE" },
{ 0x41, "BATON (Auto Odd)" },
/* Type III */
{ 0x80, "Plain" },
{ 0x81, "DES-OFB" },
{ 0x82, "2 key Triple DES" },
{ 0x83, "3 key Triple DES" },
{ 0x84, "AES-256" },
/* Motorola proprietary */
{ 0x9F, "Motorola DES-XL" },
{ 0xA0, "Motorola DVI-XL" },
{ 0xA1, "Motorola DVP-XL" },
{ 0xAA, "Motorola ADP" },
};
const size_t ALGIDS_SZ = sizeof(ALGIDS) / sizeof(ALGIDS[0]);
const value_string MFIDS[] = {
{ 0x00, "Standard MFID (pre-2001)" },
{ 0x01, "Standard MFID (post-2001)" },
{ 0x09, "Aselsan Inc." },
{ 0x10, "Relm / BK Radio" },
{ 0x18, "EADS Public Safety Inc." },
{ 0x20, "Cycomm" },
{ 0x28, "Efratom Time and Frequency Products, Inc" },
{ 0x30, "Com-Net Ericsson" },
{ 0x34, "Etherstack" },
{ 0x38, "Datron" },
{ 0x40, "Icom" },
{ 0x48, "Garmin" },
{ 0x50, "GTE" },
{ 0x55, "IFR Systems" },
{ 0x5A, "INIT Innovations in Transportation, Inc" },
{ 0x60, "GEC-Marconi" },
{ 0x64, "Harris Corp." },
{ 0x68, "Kenwood Communications" },
{ 0x70, "Glenayre Electronics" },
{ 0x74, "Japan Radio Co." },
{ 0x78, "Kokusai" },
{ 0x7C, "Maxon" },
{ 0x80, "Midland" },
{ 0x86, "Daniels Electronics Ltd." },
{ 0x90, "Motorola" },
{ 0xA0, "Thales" },
{ 0xA4, "M/A-COM" },
{ 0xB0, "Raytheon" },
{ 0xC0, "SEA" },
{ 0xC8, "Securicor" },
{ 0xD0, "ADI" },
{ 0xD8, "Tait Electronics" },
{ 0xE0, "Teletec" },
{ 0xF0, "Transcrypt International" },
{ 0xF8, "Vertex Standard" },
{ 0xFC, "Zetron, Inc" },
};
const size_t MFIDS_SZ = sizeof(MFIDS) / sizeof(MFIDS[0]);
const value_string NACS[] = {
{ 0x293, "Default NAC" },
{ 0xF7E, "Receiver to open on any NAC" },
{ 0xF7F, "Repeater to receive and retransmit any NAC" },
};
const size_t NACS_SZ = sizeof(NACS) / sizeof(NACS[0]);

View File

@ -0,0 +1,49 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_VALUE_STRING
#define INCLUDED_VALUE_STRING
#include <stdint.h>
#include <string>
/*
* Look up a value in a value_string array.
*
*/
extern std::string lookup(uint16_t value, const class value_string mappings[], size_t mappings_sz);
/*
* Look up tables.
*/
extern const value_string ALGIDS[];
extern const size_t ALGIDS_SZ;
extern const value_string MFIDS[];
extern const size_t MFIDS_SZ;
extern const value_string NACS[];
extern const size_t NACS_SZ;
#endif // INCLUDED_VALUE_STRING

View File

@ -0,0 +1,88 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include "vc55_imbe_decoder.h"
#include "op25_yank.h"
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <sstream>
#include <stdexcept>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
using namespace std;
vc55_imbe_decoder::vc55_imbe_decoder()
{
const char *dev = getenv("IMBE_DEV");
const char *default_dev = "/dev/ttyS0";
dev = dev ? dev : default_dev;
d_fd = open(dev, O_WRONLY | O_NOCTTY);
if(-1 != d_fd) {
struct termios options;
if(-1 != tcgetattr(d_fd, &options)) {
cfsetospeed(&options, B115200);
options.c_cflag |= (CLOCAL | CREAD | CS8);
options.c_cflag &= ~(CSTOPB | PARENB | CRTSCTS | IXON);
if(-1 == tcsetattr(d_fd, TCSANOW, &options)) {
ostringstream msg;
msg << "tcsetattr(fd, TCSANOW, &options): " << strerror(errno) << endl;
msg << "func: " << __PRETTY_FUNCTION__ << endl;
msg << "file: " << __FILE__ << endl;
msg << "line: " << __LINE__ << endl;
throw runtime_error(msg.str());
}
}
} else {
perror("open(dev, O_WRONLY | O_NOCTTY)"); // a warning, not an error
}
}
vc55_imbe_decoder::~vc55_imbe_decoder()
{
if(-1 != d_fd) {
close(d_fd);
}
}
void
vc55_imbe_decoder::decode(const voice_codeword& cw)
{
if(-1 != d_fd) {
uint8_t packet[20];
packet[0] = 0x56;
packet[1] = 0xf0;
extract(cw, 0, 144, &packet[2]);
if(-1 == write(d_fd, packet, sizeof(packet))) {
perror("write(d_fd, packet, sizeof(packet))");
close(d_fd);
d_fd = -1;
}
}
}

View File

@ -0,0 +1,64 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 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.
*
* OP25 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 OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_VC55_IMBE_DECODER_H
#define INCLUDED_VC55_IMBE_DECODER_H
#include "imbe_decoder.h"
/**
* vc55_imbe_decoder uses the VC55PR vocoder to decode voice. Note
* that the VC55 produces audio but this is not fed back to the flow
* graph.
*
*/
class vc55_imbe_decoder : public imbe_decoder {
public:
/**
* vc55_imbe_decoder default constructor.
*/
vc55_imbe_decoder();
/**
* vc55_imbe_decoder (virtual) destructor.
*/
virtual ~vc55_imbe_decoder();
/**
* Passess the voice_codeword in_out to the VC55PR device.
*
* \param cw IMBE codewords and parity.
*/
virtual void decode(const voice_codeword& cw);
private:
/**
* File descriptor for the actual terminal device.
*/
int32_t d_fd;
};
#endif /* INCLUDED_VC55_IMBE_DECODER_H */

Some files were not shown because too many files have changed in this diff Show More