Improvements on the overall structure of the project

* Improve performance of the Golay decoder
* Modernize some CMake modules of GNU Radio
* Re-introduce the CPPUnit automated tests
This commit is contained in:
Manolis Surligas 2019-07-20 00:50:12 +03:00
parent 8625475fd9
commit 9fe6b6f274
21 changed files with 923 additions and 111 deletions

View File

@ -1,8 +1,30 @@
variables:
GITLAB_CI_IMAGE_DEBIAN: 'debian:buster'
stages:
- test
- build
- deploy
test:
stage: test
before_script:
- apt-get update -qq && apt-get install -y -qq gnuradio-dev libcppunit-dev libpng++-dev libvorbis-dev cmake swig pkg-config build-essential git
script:
- mkdir -p build
- cd build
- cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr ..
- make
- make install
- ldconfig
- python -c "import satnogs"
- rm -rf *
- cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DINCLUDE_DEBUG_BLOCKS=OFF -DCMAKE_INSTALL_PREFIX=/usr ..
- make
- make CTEST_OUTPUT_ON_FAILURE=1 test
- make install
- ldconfig
- python -c "import satnogs"
debian:
stage: build
image: ${GITLAB_CI_IMAGE_DEBIAN}

View File

@ -51,6 +51,22 @@ set(VERSION_INFO_API_COMPAT 5)
set(VERSION_INFO_MINOR_VERSION 1)
set(VERSION_INFO_MAINT_VERSION git)
# Set cmake policies.
# This will suppress developer warnings during the cmake process that can occur
# if a newer cmake version than the minimum is used.
if(POLICY CMP0026)
cmake_policy(SET CMP0026 OLD)
endif()
if(POLICY CMP0043)
cmake_policy(SET CMP0043 OLD)
endif()
if(POLICY CMP0045)
cmake_policy(SET CMP0045 OLD)
endif()
if(POLICY CMP0046)
cmake_policy(SET CMP0046 OLD)
endif()
########################################################################
# Compiler specific setup
@ -216,7 +232,6 @@ include_directories(
${Boost_INCLUDE_DIRS}
${CPPUNIT_INCLUDE_DIRS}
${GNURADIO_ALL_INCLUDE_DIRS}
${NOVA_INCLUDE_DIRS}
)
link_directories(

View File

@ -955,7 +955,7 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>

View File

@ -58,7 +58,7 @@
# 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.
# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore.
#=============================================================================
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>

View File

@ -0,0 +1,332 @@
# Copyright (c) 2012 - 2017, Lars Bilke
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CHANGES:
#
# 2012-01-31, Lars Bilke
# - Enable Code Coverage
#
# 2013-09-17, Joakim Söderberg
# - Added support for Clang.
# - Some additional usage instructions.
#
# 2016-02-03, Lars Bilke
# - Refactored functions to use named parameters
#
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
#
# USAGE:
#
# 1. Copy this file into your cmake modules path.
#
# 2. Add the following line to your CMakeLists.txt:
# include(CodeCoverage)
#
# 3. Append necessary compiler flags:
# APPEND_COVERAGE_COMPILER_FLAGS()
#
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
#
# 4. If you need to exclude additional directories from the report, specify them
# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
# Example:
# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
#
# 6. Build a Debug build:
# cmake -DCMAKE_BUILD_TYPE=Debug ..
# make
# make my_coverage_target
#
include(CMakeParseArguments)
# Check prereqs
find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH NAMES gcovr)
find_program( PYTHON3_INTERP NAMES python3)
if(NOT PYTHON3_INTERP)
message(FATAL_ERROR "python3 not found! Aborting...")
endif()
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
endif()
set(COVERAGE_COMPILER_FLAGS "-g --coverage -fprofile-arcs -ftest-coverage"
CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C compiler during coverage builds."
FORCE )
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
###############################################################################
# Handy macro to set easily a vatriable with a list of exclude directories
###############################################################################
macro(COVERAGE_SET_EXCLUDE_DIRS var)
set(${var} ${ARGN} CACHE INTERNAL "" FORCE)
endmacro(COVERAGE_SET_EXCLUDE_DIRS)
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_LCOV(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_LCOV)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif() # NOT LCOV_PATH
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup lcov
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
# Create baseline to make sure untouched files show up in the report
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
# Run tests
COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
# Capturing lcov counters and generating report
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
# add baseline counters
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${GENHTML_PATH} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
)
# Show where to find the lcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
set(GCOVR_EXCLUDES_DIRS "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
string(REPLACE "*" "\\*" EXCLUDE_REPLACED ${EXCLUDE})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE_REPLACED}")
endforeach()
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDE_DIRS})
string(REPLACE "*" "\\*" EXCLUDE_REPLACED ${EXCLUDE})
list(APPEND GCOVR_EXCLUDE_DIRS "--exclude-directories")
list(APPEND GCOVR_EXCLUDE_DIRS "${EXCLUDE_REPLACED}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
# Running gcovr
COMMAND ${GCOVR_PATH} --xml
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES} ${GCOVR_EXCLUDE_DIRS}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce Cobertura code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
set(GCOVR_EXCLUDES_DIRS "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
string(REPLACE "*" "\\*" EXCLUDE_REPLACED ${EXCLUDE})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE_REPLACED}")
endforeach()
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDE_DIRS})
string(REPLACE "*" "\\*" EXCLUDE_REPLACED ${EXCLUDE})
list(APPEND GCOVR_EXCLUDE_DIRS "--exclude-directories")
list(APPEND GCOVR_EXCLUDE_DIRS "${EXCLUDE_REPLACED}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
# Create folder
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
# Running gcovr
COMMAND ${PYTHON3_INTERP} ${GCOVR_PATH} --html --html-details
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES} ${GCOVR_EXCLUDE_DIRS}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}/index.html
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce HTML code coverage report."
# Run it again to generate the report in text based form for the
# CI to parse it
COMMAND ${PYTHON3_INTERP} ${GCOVR_PATH}
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES} ${GCOVR_EXCLUDE_DIRS}
--object-directory=${PROJECT_BINARY_DIR}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce HTML code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
function(APPEND_COVERAGE_COMPILER_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS

View File

@ -1,6 +1,7 @@
# Copyright 2010-2011,2014 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-ccsds
#
# 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
@ -190,7 +191,7 @@ endfunction(GR_LIBRARY_FOO)
# 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,
# Custom command can't 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)
@ -209,7 +210,7 @@ function(GR_GEN_TARGET_DEPS name var)
endif(ARGN)
if(CMAKE_CROSSCOMPILING)
set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross
set(${var} "DEPENDS;${name}" PARENT_SCOPE) #can't call command when cross
else()
set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
endif()
@ -363,6 +364,7 @@ macro(GR_EXPAND_X_H component root)
import sys, os, re
sys.path.append('${GR_RUNTIME_PYTHONPATH}')
sys.path.append('${CMAKE_SOURCE_DIR}/python')
os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
@ -406,6 +408,7 @@ macro(GR_EXPAND_X_CC_H component root)
import sys, os, re
sys.path.append('${GR_RUNTIME_PYTHONPATH}')
sys.path.append('${CMAKE_SOURCE_DIR}/python')
os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
@ -466,6 +469,7 @@ macro(GR_EXPAND_X_CC_H_IMPL component root)
import sys, os, re
sys.path.append('${GR_RUNTIME_PYTHONPATH}')
sys.path.append('${CMAKE_SOURCE_DIR}/python')
os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
os.chdir('${CMAKE_CURRENT_BINARY_DIR}')

View File

@ -1,6 +1,7 @@
# Copyright 2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-ccsds
#
# 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
@ -29,15 +30,15 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LINUX TRUE)
endif()
if(LINUX AND EXISTS "/etc/debian_version")
if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/debian_version")
set(DEBIAN TRUE)
endif()
if(LINUX AND EXISTS "/etc/redhat-release")
if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/redhat-release")
set(REDHAT TRUE)
endif()
if(LINUX AND EXISTS "/etc/slackware-version")
if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/slackware-version")
set(SLACKWARE TRUE)
endif()
@ -51,4 +52,12 @@ endif()
if(NOT DEFINED LIB_SUFFIX AND LIB64_CONVENTION AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$")
set(LIB_SUFFIX 64)
endif()
########################################################################
# Detect /lib versus /lib64
########################################################################
if (CMAKE_INSTALL_LIBDIR MATCHES lib64)
set(LIB_SUFFIX 64)
endif()
set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix")

View File

@ -1,6 +1,7 @@
# Copyright 2010-2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-ccsds
#
# 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

View File

@ -1,6 +1,7 @@
# Copyright 2010-2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-ccsds
#
# 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
@ -35,7 +36,7 @@ include(GrPython)
function(GR_SWIG_MAKE_DOCS output_file)
if(ENABLE_DOXYGEN)
#setup the input files variable list, quote formated
#setup the input files variable list, quote formatted
set(input_files)
unset(INPUT_PATHS)
foreach(input_path ${ARGN})
@ -171,7 +172,12 @@ macro(GR_SWIG_MAKE name)
#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})
if(APPLE)
set(PYTHON_LINK_OPTIONS "-undefined dynamic_lookup")
else()
set(PYTHON_LINK_OPTIONS ${PYTHON_LIBRARIES})
endif(APPLE)
SWIG_LINK_LIBRARIES(${name} ${PYTHON_LINK_OPTIONS} ${GR_SWIG_LIBRARIES})
if(${name} STREQUAL "runtime_swig")
SET_TARGET_PROPERTIES(${SWIG_MODULE_runtime_swig_REAL_NAME} PROPERTIES DEFINE_SYMBOL "gnuradio_runtime_EXPORTS")
endif(${name} STREQUAL "runtime_swig")
@ -240,7 +246,7 @@ def get_swig_deps(file_path, level):
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))
break #found, we dont search in lower prio inc dirs
break #found, we don't search in lower prio inc dirs
return deps
if __name__ == '__main__':

View File

@ -1,6 +1,7 @@
# Copyright 2010-2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-satnogs
#
# 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
@ -45,7 +46,7 @@ function(GR_ADD_TEST test_name)
get_target_property(location ${target} LOCATION)
if(location)
get_filename_component(path ${location} PATH)
string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path})
string(REGEX REPLACE "\\$\\(.*\\)" "${CMAKE_BUILD_TYPE}" path "${path}")
list(APPEND GR_TEST_LIBRARY_DIRS ${path})
endif(location)
endforeach(target)
@ -141,3 +142,35 @@ function(GR_ADD_TEST test_name)
endif(WIN32)
endfunction(GR_ADD_TEST)
###############################################################################
# Enables memory checking. If this function is not callled at the top-level
# CMakeLists.txt, calls of the add_memtest() have no effect.
###############################################################################
function(satnogs_enable_memcheck)
set(SATNOGS_ENABLE_MEMCHECK_VAR ON CACHE INTERNAL "SATNOGS_ENABLE_MEMCHECK")
find_program(MEMORYCHECK_COMMAND valgrind)
endfunction(satnogs_enable_memcheck)
###############################################################################
# Adds a ctest test for memory leakage testing.
# Params:
# name: The name of the test
# target: The target to be tested. Target should be a valid target created
# from add_executable()
###############################################################################
function(add_memtest name target )
if(SATNOGS_ENABLE_MEMCHECK_VAR)
list(APPEND memcheck_cmd_options
"--trace-children=yes;"
"--leak-check=full;"
"--error-exitcode=1;"
)
add_test(memcheck_${name}
${MEMORYCHECK_COMMAND}
${memcheck_cmd_options}
${CMAKE_CURRENT_BINARY_DIR}/${target}
)
endif()
endfunction()

View File

@ -224,9 +224,9 @@ print(re.sub('\\W', '_', '${name} ${reldir} ' + unique))"
foreach(swig_gen_file ${${outfiles}})
add_custom_command(
OUTPUT ${swig_gen_file}
COMMAND ""
COMMAND "${CMAKE_COMMAND}" -E touch_nocreate "${swig_gen_file}"
DEPENDS ${_target}
COMMENT ""
COMMENT "dummy command to show ${_target} dependency of ${swig_gen_file}"
)
endforeach()

View File

@ -48,14 +48,14 @@ public:
golay24 ();
~golay24 ();
static const std::vector<uint32_t> G_P;
static const std::vector<uint32_t> G_I;
uint32_t
encode12(uint16_t in);
encode12(uint16_t in, bool lsb_parity = true);
bool
decode24(uint16_t *out, uint32_t in);
private:
std::vector<uint32_t> d_H;
std::vector<uint32_t> d_X;
decode24(uint32_t *out, uint32_t in);
};

View File

@ -115,6 +115,32 @@ endif(APPLE)
include(GrMiscUtils)
GR_LIBRARY_FOO(gnuradio-satnogs RUNTIME_COMPONENT "satnogs_runtime" DEVEL_COMPONENT "satnogs_devel")
########################################################################
# Build and register unit test
########################################################################
include(GrTest)
include_directories(${CPPUNIT_INCLUDE_DIRS})
list(APPEND test_satnogs_sources
${CMAKE_CURRENT_SOURCE_DIR}/qa_golay24.cc
${CMAKE_CURRENT_SOURCE_DIR}/test_satnogs.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_satnogs.cc
)
add_executable(test-satnogs ${test_satnogs_sources})
target_link_libraries(
test-satnogs
${GNURADIO_RUNTIME_LIBRARIES}
${GNURADIO_BLOCKS_LIBRARIES}
${Boost_LIBRARIES}
${CPPUNIT_LIBRARIES}
gnuradio-satnogs
)
GR_ADD_TEST(test_satnogs test-satnogs)
########################################################################
# Print summary
########################################################################

View File

@ -70,8 +70,11 @@ namespace gr {
pmt::pmt_t pmt_data = pmt::dict_ref(m, pmt::intern("data"), pmt::PMT_NIL);
pmt::pmt_t pmt_erasures = pmt::dict_ref(m, pmt::intern("erasures"),
pmt::PMT_NIL);
/* Check if the message contains erasure info. Otherwise handle it as
* a blob
*/
if (pmt::equal (pmt::PMT_NIL, pmt_data)) {
LOG_ERROR("Invalid message format.");
pmt_data = m;
}
data_ref = pmt::u8vector_elements(pmt_data, data_len);

View File

@ -244,6 +244,7 @@ frame_acquisition_impl::searching_sync (const uint8_t* in, int len)
d_state = DECODING_GENERIC_FRAME_LEN;
break;
case GOLAY24_CODED_FRAME_LEN:
LOG_WARN("Found!");
d_state = DECODING_GOLAY24_FRAME_LEN;
break;
}
@ -319,6 +320,7 @@ frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
{
/* Golay24 needs 3 bytes to decode */
const int s = std::min(len / 8, 3);
d_frame_len = 0;
for(int i = 0; i < s; i++) {
uint8_t b = 0x0;
b |= in[i * 8] << 7;
@ -335,16 +337,19 @@ frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
/* Try to decode the frame length */
if (d_cnt == 3) {
LOG_WARN("Len coded %u", d_frame_len);
if(d_whitening) {
uint32_t descrambled = 0x0;
d_whitening->descramble((uint8_t *)&descrambled,
d_whitening->descramble((uint8_t *) &descrambled,
(const uint8_t *)&d_frame_len, 3, false);
d_frame_len = descrambled;
}
d_frame_len = ((d_frame_len & 0xFFF) << 12) | (d_frame_len >> 12);
golay24 g = golay24 ();
uint16_t tmp = 0;
uint32_t tmp = 0;
if (g.decode24 (&tmp, d_frame_len)) {
d_frame_len = tmp;
d_frame_len = tmp >> 12;
LOG_WARN("Len %u", d_frame_len);
/* Append the CRC length if any */
d_frame_len += d_crc_len;
@ -448,7 +453,7 @@ frame_acquisition_impl::check_crc ()
crc16_c = crc16_ibm(d_pdu, d_frame_len - 2);
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
crc16_received = ntohs(crc16_received);
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
if(crc16_c == crc16_received) {
return true;
}

View File

@ -33,27 +33,56 @@ namespace gr
namespace satnogs
{
/*
* Matrix P was retrieved by:
* Lin & Costello, pg 128, Ch4, "Error Control Coding", 2nd ed, Pearson.
*
* Matrix mentioned by Morelos-Zaragoza, Robert H. "The art of error correcting coding."
* John Wiley & Sons, 2006 was not suitable.
*/
const std::vector<uint32_t> golay24::G_P =
{0x8ED, 0x1DB, 0x3B5, 0x769, 0xED1, 0xDA3, 0xB47, 0x68F, 0xD1D, 0xA3B, 0x477,
0xFFE};
const std::vector<uint32_t> golay24::G_I =
{ 0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002,
0x001 };
golay24::golay24 ()
{
d_H = { 0x7ff, 0xee2, 0xdc5, 0xb8b, 0xf16, 0xe2d, 0xc5b, 0x8b7, 0x96e, 0xadc,
0xdb8, 0xb71 };
d_X = {0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004,
0x002, 0x001};
}
golay24::~golay24 ()
{
}
static inline uint32_t
weight(uint32_t x)
{
return bit_count(x & 0xFFF);
}
static inline uint32_t
syndrome(uint16_t x, uint16_t y)
{
uint32_t s = 0;
for(size_t i = 0; i < 12; i++) {
s = (s << 1) | (weight(y & golay24::G_P[i]) % 2);
}
s ^= x;
return s;
}
/**
* Encodes a 12-bit message
* @param in the input 12-bit message. The message should be placed at the
* 12 LS bits
* @param lsb_parity if set to true, the parity part is placed on the 12 LSB,
* whereas if set to false it is placed on the 12 MSB of the 24 bit coded word
* @return the coded 24-bit message. The message is placed at the 24 LS bits
*/
uint32_t
golay24::encode12 (uint16_t in)
golay24::encode12 (uint16_t in, bool lsb_parity)
{
uint32_t c[2] =
{ 0x0, 0x0 };
@ -61,106 +90,68 @@ golay24::encode12 (uint16_t in)
for (size_t i = 0; i < 12; i++) {
uint32_t tmp = 0;
for (size_t j = 0; j < 12; j++) {
tmp ^= (((c[0] & d_H[i]) >> j) & 0x01);
tmp ^= (((c[0] & G_P[i]) >> j) & 0x01);
}
c[1] = (c[1] << 1) ^ tmp;
}
return ((c[0] & 0xFFF) << 12) | (c[1] & 0xFFF);
}
static inline uint32_t
ham_dist(uint32_t x)
{
return bit_count(x & 0xFFF);
if(lsb_parity) {
return ((c[0] & 0xFFF) << 12) | (c[1] & 0xFFF);
}
return ((c[1] & 0xFFF) << 12) | (c[0] & 0xFFF);
}
/**
* Decodes a single Golay (24, 12, 8) codeword
*
* @param out the 12-bit decoded message. The message is placed at the 12 LS bits
* @param out the 24-bit decoded message. The placement of the parity is
* implementation specific.
*
* @param in the coded 24 bit code word. The message should be placed at the
* 24 LS bits
* @return true if the decoding was successful, false in case the error correction
* could not be performed
*/
bool
golay24::decode24(uint16_t *out, const uint32_t in)
golay24::decode24(uint32_t *out, const uint32_t in)
{
uint32_t e[2] = {0x0, 0x0};
uint32_t r[2] = {0x0, 0x0};
uint32_t c[2] = {0x0, 0x0};
uint32_t syndrome = 0x0;
bool found = false;
uint32_t col = 0;
uint32_t q = 0;
uint32_t s = 0x0;
r[0] = (in >> 12) & 0xFFF;
r[1] = in & 0xFFF;
for(size_t j = 0; j < 12; j++) {
uint32_t tmp = 0x0;
for(size_t i = 0; i < 12; i++) {
tmp ^= (((d_X[j] & r[0]) >> i) & 0x1);
}
for(size_t i = 0; i < 12; i++) {
tmp ^= (((d_H[j] & r[1]) >> i) & 0x1);
}
syndrome = (syndrome << 1) ^ tmp;
s = syndrome(r[0], r[1]);
if(weight(s) <= 3) {
*out = ((r[0] ^ s) << 12) | (r[1]);
return true;
}
if(ham_dist(syndrome) <= 3) {
e[0] = syndrome;
e[1] = 0x0;
}
else{
do {
if (ham_dist (syndrome ^ d_H[col]) <= 2) {
e[0] = syndrome ^ d_H[col];
e[1] = d_X[col];
found = 1;
}
col++;
}
while ((col < 12) && !found);
if ((col == 12) && !found) {
for (size_t j = 0; j < 12; j++) {
uint32_t tmp = 0x0;
for (size_t i = 0; i < 12; i++) {
tmp ^= (((d_H[j] & syndrome) >> i) & 0x1);
}
q = (q << 1) ^ tmp;
}
}
if (ham_dist (q) <= 3) {
e[0] = 0;
e[1] = q;
}
else {
col = 0;
found = 0;
do {
if (ham_dist (q ^ d_H[col]) <= 2) {
e[0] = d_X[col];
e[1] = q ^ d_H[col];
found = 1;
}
col++;
}
while ((col < 12) && !found);
if (col == 12 && !found) {
return false;
}
for(size_t i = 0; i < 12; i++) {
const uint16_t tmp = s ^ G_P[i];
if(weight(tmp) <= 2) {
*out = ((r[0] ^ tmp) << 12) | (r[1] ^ G_I[i]);
return true;
}
}
c[0] = r[0] ^ e[0];
c[1] = r[1] ^ e[1];
/* Return the message part only, not the parity */
*out = c[0];
return true;
/* Compute the sP vector */
uint32_t sP = 0;
for(size_t i = 0; i < 12; i++) {
sP = (sP << 1) | (weight(s & G_P[i]) % 2);
}
if(weight(sP) == 2 || weight(sP) == 3) {
*out = (r[0] << 12) | (r[1] ^ sP);
return true;
}
for(size_t i = 0; i < 12; i++) {
const uint16_t tmp = sP ^ G_P[i];
if(weight(tmp) == 2) {
*out = ((r[0] ^ G_I[i]) << 12) | (r[1] ^ tmp);
return true;
}
}
return false;
}
} /* namespace satnogs */

180
lib/qa_golay24.cc Normal file
View File

@ -0,0 +1,180 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qa_golay24.h"
#include <satnogs/golay24.h>
#include <random>
#include <algorithm>
namespace gr {
namespace satnogs {
/* Inspired by the example 4.7 of
* Lin & Costello, Ch4, "Error Control Coding", 2nd ed, Pearson.
*/
void
qa_golay24::example_47()
{
golay24 gol;
uint32_t r = 0b100000110100110000000001;
uint32_t res;
bool ret = gol.decode24 (&res, r);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res >> 12) == 0b100100110110);
}
void
qa_golay24::errors_0()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<uint16_t> uni(0, 0xFFFF);
uint16_t x = uni(mt) & 0xFFF;
golay24 gol;
uint32_t coded = gol.encode12(x);
uint32_t res;
bool ret = gol.decode24(&res, coded);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res >> 12) == x);
coded = gol.encode12(x, false);
ret = gol.decode24(&res, coded);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res & 0xFFF) == x);
}
static inline uint32_t
flip(uint32_t in, uint32_t n)
{
if(!n || n > 24) {
return in;
}
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<uint8_t> flip(0, 23);
std::vector<uint8_t> idx;
while(idx.size() < n) {
uint8_t i = flip(mt);
if (std::find(idx.begin(), idx.end(), i) == idx.end()) {
idx.push_back(i);
}
}
uint32_t mask = 0;
for(uint8_t i : idx) {
mask |= (1 << i);
}
return in ^ mask;
}
void
qa_golay24::errors_1()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<uint16_t> uni(0, 0xFFFF);
for(size_t i = 0; i < 2048; i++) {
uint16_t x = uni(mt) & 0xFFF;
golay24 gol;
uint32_t coded = gol.encode12(x);
/* Apply bit flip */
uint32_t coder_error = flip(coded, 1);
uint32_t res;
bool ret = gol.decode24(&res, coded);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res >> 12)== x);
coded = gol.encode12(x, false);
/* Apply bit flip */
coder_error = flip(coded, 1);
ret = gol.decode24(&res, coded);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res & 0xFFF)== x);
}
}
void
qa_golay24::errors_3()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<uint16_t> uni(0, 0xFFFF);
for(size_t i = 0; i < 2048; i++) {
uint16_t x = uni(mt) & 0xFFF;
golay24 gol;
uint32_t coded = gol.encode12(x);
/* Apply bit flip */
uint32_t coder_error = flip(coded, 3);
uint32_t res;
bool ret = gol.decode24(&res, coded);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res >> 12)== x);
coded = gol.encode12(x, false);
/* Apply bit flip */
coder_error = flip(coded, 3);
ret = gol.decode24(&res, coded);
CPPUNIT_ASSERT(ret);
CPPUNIT_ASSERT((res & 0xFFF)== x);
}
}
void
qa_golay24::errors_4()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<uint16_t> uni(0, 0xFFFF);
for(size_t i = 0; i < 2048; i++) {
uint16_t x = uni(mt) & 0xFFF;
golay24 gol;
uint32_t coded = gol.encode12(x);
/* Apply bit flip */
uint32_t coder_error = flip(coded, 4);
uint32_t res;
bool ret = gol.decode24(&res, coded);
if(ret) {
CPPUNIT_ASSERT((res >> 12)== x);
}
coded = gol.encode12(x, false);
/* Apply bit flip */
coder_error = flip(coded, 4);
ret = gol.decode24(&res, coded);
if(ret) {
CPPUNIT_ASSERT((res & 0xFFF)== x);
}
}
}
} // namespace satnogs
} // namespace gr

66
lib/qa_golay24.h Normal file
View File

@ -0,0 +1,66 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIB_QA_GOLAY24_H_
#define LIB_QA_GOLAY24_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <satnogs/golay24.h>
namespace gr {
namespace satnogs {
class qa_golay24 : public CppUnit::TestCase
{
public:
CPPUNIT_TEST_SUITE(qa_golay24);
CPPUNIT_TEST(example_47);
CPPUNIT_TEST(errors_0);
CPPUNIT_TEST(errors_1);
CPPUNIT_TEST(errors_3);
CPPUNIT_TEST(errors_4);
CPPUNIT_TEST_SUITE_END();
private:
void
example_47();
void
errors_0 ();
void
errors_1 ();
void
errors_3 ();
void
errors_4 ();
};
} // namespace satnogs
} // namespace gr
#endif /* LIB_QA_GOLAY24_H_ */

30
lib/qa_satnogs.cc Normal file
View File

@ -0,0 +1,30 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qa_satnogs.h"
#include "qa_golay24.h"
CppUnit::TestSuite *
qa_satnogs::suite()
{
CppUnit::TestSuite *s = new CppUnit::TestSuite("satnogs");
s->addTest(gr::satnogs::qa_golay24::suite());
return s;
}

35
lib/qa_satnogs.h Normal file
View File

@ -0,0 +1,35 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _QA_SATNOGS_H_
#define _QA_SATNOGS_H_
#include <gnuradio/attributes.h>
#include <cppunit/TestSuite.h>
class __GR_ATTR_EXPORT qa_satnogs
{
public:
static CppUnit::TestSuite *suite();
};
#endif /* _QA_SATNOGS_H_ */

54
lib/test_satnogs.cc Normal file
View File

@ -0,0 +1,54 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cppunit/TextTestRunner.h>
#include <cppunit/XmlOutputter.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestResult.h>
#include <gnuradio/unittests.h>
#include "qa_satnogs.h"
#include <iostream>
#include <fstream>
int
main (int argc, char **argv)
{
CppUnit::TestResultCollector result;
CppUnit::BriefTestProgressListener progressListener;
CppUnit::TextTestRunner runner;
runner.addTest(qa_satnogs::suite());
runner.eventManager().addListener(&result);
runner.eventManager().addListener(&progressListener);
bool was_successful = runner.run("", false);
return was_successful ? 0 : 1;
}