├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── MANIFEST.md ├── README.md ├── TODO ├── apps └── CMakeLists.txt ├── cmake ├── Modules │ ├── CMakeParseArgumentsCopy.cmake │ ├── rsttConfig.cmake │ └── targetConfig.cmake.in └── cmake_uninstall.cmake.in ├── docs ├── CMakeLists.txt ├── README.rstt └── doxygen │ ├── CMakeLists.txt │ ├── Doxyfile.in │ ├── doxyxml │ ├── __init__.py │ ├── base.py │ ├── doxyindex.py │ ├── generated │ │ ├── __init__.py │ │ ├── compound.py │ │ ├── compoundsuper.py │ │ ├── index.py │ │ └── indexsuper.py │ └── text.py │ ├── other │ ├── group_defs.dox │ └── main_page.dox │ ├── pydoc_macros.h │ └── update_pydoc.py ├── examples ├── rstt_rx.grc └── rstt_rx.py ├── grc ├── CMakeLists.txt ├── rstt_clip.block.yml ├── rstt_decoder.block.yml └── rstt_panel.block.yml ├── include └── rstt │ ├── CMakeLists.txt │ ├── api.h │ ├── bits2bytes.h │ ├── bytes2frames.h │ ├── clip.h │ ├── decoder.h │ ├── error_correction.h │ ├── noise_level_estimator.h │ ├── noise_level_estimator2.h │ ├── noise_model.h │ └── symbols2bits.h ├── lib ├── CMakeLists.txt ├── bits2bytes_impl.cc ├── bits2bytes_impl.h ├── byte_status.h ├── bytes2frames_impl.cc ├── bytes2frames_impl.h ├── clip_impl.cc ├── clip_impl.h ├── decoder_impl.cc ├── decoder_impl.h ├── error_correction_guess.cc ├── error_correction_guess.h ├── error_correction_impl.cc ├── error_correction_impl.h ├── noise_level_estimator2_impl.cc ├── noise_level_estimator2_impl.h ├── noise_level_estimator_impl.cc ├── noise_level_estimator_impl.h ├── qa_error_correction.cc ├── qa_error_correction.h ├── qa_error_correction_guess.cc ├── qa_error_correction_guess.h ├── qa_noise_level_estimator.cc ├── qa_noise_level_estimator.h ├── qa_noise_level_estimator2.cc ├── qa_noise_level_estimator2.h ├── qa_rstt.cc ├── qa_rstt.h ├── symbols2bits_impl.cc ├── symbols2bits_impl.h └── test_rstt.cc ├── python ├── CMakeLists.txt ├── __init__.py ├── bindings │ ├── CMakeLists.txt │ ├── README.md │ ├── bind_oot_file.py │ ├── bits2bytes_python.cc │ ├── bytes2frames_python.cc │ ├── clip_python.cc │ ├── decoder_python.cc │ ├── docstrings │ │ ├── README.md │ │ ├── bits2bytes_pydoc_template.h │ │ ├── bytes2frames_pydoc_template.h │ │ ├── clip_pydoc_template.h │ │ ├── decoder_pydoc_template.h │ │ ├── error_correction_pydoc_template.h │ │ ├── noise_level_estimator2_pydoc_template.h │ │ ├── noise_level_estimator_pydoc_template.h │ │ ├── noise_model_pydoc_template.h │ │ └── symbols2bits_pydoc_template.h │ ├── error_correction_python.cc │ ├── header_utils.py │ ├── noise_level_estimator2_python.cc │ ├── noise_level_estimator_python.cc │ ├── noise_model_python.cc │ ├── python_bindings.cc │ └── symbols2bits_python.cc ├── calibration.py ├── conv_tools.py ├── frame.py ├── frame_dumper.py ├── nle2.py ├── nle_integral.py ├── print_row.py ├── qa_bits2bytes.py ├── qa_bytes2frames.py ├── qa_clip.py ├── qa_decoder.py ├── qa_error_correction.py ├── qa_symbols2bits.py ├── rstt_panel.py ├── subframe.py └── test_subframe.py └── utils └── dump_all.sh /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: true 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BreakBeforeBraces: Custom 24 | BraceWrapping: 25 | AfterClass: true 26 | AfterControlStatement: false 27 | AfterEnum: false 28 | AfterFunction: true 29 | AfterNamespace: false 30 | AfterObjCDeclaration: false 31 | AfterStruct: false 32 | AfterUnion: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | BreakBeforeBinaryOperators: None 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: false 39 | BreakAfterJavaFieldAnnotations: false 40 | BreakStringLiterals: true 41 | ColumnLimit: 90 42 | CommentPragmas: '^ IWYU pragma:' 43 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 44 | ConstructorInitializerIndentWidth: 4 45 | ContinuationIndentWidth: 4 46 | Cpp11BracedListStyle: false 47 | DerivePointerAlignment: false 48 | DisableFormat: false 49 | ExperimentalAutoDetectBinPacking: false 50 | ForEachMacros: 51 | - foreach 52 | - Q_FOREACH 53 | - BOOST_FOREACH 54 | IncludeCategories: 55 | - Regex: '^"(gnuradio)/' 56 | Priority: 1 57 | - Regex: '^<(gnuradio)/' 58 | Priority: 2 59 | - Regex: '^<(boost)/' 60 | Priority: 98 61 | - Regex: '^<[a-z]*>$' 62 | Priority: 99 63 | - Regex: '^".*"$' 64 | Priority: 0 65 | - Regex: '.*' 66 | Priority: 10 67 | 68 | IncludeIsMainRegex: '(Test)?$' 69 | IndentCaseLabels: false 70 | IndentWidth: 4 71 | IndentWrappedFunctionNames: false 72 | JavaScriptQuotes: Leave 73 | JavaScriptWrapImports: true 74 | KeepEmptyLinesAtTheStartOfBlocks: true 75 | MacroBlockBegin: '' 76 | MacroBlockEnd: '' 77 | MaxEmptyLinesToKeep: 2 78 | NamespaceIndentation: None 79 | ObjCBlockIndentWidth: 2 80 | ObjCSpaceAfterProperty: false 81 | ObjCSpaceBeforeProtocolList: true 82 | PenaltyBreakBeforeFirstCallParameter: 19 83 | PenaltyBreakComment: 300 84 | PenaltyBreakFirstLessLess: 120 85 | PenaltyBreakString: 1000 86 | PenaltyExcessCharacter: 1000000 87 | PenaltyReturnTypeOnItsOwnLine: 60 88 | PointerAlignment: Left 89 | ReflowComments: true 90 | SortIncludes: true 91 | SpaceAfterCStyleCast: false 92 | SpaceAfterTemplateKeyword: true 93 | SpaceBeforeAssignmentOperators: true 94 | SpaceBeforeParens: ControlStatements 95 | SpaceInEmptyParentheses: false 96 | SpacesBeforeTrailingComments: 1 97 | SpacesInAngles: false 98 | SpacesInContainerLiterals: true 99 | SpacesInCStyleCastParentheses: false 100 | SpacesInParentheses: false 101 | SpacesInSquareBrackets: false 102 | Standard: Cpp11 103 | TabWidth: 8 104 | UseTab: Never 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | *.pyo 4 | build*/ 5 | examples/grc/*.py 6 | apps/rstt_rx.py 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011-2020 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Project setup 11 | ######################################################################## 12 | cmake_minimum_required(VERSION 3.8) 13 | project(gr-rstt CXX C) 14 | enable_testing() 15 | 16 | # Install to PyBOMBS target prefix if defined 17 | if(DEFINED ENV{PYBOMBS_PREFIX}) 18 | set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX}) 19 | message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}") 20 | endif() 21 | 22 | # Select the release build type by default to get optimization flags 23 | if(NOT CMAKE_BUILD_TYPE) 24 | set(CMAKE_BUILD_TYPE "Release") 25 | message(STATUS "Build type not specified: defaulting to release.") 26 | endif(NOT CMAKE_BUILD_TYPE) 27 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") 28 | 29 | # Make sure our local CMake Modules path comes first 30 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) 31 | 32 | # Set the version information here 33 | set(VERSION_MAJOR 1) 34 | set(VERSION_API 1) 35 | set(VERSION_ABI 0) 36 | set(VERSION_PATCH git) 37 | 38 | cmake_policy(SET CMP0011 NEW) 39 | 40 | # Enable generation of compile_commands.json for code completion engines 41 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 42 | 43 | ######################################################################## 44 | # Compiler specific setup 45 | ######################################################################## 46 | if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR 47 | CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 48 | AND NOT WIN32) 49 | #http://gcc.gnu.org/wiki/Visibility 50 | add_definitions(-fvisibility=hidden) 51 | endif() 52 | 53 | IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 54 | SET(CMAKE_CXX_STANDARD 14) 55 | ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 56 | SET(CMAKE_CXX_STANDARD 14) 57 | ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 58 | SET(CMAKE_CXX_STANDARD 14) 59 | ELSE() 60 | message(WARNING "C++ standard could not be set because compiler is not GNU, Clang or MSVC.") 61 | ENDIF() 62 | 63 | IF(CMAKE_C_COMPILER_ID STREQUAL "GNU") 64 | SET(CMAKE_C_STANDARD 11) 65 | ELSEIF(CMAKE_C_COMPILER_ID MATCHES "Clang") 66 | SET(CMAKE_C_STANDARD 11) 67 | ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 68 | SET(CMAKE_C_STANDARD 11) 69 | ELSE() 70 | message(WARNING "C standard could not be set because compiler is not GNU, Clang or MSVC.") 71 | ENDIF() 72 | 73 | ######################################################################## 74 | # Install directories 75 | ######################################################################## 76 | include(FindPkgConfig) 77 | find_package(Gnuradio "3.9" REQUIRED COMPONENTS fec blocks) 78 | include(GrVersion) 79 | 80 | include(GrPlatform) #define LIB_SUFFIX 81 | 82 | # bug in GR: transitive dependencies are not resolved 83 | # fec depends on gsl, but it is not included 84 | # also gsl requires the GR-specific cmake module to create the 85 | # gsl::gsl target. 86 | # another bug in GR is that fec cmake claims to depend on 87 | # GSL::gsl target, which should be gsl::gsl........... 88 | list(INSERT CMAKE_MODULE_PATH 0 ${Gnuradio_DIR}) 89 | find_package(GSL) 90 | 91 | if(NOT CMAKE_MODULES_DIR) 92 | set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) 93 | endif(NOT CMAKE_MODULES_DIR) 94 | 95 | set(GR_INCLUDE_DIR include/rstt) 96 | set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/rstt) 97 | set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) 98 | set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) 99 | set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) 100 | set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) 101 | 102 | ######################################################################## 103 | # On Apple only, set install name and use rpath correctly, if not already set 104 | ######################################################################## 105 | if(APPLE) 106 | if(NOT CMAKE_INSTALL_NAME_DIR) 107 | set(CMAKE_INSTALL_NAME_DIR 108 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 109 | PATH "Library Install Name Destination Directory" FORCE) 110 | endif(NOT CMAKE_INSTALL_NAME_DIR) 111 | if(NOT CMAKE_INSTALL_RPATH) 112 | set(CMAKE_INSTALL_RPATH 113 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 114 | PATH "Library Install RPath" FORCE) 115 | endif(NOT CMAKE_INSTALL_RPATH) 116 | if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 117 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE 118 | BOOL "Do Build Using Library Install RPath" FORCE) 119 | endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 120 | endif(APPLE) 121 | 122 | ######################################################################## 123 | # Find gnuradio build dependencies 124 | ######################################################################## 125 | find_package(Doxygen) 126 | 127 | ######################################################################## 128 | # Setup doxygen option 129 | ######################################################################## 130 | if(DOXYGEN_FOUND) 131 | option(ENABLE_DOXYGEN "Build docs using Doxygen" ON) 132 | else(DOXYGEN_FOUND) 133 | option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF) 134 | endif(DOXYGEN_FOUND) 135 | 136 | ######################################################################## 137 | # Create uninstall target 138 | ######################################################################## 139 | configure_file( 140 | ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 141 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 142 | @ONLY) 143 | 144 | add_custom_target(uninstall 145 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 146 | ) 147 | 148 | ######################################################################## 149 | # Add subdirectories 150 | ######################################################################## 151 | add_subdirectory(include/rstt) 152 | add_subdirectory(lib) 153 | add_subdirectory(apps) 154 | add_subdirectory(docs) 155 | # NOTE: manually update below to use GRC to generate C++ flowgraphs w/o python 156 | if(ENABLE_PYTHON) 157 | message(STATUS "PYTHON and GRC components are enabled") 158 | add_subdirectory(python) 159 | add_subdirectory(grc) 160 | else(ENABLE_PYTHON) 161 | message(STATUS "PYTHON and GRC components are disabled") 162 | endif(ENABLE_PYTHON) 163 | 164 | ######################################################################## 165 | # Install cmake search helper for this library 166 | ######################################################################## 167 | 168 | install(FILES cmake/Modules/rsttConfig.cmake 169 | DESTINATION ${CMAKE_MODULES_DIR}/rstt 170 | ) 171 | -------------------------------------------------------------------------------- /MANIFEST.md: -------------------------------------------------------------------------------- 1 | title: Receiver for Vaisala Weather Balloons 2 | brief: Receiver for Vaisala Weather Balloons 3 | tags: 4 | - Vaisala 5 | - telemetry 6 | - weather balloon 7 | author: 8 | - Jiri Pinkava 9 | - Bastian Bloessl 10 | copyright_owner: 11 | - Free Software Foundation 12 | website: http://brmlab.cz/project/weathersonde/start 13 | gr_supported_version: v3.7, v3.8, v3.9 14 | --- 15 | Receive and decode telemetry from Vaisala meteorological radiosondes (namely RS92-SGP/RS92-SGPD). 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSTT - RadioSonde Telemetry Tool 2 | 3 | Recieve and decode telemetry from Vaisala meteorological radiosondes (namely 4 | RS92-SGP/RS92-SGPD). 5 | 6 | Further Information 7 | http://brmlab.cz/project/weathersonde/start 8 | 9 | See individual files for license, where no explicit license is specified see 10 | LILCENSE.txt for details. 11 | 12 | It is based on Gnuradio building blocks with some custom code. Use Python and 13 | C++ as main languagues. Result is tested only on Linux, but add tweaks for other 14 | platforms shoud be easy, feel free to send patches. 15 | 16 | ## Development 17 | 18 | Like GNU Radio, this module uses *maint* branches for development. 19 | These branches are supposed to be used with the corresponding GNU Radio 20 | branches. This means: the *maint-3.7* branch is compatible with GNU Radio 3.7, 21 | *maint-3.8* is compatible with GNU Radio 3.8, etc. 22 | 23 | ## Dependencies 24 | - GNU Radio. See the [GNU Radio 25 | Wiki](http://gnuradio.org/redmine/projects/gnuradio/wiki/InstallingGR) for 26 | installation instructions. 27 | 28 | 29 | ## Installation 30 | ``` 31 | mkdir build 32 | cd build 33 | cmake .. 34 | make 35 | sudo make install 36 | sudo ldconfig 37 | ``` 38 | 39 | ## Usage 40 | 41 | Start flow graphs in the *apps* folder. 42 | 43 | 44 | ## Demos 45 | 46 | Quick example: 47 | https://www.youtube.com/watch?v=B_IbqoJjNLw 48 | 49 | [![gr-rstt demo](http://img.youtube.com/vi/B_IbqoJjNLw/0.jpg)](http://www.youtube.com/watch?v=B_IbqoJjNLw "gr-rstt demo") 50 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Just list of what can be done, order does not correlate with priority. 2 | 3 | - decode GPS position 4 | - measurement decoder using calibration data 5 | - store recieved/decoded data (DB/filesystem) 6 | - visualize (GUI/web app) telemetry 7 | - RPC server proxy for recieved data 8 | - web based aplication for sonde flight tracking (plot map, track and decoded telemetry) 9 | - tool for automatic transmission detection 10 | - SDR based reciever 11 | - peak/signal detection 12 | - automatic start of reciever/decoder 13 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | include(GrPython) 10 | 11 | GR_PYTHON_INSTALL( 12 | PROGRAMS 13 | DESTINATION bin 14 | ) 15 | -------------------------------------------------------------------------------- /cmake/Modules/CMakeParseArgumentsCopy.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE_PARSE_ARGUMENTS( args...) 2 | # 3 | # CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for 4 | # parsing the arguments given to that macro or function. 5 | # It processes the arguments and defines a set of variables which hold the 6 | # values of the respective options. 7 | # 8 | # The argument contains all options for the respective macro, 9 | # i.e. keywords which can be used when calling the macro without any value 10 | # following, like e.g. the OPTIONAL keyword of the install() command. 11 | # 12 | # The argument contains all keywords for this macro 13 | # which are followed by one value, like e.g. DESTINATION keyword of the 14 | # install() command. 15 | # 16 | # The argument contains all keywords for this macro 17 | # which can be followed by more than one value, like e.g. the TARGETS or 18 | # FILES keywords of the install() command. 19 | # 20 | # When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the 21 | # keywords listed in , and 22 | # a variable composed of the given 23 | # followed by "_" and the name of the respective keyword. 24 | # These variables will then hold the respective value from the argument list. 25 | # For the keywords this will be TRUE or FALSE. 26 | # 27 | # All remaining arguments are collected in a variable 28 | # _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether 29 | # your macro was called with unrecognized parameters. 30 | # 31 | # As an example here a my_install() macro, which takes similar arguments as the 32 | # real install() command: 33 | # 34 | # function(MY_INSTALL) 35 | # set(options OPTIONAL FAST) 36 | # set(oneValueArgs DESTINATION RENAME) 37 | # set(multiValueArgs TARGETS CONFIGURATIONS) 38 | # cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 39 | # ... 40 | # 41 | # Assume my_install() has been called like this: 42 | # my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) 43 | # 44 | # After the cmake_parse_arguments() call the macro will have set the following 45 | # variables: 46 | # MY_INSTALL_OPTIONAL = TRUE 47 | # MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() 48 | # MY_INSTALL_DESTINATION = "bin" 49 | # MY_INSTALL_RENAME = "" (was not used) 50 | # MY_INSTALL_TARGETS = "foo;bar" 51 | # MY_INSTALL_CONFIGURATIONS = "" (was not used) 52 | # MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" 53 | # 54 | # You can the continue and process these variables. 55 | # 56 | # Keywords terminate lists of values, e.g. if directly after a one_value_keyword 57 | # another recognized keyword follows, this is interpreted as the beginning of 58 | # the new option. 59 | # E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in 60 | # MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would 61 | # be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore. 62 | 63 | #============================================================================= 64 | # Copyright 2010 Alexander Neundorf 65 | # 66 | # Distributed under the OSI-approved BSD License (the "License"); 67 | # see accompanying file Copyright.txt for details. 68 | # 69 | # This software is distributed WITHOUT ANY WARRANTY; without even the 70 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 71 | # See the License for more information. 72 | #============================================================================= 73 | # (To distribute this file outside of CMake, substitute the full 74 | # License text for the above reference.) 75 | 76 | 77 | if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) 78 | return() 79 | endif() 80 | set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) 81 | 82 | 83 | function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) 84 | # first set all result variables to empty/FALSE 85 | foreach(arg_name ${_singleArgNames} ${_multiArgNames}) 86 | set(${prefix}_${arg_name}) 87 | endforeach(arg_name) 88 | 89 | foreach(option ${_optionNames}) 90 | set(${prefix}_${option} FALSE) 91 | endforeach(option) 92 | 93 | set(${prefix}_UNPARSED_ARGUMENTS) 94 | 95 | set(insideValues FALSE) 96 | set(currentArgName) 97 | 98 | # now iterate over all arguments and fill the result variables 99 | foreach(currentArg ${ARGN}) 100 | list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword 101 | list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword 102 | list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword 103 | 104 | if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) 105 | if(insideValues) 106 | if("${insideValues}" STREQUAL "SINGLE") 107 | set(${prefix}_${currentArgName} ${currentArg}) 108 | set(insideValues FALSE) 109 | elseif("${insideValues}" STREQUAL "MULTI") 110 | list(APPEND ${prefix}_${currentArgName} ${currentArg}) 111 | endif() 112 | else(insideValues) 113 | list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) 114 | endif(insideValues) 115 | else() 116 | if(NOT ${optionIndex} EQUAL -1) 117 | set(${prefix}_${currentArg} TRUE) 118 | set(insideValues FALSE) 119 | elseif(NOT ${singleArgIndex} EQUAL -1) 120 | set(currentArgName ${currentArg}) 121 | set(${prefix}_${currentArgName}) 122 | set(insideValues "SINGLE") 123 | elseif(NOT ${multiArgIndex} EQUAL -1) 124 | set(currentArgName ${currentArg}) 125 | set(${prefix}_${currentArgName}) 126 | set(insideValues "MULTI") 127 | endif() 128 | endif() 129 | 130 | endforeach(currentArg) 131 | 132 | # propagate the result variables to the caller: 133 | foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) 134 | set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) 135 | endforeach(arg_name) 136 | set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) 137 | 138 | endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) 139 | -------------------------------------------------------------------------------- /cmake/Modules/rsttConfig.cmake: -------------------------------------------------------------------------------- 1 | if(NOT PKG_CONFIG_FOUND) 2 | INCLUDE(FindPkgConfig) 3 | endif() 4 | PKG_CHECK_MODULES(PC_RSTT rstt) 5 | 6 | FIND_PATH( 7 | RSTT_INCLUDE_DIRS 8 | NAMES rstt/api.h 9 | HINTS $ENV{RSTT_DIR}/include 10 | ${PC_RSTT_INCLUDEDIR} 11 | PATHS ${CMAKE_INSTALL_PREFIX}/include 12 | /usr/local/include 13 | /usr/include 14 | ) 15 | 16 | FIND_LIBRARY( 17 | RSTT_LIBRARIES 18 | NAMES gnuradio-rstt 19 | HINTS $ENV{RSTT_DIR}/lib 20 | ${PC_RSTT_LIBDIR} 21 | PATHS ${CMAKE_INSTALL_PREFIX}/lib 22 | ${CMAKE_INSTALL_PREFIX}/lib64 23 | /usr/local/lib 24 | /usr/local/lib64 25 | /usr/lib 26 | /usr/lib64 27 | ) 28 | 29 | include("${CMAKE_CURRENT_LIST_DIR}/rsttTarget.cmake") 30 | 31 | INCLUDE(FindPackageHandleStandardArgs) 32 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(RSTT DEFAULT_MSG RSTT_LIBRARIES RSTT_INCLUDE_DIRS) 33 | MARK_AS_ADVANCED(RSTT_LIBRARIES RSTT_INCLUDE_DIRS) 34 | -------------------------------------------------------------------------------- /cmake/Modules/targetConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | # 7 | 8 | include(CMakeFindDependencyMacro) 9 | 10 | set(target_deps "@TARGET_DEPENDENCIES@") 11 | foreach(dep IN LISTS target_deps) 12 | find_dependency(${dep}) 13 | endforeach() 14 | include("${CMAKE_CURRENT_LIST_DIR}/@TARGET@Targets.cmake") 15 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 2 | 3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | STRING(REGEX REPLACE "\n" ";" files "${files}") 9 | FOREACH(file ${files}) 10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 11 | IF(EXISTS "$ENV{DESTDIR}${file}") 12 | EXEC_PROGRAM( 13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 14 | OUTPUT_VARIABLE rm_out 15 | RETURN_VALUE rm_retval 16 | ) 17 | IF(NOT "${rm_retval}" STREQUAL 0) 18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 19 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | EXEC_PROGRAM( 22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval 25 | ) 26 | IF(NOT "${rm_retval}" STREQUAL 0) 27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 28 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 29 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 32 | ENDFOREACH(file) 33 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Setup dependencies 11 | ######################################################################## 12 | find_package(Doxygen) 13 | 14 | ######################################################################## 15 | # Begin conditional configuration 16 | ######################################################################## 17 | if(ENABLE_DOXYGEN) 18 | 19 | ######################################################################## 20 | # Add subdirectories 21 | ######################################################################## 22 | add_subdirectory(doxygen) 23 | 24 | endif(ENABLE_DOXYGEN) 25 | -------------------------------------------------------------------------------- /docs/README.rstt: -------------------------------------------------------------------------------- 1 | This is the rstt-write-a-block package meant as a guide to building 2 | out-of-tree packages. To use the rstt blocks, the Python namespaces 3 | is in 'rstt', which is imported as: 4 | 5 | import rstt 6 | 7 | See the Doxygen documentation for details about the blocks available 8 | in this package. A quick listing of the details can be found in Python 9 | after importing by using: 10 | 11 | help(rstt) 12 | -------------------------------------------------------------------------------- /docs/doxygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Create the doxygen configuration file 11 | ######################################################################## 12 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) 13 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) 14 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir) 15 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir) 16 | 17 | set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) 18 | set(enable_html_docs YES) 19 | set(enable_latex_docs NO) 20 | set(enable_mathjax NO) 21 | set(enable_xml_docs YES) 22 | 23 | configure_file( 24 | ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 25 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 26 | @ONLY) 27 | 28 | set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html) 29 | 30 | ######################################################################## 31 | # Make and install doxygen docs 32 | ######################################################################## 33 | add_custom_command( 34 | OUTPUT ${BUILT_DIRS} 35 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 36 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 37 | COMMENT "Generating documentation with doxygen" 38 | ) 39 | 40 | add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS}) 41 | 42 | install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR}) 43 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-rstt 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | Python interface to contents of doxygen xml documentation. 12 | 13 | Example use: 14 | See the contents of the example folder for the C++ and 15 | doxygen-generated xml used in this example. 16 | 17 | >>> # Parse the doxygen docs. 18 | >>> import os 19 | >>> this_dir = os.path.dirname(globals()['__file__']) 20 | >>> xml_path = this_dir + "/example/xml/" 21 | >>> di = DoxyIndex(xml_path) 22 | 23 | Get a list of all top-level objects. 24 | 25 | >>> print([mem.name() for mem in di.members()]) 26 | [u'Aadvark', u'aadvarky_enough', u'main'] 27 | 28 | Get all functions. 29 | 30 | >>> print([mem.name() for mem in di.in_category(DoxyFunction)]) 31 | [u'aadvarky_enough', u'main'] 32 | 33 | Check if an object is present. 34 | 35 | >>> di.has_member(u'Aadvark') 36 | True 37 | >>> di.has_member(u'Fish') 38 | False 39 | 40 | Get an item by name and check its properties. 41 | 42 | >>> aad = di.get_member(u'Aadvark') 43 | >>> print(aad.brief_description) 44 | Models the mammal Aadvark. 45 | >>> print(aad.detailed_description) 46 | Sadly the model is incomplete and cannot capture all aspects of an aadvark yet. 47 | 48 | This line is uninformative and is only to test line breaks in the comments. 49 | >>> [mem.name() for mem in aad.members()] 50 | [u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness'] 51 | >>> aad.get_member(u'print').brief_description 52 | u'Outputs the vital aadvark statistics.' 53 | 54 | """ 55 | 56 | from .doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther 57 | 58 | def _test(): 59 | import os 60 | this_dir = os.path.dirname(globals()['__file__']) 61 | xml_path = this_dir + "/example/xml/" 62 | di = DoxyIndex(xml_path) 63 | # Get the Aadvark class 64 | aad = di.get_member('Aadvark') 65 | aad.brief_description 66 | import doctest 67 | return doctest.testmod() 68 | 69 | if __name__ == "__main__": 70 | _test() 71 | 72 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/base.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-rstt 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | A base class is created. 12 | 13 | Classes based upon this are used to make more user-friendly interfaces 14 | to the doxygen xml docs than the generated classes provide. 15 | """ 16 | 17 | import os 18 | import pdb 19 | 20 | from xml.parsers.expat import ExpatError 21 | 22 | from .generated import compound 23 | 24 | 25 | class Base(object): 26 | 27 | class Duplicate(Exception): 28 | pass 29 | 30 | class NoSuchMember(Exception): 31 | pass 32 | 33 | class ParsingError(Exception): 34 | pass 35 | 36 | def __init__(self, parse_data, top=None): 37 | self._parsed = False 38 | self._error = False 39 | self._parse_data = parse_data 40 | self._members = [] 41 | self._dict_members = {} 42 | self._in_category = {} 43 | self._data = {} 44 | if top is not None: 45 | self._xml_path = top._xml_path 46 | # Set up holder of references 47 | else: 48 | top = self 49 | self._refs = {} 50 | self._xml_path = parse_data 51 | self.top = top 52 | 53 | @classmethod 54 | def from_refid(cls, refid, top=None): 55 | """ Instantiate class from a refid rather than parsing object. """ 56 | # First check to see if its already been instantiated. 57 | if top is not None and refid in top._refs: 58 | return top._refs[refid] 59 | # Otherwise create a new instance and set refid. 60 | inst = cls(None, top=top) 61 | inst.refid = refid 62 | inst.add_ref(inst) 63 | return inst 64 | 65 | @classmethod 66 | def from_parse_data(cls, parse_data, top=None): 67 | refid = getattr(parse_data, 'refid', None) 68 | if refid is not None and top is not None and refid in top._refs: 69 | return top._refs[refid] 70 | inst = cls(parse_data, top=top) 71 | if refid is not None: 72 | inst.refid = refid 73 | inst.add_ref(inst) 74 | return inst 75 | 76 | def add_ref(self, obj): 77 | if hasattr(obj, 'refid'): 78 | self.top._refs[obj.refid] = obj 79 | 80 | mem_classes = [] 81 | 82 | def get_cls(self, mem): 83 | for cls in self.mem_classes: 84 | if cls.can_parse(mem): 85 | return cls 86 | raise Exception(("Did not find a class for object '%s'." \ 87 | % (mem.get_name()))) 88 | 89 | def convert_mem(self, mem): 90 | try: 91 | cls = self.get_cls(mem) 92 | converted = cls.from_parse_data(mem, self.top) 93 | if converted is None: 94 | raise Exception('No class matched this object.') 95 | self.add_ref(converted) 96 | return converted 97 | except Exception as e: 98 | print(e) 99 | 100 | @classmethod 101 | def includes(cls, inst): 102 | return isinstance(inst, cls) 103 | 104 | @classmethod 105 | def can_parse(cls, obj): 106 | return False 107 | 108 | def _parse(self): 109 | self._parsed = True 110 | 111 | def _get_dict_members(self, cat=None): 112 | """ 113 | For given category a dictionary is returned mapping member names to 114 | members of that category. For names that are duplicated the name is 115 | mapped to None. 116 | """ 117 | self.confirm_no_error() 118 | if cat not in self._dict_members: 119 | new_dict = {} 120 | for mem in self.in_category(cat): 121 | if mem.name() not in new_dict: 122 | new_dict[mem.name()] = mem 123 | else: 124 | new_dict[mem.name()] = self.Duplicate 125 | self._dict_members[cat] = new_dict 126 | return self._dict_members[cat] 127 | 128 | def in_category(self, cat): 129 | self.confirm_no_error() 130 | if cat is None: 131 | return self._members 132 | if cat not in self._in_category: 133 | self._in_category[cat] = [mem for mem in self._members 134 | if cat.includes(mem)] 135 | return self._in_category[cat] 136 | 137 | def get_member(self, name, cat=None): 138 | self.confirm_no_error() 139 | # Check if it's in a namespace or class. 140 | bits = name.split('::') 141 | first = bits[0] 142 | rest = '::'.join(bits[1:]) 143 | member = self._get_dict_members(cat).get(first, self.NoSuchMember) 144 | # Raise any errors that are returned. 145 | if member in set([self.NoSuchMember, self.Duplicate]): 146 | raise member() 147 | if rest: 148 | return member.get_member(rest, cat=cat) 149 | return member 150 | 151 | def has_member(self, name, cat=None): 152 | try: 153 | mem = self.get_member(name, cat=cat) 154 | return True 155 | except self.NoSuchMember: 156 | return False 157 | 158 | def data(self): 159 | self.confirm_no_error() 160 | return self._data 161 | 162 | def members(self): 163 | self.confirm_no_error() 164 | return self._members 165 | 166 | def process_memberdefs(self): 167 | mdtss = [] 168 | for sec in self._retrieved_data.compounddef.sectiondef: 169 | mdtss += sec.memberdef 170 | # At the moment we lose all information associated with sections. 171 | # Sometimes a memberdef is in several sectiondef. 172 | # We make sure we don't get duplicates here. 173 | uniques = set([]) 174 | for mem in mdtss: 175 | converted = self.convert_mem(mem) 176 | pair = (mem.name, mem.__class__) 177 | if pair not in uniques: 178 | uniques.add(pair) 179 | self._members.append(converted) 180 | 181 | def retrieve_data(self): 182 | filename = os.path.join(self._xml_path, self.refid + '.xml') 183 | try: 184 | self._retrieved_data = compound.parse(filename) 185 | except ExpatError: 186 | print('Error in xml in file %s' % filename) 187 | self._error = True 188 | self._retrieved_data = None 189 | 190 | def check_parsed(self): 191 | if not self._parsed: 192 | self._parse() 193 | 194 | def confirm_no_error(self): 195 | self.check_parsed() 196 | if self._error: 197 | raise self.ParsingError() 198 | 199 | def error(self): 200 | self.check_parsed() 201 | return self._error 202 | 203 | def name(self): 204 | # first see if we can do it without processing. 205 | if self._parse_data is not None: 206 | return self._parse_data.name 207 | self.check_parsed() 208 | return self._retrieved_data.compounddef.name 209 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains generated files produced by generateDS.py. 3 | 4 | These do the real work of parsing the doxygen xml files but the 5 | resultant classes are not very friendly to navigate so the rest of the 6 | doxyxml module processes them further. 7 | """ 8 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generated Mon Feb 9 19:08:05 2009 by generateDS.py. 5 | """ 6 | 7 | from xml.dom import minidom 8 | 9 | import os 10 | import sys 11 | from . import compound 12 | 13 | from . import indexsuper as supermod 14 | 15 | class DoxygenTypeSub(supermod.DoxygenType): 16 | def __init__(self, version=None, compound=None): 17 | supermod.DoxygenType.__init__(self, version, compound) 18 | 19 | def find_compounds_and_members(self, details): 20 | """ 21 | Returns a list of all compounds and their members which match details 22 | """ 23 | 24 | results = [] 25 | for compound in self.compound: 26 | members = compound.find_members(details) 27 | if members: 28 | results.append([compound, members]) 29 | else: 30 | if details.match(compound): 31 | results.append([compound, []]) 32 | 33 | return results 34 | 35 | supermod.DoxygenType.subclass = DoxygenTypeSub 36 | # end class DoxygenTypeSub 37 | 38 | 39 | class CompoundTypeSub(supermod.CompoundType): 40 | def __init__(self, kind=None, refid=None, name='', member=None): 41 | supermod.CompoundType.__init__(self, kind, refid, name, member) 42 | 43 | def find_members(self, details): 44 | """ 45 | Returns a list of all members which match details 46 | """ 47 | 48 | results = [] 49 | 50 | for member in self.member: 51 | if details.match(member): 52 | results.append(member) 53 | 54 | return results 55 | 56 | supermod.CompoundType.subclass = CompoundTypeSub 57 | # end class CompoundTypeSub 58 | 59 | 60 | class MemberTypeSub(supermod.MemberType): 61 | 62 | def __init__(self, kind=None, refid=None, name=''): 63 | supermod.MemberType.__init__(self, kind, refid, name) 64 | 65 | supermod.MemberType.subclass = MemberTypeSub 66 | # end class MemberTypeSub 67 | 68 | 69 | def parse(inFilename): 70 | 71 | doc = minidom.parse(inFilename) 72 | rootNode = doc.documentElement 73 | rootObj = supermod.DoxygenType.factory() 74 | rootObj.build(rootNode) 75 | 76 | return rootObj 77 | 78 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/text.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-rstt 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | Utilities for extracting text from generated classes. 12 | """ 13 | 14 | def is_string(txt): 15 | if isinstance(txt, str): 16 | return True 17 | try: 18 | if isinstance(txt, str): 19 | return True 20 | except NameError: 21 | pass 22 | return False 23 | 24 | def description(obj): 25 | if obj is None: 26 | return None 27 | return description_bit(obj).strip() 28 | 29 | def description_bit(obj): 30 | if hasattr(obj, 'content'): 31 | contents = [description_bit(item) for item in obj.content] 32 | result = ''.join(contents) 33 | elif hasattr(obj, 'content_'): 34 | contents = [description_bit(item) for item in obj.content_] 35 | result = ''.join(contents) 36 | elif hasattr(obj, 'value'): 37 | result = description_bit(obj.value) 38 | elif is_string(obj): 39 | return obj 40 | else: 41 | raise Exception('Expecting a string or something with content, content_ or value attribute') 42 | # If this bit is a paragraph then add one some line breaks. 43 | if hasattr(obj, 'name') and obj.name == 'para': 44 | result += "\n\n" 45 | return result 46 | -------------------------------------------------------------------------------- /docs/doxygen/other/group_defs.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | * \defgroup block GNU Radio RSTT C++ Signal Processing Blocks 3 | * \brief All C++ blocks that can be used from the RSTT GNU Radio 4 | * module are listed here or in the subcategories below. 5 | * 6 | */ 7 | 8 | -------------------------------------------------------------------------------- /docs/doxygen/other/main_page.dox: -------------------------------------------------------------------------------- 1 | /*! \mainpage 2 | 3 | Welcome to the GNU Radio RSTT Block 4 | 5 | This is the intro page for the Doxygen manual generated for the RSTT 6 | block (docs/doxygen/other/main_page.dox). Edit it to add more detailed 7 | documentation about the new GNU Radio modules contained in this 8 | project. 9 | 10 | */ 11 | -------------------------------------------------------------------------------- /docs/doxygen/pydoc_macros.h: -------------------------------------------------------------------------------- 1 | #ifndef PYDOC_MACROS_H 2 | #define PYDOC_MACROS_H 3 | 4 | #define __EXPAND(x) x 5 | #define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT 6 | #define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1)) 7 | #define __CAT1(a, b) a##b 8 | #define __CAT2(a, b) __CAT1(a, b) 9 | #define __DOC1(n1) __doc_##n1 10 | #define __DOC2(n1, n2) __doc_##n1##_##n2 11 | #define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3 12 | #define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4 13 | #define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4##_##n5 14 | #define __DOC6(n1, n2, n3, n4, n5, n6) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6 15 | #define __DOC7(n1, n2, n3, n4, n5, n6, n7) \ 16 | __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7 17 | #define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) 18 | 19 | #endif // PYDOC_MACROS_H -------------------------------------------------------------------------------- /grc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | install(FILES 10 | rstt_clip.block.yml 11 | rstt_decoder.block.yml 12 | rstt_panel.block.yml DESTINATION share/gnuradio/grc/blocks 13 | ) 14 | -------------------------------------------------------------------------------- /grc/rstt_clip.block.yml: -------------------------------------------------------------------------------- 1 | # auto-generated by grc.converter 2 | 3 | id: rstt_clip 4 | label: clip 5 | category: '[RSTT]' 6 | 7 | parameters: 8 | - id: vlen 9 | label: Vector length 10 | dtype: int 11 | default: '1024' 12 | hide: ${ 'part' if vlen == 1 else 'none' } 13 | - id: in_bw 14 | label: BW of input vector 15 | dtype: float 16 | default: '1.' 17 | hide: ${ 'part' if vlen == 1 else 'none' } 18 | - id: out_bw 19 | label: BW of output vector 20 | dtype: float 21 | default: '0.8' 22 | hide: ${ 'part' if vlen == 1 else 'none' } 23 | 24 | inputs: 25 | - domain: stream 26 | dtype: float 27 | vlen: ${ vlen } 28 | 29 | outputs: 30 | - domain: stream 31 | dtype: float 32 | vlen: ${ vlen - 2 * round(vlen*(in_bw - out_bw) / in_bw / 2) } 33 | 34 | templates: 35 | imports: import rstt 36 | make: rstt.clip(${vlen}, ${in_bw}, ${out_bw}) 37 | 38 | documentation: |- 39 | Remove symetricaly outer points from input vector. 40 | 41 | file_format: 1 42 | -------------------------------------------------------------------------------- /grc/rstt_decoder.block.yml: -------------------------------------------------------------------------------- 1 | # auto-generated by grc.converter 2 | 3 | id: rstt_decoder 4 | label: Decoder 5 | category: '[RSTT]' 6 | 7 | parameters: 8 | - id: sync_nbits 9 | label: Synchronize N bits 10 | dtype: int 11 | default: 20*10 12 | - id: sync_nbytes 13 | label: Synchronize N bytes 14 | dtype: int 15 | default: '32' 16 | - id: drop_invalid 17 | label: Drop invalid frames 18 | dtype: bool 19 | default: 'True' 20 | - id: guess_level 21 | label: Guess corrections 22 | dtype: int 23 | default: '2' 24 | 25 | inputs: 26 | - domain: stream 27 | dtype: byte 28 | 29 | outputs: 30 | - domain: stream 31 | dtype: short 32 | vlen: 240 33 | 34 | templates: 35 | imports: import rstt 36 | make: rstt.decoder(${sync_nbits}, ${sync_nbytes}, ${drop_invalid}) 37 | 38 | documentation: |- 39 | Guess correction set level of 'guessing' for error correction based on 40 | byte value distribution probability. 41 | 0 - disabled, 42 | 1 - correct only well known bytes, 43 | 4/6/8 - good values for value guessing (with error probability N/256) 44 | 256 - try guess all bytes (nonsens) 45 | 46 | file_format: 1 47 | -------------------------------------------------------------------------------- /grc/rstt_panel.block.yml: -------------------------------------------------------------------------------- 1 | # auto-generated by grc.converter 2 | 3 | id: rstt_panel 4 | label: RSTT Panel 5 | category: '[RSTT]' 6 | 7 | parameters: 8 | - id: gui_hint 9 | label: GUI Hint 10 | dtype: gui_hint 11 | hide: part 12 | 13 | inputs: 14 | - domain: stream 15 | dtype: short 16 | vlen: 240 17 | 18 | templates: 19 | imports: import rstt 20 | make: | 21 | <% 22 | win = 'self._%s_win'%id 23 | %>\ 24 | rstt.rsttPanel() 25 | ${win} = self.${id} 26 | ${gui_hint() % win} 27 | 28 | file_format: 1 29 | -------------------------------------------------------------------------------- /include/rstt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Install public header files 11 | ######################################################################## 12 | install(FILES 13 | api.h 14 | symbols2bits.h 15 | bits2bytes.h 16 | bytes2frames.h 17 | error_correction.h 18 | decoder.h 19 | noise_model.h 20 | noise_level_estimator.h 21 | noise_level_estimator2.h 22 | clip.h DESTINATION include/rstt 23 | ) 24 | -------------------------------------------------------------------------------- /include/rstt/api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Free Software Foundation, Inc. 3 | * 4 | * This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | * This file is a part of gr-rstt 6 | * 7 | * SPDX-License-Identifier: GPL-3.0-or-later 8 | * 9 | */ 10 | 11 | #ifndef INCLUDED_RSTT_API_H 12 | #define INCLUDED_RSTT_API_H 13 | 14 | #include 15 | 16 | #ifdef gnuradio_rstt_EXPORTS 17 | #define RSTT_API __GR_ATTR_EXPORT 18 | #else 19 | #define RSTT_API __GR_ATTR_IMPORT 20 | #endif 21 | 22 | #endif /* INCLUDED_RSTT_API_H */ 23 | -------------------------------------------------------------------------------- /include/rstt/bits2bytes.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_BITS2BYTES_H 17 | #define INCLUDED_RSTT_BITS2BYTES_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * \brief Convert bit stream to byte stream. 27 | * \ingroup rstt 28 | * 29 | */ 30 | class RSTT_API bits2bytes : virtual public gr::block 31 | { 32 | public: 33 | typedef std::shared_ptr sptr; 34 | 35 | /*! 36 | * \brief Return a shared_ptr to a new instance of rstt::bits2bytes. 37 | * 38 | * To avoid accidental use of raw pointers, rstt::bits2bytes's 39 | * constructor is in a private implementation 40 | * class. rstt::bits2bytes::make is the public interface for 41 | * creating new instances. 42 | */ 43 | static sptr make(int sync_nbytes); 44 | }; 45 | 46 | } // namespace rstt 47 | } // namespace gr 48 | 49 | #endif /* INCLUDED_RSTT_BITS2BYTES_H */ 50 | -------------------------------------------------------------------------------- /include/rstt/bytes2frames.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef INCLUDED_RSTT_BYTES2FRAMES_H 18 | #define INCLUDED_RSTT_BYTES2FRAMES_H 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | /*! 27 | * \brief <+description of block+> 28 | * \ingroup rstt 29 | * 30 | */ 31 | class RSTT_API bytes2frames : virtual public gr::block 32 | { 33 | public: 34 | typedef std::shared_ptr sptr; 35 | 36 | /*! 37 | * \brief Return a shared_ptr to a new instance of rstt::bytes2frames. 38 | * 39 | * To avoid accidental use of raw pointers, rstt::bytes2frames's 40 | * constructor is in a private implementation 41 | * class. rstt::bytes2frames::make is the public interface for 42 | * creating new instances. 43 | */ 44 | static sptr make(); 45 | }; 46 | 47 | } // namespace rstt 48 | } // namespace gr 49 | 50 | #endif /* INCLUDED_RSTT_BYTES2FRAMES_H */ 51 | -------------------------------------------------------------------------------- /include/rstt/clip.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_CLIP_H 17 | #define INCLUDED_RSTT_CLIP_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * \brief Clip symmetrically both sides of vector, shrinking it from 27 | * in_bw to out_bw. 28 | * \ingroup rstt 29 | * 30 | */ 31 | class RSTT_API clip : virtual public gr::sync_block 32 | { 33 | public: 34 | typedef std::shared_ptr sptr; 35 | 36 | static sptr make(int vlen, float in_bw, float out_bw); 37 | 38 | virtual int trim() const = 0; 39 | virtual int vlen_out() const = 0; 40 | }; 41 | 42 | } // namespace rstt 43 | } // namespace gr 44 | 45 | #endif /* INCLUDED_RSTT_CLIP_H */ 46 | -------------------------------------------------------------------------------- /include/rstt/decoder.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef INCLUDED_RSTT_DECODER_H 18 | #define INCLUDED_RSTT_DECODER_H 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | /*! 27 | * \brief Convert demodulated symbols to frames. 28 | * \ingroup rstt 29 | * 30 | */ 31 | class RSTT_API decoder : virtual public gr::hier_block2 32 | { 33 | public: 34 | typedef std::shared_ptr sptr; 35 | 36 | /*! 37 | * \brief Return a shared_ptr to a new instance of rstt::decoder. 38 | * 39 | * \param sync_nbits Use N bits for bite stream synchronization. 40 | * \param sync_nbytes Use N bytes for byte stream synchronization. 41 | * \param drop_invalid Drop invalid frames (keep partialy valid). 42 | * \param guess_level Error correction based on byte value distribution 43 | * probability. 0 - disabled, 1 - correct only well known bytes, 44 | * 4/6/8 - good values for value guessing (with error probability N/256) 45 | * 256 - try guess all bytes (nonsens) 46 | * 47 | * To avoid accidental use of raw pointers, rstt::decoder's 48 | * constructor is in a private implementation 49 | * class. rstt::decoder::make is the public interface for 50 | * creating new instances. 51 | */ 52 | static sptr make(int sync_nbits = 20 * 10, 53 | int sync_nbytes = 32, 54 | bool drop_invalid = true, 55 | int guess_level = 1); 56 | }; 57 | 58 | } // namespace rstt 59 | } // namespace gr 60 | 61 | #endif /* INCLUDED_RSTT_DECODER_H */ 62 | -------------------------------------------------------------------------------- /include/rstt/error_correction.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef INCLUDED_RSTT_ERROR_CORRECTION_H 18 | #define INCLUDED_RSTT_ERROR_CORRECTION_H 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | /*! 27 | * \brief Correct errors in recieved radisonde frames. 28 | * \ingroup rstt 29 | * 30 | */ 31 | class RSTT_API error_correction : virtual public gr::sync_block 32 | { 33 | public: 34 | typedef std::shared_ptr sptr; 35 | 36 | /*! 37 | * \brief Return a shared_ptr to a new instance of rstt::error_correction. 38 | * 39 | * \param drop_invalid Drop totaly broken frames (keep partialy broken). 40 | * \param guess_level Enable error correction by guessing byte values, 41 | * based on content of previous frames. 42 | * 0 - guessing disables, 1 - known for sure, 4/6/8 - safe and usefull 43 | * 256 - maximum (nonsense, try guess all bytes!). 44 | * 45 | * To avoid accidental use of raw pointers, rstt::error_correction's 46 | * constructor is in a private implementation 47 | * class. rstt::error_correction::make is the public interface for 48 | * creating new instances. 49 | */ 50 | static sptr make(bool drop_invalid = false, int guess_level = 1); 51 | }; 52 | 53 | } // namespace rstt 54 | } // namespace gr 55 | 56 | #endif /* INCLUDED_RSTT_ERROR_CORRECTION_H */ 57 | -------------------------------------------------------------------------------- /include/rstt/noise_level_estimator.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_H 17 | #define INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * Estimate noise level value in signal. 27 | 28 | * It does so by spliting input signal power spectrum into chunks. 29 | * Then are identified chunks which contains only noise and 30 | * from which noise level (mean and dispersion) are estimated. 31 | */ 32 | class RSTT_API noise_level_estimator 33 | { 34 | protected: 35 | noise_level_estimator() {} 36 | 37 | public: 38 | typedef std::shared_ptr sptr; 39 | 40 | /*! 41 | * @param coverage is value in range from 0. to 1. It represents amount of 42 | * signal power spectrum used for noise estimation. 0.2 is good value. 43 | * @param nsplits numer of fragmens generated for noise estimation. 44 | */ 45 | static sptr make(float coverage, int nsplits); 46 | 47 | virtual ~noise_level_estimator() {} 48 | 49 | /*! 50 | * Do noise level estimation. 51 | * 52 | * @param data (natural) logarithm of signal power spectrum. 53 | * @param data_items length of input data. 54 | */ 55 | virtual noise_model estimate(const float* data, int data_items) const = 0; 56 | }; 57 | 58 | } // namespace rstt 59 | } // namespace gr 60 | 61 | #endif /* INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_H */ 62 | -------------------------------------------------------------------------------- /include/rstt/noise_level_estimator2.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR2_H 17 | #define INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR2_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * Estimate noise level value in signal. 27 | 28 | * It find parts of signal power spectrum with low power density. 29 | * Noise level and straggling is then estiated. 30 | */ 31 | class RSTT_API noise_level_estimator2 32 | { 33 | protected: 34 | noise_level_estimator2() {} 35 | 36 | public: 37 | typedef std::shared_ptr sptr; 38 | 39 | /*! 40 | * @param coverage size of spectrum used for noise estimation, 41 | * Expects value in range (0., 1.), 0.33 is good value. 42 | * @param chunk_size size of continous part of spectrum containign 43 | * only noise, should be value in range (0., 1), 0.05 is good value. 44 | */ 45 | static sptr make(float coverage, float chunk_size); 46 | 47 | virtual ~noise_level_estimator2() {} 48 | 49 | /*! 50 | * Do noise level estimation. 51 | * 52 | * @param data (natural) logarithm of signal power spectrum. 53 | * @param data_items length of input data. 54 | */ 55 | virtual noise_model estimate(const float* data, int data_items) const = 0; 56 | }; 57 | 58 | } // namespace rstt 59 | } // namespace gr 60 | 61 | #endif /* INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR2_H */ 62 | -------------------------------------------------------------------------------- /include/rstt/noise_model.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_NOISE_MODEL_H 17 | #define INCLUDED_RSTT_NOISE_MODEL_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * \brief Result of noise estimation. 27 | * \ingroup rstt 28 | */ 29 | class RSTT_API noise_model 30 | { 31 | public: 32 | noise_model(float mean, float sigma) : _mean(mean), _sigma(sigma) {} 33 | 34 | /*! 35 | * \brief Return logarithm of power level estimation for noise/signal border. 36 | * @param snr must be greater or equal 1 to make sense. 2 or 3 is good value. 37 | */ 38 | inline float lvl(float snr) const { return _mean + _sigma * snr; } 39 | 40 | inline float mean_lvl() const { return _mean; } 41 | 42 | inline float sigma() const { return _sigma; } 43 | 44 | protected: 45 | float _mean; 46 | float _sigma; 47 | }; 48 | 49 | } // namespace rstt 50 | } // namespace gr 51 | 52 | #endif /* INCLUDED_RSTT_NOISE_MODEL_H */ 53 | -------------------------------------------------------------------------------- /include/rstt/symbols2bits.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_SYMBOLS2BITS_H 17 | #define INCLUDED_RSTT_SYMBOLS2BITS_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * \brief Convert symbol stream to byte stream. 27 | * \ingroup rstt 28 | * 29 | */ 30 | class RSTT_API symbols2bits : virtual public gr::block 31 | { 32 | public: 33 | typedef std::shared_ptr sptr; 34 | 35 | /*! 36 | * \brief Return a shared_ptr to a new instance of rstt::symbols2bits. 37 | * 38 | * To avoid accidental use of raw pointers, rstt::symbols2bits's 39 | * constructor is in a private implementation 40 | * class. rstt::symbols2bits::make is the public interface for 41 | * creating new instances. 42 | */ 43 | static sptr make(int sync_nbits); 44 | }; 45 | 46 | } // namespace rstt 47 | } // namespace gr 48 | 49 | #endif /* INCLUDED_RSTT_SYMBOLS2BITS_H */ 50 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012,2016,2018,2019 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Setup library 11 | ######################################################################## 12 | include(GrPlatform) #define LIB_SUFFIX 13 | 14 | list(APPEND rstt_sources 15 | symbols2bits_impl.cc 16 | bits2bytes_impl.cc 17 | bytes2frames_impl.cc 18 | error_correction_guess.cc 19 | error_correction_impl.cc 20 | decoder_impl.cc 21 | noise_level_estimator_impl.cc 22 | noise_level_estimator2_impl.cc 23 | clip_impl.cc 24 | ) 25 | 26 | set(rstt_sources "${rstt_sources}" PARENT_SCOPE) 27 | if(NOT rstt_sources) 28 | MESSAGE(STATUS "No C++ sources... skipping lib/") 29 | return() 30 | endif(NOT rstt_sources) 31 | 32 | add_library(gnuradio-rstt SHARED ${rstt_sources}) 33 | target_link_libraries(gnuradio-rstt gnuradio::gnuradio-runtime gnuradio::gnuradio-blocks gnuradio::gnuradio-fec) 34 | target_include_directories(gnuradio-rstt 35 | PUBLIC $ 36 | PUBLIC $ 37 | ) 38 | set_target_properties(gnuradio-rstt PROPERTIES DEFINE_SYMBOL "gnuradio_rstt_EXPORTS") 39 | 40 | if(APPLE) 41 | set_target_properties(gnuradio-rstt PROPERTIES 42 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" 43 | ) 44 | endif(APPLE) 45 | 46 | ######################################################################## 47 | # Install built library files 48 | ######################################################################## 49 | include(GrMiscUtils) 50 | GR_LIBRARY_FOO(gnuradio-rstt) 51 | 52 | ######################################################################## 53 | # Print summary 54 | ######################################################################## 55 | message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") 56 | message(STATUS "Building for version: ${VERSION} / ${LIBVER}") 57 | 58 | ######################################################################## 59 | # Build and register unit test 60 | ######################################################################## 61 | include(GrTest) 62 | 63 | # If your unit tests require special include paths, add them here 64 | #include_directories() 65 | # List all files that contain Boost.UTF unit tests here 66 | list(APPEND test_rstt_sources 67 | ) 68 | # Anything we need to link to for the unit tests go here 69 | list(APPEND GR_TEST_TARGET_DEPS gnuradio-rstt) 70 | 71 | if(NOT test_rstt_sources) 72 | MESSAGE(STATUS "No C++ unit tests... skipping") 73 | return() 74 | endif(NOT test_rstt_sources) 75 | 76 | foreach(qa_file ${test_rstt_sources}) 77 | GR_ADD_CPP_TEST("rstt_${qa_file}" 78 | ${CMAKE_CURRENT_SOURCE_DIR}/${qa_file} 79 | ) 80 | endforeach(qa_file) 81 | -------------------------------------------------------------------------------- /lib/bits2bytes_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifdef HAVE_CONFIG_H 17 | #include "config.h" 18 | #endif 19 | 20 | #include "bits2bytes_impl.h" 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | bits2bytes::sptr bits2bytes::make(int sync_nbytes) 27 | { 28 | return gnuradio::get_initial_sptr(new bits2bytes_impl(sync_nbytes)); 29 | } 30 | 31 | bits2bytes_impl::bits2bytes_impl(int sync_nbytes) 32 | : gr::block("bits2bytes", 33 | gr::io_signature::make(1, 1, sizeof(in_t)), 34 | gr::io_signature::make(1, 1, sizeof(out_t))), 35 | sync_nbits(10 * sync_nbytes), 36 | fill_in_bits(sync_nbits), 37 | in_idx(0), 38 | do_bit_resync(true), 39 | send_bytes_remain(0), 40 | sync_win_idx(0), 41 | sync_offs(0) 42 | { 43 | memset(sync_win, 0, sizeof(sync_win)); 44 | } 45 | 46 | bits2bytes_impl::~bits2bytes_impl() {} 47 | 48 | void bits2bytes_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required) 49 | { 50 | ninput_items_required[0] = 10 * noutput_items + sync_nbits + 20; 51 | } 52 | 53 | int bits2bytes_impl::general_work(int noutput_items, 54 | gr_vector_int& ninput_items, 55 | gr_vector_const_void_star& input_items, 56 | gr_vector_void_star& output_items) 57 | { 58 | const in_t* in = (const in_t*)input_items[0]; 59 | out_t* out = (out_t*)output_items[0]; 60 | const int in_len = ninput_items[0]; 61 | 62 | if (!work_fill(in_len, in)) { 63 | return 0; 64 | } 65 | const int produced = work_convert(noutput_items, in_len, in, out); 66 | const int consume = in_idx - sync_nbits; 67 | consume_each(consume); 68 | in_idx -= consume; 69 | 70 | return produced; 71 | } 72 | 73 | bits2bytes_impl::out_t bits2bytes_impl::get_byte(const in_t* in, 74 | bool start_bite_missing) const 75 | { 76 | out_t status = STATUS_INVALID_START; 77 | int idx = in_idx - sync_nbits; 78 | if (!start_bite_missing) { 79 | if (in[idx++] == 0) { 80 | status = 0; 81 | } 82 | } 83 | out_t B = 0; 84 | for (const int end = idx + 8; idx < end; ++idx) { 85 | const in_t b = in[idx]; 86 | B >>= 1; 87 | if (b == -1) { 88 | status |= STATUS_INVALID_BYTE; 89 | continue; 90 | } 91 | B |= b << 7; 92 | } 93 | if (in[idx] != 1) { 94 | status |= STATUS_INVALID_STOP; 95 | } 96 | return B | status; 97 | } 98 | 99 | int bits2bytes_impl::get_sync_offs() const 100 | { 101 | // by default try to keep sync at current position 102 | int sync_offs_new = sync_offs; 103 | int max = sync_win[sync_offs_new]; 104 | // preffer sync to +-1 bit 105 | if (sync_win[(sync_offs - 1 + 10) % 10] > max) { 106 | sync_offs_new = (sync_offs - 1) % 10; 107 | max = sync_win[sync_offs_new]; 108 | } else if (sync_win[(sync_offs + 1) % 10] > max) { 109 | sync_offs_new = (sync_offs + 1) % 10; 110 | max = sync_win[sync_offs_new]; 111 | } 112 | // check for sync at other positions 113 | for (int i = 0; i < 10; ++i) { 114 | if (sync_win[i] > max) { 115 | sync_offs_new = i; 116 | max = sync_win[sync_offs_new]; 117 | } 118 | } 119 | 120 | return sync_offs_new; 121 | } 122 | 123 | int bits2bytes_impl::resync_stream( 124 | int out_len, int produced, int in_len, const in_t* in, out_t* out) 125 | { 126 | if (!do_bit_resync && send_bytes_remain == 0) { 127 | return produced; 128 | } 129 | while (produced < out_len && in_idx < in_len - 9 && send_bytes_remain) { 130 | out[produced++] = get_byte(in); 131 | shift_bits(in); 132 | --send_bytes_remain; 133 | } 134 | if (send_bytes_remain) { 135 | return -produced; 136 | } 137 | const int of = get_sync_offs(); 138 | const int shift = (of - sync_offs + 10) % 10; 139 | if (shift == 9) { 140 | if (in_idx < in_len - 18 && produced < out_len) { 141 | out[produced++] = get_byte(in, true); 142 | shift_bits(in, 9); 143 | sync_offs = of; 144 | do_bit_resync = false; 145 | return produced; 146 | } 147 | } else { 148 | if (shift == 0) { 149 | do_bit_resync = false; 150 | return produced; 151 | } 152 | if (in_idx < in_len - 9 - shift) { 153 | shift_bits(in, shift); 154 | sync_offs = of; 155 | do_bit_resync = false; 156 | return produced; 157 | } 158 | } 159 | 160 | return -produced; 161 | } 162 | 163 | void bits2bytes_impl::shift_bits(const in_t* in, int nbits) 164 | { 165 | for (const int end = in_idx + nbits; in_idx < end; ++in_idx) { 166 | const in_t _b0 = in[in_idx - sync_nbits]; 167 | const in_t _b9 = in[in_idx - sync_nbits + 9]; 168 | const in_t b0 = in[in_idx]; 169 | const in_t b9 = in[in_idx + 9]; 170 | 171 | sync_win_idx_pp((b0 == 0 && b9 == 1) - (_b0 == 0 && _b9 == 1)); 172 | } 173 | } 174 | 175 | void bits2bytes_impl::sync_win_idx_pp(int inc) 176 | { 177 | sync_win[sync_win_idx++] += inc; 178 | if (sync_win_idx > 9) { 179 | sync_win_idx = 0; 180 | } 181 | } 182 | 183 | int bits2bytes_impl::work_convert(int out_len, int in_len, const in_t* in, out_t* out) 184 | { 185 | if (in_idx >= in_len - 19 || 0 >= out_len) { 186 | return 0; 187 | } 188 | int produced = resync_stream(out_len, 0, in_len, in, out); 189 | if (produced < 0) { 190 | return -produced; 191 | } 192 | while (in_idx < in_len - 19 && produced < out_len) { 193 | const int so = get_sync_offs(); 194 | if (so != sync_offs) { 195 | send_bytes_remain = sync_nbits / 10 / 2 - 1; 196 | produced = resync_stream(out_len, produced, in_len, in, out); 197 | if (produced < 0) { 198 | return -produced; 199 | } 200 | continue; 201 | } 202 | out[produced++] = get_byte(in); 203 | shift_bits(in); 204 | } 205 | return produced; 206 | } 207 | 208 | bool bits2bytes_impl::work_fill(int in_len, const in_t* in) 209 | { 210 | if (!fill_in_bits) { 211 | return true; 212 | } 213 | 214 | const int len = in_idx + std::min(fill_in_bits, in_len - in_idx - 9); 215 | for (; in_idx < len; ++in_idx) { 216 | sync_win_idx_pp(in[in_idx] == 0 && in[in_idx + 9] == 1); 217 | } 218 | fill_in_bits -= len; 219 | return fill_in_bits == 0; 220 | } 221 | 222 | } /* namespace rstt */ 223 | } /* namespace gr */ 224 | -------------------------------------------------------------------------------- /lib/bits2bytes_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_BITS2BYTES_IMPL_H 17 | #define INCLUDED_RSTT_BITS2BYTES_IMPL_H 18 | 19 | #include 20 | 21 | namespace gr { 22 | namespace rstt { 23 | 24 | class bits2bytes_impl : public bits2bytes 25 | { 26 | private: 27 | typedef signed char in_t; 28 | typedef unsigned short out_t; 29 | 30 | enum { 31 | STATUS_INVALID_START = 0x100, 32 | STATUS_INVALID_BYTE = 0x200, 33 | STATUS_INVALID_STOP = 0x400 34 | }; 35 | 36 | /** Lenght of sync window in bits, */ 37 | int sync_nbits; 38 | /** Number of bits to fill in, before normal work can start. */ 39 | int fill_in_bits; 40 | /** Index to firts input bit which was not processed at all. */ 41 | int in_idx; 42 | 43 | /** If true, bits are droppend until synchronization is achieved. */ 44 | bool do_bit_resync; 45 | /** Bytes remaining to send before normal operation can continue. */ 46 | int send_bytes_remain; 47 | /** Lenght of sync window in bits. */ 48 | int sync_win[10]; 49 | int sync_win_idx; 50 | int sync_offs; 51 | 52 | out_t get_byte(const in_t* in, bool start_bite_missing = false) const; 53 | int get_sync_offs() const; 54 | int resync_stream(int out_len, int produced, int in_len, const in_t* in, out_t* out); 55 | void shift_bits(const in_t* in, int nbits = 10); 56 | 57 | /** Update current sync value by 'inc' and move to next sync window 58 | position. */ 59 | void sync_win_idx_pp(int inc = 0); 60 | 61 | int work_convert(int out_len, int in_len, const in_t* in, out_t* out); 62 | 63 | bool work_fill(int in_len, const in_t* in); 64 | 65 | public: 66 | bits2bytes_impl(int sync_nbytes); 67 | ~bits2bytes_impl(); 68 | 69 | // Where all the action really happens 70 | void forecast(int noutput_items, gr_vector_int& ninput_items_required); 71 | 72 | int general_work(int noutput_items, 73 | gr_vector_int& ninput_items, 74 | gr_vector_const_void_star& input_items, 75 | gr_vector_void_star& output_items); 76 | }; 77 | 78 | } // namespace rstt 79 | } // namespace gr 80 | 81 | #endif /* INCLUDED_RSTT_BITS2BYTES_IMPL_H */ 82 | -------------------------------------------------------------------------------- /lib/byte_status.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jiří Pinkava . 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3, or (at your option) 7 | * any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef INCLUDED_RSTT_BYTE_STATUS_H 16 | #define INCLUDED_RSTT_BYTE_STATUS_H 17 | 18 | namespace gr { 19 | namespace rstt { 20 | /** Error states for recieved byte. */ 21 | typedef enum { 22 | STATUS_ERR_START = 0x100, 23 | STATUS_ERR_BYTE = 0x200, 24 | STATUS_ERR_STOP = 0x400 25 | } byte_status_t; 26 | } // namespace rstt 27 | } // namespace gr 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /lib/bytes2frames_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifdef HAVE_CONFIG_H 17 | #include "config.h" 18 | #endif 19 | 20 | #include "byte_status.h" 21 | #include "bytes2frames_impl.h" 22 | #include 23 | 24 | namespace gr { 25 | namespace rstt { 26 | 27 | bytes2frames::sptr bytes2frames::make() 28 | { 29 | return gnuradio::get_initial_sptr(new bytes2frames_impl()); 30 | } 31 | 32 | bytes2frames_impl::bytes2frames_impl() 33 | : gr::block("bytes2frames", 34 | gr::io_signature::make(1, 1, sizeof(in_t)), 35 | gr::io_signature::make(1, 1, sizeof(out_t) * 240)), 36 | more(false) 37 | { 38 | } 39 | 40 | bytes2frames_impl::~bytes2frames_impl() {} 41 | 42 | int bytes2frames_impl::correlate(const in_t* in) const 43 | { 44 | // ignore all bite errors except 'invalid byte' 45 | const in_t _MASK = 0xff | STATUS_ERR_BYTE; 46 | 47 | int nerr = 0; 48 | for (unsigned char i = 0; i < 5; ++i) { 49 | nerr += ((in[i] & _MASK) == '*') ? 0 : 1; 50 | } 51 | if ((in[5] & _MASK) == 0x10) { 52 | if (nerr <= 3) { 53 | return nerr; 54 | } 55 | return 6; 56 | } 57 | 58 | // first and last '*' is required, to guess frame start mark 59 | // up to 3 error are tollerable (and 0x10 is missing) 60 | if (nerr <= 2) { 61 | if ((in[0] & _MASK) == '*' && (in[4] & _MASK) == '*') { 62 | return nerr + 1; 63 | } 64 | } 65 | 66 | return 6; 67 | } 68 | 69 | int bytes2frames_impl::find_sync(const in_t* in) const 70 | { 71 | int nerr_min = INT_MAX; 72 | int corr_idx = 0; 73 | for (int idx = 0; idx < PACKET_SIZE; ++idx) { 74 | const int nerr = correlate(in + idx); 75 | if (nerr < nerr_min) { 76 | nerr_min = nerr; 77 | corr_idx = idx; 78 | if (nerr == 0) { 79 | break; 80 | } 81 | } 82 | } 83 | return (nerr_min < 6 && corr_idx > 0) ? corr_idx : PACKET_SIZE; 84 | } 85 | 86 | void bytes2frames_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required) 87 | { 88 | const int n = noutput_items * PACKET_SIZE; 89 | ninput_items_required[0] = more ? n + 239 : n; 90 | } 91 | 92 | int bytes2frames_impl::general_work(int noutput_items, 93 | gr_vector_int& ninput_items, 94 | gr_vector_const_void_star& input_items, 95 | gr_vector_void_star& output_items) 96 | { 97 | const in_t* in = (const in_t*)input_items[0]; 98 | out_t* out = (out_t*)output_items[0]; 99 | const int in_len = ninput_items[0]; 100 | 101 | int consumed = 0; 102 | const int produced = work(noutput_items, in_len, consumed, in, out); 103 | consume_each(consumed); 104 | 105 | return produced; 106 | } 107 | 108 | void bytes2frames_impl::send_packet(const in_t* in, out_t* out, int packet_size) 109 | { 110 | const int missing = PACKET_SIZE - packet_size; 111 | for (int idx = 0; idx < missing; ++idx) { 112 | out[idx] = STATUS_ERR_STOP | STATUS_ERR_START | STATUS_ERR_BYTE; 113 | } 114 | memcpy(out + missing, in, (PACKET_SIZE - missing) * sizeof(out_t)); 115 | } 116 | 117 | int bytes2frames_impl::work( 118 | int out_len, int in_len, int& consumed, const in_t* in, out_t* out) 119 | { 120 | int produced = 0; 121 | while (produced < out_len && consumed < in_len - 239) { 122 | const int nerr = correlate(in + consumed); 123 | more = false; 124 | if (nerr == 0) { 125 | send_packet(in + consumed, out + produced * PACKET_SIZE); 126 | ++produced; 127 | consumed += PACKET_SIZE; 128 | 129 | continue; 130 | } 131 | if (consumed >= in_len - 2 * PACKET_SIZE + 1) { 132 | more = true; 133 | break; 134 | } 135 | int sync_idx = find_sync(in + consumed); 136 | 137 | send_packet(in + consumed, out + produced * PACKET_SIZE, sync_idx); 138 | ++produced; 139 | consumed += sync_idx; 140 | } 141 | return produced; 142 | } 143 | 144 | } /* namespace rstt */ 145 | } /* namespace gr */ 146 | -------------------------------------------------------------------------------- /lib/bytes2frames_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_BYTES2FRAMES_IMPL_H 17 | #define INCLUDED_RSTT_BYTES2FRAMES_IMPL_H 18 | 19 | #include 20 | 21 | namespace gr { 22 | namespace rstt { 23 | 24 | class bytes2frames_impl : public bytes2frames 25 | { 26 | private: 27 | typedef short in_t; 28 | typedef short out_t; 29 | 30 | const static int PACKET_SIZE = 240; 31 | /** Need more data to find a frame. */ 32 | bool more; 33 | 34 | int correlate(const in_t* in) const; 35 | int find_sync(const in_t* in) const; 36 | void send_packet(const in_t* in, out_t* out, int packet_size = PACKET_SIZE); 37 | int work(int out_len, int in_len, int& consumed, const in_t* in, out_t* out); 38 | 39 | public: 40 | bytes2frames_impl(); 41 | ~bytes2frames_impl(); 42 | 43 | void forecast(int noutput_items, gr_vector_int& ninput_items_required); 44 | 45 | int general_work(int noutput_items, 46 | gr_vector_int& ninput_items, 47 | gr_vector_const_void_star& input_items, 48 | gr_vector_void_star& output_items); 49 | }; 50 | 51 | } // namespace rstt 52 | } // namespace gr 53 | 54 | #endif /* INCLUDED_RSTT_BYTES2FRAMES_IMPL_H */ 55 | -------------------------------------------------------------------------------- /lib/clip_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifdef HAVE_CONFIG_H 17 | #include "config.h" 18 | #endif 19 | 20 | #include "clip_impl.h" 21 | #include 22 | #include 23 | 24 | namespace gr { 25 | namespace rstt { 26 | 27 | clip::sptr clip::make(int vlen_in, float bw_in, float bw_out) 28 | { 29 | const int trim = roundf(vlen_in * (bw_in - bw_out) / bw_in / 2.); 30 | if (0 > trim || 2 * trim >= vlen_in) { 31 | throw std::out_of_range( 32 | "gr::rstt::clip condition (0 <= 2 * trim < vlen_out) unsatisfied."); 33 | } 34 | 35 | return gnuradio::get_initial_sptr(new clip_impl(vlen_in, trim)); 36 | } 37 | 38 | clip_impl::clip_impl(int vlen_in, int trim) 39 | : gr::sync_block("clip", 40 | gr::io_signature::make(1, 1, sizeof(float) * vlen_in), 41 | gr::io_signature::make(1, 1, sizeof(float) * (vlen_in - 2 * trim))), 42 | _trim(trim), 43 | _vlen_out(vlen_in - 2 * trim) 44 | { 45 | } 46 | 47 | int clip_impl::trim() const { return _trim; } 48 | 49 | int clip_impl::vlen_out() const { return _vlen_out; } 50 | 51 | clip_impl::~clip_impl() {} 52 | 53 | int clip_impl::work(int noutput_items, 54 | gr_vector_const_void_star& input_items, 55 | gr_vector_void_star& output_items) 56 | { 57 | const float* in = (const float*)input_items[0]; 58 | float* out = (float*)output_items[0]; 59 | 60 | for (int ni = 0, no = 0; no < noutput_items * _vlen_out;) { 61 | ni += _trim; 62 | memcpy(out + no, in + ni, _vlen_out * sizeof(float)); 63 | no += _vlen_out; 64 | ni += _vlen_out; 65 | ni += _trim; 66 | } 67 | 68 | return noutput_items; 69 | } 70 | 71 | } /* namespace rstt */ 72 | } /* namespace gr */ 73 | -------------------------------------------------------------------------------- /lib/clip_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_CLIP_IMPL_H 17 | #define INCLUDED_RSTT_CLIP_IMPL_H 18 | 19 | #include 20 | 21 | namespace gr { 22 | namespace rstt { 23 | 24 | class clip_impl : public clip 25 | { 26 | private: 27 | int _trim; 28 | int _vlen_out; 29 | 30 | public: 31 | clip_impl(int vlen_in, int trim); 32 | ~clip_impl(); 33 | 34 | int work(int noutput_items, 35 | gr_vector_const_void_star& input_items, 36 | gr_vector_void_star& output_items); 37 | 38 | virtual int trim() const; 39 | virtual int vlen_out() const; 40 | }; 41 | 42 | } // namespace rstt 43 | } // namespace gr 44 | 45 | #endif /* INCLUDED_RSTT_CLIP_IMPL_H */ 46 | -------------------------------------------------------------------------------- /lib/decoder_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifdef HAVE_CONFIG_H 17 | #include "config.h" 18 | #endif 19 | 20 | #include "decoder_impl.h" 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | decoder::sptr 27 | decoder::make(int sync_nbits, int sync_nbytes, bool drop_invalid, int guess_level) 28 | { 29 | return gnuradio::get_initial_sptr( 30 | new decoder_impl(sync_nbits, sync_nbytes, drop_invalid, guess_level)); 31 | } 32 | 33 | decoder_impl::decoder_impl(int sync_nbits, 34 | int sync_nbytes, 35 | bool drop_invalid, 36 | int guess_level) 37 | : gr::hier_block2("decoder", 38 | gr::io_signature::make(1, 1, sizeof(in_t)), 39 | gr::io_signature::make(1, 1, sizeof(out_t) * 240)) 40 | { 41 | fbits2bytes = bits2bytes::make(sync_nbytes); 42 | fbytes2frames = bytes2frames::make(); 43 | ferror_correction = error_correction::make(drop_invalid, guess_level); 44 | fsymbols2bits = symbols2bits::make(sync_nbits); 45 | 46 | connect(self(), 0, fsymbols2bits, 0); 47 | connect(fsymbols2bits, 0, fbits2bytes, 0); 48 | connect(fbits2bytes, 0, fbytes2frames, 0); 49 | connect(fbytes2frames, 0, ferror_correction, 0); 50 | connect(ferror_correction, 0, self(), 0); 51 | } 52 | 53 | decoder_impl::~decoder_impl() {} 54 | 55 | } /* namespace rstt */ 56 | } /* namespace gr */ 57 | -------------------------------------------------------------------------------- /lib/decoder_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_DECODER_IMPL_H 17 | #define INCLUDED_RSTT_DECODER_IMPL_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace gr { 26 | namespace rstt { 27 | 28 | class decoder_impl : public decoder 29 | { 30 | private: 31 | typedef unsigned char in_t; 32 | typedef short out_t; 33 | 34 | bits2bytes::sptr fbits2bytes; 35 | bytes2frames::sptr fbytes2frames; 36 | error_correction::sptr ferror_correction; 37 | symbols2bits::sptr fsymbols2bits; 38 | 39 | public: 40 | decoder_impl(int sync_nbits, int sync_nbytes, bool drop_invalid, int guess_level); 41 | ~decoder_impl(); 42 | }; 43 | 44 | } // namespace rstt 45 | } // namespace gr 46 | 47 | #endif /* INCLUDED_RSTT_DECODER_IMPL_H */ 48 | -------------------------------------------------------------------------------- /lib/error_correction_guess.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include "error_correction_guess.h" 17 | #include 18 | 19 | namespace gr { 20 | namespace rstt { 21 | 22 | int error_correction_guess::predicate::operator()(int val, int idx) 23 | { 24 | if (idx >= LEN) { 25 | if (val & (~0xff)) { 26 | return -1; 27 | } 28 | return val; 29 | } 30 | if (changes_cnt[idx] > erasure_level && next_level > changes_cnt[idx]) { 31 | next_level = changes_cnt[idx]; 32 | } 33 | if (changes_cnt[idx] < replace_level) { 34 | return prev_data[idx]; 35 | } 36 | if (changes_cnt[idx] < erasure_level) { 37 | return val == prev_data[idx] ? val : -1; 38 | } 39 | if (val & (~0xff)) { 40 | return -1; 41 | } 42 | return val; 43 | } 44 | 45 | void error_correction_guess::update(const unsigned short* data) 46 | { 47 | ++update_count; 48 | if (update_count == 0) { 49 | memset(chenges_cnt, 0, sizeof(int) * LEN); 50 | for (int x = 0; x < LEN; ++x) { 51 | prev_data[x] = data[x]; 52 | } 53 | return; 54 | } 55 | for (int x = 0; x < LEN; ++x) { 56 | if (prev_data[x] != (data[x] & 0xff)) { 57 | prev_data[x] = data[x] & 0xff; 58 | chenges_cnt[x] += 1; 59 | } 60 | } 61 | if (update_count == 512) { 62 | update_count /= 2; 63 | for (int x = 0; x < LEN; ++x) { 64 | chenges_cnt[x] /= 2; 65 | } 66 | } 67 | } 68 | 69 | int error_correction_guess::get_level(int level) const 70 | { 71 | if (update_count < 1) { 72 | level = 0; 73 | } else if (update_count > 256) { 74 | level = level * update_count / 256; 75 | } 76 | return level; 77 | } 78 | 79 | } // namespace rstt 80 | } // namespace gr 81 | -------------------------------------------------------------------------------- /lib/error_correction_guess.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_ERROR_CORRECTION_GUESS_H 17 | #define INCLUDED_RSTT_ERROR_CORRECTION_GUESS_H 18 | 19 | namespace gr { 20 | namespace rstt { 21 | 22 | /** 23 | Collect statistics, trying to find constant bytes. 24 | */ 25 | class error_correction_guess 26 | { 27 | static const int LEN = 240 - 24; 28 | 29 | int chenges_cnt[LEN]; 30 | unsigned char prev_data[LEN]; 31 | int update_count; 32 | 33 | public: 34 | class predicate 35 | { 36 | const int* changes_cnt; 37 | const unsigned char* prev_data; 38 | int replace_level, erasure_level; 39 | int next_level; 40 | 41 | public: 42 | predicate(const int* changes_cnt, 43 | const unsigned char* prev_data, 44 | int replace_level, 45 | int erasure_level) 46 | : changes_cnt(changes_cnt), 47 | prev_data(prev_data), 48 | replace_level(replace_level), 49 | erasure_level(erasure_level), 50 | next_level(257) 51 | { 52 | } 53 | 54 | int operator()(int val, int idx); 55 | 56 | inline int get_next_level() const { return next_level; } 57 | }; 58 | 59 | error_correction_guess() 60 | : // first call of update() initializes internal state, it is not real update 61 | update_count(-1) 62 | { 63 | } 64 | 65 | void update(const unsigned short* data); 66 | int get_level(int level) const; 67 | 68 | inline predicate get_predicate(int replace_level, int erasure_level) const 69 | { 70 | return predicate( 71 | chenges_cnt, prev_data, get_level(replace_level), get_level(erasure_level)); 72 | } 73 | }; 74 | 75 | } // namespace rstt 76 | } // namespace gr 77 | 78 | #endif /* INCLUDED_RSTT_ERROR_CORRECTION_GUESS_H */ 79 | -------------------------------------------------------------------------------- /lib/error_correction_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_ERROR_CORRECTION_IMPL_H 17 | #define INCLUDED_RSTT_ERROR_CORRECTION_IMPL_H 18 | 19 | #include "error_correction_guess.h" 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | class error_correction_impl : public error_correction 26 | { 27 | private: 28 | typedef unsigned short in_t; 29 | typedef unsigned short out_t; 30 | 31 | /** Reed-Solomon codec private data. */ 32 | void* rs; 33 | 34 | bool drop_invalid; 35 | int guess_level; 36 | 37 | struct pred_byte_err; 38 | struct pred_recv_err; 39 | 40 | error_correction_guess guess_correction; 41 | 42 | /** Try serveral correction algorithms. */ 43 | bool do_corrections(const in_t* in, out_t* out) const; 44 | 45 | /** Try process correction for specified value algorithm. */ 46 | template 47 | bool do_correction(const in_t* in, out_t* out, GetValue get_value) const; 48 | 49 | /** Evaluate Reed-Solomon correction code. */ 50 | template 51 | int 52 | do_rs_correction(const in_t* in, unsigned char* rs_data, GetValue get_value) const; 53 | 54 | /** copy back corrected data and (correct) header */ 55 | void copy_corrected(unsigned char* rs_data, out_t* out) const; 56 | 57 | static bool chech_crc(const in_t* in, int len); 58 | 59 | public: 60 | error_correction_impl(bool drop_invalid, int guess_level); 61 | ~error_correction_impl(); 62 | 63 | /** 64 | Check subframes CRC. 65 | Returns positive number if all subframes are valid, 66 | negative number if some subframes are invalid, or zero 67 | if no valid subframe is found. 68 | **/ 69 | static int is_frame_valid(const in_t* in); 70 | 71 | int work(int noutput_items, 72 | gr_vector_const_void_star& input_items, 73 | gr_vector_void_star& output_items); 74 | }; 75 | 76 | } // namespace rstt 77 | } // namespace gr 78 | 79 | #endif /* INCLUDED_RSTT_ERROR_CORRECTION_IMPL_H */ 80 | -------------------------------------------------------------------------------- /lib/noise_level_estimator2_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include "noise_level_estimator2_impl.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | namespace gr { 25 | namespace rstt { 26 | 27 | noise_level_estimator2::sptr noise_level_estimator2::make(float coverage, 28 | float chunk_size) 29 | { 30 | if (!(coverage > 0.)) 31 | throw std::out_of_range("noise_level_estimator2 coverage must be > 0."); 32 | if (!(coverage <= 1.)) 33 | throw std::out_of_range("noise_level_estimator2 coverage must be <= 1."); 34 | if (!(chunk_size > 0.)) 35 | throw std::out_of_range("noise_level_estimator2 chunk_size must be > 0."); 36 | if (!(chunk_size <= coverage)) 37 | throw std::out_of_range("noise_level_estimator2 chunk_size must be <= coverage"); 38 | return sptr(new noise_level_estimator2_impl(coverage, chunk_size)); 39 | } 40 | 41 | noise_model noise_level_estimator2_impl::estimate(const float* data, int data_items) const 42 | { 43 | const int coverage = data_items * this->coverage; 44 | const int chunk_size = data_items * this->chunk_size; 45 | 46 | const int ms_size = data_items - chunk_size + 1; 47 | float mean[ms_size]; 48 | float mean2[ms_size]; 49 | 50 | // moving average, first point 51 | mean[0] = 0.; 52 | mean2[0] = 0.; 53 | for (int i = 0; i < chunk_size; ++i) { 54 | mean[0] += data[i]; 55 | mean2[0] += data[i] * data[i]; 56 | } 57 | 58 | // moving average, other points 59 | for (int i = chunk_size, j = 1; i < data_items; ++i, ++j) { 60 | mean[j] = mean[j - 1] - data[j - 1] + data[i]; 61 | mean2[j] = mean2[j - 1] - (data[j - 1] * data[j - 1]) + (data[i] * data[i]); 62 | } 63 | 64 | for (int i = 0; i < ms_size; ++i) { 65 | mean[i] /= chunk_size; 66 | mean2[i] /= chunk_size; 67 | } 68 | 69 | // moving standard deviation (s^2) 70 | float s2[ms_size]; 71 | for (int i = 0; i < ms_size; ++i) { 72 | s2[i] = mean2[i] - mean[i] * mean[i]; 73 | } 74 | 75 | // get the average of lower bound values for mean and deviation 76 | std::sort(s2, s2 + ms_size); 77 | float s = 0.; 78 | for (int i = 0; i < coverage; ++i) { 79 | s += std::sqrt(s2[i]); 80 | } 81 | s /= coverage; 82 | 83 | std::sort(mean, mean + ms_size); 84 | float m = 0.; 85 | for (int i = 0; i < coverage; ++i) { 86 | m += mean[i]; 87 | } 88 | m /= coverage; 89 | 90 | return noise_model(m, s); 91 | } 92 | 93 | } // namespace rstt 94 | } // namespace gr 95 | -------------------------------------------------------------------------------- /lib/noise_level_estimator2_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_IMPL_H 17 | #define INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_IMPL_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * \brief Estimate noise level value in signal. 27 | */ 28 | class noise_level_estimator2_impl : public noise_level_estimator2 29 | { 30 | private: 31 | float coverage; 32 | float chunk_size; 33 | 34 | public: 35 | noise_level_estimator2_impl(float coverage, float chunk_size) 36 | : coverage(coverage), chunk_size(chunk_size) 37 | { 38 | } 39 | 40 | virtual ~noise_level_estimator2_impl() {} 41 | 42 | /*! 43 | * \brief Do noise level estimation. 44 | * 45 | * @param data logarithm (natural) of signal power spectrum. 46 | * @param data_items length of input data. 47 | */ 48 | noise_model estimate(const float* data, int data_items) const; 49 | }; 50 | 51 | } // namespace rstt 52 | } // namespace gr 53 | 54 | #endif /* INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_IMPL_H */ 55 | -------------------------------------------------------------------------------- /lib/noise_level_estimator_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include "noise_level_estimator_impl.h" 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | bool chunk_by_mean(const noise_level_estimator_impl::Chunk& l, 27 | const noise_level_estimator_impl::Chunk& r) 28 | { 29 | if (l.mean() == r.mean()) 30 | return l.len() < r.len(); 31 | return l.mean() < r.mean(); 32 | } 33 | 34 | noise_level_estimator::sptr noise_level_estimator::make(float coverage, int nsplits) 35 | { 36 | return sptr(new noise_level_estimator_impl(coverage, nsplits)); 37 | } 38 | 39 | noise_model noise_level_estimator_impl::estimate(const float* data, int data_items) const 40 | { 41 | idata.resize(data_items); 42 | float prev = 0; 43 | for (int idx = 0; idx < data_items; ++idx) { 44 | prev = idata[idx] = data[idx] + prev; 45 | } 46 | 47 | chunks.clear(); 48 | chunks.push_back(Chunk(0, data_items, idata.data())); 49 | for (int chunkno = 0; chunkno < nsplits; ++chunkno) { 50 | Chunk chunk = chunks.back(); 51 | chunks.pop_back(); 52 | Chunk new_chunk = chunk.split(idata.data()); 53 | chunks.insert(std::lower_bound(chunks.begin(), chunks.end(), chunk), chunk); 54 | chunks.insert(std::lower_bound(chunks.begin(), chunks.end(), new_chunk), 55 | new_chunk); 56 | } 57 | 58 | BOOST_FOREACH (Chunk& chunk, chunks) { 59 | chunk.shift_mean(data); 60 | } 61 | std::sort(chunks.begin(), chunks.end(), chunk_by_mean); 62 | 63 | float mean = 0; 64 | float sigma = 0; 65 | int len = 0; 66 | BOOST_FOREACH (Chunk& chunk, chunks) { 67 | mean += chunk.mean() * chunk.len(); 68 | for (int idx = chunk.start(); idx < chunk.start() + chunk.len(); ++idx) { 69 | sigma += data[idx] * data[idx]; 70 | } 71 | len += chunk.len(); 72 | if (len >= coverage * data_items) 73 | break; 74 | } 75 | 76 | mean /= len; 77 | sigma = sqrt(sigma / len - mean * mean) * 2; 78 | 79 | return noise_model(mean, sigma); 80 | } 81 | 82 | } // namespace rstt 83 | } // namespace gr 84 | -------------------------------------------------------------------------------- /lib/noise_level_estimator_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_IMPL_H 17 | #define INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_IMPL_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | /*! 26 | * \brief Estimate noise level value in signal. 27 | * 28 | * It does so by spliting input signal power spectrum into chunks. 29 | * Then are identified chunks which contains only noise and 30 | * from which noise level (mean and dispersion) are estimated. 31 | */ 32 | class noise_level_estimator_impl : public noise_level_estimator 33 | { 34 | public: 35 | /*! \brief Chunk of spectrum power data for noise estimation. */ 36 | class Chunk 37 | { 38 | int _start; 39 | int _len; 40 | float _mean; 41 | float _extreme_val; 42 | int _extreme_rel_idx; 43 | 44 | inline void set_extreme(const float* data) 45 | { 46 | _extreme_val = 0; 47 | _extreme_rel_idx = 0; 48 | for (int idx = 0; idx < _len; ++idx) { 49 | float val = data[idx] - data[0] - _mean * idx; 50 | val = val < 0. ? -val : val; 51 | if (val > _extreme_val) { 52 | _extreme_val = val; 53 | _extreme_rel_idx = idx; 54 | } 55 | } 56 | } 57 | 58 | inline void reset(const float* data) 59 | { 60 | _mean = (_len > 1) ? (data[_len - 1] - data[0]) / (_len - 1) : 0.; 61 | set_extreme(data); 62 | } 63 | 64 | public: 65 | /*! 66 | * \brief Evaluate parameters for chunk of data 67 | * @param start index of first item in data for chunk 68 | * @param len lenght of chunk 69 | * @param data integrated value of signal spectrum power 70 | */ 71 | Chunk(int start, int len, const float* data) : _start(start), _len(len) 72 | { 73 | reset(data + _start); 74 | } 75 | 76 | /*! 77 | * \brief transforms relative mean to absolute mean 78 | * @param data power level values 79 | */ 80 | inline void shift_mean(const float* data) 81 | { 82 | _mean = (_mean * (_len - 1) + data[_start]) / _len; 83 | } 84 | 85 | inline Chunk split(const float* data) 86 | { 87 | const int idx2 = _start + _extreme_rel_idx + 1; 88 | const int len2 = _len - _extreme_rel_idx - 1; 89 | _len = _extreme_rel_idx + 1; 90 | reset(data + _start); 91 | return Chunk(idx2, len2, data); 92 | } 93 | 94 | inline void reset(int start, int len, const float* data) 95 | { 96 | this->_start = start; 97 | this->_len = len; 98 | reset(data + _start); 99 | } 100 | 101 | bool operator<(const Chunk& r) const 102 | { 103 | if (_extreme_val == r._extreme_val) 104 | return _len < r._len; 105 | return _extreme_val < r._extreme_val; 106 | } 107 | 108 | inline int start() const { return _start; } 109 | inline int len() const { return _len; } 110 | inline float mean() const { return _mean; } 111 | inline float extreme_val() const { return _extreme_val; } 112 | inline int extreme_rel_idx() const { return _extreme_rel_idx; }; 113 | }; 114 | 115 | private: 116 | float coverage; 117 | int nsplits; 118 | 119 | // just optimalization, it avoids buffer alocation for each call of estimate() 120 | mutable std::vector idata; 121 | mutable std::vector chunks; 122 | 123 | public: 124 | /*! 125 | * @param coverage is value in range from 0. to 1. It represents amount of 126 | * signal power spectrum used for noise estimation. 0.2 is good value. 127 | * @param nsplits numer of fragmens generated for noise estimation. 128 | */ 129 | noise_level_estimator_impl(float coverage, int nsplits) 130 | : coverage(coverage), nsplits(nsplits) 131 | { 132 | chunks.reserve(nsplits); 133 | } 134 | 135 | virtual ~noise_level_estimator_impl() {} 136 | 137 | /*! 138 | * \brief Do noise level estimation. 139 | * 140 | * @param data logarithm (natural) of signal power spectrum. 141 | * @param data_items length of input data. 142 | */ 143 | noise_model estimate(const float* data, int data_items) const; 144 | }; 145 | 146 | bool chunk_by_mean(const noise_level_estimator_impl::Chunk& l, 147 | const noise_level_estimator_impl::Chunk& r); 148 | 149 | } // namespace rstt 150 | } // namespace gr 151 | 152 | #endif /* INCLUDED_RSTT_NOISE_LEVEL_ESTIMATOR_IMPL_H */ 153 | -------------------------------------------------------------------------------- /lib/qa_error_correction.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef _QA_INVALID_FRAME_FILTER_H_ 18 | #define _QA_INVALID_FRAME_FILTER_H_ 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | class qa_error_correction : public CppUnit::TestCase 27 | { 28 | public: 29 | CPPUNIT_TEST_SUITE(qa_error_correction); 30 | CPPUNIT_TEST(t1); 31 | CPPUNIT_TEST(t2); 32 | CPPUNIT_TEST(t3); 33 | CPPUNIT_TEST_SUITE_END(); 34 | 35 | private: 36 | void t1(); 37 | void t2(); 38 | void t3(); 39 | }; 40 | 41 | } /* namespace rstt */ 42 | } /* namespace gr */ 43 | 44 | #endif /* _QA_INVALID_FRAME_FILTER_H_ */ 45 | -------------------------------------------------------------------------------- /lib/qa_error_correction_guess.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include "error_correction_guess.h" 17 | #include "qa_error_correction_guess.h" 18 | #include 19 | 20 | namespace gr { 21 | namespace rstt { 22 | 23 | static const int LEN = 240; 24 | static const int VAL_INC = 16; 25 | 26 | void init_data( 27 | int* changes_cnt, int cnt, unsigned char* prev_data, int* data, int* data_exp) 28 | { 29 | for (int i = 0; i < LEN - 24; ++i) { 30 | changes_cnt[i] = cnt; 31 | data_exp[i] = data[i] = prev_data[i] = i + VAL_INC; 32 | } 33 | for (int i = LEN - 24; i < LEN; ++i) { 34 | data_exp[i] = data[i] = i + VAL_INC; 35 | } 36 | } 37 | 38 | void qa_error_correction_guess::t1_ok() 39 | { 40 | int changes_cnt[LEN - 24]; 41 | unsigned char prev_data[LEN - 24]; 42 | int data[LEN]; 43 | int data_exp[LEN]; 44 | 45 | init_data(changes_cnt, 0, prev_data, data, data_exp); 46 | 47 | error_correction_guess::predicate predicate(changes_cnt, prev_data, 0, 0); 48 | 49 | for (int i = 0; i < LEN; ++i) { 50 | CPPUNIT_ASSERT(predicate(data[i], i) == data_exp[i]); 51 | } 52 | } 53 | 54 | void qa_error_correction_guess::t2() 55 | { 56 | int changes_cnt[LEN - 24]; 57 | unsigned char prev_data[LEN - 24]; 58 | int data[LEN]; 59 | int data_exp[LEN]; 60 | 61 | init_data(changes_cnt, 8, prev_data, data, data_exp); 62 | changes_cnt[8] = 0; 63 | data[8] = 1; 64 | 65 | error_correction_guess::predicate predicate(changes_cnt, prev_data, 1, 1); 66 | 67 | for (int i = 0; i < LEN; ++i) { 68 | CPPUNIT_ASSERT(predicate(data[i], i) == data_exp[i]); 69 | } 70 | } 71 | 72 | void qa_error_correction_guess::t3() 73 | { 74 | int changes_cnt[LEN - 24]; 75 | unsigned char prev_data[LEN - 24]; 76 | int data[LEN]; 77 | int data_exp[LEN]; 78 | 79 | init_data(changes_cnt, 8, prev_data, data, data_exp); 80 | changes_cnt[8] = 0; 81 | changes_cnt[9] = 1; 82 | data[8] = 1; 83 | data[9] = 1; 84 | data_exp[9] = -1; 85 | 86 | error_correction_guess::predicate predicate(changes_cnt, prev_data, 1, 2); 87 | 88 | for (int i = 0; i < LEN; ++i) { 89 | CPPUNIT_ASSERT(predicate(data[i], i) == data_exp[i]); 90 | } 91 | } 92 | 93 | } /* namespace rstt */ 94 | } /* namespace gr */ 95 | -------------------------------------------------------------------------------- /lib/qa_error_correction_guess.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef _QA_ERROR_CORRECTION_GUESS_H_ 18 | #define _QA_ERROR_CORRECTION_GUESS_H_ 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | class qa_error_correction_guess : public CppUnit::TestCase 27 | { 28 | public: 29 | CPPUNIT_TEST_SUITE(qa_error_correction_guess); 30 | CPPUNIT_TEST(t1_ok); 31 | CPPUNIT_TEST(t2); 32 | CPPUNIT_TEST(t3); 33 | CPPUNIT_TEST_SUITE_END(); 34 | 35 | private: 36 | void t1_ok(); 37 | void t2(); 38 | void t3(); 39 | }; 40 | 41 | } /* namespace rstt */ 42 | } /* namespace gr */ 43 | 44 | #endif /* _QA_ERROR_CORRECTION_GUESS_H_ */ 45 | -------------------------------------------------------------------------------- /lib/qa_noise_level_estimator.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef _QA_NOISE_LEVEL_ESTIMATOR_H_ 18 | #define _QA_NOISE_LEVEL_ESTIMATOR_H_ 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | class qa_noise_level_estimator : public CppUnit::TestCase 27 | { 28 | public: 29 | CPPUNIT_TEST_SUITE(qa_noise_level_estimator); 30 | CPPUNIT_TEST(t1_1); 31 | CPPUNIT_TEST(t1_2); 32 | CPPUNIT_TEST(t1_3); 33 | CPPUNIT_TEST(t1_4); 34 | CPPUNIT_TEST(t2_1); 35 | CPPUNIT_TEST_SUITE_END(); 36 | 37 | private: 38 | void t1_1(); 39 | void t1_2(); 40 | void t1_3(); 41 | void t1_4(); 42 | void t2_1(); 43 | }; 44 | 45 | } /* namespace rstt */ 46 | } /* namespace gr */ 47 | 48 | #endif /* _QA_NOISE_LEVEL_ESTIMATOR_H_ */ 49 | -------------------------------------------------------------------------------- /lib/qa_noise_level_estimator2.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | 17 | #ifndef _QA_NOISE_LEVEL_ESTIMATOR2_H_ 18 | #define _QA_NOISE_LEVEL_ESTIMATOR2_H_ 19 | 20 | #include 21 | #include 22 | 23 | namespace gr { 24 | namespace rstt { 25 | 26 | class qa_noise_level_estimator2 : public CppUnit::TestCase 27 | { 28 | public: 29 | CPPUNIT_TEST_SUITE(qa_noise_level_estimator2); 30 | CPPUNIT_TEST(t1_1); 31 | CPPUNIT_TEST(t1_2); 32 | // CPPUNIT_TEST(t1_3); 33 | // CPPUNIT_TEST(t1_4); 34 | // CPPUNIT_TEST(t2_1); 35 | CPPUNIT_TEST_SUITE_END(); 36 | 37 | private: 38 | void t1_1(); 39 | void t1_2(); 40 | // void t1_3(); 41 | // void t1_4(); 42 | // void t2_1(); 43 | }; 44 | 45 | } /* namespace rstt */ 46 | } /* namespace gr */ 47 | 48 | #endif /* _QA_NOISE_LEVEL_ESTIMATOR2_H_ */ 49 | -------------------------------------------------------------------------------- /lib/qa_rstt.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * GNU Radio is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3, or (at your option) 9 | * any later version. 10 | * 11 | * GNU Radio is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with GNU Radio; see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | /* 23 | * This class gathers together all the test cases for the gr-filter 24 | * directory into a single test suite. As you create new test cases, 25 | * add them here. 26 | */ 27 | 28 | #include "qa_error_correction.h" 29 | #include "qa_error_correction_guess.h" 30 | #include "qa_noise_level_estimator.h" 31 | #include "qa_noise_level_estimator2.h" 32 | #include "qa_rstt.h" 33 | 34 | CppUnit::TestSuite* qa_rstt::suite() 35 | { 36 | CppUnit::TestSuite* s = new CppUnit::TestSuite("rstt"); 37 | s->addTest(gr::rstt::qa_error_correction::suite()); 38 | s->addTest(gr::rstt::qa_error_correction_guess::suite()); 39 | s->addTest(gr::rstt::qa_noise_level_estimator::suite()); 40 | s->addTest(gr::rstt::qa_noise_level_estimator2::suite()); 41 | 42 | return s; 43 | } 44 | -------------------------------------------------------------------------------- /lib/qa_rstt.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2012 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifndef _QA_RSTT_H_ 24 | #define _QA_RSTT_H_ 25 | 26 | #include 27 | #include 28 | 29 | //! collect all the tests for the gr-filter directory 30 | 31 | class __GR_ATTR_EXPORT qa_rstt 32 | { 33 | public: 34 | //! return suite of tests for all of gr-filter directory 35 | static CppUnit::TestSuite* suite(); 36 | }; 37 | 38 | #endif /* _QA_RSTT_H_ */ 39 | -------------------------------------------------------------------------------- /lib/symbols2bits_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifdef HAVE_CONFIG_H 17 | #include "config.h" 18 | #endif 19 | 20 | #include "symbols2bits_impl.h" 21 | #include 22 | 23 | #include 24 | 25 | namespace gr { 26 | namespace rstt { 27 | 28 | symbols2bits::sptr symbols2bits::make(int sync_nbits) 29 | { 30 | return gnuradio::get_initial_sptr(new symbols2bits_impl(sync_nbits)); 31 | } 32 | 33 | symbols2bits_impl::symbols2bits_impl(int sync_nbits) 34 | : gr::block("symbols2bits", 35 | gr::io_signature::make(1, 1, sizeof(in_t)), 36 | gr::io_signature::make(1, 1, sizeof(out_t))), 37 | roll_out_nbits(0), 38 | sync_win_len(2 * sync_nbits), 39 | sync_win_offs(0), 40 | sync_win(new win_t[sync_win_len]), 41 | sync_win_idx(0), 42 | fill_in_nsymbols(sync_win_len) 43 | { 44 | sync_win_nerrs[0] = sync_win_nerrs[1] = 0; 45 | memset(sync_win.get(), 1, sync_win_len * sizeof(win_t)); 46 | } 47 | 48 | symbols2bits_impl::~symbols2bits_impl() {} 49 | 50 | void symbols2bits_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required) 51 | { 52 | ninput_items_required[0] = 2 * noutput_items + fill_in_nsymbols + 1; 53 | } 54 | 55 | int symbols2bits_impl::general_work(int noutput_items, 56 | gr_vector_int& ninput_items, 57 | gr_vector_const_void_star& input_items, 58 | gr_vector_void_star& output_items) 59 | { 60 | const in_t* in = (const in_t*)input_items[0]; 61 | out_t* out = (out_t*)output_items[0]; 62 | 63 | int consume = ninput_items[0]; 64 | int produced = work_fill(noutput_items, consume, in, out); 65 | 66 | if (!fill_in_nsymbols) { 67 | in += ninput_items[0] - consume; 68 | out += produced; 69 | noutput_items -= produced; 70 | produced += work_convert(noutput_items, consume, in, out); 71 | } 72 | 73 | consume_each(ninput_items[0] - consume); 74 | 75 | return produced; 76 | } 77 | 78 | bool symbols2bits_impl::is_out_of_sync() const 79 | { 80 | return (sync_win_offs == 0 && sync_win_nerrs[0] > sync_win_nerrs[1]) || 81 | (sync_win_offs == 1 && sync_win_nerrs[0] < sync_win_nerrs[1]); 82 | } 83 | 84 | symbols2bits_impl::win_t symbols2bits_impl::put_symbol(const in_t* in) 85 | { 86 | const win_t val_old = sync_win[sync_win_idx]; 87 | const win_t val_new = win_t(in[1]) - win_t(in[0]); 88 | sync_win[sync_win_idx] = val_new; 89 | sync_win_nerrs[sync_win_idx % 2] += abs(val_old) - abs(val_new); 90 | 91 | ++sync_win_idx; 92 | if (sync_win_idx == sync_win_len) { 93 | sync_win_idx = 0; 94 | } 95 | return val_old; 96 | } 97 | 98 | int symbols2bits_impl::roll_out(int out_len, int& consume, const in_t* in, out_t* out) 99 | { 100 | if (!roll_out_nbits) { 101 | return 0; 102 | } 103 | const int nroll = std::min(std::min(roll_out_nbits, out_len), consume / 2); 104 | int produced = 0; 105 | for (; produced < nroll; ++produced) { 106 | shift_bite(in, out); 107 | ++out; 108 | in += 2; 109 | consume -= 2; 110 | } 111 | 112 | roll_out_nbits -= produced; 113 | if (roll_out_nbits) { 114 | return -produced; 115 | } 116 | if (is_out_of_sync()) { 117 | sync_win_offs = 1 - sync_win_offs; 118 | } 119 | return produced; 120 | } 121 | 122 | void symbols2bits_impl::shift_bite(const in_t* in, out_t* out) 123 | { 124 | const win_t val1 = put_symbol(in); 125 | const win_t val2 = put_symbol(in + 1); 126 | const win_t val = sync_win_offs ? val2 : val1; 127 | if (val == -1) { 128 | out[0] = 0; 129 | } else if (val == 1) { 130 | out[0] = 1; 131 | } else { 132 | out[0] = -1; 133 | } 134 | } 135 | 136 | int symbols2bits_impl::work_convert(int out_len, int& consume, const in_t* in, out_t* out) 137 | { 138 | int consume_ = consume; // bellow we do: in += consumed 139 | int produced = roll_out(out_len, consume, in, out); 140 | if (produced < 0) { 141 | return -produced; 142 | } 143 | in += consume_ - consume; 144 | out += produced; 145 | 146 | while (consume > 2 && produced < out_len) { 147 | if (is_out_of_sync()) { 148 | roll_out_nbits += 149 | sync_win_len / 2 - std::max(sync_win_nerrs[0], sync_win_nerrs[1]); 150 | if (!roll_out_nbits) { 151 | sync_win_offs = 1 - sync_win_offs; 152 | continue; 153 | } 154 | consume_ = consume; 155 | const int p = roll_out(out_len - produced, consume, in, out); 156 | if (p < 0) { 157 | produced += -p; 158 | break; 159 | } 160 | produced += p; 161 | out += p; 162 | in += consume_ - consume; 163 | continue; 164 | } 165 | shift_bite(in, out); 166 | consume -= 2; 167 | in += 2; 168 | ++produced; 169 | ++out; 170 | } 171 | 172 | return produced; 173 | } 174 | 175 | int symbols2bits_impl::work_fill(int, int& consume, const in_t* in, out_t*) 176 | { 177 | if (!fill_in_nsymbols) { 178 | return 0; 179 | } 180 | while (fill_in_nsymbols && consume > 1) { 181 | put_symbol(in); 182 | ++in; 183 | --consume; 184 | --fill_in_nsymbols; 185 | } 186 | 187 | if (!fill_in_nsymbols) { 188 | if (is_out_of_sync()) { 189 | sync_win_offs = 1 - sync_win_offs; 190 | } 191 | } 192 | 193 | return 0; 194 | } 195 | 196 | } /* namespace rstt */ 197 | } /* namespace gr */ 198 | -------------------------------------------------------------------------------- /lib/symbols2bits_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2013 Jiří Pinkava . 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #ifndef INCLUDED_RSTT_SYMBOLS2BITS_IMPL_H 17 | #define INCLUDED_RSTT_SYMBOLS2BITS_IMPL_H 18 | 19 | #include 20 | #include 21 | 22 | namespace gr { 23 | namespace rstt { 24 | 25 | class symbols2bits_impl : public symbols2bits 26 | { 27 | private: 28 | typedef unsigned char in_t; 29 | typedef signed char out_t; 30 | typedef signed char win_t; 31 | 32 | /** Number of error in even/odd synchronization windw. */ 33 | int sync_win_nerrs[2]; 34 | /** Number of bits to send before normal operation can continue. */ 35 | int roll_out_nbits; 36 | /** Lenght of synchronization window. */ 37 | int sync_win_len; 38 | /** Current synchronized window, odd = 0, even = 1. */ 39 | int sync_win_offs; 40 | /** Synchronization window length. */ 41 | boost::shared_array sync_win; 42 | /** Fill buffers with nsymbols before normal operation can start. */ 43 | int sync_win_idx; 44 | int fill_in_nsymbols; 45 | 46 | bool is_out_of_sync() const; 47 | 48 | win_t put_symbol(const in_t* in); 49 | 50 | int roll_out(int out_len, int& consume, const in_t* in, out_t* out); 51 | 52 | void shift_bite(const in_t* in, out_t* out); 53 | 54 | int work_convert(int out_len, int& consume, const in_t* in, out_t* out); 55 | 56 | int work_fill(int out_len, int& consume, const in_t* in, out_t* out); 57 | 58 | public: 59 | symbols2bits_impl(int sync_nbits); 60 | ~symbols2bits_impl(); 61 | 62 | void forecast(int noutput_items, gr_vector_int& ninput_items_required); 63 | 64 | int general_work(int noutput_items, 65 | gr_vector_int& ninput_items, 66 | gr_vector_const_void_star& input_items, 67 | gr_vector_void_star& output_items); 68 | }; 69 | 70 | } // namespace rstt 71 | } // namespace gr 72 | 73 | #endif /* INCLUDED_RSTT_SYMBOLS2BITS_IMPL_H */ 74 | -------------------------------------------------------------------------------- /lib/test_rstt.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2012 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | 30 | #include "qa_rstt.h" 31 | #include 32 | #include 33 | 34 | int main(int argc, char** argv) 35 | { 36 | CppUnit::TextTestRunner runner; 37 | std::ofstream xmlfile(get_unittest_path("rstt.xml").c_str()); 38 | CppUnit::XmlOutputter* xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile); 39 | 40 | runner.addTest(qa_rstt::suite()); 41 | runner.setOutputter(xmlout); 42 | 43 | bool was_successful = runner.run("", false); 44 | 45 | return was_successful ? 0 : 1; 46 | } 47 | -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-rstt 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Include python install macros 11 | ######################################################################## 12 | include(GrPython) 13 | if(NOT PYTHONINTERP_FOUND) 14 | return() 15 | endif() 16 | 17 | add_subdirectory(bindings) 18 | 19 | ######################################################################## 20 | # Install python sources 21 | ######################################################################## 22 | GR_PYTHON_INSTALL( 23 | FILES 24 | __init__.py 25 | calibration.py 26 | conv_tools.py 27 | frame.py 28 | #print_row.py 29 | subframe.py 30 | rstt_panel.py DESTINATION ${GR_PYTHON_DIR}/rstt 31 | ) 32 | 33 | ######################################################################## 34 | # Handle the unit tests 35 | ######################################################################## 36 | include(GrTest) 37 | 38 | set(GR_TEST_TARGET_DEPS gnuradio-rstt) 39 | -------------------------------------------------------------------------------- /python/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008,2009 Free Software Foundation, Inc. 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | 7 | # The presence of this file turns this directory into a Python package 8 | 9 | ''' 10 | This is the GNU Radio RSTT module. Place your Python package 11 | description here (python/__init__.py). 12 | ''' 13 | import os 14 | 15 | # import pybind11 generated symbols into the rstt namespace 16 | try: 17 | # this might fail if the module is python-only 18 | from .rstt_python import * 19 | except ModuleNotFoundError: 20 | pass 21 | 22 | # import any pure python here 23 | from .rstt_panel import * 24 | # 25 | -------------------------------------------------------------------------------- /python/bindings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | # 7 | 8 | ######################################################################## 9 | # Check if there is C++ code at all 10 | ######################################################################## 11 | if(NOT rstt_sources) 12 | MESSAGE(STATUS "No C++ sources... skipping python bindings") 13 | return() 14 | endif(NOT rstt_sources) 15 | 16 | ######################################################################## 17 | # Check for pygccxml 18 | ######################################################################## 19 | GR_PYTHON_CHECK_MODULE_RAW( 20 | "pygccxml" 21 | "import pygccxml" 22 | PYGCCXML_FOUND 23 | ) 24 | 25 | include(GrPybind) 26 | 27 | ######################################################################## 28 | # Python Bindings 29 | ######################################################################## 30 | 31 | list(APPEND rstt_python_files 32 | bits2bytes_python.cc 33 | bytes2frames_python.cc 34 | clip_python.cc 35 | decoder_python.cc 36 | error_correction_python.cc 37 | noise_level_estimator2_python.cc 38 | noise_level_estimator_python.cc 39 | noise_model_python.cc 40 | symbols2bits_python.cc 41 | python_bindings.cc) 42 | 43 | GR_PYBIND_MAKE_OOT(rstt 44 | ../.. 45 | gr::rstt 46 | "${rstt_python_files}") 47 | 48 | install(TARGETS rstt_python DESTINATION ${GR_PYTHON_DIR}/rstt COMPONENT pythonapi) 49 | -------------------------------------------------------------------------------- /python/bindings/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bastibl/gr-rstt/a8572d3748d308a70b09ce7c13dbdc8c7c6084c8/python/bindings/README.md -------------------------------------------------------------------------------- /python/bindings/bind_oot_file.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | import argparse 3 | import os 4 | from gnuradio.bindtool import BindingGenerator 5 | import pathlib 6 | import sys 7 | 8 | parser = argparse.ArgumentParser(description='Bind a GR Out of Tree Block') 9 | parser.add_argument('--module', type=str, 10 | help='Name of gr module containing file to bind (e.g. fft digital analog)') 11 | 12 | parser.add_argument('--output_dir', default='/tmp', 13 | help='Output directory of generated bindings') 14 | parser.add_argument('--prefix', help='Prefix of Installed GNU Radio') 15 | parser.add_argument('--src', help='Directory of gnuradio source tree', 16 | default=os.path.dirname(os.path.abspath(__file__))+'/../../..') 17 | 18 | parser.add_argument( 19 | '--filename', help="File to be parsed") 20 | 21 | parser.add_argument( 22 | '--defines', help='Set additional defines for precompiler',default=(), nargs='*') 23 | parser.add_argument( 24 | '--include', help='Additional Include Dirs, separated', default=(), nargs='*') 25 | 26 | parser.add_argument( 27 | '--status', help='Location of output file for general status (used during cmake)', default=None 28 | ) 29 | parser.add_argument( 30 | '--flag_automatic', default='0' 31 | ) 32 | parser.add_argument( 33 | '--flag_pygccxml', default='0' 34 | ) 35 | 36 | args = parser.parse_args() 37 | 38 | prefix = args.prefix 39 | output_dir = args.output_dir 40 | defines = tuple(','.join(args.defines).split(',')) 41 | includes = ','.join(args.include) 42 | name = args.module 43 | 44 | namespace = ['gr', name] 45 | prefix_include_root = name 46 | 47 | 48 | with warnings.catch_warnings(): 49 | warnings.filterwarnings("ignore", category=DeprecationWarning) 50 | 51 | bg = BindingGenerator(prefix, namespace, 52 | prefix_include_root, output_dir, define_symbols=defines, addl_includes=includes, 53 | catch_exceptions=False, write_json_output=False, status_output=args.status, 54 | flag_automatic=True if args.flag_automatic.lower() in [ 55 | '1', 'true'] else False, 56 | flag_pygccxml=True if args.flag_pygccxml.lower() in ['1', 'true'] else False) 57 | bg.gen_file_binding(args.filename) 58 | -------------------------------------------------------------------------------- /python/bindings/bits2bytes_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(bits2bytes.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(e2b5fab7f58aae9a590fecac2402cfbb) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_bits2bytes(py::module& m) 31 | { 32 | 33 | using bits2bytes = ::gr::rstt::bits2bytes; 34 | 35 | 36 | py::class_>(m, "bits2bytes", D(bits2bytes)) 38 | 39 | .def(py::init(&bits2bytes::make), 40 | py::arg("sync_nbytes"), 41 | D(bits2bytes,make) 42 | ) 43 | 44 | 45 | 46 | 47 | ; 48 | 49 | 50 | 51 | 52 | } 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /python/bindings/bytes2frames_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(bytes2frames.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(0bad519909fbe521cbaed8b774f8771f) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_bytes2frames(py::module& m) 31 | { 32 | 33 | using bytes2frames = ::gr::rstt::bytes2frames; 34 | 35 | 36 | py::class_>(m, "bytes2frames", D(bytes2frames)) 38 | 39 | .def(py::init(&bytes2frames::make), 40 | D(bytes2frames,make) 41 | ) 42 | 43 | 44 | 45 | 46 | ; 47 | 48 | 49 | 50 | 51 | } 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /python/bindings/clip_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(clip.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(3989a376aa3084a2b9c9d9ebe1e9a517) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_clip(py::module& m) 31 | { 32 | 33 | using clip = ::gr::rstt::clip; 34 | 35 | 36 | py::class_>(m, "clip", D(clip)) 38 | 39 | .def(py::init(&clip::make), 40 | py::arg("vlen"), 41 | py::arg("in_bw"), 42 | py::arg("out_bw"), 43 | D(clip,make) 44 | ) 45 | 46 | 47 | 48 | 49 | 50 | 51 | .def("trim",&clip::trim, 52 | D(clip,trim) 53 | ) 54 | 55 | 56 | 57 | .def("vlen_out",&clip::vlen_out, 58 | D(clip,vlen_out) 59 | ) 60 | 61 | ; 62 | 63 | 64 | 65 | 66 | } 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /python/bindings/decoder_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(decoder.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(d0000c043792a4bff1794ea4df232587) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_decoder(py::module& m) 31 | { 32 | 33 | using decoder = ::gr::rstt::decoder; 34 | 35 | 36 | py::class_>(m, "decoder", D(decoder)) 38 | 39 | .def(py::init(&decoder::make), 40 | py::arg("sync_nbits") = 20 * 10, 41 | py::arg("sync_nbytes") = 32, 42 | py::arg("drop_invalid") = true, 43 | py::arg("guess_level") = 1, 44 | D(decoder,make) 45 | ) 46 | 47 | 48 | 49 | 50 | ; 51 | 52 | 53 | 54 | 55 | } 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /python/bindings/docstrings/README.md: -------------------------------------------------------------------------------- 1 | This directory stores templates for docstrings that are scraped from the include header files for each block -------------------------------------------------------------------------------- /python/bindings/docstrings/bits2bytes_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_bits2bytes = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_bits2bytes_bits2bytes = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_bits2bytes_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/bindings/docstrings/bytes2frames_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_bytes2frames = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_bytes2frames_bytes2frames = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_bytes2frames_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/bindings/docstrings/clip_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_clip = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_clip_clip_0 = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_clip_clip_1 = R"doc()doc"; 26 | 27 | 28 | static const char *__doc_gr_rstt_clip_make = R"doc()doc"; 29 | 30 | 31 | static const char *__doc_gr_rstt_clip_trim = R"doc()doc"; 32 | 33 | 34 | static const char *__doc_gr_rstt_clip_vlen_out = R"doc()doc"; 35 | 36 | 37 | -------------------------------------------------------------------------------- /python/bindings/docstrings/decoder_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_decoder = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_decoder_decoder = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_decoder_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/bindings/docstrings/error_correction_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_error_correction = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_error_correction_error_correction = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_error_correction_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/bindings/docstrings/noise_level_estimator2_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_noise_level_estimator2 = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_noise_level_estimator2_noise_level_estimator2 = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_noise_level_estimator2_make = R"doc()doc"; 26 | 27 | 28 | static const char *__doc_gr_rstt_noise_level_estimator2_estimate = R"doc()doc"; 29 | 30 | 31 | -------------------------------------------------------------------------------- /python/bindings/docstrings/noise_level_estimator_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_noise_level_estimator = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_noise_level_estimator_noise_level_estimator = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_noise_level_estimator_make = R"doc()doc"; 26 | 27 | 28 | static const char *__doc_gr_rstt_noise_level_estimator_estimate = R"doc()doc"; 29 | 30 | 31 | -------------------------------------------------------------------------------- /python/bindings/docstrings/noise_model_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_noise_model = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_noise_model_noise_model_0 = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_noise_model_noise_model_1 = R"doc()doc"; 26 | 27 | 28 | static const char *__doc_gr_rstt_noise_model_lvl = R"doc()doc"; 29 | 30 | 31 | static const char *__doc_gr_rstt_noise_model_mean_lvl = R"doc()doc"; 32 | 33 | 34 | static const char *__doc_gr_rstt_noise_model_sigma = R"doc()doc"; 35 | 36 | 37 | -------------------------------------------------------------------------------- /python/bindings/docstrings/symbols2bits_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,rstt, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_rstt_symbols2bits = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_rstt_symbols2bits_symbols2bits = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_rstt_symbols2bits_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/bindings/error_correction_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(error_correction.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(4716419a4dd7d887b66ae66474eeb8c8) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_error_correction(py::module& m) 31 | { 32 | 33 | using error_correction = ::gr::rstt::error_correction; 34 | 35 | 36 | py::class_>(m, "error_correction", D(error_correction)) 38 | 39 | .def(py::init(&error_correction::make), 40 | py::arg("drop_invalid") = false, 41 | py::arg("guess_level") = 1, 42 | D(error_correction,make) 43 | ) 44 | 45 | 46 | 47 | 48 | ; 49 | 50 | 51 | 52 | 53 | } 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /python/bindings/header_utils.py: -------------------------------------------------------------------------------- 1 | # Utilities for reading values in header files 2 | 3 | from argparse import ArgumentParser 4 | import re 5 | 6 | 7 | class PybindHeaderParser: 8 | def __init__(self, pathname): 9 | with open(pathname,'r') as f: 10 | self.file_txt = f.read() 11 | 12 | def get_flag_automatic(self): 13 | # p = re.compile(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)') 14 | # m = p.search(self.file_txt) 15 | m = re.search(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)', self.file_txt) 16 | if (m and m.group(1) == '1'): 17 | return True 18 | else: 19 | return False 20 | 21 | def get_flag_pygccxml(self): 22 | # p = re.compile(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)') 23 | # m = p.search(self.file_txt) 24 | m = re.search(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)', self.file_txt) 25 | if (m and m.group(1) == '1'): 26 | return True 27 | else: 28 | return False 29 | 30 | def get_header_filename(self): 31 | # p = re.compile(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)') 32 | # m = p.search(self.file_txt) 33 | m = re.search(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)', self.file_txt) 34 | if (m): 35 | return m.group(1) 36 | else: 37 | return None 38 | 39 | def get_header_file_hash(self): 40 | # p = re.compile(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)') 41 | # m = p.search(self.file_txt) 42 | m = re.search(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)', self.file_txt) 43 | if (m): 44 | return m.group(1) 45 | else: 46 | return None 47 | 48 | def get_flags(self): 49 | return f'{self.get_flag_automatic()};{self.get_flag_pygccxml()};{self.get_header_filename()};{self.get_header_file_hash()};' 50 | 51 | 52 | 53 | def argParse(): 54 | """Parses commandline args.""" 55 | desc='Reads the parameters from the comment block in the pybind files' 56 | parser = ArgumentParser(description=desc) 57 | 58 | parser.add_argument("function", help="Operation to perform on comment block of pybind file", choices=["flag_auto","flag_pygccxml","header_filename","header_file_hash","all"]) 59 | parser.add_argument("pathname", help="Pathname of pybind c++ file to read, e.g. blockname_python.cc") 60 | 61 | return parser.parse_args() 62 | 63 | if __name__ == "__main__": 64 | # Parse command line options and set up doxyxml. 65 | args = argParse() 66 | 67 | pbhp = PybindHeaderParser(args.pathname) 68 | 69 | if args.function == "flag_auto": 70 | print(pbhp.get_flag_automatic()) 71 | elif args.function == "flag_pygccxml": 72 | print(pbhp.get_flag_pygccxml()) 73 | elif args.function == "header_filename": 74 | print(pbhp.get_header_filename()) 75 | elif args.function == "header_file_hash": 76 | print(pbhp.get_header_file_hash()) 77 | elif args.function == "all": 78 | print(pbhp.get_flags()) -------------------------------------------------------------------------------- /python/bindings/noise_level_estimator2_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(noise_level_estimator2.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(49893d2dfcfbd807d18099cff4fa1eec) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_noise_level_estimator2(py::module& m) 31 | { 32 | 33 | using noise_level_estimator2 = ::gr::rstt::noise_level_estimator2; 34 | 35 | 36 | py::class_>(m, "noise_level_estimator2", D(noise_level_estimator2)) 38 | 39 | .def(py::init(&noise_level_estimator2::make), 40 | py::arg("coverage"), 41 | py::arg("chunk_size"), 42 | D(noise_level_estimator2,make) 43 | ) 44 | 45 | 46 | 47 | 48 | 49 | 50 | .def("estimate",&noise_level_estimator2::estimate, 51 | py::arg("data"), 52 | py::arg("data_items"), 53 | D(noise_level_estimator2,estimate) 54 | ) 55 | 56 | ; 57 | 58 | 59 | 60 | 61 | } 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /python/bindings/noise_level_estimator_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(noise_level_estimator.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(f6b41d1f8c4e6afed87cf57e3a36eafe) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_noise_level_estimator(py::module& m) 31 | { 32 | 33 | using noise_level_estimator = ::gr::rstt::noise_level_estimator; 34 | 35 | 36 | py::class_>(m, "noise_level_estimator", D(noise_level_estimator)) 38 | 39 | .def(py::init(&noise_level_estimator::make), 40 | py::arg("coverage"), 41 | py::arg("nsplits"), 42 | D(noise_level_estimator,make) 43 | ) 44 | 45 | 46 | 47 | 48 | 49 | 50 | .def("estimate",&noise_level_estimator::estimate, 51 | py::arg("data"), 52 | py::arg("data_items"), 53 | D(noise_level_estimator,estimate) 54 | ) 55 | 56 | ; 57 | 58 | 59 | 60 | 61 | } 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /python/bindings/noise_model_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(noise_model.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(081f4e523d1d29ac155e0109868daff8) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_noise_model(py::module& m) 31 | { 32 | 33 | using noise_model = ::gr::rstt::noise_model; 34 | 35 | 36 | py::class_>(m, "noise_model", D(noise_model)) 38 | 39 | .def(py::init(), py::arg("mean"), 40 | py::arg("sigma"), 41 | D(noise_model,noise_model,0) 42 | ) 43 | .def(py::init(), py::arg("arg0"), 44 | D(noise_model,noise_model,1) 45 | ) 46 | 47 | 48 | 49 | .def("lvl",&noise_model::lvl, 50 | py::arg("snr"), 51 | D(noise_model,lvl) 52 | ) 53 | 54 | 55 | 56 | .def("mean_lvl",&noise_model::mean_lvl, 57 | D(noise_model,mean_lvl) 58 | ) 59 | 60 | 61 | 62 | .def("sigma",&noise_model::sigma, 63 | D(noise_model,sigma) 64 | ) 65 | 66 | ; 67 | 68 | 69 | 70 | 71 | } 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /python/bindings/python_bindings.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include 11 | 12 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 13 | #include 14 | 15 | namespace py = pybind11; 16 | 17 | // Headers for binding functions 18 | /**************************************/ 19 | // The following comment block is used for 20 | // gr_modtool to insert function prototypes 21 | // Please do not delete 22 | /**************************************/ 23 | // BINDING_FUNCTION_PROTOTYPES( 24 | void bind_bits2bytes(py::module& m); 25 | void bind_bytes2frames(py::module& m); 26 | void bind_clip(py::module& m); 27 | void bind_decoder(py::module& m); 28 | void bind_error_correction(py::module& m); 29 | void bind_noise_level_estimator2(py::module& m); 30 | void bind_noise_level_estimator(py::module& m); 31 | void bind_noise_model(py::module& m); 32 | void bind_symbols2bits(py::module& m); 33 | // ) END BINDING_FUNCTION_PROTOTYPES 34 | 35 | 36 | // We need this hack because import_array() returns NULL 37 | // for newer Python versions. 38 | // This function is also necessary because it ensures access to the C API 39 | // and removes a warning. 40 | void* init_numpy() 41 | { 42 | import_array(); 43 | return NULL; 44 | } 45 | 46 | PYBIND11_MODULE(rstt_python, m) 47 | { 48 | // Initialize the numpy C API 49 | // (otherwise we will see segmentation faults) 50 | init_numpy(); 51 | 52 | // Allow access to base block methods 53 | py::module::import("gnuradio.gr"); 54 | 55 | /**************************************/ 56 | // The following comment block is used for 57 | // gr_modtool to insert binding function calls 58 | // Please do not delete 59 | /**************************************/ 60 | // BINDING_FUNCTION_CALLS( 61 | bind_bits2bytes(m); 62 | bind_bytes2frames(m); 63 | bind_clip(m); 64 | bind_decoder(m); 65 | bind_error_correction(m); 66 | bind_noise_level_estimator2(m); 67 | bind_noise_level_estimator(m); 68 | bind_noise_model(m); 69 | bind_symbols2bits(m); 70 | // ) END BINDING_FUNCTION_CALLS 71 | } 72 | -------------------------------------------------------------------------------- /python/bindings/symbols2bits_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(symbols2bits.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(1219509633310f318caabdbcaaad5094) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_symbols2bits(py::module& m) 31 | { 32 | 33 | using symbols2bits = ::gr::rstt::symbols2bits; 34 | 35 | 36 | py::class_>(m, "symbols2bits", D(symbols2bits)) 38 | 39 | .def(py::init(&symbols2bits::make), 40 | py::arg("sync_nbits"), 41 | D(symbols2bits,make) 42 | ) 43 | 44 | 45 | 46 | 47 | ; 48 | 49 | 50 | 51 | 52 | } 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /python/calibration.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | class CalibrationCollector(object): 4 | """Collect calibration data from fragments.""" 5 | 6 | def __init__(self): 7 | self._missing = [True, ] * 32 8 | self._fragments = [None, ] * 32 9 | self._data = None 10 | 11 | def addFragment(self, idx, data): 12 | """Process one subframe, with calibration data.""" 13 | self._fragments[idx] = data 14 | self._missing[idx] = False 15 | return self.completed() 16 | 17 | def calibration(self): 18 | """Return processed calibration data.""" 19 | return Calibration(self.data()) 20 | 21 | def completed(self): 22 | """Return True if all fragments are collected.""" 23 | if [x for x in self._missing if x]: 24 | return False 25 | return True 26 | 27 | def data(self): 28 | return b''.join(self._fragments) 29 | 30 | class Calibration(object): 31 | """Parse calibration data.""" 32 | def __init__(self, data): 33 | self._d_0 = data[0:2] # TODO 34 | self._d_freq = struct.unpack('") 85 | sys.exit(1) 86 | data = open(sys.argv[1], 'rb').read() 87 | c = Calibration(data) 88 | print(c) 89 | 90 | -------------------------------------------------------------------------------- /python/conv_tools.py: -------------------------------------------------------------------------------- 1 | 2 | from struct import unpack 3 | 4 | 5 | _int_min = -0x1400000 6 | _int_max = (0x1400000-1) 7 | 8 | def conv_int(data): 9 | """Convert serialized fract24 integer into int value.""" 10 | data[2] = 0xff 11 | data = ''.join(chr(x^0xff) for x in data) 12 | if len(data) == 3: 13 | data = data + b'\x00' 14 | val = unpack(' _int_max or val < _int_min: 16 | return None 17 | return val 18 | 19 | 20 | def conv_fract(data): 21 | """Convert serialized fract24 format to float value.""" 22 | val = conv_int(data) 23 | if val is None: 24 | return float('NAN') 25 | return float(val) 26 | 27 | -------------------------------------------------------------------------------- /python/frame.py: -------------------------------------------------------------------------------- 1 | from .subframe import Subframe, SubframeError 2 | import numpy as np 3 | 4 | 5 | class Frame(dict): 6 | """Parse one frame from sonde.""" 7 | 8 | def __init__(self, data, frame_prev = None): 9 | """Parse and decode frame. Input data have structure of byte 10 | stream where input data interleaves with data status, eg. 11 | bytes(data0, status0, data1, status1, ...), nonzero status indicate 12 | (potentaly) broken data. 13 | Frame_prev sould contain previous frame, if set it is used to guess 14 | frame structure if frame is broken to try dig out some data.""" 15 | dict.__init__(self) 16 | self._parse(data, frame_prev) 17 | 18 | def is_broken(self): 19 | return self._broken 20 | 21 | def _parse(self, data, frame_prev): 22 | data = np.array(data[2*6:2*240]) 23 | data, status = data[::2], data[1::2] 24 | 25 | idx = 0 26 | self._sf_len = [] 27 | self._broken = False 28 | while len(data): 29 | try: 30 | subframe = Subframe.parse(data, status) 31 | self[subframe.sf_type] = subframe 32 | sf_len = len(subframe) 33 | except SubframeError as e : 34 | if frame_prev is None: 35 | return 36 | self._broken = True 37 | if len(frame_prev._sf_len) <= idx: 38 | return 39 | sf_len = frame_prev._sf_len[idx] 40 | data = data[sf_len:] 41 | status = status[sf_len:] 42 | self._sf_len.append(sf_len) 43 | idx += 1 44 | -------------------------------------------------------------------------------- /python/nle2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import sys 6 | 7 | 8 | class Src: 9 | def __init__(self, fname, block_size, navg = 1): 10 | self.offs = 0 11 | self.navg = navg 12 | self.block_size = block_size 13 | self.data = np.fromfile(fname, dtype=np.float32) 14 | l = divmod(len(self.data), block_size)[0] 15 | self.data = self.data[0:l*block_size] 16 | self.data = self.data.reshape(l, block_size) 17 | 18 | def read(self): 19 | navg = self.navg 20 | # do frame averaging" 21 | data = np.zeros(self.block_size) 22 | while navg > 0 and self.offs < len(self.data): 23 | data += self.data[self.offs] 24 | self.offs += 1 25 | navg -= 1 26 | if navg: 27 | return None 28 | return data / self.navg 29 | 30 | 31 | class Extreme: 32 | def __init__(self, data, mean_rel): 33 | """Data should be integral of signal power value, 34 | mean_rel should be relative mean value, see Split.set_mean for details.""" 35 | idx = self.idx = 0 36 | self.val = 0 37 | while idx < len(data): 38 | val = data[idx] - data[0] - mean_rel * idx 39 | if val > self.val: 40 | self.val = val 41 | self.idx = idx 42 | elif -val > self.val: 43 | self.val = -val 44 | self.idx = idx 45 | idx += 1 46 | 47 | 48 | class Split: 49 | def __init__(self, start, _len): 50 | self.start = start 51 | self.len = _len 52 | 53 | def __str__(self): 54 | return "start = %f; len = %f; mean_rel = %f;" % (self.start, self.len, self.mean_rel, ) 55 | 56 | def get_mean(self, data): 57 | return (self.mean_rel * (self.len - 1) + data[self.start]) / self.len 58 | 59 | def set_mean(self, data): 60 | """Set relative mean value for data in range defined by Split. 61 | Data should be integrated power value of signal.""" 62 | if self.len > 1: 63 | l = self.len - 1 64 | self.mean_rel = (data[self.start + l] - data[self.start]) / l 65 | else: 66 | self.mean_rel = 0. 67 | 68 | def set_extreme(self, data): 69 | """Find new extreme.""" 70 | self.extreme = Extreme(self.data(data), self.mean_rel) 71 | 72 | def data(self, data): 73 | return data[self.start:self.start+self.len] 74 | 75 | 76 | class Show: 77 | """Noise level estimation. Input is vector of FFT(1024) series.""" 78 | 79 | def __init__(self, src): 80 | self.src = src 81 | 82 | def run2(self, noise_pct = 0.33, noise_w = 0.05, threshold = 3): 83 | d = self.src.read() 84 | noise_pct = int(self.src.block_size * noise_pct) 85 | noise_w = int(self.src.block_size * noise_w) 86 | 87 | while len(d): 88 | # plot: original signal 89 | offs = int(len(d) / 2) 90 | x = range(0 - offs, len(d) - offs) 91 | plt.plot(x, d) 92 | 93 | # plot: ln(original signal) 94 | d_log = [np.log(p) for p in d] 95 | min_ = max(d_log) 96 | for p in d_log: 97 | if p < min_ and np.isfinite(p): 98 | min_ = p 99 | d_log = [p if np.isfinite(p) else min_ for p in d_log ] 100 | #plt.plot(x, d_log) 101 | 102 | self.write_signal('out', d_log) 103 | 104 | # moving average and moving sigma 105 | mean = [sum(d_log[0:noise_w]), ] 106 | d_log2 = [x*x for x in d_log] 107 | mean2 = [sum(d_log2[0:noise_w]), ] 108 | for i in range(noise_w, len(d_log)): 109 | ii = i - noise_w 110 | mean.append(mean[ii] - d_log[ii] + d_log[i]) 111 | mean2.append(mean2[ii] - d_log2[ii] + d_log2[i]) 112 | mean = [i/noise_w for i in mean] 113 | mean2 = [i/noise_w for i in mean2] 114 | 115 | # signal dispersion around moving average 116 | s = [] 117 | for i in range(0, len(mean)): 118 | s.append(np.sqrt(mean2[i] - mean[i]**2)) 119 | 120 | #s_plt = [max(s),] * int(noise_w/2) + s 121 | #s_plt = s_plt + [max(s), ] * (len(x) - len(s)) 122 | #plt.plot(x, s_plt) 123 | 124 | s.sort() 125 | s = s[:noise_pct] 126 | s = sum(s) / len(s) * threshold 127 | 128 | mean.sort() 129 | #plt.plot(range(0, len(mean)), mean) 130 | mean = mean[:noise_pct] 131 | mean = sum(mean) / len(mean) 132 | #plt.plot(x, [mean - s, ] * len(d_log)) 133 | #plt.plot(x, [mean, ] * len(d_log)) 134 | #plt.plot(x, [mean + s, ] * len(d_log)) 135 | print(mean - s, mean, mean + s) 136 | 137 | s_lo = [np.exp(mean - s), ] * len(d_log) 138 | s_m = [np.exp(mean), ] * len(d_log) 139 | s_hi = [np.exp(mean + s), ] * len(d_log) 140 | plt.plot(x, s_lo) 141 | plt.plot(x, s_m) 142 | plt.plot(x, s_hi) 143 | plt.show() 144 | plt.close() 145 | 146 | 147 | def write_signal(self, fname, data): 148 | with open('out', 'w') as f: 149 | i = 0 150 | while i < len(data): 151 | f.write("%.4f, " % data[i]) 152 | i += 1 153 | if i % 8 == 0 and i != 0: 154 | f.write("\n") 155 | 156 | if __name__ == '__main__': 157 | s = Show(Src(sys.argv[1], 1024, 2**11)) 158 | s.run2() 159 | -------------------------------------------------------------------------------- /python/nle_integral.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import sys 6 | 7 | 8 | class Src: 9 | def __init__(self, fname, block_size, navg = 1): 10 | self.offs = 0 11 | self.navg = navg 12 | self.block_size = block_size 13 | self.data = np.fromfile(fname, dtype=np.float32) 14 | l = divmod(len(self.data), block_size)[0] 15 | self.data = self.data[0:l*block_size] 16 | self.data = self.data.reshape(l, block_size) 17 | 18 | def read(self): 19 | navg = self.navg 20 | # do frame averaging" 21 | data = np.zeros(self.block_size) 22 | while navg > 0 and self.offs < len(self.data): 23 | data += self.data[self.offs] 24 | self.offs += 1 25 | navg -= 1 26 | if navg: 27 | return None 28 | return data / self.navg 29 | 30 | 31 | class Extreme: 32 | def __init__(self, data, mean_rel): 33 | """Data should be integral of signal power value, 34 | mean_rel should be relative mean value, see Split.set_mean for details.""" 35 | idx = self.idx = 0 36 | self.val = 0 37 | while idx < len(data): 38 | val = data[idx] - data[0] - mean_rel * idx 39 | if val > self.val: 40 | self.val = val 41 | self.idx = idx 42 | # why "+ 1", because this point is last one with value above mean_rel on the 43 | # descenting side of peak, so we need firt point which does not belogn to peak 44 | elif -val > self.val: 45 | self.val = -val 46 | self.idx = idx 47 | idx += 1 48 | 49 | 50 | 51 | class Split: 52 | def __init__(self, start, _len): 53 | self.start = start 54 | self.len = _len 55 | 56 | def __str__(self): 57 | return "start = %f; len = %f; mean_rel = %f;" % (self.start, self.len, self.mean_rel, ) 58 | 59 | def get_mean(self, data): 60 | return (self.mean_rel * (self.len - 1) + data[self.start]) / self.len 61 | 62 | def set_mean(self, data): 63 | """Set relative mean value for data in range defined by Split. 64 | Data should be integrated power value of signal.""" 65 | if self.len > 1: 66 | l = self.len - 1 67 | self.mean_rel = (data[self.start + l] - data[self.start]) / l 68 | else: 69 | self.mean_rel = 0. 70 | 71 | def set_extreme(self, data): 72 | """Find new extreme.""" 73 | self.extreme = Extreme(self.data(data), self.mean_rel) 74 | 75 | def data(self, data): 76 | return data[self.start:self.start+self.len] 77 | 78 | 79 | class Show: 80 | """Noise level estimation. Input is vector of FFT(1024) series.""" 81 | 82 | def __init__(self, src): 83 | self.src = src 84 | 85 | def run(self, noise_pct = 0.2, nsplits = 60, threshold = 2): 86 | d = self.src.read() 87 | while len(d): 88 | # plot: original signal 89 | offs = int(len(d) / 2) 90 | x = range(0 - offs, len(d) - offs) 91 | plt.plot(x, d) 92 | 93 | # plot: log(original signal) 94 | d_log = [np.log(d_) for d_ in d] 95 | min_ = max(d_log) 96 | for d_ in d_log: 97 | if d_ < min_ and np.isfinite(d_): 98 | min_ = d_ 99 | d_log = [d_ if np.isfinite(d_) else min_ for d_ in d_log ] 100 | #plt.plot(x, d_log) 101 | 102 | self.write_signal('out', d_log) 103 | 104 | # get splits 105 | d_ilog = [d_log[0], ] 106 | for idx in range(1, len(d_log)): 107 | d_ilog.append(d_ilog[idx - 1] + d_log[idx]) 108 | split = Split(0, len(d_log)) 109 | splits = [split, ] 110 | split.set_mean(d_ilog) 111 | split.set_extreme(d_ilog) 112 | for sn in range(0, nsplits): 113 | smax = max(splits, key=lambda s: s.extreme.val) 114 | snew = Split(smax.start + smax.extreme.idx + 1, smax.len - smax.extreme.idx - 1) 115 | splits.append(snew) 116 | snew.set_mean(d_ilog) 117 | snew.set_extreme(d_ilog) 118 | smax.len = smax.extreme.idx + 1 119 | smax.set_mean(d_ilog) 120 | smax.set_extreme(d_ilog) 121 | 122 | # get mean and sigma for noise 123 | splits.sort(key=lambda v: v.get_mean(d_log)) 124 | l = 0 125 | mean = 0 126 | sigma = 0 127 | for split in splits: 128 | #print(split) 129 | for v in split.data(d_log): 130 | mean += v 131 | sigma += v**2 132 | l += split.len 133 | if l > len(d) * noise_pct: 134 | break 135 | mean /= l 136 | sigma = np.sqrt(sigma/l - mean**2) * threshold 137 | 138 | print("%.4f %.4f %.4f" % (mean - sigma, mean, mean + sigma, )) 139 | n_lo, mean, n_hi = np.exp(mean - sigma), np.exp(mean), np.exp(mean + sigma) 140 | plt.plot(x, [n_lo for a in x]) 141 | plt.plot(x, [mean for a in x]) 142 | plt.plot(x, [n_hi for a in x]) 143 | 144 | plt.show() 145 | plt.close() 146 | 147 | 148 | def write_signal(self, fname, data): 149 | with open('out', 'w') as f: 150 | i = 0 151 | while i < len(data): 152 | f.write("%.4f, " % data[i]) 153 | i += 1 154 | if i % 8 == 0 and i != 0: 155 | f.write("\n") 156 | 157 | 158 | if __name__ == '__main__': 159 | s = Show(Src(sys.argv[1], 1024, 100)) 160 | s.run() 161 | -------------------------------------------------------------------------------- /python/print_row.py: -------------------------------------------------------------------------------- 1 | 2 | class PrintRow: 3 | def __init__(self, fmt): 4 | self._fmt = fmt 5 | self._fmt_idx = 0 6 | 7 | def _print(self, items): 8 | for i in items: 9 | self._print_item(i) 10 | 11 | def _print_item(self, s): 12 | s = s + ' ' 13 | if len(self._fmt) <= self._fmt_idx : 14 | self._fmt.append(0) 15 | l = len(s) - self._fmt[self._fmt_idx] 16 | if l > 0: 17 | self._fmt[self._fmt_idx] = len(s) 18 | else: 19 | s = ' ' * l + s 20 | 21 | print(s, end='') 22 | self._fmt_idx += 1 23 | 24 | 25 | def print_(self): 26 | if self._crc1_ok: 27 | self._print('%6d' % self._d_frame_num) 28 | self._print(self._d_id.decode('ascii')) 29 | self._print('0x%02x' % self._d_15) 30 | self._print('0x%02x' % self._d_16) 31 | self._print('0x%02x' % self._d_17) 32 | self._print('%2d' % self._d_callibration_num) 33 | 34 | self._print('0x%02x' % self._d_37) 35 | self._print('0x%02x' % self._d_38) 36 | self._print('%6d' % self._d_wire) 37 | self._print('%6d' % self._d_hum_up) 38 | self._print('%6d' % self._d_hum_down) 39 | # self._print('%6d' % self._d_int4) 40 | # self._print('%6d' % self._d_int5) 41 | self._print('%6d' % self._d_pressure) 42 | # self._print('%6d' % self._d_int7) 43 | # self._print('%6d' % self._d_int8) 44 | print() 45 | 46 | -------------------------------------------------------------------------------- /python/qa_bits2bytes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf8 -*- 3 | # 4 | # Copyright 2013 Jiří Pinkava . 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | 17 | from gnuradio import gr, gr_unittest, blocks 18 | from rstt_swig import bits2bytes 19 | 20 | class qa_bits2bytes(gr_unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.tb = gr.top_block () 24 | 25 | def tearDown(self): 26 | self.tb = None 27 | 28 | def do(self, data_src, data_exp, test_block): 29 | src = blocks.vector_source_b(data_src) 30 | self.tb.connect(src, test_block) 31 | dst = blocks.vector_sink_s() 32 | self.tb.connect(test_block, dst) 33 | self.tb.run() 34 | result_data = tuple([int(x) for x in dst.data()]) 35 | self.assertEqual(data_exp, result_data) 36 | 37 | def test_00(self): 38 | data_src = \ 39 | (0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ) + \ 40 | (0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ) + \ 41 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 42 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 18 43 | data_exp = (0x08, 0xff, 0xd9 ) 44 | test_block = bits2bytes(16) 45 | self.do(data_src, data_exp, test_block) 46 | 47 | def test_01(self): 48 | data_src = \ 49 | (0, 1, 0, 1, 0, ) + \ 50 | (0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ) + \ 51 | (0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ) + \ 52 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 53 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 18 54 | data_exp = (0x08, 0xff, 0xd9 ) 55 | test_block = bits2bytes(16) 56 | self.do(data_src, data_exp, test_block) 57 | 58 | def test_02(self): 59 | """Test single bit insertion.""" 60 | data_src = \ 61 | (0, 0, 0, 0, 1, 0, 0, 1, 0, 1, ) + \ 62 | (0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ) + \ 63 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 16 + \ 64 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 65 | (0, ) + \ 66 | (0, 0, 1, 0, 1, 1, 1, 0, 0, 1, ) + \ 67 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 68 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 18 69 | data_exp = (0x48, 0xff,) + (0, )*16 + (0xd9, 0x3a, 0xd9, ) 70 | test_block = bits2bytes(16) 71 | self.do(data_src, data_exp, test_block) 72 | 73 | def test_03(self): 74 | """Test single bit deletion.""" 75 | data_src = \ 76 | (0, 0, 0, 0, 1, 0, 0, 1, 0, 1, ) + \ 77 | (0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ) + \ 78 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 16 + \ 79 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 80 | (1, 1, 0, 1, 0, 1, 0, 1, 1, ) + \ 81 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 82 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 18 83 | data_exp = (0x48, 0xff,) + (0, )*16 + (0xd9, 0x1ab, 0xd9, ) 84 | test_block = bits2bytes(16) 85 | self.do(data_src, data_exp, test_block) 86 | 87 | def test_04(self): 88 | """Multibite shift 4b""" 89 | data_src = \ 90 | (0, 0, 0, 0, 1, 0, 0, 1, 0, 1, ) + \ 91 | (0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ) + \ 92 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 16 + \ 93 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 94 | (0, 0, 1, 0, ) + \ 95 | (0, 1, 1, 0, 1, 0, 1, 0, 1, 1, ) + \ 96 | (0, 1, 0, 0, 1, 1, 0, 1, 1, 1, ) + \ 97 | (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ) * 19 98 | data_exp = (0x48, 0xff,) + (0, )*16 + (0xd9, 0xAB, 0xd9, 0x00 ) 99 | test_block = bits2bytes(16) 100 | self.do(data_src, data_exp, test_block) 101 | 102 | if __name__ == '__main__': 103 | gr_unittest.run(qa_bits2bytes, "qa_bits2bytes.xml") 104 | 105 | -------------------------------------------------------------------------------- /python/qa_bytes2frames.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf8 -*- 3 | # 4 | # Copyright 2013 Jiří Pinkava . 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | 17 | from gnuradio import gr, gr_unittest, blocks 18 | from rstt_swig import bytes2frames 19 | 20 | class qa_bytes2frames(gr_unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.tb = gr.top_block () 24 | 25 | def tearDown(self): 26 | self.tb = None 27 | 28 | def do(self, data_src, data_exp, test_block): 29 | src = blocks.vector_source_s(data_src) 30 | self.tb.connect(src, test_block) 31 | dst = blocks.vector_sink_s(vlen=240) 32 | self.tb.connect(test_block, dst) 33 | self.tb.run() 34 | result_data = tuple([int(x) for x in dst.data()]) 35 | self.assertEqual(data_exp, result_data) 36 | 37 | # trivial valid sync 38 | def test_00(self): 39 | data_src =(0x2A, )*5 + (0x10, 0x65, 0x10) + (0, )*34 + \ 40 | (0x69, 0x0C, ) + (0, )*26 + \ 41 | (0x67, 0x3D, ) + (0, )*124 + \ 42 | (0x68, 0x05, ) + (0, )*12 + \ 43 | (0xff, 0x02, 0x02, 0x00, 0x02, ) + (0, )*25 44 | data_exp = data_src 45 | #data_src = data_src + data_src 46 | test_block = bytes2frames() 47 | self.do(data_src, data_exp, test_block) 48 | 49 | # sync with offset 50 | def test_01(self): 51 | data_src = (0x2A, )*5 + (0x10, 0x65, 0x10) + (0, )*34 + \ 52 | (0x69, 0x0C, ) + (0, )*26 + \ 53 | (0x67, 0x3D, ) + (0, )*124 + \ 54 | (0x68, 0x05, ) + (0, )*12 + \ 55 | (0xff, 0x02, 0x02, 0x00, 0x02, ) + (0, )*25 56 | data_exp = \ 57 | (0x700,)*6 + (0x700, 0x700, ) + (0x700, )*34 + \ 58 | (0x700, 0x700, ) + (0x700, )*26 + \ 59 | (0x700, 0x700, ) + (0x700, )*124 + \ 60 | (0x700, 0x700, ) + (0x700, )*12 + \ 61 | (0x700, 0x700, 0x700, 0x700, 0x700, ) + (0x700, )*15 + (0x01, )*10 + \ 62 | data_src + \ 63 | data_src 64 | data_src = (0x01,)* 10 + data_src + data_src 65 | #data_src = data_src + data_src 66 | test_block = bytes2frames() 67 | self.do(data_src, data_exp, test_block) 68 | 69 | 70 | if __name__ == '__main__': 71 | gr_unittest.run(qa_bytes2frames, "qa_bytes2frames.xml") 72 | 73 | -------------------------------------------------------------------------------- /python/qa_clip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2013 Jiří Pinkava . 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | 17 | from gnuradio import gr, gr_unittest, blocks 18 | from rstt_swig import clip 19 | 20 | class qa_clip (gr_unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.tb = gr.top_block() 24 | 25 | def tearDown(self): 26 | self.tb = None 27 | 28 | def do(self, data_src, data_exp, test_block, vlen): 29 | src = blocks.vector_source_f(data_src, False, vlen) 30 | self.tb.connect(src, test_block) 31 | dst = blocks.vector_sink_f(test_block.vlen_out()) 32 | self.tb.connect(test_block, dst) 33 | self.tb.run() 34 | result_data = tuple([int(x) for x in dst.data()]) 35 | self.assertEqual(data_exp, result_data) 36 | 37 | def test_00(self): 38 | data_src = (11., 12., 13., 14., 15., -14., -13., -12., -11., ) 39 | data_exp = (12, 13, 14, 15, -14, -13, -12, ) 40 | vlen = len(data_src) 41 | test_block = clip(vlen, 1., 0.8) 42 | self.do(data_src, data_exp, test_block, len(data_src)) 43 | 44 | def test_01(self): 45 | data_src = (11., 12., 13., 14., 15., -15., -14., -13., -12., -11., ) 46 | data_exp = (12, 13, 14, 15, -15, -14, -13, -12, ) 47 | vlen = len(data_src) 48 | test_block = clip(vlen, 1., 0.82) 49 | self.do(data_src, data_exp, test_block, len(data_src)) 50 | 51 | def test_02(self): 52 | data_src = (11., 12., 13., 14., 15., -14., -13., -12., -11., 53 | 21., 22., 23., 24., 25., -24., -23., -22., -21., ) 54 | data_exp = (12, 13, 14, 15, -14, -13, -12, 55 | 22, 23, 24, 25, -24, -23, -22, ) 56 | vlen = len(data_src) / 2 57 | test_block = clip(vlen, 1., 0.8) 58 | self.do(data_src, data_exp, test_block, len(data_src) / 2) 59 | 60 | def test_03(self): 61 | data_src = (11., 12., 13., 14., 15., -15., -14., -13., -12., -11., 62 | 21., 22., 23., 24., 25., -25., -24., -23., -22., -21., ) 63 | data_exp = (12, 13, 14, 15, -15, -14, -13, -12, 64 | 22, 23, 24, 25, -25, -24, -23, -22, ) 65 | vlen = len(data_src) / 2 66 | test_block = clip(vlen, 1., 0.82) 67 | self.do(data_src, data_exp, test_block, len(data_src) / 2) 68 | 69 | 70 | if __name__ == '__main__': 71 | gr_unittest.run(qa_clip, "qa_clip.xml") 72 | 73 | -------------------------------------------------------------------------------- /python/qa_decoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2013 Jiří Pinkava . 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | 17 | from gnuradio import gr, gr_unittest, blocks 18 | from rstt_swig import decoder 19 | 20 | class qa_decoder (gr_unittest.TestCase): 21 | 22 | def setUp (self): 23 | self.tb = gr.top_block () 24 | 25 | def tearDown (self): 26 | self.tb = None 27 | 28 | def do(self, data_src, data_exp, test_block): 29 | src = blocks.vector_source_b(data_src) 30 | self.tb.connect(src, test_block) 31 | dst = blocks.vector_sink_s(vlen=240) 32 | self.tb.connect(test_block, dst) 33 | self.tb.run() 34 | result_data = tuple([int(x) for x in dst.data()]) 35 | self.assertEqual(data_exp, result_data) 36 | 37 | def test_01(self): 38 | """Dummy test, just proves module can be loaded/called.""" 39 | data_src = () 40 | data_exp = () 41 | test_block = decoder() 42 | self.do(data_src, data_exp, test_block) 43 | 44 | 45 | if __name__ == '__main__': 46 | gr_unittest.run(qa_decoder, "qa_decoder.xml") 47 | -------------------------------------------------------------------------------- /python/qa_error_correction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf8 -*- 3 | # 4 | # Copyright 2013 Jiří Pinkava . 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | 17 | from gnuradio import gr, gr_unittest, blocks 18 | from rstt_swig import error_correction 19 | 20 | class qa_error_correction (gr_unittest.TestCase): 21 | _packet00 = """ 22 | 2a 2a 2a 2a 2a 10 65 10 4b 05 20 20 48 34 31 33 23 | 33 32 38 34 00 6d 00 0b ba 53 b5 1e 75 73 5d c3 24 | 1f 38 b8 05 43 20 83 54 71 8b 69 0c eb 27 0f b6 25 | 82 0f 2d df 0f 0a 27 11 d8 4a 11 a8 54 0f 7e 54 26 | 0d f4 55 0d 07 47 67 3d ac 46 80 14 77 ab 37 10 27 | ab 45 80 82 9f 01 5f 3f 4f 1f 1f 6f f0 4f 7f 6f 28 | 3f f0 85 32 a1 00 6b 1b a2 01 ff a5 89 00 d1 08 29 | 8f 07 ff ff ff 7f 27 e9 a6 05 09 22 09 00 d7 e1 30 | 8a fe 0a a6 3d 00 40 6f a7 fc 26 e4 5c 00 1e 70 31 | 95 fc ff ff ff 7f 01 ce b1 00 87 10 e1 00 9a 5c 32 | 99 fe da f3 91 00 69 08 92 00 67 ac 4a 00 a0 c6 33 | 96 00 ff ff ff 7f de 50 95 00 ff ff ff 7f 9c 92 34 | f3 01 0e 02 68 05 03 03 00 00 00 00 00 00 00 00 35 | b2 7d ff 02 02 00 02 00 2e c0 0a 8b 89 3e d3 69 36 | e6 75 86 1d d8 76 ca bb 37 94 e0 69 7b 91 34 1a""".replace('\n', '').replace(' ', '') 37 | 38 | def do(self, data_src, data_exp, test_block): 39 | src = blocks.vector_source_s(data_src, vlen=240) 40 | self.tb.connect(src, test_block) 41 | dst = blocks.vector_sink_s(vlen=240) 42 | self.tb.connect(test_block, dst) 43 | self.tb.run() 44 | result_data = tuple([int(x) for x in dst.data()]) 45 | self.assertEqual(data_exp, result_data) 46 | 47 | def setUp(self): 48 | self.tb = gr.top_block () 49 | 50 | def tearDown(self): 51 | self.tb = None 52 | 53 | def test_001(self): 54 | data_src = tuple([ord(x) for x in self._packet00.decode('hex')]) 55 | data_exp = data_src 56 | data_src = data_src[:12] + (0, ) + data_src[13:] 57 | test_block = error_correction() 58 | self.do(data_src, data_exp, test_block) 59 | self.tb.run () 60 | 61 | def test_002(self): 62 | data_src = tuple([ord(x) for x in self._packet00.decode('hex')]) 63 | data_exp = data_src 64 | data_src = data_src[:230] + (0, ) + data_src[231:] 65 | test_block = error_correction() 66 | self.do(data_src, data_exp, test_block) 67 | self.tb.run () 68 | 69 | def test_004(self): 70 | """13 data bytes broken, uncorrectable.""" 71 | data_src = tuple([ord(x) for x in self._packet00.decode('hex')]) 72 | data_src = data_src[:72] + (0, )*13 + data_src[85:] 73 | data_exp = data_src 74 | test_block = error_correction() 75 | self.do(data_src, data_exp, test_block) 76 | self.tb.run () 77 | 78 | def test_005(self): 79 | """11 data bytes broken (2 erasure), correctable.""" 80 | data_src = tuple([ord(x) for x in self._packet00.decode('hex')]) 81 | data_exp = data_src 82 | data_src = data_src[:72] + (0, )*11 + (0x400, ) * 2 + data_src[85:] 83 | test_block = error_correction() 84 | self.do(data_src, data_exp, test_block) 85 | self.tb.run () 86 | 87 | 88 | if __name__ == '__main__': 89 | gr_unittest.run(qa_error_correction, "qa_error_correction.xml") 90 | -------------------------------------------------------------------------------- /python/qa_symbols2bits.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf8 -*- 3 | # 4 | # Copyright 2013 Jiří Pinkava . 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | 17 | from gnuradio import gr, gr_unittest, blocks 18 | from rstt_swig import symbols2bits 19 | 20 | _1 = (0, 1, ) 21 | _0 = (1, 0, ) 22 | _e0 = (0, 0, ) 23 | _e1 = (1, 1, ) 24 | 25 | class qa_symbols2bits(gr_unittest.TestCase): 26 | 27 | def setUp(self): 28 | self.tb = gr.top_block () 29 | 30 | def tearDown(self): 31 | self.tb = None 32 | 33 | def do(self, data_src, data_exp, test_block): 34 | src = blocks.vector_source_b(data_src) 35 | self.tb.connect(src, test_block) 36 | dst = blocks.vector_sink_b() 37 | self.tb.connect(test_block, dst) 38 | self.tb.run() 39 | result_data = tuple([int(x) for x in dst.data()]) 40 | self.assertEqual(data_exp, result_data) 41 | 42 | def test_00(self): 43 | data_src = _0 + _0 + _0*16 + _0 44 | data_exp = (0, 0, ) 45 | test_block = symbols2bits(16) 46 | self.do(data_src, data_exp, test_block) 47 | 48 | def test_01(self): 49 | data_src = _0 + _1 + _0*16 + _0 50 | data_exp = (0, 1, ) 51 | test_block = symbols2bits(16) 52 | self.do(data_src, data_exp, test_block) 53 | 54 | def test_02(self): 55 | """Single insertion error.""" 56 | _10 = _1 + _0 57 | data_src = _10*16 + (0, ) + _10*16 + _0*4 58 | data_exp = (1, 0)*16 + (1, 0)*10 59 | test_block = symbols2bits(16) 60 | self.do(data_src, data_exp, test_block) 61 | 62 | def test_03(self): 63 | """Single insertion error.""" 64 | _10 = _1 + _0 65 | data_src = (0, ) + _10*16 + (0, ) + _10*16 + _0*4 66 | data_exp = (1, 0)*16 + (255, ) + (1, 0)*9 + (1, ) 67 | test_block = symbols2bits(16) 68 | self.do(data_src, data_exp, test_block) 69 | 70 | def test_04(self): 71 | """Single insertion error.""" 72 | _10010001 = _1 + _0 + _0 + _1 + _0 + _0 + _0 + _1 73 | data_src = _10010001*2 + (0, )*5 + _10010001*2 + _0*16 74 | data_exp = \ 75 | (1, 0, 0, 1, 0, 0, 0, 1) + \ 76 | (1, 0, 0, 1, 0, 0, 0, 1) + \ 77 | (255, 255, 255, ) + \ 78 | (0, 0, 1, 0, 0, 0, 1) + \ 79 | (1, 0, 0, 1, 0, 0, 0, 1) 80 | test_block = symbols2bits(16) 81 | self.do(data_src, data_exp, test_block) 82 | 83 | def test_05(self): 84 | """Single insertion error.""" 85 | _10010001 = _1 + _0 + _0 + _1 + _0 + _0 + _0 + _1 86 | data_src = (0,) + _10010001*2 + (0, )*5 + _10010001*2 + _0*16 87 | data_exp = \ 88 | (1, 0, 0, 1, 0, 0, 0, 1) + \ 89 | (1, 0, 0, 1, 0, 0, 0, 1) + \ 90 | (255, 255, 255, ) + \ 91 | (1, 0, 0, 1, 0, 0, 0, 1) + \ 92 | (1, 0, 0, 1, 0, 0, 0) 93 | test_block = symbols2bits(16) 94 | self.do(data_src, data_exp, test_block) 95 | 96 | if __name__ == '__main__': 97 | gr_unittest.run(qa_symbols2bits, "qa_symbols2bits.xml") 98 | 99 | -------------------------------------------------------------------------------- /python/rstt_panel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy as np 4 | 5 | import matplotlib 6 | matplotlib.use("QT5Agg") 7 | import matplotlib.pyplot as plt 8 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 9 | 10 | from matplotlib.figure import Figure 11 | 12 | from gnuradio import gr, blocks 13 | 14 | from PyQt5 import Qt, QtCore, QtWidgets 15 | 16 | from .calibration import CalibrationCollector, Calibration 17 | from .frame import Frame 18 | from struct import unpack 19 | from .subframe import SF_TYPE_CONFIG, SF_TYPE_MEASUREMENTS, SF_TYPE_GPS, SF_TYPE_PADDING, SF_TYPE_WTF1 20 | 21 | class RsttCanvas(FigureCanvas): 22 | 23 | """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.).""" 24 | def __init__(self, parent=None, width=5, height=4, dpi=100): 25 | fig = Figure(figsize=(width, height), dpi=dpi) 26 | self.a = fig.add_subplot(111) 27 | # We want the axes cleared every time plot() is called 28 | self.a.set_title("Temperature") 29 | self.x = [] 30 | self.temp = [] 31 | self.hum = [] 32 | self.pres = [] 33 | 34 | FigureCanvas.__init__(self, fig) 35 | self.setParent(parent) 36 | 37 | FigureCanvas.setSizePolicy(self, 38 | QtWidgets.QSizePolicy.Expanding, 39 | QtWidgets.QSizePolicy.Expanding) 40 | FigureCanvas.updateGeometry(self) 41 | 42 | def update_figure(self, num, temp, hum, pres): 43 | self.x.append(num) 44 | self.temp.append(temp) 45 | self.hum.append(hum) 46 | self.pres.append(pres) 47 | 48 | self.a.hold(False) 49 | self.a.plot(self.x, self.temp) 50 | self.a.hold(True) 51 | self.a.plot(self.x, self.hum) 52 | self.a.plot(self.x, self.pres) 53 | self.a.legend(('temp', 'humidity', 'pressure'), loc=2) 54 | self.a.set_xlim(num-60, num) 55 | 56 | self.draw() 57 | 58 | 59 | class rsttPanel(gr.sync_block, QtWidgets.QWidget): 60 | def __init__(self, *args, **kwds): 61 | gr.sync_block.__init__( 62 | self, 63 | name = "rstt_panel", 64 | in_sig = [(np.int16, 240)], 65 | out_sig = None, 66 | ) 67 | 68 | QtWidgets.QWidget.__init__(self) 69 | 70 | vlayout = Qt.QVBoxLayout() 71 | layout = Qt.QHBoxLayout() 72 | 73 | label_nr = Qt.QLabel("Frame Nr") 74 | self.frame_num = Qt.QLabel("xxx") 75 | self.frame_num.setStyleSheet("font-weight: bold") 76 | 77 | label_node = Qt.QLabel("Node ID") 78 | self.node_id = Qt.QLabel("xxxxxxxx") 79 | self.node_id.setStyleSheet("font-weight: bold") 80 | 81 | self.calibrated_label = Qt.QLabel("not calibrated") 82 | self.calibrated_label.setStyleSheet("font-weight:bold; color: red") 83 | 84 | plotWidget = QtWidgets.QWidget(self) 85 | self.plot = RsttCanvas(plotWidget, width=5, height=4, dpi=100) 86 | 87 | layout.addWidget(label_nr) 88 | layout.addWidget(self.frame_num) 89 | layout.addWidget(label_node) 90 | layout.addWidget(self.node_id) 91 | layout.addWidget(self.calibrated_label) 92 | 93 | vlayout.addWidget(self.plot) 94 | vlayout.addLayout(layout) 95 | self.setLayout(vlayout) 96 | 97 | self.calib = CalibrationCollector() 98 | self.frame_prev = None 99 | self.calibrated = False 100 | self.conf = None 101 | 102 | def work(self, input_items, output_items): 103 | inp = input_items[0] 104 | 105 | for i in range(len(inp)): 106 | data = [] 107 | for x in inp[i]: 108 | data.append(x&0xFF) 109 | data.append(x>>8) 110 | 111 | frame = Frame(data, self.frame_prev) 112 | if not frame: 113 | print("no frame" + str(frame)) 114 | continue 115 | if not frame.is_broken(): 116 | self.frame_prev = frame 117 | 118 | self.conf = frame.get(SF_TYPE_CONFIG) 119 | if self.conf is not None: 120 | frame_num = self.conf.frame_num 121 | node_id = self.conf.id 122 | calibration_num = self.conf.calibration_num 123 | 124 | self.node_id.setText(str(node_id)) 125 | self.frame_num.setText(str(frame_num)) 126 | else: 127 | frame_num = 0 128 | 129 | self.meas = frame.get(SF_TYPE_MEASUREMENTS) 130 | if self.meas is not None and self.conf is not None: 131 | temp = self.meas.temp 132 | hum = self.meas.hum_down 133 | pres = self.meas.pressure 134 | 135 | self.plot.update_figure(frame_num, temp, hum, pres) 136 | 137 | if not self.calibrated and self.conf is not None: 138 | self.calibrated = self.calib.addFragment(self.conf.calibration_num, self.conf.calibration_data) 139 | if self.calibrated: 140 | print("calibration complete at frame %s" % frame_num) 141 | calib_data = self.calib.data() 142 | self.calib = Calibration(calib_data) 143 | 144 | self.calibrated_label.setText("calibrated") 145 | self.calibrated_label.setStyleSheet("color: green") 146 | 147 | print("frame: %s %s" % (frame_num, not frame.is_broken(), )) 148 | 149 | return len(inp) 150 | 151 | -------------------------------------------------------------------------------- /python/test_subframe.py: -------------------------------------------------------------------------------- 1 | from subframe import Subframe, SubframeErrorCorruptedData 2 | from subframe import SF_TYPE_CONFIG, SF_TYPE_GPS, SF_TYPE_MEASUREMENTS, \ 3 | SF_TYPE_PADDING, SF_TYPE_WTF1 4 | import unittest 5 | 6 | 7 | class TestSubframe(unittest.TestCase): 8 | def test_ok_t0x01_00(self): 9 | data = b'\x01\x04\x01\x02\x03\x04\x05\x06\x07\x08\x92\x47' 10 | subframe = Subframe.parse(data, (0, ) * len(data)) 11 | self.assertEqual(subframe.sf_type, 0x01) 12 | self.assertEqual(subframe.sf_bytes, data[2:-2]) 13 | 14 | def test_broken_t0x01_00(self): 15 | data = b'\x01\x04\x01\x02\x03\x04\x05\x06\x07\x08\x92\x47' 16 | self.assertRaises(SubframeErrorCorruptedData, 17 | Subframe.parse, data, (0, ) * 6 + (1, ) + (0, ) * 5 ) 18 | 19 | def test_ok_t0x65_00(self): 20 | data = b'e\x10\xf1 J1553020\x00q\x00\x11P\xbez|\x9a\x13<{&\x87t\xb8|!\x96\x8b\xf5\xfa' 21 | subframe = Subframe.parse(data, (0, ) * len(data)) 22 | self.assertEqual(subframe.sf_type, SF_TYPE_CONFIG) 23 | self.assertEqual(subframe.sf_bytes, data[2:-2]) 24 | 25 | def test_ok_t0x67_00(self): 26 | data = b'g=\xc1\xbd\xf0\xff\x99\xaa\n\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdcx\xf2\x00\xf4cJ\x00w\xd1\x17\x01)\xb8\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\x19\xf7\x16\x00\xe9p\x94\x00\xaek' 27 | subframe = Subframe.parse(data, (0, ) * len(data)) 28 | self.assertEqual(subframe.sf_type, SF_TYPE_GPS) 29 | self.assertEqual(subframe.sf_bytes, data[2:-2]) 30 | 31 | def test_ok_t0x68_00(self): 32 | data = b'h\x05\x03\x03\x00\x00\x00\x00\x00\x00\x00\x00\xb2}' 33 | subframe = Subframe.parse(data, (0, ) * len(data)) 34 | self.assertEqual(subframe.sf_type, SF_TYPE_WTF1) 35 | self.assertEqual(subframe.sf_bytes, data[2:-2]) 36 | 37 | def test_ok_t0x69_00(self): 38 | data = b'i\x0c\xa2e\r#\xb8\x0f\xde\xb6\x0f\xb32\x11\xf04\x11w\xcc\x0e#c\r\xb5d\r3g' 39 | subframe = Subframe.parse(data, (0, ) * len(data)) 40 | self.assertEqual(subframe.sf_type, SF_TYPE_MEASUREMENTS) 41 | self.assertEqual(subframe.sf_bytes, data[2:-2]) 42 | self.assertEqual(subframe.ch1, 0x0d65a2) 43 | self.assertEqual(subframe.ch2, 0x0fb823) 44 | self.assertEqual(subframe.ch3, 0x0fb6de) 45 | self.assertEqual(subframe.ch4, 0x1132b3) 46 | self.assertEqual(subframe.ch5, 0x1134f0) 47 | self.assertEqual(subframe.ch6, 0x0ecc77) 48 | self.assertEqual(subframe.ch7, 0x0d6323) 49 | self.assertEqual(subframe.ch8, 0x0d64b5) 50 | 51 | def test_ok_t0xff_00(self): 52 | data = b'\xff\x02\x02\x00\x02\x00' 53 | subframe = Subframe.parse(data, (0, ) * len(data)) 54 | self.assertEqual(subframe.sf_type, SF_TYPE_PADDING) 55 | self.assertEqual(subframe.sf_bytes, data[2:]) 56 | 57 | 58 | if __name__ == '__main__': 59 | unittest.main() 60 | 61 | -------------------------------------------------------------------------------- /utils/dump_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ -d data ] || mkdir data 4 | 5 | while [ "${1}" != "" ]; do 6 | fname="${1##.*/}" 7 | fname="data/${fname%\.frames}" 8 | echo $fname 9 | ./frame_dumper.py $1 $fname 10 | shift 11 | done 12 | --------------------------------------------------------------------------------