Initial check-in.
This commit is contained in:
commit
e9aa1ab5fe
|
@ -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)
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
include(GrPython)
|
||||
|
||||
GR_PYTHON_INSTALL(
|
||||
PROGRAMS
|
||||
DESTINATION bin
|
||||
)
|
|
@ -0,0 +1,138 @@
|
|||
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
|
||||
#
|
||||
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for
|
||||
# parsing the arguments given to that macro or function.
|
||||
# It processes the arguments and defines a set of variables which hold the
|
||||
# values of the respective options.
|
||||
#
|
||||
# The <options> argument contains all options for the respective macro,
|
||||
# i.e. keywords which can be used when calling the macro without any value
|
||||
# following, like e.g. the OPTIONAL keyword of the install() command.
|
||||
#
|
||||
# The <one_value_keywords> argument contains all keywords for this macro
|
||||
# which are followed by one value, like e.g. DESTINATION keyword of the
|
||||
# install() command.
|
||||
#
|
||||
# The <multi_value_keywords> argument contains all keywords for this macro
|
||||
# which can be followed by more than one value, like e.g. the TARGETS or
|
||||
# FILES keywords of the install() command.
|
||||
#
|
||||
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
|
||||
# keywords listed in <options>, <one_value_keywords> and
|
||||
# <multi_value_keywords> a variable composed of the given <prefix>
|
||||
# followed by "_" and the name of the respective keyword.
|
||||
# These variables will then hold the respective value from the argument list.
|
||||
# For the <options> keywords this will be TRUE or FALSE.
|
||||
#
|
||||
# All remaining arguments are collected in a variable
|
||||
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see whether
|
||||
# your macro was called with unrecognized parameters.
|
||||
#
|
||||
# As an example here a my_install() macro, which takes similar arguments as the
|
||||
# real install() command:
|
||||
#
|
||||
# function(MY_INSTALL)
|
||||
# set(options OPTIONAL FAST)
|
||||
# set(oneValueArgs DESTINATION RENAME)
|
||||
# set(multiValueArgs TARGETS CONFIGURATIONS)
|
||||
# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
# ...
|
||||
#
|
||||
# Assume my_install() has been called like this:
|
||||
# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
|
||||
#
|
||||
# After the cmake_parse_arguments() call the macro will have set the following
|
||||
# variables:
|
||||
# MY_INSTALL_OPTIONAL = TRUE
|
||||
# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
|
||||
# MY_INSTALL_DESTINATION = "bin"
|
||||
# MY_INSTALL_RENAME = "" (was not used)
|
||||
# MY_INSTALL_TARGETS = "foo;bar"
|
||||
# MY_INSTALL_CONFIGURATIONS = "" (was not used)
|
||||
# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
|
||||
#
|
||||
# You can the continue and process these variables.
|
||||
#
|
||||
# Keywords terminate lists of values, e.g. if directly after a one_value_keyword
|
||||
# another recognized keyword follows, this is interpreted as the beginning of
|
||||
# the new option.
|
||||
# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
|
||||
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
|
||||
# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
|
||||
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
|
||||
return()
|
||||
endif()
|
||||
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
|
||||
|
||||
|
||||
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
|
||||
# first set all result variables to empty/FALSE
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames})
|
||||
set(${prefix}_${arg_name})
|
||||
endforeach(arg_name)
|
||||
|
||||
foreach(option ${_optionNames})
|
||||
set(${prefix}_${option} FALSE)
|
||||
endforeach(option)
|
||||
|
||||
set(${prefix}_UNPARSED_ARGUMENTS)
|
||||
|
||||
set(insideValues FALSE)
|
||||
set(currentArgName)
|
||||
|
||||
# now iterate over all arguments and fill the result variables
|
||||
foreach(currentArg ${ARGN})
|
||||
list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
|
||||
if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
|
||||
if(insideValues)
|
||||
if("${insideValues}" STREQUAL "SINGLE")
|
||||
set(${prefix}_${currentArgName} ${currentArg})
|
||||
set(insideValues FALSE)
|
||||
elseif("${insideValues}" STREQUAL "MULTI")
|
||||
list(APPEND ${prefix}_${currentArgName} ${currentArg})
|
||||
endif()
|
||||
else(insideValues)
|
||||
list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
|
||||
endif(insideValues)
|
||||
else()
|
||||
if(NOT ${optionIndex} EQUAL -1)
|
||||
set(${prefix}_${currentArg} TRUE)
|
||||
set(insideValues FALSE)
|
||||
elseif(NOT ${singleArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "SINGLE")
|
||||
elseif(NOT ${multiArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "MULTI")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach(currentArg)
|
||||
|
||||
# propagate the result variables to the caller:
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
|
||||
set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
|
||||
endforeach(arg_name)
|
||||
set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
|
||||
|
||||
endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
|
|
@ -0,0 +1,36 @@
|
|||
# http://www.cmake.org/pipermail/cmake/2006-October/011446.html
|
||||
# Modified to use pkg config and use standard var names
|
||||
|
||||
#
|
||||
# Find the CppUnit includes and library
|
||||
#
|
||||
# This module defines
|
||||
# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
|
||||
# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
|
||||
# CPPUNIT_FOUND, If false, do not try to use CppUnit.
|
||||
|
||||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(PC_CPPUNIT "cppunit")
|
||||
|
||||
FIND_PATH(CPPUNIT_INCLUDE_DIRS
|
||||
NAMES cppunit/TestCase.h
|
||||
HINTS ${PC_CPPUNIT_INCLUDE_DIR}
|
||||
PATHS
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(CPPUNIT_LIBRARIES
|
||||
NAMES cppunit
|
||||
HINTS ${PC_CPPUNIT_LIBDIR}
|
||||
PATHS
|
||||
${CPPUNIT_INCLUDE_DIRS}/../lib
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
|
@ -0,0 +1,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)
|
|
@ -0,0 +1,210 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Set global variable macro.
|
||||
# Used for subdirectories to export settings.
|
||||
# Example: include and library paths.
|
||||
########################################################################
|
||||
function(GR_SET_GLOBAL var)
|
||||
set(${var} ${ARGN} CACHE INTERNAL "" FORCE)
|
||||
endfunction(GR_SET_GLOBAL)
|
||||
|
||||
########################################################################
|
||||
# Set the pre-processor definition if the condition is true.
|
||||
# - def the pre-processor definition to set and condition name
|
||||
########################################################################
|
||||
function(GR_ADD_COND_DEF def)
|
||||
if(${def})
|
||||
add_definitions(-D${def})
|
||||
endif(${def})
|
||||
endfunction(GR_ADD_COND_DEF)
|
||||
|
||||
########################################################################
|
||||
# Check for a header and conditionally set a compile define.
|
||||
# - hdr the relative path to the header file
|
||||
# - def the pre-processor definition to set
|
||||
########################################################################
|
||||
function(GR_CHECK_HDR_N_DEF hdr def)
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX(${hdr} ${def})
|
||||
GR_ADD_COND_DEF(${def})
|
||||
endfunction(GR_CHECK_HDR_N_DEF)
|
||||
|
||||
########################################################################
|
||||
# Include subdirectory macro.
|
||||
# Sets the CMake directory variables,
|
||||
# includes the subdirectory CMakeLists.txt,
|
||||
# resets the CMake directory variables.
|
||||
#
|
||||
# This macro includes subdirectories rather than adding them
|
||||
# so that the subdirectory can affect variables in the level above.
|
||||
# This provides a work-around for the lack of convenience libraries.
|
||||
# This way a subdirectory can append to the list of library sources.
|
||||
########################################################################
|
||||
macro(GR_INCLUDE_SUBDIRECTORY subdir)
|
||||
#insert the current directories on the front of the list
|
||||
list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
#set the current directories to the names of the subdirs
|
||||
set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir})
|
||||
set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir})
|
||||
|
||||
#include the subdirectory CMakeLists to run it
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
|
||||
|
||||
#reset the value of the current directories
|
||||
list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR)
|
||||
list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR)
|
||||
|
||||
#pop the subdir names of the front of the list
|
||||
list(REMOVE_AT _cmake_source_dirs 0)
|
||||
list(REMOVE_AT _cmake_binary_dirs 0)
|
||||
endmacro(GR_INCLUDE_SUBDIRECTORY)
|
||||
|
||||
########################################################################
|
||||
# Check if a compiler flag works and conditionally set a compile define.
|
||||
# - flag the compiler flag to check for
|
||||
# - have the variable to set with result
|
||||
########################################################################
|
||||
macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
|
||||
if(${have})
|
||||
add_definitions(${flag})
|
||||
endif(${have})
|
||||
endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
|
||||
|
||||
########################################################################
|
||||
# Generates the .la libtool file
|
||||
# This appears to generate libtool files that cannot be used by auto*.
|
||||
# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest])
|
||||
# Notice: there is not COMPONENT option, these will not get distributed.
|
||||
########################################################################
|
||||
function(GR_LIBTOOL)
|
||||
if(NOT DEFINED GENERATE_LIBTOOL)
|
||||
set(GENERATE_LIBTOOL OFF) #disabled by default
|
||||
endif()
|
||||
|
||||
if(GENERATE_LIBTOOL)
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN})
|
||||
|
||||
find_program(LIBTOOL libtool)
|
||||
if(LIBTOOL)
|
||||
include(CMakeMacroLibtoolFile)
|
||||
CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION})
|
||||
endif(LIBTOOL)
|
||||
endif(GENERATE_LIBTOOL)
|
||||
|
||||
endfunction(GR_LIBTOOL)
|
||||
|
||||
########################################################################
|
||||
# Do standard things to the library target
|
||||
# - set target properties
|
||||
# - make install rules
|
||||
# Also handle gnuradio custom naming conventions w/ extras mode.
|
||||
########################################################################
|
||||
function(GR_LIBRARY_FOO target)
|
||||
#parse the arguments for component names
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN})
|
||||
|
||||
#set additional target properties
|
||||
set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER})
|
||||
|
||||
#install the generated files like so...
|
||||
install(TARGETS ${target}
|
||||
LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file
|
||||
ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file
|
||||
RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file
|
||||
)
|
||||
|
||||
#extras mode enabled automatically on linux
|
||||
if(NOT DEFINED LIBRARY_EXTRAS)
|
||||
set(LIBRARY_EXTRAS ${LINUX})
|
||||
endif()
|
||||
|
||||
#special extras mode to enable alternative naming conventions
|
||||
if(LIBRARY_EXTRAS)
|
||||
|
||||
#create .la file before changing props
|
||||
GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR})
|
||||
|
||||
#give the library a special name with ultra-zero soversion
|
||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0")
|
||||
set(target_name lib${target}-${LIBVER}.so.0.0.0)
|
||||
|
||||
#custom command to generate symlinks
|
||||
add_custom_command(
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install
|
||||
)
|
||||
|
||||
#and install the extra symlinks
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
|
||||
DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT}
|
||||
)
|
||||
|
||||
endif(LIBRARY_EXTRAS)
|
||||
endfunction(GR_LIBRARY_FOO)
|
||||
|
||||
########################################################################
|
||||
# Create a dummy custom command that depends on other targets.
|
||||
# Usage:
|
||||
# GR_GEN_TARGET_DEPS(unique_name target_deps <target1> <target2> ...)
|
||||
# ADD_CUSTOM_COMMAND(<the usual args> ${target_deps})
|
||||
#
|
||||
# Custom command cant depend on targets, but can depend on executables,
|
||||
# and executables can depend on targets. So this is the process:
|
||||
########################################################################
|
||||
function(GR_GEN_TARGET_DEPS name var)
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
|
||||
"int main(void){return 0;}\n"
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp
|
||||
)
|
||||
add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp)
|
||||
if(ARGN)
|
||||
add_dependencies(${name} ${ARGN})
|
||||
endif(ARGN)
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross
|
||||
else()
|
||||
set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction(GR_GEN_TARGET_DEPS)
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_PLATFORM_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Setup additional defines for OS types
|
||||
########################################################################
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
|
||||
if(LINUX AND EXISTS "/etc/debian_version")
|
||||
set(DEBIAN TRUE)
|
||||
endif()
|
||||
|
||||
if(LINUX AND EXISTS "/etc/redhat-release")
|
||||
set(REDHAT TRUE)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# when the library suffix should be 64 (applies to redhat linux family)
|
||||
########################################################################
|
||||
if(NOT DEFINED LIB_SUFFIX AND REDHAT AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$")
|
||||
set(LIB_SUFFIX 64)
|
||||
endif()
|
||||
set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix")
|
|
@ -0,0 +1,227 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_PYTHON_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_PYTHON_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Setup the python interpreter:
|
||||
# This allows the user to specify a specific interpreter,
|
||||
# or finds the interpreter via the built-in cmake module.
|
||||
########################################################################
|
||||
#this allows the user to override PYTHON_EXECUTABLE
|
||||
if(PYTHON_EXECUTABLE)
|
||||
|
||||
set(PYTHONINTERP_FOUND TRUE)
|
||||
|
||||
#otherwise if not set, try to automatically find it
|
||||
else(PYTHON_EXECUTABLE)
|
||||
|
||||
#use the built-in find script
|
||||
find_package(PythonInterp 2)
|
||||
|
||||
#and if that fails use the find program routine
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5)
|
||||
if(PYTHON_EXECUTABLE)
|
||||
set(PYTHONINTERP_FOUND TRUE)
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
endif(NOT PYTHONINTERP_FOUND)
|
||||
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
|
||||
#make the path to the executable appear in the cmake gui
|
||||
set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
|
||||
|
||||
#make sure we can use -B with python (introduced in 2.6)
|
||||
if(PYTHON_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -B -c ""
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT
|
||||
)
|
||||
if(PYTHON_HAS_DASH_B_RESULT EQUAL 0)
|
||||
set(PYTHON_DASH_B "-B")
|
||||
endif()
|
||||
endif(PYTHON_EXECUTABLE)
|
||||
|
||||
########################################################################
|
||||
# Check for the existence of a python module:
|
||||
# - desc a string description of the check
|
||||
# - mod the name of the module to import
|
||||
# - cmd an additional command to run
|
||||
# - have the result variable to set
|
||||
########################################################################
|
||||
macro(GR_PYTHON_CHECK_MODULE desc mod cmd have)
|
||||
message(STATUS "")
|
||||
message(STATUS "Python checking for ${desc}")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||
#########################################
|
||||
try: import ${mod}
|
||||
except: exit(-1)
|
||||
try: assert ${cmd}
|
||||
except: exit(-1)
|
||||
#########################################"
|
||||
RESULT_VARIABLE ${have}
|
||||
)
|
||||
if(${have} EQUAL 0)
|
||||
message(STATUS "Python checking for ${desc} - found")
|
||||
set(${have} TRUE)
|
||||
else(${have} EQUAL 0)
|
||||
message(STATUS "Python checking for ${desc} - not found")
|
||||
set(${have} FALSE)
|
||||
endif(${have} EQUAL 0)
|
||||
endmacro(GR_PYTHON_CHECK_MODULE)
|
||||
|
||||
########################################################################
|
||||
# Sets the python installation directory GR_PYTHON_DIR
|
||||
########################################################################
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||
from distutils import sysconfig
|
||||
print sysconfig.get_python_lib(plat_specific=True, prefix='')
|
||||
" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
|
||||
|
||||
########################################################################
|
||||
# Create an always-built target with a unique name
|
||||
# Usage: GR_UNIQUE_TARGET(<description> <dependencies list>)
|
||||
########################################################################
|
||||
function(GR_UNIQUE_TARGET desc)
|
||||
file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
|
||||
unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
|
||||
print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))"
|
||||
OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
add_custom_target(${_target} ALL DEPENDS ${ARGN})
|
||||
endfunction(GR_UNIQUE_TARGET)
|
||||
|
||||
########################################################################
|
||||
# Install python sources (also builds and installs byte-compiled python)
|
||||
########################################################################
|
||||
function(GR_PYTHON_INSTALL)
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN})
|
||||
|
||||
####################################################################
|
||||
if(GR_PYTHON_INSTALL_FILES)
|
||||
####################################################################
|
||||
install(${ARGN}) #installs regular python files
|
||||
|
||||
#create a list of all generated files
|
||||
unset(pysrcfiles)
|
||||
unset(pycfiles)
|
||||
unset(pyofiles)
|
||||
foreach(pyfile ${GR_PYTHON_INSTALL_FILES})
|
||||
get_filename_component(pyfile ${pyfile} ABSOLUTE)
|
||||
list(APPEND pysrcfiles ${pyfile})
|
||||
|
||||
#determine if this file is in the source or binary directory
|
||||
file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile})
|
||||
string(LENGTH "${source_rel_path}" source_rel_path_len)
|
||||
file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile})
|
||||
string(LENGTH "${binary_rel_path}" binary_rel_path_len)
|
||||
|
||||
#and set the generated path appropriately
|
||||
if(${source_rel_path_len} GREATER ${binary_rel_path_len})
|
||||
set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path})
|
||||
else()
|
||||
set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path})
|
||||
endif()
|
||||
list(APPEND pycfiles ${pygenfile}c)
|
||||
list(APPEND pyofiles ${pygenfile}o)
|
||||
|
||||
#ensure generation path exists
|
||||
get_filename_component(pygen_path ${pygenfile} PATH)
|
||||
file(MAKE_DIRECTORY ${pygen_path})
|
||||
|
||||
endforeach(pyfile)
|
||||
|
||||
#the command to generate the pyc files
|
||||
add_custom_command(
|
||||
DEPENDS ${pysrcfiles} OUTPUT ${pycfiles}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles}
|
||||
)
|
||||
|
||||
#the command to generate the pyo files
|
||||
add_custom_command(
|
||||
DEPENDS ${pysrcfiles} OUTPUT ${pyofiles}
|
||||
COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles}
|
||||
)
|
||||
|
||||
#create install rule and add generated files to target list
|
||||
set(python_install_gen_targets ${pycfiles} ${pyofiles})
|
||||
install(FILES ${python_install_gen_targets}
|
||||
DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
|
||||
)
|
||||
|
||||
|
||||
####################################################################
|
||||
elseif(GR_PYTHON_INSTALL_PROGRAMS)
|
||||
####################################################################
|
||||
file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
|
||||
|
||||
foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
|
||||
get_filename_component(pyfile_name ${pyfile} NAME)
|
||||
get_filename_component(pyfile ${pyfile} ABSOLUTE)
|
||||
string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe")
|
||||
list(APPEND python_install_gen_targets ${pyexefile})
|
||||
|
||||
get_filename_component(pyexefile_path ${pyexefile} PATH)
|
||||
file(MAKE_DIRECTORY ${pyexefile_path})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${pyexefile} DEPENDS ${pyfile}
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c
|
||||
\"open('${pyexefile}', 'w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())\"
|
||||
COMMENT "Shebangin ${pyfile_name}"
|
||||
)
|
||||
|
||||
#on windows, python files need an extension to execute
|
||||
get_filename_component(pyfile_ext ${pyfile} EXT)
|
||||
if(WIN32 AND NOT pyfile_ext)
|
||||
set(pyfile_name "${pyfile_name}.py")
|
||||
endif()
|
||||
|
||||
install(PROGRAMS ${pyexefile} RENAME ${pyfile_name}
|
||||
DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
|
||||
)
|
||||
endforeach(pyfile)
|
||||
|
||||
endif()
|
||||
|
||||
GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets})
|
||||
|
||||
endfunction(GR_PYTHON_INSTALL)
|
||||
|
||||
########################################################################
|
||||
# Write the python helper script that generates byte code files
|
||||
########################################################################
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py "
|
||||
import sys, py_compile
|
||||
files = sys.argv[1:]
|
||||
srcs, gens = files[:len(files)/2], files[len(files)/2:]
|
||||
for src, gen in zip(srcs, gens):
|
||||
py_compile.compile(file=src, cfile=gen, doraise=True)
|
||||
")
|
|
@ -0,0 +1,229 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_SWIG_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_SWIG_CMAKE TRUE)
|
||||
|
||||
include(GrPython)
|
||||
|
||||
########################################################################
|
||||
# Builds a swig documentation file to be generated into python docstrings
|
||||
# Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....)
|
||||
#
|
||||
# Set the following variable to specify extra dependent targets:
|
||||
# - GR_SWIG_DOCS_SOURCE_DEPS
|
||||
# - GR_SWIG_DOCS_TARGET_DEPS
|
||||
########################################################################
|
||||
function(GR_SWIG_MAKE_DOCS output_file)
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
|
||||
#setup the input files variable list, quote formated
|
||||
set(input_files)
|
||||
unset(INPUT_PATHS)
|
||||
foreach(input_path ${ARGN})
|
||||
if (IS_DIRECTORY ${input_path}) #when input path is a directory
|
||||
file(GLOB input_path_h_files ${input_path}/*.h)
|
||||
else() #otherwise its just a file, no glob
|
||||
set(input_path_h_files ${input_path})
|
||||
endif()
|
||||
list(APPEND input_files ${input_path_h_files})
|
||||
set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"")
|
||||
endforeach(input_path)
|
||||
|
||||
#determine the output directory
|
||||
get_filename_component(name ${output_file} NAME_WE)
|
||||
get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH)
|
||||
set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs)
|
||||
make_directory(${OUTPUT_DIRECTORY})
|
||||
|
||||
#generate the Doxyfile used by doxygen
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in
|
||||
${OUTPUT_DIRECTORY}/Doxyfile
|
||||
@ONLY)
|
||||
|
||||
#Create a dummy custom command that depends on other targets
|
||||
include(GrMiscUtils)
|
||||
GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS})
|
||||
|
||||
#call doxygen on the Doxyfile + input headers
|
||||
add_custom_command(
|
||||
OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml
|
||||
DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile
|
||||
COMMENT "Generating doxygen xml for ${name} docs"
|
||||
)
|
||||
|
||||
#call the swig_doc script on the xml files
|
||||
add_custom_command(
|
||||
OUTPUT ${output_file}
|
||||
DEPENDS ${input_files} ${OUTPUT_DIRECTORY}/xml/index.xml
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||
${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py
|
||||
${OUTPUT_DIRECTORY}/xml
|
||||
${output_file}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen
|
||||
)
|
||||
|
||||
else(DOXYGEN_FOUND)
|
||||
file(WRITE ${output_file} "\n") #no doxygen -> empty file
|
||||
endif(DOXYGEN_FOUND)
|
||||
endfunction(GR_SWIG_MAKE_DOCS)
|
||||
|
||||
########################################################################
|
||||
# Build a swig target for the common gnuradio use case. Usage:
|
||||
# GR_SWIG_MAKE(target ifile ifile ifile...)
|
||||
#
|
||||
# Set the following variables before calling:
|
||||
# - GR_SWIG_FLAGS
|
||||
# - GR_SWIG_INCLUDE_DIRS
|
||||
# - GR_SWIG_LIBRARIES
|
||||
# - GR_SWIG_SOURCE_DEPS
|
||||
# - GR_SWIG_TARGET_DEPS
|
||||
# - GR_SWIG_DOC_FILE
|
||||
# - GR_SWIG_DOC_DIRS
|
||||
########################################################################
|
||||
macro(GR_SWIG_MAKE name)
|
||||
set(ifiles ${ARGN})
|
||||
|
||||
#do swig doc generation if specified
|
||||
if (GR_SWIG_DOC_FILE)
|
||||
set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
|
||||
set(GR_SWIG_DOCS_TAREGT_DEPS ${GR_SWIG_TARGET_DEPS})
|
||||
GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
|
||||
list(APPEND GR_SWIG_SOURCE_DEPS ${GR_SWIG_DOC_FILE})
|
||||
endif()
|
||||
|
||||
#append additional include directories
|
||||
find_package(PythonLibs 2)
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs)
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
#determine include dependencies for swig file
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${CMAKE_BINARY_DIR}/get_swig_deps.py
|
||||
"${ifiles}" "${GR_SWIG_INCLUDE_DIRS}"
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
#Create a dummy custom command that depends on other targets
|
||||
include(GrMiscUtils)
|
||||
GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS})
|
||||
set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag)
|
||||
add_custom_command(
|
||||
OUTPUT ${tag_file}
|
||||
DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${tag_file}
|
||||
)
|
||||
|
||||
#append the specified include directories
|
||||
include_directories(${GR_SWIG_INCLUDE_DIRS})
|
||||
list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file})
|
||||
|
||||
#setup the swig flags with flags and include directories
|
||||
set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS})
|
||||
foreach(dir ${GR_SWIG_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_SWIG_FLAGS "-I${dir}")
|
||||
endforeach(dir)
|
||||
|
||||
#set the C++ property on the swig .i file so it builds
|
||||
set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON)
|
||||
|
||||
#setup the actual swig library target to be built
|
||||
include(UseSWIG)
|
||||
SWIG_ADD_MODULE(${name} python ${ifiles})
|
||||
SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
|
||||
|
||||
endmacro(GR_SWIG_MAKE)
|
||||
|
||||
########################################################################
|
||||
# Install swig targets generated by GR_SWIG_MAKE. Usage:
|
||||
# GR_SWIG_INSTALL(
|
||||
# TARGETS target target target...
|
||||
# [DESTINATION destination]
|
||||
# [COMPONENT component]
|
||||
# )
|
||||
########################################################################
|
||||
macro(GR_SWIG_INSTALL)
|
||||
|
||||
include(CMakeParseArgumentsCopy)
|
||||
CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
|
||||
|
||||
foreach(name ${GR_SWIG_INSTALL_TARGETS})
|
||||
install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME}
|
||||
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
|
||||
)
|
||||
|
||||
include(GrPython)
|
||||
GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py
|
||||
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||
COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
|
||||
)
|
||||
|
||||
GR_LIBTOOL(
|
||||
TARGET ${SWIG_MODULE_${name}_REAL_NAME}
|
||||
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||
)
|
||||
|
||||
endforeach(name)
|
||||
|
||||
endmacro(GR_SWIG_INSTALL)
|
||||
|
||||
########################################################################
|
||||
# Generate a python file that can determine swig dependencies.
|
||||
# Used by the make macro above to determine extra dependencies.
|
||||
# When you build C++, CMake figures out the header dependencies.
|
||||
# This code essentially performs that logic for swig includes.
|
||||
########################################################################
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py "
|
||||
|
||||
import os, sys, re
|
||||
|
||||
include_matcher = re.compile('[#|%]include\\s*[<|\"](.*)[>|\"]')
|
||||
include_dirs = sys.argv[2].split(';')
|
||||
|
||||
def get_swig_incs(file_path):
|
||||
file_contents = open(file_path, 'r').read()
|
||||
return include_matcher.findall(file_contents, re.MULTILINE)
|
||||
|
||||
def get_swig_deps(file_path, level):
|
||||
deps = [file_path]
|
||||
if level == 0: return deps
|
||||
for inc_file in get_swig_incs(file_path):
|
||||
for inc_dir in include_dirs:
|
||||
inc_path = os.path.join(inc_dir, inc_file)
|
||||
if not os.path.exists(inc_path): continue
|
||||
deps.extend(get_swig_deps(inc_path, level-1))
|
||||
return deps
|
||||
|
||||
if __name__ == '__main__':
|
||||
ifiles = sys.argv[1].split(';')
|
||||
deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], [])
|
||||
#sys.stderr.write(';'.join(set(deps)) + '\\n\\n')
|
||||
print(';'.join(set(deps)))
|
||||
")
|
|
@ -0,0 +1,133 @@
|
|||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_GR_TEST_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_GR_TEST_CMAKE TRUE)
|
||||
|
||||
########################################################################
|
||||
# Add a unit test and setup the environment for a unit test.
|
||||
# Takes the same arguments as the ADD_TEST function.
|
||||
#
|
||||
# Before calling set the following variables:
|
||||
# GR_TEST_TARGET_DEPS - built targets for the library path
|
||||
# GR_TEST_LIBRARY_DIRS - directories for the library path
|
||||
# GR_TEST_PYTHON_DIRS - directories for the python path
|
||||
########################################################################
|
||||
function(GR_ADD_TEST test_name)
|
||||
|
||||
if(WIN32)
|
||||
#Ensure that the build exe also appears in the PATH.
|
||||
list(APPEND GR_TEST_TARGET_DEPS ${ARGN})
|
||||
|
||||
#In the land of windows, all libraries must be in the PATH.
|
||||
#Since the dependent libraries are not yet installed,
|
||||
#we must manually set them in the PATH to run tests.
|
||||
#The following appends the path of a target dependency.
|
||||
foreach(target ${GR_TEST_TARGET_DEPS})
|
||||
get_target_property(location ${target} LOCATION)
|
||||
if(location)
|
||||
get_filename_component(path ${location} PATH)
|
||||
string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path})
|
||||
list(APPEND GR_TEST_LIBRARY_DIRS ${path})
|
||||
endif(location)
|
||||
endforeach(target)
|
||||
|
||||
#SWIG generates the python library files into a subdirectory.
|
||||
#Therefore, we must append this subdirectory into PYTHONPATH.
|
||||
#Only do this for the python directories matching the following:
|
||||
foreach(pydir ${GR_TEST_PYTHON_DIRS})
|
||||
get_filename_component(name ${pydir} NAME)
|
||||
if(name MATCHES "^(swig|lib|src)$")
|
||||
list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
endforeach(pydir)
|
||||
endif(WIN32)
|
||||
|
||||
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir)
|
||||
file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list?
|
||||
file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list?
|
||||
|
||||
set(environs "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}")
|
||||
|
||||
#http://www.cmake.org/pipermail/cmake/2009-May/029464.html
|
||||
#Replaced this add test + set environs code with the shell script generation.
|
||||
#Its nicer to be able to manually run the shell script to diagnose problems.
|
||||
#ADD_TEST(${ARGV})
|
||||
#SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}")
|
||||
|
||||
if(UNIX)
|
||||
set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH")
|
||||
#set both LD and DYLD paths to cover multiple UNIX OS library paths
|
||||
list(APPEND libpath "$LD_LIBRARY_PATH" "$DYLD_LIBRARY_PATH")
|
||||
list(APPEND pypath "$PYTHONPATH")
|
||||
|
||||
#replace list separator with the path separator
|
||||
string(REPLACE ";" ":" libpath "${libpath}")
|
||||
string(REPLACE ";" ":" pypath "${pypath}")
|
||||
list(APPEND environs "PATH=${binpath}" "LD_LIBRARY_PATH=${libpath}" "DYLD_LIBRARY_PATH=${libpath}" "PYTHONPATH=${pypath}")
|
||||
|
||||
#generate a bat file that sets the environment and runs the test
|
||||
find_program(SHELL sh)
|
||||
set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
|
||||
file(WRITE ${sh_file} "#!${SHELL}\n")
|
||||
#each line sets an environment variable
|
||||
foreach(environ ${environs})
|
||||
file(APPEND ${sh_file} "export ${environ}\n")
|
||||
endforeach(environ)
|
||||
#load the command to run with its arguments
|
||||
foreach(arg ${ARGN})
|
||||
file(APPEND ${sh_file} "${arg} ")
|
||||
endforeach(arg)
|
||||
file(APPEND ${sh_file} "\n")
|
||||
|
||||
#make the shell file executable
|
||||
execute_process(COMMAND chmod +x ${sh_file})
|
||||
|
||||
add_test(${test_name} ${SHELL} ${sh_file})
|
||||
|
||||
endif(UNIX)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND libpath ${DLL_PATHS} "%PATH%")
|
||||
list(APPEND pypath "%PYTHONPATH%")
|
||||
|
||||
#replace list separator with the path separator (escaped)
|
||||
string(REPLACE ";" "\\;" libpath "${libpath}")
|
||||
string(REPLACE ";" "\\;" pypath "${pypath}")
|
||||
list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}")
|
||||
|
||||
#generate a bat file that sets the environment and runs the test
|
||||
set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat)
|
||||
file(WRITE ${bat_file} "@echo off\n")
|
||||
#each line sets an environment variable
|
||||
foreach(environ ${environs})
|
||||
file(APPEND ${bat_file} "SET ${environ}\n")
|
||||
endforeach(environ)
|
||||
#load the command to run with its arguments
|
||||
foreach(arg ${ARGN})
|
||||
file(APPEND ${bat_file} "${arg} ")
|
||||
endforeach(arg)
|
||||
file(APPEND ${bat_file} "\n")
|
||||
|
||||
add_test(${test_name} ${bat_file})
|
||||
endif(WIN32)
|
||||
|
||||
endfunction(GR_ADD_TEST)
|
|
@ -0,0 +1,32 @@
|
|||
# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
|
||||
|
||||
IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
STRING(REGEX REPLACE "\n" ";" files "${files}")
|
||||
FOREACH(file ${files})
|
||||
MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
IF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSE(EXISTS "$ENV{DESTDIR}${file}")
|
||||
MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
ENDIF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
ENDFOREACH(file)
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Setup dependencies
|
||||
########################################################################
|
||||
find_package(Doxygen)
|
||||
|
||||
########################################################################
|
||||
# Begin conditional configuration
|
||||
########################################################################
|
||||
if(ENABLE_DOXYGEN)
|
||||
|
||||
########################################################################
|
||||
# Add subdirectories
|
||||
########################################################################
|
||||
add_subdirectory(doxygen)
|
||||
|
||||
endif(ENABLE_DOXYGEN)
|
|
@ -0,0 +1,11 @@
|
|||
This is the 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)
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Create the doxygen configuration file
|
||||
########################################################################
|
||||
file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir)
|
||||
file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir)
|
||||
file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir)
|
||||
file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir)
|
||||
|
||||
set(HAVE_DOT ${DOXYGEN_DOT_FOUND})
|
||||
set(enable_html_docs YES)
|
||||
set(enable_latex_docs NO)
|
||||
set(enable_xml_docs YES)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
@ONLY)
|
||||
|
||||
set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html)
|
||||
|
||||
########################################################################
|
||||
# Make and install doxygen docs
|
||||
########################################################################
|
||||
add_custom_command(
|
||||
OUTPUT ${BUILT_DIRS}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating documentation with doxygen"
|
||||
)
|
||||
|
||||
add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS})
|
||||
|
||||
install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR})
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Python interface to contents of doxygen xml documentation.
|
||||
|
||||
Example use:
|
||||
See the contents of the example folder for the C++ and
|
||||
doxygen-generated xml used in this example.
|
||||
|
||||
>>> # Parse the doxygen docs.
|
||||
>>> import os
|
||||
>>> this_dir = os.path.dirname(globals()['__file__'])
|
||||
>>> xml_path = this_dir + "/example/xml/"
|
||||
>>> di = DoxyIndex(xml_path)
|
||||
|
||||
Get a list of all top-level objects.
|
||||
|
||||
>>> print([mem.name() for mem in di.members()])
|
||||
[u'Aadvark', u'aadvarky_enough', u'main']
|
||||
|
||||
Get all functions.
|
||||
|
||||
>>> print([mem.name() for mem in di.in_category(DoxyFunction)])
|
||||
[u'aadvarky_enough', u'main']
|
||||
|
||||
Check if an object is present.
|
||||
|
||||
>>> di.has_member(u'Aadvark')
|
||||
True
|
||||
>>> di.has_member(u'Fish')
|
||||
False
|
||||
|
||||
Get an item by name and check its properties.
|
||||
|
||||
>>> aad = di.get_member(u'Aadvark')
|
||||
>>> print(aad.brief_description)
|
||||
Models the mammal Aadvark.
|
||||
>>> print(aad.detailed_description)
|
||||
Sadly the model is incomplete and cannot capture all aspects of an aadvark yet.
|
||||
<BLANKLINE>
|
||||
This line is uninformative and is only to test line breaks in the comments.
|
||||
>>> [mem.name() for mem in aad.members()]
|
||||
[u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness']
|
||||
>>> aad.get_member(u'print').brief_description
|
||||
u'Outputs the vital aadvark statistics.'
|
||||
|
||||
"""
|
||||
|
||||
from doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther
|
||||
|
||||
def _test():
|
||||
import os
|
||||
this_dir = os.path.dirname(globals()['__file__'])
|
||||
xml_path = this_dir + "/example/xml/"
|
||||
di = DoxyIndex(xml_path)
|
||||
# Get the Aadvark class
|
||||
aad = di.get_member('Aadvark')
|
||||
aad.brief_description
|
||||
import doctest
|
||||
return doctest.testmod()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
A base class is created.
|
||||
|
||||
Classes based upon this are used to make more user-friendly interfaces
|
||||
to the doxygen xml docs than the generated classes provide.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pdb
|
||||
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
from generated import compound
|
||||
|
||||
|
||||
class Base(object):
|
||||
|
||||
class Duplicate(StandardError):
|
||||
pass
|
||||
|
||||
class NoSuchMember(StandardError):
|
||||
pass
|
||||
|
||||
class ParsingError(StandardError):
|
||||
pass
|
||||
|
||||
def __init__(self, parse_data, top=None):
|
||||
self._parsed = False
|
||||
self._error = False
|
||||
self._parse_data = parse_data
|
||||
self._members = []
|
||||
self._dict_members = {}
|
||||
self._in_category = {}
|
||||
self._data = {}
|
||||
if top is not None:
|
||||
self._xml_path = top._xml_path
|
||||
# Set up holder of references
|
||||
else:
|
||||
top = self
|
||||
self._refs = {}
|
||||
self._xml_path = parse_data
|
||||
self.top = top
|
||||
|
||||
@classmethod
|
||||
def from_refid(cls, refid, top=None):
|
||||
""" Instantiate class from a refid rather than parsing object. """
|
||||
# First check to see if its already been instantiated.
|
||||
if top is not None and refid in top._refs:
|
||||
return top._refs[refid]
|
||||
# Otherwise create a new instance and set refid.
|
||||
inst = cls(None, top=top)
|
||||
inst.refid = refid
|
||||
inst.add_ref(inst)
|
||||
return inst
|
||||
|
||||
@classmethod
|
||||
def from_parse_data(cls, parse_data, top=None):
|
||||
refid = getattr(parse_data, 'refid', None)
|
||||
if refid is not None and top is not None and refid in top._refs:
|
||||
return top._refs[refid]
|
||||
inst = cls(parse_data, top=top)
|
||||
if refid is not None:
|
||||
inst.refid = refid
|
||||
inst.add_ref(inst)
|
||||
return inst
|
||||
|
||||
def add_ref(self, obj):
|
||||
if hasattr(obj, 'refid'):
|
||||
self.top._refs[obj.refid] = obj
|
||||
|
||||
mem_classes = []
|
||||
|
||||
def get_cls(self, mem):
|
||||
for cls in self.mem_classes:
|
||||
if cls.can_parse(mem):
|
||||
return cls
|
||||
raise StandardError(("Did not find a class for object '%s'." \
|
||||
% (mem.get_name())))
|
||||
|
||||
def convert_mem(self, mem):
|
||||
try:
|
||||
cls = self.get_cls(mem)
|
||||
converted = cls.from_parse_data(mem, self.top)
|
||||
if converted is None:
|
||||
raise StandardError('No class matched this object.')
|
||||
self.add_ref(converted)
|
||||
return converted
|
||||
except StandardError, e:
|
||||
print e
|
||||
|
||||
@classmethod
|
||||
def includes(cls, inst):
|
||||
return isinstance(inst, cls)
|
||||
|
||||
@classmethod
|
||||
def can_parse(cls, obj):
|
||||
return False
|
||||
|
||||
def _parse(self):
|
||||
self._parsed = True
|
||||
|
||||
def _get_dict_members(self, cat=None):
|
||||
"""
|
||||
For given category a dictionary is returned mapping member names to
|
||||
members of that category. For names that are duplicated the name is
|
||||
mapped to None.
|
||||
"""
|
||||
self.confirm_no_error()
|
||||
if cat not in self._dict_members:
|
||||
new_dict = {}
|
||||
for mem in self.in_category(cat):
|
||||
if mem.name() not in new_dict:
|
||||
new_dict[mem.name()] = mem
|
||||
else:
|
||||
new_dict[mem.name()] = self.Duplicate
|
||||
self._dict_members[cat] = new_dict
|
||||
return self._dict_members[cat]
|
||||
|
||||
def in_category(self, cat):
|
||||
self.confirm_no_error()
|
||||
if cat is None:
|
||||
return self._members
|
||||
if cat not in self._in_category:
|
||||
self._in_category[cat] = [mem for mem in self._members
|
||||
if cat.includes(mem)]
|
||||
return self._in_category[cat]
|
||||
|
||||
def get_member(self, name, cat=None):
|
||||
self.confirm_no_error()
|
||||
# Check if it's in a namespace or class.
|
||||
bits = name.split('::')
|
||||
first = bits[0]
|
||||
rest = '::'.join(bits[1:])
|
||||
member = self._get_dict_members(cat).get(first, self.NoSuchMember)
|
||||
# Raise any errors that are returned.
|
||||
if member in set([self.NoSuchMember, self.Duplicate]):
|
||||
raise member()
|
||||
if rest:
|
||||
return member.get_member(rest, cat=cat)
|
||||
return member
|
||||
|
||||
def has_member(self, name, cat=None):
|
||||
try:
|
||||
mem = self.get_member(name, cat=cat)
|
||||
return True
|
||||
except self.NoSuchMember:
|
||||
return False
|
||||
|
||||
def data(self):
|
||||
self.confirm_no_error()
|
||||
return self._data
|
||||
|
||||
def members(self):
|
||||
self.confirm_no_error()
|
||||
return self._members
|
||||
|
||||
def process_memberdefs(self):
|
||||
mdtss = []
|
||||
for sec in self._retrieved_data.compounddef.sectiondef:
|
||||
mdtss += sec.memberdef
|
||||
# At the moment we lose all information associated with sections.
|
||||
# Sometimes a memberdef is in several sectiondef.
|
||||
# We make sure we don't get duplicates here.
|
||||
uniques = set([])
|
||||
for mem in mdtss:
|
||||
converted = self.convert_mem(mem)
|
||||
pair = (mem.name, mem.__class__)
|
||||
if pair not in uniques:
|
||||
uniques.add(pair)
|
||||
self._members.append(converted)
|
||||
|
||||
def retrieve_data(self):
|
||||
filename = os.path.join(self._xml_path, self.refid + '.xml')
|
||||
try:
|
||||
self._retrieved_data = compound.parse(filename)
|
||||
except ExpatError:
|
||||
print('Error in xml in file %s' % filename)
|
||||
self._error = True
|
||||
self._retrieved_data = None
|
||||
|
||||
def check_parsed(self):
|
||||
if not self._parsed:
|
||||
self._parse()
|
||||
|
||||
def confirm_no_error(self):
|
||||
self.check_parsed()
|
||||
if self._error:
|
||||
raise self.ParsingError()
|
||||
|
||||
def error(self):
|
||||
self.check_parsed()
|
||||
return self._error
|
||||
|
||||
def name(self):
|
||||
# first see if we can do it without processing.
|
||||
if self._parse_data is not None:
|
||||
return self._parse_data.name
|
||||
self.check_parsed()
|
||||
return self._retrieved_data.compounddef.name
|
|
@ -0,0 +1,237 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Classes providing more user-friendly interfaces to the doxygen xml
|
||||
docs than the generated classes provide.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from generated import index
|
||||
from base import Base
|
||||
from text import description
|
||||
|
||||
class DoxyIndex(Base):
|
||||
"""
|
||||
Parses a doxygen xml directory.
|
||||
"""
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyIndex, self)._parse()
|
||||
self._root = index.parse(os.path.join(self._xml_path, 'index.xml'))
|
||||
for mem in self._root.compound:
|
||||
converted = self.convert_mem(mem)
|
||||
# For files we want the contents to be accessible directly
|
||||
# from the parent rather than having to go through the file
|
||||
# object.
|
||||
if self.get_cls(mem) == DoxyFile:
|
||||
if mem.name.endswith('.h'):
|
||||
self._members += converted.members()
|
||||
self._members.append(converted)
|
||||
else:
|
||||
self._members.append(converted)
|
||||
|
||||
|
||||
def generate_swig_doc_i(self):
|
||||
"""
|
||||
%feature("docstring") gr_make_align_on_samplenumbers_ss::align_state "
|
||||
Wraps the C++: gr_align_on_samplenumbers_ss::align_state";
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DoxyCompMem(Base):
|
||||
|
||||
|
||||
kind = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DoxyCompMem, self).__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def can_parse(cls, obj):
|
||||
return obj.kind == cls.kind
|
||||
|
||||
def set_descriptions(self, parse_data):
|
||||
bd = description(getattr(parse_data, 'briefdescription', None))
|
||||
dd = description(getattr(parse_data, 'detaileddescription', None))
|
||||
self._data['brief_description'] = bd
|
||||
self._data['detailed_description'] = dd
|
||||
|
||||
class DoxyCompound(DoxyCompMem):
|
||||
pass
|
||||
|
||||
class DoxyMember(DoxyCompMem):
|
||||
pass
|
||||
|
||||
|
||||
class DoxyFunction(DoxyMember):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'function'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyFunction, self)._parse()
|
||||
self.set_descriptions(self._parse_data)
|
||||
self._data['params'] = []
|
||||
prms = self._parse_data.param
|
||||
for prm in prms:
|
||||
self._data['params'].append(DoxyParam(prm))
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
params = property(lambda self: self.data()['params'])
|
||||
|
||||
Base.mem_classes.append(DoxyFunction)
|
||||
|
||||
|
||||
class DoxyParam(DoxyMember):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyParam, self)._parse()
|
||||
self.set_descriptions(self._parse_data)
|
||||
self._data['declname'] = self._parse_data.declname
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
declname = property(lambda self: self.data()['declname'])
|
||||
|
||||
class DoxyClass(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'class'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyClass, self)._parse()
|
||||
self.retrieve_data()
|
||||
if self._error:
|
||||
return
|
||||
self.set_descriptions(self._retrieved_data.compounddef)
|
||||
# Sectiondef.kind tells about whether private or public.
|
||||
# We just ignore this for now.
|
||||
self.process_memberdefs()
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
|
||||
Base.mem_classes.append(DoxyClass)
|
||||
|
||||
|
||||
class DoxyFile(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'file'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyFile, self)._parse()
|
||||
self.retrieve_data()
|
||||
self.set_descriptions(self._retrieved_data.compounddef)
|
||||
if self._error:
|
||||
return
|
||||
self.process_memberdefs()
|
||||
|
||||
brief_description = property(lambda self: self.data()['brief_description'])
|
||||
detailed_description = property(lambda self: self.data()['detailed_description'])
|
||||
|
||||
Base.mem_classes.append(DoxyFile)
|
||||
|
||||
|
||||
class DoxyNamespace(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'namespace'
|
||||
|
||||
Base.mem_classes.append(DoxyNamespace)
|
||||
|
||||
|
||||
class DoxyGroup(DoxyCompound):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'group'
|
||||
|
||||
def _parse(self):
|
||||
if self._parsed:
|
||||
return
|
||||
super(DoxyGroup, self)._parse()
|
||||
self.retrieve_data()
|
||||
if self._error:
|
||||
return
|
||||
cdef = self._retrieved_data.compounddef
|
||||
self._data['title'] = description(cdef.title)
|
||||
# Process inner groups
|
||||
grps = cdef.innergroup
|
||||
for grp in grps:
|
||||
converted = DoxyGroup.from_refid(grp.refid, top=self.top)
|
||||
self._members.append(converted)
|
||||
# Process inner classes
|
||||
klasses = cdef.innerclass
|
||||
for kls in klasses:
|
||||
converted = DoxyClass.from_refid(kls.refid, top=self.top)
|
||||
self._members.append(converted)
|
||||
# Process normal members
|
||||
self.process_memberdefs()
|
||||
|
||||
title = property(lambda self: self.data()['title'])
|
||||
|
||||
|
||||
Base.mem_classes.append(DoxyGroup)
|
||||
|
||||
|
||||
class DoxyFriend(DoxyMember):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kind = 'friend'
|
||||
|
||||
Base.mem_classes.append(DoxyFriend)
|
||||
|
||||
|
||||
class DoxyOther(Base):
|
||||
|
||||
__module__ = "gnuradio.utils.doxyxml"
|
||||
|
||||
kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 'dir', 'page'])
|
||||
|
||||
@classmethod
|
||||
def can_parse(cls, obj):
|
||||
return obj.kind in cls.kinds
|
||||
|
||||
Base.mem_classes.append(DoxyOther)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
Contains generated files produced by generateDS.py.
|
||||
|
||||
These do the real work of parsing the doxygen xml files but the
|
||||
resultant classes are not very friendly to navigate so the rest of the
|
||||
doxyxml module processes them further.
|
||||
"""
|
|
@ -0,0 +1,503 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
|
||||
"""
|
||||
|
||||
from string import lower as str_lower
|
||||
from xml.dom import minidom
|
||||
from xml.dom import Node
|
||||
|
||||
import sys
|
||||
|
||||
import compoundsuper as supermod
|
||||
from compoundsuper import MixedContainer
|
||||
|
||||
|
||||
class DoxygenTypeSub(supermod.DoxygenType):
|
||||
def __init__(self, version=None, compounddef=None):
|
||||
supermod.DoxygenType.__init__(self, version, compounddef)
|
||||
|
||||
def find(self, details):
|
||||
|
||||
return self.compounddef.find(details)
|
||||
|
||||
supermod.DoxygenType.subclass = DoxygenTypeSub
|
||||
# end class DoxygenTypeSub
|
||||
|
||||
|
||||
class compounddefTypeSub(supermod.compounddefType):
|
||||
def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None):
|
||||
supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, incdepgraph, invincdepgraph, innerdir, innerfile, innerclass, innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, programlisting, location, listofallmembers)
|
||||
|
||||
def find(self, details):
|
||||
|
||||
if self.id == details.refid:
|
||||
return self
|
||||
|
||||
for sectiondef in self.sectiondef:
|
||||
result = sectiondef.find(details)
|
||||
if result:
|
||||
return result
|
||||
|
||||
|
||||
supermod.compounddefType.subclass = compounddefTypeSub
|
||||
# end class compounddefTypeSub
|
||||
|
||||
|
||||
class listofallmembersTypeSub(supermod.listofallmembersType):
|
||||
def __init__(self, member=None):
|
||||
supermod.listofallmembersType.__init__(self, member)
|
||||
supermod.listofallmembersType.subclass = listofallmembersTypeSub
|
||||
# end class listofallmembersTypeSub
|
||||
|
||||
|
||||
class memberRefTypeSub(supermod.memberRefType):
|
||||
def __init__(self, virt=None, prot=None, refid=None, ambiguityscope=None, scope='', name=''):
|
||||
supermod.memberRefType.__init__(self, virt, prot, refid, ambiguityscope, scope, name)
|
||||
supermod.memberRefType.subclass = memberRefTypeSub
|
||||
# end class memberRefTypeSub
|
||||
|
||||
|
||||
class compoundRefTypeSub(supermod.compoundRefType):
|
||||
def __init__(self, virt=None, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.compoundRefType.__init__(self, mixedclass_, content_)
|
||||
supermod.compoundRefType.subclass = compoundRefTypeSub
|
||||
# end class compoundRefTypeSub
|
||||
|
||||
|
||||
class reimplementTypeSub(supermod.reimplementType):
|
||||
def __init__(self, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.reimplementType.__init__(self, mixedclass_, content_)
|
||||
supermod.reimplementType.subclass = reimplementTypeSub
|
||||
# end class reimplementTypeSub
|
||||
|
||||
|
||||
class incTypeSub(supermod.incType):
|
||||
def __init__(self, local=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.incType.__init__(self, mixedclass_, content_)
|
||||
supermod.incType.subclass = incTypeSub
|
||||
# end class incTypeSub
|
||||
|
||||
|
||||
class refTypeSub(supermod.refType):
|
||||
def __init__(self, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.refType.__init__(self, mixedclass_, content_)
|
||||
supermod.refType.subclass = refTypeSub
|
||||
# end class refTypeSub
|
||||
|
||||
|
||||
|
||||
class refTextTypeSub(supermod.refTextType):
|
||||
def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.refTextType.__init__(self, mixedclass_, content_)
|
||||
|
||||
supermod.refTextType.subclass = refTextTypeSub
|
||||
# end class refTextTypeSub
|
||||
|
||||
class sectiondefTypeSub(supermod.sectiondefType):
|
||||
|
||||
|
||||
def __init__(self, kind=None, header='', description=None, memberdef=None):
|
||||
supermod.sectiondefType.__init__(self, kind, header, description, memberdef)
|
||||
|
||||
def find(self, details):
|
||||
|
||||
for memberdef in self.memberdef:
|
||||
if memberdef.id == details.refid:
|
||||
return memberdef
|
||||
|
||||
return None
|
||||
|
||||
|
||||
supermod.sectiondefType.subclass = sectiondefTypeSub
|
||||
# end class sectiondefTypeSub
|
||||
|
||||
|
||||
class memberdefTypeSub(supermod.memberdefType):
|
||||
def __init__(self, initonly=None, kind=None, volatile=None, const=None, raise_=None, virt=None, readable=None, prot=None, explicit=None, new=None, final=None, writable=None, add=None, static=None, remove=None, sealed=None, mutable=None, gettable=None, inline=None, settable=None, id=None, templateparamlist=None, type_=None, definition='', argsstring='', name='', read='', write='', bitfield='', reimplements=None, reimplementedby=None, param=None, enumvalue=None, initializer=None, exceptions=None, briefdescription=None, detaileddescription=None, inbodydescription=None, location=None, references=None, referencedby=None):
|
||||
supermod.memberdefType.__init__(self, initonly, kind, volatile, const, raise_, virt, readable, prot, explicit, new, final, writable, add, static, remove, sealed, mutable, gettable, inline, settable, id, templateparamlist, type_, definition, argsstring, name, read, write, bitfield, reimplements, reimplementedby, param, enumvalue, initializer, exceptions, briefdescription, detaileddescription, inbodydescription, location, references, referencedby)
|
||||
supermod.memberdefType.subclass = memberdefTypeSub
|
||||
# end class memberdefTypeSub
|
||||
|
||||
|
||||
class descriptionTypeSub(supermod.descriptionType):
|
||||
def __init__(self, title='', para=None, sect1=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.descriptionType.__init__(self, mixedclass_, content_)
|
||||
supermod.descriptionType.subclass = descriptionTypeSub
|
||||
# end class descriptionTypeSub
|
||||
|
||||
|
||||
class enumvalueTypeSub(supermod.enumvalueType):
|
||||
def __init__(self, prot=None, id=None, name='', initializer=None, briefdescription=None, detaileddescription=None, mixedclass_=None, content_=None):
|
||||
supermod.enumvalueType.__init__(self, mixedclass_, content_)
|
||||
supermod.enumvalueType.subclass = enumvalueTypeSub
|
||||
# end class enumvalueTypeSub
|
||||
|
||||
|
||||
class templateparamlistTypeSub(supermod.templateparamlistType):
|
||||
def __init__(self, param=None):
|
||||
supermod.templateparamlistType.__init__(self, param)
|
||||
supermod.templateparamlistType.subclass = templateparamlistTypeSub
|
||||
# end class templateparamlistTypeSub
|
||||
|
||||
|
||||
class paramTypeSub(supermod.paramType):
|
||||
def __init__(self, type_=None, declname='', defname='', array='', defval=None, briefdescription=None):
|
||||
supermod.paramType.__init__(self, type_, declname, defname, array, defval, briefdescription)
|
||||
supermod.paramType.subclass = paramTypeSub
|
||||
# end class paramTypeSub
|
||||
|
||||
|
||||
class linkedTextTypeSub(supermod.linkedTextType):
|
||||
def __init__(self, ref=None, mixedclass_=None, content_=None):
|
||||
supermod.linkedTextType.__init__(self, mixedclass_, content_)
|
||||
supermod.linkedTextType.subclass = linkedTextTypeSub
|
||||
# end class linkedTextTypeSub
|
||||
|
||||
|
||||
class graphTypeSub(supermod.graphType):
|
||||
def __init__(self, node=None):
|
||||
supermod.graphType.__init__(self, node)
|
||||
supermod.graphType.subclass = graphTypeSub
|
||||
# end class graphTypeSub
|
||||
|
||||
|
||||
class nodeTypeSub(supermod.nodeType):
|
||||
def __init__(self, id=None, label='', link=None, childnode=None):
|
||||
supermod.nodeType.__init__(self, id, label, link, childnode)
|
||||
supermod.nodeType.subclass = nodeTypeSub
|
||||
# end class nodeTypeSub
|
||||
|
||||
|
||||
class childnodeTypeSub(supermod.childnodeType):
|
||||
def __init__(self, relation=None, refid=None, edgelabel=None):
|
||||
supermod.childnodeType.__init__(self, relation, refid, edgelabel)
|
||||
supermod.childnodeType.subclass = childnodeTypeSub
|
||||
# end class childnodeTypeSub
|
||||
|
||||
|
||||
class linkTypeSub(supermod.linkType):
|
||||
def __init__(self, refid=None, external=None, valueOf_=''):
|
||||
supermod.linkType.__init__(self, refid, external)
|
||||
supermod.linkType.subclass = linkTypeSub
|
||||
# end class linkTypeSub
|
||||
|
||||
|
||||
class listingTypeSub(supermod.listingType):
|
||||
def __init__(self, codeline=None):
|
||||
supermod.listingType.__init__(self, codeline)
|
||||
supermod.listingType.subclass = listingTypeSub
|
||||
# end class listingTypeSub
|
||||
|
||||
|
||||
class codelineTypeSub(supermod.codelineType):
|
||||
def __init__(self, external=None, lineno=None, refkind=None, refid=None, highlight=None):
|
||||
supermod.codelineType.__init__(self, external, lineno, refkind, refid, highlight)
|
||||
supermod.codelineType.subclass = codelineTypeSub
|
||||
# end class codelineTypeSub
|
||||
|
||||
|
||||
class highlightTypeSub(supermod.highlightType):
|
||||
def __init__(self, class_=None, sp=None, ref=None, mixedclass_=None, content_=None):
|
||||
supermod.highlightType.__init__(self, mixedclass_, content_)
|
||||
supermod.highlightType.subclass = highlightTypeSub
|
||||
# end class highlightTypeSub
|
||||
|
||||
|
||||
class referenceTypeSub(supermod.referenceType):
|
||||
def __init__(self, endline=None, startline=None, refid=None, compoundref=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.referenceType.__init__(self, mixedclass_, content_)
|
||||
supermod.referenceType.subclass = referenceTypeSub
|
||||
# end class referenceTypeSub
|
||||
|
||||
|
||||
class locationTypeSub(supermod.locationType):
|
||||
def __init__(self, bodystart=None, line=None, bodyend=None, bodyfile=None, file=None, valueOf_=''):
|
||||
supermod.locationType.__init__(self, bodystart, line, bodyend, bodyfile, file)
|
||||
supermod.locationType.subclass = locationTypeSub
|
||||
# end class locationTypeSub
|
||||
|
||||
|
||||
class docSect1TypeSub(supermod.docSect1Type):
|
||||
def __init__(self, id=None, title='', para=None, sect2=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect1Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect1Type.subclass = docSect1TypeSub
|
||||
# end class docSect1TypeSub
|
||||
|
||||
|
||||
class docSect2TypeSub(supermod.docSect2Type):
|
||||
def __init__(self, id=None, title='', para=None, sect3=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect2Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect2Type.subclass = docSect2TypeSub
|
||||
# end class docSect2TypeSub
|
||||
|
||||
|
||||
class docSect3TypeSub(supermod.docSect3Type):
|
||||
def __init__(self, id=None, title='', para=None, sect4=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect3Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect3Type.subclass = docSect3TypeSub
|
||||
# end class docSect3TypeSub
|
||||
|
||||
|
||||
class docSect4TypeSub(supermod.docSect4Type):
|
||||
def __init__(self, id=None, title='', para=None, internal=None, mixedclass_=None, content_=None):
|
||||
supermod.docSect4Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docSect4Type.subclass = docSect4TypeSub
|
||||
# end class docSect4TypeSub
|
||||
|
||||
|
||||
class docInternalTypeSub(supermod.docInternalType):
|
||||
def __init__(self, para=None, sect1=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalType.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalType.subclass = docInternalTypeSub
|
||||
# end class docInternalTypeSub
|
||||
|
||||
|
||||
class docInternalS1TypeSub(supermod.docInternalS1Type):
|
||||
def __init__(self, para=None, sect2=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS1Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS1Type.subclass = docInternalS1TypeSub
|
||||
# end class docInternalS1TypeSub
|
||||
|
||||
|
||||
class docInternalS2TypeSub(supermod.docInternalS2Type):
|
||||
def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS2Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS2Type.subclass = docInternalS2TypeSub
|
||||
# end class docInternalS2TypeSub
|
||||
|
||||
|
||||
class docInternalS3TypeSub(supermod.docInternalS3Type):
|
||||
def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS3Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS3Type.subclass = docInternalS3TypeSub
|
||||
# end class docInternalS3TypeSub
|
||||
|
||||
|
||||
class docInternalS4TypeSub(supermod.docInternalS4Type):
|
||||
def __init__(self, para=None, mixedclass_=None, content_=None):
|
||||
supermod.docInternalS4Type.__init__(self, mixedclass_, content_)
|
||||
supermod.docInternalS4Type.subclass = docInternalS4TypeSub
|
||||
# end class docInternalS4TypeSub
|
||||
|
||||
|
||||
class docURLLinkSub(supermod.docURLLink):
|
||||
def __init__(self, url=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docURLLink.__init__(self, mixedclass_, content_)
|
||||
supermod.docURLLink.subclass = docURLLinkSub
|
||||
# end class docURLLinkSub
|
||||
|
||||
|
||||
class docAnchorTypeSub(supermod.docAnchorType):
|
||||
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docAnchorType.__init__(self, mixedclass_, content_)
|
||||
supermod.docAnchorType.subclass = docAnchorTypeSub
|
||||
# end class docAnchorTypeSub
|
||||
|
||||
|
||||
class docFormulaTypeSub(supermod.docFormulaType):
|
||||
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docFormulaType.__init__(self, mixedclass_, content_)
|
||||
supermod.docFormulaType.subclass = docFormulaTypeSub
|
||||
# end class docFormulaTypeSub
|
||||
|
||||
|
||||
class docIndexEntryTypeSub(supermod.docIndexEntryType):
|
||||
def __init__(self, primaryie='', secondaryie=''):
|
||||
supermod.docIndexEntryType.__init__(self, primaryie, secondaryie)
|
||||
supermod.docIndexEntryType.subclass = docIndexEntryTypeSub
|
||||
# end class docIndexEntryTypeSub
|
||||
|
||||
|
||||
class docListTypeSub(supermod.docListType):
|
||||
def __init__(self, listitem=None):
|
||||
supermod.docListType.__init__(self, listitem)
|
||||
supermod.docListType.subclass = docListTypeSub
|
||||
# end class docListTypeSub
|
||||
|
||||
|
||||
class docListItemTypeSub(supermod.docListItemType):
|
||||
def __init__(self, para=None):
|
||||
supermod.docListItemType.__init__(self, para)
|
||||
supermod.docListItemType.subclass = docListItemTypeSub
|
||||
# end class docListItemTypeSub
|
||||
|
||||
|
||||
class docSimpleSectTypeSub(supermod.docSimpleSectType):
|
||||
def __init__(self, kind=None, title=None, para=None):
|
||||
supermod.docSimpleSectType.__init__(self, kind, title, para)
|
||||
supermod.docSimpleSectType.subclass = docSimpleSectTypeSub
|
||||
# end class docSimpleSectTypeSub
|
||||
|
||||
|
||||
class docVarListEntryTypeSub(supermod.docVarListEntryType):
|
||||
def __init__(self, term=None):
|
||||
supermod.docVarListEntryType.__init__(self, term)
|
||||
supermod.docVarListEntryType.subclass = docVarListEntryTypeSub
|
||||
# end class docVarListEntryTypeSub
|
||||
|
||||
|
||||
class docRefTextTypeSub(supermod.docRefTextType):
|
||||
def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docRefTextType.__init__(self, mixedclass_, content_)
|
||||
supermod.docRefTextType.subclass = docRefTextTypeSub
|
||||
# end class docRefTextTypeSub
|
||||
|
||||
|
||||
class docTableTypeSub(supermod.docTableType):
|
||||
def __init__(self, rows=None, cols=None, row=None, caption=None):
|
||||
supermod.docTableType.__init__(self, rows, cols, row, caption)
|
||||
supermod.docTableType.subclass = docTableTypeSub
|
||||
# end class docTableTypeSub
|
||||
|
||||
|
||||
class docRowTypeSub(supermod.docRowType):
|
||||
def __init__(self, entry=None):
|
||||
supermod.docRowType.__init__(self, entry)
|
||||
supermod.docRowType.subclass = docRowTypeSub
|
||||
# end class docRowTypeSub
|
||||
|
||||
|
||||
class docEntryTypeSub(supermod.docEntryType):
|
||||
def __init__(self, thead=None, para=None):
|
||||
supermod.docEntryType.__init__(self, thead, para)
|
||||
supermod.docEntryType.subclass = docEntryTypeSub
|
||||
# end class docEntryTypeSub
|
||||
|
||||
|
||||
class docHeadingTypeSub(supermod.docHeadingType):
|
||||
def __init__(self, level=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docHeadingType.__init__(self, mixedclass_, content_)
|
||||
supermod.docHeadingType.subclass = docHeadingTypeSub
|
||||
# end class docHeadingTypeSub
|
||||
|
||||
|
||||
class docImageTypeSub(supermod.docImageType):
|
||||
def __init__(self, width=None, type_=None, name=None, height=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docImageType.__init__(self, mixedclass_, content_)
|
||||
supermod.docImageType.subclass = docImageTypeSub
|
||||
# end class docImageTypeSub
|
||||
|
||||
|
||||
class docDotFileTypeSub(supermod.docDotFileType):
|
||||
def __init__(self, name=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docDotFileType.__init__(self, mixedclass_, content_)
|
||||
supermod.docDotFileType.subclass = docDotFileTypeSub
|
||||
# end class docDotFileTypeSub
|
||||
|
||||
|
||||
class docTocItemTypeSub(supermod.docTocItemType):
|
||||
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
|
||||
supermod.docTocItemType.__init__(self, mixedclass_, content_)
|
||||
supermod.docTocItemType.subclass = docTocItemTypeSub
|
||||
# end class docTocItemTypeSub
|
||||
|
||||
|
||||
class docTocListTypeSub(supermod.docTocListType):
|
||||
def __init__(self, tocitem=None):
|
||||
supermod.docTocListType.__init__(self, tocitem)
|
||||
supermod.docTocListType.subclass = docTocListTypeSub
|
||||
# end class docTocListTypeSub
|
||||
|
||||
|
||||
class docLanguageTypeSub(supermod.docLanguageType):
|
||||
def __init__(self, langid=None, para=None):
|
||||
supermod.docLanguageType.__init__(self, langid, para)
|
||||
supermod.docLanguageType.subclass = docLanguageTypeSub
|
||||
# end class docLanguageTypeSub
|
||||
|
||||
|
||||
class docParamListTypeSub(supermod.docParamListType):
|
||||
def __init__(self, kind=None, parameteritem=None):
|
||||
supermod.docParamListType.__init__(self, kind, parameteritem)
|
||||
supermod.docParamListType.subclass = docParamListTypeSub
|
||||
# end class docParamListTypeSub
|
||||
|
||||
|
||||
class docParamListItemSub(supermod.docParamListItem):
|
||||
def __init__(self, parameternamelist=None, parameterdescription=None):
|
||||
supermod.docParamListItem.__init__(self, parameternamelist, parameterdescription)
|
||||
supermod.docParamListItem.subclass = docParamListItemSub
|
||||
# end class docParamListItemSub
|
||||
|
||||
|
||||
class docParamNameListSub(supermod.docParamNameList):
|
||||
def __init__(self, parametername=None):
|
||||
supermod.docParamNameList.__init__(self, parametername)
|
||||
supermod.docParamNameList.subclass = docParamNameListSub
|
||||
# end class docParamNameListSub
|
||||
|
||||
|
||||
class docParamNameSub(supermod.docParamName):
|
||||
def __init__(self, direction=None, ref=None, mixedclass_=None, content_=None):
|
||||
supermod.docParamName.__init__(self, mixedclass_, content_)
|
||||
supermod.docParamName.subclass = docParamNameSub
|
||||
# end class docParamNameSub
|
||||
|
||||
|
||||
class docXRefSectTypeSub(supermod.docXRefSectType):
|
||||
def __init__(self, id=None, xreftitle=None, xrefdescription=None):
|
||||
supermod.docXRefSectType.__init__(self, id, xreftitle, xrefdescription)
|
||||
supermod.docXRefSectType.subclass = docXRefSectTypeSub
|
||||
# end class docXRefSectTypeSub
|
||||
|
||||
|
||||
class docCopyTypeSub(supermod.docCopyType):
|
||||
def __init__(self, link=None, para=None, sect1=None, internal=None):
|
||||
supermod.docCopyType.__init__(self, link, para, sect1, internal)
|
||||
supermod.docCopyType.subclass = docCopyTypeSub
|
||||
# end class docCopyTypeSub
|
||||
|
||||
|
||||
class docCharTypeSub(supermod.docCharType):
|
||||
def __init__(self, char=None, valueOf_=''):
|
||||
supermod.docCharType.__init__(self, char)
|
||||
supermod.docCharType.subclass = docCharTypeSub
|
||||
# end class docCharTypeSub
|
||||
|
||||
class docParaTypeSub(supermod.docParaType):
|
||||
def __init__(self, char=None, valueOf_=''):
|
||||
supermod.docParaType.__init__(self, char)
|
||||
|
||||
self.parameterlist = []
|
||||
self.simplesects = []
|
||||
self.content = []
|
||||
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
supermod.docParaType.buildChildren(self, child_, nodeName_)
|
||||
|
||||
if child_.nodeType == Node.TEXT_NODE:
|
||||
obj_ = self.mixedclass_(MixedContainer.CategoryText,
|
||||
MixedContainer.TypeNone, '', child_.nodeValue)
|
||||
self.content.append(obj_)
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == "ref":
|
||||
obj_ = supermod.docRefTextType.factory()
|
||||
obj_.build(child_)
|
||||
self.content.append(obj_)
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'parameterlist':
|
||||
obj_ = supermod.docParamListType.factory()
|
||||
obj_.build(child_)
|
||||
self.parameterlist.append(obj_)
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'simplesect':
|
||||
obj_ = supermod.docSimpleSectType.factory()
|
||||
obj_.build(child_)
|
||||
self.simplesects.append(obj_)
|
||||
|
||||
|
||||
supermod.docParaType.subclass = docParaTypeSub
|
||||
# end class docParaTypeSub
|
||||
|
||||
|
||||
|
||||
def parse(inFilename):
|
||||
doc = minidom.parse(inFilename)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = supermod.DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
return rootObj
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
|
||||
"""
|
||||
|
||||
from xml.dom import minidom
|
||||
|
||||
import os
|
||||
import sys
|
||||
import compound
|
||||
|
||||
import indexsuper as supermod
|
||||
|
||||
class DoxygenTypeSub(supermod.DoxygenType):
|
||||
def __init__(self, version=None, compound=None):
|
||||
supermod.DoxygenType.__init__(self, version, compound)
|
||||
|
||||
def find_compounds_and_members(self, details):
|
||||
"""
|
||||
Returns a list of all compounds and their members which match details
|
||||
"""
|
||||
|
||||
results = []
|
||||
for compound in self.compound:
|
||||
members = compound.find_members(details)
|
||||
if members:
|
||||
results.append([compound, members])
|
||||
else:
|
||||
if details.match(compound):
|
||||
results.append([compound, []])
|
||||
|
||||
return results
|
||||
|
||||
supermod.DoxygenType.subclass = DoxygenTypeSub
|
||||
# end class DoxygenTypeSub
|
||||
|
||||
|
||||
class CompoundTypeSub(supermod.CompoundType):
|
||||
def __init__(self, kind=None, refid=None, name='', member=None):
|
||||
supermod.CompoundType.__init__(self, kind, refid, name, member)
|
||||
|
||||
def find_members(self, details):
|
||||
"""
|
||||
Returns a list of all members which match details
|
||||
"""
|
||||
|
||||
results = []
|
||||
|
||||
for member in self.member:
|
||||
if details.match(member):
|
||||
results.append(member)
|
||||
|
||||
return results
|
||||
|
||||
supermod.CompoundType.subclass = CompoundTypeSub
|
||||
# end class CompoundTypeSub
|
||||
|
||||
|
||||
class MemberTypeSub(supermod.MemberType):
|
||||
|
||||
def __init__(self, kind=None, refid=None, name=''):
|
||||
supermod.MemberType.__init__(self, kind, refid, name)
|
||||
|
||||
supermod.MemberType.subclass = MemberTypeSub
|
||||
# end class MemberTypeSub
|
||||
|
||||
|
||||
def parse(inFilename):
|
||||
|
||||
doc = minidom.parse(inFilename)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = supermod.DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
|
||||
return rootObj
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Generated Thu Jun 11 18:43:54 2009 by generateDS.py.
|
||||
#
|
||||
|
||||
import sys
|
||||
import getopt
|
||||
from string import lower as str_lower
|
||||
from xml.dom import minidom
|
||||
from xml.dom import Node
|
||||
|
||||
#
|
||||
# User methods
|
||||
#
|
||||
# Calls to the methods in these classes are generated by generateDS.py.
|
||||
# You can replace these methods by re-implementing the following class
|
||||
# in a module named generatedssuper.py.
|
||||
|
||||
try:
|
||||
from generatedssuper import GeneratedsSuper
|
||||
except ImportError, exp:
|
||||
|
||||
class GeneratedsSuper:
|
||||
def format_string(self, input_data, input_name=''):
|
||||
return input_data
|
||||
def format_integer(self, input_data, input_name=''):
|
||||
return '%d' % input_data
|
||||
def format_float(self, input_data, input_name=''):
|
||||
return '%f' % input_data
|
||||
def format_double(self, input_data, input_name=''):
|
||||
return '%e' % input_data
|
||||
def format_boolean(self, input_data, input_name=''):
|
||||
return '%s' % input_data
|
||||
|
||||
|
||||
#
|
||||
# If you have installed IPython you can uncomment and use the following.
|
||||
# IPython is available from http://ipython.scipy.org/.
|
||||
#
|
||||
|
||||
## from IPython.Shell import IPShellEmbed
|
||||
## args = ''
|
||||
## ipshell = IPShellEmbed(args,
|
||||
## banner = 'Dropping into IPython',
|
||||
## exit_msg = 'Leaving Interpreter, back to program.')
|
||||
|
||||
# Then use the following line where and when you want to drop into the
|
||||
# IPython shell:
|
||||
# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit')
|
||||
|
||||
#
|
||||
# Globals
|
||||
#
|
||||
|
||||
ExternalEncoding = 'ascii'
|
||||
|
||||
#
|
||||
# Support/utility functions.
|
||||
#
|
||||
|
||||
def showIndent(outfile, level):
|
||||
for idx in range(level):
|
||||
outfile.write(' ')
|
||||
|
||||
def quote_xml(inStr):
|
||||
s1 = (isinstance(inStr, basestring) and inStr or
|
||||
'%s' % inStr)
|
||||
s1 = s1.replace('&', '&')
|
||||
s1 = s1.replace('<', '<')
|
||||
s1 = s1.replace('>', '>')
|
||||
return s1
|
||||
|
||||
def quote_attrib(inStr):
|
||||
s1 = (isinstance(inStr, basestring) and inStr or
|
||||
'%s' % inStr)
|
||||
s1 = s1.replace('&', '&')
|
||||
s1 = s1.replace('<', '<')
|
||||
s1 = s1.replace('>', '>')
|
||||
if '"' in s1:
|
||||
if "'" in s1:
|
||||
s1 = '"%s"' % s1.replace('"', """)
|
||||
else:
|
||||
s1 = "'%s'" % s1
|
||||
else:
|
||||
s1 = '"%s"' % s1
|
||||
return s1
|
||||
|
||||
def quote_python(inStr):
|
||||
s1 = inStr
|
||||
if s1.find("'") == -1:
|
||||
if s1.find('\n') == -1:
|
||||
return "'%s'" % s1
|
||||
else:
|
||||
return "'''%s'''" % s1
|
||||
else:
|
||||
if s1.find('"') != -1:
|
||||
s1 = s1.replace('"', '\\"')
|
||||
if s1.find('\n') == -1:
|
||||
return '"%s"' % s1
|
||||
else:
|
||||
return '"""%s"""' % s1
|
||||
|
||||
|
||||
class MixedContainer:
|
||||
# Constants for category:
|
||||
CategoryNone = 0
|
||||
CategoryText = 1
|
||||
CategorySimple = 2
|
||||
CategoryComplex = 3
|
||||
# Constants for content_type:
|
||||
TypeNone = 0
|
||||
TypeText = 1
|
||||
TypeString = 2
|
||||
TypeInteger = 3
|
||||
TypeFloat = 4
|
||||
TypeDecimal = 5
|
||||
TypeDouble = 6
|
||||
TypeBoolean = 7
|
||||
def __init__(self, category, content_type, name, value):
|
||||
self.category = category
|
||||
self.content_type = content_type
|
||||
self.name = name
|
||||
self.value = value
|
||||
def getCategory(self):
|
||||
return self.category
|
||||
def getContenttype(self, content_type):
|
||||
return self.content_type
|
||||
def getValue(self):
|
||||
return self.value
|
||||
def getName(self):
|
||||
return self.name
|
||||
def export(self, outfile, level, name, namespace):
|
||||
if self.category == MixedContainer.CategoryText:
|
||||
outfile.write(self.value)
|
||||
elif self.category == MixedContainer.CategorySimple:
|
||||
self.exportSimple(outfile, level, name)
|
||||
else: # category == MixedContainer.CategoryComplex
|
||||
self.value.export(outfile, level, namespace,name)
|
||||
def exportSimple(self, outfile, level, name):
|
||||
if self.content_type == MixedContainer.TypeString:
|
||||
outfile.write('<%s>%s</%s>' % (self.name, self.value, self.name))
|
||||
elif self.content_type == MixedContainer.TypeInteger or \
|
||||
self.content_type == MixedContainer.TypeBoolean:
|
||||
outfile.write('<%s>%d</%s>' % (self.name, self.value, self.name))
|
||||
elif self.content_type == MixedContainer.TypeFloat or \
|
||||
self.content_type == MixedContainer.TypeDecimal:
|
||||
outfile.write('<%s>%f</%s>' % (self.name, self.value, self.name))
|
||||
elif self.content_type == MixedContainer.TypeDouble:
|
||||
outfile.write('<%s>%g</%s>' % (self.name, self.value, self.name))
|
||||
def exportLiteral(self, outfile, level, name):
|
||||
if self.category == MixedContainer.CategoryText:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \
|
||||
(self.category, self.content_type, self.name, self.value))
|
||||
elif self.category == MixedContainer.CategorySimple:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \
|
||||
(self.category, self.content_type, self.name, self.value))
|
||||
else: # category == MixedContainer.CategoryComplex
|
||||
showIndent(outfile, level)
|
||||
outfile.write('MixedContainer(%d, %d, "%s",\n' % \
|
||||
(self.category, self.content_type, self.name,))
|
||||
self.value.exportLiteral(outfile, level + 1)
|
||||
showIndent(outfile, level)
|
||||
outfile.write(')\n')
|
||||
|
||||
|
||||
class _MemberSpec(object):
|
||||
def __init__(self, name='', data_type='', container=0):
|
||||
self.name = name
|
||||
self.data_type = data_type
|
||||
self.container = container
|
||||
def set_name(self, name): self.name = name
|
||||
def get_name(self): return self.name
|
||||
def set_data_type(self, data_type): self.data_type = data_type
|
||||
def get_data_type(self): return self.data_type
|
||||
def set_container(self, container): self.container = container
|
||||
def get_container(self): return self.container
|
||||
|
||||
|
||||
#
|
||||
# Data representation classes.
|
||||
#
|
||||
|
||||
class DoxygenType(GeneratedsSuper):
|
||||
subclass = None
|
||||
superclass = None
|
||||
def __init__(self, version=None, compound=None):
|
||||
self.version = version
|
||||
if compound is None:
|
||||
self.compound = []
|
||||
else:
|
||||
self.compound = compound
|
||||
def factory(*args_, **kwargs_):
|
||||
if DoxygenType.subclass:
|
||||
return DoxygenType.subclass(*args_, **kwargs_)
|
||||
else:
|
||||
return DoxygenType(*args_, **kwargs_)
|
||||
factory = staticmethod(factory)
|
||||
def get_compound(self): return self.compound
|
||||
def set_compound(self, compound): self.compound = compound
|
||||
def add_compound(self, value): self.compound.append(value)
|
||||
def insert_compound(self, index, value): self.compound[index] = value
|
||||
def get_version(self): return self.version
|
||||
def set_version(self, version): self.version = version
|
||||
def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
|
||||
self.exportAttributes(outfile, level, namespace_, name_='DoxygenType')
|
||||
if self.hasContent_():
|
||||
outfile.write('>\n')
|
||||
self.exportChildren(outfile, level + 1, namespace_, name_)
|
||||
showIndent(outfile, level)
|
||||
outfile.write('</%s%s>\n' % (namespace_, name_))
|
||||
else:
|
||||
outfile.write(' />\n')
|
||||
def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'):
|
||||
outfile.write(' version=%s' % (self.format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), ))
|
||||
def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'):
|
||||
for compound_ in self.compound:
|
||||
compound_.export(outfile, level, namespace_, name_='compound')
|
||||
def hasContent_(self):
|
||||
if (
|
||||
self.compound is not None
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def exportLiteral(self, outfile, level, name_='DoxygenType'):
|
||||
level += 1
|
||||
self.exportLiteralAttributes(outfile, level, name_)
|
||||
if self.hasContent_():
|
||||
self.exportLiteralChildren(outfile, level, name_)
|
||||
def exportLiteralAttributes(self, outfile, level, name_):
|
||||
if self.version is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('version = %s,\n' % (self.version,))
|
||||
def exportLiteralChildren(self, outfile, level, name_):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('compound=[\n')
|
||||
level += 1
|
||||
for compound in self.compound:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('model_.compound(\n')
|
||||
compound.exportLiteral(outfile, level, name_='compound')
|
||||
showIndent(outfile, level)
|
||||
outfile.write('),\n')
|
||||
level -= 1
|
||||
showIndent(outfile, level)
|
||||
outfile.write('],\n')
|
||||
def build(self, node_):
|
||||
attrs = node_.attributes
|
||||
self.buildAttributes(attrs)
|
||||
for child_ in node_.childNodes:
|
||||
nodeName_ = child_.nodeName.split(':')[-1]
|
||||
self.buildChildren(child_, nodeName_)
|
||||
def buildAttributes(self, attrs):
|
||||
if attrs.get('version'):
|
||||
self.version = attrs.get('version').value
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
if child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'compound':
|
||||
obj_ = CompoundType.factory()
|
||||
obj_.build(child_)
|
||||
self.compound.append(obj_)
|
||||
# end class DoxygenType
|
||||
|
||||
|
||||
class CompoundType(GeneratedsSuper):
|
||||
subclass = None
|
||||
superclass = None
|
||||
def __init__(self, kind=None, refid=None, name=None, member=None):
|
||||
self.kind = kind
|
||||
self.refid = refid
|
||||
self.name = name
|
||||
if member is None:
|
||||
self.member = []
|
||||
else:
|
||||
self.member = member
|
||||
def factory(*args_, **kwargs_):
|
||||
if CompoundType.subclass:
|
||||
return CompoundType.subclass(*args_, **kwargs_)
|
||||
else:
|
||||
return CompoundType(*args_, **kwargs_)
|
||||
factory = staticmethod(factory)
|
||||
def get_name(self): return self.name
|
||||
def set_name(self, name): self.name = name
|
||||
def get_member(self): return self.member
|
||||
def set_member(self, member): self.member = member
|
||||
def add_member(self, value): self.member.append(value)
|
||||
def insert_member(self, index, value): self.member[index] = value
|
||||
def get_kind(self): return self.kind
|
||||
def set_kind(self, kind): self.kind = kind
|
||||
def get_refid(self): return self.refid
|
||||
def set_refid(self, refid): self.refid = refid
|
||||
def export(self, outfile, level, namespace_='', name_='CompoundType', namespacedef_=''):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
|
||||
self.exportAttributes(outfile, level, namespace_, name_='CompoundType')
|
||||
if self.hasContent_():
|
||||
outfile.write('>\n')
|
||||
self.exportChildren(outfile, level + 1, namespace_, name_)
|
||||
showIndent(outfile, level)
|
||||
outfile.write('</%s%s>\n' % (namespace_, name_))
|
||||
else:
|
||||
outfile.write(' />\n')
|
||||
def exportAttributes(self, outfile, level, namespace_='', name_='CompoundType'):
|
||||
outfile.write(' kind=%s' % (quote_attrib(self.kind), ))
|
||||
outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), ))
|
||||
def exportChildren(self, outfile, level, namespace_='', name_='CompoundType'):
|
||||
if self.name is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
|
||||
for member_ in self.member:
|
||||
member_.export(outfile, level, namespace_, name_='member')
|
||||
def hasContent_(self):
|
||||
if (
|
||||
self.name is not None or
|
||||
self.member is not None
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def exportLiteral(self, outfile, level, name_='CompoundType'):
|
||||
level += 1
|
||||
self.exportLiteralAttributes(outfile, level, name_)
|
||||
if self.hasContent_():
|
||||
self.exportLiteralChildren(outfile, level, name_)
|
||||
def exportLiteralAttributes(self, outfile, level, name_):
|
||||
if self.kind is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('kind = "%s",\n' % (self.kind,))
|
||||
if self.refid is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('refid = %s,\n' % (self.refid,))
|
||||
def exportLiteralChildren(self, outfile, level, name_):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding))
|
||||
showIndent(outfile, level)
|
||||
outfile.write('member=[\n')
|
||||
level += 1
|
||||
for member in self.member:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('model_.member(\n')
|
||||
member.exportLiteral(outfile, level, name_='member')
|
||||
showIndent(outfile, level)
|
||||
outfile.write('),\n')
|
||||
level -= 1
|
||||
showIndent(outfile, level)
|
||||
outfile.write('],\n')
|
||||
def build(self, node_):
|
||||
attrs = node_.attributes
|
||||
self.buildAttributes(attrs)
|
||||
for child_ in node_.childNodes:
|
||||
nodeName_ = child_.nodeName.split(':')[-1]
|
||||
self.buildChildren(child_, nodeName_)
|
||||
def buildAttributes(self, attrs):
|
||||
if attrs.get('kind'):
|
||||
self.kind = attrs.get('kind').value
|
||||
if attrs.get('refid'):
|
||||
self.refid = attrs.get('refid').value
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
if child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'name':
|
||||
name_ = ''
|
||||
for text__content_ in child_.childNodes:
|
||||
name_ += text__content_.nodeValue
|
||||
self.name = name_
|
||||
elif child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'member':
|
||||
obj_ = MemberType.factory()
|
||||
obj_.build(child_)
|
||||
self.member.append(obj_)
|
||||
# end class CompoundType
|
||||
|
||||
|
||||
class MemberType(GeneratedsSuper):
|
||||
subclass = None
|
||||
superclass = None
|
||||
def __init__(self, kind=None, refid=None, name=None):
|
||||
self.kind = kind
|
||||
self.refid = refid
|
||||
self.name = name
|
||||
def factory(*args_, **kwargs_):
|
||||
if MemberType.subclass:
|
||||
return MemberType.subclass(*args_, **kwargs_)
|
||||
else:
|
||||
return MemberType(*args_, **kwargs_)
|
||||
factory = staticmethod(factory)
|
||||
def get_name(self): return self.name
|
||||
def set_name(self, name): self.name = name
|
||||
def get_kind(self): return self.kind
|
||||
def set_kind(self, kind): self.kind = kind
|
||||
def get_refid(self): return self.refid
|
||||
def set_refid(self, refid): self.refid = refid
|
||||
def export(self, outfile, level, namespace_='', name_='MemberType', namespacedef_=''):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
|
||||
self.exportAttributes(outfile, level, namespace_, name_='MemberType')
|
||||
if self.hasContent_():
|
||||
outfile.write('>\n')
|
||||
self.exportChildren(outfile, level + 1, namespace_, name_)
|
||||
showIndent(outfile, level)
|
||||
outfile.write('</%s%s>\n' % (namespace_, name_))
|
||||
else:
|
||||
outfile.write(' />\n')
|
||||
def exportAttributes(self, outfile, level, namespace_='', name_='MemberType'):
|
||||
outfile.write(' kind=%s' % (quote_attrib(self.kind), ))
|
||||
outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), ))
|
||||
def exportChildren(self, outfile, level, namespace_='', name_='MemberType'):
|
||||
if self.name is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
|
||||
def hasContent_(self):
|
||||
if (
|
||||
self.name is not None
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def exportLiteral(self, outfile, level, name_='MemberType'):
|
||||
level += 1
|
||||
self.exportLiteralAttributes(outfile, level, name_)
|
||||
if self.hasContent_():
|
||||
self.exportLiteralChildren(outfile, level, name_)
|
||||
def exportLiteralAttributes(self, outfile, level, name_):
|
||||
if self.kind is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('kind = "%s",\n' % (self.kind,))
|
||||
if self.refid is not None:
|
||||
showIndent(outfile, level)
|
||||
outfile.write('refid = %s,\n' % (self.refid,))
|
||||
def exportLiteralChildren(self, outfile, level, name_):
|
||||
showIndent(outfile, level)
|
||||
outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding))
|
||||
def build(self, node_):
|
||||
attrs = node_.attributes
|
||||
self.buildAttributes(attrs)
|
||||
for child_ in node_.childNodes:
|
||||
nodeName_ = child_.nodeName.split(':')[-1]
|
||||
self.buildChildren(child_, nodeName_)
|
||||
def buildAttributes(self, attrs):
|
||||
if attrs.get('kind'):
|
||||
self.kind = attrs.get('kind').value
|
||||
if attrs.get('refid'):
|
||||
self.refid = attrs.get('refid').value
|
||||
def buildChildren(self, child_, nodeName_):
|
||||
if child_.nodeType == Node.ELEMENT_NODE and \
|
||||
nodeName_ == 'name':
|
||||
name_ = ''
|
||||
for text__content_ in child_.childNodes:
|
||||
name_ += text__content_.nodeValue
|
||||
self.name = name_
|
||||
# end class MemberType
|
||||
|
||||
|
||||
USAGE_TEXT = """
|
||||
Usage: python <Parser>.py [ -s ] <in_xml_file>
|
||||
Options:
|
||||
-s Use the SAX parser, not the minidom parser.
|
||||
"""
|
||||
|
||||
def usage():
|
||||
print USAGE_TEXT
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse(inFileName):
|
||||
doc = minidom.parse(inFileName)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
# Enable Python to collect the space used by the DOM.
|
||||
doc = None
|
||||
sys.stdout.write('<?xml version="1.0" ?>\n')
|
||||
rootObj.export(sys.stdout, 0, name_="doxygenindex",
|
||||
namespacedef_='')
|
||||
return rootObj
|
||||
|
||||
|
||||
def parseString(inString):
|
||||
doc = minidom.parseString(inString)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
# Enable Python to collect the space used by the DOM.
|
||||
doc = None
|
||||
sys.stdout.write('<?xml version="1.0" ?>\n')
|
||||
rootObj.export(sys.stdout, 0, name_="doxygenindex",
|
||||
namespacedef_='')
|
||||
return rootObj
|
||||
|
||||
|
||||
def parseLiteral(inFileName):
|
||||
doc = minidom.parse(inFileName)
|
||||
rootNode = doc.documentElement
|
||||
rootObj = DoxygenType.factory()
|
||||
rootObj.build(rootNode)
|
||||
# Enable Python to collect the space used by the DOM.
|
||||
doc = None
|
||||
sys.stdout.write('from index import *\n\n')
|
||||
sys.stdout.write('rootObj = doxygenindex(\n')
|
||||
rootObj.exportLiteral(sys.stdout, 0, name_="doxygenindex")
|
||||
sys.stdout.write(')\n')
|
||||
return rootObj
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 1:
|
||||
parse(args[0])
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
#import pdb
|
||||
#pdb.run('main()')
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# Copyright 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Utilities for extracting text from generated classes.
|
||||
"""
|
||||
|
||||
def is_string(txt):
|
||||
if isinstance(txt, str):
|
||||
return True
|
||||
try:
|
||||
if isinstance(txt, unicode):
|
||||
return True
|
||||
except NameError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def description(obj):
|
||||
if obj is None:
|
||||
return None
|
||||
return description_bit(obj).strip()
|
||||
|
||||
def description_bit(obj):
|
||||
if hasattr(obj, 'content'):
|
||||
contents = [description_bit(item) for item in obj.content]
|
||||
result = ''.join(contents)
|
||||
elif hasattr(obj, 'content_'):
|
||||
contents = [description_bit(item) for item in obj.content_]
|
||||
result = ''.join(contents)
|
||||
elif hasattr(obj, 'value'):
|
||||
result = description_bit(obj.value)
|
||||
elif is_string(obj):
|
||||
return obj
|
||||
else:
|
||||
raise StandardError('Expecting a string or something with content, content_ or value attribute')
|
||||
# If this bit is a paragraph then add one some line breaks.
|
||||
if hasattr(obj, 'name') and obj.name == 'para':
|
||||
result += "\n\n"
|
||||
return result
|
|
@ -0,0 +1,7 @@
|
|||
/*!
|
||||
* \defgroup block GNU Radio 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.
|
||||
*
|
||||
*/
|
||||
|
|
@ -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.
|
||||
|
||||
*/
|
|
@ -0,0 +1,255 @@
|
|||
#
|
||||
# Copyright 2010,2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
"""
|
||||
Creates the swig_doc.i SWIG interface file.
|
||||
Execute using: python swig_doc.py xml_path outputfilename
|
||||
|
||||
The file instructs SWIG to transfer the doxygen comments into the
|
||||
python docstrings.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
|
||||
except ImportError:
|
||||
from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
|
||||
|
||||
|
||||
def py_name(name):
|
||||
bits = name.split('_')
|
||||
return '_'.join(bits[1:])
|
||||
|
||||
def make_name(name):
|
||||
bits = name.split('_')
|
||||
return bits[0] + '_make_' + '_'.join(bits[1:])
|
||||
|
||||
|
||||
class Block(object):
|
||||
"""
|
||||
Checks if doxyxml produced objects correspond to a gnuradio block.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def includes(cls, item):
|
||||
if not isinstance(item, DoxyClass):
|
||||
return False
|
||||
# Check for a parsing error.
|
||||
if item.error():
|
||||
return False
|
||||
return item.has_member(make_name(item.name()), DoxyFriend)
|
||||
|
||||
|
||||
def utoascii(text):
|
||||
"""
|
||||
Convert unicode text into ascii and escape quotes.
|
||||
"""
|
||||
if text is None:
|
||||
return ''
|
||||
out = text.encode('ascii', 'replace')
|
||||
out = out.replace('"', '\\"')
|
||||
return out
|
||||
|
||||
|
||||
def combine_descriptions(obj):
|
||||
"""
|
||||
Combines the brief and detailed descriptions of an object together.
|
||||
"""
|
||||
description = []
|
||||
bd = obj.brief_description.strip()
|
||||
dd = obj.detailed_description.strip()
|
||||
if bd:
|
||||
description.append(bd)
|
||||
if dd:
|
||||
description.append(dd)
|
||||
return utoascii('\n\n'.join(description)).strip()
|
||||
|
||||
|
||||
entry_templ = '%feature("docstring") {name} "{docstring}"'
|
||||
def make_entry(obj, name=None, templ="{description}", description=None):
|
||||
"""
|
||||
Create a docstring entry for a swig interface file.
|
||||
|
||||
obj - a doxyxml object from which documentation will be extracted.
|
||||
name - the name of the C object (defaults to obj.name())
|
||||
templ - an optional template for the docstring containing only one
|
||||
variable named 'description'.
|
||||
description - if this optional variable is set then it's value is
|
||||
used as the description instead of extracting it from obj.
|
||||
"""
|
||||
if name is None:
|
||||
name=obj.name()
|
||||
if "operator " in name:
|
||||
return ''
|
||||
if description is None:
|
||||
description = combine_descriptions(obj)
|
||||
docstring = templ.format(description=description)
|
||||
if not docstring:
|
||||
return ''
|
||||
return entry_templ.format(
|
||||
name=name,
|
||||
docstring=docstring,
|
||||
)
|
||||
|
||||
|
||||
def make_func_entry(func, name=None, description=None, params=None):
|
||||
"""
|
||||
Create a function docstring entry for a swig interface file.
|
||||
|
||||
func - a doxyxml object from which documentation will be extracted.
|
||||
name - the name of the C object (defaults to func.name())
|
||||
description - if this optional variable is set then it's value is
|
||||
used as the description instead of extracting it from func.
|
||||
params - a parameter list that overrides using func.params.
|
||||
"""
|
||||
if params is None:
|
||||
params = func.params
|
||||
params = [prm.declname for prm in params]
|
||||
if params:
|
||||
sig = "Params: (%s)" % ", ".join(params)
|
||||
else:
|
||||
sig = "Params: (NONE)"
|
||||
templ = "{description}\n\n" + sig
|
||||
return make_entry(func, name=name, templ=utoascii(templ),
|
||||
description=description)
|
||||
|
||||
|
||||
def make_class_entry(klass, description=None):
|
||||
"""
|
||||
Create a class docstring for a swig interface file.
|
||||
"""
|
||||
output = []
|
||||
output.append(make_entry(klass, description=description))
|
||||
for func in klass.in_category(DoxyFunction):
|
||||
name = klass.name() + '::' + func.name()
|
||||
output.append(make_func_entry(func, name=name))
|
||||
return "\n\n".join(output)
|
||||
|
||||
|
||||
def make_block_entry(di, block):
|
||||
"""
|
||||
Create class and function docstrings of a gnuradio block for a
|
||||
swig interface file.
|
||||
"""
|
||||
descriptions = []
|
||||
# Get the documentation associated with the class.
|
||||
class_desc = combine_descriptions(block)
|
||||
if class_desc:
|
||||
descriptions.append(class_desc)
|
||||
# Get the documentation associated with the make function
|
||||
make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
||||
make_func_desc = combine_descriptions(make_func)
|
||||
if make_func_desc:
|
||||
descriptions.append(make_func_desc)
|
||||
# Get the documentation associated with the file
|
||||
try:
|
||||
block_file = di.get_member(block.name() + ".h", DoxyFile)
|
||||
file_desc = combine_descriptions(block_file)
|
||||
if file_desc:
|
||||
descriptions.append(file_desc)
|
||||
except base.Base.NoSuchMember:
|
||||
# Don't worry if we can't find a matching file.
|
||||
pass
|
||||
# And join them all together to make a super duper description.
|
||||
super_description = "\n\n".join(descriptions)
|
||||
# Associate the combined description with the class and
|
||||
# the make function.
|
||||
output = []
|
||||
output.append(make_class_entry(block, description=super_description))
|
||||
creator = block.get_member(block.name(), DoxyFunction)
|
||||
output.append(make_func_entry(make_func, description=super_description,
|
||||
params=creator.params))
|
||||
return "\n\n".join(output)
|
||||
|
||||
|
||||
def make_swig_interface_file(di, swigdocfilename, custom_output=None):
|
||||
|
||||
output = ["""
|
||||
/*
|
||||
* This file was automatically generated using swig_doc.py.
|
||||
*
|
||||
* Any changes to it will be lost next time it is regenerated.
|
||||
*/
|
||||
"""]
|
||||
|
||||
if custom_output is not None:
|
||||
output.append(custom_output)
|
||||
|
||||
# Create docstrings for the blocks.
|
||||
blocks = di.in_category(Block)
|
||||
make_funcs = set([])
|
||||
for block in blocks:
|
||||
try:
|
||||
make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
||||
make_funcs.add(make_func.name())
|
||||
output.append(make_block_entry(di, block))
|
||||
except block.ParsingError:
|
||||
print('Parsing error for block %s' % block.name())
|
||||
|
||||
# Create docstrings for functions
|
||||
# Don't include the make functions since they have already been dealt with.
|
||||
funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in make_funcs]
|
||||
for f in funcs:
|
||||
try:
|
||||
output.append(make_func_entry(f))
|
||||
except f.ParsingError:
|
||||
print('Parsing error for function %s' % f.name())
|
||||
|
||||
# Create docstrings for classes
|
||||
block_names = [block.name() for block in blocks]
|
||||
klasses = [k for k in di.in_category(DoxyClass) if k.name() not in block_names]
|
||||
for k in klasses:
|
||||
try:
|
||||
output.append(make_class_entry(k))
|
||||
except k.ParsingError:
|
||||
print('Parsing error for class %s' % k.name())
|
||||
|
||||
# Docstrings are not created for anything that is not a function or a class.
|
||||
# If this excludes anything important please add it here.
|
||||
|
||||
output = "\n\n".join(output)
|
||||
|
||||
swig_doc = file(swigdocfilename, 'w')
|
||||
swig_doc.write(output)
|
||||
swig_doc.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Parse command line options and set up doxyxml.
|
||||
err_msg = "Execute using: python swig_doc.py xml_path outputfilename"
|
||||
if len(sys.argv) != 3:
|
||||
raise StandardError(err_msg)
|
||||
xml_path = sys.argv[1]
|
||||
swigdocfilename = sys.argv[2]
|
||||
di = DoxyIndex(xml_path)
|
||||
|
||||
# gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined!
|
||||
# This is presumably a bug in SWIG.
|
||||
#msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
|
||||
#insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
|
||||
#delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
|
||||
output = []
|
||||
#output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
|
||||
#output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
|
||||
custom_output = "\n\n".join(output)
|
||||
|
||||
# Generate the docstrings interface file.
|
||||
make_swig_interface_file(di, swigdocfilename, custom_output=custom_output)
|
|
@ -0,0 +1,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
|
||||
)
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
)
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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)
|
|
@ -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();
|
||||
}
|
|
@ -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 */
|
|
@ -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()
|
||||
{
|
||||
}
|
|
@ -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 */
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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)
|
||||
{
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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 */
|
|
@ -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");
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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();
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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]);
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue